silverstripe-admin
silverstripe-admin copied to clipboard
React TinyMCE
Currently (SS 4.2.1) TinyMCE is loaded via Entwine, which is causing issues as we progressively move towards more and more react driven UI components.
The usecase sparking this particular issue is the development of a more intuitive UI for editing Elemental blocks. In the case of the single default block (ElementContent
) TinyMCE fails to load as per the usual methods, even after forming a new component to include all the config as the current HtmlEditorField
output does. This comes from either a lack of tinymce
being loaded in the window
scope already, or a lack of firing the Entwine onAdd
hook.
My proposed solution (I'd hoped to open a PR instead of an issue) is to create a new HtmlEditorField
component which then leverages the TinyMCEConfig
output - exported to the component via schema data ['data']
& makes use of the official https://github.com/tinymce/tinymce-react wrapper.
This is proving a little more difficult than first thought since the wrapper really is a wrapper, and still requires a global tinymce
object, or it hooks off to tinymce cloud and shows a big 'unregistered domain' warning that isn't nice for anyone's user experience.
In light of needing to get the bundled tinymce (and all our custom plugins) loaded, I'd like to create this issue to check on thoughts for this before I spend too much time doing the wrong thing.
OK, so there's a preliminary PR open at #628 however this will not solve this issue as it's a halfway shim that still relies on the legacy entwine scripts in order to function.
The issues I ran into while attempting to switch to a fully react based solution are as follows:
- TinyMCE wrapper component relies on the same global instance that a non-react solution would. While this is not a challenge per-se, it is something to keep in mind for the rest of this list.
- The config exported from PHP alone is not enough to bootstrap TinyMCE via the
init
prop.- We set the
baseURL
field to the globaltinymce.EditorManager.baseURL
before calling init. - TinyMCE is rather convoluted and the docs are a nightmare to navigate - I don't fully understand what this is or does, however there is no corresponding instance property it seems that would allow this to be set individually.
- This begs the question about future changes, and how much 'on the fly' configuration to we allow... and how do we manage that? e.g. Closures, Injector, ???
- We set the
- Our plugins are not self contained.
- The plugins load into TinyMCE fine
- The buttons and dropdowns appear and function in the editor toolbar
- However a whole lot of Entwine bootstrapping is needed to actually load the "do something useful" part (the modal dialog - presumably in order to be able to style it as desired to the rest of the CMS).
- I notice the Entwine
openDialog
seems to hook back into react, so it all gets very messy.
To this point we cannot load TinyMCE as we have it in Page with react without first porting our plugins to load via react, hopefully in a self contained manner (ideally configurable, so one may swap out the UI chrome if desired... perahps Injector
could do this?)
Just noting that I'm currently debugging an issue where change detection is happening when TinyMCE is loaded by a FormBuilderLoader (context: SilverStripe 4.4 [React 16] and Elemental 4.x). Not detecting changes means that the value doesn't make its way into the hidden textarea, and therefore doesn't get saved via the Elemental inline save action.
A response to a similar issue is to use the official tinymce-react package, which I guess we'll need to look at doing sooner or later.
I suspect it would be worth doing this at the same time as upgrading to TinyMCE v5 though.