mirror of
https://github.com/showdownjs/showdown.git
synced 2024-03-22 13:30:55 +08:00
feat(hashHTMLSpans): Add support for hashing span elements
This feature enables hashing span elements that should not be touched by
showdown. For instance, `<code>` tags in markdown source should not be
parsed by showdown, so the text inside them remains unchanged.
This is made possible by a new exciting internal feature,
matchRecursiveRegExp.
Closes #196, Closes #175, Partially reverts 5f043ca
This commit is contained in:
parent
0416218d27
commit
3097bd45c2
BIN
dist/showdown.js
vendored
BIN
dist/showdown.js
vendored
Binary file not shown.
BIN
dist/showdown.js.map
vendored
BIN
dist/showdown.js.map
vendored
Binary file not shown.
BIN
dist/showdown.min.js
vendored
BIN
dist/showdown.min.js
vendored
Binary file not shown.
BIN
dist/showdown.min.js.map
vendored
BIN
dist/showdown.min.js.map
vendored
Binary file not shown.
|
@ -41,8 +41,10 @@ showdown.Converter = function (converterOptions) {
|
||||||
parserOrder = [
|
parserOrder = [
|
||||||
'githubCodeBlocks',
|
'githubCodeBlocks',
|
||||||
'hashHTMLBlocks',
|
'hashHTMLBlocks',
|
||||||
|
'hashHTMLSpans',
|
||||||
'stripLinkDefinitions',
|
'stripLinkDefinitions',
|
||||||
'blockGamut',
|
'blockGamut',
|
||||||
|
'unhashHTMLSpans',
|
||||||
'unescapeSpecialChars'
|
'unescapeSpecialChars'
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -183,6 +185,7 @@ showdown.Converter = function (converterOptions) {
|
||||||
|
|
||||||
var globals = {
|
var globals = {
|
||||||
gHtmlBlocks: [],
|
gHtmlBlocks: [],
|
||||||
|
gHtmlSpans: [],
|
||||||
gUrls: {},
|
gUrls: {},
|
||||||
gTitles: {},
|
gTitles: {},
|
||||||
gDimensions: {},
|
gDimensions: {},
|
||||||
|
|
|
@ -106,6 +106,68 @@ showdown.helper.escapeCharacters = function escapeCharacters(text, charsToEscape
|
||||||
return text;
|
return text;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* matchRecursiveRegExp
|
||||||
|
*
|
||||||
|
* (c) 2007 Steven Levithan <stevenlevithan.com>
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Accepts a string to search, a left and right format delimiter
|
||||||
|
* as regex patterns, and optional regex flags. Returns an array
|
||||||
|
* of matches, allowing nested instances of left/right delimiters.
|
||||||
|
* Use the "g" flag to return all matches, otherwise only the
|
||||||
|
* first is returned. Be careful to ensure that the left and
|
||||||
|
* right format delimiters produce mutually exclusive matches.
|
||||||
|
* Backreferences are not supported within the right delimiter
|
||||||
|
* due to how it is internally combined with the left delimiter.
|
||||||
|
* When matching strings whose format delimiters are unbalanced
|
||||||
|
* to the left or right, the output is intentionally as a
|
||||||
|
* conventional regex library with recursion support would
|
||||||
|
* produce, e.g. "<<x>" and "<x>>" both produce ["x"] when using
|
||||||
|
* "<" and ">" as the delimiters (both strings contain a single,
|
||||||
|
* balanced instance of "<x>").
|
||||||
|
*
|
||||||
|
* examples:
|
||||||
|
* matchRecursiveRegExp("test", "\\(", "\\)")
|
||||||
|
* returns: []
|
||||||
|
* matchRecursiveRegExp("<t<<e>><s>>t<>", "<", ">", "g")
|
||||||
|
* returns: ["t<<e>><s>", ""]
|
||||||
|
* matchRecursiveRegExp("<div id=\"x\">test</div>", "<div\\b[^>]*>", "</div>", "gi")
|
||||||
|
* returns: ["test"]
|
||||||
|
*/
|
||||||
|
showdown.helper.matchRecursiveRegExp = function (str, left, right, flags) {
|
||||||
|
'use strict';
|
||||||
|
var f = flags || '',
|
||||||
|
g = f.indexOf('g') > -1,
|
||||||
|
x = new RegExp(left + '|' + right, f),
|
||||||
|
l = new RegExp(left, f.replace(/g/g, '')),
|
||||||
|
a = [],
|
||||||
|
t, s, m, start, end;
|
||||||
|
|
||||||
|
do {
|
||||||
|
t = 0;
|
||||||
|
while ((m = x.exec(str))) {
|
||||||
|
if (l.test(m[0])) {
|
||||||
|
if (!(t++)) {
|
||||||
|
start = m[0];
|
||||||
|
s = x.lastIndex;
|
||||||
|
}
|
||||||
|
} else if (t) {
|
||||||
|
if (!--t) {
|
||||||
|
end = m[0];
|
||||||
|
var match = str.slice(s, m.index);
|
||||||
|
a.push([start + match + end, match]);
|
||||||
|
if (!g) {
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while (t && (x.lastIndex = s));
|
||||||
|
|
||||||
|
return a;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* POLYFILLS
|
* POLYFILLS
|
||||||
*/
|
*/
|
||||||
|
@ -118,6 +180,10 @@ if (showdown.helper.isUndefined(console)) {
|
||||||
log: function (msg) {
|
log: function (msg) {
|
||||||
'use strict';
|
'use strict';
|
||||||
alert(msg);
|
alert(msg);
|
||||||
|
},
|
||||||
|
error: function (msg) {
|
||||||
|
'use strict';
|
||||||
|
throw msg;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,13 +26,16 @@
|
||||||
showdown.subParser('codeSpans', function (text) {
|
showdown.subParser('codeSpans', function (text) {
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
/*
|
||||||
//special case -> literal html code tag
|
//special case -> literal html code tag
|
||||||
|
// Introduced in commit 5f043ca46d20eb88240c753ae7f7c7429f4ee27
|
||||||
|
// Commented out due to issue #196
|
||||||
text = text.replace(/(<code[^><]*?>)([^]*?)<\/code>/g, function (wholeMatch, tag, c) {
|
text = text.replace(/(<code[^><]*?>)([^]*?)<\/code>/g, function (wholeMatch, tag, c) {
|
||||||
c = c.replace(/^([ \t]*)/g, ''); // leading whitespace
|
c = c.replace(/^([ \t]*)/g, ''); // leading whitespace
|
||||||
c = c.replace(/[ \t]*$/g, ''); // trailing whitespace
|
c = c.replace(/[ \t]*$/g, ''); // trailing whitespace
|
||||||
c = showdown.subParser('encodeCode')(c);
|
c = showdown.subParser('encodeCode')(c);
|
||||||
return tag + c + '</code>';
|
return tag + c + '</code>';
|
||||||
});
|
});*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
text = text.replace(/
|
text = text.replace(/
|
||||||
|
|
26
src/subParsers/hashHTMLSpans.js
Normal file
26
src/subParsers/hashHTMLSpans.js
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
/**
|
||||||
|
* Hash span elements that should not be parsed as markdown
|
||||||
|
*/
|
||||||
|
showdown.subParser('hashHTMLSpans', function (text, config, globals) {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var matches = showdown.helper.matchRecursiveRegExp(text, '<code\\b[^>]*>', '</code>', 'gi');
|
||||||
|
|
||||||
|
for (var i = 0; i < matches.length; ++i) {
|
||||||
|
text = text.replace(matches[i][0], '~L' + (globals.gHtmlSpans.push(matches[i][0]) - 1) + 'L');
|
||||||
|
}
|
||||||
|
return text;
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unhash HTML spans
|
||||||
|
*/
|
||||||
|
showdown.subParser('unhashHTMLSpans', function (text, config, globals) {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
for (var i = 0; i < globals.gHtmlSpans.length; ++i) {
|
||||||
|
text = text.replace('~L' + i + 'L', globals.gHtmlSpans[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return text;
|
||||||
|
});
|
9
test/cases/literal-html-tags.html
Normal file
9
test/cases/literal-html-tags.html
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
<p><code>some **code** yeah</code></p>
|
||||||
|
|
||||||
|
<p>some <code>inline **code** block</code></p>
|
||||||
|
|
||||||
|
<p><code>some inline **code**</code> block</p>
|
||||||
|
|
||||||
|
<p>yo dawg <code start="true">some <code start="false">code</code> inception</code></p>
|
||||||
|
|
||||||
|
<div>some **div** yeah</div>
|
9
test/cases/literal-html-tags.md
Normal file
9
test/cases/literal-html-tags.md
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
<code>some **code** yeah</code>
|
||||||
|
|
||||||
|
some <code>inline **code** block</code>
|
||||||
|
|
||||||
|
<code>some inline **code**</code> block
|
||||||
|
|
||||||
|
yo dawg <code start="true">some <code start="false">code</code> inception</code>
|
||||||
|
|
||||||
|
<div>some **div** yeah</div>
|
Loading…
Reference in New Issue
Block a user