PluginProbe ʕ •ᴥ•ʔ
Admin and Site Enhancements (ASE) / 7.8.13
Admin and Site Enhancements (ASE) v7.8.13
9.1.0 9.0.2 9.0.1 9.0.0 8.9.2 8.9.1 8.9.0 8.8.8 8.8.7 8.8.6 8.8.5 8.8.4 8.8.3 8.8.2 8.8.1 8.8.0 8.7.3 8.7.2 8.7.1 8.2.1 8.2.2 8.2.3 8.3.0 8.3.1 8.3.2 8.4.0 8.4.1 8.4.2 8.5.0 8.5.1 8.5.2 8.6.0 8.6.1 8.6.2 8.7.0 5.0.1 5.0.2 5.0.2.1 5.0.2.2 5.0.2.3 5.0.2.4 5.1.0 5.2.0 5.2.1 5.2.10 5.2.11 5.2.2 5.2.3 5.2.4 5.2.5 5.2.6 5.2.7 5.2.8 5.2.9 5.3.0 5.3.1 5.3.2 5.4.0 5.4.1 5.5.0 5.5.1 5.5.2 5.6.0 5.6.1 5.6.2 5.7.0 5.7.1 5.8.0 5.8.1 6.0.0 6.0.3 6.0.4 6.0.5 6.0.5.1 6.0.6 6.0.7 6.0.8.1 6.1.0 6.1.3 6.2.0 6.2.1 6.2.2 6.2.3 6.2.4 6.2.5 6.2.6 6.2.7 6.3.0 6.3.1 6.3.2 6.4.0 6.5.0 6.5.1 6.6.0 6.7.0 6.8.0 6.8.2 6.8.3 6.9.0 6.9.1 6.9.10 6.9.11 6.9.12 6.9.13.1 6.9.13.2 6.9.2 6.9.3 6.9.4 6.9.5 6.9.6 6.9.7 6.9.8 6.9.9 7.0.0 7.0.2 7.0.2.1 7.0.2.2 7.0.2.3 7.0.3 7.1.0 7.1.1 7.1.2 7.1.3 7.1.4 7.1.5 7.2.0 7.2.1 7.3.0 7.3.1 7.3.2 7.3.3 7.4.0 7.4.2 7.4.4 7.4.5 7.4.6 7.4.7 7.4.8 7.5.0 7.5.1 7.5.2 7.5.3 7.5.4 7.6.0 7.6.1 7.6.1.1 7.6.10 7.6.11 7.6.2 7.6.3 7.6.4 7.6.5 7.6.6 7.6.7 7.6.7.1 7.6.8 7.6.9 7.7.0 7.8.0 7.8.1 7.8.10 7.8.11 7.8.12 7.8.13 7.8.14 7.8.15 7.8.16 7.8.17 7.8.18 7.8.2 7.8.3 7.8.4 7.8.5 7.8.5.1 7.8.6 7.8.7 7.8.8 7.8.9 7.9.0 7.9.1 7.9.10 7.9.11 7.9.2 7.9.3 7.9.4 7.9.5 7.9.6 7.9.7 7.9.8 7.9.9 8.0.0 8.0.1 8.0.2 8.0.3 8.0.4 8.0.5 8.0.6 8.0.7 8.0.8 8.1.0 8.1.1 8.1.2 8.1.3 8.1.4 8.2.0 trunk 1.0.0 1.1.0 1.2.0 1.3.0 1.4.0 1.5.0 1.6.0 1.7.0 1.8.0 1.9.0 2.0.0 2.1.0 2.2.0 2.3.0 2.4.0 2.5.0 2.6.0 2.7.0 2.8.0 2.8.1 2.8.2 2.8.3 2.9.0 3.0.0 3.0.1 3.0.2 3.0.3 3.0.4 3.0.5 3.0.6 3.1.0 3.2.0 3.3.0 3.4.0 3.5.0 3.6.1 3.7.0 3.8.0 3.9.0 3.9.1 3.9.2 4.0.0 4.0.1 4.1.0 4.2.0 4.2.1 4.2.2 4.3.0 4.3.1 4.4.0 4.5.0 4.6.0 4.7.0 4.7.1 4.7.2 4.7.3 4.7.4 4.8.0 4.8.1 4.8.2 4.8.3 4.9.0 4.9.1 4.9.2 4.9.3 5.0.0
admin-site-enhancements / assets / js / codemirror / markdown.js
admin-site-enhancements / assets / js / codemirror Last commit date
codemirror.min.js 1 year ago css.js 1 year ago htmlmixed.js 1 year ago javascript.js 1 year ago markdown.js 1 year ago xml.js 1 year ago
markdown.js
887 lines
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: https://codemirror.net/5/LICENSE
3
4 (function(mod) {
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
6 mod(require("../../lib/codemirror"), require("../xml/xml"), require("../meta"));
7 else if (typeof define == "function" && define.amd) // AMD
8 define(["../../lib/codemirror", "../xml/xml", "../meta"], mod);
9 else // Plain browser env
10 mod(CodeMirror);
11 })(function(CodeMirror) {
12 "use strict";
13
14 CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {
15
16 var htmlMode = CodeMirror.getMode(cmCfg, "text/html");
17 var htmlModeMissing = htmlMode.name == "null"
18
19 function getMode(name) {
20 if (CodeMirror.findModeByName) {
21 var found = CodeMirror.findModeByName(name);
22 if (found) name = found.mime || found.mimes[0];
23 }
24 var mode = CodeMirror.getMode(cmCfg, name);
25 return mode.name == "null" ? null : mode;
26 }
27
28 // Should characters that affect highlighting be highlighted separate?
29 // Does not include characters that will be output (such as `1.` and `-` for lists)
30 if (modeCfg.highlightFormatting === undefined)
31 modeCfg.highlightFormatting = false;
32
33 // Maximum number of nested blockquotes. Set to 0 for infinite nesting.
34 // Excess `>` will emit `error` token.
35 if (modeCfg.maxBlockquoteDepth === undefined)
36 modeCfg.maxBlockquoteDepth = 0;
37
38 // Turn on task lists? ("- [ ] " and "- [x] ")
39 if (modeCfg.taskLists === undefined) modeCfg.taskLists = false;
40
41 // Turn on strikethrough syntax
42 if (modeCfg.strikethrough === undefined)
43 modeCfg.strikethrough = false;
44
45 if (modeCfg.emoji === undefined)
46 modeCfg.emoji = false;
47
48 if (modeCfg.fencedCodeBlockHighlighting === undefined)
49 modeCfg.fencedCodeBlockHighlighting = true;
50
51 if (modeCfg.fencedCodeBlockDefaultMode === undefined)
52 modeCfg.fencedCodeBlockDefaultMode = 'text/plain';
53
54 if (modeCfg.xml === undefined)
55 modeCfg.xml = true;
56
57 // Allow token types to be overridden by user-provided token types.
58 if (modeCfg.tokenTypeOverrides === undefined)
59 modeCfg.tokenTypeOverrides = {};
60
61 var tokenTypes = {
62 header: "header",
63 code: "comment",
64 quote: "quote",
65 list1: "variable-2",
66 list2: "variable-3",
67 list3: "keyword",
68 hr: "hr",
69 image: "image",
70 imageAltText: "image-alt-text",
71 imageMarker: "image-marker",
72 formatting: "formatting",
73 linkInline: "link",
74 linkEmail: "link",
75 linkText: "link",
76 linkHref: "string",
77 em: "em",
78 strong: "strong",
79 strikethrough: "strikethrough",
80 emoji: "builtin"
81 };
82
83 for (var tokenType in tokenTypes) {
84 if (tokenTypes.hasOwnProperty(tokenType) && modeCfg.tokenTypeOverrides[tokenType]) {
85 tokenTypes[tokenType] = modeCfg.tokenTypeOverrides[tokenType];
86 }
87 }
88
89 var hrRE = /^([*\-_])(?:\s*\1){2,}\s*$/
90 , listRE = /^(?:[*\-+]|^[0-9]+([.)]))\s+/
91 , taskListRE = /^\[(x| )\](?=\s)/i // Must follow listRE
92 , atxHeaderRE = modeCfg.allowAtxHeaderWithoutSpace ? /^(#+)/ : /^(#+)(?: |$)/
93 , setextHeaderRE = /^ {0,3}(?:\={1,}|-{2,})\s*$/
94 , textRE = /^[^#!\[\]*_\\<>` "'(~:]+/
95 , fencedCodeRE = /^(~~~+|```+)[ \t]*([\w\/+#-]*)[^\n`]*$/
96 , linkDefRE = /^\s*\[[^\]]+?\]:.*$/ // naive link-definition
97 , punctuation = /[!"#$%&'()*+,\-.\/:;<=>?@\[\\\]^_`{|}~\xA1\xA7\xAB\xB6\xB7\xBB\xBF\u037E\u0387\u055A-\u055F\u0589\u058A\u05BE\u05C0\u05C3\u05C6\u05F3\u05F4\u0609\u060A\u060C\u060D\u061B\u061E\u061F\u066A-\u066D\u06D4\u0700-\u070D\u07F7-\u07F9\u0830-\u083E\u085E\u0964\u0965\u0970\u0AF0\u0DF4\u0E4F\u0E5A\u0E5B\u0F04-\u0F12\u0F14\u0F3A-\u0F3D\u0F85\u0FD0-\u0FD4\u0FD9\u0FDA\u104A-\u104F\u10FB\u1360-\u1368\u1400\u166D\u166E\u169B\u169C\u16EB-\u16ED\u1735\u1736\u17D4-\u17D6\u17D8-\u17DA\u1800-\u180A\u1944\u1945\u1A1E\u1A1F\u1AA0-\u1AA6\u1AA8-\u1AAD\u1B5A-\u1B60\u1BFC-\u1BFF\u1C3B-\u1C3F\u1C7E\u1C7F\u1CC0-\u1CC7\u1CD3\u2010-\u2027\u2030-\u2043\u2045-\u2051\u2053-\u205E\u207D\u207E\u208D\u208E\u2308-\u230B\u2329\u232A\u2768-\u2775\u27C5\u27C6\u27E6-\u27EF\u2983-\u2998\u29D8-\u29DB\u29FC\u29FD\u2CF9-\u2CFC\u2CFE\u2CFF\u2D70\u2E00-\u2E2E\u2E30-\u2E42\u3001-\u3003\u3008-\u3011\u3014-\u301F\u3030\u303D\u30A0\u30FB\uA4FE\uA4FF\uA60D-\uA60F\uA673\uA67E\uA6F2-\uA6F7\uA874-\uA877\uA8CE\uA8CF\uA8F8-\uA8FA\uA8FC\uA92E\uA92F\uA95F\uA9C1-\uA9CD\uA9DE\uA9DF\uAA5C-\uAA5F\uAADE\uAADF\uAAF0\uAAF1\uABEB\uFD3E\uFD3F\uFE10-\uFE19\uFE30-\uFE52\uFE54-\uFE61\uFE63\uFE68\uFE6A\uFE6B\uFF01-\uFF03\uFF05-\uFF0A\uFF0C-\uFF0F\uFF1A\uFF1B\uFF1F\uFF20\uFF3B-\uFF3D\uFF3F\uFF5B\uFF5D\uFF5F-\uFF65]|\uD800[\uDD00-\uDD02\uDF9F\uDFD0]|\uD801\uDD6F|\uD802[\uDC57\uDD1F\uDD3F\uDE50-\uDE58\uDE7F\uDEF0-\uDEF6\uDF39-\uDF3F\uDF99-\uDF9C]|\uD804[\uDC47-\uDC4D\uDCBB\uDCBC\uDCBE-\uDCC1\uDD40-\uDD43\uDD74\uDD75\uDDC5-\uDDC9\uDDCD\uDDDB\uDDDD-\uDDDF\uDE38-\uDE3D\uDEA9]|\uD805[\uDCC6\uDDC1-\uDDD7\uDE41-\uDE43\uDF3C-\uDF3E]|\uD809[\uDC70-\uDC74]|\uD81A[\uDE6E\uDE6F\uDEF5\uDF37-\uDF3B\uDF44]|\uD82F\uDC9F|\uD836[\uDE87-\uDE8B]/
98 , expandedTab = " " // CommonMark specifies tab as 4 spaces
99
100 function switchInline(stream, state, f) {
101 state.f = state.inline = f;
102 return f(stream, state);
103 }
104
105 function switchBlock(stream, state, f) {
106 state.f = state.block = f;
107 return f(stream, state);
108 }
109
110 function lineIsEmpty(line) {
111 return !line || !/\S/.test(line.string)
112 }
113
114 // Blocks
115
116 function blankLine(state) {
117 // Reset linkTitle state
118 state.linkTitle = false;
119 state.linkHref = false;
120 state.linkText = false;
121 // Reset EM state
122 state.em = false;
123 // Reset STRONG state
124 state.strong = false;
125 // Reset strikethrough state
126 state.strikethrough = false;
127 // Reset state.quote
128 state.quote = 0;
129 // Reset state.indentedCode
130 state.indentedCode = false;
131 if (state.f == htmlBlock) {
132 var exit = htmlModeMissing
133 if (!exit) {
134 var inner = CodeMirror.innerMode(htmlMode, state.htmlState)
135 exit = inner.mode.name == "xml" && inner.state.tagStart === null &&
136 (!inner.state.context && inner.state.tokenize.isInText)
137 }
138 if (exit) {
139 state.f = inlineNormal;
140 state.block = blockNormal;
141 state.htmlState = null;
142 }
143 }
144 // Reset state.trailingSpace
145 state.trailingSpace = 0;
146 state.trailingSpaceNewLine = false;
147 // Mark this line as blank
148 state.prevLine = state.thisLine
149 state.thisLine = {stream: null}
150 return null;
151 }
152
153 function blockNormal(stream, state) {
154 var firstTokenOnLine = stream.column() === state.indentation;
155 var prevLineLineIsEmpty = lineIsEmpty(state.prevLine.stream);
156 var prevLineIsIndentedCode = state.indentedCode;
157 var prevLineIsHr = state.prevLine.hr;
158 var prevLineIsList = state.list !== false;
159 var maxNonCodeIndentation = (state.listStack[state.listStack.length - 1] || 0) + 3;
160
161 state.indentedCode = false;
162
163 var lineIndentation = state.indentation;
164 // compute once per line (on first token)
165 if (state.indentationDiff === null) {
166 state.indentationDiff = state.indentation;
167 if (prevLineIsList) {
168 state.list = null;
169 // While this list item's marker's indentation is less than the deepest
170 // list item's content's indentation,pop the deepest list item
171 // indentation off the stack, and update block indentation state
172 while (lineIndentation < state.listStack[state.listStack.length - 1]) {
173 state.listStack.pop();
174 if (state.listStack.length) {
175 state.indentation = state.listStack[state.listStack.length - 1];
176 // less than the first list's indent -> the line is no longer a list
177 } else {
178 state.list = false;
179 }
180 }
181 if (state.list !== false) {
182 state.indentationDiff = lineIndentation - state.listStack[state.listStack.length - 1]
183 }
184 }
185 }
186
187 // not comprehensive (currently only for setext detection purposes)
188 var allowsInlineContinuation = (
189 !prevLineLineIsEmpty && !prevLineIsHr && !state.prevLine.header &&
190 (!prevLineIsList || !prevLineIsIndentedCode) &&
191 !state.prevLine.fencedCodeEnd
192 );
193
194 var isHr = (state.list === false || prevLineIsHr || prevLineLineIsEmpty) &&
195 state.indentation <= maxNonCodeIndentation && stream.match(hrRE);
196
197 var match = null;
198 if (state.indentationDiff >= 4 && (prevLineIsIndentedCode || state.prevLine.fencedCodeEnd ||
199 state.prevLine.header || prevLineLineIsEmpty)) {
200 stream.skipToEnd();
201 state.indentedCode = true;
202 return tokenTypes.code;
203 } else if (stream.eatSpace()) {
204 return null;
205 } else if (firstTokenOnLine && state.indentation <= maxNonCodeIndentation && (match = stream.match(atxHeaderRE)) && match[1].length <= 6) {
206 state.quote = 0;
207 state.header = match[1].length;
208 state.thisLine.header = true;
209 if (modeCfg.highlightFormatting) state.formatting = "header";
210 state.f = state.inline;
211 return getType(state);
212 } else if (state.indentation <= maxNonCodeIndentation && stream.eat('>')) {
213 state.quote = firstTokenOnLine ? 1 : state.quote + 1;
214 if (modeCfg.highlightFormatting) state.formatting = "quote";
215 stream.eatSpace();
216 return getType(state);
217 } else if (!isHr && !state.setext && firstTokenOnLine && state.indentation <= maxNonCodeIndentation && (match = stream.match(listRE))) {
218 var listType = match[1] ? "ol" : "ul";
219
220 state.indentation = lineIndentation + stream.current().length;
221 state.list = true;
222 state.quote = 0;
223
224 // Add this list item's content's indentation to the stack
225 state.listStack.push(state.indentation);
226 // Reset inline styles which shouldn't propagate across list items
227 state.em = false;
228 state.strong = false;
229 state.code = false;
230 state.strikethrough = false;
231
232 if (modeCfg.taskLists && stream.match(taskListRE, false)) {
233 state.taskList = true;
234 }
235 state.f = state.inline;
236 if (modeCfg.highlightFormatting) state.formatting = ["list", "list-" + listType];
237 return getType(state);
238 } else if (firstTokenOnLine && state.indentation <= maxNonCodeIndentation && (match = stream.match(fencedCodeRE, true))) {
239 state.quote = 0;
240 state.fencedEndRE = new RegExp(match[1] + "+ *$");
241 // try switching mode
242 state.localMode = modeCfg.fencedCodeBlockHighlighting && getMode(match[2] || modeCfg.fencedCodeBlockDefaultMode );
243 if (state.localMode) state.localState = CodeMirror.startState(state.localMode);
244 state.f = state.block = local;
245 if (modeCfg.highlightFormatting) state.formatting = "code-block";
246 state.code = -1
247 return getType(state);
248 // SETEXT has lowest block-scope precedence after HR, so check it after
249 // the others (code, blockquote, list...)
250 } else if (
251 // if setext set, indicates line after ---/===
252 state.setext || (
253 // line before ---/===
254 (!allowsInlineContinuation || !prevLineIsList) && !state.quote && state.list === false &&
255 !state.code && !isHr && !linkDefRE.test(stream.string) &&
256 (match = stream.lookAhead(1)) && (match = match.match(setextHeaderRE))
257 )
258 ) {
259 if ( !state.setext ) {
260 state.header = match[0].charAt(0) == '=' ? 1 : 2;
261 state.setext = state.header;
262 } else {
263 state.header = state.setext;
264 // has no effect on type so we can reset it now
265 state.setext = 0;
266 stream.skipToEnd();
267 if (modeCfg.highlightFormatting) state.formatting = "header";
268 }
269 state.thisLine.header = true;
270 state.f = state.inline;
271 return getType(state);
272 } else if (isHr) {
273 stream.skipToEnd();
274 state.hr = true;
275 state.thisLine.hr = true;
276 return tokenTypes.hr;
277 } else if (stream.peek() === '[') {
278 return switchInline(stream, state, footnoteLink);
279 }
280
281 return switchInline(stream, state, state.inline);
282 }
283
284 function htmlBlock(stream, state) {
285 var style = htmlMode.token(stream, state.htmlState);
286 if (!htmlModeMissing) {
287 var inner = CodeMirror.innerMode(htmlMode, state.htmlState)
288 if ((inner.mode.name == "xml" && inner.state.tagStart === null &&
289 (!inner.state.context && inner.state.tokenize.isInText)) ||
290 (state.md_inside && stream.current().indexOf(">") > -1)) {
291 state.f = inlineNormal;
292 state.block = blockNormal;
293 state.htmlState = null;
294 }
295 }
296 return style;
297 }
298
299 function local(stream, state) {
300 var currListInd = state.listStack[state.listStack.length - 1] || 0;
301 var hasExitedList = state.indentation < currListInd;
302 var maxFencedEndInd = currListInd + 3;
303 if (state.fencedEndRE && state.indentation <= maxFencedEndInd && (hasExitedList || stream.match(state.fencedEndRE))) {
304 if (modeCfg.highlightFormatting) state.formatting = "code-block";
305 var returnType;
306 if (!hasExitedList) returnType = getType(state)
307 state.localMode = state.localState = null;
308 state.block = blockNormal;
309 state.f = inlineNormal;
310 state.fencedEndRE = null;
311 state.code = 0
312 state.thisLine.fencedCodeEnd = true;
313 if (hasExitedList) return switchBlock(stream, state, state.block);
314 return returnType;
315 } else if (state.localMode) {
316 return state.localMode.token(stream, state.localState);
317 } else {
318 stream.skipToEnd();
319 return tokenTypes.code;
320 }
321 }
322
323 // Inline
324 function getType(state) {
325 var styles = [];
326
327 if (state.formatting) {
328 styles.push(tokenTypes.formatting);
329
330 if (typeof state.formatting === "string") state.formatting = [state.formatting];
331
332 for (var i = 0; i < state.formatting.length; i++) {
333 styles.push(tokenTypes.formatting + "-" + state.formatting[i]);
334
335 if (state.formatting[i] === "header") {
336 styles.push(tokenTypes.formatting + "-" + state.formatting[i] + "-" + state.header);
337 }
338
339 // Add `formatting-quote` and `formatting-quote-#` for blockquotes
340 // Add `error` instead if the maximum blockquote nesting depth is passed
341 if (state.formatting[i] === "quote") {
342 if (!modeCfg.maxBlockquoteDepth || modeCfg.maxBlockquoteDepth >= state.quote) {
343 styles.push(tokenTypes.formatting + "-" + state.formatting[i] + "-" + state.quote);
344 } else {
345 styles.push("error");
346 }
347 }
348 }
349 }
350
351 if (state.taskOpen) {
352 styles.push("meta");
353 return styles.length ? styles.join(' ') : null;
354 }
355 if (state.taskClosed) {
356 styles.push("property");
357 return styles.length ? styles.join(' ') : null;
358 }
359
360 if (state.linkHref) {
361 styles.push(tokenTypes.linkHref, "url");
362 } else { // Only apply inline styles to non-url text
363 if (state.strong) { styles.push(tokenTypes.strong); }
364 if (state.em) { styles.push(tokenTypes.em); }
365 if (state.strikethrough) { styles.push(tokenTypes.strikethrough); }
366 if (state.emoji) { styles.push(tokenTypes.emoji); }
367 if (state.linkText) { styles.push(tokenTypes.linkText); }
368 if (state.code) { styles.push(tokenTypes.code); }
369 if (state.image) { styles.push(tokenTypes.image); }
370 if (state.imageAltText) { styles.push(tokenTypes.imageAltText, "link"); }
371 if (state.imageMarker) { styles.push(tokenTypes.imageMarker); }
372 }
373
374 if (state.header) { styles.push(tokenTypes.header, tokenTypes.header + "-" + state.header); }
375
376 if (state.quote) {
377 styles.push(tokenTypes.quote);
378
379 // Add `quote-#` where the maximum for `#` is modeCfg.maxBlockquoteDepth
380 if (!modeCfg.maxBlockquoteDepth || modeCfg.maxBlockquoteDepth >= state.quote) {
381 styles.push(tokenTypes.quote + "-" + state.quote);
382 } else {
383 styles.push(tokenTypes.quote + "-" + modeCfg.maxBlockquoteDepth);
384 }
385 }
386
387 if (state.list !== false) {
388 var listMod = (state.listStack.length - 1) % 3;
389 if (!listMod) {
390 styles.push(tokenTypes.list1);
391 } else if (listMod === 1) {
392 styles.push(tokenTypes.list2);
393 } else {
394 styles.push(tokenTypes.list3);
395 }
396 }
397
398 if (state.trailingSpaceNewLine) {
399 styles.push("trailing-space-new-line");
400 } else if (state.trailingSpace) {
401 styles.push("trailing-space-" + (state.trailingSpace % 2 ? "a" : "b"));
402 }
403
404 return styles.length ? styles.join(' ') : null;
405 }
406
407 function handleText(stream, state) {
408 if (stream.match(textRE, true)) {
409 return getType(state);
410 }
411 return undefined;
412 }
413
414 function inlineNormal(stream, state) {
415 var style = state.text(stream, state);
416 if (typeof style !== 'undefined')
417 return style;
418
419 if (state.list) { // List marker (*, +, -, 1., etc)
420 state.list = null;
421 return getType(state);
422 }
423
424 if (state.taskList) {
425 var taskOpen = stream.match(taskListRE, true)[1] === " ";
426 if (taskOpen) state.taskOpen = true;
427 else state.taskClosed = true;
428 if (modeCfg.highlightFormatting) state.formatting = "task";
429 state.taskList = false;
430 return getType(state);
431 }
432
433 state.taskOpen = false;
434 state.taskClosed = false;
435
436 if (state.header && stream.match(/^#+$/, true)) {
437 if (modeCfg.highlightFormatting) state.formatting = "header";
438 return getType(state);
439 }
440
441 var ch = stream.next();
442
443 // Matches link titles present on next line
444 if (state.linkTitle) {
445 state.linkTitle = false;
446 var matchCh = ch;
447 if (ch === '(') {
448 matchCh = ')';
449 }
450 matchCh = (matchCh+'').replace(/([.?*+^\[\]\\(){}|-])/g, "\\$1");
451 var regex = '^\\s*(?:[^' + matchCh + '\\\\]+|\\\\\\\\|\\\\.)' + matchCh;
452 if (stream.match(new RegExp(regex), true)) {
453 return tokenTypes.linkHref;
454 }
455 }
456
457 // If this block is changed, it may need to be updated in GFM mode
458 if (ch === '`') {
459 var previousFormatting = state.formatting;
460 if (modeCfg.highlightFormatting) state.formatting = "code";
461 stream.eatWhile('`');
462 var count = stream.current().length
463 if (state.code == 0 && (!state.quote || count == 1)) {
464 state.code = count
465 return getType(state)
466 } else if (count == state.code) { // Must be exact
467 var t = getType(state)
468 state.code = 0
469 return t
470 } else {
471 state.formatting = previousFormatting
472 return getType(state)
473 }
474 } else if (state.code) {
475 return getType(state);
476 }
477
478 if (ch === '\\') {
479 stream.next();
480 if (modeCfg.highlightFormatting) {
481 var type = getType(state);
482 var formattingEscape = tokenTypes.formatting + "-escape";
483 return type ? type + " " + formattingEscape : formattingEscape;
484 }
485 }
486
487 if (ch === '!' && stream.match(/\[[^\]]*\] ?(?:\(|\[)/, false)) {
488 state.imageMarker = true;
489 state.image = true;
490 if (modeCfg.highlightFormatting) state.formatting = "image";
491 return getType(state);
492 }
493
494 if (ch === '[' && state.imageMarker && stream.match(/[^\]]*\](\(.*?\)| ?\[.*?\])/, false)) {
495 state.imageMarker = false;
496 state.imageAltText = true
497 if (modeCfg.highlightFormatting) state.formatting = "image";
498 return getType(state);
499 }
500
501 if (ch === ']' && state.imageAltText) {
502 if (modeCfg.highlightFormatting) state.formatting = "image";
503 var type = getType(state);
504 state.imageAltText = false;
505 state.image = false;
506 state.inline = state.f = linkHref;
507 return type;
508 }
509
510 if (ch === '[' && !state.image) {
511 if (state.linkText && stream.match(/^.*?\]/)) return getType(state)
512 state.linkText = true;
513 if (modeCfg.highlightFormatting) state.formatting = "link";
514 return getType(state);
515 }
516
517 if (ch === ']' && state.linkText) {
518 if (modeCfg.highlightFormatting) state.formatting = "link";
519 var type = getType(state);
520 state.linkText = false;
521 state.inline = state.f = stream.match(/\(.*?\)| ?\[.*?\]/, false) ? linkHref : inlineNormal
522 return type;
523 }
524
525 if (ch === '<' && stream.match(/^(https?|ftps?):\/\/(?:[^\\>]|\\.)+>/, false)) {
526 state.f = state.inline = linkInline;
527 if (modeCfg.highlightFormatting) state.formatting = "link";
528 var type = getType(state);
529 if (type){
530 type += " ";
531 } else {
532 type = "";
533 }
534 return type + tokenTypes.linkInline;
535 }
536
537 if (ch === '<' && stream.match(/^[^> \\]+@(?:[^\\>]|\\.)+>/, false)) {
538 state.f = state.inline = linkInline;
539 if (modeCfg.highlightFormatting) state.formatting = "link";
540 var type = getType(state);
541 if (type){
542 type += " ";
543 } else {
544 type = "";
545 }
546 return type + tokenTypes.linkEmail;
547 }
548
549 if (modeCfg.xml && ch === '<' && stream.match(/^(!--|\?|!\[CDATA\[|[a-z][a-z0-9-]*(?:\s+[a-z_:.\-]+(?:\s*=\s*[^>]+)?)*\s*(?:>|$))/i, false)) {
550 var end = stream.string.indexOf(">", stream.pos);
551 if (end != -1) {
552 var atts = stream.string.substring(stream.start, end);
553 if (/markdown\s*=\s*('|"){0,1}1('|"){0,1}/.test(atts)) state.md_inside = true;
554 }
555 stream.backUp(1);
556 state.htmlState = CodeMirror.startState(htmlMode);
557 return switchBlock(stream, state, htmlBlock);
558 }
559
560 if (modeCfg.xml && ch === '<' && stream.match(/^\/\w*?>/)) {
561 state.md_inside = false;
562 return "tag";
563 } else if (ch === "*" || ch === "_") {
564 var len = 1, before = stream.pos == 1 ? " " : stream.string.charAt(stream.pos - 2)
565 while (len < 3 && stream.eat(ch)) len++
566 var after = stream.peek() || " "
567 // See http://spec.commonmark.org/0.27/#emphasis-and-strong-emphasis
568 var leftFlanking = !/\s/.test(after) && (!punctuation.test(after) || /\s/.test(before) || punctuation.test(before))
569 var rightFlanking = !/\s/.test(before) && (!punctuation.test(before) || /\s/.test(after) || punctuation.test(after))
570 var setEm = null, setStrong = null
571 if (len % 2) { // Em
572 if (!state.em && leftFlanking && (ch === "*" || !rightFlanking || punctuation.test(before)))
573 setEm = true
574 else if (state.em == ch && rightFlanking && (ch === "*" || !leftFlanking || punctuation.test(after)))
575 setEm = false
576 }
577 if (len > 1) { // Strong
578 if (!state.strong && leftFlanking && (ch === "*" || !rightFlanking || punctuation.test(before)))
579 setStrong = true
580 else if (state.strong == ch && rightFlanking && (ch === "*" || !leftFlanking || punctuation.test(after)))
581 setStrong = false
582 }
583 if (setStrong != null || setEm != null) {
584 if (modeCfg.highlightFormatting) state.formatting = setEm == null ? "strong" : setStrong == null ? "em" : "strong em"
585 if (setEm === true) state.em = ch
586 if (setStrong === true) state.strong = ch
587 var t = getType(state)
588 if (setEm === false) state.em = false
589 if (setStrong === false) state.strong = false
590 return t
591 }
592 } else if (ch === ' ') {
593 if (stream.eat('*') || stream.eat('_')) { // Probably surrounded by spaces
594 if (stream.peek() === ' ') { // Surrounded by spaces, ignore
595 return getType(state);
596 } else { // Not surrounded by spaces, back up pointer
597 stream.backUp(1);
598 }
599 }
600 }
601
602 if (modeCfg.strikethrough) {
603 if (ch === '~' && stream.eatWhile(ch)) {
604 if (state.strikethrough) {// Remove strikethrough
605 if (modeCfg.highlightFormatting) state.formatting = "strikethrough";
606 var t = getType(state);
607 state.strikethrough = false;
608 return t;
609 } else if (stream.match(/^[^\s]/, false)) {// Add strikethrough
610 state.strikethrough = true;
611 if (modeCfg.highlightFormatting) state.formatting = "strikethrough";
612 return getType(state);
613 }
614 } else if (ch === ' ') {
615 if (stream.match('~~', true)) { // Probably surrounded by space
616 if (stream.peek() === ' ') { // Surrounded by spaces, ignore
617 return getType(state);
618 } else { // Not surrounded by spaces, back up pointer
619 stream.backUp(2);
620 }
621 }
622 }
623 }
624
625 if (modeCfg.emoji && ch === ":" && stream.match(/^(?:[a-z_\d+][a-z_\d+-]*|\-[a-z_\d+][a-z_\d+-]*):/)) {
626 state.emoji = true;
627 if (modeCfg.highlightFormatting) state.formatting = "emoji";
628 var retType = getType(state);
629 state.emoji = false;
630 return retType;
631 }
632
633 if (ch === ' ') {
634 if (stream.match(/^ +$/, false)) {
635 state.trailingSpace++;
636 } else if (state.trailingSpace) {
637 state.trailingSpaceNewLine = true;
638 }
639 }
640
641 return getType(state);
642 }
643
644 function linkInline(stream, state) {
645 var ch = stream.next();
646
647 if (ch === ">") {
648 state.f = state.inline = inlineNormal;
649 if (modeCfg.highlightFormatting) state.formatting = "link";
650 var type = getType(state);
651 if (type){
652 type += " ";
653 } else {
654 type = "";
655 }
656 return type + tokenTypes.linkInline;
657 }
658
659 stream.match(/^[^>]+/, true);
660
661 return tokenTypes.linkInline;
662 }
663
664 function linkHref(stream, state) {
665 // Check if space, and return NULL if so (to avoid marking the space)
666 if(stream.eatSpace()){
667 return null;
668 }
669 var ch = stream.next();
670 if (ch === '(' || ch === '[') {
671 state.f = state.inline = getLinkHrefInside(ch === "(" ? ")" : "]");
672 if (modeCfg.highlightFormatting) state.formatting = "link-string";
673 state.linkHref = true;
674 return getType(state);
675 }
676 return 'error';
677 }
678
679 var linkRE = {
680 ")": /^(?:[^\\\(\)]|\\.|\((?:[^\\\(\)]|\\.)*\))*?(?=\))/,
681 "]": /^(?:[^\\\[\]]|\\.|\[(?:[^\\\[\]]|\\.)*\])*?(?=\])/
682 }
683
684 function getLinkHrefInside(endChar) {
685 return function(stream, state) {
686 var ch = stream.next();
687
688 if (ch === endChar) {
689 state.f = state.inline = inlineNormal;
690 if (modeCfg.highlightFormatting) state.formatting = "link-string";
691 var returnState = getType(state);
692 state.linkHref = false;
693 return returnState;
694 }
695
696 stream.match(linkRE[endChar])
697 state.linkHref = true;
698 return getType(state);
699 };
700 }
701
702 function footnoteLink(stream, state) {
703 if (stream.match(/^([^\]\\]|\\.)*\]:/, false)) {
704 state.f = footnoteLinkInside;
705 stream.next(); // Consume [
706 if (modeCfg.highlightFormatting) state.formatting = "link";
707 state.linkText = true;
708 return getType(state);
709 }
710 return switchInline(stream, state, inlineNormal);
711 }
712
713 function footnoteLinkInside(stream, state) {
714 if (stream.match(']:', true)) {
715 state.f = state.inline = footnoteUrl;
716 if (modeCfg.highlightFormatting) state.formatting = "link";
717 var returnType = getType(state);
718 state.linkText = false;
719 return returnType;
720 }
721
722 stream.match(/^([^\]\\]|\\.)+/, true);
723
724 return tokenTypes.linkText;
725 }
726
727 function footnoteUrl(stream, state) {
728 // Check if space, and return NULL if so (to avoid marking the space)
729 if(stream.eatSpace()){
730 return null;
731 }
732 // Match URL
733 stream.match(/^[^\s]+/, true);
734 // Check for link title
735 if (stream.peek() === undefined) { // End of line, set flag to check next line
736 state.linkTitle = true;
737 } else { // More content on line, check if link title
738 stream.match(/^(?:\s+(?:"(?:[^"\\]|\\.)+"|'(?:[^'\\]|\\.)+'|\((?:[^)\\]|\\.)+\)))?/, true);
739 }
740 state.f = state.inline = inlineNormal;
741 return tokenTypes.linkHref + " url";
742 }
743
744 var mode = {
745 startState: function() {
746 return {
747 f: blockNormal,
748
749 prevLine: {stream: null},
750 thisLine: {stream: null},
751
752 block: blockNormal,
753 htmlState: null,
754 indentation: 0,
755
756 inline: inlineNormal,
757 text: handleText,
758
759 formatting: false,
760 linkText: false,
761 linkHref: false,
762 linkTitle: false,
763 code: 0,
764 em: false,
765 strong: false,
766 header: 0,
767 setext: 0,
768 hr: false,
769 taskList: false,
770 list: false,
771 listStack: [],
772 quote: 0,
773 trailingSpace: 0,
774 trailingSpaceNewLine: false,
775 strikethrough: false,
776 emoji: false,
777 fencedEndRE: null
778 };
779 },
780
781 copyState: function(s) {
782 return {
783 f: s.f,
784
785 prevLine: s.prevLine,
786 thisLine: s.thisLine,
787
788 block: s.block,
789 htmlState: s.htmlState && CodeMirror.copyState(htmlMode, s.htmlState),
790 indentation: s.indentation,
791
792 localMode: s.localMode,
793 localState: s.localMode ? CodeMirror.copyState(s.localMode, s.localState) : null,
794
795 inline: s.inline,
796 text: s.text,
797 formatting: false,
798 linkText: s.linkText,
799 linkTitle: s.linkTitle,
800 linkHref: s.linkHref,
801 code: s.code,
802 em: s.em,
803 strong: s.strong,
804 strikethrough: s.strikethrough,
805 emoji: s.emoji,
806 header: s.header,
807 setext: s.setext,
808 hr: s.hr,
809 taskList: s.taskList,
810 list: s.list,
811 listStack: s.listStack.slice(0),
812 quote: s.quote,
813 indentedCode: s.indentedCode,
814 trailingSpace: s.trailingSpace,
815 trailingSpaceNewLine: s.trailingSpaceNewLine,
816 md_inside: s.md_inside,
817 fencedEndRE: s.fencedEndRE
818 };
819 },
820
821 token: function(stream, state) {
822
823 // Reset state.formatting
824 state.formatting = false;
825
826 if (stream != state.thisLine.stream) {
827 state.header = 0;
828 state.hr = false;
829
830 if (stream.match(/^\s*$/, true)) {
831 blankLine(state);
832 return null;
833 }
834
835 state.prevLine = state.thisLine
836 state.thisLine = {stream: stream}
837
838 // Reset state.taskList
839 state.taskList = false;
840
841 // Reset state.trailingSpace
842 state.trailingSpace = 0;
843 state.trailingSpaceNewLine = false;
844
845 if (!state.localState) {
846 state.f = state.block;
847 if (state.f != htmlBlock) {
848 var indentation = stream.match(/^\s*/, true)[0].replace(/\t/g, expandedTab).length;
849 state.indentation = indentation;
850 state.indentationDiff = null;
851 if (indentation > 0) return null;
852 }
853 }
854 }
855 return state.f(stream, state);
856 },
857
858 innerMode: function(state) {
859 if (state.block == htmlBlock) return {state: state.htmlState, mode: htmlMode};
860 if (state.localState) return {state: state.localState, mode: state.localMode};
861 return {state: state, mode: mode};
862 },
863
864 indent: function(state, textAfter, line) {
865 if (state.block == htmlBlock && htmlMode.indent) return htmlMode.indent(state.htmlState, textAfter, line)
866 if (state.localState && state.localMode.indent) return state.localMode.indent(state.localState, textAfter, line)
867 return CodeMirror.Pass
868 },
869
870 blankLine: blankLine,
871
872 getType: getType,
873
874 blockCommentStart: "<!--",
875 blockCommentEnd: "-->",
876 closeBrackets: "()[]{}''\"\"``",
877 fold: "markdown"
878 };
879 return mode;
880 }, "xml");
881
882 CodeMirror.defineMIME("text/markdown", "markdown");
883
884 CodeMirror.defineMIME("text/x-markdown", "markdown");
885
886 });
887