html_block.mjs 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869
  1. // HTML block
  2. import block_names from '../common/html_blocks.mjs'
  3. import { HTML_OPEN_CLOSE_TAG_RE } from '../common/html_re.mjs'
  4. // An array of opening and corresponding closing sequences for html tags,
  5. // last argument defines whether it can terminate a paragraph or not
  6. //
  7. const HTML_SEQUENCES = [
  8. [/^<(script|pre|style|textarea)(?=(\s|>|$))/i, /<\/(script|pre|style|textarea)>/i, true],
  9. [/^<!--/, /-->/, true],
  10. [/^<\?/, /\?>/, true],
  11. [/^<![A-Z]/, />/, true],
  12. [/^<!\[CDATA\[/, /\]\]>/, true],
  13. [new RegExp('^</?(' + block_names.join('|') + ')(?=(\\s|/?>|$))', 'i'), /^$/, true],
  14. [new RegExp(HTML_OPEN_CLOSE_TAG_RE.source + '\\s*$'), /^$/, false]
  15. ]
  16. export default function html_block (state, startLine, endLine, silent) {
  17. let pos = state.bMarks[startLine] + state.tShift[startLine]
  18. let max = state.eMarks[startLine]
  19. // if it's indented more than 3 spaces, it should be a code block
  20. if (state.sCount[startLine] - state.blkIndent >= 4) { return false }
  21. if (!state.md.options.html) { return false }
  22. if (state.src.charCodeAt(pos) !== 0x3C/* < */) { return false }
  23. let lineText = state.src.slice(pos, max)
  24. let i = 0
  25. for (; i < HTML_SEQUENCES.length; i++) {
  26. if (HTML_SEQUENCES[i][0].test(lineText)) { break }
  27. }
  28. if (i === HTML_SEQUENCES.length) { return false }
  29. if (silent) {
  30. // true if this sequence can be a terminator, false otherwise
  31. return HTML_SEQUENCES[i][2]
  32. }
  33. let nextLine = startLine + 1
  34. // If we are here - we detected HTML block.
  35. // Let's roll down till block end.
  36. if (!HTML_SEQUENCES[i][1].test(lineText)) {
  37. for (; nextLine < endLine; nextLine++) {
  38. if (state.sCount[nextLine] < state.blkIndent) { break }
  39. pos = state.bMarks[nextLine] + state.tShift[nextLine]
  40. max = state.eMarks[nextLine]
  41. lineText = state.src.slice(pos, max)
  42. if (HTML_SEQUENCES[i][1].test(lineText)) {
  43. if (lineText.length !== 0) { nextLine++ }
  44. break
  45. }
  46. }
  47. }
  48. state.line = nextLine
  49. const token = state.push('html_block', '', 0)
  50. token.map = [startLine, nextLine]
  51. token.content = state.getLines(startLine, nextLine, state.blkIndent, true)
  52. return true
  53. }