Skip to content

Commit 3097bd4

Browse files
committed
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
1 parent 0416218 commit 3097bd4

10 files changed

Lines changed: 222 additions & 7 deletions

File tree

dist/showdown.js

Lines changed: 101 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/showdown.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/showdown.min.js

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/showdown.min.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/converter.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,10 @@ showdown.Converter = function (converterOptions) {
4141
parserOrder = [
4242
'githubCodeBlocks',
4343
'hashHTMLBlocks',
44+
'hashHTMLSpans',
4445
'stripLinkDefinitions',
4546
'blockGamut',
47+
'unhashHTMLSpans',
4648
'unescapeSpecialChars'
4749
];
4850

@@ -183,6 +185,7 @@ showdown.Converter = function (converterOptions) {
183185

184186
var globals = {
185187
gHtmlBlocks: [],
188+
gHtmlSpans: [],
186189
gUrls: {},
187190
gTitles: {},
188191
gDimensions: {},

src/helpers.js

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,68 @@ showdown.helper.escapeCharacters = function escapeCharacters(text, charsToEscape
106106
return text;
107107
};
108108

109+
/**
110+
* matchRecursiveRegExp
111+
*
112+
* (c) 2007 Steven Levithan <stevenlevithan.com>
113+
* MIT License
114+
*
115+
* Accepts a string to search, a left and right format delimiter
116+
* as regex patterns, and optional regex flags. Returns an array
117+
* of matches, allowing nested instances of left/right delimiters.
118+
* Use the "g" flag to return all matches, otherwise only the
119+
* first is returned. Be careful to ensure that the left and
120+
* right format delimiters produce mutually exclusive matches.
121+
* Backreferences are not supported within the right delimiter
122+
* due to how it is internally combined with the left delimiter.
123+
* When matching strings whose format delimiters are unbalanced
124+
* to the left or right, the output is intentionally as a
125+
* conventional regex library with recursion support would
126+
* produce, e.g. "<<x>" and "<x>>" both produce ["x"] when using
127+
* "<" and ">" as the delimiters (both strings contain a single,
128+
* balanced instance of "<x>").
129+
*
130+
* examples:
131+
* matchRecursiveRegExp("test", "\\(", "\\)")
132+
* returns: []
133+
* matchRecursiveRegExp("<t<<e>><s>>t<>", "<", ">", "g")
134+
* returns: ["t<<e>><s>", ""]
135+
* matchRecursiveRegExp("<div id=\"x\">test</div>", "<div\\b[^>]*>", "</div>", "gi")
136+
* returns: ["test"]
137+
*/
138+
showdown.helper.matchRecursiveRegExp = function (str, left, right, flags) {
139+
'use strict';
140+
var f = flags || '',
141+
g = f.indexOf('g') > -1,
142+
x = new RegExp(left + '|' + right, f),
143+
l = new RegExp(left, f.replace(/g/g, '')),
144+
a = [],
145+
t, s, m, start, end;
146+
147+
do {
148+
t = 0;
149+
while ((m = x.exec(str))) {
150+
if (l.test(m[0])) {
151+
if (!(t++)) {
152+
start = m[0];
153+
s = x.lastIndex;
154+
}
155+
} else if (t) {
156+
if (!--t) {
157+
end = m[0];
158+
var match = str.slice(s, m.index);
159+
a.push([start + match + end, match]);
160+
if (!g) {
161+
return a;
162+
}
163+
}
164+
}
165+
}
166+
} while (t && (x.lastIndex = s));
167+
168+
return a;
169+
};
170+
109171
/**
110172
* POLYFILLS
111173
*/
@@ -118,6 +180,10 @@ if (showdown.helper.isUndefined(console)) {
118180
log: function (msg) {
119181
'use strict';
120182
alert(msg);
183+
},
184+
error: function (msg) {
185+
'use strict';
186+
throw msg;
121187
}
122188
};
123189
}

src/subParsers/codeSpans.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,16 @@
2626
showdown.subParser('codeSpans', function (text) {
2727
'use strict';
2828

29+
/*
2930
//special case -> literal html code tag
31+
// Introduced in commit 5f043ca46d20eb88240c753ae7f7c7429f4ee27
32+
// Commented out due to issue #196
3033
text = text.replace(/(<code[^><]*?>)([^]*?)<\/code>/g, function (wholeMatch, tag, c) {
3134
c = c.replace(/^([ \t]*)/g, ''); // leading whitespace
3235
c = c.replace(/[ \t]*$/g, ''); // trailing whitespace
3336
c = showdown.subParser('encodeCode')(c);
3437
return tag + c + '</code>';
35-
});
38+
});*/
3639

3740
/*
3841
text = text.replace(/

src/subParsers/hashHTMLSpans.js

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/**
2+
* Hash span elements that should not be parsed as markdown
3+
*/
4+
showdown.subParser('hashHTMLSpans', function (text, config, globals) {
5+
'use strict';
6+
7+
var matches = showdown.helper.matchRecursiveRegExp(text, '<code\\b[^>]*>', '</code>', 'gi');
8+
9+
for (var i = 0; i < matches.length; ++i) {
10+
text = text.replace(matches[i][0], '~L' + (globals.gHtmlSpans.push(matches[i][0]) - 1) + 'L');
11+
}
12+
return text;
13+
});
14+
15+
/**
16+
* Unhash HTML spans
17+
*/
18+
showdown.subParser('unhashHTMLSpans', function (text, config, globals) {
19+
'use strict';
20+
21+
for (var i = 0; i < globals.gHtmlSpans.length; ++i) {
22+
text = text.replace('~L' + i + 'L', globals.gHtmlSpans[i]);
23+
}
24+
25+
return text;
26+
});

test/cases/literal-html-tags.html

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<p><code>some **code** yeah</code></p>
2+
3+
<p>some <code>inline **code** block</code></p>
4+
5+
<p><code>some inline **code**</code> block</p>
6+
7+
<p>yo dawg <code start="true">some <code start="false">code</code> inception</code></p>
8+
9+
<div>some **div** yeah</div>

test/cases/literal-html-tags.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<code>some **code** yeah</code>
2+
3+
some <code>inline **code** block</code>
4+
5+
<code>some inline **code**</code> block
6+
7+
yo dawg <code start="true">some <code start="false">code</code> inception</code>
8+
9+
<div>some **div** yeah</div>

0 commit comments

Comments
 (0)