Updated Drupal to 8.6. This goes with the following updates because it's possible...
[yaffs-website] / web / core / modules / ckeditor / js / plugins / drupalimagecaption / plugin.es6.js
index 1d51bcb82d486240307929e1e0a0d7476458dd8f..1e63c4b782eb9a20e6444bc0b6e1ac54d44342cb 100644 (file)
  * @ignore
  */
 
-(function (CKEDITOR) {
+(function(CKEDITOR) {
+  /**
+   * Finds an element by its name.
+   *
+   * Function will check first the passed element itself and then all its
+   * children in DFS order.
+   *
+   * @param {CKEDITOR.htmlParser.element} element
+   *   The element to search.
+   * @param {string} name
+   *   The element name to search for.
+   *
+   * @return {?CKEDITOR.htmlParser.element}
+   *   The found element, or null.
+   */
+  function findElementByName(element, name) {
+    if (element.name === name) {
+      return element;
+    }
+
+    let found = null;
+    element.forEach(el => {
+      if (el.name === name) {
+        found = el;
+        // Stop here.
+        return false;
+      }
+    }, CKEDITOR.NODE_ELEMENT);
+    return found;
+  }
+
   CKEDITOR.plugins.add('drupalimagecaption', {
     requires: 'drupalimage',
 
       // Drupal.t() will not work inside CKEditor plugins because CKEditor loads
       // the JavaScript file instead of Drupal. Pull translated strings from the
       // plugin settings that are translated server-side.
-      const placeholderText = editor.config.drupalImageCaption_captionPlaceholderText;
+      const placeholderText =
+        editor.config.drupalImageCaption_captionPlaceholderText;
 
       // Override the image2 widget definition to handle the additional
       // data-align and data-caption attributes.
-      editor.on('widgetDefinition', (event) => {
-        const widgetDefinition = event.data;
-        if (widgetDefinition.name !== 'image') {
-          return;
-        }
+      editor.on(
+        'widgetDefinition',
+        event => {
+          const widgetDefinition = event.data;
+          if (widgetDefinition.name !== 'image') {
+            return;
+          }
 
-        // Only perform the downcasting/upcasting for to the enabled filters.
-        const captionFilterEnabled = editor.config.drupalImageCaption_captionFilterEnabled;
-        const alignFilterEnabled = editor.config.drupalImageCaption_alignFilterEnabled;
-
-        // Override default features definitions for drupalimagecaption.
-        CKEDITOR.tools.extend(widgetDefinition.features, {
-          caption: {
-            requiredContent: 'img[data-caption]',
-          },
-          align: {
-            requiredContent: 'img[data-align]',
-          },
-        }, true);
-
-        // Extend requiredContent & allowedContent.
-        // CKEDITOR.style is an immutable object: we cannot modify its
-        // definition to extend requiredContent. Hence we get the definition,
-        // modify it, and pass it to a new CKEDITOR.style instance.
-        const requiredContent = widgetDefinition.requiredContent.getDefinition();
-        requiredContent.attributes['data-align'] = '';
-        requiredContent.attributes['data-caption'] = '';
-        widgetDefinition.requiredContent = new CKEDITOR.style(requiredContent);
-        widgetDefinition.allowedContent.img.attributes['!data-align'] = true;
-        widgetDefinition.allowedContent.img.attributes['!data-caption'] = true;
-
-        // Override allowedContent setting for the 'caption' nested editable.
-        // This must match what caption_filter enforces.
-        // @see \Drupal\filter\Plugin\Filter\FilterCaption::process()
-        // @see \Drupal\Component\Utility\Xss::filter()
-        widgetDefinition.editables.caption.allowedContent = 'a[!href]; em strong cite code br';
-
-        // Override downcast(): ensure we *only* output <img>, but also ensure
-        // we include the data-entity-type, data-entity-uuid, data-align and
-        // data-caption attributes.
-        const originalDowncast = widgetDefinition.downcast;
-        widgetDefinition.downcast = function (element) {
-          const img = findElementByName(element, 'img');
-          originalDowncast.call(this, img);
-
-          const caption = this.editables.caption;
-          const captionHtml = caption && caption.getData();
-          const attrs = img.attributes;
-
-          if (captionFilterEnabled) {
-            // If image contains a non-empty caption, serialize caption to the
-            // data-caption attribute.
-            if (captionHtml) {
-              attrs['data-caption'] = captionHtml;
+          // Only perform the downcasting/upcasting for to the enabled filters.
+          const captionFilterEnabled =
+            editor.config.drupalImageCaption_captionFilterEnabled;
+          const alignFilterEnabled =
+            editor.config.drupalImageCaption_alignFilterEnabled;
+
+          // Override default features definitions for drupalimagecaption.
+          CKEDITOR.tools.extend(
+            widgetDefinition.features,
+            {
+              caption: {
+                requiredContent: 'img[data-caption]',
+              },
+              align: {
+                requiredContent: 'img[data-align]',
+              },
+            },
+            true,
+          );
+
+          // Extend requiredContent & allowedContent.
+          // CKEDITOR.style is an immutable object: we cannot modify its
+          // definition to extend requiredContent. Hence we get the definition,
+          // modify it, and pass it to a new CKEDITOR.style instance.
+          const requiredContent = widgetDefinition.requiredContent.getDefinition();
+          requiredContent.attributes['data-align'] = '';
+          requiredContent.attributes['data-caption'] = '';
+          widgetDefinition.requiredContent = new CKEDITOR.style(
+            requiredContent,
+          );
+          widgetDefinition.allowedContent.img.attributes['!data-align'] = true;
+          widgetDefinition.allowedContent.img.attributes[
+            '!data-caption'
+          ] = true;
+
+          // Override allowedContent setting for the 'caption' nested editable.
+          // This must match what caption_filter enforces.
+          // @see \Drupal\filter\Plugin\Filter\FilterCaption::process()
+          // @see \Drupal\Component\Utility\Xss::filter()
+          widgetDefinition.editables.caption.allowedContent =
+            'a[!href]; em strong cite code br';
+
+          // Override downcast(): ensure we *only* output <img>, but also ensure
+          // we include the data-entity-type, data-entity-uuid, data-align and
+          // data-caption attributes.
+          const originalDowncast = widgetDefinition.downcast;
+          widgetDefinition.downcast = function(element) {
+            const img = findElementByName(element, 'img');
+            originalDowncast.call(this, img);
+
+            const caption = this.editables.caption;
+            const captionHtml = caption && caption.getData();
+            const attrs = img.attributes;
+
+            if (captionFilterEnabled) {
+              // If image contains a non-empty caption, serialize caption to the
+              // data-caption attribute.
+              if (captionHtml) {
+                attrs['data-caption'] = captionHtml;
+              }
             }
-          }
-          if (alignFilterEnabled) {
-            if (this.data.align !== 'none') {
-              attrs['data-align'] = this.data.align;
+            if (alignFilterEnabled) {
+              if (this.data.align !== 'none') {
+                attrs['data-align'] = this.data.align;
+              }
             }
-          }
 
-          // If img is wrapped with a link, we want to return that link.
-          if (img.parent.name === 'a') {
-            return img.parent;
-          }
+            // If img is wrapped with a link, we want to return that link.
+            if (img.parent.name === 'a') {
+              return img.parent;
+            }
 
-          return img;
-        };
-
-        // We want to upcast <img> elements to a DOM structure required by the
-        // image2 widget. Depending on a case it may be:
-        //   - just an <img> tag (non-captioned, not-centered image),
-        //   - <img> tag in a paragraph (non-captioned, centered image),
-        //   - <figure> tag (captioned image).
-        // We take the same attributes into account as downcast() does.
-        const originalUpcast = widgetDefinition.upcast;
-        widgetDefinition.upcast = function (element, data) {
-          if (element.name !== 'img' || !element.attributes['data-entity-type'] || !element.attributes['data-entity-uuid']) {
-            return;
-          }
-          // Don't initialize on pasted fake objects.
-          else if (element.attributes['data-cke-realelement']) {
-            return;
-          }
+            return img;
+          };
 
-          element = originalUpcast.call(this, element, data);
-          const attrs = element.attributes;
+          // We want to upcast <img> elements to a DOM structure required by the
+          // image2 widget. Depending on a case it may be:
+          //   - just an <img> tag (non-captioned, not-centered image),
+          //   - <img> tag in a paragraph (non-captioned, centered image),
+          //   - <figure> tag (captioned image).
+          // We take the same attributes into account as downcast() does.
+          const originalUpcast = widgetDefinition.upcast;
+          widgetDefinition.upcast = function(element, data) {
+            if (
+              element.name !== 'img' ||
+              !element.attributes['data-entity-type'] ||
+              !element.attributes['data-entity-uuid']
+            ) {
+              return;
+            }
+            // Don't initialize on pasted fake objects.
+            if (element.attributes['data-cke-realelement']) {
+              return;
+            }
 
-          if (element.parent.name === 'a') {
-            element = element.parent;
-          }
+            element = originalUpcast.call(this, element, data);
+            const attrs = element.attributes;
 
-          let retElement = element;
-          let caption;
+            if (element.parent.name === 'a') {
+              element = element.parent;
+            }
 
-          // We won't need the attributes during editing: we'll use widget.data
-          // to store them (except the caption, which is stored in the DOM).
-          if (captionFilterEnabled) {
-            caption = attrs['data-caption'];
-            delete attrs['data-caption'];
-          }
-          if (alignFilterEnabled) {
-            data.align = attrs['data-align'];
-            delete attrs['data-align'];
-          }
-          data['data-entity-type'] = attrs['data-entity-type'];
-          delete attrs['data-entity-type'];
-          data['data-entity-uuid'] = attrs['data-entity-uuid'];
-          delete attrs['data-entity-uuid'];
-
-          if (captionFilterEnabled) {
-            // Unwrap from <p> wrapper created by HTML parser for a captioned
-            // image. The captioned image will be transformed to <figure>, so we
-            // don't want the <p> anymore.
-            if (element.parent.name === 'p' && caption) {
-              let index = element.getIndex();
-              const splitBefore = index > 0;
-              const splitAfter = index + 1 < element.parent.children.length;
-
-              if (splitBefore) {
-                element.parent.split(index);
-              }
-              index = element.getIndex();
-              if (splitAfter) {
-                element.parent.split(index + 1);
-              }
+            let retElement = element;
+            let caption;
 
-              element.parent.replaceWith(element);
-              retElement = element;
+            // We won't need the attributes during editing: we'll use widget.data
+            // to store them (except the caption, which is stored in the DOM).
+            if (captionFilterEnabled) {
+              caption = attrs['data-caption'];
+              delete attrs['data-caption'];
             }
-
-            // If this image has a caption, create a full <figure> structure.
-            if (caption) {
-              const figure = new CKEDITOR.htmlParser.element('figure');
-              caption = new CKEDITOR.htmlParser.fragment.fromHtml(caption, 'figcaption');
-
-              // Use Drupal's data-placeholder attribute to insert a CSS-based,
-              // translation-ready placeholder for empty captions. Note that it
-              // also must to be done for new instances (see
-              // widgetDefinition._createDialogSaveCallback).
-              caption.attributes['data-placeholder'] = placeholderText;
-
-              element.replaceWith(figure);
-              figure.add(element);
-              figure.add(caption);
-              figure.attributes.class = editor.config.image2_captionedClass;
-              retElement = figure;
+            if (alignFilterEnabled) {
+              data.align = attrs['data-align'];
+              delete attrs['data-align'];
             }
-          }
+            data['data-entity-type'] = attrs['data-entity-type'];
+            delete attrs['data-entity-type'];
+            data['data-entity-uuid'] = attrs['data-entity-uuid'];
+            delete attrs['data-entity-uuid'];
+
+            if (captionFilterEnabled) {
+              // Unwrap from <p> wrapper created by HTML parser for a captioned
+              // image. The captioned image will be transformed to <figure>, so we
+              // don't want the <p> anymore.
+              if (element.parent.name === 'p' && caption) {
+                let index = element.getIndex();
+                const splitBefore = index > 0;
+                const splitAfter = index + 1 < element.parent.children.length;
+
+                if (splitBefore) {
+                  element.parent.split(index);
+                }
+                index = element.getIndex();
+                if (splitAfter) {
+                  element.parent.split(index + 1);
+                }
+
+                element.parent.replaceWith(element);
+                retElement = element;
+              }
 
-          if (alignFilterEnabled) {
-            // If this image doesn't have a caption (or the caption filter is
-            // disabled), but it is centered, make sure that it's wrapped with
-            // <p>, which will become a part of the widget.
-            if (data.align === 'center' && (!captionFilterEnabled || !caption)) {
-              const p = new CKEDITOR.htmlParser.element('p');
-              element.replaceWith(p);
-              p.add(element);
-              // Apply the class for centered images.
-              p.addClass(editor.config.image2_alignClasses[1]);
-              retElement = p;
+              // If this image has a caption, create a full <figure> structure.
+              if (caption) {
+                const figure = new CKEDITOR.htmlParser.element('figure');
+                caption = new CKEDITOR.htmlParser.fragment.fromHtml(
+                  caption,
+                  'figcaption',
+                );
+
+                // Use Drupal's data-placeholder attribute to insert a CSS-based,
+                // translation-ready placeholder for empty captions. Note that it
+                // also must to be done for new instances (see
+                // widgetDefinition._createDialogSaveCallback).
+                caption.attributes['data-placeholder'] = placeholderText;
+
+                element.replaceWith(figure);
+                figure.add(element);
+                figure.add(caption);
+                figure.attributes.class = editor.config.image2_captionedClass;
+                retElement = figure;
+              }
             }
-          }
 
-          // Return the upcasted element (<img>, <figure> or <p>).
-          return retElement;
-        };
-
-        // Protected; keys of the widget data to be sent to the Drupal dialog.
-        // Append to the values defined by the drupalimage plugin.
-        // @see core/modules/ckeditor/js/plugins/drupalimage/plugin.js
-        CKEDITOR.tools.extend(widgetDefinition._mapDataToDialog, {
-          align: 'data-align',
-          'data-caption': 'data-caption',
-          hasCaption: 'hasCaption',
-        });
-
-        // Override Drupal dialog save callback.
-        const originalCreateDialogSaveCallback = widgetDefinition._createDialogSaveCallback;
-        widgetDefinition._createDialogSaveCallback = function (editor, widget) {
-          const saveCallback = originalCreateDialogSaveCallback.call(this, editor, widget);
-
-          return function (dialogReturnValues) {
-            // Ensure hasCaption is a boolean. image2 assumes it always works
-            // with booleans; if this is not the case, then
-            // CKEDITOR.plugins.image2.stateShifter() will incorrectly mark
-            // widget.data.hasCaption as "changed" (e.g. when hasCaption === 0
-            // instead of hasCaption === false). This causes image2's "state
-            // shifter" to enter the wrong branch of the algorithm and blow up.
-            dialogReturnValues.attributes.hasCaption = !!dialogReturnValues.attributes.hasCaption;
-
-            const actualWidget = saveCallback(dialogReturnValues);
-
-            // By default, the template of captioned widget has no
-            // data-placeholder attribute. Note that it also must be done when
-            // upcasting existing elements (see widgetDefinition.upcast).
-            if (dialogReturnValues.attributes.hasCaption) {
-              actualWidget.editables.caption.setAttribute('data-placeholder', placeholderText);
-
-              // Some browsers will add a <br> tag to a newly created DOM
-              // element with no content. Remove this <br> if it is the only
-              // thing in the caption. Our placeholder support requires the
-              // element be entirely empty. See filter-caption.css.
-              const captionElement = actualWidget.editables.caption.$;
-              if (captionElement.childNodes.length === 1 && captionElement.childNodes.item(0).nodeName === 'BR') {
-                captionElement.removeChild(captionElement.childNodes.item(0));
+            if (alignFilterEnabled) {
+              // If this image doesn't have a caption (or the caption filter is
+              // disabled), but it is centered, make sure that it's wrapped with
+              // <p>, which will become a part of the widget.
+              if (
+                data.align === 'center' &&
+                (!captionFilterEnabled || !caption)
+              ) {
+                const p = new CKEDITOR.htmlParser.element('p');
+                element.replaceWith(p);
+                p.add(element);
+                // Apply the class for centered images.
+                p.addClass(editor.config.image2_alignClasses[1]);
+                retElement = p;
               }
             }
+
+            // Return the upcasted element (<img>, <figure> or <p>).
+            return retElement;
+          };
+
+          // Protected; keys of the widget data to be sent to the Drupal dialog.
+          // Append to the values defined by the drupalimage plugin.
+          // @see core/modules/ckeditor/js/plugins/drupalimage/plugin.js
+          CKEDITOR.tools.extend(widgetDefinition._mapDataToDialog, {
+            align: 'data-align',
+            'data-caption': 'data-caption',
+            hasCaption: 'hasCaption',
+          });
+
+          // Override Drupal dialog save callback.
+          const originalCreateDialogSaveCallback =
+            widgetDefinition._createDialogSaveCallback;
+          widgetDefinition._createDialogSaveCallback = function(
+            editor,
+            widget,
+          ) {
+            const saveCallback = originalCreateDialogSaveCallback.call(
+              this,
+              editor,
+              widget,
+            );
+
+            return function(dialogReturnValues) {
+              // Ensure hasCaption is a boolean. image2 assumes it always works
+              // with booleans; if this is not the case, then
+              // CKEDITOR.plugins.image2.stateShifter() will incorrectly mark
+              // widget.data.hasCaption as "changed" (e.g. when hasCaption === 0
+              // instead of hasCaption === false). This causes image2's "state
+              // shifter" to enter the wrong branch of the algorithm and blow up.
+              dialogReturnValues.attributes.hasCaption = !!dialogReturnValues
+                .attributes.hasCaption;
+
+              const actualWidget = saveCallback(dialogReturnValues);
+
+              // By default, the template of captioned widget has no
+              // data-placeholder attribute. Note that it also must be done when
+              // upcasting existing elements (see widgetDefinition.upcast).
+              if (dialogReturnValues.attributes.hasCaption) {
+                actualWidget.editables.caption.setAttribute(
+                  'data-placeholder',
+                  placeholderText,
+                );
+
+                // Some browsers will add a <br> tag to a newly created DOM
+                // element with no content. Remove this <br> if it is the only
+                // thing in the caption. Our placeholder support requires the
+                // element be entirely empty. See filter-caption.css.
+                const captionElement = actualWidget.editables.caption.$;
+                if (
+                  captionElement.childNodes.length === 1 &&
+                  captionElement.childNodes.item(0).nodeName === 'BR'
+                ) {
+                  captionElement.removeChild(captionElement.childNodes.item(0));
+                }
+              }
+            };
           };
-        };
-      // Low priority to ensure drupalimage's event handler runs first.
-      }, null, null, 20);
+          // Low priority to ensure drupalimage's event handler runs first.
+        },
+        null,
+        null,
+        20,
+      );
     },
 
     afterInit(editor) {
-      const disableButtonIfOnWidget = function (evt) {
+      const disableButtonIfOnWidget = function(evt) {
         const widget = editor.widgets.focused;
         if (widget && widget.name === 'image') {
           this.setState(CKEDITOR.TRISTATE_DISABLED);
       };
 
       // Disable alignment buttons if the align filter is not enabled.
-      if (editor.plugins.justify && !editor.config.drupalImageCaption_alignFilterEnabled) {
+      if (
+        editor.plugins.justify &&
+        !editor.config.drupalImageCaption_alignFilterEnabled
+      ) {
         let cmd;
-        const commands = ['justifyleft', 'justifycenter', 'justifyright', 'justifyblock'];
+        const commands = [
+          'justifyleft',
+          'justifycenter',
+          'justifyright',
+          'justifyblock',
+        ];
         for (let n = 0; n < commands.length; n++) {
           cmd = editor.getCommand(commands[n]);
           cmd.contextSensitive = 1;
       }
     },
   });
-
-  /**
-   * Finds an element by its name.
-   *
-   * Function will check first the passed element itself and then all its
-   * children in DFS order.
-   *
-   * @param {CKEDITOR.htmlParser.element} element
-   *   The element to search.
-   * @param {string} name
-   *   The element name to search for.
-   *
-   * @return {?CKEDITOR.htmlParser.element}
-   *   The found element, or null.
-   */
-  function findElementByName(element, name) {
-    if (element.name === name) {
-      return element;
-    }
-
-    let found = null;
-    element.forEach((el) => {
-      if (el.name === name) {
-        found = el;
-        // Stop here.
-        return false;
-      }
-    }, CKEDITOR.NODE_ELEMENT);
-    return found;
-  }
-}(CKEDITOR));
+})(CKEDITOR);