8 (function ($, Drupal, drupalSettings, CKEDITOR) {
12 // Alter the dialog settings to make a bigger dialog.
13 // $(window).on('dialog:beforecreate', function (event, dialog, $element, settings) {
14 // settings.dialogClass = settings.dialogClass.replace('ui-dialog--narrow', '');
15 // settings.width = 700;
18 CKEDITOR.plugins.add('linkit', {
19 init: function (editor) {
20 // Add the commands for link and unlink.
21 editor.addCommand('linkit', {
22 allowedContent: new CKEDITOR.style({
26 // @TODO: Read these dynamically from the profile.
34 requiredContent: new CKEDITOR.style({
42 exec: function (editor) {
43 var linkElement = getSelectedLink(editor);
44 var linkDOMElement = null;
46 // Set existing values based on selected element.
47 var existingValues = {};
48 if (linkElement && linkElement.$) {
49 linkDOMElement = linkElement.$;
51 // Populate an array with the link's current attributes.
54 for (var attrIndex = 0; attrIndex < linkDOMElement.attributes.length; attrIndex++) {
55 attribute = linkDOMElement.attributes.item(attrIndex);
56 attributeName = attribute.nodeName.toLowerCase();
57 // Don't consider data-cke-saved- attributes; they're just there
58 // to work around browser quirks.
59 if (attributeName.substring(0, 15) === 'data-cke-saved-') {
62 // Store the value for this attribute, unless there's a
63 // data-cke-saved- alternative for it, which will contain the
64 // quirk-free, original value.
65 existingValues[attributeName] = linkElement.data('cke-saved-' + attributeName) || attribute.nodeValue;
69 // Prepare a save callback to be used upon saving the dialog.
70 var saveCallback = function (returnValues) {
71 editor.fire('saveSnapshot');
73 // Create a new link element if needed.
74 if (!linkElement && returnValues.attributes.href) {
75 var selection = editor.getSelection();
76 var range = selection.getRanges(1)[0];
78 // Use link URL as text with a collapsed cursor.
79 if (range.collapsed) {
80 // Shorten mailto URLs to just the email address.
81 var text = new CKEDITOR.dom.text(returnValues.attributes.href.replace(/^mailto:/, ''), editor.document);
82 range.insertNode(text);
83 range.selectNodeContents(text);
86 // Create the new link by applying a style to the new text.
87 var style = new CKEDITOR.style({element: 'a', attributes: returnValues.attributes});
88 style.type = CKEDITOR.STYLE_INLINE;
89 style.applyToRange(range);
92 // Set the link so individual properties may be set below.
93 linkElement = getSelectedLink(editor);
95 // Update the link properties.
96 else if (linkElement) {
97 for (var attrName in returnValues.attributes) {
98 if (returnValues.attributes.hasOwnProperty(attrName)) {
99 // Update the property if a value is specified.
100 if (returnValues.attributes[attrName].length > 0) {
101 var value = returnValues.attributes[attrName];
102 linkElement.data('cke-saved-' + attrName, value);
103 linkElement.setAttribute(attrName, value);
105 // Delete the property if set to an empty string.
107 linkElement.removeAttribute(attrName);
113 // Save snapshot for undo support.
114 editor.fire('saveSnapshot');
116 // Drupal.t() will not work inside CKEditor plugins because CKEditor
117 // loads the JavaScript file instead of Drupal. Pull translated
118 // strings from the plugin settings that are translated server-side.
119 var dialogSettings = {
120 title: linkElement ? editor.config.linkit_dialogTitleAdd : editor.config.linkit_dialogTitleEdit,
121 dialogClass: 'editor-linkit-dialog'
124 // Open the dialog for the edit form.
125 Drupal.ckeditor.openDialog(editor, Drupal.url('linkit/dialog/linkit/' + editor.config.drupal.format), existingValues, saveCallback, dialogSettings);
130 editor.setKeystroke(CKEDITOR.CTRL + 76, 'linkit');
133 if (editor.ui.addButton) {
134 editor.ui.addButton('Linkit', {
135 label: Drupal.t('Link'),
137 icon: this.path + '/linkit.png'
141 editor.on('doubleclick', function (evt) {
142 var element = getSelectedLink(editor) || evt.data.element;
144 if (!element.isReadOnly()) {
145 if (element.is('a')) {
146 editor.getSelection().selectElement(element);
147 editor.getCommand('linkit').exec();
152 // If the "menu" plugin is loaded, register the menu items.
153 if (editor.addMenuItems) {
154 editor.addMenuItems({
156 label: Drupal.t('Edit Link'),
164 // If the "contextmenu" plugin is loaded, register the listeners.
165 if (editor.contextMenu) {
166 editor.contextMenu.addListener(function (element, selection) {
167 if (!element || element.isReadOnly()) {
170 var anchor = getSelectedLink(editor);
176 if (anchor.getAttribute('href') && anchor.getChildCount()) {
178 linkit: CKEDITOR.TRISTATE_OFF
188 * Get the surrounding link element of current selection.
190 * The following selection will all return the link element.
193 * <a href="#">li^nk</a>
194 * <a href="#">[link]</a>
195 * text[<a href="#">link]</a>
196 * <a href="#">li[nk</a>]
197 * [<b><a href="#">li]nk</a></b>]
198 * [<a href="#"><b>li]nk</b></a>
200 * @param {CKEDITOR.editor} editor
201 * The CKEditor editor object
203 * @return {?HTMLElement}
204 * The selected link element, or null.
207 function getSelectedLink(editor) {
208 var selection = editor.getSelection();
209 var selectedElement = selection.getSelectedElement();
210 if (selectedElement && selectedElement.is('a')) {
211 return selectedElement;
214 var range = selection.getRanges(true)[0];
217 range.shrink(CKEDITOR.SHRINK_TEXT);
218 return editor.elementPath(range.getCommonAncestor()).contains('a', 1);
223 })(jQuery, Drupal, drupalSettings, CKEDITOR);