PageRenderTime 44ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/ajax/libs/jQuery-linkify/1.1.1/jquery.linkify.js

https://gitlab.com/Mirros/cdnjs
JavaScript | 424 lines | 224 code | 81 blank | 119 comment | 33 complexity | 1b860ae5211b7988cf71682840d30617 MD5 | raw file
  1. /*
  2. * Linkify - v1.1.1
  3. * Find URLs in plain text and return HTML for discovered links.
  4. * https://github.com/HitSend/jQuery-linkify/
  5. *
  6. * Made by SoapBox Innovations, Inc.
  7. * Under MIT License
  8. */
  9. ;(function ($, window, document, undefined) {
  10. "use strict";
  11. /**
  12. A Linkified object contains a DOM node (or just plain text) whose
  13. inner text is replaced by HTML containing `<a>` links to URLs
  14. discovered in that text. Call with
  15. new Linkified(text, options)
  16. Here are some the available options and their defaults
  17. {
  18. tagName: 'a',
  19. newLine: '\n',
  20. target: '_blank',
  21. linkClass: null,
  22. linkClasses: [],
  23. linkAttributes: null
  24. }
  25. @class Linkified
  26. */
  27. var defaults = {
  28. tagName: 'a',
  29. newLine: '\n',
  30. target: '_blank',
  31. linkClass: null,
  32. linkClasses: [],
  33. linkAttributes: null
  34. };
  35. function Linkified(element, options) {
  36. // Setup
  37. this._defaults = defaults;
  38. this.element = element;
  39. this.setOptions(options);
  40. this.init();
  41. }
  42. Linkified.prototype = {
  43. constructor: Linkified,
  44. /**
  45. Initializer
  46. @method init
  47. */
  48. init: function () {
  49. if (this.element.nodeType === 1) {
  50. Linkified.linkifyNode.call(this, this.element);
  51. } else {
  52. this.element = Linkified.linkify.call(
  53. this,
  54. this.element.toString()
  55. );
  56. }
  57. },
  58. /**
  59. Used to reset the options for this plugin
  60. @method setOptions
  61. @param {Object} options
  62. */
  63. setOptions: function (options) {
  64. this.settings = Linkified.extendSettings(options, this.settings);
  65. },
  66. /**
  67. Returns the HTML of the linkified text.
  68. @method toString
  69. @return {String} html
  70. */
  71. toString: function () {
  72. // Returned the linkified HTML
  73. return this.element.toString();
  74. }
  75. };
  76. /**
  77. Create an extended settings object using the default options.
  78. Include a second hash to use those as defaults instead.
  79. @method extendSettings
  80. @static
  81. @param {Object} options Hash of options to use for extending
  82. @param {Object} settings Existing settings object to extend from. If undefined, the defaults will be used
  83. */
  84. Linkified.extendSettings = function (options, settings) {
  85. var prop;
  86. settings = settings || {};
  87. for (prop in defaults) {
  88. if (!settings[prop]) {
  89. settings[prop] = defaults[prop];
  90. }
  91. }
  92. for (prop in options) {
  93. settings[prop] = options[prop];
  94. }
  95. return settings;
  96. };
  97. /**
  98. The url-matching regular expression for double-spaced text
  99. @property linkMatch
  100. @static
  101. @type RegExp
  102. */
  103. Linkified.linkMatch = new RegExp([
  104. // The groups
  105. '(', // 1. Character before the link
  106. '\\s|[^a-zA-Z0-9.\\+_\\/"\\>\\-]|^',
  107. ')(?:', //Main group
  108. '(', // 2. Email address (optional)
  109. '[a-zA-Z0-9\\+_\\-]+',
  110. '(?:',
  111. '\\.[a-zA-Z0-9\\+_\\-]+',
  112. ')*@',
  113. ')?(', // 3. Protocol (optional)
  114. 'http:\\/\\/|https:\\/\\/|ftp:\\/\\/',
  115. ')?(', // 4. Domain & Subdomains
  116. '(?:(?:[a-z0-9][a-z0-9_%\\-_+]*\\.)+)',
  117. ')(', // 5. Top-level domain - http://en.wikipedia.org/wiki/List_of_Internet_top-level_domains
  118. '(?:com|ca|co|edu|gov|net|org|dev|biz|cat|int|pro|tel|mil|aero|asia|coop|info|jobs|mobi|museum|name|post|travel|local|[a-z]{2})',
  119. ')(', // 6. Query string (optional)
  120. '(?:',
  121. '[\\/|\\?]',
  122. '(?:',
  123. '[\\-a-zA-Z0-9_%#*&+=~!?,;:.\\/]*',
  124. ')*',
  125. ')',
  126. '[\\-\\/a-zA-Z0-9_%#*&+=~]',
  127. '|',
  128. '\\/?',
  129. ')?',
  130. ')(', // 7. Character after the link
  131. '[^a-zA-Z0-9\\+_\\/"\\<\\-]|$',
  132. ')'
  133. ].join(''), 'g');
  134. /**
  135. The regular expression of matching email links after the
  136. application of the initial link matcher.
  137. @property emailLinkMatch
  138. @static
  139. @type RegExp
  140. */
  141. Linkified.emailLinkMatch = /(<[a-z]+ href=\")(http:\/\/)([a-zA-Z0-9\+_\-]+(?:\.[a-zA-Z0-9\+_\-]+)*@)/g;
  142. /**
  143. Linkify the given text
  144. @method linkify
  145. @param {String} text Plain text to linkify
  146. @param {Options} options to linkify with, in addition to the defaults for the context
  147. @return {String} html
  148. */
  149. Linkified.linkify = function (text, options) {
  150. var attr,
  151. settings,
  152. linkClasses,
  153. linkReplace = [];
  154. if (this.constructor === Linkified && this.settings) {
  155. // Called from an instance of Linkified
  156. settings = this.settings;
  157. if (options) {
  158. settings = Linkified.extendSettings(options, settings);
  159. }
  160. } else {
  161. settings = Linkified.extendSettings(options);
  162. }
  163. // Normalize class names
  164. if (settings.linkClass) {
  165. linkClasses = settings.linkClass.split(/\s+/);
  166. } else {
  167. linkClasses = [];
  168. }
  169. linkClasses.push.apply(linkClasses, settings.linkClasses);
  170. // Get rid of tags and HTML-structure,
  171. // Duplicate whitespace in preparation for linking
  172. text = text
  173. .replace(/</g, '&lt;')
  174. .replace(/(\s)/g, '$1$1');
  175. // Build up the replacement string
  176. linkReplace.push(
  177. '$1<' + settings.tagName,
  178. 'href="http://$2$4$5$6"'
  179. );
  180. // Add classes
  181. linkReplace.push(
  182. 'class="linkified' +
  183. (linkClasses.length > 0 ? ' ' + linkClasses.join(' ') : '') +
  184. '"'
  185. );
  186. // Add target
  187. if (settings.target) {
  188. linkReplace.push('target="' + settings.target + '"');
  189. }
  190. // Add other (normalized) attributes
  191. for (attr in settings.linkAttributes) {
  192. linkReplace.push([
  193. attr,
  194. '="',
  195. settings.linkAttributes[attr]
  196. .replace(/\"/g, '&quot;')
  197. .replace(/\$/g, '&#36;'),
  198. '"'
  199. ].join(''));
  200. }
  201. // Finish off
  202. linkReplace.push('>$2$3$4$5$6</' + settings.tagName + '>$7');
  203. // Create the link
  204. text = text.replace(Linkified.linkMatch, linkReplace.join(' '));
  205. // The previous line added `http://` to emails. Replace that with `mailto:`
  206. text = text.replace(Linkified.emailLinkMatch, '$1mailto:$3');
  207. // Revert whitespace characters back to a single character
  208. text = text.replace(/(\s){2}/g, '$1');
  209. // Trim and account for new lines
  210. text = text.replace(/\n/g, settings.newLine);
  211. return text;
  212. };
  213. /**
  214. Given an HTML DOM node, linkify its contents
  215. @method linkifyNode
  216. @static
  217. @param {Element} node The HTML node to find URLs in
  218. @return {Element} node
  219. */
  220. Linkified.linkifyNode = function (node) {
  221. var children,
  222. childNode,
  223. childCount,
  224. dummyElement,
  225. i;
  226. // Don't linkify anchor tags or tags that have the .linkified class
  227. if (node &&
  228. typeof node === 'object' &&
  229. node.nodeType === 1 &&
  230. node.tagName.toLowerCase() !== 'a' &&
  231. !/[^\s]linkified[\s$]/.test(node.className)
  232. ) {
  233. children = [];
  234. dummyElement = Linkified._dummyElement ||
  235. document.createElement('div');
  236. childNode = node.firstChild;
  237. childCount = node.childElementCount;
  238. while (childNode) {
  239. if (childNode.nodeType === 3) {
  240. /*
  241. Cleanup dummy node. This is to make sure that
  242. existing nodes don't get improperly removed
  243. */
  244. while (dummyElement.firstChild) {
  245. dummyElement.removeChild(dummyElement.firstChild);
  246. }
  247. /*
  248. Linkify the text node, set the result to the
  249. dummy's contents
  250. */
  251. dummyElement.innerHTML = Linkified.linkify.call(
  252. this,
  253. childNode.textContent || childNode.innerText
  254. );
  255. /*
  256. Parse the linkified text and append it to the
  257. new children
  258. */
  259. children.push.apply(
  260. children,
  261. dummyElement.childNodes
  262. );
  263. // Clean up the dummy again?
  264. while (dummyElement.firstChild) {
  265. dummyElement.removeChild(dummyElement.firstChild);
  266. }
  267. } else if (childNode.nodeType === 1) {
  268. // This is an HTML node, linkify it and add it
  269. children.push(Linkified.linkifyNode(childNode));
  270. } else {
  271. // This is some other kind of node, just push it
  272. children.push(childNode);
  273. }
  274. childNode = childNode.nextSibling;
  275. }
  276. // Remove all existing nodes.
  277. while (node.firstChild) {
  278. node.removeChild(node.firstChild);
  279. }
  280. // Replace with all the new nodes
  281. for (i = 0; i < children.length; i++) {
  282. node.appendChild(children[i]);
  283. }
  284. }
  285. return node;
  286. },
  287. Linkified._dummyElement = document.createElement('div');
  288. // Plugin definition
  289. $.fn.linkify = function (options) {
  290. return this.each(function () {
  291. var linkified;
  292. if (linkified = $.data(this, 'plugin-linkify')) {
  293. // Relinkify
  294. linkified.setOptions(options);
  295. linkified.init();
  296. } else {
  297. // Linkify
  298. $.data(
  299. this,
  300. 'plugin-linkify',
  301. new Linkified(this, options)
  302. );
  303. }
  304. });
  305. };
  306. // Maintain access to the constructor from the plugin
  307. $.fn.linkify.Constructor = Linkified;
  308. // DOM data- API setup
  309. $(window).on('load', function () {
  310. $('[data-linkify]').each(function () {
  311. var $this = $(this),
  312. $target,
  313. target = $this.attr('data-linkify'),
  314. options = {
  315. tagName: $this.attr('data-linkify-tagname') || undefined,
  316. newLine: $this.attr('data-linkify-newline') || undefined,
  317. target: $this.attr('data-linkify-target') || undefined,
  318. linkClass: $this.attr('data-linkify-linkclass') || undefined
  319. };
  320. $target = target === 'this' ? $this : $this.find(target);
  321. $target.linkify(options);
  322. });
  323. });
  324. // Setup click events for linkified elements
  325. $('body').on('click', '.linkified', function () {
  326. var $link = $(this),
  327. url = $link.attr('href'),
  328. isEmail = /^mailto:/i.test(url),
  329. target = $link.attr('target');
  330. if (isEmail) {
  331. // mailto links ignore the target
  332. window.location.href = url;
  333. } else {
  334. window.open(url, target);
  335. }
  336. return false;
  337. });
  338. })(jQuery, window, document)