Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: View text-enabled plugins #7

Merged
merged 17 commits into from
Dec 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9,145 changes: 4,430 additions & 4,715 deletions package-lock.json

Large diffs are not rendered by default.

8 changes: 4 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"name": "djangocms-text",
"name": "djangocms-text-ckeditor5",
"version": "1.0.0",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
Expand All @@ -9,14 +9,14 @@
},
"repository": {
"type": "git",
"url": "git+https://github.com/django-cms/djangocms-text.git"
"url": "git+https://github.com/django-cms/djangocms-text-ckeditor5.git"
},
"author": "",
"license": "MIT",
"bugs": {
"url": "https://github.com/django-cms/djangocms-text/issues"
"url": "https://github.com/django-cms/djangocms-text-ckeditor5/issues"
},
"homepage": "https://github.com/django-cms/djangocms-text-rte",
"homepage": "https://github.com/django-cms/djangocms-text-ckeditor5",
"devDependencies": {
"css-loader": "^7.1.2",
"css-minimizer-webpack-plugin": "^7.0.0",
Expand Down
16 changes: 16 additions & 0 deletions private/js/ckeditor5_plugins/ckeditor5-cmsplugins/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/**
* @license Copyright (c) 2003-2022, Django-CMS Association
*/

/**
* @module cmsplugin
*/

/* eslint-env es11 */
/* jshint esversion: 11 */

import CMSPlugin from "./src/cmsplugin";

export default CMSPlugin;
export { default as CMSPluginEditing } from './src/cmspluginediting';
// export { default as CMSPluginUI } from './src/cmspluginui';
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import CMSPluginEditing from "./cmspluginediting";

export default class CMSPlugin extends Plugin {
static get requires() {
return [ CMSPluginEditing, CMSPluginUI ];
return [ CMSPluginEditing ];
}

init() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// placeholder/placeholdercommand.js
/* eslint-env es11 */
/* jshint esversion: 11 */

import Command from '@ckeditor/ckeditor5-core/src/command';

Expand Down
Original file line number Diff line number Diff line change
@@ -1,46 +1,63 @@
/* eslint-env es11 */
/* jshint esversion: 11 */


import Plugin from '@ckeditor/ckeditor5-core/src/plugin';

import { stringify } from '@ckeditor/ckeditor5-engine/src/dev-utils/view';
import { toWidget } from '@ckeditor/ckeditor5-widget/src/utils';
import Widget from '@ckeditor/ckeditor5-widget/src/widget';
import CMSPluginCommand from "./cmsplugincommand";

const blockTags = ((str) => str.toUpperCase().substring(1, str.length-1).split("><"))(
"<address><article><aside><blockquote><canvas><dd><div><dl><dt><fieldset><figcaption><figure><footer><form>" +
"<h1><h2><h3><h4><h5><h6><header><hr><li><main><nav><noscript><ol><p><pre><section><table><tfoot><ul><video>"
);


function blockContent( children ) {
for (const item of children) {
if (item.name) {
return blockTags.includes(item?.name.toUpperCase());
}
}
return false;
}

const inlinePluginSchema = 'cms-inline-plugin';
const blockPluginSchema = 'cms-block-plugin';
const pluginAttributes = [ 'id', 'render_plugin', 'plugin_title', 'type', 'plugin_content' ];

export default class CMSPluginEditing extends Plugin {
static get requires() {
return [ Widget ];
}

init() {
console.log( 'CMSPluginEditing#init() got called' );
this._defineSchema();
this._defineConverters();
this.editor.commands.add( 'cms-plugin', new CMSPluginCommand( this.editor ) );
}

_defineSchema() { // ADDED
_defineSchema() {
/*
* Define two schemas for the CMS plugin, one for inline and one for block content
*/
const schema = this.editor.model.schema;

schema.register( 'cms-plugin', {
// Allow wherever text is allowed:
schema.register( inlinePluginSchema, {
isObject: true,
allowWhere: '$text',
allowAttributes: pluginAttributes
} );

// The placeholder will act as an inline node:
isInline: true,

// The inline widget is self-contained so it cannot be split by the caret and can be selected:
schema.register( blockPluginSchema, {
isObject: true,

// The inline widget can have the same attributes as text (for example linkHref, bold).
allowAttributesOf: '$text',

// The placeholder can have many types, like date, name, surname, etc:
allowAttributes: [ 'id', 'plugin_type', 'content' ]
allowWhere: '$block',
allowAttributes: pluginAttributes
} );
}

_defineConverters() { // ADDED
_defineConverters() { // ADDED
const conversion = this.editor.conversion;

conversion.for( 'upcast' ).elementToElement( {
Expand All @@ -49,53 +66,83 @@ export default class CMSPluginEditing extends Plugin {
},
model: ( viewElement, { writer: modelWriter } ) => {
// Extract the "name" from "{name}".
const plugin_type = viewElement.getAttribute("plugin-type") ; //viewElement.getChild( 0 ).attr("plugin-type");
var content = viewElement.getChild(0);
content = content ? content.data : 'XXX';
return modelWriter.createElement( 'cms-plugin', {
id: viewElement.getAttribute("id"),
plugin_type: viewElement.getAttribute("plugin-type"),
content: content
} );
}
} );
const children = Array.from(viewElement.getChildren());
const schema = blockContent(children) ? blockPluginSchema : inlinePluginSchema;

conversion.for( 'editingDowncast' ).elementToElement( {
model: 'cms-plugin',
view: ( modelItem, { writer: viewWriter } ) => {
const widgetElement = createCMSPluginView( modelItem, viewWriter );
let innerHTML = '';
for (const child of children) {
innerHTML += stringify(child);
}

// Enable widget handling on a cms-plugion element inside the editing view.
return toWidget( widgetElement, viewWriter );
return modelWriter.createElement( schema, {
id: viewElement.getAttribute("id"),
plugin_title: viewElement.getAttribute('title') || '',
render_plugin: viewElement.getAttribute('render-plugin') || true,
type: viewElement.getAttribute('type') || 'CmsPluginBase',
plugin_content: innerHTML,
} );
}
} );

conversion.for( 'dataDowncast' ).elementToElement( {
model: 'cms-plugin',
view: ( modelItem, { writer: viewWriter } ) => createCMSPluginView( modelItem, viewWriter )
} );

// Helper method for both downcast converters.
function createCMSPluginView( modelItem, viewWriter ) {
const plugin_type = modelItem.getAttribute( 'plugin_type' );
const plugin_id = modelItem.getAttribute( 'id' );
const content = modelItem.getAttribute( 'content', 'XXX' );

const cmsPluginView = viewWriter.createContainerElement( 'cms-plugin', {
plugin_type: plugin_type,
id: plugin_id,
conversion.for( 'editingDowncast' )
.elementToElement({
model: inlinePluginSchema,
view: (modelItem, {writer: viewWriter}) =>
toWidget(createCMSPluginView(modelItem, viewWriter, true), viewWriter, {
label: modelItem.getAttribute('plugin_title'),
})
} )
.elementToElement({
model: blockPluginSchema,
view: (modelItem, {writer: viewWriter}) => {
const widget = toWidget(createCMSPluginView(modelItem, viewWriter, true), viewWriter, {
label: modelItem.getAttribute('plugin_title'),
});
widget.on('dblclick', () => {
fsbraun marked this conversation as resolved.
Show resolved Hide resolved
alert('dblclick');
});
return widget;
}
});

conversion.for( 'dataDowncast' )
.elementToElement( {
model: inlinePluginSchema,
view: (modelItem, {writer: viewWriter}) =>
createCMSPluginView(modelItem, viewWriter)
} )
.elementToElement({
model: blockPluginSchema,
view: (modelItem, {writer: viewWriter}) =>
createCMSPluginView(modelItem, viewWriter)
} );

// Insert the placeholder name (as a text).
const innerHTML = viewWriter.createRawElement(
'span', {
class: 'badge bg-warning'
}, function( domElement ) {
domElement.innerHTML = content;
} );
viewWriter.insert( viewWriter.createPositionAt( cmsPluginView, 0 ), innerHTML );

return cmsPluginView;
// Helper method for both downcast converters.
function createCMSPluginView( modelItem, viewWriter, edit = false ) {
const attrs = {
'alt': modelItem.getAttribute( 'plugin_title' ),
'id': modelItem.getAttribute( 'id' ),
'render-plugin': modelItem.getAttribute( 'render_plugin' ),
'title': modelItem.getAttribute( 'plugin_title' ),
'type': modelItem.getAttribute( 'type' ),
};
const innerHTML = modelItem.getAttribute( 'plugin_content' );

const plugin = viewWriter.createRawElement(
'cms-plugin', attrs, ( domElement ) => {
domElement.innerHTML = innerHTML;
}
);

if (edit) {
// Artificial wrapper to add UI elements to
const wrapper = viewWriter.createContainerElement(
modelItem.name === inlinePluginSchema ? 'span' : 'div'
);
viewWriter.insert( viewWriter.createPositionAt( wrapper, 0 ), plugin );
return wrapper;
}
return plugin;
}
fsbraun marked this conversation as resolved.
Show resolved Hide resolved
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
* @module userstyle/userstyle
*/

/* eslint-env es11 */
/* jshint esversion: 11 */

import { Plugin } from 'ckeditor5/src/core';
import { Collection } from 'ckeditor5/src/utils';
import { Model, createDropdown, addListToDropdown } from 'ckeditor5/src/ui';
Expand Down Expand Up @@ -145,7 +148,7 @@ function getDropdownItemsDefinitions( editor ) {
// only collect items in dropdown that do not have an own icon
const definition = {
type: 'button',
model: new Model( {
model: new Modal( {
commandParam: plugin.value,
label: plugin.name,
withText: true
Expand Down
11 changes: 0 additions & 11 deletions private/js/ckeditor5_plugins/ckeditor5-cmsplugins/src/index.js

This file was deleted.

Loading
Loading