balmet.com

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs

plugin.js (24009B)


      1 (function () {
      2 var link = (function (domGlobals) {
      3     'use strict';
      4 
      5     var global = tinymce.util.Tools.resolve('tinymce.PluginManager');
      6 
      7     var global$1 = tinymce.util.Tools.resolve('tinymce.util.VK');
      8 
      9     var assumeExternalTargets = function (editorSettings) {
     10       return typeof editorSettings.link_assume_external_targets === 'boolean' ? editorSettings.link_assume_external_targets : false;
     11     };
     12     var hasContextToolbar = function (editorSettings) {
     13       return typeof editorSettings.link_context_toolbar === 'boolean' ? editorSettings.link_context_toolbar : false;
     14     };
     15     var getLinkList = function (editorSettings) {
     16       return editorSettings.link_list;
     17     };
     18     var hasDefaultLinkTarget = function (editorSettings) {
     19       return typeof editorSettings.default_link_target === 'string';
     20     };
     21     var getDefaultLinkTarget = function (editorSettings) {
     22       return editorSettings.default_link_target;
     23     };
     24     var getTargetList = function (editorSettings) {
     25       return editorSettings.target_list;
     26     };
     27     var setTargetList = function (editor, list) {
     28       editor.settings.target_list = list;
     29     };
     30     var shouldShowTargetList = function (editorSettings) {
     31       return getTargetList(editorSettings) !== false;
     32     };
     33     var getRelList = function (editorSettings) {
     34       return editorSettings.rel_list;
     35     };
     36     var hasRelList = function (editorSettings) {
     37       return getRelList(editorSettings) !== undefined;
     38     };
     39     var getLinkClassList = function (editorSettings) {
     40       return editorSettings.link_class_list;
     41     };
     42     var hasLinkClassList = function (editorSettings) {
     43       return getLinkClassList(editorSettings) !== undefined;
     44     };
     45     var shouldShowLinkTitle = function (editorSettings) {
     46       return editorSettings.link_title !== false;
     47     };
     48     var allowUnsafeLinkTarget = function (editorSettings) {
     49       return typeof editorSettings.allow_unsafe_link_target === 'boolean' ? editorSettings.allow_unsafe_link_target : false;
     50     };
     51     var Settings = {
     52       assumeExternalTargets: assumeExternalTargets,
     53       hasContextToolbar: hasContextToolbar,
     54       getLinkList: getLinkList,
     55       hasDefaultLinkTarget: hasDefaultLinkTarget,
     56       getDefaultLinkTarget: getDefaultLinkTarget,
     57       getTargetList: getTargetList,
     58       setTargetList: setTargetList,
     59       shouldShowTargetList: shouldShowTargetList,
     60       getRelList: getRelList,
     61       hasRelList: hasRelList,
     62       getLinkClassList: getLinkClassList,
     63       hasLinkClassList: hasLinkClassList,
     64       shouldShowLinkTitle: shouldShowLinkTitle,
     65       allowUnsafeLinkTarget: allowUnsafeLinkTarget
     66     };
     67 
     68     var global$2 = tinymce.util.Tools.resolve('tinymce.dom.DOMUtils');
     69 
     70     var global$3 = tinymce.util.Tools.resolve('tinymce.Env');
     71 
     72     var appendClickRemove = function (link, evt) {
     73       domGlobals.document.body.appendChild(link);
     74       link.dispatchEvent(evt);
     75       domGlobals.document.body.removeChild(link);
     76     };
     77     var open = function (url) {
     78       if (!global$3.ie || global$3.ie > 10) {
     79         var link = domGlobals.document.createElement('a');
     80         link.target = '_blank';
     81         link.href = url;
     82         link.rel = 'noreferrer noopener';
     83         var evt = domGlobals.document.createEvent('MouseEvents');
     84         evt.initMouseEvent('click', true, true, domGlobals.window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
     85         appendClickRemove(link, evt);
     86       } else {
     87         var win = domGlobals.window.open('', '_blank');
     88         if (win) {
     89           win.opener = null;
     90           var doc = win.document;
     91           doc.open();
     92           doc.write('<meta http-equiv="refresh" content="0; url=' + global$2.DOM.encode(url) + '">');
     93           doc.close();
     94         }
     95       }
     96     };
     97     var OpenUrl = { open: open };
     98 
     99     var global$4 = tinymce.util.Tools.resolve('tinymce.util.Tools');
    100 
    101     var toggleTargetRules = function (rel, isUnsafe) {
    102       var rules = ['noopener'];
    103       var newRel = rel ? rel.split(/\s+/) : [];
    104       var toString = function (rel) {
    105         return global$4.trim(rel.sort().join(' '));
    106       };
    107       var addTargetRules = function (rel) {
    108         rel = removeTargetRules(rel);
    109         return rel.length ? rel.concat(rules) : rules;
    110       };
    111       var removeTargetRules = function (rel) {
    112         return rel.filter(function (val) {
    113           return global$4.inArray(rules, val) === -1;
    114         });
    115       };
    116       newRel = isUnsafe ? addTargetRules(newRel) : removeTargetRules(newRel);
    117       return newRel.length ? toString(newRel) : null;
    118     };
    119     var trimCaretContainers = function (text) {
    120       return text.replace(/\uFEFF/g, '');
    121     };
    122     var getAnchorElement = function (editor, selectedElm) {
    123       selectedElm = selectedElm || editor.selection.getNode();
    124       if (isImageFigure(selectedElm)) {
    125         return editor.dom.select('a[href]', selectedElm)[0];
    126       } else {
    127         return editor.dom.getParent(selectedElm, 'a[href]');
    128       }
    129     };
    130     var getAnchorText = function (selection, anchorElm) {
    131       var text = anchorElm ? anchorElm.innerText || anchorElm.textContent : selection.getContent({ format: 'text' });
    132       return trimCaretContainers(text);
    133     };
    134     var isLink = function (elm) {
    135       return elm && elm.nodeName === 'A' && elm.href;
    136     };
    137     var hasLinks = function (elements) {
    138       return global$4.grep(elements, isLink).length > 0;
    139     };
    140     var isOnlyTextSelected = function (html) {
    141       if (/</.test(html) && (!/^<a [^>]+>[^<]+<\/a>$/.test(html) || html.indexOf('href=') === -1)) {
    142         return false;
    143       }
    144       return true;
    145     };
    146     var isImageFigure = function (node) {
    147       return node && node.nodeName === 'FIGURE' && /\bimage\b/i.test(node.className);
    148     };
    149     var link = function (editor, attachState) {
    150       return function (data) {
    151         editor.undoManager.transact(function () {
    152           var selectedElm = editor.selection.getNode();
    153           var anchorElm = getAnchorElement(editor, selectedElm);
    154           var linkAttrs = {
    155             href: data.href,
    156             target: data.target ? data.target : null,
    157             rel: data.rel ? data.rel : null,
    158             class: data.class ? data.class : null,
    159             title: data.title ? data.title : null
    160           };
    161           if (!Settings.hasRelList(editor.settings) && Settings.allowUnsafeLinkTarget(editor.settings) === false) {
    162             linkAttrs.rel = toggleTargetRules(linkAttrs.rel, linkAttrs.target === '_blank');
    163           }
    164           if (data.href === attachState.href) {
    165             attachState.attach();
    166             attachState = {};
    167           }
    168           if (anchorElm) {
    169             editor.focus();
    170             if (data.hasOwnProperty('text')) {
    171               if ('innerText' in anchorElm) {
    172                 anchorElm.innerText = data.text;
    173               } else {
    174                 anchorElm.textContent = data.text;
    175               }
    176             }
    177             editor.dom.setAttribs(anchorElm, linkAttrs);
    178             editor.selection.select(anchorElm);
    179             editor.undoManager.add();
    180           } else {
    181             if (isImageFigure(selectedElm)) {
    182               linkImageFigure(editor, selectedElm, linkAttrs);
    183             } else if (data.hasOwnProperty('text')) {
    184               editor.insertContent(editor.dom.createHTML('a', linkAttrs, editor.dom.encode(data.text)));
    185             } else {
    186               editor.execCommand('mceInsertLink', false, linkAttrs);
    187             }
    188           }
    189         });
    190       };
    191     };
    192     var unlink = function (editor) {
    193       return function () {
    194         editor.undoManager.transact(function () {
    195           var node = editor.selection.getNode();
    196           if (isImageFigure(node)) {
    197             unlinkImageFigure(editor, node);
    198           } else {
    199             editor.execCommand('unlink');
    200           }
    201         });
    202       };
    203     };
    204     var unlinkImageFigure = function (editor, fig) {
    205       var a, img;
    206       img = editor.dom.select('img', fig)[0];
    207       if (img) {
    208         a = editor.dom.getParents(img, 'a[href]', fig)[0];
    209         if (a) {
    210           a.parentNode.insertBefore(img, a);
    211           editor.dom.remove(a);
    212         }
    213       }
    214     };
    215     var linkImageFigure = function (editor, fig, attrs) {
    216       var a, img;
    217       img = editor.dom.select('img', fig)[0];
    218       if (img) {
    219         a = editor.dom.create('a', attrs);
    220         img.parentNode.insertBefore(a, img);
    221         a.appendChild(img);
    222       }
    223     };
    224     var Utils = {
    225       link: link,
    226       unlink: unlink,
    227       isLink: isLink,
    228       hasLinks: hasLinks,
    229       isOnlyTextSelected: isOnlyTextSelected,
    230       getAnchorElement: getAnchorElement,
    231       getAnchorText: getAnchorText,
    232       toggleTargetRules: toggleTargetRules
    233     };
    234 
    235     var global$5 = tinymce.util.Tools.resolve('tinymce.util.Delay');
    236 
    237     var global$6 = tinymce.util.Tools.resolve('tinymce.util.XHR');
    238 
    239     var attachState = {};
    240     var createLinkList = function (editor, callback) {
    241       var linkList = Settings.getLinkList(editor.settings);
    242       if (typeof linkList === 'string') {
    243         global$6.send({
    244           url: linkList,
    245           success: function (text) {
    246             callback(editor, JSON.parse(text));
    247           }
    248         });
    249       } else if (typeof linkList === 'function') {
    250         linkList(function (list) {
    251           callback(editor, list);
    252         });
    253       } else {
    254         callback(editor, linkList);
    255       }
    256     };
    257     var buildListItems = function (inputList, itemCallback, startItems) {
    258       var appendItems = function (values, output) {
    259         output = output || [];
    260         global$4.each(values, function (item) {
    261           var menuItem = { text: item.text || item.title };
    262           if (item.menu) {
    263             menuItem.menu = appendItems(item.menu);
    264           } else {
    265             menuItem.value = item.value;
    266             if (itemCallback) {
    267               itemCallback(menuItem);
    268             }
    269           }
    270           output.push(menuItem);
    271         });
    272         return output;
    273       };
    274       return appendItems(inputList, startItems || []);
    275     };
    276     var delayedConfirm = function (editor, message, callback) {
    277       var rng = editor.selection.getRng();
    278       global$5.setEditorTimeout(editor, function () {
    279         editor.windowManager.confirm(message, function (state) {
    280           editor.selection.setRng(rng);
    281           callback(state);
    282         });
    283       });
    284     };
    285     var showDialog = function (editor, linkList) {
    286       var data = {};
    287       var selection = editor.selection;
    288       var dom = editor.dom;
    289       var anchorElm, initialText;
    290       var win, onlyText, textListCtrl, linkListCtrl, relListCtrl, targetListCtrl, classListCtrl, linkTitleCtrl, value;
    291       var linkListChangeHandler = function (e) {
    292         var textCtrl = win.find('#text');
    293         if (!textCtrl.value() || e.lastControl && textCtrl.value() === e.lastControl.text()) {
    294           textCtrl.value(e.control.text());
    295         }
    296         win.find('#href').value(e.control.value());
    297       };
    298       var buildAnchorListControl = function (url) {
    299         var anchorList = [];
    300         global$4.each(editor.dom.select('a:not([href])'), function (anchor) {
    301           var id = anchor.name || anchor.id;
    302           if (id) {
    303             anchorList.push({
    304               text: id,
    305               value: '#' + id,
    306               selected: url.indexOf('#' + id) !== -1
    307             });
    308           }
    309         });
    310         if (anchorList.length) {
    311           anchorList.unshift({
    312             text: 'None',
    313             value: ''
    314           });
    315           return {
    316             name: 'anchor',
    317             type: 'listbox',
    318             label: 'Anchors',
    319             values: anchorList,
    320             onselect: linkListChangeHandler
    321           };
    322         }
    323       };
    324       var updateText = function () {
    325         if (!initialText && onlyText && !data.text) {
    326           this.parent().parent().find('#text')[0].value(this.value());
    327         }
    328       };
    329       var urlChange = function (e) {
    330         var meta = e.meta || {};
    331         if (linkListCtrl) {
    332           linkListCtrl.value(editor.convertURL(this.value(), 'href'));
    333         }
    334         global$4.each(e.meta, function (value, key) {
    335           var inp = win.find('#' + key);
    336           if (key === 'text') {
    337             if (initialText.length === 0) {
    338               inp.value(value);
    339               data.text = value;
    340             }
    341           } else {
    342             inp.value(value);
    343           }
    344         });
    345         if (meta.attach) {
    346           attachState = {
    347             href: this.value(),
    348             attach: meta.attach
    349           };
    350         }
    351         if (!meta.text) {
    352           updateText.call(this);
    353         }
    354       };
    355       var onBeforeCall = function (e) {
    356         e.meta = win.toJSON();
    357       };
    358       onlyText = Utils.isOnlyTextSelected(selection.getContent());
    359       anchorElm = Utils.getAnchorElement(editor);
    360       data.text = initialText = Utils.getAnchorText(editor.selection, anchorElm);
    361       data.href = anchorElm ? dom.getAttrib(anchorElm, 'href') : '';
    362       if (anchorElm) {
    363         data.target = dom.getAttrib(anchorElm, 'target');
    364       } else if (Settings.hasDefaultLinkTarget(editor.settings)) {
    365         data.target = Settings.getDefaultLinkTarget(editor.settings);
    366       }
    367       if (value = dom.getAttrib(anchorElm, 'rel')) {
    368         data.rel = value;
    369       }
    370       if (value = dom.getAttrib(anchorElm, 'class')) {
    371         data.class = value;
    372       }
    373       if (value = dom.getAttrib(anchorElm, 'title')) {
    374         data.title = value;
    375       }
    376       if (onlyText) {
    377         textListCtrl = {
    378           name: 'text',
    379           type: 'textbox',
    380           size: 40,
    381           label: 'Text to display',
    382           onchange: function () {
    383             data.text = this.value();
    384           }
    385         };
    386       }
    387       if (linkList) {
    388         linkListCtrl = {
    389           type: 'listbox',
    390           label: 'Link list',
    391           values: buildListItems(linkList, function (item) {
    392             item.value = editor.convertURL(item.value || item.url, 'href');
    393           }, [{
    394               text: 'None',
    395               value: ''
    396             }]),
    397           onselect: linkListChangeHandler,
    398           value: editor.convertURL(data.href, 'href'),
    399           onPostRender: function () {
    400             linkListCtrl = this;
    401           }
    402         };
    403       }
    404       if (Settings.shouldShowTargetList(editor.settings)) {
    405         if (Settings.getTargetList(editor.settings) === undefined) {
    406           Settings.setTargetList(editor, [
    407             {
    408               text: 'None',
    409               value: ''
    410             },
    411             {
    412               text: 'New window',
    413               value: '_blank'
    414             }
    415           ]);
    416         }
    417         targetListCtrl = {
    418           name: 'target',
    419           type: 'listbox',
    420           label: 'Target',
    421           values: buildListItems(Settings.getTargetList(editor.settings))
    422         };
    423       }
    424       if (Settings.hasRelList(editor.settings)) {
    425         relListCtrl = {
    426           name: 'rel',
    427           type: 'listbox',
    428           label: 'Rel',
    429           values: buildListItems(Settings.getRelList(editor.settings), function (item) {
    430             if (Settings.allowUnsafeLinkTarget(editor.settings) === false) {
    431               item.value = Utils.toggleTargetRules(item.value, data.target === '_blank');
    432             }
    433           })
    434         };
    435       }
    436       if (Settings.hasLinkClassList(editor.settings)) {
    437         classListCtrl = {
    438           name: 'class',
    439           type: 'listbox',
    440           label: 'Class',
    441           values: buildListItems(Settings.getLinkClassList(editor.settings), function (item) {
    442             if (item.value) {
    443               item.textStyle = function () {
    444                 return editor.formatter.getCssText({
    445                   inline: 'a',
    446                   classes: [item.value]
    447                 });
    448               };
    449             }
    450           })
    451         };
    452       }
    453       if (Settings.shouldShowLinkTitle(editor.settings)) {
    454         linkTitleCtrl = {
    455           name: 'title',
    456           type: 'textbox',
    457           label: 'Title',
    458           value: data.title
    459         };
    460       }
    461       win = editor.windowManager.open({
    462         title: 'Insert link',
    463         data: data,
    464         body: [
    465           {
    466             name: 'href',
    467             type: 'filepicker',
    468             filetype: 'file',
    469             size: 40,
    470             autofocus: true,
    471             label: 'Url',
    472             onchange: urlChange,
    473             onkeyup: updateText,
    474             onpaste: updateText,
    475             onbeforecall: onBeforeCall
    476           },
    477           textListCtrl,
    478           linkTitleCtrl,
    479           buildAnchorListControl(data.href),
    480           linkListCtrl,
    481           relListCtrl,
    482           targetListCtrl,
    483           classListCtrl
    484         ],
    485         onSubmit: function (e) {
    486           var assumeExternalTargets = Settings.assumeExternalTargets(editor.settings);
    487           var insertLink = Utils.link(editor, attachState);
    488           var removeLink = Utils.unlink(editor);
    489           var resultData = global$4.extend({}, data, e.data);
    490           var href = resultData.href;
    491           if (!href) {
    492             removeLink();
    493             return;
    494           }
    495           if (!onlyText || resultData.text === initialText) {
    496             delete resultData.text;
    497           }
    498           if (href.indexOf('@') > 0 && href.indexOf('//') === -1 && href.indexOf('mailto:') === -1) {
    499             delayedConfirm(editor, 'The URL you entered seems to be an email address. Do you want to add the required mailto: prefix?', function (state) {
    500               if (state) {
    501                 resultData.href = 'mailto:' + href;
    502               }
    503               insertLink(resultData);
    504             });
    505             return;
    506           }
    507           if (assumeExternalTargets === true && !/^\w+:/i.test(href) || assumeExternalTargets === false && /^\s*www[\.|\d\.]/i.test(href)) {
    508             delayedConfirm(editor, 'The URL you entered seems to be an external link. Do you want to add the required http:// prefix?', function (state) {
    509               if (state) {
    510                 resultData.href = 'http://' + href;
    511               }
    512               insertLink(resultData);
    513             });
    514             return;
    515           }
    516           insertLink(resultData);
    517         }
    518       });
    519     };
    520     var open$1 = function (editor) {
    521       createLinkList(editor, showDialog);
    522     };
    523     var Dialog = { open: open$1 };
    524 
    525     var getLink = function (editor, elm) {
    526       return editor.dom.getParent(elm, 'a[href]');
    527     };
    528     var getSelectedLink = function (editor) {
    529       return getLink(editor, editor.selection.getStart());
    530     };
    531     var getHref = function (elm) {
    532       var href = elm.getAttribute('data-mce-href');
    533       return href ? href : elm.getAttribute('href');
    534     };
    535     var isContextMenuVisible = function (editor) {
    536       var contextmenu = editor.plugins.contextmenu;
    537       return contextmenu ? contextmenu.isContextMenuVisible() : false;
    538     };
    539     var hasOnlyAltModifier = function (e) {
    540       return e.altKey === true && e.shiftKey === false && e.ctrlKey === false && e.metaKey === false;
    541     };
    542     var gotoLink = function (editor, a) {
    543       if (a) {
    544         var href = getHref(a);
    545         if (/^#/.test(href)) {
    546           var targetEl = editor.$(href);
    547           if (targetEl.length) {
    548             editor.selection.scrollIntoView(targetEl[0], true);
    549           }
    550         } else {
    551           OpenUrl.open(a.href);
    552         }
    553       }
    554     };
    555     var openDialog = function (editor) {
    556       return function () {
    557         Dialog.open(editor);
    558       };
    559     };
    560     var gotoSelectedLink = function (editor) {
    561       return function () {
    562         gotoLink(editor, getSelectedLink(editor));
    563       };
    564     };
    565     var leftClickedOnAHref = function (editor) {
    566       return function (elm) {
    567         var sel, rng, node;
    568         if (Settings.hasContextToolbar(editor.settings) && !isContextMenuVisible(editor) && Utils.isLink(elm)) {
    569           sel = editor.selection;
    570           rng = sel.getRng();
    571           node = rng.startContainer;
    572           if (node.nodeType === 3 && sel.isCollapsed() && rng.startOffset > 0 && rng.startOffset < node.data.length) {
    573             return true;
    574           }
    575         }
    576         return false;
    577       };
    578     };
    579     var setupGotoLinks = function (editor) {
    580       editor.on('click', function (e) {
    581         var link = getLink(editor, e.target);
    582         if (link && global$1.metaKeyPressed(e)) {
    583           e.preventDefault();
    584           gotoLink(editor, link);
    585         }
    586       });
    587       editor.on('keydown', function (e) {
    588         var link = getSelectedLink(editor);
    589         if (link && e.keyCode === 13 && hasOnlyAltModifier(e)) {
    590           e.preventDefault();
    591           gotoLink(editor, link);
    592         }
    593       });
    594     };
    595     var toggleActiveState = function (editor) {
    596       return function () {
    597         var self = this;
    598         editor.on('nodechange', function (e) {
    599           self.active(!editor.readonly && !!Utils.getAnchorElement(editor, e.element));
    600         });
    601       };
    602     };
    603     var toggleViewLinkState = function (editor) {
    604       return function () {
    605         var self = this;
    606         var toggleVisibility = function (e) {
    607           if (Utils.hasLinks(e.parents)) {
    608             self.show();
    609           } else {
    610             self.hide();
    611           }
    612         };
    613         if (!Utils.hasLinks(editor.dom.getParents(editor.selection.getStart()))) {
    614           self.hide();
    615         }
    616         editor.on('nodechange', toggleVisibility);
    617         self.on('remove', function () {
    618           editor.off('nodechange', toggleVisibility);
    619         });
    620       };
    621     };
    622     var Actions = {
    623       openDialog: openDialog,
    624       gotoSelectedLink: gotoSelectedLink,
    625       leftClickedOnAHref: leftClickedOnAHref,
    626       setupGotoLinks: setupGotoLinks,
    627       toggleActiveState: toggleActiveState,
    628       toggleViewLinkState: toggleViewLinkState
    629     };
    630 
    631     var register = function (editor) {
    632       editor.addCommand('mceLink', Actions.openDialog(editor));
    633     };
    634     var Commands = { register: register };
    635 
    636     var setup = function (editor) {
    637       editor.addShortcut('Meta+K', '', Actions.openDialog(editor));
    638     };
    639     var Keyboard = { setup: setup };
    640 
    641     var setupButtons = function (editor) {
    642       editor.addButton('link', {
    643         active: false,
    644         icon: 'link',
    645         tooltip: 'Insert/edit link',
    646         onclick: Actions.openDialog(editor),
    647         onpostrender: Actions.toggleActiveState(editor)
    648       });
    649       editor.addButton('unlink', {
    650         active: false,
    651         icon: 'unlink',
    652         tooltip: 'Remove link',
    653         onclick: Utils.unlink(editor),
    654         onpostrender: Actions.toggleActiveState(editor)
    655       });
    656       if (editor.addContextToolbar) {
    657         editor.addButton('openlink', {
    658           icon: 'newtab',
    659           tooltip: 'Open link',
    660           onclick: Actions.gotoSelectedLink(editor)
    661         });
    662       }
    663     };
    664     var setupMenuItems = function (editor) {
    665       editor.addMenuItem('openlink', {
    666         text: 'Open link',
    667         icon: 'newtab',
    668         onclick: Actions.gotoSelectedLink(editor),
    669         onPostRender: Actions.toggleViewLinkState(editor),
    670         prependToContext: true
    671       });
    672       editor.addMenuItem('link', {
    673         icon: 'link',
    674         text: 'Link',
    675         shortcut: 'Meta+K',
    676         onclick: Actions.openDialog(editor),
    677         stateSelector: 'a[href]',
    678         context: 'insert',
    679         prependToContext: true
    680       });
    681       editor.addMenuItem('unlink', {
    682         icon: 'unlink',
    683         text: 'Remove link',
    684         onclick: Utils.unlink(editor),
    685         stateSelector: 'a[href]'
    686       });
    687     };
    688     var setupContextToolbars = function (editor) {
    689       if (editor.addContextToolbar) {
    690         editor.addContextToolbar(Actions.leftClickedOnAHref(editor), 'openlink | link unlink');
    691       }
    692     };
    693     var Controls = {
    694       setupButtons: setupButtons,
    695       setupMenuItems: setupMenuItems,
    696       setupContextToolbars: setupContextToolbars
    697     };
    698 
    699     global.add('link', function (editor) {
    700       Controls.setupButtons(editor);
    701       Controls.setupMenuItems(editor);
    702       Controls.setupContextToolbars(editor);
    703       Actions.setupGotoLinks(editor);
    704       Commands.register(editor);
    705       Keyboard.setup(editor);
    706     });
    707     function Plugin () {
    708     }
    709 
    710     return Plugin;
    711 
    712 }(window));
    713 })();