Commit b9de6972 authored by Jacob Rockowitz's avatar Jacob Rockowitz
Browse files

Issue #3322552: CKEditor 5 support

parent 4629a1b2
Loading
Loading
Loading
Loading
+0 −85
Original line number Diff line number Diff line
@@ -32,11 +32,6 @@
        "composer/installers": "*",
        "algolia/places": "*",
        "choices/choices": "*",
        "ckeditor/autogrow": "*",
        "ckeditor/codemirror": "*",
        "ckeditor/fakeobjects": "*",
        "ckeditor/image": "*",
        "ckeditor/link": "*",
        "codemirror/codemirror": "*",
        "jquery/chosen": "*",
        "jquery/geocomplete": "*",
@@ -93,86 +88,6 @@
                "license": "MIT"
            }
        },
        "ckeditor.autogrow": {
            "type": "package",
            "package": {
                "name": "ckeditor/autogrow",
                "version": "4.18.0",
                "type": "drupal-library",
                "extra": {
                    "installer-name": "ckeditor.autogrow"
                },
                "dist": {
                    "url": "https://download.ckeditor.com/autogrow/releases/autogrow_4.18.0.zip",
                    "type": "zip"
                },
                "license": "GPL-2.0-or-later"
            }
        },
        "ckeditor.codemirror": {
            "type": "package",
            "package": {
                "name": "ckeditor/codemirror",
                "version": "v1.18.3",
                "type": "drupal-library",
                "extra": {
                    "installer-name": "ckeditor.codemirror"
                },
                "dist": {
                    "url": "https://github.com/w8tcha/CKEditor-CodeMirror-Plugin/releases/download/v1.18.3/CKEditor-CodeMirror-Plugin.zip",
                    "type": "zip"
                },
                "license": "MIT"
            }
        },
        "ckeditor.fakeobjects": {
            "type": "package",
            "package": {
                "name": "ckeditor/fakeobjects",
                "version": "4.18.0",
                "type": "drupal-library",
                "extra": {
                    "installer-name": "ckeditor.fakeobjects"
                },
                "dist": {
                    "url": "https://download.ckeditor.com/fakeobjects/releases/fakeobjects_4.18.0.zip",
                    "type": "zip"
                },
                "license": "GPL-2.0-or-later"
            }
        },
        "ckeditor.image": {
            "type": "package",
            "package": {
                "name": "ckeditor/image",
                "version": "4.18.0",
                "type": "drupal-library",
                "extra": {
                    "installer-name": "ckeditor.image"
                },
                "dist": {
                    "url": "https://download.ckeditor.com/image/releases/image_4.18.0.zip",
                    "type": "zip"
                },
                "license": "GPL-2.0-or-later"
            }
        },
        "ckeditor.link": {
            "type": "package",
            "package": {
                "name": "ckeditor/link",
                "version": "4.18.0",
                "type": "drupal-library",
                "extra": {
                    "installer-name": "ckeditor.link"
                },
                "dist": {
                    "url": "https://download.ckeditor.com/link/releases/link_4.18.0.zip",
                    "type": "zip"
                },
                "license": "GPL-2.0-or-later"
            }
        },
        "codemirror": {
            "type": "package",
            "package": {

js/webform.element.html_editor.js

deleted100644 → 0
+0 −137
Original line number Diff line number Diff line
/**
 * @file
 * JavaScript behaviors for HTML editor integration.
 */

(function ($, Drupal, drupalSettings, once) {

  'use strict';

  // @see http://docs.ckeditor.com/#!/api/CKEDITOR.config
  Drupal.webform = Drupal.webform || {};
  Drupal.webform.htmlEditor = Drupal.webform.htmlEditor || {};
  Drupal.webform.htmlEditor.options = Drupal.webform.htmlEditor.options || {};

  /**
   * Initialize HTML Editor.
   *
   * @type {Drupal~behavior}
   */
  Drupal.behaviors.webformHtmlEditor = {
    attach: function (context) {
      if (!window.CKEDITOR) {
        return;
      }

      $(once('webform-html-editor', 'textarea.js-html-editor', context)).each(function () {
        var $textarea = $(this);

        var allowedContent = drupalSettings['webform']['html_editor']['allowedContent'];

        // Load additional CKEditor plugins used by the Webform HTML editor.
        // @see \Drupal\webform\Element\WebformHtmlEditor::preRenderWebformHtmlEditor
        // @see \Drupal\webform\WebformLibrariesManager::initLibraries
        var plugins = drupalSettings['webform']['html_editor']['plugins'];

        // If requirejs is present don't use the codemirror plugin.
        // @see Issue #2936147: ckeditor.codemirror plugin breaks admin textarea.
        // @todo Remove the below code once this issue is resolved.
        if (plugins.codemirror
          && drupalSettings.yamlEditor
          && drupalSettings.yamlEditor.source
          && drupalSettings.yamlEditor.source.indexOf('noconflict') !== -1) {
          delete plugins.codemirror;
          if ('console' in window) {
            window.console.log('YAML Editor module is not compatible with the ckeditor.codemirror plugin. @see Issue #2936147: ckeditor.codemirror plugin breaks admin textarea.');
          }
        }

        for (var plugin_name in plugins) {
          if (plugins.hasOwnProperty(plugin_name)) {
            CKEDITOR.plugins.addExternal(plugin_name, plugins[plugin_name]);
          }
        }

        var options = {
          // Turn off external config and styles.
          customConfig: '',
          stylesSet: false,
          contentsCss: [],
          allowedContent: allowedContent,
          // Use <br> tags instead of <p> tags.
          enterMode: CKEDITOR.ENTER_BR,
          shiftEnterMode: CKEDITOR.ENTER_BR,
          // Set height.
          height: '100px',
          // Remove status bar.
          resize_enabled: false,
          removePlugins: 'elementspath,magicline',
          // Toolbar settings.
          format_tags: 'p;h2;h3;h4;h5;h6',
          // extraPlugins
          extraPlugins: ''
        };

        // Add toolbar.
        if (!options.toolbar) {
          options.toolbar = [];
          options.toolbar.push({name: 'styles', items: ['Format', 'Font', 'FontSize']});
          options.toolbar.push({name: 'basicstyles', items: ['Bold', 'Italic', 'Subscript', 'Superscript']});
          // Add IMCE image button.
          if (CKEDITOR.plugins.get('imce')) {
            CKEDITOR.config.ImceImageIcon = drupalSettings['webform']['html_editor']['ImceImageIcon'];
            options.extraPlugins += (options.extraPlugins ? ',' : '') + 'imce';
            options.toolbar.push({name: 'insert', items: ['ImceImage', 'SpecialChar']});
          }
          else {
            options.toolbar.push({name: 'insert', items: ['SpecialChar']});
          }

          // Add link plugin.
          if (plugins['link']) {
            options.extraPlugins += (options.extraPlugins ? ',' : '') + 'link';
            options.toolbar.push({name: 'links', items: ['Link', 'Unlink']});
          }
          options.toolbar.push({name: 'colors', items: ['TextColor', 'BGColor']});
          options.toolbar.push({name: 'paragraph', items: ['NumberedList', 'BulletedList', '-', 'Outdent', 'Indent', '-', 'Blockquote']});
          options.toolbar.push({name: 'tools', items: ['Source', '-', 'Maximize']});
        }

        // Add autogrow plugin.
        if (plugins['autogrow']) {
          options.extraPlugins += (options.extraPlugins ? ',' : '') + 'autogrow';
          options.autoGrow_minHeight = 60;
          options.autoGrow_maxHeight = 300;
        }

        // Add CodeMirror integration plugin.
        if (plugins['codemirror']) {
          options.extraPlugins += (options.extraPlugins ? ',' : '') + 'codemirror';
          options.codemirror = {
            mode: 'text/html'
          };
        }

        options = $.extend(options, Drupal.webform.htmlEditor.options);

        // Catch and suppress
        // "Uncaught TypeError: Cannot read property 'getEditor' of undefined".
        //
        // Steps to reproduce this error.
        // - Goto any form elements.
        // - Edit an element.
        // - Save the element.
        try {
          CKEDITOR.replace(this.id, options).on('change', function (evt) {
            // Save data onchange since Ajax dialogs don't execute form.onsubmit.
            $textarea.val(evt.editor.getData().trim());
          });
        }
        catch (e) {
          // Do nothing.
        }
      });
    }
  };

})(jQuery, Drupal, drupalSettings, once);
+1 −31
Original line number Diff line number Diff line
@@ -118,40 +118,10 @@ class WebformHtmlEditor extends FormElement implements TrustedCallbackInterface
      return $element;
    }

    // Else use textarea with completely custom HTML Editor.
    // Else use a textarea.
    $element['value'] += [
      '#type' => 'textarea',
    ];
    $element['value']['#attributes']['class'][] = 'js-html-editor';

    $element['#attached']['library'][] = 'webform/webform.element.html_editor';
    $element['#attached']['drupalSettings']['webform']['html_editor']['allowedContent'] = static::getAllowedContent();

    /** @var \Drupal\webform\WebformLibrariesManagerInterface $libraries_manager */
    $libraries_manager = \Drupal::service('webform.libraries_manager');
    $libraries = $libraries_manager->getLibraries(TRUE);
    $element['#attached']['drupalSettings']['webform']['html_editor']['plugins'] = [];
    foreach ($libraries as $library_name => $library) {
      if (strpos($library_name, 'ckeditor.') === FALSE) {
        continue;
      }

      $plugin_name = str_replace('ckeditor.', '', $library_name);
      $plugin_path = $library['plugin_path'];
      $plugin_url = $library['plugin_url'];
      if (file_exists($plugin_path)) {
        $element['#attached']['drupalSettings']['webform']['html_editor']['plugins'][$plugin_name] = base_path() . $plugin_path;
      }
      else {
        $element['#attached']['drupalSettings']['webform']['html_editor']['plugins'][$plugin_name] = $plugin_url;
      }
    }

    // phpcs:ignore Drupal.Classes.FullyQualifiedNamespace.UseStatementMissing
    if (\Drupal::moduleHandler()->moduleExists('imce') && \Drupal\imce\Imce::access()) {
      $element['#attached']['library'][] = 'imce/drupal.imce.ckeditor';
      $element['#attached']['drupalSettings']['webform']['html_editor']['ImceImageIcon'] = \Drupal::service('file_url_generator')->generateAbsoluteString(\Drupal::service('extension.list.module')->getPath('imce') . '/js/plugins/ckeditor/icons/imceimage.png');
    }

    if (!empty($element['#states'])) {
      WebformFormHelper::processStates($element, '#wrapper_attributes');
+0 −1
Original line number Diff line number Diff line
@@ -1391,7 +1391,6 @@ class EmailWebformHandler extends WebformHandlerBase implements WebformHandlerMe
    }
    // Preload HTML Editor and CodeMirror so that they can be properly
    // initialized when loaded via Ajax.
    $element['#attached']['library'][] = 'webform/webform.element.html_editor';
    $element['#attached']['library'][] = 'webform/webform.element.codemirror.text';

    return $element;
+0 −6
Original line number Diff line number Diff line
@@ -64,12 +64,6 @@ class WebformDialogHelper {
    if (static::useOffCanvas()) {
      $build['#attached']['library'][] = 'webform/webform.admin.off_canvas';
    }
    // @see \Drupal\webform\Element\WebformHtmlEditor::preRenderWebformHtmlEditor
    // phpcs:ignore Drupal.Classes.FullyQualifiedNamespace.UseStatementMissing
    if (\Drupal::moduleHandler()->moduleExists('imce') && \Drupal\imce\Imce::access()) {
      $build['#attached']['library'][] = 'imce/drupal.imce.ckeditor';
      $build['#attached']['drupalSettings']['webform']['html_editor']['ImceImageIcon'] = \Drupal::service('file_url_generator')->generateAbsoluteString(\Drupal::service('extension.list.module')->getPath('imce') . '/js/plugins/ckeditor/icons/imceimage.png');
    }
  }

  /**
Loading