home *** CD-ROM | disk | FTP | other *** search
/ HTML Examples / WP.iso / wordpress2 / wp-includes / js / tinymce / plugins / link / plugin.js next >
Encoding:
JavaScript  |  2017-09-26  |  31.3 KB  |  1,175 lines

  1. (function () {
  2.  
  3. var defs = {}; // id -> {dependencies, definition, instance (possibly undefined)}
  4.  
  5. // Used when there is no 'main' module.
  6. // The name is probably (hopefully) unique so minification removes for releases.
  7. var register_3795 = function (id) {
  8.   var module = dem(id);
  9.   var fragments = id.split('.');
  10.   var target = Function('return this;')();
  11.   for (var i = 0; i < fragments.length - 1; ++i) {
  12.     if (target[fragments[i]] === undefined)
  13.       target[fragments[i]] = {};
  14.     target = target[fragments[i]];
  15.   }
  16.   target[fragments[fragments.length - 1]] = module;
  17. };
  18.  
  19. var instantiate = function (id) {
  20.   var actual = defs[id];
  21.   var dependencies = actual.deps;
  22.   var definition = actual.defn;
  23.   var len = dependencies.length;
  24.   var instances = new Array(len);
  25.   for (var i = 0; i < len; ++i)
  26.     instances[i] = dem(dependencies[i]);
  27.   var defResult = definition.apply(null, instances);
  28.   if (defResult === undefined)
  29.      throw 'module [' + id + '] returned undefined';
  30.   actual.instance = defResult;
  31. };
  32.  
  33. var def = function (id, dependencies, definition) {
  34.   if (typeof id !== 'string')
  35.     throw 'module id must be a string';
  36.   else if (dependencies === undefined)
  37.     throw 'no dependencies for ' + id;
  38.   else if (definition === undefined)
  39.     throw 'no definition function for ' + id;
  40.   defs[id] = {
  41.     deps: dependencies,
  42.     defn: definition,
  43.     instance: undefined
  44.   };
  45. };
  46.  
  47. var dem = function (id) {
  48.   var actual = defs[id];
  49.   if (actual === undefined)
  50.     throw 'module [' + id + '] was undefined';
  51.   else if (actual.instance === undefined)
  52.     instantiate(id);
  53.   return actual.instance;
  54. };
  55.  
  56. var req = function (ids, callback) {
  57.   var len = ids.length;
  58.   var instances = new Array(len);
  59.   for (var i = 0; i < len; ++i)
  60.     instances.push(dem(ids[i]));
  61.   callback.apply(null, callback);
  62. };
  63.  
  64. var ephox = {};
  65.  
  66. ephox.bolt = {
  67.   module: {
  68.     api: {
  69.       define: def,
  70.       require: req,
  71.       demand: dem
  72.     }
  73.   }
  74. };
  75.  
  76. var define = def;
  77. var require = req;
  78. var demand = dem;
  79. // this helps with minificiation when using a lot of global references
  80. var defineGlobal = function (id, ref) {
  81.   define(id, [], function () { return ref; });
  82. };
  83. /*jsc
  84. ["tinymce.plugins.link.Plugin","tinymce.core.PluginManager","tinymce.plugins.link.core.Actions","tinymce.plugins.link.ui.Controls","global!tinymce.util.Tools.resolve","tinymce.core.util.VK","tinymce.plugins.link.ui.Dialog","tinymce.plugins.link.core.OpenUrl","tinymce.plugins.link.core.Utils","tinymce.plugins.link.core.Settings","tinymce.core.util.Delay","tinymce.core.util.Tools","tinymce.core.util.XHR","global!RegExp","tinymce.core.dom.DOMUtils","tinymce.core.Env"]
  85. jsc*/
  86. defineGlobal("global!tinymce.util.Tools.resolve", tinymce.util.Tools.resolve);
  87. /**
  88.  * ResolveGlobal.js
  89.  *
  90.  * Released under LGPL License.
  91.  * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
  92.  *
  93.  * License: http://www.tinymce.com/license
  94.  * Contributing: http://www.tinymce.com/contributing
  95.  */
  96.  
  97. define(
  98.   'tinymce.core.PluginManager',
  99.   [
  100.     'global!tinymce.util.Tools.resolve'
  101.   ],
  102.   function (resolve) {
  103.     return resolve('tinymce.PluginManager');
  104.   }
  105. );
  106.  
  107. /**
  108.  * ResolveGlobal.js
  109.  *
  110.  * Released under LGPL License.
  111.  * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
  112.  *
  113.  * License: http://www.tinymce.com/license
  114.  * Contributing: http://www.tinymce.com/contributing
  115.  */
  116.  
  117. define(
  118.   'tinymce.core.util.VK',
  119.   [
  120.     'global!tinymce.util.Tools.resolve'
  121.   ],
  122.   function (resolve) {
  123.     return resolve('tinymce.util.VK');
  124.   }
  125. );
  126.  
  127. /**
  128.  * ResolveGlobal.js
  129.  *
  130.  * Released under LGPL License.
  131.  * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
  132.  *
  133.  * License: http://www.tinymce.com/license
  134.  * Contributing: http://www.tinymce.com/contributing
  135.  */
  136.  
  137. define(
  138.   'tinymce.core.util.Delay',
  139.   [
  140.     'global!tinymce.util.Tools.resolve'
  141.   ],
  142.   function (resolve) {
  143.     return resolve('tinymce.util.Delay');
  144.   }
  145. );
  146.  
  147. /**
  148.  * ResolveGlobal.js
  149.  *
  150.  * Released under LGPL License.
  151.  * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
  152.  *
  153.  * License: http://www.tinymce.com/license
  154.  * Contributing: http://www.tinymce.com/contributing
  155.  */
  156.  
  157. define(
  158.   'tinymce.core.util.Tools',
  159.   [
  160.     'global!tinymce.util.Tools.resolve'
  161.   ],
  162.   function (resolve) {
  163.     return resolve('tinymce.util.Tools');
  164.   }
  165. );
  166.  
  167. /**
  168.  * ResolveGlobal.js
  169.  *
  170.  * Released under LGPL License.
  171.  * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
  172.  *
  173.  * License: http://www.tinymce.com/license
  174.  * Contributing: http://www.tinymce.com/contributing
  175.  */
  176.  
  177. define(
  178.   'tinymce.core.util.XHR',
  179.   [
  180.     'global!tinymce.util.Tools.resolve'
  181.   ],
  182.   function (resolve) {
  183.     return resolve('tinymce.util.XHR');
  184.   }
  185. );
  186.  
  187. define(
  188.   'tinymce.plugins.link.core.Settings',
  189.   [
  190.  
  191.   ],
  192.   function () {
  193.     var assumeExternalTargets = function (editorSettings) {
  194.       return typeof editorSettings.link_assume_external_targets === 'boolean' ? editorSettings.link_assume_external_targets : false;
  195.     };
  196.  
  197.     var hasContextToolbar = function (editorSettings) {
  198.       return typeof editorSettings.link_context_toolbar === 'boolean' ? editorSettings.link_context_toolbar : false;
  199.     };
  200.  
  201.     var getLinkList = function (editorSettings) {
  202.       return editorSettings.link_list;
  203.     };
  204.  
  205.     var hasDefaultLinkTarget = function (editorSettings) {
  206.       return typeof editorSettings.default_link_target === 'string';
  207.     };
  208.  
  209.     var getDefaultLinkTarget = function (editorSettings) {
  210.       return editorSettings.default_link_target;
  211.     };
  212.  
  213.     var getTargetList = function (editorSettings) {
  214.       return editorSettings.target_list;
  215.     };
  216.  
  217.     var setTargetList = function (editor, list) {
  218.       editor.settings.target_list = list;
  219.     };
  220.  
  221.     var shouldShowTargetList = function (editorSettings) {
  222.       return getTargetList(editorSettings) !== false;
  223.     };
  224.  
  225.     var getRelList = function (editorSettings) {
  226.       return editorSettings.rel_list;
  227.     };
  228.  
  229.     var hasRelList = function (editorSettings) {
  230.       return getRelList(editorSettings) !== undefined;
  231.     };
  232.  
  233.     var getLinkClassList = function (editorSettings) {
  234.       return editorSettings.link_class_list;
  235.     };
  236.  
  237.     var hasLinkClassList = function (editorSettings) {
  238.       return getLinkClassList(editorSettings) !== undefined;
  239.     };
  240.  
  241.     var shouldShowLinkTitle = function (editorSettings) {
  242.       return editorSettings.link_title !== false;
  243.     };
  244.  
  245.     var allowUnsafeLinkTarget = function (editorSettings) {
  246.       return typeof editorSettings.allow_unsafe_link_target === 'boolean' ? editorSettings.allow_unsafe_link_target : false;
  247.     };
  248.  
  249.     return {
  250.       assumeExternalTargets: assumeExternalTargets,
  251.       hasContextToolbar: hasContextToolbar,
  252.       getLinkList: getLinkList,
  253.       hasDefaultLinkTarget: hasDefaultLinkTarget,
  254.       getDefaultLinkTarget: getDefaultLinkTarget,
  255.       getTargetList: getTargetList,
  256.       setTargetList: setTargetList,
  257.       shouldShowTargetList: shouldShowTargetList,
  258.       getRelList: getRelList,
  259.       hasRelList: hasRelList,
  260.       getLinkClassList: getLinkClassList,
  261.       hasLinkClassList: hasLinkClassList,
  262.       shouldShowLinkTitle: shouldShowLinkTitle,
  263.       allowUnsafeLinkTarget: allowUnsafeLinkTarget
  264.     };
  265.   }
  266. );
  267.  
  268. defineGlobal("global!RegExp", RegExp);
  269. /**
  270.  * Utils.js
  271.  *
  272.  * Released under LGPL License.
  273.  * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
  274.  *
  275.  * License: http://www.tinymce.com/license
  276.  * Contributing: http://www.tinymce.com/contributing
  277.  */
  278.  
  279. define(
  280.   'tinymce.plugins.link.core.Utils',
  281.   [
  282.     'tinymce.core.util.Tools',
  283.     'tinymce.plugins.link.core.Settings',
  284.     'global!RegExp'
  285.   ],
  286.   function (Tools, Settings, RegExp) {
  287.  
  288.     var toggleTargetRules = function (rel, isUnsafe) {
  289.       var rules = ['noopener'];
  290.       var newRel = rel ? rel.split(/\s+/) : [];
  291.  
  292.       var toString = function (rel) {
  293.         return Tools.trim(rel.sort().join(' '));
  294.       };
  295.  
  296.       var addTargetRules = function (rel) {
  297.         rel = removeTargetRules(rel);
  298.         return rel.length ? rel.concat(rules) : rules;
  299.       };
  300.  
  301.       var removeTargetRules = function (rel) {
  302.         return rel.filter(function (val) {
  303.           return Tools.inArray(rules, val) === -1;
  304.         });
  305.       };
  306.  
  307.       newRel = isUnsafe ? addTargetRules(newRel) : removeTargetRules(newRel);
  308.       return newRel.length ? toString(newRel) : null;
  309.     };
  310.  
  311.  
  312.     var trimCaretContainers = function (text) {
  313.       return text.replace(/\uFEFF/g, '');
  314.     };
  315.  
  316.  
  317.     var getAnchorElement = function (editor, selectedElm) {
  318.       selectedElm = selectedElm || editor.selection.getStart();
  319.       if (isImageFigure(selectedElm)) {
  320.         // for an image conained in a figure we look for a link inside the selected element
  321.         return editor.dom.select('a[href]', selectedElm)[0];
  322.       } else {
  323.         return editor.dom.getParent(selectedElm, 'a[href]');
  324.       }
  325.     };
  326.  
  327.  
  328.     var getAnchorText = function (selection, anchorElm) {
  329.       var text = anchorElm ? (anchorElm.innerText || anchorElm.textContent) : selection.getContent({ format: 'text' });
  330.       return trimCaretContainers(text);
  331.     };
  332.  
  333.  
  334.     var isLink = function (elm) {
  335.       return elm && elm.nodeName === 'A' && elm.href;
  336.     };
  337.  
  338.     var hasLinks = function (elements) {
  339.       return Tools.grep(elements, isLink).length > 0;
  340.     };
  341.  
  342.  
  343.     var isOnlyTextSelected = function (html) {
  344.       // Partial html and not a fully selected anchor element
  345.       if (/</.test(html) && (!/^<a [^>]+>[^<]+<\/a>$/.test(html) || html.indexOf('href=') == -1)) {
  346.         return false;
  347.       }
  348.  
  349.       return true;
  350.     };
  351.  
  352.  
  353.     var isImageFigure = function (node) {
  354.       return node && node.nodeName === 'FIGURE' && /\bimage\b/i.test(node.className);
  355.     };
  356.  
  357.  
  358.     var link = function (editor, attachState) {
  359.       return function (data) {
  360.         editor.undoManager.transact(function () {
  361.           var selectedElm = editor.selection.getNode();
  362.           var anchorElm = getAnchorElement(editor, selectedElm);
  363.  
  364.           var linkAttrs = {
  365.             href: data.href,
  366.             target: data.target ? data.target : null,
  367.             rel: data.rel ? data.rel : null,
  368.             "class": data["class"] ? data["class"] : null,
  369.             title: data.title ? data.title : null
  370.           };
  371.  
  372.           if (!Settings.hasRelList(editor.settings) && Settings.allowUnsafeLinkTarget(editor.settings) === false) {
  373.             linkAttrs.rel = toggleTargetRules(linkAttrs.rel, linkAttrs.target == '_blank');
  374.           }
  375.  
  376.           if (data.href === attachState.href) {
  377.             attachState.attach();
  378.             attachState = {};
  379.           }
  380.  
  381.           if (anchorElm) {
  382.             editor.focus();
  383.  
  384.             if (data.hasOwnProperty('text')) {
  385.               if ("innerText" in anchorElm) {
  386.                 anchorElm.innerText = data.text;
  387.               } else {
  388.                 anchorElm.textContent = data.text;
  389.               }
  390.             }
  391.  
  392.             editor.dom.setAttribs(anchorElm, linkAttrs);
  393.  
  394.             editor.selection.select(anchorElm);
  395.             editor.undoManager.add();
  396.           } else {
  397.             if (isImageFigure(selectedElm)) {
  398.               linkImageFigure(editor, selectedElm, linkAttrs);
  399.             } else if (data.hasOwnProperty('text')) {
  400.               editor.insertContent(editor.dom.createHTML('a', linkAttrs, editor.dom.encode(data.text)));
  401.             } else {
  402.               editor.execCommand('mceInsertLink', false, linkAttrs);
  403.             }
  404.           }
  405.         });
  406.       };
  407.     };
  408.  
  409.  
  410.     var unlink = function (editor) {
  411.       return function () {
  412.         editor.undoManager.transact(function () {
  413.           var node = editor.selection.getNode();
  414.           if (isImageFigure(node)) {
  415.             unlinkImageFigure(editor, node);
  416.           } else {
  417.             editor.execCommand('unlink');
  418.           }
  419.         });
  420.       };
  421.     };
  422.  
  423.  
  424.     var unlinkImageFigure = function (editor, fig) {
  425.       var a, img;
  426.       img = editor.dom.select('img', fig)[0];
  427.       if (img) {
  428.         a = editor.dom.getParents(img, 'a[href]', fig)[0];
  429.         if (a) {
  430.           a.parentNode.insertBefore(img, a);
  431.           editor.dom.remove(a);
  432.         }
  433.       }
  434.     };
  435.  
  436.  
  437.     var linkImageFigure = function (editor, fig, attrs) {
  438.       var a, img;
  439.       img = editor.dom.select('img', fig)[0];
  440.       if (img) {
  441.         a = editor.dom.create('a', attrs);
  442.         img.parentNode.insertBefore(a, img);
  443.         a.appendChild(img);
  444.       }
  445.     };
  446.  
  447.     return {
  448.       link: link,
  449.       unlink: unlink,
  450.       isLink: isLink,
  451.       hasLinks: hasLinks,
  452.       isOnlyTextSelected: isOnlyTextSelected,
  453.       getAnchorElement: getAnchorElement,
  454.       getAnchorText: getAnchorText,
  455.       toggleTargetRules: toggleTargetRules
  456.     };
  457.   }
  458. );
  459. /**
  460.  * Dialog.js
  461.  *
  462.  * Released under LGPL License.
  463.  * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
  464.  *
  465.  * License: http://www.tinymce.com/license
  466.  * Contributing: http://www.tinymce.com/contributing
  467.  */
  468.  
  469. define(
  470.   'tinymce.plugins.link.ui.Dialog',
  471.   [
  472.     'tinymce.core.util.Delay',
  473.     'tinymce.core.util.Tools',
  474.     'tinymce.core.util.XHR',
  475.     'tinymce.plugins.link.core.Utils',
  476.     'tinymce.plugins.link.core.Settings'
  477.   ],
  478.   function (Delay, Tools, XHR, Utils, Settings) {
  479.     var attachState = {};
  480.  
  481.     var createLinkList = function (editor, callback) {
  482.       var linkList = Settings.getLinkList(editor.settings);
  483.  
  484.       if (typeof linkList == "string") {
  485.         XHR.send({
  486.           url: linkList,
  487.           success: function (text) {
  488.             callback(editor, JSON.parse(text));
  489.           }
  490.         });
  491.       } else if (typeof linkList == "function") {
  492.         linkList(function (list) {
  493.           callback(editor, list);
  494.         });
  495.       } else {
  496.         callback(editor, linkList);
  497.       }
  498.     };
  499.  
  500.     var buildListItems = function (inputList, itemCallback, startItems) {
  501.       var appendItems = function (values, output) {
  502.         output = output || [];
  503.  
  504.         Tools.each(values, function (item) {
  505.           var menuItem = { text: item.text || item.title };
  506.  
  507.           if (item.menu) {
  508.             menuItem.menu = appendItems(item.menu);
  509.           } else {
  510.             menuItem.value = item.value;
  511.  
  512.             if (itemCallback) {
  513.               itemCallback(menuItem);
  514.             }
  515.           }
  516.  
  517.           output.push(menuItem);
  518.         });
  519.  
  520.         return output;
  521.       };
  522.  
  523.       return appendItems(inputList, startItems || []);
  524.     };
  525.  
  526.     // Delay confirm since onSubmit will move focus
  527.     var delayedConfirm = function (editor, message, callback) {
  528.       var rng = editor.selection.getRng();
  529.  
  530.       Delay.setEditorTimeout(editor, function () {
  531.         editor.windowManager.confirm(message, function (state) {
  532.           editor.selection.setRng(rng);
  533.           callback(state);
  534.         });
  535.       });
  536.     };
  537.  
  538.     var showDialog = function (editor, linkList) {
  539.       var data = {}, selection = editor.selection, dom = editor.dom, anchorElm, initialText;
  540.       var win, onlyText, textListCtrl, linkListCtrl, relListCtrl, targetListCtrl, classListCtrl, linkTitleCtrl, value;
  541.  
  542.       var linkListChangeHandler = function (e) {
  543.         var textCtrl = win.find('#text');
  544.  
  545.         if (!textCtrl.value() || (e.lastControl && textCtrl.value() == e.lastControl.text())) {
  546.           textCtrl.value(e.control.text());
  547.         }
  548.  
  549.         win.find('#href').value(e.control.value());
  550.       };
  551.  
  552.       var buildAnchorListControl = function (url) {
  553.         var anchorList = [];
  554.  
  555.         Tools.each(editor.dom.select('a:not([href])'), function (anchor) {
  556.           var id = anchor.name || anchor.id;
  557.  
  558.           if (id) {
  559.             anchorList.push({
  560.               text: id,
  561.               value: '#' + id,
  562.               selected: url.indexOf('#' + id) != -1
  563.             });
  564.           }
  565.         });
  566.  
  567.         if (anchorList.length) {
  568.           anchorList.unshift({ text: 'None', value: '' });
  569.  
  570.           return {
  571.             name: 'anchor',
  572.             type: 'listbox',
  573.             label: 'Anchors',
  574.             values: anchorList,
  575.             onselect: linkListChangeHandler
  576.           };
  577.         }
  578.       };
  579.  
  580.       var updateText = function () {
  581.         if (!initialText && onlyText && !data.text) {
  582.           this.parent().parent().find('#text')[0].value(this.value());
  583.         }
  584.       };
  585.  
  586.       var urlChange = function (e) {
  587.         var meta = e.meta || {};
  588.  
  589.         if (linkListCtrl) {
  590.           linkListCtrl.value(editor.convertURL(this.value(), 'href'));
  591.         }
  592.  
  593.         Tools.each(e.meta, function (value, key) {
  594.           var inp = win.find('#' + key);
  595.  
  596.           if (key === 'text') {
  597.             if (initialText.length === 0) {
  598.               inp.value(value);
  599.               data.text = value;
  600.             }
  601.           } else {
  602.             inp.value(value);
  603.           }
  604.         });
  605.  
  606.         if (meta.attach) {
  607.           attachState = {
  608.             href: this.value(),
  609.             attach: meta.attach
  610.           };
  611.         }
  612.  
  613.         if (!meta.text) {
  614.           updateText.call(this);
  615.         }
  616.       };
  617.  
  618.       var onBeforeCall = function (e) {
  619.         e.meta = win.toJSON();
  620.       };
  621.  
  622.       onlyText = Utils.isOnlyTextSelected(selection.getContent());
  623.       anchorElm = Utils.getAnchorElement(editor);
  624.  
  625.       data.text = initialText = Utils.getAnchorText(editor.selection, anchorElm);
  626.       data.href = anchorElm ? dom.getAttrib(anchorElm, 'href') : '';
  627.  
  628.       if (anchorElm) {
  629.         data.target = dom.getAttrib(anchorElm, 'target');
  630.       } else if (Settings.hasDefaultLinkTarget(editor.settings)) {
  631.         data.target = Settings.getDefaultLinkTarget(editor.settings);
  632.       }
  633.  
  634.       if ((value = dom.getAttrib(anchorElm, 'rel'))) {
  635.         data.rel = value;
  636.       }
  637.  
  638.       if ((value = dom.getAttrib(anchorElm, 'class'))) {
  639.         data['class'] = value;
  640.       }
  641.  
  642.       if ((value = dom.getAttrib(anchorElm, 'title'))) {
  643.         data.title = value;
  644.       }
  645.  
  646.       if (onlyText) {
  647.         textListCtrl = {
  648.           name: 'text',
  649.           type: 'textbox',
  650.           size: 40,
  651.           label: 'Text to display',
  652.           onchange: function () {
  653.             data.text = this.value();
  654.           }
  655.         };
  656.       }
  657.  
  658.       if (linkList) {
  659.         linkListCtrl = {
  660.           type: 'listbox',
  661.           label: 'Link list',
  662.           values: buildListItems(
  663.             linkList,
  664.             function (item) {
  665.               item.value = editor.convertURL(item.value || item.url, 'href');
  666.             },
  667.             [{ text: 'None', value: '' }]
  668.           ),
  669.           onselect: linkListChangeHandler,
  670.           value: editor.convertURL(data.href, 'href'),
  671.           onPostRender: function () {
  672.             /*eslint consistent-this:0*/
  673.             linkListCtrl = this;
  674.           }
  675.         };
  676.       }
  677.  
  678.       if (Settings.shouldShowTargetList(editor.settings)) {
  679.         if (Settings.getTargetList(editor.settings) === undefined) {
  680.           Settings.setTargetList(editor, [
  681.             { text: 'None', value: '' },
  682.             { text: 'New window', value: '_blank' }
  683.           ]);
  684.         }
  685.  
  686.         targetListCtrl = {
  687.           name: 'target',
  688.           type: 'listbox',
  689.           label: 'Target',
  690.           values: buildListItems(Settings.getTargetList(editor.settings))
  691.         };
  692.       }
  693.  
  694.       if (Settings.hasRelList(editor.settings)) {
  695.         relListCtrl = {
  696.           name: 'rel',
  697.           type: 'listbox',
  698.           label: 'Rel',
  699.           values: buildListItems(
  700.             Settings.getRelList(editor.settings),
  701.             function (item) {
  702.               if (Settings.allowUnsafeLinkTarget(editor.settings) === false) {
  703.                 item.value = Utils.toggleTargetRules(item.value, data.target === '_blank');
  704.               }
  705.             }
  706.           )
  707.         };
  708.       }
  709.  
  710.       if (Settings.hasLinkClassList(editor.settings)) {
  711.         classListCtrl = {
  712.           name: 'class',
  713.           type: 'listbox',
  714.           label: 'Class',
  715.           values: buildListItems(
  716.             Settings.getLinkClassList(editor.settings),
  717.             function (item) {
  718.               if (item.value) {
  719.                 item.textStyle = function () {
  720.                   return editor.formatter.getCssText({ inline: 'a', classes: [item.value] });
  721.                 };
  722.               }
  723.             }
  724.           )
  725.         };
  726.       }
  727.  
  728.       if (Settings.shouldShowLinkTitle(editor.settings)) {
  729.         linkTitleCtrl = {
  730.           name: 'title',
  731.           type: 'textbox',
  732.           label: 'Title',
  733.           value: data.title
  734.         };
  735.       }
  736.  
  737.       win = editor.windowManager.open({
  738.         title: 'Insert link',
  739.         data: data,
  740.         body: [
  741.           {
  742.             name: 'href',
  743.             type: 'filepicker',
  744.             filetype: 'file',
  745.             size: 40,
  746.             autofocus: true,
  747.             label: 'Url',
  748.             onchange: urlChange,
  749.             onkeyup: updateText,
  750.             onbeforecall: onBeforeCall
  751.           },
  752.           textListCtrl,
  753.           linkTitleCtrl,
  754.           buildAnchorListControl(data.href),
  755.           linkListCtrl,
  756.           relListCtrl,
  757.           targetListCtrl,
  758.           classListCtrl
  759.         ],
  760.         onSubmit: function (e) {
  761.           var assumeExternalTargets = Settings.assumeExternalTargets(editor.settings);
  762.           var insertLink = Utils.link(editor, attachState);
  763.           var removeLink = Utils.unlink(editor);
  764.  
  765.           var resultData = Tools.extend({}, data, e.data);
  766.           /*eslint dot-notation: 0*/
  767.           var href = resultData.href;
  768.  
  769.           if (!href) {
  770.             removeLink();
  771.             return;
  772.           }
  773.  
  774.           if (!onlyText || resultData.text === initialText) {
  775.             delete resultData.text;
  776.           }
  777.  
  778.           // Is email and not //user@domain.com
  779.           if (href.indexOf('@') > 0 && href.indexOf('//') == -1 && href.indexOf('mailto:') == -1) {
  780.             delayedConfirm(
  781.               editor,
  782.               'The URL you entered seems to be an email address. Do you want to add the required mailto: prefix?',
  783.               function (state) {
  784.                 if (state) {
  785.                   resultData.href = 'mailto:' + href;
  786.                 }
  787.                 insertLink(resultData);
  788.               }
  789.             );
  790.             return;
  791.           }
  792.  
  793.           // Is not protocol prefixed
  794.           if ((assumeExternalTargets === true && !/^\w+:/i.test(href)) ||
  795.             (assumeExternalTargets === false && /^\s*www[\.|\d\.]/i.test(href))) {
  796.             delayedConfirm(
  797.               editor,
  798.               'The URL you entered seems to be an external link. Do you want to add the required http:// prefix?',
  799.               function (state) {
  800.                 if (state) {
  801.                   resultData.href = 'http://' + href;
  802.                 }
  803.                 insertLink(resultData);
  804.               }
  805.             );
  806.             return;
  807.           }
  808.  
  809.           insertLink(resultData);
  810.         }
  811.       });
  812.     };
  813.  
  814.     var open = function (editor) {
  815.       createLinkList(editor, showDialog);
  816.     };
  817.  
  818.     return {
  819.       open: open
  820.     };
  821.   }
  822. );
  823. /**
  824.  * ResolveGlobal.js
  825.  *
  826.  * Released under LGPL License.
  827.  * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
  828.  *
  829.  * License: http://www.tinymce.com/license
  830.  * Contributing: http://www.tinymce.com/contributing
  831.  */
  832.  
  833. define(
  834.   'tinymce.core.dom.DOMUtils',
  835.   [
  836.     'global!tinymce.util.Tools.resolve'
  837.   ],
  838.   function (resolve) {
  839.     return resolve('tinymce.dom.DOMUtils');
  840.   }
  841. );
  842.  
  843. /**
  844.  * ResolveGlobal.js
  845.  *
  846.  * Released under LGPL License.
  847.  * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
  848.  *
  849.  * License: http://www.tinymce.com/license
  850.  * Contributing: http://www.tinymce.com/contributing
  851.  */
  852.  
  853. define(
  854.   'tinymce.core.Env',
  855.   [
  856.     'global!tinymce.util.Tools.resolve'
  857.   ],
  858.   function (resolve) {
  859.     return resolve('tinymce.Env');
  860.   }
  861. );
  862.  
  863. /**
  864.  * OpenUrl.js
  865.  *
  866.  * Released under LGPL License.
  867.  * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
  868.  *
  869.  * License: http://www.tinymce.com/license
  870.  * Contributing: http://www.tinymce.com/contributing
  871.  */
  872.  
  873. define(
  874.   'tinymce.plugins.link.core.OpenUrl',
  875.   [
  876.     'tinymce.core.dom.DOMUtils',
  877.     'tinymce.core.Env'
  878.   ],
  879.   function (DOMUtils, Env) {
  880.     var appendClickRemove = function (link, evt) {
  881.       document.body.appendChild(link);
  882.       link.dispatchEvent(evt);
  883.       document.body.removeChild(link);
  884.     };
  885.  
  886.     var open = function (url) {
  887.       // Chrome and Webkit has implemented noopener and works correctly with/without popup blocker
  888.       // Firefox has it implemented noopener but when the popup blocker is activated it doesn't work
  889.       // Edge has only implemented noreferrer and it seems to remove opener as well
  890.       // Older IE versions pre IE 11 falls back to a window.open approach
  891.       if (!Env.ie || Env.ie > 10) {
  892.         var link = document.createElement('a');
  893.         link.target = '_blank';
  894.         link.href = url;
  895.         link.rel = 'noreferrer noopener';
  896.  
  897.         var evt = document.createEvent('MouseEvents');
  898.         evt.initMouseEvent('click', true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
  899.  
  900.         appendClickRemove(link, evt);
  901.       } else {
  902.         var win = window.open('', '_blank');
  903.         if (win) {
  904.           win.opener = null;
  905.           var doc = win.document;
  906.           doc.open();
  907.           doc.write('<meta http-equiv="refresh" content="0; url=' + DOMUtils.DOM.encode(url) + '">');
  908.           doc.close();
  909.         }
  910.       }
  911.     };
  912.  
  913.     return {
  914.       open: open
  915.     };
  916.   }
  917. );
  918. /**
  919.  * Actions.js
  920.  *
  921.  * Released under LGPL License.
  922.  * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
  923.  *
  924.  * License: http://www.tinymce.com/license
  925.  * Contributing: http://www.tinymce.com/contributing
  926.  */
  927.  
  928. define(
  929.   'tinymce.plugins.link.core.Actions',
  930.   [
  931.     'tinymce.core.util.VK',
  932.     'tinymce.plugins.link.ui.Dialog',
  933.     'tinymce.plugins.link.core.OpenUrl',
  934.     'tinymce.plugins.link.core.Utils',
  935.     'tinymce.plugins.link.core.Settings'
  936.   ],
  937.   function (VK, Dialog, OpenUrl, Utils, Settings) {
  938.     var getLink = function (editor, elm) {
  939.       return editor.dom.getParent(elm, 'a[href]');
  940.     };
  941.  
  942.     var getSelectedLink = function (editor) {
  943.       return getLink(editor, editor.selection.getStart());
  944.     };
  945.  
  946.     var getHref = function (elm) {
  947.       // Returns the real href value not the resolved a.href value
  948.       var href = elm.getAttribute('data-mce-href');
  949.       return href ? href : elm.getAttribute('href');
  950.     };
  951.  
  952.     var isContextMenuVisible = function (editor) {
  953.       var contextmenu = editor.plugins.contextmenu;
  954.       return contextmenu ? contextmenu.isContextMenuVisible() : false;
  955.     };
  956.  
  957.     var hasOnlyAltModifier = function (e) {
  958.       return e.altKey === true && e.shiftKey === false && e.ctrlKey === false && e.metaKey === false;
  959.     };
  960.  
  961.     var gotoLink = function (editor, a) {
  962.       if (a) {
  963.         var href = getHref(a);
  964.         if (/^#/.test(href)) {
  965.           var targetEl = editor.$(href);
  966.           if (targetEl.length) {
  967.             editor.selection.scrollIntoView(targetEl[0], true);
  968.           }
  969.         } else {
  970.           OpenUrl.open(a.href);
  971.         }
  972.       }
  973.     };
  974.  
  975.     var openDialog = function (editor) {
  976.       return function () {
  977.         Dialog.open(editor);
  978.       };
  979.     };
  980.  
  981.     var gotoSelectedLink = function (editor) {
  982.       return function () {
  983.         gotoLink(editor, getSelectedLink(editor));
  984.       };
  985.     };
  986.  
  987.     var leftClickedOnAHref = function (editor) {
  988.       return function (elm) {
  989.         var sel, rng, node;
  990.         if (Settings.hasContextToolbar(editor.settings) && !isContextMenuVisible(editor) && Utils.isLink(elm)) {
  991.           sel = editor.selection;
  992.           rng = sel.getRng();
  993.           node = rng.startContainer;
  994.           // ignore cursor positions at the beginning/end (to make context toolbar less noisy)
  995.           if (node.nodeType == 3 && sel.isCollapsed() && rng.startOffset > 0 && rng.startOffset < node.data.length) {
  996.             return true;
  997.           }
  998.         }
  999.         return false;
  1000.       };
  1001.     };
  1002.  
  1003.     var setupGotoLinks = function (editor) {
  1004.       editor.on('click', function (e) {
  1005.         var link = getLink(editor, e.target);
  1006.         if (link && VK.metaKeyPressed(e)) {
  1007.           e.preventDefault();
  1008.           gotoLink(editor, link);
  1009.         }
  1010.       });
  1011.  
  1012.       editor.on('keydown', function (e) {
  1013.         var link = getSelectedLink(editor);
  1014.         if (link && e.keyCode === 13 && hasOnlyAltModifier(e)) {
  1015.           e.preventDefault();
  1016.           gotoLink(editor, link);
  1017.         }
  1018.       });
  1019.     };
  1020.  
  1021.     var toggleActiveState = function (editor) {
  1022.       return function () {
  1023.         var self = this;
  1024.         editor.on('nodechange', function (e) {
  1025.           self.active(!editor.readonly && !!Utils.getAnchorElement(editor, e.element));
  1026.         });
  1027.       };
  1028.     };
  1029.  
  1030.     var toggleViewLinkState = function (editor) {
  1031.       return function () {
  1032.         var self = this;
  1033.  
  1034.         var toggleVisibility = function (e) {
  1035.           if (Utils.hasLinks(e.parents)) {
  1036.             self.show();
  1037.           } else {
  1038.             self.hide();
  1039.           }
  1040.         };
  1041.  
  1042.         if (!Utils.hasLinks(editor.dom.getParents(editor.selection.getStart()))) {
  1043.           self.hide();
  1044.         }
  1045.  
  1046.         editor.on('nodechange', toggleVisibility);
  1047.  
  1048.         self.on('remove', function () {
  1049.           editor.off('nodechange', toggleVisibility);
  1050.         });
  1051.       };
  1052.     };
  1053.  
  1054.     return {
  1055.       openDialog: openDialog,
  1056.       gotoSelectedLink: gotoSelectedLink,
  1057.       leftClickedOnAHref: leftClickedOnAHref,
  1058.       setupGotoLinks: setupGotoLinks,
  1059.       toggleActiveState: toggleActiveState,
  1060.       toggleViewLinkState: toggleViewLinkState
  1061.     };
  1062.   }
  1063. );
  1064. /**
  1065.  * Controls.js
  1066.  *
  1067.  * Released under LGPL License.
  1068.  * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
  1069.  *
  1070.  * License: http://www.tinymce.com/license
  1071.  * Contributing: http://www.tinymce.com/contributing
  1072.  */
  1073.  
  1074. define(
  1075.   'tinymce.plugins.link.ui.Controls',
  1076.   [
  1077.     'tinymce.plugins.link.core.Actions',
  1078.     'tinymce.plugins.link.core.Utils'
  1079.   ],
  1080.   function (Actions, Utils) {
  1081.  
  1082.     var setupButtons = function (editor) {
  1083.       editor.addButton('link', {
  1084.         icon: 'link',
  1085.         tooltip: 'Insert/edit link',
  1086.         shortcut: 'Meta+K',
  1087.         onclick: Actions.openDialog(editor),
  1088.         onpostrender: Actions.toggleActiveState(editor)
  1089.       });
  1090.  
  1091.       editor.addButton('unlink', {
  1092.         icon: 'unlink',
  1093.         tooltip: 'Remove link',
  1094.         onclick: Utils.unlink(editor),
  1095.         onpostrender: Actions.toggleActiveState(editor)
  1096.       });
  1097.  
  1098.       if (editor.addContextToolbar) {
  1099.         editor.addButton('openlink', {
  1100.           icon: 'newtab',
  1101.           tooltip: 'Open link',
  1102.           onclick: Actions.gotoSelectedLink(editor)
  1103.         });
  1104.       }
  1105.     };
  1106.  
  1107.     var setupMenuItems = function (editor) {
  1108.       editor.addMenuItem('openlink', {
  1109.         text: 'Open link',
  1110.         icon: 'newtab',
  1111.         onclick: Actions.gotoSelectedLink(editor),
  1112.         onPostRender: Actions.toggleViewLinkState(editor),
  1113.         prependToContext: true
  1114.       });
  1115.  
  1116.       editor.addMenuItem('link', {
  1117.         icon: 'link',
  1118.         text: 'Link',
  1119.         shortcut: 'Meta+K',
  1120.         onclick: Actions.openDialog(editor),
  1121.         stateSelector: 'a[href]',
  1122.         context: 'insert',
  1123.         prependToContext: true
  1124.       });
  1125.     };
  1126.  
  1127.     var setupContextToolbars = function (editor) {
  1128.       if (editor.addContextToolbar) {
  1129.         editor.addContextToolbar(
  1130.           Actions.leftClickedOnAHref(editor),
  1131.           'openlink | link unlink'
  1132.         );
  1133.       }
  1134.     };
  1135.  
  1136.     return {
  1137.       setupButtons: setupButtons,
  1138.       setupMenuItems: setupMenuItems,
  1139.       setupContextToolbars: setupContextToolbars
  1140.     };
  1141.   }
  1142. );
  1143. /**
  1144.  * Plugin.js
  1145.  *
  1146.  * Released under LGPL License.
  1147.  * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
  1148.  *
  1149.  * License: http://www.tinymce.com/license
  1150.  * Contributing: http://www.tinymce.com/contributing
  1151.  */
  1152.  
  1153. define(
  1154.   'tinymce.plugins.link.Plugin',
  1155.   [
  1156.     'tinymce.core.PluginManager',
  1157.     'tinymce.plugins.link.core.Actions',
  1158.     'tinymce.plugins.link.ui.Controls'
  1159.   ],
  1160.   function (PluginManager, Actions, Controls) {
  1161.     PluginManager.add('link', function (editor) {
  1162.       Controls.setupButtons(editor);
  1163.       Controls.setupMenuItems(editor);
  1164.       Controls.setupContextToolbars(editor);
  1165.       Actions.setupGotoLinks(editor);
  1166.       editor.addShortcut('Meta+K', '', Actions.openDialog(editor));
  1167.       editor.addCommand('mceLink', Actions.openDialog(editor));
  1168.     });
  1169.  
  1170.     return function () { };
  1171.   }
  1172. );
  1173. dem('tinymce.plugins.link.Plugin')();
  1174. })();
  1175.