|
|
@ -4,69 +4,68 @@ |
|
|
|
|
|
|
|
|
|
|
|
var block_names = require('../common/html_blocks'); |
|
|
|
var HTML_OPEN_CLOSE_TAG_RE = require('../common/html_re').HTML_OPEN_CLOSE_TAG_RE; |
|
|
|
|
|
|
|
// An array of opening and corresponding closing sequences for html tags,
|
|
|
|
// last argument defines whether it can terminate a paragraph or not
|
|
|
|
//
|
|
|
|
var HTML_SEQUENCES = [ |
|
|
|
[ /^<(script|pre|style)(?=(\s|>|$))/i, /<\/(script|pre|style)>/i, true ], |
|
|
|
[ /^<!--/, /-->/, true ], |
|
|
|
[ /^<\?/, /\?>/, true ], |
|
|
|
[ /^<![A-Z]/, />/, true ], |
|
|
|
[ /^<!\[CDATA\[/, /\]\]>/, true ], |
|
|
|
[ new RegExp('^</?(' + block_names.join('|') + ')(?=(\\s|/?>|$))', 'i'), /^$/, true ], |
|
|
|
[ new RegExp(HTML_OPEN_CLOSE_TAG_RE.source + '\\s*$'), /^$/, false ] |
|
|
|
]; |
|
|
|
|
|
|
|
|
|
|
|
var HTML_TAG_OPEN_RE = /^<([a-zA-Z][a-zA-Z0-9]{0,14})[\s\/>]/; |
|
|
|
var HTML_TAG_CLOSE_RE = /^<\/([a-zA-Z][a-zA-Z0-9]{0,14})[\s>]/; |
|
|
|
|
|
|
|
function isLetter(ch) { |
|
|
|
/*eslint no-bitwise:0*/ |
|
|
|
var lc = ch | 0x20; // to lower case
|
|
|
|
return (lc >= 0x61/* a */) && (lc <= 0x7a/* z */); |
|
|
|
} |
|
|
|
|
|
|
|
module.exports = function html_block(state, startLine, endLine, silent) { |
|
|
|
var ch, match, nextLine, token, |
|
|
|
pos = state.bMarks[startLine], |
|
|
|
max = state.eMarks[startLine], |
|
|
|
shift = state.tShift[startLine]; |
|
|
|
|
|
|
|
pos += shift; |
|
|
|
var i, nextLine, token, lineText, |
|
|
|
pos = state.bMarks[startLine] + state.tShift[startLine], |
|
|
|
max = state.eMarks[startLine]; |
|
|
|
|
|
|
|
if (!state.md.options.html) { return false; } |
|
|
|
|
|
|
|
if (shift > 3 || pos + 2 >= max) { return false; } |
|
|
|
|
|
|
|
if (state.src.charCodeAt(pos) !== 0x3C/* < */) { return false; } |
|
|
|
|
|
|
|
ch = state.src.charCodeAt(pos + 1); |
|
|
|
lineText = state.src.slice(pos, max); |
|
|
|
|
|
|
|
if (ch === 0x21/* ! */ || ch === 0x3F/* ? */) { |
|
|
|
// Directive start / comment start / processing instruction start
|
|
|
|
if (silent) { return true; } |
|
|
|
for (i = 0; i < HTML_SEQUENCES.length; i++) { |
|
|
|
if (HTML_SEQUENCES[i][0].test(lineText)) { break; } |
|
|
|
} |
|
|
|
|
|
|
|
} else if (ch === 0x2F/* / */ || isLetter(ch)) { |
|
|
|
if (i === HTML_SEQUENCES.length) { return false; } |
|
|
|
|
|
|
|
// Probably start or end of tag
|
|
|
|
if (ch === 0x2F/* \ */) { |
|
|
|
// closing tag
|
|
|
|
match = state.src.slice(pos, max).match(HTML_TAG_CLOSE_RE); |
|
|
|
if (!match) { return false; } |
|
|
|
} else { |
|
|
|
// opening tag
|
|
|
|
match = state.src.slice(pos, max).match(HTML_TAG_OPEN_RE); |
|
|
|
if (!match) { return false; } |
|
|
|
} |
|
|
|
// Make sure tag name is valid
|
|
|
|
if (block_names[match[1].toLowerCase()] !== true) { return false; } |
|
|
|
if (silent) { return true; } |
|
|
|
|
|
|
|
} else { |
|
|
|
return false; |
|
|
|
if (silent) { |
|
|
|
// true if this sequence can be a terminator, false otherwise
|
|
|
|
return HTML_SEQUENCES[i][2]; |
|
|
|
} |
|
|
|
|
|
|
|
// If we are here - we detected HTML block.
|
|
|
|
// Let's roll down till empty line (block end).
|
|
|
|
nextLine = startLine + 1; |
|
|
|
while (nextLine < state.lineMax && !state.isEmpty(nextLine)) { |
|
|
|
nextLine++; |
|
|
|
|
|
|
|
// If we are here - we detected HTML block.
|
|
|
|
// Let's roll down till block end.
|
|
|
|
if (!HTML_SEQUENCES[i][1].test(lineText)) { |
|
|
|
for (; nextLine < endLine; nextLine++) { |
|
|
|
if (state.tShift[nextLine] < state.blkIndent) { break; } |
|
|
|
|
|
|
|
pos = state.bMarks[nextLine] + state.tShift[nextLine]; |
|
|
|
max = state.eMarks[nextLine]; |
|
|
|
lineText = state.src.slice(pos, max); |
|
|
|
|
|
|
|
if (HTML_SEQUENCES[i][1].test(lineText)) { |
|
|
|
if (lineText.length !== 0) { nextLine++; } |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
state.line = nextLine; |
|
|
|
|
|
|
|
token = state.push('html_block', '', 0); |
|
|
|
token.map = [ startLine, state.line ]; |
|
|
|
token.content = state.getLines(startLine, nextLine, 0, true); |
|
|
|
token.map = [ startLine, nextLine ]; |
|
|
|
token.content = state.getLines(startLine, nextLine, state.blkIndent, true); |
|
|
|
|
|
|
|
return true; |
|
|
|
}; |
|
|
|