plugin.js 42 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384
  1. /**
  2. * Copyright (c) Tiny Technologies, Inc. All rights reserved.
  3. * Licensed under the LGPL or a commercial license.
  4. * For LGPL see License.txt in the project root for license information.
  5. * For commercial licenses see https://www.tiny.cloud/
  6. *
  7. * Version: 5.0.7 (2019-06-05)
  8. */
  9. (function () {
  10. var link = (function (domGlobals) {
  11. 'use strict';
  12. var global = tinymce.util.Tools.resolve('tinymce.PluginManager');
  13. var global$1 = tinymce.util.Tools.resolve('tinymce.util.VK');
  14. var assumeExternalTargets = function (editorSettings) {
  15. var externalTargets = editorSettings.link_assume_external_targets;
  16. if (typeof externalTargets === 'boolean' && externalTargets) {
  17. return 1;
  18. } else if (typeof externalTargets === 'string' && (externalTargets === 'http' || externalTargets === 'https')) {
  19. return externalTargets;
  20. }
  21. return 0;
  22. };
  23. var hasContextToolbar = function (editorSettings) {
  24. return typeof editorSettings.link_context_toolbar === 'boolean' ? editorSettings.link_context_toolbar : false;
  25. };
  26. var getLinkList = function (editorSettings) {
  27. return editorSettings.link_list;
  28. };
  29. var hasDefaultLinkTarget = function (editorSettings) {
  30. return typeof editorSettings.default_link_target === 'string';
  31. };
  32. var useQuickLink = function (editorSettings) {
  33. return editorSettings.link_quicklink === true;
  34. };
  35. var getDefaultLinkTarget = function (editorSettings) {
  36. return editorSettings.default_link_target;
  37. };
  38. var getTargetList = function (editorSettings) {
  39. return editorSettings.target_list;
  40. };
  41. var setTargetList = function (editor, list) {
  42. editor.settings.target_list = list;
  43. };
  44. var shouldShowTargetList = function (editorSettings) {
  45. return getTargetList(editorSettings) !== false;
  46. };
  47. var getRelList = function (editorSettings) {
  48. return editorSettings.rel_list;
  49. };
  50. var hasRelList = function (editorSettings) {
  51. return getRelList(editorSettings) !== undefined;
  52. };
  53. var getLinkClassList = function (editorSettings) {
  54. return editorSettings.link_class_list;
  55. };
  56. var hasLinkClassList = function (editorSettings) {
  57. return getLinkClassList(editorSettings) !== undefined;
  58. };
  59. var shouldShowLinkTitle = function (editorSettings) {
  60. return editorSettings.link_title !== false;
  61. };
  62. var allowUnsafeLinkTarget = function (editorSettings) {
  63. return typeof editorSettings.allow_unsafe_link_target === 'boolean' ? editorSettings.allow_unsafe_link_target : false;
  64. };
  65. var Settings = {
  66. assumeExternalTargets: assumeExternalTargets,
  67. hasContextToolbar: hasContextToolbar,
  68. getLinkList: getLinkList,
  69. hasDefaultLinkTarget: hasDefaultLinkTarget,
  70. getDefaultLinkTarget: getDefaultLinkTarget,
  71. getTargetList: getTargetList,
  72. setTargetList: setTargetList,
  73. shouldShowTargetList: shouldShowTargetList,
  74. getRelList: getRelList,
  75. hasRelList: hasRelList,
  76. getLinkClassList: getLinkClassList,
  77. hasLinkClassList: hasLinkClassList,
  78. shouldShowLinkTitle: shouldShowLinkTitle,
  79. allowUnsafeLinkTarget: allowUnsafeLinkTarget,
  80. useQuickLink: useQuickLink
  81. };
  82. var global$2 = tinymce.util.Tools.resolve('tinymce.dom.DOMUtils');
  83. var global$3 = tinymce.util.Tools.resolve('tinymce.Env');
  84. var appendClickRemove = function (link, evt) {
  85. domGlobals.document.body.appendChild(link);
  86. link.dispatchEvent(evt);
  87. domGlobals.document.body.removeChild(link);
  88. };
  89. var open = function (url) {
  90. if (!global$3.ie || global$3.ie > 10) {
  91. var link = domGlobals.document.createElement('a');
  92. link.target = '_blank';
  93. link.href = url;
  94. link.rel = 'noreferrer noopener';
  95. var evt = domGlobals.document.createEvent('MouseEvents');
  96. evt.initMouseEvent('click', true, true, domGlobals.window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
  97. appendClickRemove(link, evt);
  98. } else {
  99. var win = domGlobals.window.open('', '_blank');
  100. if (win) {
  101. win.opener = null;
  102. var doc = win.document;
  103. doc.open();
  104. doc.write('<meta http-equiv="refresh" content="0; url=' + global$2.DOM.encode(url) + '">');
  105. doc.close();
  106. }
  107. }
  108. };
  109. var OpenUrl = { open: open };
  110. var noop = function () {
  111. };
  112. var constant = function (value) {
  113. return function () {
  114. return value;
  115. };
  116. };
  117. var never = constant(false);
  118. var always = constant(true);
  119. var never$1 = never;
  120. var always$1 = always;
  121. var none = function () {
  122. return NONE;
  123. };
  124. var NONE = function () {
  125. var eq = function (o) {
  126. return o.isNone();
  127. };
  128. var call = function (thunk) {
  129. return thunk();
  130. };
  131. var id = function (n) {
  132. return n;
  133. };
  134. var noop = function () {
  135. };
  136. var nul = function () {
  137. return null;
  138. };
  139. var undef = function () {
  140. return undefined;
  141. };
  142. var me = {
  143. fold: function (n, s) {
  144. return n();
  145. },
  146. is: never$1,
  147. isSome: never$1,
  148. isNone: always$1,
  149. getOr: id,
  150. getOrThunk: call,
  151. getOrDie: function (msg) {
  152. throw new Error(msg || 'error: getOrDie called on none.');
  153. },
  154. getOrNull: nul,
  155. getOrUndefined: undef,
  156. or: id,
  157. orThunk: call,
  158. map: none,
  159. ap: none,
  160. each: noop,
  161. bind: none,
  162. flatten: none,
  163. exists: never$1,
  164. forall: always$1,
  165. filter: none,
  166. equals: eq,
  167. equals_: eq,
  168. toArray: function () {
  169. return [];
  170. },
  171. toString: constant('none()')
  172. };
  173. if (Object.freeze)
  174. Object.freeze(me);
  175. return me;
  176. }();
  177. var some = function (a) {
  178. var constant_a = function () {
  179. return a;
  180. };
  181. var self = function () {
  182. return me;
  183. };
  184. var map = function (f) {
  185. return some(f(a));
  186. };
  187. var bind = function (f) {
  188. return f(a);
  189. };
  190. var me = {
  191. fold: function (n, s) {
  192. return s(a);
  193. },
  194. is: function (v) {
  195. return a === v;
  196. },
  197. isSome: always$1,
  198. isNone: never$1,
  199. getOr: constant_a,
  200. getOrThunk: constant_a,
  201. getOrDie: constant_a,
  202. getOrNull: constant_a,
  203. getOrUndefined: constant_a,
  204. or: self,
  205. orThunk: self,
  206. map: map,
  207. ap: function (optfab) {
  208. return optfab.fold(none, function (fab) {
  209. return some(fab(a));
  210. });
  211. },
  212. each: function (f) {
  213. f(a);
  214. },
  215. bind: bind,
  216. flatten: constant_a,
  217. exists: bind,
  218. forall: bind,
  219. filter: function (f) {
  220. return f(a) ? me : NONE;
  221. },
  222. equals: function (o) {
  223. return o.is(a);
  224. },
  225. equals_: function (o, elementEq) {
  226. return o.fold(never$1, function (b) {
  227. return elementEq(a, b);
  228. });
  229. },
  230. toArray: function () {
  231. return [a];
  232. },
  233. toString: function () {
  234. return 'some(' + a + ')';
  235. }
  236. };
  237. return me;
  238. };
  239. var from = function (value) {
  240. return value === null || value === undefined ? NONE : some(value);
  241. };
  242. var Option = {
  243. some: some,
  244. none: none,
  245. from: from
  246. };
  247. var typeOf = function (x) {
  248. if (x === null)
  249. return 'null';
  250. var t = typeof x;
  251. if (t === 'object' && Array.prototype.isPrototypeOf(x))
  252. return 'array';
  253. if (t === 'object' && String.prototype.isPrototypeOf(x))
  254. return 'string';
  255. return t;
  256. };
  257. var isType = function (type) {
  258. return function (value) {
  259. return typeOf(value) === type;
  260. };
  261. };
  262. var isString = isType('string');
  263. var isFunction = isType('function');
  264. var slice = Array.prototype.slice;
  265. var rawIndexOf = function () {
  266. var pIndexOf = Array.prototype.indexOf;
  267. var fastIndex = function (xs, x) {
  268. return pIndexOf.call(xs, x);
  269. };
  270. var slowIndex = function (xs, x) {
  271. return slowIndexOf(xs, x);
  272. };
  273. return pIndexOf === undefined ? slowIndex : fastIndex;
  274. }();
  275. var contains = function (xs, x) {
  276. return rawIndexOf(xs, x) > -1;
  277. };
  278. var map = function (xs, f) {
  279. var len = xs.length;
  280. var r = new Array(len);
  281. for (var i = 0; i < len; i++) {
  282. var x = xs[i];
  283. r[i] = f(x, i, xs);
  284. }
  285. return r;
  286. };
  287. var each = function (xs, f) {
  288. for (var i = 0, len = xs.length; i < len; i++) {
  289. var x = xs[i];
  290. f(x, i, xs);
  291. }
  292. };
  293. var foldl = function (xs, f, acc) {
  294. each(xs, function (x) {
  295. acc = f(acc, x);
  296. });
  297. return acc;
  298. };
  299. var slowIndexOf = function (xs, x) {
  300. for (var i = 0, len = xs.length; i < len; ++i) {
  301. if (xs[i] === x) {
  302. return i;
  303. }
  304. }
  305. return -1;
  306. };
  307. var push = Array.prototype.push;
  308. var flatten = function (xs) {
  309. var r = [];
  310. for (var i = 0, len = xs.length; i < len; ++i) {
  311. if (!Array.prototype.isPrototypeOf(xs[i]))
  312. throw new Error('Arr.flatten item ' + i + ' was not an array, input: ' + xs);
  313. push.apply(r, xs[i]);
  314. }
  315. return r;
  316. };
  317. var bind = function (xs, f) {
  318. var output = map(xs, f);
  319. return flatten(output);
  320. };
  321. var from$1 = isFunction(Array.from) ? Array.from : function (x) {
  322. return slice.call(x);
  323. };
  324. var global$4 = tinymce.util.Tools.resolve('tinymce.util.Tools');
  325. var hasProtocol = function (url) {
  326. return /^\w+:/i.test(url);
  327. };
  328. var getHref = function (elm) {
  329. var href = elm.getAttribute('data-mce-href');
  330. return href ? href : elm.getAttribute('href');
  331. };
  332. var applyRelTargetRules = function (rel, isUnsafe) {
  333. var rules = ['noopener'];
  334. var rels = rel ? rel.split(/\s+/) : [];
  335. var toString = function (rels) {
  336. return global$4.trim(rels.sort().join(' '));
  337. };
  338. var addTargetRules = function (rels) {
  339. rels = removeTargetRules(rels);
  340. return rels.length > 0 ? rels.concat(rules) : rules;
  341. };
  342. var removeTargetRules = function (rels) {
  343. return rels.filter(function (val) {
  344. return global$4.inArray(rules, val) === -1;
  345. });
  346. };
  347. var newRels = isUnsafe ? addTargetRules(rels) : removeTargetRules(rels);
  348. return newRels.length > 0 ? toString(newRels) : '';
  349. };
  350. var trimCaretContainers = function (text) {
  351. return text.replace(/\uFEFF/g, '');
  352. };
  353. var getAnchorElement = function (editor, selectedElm) {
  354. selectedElm = selectedElm || editor.selection.getNode();
  355. if (isImageFigure(selectedElm)) {
  356. return editor.dom.select('a[href]', selectedElm)[0];
  357. } else {
  358. return editor.dom.getParent(selectedElm, 'a[href]');
  359. }
  360. };
  361. var getAnchorText = function (selection, anchorElm) {
  362. var text = anchorElm ? anchorElm.innerText || anchorElm.textContent : selection.getContent({ format: 'text' });
  363. return trimCaretContainers(text);
  364. };
  365. var isLink = function (elm) {
  366. return elm && elm.nodeName === 'A' && !!elm.href;
  367. };
  368. var hasLinks = function (elements) {
  369. return global$4.grep(elements, isLink).length > 0;
  370. };
  371. var isOnlyTextSelected = function (html) {
  372. if (/</.test(html) && (!/^<a [^>]+>[^<]+<\/a>$/.test(html) || html.indexOf('href=') === -1)) {
  373. return false;
  374. }
  375. return true;
  376. };
  377. var isImageFigure = function (elm) {
  378. return elm && elm.nodeName === 'FIGURE' && /\bimage\b/i.test(elm.className);
  379. };
  380. var getLinkAttrs = function (data) {
  381. return foldl([
  382. 'title',
  383. 'rel',
  384. 'class',
  385. 'target'
  386. ], function (acc, key) {
  387. data[key].each(function (value) {
  388. acc[key] = value.length > 0 ? value : null;
  389. });
  390. return acc;
  391. }, { href: data.href });
  392. };
  393. var handleExternalTargets = function (href, assumeExternalTargets) {
  394. if ((assumeExternalTargets === 'http' || assumeExternalTargets === 'https') && !hasProtocol(href)) {
  395. return assumeExternalTargets + '://' + href;
  396. }
  397. return href;
  398. };
  399. var updateLink = function (editor, anchorElm, text, linkAttrs) {
  400. text.each(function (text) {
  401. if (anchorElm.hasOwnProperty('innerText')) {
  402. anchorElm.innerText = text;
  403. } else {
  404. anchorElm.textContent = text;
  405. }
  406. });
  407. editor.dom.setAttribs(anchorElm, linkAttrs);
  408. editor.selection.select(anchorElm);
  409. };
  410. var createLink = function (editor, selectedElm, text, linkAttrs) {
  411. if (isImageFigure(selectedElm)) {
  412. linkImageFigure(editor, selectedElm, linkAttrs);
  413. } else {
  414. text.fold(function () {
  415. editor.execCommand('mceInsertLink', false, linkAttrs);
  416. }, function (text) {
  417. editor.insertContent(editor.dom.createHTML('a', linkAttrs, editor.dom.encode(text)));
  418. });
  419. }
  420. };
  421. var link = function (editor, attachState, data) {
  422. editor.undoManager.transact(function () {
  423. var selectedElm = editor.selection.getNode();
  424. var anchorElm = getAnchorElement(editor, selectedElm);
  425. var linkAttrs = getLinkAttrs(data);
  426. if (!Settings.hasRelList(editor.settings) && Settings.allowUnsafeLinkTarget(editor.settings) === false) {
  427. var newRel = applyRelTargetRules(linkAttrs.rel, linkAttrs.target === '_blank');
  428. linkAttrs.rel = newRel ? newRel : null;
  429. }
  430. linkAttrs.href = handleExternalTargets(linkAttrs.href, Settings.assumeExternalTargets(editor.settings));
  431. if (data.href === attachState.href) {
  432. attachState.attach();
  433. }
  434. if (anchorElm) {
  435. editor.focus();
  436. updateLink(editor, anchorElm, data.text, linkAttrs);
  437. } else {
  438. createLink(editor, selectedElm, data.text, linkAttrs);
  439. }
  440. });
  441. };
  442. var unlink = function (editor) {
  443. editor.undoManager.transact(function () {
  444. var node = editor.selection.getNode();
  445. if (isImageFigure(node)) {
  446. unlinkImageFigure(editor, node);
  447. } else {
  448. var anchorElm = editor.dom.getParent(node, 'a[href]', editor.getBody());
  449. if (anchorElm) {
  450. editor.dom.remove(anchorElm, true);
  451. }
  452. }
  453. editor.focus();
  454. });
  455. };
  456. var unlinkImageFigure = function (editor, fig) {
  457. var img = editor.dom.select('img', fig)[0];
  458. if (img) {
  459. var a = editor.dom.getParents(img, 'a[href]', fig)[0];
  460. if (a) {
  461. a.parentNode.insertBefore(img, a);
  462. editor.dom.remove(a);
  463. }
  464. }
  465. };
  466. var linkImageFigure = function (editor, fig, attrs) {
  467. var img = editor.dom.select('img', fig)[0];
  468. if (img) {
  469. var a = editor.dom.create('a', attrs);
  470. img.parentNode.insertBefore(a, img);
  471. a.appendChild(img);
  472. }
  473. };
  474. var Utils = {
  475. link: link,
  476. unlink: unlink,
  477. isLink: isLink,
  478. hasLinks: hasLinks,
  479. getHref: getHref,
  480. isOnlyTextSelected: isOnlyTextSelected,
  481. getAnchorElement: getAnchorElement,
  482. getAnchorText: getAnchorText,
  483. applyRelTargetRules: applyRelTargetRules,
  484. hasProtocol: hasProtocol
  485. };
  486. var cat = function (arr) {
  487. var r = [];
  488. var push = function (x) {
  489. r.push(x);
  490. };
  491. for (var i = 0; i < arr.length; i++) {
  492. arr[i].each(push);
  493. }
  494. return r;
  495. };
  496. var findMap = function (arr, f) {
  497. for (var i = 0; i < arr.length; i++) {
  498. var r = f(arr[i], i);
  499. if (r.isSome()) {
  500. return r;
  501. }
  502. }
  503. return Option.none();
  504. };
  505. var getValue = function (item) {
  506. return isString(item.value) ? item.value : '';
  507. };
  508. var sanitizeList = function (list, extractValue) {
  509. var out = [];
  510. global$4.each(list, function (item) {
  511. var text = isString(item.text) ? item.text : isString(item.title) ? item.title : '';
  512. if (item.menu !== undefined) ; else {
  513. var value = extractValue(item);
  514. out.push({
  515. text: text,
  516. value: value
  517. });
  518. }
  519. });
  520. return out;
  521. };
  522. var sanitizeWith = function (extracter) {
  523. if (extracter === void 0) {
  524. extracter = getValue;
  525. }
  526. return function (list) {
  527. return Option.from(list).map(function (list) {
  528. return sanitizeList(list, extracter);
  529. });
  530. };
  531. };
  532. var sanitize = function (list) {
  533. return sanitizeWith(getValue)(list);
  534. };
  535. var createUi = function (name, label) {
  536. return function (items) {
  537. return {
  538. name: name,
  539. type: 'selectbox',
  540. label: label,
  541. items: items
  542. };
  543. };
  544. };
  545. var ListOptions = {
  546. sanitize: sanitize,
  547. sanitizeWith: sanitizeWith,
  548. createUi: createUi,
  549. getValue: getValue
  550. };
  551. var Cell = function (initial) {
  552. var value = initial;
  553. var get = function () {
  554. return value;
  555. };
  556. var set = function (v) {
  557. value = v;
  558. };
  559. var clone = function () {
  560. return Cell(get());
  561. };
  562. return {
  563. get: get,
  564. set: set,
  565. clone: clone
  566. };
  567. };
  568. var findTextByValue = function (value, catalog) {
  569. return findMap(catalog, function (item) {
  570. return Option.some(item).filter(function (i) {
  571. return i.value === value;
  572. });
  573. });
  574. };
  575. var getDelta = function (persistentText, fieldName, catalog, data) {
  576. var value = data[fieldName];
  577. var hasPersistentText = persistentText.length > 0;
  578. return value !== undefined ? findTextByValue(value, catalog).map(function (i) {
  579. return {
  580. url: {
  581. value: i.value,
  582. meta: {
  583. text: hasPersistentText ? persistentText : i.text,
  584. attach: noop
  585. }
  586. },
  587. text: hasPersistentText ? persistentText : i.text
  588. };
  589. }) : Option.none();
  590. };
  591. var findCatalog = function (settings, fieldName) {
  592. if (fieldName === 'link') {
  593. return settings.catalogs.link;
  594. } else if (fieldName === 'anchor') {
  595. return settings.catalogs.anchor;
  596. } else {
  597. return Option.none();
  598. }
  599. };
  600. var init = function (initialData, linkSettings) {
  601. var persistentText = Cell(initialData.text);
  602. var onUrlChange = function (data) {
  603. if (persistentText.get().length <= 0) {
  604. var urlText = data.url.meta.text !== undefined ? data.url.meta.text : data.url.value;
  605. return Option.some({ text: urlText });
  606. } else {
  607. return Option.none();
  608. }
  609. };
  610. var onCatalogChange = function (data, change) {
  611. var catalog = findCatalog(linkSettings, change.name).getOr([]);
  612. return getDelta(persistentText.get(), change.name, catalog, data);
  613. };
  614. var onChange = function (getData, change) {
  615. if (change.name === 'url') {
  616. return onUrlChange(getData());
  617. } else if (contains([
  618. 'anchor',
  619. 'link'
  620. ], change.name)) {
  621. return onCatalogChange(getData(), change);
  622. } else if (change.name === 'text') {
  623. persistentText.set(getData().text);
  624. return Option.none();
  625. } else {
  626. return Option.none();
  627. }
  628. };
  629. return { onChange: onChange };
  630. };
  631. var DialogChanges = {
  632. init: init,
  633. getDelta: getDelta
  634. };
  635. var __assign = function () {
  636. __assign = Object.assign || function __assign(t) {
  637. for (var s, i = 1, n = arguments.length; i < n; i++) {
  638. s = arguments[i];
  639. for (var p in s)
  640. if (Object.prototype.hasOwnProperty.call(s, p))
  641. t[p] = s[p];
  642. }
  643. return t;
  644. };
  645. return __assign.apply(this, arguments);
  646. };
  647. var nu = function (baseFn) {
  648. var data = Option.none();
  649. var callbacks = [];
  650. var map = function (f) {
  651. return nu(function (nCallback) {
  652. get(function (data) {
  653. nCallback(f(data));
  654. });
  655. });
  656. };
  657. var get = function (nCallback) {
  658. if (isReady())
  659. call(nCallback);
  660. else
  661. callbacks.push(nCallback);
  662. };
  663. var set = function (x) {
  664. data = Option.some(x);
  665. run(callbacks);
  666. callbacks = [];
  667. };
  668. var isReady = function () {
  669. return data.isSome();
  670. };
  671. var run = function (cbs) {
  672. each(cbs, call);
  673. };
  674. var call = function (cb) {
  675. data.each(function (x) {
  676. domGlobals.setTimeout(function () {
  677. cb(x);
  678. }, 0);
  679. });
  680. };
  681. baseFn(set);
  682. return {
  683. get: get,
  684. map: map,
  685. isReady: isReady
  686. };
  687. };
  688. var pure = function (a) {
  689. return nu(function (callback) {
  690. callback(a);
  691. });
  692. };
  693. var LazyValue = {
  694. nu: nu,
  695. pure: pure
  696. };
  697. var bounce = function (f) {
  698. return function () {
  699. var args = [];
  700. for (var _i = 0; _i < arguments.length; _i++) {
  701. args[_i] = arguments[_i];
  702. }
  703. var me = this;
  704. domGlobals.setTimeout(function () {
  705. f.apply(me, args);
  706. }, 0);
  707. };
  708. };
  709. var nu$1 = function (baseFn) {
  710. var get = function (callback) {
  711. baseFn(bounce(callback));
  712. };
  713. var map = function (fab) {
  714. return nu$1(function (callback) {
  715. get(function (a) {
  716. var value = fab(a);
  717. callback(value);
  718. });
  719. });
  720. };
  721. var bind = function (aFutureB) {
  722. return nu$1(function (callback) {
  723. get(function (a) {
  724. aFutureB(a).get(callback);
  725. });
  726. });
  727. };
  728. var anonBind = function (futureB) {
  729. return nu$1(function (callback) {
  730. get(function (a) {
  731. futureB.get(callback);
  732. });
  733. });
  734. };
  735. var toLazy = function () {
  736. return LazyValue.nu(get);
  737. };
  738. var toCached = function () {
  739. var cache = null;
  740. return nu$1(function (callback) {
  741. if (cache === null) {
  742. cache = toLazy();
  743. }
  744. cache.get(callback);
  745. });
  746. };
  747. return {
  748. map: map,
  749. bind: bind,
  750. anonBind: anonBind,
  751. toLazy: toLazy,
  752. toCached: toCached,
  753. get: get
  754. };
  755. };
  756. var pure$1 = function (a) {
  757. return nu$1(function (callback) {
  758. callback(a);
  759. });
  760. };
  761. var Future = {
  762. nu: nu$1,
  763. pure: pure$1
  764. };
  765. var global$5 = tinymce.util.Tools.resolve('tinymce.util.Delay');
  766. var delayedConfirm = function (editor, message, callback) {
  767. var rng = editor.selection.getRng();
  768. global$5.setEditorTimeout(editor, function () {
  769. editor.windowManager.confirm(message, function (state) {
  770. editor.selection.setRng(rng);
  771. callback(state);
  772. });
  773. });
  774. };
  775. var tryEmailTransform = function (data) {
  776. var url = data.href;
  777. var suggestMailTo = url.indexOf('@') > 0 && url.indexOf('//') === -1 && url.indexOf('mailto:') === -1;
  778. return suggestMailTo ? Option.some({
  779. message: 'The URL you entered seems to be an email address. Do you want to add the required mailto: prefix?',
  780. preprocess: function (oldData) {
  781. return __assign({}, oldData, { href: 'mailto:' + url });
  782. }
  783. }) : Option.none();
  784. };
  785. var tryProtocolTransform = function (assumeExternalTargets) {
  786. return function (data) {
  787. var url = data.href;
  788. var suggestProtocol = assumeExternalTargets === 1 && !Utils.hasProtocol(url) || assumeExternalTargets === 0 && /^\s*www[\.|\d\.]/i.test(url);
  789. return suggestProtocol ? Option.some({
  790. message: 'The URL you entered seems to be an external link. Do you want to add the required http:// prefix?',
  791. preprocess: function (oldData) {
  792. return __assign({}, oldData, { href: 'http://' + url });
  793. }
  794. }) : Option.none();
  795. };
  796. };
  797. var preprocess = function (editor, assumeExternalTargets, data) {
  798. return findMap([
  799. tryEmailTransform,
  800. tryProtocolTransform(assumeExternalTargets)
  801. ], function (f) {
  802. return f(data);
  803. }).fold(function () {
  804. return Future.pure(data);
  805. }, function (transform) {
  806. return Future.nu(function (callback) {
  807. delayedConfirm(editor, transform.message, function (state) {
  808. domGlobals.console.log('state', state);
  809. callback(state ? transform.preprocess(data) : data);
  810. });
  811. });
  812. });
  813. };
  814. var DialogConfirms = { preprocess: preprocess };
  815. var getAnchors = function (editor) {
  816. var anchorNodes = editor.dom.select('a:not([href])');
  817. var anchors = bind(anchorNodes, function (anchor) {
  818. var id = anchor.name || anchor.id;
  819. return id ? [{
  820. text: id,
  821. value: '#' + id
  822. }] : [];
  823. });
  824. return anchors.length > 0 ? Option.some([{
  825. text: 'None',
  826. value: ''
  827. }].concat(anchors)) : Option.none();
  828. };
  829. var AnchorListOptions = { getAnchors: getAnchors };
  830. var getClasses = function (editor) {
  831. if (Settings.hasLinkClassList(editor.settings)) {
  832. var list = Settings.getLinkClassList(editor.settings);
  833. return ListOptions.sanitize(list);
  834. }
  835. return Option.none();
  836. };
  837. var ClassListOptions = { getClasses: getClasses };
  838. var global$6 = tinymce.util.Tools.resolve('tinymce.util.XHR');
  839. var parseJson = function (text) {
  840. try {
  841. return Option.some(JSON.parse(text));
  842. } catch (err) {
  843. return Option.none();
  844. }
  845. };
  846. var getLinks = function (editor) {
  847. var extractor = function (item) {
  848. return editor.convertURL(item.value || item.url, 'href');
  849. };
  850. var linkList = Settings.getLinkList(editor.settings);
  851. return Future.nu(function (callback) {
  852. if (typeof linkList === 'string') {
  853. global$6.send({
  854. url: linkList,
  855. success: function (text) {
  856. return callback(parseJson(text));
  857. },
  858. error: function (_) {
  859. return callback(Option.none());
  860. }
  861. });
  862. } else if (typeof linkList === 'function') {
  863. linkList(function (output) {
  864. return callback(Option.some(output));
  865. });
  866. } else {
  867. callback(Option.from(linkList));
  868. }
  869. }).map(function (opt) {
  870. return opt.bind(ListOptions.sanitizeWith(extractor));
  871. });
  872. };
  873. var LinkListOptions = { getLinks: getLinks };
  874. var getRels = function (editor, initialTarget) {
  875. if (Settings.hasRelList(editor.settings)) {
  876. var list = Settings.getRelList(editor.settings);
  877. var isTargetBlank_1 = initialTarget.is('_blank');
  878. var enforceSafe = Settings.allowUnsafeLinkTarget(editor.settings) === false;
  879. var safeRelExtractor = function (item) {
  880. return Utils.applyRelTargetRules(ListOptions.getValue(item), isTargetBlank_1);
  881. };
  882. var sanitizer = enforceSafe ? ListOptions.sanitizeWith(safeRelExtractor) : ListOptions.sanitize;
  883. return sanitizer(list);
  884. }
  885. return Option.none();
  886. };
  887. var RelOptions = { getRels: getRels };
  888. var fallbacks = [
  889. {
  890. text: 'Current window',
  891. value: ''
  892. },
  893. {
  894. text: 'New window',
  895. value: '_blank'
  896. }
  897. ];
  898. var getTargets = function (editor) {
  899. if (Settings.shouldShowTargetList(editor.settings)) {
  900. var list = Settings.getTargetList(editor.settings);
  901. return ListOptions.sanitize(list).orThunk(function () {
  902. return Option.some(fallbacks);
  903. });
  904. }
  905. return Option.none();
  906. };
  907. var TargetOptions = { getTargets: getTargets };
  908. var nonEmptyAttr = function (dom, elem, name) {
  909. var val = dom.getAttrib(elem, name);
  910. return val !== null && val.length > 0 ? Option.some(val) : Option.none();
  911. };
  912. var extractFromAnchor = function (editor, settings, anchor, selection) {
  913. var dom = editor.dom;
  914. var onlyText = Utils.isOnlyTextSelected(selection.getContent());
  915. var text = onlyText ? Option.some(Utils.getAnchorText(selection, anchor)) : Option.none();
  916. var url = anchor ? Option.some(dom.getAttrib(anchor, 'href')) : Option.none();
  917. var target = anchor ? Option.from(dom.getAttrib(anchor, 'target')) : Option.none();
  918. var rel = nonEmptyAttr(dom, anchor, 'rel');
  919. var linkClass = nonEmptyAttr(dom, anchor, 'class');
  920. var title = nonEmptyAttr(dom, anchor, 'title');
  921. return {
  922. url: url,
  923. text: text,
  924. title: title,
  925. target: target,
  926. rel: rel,
  927. linkClass: linkClass
  928. };
  929. };
  930. var collect = function (editor, settings, linkNode) {
  931. return LinkListOptions.getLinks(editor).map(function (links) {
  932. var anchor = extractFromAnchor(editor, settings, linkNode, editor.selection);
  933. return {
  934. anchor: anchor,
  935. catalogs: {
  936. targets: TargetOptions.getTargets(editor),
  937. rels: RelOptions.getRels(editor, anchor.target),
  938. classes: ClassListOptions.getClasses(editor),
  939. anchor: AnchorListOptions.getAnchors(editor),
  940. link: links
  941. },
  942. optNode: Option.from(linkNode),
  943. flags: { titleEnabled: Settings.shouldShowLinkTitle(settings) }
  944. };
  945. });
  946. };
  947. var DialogInfo = { collect: collect };
  948. var handleSubmit = function (editor, info, assumeExternalTargets) {
  949. return function (api) {
  950. var data = api.getData();
  951. if (!data.url.value) {
  952. Utils.unlink(editor);
  953. api.close();
  954. return;
  955. }
  956. var getChangedValue = function (key) {
  957. return Option.from(data[key]).filter(function (value) {
  958. return !info.anchor[key].is(value);
  959. });
  960. };
  961. var changedData = {
  962. href: data.url.value,
  963. text: getChangedValue('text'),
  964. target: getChangedValue('target'),
  965. rel: getChangedValue('rel'),
  966. class: getChangedValue('linkClass'),
  967. title: getChangedValue('title')
  968. };
  969. var attachState = {
  970. href: data.url.value,
  971. attach: data.url.meta !== undefined && data.url.meta.attach ? data.url.meta.attach : function () {
  972. }
  973. };
  974. DialogConfirms.preprocess(editor, assumeExternalTargets, changedData).get(function (pData) {
  975. Utils.link(editor, attachState, pData);
  976. });
  977. api.close();
  978. };
  979. };
  980. var collectData = function (editor) {
  981. var settings = editor.settings;
  982. var anchorNode = Utils.getAnchorElement(editor);
  983. return DialogInfo.collect(editor, settings, anchorNode);
  984. };
  985. var getInitialData = function (info, defaultTarget) {
  986. return {
  987. url: {
  988. value: info.anchor.url.getOr(''),
  989. meta: {
  990. attach: function () {
  991. },
  992. text: info.anchor.url.fold(function () {
  993. return '';
  994. }, function () {
  995. return info.anchor.text.getOr('');
  996. }),
  997. original: { value: info.anchor.url.getOr('') }
  998. }
  999. },
  1000. text: info.anchor.text.getOr(''),
  1001. title: info.anchor.title.getOr(''),
  1002. anchor: info.anchor.url.getOr(''),
  1003. link: info.anchor.url.getOr(''),
  1004. rel: info.anchor.rel.getOr(''),
  1005. target: info.anchor.target.or(defaultTarget).getOr(''),
  1006. linkClass: info.anchor.linkClass.getOr('')
  1007. };
  1008. };
  1009. var makeDialog = function (settings, onSubmit, editorSettings) {
  1010. var urlInput = [{
  1011. name: 'url',
  1012. type: 'urlinput',
  1013. filetype: 'file',
  1014. label: 'URL'
  1015. }];
  1016. var displayText = settings.anchor.text.map(function () {
  1017. return {
  1018. name: 'text',
  1019. type: 'input',
  1020. label: 'Text to display'
  1021. };
  1022. }).toArray();
  1023. var titleText = settings.flags.titleEnabled ? [{
  1024. name: 'title',
  1025. type: 'input',
  1026. label: 'Title'
  1027. }] : [];
  1028. var defaultTarget = Settings.hasDefaultLinkTarget(editorSettings) ? Option.some(Settings.getDefaultLinkTarget(editorSettings)) : Option.none();
  1029. var initialData = getInitialData(settings, defaultTarget);
  1030. var dialogDelta = DialogChanges.init(initialData, settings);
  1031. var catalogs = settings.catalogs;
  1032. var body = {
  1033. type: 'panel',
  1034. items: flatten([
  1035. urlInput,
  1036. displayText,
  1037. titleText,
  1038. cat([
  1039. catalogs.anchor.map(ListOptions.createUi('anchor', 'Anchors')),
  1040. catalogs.rels.map(ListOptions.createUi('rel', 'Rel')),
  1041. catalogs.targets.map(ListOptions.createUi('target', 'Open link in...')),
  1042. catalogs.link.map(ListOptions.createUi('link', 'Link list')),
  1043. catalogs.classes.map(ListOptions.createUi('linkClass', 'Class'))
  1044. ])
  1045. ])
  1046. };
  1047. return {
  1048. title: 'Insert/Edit Link',
  1049. size: 'normal',
  1050. body: body,
  1051. buttons: [
  1052. {
  1053. type: 'cancel',
  1054. name: 'cancel',
  1055. text: 'Cancel'
  1056. },
  1057. {
  1058. type: 'submit',
  1059. name: 'save',
  1060. text: 'Save',
  1061. primary: true
  1062. }
  1063. ],
  1064. initialData: initialData,
  1065. onChange: function (api, _a) {
  1066. var name = _a.name;
  1067. dialogDelta.onChange(api.getData, { name: name }).each(function (newData) {
  1068. api.setData(newData);
  1069. });
  1070. },
  1071. onSubmit: onSubmit
  1072. };
  1073. };
  1074. var open$1 = function (editor) {
  1075. var data = collectData(editor);
  1076. data.map(function (info) {
  1077. var onSubmit = handleSubmit(editor, info, Settings.assumeExternalTargets(editor.settings));
  1078. return makeDialog(info, onSubmit, editor.settings);
  1079. }).get(function (spec) {
  1080. editor.windowManager.open(spec);
  1081. });
  1082. };
  1083. var Dialog = { open: open$1 };
  1084. var getLink = function (editor, elm) {
  1085. return editor.dom.getParent(elm, 'a[href]');
  1086. };
  1087. var getSelectedLink = function (editor) {
  1088. return getLink(editor, editor.selection.getStart());
  1089. };
  1090. var hasOnlyAltModifier = function (e) {
  1091. return e.altKey === true && e.shiftKey === false && e.ctrlKey === false && e.metaKey === false;
  1092. };
  1093. var gotoLink = function (editor, a) {
  1094. if (a) {
  1095. var href = Utils.getHref(a);
  1096. if (/^#/.test(href)) {
  1097. var targetEl = editor.$(href);
  1098. if (targetEl.length) {
  1099. editor.selection.scrollIntoView(targetEl[0], true);
  1100. }
  1101. } else {
  1102. OpenUrl.open(a.href);
  1103. }
  1104. }
  1105. };
  1106. var openDialog = function (editor) {
  1107. return function () {
  1108. Dialog.open(editor);
  1109. };
  1110. };
  1111. var gotoSelectedLink = function (editor) {
  1112. return function () {
  1113. gotoLink(editor, getSelectedLink(editor));
  1114. };
  1115. };
  1116. var leftClickedOnAHref = function (editor) {
  1117. return function (elm) {
  1118. var sel, rng, node;
  1119. if (Settings.hasContextToolbar(editor.settings) && Utils.isLink(elm)) {
  1120. sel = editor.selection;
  1121. rng = sel.getRng();
  1122. node = rng.startContainer;
  1123. if (node.nodeType === 3 && sel.isCollapsed() && rng.startOffset > 0 && rng.startOffset < node.data.length) {
  1124. return true;
  1125. }
  1126. }
  1127. return false;
  1128. };
  1129. };
  1130. var setupGotoLinks = function (editor) {
  1131. editor.on('click', function (e) {
  1132. var link = getLink(editor, e.target);
  1133. if (link && global$1.metaKeyPressed(e)) {
  1134. e.preventDefault();
  1135. gotoLink(editor, link);
  1136. }
  1137. });
  1138. editor.on('keydown', function (e) {
  1139. var link = getSelectedLink(editor);
  1140. if (link && e.keyCode === 13 && hasOnlyAltModifier(e)) {
  1141. e.preventDefault();
  1142. gotoLink(editor, link);
  1143. }
  1144. });
  1145. };
  1146. var toggleActiveState = function (editor) {
  1147. return function (api) {
  1148. var nodeChangeHandler = function (e) {
  1149. return api.setActive(!editor.readonly && !!Utils.getAnchorElement(editor, e.element));
  1150. };
  1151. editor.on('NodeChange', nodeChangeHandler);
  1152. return function () {
  1153. return editor.off('NodeChange', nodeChangeHandler);
  1154. };
  1155. };
  1156. };
  1157. var toggleEnabledState = function (editor) {
  1158. return function (api) {
  1159. api.setDisabled(!Utils.hasLinks(editor.dom.getParents(editor.selection.getStart())));
  1160. var nodeChangeHandler = function (e) {
  1161. return api.setDisabled(!Utils.hasLinks(e.parents));
  1162. };
  1163. editor.on('NodeChange', nodeChangeHandler);
  1164. return function () {
  1165. return editor.off('NodeChange', nodeChangeHandler);
  1166. };
  1167. };
  1168. };
  1169. var Actions = {
  1170. openDialog: openDialog,
  1171. gotoSelectedLink: gotoSelectedLink,
  1172. leftClickedOnAHref: leftClickedOnAHref,
  1173. setupGotoLinks: setupGotoLinks,
  1174. toggleActiveState: toggleActiveState,
  1175. toggleEnabledState: toggleEnabledState
  1176. };
  1177. var register = function (editor) {
  1178. editor.addCommand('mceLink', function () {
  1179. if (Settings.useQuickLink(editor.settings)) {
  1180. editor.fire('contexttoolbar-show', { toolbarKey: 'quicklink' });
  1181. } else {
  1182. Actions.openDialog(editor)();
  1183. }
  1184. });
  1185. };
  1186. var Commands = { register: register };
  1187. var setup = function (editor) {
  1188. editor.addShortcut('Meta+K', '', function () {
  1189. editor.execCommand('mceLink');
  1190. });
  1191. };
  1192. var Keyboard = { setup: setup };
  1193. var setupButtons = function (editor) {
  1194. editor.ui.registry.addToggleButton('link', {
  1195. icon: 'link',
  1196. tooltip: 'Insert/edit link',
  1197. onAction: Actions.openDialog(editor),
  1198. onSetup: Actions.toggleActiveState(editor)
  1199. });
  1200. editor.ui.registry.addButton('unlink', {
  1201. icon: 'unlink',
  1202. tooltip: 'Remove link',
  1203. onAction: function () {
  1204. return Utils.unlink(editor);
  1205. },
  1206. onSetup: Actions.toggleEnabledState(editor)
  1207. });
  1208. };
  1209. var setupMenuItems = function (editor) {
  1210. editor.ui.registry.addMenuItem('openlink', {
  1211. text: 'Open link',
  1212. icon: 'new-tab',
  1213. onAction: Actions.gotoSelectedLink(editor),
  1214. onSetup: Actions.toggleEnabledState(editor)
  1215. });
  1216. editor.ui.registry.addMenuItem('link', {
  1217. icon: 'link',
  1218. text: 'Link...',
  1219. shortcut: 'Meta+K',
  1220. onAction: Actions.openDialog(editor)
  1221. });
  1222. editor.ui.registry.addMenuItem('unlink', {
  1223. icon: 'unlink',
  1224. text: 'Remove link',
  1225. onAction: function () {
  1226. return Utils.unlink(editor);
  1227. },
  1228. onSetup: Actions.toggleEnabledState(editor)
  1229. });
  1230. };
  1231. var setupContextMenu = function (editor) {
  1232. var noLink = 'link';
  1233. var inLink = 'link unlink openlink';
  1234. editor.ui.registry.addContextMenu('link', {
  1235. update: function (element) {
  1236. return Utils.hasLinks(editor.dom.getParents(element, 'a')) ? inLink : noLink;
  1237. }
  1238. });
  1239. };
  1240. var setupContextToolbars = function (editor) {
  1241. var collapseSelectionToEnd = function (editor) {
  1242. editor.selection.collapse(false);
  1243. };
  1244. var onSetupLink = function (buttonApi) {
  1245. var node = editor.selection.getNode();
  1246. buttonApi.setDisabled(!Utils.getAnchorElement(editor, node));
  1247. return function () {
  1248. };
  1249. };
  1250. editor.ui.registry.addContextForm('quicklink', {
  1251. launch: {
  1252. type: 'contextformtogglebutton',
  1253. icon: 'link',
  1254. tooltip: 'Link',
  1255. onSetup: Actions.toggleActiveState(editor)
  1256. },
  1257. label: 'Link',
  1258. predicate: function (node) {
  1259. return !!Utils.getAnchorElement(editor, node) && Settings.hasContextToolbar(editor.settings);
  1260. },
  1261. initValue: function () {
  1262. var elm = Utils.getAnchorElement(editor);
  1263. return !!elm ? Utils.getHref(elm) : '';
  1264. },
  1265. commands: [
  1266. {
  1267. type: 'contextformtogglebutton',
  1268. icon: 'link',
  1269. tooltip: 'Link',
  1270. primary: true,
  1271. onSetup: function (buttonApi) {
  1272. var node = editor.selection.getNode();
  1273. buttonApi.setActive(!!Utils.getAnchorElement(editor, node));
  1274. return Actions.toggleActiveState(editor)(buttonApi);
  1275. },
  1276. onAction: function (formApi) {
  1277. var anchor = Utils.getAnchorElement(editor);
  1278. var value = formApi.getValue();
  1279. if (!anchor) {
  1280. var attachState = {
  1281. href: value,
  1282. attach: function () {
  1283. }
  1284. };
  1285. var onlyText = Utils.isOnlyTextSelected(editor.selection.getContent());
  1286. var text = onlyText ? Option.some(Utils.getAnchorText(editor.selection, anchor)).filter(function (t) {
  1287. return t.length > 0;
  1288. }).or(Option.from(value)) : Option.none();
  1289. Utils.link(editor, attachState, {
  1290. href: value,
  1291. text: text,
  1292. title: Option.none(),
  1293. rel: Option.none(),
  1294. target: Option.none(),
  1295. class: Option.none()
  1296. });
  1297. formApi.hide();
  1298. } else {
  1299. editor.dom.setAttrib(anchor, 'href', value);
  1300. collapseSelectionToEnd(editor);
  1301. formApi.hide();
  1302. }
  1303. }
  1304. },
  1305. {
  1306. type: 'contextformbutton',
  1307. icon: 'unlink',
  1308. tooltip: 'Remove link',
  1309. onSetup: onSetupLink,
  1310. onAction: function (formApi) {
  1311. Utils.unlink(editor);
  1312. formApi.hide();
  1313. }
  1314. },
  1315. {
  1316. type: 'contextformbutton',
  1317. icon: 'new-tab',
  1318. tooltip: 'Open link',
  1319. onSetup: onSetupLink,
  1320. onAction: function (formApi) {
  1321. Actions.gotoSelectedLink(editor)();
  1322. formApi.hide();
  1323. }
  1324. }
  1325. ]
  1326. });
  1327. };
  1328. var Controls = {
  1329. setupButtons: setupButtons,
  1330. setupMenuItems: setupMenuItems,
  1331. setupContextMenu: setupContextMenu,
  1332. setupContextToolbars: setupContextToolbars
  1333. };
  1334. global.add('link', function (editor) {
  1335. Controls.setupButtons(editor);
  1336. Controls.setupMenuItems(editor);
  1337. Controls.setupContextMenu(editor);
  1338. Controls.setupContextToolbars(editor);
  1339. Actions.setupGotoLinks(editor);
  1340. Commands.register(editor);
  1341. Keyboard.setup(editor);
  1342. });
  1343. function Plugin () {
  1344. }
  1345. return Plugin;
  1346. }(window));
  1347. })();