mirror of
https://github.com/showdownjs/showdown.git
synced 2024-03-22 13:30:55 +08:00
fix(lists): enforce 4 space indentation in sublists
Acording to the spec, multi paragraph (or block) list item requires subblocks to be indented 4 spaces (or 1 tab). Although, this is mentioned in the documentation, Showdown didn't enforce this rule in sublists because other implementations, such as GFM also didn't. However, in some edge cases, this led to inconsistent behavior, as shown in issue #299. This commit makes 4 space indentation in sublists mandatory. BREAKING CHANGE: syntax for sublists is more restrictive. Before, sublists SHOULD be indented by 4 spaces, but indenting 2 spaces would work. Now, sublists MUST be indented 4 spaces or they won't work. With this input: ```md * one * two * three ``` Before (ouput): ```html <ul> <li>one <ul> <li>two <ul><li>three</li></ul> <li> </ul> </li> <ul> ``` After (output): ```html <ul> <li>one</li> <li>two <ul><li>three</li></ul> </li> </ul> ``` To migrate either fix source md files or activate the option `disableForced4SpacesIndentedSublists` (coming in v1.5.0): ```md showdown.setOption('disableForced4SpacesIndentedSublists', true); ```
This commit is contained in:
parent
9cfe8b1412
commit
d51be6e0b4
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,11 +41,12 @@ showdown.subParser('lists', function (text, options, globals) {
|
|||
// attacklab: add sentinel to emulate \z
|
||||
listStr += '~0';
|
||||
|
||||
var rgx = /(\n)?(^[ \t]*)([*+-]|\d+[.])[ \t]+((\[(x|X| )?])?[ \t]*[^\r]+?(\n{1,2}))(?=\n*(~0|\2([*+-]|\d+[.])[ \t]+))/gm,
|
||||
var rgx = /(\n)?(^ {0,3})([*+-]|\d+[.])[ \t]+((\[(x|X| )?])?[ \t]*[^\r]+?(\n{1,2}))(?=\n*(~0| {0,3}([*+-]|\d+[.])[ \t]+))/gm,
|
||||
isParagraphed = (/\n[ \t]*\n(?!~0)/.test(listStr));
|
||||
|
||||
listStr = listStr.replace(rgx, function (wholeMatch, m1, m2, m3, m4, taskbtn, checked) {
|
||||
checked = (checked && checked.trim() !== '');
|
||||
|
||||
var item = showdown.subParser('outdent')(m4, options, globals),
|
||||
bulletStyle = '';
|
||||
|
||||
|
@ -61,6 +62,7 @@ showdown.subParser('lists', function (text, options, globals) {
|
|||
return otp;
|
||||
});
|
||||
}
|
||||
|
||||
// m1 - Leading line or
|
||||
// Has a double return (multi paragraph) or
|
||||
// Has sublist
|
||||
|
@ -103,7 +105,9 @@ showdown.subParser('lists', function (text, options, globals) {
|
|||
function parseConsecutiveLists(list, listType, trimTrailing) {
|
||||
// check if we caught 2 or more consecutive lists by mistake
|
||||
// we use the counterRgx, meaning if listType is UL we look for OL and vice versa
|
||||
var counterRxg = (listType === 'ul') ? /^\d+\.[ \t]/gm : /^[*+-][ \t]/gm,
|
||||
var olRgx = /^ {0,3}\d+\.[ \t]/gm,
|
||||
ulRgx = /^ {0,3}[*+-][ \t]/gm,
|
||||
counterRxg = (listType === 'ul') ? olRgx : ulRgx,
|
||||
result = '';
|
||||
|
||||
if (list.search(counterRxg) !== -1) {
|
||||
|
@ -115,7 +119,7 @@ showdown.subParser('lists', function (text, options, globals) {
|
|||
|
||||
// invert counterType and listType
|
||||
listType = (listType === 'ul') ? 'ol' : 'ul';
|
||||
counterRxg = (listType === 'ul') ? /^ {0,2}\d+\.[ \t]/gm : /^ {0,2}[*+-][ \t]/gm;
|
||||
counterRxg = (listType === 'ul') ? olRgx : ulRgx;
|
||||
|
||||
//recurse
|
||||
parseCL(txt.slice(pos));
|
||||
|
@ -134,21 +138,20 @@ showdown.subParser('lists', function (text, options, globals) {
|
|||
// http://bugs.webkit.org/show_bug.cgi?id=11231
|
||||
text += '~0';
|
||||
|
||||
// Re-usable pattern to match any entire ul or ol list:
|
||||
var wholeList = /^(( {0,3}([*+-]|\d+[.])[ \t]+)[^\r]+?(~0|\n{2,}(?=\S)(?![ \t]*(?:[*+-]|\d+[.])[ \t]+)))/gm;
|
||||
|
||||
if (globals.gListLevel) {
|
||||
text = text.replace(wholeList, function (wholeMatch, list, m2) {
|
||||
text = text.replace(/^(( {0,3}([*+-]|\d+[.])[ \t]+)[^\r]+?(~0|\n{2,}(?=\S)(?![ \t]*(?:[*+-]|\d+[.])[ \t]+)))/gm,
|
||||
function (wholeMatch, list, m2) {
|
||||
var listType = (m2.search(/[*+-]/g) > -1) ? 'ul' : 'ol';
|
||||
return parseConsecutiveLists(list, listType, true);
|
||||
});
|
||||
}
|
||||
);
|
||||
} else {
|
||||
wholeList = /(\n\n|^\n?)(( {0,3}([*+-]|\d+[.])[ \t]+)[^\r]+?(~0|\n{2,}(?=\S)(?![ \t]*(?:[*+-]|\d+[.])[ \t]+)))/gm;
|
||||
text = text.replace(wholeList, function (wholeMatch, m1, list, m3) {
|
||||
|
||||
text = text.replace(/(\n\n|^\n?)(( {0,3}([*+-]|\d+[.])[ \t]+)[^\r]+?(~0|\n{2,}(?=\S)(?![ \t]*(?:[*+-]|\d+[.])[ \t]+)))/gm,
|
||||
function (wholeMatch, m1, list, m3) {
|
||||
var listType = (m3.search(/[*+-]/g) > -1) ? 'ul' : 'ol';
|
||||
return parseConsecutiveLists(list, listType, false);
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// strip sentinel
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
<ul>
|
||||
<li>one</li>
|
||||
</ul>
|
||||
<ol>
|
||||
<li>two</li>
|
||||
</ol>
|
||||
<p>foo</p>
|
||||
<ul>
|
||||
<li>one</li>
|
||||
</ul>
|
||||
<ol>
|
||||
<li>two</li>
|
||||
</ol>
|
||||
<p>foo</p>
|
||||
<ul>
|
||||
<li>one</li>
|
||||
</ul>
|
||||
<ol>
|
||||
<li>two</li>
|
||||
</ol>
|
||||
<p>foo</p>
|
||||
<ul>
|
||||
<li>one
|
||||
|
||||
<ol>
|
||||
<li>two</li></ol></li>
|
||||
</ul>
|
||||
<p>foo</p>
|
||||
<ul>
|
||||
<li>one</li>
|
||||
<li>two</li>
|
||||
</ul>
|
||||
<p>foo</p>
|
||||
<ul>
|
||||
<li>one</li>
|
||||
<li>two</li>
|
||||
</ul>
|
||||
<p>foo</p>
|
||||
<ul>
|
||||
<li>one</li>
|
||||
<li>two</li>
|
||||
</ul>
|
||||
<p>foo</p>
|
||||
<ul>
|
||||
<li>one</li>
|
||||
<li>two</li>
|
||||
</ul>
|
||||
<p>foo</p>
|
||||
<ul>
|
||||
<li>one
|
||||
|
||||
<ul>
|
||||
<li>two</li></ul></li>
|
||||
</ul>
|
|
@ -0,0 +1,42 @@
|
|||
* one
|
||||
1. two
|
||||
|
||||
foo
|
||||
|
||||
* one
|
||||
1. two
|
||||
|
||||
foo
|
||||
|
||||
* one
|
||||
1. two
|
||||
|
||||
foo
|
||||
|
||||
* one
|
||||
1. two
|
||||
|
||||
foo
|
||||
|
||||
* one
|
||||
* two
|
||||
|
||||
foo
|
||||
|
||||
* one
|
||||
* two
|
||||
|
||||
foo
|
||||
|
||||
* one
|
||||
* two
|
||||
|
||||
foo
|
||||
|
||||
* one
|
||||
* two
|
||||
|
||||
foo
|
||||
|
||||
* one
|
||||
* two
|
|
@ -0,0 +1,15 @@
|
|||
<ul>
|
||||
<li>one long paragraph of
|
||||
text</li>
|
||||
</ul>
|
||||
<ol>
|
||||
<li>two</li>
|
||||
</ol>
|
||||
<p>foo</p>
|
||||
<ul>
|
||||
<li>one long paragraph of
|
||||
text</li>
|
||||
</ul>
|
||||
<ol>
|
||||
<li>two</li>
|
||||
</ol>
|
|
@ -0,0 +1,9 @@
|
|||
* one long paragraph of
|
||||
text
|
||||
1. two
|
||||
|
||||
foo
|
||||
|
||||
* one long paragraph of
|
||||
text
|
||||
1. two
|
|
@ -6,15 +6,42 @@
|
|||
</ol>
|
||||
<p>foo</p>
|
||||
<ul>
|
||||
<li>one
|
||||
|
||||
<li>one</li>
|
||||
</ul>
|
||||
<ol>
|
||||
<li>two</li></ol></li>
|
||||
<li>two</li>
|
||||
</ol>
|
||||
<p>foo</p>
|
||||
<ul>
|
||||
<li>one</li>
|
||||
</ul>
|
||||
<ol>
|
||||
<li>two</li>
|
||||
</ol>
|
||||
<p>foo</p>
|
||||
<ul>
|
||||
<li>one</li>
|
||||
</ul>
|
||||
<ol>
|
||||
<li>two</li>
|
||||
</ol>
|
||||
<p>foo</p>
|
||||
<ul>
|
||||
<li>uli one</li>
|
||||
<li>uli two</li>
|
||||
</ul>
|
||||
<p>foo</p>
|
||||
<ul>
|
||||
<li>one
|
||||
|
||||
<ul>
|
||||
<li>two</li></ul></li>
|
||||
<li>uli one</li>
|
||||
<li>uli two</li>
|
||||
</ul>
|
||||
<p>foo</p>
|
||||
<ul>
|
||||
<li>uli one</li>
|
||||
<li>uli two</li>
|
||||
</ul>
|
||||
<p>foo</p>
|
||||
<ul>
|
||||
<li>uli one</li>
|
||||
<li>uli two</li>
|
||||
</ul>
|
||||
|
|
|
@ -9,4 +9,29 @@ foo
|
|||
foo
|
||||
|
||||
* one
|
||||
* two
|
||||
1. two
|
||||
|
||||
foo
|
||||
|
||||
* one
|
||||
1. two
|
||||
|
||||
foo
|
||||
|
||||
* uli one
|
||||
* uli two
|
||||
|
||||
foo
|
||||
|
||||
* uli one
|
||||
* uli two
|
||||
|
||||
foo
|
||||
|
||||
* uli one
|
||||
* uli two
|
||||
|
||||
foo
|
||||
|
||||
* uli one
|
||||
* uli two
|
||||
|
|
Loading…
Reference in New Issue
Block a user