source: node_modules/remarkable/dist/esm/linkify.js

main
Last change on this file was d24f17c, checked in by Aleksandar Panovski <apano77@…>, 15 months ago

Initial commit

  • Property mode set to 100644
File size: 3.8 KB
Line 
1import Autolinker from 'autolinker';
2
3// Autoconvert URL-like texts to links
4
5
6var LINK_SCAN_RE = /www|@|\:\/\//;
7
8
9function isLinkOpen(str) {
10 return /^<a[>\s]/i.test(str);
11}
12function isLinkClose(str) {
13 return /^<\/a\s*>/i.test(str);
14}
15
16// Stupid fabric to avoid singletons, for thread safety.
17// Required for engines like Nashorn.
18//
19function createLinkifier() {
20 var links = [];
21 var autolinker = new Autolinker({
22 stripPrefix: false,
23 url: true,
24 email: true,
25 replaceFn: function (match) {
26 // Only collect matched strings but don't change anything.
27 switch (match.getType()) {
28 /*eslint default-case:0*/
29 case 'url':
30 links.push({
31 text: match.matchedText,
32 url: match.getUrl()
33 });
34 break;
35 case 'email':
36 links.push({
37 text: match.matchedText,
38 // normalize email protocol
39 url: 'mailto:' + match.getEmail().replace(/^mailto:/i, '')
40 });
41 break;
42 }
43 return false;
44 }
45 });
46
47 return {
48 links: links,
49 autolinker: autolinker
50 };
51}
52
53
54function parseTokens(state) {
55 var i, j, l, tokens, token, text, nodes, ln, pos, level, htmlLinkLevel,
56 blockTokens = state.tokens,
57 linkifier = null, links, autolinker;
58
59 for (j = 0, l = blockTokens.length; j < l; j++) {
60 if (blockTokens[j].type !== 'inline') { continue; }
61 tokens = blockTokens[j].children;
62
63 htmlLinkLevel = 0;
64
65 // We scan from the end, to keep position when new tags added.
66 // Use reversed logic in links start/end match
67 for (i = tokens.length - 1; i >= 0; i--) {
68 token = tokens[i];
69
70 // Skip content of markdown links
71 if (token.type === 'link_close') {
72 i--;
73 while (tokens[i].level !== token.level && tokens[i].type !== 'link_open') {
74 i--;
75 }
76 continue;
77 }
78
79 // Skip content of html tag links
80 if (token.type === 'htmltag') {
81 if (isLinkOpen(token.content) && htmlLinkLevel > 0) {
82 htmlLinkLevel--;
83 }
84 if (isLinkClose(token.content)) {
85 htmlLinkLevel++;
86 }
87 }
88 if (htmlLinkLevel > 0) { continue; }
89
90 if (token.type === 'text' && LINK_SCAN_RE.test(token.content)) {
91
92 // Init linkifier in lazy manner, only if required.
93 if (!linkifier) {
94 linkifier = createLinkifier();
95 links = linkifier.links;
96 autolinker = linkifier.autolinker;
97 }
98
99 text = token.content;
100 links.length = 0;
101 autolinker.link(text);
102
103 if (!links.length) { continue; }
104
105 // Now split string to nodes
106 nodes = [];
107 level = token.level;
108
109 for (ln = 0; ln < links.length; ln++) {
110
111 if (!state.inline.validateLink(links[ln].url)) { continue; }
112
113 pos = text.indexOf(links[ln].text);
114
115 if (pos) {
116 nodes.push({
117 type: 'text',
118 content: text.slice(0, pos),
119 level: level
120 });
121 }
122 nodes.push({
123 type: 'link_open',
124 href: links[ln].url,
125 title: '',
126 level: level++
127 });
128 nodes.push({
129 type: 'text',
130 content: links[ln].text,
131 level: level
132 });
133 nodes.push({
134 type: 'link_close',
135 level: --level
136 });
137 text = text.slice(pos + links[ln].text.length);
138 }
139 if (text.length) {
140 nodes.push({
141 type: 'text',
142 content: text,
143 level: level
144 });
145 }
146
147 // replace current node
148 blockTokens[j].children = tokens = [].concat(tokens.slice(0, i), nodes, tokens.slice(i + 1));
149 }
150 }
151 }
152}
153function linkify(md) {
154 md.core.ruler.push('linkify', parseTokens);
155}
156
157export { linkify };
Note: See TracBrowser for help on using the repository browser.