]>
Commit | Line | Data |
---|---|---|
2207d356 DI |
1 | /** |
2 | * The time to wait after a row is changed before it is linkified. This prevents | |
3 | * the costly operation of searching every row multiple times, pntentially a | |
4 | * huge aount of times. | |
5 | */ | |
6 | const TIME_BEFORE_LINKIFY = 200; | |
7 | ||
8 | const badUrlRegex = /https?:\/\/(\/[\/\\w\.-]*)*/; | |
9 | ||
10 | const protocolClause = '(https?:\\/\\/)'; | |
11 | const domainCharacterSet = '[\\da-z\\.-]+'; | |
12 | const negatedDomainCharacterSet = '[^\\da-z\\.-]+'; | |
13 | const domainBodyClause = '(' + domainCharacterSet + ')'; | |
14 | const tldClause = '([a-z\\.]{2,6})'; | |
15 | const ipClause = '((\\d{1,3}\\.){3}\\d{1,3})'; | |
16 | const portClause = '(:\\d{1,5})'; | |
17 | const hostClause = '((' + domainBodyClause + '\\.' + tldClause + ')|' + ipClause + ')' + portClause + '?'; | |
18 | const pathClause = '(\\/[\\/\\w\\.-]*)*'; | |
19 | const negatedPathCharacterSet = '[^\\/\\w\\.-]+'; | |
20 | const bodyClause = hostClause + pathClause; | |
21 | const start = '(?:^|' + negatedDomainCharacterSet + ')('; | |
22 | const end = ')($|' + negatedPathCharacterSet + ')'; | |
23 | const lenientUrlClause = start + protocolClause + '?' + bodyClause + end; | |
24 | const strictUrlClause = start + protocolClause + bodyClause + end; | |
25 | const lenientUrlRegex = new RegExp(lenientUrlClause); | |
26 | const strictUrlRegex = new RegExp(strictUrlClause); | |
27 | ||
28 | export type LinkHandler = (uri: string) => void; | |
29 | ||
30 | export class Linkifier { | |
31 | private _rows: HTMLElement[]; | |
32 | private _rowTimeoutIds: number[]; | |
33 | private _webLinkHandler: LinkHandler; | |
34 | ||
35 | constructor(rows: HTMLElement[]) { | |
36 | this._rows = rows; | |
37 | this._rowTimeoutIds = []; | |
38 | } | |
39 | ||
40 | /** | |
41 | * Queues a row for linkification. | |
42 | * @param {number} rowIndex The index of the row to linkify. | |
43 | */ | |
44 | public linkifyRow(rowIndex: number): void { | |
45 | const timeoutId = this._rowTimeoutIds[rowIndex]; | |
46 | if (timeoutId) { | |
47 | clearTimeout(timeoutId); | |
48 | } | |
49 | this._rowTimeoutIds[rowIndex] = setTimeout(this._linkifyRow.bind(this, rowIndex), TIME_BEFORE_LINKIFY); | |
50 | } | |
51 | ||
52 | public attachWebLinkHandler(handler: LinkHandler): void { | |
53 | this._webLinkHandler = handler; | |
54 | } | |
55 | ||
56 | /** | |
57 | * Linkifies a row. | |
58 | * @param {number} rowIndex The index of the row to linkify. | |
59 | */ | |
60 | private _linkifyRow(rowIndex: number): void { | |
61 | const rowHtml = this._rows[rowIndex].innerHTML; | |
62 | const uri = this._findLinkMatch(rowHtml); | |
63 | if (uri) { | |
64 | const link = '<a href="' + uri + '">' + uri + '</a>'; | |
65 | const newHtml = rowHtml.replace(uri, link); | |
66 | this._rows[rowIndex].innerHTML = newHtml; | |
67 | console.log(this._rows[rowIndex].innerHTML); | |
68 | } | |
69 | } | |
70 | ||
71 | /** | |
72 | * Finds a link match in a piece of HTML. | |
73 | * @param {string} html The HTML to search. | |
74 | * @return The matching URI or null if not found. | |
75 | */ | |
76 | private _findLinkMatch(html): string { | |
77 | const match = html.match(strictUrlRegex); | |
78 | if (!match || match.length === 0) { | |
79 | return null; | |
80 | } | |
81 | return match[1]; | |
82 | } | |
83 | } |