github.com/jancarloviray/community@v0.41.1-0.20170124221257-33a66c87cf2f/app/public/codemirror/mode/markdown/markdown.js (about) 1 // CodeMirror, copyright (c) by Marijn Haverbeke and others 2 // Distributed under an MIT license: http://codemirror.net/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 htmlFound = CodeMirror.modes.hasOwnProperty("xml"); 17 var htmlMode = CodeMirror.getMode(cmCfg, htmlFound ? {name: "xml", htmlMode: true} : "text/plain"); 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 // Should underscores in words open/close em/strong? 39 if (modeCfg.underscoresBreakWords === undefined) 40 modeCfg.underscoresBreakWords = true; 41 42 // Use `fencedCodeBlocks` to configure fenced code blocks. false to 43 // disable, string to specify a precise regexp that the fence should 44 // match, and true to allow three or more backticks or tildes (as 45 // per CommonMark). 46 47 // Turn on task lists? ("- [ ] " and "- [x] ") 48 if (modeCfg.taskLists === undefined) modeCfg.taskLists = false; 49 50 // Turn on strikethrough syntax 51 if (modeCfg.strikethrough === undefined) 52 modeCfg.strikethrough = false; 53 54 // Allow token types to be overridden by user-provided token types. 55 if (modeCfg.tokenTypeOverrides === undefined) 56 modeCfg.tokenTypeOverrides = {}; 57 58 var codeDepth = 0; 59 60 var tokenTypes = { 61 header: "header", 62 code: "comment", 63 quote: "quote", 64 list1: "variable-2", 65 list2: "variable-3", 66 list3: "keyword", 67 hr: "hr", 68 image: "tag", 69 formatting: "formatting", 70 linkInline: "link", 71 linkEmail: "link", 72 linkText: "link", 73 linkHref: "string", 74 em: "em", 75 strong: "strong", 76 strikethrough: "strikethrough" 77 }; 78 79 for (var tokenType in tokenTypes) { 80 if (tokenTypes.hasOwnProperty(tokenType) && modeCfg.tokenTypeOverrides[tokenType]) { 81 tokenTypes[tokenType] = modeCfg.tokenTypeOverrides[tokenType]; 82 } 83 } 84 85 var hrRE = /^([*\-_])(?:\s*\1){2,}\s*$/ 86 , ulRE = /^[*\-+]\s+/ 87 , olRE = /^[0-9]+([.)])\s+/ 88 , taskListRE = /^\[(x| )\](?=\s)/ // Must follow ulRE or olRE 89 , atxHeaderRE = modeCfg.allowAtxHeaderWithoutSpace ? /^(#+)/ : /^(#+)(?: |$)/ 90 , setextHeaderRE = /^ *(?:\={1,}|-{1,})\s*$/ 91 , textRE = /^[^#!\[\]*_\\<>` "'(~]+/ 92 , fencedCodeRE = new RegExp("^(" + (modeCfg.fencedCodeBlocks === true ? "~~~+|```+" : modeCfg.fencedCodeBlocks) + 93 ")[ \\t]*([\\w+#]*)"); 94 95 function switchInline(stream, state, f) { 96 state.f = state.inline = f; 97 return f(stream, state); 98 } 99 100 function switchBlock(stream, state, f) { 101 state.f = state.block = f; 102 return f(stream, state); 103 } 104 105 function lineIsEmpty(line) { 106 return !line || !/\S/.test(line.string) 107 } 108 109 // Blocks 110 111 function blankLine(state) { 112 // Reset linkTitle state 113 state.linkTitle = false; 114 // Reset EM state 115 state.em = false; 116 // Reset STRONG state 117 state.strong = false; 118 // Reset strikethrough state 119 state.strikethrough = false; 120 // Reset state.quote 121 state.quote = 0; 122 // Reset state.indentedCode 123 state.indentedCode = false; 124 if (!htmlFound && state.f == htmlBlock) { 125 state.f = inlineNormal; 126 state.block = blockNormal; 127 } 128 // Reset state.trailingSpace 129 state.trailingSpace = 0; 130 state.trailingSpaceNewLine = false; 131 // Mark this line as blank 132 state.prevLine = state.thisLine 133 state.thisLine = null 134 return null; 135 } 136 137 function blockNormal(stream, state) { 138 139 var sol = stream.sol(); 140 141 var prevLineIsList = state.list !== false, 142 prevLineIsIndentedCode = state.indentedCode; 143 144 state.indentedCode = false; 145 146 if (prevLineIsList) { 147 if (state.indentationDiff >= 0) { // Continued list 148 if (state.indentationDiff < 4) { // Only adjust indentation if *not* a code block 149 state.indentation -= state.indentationDiff; 150 } 151 state.list = null; 152 } else if (state.indentation > 0) { 153 state.list = null; 154 state.listDepth = Math.floor(state.indentation / 4); 155 } else { // No longer a list 156 state.list = false; 157 state.listDepth = 0; 158 } 159 } 160 161 var match = null; 162 if (state.indentationDiff >= 4) { 163 stream.skipToEnd(); 164 if (prevLineIsIndentedCode || lineIsEmpty(state.prevLine)) { 165 state.indentation -= 4; 166 state.indentedCode = true; 167 return tokenTypes.code; 168 } else { 169 return null; 170 } 171 } else if (stream.eatSpace()) { 172 return null; 173 } else if ((match = stream.match(atxHeaderRE)) && match[1].length <= 6) { 174 state.header = match[1].length; 175 if (modeCfg.highlightFormatting) state.formatting = "header"; 176 state.f = state.inline; 177 return getType(state); 178 } else if (!lineIsEmpty(state.prevLine) && !state.quote && !prevLineIsList && 179 !prevLineIsIndentedCode && (match = stream.match(setextHeaderRE))) { 180 state.header = match[0].charAt(0) == '=' ? 1 : 2; 181 if (modeCfg.highlightFormatting) state.formatting = "header"; 182 state.f = state.inline; 183 return getType(state); 184 } else if (stream.eat('>')) { 185 state.quote = sol ? 1 : state.quote + 1; 186 if (modeCfg.highlightFormatting) state.formatting = "quote"; 187 stream.eatSpace(); 188 return getType(state); 189 } else if (stream.peek() === '[') { 190 return switchInline(stream, state, footnoteLink); 191 } else if (stream.match(hrRE, true)) { 192 state.hr = true; 193 return tokenTypes.hr; 194 } else if ((lineIsEmpty(state.prevLine) || prevLineIsList) && (stream.match(ulRE, false) || stream.match(olRE, false))) { 195 var listType = null; 196 if (stream.match(ulRE, true)) { 197 listType = 'ul'; 198 } else { 199 stream.match(olRE, true); 200 listType = 'ol'; 201 } 202 state.indentation = stream.column() + stream.current().length; 203 state.list = true; 204 state.listDepth++; 205 if (modeCfg.taskLists && stream.match(taskListRE, false)) { 206 state.taskList = true; 207 } 208 state.f = state.inline; 209 if (modeCfg.highlightFormatting) state.formatting = ["list", "list-" + listType]; 210 return getType(state); 211 } else if (modeCfg.fencedCodeBlocks && (match = stream.match(fencedCodeRE, true))) { 212 state.fencedChars = match[1] 213 // try switching mode 214 state.localMode = getMode(match[2]); 215 if (state.localMode) state.localState = state.localMode.startState(); 216 state.f = state.block = local; 217 if (modeCfg.highlightFormatting) state.formatting = "code-block"; 218 state.code = true; 219 return getType(state); 220 } 221 222 return switchInline(stream, state, state.inline); 223 } 224 225 function htmlBlock(stream, state) { 226 var style = htmlMode.token(stream, state.htmlState); 227 if ((htmlFound && state.htmlState.tagStart === null && 228 (!state.htmlState.context && state.htmlState.tokenize.isInText)) || 229 (state.md_inside && stream.current().indexOf(">") > -1)) { 230 state.f = inlineNormal; 231 state.block = blockNormal; 232 state.htmlState = null; 233 } 234 return style; 235 } 236 237 function local(stream, state) { 238 if (stream.sol() && state.fencedChars && stream.match(state.fencedChars, false)) { 239 state.localMode = state.localState = null; 240 state.f = state.block = leavingLocal; 241 return null; 242 } else if (state.localMode) { 243 return state.localMode.token(stream, state.localState); 244 } else { 245 stream.skipToEnd(); 246 return tokenTypes.code; 247 } 248 } 249 250 function leavingLocal(stream, state) { 251 stream.match(state.fencedChars); 252 state.block = blockNormal; 253 state.f = inlineNormal; 254 state.fencedChars = null; 255 if (modeCfg.highlightFormatting) state.formatting = "code-block"; 256 state.code = true; 257 var returnType = getType(state); 258 state.code = false; 259 return returnType; 260 } 261 262 // Inline 263 function getType(state) { 264 var styles = []; 265 266 if (state.formatting) { 267 styles.push(tokenTypes.formatting); 268 269 if (typeof state.formatting === "string") state.formatting = [state.formatting]; 270 271 for (var i = 0; i < state.formatting.length; i++) { 272 styles.push(tokenTypes.formatting + "-" + state.formatting[i]); 273 274 if (state.formatting[i] === "header") { 275 styles.push(tokenTypes.formatting + "-" + state.formatting[i] + "-" + state.header); 276 } 277 278 // Add `formatting-quote` and `formatting-quote-#` for blockquotes 279 // Add `error` instead if the maximum blockquote nesting depth is passed 280 if (state.formatting[i] === "quote") { 281 if (!modeCfg.maxBlockquoteDepth || modeCfg.maxBlockquoteDepth >= state.quote) { 282 styles.push(tokenTypes.formatting + "-" + state.formatting[i] + "-" + state.quote); 283 } else { 284 styles.push("error"); 285 } 286 } 287 } 288 } 289 290 if (state.taskOpen) { 291 styles.push("meta"); 292 return styles.length ? styles.join(' ') : null; 293 } 294 if (state.taskClosed) { 295 styles.push("property"); 296 return styles.length ? styles.join(' ') : null; 297 } 298 299 if (state.linkHref) { 300 styles.push(tokenTypes.linkHref, "url"); 301 } else { // Only apply inline styles to non-url text 302 if (state.strong) { styles.push(tokenTypes.strong); } 303 if (state.em) { styles.push(tokenTypes.em); } 304 if (state.strikethrough) { styles.push(tokenTypes.strikethrough); } 305 if (state.linkText) { styles.push(tokenTypes.linkText); } 306 if (state.code) { styles.push(tokenTypes.code); } 307 } 308 309 if (state.header) { styles.push(tokenTypes.header, tokenTypes.header + "-" + state.header); } 310 311 if (state.quote) { 312 styles.push(tokenTypes.quote); 313 314 // Add `quote-#` where the maximum for `#` is modeCfg.maxBlockquoteDepth 315 if (!modeCfg.maxBlockquoteDepth || modeCfg.maxBlockquoteDepth >= state.quote) { 316 styles.push(tokenTypes.quote + "-" + state.quote); 317 } else { 318 styles.push(tokenTypes.quote + "-" + modeCfg.maxBlockquoteDepth); 319 } 320 } 321 322 if (state.list !== false) { 323 var listMod = (state.listDepth - 1) % 3; 324 if (!listMod) { 325 styles.push(tokenTypes.list1); 326 } else if (listMod === 1) { 327 styles.push(tokenTypes.list2); 328 } else { 329 styles.push(tokenTypes.list3); 330 } 331 } 332 333 if (state.trailingSpaceNewLine) { 334 styles.push("trailing-space-new-line"); 335 } else if (state.trailingSpace) { 336 styles.push("trailing-space-" + (state.trailingSpace % 2 ? "a" : "b")); 337 } 338 339 return styles.length ? styles.join(' ') : null; 340 } 341 342 function handleText(stream, state) { 343 if (stream.match(textRE, true)) { 344 return getType(state); 345 } 346 return undefined; 347 } 348 349 function inlineNormal(stream, state) { 350 var style = state.text(stream, state); 351 if (typeof style !== 'undefined') 352 return style; 353 354 if (state.list) { // List marker (*, +, -, 1., etc) 355 state.list = null; 356 return getType(state); 357 } 358 359 if (state.taskList) { 360 var taskOpen = stream.match(taskListRE, true)[1] !== "x"; 361 if (taskOpen) state.taskOpen = true; 362 else state.taskClosed = true; 363 if (modeCfg.highlightFormatting) state.formatting = "task"; 364 state.taskList = false; 365 return getType(state); 366 } 367 368 state.taskOpen = false; 369 state.taskClosed = false; 370 371 if (state.header && stream.match(/^#+$/, true)) { 372 if (modeCfg.highlightFormatting) state.formatting = "header"; 373 return getType(state); 374 } 375 376 // Get sol() value now, before character is consumed 377 var sol = stream.sol(); 378 379 var ch = stream.next(); 380 381 if (ch === '\\') { 382 stream.next(); 383 if (modeCfg.highlightFormatting) { 384 var type = getType(state); 385 var formattingEscape = tokenTypes.formatting + "-escape"; 386 return type ? type + " " + formattingEscape : formattingEscape; 387 } 388 } 389 390 // Matches link titles present on next line 391 if (state.linkTitle) { 392 state.linkTitle = false; 393 var matchCh = ch; 394 if (ch === '(') { 395 matchCh = ')'; 396 } 397 matchCh = (matchCh+'').replace(/([.?*+^$[\]\\(){}|-])/g, "\\$1"); 398 var regex = '^\\s*(?:[^' + matchCh + '\\\\]+|\\\\\\\\|\\\\.)' + matchCh; 399 if (stream.match(new RegExp(regex), true)) { 400 return tokenTypes.linkHref; 401 } 402 } 403 404 // If this block is changed, it may need to be updated in GFM mode 405 if (ch === '`') { 406 var previousFormatting = state.formatting; 407 if (modeCfg.highlightFormatting) state.formatting = "code"; 408 var t = getType(state); 409 var before = stream.pos; 410 stream.eatWhile('`'); 411 var difference = 1 + stream.pos - before; 412 if (!state.code) { 413 codeDepth = difference; 414 state.code = true; 415 return getType(state); 416 } else { 417 if (difference === codeDepth) { // Must be exact 418 state.code = false; 419 return t; 420 } 421 state.formatting = previousFormatting; 422 return getType(state); 423 } 424 } else if (state.code) { 425 return getType(state); 426 } 427 428 if (ch === '!' && stream.match(/\[[^\]]*\] ?(?:\(|\[)/, false)) { 429 stream.match(/\[[^\]]*\]/); 430 state.inline = state.f = linkHref; 431 return tokenTypes.image; 432 } 433 434 if (ch === '[' && stream.match(/.*\](\(.*\)| ?\[.*\])/, false)) { 435 state.linkText = true; 436 if (modeCfg.highlightFormatting) state.formatting = "link"; 437 return getType(state); 438 } 439 440 if (ch === ']' && state.linkText && stream.match(/\(.*\)| ?\[.*\]/, false)) { 441 if (modeCfg.highlightFormatting) state.formatting = "link"; 442 var type = getType(state); 443 state.linkText = false; 444 state.inline = state.f = linkHref; 445 return type; 446 } 447 448 if (ch === '<' && stream.match(/^(https?|ftps?):\/\/(?:[^\\>]|\\.)+>/, false)) { 449 state.f = state.inline = linkInline; 450 if (modeCfg.highlightFormatting) state.formatting = "link"; 451 var type = getType(state); 452 if (type){ 453 type += " "; 454 } else { 455 type = ""; 456 } 457 return type + tokenTypes.linkInline; 458 } 459 460 if (ch === '<' && stream.match(/^[^> \\]+@(?:[^\\>]|\\.)+>/, false)) { 461 state.f = state.inline = linkInline; 462 if (modeCfg.highlightFormatting) state.formatting = "link"; 463 var type = getType(state); 464 if (type){ 465 type += " "; 466 } else { 467 type = ""; 468 } 469 return type + tokenTypes.linkEmail; 470 } 471 472 if (ch === '<' && stream.match(/^(!--|\w)/, false)) { 473 var end = stream.string.indexOf(">", stream.pos); 474 if (end != -1) { 475 var atts = stream.string.substring(stream.start, end); 476 if (/markdown\s*=\s*('|"){0,1}1('|"){0,1}/.test(atts)) state.md_inside = true; 477 } 478 stream.backUp(1); 479 state.htmlState = CodeMirror.startState(htmlMode); 480 return switchBlock(stream, state, htmlBlock); 481 } 482 483 if (ch === '<' && stream.match(/^\/\w*?>/)) { 484 state.md_inside = false; 485 return "tag"; 486 } 487 488 var ignoreUnderscore = false; 489 if (!modeCfg.underscoresBreakWords) { 490 if (ch === '_' && stream.peek() !== '_' && stream.match(/(\w)/, false)) { 491 var prevPos = stream.pos - 2; 492 if (prevPos >= 0) { 493 var prevCh = stream.string.charAt(prevPos); 494 if (prevCh !== '_' && prevCh.match(/(\w)/, false)) { 495 ignoreUnderscore = true; 496 } 497 } 498 } 499 } 500 if (ch === '*' || (ch === '_' && !ignoreUnderscore)) { 501 if (sol && stream.peek() === ' ') { 502 // Do nothing, surrounded by newline and space 503 } else if (state.strong === ch && stream.eat(ch)) { // Remove STRONG 504 if (modeCfg.highlightFormatting) state.formatting = "strong"; 505 var t = getType(state); 506 state.strong = false; 507 return t; 508 } else if (!state.strong && stream.eat(ch)) { // Add STRONG 509 state.strong = ch; 510 if (modeCfg.highlightFormatting) state.formatting = "strong"; 511 return getType(state); 512 } else if (state.em === ch) { // Remove EM 513 if (modeCfg.highlightFormatting) state.formatting = "em"; 514 var t = getType(state); 515 state.em = false; 516 return t; 517 } else if (!state.em) { // Add EM 518 state.em = ch; 519 if (modeCfg.highlightFormatting) state.formatting = "em"; 520 return getType(state); 521 } 522 } else if (ch === ' ') { 523 if (stream.eat('*') || stream.eat('_')) { // Probably surrounded by spaces 524 if (stream.peek() === ' ') { // Surrounded by spaces, ignore 525 return getType(state); 526 } else { // Not surrounded by spaces, back up pointer 527 stream.backUp(1); 528 } 529 } 530 } 531 532 if (modeCfg.strikethrough) { 533 if (ch === '~' && stream.eatWhile(ch)) { 534 if (state.strikethrough) {// Remove strikethrough 535 if (modeCfg.highlightFormatting) state.formatting = "strikethrough"; 536 var t = getType(state); 537 state.strikethrough = false; 538 return t; 539 } else if (stream.match(/^[^\s]/, false)) {// Add strikethrough 540 state.strikethrough = true; 541 if (modeCfg.highlightFormatting) state.formatting = "strikethrough"; 542 return getType(state); 543 } 544 } else if (ch === ' ') { 545 if (stream.match(/^~~/, true)) { // Probably surrounded by space 546 if (stream.peek() === ' ') { // Surrounded by spaces, ignore 547 return getType(state); 548 } else { // Not surrounded by spaces, back up pointer 549 stream.backUp(2); 550 } 551 } 552 } 553 } 554 555 if (ch === ' ') { 556 if (stream.match(/ +$/, false)) { 557 state.trailingSpace++; 558 } else if (state.trailingSpace) { 559 state.trailingSpaceNewLine = true; 560 } 561 } 562 563 return getType(state); 564 } 565 566 function linkInline(stream, state) { 567 var ch = stream.next(); 568 569 if (ch === ">") { 570 state.f = state.inline = inlineNormal; 571 if (modeCfg.highlightFormatting) state.formatting = "link"; 572 var type = getType(state); 573 if (type){ 574 type += " "; 575 } else { 576 type = ""; 577 } 578 return type + tokenTypes.linkInline; 579 } 580 581 stream.match(/^[^>]+/, true); 582 583 return tokenTypes.linkInline; 584 } 585 586 function linkHref(stream, state) { 587 // Check if space, and return NULL if so (to avoid marking the space) 588 if(stream.eatSpace()){ 589 return null; 590 } 591 var ch = stream.next(); 592 if (ch === '(' || ch === '[') { 593 state.f = state.inline = getLinkHrefInside(ch === "(" ? ")" : "]"); 594 if (modeCfg.highlightFormatting) state.formatting = "link-string"; 595 state.linkHref = true; 596 return getType(state); 597 } 598 return 'error'; 599 } 600 601 function getLinkHrefInside(endChar) { 602 return function(stream, state) { 603 var ch = stream.next(); 604 605 if (ch === endChar) { 606 state.f = state.inline = inlineNormal; 607 if (modeCfg.highlightFormatting) state.formatting = "link-string"; 608 var returnState = getType(state); 609 state.linkHref = false; 610 return returnState; 611 } 612 613 if (stream.match(inlineRE(endChar), true)) { 614 stream.backUp(1); 615 } 616 617 state.linkHref = true; 618 return getType(state); 619 }; 620 } 621 622 function footnoteLink(stream, state) { 623 if (stream.match(/^([^\]\\]|\\.)*\]:/, false)) { 624 state.f = footnoteLinkInside; 625 stream.next(); // Consume [ 626 if (modeCfg.highlightFormatting) state.formatting = "link"; 627 state.linkText = true; 628 return getType(state); 629 } 630 return switchInline(stream, state, inlineNormal); 631 } 632 633 function footnoteLinkInside(stream, state) { 634 if (stream.match(/^\]:/, true)) { 635 state.f = state.inline = footnoteUrl; 636 if (modeCfg.highlightFormatting) state.formatting = "link"; 637 var returnType = getType(state); 638 state.linkText = false; 639 return returnType; 640 } 641 642 stream.match(/^([^\]\\]|\\.)+/, true); 643 644 return tokenTypes.linkText; 645 } 646 647 function footnoteUrl(stream, state) { 648 // Check if space, and return NULL if so (to avoid marking the space) 649 if(stream.eatSpace()){ 650 return null; 651 } 652 // Match URL 653 stream.match(/^[^\s]+/, true); 654 // Check for link title 655 if (stream.peek() === undefined) { // End of line, set flag to check next line 656 state.linkTitle = true; 657 } else { // More content on line, check if link title 658 stream.match(/^(?:\s+(?:"(?:[^"\\]|\\\\|\\.)+"|'(?:[^'\\]|\\\\|\\.)+'|\((?:[^)\\]|\\\\|\\.)+\)))?/, true); 659 } 660 state.f = state.inline = inlineNormal; 661 return tokenTypes.linkHref + " url"; 662 } 663 664 var savedInlineRE = []; 665 function inlineRE(endChar) { 666 if (!savedInlineRE[endChar]) { 667 // Escape endChar for RegExp (taken from http://stackoverflow.com/a/494122/526741) 668 endChar = (endChar+'').replace(/([.?*+^$[\]\\(){}|-])/g, "\\$1"); 669 // Match any non-endChar, escaped character, as well as the closing 670 // endChar. 671 savedInlineRE[endChar] = new RegExp('^(?:[^\\\\]|\\\\.)*?(' + endChar + ')'); 672 } 673 return savedInlineRE[endChar]; 674 } 675 676 var mode = { 677 startState: function() { 678 return { 679 f: blockNormal, 680 681 prevLine: null, 682 thisLine: null, 683 684 block: blockNormal, 685 htmlState: null, 686 indentation: 0, 687 688 inline: inlineNormal, 689 text: handleText, 690 691 formatting: false, 692 linkText: false, 693 linkHref: false, 694 linkTitle: false, 695 em: false, 696 strong: false, 697 header: 0, 698 hr: false, 699 taskList: false, 700 list: false, 701 listDepth: 0, 702 quote: 0, 703 trailingSpace: 0, 704 trailingSpaceNewLine: false, 705 strikethrough: false, 706 fencedChars: null 707 }; 708 }, 709 710 copyState: function(s) { 711 return { 712 f: s.f, 713 714 prevLine: s.prevLine, 715 thisLine: s.thisLine, 716 717 block: s.block, 718 htmlState: s.htmlState && CodeMirror.copyState(htmlMode, s.htmlState), 719 indentation: s.indentation, 720 721 localMode: s.localMode, 722 localState: s.localMode ? CodeMirror.copyState(s.localMode, s.localState) : null, 723 724 inline: s.inline, 725 text: s.text, 726 formatting: false, 727 linkTitle: s.linkTitle, 728 code: s.code, 729 em: s.em, 730 strong: s.strong, 731 strikethrough: s.strikethrough, 732 header: s.header, 733 hr: s.hr, 734 taskList: s.taskList, 735 list: s.list, 736 listDepth: s.listDepth, 737 quote: s.quote, 738 indentedCode: s.indentedCode, 739 trailingSpace: s.trailingSpace, 740 trailingSpaceNewLine: s.trailingSpaceNewLine, 741 md_inside: s.md_inside, 742 fencedChars: s.fencedChars 743 }; 744 }, 745 746 token: function(stream, state) { 747 748 // Reset state.formatting 749 state.formatting = false; 750 751 if (stream != state.thisLine) { 752 var forceBlankLine = state.header || state.hr; 753 754 // Reset state.header and state.hr 755 state.header = 0; 756 state.hr = false; 757 758 if (stream.match(/^\s*$/, true) || forceBlankLine) { 759 blankLine(state); 760 if (!forceBlankLine) return null 761 state.prevLine = null 762 } 763 764 state.prevLine = state.thisLine 765 state.thisLine = stream 766 767 // Reset state.taskList 768 state.taskList = false; 769 770 // Reset state.trailingSpace 771 state.trailingSpace = 0; 772 state.trailingSpaceNewLine = false; 773 774 state.f = state.block; 775 var indentation = stream.match(/^\s*/, true)[0].replace(/\t/g, ' ').length; 776 var difference = Math.floor((indentation - state.indentation) / 4) * 4; 777 if (difference > 4) difference = 4; 778 var adjustedIndentation = state.indentation + difference; 779 state.indentationDiff = adjustedIndentation - state.indentation; 780 state.indentation = adjustedIndentation; 781 if (indentation > 0) return null; 782 } 783 return state.f(stream, state); 784 }, 785 786 innerMode: function(state) { 787 if (state.block == htmlBlock) return {state: state.htmlState, mode: htmlMode}; 788 if (state.localState) return {state: state.localState, mode: state.localMode}; 789 return {state: state, mode: mode}; 790 }, 791 792 blankLine: blankLine, 793 794 getType: getType, 795 796 fold: "markdown" 797 }; 798 return mode; 799 }, "xml"); 800 801 CodeMirror.defineMIME("text/x-markdown", "markdown"); 802 803 });