wrapper created by HTML parser for a captioned
+ // image. The captioned image will be transformed to 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 this image has a caption, create a full , 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 ( ).
+ 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 ,
tag to a newly created DOM
+ // element with no content. Remove this
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);
+ },
+
+ afterInit(editor) {
+ const disableButtonIfOnWidget = function (evt) {
+ const widget = editor.widgets.focused;
+ if (widget && widget.name === 'image') {
+ this.setState(CKEDITOR.TRISTATE_DISABLED);
+ evt.cancel();
+ }
+ };
+
+ // Disable alignment buttons if the align filter is not enabled.
+ if (editor.plugins.justify && !editor.config.drupalImageCaption_alignFilterEnabled) {
+ let cmd;
+ const commands = ['justifyleft', 'justifycenter', 'justifyright', 'justifyblock'];
+ for (let n = 0; n < commands.length; n++) {
+ cmd = editor.getCommand(commands[n]);
+ cmd.contextSensitive = 1;
+ cmd.on('refresh', disableButtonIfOnWidget, null, null, 4);
+ }
+ }
+ },
+ });
+
+ /**
+ * 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));