From 39fcd8d5137efd97a0f7180f0c2e3c8f635117a3 Mon Sep 17 00:00:00 2001
From: joyqi ' + (this.markLine(start, end)) + (htmlspecialchars(lines.join("\n"))) + '' + (htmlspecialchars(matches[3])) + '');
+ });
+
+ // mathjax
+ text = text.replace(/(^|[^\\])(\$+)(.+?)\2/mg, (...matches) => {
+ return matches[1] + this.makeHolder(matches[2] + (htmlspecialchars(matches[3])) + matches[2]);
+ });
+ // escape
+ text = text.replace(/\\(.)/g, (...matches) => {
+ var escaped, prefix;
+ prefix = matches[1].match(/^[-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]$/) ? '' : '\\';
+ escaped = htmlspecialchars(matches[1]);
+ escaped = escaped.replace(/\$/g, '$');
+ return this.makeHolder(prefix + escaped);
+ });
+
+ // link
+ text = text.replace(/<(https?:\/\/.+|(?:mailto:)?[_a-z0-9-\.\+]+@[_\w-]+(?:\.[a-z]{2,})+)>/ig, (...matches) => {
+ var link, url;
+ url = this.cleanUrl(matches[1]);
+ link = this.call('parseLink', url);
+ return this.makeHolder(`${link}`);
+ });
+ // encode unsafe tags
+ text = text.replace(/<(\/?)([a-z0-9-]+)(\s+[^>]*)?>/ig, (...matches) => {
+ if (this.html || (('|' + this.commonWhiteList + '|' + whiteList + '|').indexOf('|' + matches[2].toLowerCase() + '|')) >= 0) {
+ return this.makeHolder(matches[0]);
+ } else {
+ return this.makeHolder(htmlspecialchars(matches[0]));
+ }
+ });
+ if (this.html) {
+ text = text.replace(//g, (...matches) => {
+ return this.makeHolder(matches[0]);
+ });
+ }
+ text = str_replace(['<', '>'], ['<', '>'], text);
+ // footnote
+ text = text.replace(/\[\^((?:[^\]]|\\\]|\\\[)+?)\]/g, (...matches) => {
+ var id;
+ id = this.footnotes.indexOf(matches[1]);
+ if (id < 0) {
+ id = this.footnotes.length + 1;
+ this.footnotes.push(this.parseInline(matches[1], '', false));
+ }
+ return this.makeHolder(`${id}`);
+ });
+ // image
+ text = text.replace(/!\[((?:[^\]]|\\\]|\\\[)*?)\]\(((?:[^\)]|\\\)|\\\()+?)\)/g, (...matches) => {
+ var escaped, title, url;
+ escaped = htmlspecialchars(this.escapeBracket(matches[1]));
+ url = this.escapeBracket(matches[2]);
+ [url, title] = this.cleanUrl(url, true);
+ title = title == null ? escaped : ` title=\"${title}\"`;
+ return this.makeHolder(``);
+ });
+ text = text.replace(/!\[((?:[^\]]|\\\]|\\\[)*?)\]\[((?:[^\]]|\\\]|\\\[)+?)\]/g, (...matches) => {
+ var escaped, result;
+ escaped = htmlspecialchars(this.escapeBracket(matches[1]));
+ result = this.definitions[matches[2]] != null ? `
` : escaped;
+ return this.makeHolder(result);
+ });
+ // link
+ text = text.replace(/\[((?:[^\]]|\\\]|\\\[)+?)\]\(((?:[^\)]|\\\)|\\\()+?)\)/g, (...matches) => {
+ var escaped, title, url;
+ escaped = this.parseInline(this.escapeBracket(matches[1]), '', false, false);
+ url = this.escapeBracket(matches[2]);
+ [url, title] = this.cleanUrl(url, true);
+ title = title == null ? '' : ` title=\"${title}\"`;
+ return this.makeHolder(`${escaped}`);
+ });
+ text = text.replace(/\[((?:[^\]]|\\\]|\\\[)+?)\]\[((?:[^\]]|\\\]|\\\[)+?)\]/g, (...matches) => {
+ var escaped, result;
+ escaped = this.parseInline(this.escapeBracket(matches[1]), '', false, false);
+ result = this.definitions[matches[2]] != null ? `${escaped}` : escaped;
+ return this.makeHolder(result);
+ });
+ // strong and em and some fuck
+ text = this.parseInlineCallback(text);
+ // autolink url
+ if (enableAutoLink) {
+ text = text.replace(/(^|[^\"])(https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\b([-a-zA-Z0-9()@:%_\+.~#?&\/=]*)|(?:mailto:)?[_a-z0-9-\.\+]+@[_\w-]+(?:\.[a-z]{2,})+)($|[^\"])/g, (...matches) => {
+ var link, url;
+ url = this.cleanUrl(matches[2]);
+ link = this.call('parseLink', matches[2]);
+ return `${matches[1]}${link}${matches[5]}`;
+ });
+ }
+ text = this.call('afterParseInlineBeforeRelease', text);
+ text = this.releaseHolder(text, clearHolders);
+ text = this.call('afterParseInline', text);
+ return text;
+ }
+
+ parseInlineCallback(text) {
+ text = text.replace(/(\*{3})((?:.|\r)+?)\1/mg, (...matches) => {
+ return '' + (this.parseInlineCallback(matches[2])) + '';
+ });
+ text = text.replace(/(\*{2})((?:.|\r)+?)\1/mg, (...matches) => {
+ return '' + (this.parseInlineCallback(matches[2])) + '';
+ });
+ text = text.replace(/(\*)((?:.|\r)+?)\1/mg, (...matches) => {
+ return '' + (this.parseInlineCallback(matches[2])) + '';
+ });
+ text = text.replace(/(\s+|^)(_{3})((?:.|\r)+?)\2(\s+|$)/mg, (...matches) => {
+ return matches[1] + '' + (this.parseInlineCallback(matches[3])) + '' + matches[4];
+ });
+ text = text.replace(/(\s+|^)(_{2})((?:.|\r)+?)\2(\s+|$)/mg, (...matches) => {
+ return matches[1] + '' + (this.parseInlineCallback(matches[3])) + '' + matches[4];
+ });
+ text = text.replace(/(\s+|^)(_)((?:.|\r)+?)\2(\s+|$)/mg, (...matches) => {
+ return matches[1] + '' + (this.parseInlineCallback(matches[3])) + '' + matches[4];
+ });
+ text = text.replace(/(~{2})((?:.|\r)+?)\1/mg, (...matches) => {
+ return '
' + (this.parseInlineCallback(matches[2])) + '';
+ });
+ return text;
+ }
+
+ // parse block
+ parseBlock(text, lines) {
+ var block, j, key, l, len, len1, line, name, parser, pass, ref, ref1, state;
+ ref = text.split("\n");
+ for (j = 0, len = ref.length; j < len; j++) {
+ line = ref[j];
+ lines.push(line);
+ }
+ this.blocks = [];
+ this.current = 'normal';
+ this.pos = -1;
+ state = {
+ special: (array_keys(this.specialWhiteList)).join('|'),
+ empty: 0,
+ html: false
+ };
+ for (key = l = 0, len1 = lines.length; l < len1; key = ++l) {
+ line = lines[key];
+ block = this.getBlock();
+ if (block != null) {
+ block = block.slice(0);
+ }
+ if (this.current !== 'normal') {
+ pass = this.parsers[this.current](block, key, line, state, lines);
+ if (!pass) {
+ continue;
+ }
+ }
+ ref1 = this.parsers;
+ for (name in ref1) {
+ parser = ref1[name];
+ if (name !== this.current) {
+ pass = parser(block, key, line, state, lines);
+ if (!pass) {
+ break;
+ }
+ }
+ }
+ }
+ return this.optimizeBlocks(this.blocks, lines);
+ }
+
+ parseBlockList(block, key, line, state) {
+ var matches, space, tab, type;
+ // list
+ if ((this.isBlock('list')) && !line.match(/^\s*\[((?:[^\]]|\\\]|\\\[)+?)\]:\s*(.+)$/)) {
+ if (!!(line.match(/^(\s*)(~{3,}|`{3,})([^`~]*)$/i))) {
+ // ignore code
+ return true;
+ } else if ((state.empty <= 1) && !!(matches = line.match(/^(\s*)\S+/)) && matches[1].length >= (block[3][0] + state.empty)) {
+ state.empty = 0;
+ this.setBlock(key);
+ return false;
+ } else if ((line.match(/^\s*$/)) && state.empty === 0) {
+ state.empty += 1;
+ this.setBlock(key);
+ return false;
+ }
+ }
+ if (!!(matches = line.match(/^(\s*)((?:[0-9]+\.)|\-|\+|\*)\s+/i))) {
+ space = matches[1].length;
+ tab = matches[0].length - space;
+ state.empty = 0;
+ type = 0 <= '+-*'.indexOf(matches[2]) ? 'ul' : 'ol';
+ // opened
+ if (this.isBlock('list')) {
+ if (space < block[3][0] || (space === block[3][0] && type !== block[3][1])) {
+ this.startBlock('list', key, [space, type, tab]);
+ } else {
+ this.setBlock(key);
+ }
+ } else {
+ this.startBlock('list', key, [space, type, tab]);
+ }
+ return false;
+ }
+ return true;
+ }
+
+ parseBlockCode(block, key, line, state) {
+ var isAfterList, matches, space;
+ if (!!(matches = line.match(/^(\s*)(~{3,}|`{3,})([^`~]*)$/i))) {
+ if (this.isBlock('code')) {
+ if (state.code !== matches[2]) {
+ this.setBlock(key);
+ return false;
+ }
+ isAfterList = block[3][2];
+ if (isAfterList) {
+ state.empty = 0;
+ this.combineBlock().setBlock(key);
+ } else {
+ (this.setBlock(key)).endBlock();
+ }
+ } else {
+ isAfterList = false;
+ if (this.isBlock('list')) {
+ space = block[3][0];
+ isAfterList = matches[1].length >= space + state.empty;
+ }
+ state.code = matches[2];
+ this.startBlock('code', key, [matches[1], matches[3], isAfterList]);
+ }
+ return false;
+ } else if (this.isBlock('code')) {
+ this.setBlock(key);
+ return false;
+ }
+ return true;
+ }
+
+ parseBlockShtml(block, key, line, state) {
+ var matches;
+ if (this.html) {
+ if (!!(matches = line.match(/^(\s*)!!!(\s*)$/))) {
+ if (this.isBlock('shtml')) {
+ this.setBlock(key).endBlock();
+ } else {
+ this.startBlock('shtml', key);
+ }
+ return false;
+ } else if (this.isBlock('shtml')) {
+ this.setBlock(key);
+ return false;
+ }
+ }
+ return true;
+ }
+
+ parseBlockAhtml(block, key, line, state) {
+ var htmlTagAllRegExp, htmlTagRegExp, lastMatch, m, matches;
+ if (this.html) {
+ htmlTagRegExp = new RegExp(`^\\s*<(${this.blockHtmlTags})(\\s+[^>]*)?>`, 'i');
+ if (matches = line.match(htmlTagRegExp)) {
+ if (this.isBlock('ahtml')) {
+ this.setBlock(key);
+ return false;
+ } else if (matches[2] === void 0 || matches[2] !== '/') {
+ this.startBlock('ahtml', key);
+ htmlTagAllRegExp = new RegExp(`\\s*<(${this.blockHtmlTags})(\\s+[^>]*)?>`, 'ig');
+ while (true) {
+ m = htmlTagAllRegExp.exec(line);
+ if (!m) {
+ break;
+ }
+ lastMatch = m[1];
+ }
+ if (0 <= line.indexOf(`${lastMatch}>`)) {
+ this.endBlock();
+ } else {
+ state.html = lastMatch;
+ }
+ return false;
+ }
+ } else if (!!state.html && 0 <= line.indexOf(`${state.html}>`)) {
+ this.setBlock(key).endBlock();
+ state.html = false;
+ return false;
+ } else if (this.isBlock('ahtml')) {
+ this.setBlock(key);
+ return false;
+ } else if (!!(matches = line.match(/^\s*\s*$/))) {
+ this.startBlock('ahtml', key).endBlock();
+ return false;
+ }
+ }
+ return true;
+ }
+
+ parseBlockMath(block, key, line) {
+ var matches;
+ if (!!(matches = line.match(/^(\s*)\$\$(\s*)$/))) {
+ if (this.isBlock('math')) {
+ this.setBlock(key).endBlock();
+ } else {
+ this.startBlock('math', key);
+ }
+ return false;
+ } else if (this.isBlock('math')) {
+ this.setBlock(key);
+ return false;
+ }
+ return true;
+ }
+
+ parseBlockPre(block, key, line, state) {
+ if (!!(line.match(/^ {4}/))) {
+ if (this.isBlock('pre')) {
+ this.setBlock(key);
+ } else {
+ this.startBlock('pre', key);
+ }
+ return false;
+ } else if ((this.isBlock('pre')) && line.match(/^\s*$/)) {
+ this.setBlock(key);
+ return false;
+ }
+ return true;
+ }
+
+ parseBlockHtml(block, key, line, state) {
+ var matches, tag;
+ if (!!(matches = line.match(new RegExp(`^\\s*<(${state.special})(\\s+[^>]*)?>`, 'i')))) {
+ tag = matches[1].toLowerCase();
+ if (!(this.isBlock('html', tag)) && !(this.isBlock('pre'))) {
+ this.startBlock('html', key, tag);
+ }
+ return false;
+ } else if (!!(matches = line.match(new RegExp(`(${state.special})>\\s*$`, 'i')))) {
+ tag = matches[1].toLowerCase();
+ if (this.isBlock('html', tag)) {
+ this.setBlock(key).endBlock();
+ }
+ return false;
+ } else if (this.isBlock('html')) {
+ this.setBlock(key);
+ return false;
+ }
+ return true;
+ }
+
+ parseBlockFootnote(block, key, line) {
+ var matches, space;
+ if (!!(matches = line.match(/^\[\^((?:[^\]]|\\\]|\\\[)+?)\]:/))) {
+ space = matches[0].length - 1;
+ this.startBlock('footnote', key, [space, matches[1]]);
+ return false;
+ }
+ return true;
+ }
+
+ parseBlockDefinition(block, key, line) {
+ var matches;
+ if (!!(matches = line.match(/^\s*\[((?:[^\]]|\\\]|\\\[)+?)\]:\s*(.+)$/))) {
+ this.definitions[matches[1]] = this.cleanUrl(matches[2]);
+ this.startBlock('definition', key).endBlock();
+ return false;
+ }
+ return true;
+ }
+
+ parseBlockQuote(block, key, line) {
+ var matches;
+ if (!!(matches = line.match(/^(\s*)>/))) {
+ if ((this.isBlock('list')) && matches[1].length > 0) {
+ this.setBlock(key);
+ } else if (this.isBlock('quote')) {
+ this.setBlock(key);
+ } else {
+ this.startBlock('quote', key);
+ }
+ return false;
+ }
+ return true;
+ }
+
+ parseBlockTable(block, key, line, state, lines) {
+ var align, aligns, head, j, len, matches, row, rows;
+ if (!!(matches = line.match(/^((?:(?:(?:\||\+)(?:[ :]*\-+[ :]*)(?:\||\+))|(?:(?:[ :]*\-+[ :]*)(?:\||\+)(?:[ :]*\-+[ :]*))|(?:(?:[ :]*\-+[ :]*)(?:\||\+))|(?:(?:\||\+)(?:[ :]*\-+[ :]*)))+)$/))) {
+ if (this.isBlock('table')) {
+ block[3][0].push(block[3][2]);
+ block[3][2] += 1;
+ this.setBlock(key, block[3]);
+ } else {
+ head = 0;
+ if ((block == null) || block[0] !== 'normal' || lines[block[2]].match(/^\s*$/)) {
+ this.startBlock('table', key);
+ } else {
+ head = 1;
+ this.backBlock(1, 'table');
+ }
+ if (matches[1][0] === '|') {
+ matches[1] = matches[1].substring(1);
+ if (matches[1][matches[1].length - 1] === '|') {
+ matches[1] = matches[1].substring(0, matches[1].length - 1);
+ }
+ }
+ rows = matches[1].split(/\+|\|/);
+ aligns = [];
+ for (j = 0, len = rows.length; j < len; j++) {
+ row = rows[j];
+ align = 'none';
+ if (!!(matches = row.match(/^\s*(:?)\-+(:?)\s*$/))) {
+ if (!!matches[1] && !!matches[2]) {
+ align = 'center';
+ } else if (!!matches[1]) {
+ align = 'left';
+ } else if (!!matches[2]) {
+ align = 'right';
+ }
+ }
+ aligns.push(align);
+ }
+ this.setBlock(key, [[head], aligns, head + 1]);
+ }
+ return false;
+ }
+ return true;
+ }
+
+ parseBlockSh(block, key, line) {
+ var matches, num;
+ if (!!(matches = line.match(/^(#+)(.*)$/))) {
+ num = Math.min(matches[1].length, 6);
+ this.startBlock('sh', key, num).endBlock();
+ return false;
+ }
+ return true;
+ }
+
+ parseBlockMh(block, key, line, state, lines) {
+ var matches;
+ if (!!(matches = line.match(/^\s*((=|-){2,})\s*$/)) && ((block != null) && block[0] === 'normal' && !lines[block[2]].match(/^\s*$/))) {
+ if (this.isBlock('normal')) {
+ this.backBlock(1, 'mh', matches[1][0] === '=' ? 1 : 2).setBlock(key).endBlock();
+ } else {
+ this.startBlock('normal', key);
+ }
+ return false;
+ }
+ return true;
+ }
+
+ parseBlockShr(block, key, line) {
+ if (!!(line.match(/^(\* *){3,}\s*$/))) {
+ this.startBlock('hr', key).endBlock();
+ return false;
+ }
+ return true;
+ }
+
+ parseBlockDhr(block, key, line) {
+ if (!!(line.match(/^(- *){3,}\s*$/))) {
+ this.startBlock('hr', key).endBlock();
+ return false;
+ }
+ return true;
+ }
+
+ parseBlockDefault(block, key, line, state) {
+ var matches;
+ if (this.isBlock('footnote')) {
+ matches = line.match(/^(\s*)/);
+ if (matches[1].length >= block[3][0]) {
+ this.setBlock(key);
+ } else {
+ this.startBlock('normal', key);
+ }
+ } else if (this.isBlock('table')) {
+ if (0 <= line.indexOf('|')) {
+ block[3][2] += 1;
+ this.setBlock(key, block[3]);
+ } else {
+ this.startBlock('normal', key);
+ }
+ } else if (this.isBlock('quote')) {
+ if (!line.match(/^(\s*)$/)) { // empty line
+ this.setBlock(key);
+ } else {
+ this.startBlock('normal', key);
+ }
+ } else {
+ if ((block == null) || block[0] !== 'normal') {
+ this.startBlock('normal', key);
+ } else {
+ this.setBlock(key);
+ }
+ }
+ return true;
+ }
+
+ optimizeBlocks(_blocks, _lines) {
+ var block, blocks, from, isEmpty, key, lines, moved, nextBlock, prevBlock, to, type, types;
+ blocks = _blocks.slice(0);
+ lines = _lines.slice(0);
+ blocks = this.call('beforeOptimizeBlocks', blocks, lines);
+ key = 0;
+ while (blocks[key] != null) {
+ moved = false;
+ block = blocks[key];
+ prevBlock = blocks[key - 1] != null ? blocks[key - 1] : null;
+ nextBlock = blocks[key + 1] != null ? blocks[key + 1] : null;
+ [type, from, to] = block;
+ if ('pre' === type) {
+ isEmpty = (lines.slice(block[1], block[2] + 1)).reduce(function(result, line) {
+ return (line.match(/^\s*$/)) && result;
+ }, true);
+ if (isEmpty) {
+ block[0] = type = 'normal';
+ }
+ }
+ if ('normal' === type) {
+ types = ['list', 'quote'];
+ if (from === to && (lines[from].match(/^\s*$/)) && (prevBlock != null) && (nextBlock != null)) {
+ if (prevBlock[0] === nextBlock[0] && (types.indexOf(prevBlock[0])) >= 0 && (prevBlock[0] !== 'list' || (prevBlock[3][0] === nextBlock[3][0] && prevBlock[3][1] === nextBlock[3][1]))) {
+ // combine 3 blocks
+ blocks[key - 1] = [prevBlock[0], prevBlock[1], nextBlock[2], prevBlock[3] != null ? prevBlock[3] : null];
+ blocks.splice(key, 2);
+ // do not move
+ moved = true;
+ }
+ }
+ }
+ if (!moved) {
+ key += 1;
+ }
+ }
+ return this.call('afterOptimizeBlocks', blocks, lines);
+ }
+
+ parseCode(lines, parts, start) {
+ var blank, count, isEmpty, lang, rel, str;
+ [blank, lang] = parts;
+ lang = trim(lang);
+ count = blank.length;
+ if (!lang.match(/^[_a-z0-9-\+\#\:\.]+$/i)) {
+ lang = null;
+ } else {
+ parts = lang.split(':');
+ if (parts.length > 1) {
+ [lang, rel] = parts;
+ lang = trim(lang);
+ rel = trim(rel);
+ }
+ }
+ isEmpty = true;
+ lines = lines.slice(1, -1).map(function(line) {
+ line = line.replace(new RegExp(`^[ ]{${count}}`), '');
+ if (isEmpty && !line.match(/^\s*$/)) {
+ isEmpty = false;
+ }
+ return htmlspecialchars(line);
+ });
+ str = (this.markLines(lines, start + 1)).join("\n");
+ if (isEmpty) {
+ return '';
+ } else {
+ return '
';
+ }
+ }
+
+ parsePre(lines, value, start) {
+ var str;
+ lines = lines.map(function(line) {
+ return htmlspecialchars(line.substring(4));
+ });
+ str = (this.markLines(lines, start)).join("\n");
+ if (str.match(/^\s*$/)) {
+ return '';
+ } else {
+ return '' + str + '
';
+ }
+ }
+
+ parseAhtml(lines, value, start) {
+ return trim((this.markLines(lines, start)).join("\n"));
+ }
+
+ parseShtml(lines, value, start) {
+ return trim((this.markLines(lines.slice(1, -1), start + 1)).join("\n"));
+ }
+
+ parseMath(lines, value, start, end) {
+ return '' + str + '' + (this.parse(str, true, start)) + '
';
+ }
+ }
+
+ parseList(lines, value, start) {
+ var html, j, key, l, last, len, len1, line, matches, row, rows, space, suffix, tab, type;
+ html = '';
+ [space, type, tab] = value;
+ rows = [];
+ suffix = '';
+ last = 0;
+ for (key = j = 0, len = lines.length; j < len; key = ++j) {
+ line = lines[key];
+ if (matches = line.match(new RegExp(`^(\\s{${space}})((?:[0-9]+\\.?)|\\-|\\+|\\*)(\\s+)(.*)$`))) {
+ if (type === 'ol' && key === 0) {
+ start = parseInt(matches[2]);
+ if (start !== 1) {
+ suffix = ' start="' + start + '"';
+ }
+ }
+ rows.push([matches[4]]);
+ last = rows.length - 1;
+ } else {
+ rows[last].push(line.replace(new RegExp(`^\\s{${tab + space}}`), ''));
+ }
+ }
+ for (l = 0, len1 = rows.length; l < len1; l++) {
+ row = rows[l];
+ html += '';
+ body = head ? null : true;
+ output = false;
+ for (key = j = 0, len = lines.length; j < len; key = ++j) {
+ line = lines[key];
+ if (0 <= ignores.indexOf(key)) {
+ if (head && output) {
+ head = false;
+ body = true;
+ }
+ continue;
+ }
+ line = trim(line);
+ output = true;
+ if (line[0] === '|') {
+ line = line.substring(1);
+ if (line[line.length - 1] === '|') {
+ line = line.substring(0, line.length - 1);
+ }
+ }
+ rows = line.split('|').map(function(row) {
+ if (row.match(/^\s*$/)) {
+ return ' ';
+ } else {
+ return trim(row);
+ }
+ });
+ columns = {};
+ last = -1;
+ for (l = 0, len1 = rows.length; l < len1; l++) {
+ row = rows[l];
+ if (row.length > 0) {
+ last += 1;
+ columns[last] = [(columns[last] != null ? columns[last][0] + 1 : 1), row];
+ } else if (columns[last] != null) {
+ columns[last][0] += 1;
+ } else {
+ columns[0] = [1, row];
+ }
+ }
+ if (head) {
+ html += '';
+ } else if (body) {
+ html += '';
+ }
+ html += '
';
+ }
+
+ parseHr(lines, value, start) {
+ if (this.line) {
+ return '';
+ for (key in columns) {
+ column = columns[key];
+ [num, text] = column;
+ tag = head ? 'th' : 'td';
+ html += `<${tag}`;
+ if (num > 1) {
+ html += ` colspan=\"${num}\"`;
+ }
+ if ((aligns[key] != null) && aligns[key] !== 'none') {
+ html += ` align=\"${aligns[key]}\"`;
+ }
+ html += '>' + (this.parseInline(text)) + `${tag}>`;
+ }
+ html += ' ';
+ if (head) {
+ html += '';
+ } else if (body) {
+ body = false;
+ }
+ }
+ if (body !== null) {
+ html += '';
+ }
+ return html += '
';
+ } else {
+ return '
';
+ }
+ }
+
+ parseNormal(lines, inline, start) {
+ var key, str;
+ key = 0;
+ lines = lines.map((line) => {
+ line = this.parseInline(line);
+ if (!line.match(/^\s*$/)) {
+ line = (this.markLine(start + key)) + line;
+ }
+ key += 1;
+ return line;
+ });
+ str = trim(lines.join("\n"));
+ str = str.replace(/(\n\s*){2,}/g, () => {
+ inline = false;
+ return '
';
+ });
+ str = str.replace(/\n/g, '
');
+ if (str.match(/^\s*$/)) {
+ return '';
+ } else {
+ if (inline) {
+ return str;
+ } else {
+ return `
${str}
`; + } + } + } + + parseFootnote(lines, value) { + var index, note, space; + [space, note] = value; + index = this.footnotes.indexOf(note); + if (index >= 0) { + lines = lines.slice(0); // clone array + lines[0] = lines[0].replace(/^\[\^((?:[^\]]|\]|\[)+?)\]:/, ''); + this.footnotes[index] = lines; + } + return ''; + } + + parseDefinition() { + return ''; + } + + parseHtml(lines, type, start) { + lines = lines.map((line) => { + return this.parseInline(line, this.specialWhiteList[type] != null ? this.specialWhiteList[type] : ''); + }); + return (this.markLines(lines, start)).join("\n"); + } + + cleanUrl(url, parseTitle = false) { + var matches, pos, title; + title = null; + url = trim(url); + if (parseTitle) { + pos = url.indexOf(' '); + if (pos >= 0) { + title = htmlspecialchars(trim(url.substring(pos + 1), ' "\'')); + url = url.substring(0, pos); + } + } + url = url.replace(/["'<>\s]/g, ''); + if (!!(matches = url.match(/^(mailto:)?[_a-z0-9-\.\+]+@[_\w-]+(?:\.[a-z]{2,})+$/i))) { + if (matches[1] == null) { + url = 'mailto:' + url; + } + } + if ((url.match(/^\w+:/i)) && !(url.match(/^(https?|mailto):/i))) { + return '#'; + } + if (parseTitle) { + return [url, title]; + } else { + return url; + } + } + + escapeBracket(str) { + return str_replace(['\\[', '\\]', '\\(', '\\)'], ['[', ']', '(', ')'], str); + } + + startBlock(type, start, value = null) { + this.pos += 1; + this.current = type; + this.blocks.push([type, start, start, value]); + return this; + } + + endBlock() { + this.current = 'normal'; + return this; + } + + isBlock(type, value = null) { + return this.current === type && (null === value ? true : this.blocks[this.pos][3] === value); + } + + getBlock() { + if (this.blocks[this.pos] != null) { + return this.blocks[this.pos]; + } else { + return null; + } + } + + setBlock(to = null, value = null) { + if (to !== null) { + this.blocks[this.pos][2] = to; + } + if (value !== null) { + this.blocks[this.pos][3] = value; + } + return this; + } + + backBlock(step, type, value = null) { + var item, last; + if (this.pos < 0) { + return this.startBlock(type, 0, value); + } + last = this.blocks[this.pos][2]; + this.blocks[this.pos][2] = last - step; + item = [type, last - step + 1, last, value]; + if (this.blocks[this.pos][1] <= this.blocks[this.pos][2]) { + this.pos += 1; + this.blocks.push(item); + } else { + this.blocks[this.pos] = item; + } + this.current = type; + return this; + } + + combineBlock() { + var current, prev; + if (this.pos < 1) { + return this; + } + prev = this.blocks[this.pos - 1].slice(0); + current = this.blocks[this.pos].slice(0); + prev[2] = current[2]; + this.blocks[this.pos - 1] = prev; + this.current = prev[0]; + this.blocks = this.blocks.slice(0, -1); + this.pos -= 1; + return this; + } + + }; + + // begin php function wrappers ucfirst = function(str) { return (str.charAt(0)).toUpperCase() + str.substring(1); }; @@ -39,14 +1123,11 @@ return str.replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"'); }; - trim = function(str, ch) { + trim = function(str, ch = null) { var c, i, j, ref, search; - if (ch == null) { - ch = null; - } if (ch != null) { search = ''; - for (i = j = 0, ref = ch.length - 1; 0 <= ref ? j <= ref : j >= ref; i = 0 <= ref ? ++j : --j) { + for (i = j = 0, ref = ch.length - 1; (0 <= ref ? j <= ref : j >= ref); i = 0 <= ref ? ++j : --j) { c = ch[i]; c = preg_quote(c); search += c; @@ -91,1174 +1172,9 @@ return result; }; - function Parser() { - this.commonWhiteList = 'kbd|b|i|strong|em|sup|sub|br|code|del|a|hr|small'; - this.blockHtmlTags = 'p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|address|form|fieldset|iframe|hr|legend|article|section|nav|aside|hgroup|header|footer|figcaption|svg|script|noscript'; - this.specialWhiteList = { - table: 'table|tbody|thead|tfoot|tr|td|th' - }; - this.hooks = {}; - this.html = false; - this.line = false; - this.blockParsers = [['code', 10], ['shtml', 20], ['pre', 30], ['ahtml', 40], ['shr', 50], ['list', 60], ['math', 70], ['html', 80], ['footnote', 90], ['definition', 100], ['quote', 110], ['table', 120], ['sh', 130], ['mh', 140], ['dhr', 150], ['default', 9999]]; - this.parsers = {}; - } - - Parser.prototype.makeHtml = function(text) { - var html, j, len, name, parser, ref; - this.footnotes = []; - this.definitions = {}; - this.holders = {}; - this.uniqid = (Math.ceil(Math.random() * 10000000)) + (Math.ceil(Math.random() * 10000000)); - this.id = 0; - this.blockParsers.sort(function(a, b) { - if (a[1] < b[1]) { - return -1; - } else { - return 1; - } - }); - ref = this.blockParsers; - for (j = 0, len = ref.length; j < len; j++) { - parser = ref[j]; - name = parser[0]; - if (parser[2] !== void 0) { - this.parsers[name] = parser[2]; - } else { - this.parsers[name] = this['parseBlock' + (ucfirst(name))].bind(this); - } - } - text = this.initText(text); - html = this.parse(text); - html = this.makeFootnotes(html); - html = this.optimizeLines(html); - return this.call('makeHtml', html); - }; - - Parser.prototype.enableHtml = function(html1) { - this.html = html1 != null ? html1 : true; - }; - - Parser.prototype.enableLine = function(line1) { - this.line = line1 != null ? line1 : true; - }; - - Parser.prototype.hook = function(type, cb) { - if (this.hooks[type] == null) { - this.hooks[type] = []; - } - return this.hooks[type].push(cb); - }; - - Parser.prototype.makeHolder = function(str) { - var key; - key = "|\r" + this.uniqid + this.id + "\r|"; - this.id += 1; - this.holders[key] = str; - return key; - }; - - Parser.prototype.initText = function(text) { - return text.replace(/\t/g, ' ').replace(/\r/g, '').replace(/(\u000A|\u000D|\u2028|\u2029)/g, "\n"); - }; - - Parser.prototype.makeFootnotes = function(html) { - var index, val; - if (this.footnotes.length > 0) { - html += '' + (htmlspecialchars(matches[3])) + '');
- };
- })(this));
- text = text.replace(/(^|[^\\])(\$+)(.+?)\2/mg, (function(_this) {
- return function() {
- var matches;
- matches = 1 <= arguments.length ? slice.call(arguments, 0) : [];
- return matches[1] + _this.makeHolder(matches[2] + (htmlspecialchars(matches[3])) + matches[2]);
- };
- })(this));
- text = text.replace(/\\(.)/g, (function(_this) {
- return function() {
- var escaped, matches, prefix;
- matches = 1 <= arguments.length ? slice.call(arguments, 0) : [];
- prefix = matches[1].match(/^[-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]$/) ? '' : '\\';
- escaped = htmlspecialchars(matches[1]);
- escaped = escaped.replace(/\$/g, '$');
- return _this.makeHolder(prefix + escaped);
- };
- })(this));
- text = text.replace(/<(https?:\/\/.+|(?:mailto:)?[_a-z0-9-\.\+]+@[_\w-]+\.[a-z]{2,})>/ig, (function(_this) {
- return function() {
- var link, matches, url;
- matches = 1 <= arguments.length ? slice.call(arguments, 0) : [];
- url = _this.cleanUrl(matches[1]);
- link = _this.call('parseLink', url);
- return _this.makeHolder("" + link + "");
- };
- })(this));
- text = text.replace(/<(\/?)([a-z0-9-]+)(\s+[^>]*)?>/ig, (function(_this) {
- return function() {
- var matches;
- matches = 1 <= arguments.length ? slice.call(arguments, 0) : [];
- if (_this.html || (('|' + _this.commonWhiteList + '|' + whiteList + '|').indexOf('|' + matches[2].toLowerCase() + '|')) >= 0) {
- return _this.makeHolder(matches[0]);
- } else {
- return _this.makeHolder(htmlspecialchars(matches[0]));
- }
- };
- })(this));
- if (this.html) {
- text = text.replace(//g, (function(_this) {
- return function() {
- var matches;
- matches = 1 <= arguments.length ? slice.call(arguments, 0) : [];
- return _this.makeHolder(matches[0]);
- };
- })(this));
- }
- text = str_replace(['<', '>'], ['<', '>'], text);
- text = text.replace(/\[\^((?:[^\]]|\\\]|\\\[)+?)\]/g, (function(_this) {
- return function() {
- var id, matches;
- matches = 1 <= arguments.length ? slice.call(arguments, 0) : [];
- id = _this.footnotes.indexOf(matches[1]);
- if (id < 0) {
- id = _this.footnotes.length + 1;
- _this.footnotes.push(_this.parseInline(matches[1], '', false));
- }
- return _this.makeHolder("" + id + "");
- };
- })(this));
- text = text.replace(/!\[((?:[^\]]|\\\]|\\\[)*?)\]\(((?:[^\)]|\\\)|\\\()+?)\)/g, (function(_this) {
- return function() {
- var escaped, matches, ref, title, url;
- matches = 1 <= arguments.length ? slice.call(arguments, 0) : [];
- escaped = htmlspecialchars(_this.escapeBracket(matches[1]));
- url = _this.escapeBracket(matches[2]);
- ref = _this.cleanUrl(url, true), url = ref[0], title = ref[1];
- title = title == null ? escaped : " title=\"" + title + "\"";
- return _this.makeHolder("' + str + '';
- }
- };
-
- Parser.prototype.parsePre = function(lines, value, start) {
- var str;
- lines = lines.map(function(line) {
- return htmlspecialchars(line.substring(4));
- });
- str = (this.markLines(lines, start)).join("\n");
- if (str.match(/^\s*$/)) {
- return '';
- } else {
- return '' + str + '';
- }
- };
-
- Parser.prototype.parseAhtml = function(lines, value, start) {
- return trim((this.markLines(lines, start)).join("\n"));
- };
-
- Parser.prototype.parseShtml = function(lines, value, start) {
- return trim((this.markLines(lines.slice(1, -1), start + 1)).join("\n"));
- };
-
- Parser.prototype.parseMath = function(lines, value, start, end) {
- return '' + (this.markLine(start, end)) + (htmlspecialchars(lines.join("\n"))) + '
'; - }; - - Parser.prototype.parseSh = function(lines, num, start, end) { - var line; - line = (this.markLine(start, end)) + this.parseInline(trim(lines[0], '# ')); - if (line.match(/^\s*$/)) { - return ''; - } else { - return "' + (this.parse(str, true, start)) + ''; - } - }; - - Parser.prototype.parseList = function(lines, value, start) { - var html, j, key, l, last, len, len1, line, matches, row, rows, space, suffix, tab, type; - html = ''; - space = value[0], type = value[1], tab = value[2]; - rows = []; - suffix = ''; - last = 0; - for (key = j = 0, len = lines.length; j < len; key = ++j) { - line = lines[key]; - if (matches = line.match(new RegExp("^(\\s{" + space + "})((?:[0-9]+\\.?)|\\-|\\+|\\*)(\\s+)(.*)$"))) { - if (type === 'ol' && key === 0) { - start = parseInt(matches[2]); - if (start !== 1) { - suffix = ' start="' + start + '"'; - } - } - rows.push([matches[4]]); - last = rows.length - 1; - } else { - rows[last].push(line.replace(new RegExp("^\\s{" + (tab + space) + "}"), '')); - } - } - for (l = 0, len1 = rows.length; l < len1; l++) { - row = rows[l]; - html += '
';
- };
- })(this));
- str = str.replace(/\n/g, '
');
- if (str.match(/^\s*$/)) {
- return '';
- } else {
- if (inline) {
- return str;
- } else {
- return "
" + str + "
"; - } - } - }; - - Parser.prototype.parseFootnote = function(lines, value) { - var index, note, space; - space = value[0], note = value[1]; - index = this.footnotes.indexOf(note); - if (index >= 0) { - lines = lines.slice(0); - lines[0] = lines[0].replace(/^\[\^((?:[^\]]|\]|\[)+?)\]:/, ''); - this.footnotes[index] = lines; - } - return ''; - }; - - Parser.prototype.parseDefinition = function() { - return ''; - }; - - Parser.prototype.parseHtml = function(lines, type, start) { - lines = lines.map((function(_this) { - return function(line) { - return _this.parseInline(line, _this.specialWhiteList[type] != null ? _this.specialWhiteList[type] : ''); - }; - })(this)); - return (this.markLines(lines, start)).join("\n"); - }; - - Parser.prototype.cleanUrl = function(url, parseTitle) { - var matches, pos, title; - if (parseTitle == null) { - parseTitle = false; - } - title = null; - url = trim(url); - if (parseTitle) { - pos = url.indexOf(' '); - if (pos >= 0) { - title = htmlspecialchars(trim(url.substring(pos + 1), ' "\'')); - url = url.substring(0, pos); - } - } - url = url.replace(/["'<>\s]/g, ''); - if (!!(matches = url.match(/^(mailto:)?[_a-z0-9-\.\+]+@[_\w-]+\.[a-z]{2,}$/i))) { - if (matches[1] == null) { - url = 'mailto:' + url; - } - } - if ((url.match(/^\w+:/i)) && !(url.match(/^(https?|mailto):/i))) { - return '#'; - } - if (parseTitle) { - return [url, title]; - } else { - return url; - } - }; - - Parser.prototype.escapeBracket = function(str) { - return str_replace(['\\[', '\\]', '\\(', '\\)'], ['[', ']', '(', ')'], str); - }; - - Parser.prototype.startBlock = function(type, start, value) { - if (value == null) { - value = null; - } - this.pos += 1; - this.current = type; - this.blocks.push([type, start, start, value]); - return this; - }; - - Parser.prototype.endBlock = function() { - this.current = 'normal'; - return this; - }; - - Parser.prototype.isBlock = function(type, value) { - if (value == null) { - value = null; - } - return this.current === type && (null === value ? true : this.blocks[this.pos][3] === value); - }; - - Parser.prototype.getBlock = function() { - if (this.blocks[this.pos] != null) { - return this.blocks[this.pos]; - } else { - return null; - } - }; - - Parser.prototype.setBlock = function(to, value) { - if (to == null) { - to = null; - } - if (value == null) { - value = null; - } - if (to !== null) { - this.blocks[this.pos][2] = to; - } - if (value !== null) { - this.blocks[this.pos][3] = value; - } - return this; - }; - - Parser.prototype.backBlock = function(step, type, value) { - var item, last; - if (value == null) { - value = null; - } - if (this.pos < 0) { - return this.startBlock(type, 0, value); - } - last = this.blocks[this.pos][2]; - this.blocks[this.pos][2] = last - step; - item = [type, last - step + 1, last, value]; - if (this.blocks[this.pos][1] <= this.blocks[this.pos][2]) { - this.pos += 1; - this.blocks.push(item); - } else { - this.blocks[this.pos] = item; - } - this.current = type; - return this; - }; - - Parser.prototype.combineBlock = function() { - var current, prev; - if (this.pos < 1) { - return this; - } - prev = this.blocks[this.pos - 1].slice(0); - current = this.blocks[this.pos].slice(0); - prev[2] = current[2]; - this.blocks[this.pos - 1] = prev; - this.current = prev[0]; - this.blocks = this.blocks.slice(0, -1); - this.pos -= 1; - return this; - }; - return Parser; - })(); + }).call(this); if (typeof module !== "undefined" && module !== null) { module.exports = Parser; diff --git a/var/HyperDown.php b/var/HyperDown.php index 028f51dc..a06a9f40 100644 --- a/var/HyperDown.php +++ b/var/HyperDown.php @@ -385,8 +385,8 @@ class HyperDown "/(^|[^\\\])(`+)(.+?)\\2/", function ($matches) use ($self) { return $matches[1] . $self->makeHolder( - '' . htmlspecialchars($matches[3]) . ''
- );
+ '' . htmlspecialchars($matches[3]) . ''
+ );
},
$text
);
@@ -396,8 +396,8 @@ class HyperDown
"/(^|[^\\\])(\\$+)(.+?)\\2/",
function ($matches) use ($self) {
return $matches[1] . $self->makeHolder(
- $matches[2] . htmlspecialchars($matches[3]) . $matches[2]
- );
+ $matches[2] . htmlspecialchars($matches[3]) . $matches[2]
+ );
},
$text
);
@@ -416,7 +416,7 @@ class HyperDown
// link
$text = preg_replace_callback(
- "/<(https?:\/\/.+|(?:mailto:)?[_a-z0-9-\.\+]+@[_\w-]+\.[a-z]{2,})>/i",
+ "/<(https?:\/\/.+|(?:mailto:)?[_a-z0-9-\.\+]+@[_\w-]+(?:\.[a-z]{2,})+)>/i",
function ($matches) use ($self) {
$url = $self->cleanUrl($matches[1]);
$link = $self->call('parseLink', $url);
@@ -433,8 +433,8 @@ class HyperDown
"/<(\/?)([a-z0-9-]+)(\s+[^>]*)?>/i",
function ($matches) use ($self, $whiteList) {
if ($self->_html || false !== stripos(
- '|' . $self->_commonWhiteList . '|' . $whiteList . '|', '|' . $matches[2] . '|'
- )) {
+ '|' . $self->_commonWhiteList . '|' . $whiteList . '|', '|' . $matches[2] . '|'
+ )) {
return $self->makeHolder($matches[0]);
} else {
return $self->makeHolder(htmlspecialchars($matches[0]));
@@ -541,7 +541,7 @@ class HyperDown
// autolink url
if ($enableAutoLink) {
$text = preg_replace_callback(
- "/(^|[^\"])(https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\b([-a-zA-Z0-9()@:%_\+.~#?&\/=]*)|(?:mailto:)?[_a-z0-9-\.\+]+@[_\w-]+\.[a-z]{2,})($|[^\"])/",
+ "/(^|[^\"])(https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\b([-a-zA-Z0-9()@:%_\+.~#?&\/=]*)|(?:mailto:)?[_a-z0-9-\.\+]+@[_\w-]+(?:\.[a-z]{2,})+)($|[^\"])/",
function ($matches) use ($self) {
$url = $self->cleanUrl($matches[2]);
$link = $self->call('parseLink', $matches[2]);
@@ -1093,7 +1093,7 @@ class HyperDown
private function parseBlockMh($block, $key, $line, &$state, $lines)
{
if (preg_match("/^\s*((=|-){2,})\s*$/", $line, $matches)
- && ($block && $block[0] == "normal" && !preg_match("/^\s*$/", $lines[$block[2]]))) { // check if last line isn't empty
+ && ($block && $block[0] == "normal" && !preg_match("/^\s*$/", $lines[$block[2]]))) { // check if last line isn't empty
if ($this->isBlock('normal')) {
$this->backBlock(1, 'mh', $matches[1][0] == '=' ? 1 : 2)
->setBlock($key)
@@ -1649,7 +1649,7 @@ class HyperDown
$url = preg_replace("/[\"'<>\s]/", '', $url);
- if (preg_match("/^(mailto:)?[_a-z0-9-\.\+]+@[_\w-]+\.[a-z]{2,}$/i", $url, $matches)) {
+ if (preg_match("/^(mailto:)?[_a-z0-9-\.\+]+@[_\w-]+(?:\.[a-z]{2,})+$/i", $url, $matches)) {
if (empty($matches[1])) {
$url = 'mailto:' . $url;
}