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 - rest api based - allow to link custom models, eg apphooks (blog articles, events, etc) - automatically handle redirects - [blog post updates google doc]( ## Links - PR (draft) - - - login: - password: - (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 | | ⚙️ | Q3 2021 | the python packages from pypi should be integratable with djangocms-text-ckeditor5 (eg as djangocms-text-ckeditor5-image) | | ⚙️ | Q3 2021 | implement REST api for the url manager along with the new CMSPlugin'less architecture | | ⚙️ | Q3 2021 | implement a ckeditor5 es6 plugin for the url manager | ## Tentative Roadmap - 2021 Q3 - the first alpha release (PoC) - 2021 Q3 - the beta community release - collect feedback form the community, verify the feasibility of the selected direction - 2021 Q3-Q4 - the stable release ## Approximate specification Main points: - drop the in-text plugins support, no migration - allow to extend CKEditor5 through [its es6 framework]( - 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 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]( ### 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 - `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 - - the developer adds to his `` 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 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 - A ticket about loading plugins with a library function - ```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> ![]( </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]( - 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