Workgroup - Django CMS CKEditor5 Technical Brief ============================================================================= ###### tags: `workgroup` ## Workgroup Goals - integrate ckeditor5 modern & reliable UX - allow to extend it with the new ckeditor5 es6 framework - allow to create flexible es6 extentions for ckeditor5 instead of the old in-text plugins - implement the new url management system (based on https://github.com/divio/djangocms-url-manager/) - rest api based - allow to link custom models, eg apphooks (blog articles, events, etc) - automatically handle redirects ## Links - PR (draft) - https://github.com/django-cms/djangocms-text-ckeditor/pull/551/files - https://django-cms-ckeditor5-stage.us.aldryn.io/en/ - login: test@django-cms.org - password: test@django-cms.org - https://control.divio.com/control/6231/edit/88939/ (for access ask Victor) ## Milestones | status | date | description | | ------ | ---------- | ----------- | | ✅ | 10.12.2020 | deploy a demo project to divio with plain ckeditor5 integration | | ✅ | 17.12.2020 | create a demo ckeditor5 framework es6 plugin and add it to the PR | | ✅ | 21.12.2020 | specify the djangocms-url-manager integration | | ⚙️ | Q1 2021 | the python packages from pypi should be integratable with djangocms-text-ckeditor5 (eg as djangocms-text-ckeditor5-image) | | ⚙️ | Q1 2021 | implement REST api for the url manager along with the new CMSPlugin'less architecture | | ⚙️ | Q1 2021 | implement a ckeditor5 es6 plugin for the url manager | ## Tentative Roadmap - 2021 Q1 - the first alpha release (PoC) - 2021 Q2 - the beta community release - collect feedback form the community, verify the feasibility of the selected direction - 2021 Q3 - the stable release ## Approximate specification Main points: - drop the in-text plugins support, no migration - allow to extend CKEditor5 through [its es6 framework](https://ckeditor.com/docs/ckeditor5/latest/framework/guides/overview.html) - for example a dev can: - copy-past webpack.config.js - add custom action items, plugins, toolbars buttons, etc - build it and put the compiled app in `static/djangocms_text_ckeditor5/app.js` - run `python manage.py collectstatic` which would override the default `static/djangocms_text_ckeditor5/app.js` from pypi - implement a rest api based url manager - release as a separate pypi package, eg [djangocms-text-ckeditor5](https://github.com/django-cms/djangocms-text-ckeditor5) ### api draft ideas - GET `/api/urls/types/` returns a list of `django.contrib.contenttypes.models.ContentType` instances that can be attached to urls - or maybe not content types, because we also need to have types as `phone`, `email`, etc - POST `/api/url/`, which would create a new `Url` model instance by accepting - `type` - either a content type or a Enum type as `Type.PHONE`, `Type.EMAIL` - `instance_id`, eg cms.Page.id - `label` - the text label to be rendered - a custom ckeditor5 es6 plugin would fetch the required `Url` django model instance by id from the respective endpoint. To implement that we can store the link code in html as following `<a data-url-id="35" data-plugin-type="django-url-manager" href="${url.path}">label from ckeditor</a>` standarization: - /api/url/{id} GET - /api/url/{id} POST - /api/url/{id} DELETE - /api/url/{id} PATCH which django model fields do we want standarize: - is_attached_to_cms_plugin: bool = False And then we might have a cronjob that drops the ghost models, eg `Url.objects.filter(is_attached_to_cms_plugin=False).delete()` - but this will drop the Url instancesa that an editor might intend to save in the next few minutes ### es6 plugins integration proposition - ckeditor-build with `npm run build` a dist ckeditor.js blob and push it to pypi - the developer runs pip install djangocms-ckeditor-text - the developer creates a custom es6 ckeditor5 plugin in his project and compiles it into `demo_plugin/static/demo-plugin.js` - we're planning to allow that using webpack DDL + ckeditor 5 integration - https://github.com/ckeditor/ckeditor5/issues/8395 - the developer adds to his `settings.py` something as ```python CKEDITOR5_PLUGINS = [ 'demo_plugin/static/demo-plugin.js', ] ``` - ckeditor5 in its `render_template` renders: ```html <script src="{% 'djangocms_text_ckeditor/ckeditor5.js'"> <script> CKEditor.init({ plugins: {{ settings.CKEDITOR5_PLUGINS }} }) </script> ``` ##### plugins integration use cases 1. installing djangocms-text-ckeditor5 from pypi should work out of the box without webpack build 2. installing third-party djangocms-text-ckeditor5 plugins from pypi (eg as djangocms-text-ckeditor5-image) should work without webpack build - by adding it to settings.py 3. creation of a custom es6 ckeditor5 plugin - which would have to use a webpack/esbuilt/rollup builder, since it would require ckedito5 es6 framework - Alex: it seems to be possible to connect custom es6 plugins to ckeditor5 framework to webpack DLL system without requiring a specific builder (eg webpack) - Andrew: the case #3 would be as important as #2 #### links for dynamic loading of plugins init a compiled ckeditor5 by selector - https://ckeditor.com/docs/ckeditor5/latest/builds/guides/integration/advanced-setup.html A ticket about loading plugins with a library function - https://github.com/ckeditor/ckeditor5/issues/8395 ```html <script src="../build/ckeditor.js"></script> <script> CKEDITOR.ClassicEditor .create( document.querySelector( '#classic-editor' ) ) .catch( err => { console.error( err.stack ); } ); CKEDITOR.InlineEditor .create( document.querySelector( '#inline-editor' ) ) .catch( err => { console.error( err.stack ); } ); </script> ``` ### edge cases #### ghost models Our case of potential django "ghost" models: 1. user opens a new ckeditor5 creation modal 2. user adds a url es6 plugin which creates an instance with `Url.objects.create(pk=1, is_attached_to_cms_plugin=False)` 3. user closes the tab 4. the `Url` models instance stays attached to nothing and we need to define a cleaning routine to get rid of it #### any existing in-text plugins that can't be replaced with ckeditor5 es6 framework? - ... ## Pre-MVP launch (Q3) - document why we're dropping the plugins - WYSIWYG correct styling - ie when the resulting plugin is rendered with a specific background and fonts, the WYSIWYG editing window should render it respectively. It has been implemented for CKEditor4 already, we would need to integrate it though <details> <summary>example screenshot of a footer editing in CKEditor4</summary> ![](https://i.imgur.com/HJ2zy3h.png) </details> ## Post-MVP Launch (Optional Features) - image plugin - localization - the documentation for the developers who would like to upgrade from ckeditor 4 to 5 - [Restricetive editing](https://ckeditor.com/docs/ckeditor5/latest/features/restricted-editing.html) - we can try to use it eg when only few areas of a plugin are supposed to be editable. Up until now we would move those fields to a django model as CharFields, but restrictive editing has the potential to resolve it. - IE11 support