feat(literalMidWordAsterisks): add option for mid word asterisks

Implements feature similar to ignoring midword underscores but with asterisks. The main use case is ignoring cursing.
This commit is contained in:
Miguel Laginha 2017-04-05 16:25:20 +01:00 committed by Estevão Soares dos Santos
parent f1eab2a7f2
commit 5bec8f9e9a
6 changed files with 114 additions and 10 deletions

View File

@ -254,6 +254,18 @@ var defaultOptions = showdown.getDefaultOptions();
<p>some text with__underscores__in middle</p> <p>some text with__underscores__in middle</p>
``` ```
* **literalMidWordAsterisks**: (boolean) [default false] Turning this on will stop showdown from interpreting asterisks in the middle of words as `<em>` and `<strong>` and instead treat them as literal asterisks.
Example:
```md
some text with**underscores**in middle
```
will be parsed as
```html
<p>some text with**underscores**in middle</p>
```
* **strikethrough**: (boolean) [default false] Enable support for strikethrough syntax. * **strikethrough**: (boolean) [default false] Enable support for strikethrough syntax.
`~~strikethrough~~` as `<del>strikethrough</del>` `~~strikethrough~~` as `<del>strikethrough</del>`

View File

@ -51,6 +51,11 @@ function getDefaultOpts (simple) {
describe: 'Parse midword underscores as literal underscores', describe: 'Parse midword underscores as literal underscores',
type: 'boolean' type: 'boolean'
}, },
literalMidWordAsterisks: {
defaultValue: false,
describe: 'Parse midword asterisks as literal asterisks',
type: 'boolean'
},
strikethrough: { strikethrough: {
defaultValue: false, defaultValue: false,
describe: 'Turn on/off strikethrough support', describe: 'Turn on/off strikethrough support',

View File

@ -39,16 +39,29 @@ showdown.subParser('italicsAndBold', function (text, options, globals) {
} }
// Now parse asterisks // Now parse asterisks
text = text.replace(/\*\*\*(\S[\s\S]*?)\*\*\*/g, function (wm, m) { if (options.literalMidWordAsterisks) {
return (/\S$/.test(m)) ? parseInside (m, '<strong><em>', '</em></strong>') : wm; text = text.trim().replace(/(?:^| +)\*{3}(\S[\s\S]*?)\*{3}(?: +|$)/g, function (wm, txt) {
}); return parseInside (txt, ' <strong><em>', '</em></strong> ');
text = text.replace(/\*\*(\S[\s\S]*?)\*\*/g, function (wm, m) { });
return (/\S$/.test(m)) ? parseInside (m, '<strong>', '</strong>') : wm; text = text.trim().replace(/(?:^| +)\*{2}(\S[\s\S]*?)\*{2}(?: +|$)/g, function (wm, txt) {
}); return parseInside (txt, ' <strong>', '</strong> ');
text = text.replace(/\*([^\s*][\s\S]*?)\*/g, function (wm, m) { });
// !/^\*[^*]/.test(m) - test if it doesn't start with ** (since it seems redundant, we removed it) text = text.trim().replace(/(?:^| +)\*{1}(\S[\s\S]*?)\*{1}(?: +|$)/g, function (wm, txt) {
return (/\S$/.test(m)) ? parseInside (m, '<em>', '</em>') : wm; return parseInside (txt, ' <em>', '</em>' + (wm.slice(-1) === ' ' ? ' ' : ''));
}); });
} else {
text = text.replace(/\*\*\*(\S[\s\S]*?)\*\*\*/g, function (wm, m) {
return (/\S$/.test(m)) ? parseInside (m, '<strong><em>', '</em></strong>') : wm;
});
text = text.replace(/\*\*(\S[\s\S]*?)\*\*/g, function (wm, m) {
return (/\S$/.test(m)) ? parseInside (m, '<strong>', '</strong>') : wm;
});
text = text.replace(/\*([^\s*][\s\S]*?)\*/g, function (wm, m) {
// !/^\*[^*]/.test(m) - test if it doesn't start with ** (since it seems redundant, we removed it)
return (/\S$/.test(m)) ? parseInside (m, '<em>', '</em>') : wm;
});
}
text = globals.converter._dispatch('italicsAndBold.after', text, options, globals); text = globals.converter._dispatch('italicsAndBold.after', text, options, globals);
return text; return text;

