.../ckeditor/js/plugins/drupalimage/plugin.js | 91 +++++++++++++++++----- .../js/plugins/drupalimagecaption/plugin.js | 20 ++++- .../ckeditor/js/plugins/drupallink/plugin.js | 72 +++++++++++++++++ 3 files changed, 159 insertions(+), 24 deletions(-) diff --git a/core/modules/ckeditor/js/plugins/drupalimage/plugin.js b/core/modules/ckeditor/js/plugins/drupalimage/plugin.js index 80921c2..1c1ca87 100644 --- a/core/modules/ckeditor/js/plugins/drupalimage/plugin.js +++ b/core/modules/ckeditor/js/plugins/drupalimage/plugin.js @@ -65,10 +65,6 @@ } widgetDefinition.allowedContent = new CKEDITOR.style(allowedContentDefinition); - // Override the 'link' part, to completely disable image2's link - // support: http://dev.ckeditor.com/ticket/11341. - widgetDefinition.parts.link = 'This is a nonsensical selector to disable this functionality completely'; - // Override downcast(): since we only accept in our upcast method, // the element is already correct. We only need to update the element's // data-entity-uuid attribute. @@ -176,6 +172,17 @@ return widget; }; }; + + var originalInit = widgetDefinition.init; + widgetDefinition.init = function () { + originalInit.call(this); + + // Update data.link object with attributes if the link has been discovered. + // @see plugins/image2/plugin.js/init() in CKEditor; this is similar. + if (this.parts.link) { + this.setData('link', CKEDITOR.plugins.link.parseLinkAttributes(editor, this.parts.link)); + } + }; }); // Add a widget#edit listener to every instance of image2 widget in order @@ -233,25 +240,69 @@ } }, - // Disable image2's integration with the link/drupallink plugins: don't - // allow the widget itself to become a link. Support for that may be added - // by an text filter that adds a data- attribute specifically for that. afterInit: function (editor) { - if (editor.plugins.drupallink) { - var cmd = editor.getCommand('drupallink'); - // Needs to be refreshed on selection changes. - cmd.contextSensitive = 1; - // Disable command and cancel event when the image widget is selected. - cmd.on('refresh', function (evt) { - var widget = editor.widgets.focused; - if (widget && widget.name === 'image') { - this.setState(CKEDITOR.TRISTATE_DISABLED); - evt.cancel(); - } - }); - } + linkCommandIntegrator(editor); } }); + + function linkCommandIntegrator(editor) { + // Nothing to integrate with if link is not loaded. + if (!editor.plugins.drupallink) + return; + + // Overwrite default behaviour of unlink command. + editor.getCommand('drupalunlink').on('exec', function (evt) { + var widget = getFocusedWidget(editor); + + // Override unlink only when link truly belongs to the widget. + // If wrapped inline widget in a link, let default unlink work (#11814). + if (!widget || !widget.parts.link) + return; + + widget.setData('link', null); + + // Selection (which is fake) may not change if unlinked image in focused widget, + // i.e. if captioned image. Let's refresh command state manually here. + this.refresh(editor, editor.elementPath()); + + evt.cancel(); + }); + + // Overwrite default refresh of unlink command. + editor.getCommand('drupalunlink').on('refresh', function (evt) { + var widget = getFocusedWidget(editor); + + if (!widget) + return; + + // Note that widget may be wrapped in a link, which + // does not belong to that widget (#11814). + this.setState(widget.data.link || widget.wrapper.getAscendant('a') ? + CKEDITOR.TRISTATE_OFF : CKEDITOR.TRISTATE_DISABLED); + + evt.cancel(); + }); + } + + // Returns the focused widget, if of the type specific for this plugin. + // If no widget is focused, `null` is returned. + // + // @param {CKEDITOR.editor} + // @returns {CKEDITOR.plugins.widget} + function getFocusedWidget(editor) { + var widget = editor.widgets.focused; + + if (widget && widget.name == 'image') + return widget; + + return null; + } + + // Exposed some API just for convenience. + CKEDITOR.plugins.drupalimage = { + getFocusedWidget: getFocusedWidget + }; + })(jQuery, Drupal, CKEDITOR); diff --git a/core/modules/ckeditor/js/plugins/drupalimagecaption/plugin.js b/core/modules/ckeditor/js/plugins/drupalimagecaption/plugin.js index 8dd91b1..fe89872 100644 --- a/core/modules/ckeditor/js/plugins/drupalimagecaption/plugin.js +++ b/core/modules/ckeditor/js/plugins/drupalimagecaption/plugin.js @@ -93,8 +93,13 @@ } attrs['data-entity-type'] = this.data['data-entity-type']; attrs['data-entity-uuid'] = this.data['data-entity-uuid']; - - return img; + + // If img is wrapped with a link, we want to return that link. + if (img.parent.name == 'a') { + return img.parent; + } else { + return img; + } }; // We want to upcast elements to a DOM structure required by the @@ -115,6 +120,11 @@ element = originalUpcast.call(this, element, data); var attrs = element.attributes; + + if (element.parent.name === 'a') { + element = element.parent; + } + var retElement = element; var caption; @@ -132,11 +142,13 @@ delete attrs['data-entity-type']; data['data-entity-uuid'] = attrs['data-entity-uuid']; delete attrs['data-entity-uuid']; - + if (captionFilterEnabled) { // Unwrap from
wrapper created by HTML parser for a captioned // image. The captioned image will be transformed to