linkify.js 48 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286
  1. ;(function () {
  2. 'use strict';
  3. var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
  4. (function (exports) {
  5. 'use strict';
  6. function inherits(parent, child) {
  7. var props = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
  8. var extended = Object.create(parent.prototype);
  9. for (var p in props) {
  10. extended[p] = props[p];
  11. }
  12. extended.constructor = child;
  13. child.prototype = extended;
  14. return child;
  15. }
  16. var defaults = {
  17. defaultProtocol: 'http',
  18. events: null,
  19. format: noop,
  20. formatHref: noop,
  21. nl2br: false,
  22. tagName: 'a',
  23. target: typeToTarget,
  24. validate: true,
  25. ignoreTags: [],
  26. attributes: null,
  27. className: 'linkified' // Deprecated value - no default class will be provided in the future
  28. };
  29. function Options(opts) {
  30. opts = opts || {};
  31. this.defaultProtocol = opts.hasOwnProperty('defaultProtocol') ? opts.defaultProtocol : defaults.defaultProtocol;
  32. this.events = opts.hasOwnProperty('events') ? opts.events : defaults.events;
  33. this.format = opts.hasOwnProperty('format') ? opts.format : defaults.format;
  34. this.formatHref = opts.hasOwnProperty('formatHref') ? opts.formatHref : defaults.formatHref;
  35. this.nl2br = opts.hasOwnProperty('nl2br') ? opts.nl2br : defaults.nl2br;
  36. this.tagName = opts.hasOwnProperty('tagName') ? opts.tagName : defaults.tagName;
  37. this.target = opts.hasOwnProperty('target') ? opts.target : defaults.target;
  38. this.validate = opts.hasOwnProperty('validate') ? opts.validate : defaults.validate;
  39. this.ignoreTags = [];
  40. // linkAttributes and linkClass is deprecated
  41. this.attributes = opts.attributes || opts.linkAttributes || defaults.attributes;
  42. this.className = opts.hasOwnProperty('className') ? opts.className : opts.linkClass || defaults.className;
  43. // Make all tags names upper case
  44. var ignoredTags = opts.hasOwnProperty('ignoreTags') ? opts.ignoreTags : defaults.ignoreTags;
  45. for (var i = 0; i < ignoredTags.length; i++) {
  46. this.ignoreTags.push(ignoredTags[i].toUpperCase());
  47. }
  48. }
  49. Options.prototype = {
  50. /**
  51. * Given the token, return all options for how it should be displayed
  52. */
  53. resolve: function resolve(token) {
  54. var href = token.toHref(this.defaultProtocol);
  55. return {
  56. formatted: this.get('format', token.toString(), token),
  57. formattedHref: this.get('formatHref', href, token),
  58. tagName: this.get('tagName', href, token),
  59. className: this.get('className', href, token),
  60. target: this.get('target', href, token),
  61. events: this.getObject('events', href, token),
  62. attributes: this.getObject('attributes', href, token)
  63. };
  64. },
  65. /**
  66. * Returns true or false based on whether a token should be displayed as a
  67. * link based on the user options. By default,
  68. */
  69. check: function check(token) {
  70. return this.get('validate', token.toString(), token);
  71. },
  72. // Private methods
  73. /**
  74. * Resolve an option's value based on the value of the option and the given
  75. * params.
  76. * @param {String} key Name of option to use
  77. * @param operator will be passed to the target option if it's method
  78. * @param {MultiToken} token The token from linkify.tokenize
  79. */
  80. get: function get(key, operator, token) {
  81. var optionValue = void 0,
  82. option = this[key];
  83. if (!option) {
  84. return option;
  85. }
  86. switch (typeof option === 'undefined' ? 'undefined' : _typeof(option)) {
  87. case 'function':
  88. return option(operator, token.type);
  89. case 'object':
  90. optionValue = option.hasOwnProperty(token.type) ? option[token.type] : defaults[key];
  91. return typeof optionValue === 'function' ? optionValue(operator, token.type) : optionValue;
  92. }
  93. return option;
  94. },
  95. getObject: function getObject(key, operator, token) {
  96. var option = this[key];
  97. return typeof option === 'function' ? option(operator, token.type) : option;
  98. }
  99. };
  100. /**
  101. * Quick indexOf replacement for checking the ignoreTags option
  102. */
  103. function contains(arr, value) {
  104. for (var i = 0; i < arr.length; i++) {
  105. if (arr[i] === value) {
  106. return true;
  107. }
  108. }
  109. return false;
  110. }
  111. function noop(val) {
  112. return val;
  113. }
  114. function typeToTarget(href, type) {
  115. return type === 'url' ? '_blank' : null;
  116. }
  117. var options = Object.freeze({
  118. defaults: defaults,
  119. Options: Options,
  120. contains: contains
  121. });
  122. function createStateClass() {
  123. return function (tClass) {
  124. this.j = [];
  125. this.T = tClass || null;
  126. };
  127. }
  128. /**
  129. A simple state machine that can emit token classes
  130. The `j` property in this class refers to state jumps. It's a
  131. multidimensional array where for each element:
  132. * index [0] is a symbol or class of symbols to transition to.
  133. * index [1] is a State instance which matches
  134. The type of symbol will depend on the target implementation for this class.
  135. In Linkify, we have a two-stage scanner. Each stage uses this state machine
  136. but with a slighly different (polymorphic) implementation.
  137. The `T` property refers to the token class.
  138. TODO: Can the `on` and `next` methods be combined?
  139. @class BaseState
  140. */
  141. var BaseState = createStateClass();
  142. BaseState.prototype = {
  143. defaultTransition: false,
  144. /**
  145. @method constructor
  146. @param {Class} tClass Pass in the kind of token to emit if there are
  147. no jumps after this state and the state is accepting.
  148. */
  149. /**
  150. On the given symbol(s), this machine should go to the given state
  151. @method on
  152. @param {Array|Mixed} symbol
  153. @param {BaseState} state Note that the type of this state should be the
  154. same as the current instance (i.e., don't pass in a different
  155. subclass)
  156. */
  157. on: function on(symbol, state) {
  158. if (symbol instanceof Array) {
  159. for (var i = 0; i < symbol.length; i++) {
  160. this.j.push([symbol[i], state]);
  161. }
  162. return this;
  163. }
  164. this.j.push([symbol, state]);
  165. return this;
  166. },
  167. /**
  168. Given the next item, returns next state for that item
  169. @method next
  170. @param {Mixed} item Should be an instance of the symbols handled by
  171. this particular machine.
  172. @return {State} state Returns false if no jumps are available
  173. */
  174. next: function next(item) {
  175. for (var i = 0; i < this.j.length; i++) {
  176. var jump = this.j[i];
  177. var symbol = jump[0]; // Next item to check for
  178. var state = jump[1]; // State to jump to if items match
  179. // compare item with symbol
  180. if (this.test(item, symbol)) {
  181. return state;
  182. }
  183. }
  184. // Nowhere left to jump!
  185. return this.defaultTransition;
  186. },
  187. /**
  188. Does this state accept?
  189. `true` only of `this.T` exists
  190. @method accepts
  191. @return {Boolean}
  192. */
  193. accepts: function accepts() {
  194. return !!this.T;
  195. },
  196. /**
  197. Determine whether a given item "symbolizes" the symbol, where symbol is
  198. a class of items handled by this state machine.
  199. This method should be overriden in extended classes.
  200. @method test
  201. @param {Mixed} item Does this item match the given symbol?
  202. @param {Mixed} symbol
  203. @return {Boolean}
  204. */
  205. test: function test(item, symbol) {
  206. return item === symbol;
  207. },
  208. /**
  209. Emit the token for this State (just return it in this case)
  210. If this emits a token, this instance is an accepting state
  211. @method emit
  212. @return {Class} T
  213. */
  214. emit: function emit() {
  215. return this.T;
  216. }
  217. };
  218. /**
  219. State machine for string-based input
  220. @class CharacterState
  221. @extends BaseState
  222. */
  223. var CharacterState = inherits(BaseState, createStateClass(), {
  224. /**
  225. Does the given character match the given character or regular
  226. expression?
  227. @method test
  228. @param {String} char
  229. @param {String|RegExp} charOrRegExp
  230. @return {Boolean}
  231. */
  232. test: function test(character, charOrRegExp) {
  233. return character === charOrRegExp || charOrRegExp instanceof RegExp && charOrRegExp.test(character);
  234. }
  235. });
  236. /**
  237. State machine for input in the form of TextTokens
  238. @class TokenState
  239. @extends BaseState
  240. */
  241. var TokenState = inherits(BaseState, createStateClass(), {
  242. /**
  243. * Similar to `on`, but returns the state the results in the transition from
  244. * the given item
  245. * @method jump
  246. * @param {Mixed} item
  247. * @param {Token} [token]
  248. * @return state
  249. */
  250. jump: function jump(token) {
  251. var tClass = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
  252. var state = this.next(new token('')); // dummy temp token
  253. if (state === this.defaultTransition) {
  254. // Make a new state!
  255. state = new this.constructor(tClass);
  256. this.on(token, state);
  257. } else if (tClass) {
  258. state.T = tClass;
  259. }
  260. return state;
  261. },
  262. /**
  263. Is the given token an instance of the given token class?
  264. @method test
  265. @param {TextToken} token
  266. @param {Class} tokenClass
  267. @return {Boolean}
  268. */
  269. test: function test(token, tokenClass) {
  270. return token instanceof tokenClass;
  271. }
  272. });
  273. /**
  274. Given a non-empty target string, generates states (if required) for each
  275. consecutive substring of characters in str starting from the beginning of
  276. the string. The final state will have a special value, as specified in
  277. options. All other "in between" substrings will have a default end state.
  278. This turns the state machine into a Trie-like data structure (rather than a
  279. intelligently-designed DFA).
  280. Note that I haven't really tried these with any strings other than
  281. DOMAIN.
  282. @param {String} str
  283. @param {CharacterState} start State to jump from the first character
  284. @param {Class} endToken Token class to emit when the given string has been
  285. matched and no more jumps exist.
  286. @param {Class} defaultToken "Filler token", or which token type to emit when
  287. we don't have a full match
  288. @return {Array} list of newly-created states
  289. */
  290. function stateify(str, start, endToken, defaultToken) {
  291. var i = 0,
  292. len = str.length,
  293. state = start,
  294. newStates = [],
  295. nextState = void 0;
  296. // Find the next state without a jump to the next character
  297. while (i < len && (nextState = state.next(str[i]))) {
  298. state = nextState;
  299. i++;
  300. }
  301. if (i >= len) {
  302. return [];
  303. } // no new tokens were added
  304. while (i < len - 1) {
  305. nextState = new CharacterState(defaultToken);
  306. newStates.push(nextState);
  307. state.on(str[i], nextState);
  308. state = nextState;
  309. i++;
  310. }
  311. nextState = new CharacterState(endToken);
  312. newStates.push(nextState);
  313. state.on(str[len - 1], nextState);
  314. return newStates;
  315. }
  316. function createTokenClass() {
  317. return function (value) {
  318. if (value) {
  319. this.v = value;
  320. }
  321. };
  322. }
  323. /******************************************************************************
  324. Text Tokens
  325. Tokens composed of strings
  326. ******************************************************************************/
  327. /**
  328. Abstract class used for manufacturing text tokens.
  329. Pass in the value this token represents
  330. @class TextToken
  331. @abstract
  332. */
  333. var TextToken = createTokenClass();
  334. TextToken.prototype = {
  335. toString: function toString() {
  336. return this.v + '';
  337. }
  338. };
  339. function inheritsToken(value) {
  340. var props = value ? { v: value } : {};
  341. return inherits(TextToken, createTokenClass(), props);
  342. }
  343. /**
  344. A valid domain token
  345. @class DOMAIN
  346. @extends TextToken
  347. */
  348. var DOMAIN = inheritsToken();
  349. /**
  350. @class AT
  351. @extends TextToken
  352. */
  353. var AT = inheritsToken('@');
  354. /**
  355. Represents a single colon `:` character
  356. @class COLON
  357. @extends TextToken
  358. */
  359. var COLON = inheritsToken(':');
  360. /**
  361. @class DOT
  362. @extends TextToken
  363. */
  364. var DOT = inheritsToken('.');
  365. /**
  366. A character class that can surround the URL, but which the URL cannot begin
  367. or end with. Does not include certain English punctuation like parentheses.
  368. @class PUNCTUATION
  369. @extends TextToken
  370. */
  371. var PUNCTUATION = inheritsToken();
  372. /**
  373. The word localhost (by itself)
  374. @class LOCALHOST
  375. @extends TextToken
  376. */
  377. var LOCALHOST = inheritsToken();
  378. /**
  379. Newline token
  380. @class NL
  381. @extends TextToken
  382. */
  383. var NL = inheritsToken('\n');
  384. /**
  385. @class NUM
  386. @extends TextToken
  387. */
  388. var NUM = inheritsToken();
  389. /**
  390. @class PLUS
  391. @extends TextToken
  392. */
  393. var PLUS = inheritsToken('+');
  394. /**
  395. @class POUND
  396. @extends TextToken
  397. */
  398. var POUND = inheritsToken('#');
  399. /**
  400. Represents a web URL protocol. Supported types include
  401. * `http:`
  402. * `https:`
  403. * `ftp:`
  404. * `ftps:`
  405. @class PROTOCOL
  406. @extends TextToken
  407. */
  408. var PROTOCOL = inheritsToken();
  409. /**
  410. Represents the start of the email URI protocol
  411. @class MAILTO
  412. @extends TextToken
  413. */
  414. var MAILTO = inheritsToken('mailto:');
  415. /**
  416. @class QUERY
  417. @extends TextToken
  418. */
  419. var QUERY = inheritsToken('?');
  420. /**
  421. @class SLASH
  422. @extends TextToken
  423. */
  424. var SLASH = inheritsToken('/');
  425. /**
  426. @class UNDERSCORE
  427. @extends TextToken
  428. */
  429. var UNDERSCORE = inheritsToken('_');
  430. /**
  431. One ore more non-whitespace symbol.
  432. @class SYM
  433. @extends TextToken
  434. */
  435. var SYM = inheritsToken();
  436. /**
  437. @class TLD
  438. @extends TextToken
  439. */
  440. var TLD = inheritsToken();
  441. /**
  442. Represents a string of consecutive whitespace characters
  443. @class WS
  444. @extends TextToken
  445. */
  446. var WS = inheritsToken();
  447. /**
  448. Opening/closing bracket classes
  449. */
  450. var OPENBRACE = inheritsToken('{');
  451. var OPENBRACKET = inheritsToken('[');
  452. var OPENANGLEBRACKET = inheritsToken('<');
  453. var OPENPAREN = inheritsToken('(');
  454. var CLOSEBRACE = inheritsToken('}');
  455. var CLOSEBRACKET = inheritsToken(']');
  456. var CLOSEANGLEBRACKET = inheritsToken('>');
  457. var CLOSEPAREN = inheritsToken(')');
  458. var AMPERSAND = inheritsToken('&');
  459. var text = Object.freeze({
  460. Base: TextToken,
  461. DOMAIN: DOMAIN,
  462. AT: AT,
  463. COLON: COLON,
  464. DOT: DOT,
  465. PUNCTUATION: PUNCTUATION,
  466. LOCALHOST: LOCALHOST,
  467. NL: NL,
  468. NUM: NUM,
  469. PLUS: PLUS,
  470. POUND: POUND,
  471. QUERY: QUERY,
  472. PROTOCOL: PROTOCOL,
  473. MAILTO: MAILTO,
  474. SLASH: SLASH,
  475. UNDERSCORE: UNDERSCORE,
  476. SYM: SYM,
  477. TLD: TLD,
  478. WS: WS,
  479. OPENBRACE: OPENBRACE,
  480. OPENBRACKET: OPENBRACKET,
  481. OPENANGLEBRACKET: OPENANGLEBRACKET,
  482. OPENPAREN: OPENPAREN,
  483. CLOSEBRACE: CLOSEBRACE,
  484. CLOSEBRACKET: CLOSEBRACKET,
  485. CLOSEANGLEBRACKET: CLOSEANGLEBRACKET,
  486. CLOSEPAREN: CLOSEPAREN,
  487. AMPERSAND: AMPERSAND
  488. });
  489. /**
  490. The scanner provides an interface that takes a string of text as input, and
  491. outputs an array of tokens instances that can be used for easy URL parsing.
  492. @module linkify
  493. @submodule scanner
  494. @main scanner
  495. */
  496. var tlds = 'aaa|aarp|abarth|abb|abbott|abbvie|abc|able|abogado|abudhabi|ac|academy|accenture|accountant|accountants|aco|active|actor|ad|adac|ads|adult|ae|aeg|aero|aetna|af|afamilycompany|afl|africa|ag|agakhan|agency|ai|aig|aigo|airbus|airforce|airtel|akdn|al|alfaromeo|alibaba|alipay|allfinanz|allstate|ally|alsace|alstom|am|americanexpress|americanfamily|amex|amfam|amica|amsterdam|analytics|android|anquan|anz|ao|aol|apartments|app|apple|aq|aquarelle|ar|arab|aramco|archi|army|arpa|art|arte|as|asda|asia|associates|at|athleta|attorney|au|auction|audi|audible|audio|auspost|author|auto|autos|avianca|aw|aws|ax|axa|az|azure|ba|baby|baidu|banamex|bananarepublic|band|bank|bar|barcelona|barclaycard|barclays|barefoot|bargains|baseball|basketball|bauhaus|bayern|bb|bbc|bbt|bbva|bcg|bcn|bd|be|beats|beauty|beer|bentley|berlin|best|bestbuy|bet|bf|bg|bh|bharti|bi|bible|bid|bike|bing|bingo|bio|biz|bj|black|blackfriday|blanco|blockbuster|blog|bloomberg|blue|bm|bms|bmw|bn|bnl|bnpparibas|bo|boats|boehringer|bofa|bom|bond|boo|book|booking|boots|bosch|bostik|boston|bot|boutique|box|br|bradesco|bridgestone|broadway|broker|brother|brussels|bs|bt|budapest|bugatti|build|builders|business|buy|buzz|bv|bw|by|bz|bzh|ca|cab|cafe|cal|call|calvinklein|cam|camera|camp|cancerresearch|canon|capetown|capital|capitalone|car|caravan|cards|care|career|careers|cars|cartier|casa|case|caseih|cash|casino|cat|catering|catholic|cba|cbn|cbre|cbs|cc|cd|ceb|center|ceo|cern|cf|cfa|cfd|cg|ch|chanel|channel|chase|chat|cheap|chintai|chloe|christmas|chrome|chrysler|church|ci|cipriani|circle|cisco|citadel|citi|citic|city|cityeats|ck|cl|claims|cleaning|click|clinic|clinique|clothing|cloud|club|clubmed|cm|cn|co|coach|codes|coffee|college|cologne|com|comcast|commbank|community|company|compare|computer|comsec|condos|construction|consulting|contact|contractors|cooking|cookingchannel|cool|coop|corsica|country|coupon|coupons|courses|cr|credit|creditcard|creditunion|cricket|crown|crs|cruise|cruises|csc|cu|cuisinella|cv|cw|cx|cy|cymru|cyou|cz|dabur|dad|dance|data|date|dating|datsun|day|dclk|dds|de|deal|dealer|deals|degree|delivery|dell|deloitte|delta|democrat|dental|dentist|desi|design|dev|dhl|diamonds|diet|digital|direct|directory|discount|discover|dish|diy|dj|dk|dm|dnp|do|docs|doctor|dodge|dog|doha|domains|dot|download|drive|dtv|dubai|duck|dunlop|duns|dupont|durban|dvag|dvr|dz|earth|eat|ec|eco|edeka|edu|education|ee|eg|email|emerck|energy|engineer|engineering|enterprises|epost|epson|equipment|er|ericsson|erni|es|esq|estate|esurance|et|etisalat|eu|eurovision|eus|events|everbank|exchange|expert|exposed|express|extraspace|fage|fail|fairwinds|faith|family|fan|fans|farm|farmers|fashion|fast|fedex|feedback|ferrari|ferrero|fi|fiat|fidelity|fido|film|final|finance|financial|fire|firestone|firmdale|fish|fishing|fit|fitness|fj|fk|flickr|flights|flir|florist|flowers|fly|fm|fo|foo|food|foodnetwork|football|ford|forex|forsale|forum|foundation|fox|fr|free|fresenius|frl|frogans|frontdoor|frontier|ftr|fujitsu|fujixerox|fun|fund|furniture|futbol|fyi|ga|gal|gallery|gallo|gallup|game|games|gap|garden|gb|gbiz|gd|gdn|ge|gea|gent|genting|george|gf|gg|ggee|gh|gi|gift|gifts|gives|giving|gl|glade|glass|gle|global|globo|gm|gmail|gmbh|gmo|gmx|gn|godaddy|gold|goldpoint|golf|goo|goodhands|goodyear|goog|google|gop|got|gov|gp|gq|gr|grainger|graphics|gratis|green|gripe|grocery|group|gs|gt|gu|guardian|gucci|guge|guide|guitars|guru|gw|gy|hair|hamburg|hangout|haus|hbo|hdfc|hdfcbank|health|healthcare|help|helsinki|here|hermes|hgtv|hiphop|hisamitsu|hitachi|hiv|hk|hkt|hm|hn|hockey|holdings|holiday|homedepot|homegoods|homes|homesense|honda|honeywell|horse|hospital|host|hosting|hot|hoteles|hotels|hotmail|house|how|hr|hsbc|ht|htc|hu|hughes|hyatt|hyundai|ibm|icbc|ice|icu|id|ie|ieee|ifm|ikano|il|im|imamat|imdb|immo|immobilien|in|industries|infiniti|info|ing|ink|institute|insurance|insure|int|intel|international|intuit|investments|io|ipiranga|iq|ir|irish|is|iselect|ismaili|ist|istanbul|it|itau|itv|iveco|iwc|jaguar|java|jcb|jcp|je|jeep|jetzt|jewelry|jio|jlc|jll|jm|jmp|jnj|jo|jobs|joburg|jot|joy|jp|jpmorgan|jprs|juegos|juniper|kaufen|kddi|ke|kerryhotels|kerrylogistics|kerryproperties|kfh|kg|kh|ki|kia|kim|kinder|kindle|kitchen|kiwi|km|kn|koeln|komatsu|kosher|kp|kpmg|kpn|kr|krd|kred|kuokgroup|kw|ky|kyoto|kz|la|lacaixa|ladbrokes|lamborghini|lamer|lancaster|lancia|lancome|land|landrover|lanxess|lasalle|lat|latino|latrobe|law|lawyer|lb|lc|lds|lease|leclerc|lefrak|legal|lego|lexus|lgbt|li|liaison|lidl|life|lifeinsurance|lifestyle|lighting|like|lilly|limited|limo|lincoln|linde|link|lipsy|live|living|lixil|lk|loan|loans|locker|locus|loft|lol|london|lotte|lotto|love|lpl|lplfinancial|lr|ls|lt|ltd|ltda|lu|lundbeck|lupin|luxe|luxury|lv|ly|ma|macys|madrid|maif|maison|makeup|man|management|mango|map|market|marketing|markets|marriott|marshalls|maserati|mattel|mba|mc|mckinsey|md|me|med|media|meet|melbourne|meme|memorial|men|menu|meo|merckmsd|metlife|mg|mh|miami|microsoft|mil|mini|mint|mit|mitsubishi|mk|ml|mlb|mls|mm|mma|mn|mo|mobi|mobile|mobily|moda|moe|moi|mom|monash|money|monster|mopar|mormon|mortgage|moscow|moto|motorcycles|mov|movie|movistar|mp|mq|mr|ms|msd|mt|mtn|mtr|mu|museum|mutual|mv|mw|mx|my|mz|na|nab|nadex|nagoya|name|nationwide|natura|navy|nba|nc|ne|nec|net|netbank|netflix|network|neustar|new|newholland|news|next|nextdirect|nexus|nf|nfl|ng|ngo|nhk|ni|nico|nike|nikon|ninja|nissan|nissay|nl|no|nokia|northwesternmutual|norton|now|nowruz|nowtv|np|nr|nra|nrw|ntt|nu|nyc|nz|obi|observer|off|office|okinawa|olayan|olayangroup|oldnavy|ollo|om|omega|one|ong|onl|online|onyourside|ooo|open|oracle|orange|org|organic|origins|osaka|otsuka|ott|ovh|pa|page|panasonic|panerai|paris|pars|partners|parts|party|passagens|pay|pccw|pe|pet|pf|pfizer|pg|ph|pharmacy|phd|philips|phone|photo|photography|photos|physio|piaget|pics|pictet|pictures|pid|pin|ping|pink|pioneer|pizza|pk|pl|place|play|playstation|plumbing|plus|pm|pn|pnc|pohl|poker|politie|porn|post|pr|pramerica|praxi|press|prime|pro|prod|productions|prof|progressive|promo|properties|property|protection|pru|prudential|ps|pt|pub|pw|pwc|py|qa|qpon|quebec|quest|qvc|racing|radio|raid|re|read|realestate|realtor|realty|recipes|red|redstone|redumbrella|rehab|reise|reisen|reit|reliance|ren|rent|rentals|repair|report|republican|rest|restaurant|review|reviews|rexroth|rich|richardli|ricoh|rightathome|ril|rio|rip|rmit|ro|rocher|rocks|rodeo|rogers|room|rs|rsvp|ru|rugby|ruhr|run|rw|rwe|ryukyu|sa|saarland|safe|safety|sakura|sale|salon|samsclub|samsung|sandvik|sandvikcoromant|sanofi|sap|sapo|sarl|sas|save|saxo|sb|sbi|sbs|sc|sca|scb|schaeffler|schmidt|scholarships|school|schule|schwarz|science|scjohnson|scor|scot|sd|se|search|seat|secure|security|seek|select|sener|services|ses|seven|sew|sex|sexy|sfr|sg|sh|shangrila|sharp|shaw|shell|shia|shiksha|shoes|shop|shopping|shouji|show|showtime|shriram|si|silk|sina|singles|site|sj|sk|ski|skin|sky|skype|sl|sling|sm|smart|smile|sn|sncf|so|soccer|social|softbank|software|sohu|solar|solutions|song|sony|soy|space|spiegel|spot|spreadbetting|sr|srl|srt|st|stada|staples|star|starhub|statebank|statefarm|statoil|stc|stcgroup|stockholm|storage|store|stream|studio|study|style|su|sucks|supplies|supply|support|surf|surgery|suzuki|sv|swatch|swiftcover|swiss|sx|sy|sydney|symantec|systems|sz|tab|taipei|talk|taobao|target|tatamotors|tatar|tattoo|tax|taxi|tc|tci|td|tdk|team|tech|technology|tel|telecity|telefonica|temasek|tennis|teva|tf|tg|th|thd|theater|theatre|tiaa|tickets|tienda|tiffany|tips|tires|tirol|tj|tjmaxx|tjx|tk|tkmaxx|tl|tm|tmall|tn|to|today|tokyo|tools|top|toray|toshiba|total|tours|town|toyota|toys|tr|trade|trading|training|travel|travelchannel|travelers|travelersinsurance|trust|trv|tt|tube|tui|tunes|tushu|tv|tvs|tw|tz|ua|ubank|ubs|uconnect|ug|uk|unicom|university|uno|uol|ups|us|uy|uz|va|vacations|vana|vanguard|vc|ve|vegas|ventures|verisign|versicherung|vet|vg|vi|viajes|video|vig|viking|villas|vin|vip|virgin|visa|vision|vista|vistaprint|viva|vivo|vlaanderen|vn|vodka|volkswagen|volvo|vote|voting|voto|voyage|vu|vuelos|wales|walmart|walter|wang|wanggou|warman|watch|watches|weather|weatherchannel|webcam|weber|website|wed|wedding|weibo|weir|wf|whoswho|wien|wiki|williamhill|win|windows|wine|winners|wme|wolterskluwer|woodside|work|works|world|wow|ws|wtc|wtf|xbox|xerox|xfinity|xihuan|xin|xn--11b4c3d|xn--1ck2e1b|xn--1qqw23a|xn--2scrj9c|xn--30rr7y|xn--3bst00m|xn--3ds443g|xn--3e0b707e|xn--3hcrj9c|xn--3oq18vl8pn36a|xn--3pxu8k|xn--42c2d9a|xn--45br5cyl|xn--45brj9c|xn--45q11c|xn--4gbrim|xn--54b7fta0cc|xn--55qw42g|xn--55qx5d|xn--5su34j936bgsg|xn--5tzm5g|xn--6frz82g|xn--6qq986b3xl|xn--80adxhks|xn--80ao21a|xn--80aqecdr1a|xn--80asehdb|xn--80aswg|xn--8y0a063a|xn--90a3ac|xn--90ae|xn--90ais|xn--9dbq2a|xn--9et52u|xn--9krt00a|xn--b4w605ferd|xn--bck1b9a5dre4c|xn--c1avg|xn--c2br7g|xn--cck2b3b|xn--cg4bki|xn--clchc0ea0b2g2a9gcd|xn--czr694b|xn--czrs0t|xn--czru2d|xn--d1acj3b|xn--d1alf|xn--e1a4c|xn--eckvdtc9d|xn--efvy88h|xn--estv75g|xn--fct429k|xn--fhbei|xn--fiq228c5hs|xn--fiq64b|xn--fiqs8s|xn--fiqz9s|xn--fjq720a|xn--flw351e|xn--fpcrj9c3d|xn--fzc2c9e2c|xn--fzys8d69uvgm|xn--g2xx48c|xn--gckr3f0f|xn--gecrj9c|xn--gk3at1e|xn--h2breg3eve|xn--h2brj9c|xn--h2brj9c8c|xn--hxt814e|xn--i1b6b1a6a2e|xn--imr513n|xn--io0a7i|xn--j1aef|xn--j1amh|xn--j6w193g|xn--jlq61u9w7b|xn--jvr189m|xn--kcrx77d1x4a|xn--kprw13d|xn--kpry57d|xn--kpu716f|xn--kput3i|xn--l1acc|xn--lgbbat1ad8j|xn--mgb9awbf|xn--mgba3a3ejt|xn--mgba3a4f16a|xn--mgba7c0bbn0a|xn--mgbaakc7dvf|xn--mgbaam7a8h|xn--mgbab2bd|xn--mgbai9azgqp6j|xn--mgbayh7gpa|xn--mgbb9fbpob|xn--mgbbh1a|xn--mgbbh1a71e|xn--mgbc0a9azcg|xn--mgbca7dzdo|xn--mgberp4a5d4ar|xn--mgbgu82a|xn--mgbi4ecexp|xn--mgbpl2fh|xn--mgbt3dhd|xn--mgbtx2b|xn--mgbx4cd0ab|xn--mix891f|xn--mk1bu44c|xn--mxtq1m|xn--ngbc5azd|xn--ngbe9e0a|xn--ngbrx|xn--node|xn--nqv7f|xn--nqv7fs00ema|xn--nyqy26a|xn--o3cw4h|xn--ogbpf8fl|xn--p1acf|xn--p1ai|xn--pbt977c|xn--pgbs0dh|xn--pssy2u|xn--q9jyb4c|xn--qcka1pmc|xn--qxam|xn--rhqv96g|xn--rovu88b|xn--rvc1e0am3e|xn--s9brj9c|xn--ses554g|xn--t60b56a|xn--tckwe|xn--tiq49xqyj|xn--unup4y|xn--vermgensberater-ctb|xn--vermgensberatung-pwb|xn--vhquv|xn--vuq861b|xn--w4r85el8fhu5dnra|xn--w4rs40l|xn--wgbh1c|xn--wgbl6a|xn--xhq521b|xn--xkc2al3hye2a|xn--xkc2dl3a5ee0h|xn--y9a3aq|xn--yfro4i67o|xn--ygbi2ammx|xn--zfr164b|xperia|xxx|xyz|yachts|yahoo|yamaxun|yandex|ye|yodobashi|yoga|yokohama|you|youtube|yt|yun|za|zappos|zara|zero|zip|zippo|zm|zone|zuerich|zw'.split('|'); // macro, see gulpfile.js
  497. var NUMBERS = '0123456789'.split('');
  498. var ALPHANUM = '0123456789abcdefghijklmnopqrstuvwxyz'.split('');
  499. var WHITESPACE = [' ', '\f', '\r', '\t', '\v', '\xA0', '\u1680', '\u180E']; // excluding line breaks
  500. var domainStates = []; // states that jump to DOMAIN on /[a-z0-9]/
  501. var makeState = function makeState(tokenClass) {
  502. return new CharacterState(tokenClass);
  503. };
  504. // Frequently used states
  505. var S_START = makeState();
  506. var S_NUM = makeState(NUM);
  507. var S_DOMAIN = makeState(DOMAIN);
  508. var S_DOMAIN_HYPHEN = makeState(); // domain followed by 1 or more hyphen characters
  509. var S_WS = makeState(WS);
  510. // States for special URL symbols
  511. S_START.on('@', makeState(AT)).on('.', makeState(DOT)).on('+', makeState(PLUS)).on('#', makeState(POUND)).on('?', makeState(QUERY)).on('/', makeState(SLASH)).on('_', makeState(UNDERSCORE)).on(':', makeState(COLON)).on('{', makeState(OPENBRACE)).on('[', makeState(OPENBRACKET)).on('<', makeState(OPENANGLEBRACKET)).on('(', makeState(OPENPAREN)).on('}', makeState(CLOSEBRACE)).on(']', makeState(CLOSEBRACKET)).on('>', makeState(CLOSEANGLEBRACKET)).on(')', makeState(CLOSEPAREN)).on('&', makeState(AMPERSAND)).on([',', ';', '!', '"', '\''], makeState(PUNCTUATION));
  512. // Whitespace jumps
  513. // Tokens of only non-newline whitespace are arbitrarily long
  514. S_START.on('\n', makeState(NL)).on(WHITESPACE, S_WS);
  515. // If any whitespace except newline, more whitespace!
  516. S_WS.on(WHITESPACE, S_WS);
  517. // Generates states for top-level domains
  518. // Note that this is most accurate when tlds are in alphabetical order
  519. for (var i = 0; i < tlds.length; i++) {
  520. var newStates = stateify(tlds[i], S_START, TLD, DOMAIN);
  521. domainStates.push.apply(domainStates, newStates);
  522. }
  523. // Collect the states generated by different protocls
  524. var partialProtocolFileStates = stateify('file', S_START, DOMAIN, DOMAIN);
  525. var partialProtocolFtpStates = stateify('ftp', S_START, DOMAIN, DOMAIN);
  526. var partialProtocolHttpStates = stateify('http', S_START, DOMAIN, DOMAIN);
  527. var partialProtocolMailtoStates = stateify('mailto', S_START, DOMAIN, DOMAIN);
  528. // Add the states to the array of DOMAINeric states
  529. domainStates.push.apply(domainStates, partialProtocolFileStates);
  530. domainStates.push.apply(domainStates, partialProtocolFtpStates);
  531. domainStates.push.apply(domainStates, partialProtocolHttpStates);
  532. domainStates.push.apply(domainStates, partialProtocolMailtoStates);
  533. // Protocol states
  534. var S_PROTOCOL_FILE = partialProtocolFileStates.pop();
  535. var S_PROTOCOL_FTP = partialProtocolFtpStates.pop();
  536. var S_PROTOCOL_HTTP = partialProtocolHttpStates.pop();
  537. var S_MAILTO = partialProtocolMailtoStates.pop();
  538. var S_PROTOCOL_SECURE = makeState(DOMAIN);
  539. var S_FULL_PROTOCOL = makeState(PROTOCOL); // Full protocol ends with COLON
  540. var S_FULL_MAILTO = makeState(MAILTO); // Mailto ends with COLON
  541. // Secure protocols (end with 's')
  542. S_PROTOCOL_FTP.on('s', S_PROTOCOL_SECURE).on(':', S_FULL_PROTOCOL);
  543. S_PROTOCOL_HTTP.on('s', S_PROTOCOL_SECURE).on(':', S_FULL_PROTOCOL);
  544. domainStates.push(S_PROTOCOL_SECURE);
  545. // Become protocol tokens after a COLON
  546. S_PROTOCOL_FILE.on(':', S_FULL_PROTOCOL);
  547. S_PROTOCOL_SECURE.on(':', S_FULL_PROTOCOL);
  548. S_MAILTO.on(':', S_FULL_MAILTO);
  549. // Localhost
  550. var partialLocalhostStates = stateify('localhost', S_START, LOCALHOST, DOMAIN);
  551. domainStates.push.apply(domainStates, partialLocalhostStates);
  552. // Everything else
  553. // DOMAINs make more DOMAINs
  554. // Number and character transitions
  555. S_START.on(NUMBERS, S_NUM);
  556. S_NUM.on('-', S_DOMAIN_HYPHEN).on(NUMBERS, S_NUM).on(ALPHANUM, S_DOMAIN); // number becomes DOMAIN
  557. S_DOMAIN.on('-', S_DOMAIN_HYPHEN).on(ALPHANUM, S_DOMAIN);
  558. // All the generated states should have a jump to DOMAIN
  559. for (var _i = 0; _i < domainStates.length; _i++) {
  560. domainStates[_i].on('-', S_DOMAIN_HYPHEN).on(ALPHANUM, S_DOMAIN);
  561. }
  562. S_DOMAIN_HYPHEN.on('-', S_DOMAIN_HYPHEN).on(NUMBERS, S_DOMAIN).on(ALPHANUM, S_DOMAIN);
  563. // Set default transition
  564. S_START.defaultTransition = makeState(SYM);
  565. /**
  566. Given a string, returns an array of TOKEN instances representing the
  567. composition of that string.
  568. @method run
  569. @param {String} str Input string to scan
  570. @return {Array} Array of TOKEN instances
  571. */
  572. var run = function run(str) {
  573. // The state machine only looks at lowercase strings.
  574. // This selective `toLowerCase` is used because lowercasing the entire
  575. // string causes the length and character position to vary in some in some
  576. // non-English strings. This happens only on V8-based runtimes.
  577. var lowerStr = str.replace(/[A-Z]/g, function (c) {
  578. return c.toLowerCase();
  579. });
  580. var len = str.length;
  581. var tokens = []; // return value
  582. var cursor = 0;
  583. // Tokenize the string
  584. while (cursor < len) {
  585. var state = S_START;
  586. var nextState = null;
  587. var tokenLength = 0;
  588. var latestAccepting = null;
  589. var sinceAccepts = -1;
  590. while (cursor < len && (nextState = state.next(lowerStr[cursor]))) {
  591. state = nextState;
  592. // Keep track of the latest accepting state
  593. if (state.accepts()) {
  594. sinceAccepts = 0;
  595. latestAccepting = state;
  596. } else if (sinceAccepts >= 0) {
  597. sinceAccepts++;
  598. }
  599. tokenLength++;
  600. cursor++;
  601. }
  602. if (sinceAccepts < 0) {
  603. continue;
  604. } // Should never happen
  605. // Roll back to the latest accepting state
  606. cursor -= sinceAccepts;
  607. tokenLength -= sinceAccepts;
  608. // Get the class for the new token
  609. var TOKEN = latestAccepting.emit(); // Current token class
  610. // No more jumps, just make a new token
  611. tokens.push(new TOKEN(str.substr(cursor - tokenLength, tokenLength)));
  612. }
  613. return tokens;
  614. };
  615. var start = S_START;
  616. var scanner = Object.freeze({
  617. State: CharacterState,
  618. TOKENS: text,
  619. run: run,
  620. start: start
  621. });
  622. /******************************************************************************
  623. Multi-Tokens
  624. Tokens composed of arrays of TextTokens
  625. ******************************************************************************/
  626. // Is the given token a valid domain token?
  627. // Should nums be included here?
  628. function isDomainToken(token) {
  629. return token instanceof DOMAIN || token instanceof TLD;
  630. }
  631. /**
  632. Abstract class used for manufacturing tokens of text tokens. That is rather
  633. than the value for a token being a small string of text, it's value an array
  634. of text tokens.
  635. Used for grouping together URLs, emails, hashtags, and other potential
  636. creations.
  637. @class MultiToken
  638. @abstract
  639. */
  640. var MultiToken = createTokenClass();
  641. MultiToken.prototype = {
  642. /**
  643. String representing the type for this token
  644. @property type
  645. @default 'TOKEN'
  646. */
  647. type: 'token',
  648. /**
  649. Is this multitoken a link?
  650. @property isLink
  651. @default false
  652. */
  653. isLink: false,
  654. /**
  655. Return the string this token represents.
  656. @method toString
  657. @return {String}
  658. */
  659. toString: function toString() {
  660. var result = [];
  661. for (var _i2 = 0; _i2 < this.v.length; _i2++) {
  662. result.push(this.v[_i2].toString());
  663. }
  664. return result.join('');
  665. },
  666. /**
  667. What should the value for this token be in the `href` HTML attribute?
  668. Returns the `.toString` value by default.
  669. @method toHref
  670. @return {String}
  671. */
  672. toHref: function toHref() {
  673. return this.toString();
  674. },
  675. /**
  676. Returns a hash of relevant values for this token, which includes keys
  677. * type - Kind of token ('url', 'email', etc.)
  678. * value - Original text
  679. * href - The value that should be added to the anchor tag's href
  680. attribute
  681. @method toObject
  682. @param {String} [protocol] `'http'` by default
  683. @return {Object}
  684. */
  685. toObject: function toObject() {
  686. var protocol = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'http';
  687. return {
  688. type: this.type,
  689. value: this.toString(),
  690. href: this.toHref(protocol)
  691. };
  692. }
  693. };
  694. /**
  695. Represents an arbitrarily mailto email address with the prefix included
  696. @class MAILTO
  697. @extends MultiToken
  698. */
  699. var MAILTOEMAIL = inherits(MultiToken, createTokenClass(), {
  700. type: 'email',
  701. isLink: true
  702. });
  703. /**
  704. Represents a list of tokens making up a valid email address
  705. @class EMAIL
  706. @extends MultiToken
  707. */
  708. var EMAIL = inherits(MultiToken, createTokenClass(), {
  709. type: 'email',
  710. isLink: true,
  711. toHref: function toHref() {
  712. return 'mailto:' + this.toString();
  713. }
  714. });
  715. /**
  716. Represents some plain text
  717. @class TEXT
  718. @extends MultiToken
  719. */
  720. var TEXT = inherits(MultiToken, createTokenClass(), { type: 'text' });
  721. /**
  722. Multi-linebreak token - represents a line break
  723. @class NL
  724. @extends MultiToken
  725. */
  726. var NL$1 = inherits(MultiToken, createTokenClass(), { type: 'nl' });
  727. /**
  728. Represents a list of tokens making up a valid URL
  729. @class URL
  730. @extends MultiToken
  731. */
  732. var URL = inherits(MultiToken, createTokenClass(), {
  733. type: 'url',
  734. isLink: true,
  735. /**
  736. Lowercases relevant parts of the domain and adds the protocol if
  737. required. Note that this will not escape unsafe HTML characters in the
  738. URL.
  739. @method href
  740. @param {String} protocol
  741. @return {String}
  742. */
  743. toHref: function toHref() {
  744. var protocol = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'http';
  745. var hasProtocol = false;
  746. var hasSlashSlash = false;
  747. var tokens = this.v;
  748. var result = [];
  749. var i = 0;
  750. // Make the first part of the domain lowercase
  751. // Lowercase protocol
  752. while (tokens[i] instanceof PROTOCOL) {
  753. hasProtocol = true;
  754. result.push(tokens[i].toString().toLowerCase());
  755. i++;
  756. }
  757. // Skip slash-slash
  758. while (tokens[i] instanceof SLASH) {
  759. hasSlashSlash = true;
  760. result.push(tokens[i].toString());
  761. i++;
  762. }
  763. // Lowercase all other characters in the domain
  764. while (isDomainToken(tokens[i])) {
  765. result.push(tokens[i].toString().toLowerCase());
  766. i++;
  767. }
  768. // Leave all other characters as they were written
  769. for (; i < tokens.length; i++) {
  770. result.push(tokens[i].toString());
  771. }
  772. result = result.join('');
  773. if (!(hasProtocol || hasSlashSlash)) {
  774. result = protocol + '://' + result;
  775. }
  776. return result;
  777. },
  778. hasProtocol: function hasProtocol() {
  779. return this.v[0] instanceof PROTOCOL;
  780. }
  781. });
  782. var multi = Object.freeze({
  783. Base: MultiToken,
  784. MAILTOEMAIL: MAILTOEMAIL,
  785. EMAIL: EMAIL,
  786. NL: NL$1,
  787. TEXT: TEXT,
  788. URL: URL
  789. });
  790. /**
  791. Not exactly parser, more like the second-stage scanner (although we can
  792. theoretically hotswap the code here with a real parser in the future... but
  793. for a little URL-finding utility abstract syntax trees may be a little
  794. overkill).
  795. URL format: http://en.wikipedia.org/wiki/URI_scheme
  796. Email format: http://en.wikipedia.org/wiki/Email_address (links to RFC in
  797. reference)
  798. @module linkify
  799. @submodule parser
  800. @main parser
  801. */
  802. var makeState$1 = function makeState$1(tokenClass) {
  803. return new TokenState(tokenClass);
  804. };
  805. // The universal starting state.
  806. var S_START$1 = makeState$1();
  807. // Intermediate states for URLs. Note that domains that begin with a protocol
  808. // are treated slighly differently from those that don't.
  809. var S_PROTOCOL = makeState$1(); // e.g., 'http:'
  810. var S_MAILTO$1 = makeState$1(); // 'mailto:'
  811. var S_PROTOCOL_SLASH = makeState$1(); // e.g., '/', 'http:/''
  812. var S_PROTOCOL_SLASH_SLASH = makeState$1(); // e.g., '//', 'http://'
  813. var S_DOMAIN$1 = makeState$1(); // parsed string ends with a potential domain name (A)
  814. var S_DOMAIN_DOT = makeState$1(); // (A) domain followed by DOT
  815. var S_TLD = makeState$1(URL); // (A) Simplest possible URL with no query string
  816. var S_TLD_COLON = makeState$1(); // (A) URL followed by colon (potential port number here)
  817. var S_TLD_PORT = makeState$1(URL); // TLD followed by a port number
  818. var S_URL = makeState$1(URL); // Long URL with optional port and maybe query string
  819. var S_URL_NON_ACCEPTING = makeState$1(); // URL followed by some symbols (will not be part of the final URL)
  820. var S_URL_OPENBRACE = makeState$1(); // URL followed by {
  821. var S_URL_OPENBRACKET = makeState$1(); // URL followed by [
  822. var S_URL_OPENANGLEBRACKET = makeState$1(); // URL followed by <
  823. var S_URL_OPENPAREN = makeState$1(); // URL followed by (
  824. var S_URL_OPENBRACE_Q = makeState$1(URL); // URL followed by { and some symbols that the URL can end it
  825. var S_URL_OPENBRACKET_Q = makeState$1(URL); // URL followed by [ and some symbols that the URL can end it
  826. var S_URL_OPENANGLEBRACKET_Q = makeState$1(URL); // URL followed by < and some symbols that the URL can end it
  827. var S_URL_OPENPAREN_Q = makeState$1(URL); // URL followed by ( and some symbols that the URL can end it
  828. var S_URL_OPENBRACE_SYMS = makeState$1(); // S_URL_OPENBRACE_Q followed by some symbols it cannot end it
  829. var S_URL_OPENBRACKET_SYMS = makeState$1(); // S_URL_OPENBRACKET_Q followed by some symbols it cannot end it
  830. var S_URL_OPENANGLEBRACKET_SYMS = makeState$1(); // S_URL_OPENANGLEBRACKET_Q followed by some symbols it cannot end it
  831. var S_URL_OPENPAREN_SYMS = makeState$1(); // S_URL_OPENPAREN_Q followed by some symbols it cannot end it
  832. var S_EMAIL_DOMAIN = makeState$1(); // parsed string starts with local email info + @ with a potential domain name (C)
  833. var S_EMAIL_DOMAIN_DOT = makeState$1(); // (C) domain followed by DOT
  834. var S_EMAIL = makeState$1(EMAIL); // (C) Possible email address (could have more tlds)
  835. var S_EMAIL_COLON = makeState$1(); // (C) URL followed by colon (potential port number here)
  836. var S_EMAIL_PORT = makeState$1(EMAIL); // (C) Email address with a port
  837. var S_MAILTO_EMAIL = makeState$1(MAILTOEMAIL); // Email that begins with the mailto prefix (D)
  838. var S_MAILTO_EMAIL_NON_ACCEPTING = makeState$1(); // (D) Followed by some non-query string chars
  839. var S_LOCALPART = makeState$1(); // Local part of the email address
  840. var S_LOCALPART_AT = makeState$1(); // Local part of the email address plus @
  841. var S_LOCALPART_DOT = makeState$1(); // Local part of the email address plus '.' (localpart cannot end in .)
  842. var S_NL = makeState$1(NL$1); // single new line
  843. // Make path from start to protocol (with '//')
  844. S_START$1.on(NL, S_NL).on(PROTOCOL, S_PROTOCOL).on(MAILTO, S_MAILTO$1).on(SLASH, S_PROTOCOL_SLASH);
  845. S_PROTOCOL.on(SLASH, S_PROTOCOL_SLASH);
  846. S_PROTOCOL_SLASH.on(SLASH, S_PROTOCOL_SLASH_SLASH);
  847. // The very first potential domain name
  848. S_START$1.on(TLD, S_DOMAIN$1).on(DOMAIN, S_DOMAIN$1).on(LOCALHOST, S_TLD).on(NUM, S_DOMAIN$1);
  849. // Force URL for protocol followed by anything sane
  850. S_PROTOCOL_SLASH_SLASH.on(TLD, S_URL).on(DOMAIN, S_URL).on(NUM, S_URL).on(LOCALHOST, S_URL);
  851. // Account for dots and hyphens
  852. // hyphens are usually parts of domain names
  853. S_DOMAIN$1.on(DOT, S_DOMAIN_DOT);
  854. S_EMAIL_DOMAIN.on(DOT, S_EMAIL_DOMAIN_DOT);
  855. // Hyphen can jump back to a domain name
  856. // After the first domain and a dot, we can find either a URL or another domain
  857. S_DOMAIN_DOT.on(TLD, S_TLD).on(DOMAIN, S_DOMAIN$1).on(NUM, S_DOMAIN$1).on(LOCALHOST, S_DOMAIN$1);
  858. S_EMAIL_DOMAIN_DOT.on(TLD, S_EMAIL).on(DOMAIN, S_EMAIL_DOMAIN).on(NUM, S_EMAIL_DOMAIN).on(LOCALHOST, S_EMAIL_DOMAIN);
  859. // S_TLD accepts! But the URL could be longer, try to find a match greedily
  860. // The `run` function should be able to "rollback" to the accepting state
  861. S_TLD.on(DOT, S_DOMAIN_DOT);
  862. S_EMAIL.on(DOT, S_EMAIL_DOMAIN_DOT);
  863. // Become real URLs after `SLASH` or `COLON NUM SLASH`
  864. // Here PSS and non-PSS converge
  865. S_TLD.on(COLON, S_TLD_COLON).on(SLASH, S_URL);
  866. S_TLD_COLON.on(NUM, S_TLD_PORT);
  867. S_TLD_PORT.on(SLASH, S_URL);
  868. S_EMAIL.on(COLON, S_EMAIL_COLON);
  869. S_EMAIL_COLON.on(NUM, S_EMAIL_PORT);
  870. // Types of characters the URL can definitely end in
  871. var qsAccepting = [DOMAIN, AT, LOCALHOST, NUM, PLUS, POUND, PROTOCOL, SLASH, TLD, UNDERSCORE, SYM, AMPERSAND];
  872. // Types of tokens that can follow a URL and be part of the query string
  873. // but cannot be the very last characters
  874. // Characters that cannot appear in the URL at all should be excluded
  875. var qsNonAccepting = [COLON, DOT, QUERY, PUNCTUATION, CLOSEBRACE, CLOSEBRACKET, CLOSEANGLEBRACKET, CLOSEPAREN, OPENBRACE, OPENBRACKET, OPENANGLEBRACKET, OPENPAREN];
  876. // These states are responsible primarily for determining whether or not to
  877. // include the final round bracket.
  878. // URL, followed by an opening bracket
  879. S_URL.on(OPENBRACE, S_URL_OPENBRACE).on(OPENBRACKET, S_URL_OPENBRACKET).on(OPENANGLEBRACKET, S_URL_OPENANGLEBRACKET).on(OPENPAREN, S_URL_OPENPAREN);
  880. // URL with extra symbols at the end, followed by an opening bracket
  881. S_URL_NON_ACCEPTING.on(OPENBRACE, S_URL_OPENBRACE).on(OPENBRACKET, S_URL_OPENBRACKET).on(OPENANGLEBRACKET, S_URL_OPENANGLEBRACKET).on(OPENPAREN, S_URL_OPENPAREN);
  882. // Closing bracket component. This character WILL be included in the URL
  883. S_URL_OPENBRACE.on(CLOSEBRACE, S_URL);
  884. S_URL_OPENBRACKET.on(CLOSEBRACKET, S_URL);
  885. S_URL_OPENANGLEBRACKET.on(CLOSEANGLEBRACKET, S_URL);
  886. S_URL_OPENPAREN.on(CLOSEPAREN, S_URL);
  887. S_URL_OPENBRACE_Q.on(CLOSEBRACE, S_URL);
  888. S_URL_OPENBRACKET_Q.on(CLOSEBRACKET, S_URL);
  889. S_URL_OPENANGLEBRACKET_Q.on(CLOSEANGLEBRACKET, S_URL);
  890. S_URL_OPENPAREN_Q.on(CLOSEPAREN, S_URL);
  891. S_URL_OPENBRACE_SYMS.on(CLOSEBRACE, S_URL);
  892. S_URL_OPENBRACKET_SYMS.on(CLOSEBRACKET, S_URL);
  893. S_URL_OPENANGLEBRACKET_SYMS.on(CLOSEANGLEBRACKET, S_URL);
  894. S_URL_OPENPAREN_SYMS.on(CLOSEPAREN, S_URL);
  895. // URL that beings with an opening bracket, followed by a symbols.
  896. // Note that the final state can still be `S_URL_OPENBRACE_Q` (if the URL only
  897. // has a single opening bracket for some reason).
  898. S_URL_OPENBRACE.on(qsAccepting, S_URL_OPENBRACE_Q);
  899. S_URL_OPENBRACKET.on(qsAccepting, S_URL_OPENBRACKET_Q);
  900. S_URL_OPENANGLEBRACKET.on(qsAccepting, S_URL_OPENANGLEBRACKET_Q);
  901. S_URL_OPENPAREN.on(qsAccepting, S_URL_OPENPAREN_Q);
  902. S_URL_OPENBRACE.on(qsNonAccepting, S_URL_OPENBRACE_SYMS);
  903. S_URL_OPENBRACKET.on(qsNonAccepting, S_URL_OPENBRACKET_SYMS);
  904. S_URL_OPENANGLEBRACKET.on(qsNonAccepting, S_URL_OPENANGLEBRACKET_SYMS);
  905. S_URL_OPENPAREN.on(qsNonAccepting, S_URL_OPENPAREN_SYMS);
  906. // URL that begins with an opening bracket, followed by some symbols
  907. S_URL_OPENBRACE_Q.on(qsAccepting, S_URL_OPENBRACE_Q);
  908. S_URL_OPENBRACKET_Q.on(qsAccepting, S_URL_OPENBRACKET_Q);
  909. S_URL_OPENANGLEBRACKET_Q.on(qsAccepting, S_URL_OPENANGLEBRACKET_Q);
  910. S_URL_OPENPAREN_Q.on(qsAccepting, S_URL_OPENPAREN_Q);
  911. S_URL_OPENBRACE_Q.on(qsNonAccepting, S_URL_OPENBRACE_Q);
  912. S_URL_OPENBRACKET_Q.on(qsNonAccepting, S_URL_OPENBRACKET_Q);
  913. S_URL_OPENANGLEBRACKET_Q.on(qsNonAccepting, S_URL_OPENANGLEBRACKET_Q);
  914. S_URL_OPENPAREN_Q.on(qsNonAccepting, S_URL_OPENPAREN_Q);
  915. S_URL_OPENBRACE_SYMS.on(qsAccepting, S_URL_OPENBRACE_Q);
  916. S_URL_OPENBRACKET_SYMS.on(qsAccepting, S_URL_OPENBRACKET_Q);
  917. S_URL_OPENANGLEBRACKET_SYMS.on(qsAccepting, S_URL_OPENANGLEBRACKET_Q);
  918. S_URL_OPENPAREN_SYMS.on(qsAccepting, S_URL_OPENPAREN_Q);
  919. S_URL_OPENBRACE_SYMS.on(qsNonAccepting, S_URL_OPENBRACE_SYMS);
  920. S_URL_OPENBRACKET_SYMS.on(qsNonAccepting, S_URL_OPENBRACKET_SYMS);
  921. S_URL_OPENANGLEBRACKET_SYMS.on(qsNonAccepting, S_URL_OPENANGLEBRACKET_SYMS);
  922. S_URL_OPENPAREN_SYMS.on(qsNonAccepting, S_URL_OPENPAREN_SYMS);
  923. // Account for the query string
  924. S_URL.on(qsAccepting, S_URL);
  925. S_URL_NON_ACCEPTING.on(qsAccepting, S_URL);
  926. S_URL.on(qsNonAccepting, S_URL_NON_ACCEPTING);
  927. S_URL_NON_ACCEPTING.on(qsNonAccepting, S_URL_NON_ACCEPTING);
  928. // Email address-specific state definitions
  929. // Note: We are not allowing '/' in email addresses since this would interfere
  930. // with real URLs
  931. // For addresses with the mailto prefix
  932. // 'mailto:' followed by anything sane is a valid email
  933. S_MAILTO$1.on(TLD, S_MAILTO_EMAIL).on(DOMAIN, S_MAILTO_EMAIL).on(NUM, S_MAILTO_EMAIL).on(LOCALHOST, S_MAILTO_EMAIL);
  934. // Greedily get more potential valid email values
  935. S_MAILTO_EMAIL.on(qsAccepting, S_MAILTO_EMAIL).on(qsNonAccepting, S_MAILTO_EMAIL_NON_ACCEPTING);
  936. S_MAILTO_EMAIL_NON_ACCEPTING.on(qsAccepting, S_MAILTO_EMAIL).on(qsNonAccepting, S_MAILTO_EMAIL_NON_ACCEPTING);
  937. // For addresses without the mailto prefix
  938. // Tokens allowed in the localpart of the email
  939. var localpartAccepting = [DOMAIN, NUM, PLUS, POUND, QUERY, UNDERSCORE, SYM, AMPERSAND, TLD];
  940. // Some of the tokens in `localpartAccepting` are already accounted for here and
  941. // will not be overwritten (don't worry)
  942. S_DOMAIN$1.on(localpartAccepting, S_LOCALPART).on(AT, S_LOCALPART_AT);
  943. S_TLD.on(localpartAccepting, S_LOCALPART).on(AT, S_LOCALPART_AT);
  944. S_DOMAIN_DOT.on(localpartAccepting, S_LOCALPART);
  945. // Okay we're on a localpart. Now what?
  946. // TODO: IP addresses and what if the email starts with numbers?
  947. S_LOCALPART.on(localpartAccepting, S_LOCALPART).on(AT, S_LOCALPART_AT) // close to an email address now
  948. .on(DOT, S_LOCALPART_DOT);
  949. S_LOCALPART_DOT.on(localpartAccepting, S_LOCALPART);
  950. S_LOCALPART_AT.on(TLD, S_EMAIL_DOMAIN).on(DOMAIN, S_EMAIL_DOMAIN).on(LOCALHOST, S_EMAIL);
  951. // States following `@` defined above
  952. var run$1 = function run$1(tokens) {
  953. var len = tokens.length;
  954. var cursor = 0;
  955. var multis = [];
  956. var textTokens = [];
  957. while (cursor < len) {
  958. var state = S_START$1;
  959. var secondState = null;
  960. var nextState = null;
  961. var multiLength = 0;
  962. var latestAccepting = null;
  963. var sinceAccepts = -1;
  964. while (cursor < len && !(secondState = state.next(tokens[cursor]))) {
  965. // Starting tokens with nowhere to jump to.
  966. // Consider these to be just plain text
  967. textTokens.push(tokens[cursor++]);
  968. }
  969. while (cursor < len && (nextState = secondState || state.next(tokens[cursor]))) {
  970. // Get the next state
  971. secondState = null;
  972. state = nextState;
  973. // Keep track of the latest accepting state
  974. if (state.accepts()) {
  975. sinceAccepts = 0;
  976. latestAccepting = state;
  977. } else if (sinceAccepts >= 0) {
  978. sinceAccepts++;
  979. }
  980. cursor++;
  981. multiLength++;
  982. }
  983. if (sinceAccepts < 0) {
  984. // No accepting state was found, part of a regular text token
  985. // Add all the tokens we looked at to the text tokens array
  986. for (var _i3 = cursor - multiLength; _i3 < cursor; _i3++) {
  987. textTokens.push(tokens[_i3]);
  988. }
  989. } else {
  990. // Accepting state!
  991. // First close off the textTokens (if available)
  992. if (textTokens.length > 0) {
  993. multis.push(new TEXT(textTokens));
  994. textTokens = [];
  995. }
  996. // Roll back to the latest accepting state
  997. cursor -= sinceAccepts;
  998. multiLength -= sinceAccepts;
  999. // Create a new multitoken
  1000. var MULTI = latestAccepting.emit();
  1001. multis.push(new MULTI(tokens.slice(cursor - multiLength, cursor)));
  1002. }
  1003. }
  1004. // Finally close off the textTokens (if available)
  1005. if (textTokens.length > 0) {
  1006. multis.push(new TEXT(textTokens));
  1007. }
  1008. return multis;
  1009. };
  1010. var parser = Object.freeze({
  1011. State: TokenState,
  1012. TOKENS: multi,
  1013. run: run$1,
  1014. start: S_START$1
  1015. });
  1016. if (!Array.isArray) {
  1017. Array.isArray = function (arg) {
  1018. return Object.prototype.toString.call(arg) === '[object Array]';
  1019. };
  1020. }
  1021. /**
  1022. Converts a string into tokens that represent linkable and non-linkable bits
  1023. @method tokenize
  1024. @param {String} str
  1025. @return {Array} tokens
  1026. */
  1027. var tokenize = function tokenize(str) {
  1028. return run$1(run(str));
  1029. };
  1030. /**
  1031. Returns a list of linkable items in the given string.
  1032. */
  1033. var find = function find(str) {
  1034. var type = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
  1035. var tokens = tokenize(str);
  1036. var filtered = [];
  1037. for (var i = 0; i < tokens.length; i++) {
  1038. var token = tokens[i];
  1039. if (token.isLink && (!type || token.type === type)) {
  1040. filtered.push(token.toObject());
  1041. }
  1042. }
  1043. return filtered;
  1044. };
  1045. /**
  1046. Is the given string valid linkable text of some sort
  1047. Note that this does not trim the text for you.
  1048. Optionally pass in a second `type` param, which is the type of link to test
  1049. for.
  1050. For example,
  1051. test(str, 'email');
  1052. Will return `true` if str is a valid email.
  1053. */
  1054. var test = function test(str) {
  1055. var type = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
  1056. var tokens = tokenize(str);
  1057. return tokens.length === 1 && tokens[0].isLink && (!type || tokens[0].type === type);
  1058. };
  1059. exports.find = find;
  1060. exports.inherits = inherits;
  1061. exports.options = options;
  1062. exports.parser = parser;
  1063. exports.scanner = scanner;
  1064. exports.test = test;
  1065. exports.tokenize = tokenize;
  1066. })(self.linkify = self.linkify || {});
  1067. })();