View File

@ -0,0 +1,24 @@
<p>this is a sentence*with*mid asterisks</p>
<p>this is a sentence**with**two mid asterisks</p>
<p>this is a sentence***with***three mid asterisks</p>
<p>this is a sentence with just*one asterisk</p>
<p>this is a sentence with just**one asterisk</p>
<p>this is a sentence with just***one asterisk</p>
<p>this is double**asterisk**mid word</p>
<p>this has just**one double asterisk</p>
<p>this has just***one triple asterisk</p>
<p>this <em>should be parsed</em> as emphasis</p>
<p>this <strong>should be parsed</strong> as bold</p>
<p>this <strong><em>should be parsed</em></strong> as bold and emphasis</p>
<p>emphasis at <em>end of sentence</em></p>
<p>bold at <strong>end of sentence</strong></p>
<p>bold and emphasis at <strong><em>end of sentence</em></strong></p>
<p><em>emphasis at</em> line start</p>
<p><strong>bold at</strong> line start</p>
<p><strong><em>bold and emphasis at</em></strong> line start</p>
<p>multi <em>line emphasis
yeah it is</em> yeah</p>
<p>multi <strong>line emphasis
yeah it is</strong> yeah</p>
<p>multi <strong><em>line emphasis
yeah it is</em></strong> yeah</p>

View File

@ -0,0 +1,46 @@
this is a sentence*with*mid asterisks
this is a sentence**with**two mid asterisks
this is a sentence***with***three mid asterisks
this is a sentence with just*one asterisk
this is a sentence with just**one asterisk
this is a sentence with just***one asterisk
this is double**asterisk**mid word
this has just**one double asterisk
this has just***one triple asterisk
this *should be parsed* as emphasis
this **should be parsed** as bold
this ***should be parsed*** as bold and emphasis
emphasis at *end of sentence*
bold at **end of sentence**
bold and emphasis at ***end of sentence***
*emphasis at* line start
**bold at** line start
***bold and emphasis at*** line start
multi *line emphasis
yeah it is* yeah
multi **line emphasis
yeah it is** yeah
multi ***line emphasis
yeah it is*** yeah

View File

@ -62,6 +62,8 @@ describe('makeHtml() features testsuite', function () {
converter = new showdown.Converter({encodeEmails: false, simplifiedAutoLink: true}); converter = new showdown.Converter({encodeEmails: false, simplifiedAutoLink: true});
} else if (testsuite[i].name === '#331.allow-escaping-of-tilde') { } else if (testsuite[i].name === '#331.allow-escaping-of-tilde') {
converter = new showdown.Converter({strikethrough: true}); converter = new showdown.Converter({strikethrough: true});
} else if (testsuite[i].name === 'enable-literalMidWordAsterisks') {
converter = new showdown.Converter({literalMidWordAsterisks: true});
} else if (testsuite[i].name === 'prefixHeaderId-simple') { } else if (testsuite[i].name === 'prefixHeaderId-simple') {
converter = new showdown.Converter({prefixHeaderId: true}); converter = new showdown.Converter({prefixHeaderId: true});
} else if (testsuite[i].name === 'prefixHeaderId-string') { } else if (testsuite[i].name === 'prefixHeaderId-string') {
@ -104,6 +106,8 @@ describe('makeHtml() features testsuite', function () {
converter = new showdown.Converter({simplifiedAutoLink: true, strikethrough: true}); converter = new showdown.Converter({simplifiedAutoLink: true, strikethrough: true});
} else if (suite[i].name === 'disallow-underscores') { } else if (suite[i].name === 'disallow-underscores') {
converter = new showdown.Converter({literalMidWordUnderscores: true, simplifiedAutoLink: true}); converter = new showdown.Converter({literalMidWordUnderscores: true, simplifiedAutoLink: true});
} else if (suite[i].name === 'disallow-asterisks') {
converter = new showdown.Converter({literalMidWordAsterisks: true, simplifiedAutoLink: true});
} else { } else {
converter = new showdown.Converter({simplifiedAutoLink: true}); converter = new showdown.Converter({simplifiedAutoLink: true});
} }