Merge branch 'develop'

This commit is contained in:
Estevao Soares dos Santos 2017-08-23 22:38:36 +01:00
commit cb2ef8a93c
23 changed files with 281 additions and 47 deletions

View File

@ -10,7 +10,8 @@
------
Showdown is a Javascript Markdown to HTML converter, based on the original works by John Gruber. Showdown can be used client side (in the browser) or server side (with NodeJs).
Showdown is a Javascript Markdown to HTML converter, based on the original works by John Gruber.
Showdown can be used client side (in the browser) or server side (with NodeJs).
## Live DEMO
@ -28,7 +29,8 @@ Check a live Demo here http://showdownjs.github.io/demo/
## Donate [![Donate](https://img.shields.io/badge/Donate-PayPal-green.svg)](https://www.paypal.me/tiviesantos)
We're currently looking to improve showdown with automated tests in all browsers and a proper domain and webpage. [If you like our work, please donate!!](https://www.paypal.me/tiviesantos) Your contribution will be greatly appreciated.
We're currently looking to improve showdown with automated tests in all browsers and a proper domain and webpage.
[If you like our work, please donate!!](https://www.paypal.me/tiviesantos) Your contribution will be greatly appreciated.
## Installation
@ -75,7 +77,8 @@ Showdown has been tested successfully with:
* Netscape 8.1.2
* Konqueror 3.5.4
In theory, Showdown will work in any browser that supports ECMA 262 3rd Edition (JavaScript 1.5). The converter itself might even work in things that aren't web browsers, like Acrobat. No promises.
In theory, Showdown will work in any browser that supports ECMA 262 3rd Edition (JavaScript 1.5).
The converter itself might even work in things that aren't web browsers, like Acrobat. No promises.
## Node compatibility
@ -196,17 +199,27 @@ var defaultOptions = showdown.getDefaultOptions();
<code><pre>var foo = 'bar';</pre></code>
```
* **noHeaderId**: (boolean) [default false] Disable the automatic generation of header ids. Setting to true overrides **prefixHeaderId**
* **noHeaderId**: (boolean) [default false] Disable the automatic generation of header ids.
Setting to true overrides **prefixHeaderId**
* **customizedHeaderId**: (boolean) [default false] Use text in curly braces as header id. (since v1.7.0)
* **customizedHeaderId**: (boolean) [default false] Use text in curly braces as header id. **(since v1.7.0)**
Example:
```
## Sample header {real-id} will use real-id as id
```
* **ghCompatibleHeaderId**: (boolean) [default false] Generate header ids compatible with github style (spaces are replaced with dashes and a bunch of non alphanumeric chars are removed) (since v1.5.5)
* **ghCompatibleHeaderId**: (boolean) [default false] Generate header ids compatible with github style
(spaces are replaced with dashes and a bunch of non alphanumeric chars are removed) **(since v1.5.5)**
* **prefixHeaderId**: (string/boolean) [default false] Add a prefix to the generated header ids. Passing a string will prefix that string to the header id. Setting to `true` will add a generic 'section' prefix.
* **prefixHeaderId**: (string/boolean) [default false] Add a prefix to the generated header ids.
Passing a string will prefix that string to the header id. Setting to `true` will add a generic 'section' prefix.
* **rawPrefixHeaderId**: (boolean) [default false] Setting this option to true will prevent showdown from modifying the prefix.
This might result in malformed IDs (if, for instance, the " char is used in the prefix).
Has no effect if prefixHeaderId is set to false. **(since v 1.7.3)**
* **rawHeaderId**: (boolean) [default false] Remove only spaces, ' and " from generated header ids (including prefixes),
replacing them with dashes (-). WARNING: This might result in malformed ids **(since v1.7.3)**
* **parseImgDimensions**: (boolean) [default false] Enable support for setting image dimensions from within markdown syntax.
Examples:
@ -227,7 +240,8 @@ var defaultOptions = showdown.getDefaultOptions();
<h3>foo</h3>
```
* **simplifiedAutoLink**: (boolean) [default false] Turning this option on will enable automatic linking to urls. This means that
* **simplifiedAutoLink**: (boolean) [default false] Turning this option on will enable automatic linking to urls.
This means that:
```md
some text www.google.com
@ -248,7 +262,8 @@ var defaultOptions = showdown.getDefaultOptions();
<p>check this link <a href="www.google.com">www.google.com</a>!</p>
```
* **literalMidWordUnderscores**: (boolean) [default false] Turning this on will stop showdown from interpreting underscores in the middle of words as `<em>` and `<strong>` and instead treat them as literal underscores.
* **literalMidWordUnderscores**: (boolean) [default false] Turning this on will stop showdown from interpreting
underscores in the middle of words as `<em>` and `<strong>` and instead treat them as literal underscores.
Example:
@ -260,7 +275,8 @@ var defaultOptions = showdown.getDefaultOptions();
<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.
* **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:
@ -298,12 +314,15 @@ var defaultOptions = showdown.getDefaultOptions();
```
* **smoothLivePreview**: (boolean) [default false] Prevents weird effects in live previews due to incomplete input
* **smartIndentationFix**: (boolean) [default false] Tries to smartly fix indentation problems related to es6 template strings in the midst of indented code.
* **smartIndentationFix**: (boolean) [default false] Tries to smartly fix indentation problems related to es6 template
strings in the midst of indented code.
* **disableForced4SpacesIndentedSublists**: (boolean) [default false] Disables the requirement of indenting sublists by 4 spaces for them to be nested,
effectively reverting to the old behavior where 2 or 3 spaces were enough. (since v1.5.0)
* **disableForced4SpacesIndentedSublists**: (boolean) [default false] Disables the requirement of indenting sublists
by 4 spaces for them to be nested, effectively reverting to the old behavior where 2 or 3 spaces were enough.
**(since v1.5.0)**
* **simpleLineBreaks**: (boolean) [default false] Parses line breaks as <br> like GitHub does, without needing 2 spaces at the end of the line (since v1.5.1)
* **simpleLineBreaks**: (boolean) [default false] Parses line breaks as <br> like GitHub does, without
needing 2 spaces at the end of the line **(since v1.5.1)**
```md
a line
@ -317,22 +336,24 @@ var defaultOptions = showdown.getDefaultOptions();
wrapped in two</p>
```
* **requireSpaceBeforeHeadingText**: (boolean) [default false] Makes adding a space between `#` and the header text mandatory (since v1.5.3)
* **requireSpaceBeforeHeadingText**: (boolean) [default false] Makes adding a space between `#` and the header text mandatory **(since v1.5.3)**
* **ghMentions**: (boolean) [default false] Enables github @mentions, which link to the username mentioned (since v1.6.0)
* **ghMentions**: (boolean) [default false] Enables github @mentions, which link to the username mentioned **(since v1.6.0)**
* **ghMentionsLink**: (string) [default `https://github.com/{u}`] Changes the link generated by @mentions. Showdown will replace `{u}` with the username. Only applies if ghMentions option is enabled.
* **ghMentionsLink**: (string) [default `https://github.com/{u}`] Changes the link generated by @mentions.
Showdown will replace `{u}` with the username. Only applies if ghMentions option is enabled.
Example: `@tivie` with ghMentionsOption set to `//mysite.com/{u}/profile` will result in `<a href="//mysite.com/tivie/profile">@tivie</a>`
* **encodeEmails**: (boolean) [default true] Enables e-mail addresses encoding through the use of Character Entities, transforming ASCII e-mail addresses into its equivalent decimal entities. (since v1.6.1)
NOTE: Prior to version 1.6.1, emails would always be obfuscated through dec and hex encoding.
* **openLinksInNewWindow**: (boolean) [default false] Open all links in new windows (by adding the attribute `target="_blank"` to `<a>` tags) (since v1.7.0)
* **openLinksInNewWindow**: (boolean) [default false] Open all links in new windows
(by adding the attribute `target="_blank"` to `<a>` tags) **(since v1.7.0)**
* **backslashEscapesHTMLTags**: (boolean) [default false] Support for HTML Tag escaping. ex: `\<div>foo\</div>` (since v1.7.2)
* **backslashEscapesHTMLTags**: (boolean) [default false] Support for HTML Tag escaping. ex: `\<div>foo\</div>` **(since v1.7.2)**
**NOTE**: Please note that until version 1.6.0, all of these options are ***DISABLED*** by default in the cli tool.
**NOTE**: Please note that until **version 1.6.0**, all of these options are ***DISABLED*** by default in the cli tool.
## Flavors
@ -405,7 +426,8 @@ var showdown = require('showdown'),
## Tests
A suite of tests is available which require node.js. Once node is installed, run the following command from the project root to install the dependencies:
A suite of tests is available which require node.js. Once node is installed, run the following command from
the project root to install the dependencies:
npm install
@ -413,7 +435,8 @@ Once installed the tests can be run from the project root using:
npm test
New test cases can easily be added. Create a markdown file (ending in `.md`) which contains the markdown to test. Create a `.html` file of the exact same name. It will automatically be tested when the tests are executed with `mocha`.
New test cases can easily be added. Create a markdown file (ending in `.md`) which contains the markdown to test.
Create a `.html` file of the exact same name. It will automatically be tested when the tests are executed with `mocha`.
## Contributing

BIN
dist/showdown.js vendored

Binary file not shown.

BIN
dist/showdown.js.map vendored

Binary file not shown.

BIN
dist/showdown.min.js vendored

Binary file not shown.

Binary file not shown.

View File

@ -18,14 +18,24 @@ function getDefaultOpts (simple) {
},
prefixHeaderId: {
defaultValue: false,
describe: 'Specify a prefix to generated header ids',
describe: 'Add a prefix to the generated header ids. Passing a string will prefix that string to the header id. Setting to true will add a generic \'section-\' prefix',
type: 'string'
},
rawPrefixHeaderId: {
defaultValue: false,
describe: 'Setting this option to true will prevent showdown from modifying the prefix. This might result in malformed IDs (if, for instance, the " char is used in the prefix)',
type: 'boolean'
},
ghCompatibleHeaderId: {
defaultValue: false,
describe: 'Generate header ids compatible with github style (spaces are replaced with dashes, a bunch of non alphanumeric chars are removed)',
type: 'boolean'
},
rawHeaderId: {
defaultValue: false,
describe: 'Remove only spaces, \' and " from generated header ids (including prefixes), replacing them with dashes (-). WARNING: This might result in malformed ids',
type: 'boolean'
},
headerLevelStart: {
defaultValue: false,
describe: 'The header blocks level start',

View File

@ -23,7 +23,8 @@ var showdown = {},
simpleLineBreaks: true,
requireSpaceBeforeHeadingText: true,
ghCompatibleHeaderId: true,
ghMentions: true
ghMentions: true,
backslashEscapesHTMLTags: true
},
original: {
noHeaderId: true,

View File

@ -4,7 +4,6 @@ showdown.subParser('headers', function (text, options, globals) {
text = globals.converter._dispatch('headers.before', text, options, globals);
var headerLevelStart = (isNaN(parseInt(options.headerLevelStart))) ? 1 : parseInt(options.headerLevelStart),
ghHeaderId = options.ghCompatibleHeaderId,
// Set text-style headers:
// Header 1
@ -57,7 +56,8 @@ showdown.subParser('headers', function (text, options, globals) {
});
function headerId (m) {
var title;
var title,
prefix;
// It is separate from other options to allow combining prefix and customized
if (options.customizedHeaderId) {
@ -67,16 +67,22 @@ showdown.subParser('headers', function (text, options, globals) {
}
}
title = m;
// Prefix id to prevent causing inadvertent pre-existing style matches.
if (showdown.helper.isString(options.prefixHeaderId)) {
title = options.prefixHeaderId + m;
prefix = options.prefixHeaderId;
} else if (options.prefixHeaderId === true) {
title = 'section ' + m;
prefix = 'section-';
} else {
title = m;
prefix = '';
}
if (ghHeaderId) {
if (!options.rawPrefixHeaderId) {
title = prefix + title;
}
if (options.ghCompatibleHeaderId) {
title = title
.replace(/ /g, '-')
// replace previously escaped chars (&, ¨ and $)
@ -87,12 +93,26 @@ showdown.subParser('headers', function (text, options, globals) {
// borrowed from github's redcarpet (some they should produce similar results)
.replace(/[&+$,\/:;=?@"#{}|^¨~\[\]`\\*)(%.!'<>]/g, '')
.toLowerCase();
} else if (options.rawHeaderId) {
title = title
.replace(/ /g, '-')
// replace previously escaped chars (&, ¨ and $)
.replace(/&amp;/g, '&')
.replace(/¨T/g, '¨')
.replace(/¨D/g, '$')
// replace " and '
.replace(/["']/g, '-')
.toLowerCase();
} else {
title = title
.replace(/[^\w]/g, '')
.toLowerCase();
}
if (options.rawPrefixHeaderId) {
title = prefix + title;
}
if (globals.hashLinkCounts[title]) {
title = title + '-' + (globals.hashLinkCounts[title]++);
} else {

View File

@ -40,14 +40,14 @@ showdown.subParser('italicsAndBold', function (text, options, globals) {
// Now parse asterisks
if (options.literalMidWordAsterisks) {
text = text.trim().replace(/(?:^| +)\*{3}(\S[\s\S]*?)\*{3}(?: +|$)/g, function (wm, txt) {
return parseInside (txt, ' <strong><em>', '</em></strong> ');
text = text.trim().replace(/(^| )\*{3}(\S[\s\S]*?)\*{3}([ ,;!?.]|$)/g, function (wm, lead, txt, trail) {
return parseInside (txt, lead + '<strong><em>', '</em></strong>' + trail);
});
text = text.trim().replace(/(?:^| +)\*{2}(\S[\s\S]*?)\*{2}(?: +|$)/g, function (wm, txt) {
return parseInside (txt, ' <strong>', '</strong> ');
text = text.trim().replace(/(^| )\*{2}(\S[\s\S]*?)\*{2}([ ,;!?.]|$)/g, function (wm, lead, txt, trail) {
return parseInside (txt, lead + '<strong>', '</strong>' + trail);
});
text = text.trim().replace(/(?:^| +)\*{1}(\S[\s\S]*?)\*{1}(?: +|$)/g, function (wm, txt) {
return parseInside (txt, ' <em>', '</em>' + (wm.slice(-1) === ' ' ? ' ' : ''));
text = text.trim().replace(/(^| )\*(\S[\s\S]*?)\*([ ,;!?.]|$)/g, function (wm, lead, txt, trail) {
return parseInside (txt, lead + '<em>', '</em>' + trail);
});
} else {
text = text.replace(/\*\*\*(\S[\s\S]*?)\*\*\*/g, function (wm, m) {

View File

@ -5,7 +5,9 @@ showdown.subParser('tables', function (text, options, globals) {
return text;
}
var tableRgx = /^ {0,3}\|?.+\|.+\n[ \t]{0,3}\|?[ \t]*:?[ \t]*(?:-|=){2,}[ \t]*:?[ \t]*\|[ \t]*:?[ \t]*(?:-|=){2,}[\s\S]+?(?:\n\n|¨0)/gm;
var tableRgx = /^ {0,3}\|?.+\|.+\n {0,3}\|?[ \t]*:?[ \t]*(?:[-=]){2,}[ \t]*:?[ \t]*\|[ \t]*:?[ \t]*(?:[-=]){2,}[\s\S]+?(?:\n\n|¨0)/gm,
//singeColTblRgx = /^ {0,3}\|.+\|\n {0,3}\|[ \t]*:?[ \t]*(?:[-=]){2,}[ \t]*:?[ \t]*\|[ \t]*\n(?: {0,3}\|.+\|\n)+(?:\n\n|¨0)/gm;
singeColTblRgx = /^ {0,3}\|.+\|\n {0,3}\|[ \t]*:?[ \t]*(?:[-=]){2,}[ \t]*:?[ \t]*\|\n( {0,3}\|.+\|\n)*(?:\n|¨0)/gm;
function parseStyles (sLine) {
if (/^:[ \t]*--*$/.test(sLine)) {
@ -56,14 +58,7 @@ showdown.subParser('tables', function (text, options, globals) {
return tb;
}
text = globals.converter._dispatch('tables.before', text, options, globals);
// find escaped pipe characters
text = text.replace(/\\(\|)/g, showdown.helper.escapeCharactersCallback);
// parse tables
text = text.replace(tableRgx, function (rawTable) {
function parseTable (rawTable) {
var i, tableLines = rawTable.split('\n');
// strip wrong first and last column if wrapped tables are used
@ -126,7 +121,18 @@ showdown.subParser('tables', function (text, options, globals) {
}
return buildTable(headers, cells);
});
}
text = globals.converter._dispatch('tables.before', text, options, globals);
// find escaped pipe characters
text = text.replace(/\\(\|)/g, showdown.helper.escapeCharactersCallback);
// parse multi column tables
text = text.replace(tableRgx, parseTable);
// parse one column tables
text = text.replace(singeColTblRgx, parseTable);
text = globals.converter._dispatch('tables.after', text, options, globals);

View File

@ -0,0 +1 @@
<p>strippers, <strong>hitler</strong>, and stalin</p>

View File

@ -0,0 +1 @@
strippers, **hitler**, and stalin

View File

@ -0,0 +1,9 @@
<p>some <em>foo</em> yeah</p>
<p>some <strong>foo</strong> yeah</p>
<p>some <strong><em>foo</em></strong> yeah</p>
<p>some word_foo_yeah</p>
<p>some word__foo__yeah</p>
<p>some word___foo___yeah</p>
<p>strippers, <em>hitler</em>, and stalin</p>
<p>strippers, <strong>hitler</strong>, and stalin</p>
<p>strippers, <strong><em>hitler</em></strong>, and stalin</p>

View File

@ -0,0 +1,17 @@
some _foo_ yeah
some __foo__ yeah
some ___foo___ yeah
some word_foo_yeah
some word__foo__yeah
some word___foo___yeah
strippers, _hitler_, and stalin
strippers, __hitler__, and stalin
strippers, ___hitler___, and stalin

View File

@ -0,0 +1 @@
<h1 id="123-my#very/-strange-\header*`^ªº-_.,-yeah">123 My#very/ strange \header*`^ªº-_., yeah</h1>

View File

@ -0,0 +1 @@
# 123 My#very/ strange \header*`^ªº-_., yeah

View File

@ -0,0 +1,2 @@
<h1 id="/prefix/some-header">some header</h1>
<h1 id="/prefix/another-!-#$%&/()=?»@£§{[]}«--header">another !"#$%&amp;/()=?»@£§{[]}«' header</h1>

View File

@ -0,0 +1,3 @@
# some header
# another !"#$%&/()=?»@£§{[]}«' header

View File

@ -0,0 +1 @@
<h1 id="/prefix/someheaderfoo">some header &amp;/) foo</h1>

View File

@ -0,0 +1 @@
# some header &/) foo

View File

@ -0,0 +1,81 @@
<table>
<thead>
<tr>
<th>some header</th>
</tr>
</thead>
<tbody>
<tr>
<td>some content</td>
</tr>
</tbody>
</table>
<table>
<thead>
<tr>
<th>some header</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
<table>
<thead>
<tr>
<th>some header</th>
</tr>
</thead>
<tbody>
<tr>
<td>some content</td>
</tr>
<tr>
<td>some content</td>
</tr>
<tr>
<td>some content</td>
</tr>
<tr>
<td>some content</td>
</tr>
<tr>
<td>some content</td>
</tr>
</tbody>
</table>
<table>
<thead>
<tr>
<th style="text-align:left;">some header</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left;">some content</td>
</tr>
</tbody>
</table>
<table>
<thead>
<tr>
<th style="text-align:right;">some header</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:right;">some content</td>
</tr>
</tbody>
</table>
<table>
<thead>
<tr>
<th style="text-align:center;">some header</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:center;">some content</td>
</tr>
</tbody>
</table>

View File

@ -0,0 +1,26 @@
|some header |
|------------|
|some content|
|some header |
|------------|
|some header |
|------------|
|some content|
|some content|
|some content|
|some content|
|some content|
|some header |
|:-----------|
|some content|
|some header |
|-----------:|
|some content|
|some header |
|:----------:|
|some content|

View File

@ -8,7 +8,9 @@ var bootstrap = require('../bootstrap.js'),
tableSuite = bootstrap.getTestSuite('test/features/tables/'),
simplifiedAutoLinkSuite = bootstrap.getTestSuite('test/features/simplifiedAutoLink/'),
openLinksInNewWindowSuite = bootstrap.getTestSuite('test/features/openLinksInNewWindow/'),
disableForced4SpacesIndentedSublistsSuite = bootstrap.getTestSuite('test/features/disableForced4SpacesIndentedSublists/');
disableForced4SpacesIndentedSublistsSuite = bootstrap.getTestSuite('test/features/disableForced4SpacesIndentedSublists/'),
rawHeaderIdSuite = bootstrap.getTestSuite('test/features/rawHeaderId/'),
rawPrefixHeaderIdSuite = bootstrap.getTestSuite('test/features/rawPrefixHeaderId/');
describe('makeHtml() features testsuite', function () {
'use strict';
@ -22,6 +24,8 @@ describe('makeHtml() features testsuite', function () {
converter = new showdown.Converter({headerLevelStart: 3});
} else if (testsuite[i].name === '#164.1.simple-autolink' || testsuite[i].name === '#204.certain-links-with-at-and-dot-break-url') {
converter = new showdown.Converter({simplifiedAutoLink: true});
} else if (testsuite[i].name === 'literalMidWordUnderscores') {
converter = new showdown.Converter({literalMidWordUnderscores: true});
} else if (testsuite[i].name === '#164.2.disallow-underscore-emphasis-mid-word') {
converter = new showdown.Converter({literalMidWordUnderscores: true});
} else if (testsuite[i].name === '#164.3.strikethrough' || testsuite[i].name === '#214.escaped-markdown-chars-break-strikethrough') {
@ -84,6 +88,8 @@ describe('makeHtml() features testsuite', function () {
converter = new showdown.Converter({backslashEscapesHTMLTags: true});
} else if (testsuite[i].name === '#379.openLinksInNewWindow-breaks-em-markdup') {
converter = new showdown.Converter({openLinksInNewWindow: true});
} else if (testsuite[i].name === '#398.literalMidWordAsterisks-treats-non-word-characters-as-characters') {
converter = new showdown.Converter({literalMidWordAsterisks: true});
} else {
converter = new showdown.Converter();
}
@ -148,4 +154,28 @@ describe('makeHtml() features testsuite', function () {
it(suite[i].name.replace(/-/g, ' '), assertion(suite[i], converter));
}
});
// test rawHeaderId support
describe('rawHeaderId support', function () {
var converter,
suite = rawHeaderIdSuite;
for (var i = 0; i < suite.length; ++i) {
if (suite[i].name === 'with-prefixHeaderId') {
converter = new showdown.Converter({rawHeaderId: true, prefixHeaderId: '/prefix/'});
} else {
converter = new showdown.Converter({rawHeaderId: true});
}
it(suite[i].name.replace(/-/g, ' '), assertion(suite[i], converter));
}
});
// test rawPrefixHeaderId support
describe('rawPrefixHeaderId support', function () {
var converter,
suite = rawPrefixHeaderIdSuite;
for (var i = 0; i < suite.length; ++i) {
converter = new showdown.Converter({rawPrefixHeaderId: true, prefixHeaderId: '/prefix/'});
it(suite[i].name.replace(/-/g, ' '), assertion(suite[i], converter));
}
});
});