plugin.js 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  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.9.1 (2021-08-27)
  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 rangeEqualsDelimiterOrSpace = function (rangeString, delimiter) {
  36. return rangeString === delimiter || rangeString === ' ' || rangeString.charCodeAt(0) === 160;
  37. };
  38. var handleEclipse = function (editor) {
  39. parseCurrentLine(editor, -1, '(');
  40. };
  41. var handleSpacebar = function (editor) {
  42. parseCurrentLine(editor, 0, '');
  43. };
  44. var handleEnter = function (editor) {
  45. parseCurrentLine(editor, -1, '');
  46. };
  47. var scopeIndex = function (container, index) {
  48. if (index < 0) {
  49. index = 0;
  50. }
  51. if (container.nodeType === 3) {
  52. var len = container.data.length;
  53. if (index > len) {
  54. index = len;
  55. }
  56. }
  57. return index;
  58. };
  59. var setStart = function (rng, container, offset) {
  60. if (container.nodeType !== 1 || container.hasChildNodes()) {
  61. rng.setStart(container, scopeIndex(container, offset));
  62. } else {
  63. rng.setStartBefore(container);
  64. }
  65. };
  66. var setEnd = function (rng, container, offset) {
  67. if (container.nodeType !== 1 || container.hasChildNodes()) {
  68. rng.setEnd(container, scopeIndex(container, offset));
  69. } else {
  70. rng.setEndAfter(container);
  71. }
  72. };
  73. var hasProtocol = function (url) {
  74. return /^([A-Za-z][A-Za-z\d.+-]*:\/\/)|mailto:/.test(url);
  75. };
  76. var isPunctuation = function (char) {
  77. return /[?!,.;:]/.test(char);
  78. };
  79. var parseCurrentLine = function (editor, endOffset, delimiter) {
  80. var end, endContainer, bookmark, text, prev, len, rngText;
  81. var autoLinkPattern = getAutoLinkPattern(editor);
  82. var defaultLinkTarget = getDefaultLinkTarget(editor);
  83. if (editor.selection.getNode().tagName === 'A') {
  84. return;
  85. }
  86. var rng = editor.selection.getRng().cloneRange();
  87. if (rng.startOffset < 5) {
  88. prev = rng.endContainer.previousSibling;
  89. if (!prev) {
  90. if (!rng.endContainer.firstChild || !rng.endContainer.firstChild.nextSibling) {
  91. return;
  92. }
  93. prev = rng.endContainer.firstChild.nextSibling;
  94. }
  95. len = prev.length;
  96. setStart(rng, prev, len);
  97. setEnd(rng, prev, len);
  98. if (rng.endOffset < 5) {
  99. return;
  100. }
  101. end = rng.endOffset;
  102. endContainer = prev;
  103. } else {
  104. endContainer = rng.endContainer;
  105. if (endContainer.nodeType !== 3 && endContainer.firstChild) {
  106. while (endContainer.nodeType !== 3 && endContainer.firstChild) {
  107. endContainer = endContainer.firstChild;
  108. }
  109. if (endContainer.nodeType === 3) {
  110. setStart(rng, endContainer, 0);
  111. setEnd(rng, endContainer, endContainer.nodeValue.length);
  112. }
  113. }
  114. if (rng.endOffset === 1) {
  115. end = 2;
  116. } else {
  117. end = rng.endOffset - 1 - endOffset;
  118. }
  119. }
  120. var start = end;
  121. do {
  122. setStart(rng, endContainer, end >= 2 ? end - 2 : 0);
  123. setEnd(rng, endContainer, end >= 1 ? end - 1 : 0);
  124. end -= 1;
  125. rngText = rng.toString();
  126. } while (rngText !== ' ' && rngText !== '' && rngText.charCodeAt(0) !== 160 && end - 2 >= 0 && rngText !== delimiter);
  127. if (rangeEqualsDelimiterOrSpace(rng.toString(), delimiter)) {
  128. setStart(rng, endContainer, end);
  129. setEnd(rng, endContainer, start);
  130. end += 1;
  131. } else if (rng.startOffset === 0) {
  132. setStart(rng, endContainer, 0);
  133. setEnd(rng, endContainer, start);
  134. } else {
  135. setStart(rng, endContainer, end);
  136. setEnd(rng, endContainer, start);
  137. }
  138. text = rng.toString();
  139. if (isPunctuation(text.charAt(text.length - 1))) {
  140. setEnd(rng, endContainer, start - 1);
  141. }
  142. text = rng.toString().trim();
  143. var matches = text.match(autoLinkPattern);
  144. var protocol = getDefaultLinkProtocol(editor);
  145. if (matches) {
  146. var url = matches[0];
  147. if (startsWith(url, 'www.')) {
  148. url = protocol + '://' + url;
  149. } else if (contains(url, '@') && !hasProtocol(url)) {
  150. url = 'mailto:' + url;
  151. }
  152. bookmark = editor.selection.getBookmark();
  153. editor.selection.setRng(rng);
  154. editor.execCommand('createlink', false, url);
  155. if (defaultLinkTarget !== false) {
  156. editor.dom.setAttrib(editor.selection.getNode(), 'target', defaultLinkTarget);
  157. }
  158. editor.selection.moveToBookmark(bookmark);
  159. editor.nodeChanged();
  160. }
  161. };
  162. var setup = function (editor) {
  163. var autoUrlDetectState;
  164. editor.on('keydown', function (e) {
  165. if (e.keyCode === 13) {
  166. return handleEnter(editor);
  167. }
  168. });
  169. if (global.browser.isIE()) {
  170. editor.on('focus', function () {
  171. if (!autoUrlDetectState) {
  172. autoUrlDetectState = true;
  173. try {
  174. editor.execCommand('AutoUrlDetect', false, true);
  175. } catch (ex) {
  176. }
  177. }
  178. });
  179. return;
  180. }
  181. editor.on('keypress', function (e) {
  182. if (e.keyCode === 41) {
  183. return handleEclipse(editor);
  184. }
  185. });
  186. editor.on('keyup', function (e) {
  187. if (e.keyCode === 32) {
  188. return handleSpacebar(editor);
  189. }
  190. });
  191. };
  192. function Plugin () {
  193. global$1.add('autolink', function (editor) {
  194. setup(editor);
  195. });
  196. }
  197. Plugin();
  198. }());