diff --git a/README.md b/README.md index 578464788582851a111c012b8332a31b625f9a2c..861f4beb035741943cdb81d7b232b8e124dd9e87 100644 --- a/README.md +++ b/README.md @@ -126,57 +126,6 @@ Configure the text format to include the desired CKEditor buttons. Then, on `/admin/config/user-interface/patternkit/json`, you can select this text format in _CKEditor toolbar_. -// TODO: Include language about Patternkit processing text format filters once -this feature has been implemented. - -##### CKEditor content filtering - -If using CKEditor as the wysiwyg plugin, you can configure the schema to allow -or disallow certain HTML tags and attributes. This feature uses [CKEditor's -content filtering -system](https://ckeditor.com/docs/ckeditor4/latest/guide/dev_acf.html). - -###### Setting allowed content - -To set which content is allowed, use property `allowedContent` in the `options` -key of your schema. The property's value will be passed as-is to CKEditor's -`allowedContent` configuration ([expected -format](https://ckeditor.com/docs/ckeditor4/latest/guide/dev_allowed_content_rules.html)). - -###### Setting disallowed content - -Conversely, to prevent certain content, use property `disallowedContent` in the -`options` key of your schema. The property's value will be passed as-is to -CKEditor's `disallowedContent` configuration ([expected -format](https://ckeditor.com/docs/ckeditor4/latest/guide/dev_disallowed_content.html)). - -###### Example - -In this example, only links, bold/strong, and italic/emphasis tags are allowed. -You can use any attributes on these elements (including class, style, and other -attributes), except ones prefixed with `data-`. - -```json -{ - "formatted_text": { - "title": "Formatted Text", - "type": "string", - "format": "html", - "options": { - "wysiwyg": true, - "allowedContent": "a b strong em i[*](*){*}", - "disallowedContent": "*[data-*]" - } - } -} -``` - -_Security note_: Filtering content at the CKEditor layer (i.e., at content -entry) does not filter it when rendered. For example, if you disallow `onclick` -attributes in CKEditor but the pattern's template (e.g., Twig) does not strip -those attributes, a user might, possibly save content with an `onclick` -attribute, and that attribute would be rendered to the page. - ## Definitions Most of the thinking and vernacular used in Patternkit is inspired by diff --git a/composer.json b/composer.json index 25d9a73fba514765c66301ab2795668c11c08b02..64fa0f273e7935cca84f8234100fbcbfb4ea535f 100644 --- a/composer.json +++ b/composer.json @@ -28,7 +28,6 @@ "webmozart/path-util": "^2.1.0" }, "require-dev": { - "drupal/ckeditor": "^1.0", "drupal/core-recommended": "^9 || ^10", "drupal/core-dev": "^9 || ^10", "drupal/devel": "^4.2 || ^5.0" diff --git a/js/patternkit.jsoneditor.ckeditor.es6.js b/js/patternkit.jsoneditor.ckeditor.es6.js deleted file mode 100644 index 0999b1d98a415b9d632531bf24a50483cfbb0b04..0000000000000000000000000000000000000000 --- a/js/patternkit.jsoneditor.ckeditor.es6.js +++ /dev/null @@ -1,231 +0,0 @@ -/*globals Console:false */ -/*globals Drupal:false */ -/*globals jQuery:false */ -/*globals JSONEditor:false */ -/** - * @file DrupalCKEditor class. - * - * @external Drupal - * @external jQuery - * @external JSONEditor - */ - -import {DrupalCKEditor5} from './patternkit.jsoneditor.ckeditor5.es6'; - -class DrupalCKEditor extends JSONEditor.defaults.editors.string { - - build() { - // Override the format when building the base string editor. - this.options.format = 'textarea'; - super.build(); - this.input_type = this.schema.format; - this.input.setAttribute('data-schemaformat', this.input_type); - } - - /** - * Post-load after CKEditor has created a successful instance. - */ - ckeditorPostLoad() { - this.ckeditor_instance.setData(this.getValue()); - if (this.schema.readOnly || this.schema.readonly || this.schema.template) { - this.ckeditor_instance.setReadOnly(true); - } - - const saveEditorContent = Drupal.debounce(() => { - this.input.value = this.ckeditor_instance.getData(); - this.refreshValue(); - // Dirty means display cache is invalidated for string editors. - this.is_dirty = true; - this.onChange(true); - }, 400); - - this.ckeditor_instance.on('change', saveEditorContent); - // In "source" mode (e.g., by clicking the "Source" button), CKEditor's - // "change" event does not fire, so we need to listen on the "input" - // event. - // See https://ckeditor.com/docs/ckeditor4/latest/api/CKEDITOR_editor.html#event-change - this.ckeditor_instance.on('mode', () => { - if (this.ckeditor_instance.mode === 'source') { - const editable = this.ckeditor_instance.editable(); - editable.attachListener(editable, 'input', saveEditorContent); - } - }); - this.ckeditor_instance.on('blur', () => { - if (this.ckeditor_instance.mode === 'wysiwyg') { - saveEditorContent(); - } - }); - this.theme.afterInputReady(this.input); - } - - afterInputReady() { - if (window.CKEDITOR) { - // Editor options. - // @todo Replace JSONEditor.defaults with this.defaults. - this.options = jQuery.extend({}, JSONEditor.defaults.options.drupal_ckeditor || {}, this.options.drupal_ckeditor || {}); - - // Copies logic from Drupal.editors.ckeditor.attach(), so that certain - // buttons (e.g., DrupalLink) work. - this.options.ckeditor_config.drupal = { - format: this.options.ckeditor_config.selected_toolbar, - }; - - // The schema can determine which HTML tags are allowed and disallowed. - // These settings are passed as-is to CKEditor's ACF (content filtering) - // system. See https://ckeditor.com/docs/ckeditor4/latest/guide/dev_acf.html. - // (Clears existing settings in case they were set previously in this request - // by prior schema.) - const allowedContent = this.options.ckeditor_config.allowedContent || null; - const disallowedContent = this.options.ckeditor_config.disallowedContent || null; - delete this.options.ckeditor_config.allowedContent; - delete this.options.ckeditor_config.disallowedContent; - if (this.schema.options.allowedContent) { - this.options.ckeditor_config.allowedContent = this.schema.options.allowedContent; - } - else if (allowedContent) { - this.options.ckeditor_config.allowedContent = allowedContent; - } - - if (this.schema.options.disallowedContent) { - this.options.ckeditor_config.disallowedContent = this.schema.options.disallowedContent; - } - else if (disallowedContent) { - this.options.ckeditor_config.disallowedContent = disallowedContent; - } - - // @see Drupal.editors.ckeditor._loadExternalPlugins - const externalPlugins = this.options.ckeditor_config.drupalExternalPlugins; - if (externalPlugins) { - Object.keys(externalPlugins || {}).forEach(pluginName => { - CKEDITOR.plugins.addExternal( - pluginName, - externalPlugins[pluginName], - '', - ); - }); - delete this.options.ckeditor_config.drupalExternalPlugins; - } - - this.ckeditor_container = document.createElement('div'); - this.ckeditor_container.style.width = '100%'; - this.ckeditor_container.style.position = 'relative'; - this.input.style.display = 'none'; - this.input.parentNode.insertBefore(this.ckeditor_container, this.input); - // Using the delay if delayIfDetached and delayIfDetached_callback, - // was getting an error code: editor-delayed-creation-success, and still - // needed to be in the timeout to work. - setTimeout(() => { - // The input element may be removed due to changes made via the - // jsoneditor properties selections. - if (this.jsoneditor.editors[this.path]) { - this.ckeditor_instance = window.CKEDITOR.replace(this.ckeditor_container, this.options.ckeditor_config); - this.ckeditorPostLoad(); - } - else { - // Store any unloaded textarea that doesn't have a CKEditor instance - // loaded yet. - if (typeof window.DrupalCKEditors == 'undefined' ) { - window.DrupalCKEditors = {}; - } - window.DrupalCKEditors[this.path] = { - ckeditor_container: this.ckeditor_container, - ckeditor_config: this.options.ckeditor_config, - } - this.input.style.display = 'block'; - } - }, 1000); - } - else { - super.afterInputReady(); - } - } - - destroy() { - if (this.ckeditor_instance) { - this.ckeditor_instance.destroy(true); - window.CKEDITOR.remove(this.ckeditor_instance); - this.ckeditor_instance = null; - } - if (window.DrupalCKEditors) { - delete window.DrupalCKEditors; - } - super.destroy(); - } - - disable(always_disabled) { - if (always_disabled) { - this.always_disabled = true; - } - if (this.ckeditor_instance) { - this.ckeditor_instance.setReadOnly(true); - } - super.disable(always_disabled); - } - - enable() { - if (this.always_disabled) { - return; - } - - if (this.ckeditor_instance) { - this.ckeditor_instance.setReadOnly(false); - } - - // Handle cases where the Ckeditor instance is removed before binding. Once - // enabled by properties it will run only once. After being able to bind to - // a DOM element it should be fine since it now has the instance created. - if (window.DrupalCKEditors && window.DrupalCKEditors[this.path] && !this.ckeditor_instance) { - const editor_config = window.DrupalCKEditors[this.path]; - this.ckeditor_instance = window.CKEDITOR.replace(editor_config.ckeditor_container, editor_config.ckeditor_config); - this.ckeditorPostLoad(); - this.input.style.display = 'none'; - } - super.enable(); - } - - getNumColumns() { - return 6; - } - - setValue(val, initial, from_template) { - const input = super.setValue(val, initial, from_template); - if (input !== undefined && input.changed && this.ckeditor_instance) { - this.ckeditor_instance.setData(input.value); - this.refreshWatchedFieldValues(); - this.onChange(true); - } - } -} - -export function patternkitEditorCKEditor($, Drupal, JSONEditor) { - 'use strict'; - Drupal.behaviors.patternkitEditorCKEditor = { - attach: function (context, settings) { - if (!window.JSONEditor || !drupalSettings.patternkitEditor) { - return; - } - - JSONEditor.defaults.options.drupal_ckeditor = { - ckeditor_config: settings.patternkitEditor.patternkitCKEditorConfig || {} - }; - if (drupalSettings.patternkitEditor.wysiwygEditorName === 'ckeditor5') { - JSONEditor.defaults.editors.drupal_ckeditor = DrupalCKEditor5; - } - else { - JSONEditor.defaults.editors.drupal_ckeditor = DrupalCKEditor; - } - - JSONEditor.defaults.resolvers.unshift(function (schema) { - if (schema.type === 'string' - && schema.format === 'html' - && schema.options - && schema.options.wysiwyg - && (settings.patternkitEditor.wysiwygEditorName === 'ckeditor' || settings.patternkitEditor.wysiwygEditorName === 'ckeditor5') - // Ensures the Text format with CKEditor profile loaded okay. - && settings.patternkitEditor.patternkitCKEditorConfig) { - return 'drupal_ckeditor'; - } - }); - } - } -} diff --git a/js/patternkit.jsoneditor.ckeditor5.es6.js b/js/patternkit.jsoneditor.ckeditor5.es6.js index 0641c14fd1c141038941126022de945005777fb2..6fa15bdda92302416cbd15375d1e7b84963fc8d7 100644 --- a/js/patternkit.jsoneditor.ckeditor5.es6.js +++ b/js/patternkit.jsoneditor.ckeditor5.es6.js @@ -3,7 +3,7 @@ /*globals jQuery:false */ /*globals JSONEditor:false */ /** - * @file DrupalImageEditor class. + * @file DrupalCKEditor5 class. * * @external Drupal * @external jQuery @@ -201,3 +201,33 @@ export class DrupalCKEditor5 extends JSONEditor.defaults.editors.string { } } + +export function patternkitEditorCKEditor5($, Drupal, JSONEditor) { + 'use strict'; + Drupal.behaviors.patternkitEditorCKEditor = { + attach: function (context, settings) { + if (!window.JSONEditor || !drupalSettings.patternkitEditor) { + return; + } + + JSONEditor.defaults.options.drupal_ckeditor = { + ckeditor_config: settings.patternkitEditor.patternkitCKEditorConfig || {} + }; + if (drupalSettings.patternkitEditor.wysiwygEditorName === 'ckeditor5') { + JSONEditor.defaults.editors.drupal_ckeditor = DrupalCKEditor5; + } + + JSONEditor.defaults.resolvers.unshift(function (schema) { + if (schema.type === 'string' + && schema.format === 'html' + && schema.options + && schema.options.wysiwyg + && (settings.patternkitEditor.wysiwygEditorName === 'ckeditor5') + // Ensures the Text format with CKEditor profile loaded okay. + && settings.patternkitEditor.patternkitCKEditorConfig) { + return 'drupal_ckeditor'; + } + }); + } + } +} diff --git a/js/patternkit.jsoneditor.es6.js b/js/patternkit.jsoneditor.es6.js index 5ce494b57fde6488c3425222e24b2182b2e4e6c7..1548a24a1803155b5449958a271e02d0ef59caf5 100644 --- a/js/patternkit.jsoneditor.es6.js +++ b/js/patternkit.jsoneditor.es6.js @@ -19,7 +19,7 @@ */ import {patternkitEditorQuill} from './patternkit.jsoneditor.quill.es6.js'; -import {patternkitEditorCKEditor} from './patternkit.jsoneditor.ckeditor.es6'; +import {patternkitEditorCKEditor5} from './patternkit.jsoneditor.ckeditor5.es6'; import {patternkitEditorCygnet} from './patternkit.jsoneditor.cygnet.es6.js'; import {patternkitEditorProseMirror} from "./patternkit.jsoneditor.prosemirror.es6"; import {patternkitEditorObject} from './patternkit.jsoneditor.editor.object.es6'; @@ -27,7 +27,7 @@ import {patternkitEditorArray} from './patternkit.jsoneditor.editor.array.es6'; // Instantiates wysiwyg plugins. patternkitEditorQuill(jQuery, Drupal, JSONEditor); -patternkitEditorCKEditor(jQuery, Drupal, JSONEditor); +patternkitEditorCKEditor5(jQuery, Drupal, JSONEditor); patternkitEditorCygnet(jQuery, Drupal, JSONEditor); patternkitEditorProseMirror(jQuery, Drupal, JSONEditor); diff --git a/js/patternkit.jsoneditor.js b/js/patternkit.jsoneditor.js index 763d03b00e9e8aa9c331ee99403ea957abe57990..11074839238a615cdc945fbdc1f2336fc8bf5a4d 100644 --- a/js/patternkit.jsoneditor.js +++ b/js/patternkit.jsoneditor.js @@ -4,288 +4,7 @@ Object.defineProperty(exports, "__esModule", { value: true }); -exports.patternkitEditorCKEditor = patternkitEditorCKEditor; - -var _patternkitJsoneditorCkeditor = require("./patternkit.jsoneditor.ckeditor5.es6"); - -function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } - -function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } - -function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } - -function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } - -function _get(target, property, receiver) { if (typeof Reflect !== "undefined" && Reflect.get) { _get = Reflect.get; } else { _get = function _get(target, property, receiver) { var base = _superPropBase(target, property); if (!base) return; var desc = Object.getOwnPropertyDescriptor(base, property); if (desc.get) { return desc.get.call(receiver); } return desc.value; }; } return _get(target, property, receiver || target); } - -function _superPropBase(object, property) { while (!Object.prototype.hasOwnProperty.call(object, property)) { object = _getPrototypeOf(object); if (object === null) break; } return object; } - -function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); } - -function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); } - -function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; } - -function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); } - -function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; } - -function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); return true; } catch (e) { return false; } } - -function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); } - -var DrupalCKEditor = /*#__PURE__*/function (_JSONEditor$defaults$) { - _inherits(DrupalCKEditor, _JSONEditor$defaults$); - - var _super = _createSuper(DrupalCKEditor); - - function DrupalCKEditor() { - _classCallCheck(this, DrupalCKEditor); - - return _super.apply(this, arguments); - } - - _createClass(DrupalCKEditor, [{ - key: "build", - value: function build() { - // Override the format when building the base string editor. - this.options.format = 'textarea'; - - _get(_getPrototypeOf(DrupalCKEditor.prototype), "build", this).call(this); - - this.input_type = this.schema.format; - this.input.setAttribute('data-schemaformat', this.input_type); - } - /** - * Post-load after CKEditor has created a successful instance. - */ - - }, { - key: "ckeditorPostLoad", - value: function ckeditorPostLoad() { - var _this = this; - - this.ckeditor_instance.setData(this.getValue()); - - if (this.schema.readOnly || this.schema.readonly || this.schema.template) { - this.ckeditor_instance.setReadOnly(true); - } - - var saveEditorContent = Drupal.debounce(function () { - _this.input.value = _this.ckeditor_instance.getData(); - - _this.refreshValue(); // Dirty means display cache is invalidated for string editors. - - - _this.is_dirty = true; - - _this.onChange(true); - }, 400); - this.ckeditor_instance.on('change', saveEditorContent); // In "source" mode (e.g., by clicking the "Source" button), CKEditor's - // "change" event does not fire, so we need to listen on the "input" - // event. - // See https://ckeditor.com/docs/ckeditor4/latest/api/CKEDITOR_editor.html#event-change - - this.ckeditor_instance.on('mode', function () { - if (_this.ckeditor_instance.mode === 'source') { - var editable = _this.ckeditor_instance.editable(); - - editable.attachListener(editable, 'input', saveEditorContent); - } - }); - this.ckeditor_instance.on('blur', function () { - if (_this.ckeditor_instance.mode === 'wysiwyg') { - saveEditorContent(); - } - }); - this.theme.afterInputReady(this.input); - } - }, { - key: "afterInputReady", - value: function afterInputReady() { - var _this2 = this; - - if (window.CKEDITOR) { - // Editor options. - // @todo Replace JSONEditor.defaults with this.defaults. - this.options = jQuery.extend({}, JSONEditor.defaults.options.drupal_ckeditor || {}, this.options.drupal_ckeditor || {}); // Copies logic from Drupal.editors.ckeditor.attach(), so that certain - // buttons (e.g., DrupalLink) work. - - this.options.ckeditor_config.drupal = { - format: this.options.ckeditor_config.selected_toolbar - }; // The schema can determine which HTML tags are allowed and disallowed. - // These settings are passed as-is to CKEditor's ACF (content filtering) - // system. See https://ckeditor.com/docs/ckeditor4/latest/guide/dev_acf.html. - // (Clears existing settings in case they were set previously in this request - // by prior schema.) - - var allowedContent = this.options.ckeditor_config.allowedContent || null; - var disallowedContent = this.options.ckeditor_config.disallowedContent || null; - delete this.options.ckeditor_config.allowedContent; - delete this.options.ckeditor_config.disallowedContent; - - if (this.schema.options.allowedContent) { - this.options.ckeditor_config.allowedContent = this.schema.options.allowedContent; - } else if (allowedContent) { - this.options.ckeditor_config.allowedContent = allowedContent; - } - - if (this.schema.options.disallowedContent) { - this.options.ckeditor_config.disallowedContent = this.schema.options.disallowedContent; - } else if (disallowedContent) { - this.options.ckeditor_config.disallowedContent = disallowedContent; - } // @see Drupal.editors.ckeditor._loadExternalPlugins - - - var externalPlugins = this.options.ckeditor_config.drupalExternalPlugins; - - if (externalPlugins) { - Object.keys(externalPlugins || {}).forEach(function (pluginName) { - CKEDITOR.plugins.addExternal(pluginName, externalPlugins[pluginName], ''); - }); - delete this.options.ckeditor_config.drupalExternalPlugins; - } - - this.ckeditor_container = document.createElement('div'); - this.ckeditor_container.style.width = '100%'; - this.ckeditor_container.style.position = 'relative'; - this.input.style.display = 'none'; - this.input.parentNode.insertBefore(this.ckeditor_container, this.input); // Using the delay if delayIfDetached and delayIfDetached_callback, - // was getting an error code: editor-delayed-creation-success, and still - // needed to be in the timeout to work. - - setTimeout(function () { - // The input element may be removed due to changes made via the - // jsoneditor properties selections. - if (_this2.jsoneditor.editors[_this2.path]) { - _this2.ckeditor_instance = window.CKEDITOR.replace(_this2.ckeditor_container, _this2.options.ckeditor_config); - - _this2.ckeditorPostLoad(); - } else { - // Store any unloaded textarea that doesn't have a CKEditor instance - // loaded yet. - if (typeof window.DrupalCKEditors == 'undefined') { - window.DrupalCKEditors = {}; - } - - window.DrupalCKEditors[_this2.path] = { - ckeditor_container: _this2.ckeditor_container, - ckeditor_config: _this2.options.ckeditor_config - }; - _this2.input.style.display = 'block'; - } - }, 1000); - } else { - _get(_getPrototypeOf(DrupalCKEditor.prototype), "afterInputReady", this).call(this); - } - } - }, { - key: "destroy", - value: function destroy() { - if (this.ckeditor_instance) { - this.ckeditor_instance.destroy(true); - window.CKEDITOR.remove(this.ckeditor_instance); - this.ckeditor_instance = null; - } - - if (window.DrupalCKEditors) { - delete window.DrupalCKEditors; - } - - _get(_getPrototypeOf(DrupalCKEditor.prototype), "destroy", this).call(this); - } - }, { - key: "disable", - value: function disable(always_disabled) { - if (always_disabled) { - this.always_disabled = true; - } - - if (this.ckeditor_instance) { - this.ckeditor_instance.setReadOnly(true); - } - - _get(_getPrototypeOf(DrupalCKEditor.prototype), "disable", this).call(this, always_disabled); - } - }, { - key: "enable", - value: function enable() { - if (this.always_disabled) { - return; - } - - if (this.ckeditor_instance) { - this.ckeditor_instance.setReadOnly(false); - } // Handle cases where the Ckeditor instance is removed before binding. Once - // enabled by properties it will run only once. After being able to bind to - // a DOM element it should be fine since it now has the instance created. - - - if (window.DrupalCKEditors && window.DrupalCKEditors[this.path] && !this.ckeditor_instance) { - var editor_config = window.DrupalCKEditors[this.path]; - this.ckeditor_instance = window.CKEDITOR.replace(editor_config.ckeditor_container, editor_config.ckeditor_config); - this.ckeditorPostLoad(); - this.input.style.display = 'none'; - } - - _get(_getPrototypeOf(DrupalCKEditor.prototype), "enable", this).call(this); - } - }, { - key: "getNumColumns", - value: function getNumColumns() { - return 6; - } - }, { - key: "setValue", - value: function setValue(val, initial, from_template) { - var input = _get(_getPrototypeOf(DrupalCKEditor.prototype), "setValue", this).call(this, val, initial, from_template); - - if (input !== undefined && input.changed && this.ckeditor_instance) { - this.ckeditor_instance.setData(input.value); - this.refreshWatchedFieldValues(); - this.onChange(true); - } - } - }]); - - return DrupalCKEditor; -}(JSONEditor.defaults.editors.string); - -function patternkitEditorCKEditor($, Drupal, JSONEditor) { - 'use strict'; - - Drupal.behaviors.patternkitEditorCKEditor = { - attach: function attach(context, settings) { - if (!window.JSONEditor || !drupalSettings.patternkitEditor) { - return; - } - - JSONEditor.defaults.options.drupal_ckeditor = { - ckeditor_config: settings.patternkitEditor.patternkitCKEditorConfig || {} - }; - - if (drupalSettings.patternkitEditor.wysiwygEditorName === 'ckeditor5') { - JSONEditor.defaults.editors.drupal_ckeditor = _patternkitJsoneditorCkeditor.DrupalCKEditor5; - } else { - JSONEditor.defaults.editors.drupal_ckeditor = DrupalCKEditor; - } - - JSONEditor.defaults.resolvers.unshift(function (schema) { - if (schema.type === 'string' && schema.format === 'html' && schema.options && schema.options.wysiwyg && (settings.patternkitEditor.wysiwygEditorName === 'ckeditor' || settings.patternkitEditor.wysiwygEditorName === 'ckeditor5') // Ensures the Text format with CKEditor profile loaded okay. - && settings.patternkitEditor.patternkitCKEditorConfig) { - return 'drupal_ckeditor'; - } - }); - } - }; -} - -},{"./patternkit.jsoneditor.ckeditor5.es6":2}],2:[function(require,module,exports){ -"use strict"; - -Object.defineProperty(exports, "__esModule", { - value: true -}); +exports.patternkitEditorCKEditor5 = patternkitEditorCKEditor5; exports.DrupalCKEditor5 = void 0; function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } @@ -323,7 +42,7 @@ function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.g /*globals JSONEditor:false */ /** - * @file DrupalImageEditor class. + * @file DrupalCKEditor5 class. * * @external Drupal * @external jQuery @@ -545,7 +264,34 @@ var DrupalCKEditor5 = /*#__PURE__*/function (_JSONEditor$defaults$) { exports.DrupalCKEditor5 = DrupalCKEditor5; -},{}],3:[function(require,module,exports){ +function patternkitEditorCKEditor5($, Drupal, JSONEditor) { + 'use strict'; + + Drupal.behaviors.patternkitEditorCKEditor = { + attach: function attach(context, settings) { + if (!window.JSONEditor || !drupalSettings.patternkitEditor) { + return; + } + + JSONEditor.defaults.options.drupal_ckeditor = { + ckeditor_config: settings.patternkitEditor.patternkitCKEditorConfig || {} + }; + + if (drupalSettings.patternkitEditor.wysiwygEditorName === 'ckeditor5') { + JSONEditor.defaults.editors.drupal_ckeditor = DrupalCKEditor5; + } + + JSONEditor.defaults.resolvers.unshift(function (schema) { + if (schema.type === 'string' && schema.format === 'html' && schema.options && schema.options.wysiwyg && settings.patternkitEditor.wysiwygEditorName === 'ckeditor5' // Ensures the Text format with CKEditor profile loaded okay. + && settings.patternkitEditor.patternkitCKEditorConfig) { + return 'drupal_ckeditor'; + } + }); + } + }; +} + +},{}],2:[function(require,module,exports){ "use strict"; Object.defineProperty(exports, "__esModule", { @@ -764,7 +510,7 @@ function patternkitEditorCygnet($, Drupal, JSONEditor) { }; } -},{}],4:[function(require,module,exports){ +},{}],3:[function(require,module,exports){ "use strict"; Object.defineProperty(exports, "__esModule", { @@ -908,7 +654,7 @@ function patternkitEditorArray($, Drupal, JSONEditor) { }; } -},{}],5:[function(require,module,exports){ +},{}],4:[function(require,module,exports){ "use strict"; Object.defineProperty(exports, "__esModule", { @@ -1334,12 +1080,12 @@ function patternkitEditorObject($, Drupal, JSONEditor) { }; } -},{}],6:[function(require,module,exports){ +},{}],5:[function(require,module,exports){ "use strict"; var _patternkitJsoneditorQuillEs = require("./patternkit.jsoneditor.quill.es6.js"); -var _patternkitJsoneditorCkeditor = require("./patternkit.jsoneditor.ckeditor.es6"); +var _patternkitJsoneditorCkeditor = require("./patternkit.jsoneditor.ckeditor5.es6"); var _patternkitJsoneditorCygnetEs = require("./patternkit.jsoneditor.cygnet.es6.js"); @@ -1365,7 +1111,7 @@ function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _d // Instantiates wysiwyg plugins. (0, _patternkitJsoneditorQuillEs.patternkitEditorQuill)(jQuery, Drupal, JSONEditor); -(0, _patternkitJsoneditorCkeditor.patternkitEditorCKEditor)(jQuery, Drupal, JSONEditor); +(0, _patternkitJsoneditorCkeditor.patternkitEditorCKEditor5)(jQuery, Drupal, JSONEditor); (0, _patternkitJsoneditorCygnetEs.patternkitEditorCygnet)(jQuery, Drupal, JSONEditor); (0, _patternkitJsoneditorProsemirror.patternkitEditorProseMirror)(jQuery, Drupal, JSONEditor); // Overrides the object and array json-editor editors, to customize certain // methods. The only use case so far is to trigger toggling of items by @@ -1746,7 +1492,7 @@ function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _d }; })(jQuery, Drupal, JSONEditor, once); -},{"./patternkit.jsoneditor.ckeditor.es6":1,"./patternkit.jsoneditor.cygnet.es6.js":3,"./patternkit.jsoneditor.editor.array.es6":4,"./patternkit.jsoneditor.editor.object.es6":5,"./patternkit.jsoneditor.prosemirror.es6":7,"./patternkit.jsoneditor.quill.es6.js":8}],7:[function(require,module,exports){ +},{"./patternkit.jsoneditor.ckeditor5.es6":1,"./patternkit.jsoneditor.cygnet.es6.js":2,"./patternkit.jsoneditor.editor.array.es6":3,"./patternkit.jsoneditor.editor.object.es6":4,"./patternkit.jsoneditor.prosemirror.es6":6,"./patternkit.jsoneditor.quill.es6.js":7}],6:[function(require,module,exports){ "use strict"; Object.defineProperty(exports, "__esModule", { @@ -1929,7 +1675,7 @@ function patternkitEditorProseMirror($, Drupal, JSONEditor) { }; } -},{"prosemirror-example-setup":13,"prosemirror-model":19,"prosemirror-schema-basic":20,"prosemirror-schema-list":21,"prosemirror-state":22,"prosemirror-view":24}],8:[function(require,module,exports){ +},{"prosemirror-example-setup":12,"prosemirror-model":18,"prosemirror-schema-basic":19,"prosemirror-schema-list":20,"prosemirror-state":21,"prosemirror-view":23}],7:[function(require,module,exports){ "use strict"; Object.defineProperty(exports, "__esModule", { @@ -2137,7 +1883,7 @@ function patternkitEditorQuill($, Drupal, JSONEditor) { }; } -},{}],9:[function(require,module,exports){ +},{}],8:[function(require,module,exports){ 'use strict'; function crelt() { @@ -2170,7 +1916,7 @@ function add(elt, child) { module.exports = crelt; -},{}],10:[function(require,module,exports){ +},{}],9:[function(require,module,exports){ // ::- Persistent data structure representing an ordered mapping from // strings to values, with some convenient update methods. function OrderedMap(content) { @@ -2301,7 +2047,7 @@ OrderedMap.from = function(value) { module.exports = OrderedMap -},{}],11:[function(require,module,exports){ +},{}],10:[function(require,module,exports){ 'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); @@ -2984,7 +2730,7 @@ exports.toggleMark = toggleMark; exports.wrapIn = wrapIn; -},{"prosemirror-model":19,"prosemirror-state":22,"prosemirror-transform":23}],12:[function(require,module,exports){ +},{"prosemirror-model":18,"prosemirror-state":21,"prosemirror-transform":22}],11:[function(require,module,exports){ 'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); @@ -3127,7 +2873,7 @@ DropCursorView.prototype.dragleave = function dragleave (event) { exports.dropCursor = dropCursor; -},{"prosemirror-state":22,"prosemirror-transform":23}],13:[function(require,module,exports){ +},{"prosemirror-state":21,"prosemirror-transform":22}],12:[function(require,module,exports){ 'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); @@ -3732,7 +3478,7 @@ exports.buildMenuItems = buildMenuItems; exports.exampleSetup = exampleSetup; -},{"prosemirror-commands":11,"prosemirror-dropcursor":12,"prosemirror-gapcursor":14,"prosemirror-history":15,"prosemirror-inputrules":16,"prosemirror-keymap":17,"prosemirror-menu":18,"prosemirror-schema-list":21,"prosemirror-state":22}],14:[function(require,module,exports){ +},{"prosemirror-commands":10,"prosemirror-dropcursor":11,"prosemirror-gapcursor":13,"prosemirror-history":14,"prosemirror-inputrules":15,"prosemirror-keymap":16,"prosemirror-menu":17,"prosemirror-schema-list":20,"prosemirror-state":21}],13:[function(require,module,exports){ 'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); @@ -3937,7 +3683,7 @@ exports.GapCursor = GapCursor; exports.gapCursor = gapCursor; -},{"prosemirror-keymap":17,"prosemirror-model":19,"prosemirror-state":22,"prosemirror-view":24}],15:[function(require,module,exports){ +},{"prosemirror-keymap":16,"prosemirror-model":18,"prosemirror-state":21,"prosemirror-view":23}],14:[function(require,module,exports){ 'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); @@ -4396,7 +4142,7 @@ exports.undo = undo; exports.undoDepth = undoDepth; -},{"prosemirror-state":22,"prosemirror-transform":23,"rope-sequence":25}],16:[function(require,module,exports){ +},{"prosemirror-state":21,"prosemirror-transform":22,"rope-sequence":24}],15:[function(require,module,exports){ 'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); @@ -4590,7 +4336,7 @@ exports.undoInputRule = undoInputRule; exports.wrappingInputRule = wrappingInputRule; -},{"prosemirror-state":22,"prosemirror-transform":23}],17:[function(require,module,exports){ +},{"prosemirror-state":21,"prosemirror-transform":22}],16:[function(require,module,exports){ 'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); @@ -4702,7 +4448,7 @@ exports.keydownHandler = keydownHandler; exports.keymap = keymap; -},{"prosemirror-state":22,"w3c-keyname":26}],18:[function(require,module,exports){ +},{"prosemirror-state":21,"w3c-keyname":25}],17:[function(require,module,exports){ 'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); @@ -5360,7 +5106,7 @@ exports.undoItem = undoItem; exports.wrapItem = wrapItem; -},{"crelt":9,"prosemirror-commands":11,"prosemirror-history":15,"prosemirror-state":22}],19:[function(require,module,exports){ +},{"crelt":8,"prosemirror-commands":10,"prosemirror-history":14,"prosemirror-state":21}],18:[function(require,module,exports){ 'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); @@ -8805,7 +8551,7 @@ exports.Schema = Schema; exports.Slice = Slice; -},{"orderedmap":10}],20:[function(require,module,exports){ +},{"orderedmap":9}],19:[function(require,module,exports){ 'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); @@ -8980,7 +8726,7 @@ exports.nodes = nodes; exports.schema = schema; -},{"prosemirror-model":19}],21:[function(require,module,exports){ +},{"prosemirror-model":18}],20:[function(require,module,exports){ 'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); @@ -9236,7 +8982,7 @@ exports.splitListItem = splitListItem; exports.wrapInList = wrapInList; -},{"prosemirror-model":19,"prosemirror-transform":23}],22:[function(require,module,exports){ +},{"prosemirror-model":18,"prosemirror-transform":22}],21:[function(require,module,exports){ 'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); @@ -10387,7 +10133,7 @@ exports.TextSelection = TextSelection; exports.Transaction = Transaction; -},{"prosemirror-model":19,"prosemirror-transform":23}],23:[function(require,module,exports){ +},{"prosemirror-model":18,"prosemirror-transform":22}],22:[function(require,module,exports){ 'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); @@ -12058,7 +11804,7 @@ exports.liftTarget = liftTarget; exports.replaceStep = replaceStep; -},{"prosemirror-model":19}],24:[function(require,module,exports){ +},{"prosemirror-model":18}],23:[function(require,module,exports){ 'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); @@ -17240,7 +16986,7 @@ exports.__parseFromClipboard = parseFromClipboard; exports.__serializeForClipboard = serializeForClipboard; -},{"prosemirror-model":19,"prosemirror-state":22,"prosemirror-transform":23}],25:[function(require,module,exports){ +},{"prosemirror-model":18,"prosemirror-state":21,"prosemirror-transform":22}],24:[function(require,module,exports){ 'use strict'; var GOOD_LEAF_SIZE = 200; @@ -17453,7 +17199,7 @@ var ropeSequence = RopeSequence; module.exports = ropeSequence; -},{}],26:[function(require,module,exports){ +},{}],25:[function(require,module,exports){ 'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); @@ -17587,4 +17333,4 @@ exports.base = base; exports.keyName = keyName; exports.shift = shift; -},{}]},{},[6]); +},{}]},{},[5]); diff --git a/modules/patternkit_media_library/tests/src/FunctionalJavascript/CKEditorMediaIntegrationTest.php b/modules/patternkit_media_library/tests/src/FunctionalJavascript/CKEditorMediaIntegrationTest.php deleted file mode 100644 index 41698ce0f7f6a334a3c61088fad3ae5130771829..0000000000000000000000000000000000000000 --- a/modules/patternkit_media_library/tests/src/FunctionalJavascript/CKEditorMediaIntegrationTest.php +++ /dev/null @@ -1,190 +0,0 @@ -<?php - -namespace Drupal\Tests\patternkit_media_library\FunctionalJavascript; - -use Drupal\Component\Utility\Html; -use Drupal\editor\Entity\Editor; -use Drupal\filter\Entity\FilterFormat; -use Drupal\node\Entity\Node; -use Drupal\Tests\patternkit\Traits\CKEditorIntegrationTestTrait; - -/** - * Testing for media library integration with CKEditor in Patternkit forms. - * - * @group patternkit - * @group patternkit_media_library - * @group legacy - * @requires module ckeditor - */ -class CKEditorMediaIntegrationTest extends PatternkitMediaLibraryBrowserTestBase { - - use CKEditorIntegrationTestTrait; - - /** - * {@inheritdoc} - */ - protected static $modules = [ - 'patternkit_example', - 'ckeditor', - 'media_library', - ]; - - /** - * An array of needed editor permissions. - * - * @var string[] - */ - protected array $editorPermissions = [ - 'configure any layout', - 'create and edit custom blocks', - 'bypass node access', - - // Add additional permissions for media interaction. - 'use text format test_format', - 'access media overview', - ]; - - /** - * {@inheritdoc} - */ - public function setUp(): void { - parent::setUp(); - - FilterFormat::create([ - 'format' => 'test_format', - 'name' => 'Test format', - 'filters' => [ - 'media_embed' => ['status' => TRUE], - ], - ])->save(); - Editor::create([ - 'editor' => 'ckeditor', - 'format' => 'test_format', - 'settings' => [ - 'toolbar' => [ - 'rows' => [ - [ - [ - 'name' => 'Main', - 'items' => [ - 'Source', - 'Undo', - 'Redo', - ], - ], - ], - [ - [ - 'name' => 'Embeds', - 'items' => [ - 'DrupalMediaLibrary', - ], - ], - ], - ], - ], - ], - ])->save(); - - // Enable CKEditor integration. - $config = $this->config('patternkit.settings'); - $config->set('patternkit_json_editor_wysiwyg', 'ckeditor'); - $config->set('patternkit_json_editor_ckeditor_toolbar', 'test_format'); - $config->save(); - - $this->editorUser = $this->drupalCreateUser($this->editorPermissions); - $this->drupalLogin($this->editorUser); - } - - /** - * Test placement of media within a CKEditor field. - * - * Most of the CKEditor interaction and testing is based off of the - * @link \Drupal\Tests\media_library\FunctionalJavascript\CKEditorIntegrationTest::testButton @endlink - * method. - * - * @see \Drupal\Tests\media_library\FunctionalJavascript\CKEditorIntegrationTest::testButton() - * - * @todo Re-enable this test once #3092593 is resolved. - * @see https://www.drupal.org/project/drupal/issues/3092593 - */ - public function testCkeditorMediaSelection(): void { - // See https://www.drupal.org/project/drupal/issues/3092593. - $this->markTestSkipped('Skip CKEditor media embed testing until issue #3092593 is resolved.'); - - $assert = $this->assertSession(); - $page = $this->getSession()->getPage(); - - $pattern_name = '[Patternkit] Example'; - - // Log in as an editor with access to update layouts. - $this->drupalLogin($this->editorUser); - - // Override the Node layout and place a patternkit block. - $this->drupalGet('node/1/layout'); - $page->clickLink('Add block'); - - // Wait for the block list to load before selecting a pattern to insert. - $assert->waitForLink($pattern_name)->click(); - - // Wait for CKEditor to load. - $assert->waitForField('root[text]'); - $this->waitForEditor('editor1'); - - // Press to select and insert media from the library. - $this->pressEditorButton('drupalmedialibrary', 'editor1'); - - // Wait for the library modal. - $this->assertElementExistsAfterWait('css', '.js-media-library-view'); - - // Select and save a media item. - $this->selectMediaItem(0); - $buttons = $this->assertElementExistsAfterWait('css', '.ui-dialog-buttonpane'); - $buttons->findButton('Insert selected')->press(); - - $assert->waitForElementRemoved('css', '.js-media-library-view'); - - // Confirm the media item was added to the CKEditor field. - $this->assignNameToCkeditorIframe('ckeditor', 'editor1'); - $this->getSession()->switchToIFrame('ckeditor'); - - // Search for the media entity added into the CKEditor rich text display. - $this->assertElementExistsAfterWait('css', '.cke_widget_drupalmedia drupal-media img'); - - // Confirm the media token was added to the source. - $this->pressEditorButton('source', 'editor1'); - $value = $this->assertElementExistsAfterWait('css', 'textarea.cke_source')->getValue(); - $dom = Html::load($value); - $xpath = new \DOMXPath($dom); - $drupal_media = $xpath->query('//drupal-media')[0]; - $expected_attributes = [ - 'data-entity-type' => 'media', - 'data-entity-uuid' => $this->media->uuid(), - 'data-align' => 'center', - ]; - foreach ($expected_attributes as $name => $expected) { - $this->assertSame($expected, $drupal_media->getAttribute($name)); - } - - // Save the layout to confirm it displays as expected. - $page->pressButton('Add block'); - $page->pressButton('Save layout'); - - // Confirm the pattern is rendered on the Node display. - $this->drupalGet('node/1'); - $assert->elementExists('css', '.media .field--type-image img'); - - // Get block ID to return to edit form. - $uuid = $this->getLastLayoutBlockUuid(Node::load(1)); - - // Confirm all configuration content is persisted when editing the block. - $this->drupalGet('layout_builder/update/block/overrides/node.1/0/content/' . $uuid); - $assert->waitForField('root[text]'); - $this->waitForEditor('editor1'); - - // Confirm text values in CKEditor fields. - $value = $this->getEditorValue('root.formatted_text'); - $this->assertStringContainsString('<drupal-media', $value); - } - -} diff --git a/patternkit.info.yml b/patternkit.info.yml index 9319f407290289d085853f1e70ef2b2df20bea01..a4c7e407f6f776dcda46a329cf6e6a8e9c56f9bc 100644 --- a/patternkit.info.yml +++ b/patternkit.info.yml @@ -6,6 +6,4 @@ core_version_requirement: ^9 || ^10 configure: patternkit.settings dependencies: - drupal:block_content -test_dependencies: - - ckeditor:ckeditor php: 7.4 diff --git a/patternkit.install b/patternkit.install index cf8310403ce49489eaf8ddbdb2199819b7b0ab67..6058693cba1e19cb06d4ee7b7fdb3c03a1f343a6 100644 --- a/patternkit.install +++ b/patternkit.install @@ -358,3 +358,25 @@ function patternkit_update_9005(): void { $config->save(TRUE); } } + +/** + * Remove ckeditor4 usage from configuration. + */ +function patternkit_update_9006(): ?string { + $config_key = 'patternkit.settings'; + $wysiwyg_setting = 'patternkit_json_editor_wysiwyg'; + $config = \Drupal::configFactory()->getEditable($config_key); + + if ($config && $config->get($wysiwyg_setting) === 'ckeditor') { + // Remove ckeditor and toolbar configuration. + $config->set($wysiwyg_setting, ''); + $config->set('patternkit_json_editor_ckeditor_toolbar', ''); + + // Save the changes. + $config->save(TRUE); + + return t('Patternkit configuration using CKEditor 4 was removed. These settings will need to be reconfigured.'); + } + + return NULL; +} diff --git a/src/Form/PatternLibraryJSONForm.php b/src/Form/PatternLibraryJSONForm.php index 330c2877eb6c45e728907476cfbd2aaf8a5ea364..3b3a3dfd7c1850660d0c568e6624d001b99788db 100644 --- a/src/Form/PatternLibraryJSONForm.php +++ b/src/Form/PatternLibraryJSONForm.php @@ -106,7 +106,6 @@ class PatternLibraryJSONForm extends ConfigFormBase { * @see self::getAllowedWysiwygEditors() */ public const EDITORS = [ - 'ckeditor' => 'CKEditor', 'ckeditor5' => 'CKEditor5', 'prosemirror' => 'ProseMirror', 'quill' => 'Quill', @@ -190,7 +189,6 @@ class PatternLibraryJSONForm extends ConfigFormBase { $ckeditor_toolbar_options = []; foreach ($this->entityTypeManager->getStorage('editor')->loadMultiple() as $editor) { $accepted_editors = [ - 'ckeditor', 'ckeditor5', ]; /** @var \Drupal\editor\EditorInterface $editor */ @@ -209,7 +207,6 @@ class PatternLibraryJSONForm extends ConfigFormBase { '#states' => [ 'visible' => [ ':input[name="patternkit_json_editor_wysiwyg"]' => [ - ['value' => 'ckeditor'], ['value' => 'ckeditor5'], ], ], @@ -237,9 +234,6 @@ class PatternLibraryJSONForm extends ConfigFormBase { // enabled. $excluded = []; - if (!$this->moduleHandler->moduleExists('ckeditor')) { - $excluded[] = 'CKEditor'; - } if (!$this->moduleHandler->moduleExists('ckeditor5')) { $excluded[] = 'CKEditor5'; } @@ -261,8 +255,9 @@ class PatternLibraryJSONForm extends ConfigFormBase { // Validate editor and WYSIWYG toolbar selections. $wysiwyg = $form_state->getValue('patternkit_json_editor_wysiwyg'); $toolbar = $form_state->getValue('patternkit_json_editor_ckeditor_toolbar'); + $supported_wysiwygs = ['ckeditor5']; - if ($toolbar && in_array($wysiwyg, ['ckeditor', 'ckeditor5'])) { + if ($toolbar && in_array($wysiwyg, $supported_wysiwygs)) { $editor = Editor::load($toolbar); if ($editor->getEditor() !== $wysiwyg) { diff --git a/src/JSONSchemaEditorTrait.php b/src/JSONSchemaEditorTrait.php index bee3c684ba4c76eca0c640d02236ccc48eda737a..2223fce7c2ef816f18a5bf4ba7b33f0eafa4cb4f 100644 --- a/src/JSONSchemaEditorTrait.php +++ b/src/JSONSchemaEditorTrait.php @@ -2,7 +2,6 @@ namespace Drupal\patternkit; -use Drupal\ckeditor\Plugin\Editor\CKEditor; use Drupal\ckeditor5\Plugin\Editor\CKEditor5; use Drupal\Component\Serialization\SerializationInterface; use Drupal\Core\Asset\AssetQueryStringInterface; @@ -159,31 +158,35 @@ trait JSONSchemaEditorTrait { } $accepted_editors = [ - 'ckeditor', 'ckeditor5', ]; - if (in_array($this->config->get('patternkit_json_editor_wysiwyg'), $accepted_editors)) { + $editor = $this->config->get('patternkit_json_editor_wysiwyg'); + if (in_array($editor, $accepted_editors)) { $selected_toolbar = $this->config->get('patternkit_json_editor_ckeditor_toolbar'); if (!empty($selected_toolbar)) { - $editor = $this->config->get('patternkit_json_editor_wysiwyg'); // The following code builds a CKEditor toolbar. Code stolen from // \Drupal\editor\Element::preRenderTextFormat. if ($editor === 'ckeditor5') { $ckeditor_instance = CKEditor5::create(\Drupal::getContainer(), [], 'ckeditor5', ['provider' => 'patternkit']); } - else { - $ckeditor_instance = CKEditor::create(\Drupal::getContainer(), [], 'ckeditor5', ['provider' => 'patternkit']); - } - /** @var \Drupal\editor\Entity\Editor $ckeditor_config */ - $ckeditor_entity = Editor::load($selected_toolbar); - if ($ckeditor_entity && $ckeditor_entity->status()) { - $editor_settings['patternkitCKEditorConfig'] = $ckeditor_instance->getJSSettings($ckeditor_entity); - // Pushes the selected toolbar to drupalSettings, so that client-side - // so that DrupalCKEditor.afterInputReady. - $editor_settings['patternkitCKEditorConfig']['selected_toolbar'] = $selected_toolbar; + + if ($ckeditor_instance) { + /** @var \Drupal\editor\Entity\Editor $ckeditor_config */ + $ckeditor_entity = Editor::load($selected_toolbar); + if ($ckeditor_entity && $ckeditor_entity->status()) { + $editor_settings['patternkitCKEditorConfig'] = $ckeditor_instance->getJSSettings($ckeditor_entity); + // Pushes the selected toolbar to drupalSettings, for use clientside + // in DrupalCKEditor5.afterInputReady. + $editor_settings['patternkitCKEditorConfig']['selected_toolbar'] = $selected_toolbar; + } + else { + $msg = $this->t('Missing Editor entity @name', ['@name' => $selected_toolbar]); + $this->getLogger('patternkit')->error($msg); + $this->messenger()->addError($msg); + } } else { - $msg = $this->t('Missing Editor entity @name', ['@name' => $selected_toolbar]); + $msg = $this->t('Unable to create WYSIWYG editor instance for @name', ['@name' => $editor]); $this->getLogger('patternkit')->error($msg); $this->messenger()->addError($msg); } @@ -216,10 +219,6 @@ trait JSONSchemaEditorTrait { case 'ckeditor5': $element['#attached']['library'][] = 'core/ckeditor5.editorClassic'; break; - - case 'ckeditor': - $element['#attached']['library'][] = 'ckeditor/drupal.ckeditor'; - break; } } diff --git a/tests/src/FunctionalJavascript/CKEditorIntegrationTest.php b/tests/src/FunctionalJavascript/CKEditorIntegrationTest.php index bd558f3c765a9d7da8a0a38ddea6f8d2d8549e69..39a716f92ef4d02706a8388ce345a8b812b7b0a2 100644 --- a/tests/src/FunctionalJavascript/CKEditorIntegrationTest.php +++ b/tests/src/FunctionalJavascript/CKEditorIntegrationTest.php @@ -9,8 +9,6 @@ use Drupal\Tests\patternkit\Traits\CKEditor5IntegrationTestTrait; * End-to-end testing for patternkit block CKEditor integration. * * @group patternkit - * @group legacy - * @requires module ckeditor */ class CKEditorIntegrationTest extends PatternkitBrowserTestBase { diff --git a/tests/src/Traits/CKEditorIntegrationTestTrait.php b/tests/src/Traits/CKEditorIntegrationTestTrait.php deleted file mode 100644 index a4f4d02ff7fbfbc8c69fdd4afeef6bf1cb9c7ba9..0000000000000000000000000000000000000000 --- a/tests/src/Traits/CKEditorIntegrationTestTrait.php +++ /dev/null @@ -1,45 +0,0 @@ -<?php - -namespace Drupal\Tests\patternkit\Traits; - -use Drupal\Tests\ckeditor\Traits\CKEditorTestTrait; - -/** - * A helper trait to interact with and test CKEditor integration. - * - * This trait is only intended for use in tests. - */ -trait CKEditorIntegrationTestTrait { - - use CKEditorTestTrait; - - /** - * Get the content of a field's editor instance. - * - * @param string $field_name - * The JSON Editor field name for the field to interact with, such as - * 'root.formatted_text'. - * - * @return string - * The returned value from the editor instance. - */ - protected function getEditorValue(string $field_name): string { - $js = sprintf('patternkitEditor.getEditor("%s").getValue()', $field_name); - return $this->getSession()->evaluateScript($js); - } - - /** - * Get the content of a field's editor instance. - * - * @param string $field_name - * The JSON Editor field name for the field to interact with, such as - * 'root.formatted_text'. - * @param string $value - * The markup value to set in the editor. - */ - protected function setEditorValue(string $field_name, string $value): void { - $js = sprintf('patternkitEditor.getEditor("%s").setValue("%s")', $field_name, $value); - $this->getSession()->evaluateScript($js); - } - -}