plugin.js 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  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.10.2 (2021-11-17)
  8. */
  9. (function () {
  10. 'use strict';
  11. var global$1 = tinymce.util.Tools.resolve('tinymce.PluginManager');
  12. var checkRange = function (str, substr, start) {
  13. return substr === '' || str.length >= substr.length && str.substr(start, start + substr.length) === substr;
  14. };
  15. var contains = function (str, substr) {
  16. return str.indexOf(substr) !== -1;
  17. };
  18. var startsWith = function (str, prefix) {
  19. return checkRange(str, prefix, 0);
  20. };
  21. var global = tinymce.util.Tools.resolve('tinymce.Env');
  22. var link = function () {
  23. return /(?:[A-Za-z][A-Za-z\d.+-]{0,14}:\/\/(?:[-.~*+=!&;:'%@?^${}(),\w]+@)?|www\.|[-;:&=+$,.\w]+@)[A-Za-z\d-]+(?:\.[A-Za-z\d-]+)*(?::\d+)?(?:\/(?:[-+~=.,%()\/\w]*[-+~=%()\/\w])?)?(?:\?(?:[-.~*+=!&;:'%@?^${}(),\/\w]+))?(?:#(?:[-.~*+=!&;:'%@?^${}(),\/\w]+))?/g;
  24. };
  25. var defaultLinkPattern = new RegExp('^' + link().source + '$', 'i');
  26. var getAutoLinkPattern = function (editor) {
  27. return editor.getParam('autolink_pattern', defaultLinkPattern);
  28. };
  29. var getDefaultLinkTarget = function (editor) {
  30. return editor.getParam('default_link_target', false);
  31. };
  32. var getDefaultLinkProtocol = function (editor) {
  33. return editor.getParam('link_default_protocol', 'http', 'string');
  34. };
  35. var rangeEqualsBracketOrSpace = function (rangeString) {
  36. return /^[(\[{ \u00a0]$/.test(rangeString);
  37. };
  38. var isTextNode = function (node) {
  39. return node.nodeType === 3;
  40. };
  41. var isElement = function (node) {
  42. return node.nodeType === 1;
  43. };
  44. var handleBracket = function (editor) {
  45. return parseCurrentLine(editor, -1);
  46. };
  47. var handleSpacebar = function (editor) {
  48. return parseCurrentLine(editor, 0);
  49. };
  50. var handleEnter = function (editor) {
  51. return parseCurrentLine(editor, -1);
  52. };
  53. var scopeIndex = function (container, index) {
  54. if (index < 0) {
  55. index = 0;
  56. }
  57. if (isTextNode(container)) {
  58. var len = container.data.length;
  59. if (index > len) {
  60. index = len;
  61. }
  62. }
  63. return index;
  64. };
  65. var setStart = function (rng, container, offset) {
  66. if (!isElement(container) || container.hasChildNodes()) {
  67. rng.setStart(container, scopeIndex(container, offset));
  68. } else {
  69. rng.setStartBefore(container);
  70. }
  71. };
  72. var setEnd = function (rng, container, offset) {
  73. if (!isElement(container) || container.hasChildNodes()) {
  74. rng.setEnd(container, scopeIndex(container, offset));
  75. } else {
  76. rng.setEndAfter(container);
  77. }
  78. };
  79. var hasProtocol = function (url) {
  80. return /^([A-Za-z][A-Za-z\d.+-]*:\/\/)|mailto:/.test(url);
  81. };
  82. var isPunctuation = function (char) {
  83. return /[?!,.;:]/.test(char);
  84. };
  85. var parseCurrentLine = function (editor, endOffset) {
  86. var end, endContainer, bookmark, text, prev, len, rngText;
  87. var autoLinkPattern = getAutoLinkPattern(editor);
  88. var defaultLinkTarget = getDefaultLinkTarget(editor);
  89. if (editor.dom.getParent(editor.selection.getNode(), 'a[href]') !== null) {
  90. return;
  91. }
  92. var rng = editor.selection.getRng().cloneRange();
  93. if (rng.startOffset < 5) {
  94. prev = rng.endContainer.previousSibling;
  95. if (!prev) {
  96. if (!rng.endContainer.firstChild || !rng.endContainer.firstChild.nextSibling) {
  97. return;
  98. }
  99. prev = rng.endContainer.firstChild.nextSibling;
  100. }
  101. len = prev.length;
  102. setStart(rng, prev, len);
  103. setEnd(rng, prev, len);
  104. if (rng.endOffset < 5) {
  105. return;
  106. }
  107. end = rng.endOffset;
  108. endContainer = prev;
  109. } else {
  110. endContainer = rng.endContainer;
  111. if (!isTextNode(endContainer) && endContainer.firstChild) {
  112. while (!isTextNode(endContainer) && endContainer.firstChild) {
  113. endContainer = endContainer.firstChild;
  114. }
  115. if (isTextNode(endContainer)) {
  116. setStart(rng, endContainer, 0);
  117. setEnd(rng, endContainer, endContainer.nodeValue.length);
  118. }
  119. }
  120. if (rng.endOffset === 1) {
  121. end = 2;
  122. } else {
  123. end = rng.endOffset - 1 - endOffset;
  124. }
  125. }
  126. var start = end;
  127. do {
  128. setStart(rng, endContainer, end >= 2 ? end - 2 : 0);
  129. setEnd(rng, endContainer, end >= 1 ? end - 1 : 0);
  130. end -= 1;
  131. rngText = rng.toString();
  132. } while (!rangeEqualsBracketOrSpace(rngText) && end - 2 >= 0);
  133. if (rangeEqualsBracketOrSpace(rng.toString())) {
  134. setStart(rng, endContainer, end);
  135. setEnd(rng, endContainer, start);
  136. end += 1;
  137. } else if (rng.startOffset === 0) {
  138. setStart(rng, endContainer, 0);
  139. setEnd(rng, endContainer, start);
  140. } else {
  141. setStart(rng, endContainer, end);
  142. setEnd(rng, endContainer, start);
  143. }
  144. text = rng.toString();
  145. if (isPunctuation(text.charAt(text.length - 1))) {
  146. setEnd(rng, endContainer, start - 1);
  147. }
  148. text = rng.toString().trim();
  149. var matches = text.match(autoLinkPattern);
  150. var protocol = getDefaultLinkProtocol(editor);
  151. if (matches) {
  152. var url = matches[0];
  153. if (startsWith(url, 'www.')) {
  154. url = protocol + '://' + url;
  155. } else if (contains(url, '@') && !hasProtocol(url)) {
  156. url = 'mailto:' + url;
  157. }
  158. bookmark = editor.selection.getBookmark();
  159. editor.selection.setRng(rng);
  160. editor.execCommand('createlink', false, url);
  161. if (defaultLinkTarget !== false) {
  162. editor.dom.setAttrib(editor.selection.getNode(), 'target', defaultLinkTarget);
  163. }
  164. editor.selection.moveToBookmark(bookmark);
  165. editor.nodeChanged();
  166. }
  167. };
  168. var setup = function (editor) {
  169. var autoUrlDetectState;
  170. editor.on('keydown', function (e) {
  171. if (e.keyCode === 13) {
  172. return handleEnter(editor);
  173. }
  174. });
  175. if (global.browser.isIE()) {
  176. editor.on('focus', function () {
  177. if (!autoUrlDetectState) {
  178. autoUrlDetectState = true;
  179. try {
  180. editor.execCommand('AutoUrlDetect', false, true);
  181. } catch (ex) {
  182. }
  183. }
  184. });
  185. return;
  186. }
  187. editor.on('keypress', function (e) {
  188. if (e.keyCode === 41 || e.keyCode === 93 || e.keyCode === 125) {
  189. return handleBracket(editor);
  190. }
  191. });
  192. editor.on('keyup', function (e) {
  193. if (e.keyCode === 32) {
  194. return handleSpacebar(editor);
  195. }
  196. });
  197. };
  198. function Plugin () {
  199. global$1.add('autolink', function (editor) {
  200. setup(editor);
  201. });
  202. }
  203. Plugin();
  204. }());