e3fd0ce0239374e1492ae54ec5640bc687199ae3
[yaffs-website] / web / modules / contrib / linkit / js / plugins / linkit / plugin.js
1 /**
2  * @file
3  * Linkit plugin.
4  *
5  * @ignore
6  */
7
8 (function ($, Drupal, drupalSettings, CKEDITOR) {
9
10   'use strict';
11
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;
16   // });
17
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({
23           element: 'a',
24           attributes: {
25             '!href': '',
26             // @TODO: Read these dynamically from the profile.
27             'accesskey': '',
28             'id': '',
29             'rel': '',
30             'target': '',
31             'title': ''
32           }
33         }),
34         requiredContent: new CKEDITOR.style({
35           element: 'a',
36           attributes: {
37             href: ''
38           }
39         }),
40         modes: {wysiwyg: 1},
41         canUndo: true,
42         exec: function (editor) {
43           var linkElement = getSelectedLink(editor);
44           var linkDOMElement = null;
45
46           // Set existing values based on selected element.
47           var existingValues = {};
48           if (linkElement && linkElement.$) {
49             linkDOMElement = linkElement.$;
50
51             // Populate an array with the link's current attributes.
52             var attribute = null;
53             var attributeName;
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-') {
60                 continue;
61               }
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;
66             }
67           }
68
69           // Prepare a save callback to be used upon saving the dialog.
70           var saveCallback = function (returnValues) {
71             editor.fire('saveSnapshot');
72
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];
77
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);
84               }
85
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);
90               range.select();
91
92               // Set the link so individual properties may be set below.
93               linkElement = getSelectedLink(editor);
94             }
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);
104                   }
105                   // Delete the property if set to an empty string.
106                   else {
107                     linkElement.removeAttribute(attrName);
108                   }
109                 }
110               }
111             }
112
113             // Save snapshot for undo support.
114             editor.fire('saveSnapshot');
115           };
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'
122           };
123
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);
126         }
127       });
128
129       // CTRL + L.
130       editor.setKeystroke(CKEDITOR.CTRL + 76, 'linkit');
131
132       // Add buttons.
133       if (editor.ui.addButton) {
134         editor.ui.addButton('Linkit', {
135           label: Drupal.t('Link'),
136           command: 'linkit',
137           icon: this.path + '/linkit.png'
138         });
139       }
140
141       editor.on('doubleclick', function (evt) {
142         var element = getSelectedLink(editor) || evt.data.element;
143
144         if (!element.isReadOnly()) {
145           if (element.is('a')) {
146             editor.getSelection().selectElement(element);
147             editor.getCommand('linkit').exec();
148           }
149         }
150       });
151
152       // If the "menu" plugin is loaded, register the menu items.
153       if (editor.addMenuItems) {
154         editor.addMenuItems({
155           linkit: {
156             label: Drupal.t('Edit Link'),
157             command: 'linkit',
158             group: 'link',
159             order: 1
160           }
161         });
162       }
163
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()) {
168             return null;
169           }
170           var anchor = getSelectedLink(editor);
171           if (!anchor) {
172             return null;
173           }
174
175           var menu = {};
176           if (anchor.getAttribute('href') && anchor.getChildCount()) {
177             menu = {
178               linkit: CKEDITOR.TRISTATE_OFF
179             };
180           }
181           return menu;
182         });
183       }
184     }
185   });
186
187   /**
188    * Get the surrounding link element of current selection.
189    *
190    * The following selection will all return the link element.
191    *
192    * @example
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>
199    *
200    * @param {CKEDITOR.editor} editor
201    *   The CKEditor editor object
202    *
203    * @return {?HTMLElement}
204    *   The selected link element, or null.
205    *
206    */
207   function getSelectedLink(editor) {
208     var selection = editor.getSelection();
209     var selectedElement = selection.getSelectedElement();
210     if (selectedElement && selectedElement.is('a')) {
211       return selectedElement;
212     }
213
214     var range = selection.getRanges(true)[0];
215
216     if (range) {
217       range.shrink(CKEDITOR.SHRINK_TEXT);
218       return editor.elementPath(range.getCommonAncestor()).contains('a', 1);
219     }
220     return null;
221   }
222
223 })(jQuery, Drupal, drupalSettings, CKEDITOR);