mirror of
https://github.com/showdownjs/showdown.git
synced 2024-03-22 13:30:55 +08:00
Merge branch 'develop' into 922-commonmark-compliance
# Conflicts: # src/subParsers/makehtml/heading.js # test/functional/makehtml/cases/features/#320.github-compatible-generated-header-id.html # test/functional/makehtml/cases/features/#320.github-compatible-generated-header-id.md
This commit is contained in:
commit
150c4c36cb
53
CREDITS.md
53
CREDITS.md
@ -1,53 +0,0 @@
|
|||||||
Credits
|
|
||||||
=======
|
|
||||||
|
|
||||||
- Showdown v2
|
|
||||||
* [Estevão Santos](https://github.com/tivie)
|
|
||||||
* [SyntaxRules](https://github.com/SyntaxRules)
|
|
||||||
|
|
||||||
- Showdown v1
|
|
||||||
* [Estevão Santos](https://github.com/tivie)
|
|
||||||
* [Pascal Deschênes](https://github.com/pdeschen)
|
|
||||||
|
|
||||||
- Showdown v0
|
|
||||||
* [Corey Innis](http://github.com/coreyti):<br/>
|
|
||||||
Original GitHub project maintainer
|
|
||||||
* [Remy Sharp](https://github.com/remy/):<br/>
|
|
||||||
CommonJS-compatibility and more
|
|
||||||
* [Konstantin Käfer](https://github.com/kkaefer/):<br/>
|
|
||||||
CommonJS packaging
|
|
||||||
* [Roger Braun](https://github.com/rogerbraun):<br/>
|
|
||||||
Github-style code blocks
|
|
||||||
* [Dominic Tarr](https://github.com/dominictarr):<br/>
|
|
||||||
Documentation
|
|
||||||
* [Cat Chen](https://github.com/CatChen):<br/>
|
|
||||||
Export fix
|
|
||||||
* [Titus Stone](https://github.com/tstone):<br/>
|
|
||||||
Mocha tests, extension mechanism, and bug fixes
|
|
||||||
* [Rob Sutherland](https://github.com/roberocity):<br/>
|
|
||||||
The idea that lead to extensions
|
|
||||||
* [Pavel Lang](https://github.com/langpavel):<br/>
|
|
||||||
Code cleanup
|
|
||||||
* [Ben Combee](https://github.com/unwiredben):<br/>
|
|
||||||
Regex optimization
|
|
||||||
* [Adam Backstrom](https://github.com/abackstrom):<br/>
|
|
||||||
WebKit bugfix
|
|
||||||
* [Pascal Deschênes](https://github.com/pdeschen):<br/>
|
|
||||||
Grunt support, extension fixes + additions, packaging improvements, documentation
|
|
||||||
* [Estevão Santos](https://github.com/tivie)<br/>
|
|
||||||
Bug fixing and late maintainer
|
|
||||||
* [Hannah Wolfe](https://github.com/ErisDS)<br/>
|
|
||||||
Bug fixes
|
|
||||||
* [Alexandre Courtiol](https://github.com/acourtiol)<br/>
|
|
||||||
Bug fixes and build optimization
|
|
||||||
* [Karthik Balakrishnan](https://github.com/torcellite)<br/>
|
|
||||||
Support for table alignment
|
|
||||||
* [rheber](https://github.com/rheber)<br/>
|
|
||||||
Cli
|
|
||||||
|
|
||||||
|
|
||||||
- Original Project
|
|
||||||
* [John Gruber](http://daringfireball.net/projects/markdown/)<br/>
|
|
||||||
Author of Markdown
|
|
||||||
* [John Fraser](http://attacklab.net/)<br/>
|
|
||||||
Author of Showdown
|
|
546
README.md
546
README.md
@ -2,541 +2,77 @@
|
|||||||
|
|
||||||

|

|
||||||

|

|
||||||
[](https://automate.browserstack.com/public-build/VTIvTDNqWVdaTHljbS9RNmYrcTBiL0Uxc3dkRDhaN1dPaXpPb2VOc1B2VT0tLU1Ib09kVjVzMjhFcHExbWFSWlJEV3c9PQ==--1fb92e1730e4a00630d17d533822de6403ca65ec)
|
|
||||||
[](http://badge.fury.io/js/showdown)
|
[](http://badge.fury.io/js/showdown)
|
||||||
[](http://badge.fury.io/bo/showdown)
|
[](http://badge.fury.io/bo/showdown)
|
||||||
|
[](https://gitter.im/showdownjs/showdown?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||||
[](https://www.paypal.me/tiviesantos)
|
[](https://www.paypal.me/tiviesantos)
|
||||||
|
|
||||||
------
|
|
||||||
|
|
||||||
Showdown is a JavaScript Markdown to HTML converter, based on the original works by John Gruber.
|
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 Node.js).
|
|
||||||
|
|
||||||
## Live DEMO
|
Showdown can be used on the client-side (in the browser) or server-side (with Node.js).
|
||||||
|
|
||||||
Check out a live demo here: http://demo.showdownjs.com/
|
----
|
||||||
|
|
||||||
As you know, ShowdownJS is a free library and it will remain free forever. However, maintaining and improving the library costs time and money.
|
## Live demo
|
||||||
|
|
||||||
If you like our work and find our library useful, please donate through [PayPal](https://www.paypal.me/tiviesantos)! Your contribution will be greatly appreciated and help me continue to develop this awesome library.
|
<http://demo.showdownjs.com/>
|
||||||
|
|
||||||
## License
|
|
||||||
|
|
||||||
ShowdownJS v 2.0 is released under the MIT license.
|
|
||||||
Previous versions are released under BSD.
|
|
||||||
|
|
||||||
## Who uses Showdown (or a fork)
|
## Who uses Showdown (or a fork)
|
||||||
|
|
||||||
- [GoogleCloudPlatform](https://github.com/GoogleCloudPlatform)
|
* [Antmarky](https://github.com/bandantonio/antmarky)
|
||||||
- [Meteor](https://www.meteor.com/)
|
* [GoogleCloudPlatform](https://github.com/GoogleCloudPlatform)
|
||||||
- [Stackexchange](http://stackexchange.com/) - forked as [PageDown](https://code.google.com/p/pagedown/)
|
* [Meteor](https://www.meteor.com/)
|
||||||
- [docular](https://github.com/Vertafore/docular)
|
* [StackExchange](http://stackexchange.com/) - forked as [PageDown](https://code.google.com/p/pagedown/)
|
||||||
- [md-page](https://github.com/oscarmorrison/md-page)
|
* [docular](https://github.com/Vertafore/docular)
|
||||||
- [QCObjects](https://qcobjects.dev)
|
* [md-page](https://github.com/oscarmorrison/md-page)
|
||||||
- [and some others...](https://www.npmjs.com/browse/depended/showdown)
|
* [QCObjects](https://qcobjects.dev)
|
||||||
|
* [and some others](https://www.npmjs.com/browse/depended/showdown)
|
||||||
|
|
||||||
## Installation
|
## Quickstart
|
||||||
|
|
||||||
### Download tarball
|
Check our documentation for the [quickstart guide][quickstart]
|
||||||
|
and possible [installation methods][installation-methods].
|
||||||
|
|
||||||
You can download the latest release tarball directly from [releases][releases].
|
## Showdown features
|
||||||
|
|
||||||
### Bower
|
### Platform-agnostic
|
||||||
|
|
||||||
bower install showdown
|
Showdown can easily be used on server-side and client-side.
|
||||||
|
|
||||||
### npm (server-side)
|
### Two-way conversion
|
||||||
|
|
||||||
npm install showdown
|
Showdown not only helps you to convert your Markdown documents into HTML but also can bring them back to Markdown from HTML.
|
||||||
|
|
||||||
### NuGet package
|
### Extensions
|
||||||
|
|
||||||
PM> Install-Package showdownjs
|
Expand Showdown's functionality using a powerful [extension system][extensions]. Extensions can also be used on server-side and client-side.
|
||||||
|
|
||||||
The NuGet Packages can be found [here](https://www.nuget.org/packages/showdownjs/).
|
### CLI
|
||||||
|
|
||||||
### CDN
|
Showdown comes bundled with a Command-line interface (CLI) tool that allows you to run Showdown converter from the command line.
|
||||||
|
|
||||||
You can also use one of several CDNs available:
|
Check the [CLI][cli] section in the documentation for more information.
|
||||||
|
|
||||||
* jsDelivr
|
## Contribution guide
|
||||||
|
|
||||||
https://cdn.jsdelivr.net/npm/showdown@<version tag>/dist/showdown.min.js
|
If you want to contribute to the project, that's awesome! Please check our [guide][contribution-guide].
|
||||||
|
|
||||||
* cdnjs
|
|
||||||
|
|
||||||
https://cdnjs.cloudflare.com/ajax/libs/showdown/<version tag>/showdown.min.js
|
|
||||||
|
|
||||||
* unpkg
|
|
||||||
|
|
||||||
https://unpkg.com/showdown/dist/showdown.min.js
|
|
||||||
|
|
||||||
*Note*: replace `<version tag>` with an actual full length version you're interested in e.g. `1.9.0`
|
|
||||||
## Browser Compatibility
|
|
||||||
|
|
||||||
Showdown has been tested successfully with:
|
|
||||||
|
|
||||||
* Firefox 1.5 and 2.0
|
|
||||||
* Chrome 12.0
|
|
||||||
* Internet Explorer 6 and 7
|
|
||||||
* Safari 2.0.4
|
|
||||||
* Opera 8.54 and 9.10
|
|
||||||
* 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.
|
|
||||||
|
|
||||||
|
|
||||||
## Node compatibility
|
|
||||||
|
|
||||||
Showdown is intended to work on any supported Node.js version (see the [Node.js releases schedule](https://nodejs.org/en/about/releases/). The code may work with previous versions of Node.js, but no accomidations are made to ensure it does.
|
|
||||||
|
|
||||||
|
|
||||||
## Legacy version
|
|
||||||
|
|
||||||
If you're looking for showdown v<1.0.0, you can find it in the [**legacy branch**][legacy-branch].
|
|
||||||
|
|
||||||
## Changelog
|
|
||||||
|
|
||||||
You can check the full [changelog][changelog]
|
|
||||||
|
|
||||||
## Extended documentation
|
|
||||||
Check our [wiki pages][wiki] for examples and a more in-depth documentation.
|
|
||||||
|
|
||||||
|
|
||||||
## Quick Example
|
|
||||||
|
|
||||||
### Node
|
|
||||||
|
|
||||||
```js
|
|
||||||
var showdown = require('showdown'),
|
|
||||||
converter = new showdown.Converter(),
|
|
||||||
text = '# hello, markdown!',
|
|
||||||
html = converter.makeHtml(text);
|
|
||||||
```
|
|
||||||
|
|
||||||
### Browser
|
|
||||||
|
|
||||||
```js
|
|
||||||
var converter = new showdown.Converter(),
|
|
||||||
text = '# hello, markdown!',
|
|
||||||
html = converter.makeHtml(text);
|
|
||||||
```
|
|
||||||
|
|
||||||
### Output
|
|
||||||
|
|
||||||
Both examples should output...
|
|
||||||
|
|
||||||
```html
|
|
||||||
<h1 id="hellomarkdown">hello, markdown!</h1>
|
|
||||||
```
|
|
||||||
|
|
||||||
## Options
|
|
||||||
|
|
||||||
You can change some of showdown's default behavior through options.
|
|
||||||
|
|
||||||
### Setting options
|
|
||||||
|
|
||||||
Options can be set:
|
|
||||||
|
|
||||||
#### Globally
|
|
||||||
|
|
||||||
Setting a "global" option affects all instances of showdown
|
|
||||||
|
|
||||||
```js
|
|
||||||
showdown.setOption('optionKey', 'value');
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Locally
|
|
||||||
Setting a "local" option only affects the specified Converter object.
|
|
||||||
Local options can be set:
|
|
||||||
|
|
||||||
* **through the constructor**
|
|
||||||
```js
|
|
||||||
var converter = new showdown.Converter({optionKey: 'value'});
|
|
||||||
```
|
|
||||||
|
|
||||||
* **through the setOption() method**
|
|
||||||
```js
|
|
||||||
var converter = new showdown.Converter();
|
|
||||||
converter.setOption('optionKey', 'value');
|
|
||||||
```
|
|
||||||
|
|
||||||
### Getting an option
|
|
||||||
|
|
||||||
Showdown provides 2 methods (both local and global) to retrieve previous set options.
|
|
||||||
|
|
||||||
#### getOption()
|
|
||||||
|
|
||||||
```js
|
|
||||||
// Global
|
|
||||||
var myOption = showdown.getOption('optionKey');
|
|
||||||
|
|
||||||
//Local
|
|
||||||
var myOption = converter.getOption('optionKey');
|
|
||||||
```
|
|
||||||
|
|
||||||
#### getOptions()
|
|
||||||
|
|
||||||
```js
|
|
||||||
// Global
|
|
||||||
var showdownGlobalOptions = showdown.getOptions();
|
|
||||||
|
|
||||||
//Local
|
|
||||||
var thisConverterSpecificOptions = converter.getOptions();
|
|
||||||
```
|
|
||||||
|
|
||||||
### Retrieve the default options
|
|
||||||
|
|
||||||
You can get showdown's default options with:
|
|
||||||
```js
|
|
||||||
var defaultOptions = showdown.getDefaultOptions();
|
|
||||||
```
|
|
||||||
|
|
||||||
### Valid Options
|
|
||||||
|
|
||||||
* **omitExtraWLInCodeBlocks**: (boolean) [default false] Omit the trailing newline in a code block. Ex:
|
|
||||||
|
|
||||||
This:
|
|
||||||
```html
|
|
||||||
<code><pre>var foo = 'bar';
|
|
||||||
</pre></code>
|
|
||||||
```
|
|
||||||
Becomes this:
|
|
||||||
```html
|
|
||||||
<code><pre>var foo = 'bar';</pre></code>
|
|
||||||
```
|
|
||||||
|
|
||||||
* **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)**
|
|
||||||
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)**
|
|
||||||
|
|
||||||
* **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)**
|
|
||||||
|
|
||||||
* **headerLevelStart**: (integer) [default 1] Set the header starting level. For instance, setting this to 3 means that
|
|
||||||
|
|
||||||
```md
|
|
||||||
# foo
|
|
||||||
```
|
|
||||||
will be parsed as
|
|
||||||
|
|
||||||
```html
|
|
||||||
<h3>foo</h3>
|
|
||||||
```
|
|
||||||
|
|
||||||
* **parseImgDimensions**: (boolean) [default false] Enable support for setting image dimensions from within markdown syntax.
|
|
||||||
Examples:
|
|
||||||
```
|
|
||||||
 simple, assumes units are in px
|
|
||||||
 sets the height to "auto"
|
|
||||||
 Image with width of 80% and height of 5em
|
|
||||||
```
|
|
||||||
|
|
||||||
* **simplifiedAutoLink**: (boolean) [default false] Turning this option on will enable automatic linking to urls.
|
|
||||||
This means that:
|
|
||||||
|
|
||||||
```md
|
|
||||||
some text www.google.com
|
|
||||||
```
|
|
||||||
will be parsed as
|
|
||||||
```html
|
|
||||||
<p>some text <a href="www.google.com">www.google.com</a>
|
|
||||||
```
|
|
||||||
|
|
||||||
* ~~**excludeTrailingPunctuationFromURLs**: (boolean) [default false] This option excludes trailing punctuation from autolinking urls.
|
|
||||||
Punctuation excluded: `. ! ? ( )`. Only applies if **simplifiedAutoLink** option is set to `true`.~~
|
|
||||||
|
|
||||||
* **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:
|
|
||||||
|
|
||||||
```md
|
|
||||||
some text with__underscores__in middle
|
|
||||||
```
|
|
||||||
will be parsed as
|
|
||||||
```html
|
|
||||||
<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.~~
|
|
||||||
|
|
||||||
* **strikethrough**: (boolean) [default false] Enable support for strikethrough syntax.
|
|
||||||
`~~strikethrough~~` as `<del>strikethrough</del>`
|
|
||||||
|
|
||||||
* **tables**: (boolean) [default false] Enable support for tables syntax. Example:
|
|
||||||
|
|
||||||
```md
|
|
||||||
| h1 | h2 | h3 |
|
|
||||||
|:------|:-------:|--------:|
|
|
||||||
| 100 | [a][1] | ![b][2] |
|
|
||||||
| *foo* | **bar** | ~~baz~~ |
|
|
||||||
```
|
|
||||||
|
|
||||||
See the wiki for more info
|
|
||||||
|
|
||||||
* **tablesHeaderId**: (boolean) [default false] If enabled adds an id property to table headers tags.
|
|
||||||
|
|
||||||
* **ghCodeBlocks**: (boolean) [default true] Enable support for GFM code block style.
|
|
||||||
|
|
||||||
* **tasklists**: (boolean) [default false] Enable support for GFM tasklists. Example:
|
|
||||||
|
|
||||||
```md
|
|
||||||
- [x] This task is done
|
|
||||||
- [ ] This is still pending
|
|
||||||
```
|
|
||||||
* **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.
|
|
||||||
|
|
||||||
* **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>`, without
|
|
||||||
needing 2 spaces at the end of the line **(since v1.5.1)**
|
|
||||||
|
|
||||||
```md
|
|
||||||
a line
|
|
||||||
wrapped in two
|
|
||||||
```
|
|
||||||
|
|
||||||
turns into:
|
|
||||||
|
|
||||||
```html
|
|
||||||
<p>a line<br>
|
|
||||||
wrapped in two</p>
|
|
||||||
```
|
|
||||||
|
|
||||||
* **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)**
|
|
||||||
|
|
||||||
* **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] Enable 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)**
|
|
||||||
|
|
||||||
* **backslashEscapesHTMLTags**: (boolean) [default false] Support for HTML Tag escaping. ex: `\<div>foo\</div>` **(since v1.7.2)**
|
|
||||||
|
|
||||||
* **emoji**: (boolean) [default false] Enable emoji support. Ex: `this is a :smile: emoji`
|
|
||||||
For more info on available emojis, see https://github.com/showdownjs/showdown/wiki/Emojis **(since v.1.8.0)**
|
|
||||||
|
|
||||||
* **underline**: (boolean) [default false] ***EXPERIMENTAL FEATURE*** Enable support for underline.
|
|
||||||
Syntax is **double** or **triple** **underscores** ex: `__underlined word__`. With this option enabled, underscores are no longer parses into `<em>` and `<strong>`.
|
|
||||||
|
|
||||||
* **ellipsis**: (boolean) [default true] Replaces three dots with the ellipsis unicode character.
|
|
||||||
|
|
||||||
* **completeHTMLDocument**: (boolean) [default false] Outputs a complete html document,
|
|
||||||
including `<html>`, `<head>` and `<body>` tags' instead of an HTML fragment. (since v.1.8.5)
|
|
||||||
|
|
||||||
* **metadata**: (boolean) [default false] Enable support for document metadata (defined at the top of the document
|
|
||||||
between `«««` and `»»»` or between `---` and `---`). (since v.1.8.5)
|
|
||||||
|
|
||||||
```js
|
|
||||||
var conv = new showdown.Converter({metadata: true});
|
|
||||||
var html = conv.makeHtml(someMd);
|
|
||||||
var metadata = conv.getMetadata(); // returns an object with the document metadata
|
|
||||||
```
|
|
||||||
|
|
||||||
* **splitAdjacentBlockquotes**: (boolean) [default false] Split adjacent blockquote blocks.(since v.1.8.6)
|
|
||||||
|
|
||||||
* **moreStyling**: (boolean) [default false] Adds some useful classes for css styling. (since v2.0.1)
|
|
||||||
|
|
||||||
- Tasklists: Adds the class `task-list-item-complete` to completed tasks items in GFM tasklists.
|
|
||||||
|
|
||||||
**NOTE**: Please note that until **version 1.6.0**, all of these options are ***DISABLED*** by default in the cli tool.
|
|
||||||
|
|
||||||
|
|
||||||
## Flavors
|
|
||||||
|
|
||||||
You can also use flavors or presets to set the correct options automatically, so that showdown behaves like popular markdown flavors.
|
|
||||||
|
|
||||||
Currently, the following flavors are available:
|
|
||||||
|
|
||||||
* original - original markdown flavor as in [John Gruber's spec](https://daringfireball.net/projects/markdown/)
|
|
||||||
* vanilla - showdown base flavor (as from v1.3.1)
|
|
||||||
* github - GFM (GitHub Flavored Markdown)
|
|
||||||
|
|
||||||
|
|
||||||
### Global
|
|
||||||
```javascript
|
|
||||||
showdown.setFlavor('github');
|
|
||||||
```
|
|
||||||
|
|
||||||
### Instance
|
|
||||||
```javascript
|
|
||||||
converter.setFlavor('github');
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
## CLI Tool
|
|
||||||
|
|
||||||
Showdown also comes bundled with a Command Line Interface tool. You can check the [CLI wiki page][cli-wiki] for more info
|
|
||||||
|
|
||||||
## Integration with AngularJS
|
|
||||||
|
|
||||||
ShowdownJS project also provides seamlessly integration with AngularJS via a "plugin".
|
|
||||||
Please visit https://github.com/showdownjs/ngShowdown for more information.
|
|
||||||
|
|
||||||
## Integration with TypeScript
|
|
||||||
|
|
||||||
If you're using TypeScript you maybe want to use the types from [DefinitelyTyped][definitely-typed]
|
|
||||||
|
|
||||||
## Integration with SystemJS/JSPM
|
|
||||||
|
|
||||||
Integration with SystemJS can be obtained via the third party ["system-md" plugin](https://github.com/guybedford/system-md).
|
|
||||||
|
|
||||||
## Integration with VueJS
|
|
||||||
|
|
||||||
To use ShowdownJS as a Vue component quickly, you can check [vue-showdown](https://vue-showdown.js.org/).
|
|
||||||
|
|
||||||
## XSS vulnerability
|
|
||||||
|
|
||||||
Showdown doesn't sanitize the input. This is by design since markdown relies on it to allow certain features to be correctly parsed into HTML.
|
|
||||||
This, however, means XSS injection is quite possible.
|
|
||||||
|
|
||||||
Please refer to the wiki article [Markdown's XSS Vulnerability (and how to mitigate it)][xss-wiki]
|
|
||||||
for more information.
|
|
||||||
|
|
||||||
## Extensions
|
|
||||||
|
|
||||||
Showdown allows additional functionality to be loaded via extensions. (you can find a list of known showdown extensions [here][ext-wiki])
|
|
||||||
You can also find a boilerplate, to create your own extensions in [this repository][boilerplate-repo]
|
|
||||||
|
|
||||||
### Client-side Extension Usage
|
|
||||||
|
|
||||||
```js
|
|
||||||
<script src="showdown.js" />
|
|
||||||
<script src="twitter-extension.js" />
|
|
||||||
|
|
||||||
var converter = new showdown.Converter({ extensions: ['twitter'] });
|
|
||||||
```
|
|
||||||
|
|
||||||
### Server-side Extension Usage
|
|
||||||
|
|
||||||
```js
|
|
||||||
var showdown = require('showdown'),
|
|
||||||
myExtension = require('myExtension'),
|
|
||||||
converter = new showdown.Converter({ extensions: ['myExtension'] });
|
|
||||||
```
|
|
||||||
|
|
||||||
## Building
|
|
||||||
|
|
||||||
Building your clone of the repository is easy.
|
|
||||||
> Prerequesites: [Node.js](https://nodejs.org/) v12, [npm](https://www.npmjs.com/package/npm) and [npx](https://www.npmjs.com/package/npx) must be installed.
|
|
||||||
|
|
||||||
1. run `npm install`.
|
|
||||||
2. run `npx grunt build` (see [`Gruntfile.js`](/Gruntfile.js)). This command:
|
|
||||||
|
|
||||||
1. Cleans the repo.
|
|
||||||
2. Checks code quality ([JSHint](https://jshint.com/) and [ESLint](https://eslint.org/)).
|
|
||||||
3. Runs tests.
|
|
||||||
4. Creates the [distributable](/showdown.js) and [minified](/showdown.min.js) files in the [`dist`](/dist) folder.
|
|
||||||
|
|
||||||
## 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:
|
|
||||||
|
|
||||||
npm install
|
|
||||||
|
|
||||||
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`.
|
|
||||||
|
|
||||||
## Contributing
|
|
||||||
|
|
||||||
If you wish to contribute please read the following quick guide.
|
|
||||||
|
|
||||||
### Want a Feature?
|
|
||||||
You can request a new feature by submitting an issue. If you would like to implement a new feature feel free to issue a
|
|
||||||
Pull Request.
|
|
||||||
|
|
||||||
|
|
||||||
### Pull requests (PRs)
|
|
||||||
PRs are awesome. However, before you submit your pull request consider the following guidelines:
|
|
||||||
|
|
||||||
- Search GitHub for an open or closed Pull Request that relates to your submission. You don't want to duplicate effort.
|
|
||||||
- When issuing PRs that change code, make your changes in a new git branch based on master:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git checkout -b my-fix-branch master
|
|
||||||
```
|
|
||||||
|
|
||||||
- Documentation (i.e: README.md) changes can be made directly against master.
|
|
||||||
- Run the full test suite before submitting and make sure all tests pass (obviously =P).
|
|
||||||
- Try to follow our [**coding style rules**][coding-rules].
|
|
||||||
Breaking them prevents the PR to pass the tests.
|
|
||||||
- Refrain from fixing multiple issues in the same pull request. It's preferable to open multiple small PRs instead of one
|
|
||||||
hard to review big one.
|
|
||||||
- If the PR introduces a new feature or fixes an issue, please add the appropriate test case.
|
|
||||||
- We use commit notes to generate the changelog. It's extremely helpful if your commit messages adhere to the
|
|
||||||
[**AngularJS Git Commit Guidelines**][ng-commit-guide].
|
|
||||||
- If we suggest changes then:
|
|
||||||
- Make the required updates.
|
|
||||||
- Re-run the Angular test suite to ensure tests are still passing.
|
|
||||||
- Rebase your branch and force push to your GitHub repository (this will update your Pull Request):
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git rebase master -i
|
|
||||||
git push origin my-fix-branch -f
|
|
||||||
```
|
|
||||||
- After your pull request is merged, you can safely delete your branch.
|
|
||||||
|
|
||||||
If you have time to contribute to this project, we feel obliged that you get credit for it.
|
|
||||||
These rules enable us to review your PR faster and will give you appropriate credit in your GitHub profile.
|
|
||||||
We thank you in advance for your contribution!
|
|
||||||
|
|
||||||
### Joining the team
|
|
||||||
We're looking for members to help maintaining Showdown.
|
|
||||||
Please see [this issue](https://github.com/showdownjs/showdown/issues/114) to express interest or comment on this note.
|
|
||||||
|
|
||||||
## Credits
|
## Credits
|
||||||
Full credit list at https://github.com/showdownjs/showdown/blob/master/CREDITS.md
|
|
||||||
|
|
||||||
Showdown is powered by:<br/>
|
Full credit list across the versions is available [here][credits].
|
||||||
[](https://www.jetbrains.com/webstorm/)
|
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
ShowdownJS v 2.0 is release under the MIT version.
|
||||||
|
|
||||||
|
Previous versions are release under BSD.
|
||||||
|
|
||||||
|
----
|
||||||
|
|
||||||
[sd-logo]: https://raw.githubusercontent.com/showdownjs/logo/master/dist/logo.readme.png
|
[sd-logo]: https://raw.githubusercontent.com/showdownjs/logo/master/dist/logo.readme.png
|
||||||
[legacy-branch]: https://github.com/showdownjs/showdown/tree/legacy
|
[quickstart]: https://showdownjs.com/docs/quickstart/
|
||||||
[releases]: https://github.com/showdownjs/showdown/releases
|
[installation-methods]: https://showdownjs.com/docs/quickstart/#other-installation-methods
|
||||||
[changelog]: https://github.com/showdownjs/showdown/blob/master/CHANGELOG.md
|
[extensions]: https://showdownjs.com/docs/extensions/
|
||||||
[wiki]: https://github.com/showdownjs/showdown/wiki
|
[cli]: https://showdownjs.com/docs/cli/
|
||||||
[cli-wiki]: https://github.com/showdownjs/showdown/wiki/CLI-tool
|
[contribution-guide]: https://showdownjs.com/docs/contribution-guide/
|
||||||
[definitely-typed]: https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/showdown
|
[credits]: https://showdownjs.com/docs/credits/
|
||||||
[xss-wiki]: https://github.com/showdownjs/showdown/wiki/Markdown's-XSS-Vulnerability-(and-how-to-mitigate-it)
|
|
||||||
[ext-wiki]: https://github.com/showdownjs/showdown/wiki/extensions
|
|
||||||
[coding-rules]: https://github.com/showdownjs/code-style/blob/master/README.md
|
|
||||||
[ng-commit-guide]: https://github.com/showdownjs/code-style/blob/master/README.md#commit-message-convention
|
|
||||||
[boilerplate-repo]: https://github.com/showdownjs/extension-boilerplate
|
|
@ -1,4 +1,8 @@
|
|||||||
:root {
|
:root {
|
||||||
--md-primary-fg-color: rgb(196, 54, 39);
|
--md-primary-fg-color: rgb(196, 54, 39);
|
||||||
--md-accent-fg-color: rgb(62, 139, 138);
|
--md-accent-fg-color: rgb(62, 139, 138);
|
||||||
|
}
|
||||||
|
|
||||||
|
table {
|
||||||
|
box-sizing: initial;
|
||||||
}
|
}
|
49
docs/contribution-guide.md
Normal file
49
docs/contribution-guide.md
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
If you wish to contribute, this is your starting point.
|
||||||
|
|
||||||
|
This document contains guidelines to help you make your contribution clear and consistent.
|
||||||
|
These guidelines also help us to review your PR faster and, as a result, will give you
|
||||||
|
appropriate credit in your GitHub profile.
|
||||||
|
|
||||||
|
If you have time to contribute to this project, we are happy to give you credit for it.
|
||||||
|
|
||||||
|
We thank you in advance for your contribution!
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
You can request a new feature by submitting an issue. If you would like to implement a new feature,
|
||||||
|
feel free to issue a Pull Request.
|
||||||
|
|
||||||
|
### Pull requests
|
||||||
|
|
||||||
|
Pull Requests (PRs) are awesome. Get familiar with the following guidelines before you begin:
|
||||||
|
|
||||||
|
1. Search the project for a Pull Request related to your submission. You don't want to duplicate effort.
|
||||||
|
1. A PR that contains code changes should be created from a git branch based on **develop**:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git checkout -b my-fix-branch develop
|
||||||
|
```
|
||||||
|
|
||||||
|
1. Follow our [coding style rules][coding-rules].
|
||||||
|
1. Run full test suite and ensure all tests pass.
|
||||||
|
1. If some tests fail, ensure that you follow [coding style rules][coding-rules].
|
||||||
|
1. One PR - one issue. Refrain from fixing multiple issues in the same pull request. Several small PRs are preferable instead of a big one.
|
||||||
|
1. If the PR introduces a new feature or fixes an issue, **please add the appropriate test case(s)**.
|
||||||
|
1. Follow [conventional commit guidelines][conventional-commits] for your commit message(s) when saving changes in your branch and PR.
|
||||||
|
1. Add your name to the [Credits](credits.md) file. We like to give credit where it's due.
|
||||||
|
|
||||||
|
1. If we suggest changes:
|
||||||
|
1. Make the required updates.
|
||||||
|
1. Re-run test suite to ensure tests are still green.
|
||||||
|
1. Rebase your branch and force push to your GitHub repository (this will update your Pull Request):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git rebase develop -i
|
||||||
|
git push origin my-fix-branch -f
|
||||||
|
```
|
||||||
|
|
||||||
|
1. After your pull request is merged, you can safely delete your branch.
|
||||||
|
|
||||||
|
|
||||||
|
[coding-rules]: https://github.com/showdownjs/code-style/blob/master/README.md
|
||||||
|
[conventional-commits]: https://www.conventionalcommits.org/
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
* [Estevão Santos](https://github.com/tivie)
|
* [Estevão Santos](https://github.com/tivie)
|
||||||
* [SyntaxRules](https://github.com/SyntaxRules)
|
* [SyntaxRules](https://github.com/SyntaxRules)
|
||||||
|
* [Anton Zolotukhin](https://github.com/bandantonio)
|
||||||
|
|
||||||
=== "v.1"
|
=== "v.1"
|
||||||
|
|
||||||
|
238
docs/event-system.md
Normal file
238
docs/event-system.md
Normal file
@ -0,0 +1,238 @@
|
|||||||
|
## Introduction
|
||||||
|
|
||||||
|
The Event System is the basis of the new Listener extensions, replacing the ["old" extension system](extensions.md) altogether.
|
||||||
|
|
||||||
|
In short, the Event System lifecycle looks as follows:
|
||||||
|
|
||||||
|
1. A sub-parser emits an event.
|
||||||
|
|
||||||
|
!!! note ""
|
||||||
|
Each sub-parser can emit a batch of events (see the list below)
|
||||||
|
|
||||||
|
1. Extension A (which is a _Listener Extension_) registers and listens to a specific event.
|
||||||
|
|
||||||
|
!!! note ""
|
||||||
|
An extension can only register for a specific event
|
||||||
|
|
||||||
|
1. Extension A receives an event object and modifies it.
|
||||||
|
|
||||||
|
!!! note ""
|
||||||
|
Certain properties of the event object can be changed, which will change the behavior or output of the sub-parser
|
||||||
|
|
||||||
|
1. Extension A returns the event object to the converter.
|
||||||
|
1. The converter passes the received event object to the next extension in the chain.
|
||||||
|
|
||||||
|
## Event Object
|
||||||
|
|
||||||
|
### Properties
|
||||||
|
|
||||||
|
#### matches
|
||||||
|
|
||||||
|
**matches** is an object that holds the text captured by the sub-parser. The properties of this object are different for each sub-parser.
|
||||||
|
Some properties can be read-only: their names start with `_` (underscore).
|
||||||
|
|
||||||
|
!!! example "blockquote `onCapture` event"
|
||||||
|
|
||||||
|
```js
|
||||||
|
{
|
||||||
|
_wholeMatch: "> some awesome quote",
|
||||||
|
blockquote: "some awesome quote"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
<!-- ## Basic Event -->
|
||||||
|
|
||||||
|
## Event types
|
||||||
|
|
||||||
|
Events are emitted when a sub-parser runs (or about to be run).
|
||||||
|
In the sub-parser, the events follow strict order sequence: [`onStart`](#onstart) -> [`onCapture`](#oncapture) -> [`onHash`](#onhash) -> [`onEnd`](#onend)
|
||||||
|
|
||||||
|
It means that `.before` events always run before `.captureStart`.
|
||||||
|
|
||||||
|
### onStart
|
||||||
|
|
||||||
|
**`<converter>.<subparser>.onStart`**: **always runs** except if the sub-parser is disabled.
|
||||||
|
|
||||||
|
Emitted when the sub-parser has started, but no capturing or modifications to the text were done.
|
||||||
|
|
||||||
|
**Always runs** except if the sub-parser is disabled via options.
|
||||||
|
|
||||||
|
!!! hint "When to use `onStart` event"
|
||||||
|
Use this event when you want to change the input passed to the sub-parser.
|
||||||
|
|
||||||
|
!!! warning ""
|
||||||
|
Please note that the input is the **full text** that was passed to the converter.
|
||||||
|
|
||||||
|
**Properties**
|
||||||
|
|
||||||
|
| property | type | access | description |
|
||||||
|
|--------------|----------|---------|----------------------------------------------------------------|
|
||||||
|
| `input` | `string` | `read` | Full text that was passed to the subparser |
|
||||||
|
| `output` | `string` | `write` | Full text with modification that will be passed along the chain |
|
||||||
|
| `regexp` | `null` | | |
|
||||||
|
| `matches` | `null` | | |
|
||||||
|
| `attributes` | `null` | | |
|
||||||
|
|
||||||
|
### onCapture
|
||||||
|
|
||||||
|
**`<converter>.<subparser>.onCapture`**: *might not be run*.
|
||||||
|
|
||||||
|
Emitted when a regex match is found and capture was successful.
|
||||||
|
Further normalization and modification of the regex captured groups might be performed.
|
||||||
|
|
||||||
|
Might not be run if no regex match found.
|
||||||
|
|
||||||
|
!!! hint "When to use `onCapture` event"
|
||||||
|
Use this event if you want to:
|
||||||
|
|
||||||
|
* modify the sub-parser behavior, text;
|
||||||
|
* modify the HTML output of the sub-parser.
|
||||||
|
|
||||||
|
**Properties**
|
||||||
|
|
||||||
|
| property | type | access | description |
|
||||||
|
|--------------|----------|--------------|-------------------------------------------------------------------|
|
||||||
|
| `input` | `string` | `readonly` | The captured text |
|
||||||
|
| `output` | `string` | `write` | `null` or well-formed HTML (see the Important Note below) |
|
||||||
|
| `regexp` | `RegExp` | `readonly` | Regular Expression to capture groups |
|
||||||
|
| `matches` | `object` | `read/write` | Match groups. Changes to this object are reflected in the output. |
|
||||||
|
| `attributes` | `object` | `read/write` | Attributes to add to the HTML output |
|
||||||
|
|
||||||
|
!!! warning "IMPORTANT NOTE"
|
||||||
|
Extensions listening to the `onCapture` event **should avoid** changing the output property.
|
||||||
|
Instead, they should modify the values of the matches and attribute objects.
|
||||||
|
|
||||||
|
The reason is that the **output property takes precedence over the matches objects** and
|
||||||
|
**prevents showdown from calling other sub-parsers** inside the captured fragment.
|
||||||
|
|
||||||
|
The above means the following:
|
||||||
|
|
||||||
|
1. If something is passed as the output property, any changes to the matches and attributes objects will be ignored.
|
||||||
|
1. Any changes made by other extensions to the matches or attributes objects will be ignored.
|
||||||
|
1. Showdown will not call other sub-parsers, such as encode code or span gamut in the text fragment, which may lead to unexpected results.
|
||||||
|
|
||||||
|
**Example**
|
||||||
|
|
||||||
|
!!! example ""
|
||||||
|
|
||||||
|
```js hl_lines="4"
|
||||||
|
// Showdown extension 1 that is listening to makehtml.blockquote.onCapture
|
||||||
|
function extension_1 (showdownEvent) {
|
||||||
|
// Let's imagine you're a bad person who writes to output
|
||||||
|
showdownEvent.output = '<blockquote>foo</blockquote>'; // must be a well-formed HTML
|
||||||
|
showdownEvent.matches.blockquote = 'some nice quote';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Showdown extension 2 that is also listening to makehtml.blockquote.onCapture
|
||||||
|
function extension_2 (showdownEvent) {
|
||||||
|
// I make blockquotes bold
|
||||||
|
let quote = showdownEvent.matches.blockquote;
|
||||||
|
showdownEvent.matches.blockquote = '<strong>' + quote + '</strong>';
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
In the example above, the result will always be `<blockquote>foo</blockquote>`, regardless of the order of extension loading and call.
|
||||||
|
|
||||||
|
!!! danger "Infinite loop"
|
||||||
|
Do not pass the input as output to the `onCapture` event, or you might trigger an infinite loop.
|
||||||
|
|
||||||
|
### onHash
|
||||||
|
|
||||||
|
**`<converter>.<subparser>.onHash`**: *always runs*.
|
||||||
|
|
||||||
|
Raised before the output is hashed.
|
||||||
|
|
||||||
|
**Always runs** (except if the sub-parser is disabled via options), even if no hashing is performed.
|
||||||
|
|
||||||
|
!!! hint "When to use `onHash` event"
|
||||||
|
Use this event when you want to change the sub-parser's raw output before it is hashed.
|
||||||
|
|
||||||
|
**Properties**
|
||||||
|
|
||||||
|
| property | type | access | description |
|
||||||
|
|--------------|----------|---------|----------------------------------------------|
|
||||||
|
| `input` | `string` | `read` | The captured text |
|
||||||
|
| `output` | `string` | `write` | The text that will be passed along the chain |
|
||||||
|
| `regexp` | `null` | | |
|
||||||
|
| `matches` | `null` | | |
|
||||||
|
| `attributes` | `null` | | |
|
||||||
|
|
||||||
|
### onEnd
|
||||||
|
|
||||||
|
**`<converter>.<subparser>.onEnd`**: **always runs**;
|
||||||
|
|
||||||
|
Emitted when the sub-parser has finished its work and is about to exit.
|
||||||
|
|
||||||
|
**Always runs** (except if the sub-parser is disabled via options).
|
||||||
|
|
||||||
|
!!! hint "When to use `onEnd` event"
|
||||||
|
Use this event when you want to run code or perform changes to the text after the subparser has run and its output was hashed.
|
||||||
|
|
||||||
|
!!! warning ""
|
||||||
|
Please note that the input is the **full text** and might contain hashed elements.
|
||||||
|
|
||||||
|
**Properties**
|
||||||
|
|
||||||
|
| property | type | access | description |
|
||||||
|
|-----------|----------|---------|-------------------------------------------------------------|
|
||||||
|
| `input` | `string` | `read` | Full text with the subparser modifications (contains hashes) |
|
||||||
|
| `output` | `string` | `write` | The text that will be passed to other subparsers |
|
||||||
|
| `regexp` | `null` | | |
|
||||||
|
| `matches` | `null` | | |
|
||||||
|
|
||||||
|
## Special Events
|
||||||
|
|
||||||
|
There are special events useful for *"positioning"* a listener extension in the main chain of events.
|
||||||
|
Usually, these extensions introduce new syntax that, due to precedence
|
||||||
|
|
||||||
|
In contrary, the special events will always be called, regardless of options or circumstances.
|
||||||
|
|
||||||
|
### .before.{subparserName}
|
||||||
|
|
||||||
|
**`.before.{subparserName}`**: **always runs**
|
||||||
|
|
||||||
|
Emitted just before the **`{subparserName}` is about to be entered**.
|
||||||
|
|
||||||
|
**Properties**
|
||||||
|
|
||||||
|
| property | type | access | description |
|
||||||
|
|-----------|----------|---------|----------------------------------------------------------------|
|
||||||
|
| `input` | `string` | `read` | Full text that was passed to the subparser |
|
||||||
|
| `output` | `string` | `write` | Full text with modification that will be passed along the chain |
|
||||||
|
| `regexp` | `null` | | |
|
||||||
|
| `matches` | `null` | | |
|
||||||
|
|
||||||
|
!!! note "Difference between `before.{subparserName}` and `{subparserName}.start`"
|
||||||
|
|
||||||
|
1. **`before.{subparserName}`** is always guaranteed to be called, **even if the subparser is disabled**,
|
||||||
|
while **{subparserName}.start** isn't.
|
||||||
|
|
||||||
|
For example, `makehtml.before.strikethrough` is always called even if the option `strikethrough` is `false`.
|
||||||
|
|
||||||
|
1. **`before.{subparserName}`** is only emitted **once** in a span context while **`{subparserName}.start`** is emitted
|
||||||
|
everytime **`{subparserName}`** is called.
|
||||||
|
|
||||||
|
<!-- As a rule of thumb -->
|
||||||
|
|
||||||
|
### .after.{subparserName}
|
||||||
|
|
||||||
|
**`.after.{subparserName}`**: **always runs**;
|
||||||
|
|
||||||
|
Emitted when the **`{subparserName}` has exited** and before the next one is called.
|
||||||
|
|
||||||
|
**Properties**
|
||||||
|
|
||||||
|
| property | type | access | description |
|
||||||
|
|-----------|----------|---------|---------------------------------------------------|
|
||||||
|
| `input` | `string` | `read` | Partial/full text with the subparser modifications |
|
||||||
|
| `output` | `string` | `write` | The text that will be passed to other subparsers |
|
||||||
|
| `regexp` | `null` | | |
|
||||||
|
| `matches` | `null` | | |
|
||||||
|
|
||||||
|
<!--
|
||||||
|
## Events List
|
||||||
|
|
||||||
|
### blockquote
|
||||||
|
|
||||||
|
### metadata
|
||||||
|
-->
|
@ -1,228 +0,0 @@
|
|||||||
# Event System )
|
|
||||||
|
|
||||||
## Introduction
|
|
||||||
|
|
||||||
The Event System is the basis of the new Listener extensions, replacing the old extension system altogether.
|
|
||||||
|
|
||||||
The life cycle can be summarized as this:
|
|
||||||
|
|
||||||
- A subparsers emmits an event
|
|
||||||
- Each subparser can emmit a bunch of events (see list below)
|
|
||||||
- Extension A, which is a _Listener Extension_ registers and listens to a specific event
|
|
||||||
- An extension can only register to a specific event
|
|
||||||
- Extension A receives an event object and modifies it
|
|
||||||
- Certain properties of the event object can be changed, ehich will change the behavior or output of the subparser
|
|
||||||
- The extension then returns the event object
|
|
||||||
- The converter passes this event object to the next extension in the chain
|
|
||||||
|
|
||||||
|
|
||||||
Note:
|
|
||||||
|
|
||||||
## The Event Object
|
|
||||||
|
|
||||||
### Properties
|
|
||||||
|
|
||||||
#### matches (type: **object**)
|
|
||||||
|
|
||||||
This object holds the text captured by the subparser. The properties of this object
|
|
||||||
are different for each subparser.
|
|
||||||
|
|
||||||
**Properties whose name starts with `_` are readonly**.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
```js
|
|
||||||
// blockquote onCapture event
|
|
||||||
{
|
|
||||||
_wholeMatch: "> some awesome quote",
|
|
||||||
blockquote: "some awesome quote"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
## Basic Event
|
|
||||||
|
|
||||||
|
|
||||||
## Event Types
|
|
||||||
|
|
||||||
Events are raised when a subparser is run (or about to be run).
|
|
||||||
Within a subparser, the events always follow a certain order (sequence). For instance, **.before** events always run before **.captureStart**.
|
|
||||||
Each subparser raises several events sequentially:
|
|
||||||
|
|
||||||
### onStart
|
|
||||||
|
|
||||||
**`<converter>.<subparser>.onStart`**: **always runs** except if the subparser is disabled
|
|
||||||
|
|
||||||
Raised when the **subparser has started**, but no capturing or any modification to the text was done.
|
|
||||||
**Always runs** (except if the subparser is deactivated through options).
|
|
||||||
|
|
||||||
***Properties***:
|
|
||||||
|
|
||||||
| property | type | access | description |
|
|
||||||
|------------|-----------|------------|--------------------------------------------------------------------|
|
|
||||||
| input | string | read | The full text that was passed to the subparser |
|
|
||||||
| output | string | write | The full text with modification that will be passed along the chain|
|
|
||||||
| regexp | null | | |
|
|
||||||
| matches | null | | |
|
|
||||||
| attributes | null | | |
|
|
||||||
|
|
||||||
|
|
||||||
Usually you would want to use this event if you wish to change the input to the subparser. Please note,
|
|
||||||
however, that the input text is the **complete text** that was fed to the converter.
|
|
||||||
|
|
||||||
### onCapture
|
|
||||||
|
|
||||||
**`<converter>.<subparser>.onCapture`**: *might not be run*;
|
|
||||||
|
|
||||||
Raised when a regex match is found and a capture was successful. Some normalization and modification
|
|
||||||
of the regex captured groups might be performed.
|
|
||||||
|
|
||||||
Might not be run if no regex match is found.
|
|
||||||
|
|
||||||
***Properties***:
|
|
||||||
|
|
||||||
| property | type | access | description |
|
|
||||||
|------------|----------|------------|--------------------------------------------------------------------|
|
|
||||||
| input | string | readonly | The captured text |
|
|
||||||
| output | string | write | null or well formed HTML (see note) |
|
|
||||||
| regexp | RegExp | readonly | Regular Expression used to capture groups |
|
|
||||||
| matches | object | read/write | Matches groups. Changes to this object are reflected in the output |
|
|
||||||
| attributes | object | read/write | Attributes to add to the HTML output |
|
|
||||||
|
|
||||||
Usually you would want to use this event if you wish to modify the subparser behavior, text or modify the HTML output
|
|
||||||
of the subparser.
|
|
||||||
|
|
||||||
**IMPORTANT NOTE**: Extensions listening to onCapture event should try to AVOID changing the output property.
|
|
||||||
Instead, they should modify the values of the matches and attributes objects. This is because
|
|
||||||
the **output property takes precedence over the matches objects** and **prevents showdown to call other subparsers**
|
|
||||||
inside the captured fragment.This means 3 very important things:
|
|
||||||
|
|
||||||
1. If something is passed as the output property, any changes to the matches and attributes objects will be ignored.
|
|
||||||
2. Changes made by other extensions to the matches or attributes objects will also be ignored
|
|
||||||
3. Showdown will not call other subparsers, such as encode code or span gamut in the text fragment, which may lead to
|
|
||||||
weird results.
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
// showdown extension 1 that is listening to makehtml.blockquote.onCapture
|
|
||||||
function extension_1 (showdownEvent) {
|
|
||||||
// i'm bad and write to output
|
|
||||||
showdownEvent.output = '<blockquote>foo</blockquote>'; // must be an well formed html string
|
|
||||||
showdownEvent.matches.blockquote = 'some nice quote';
|
|
||||||
}
|
|
||||||
|
|
||||||
// showdown extension 1 that is also listening to makehtml.blockquote.onCapture
|
|
||||||
function extension_2 (showdownEvent) {
|
|
||||||
// I make blockquotes become bold
|
|
||||||
let quote = showdownEvent.matches.blockquote;
|
|
||||||
showdownEvent.matches.blockquote = '<strong>' + quote + '</strong>';
|
|
||||||
}
|
|
||||||
|
|
||||||
// the result will always be <blockquote>foo</blockquote>, regardless of the order of extension loading and call
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
### onHash
|
|
||||||
|
|
||||||
**`<converter>.<subparser>.onHash`**: *always runs*;
|
|
||||||
|
|
||||||
Raised before the output is hashed. **Always runs** (except if the subparser was deactivated through options),
|
|
||||||
even if no hashing is performed.
|
|
||||||
|
|
||||||
***Properties***:
|
|
||||||
|
|
||||||
| property | type | access | description |
|
|
||||||
|------------|------------|------------|--------------------------------------------------------------------|
|
|
||||||
| input | string | read | The captured text |
|
|
||||||
| output | string | write | The text that will be passed to the subparser/other listeners |
|
|
||||||
| regexp | null | | |
|
|
||||||
| matches | null | | |
|
|
||||||
| attributes | null | | |
|
|
||||||
|
|
||||||
Usually you would want to use this event if you wish change the subparser's raw output before it is hashed.
|
|
||||||
|
|
||||||
### onEnd
|
|
||||||
|
|
||||||
**`<converter>.<subparser>.onEnd`**: *always runs*;
|
|
||||||
|
|
||||||
Raised when the subparser has finished its work and is about to exit.
|
|
||||||
|
|
||||||
Always runs (except if the subparser is deactivated through options).
|
|
||||||
|
|
||||||
***Properties***:
|
|
||||||
|
|
||||||
| property | type | access | description |
|
|
||||||
|----------|-----------|------------|--------------------------------------------------------------------|
|
|
||||||
| input | string | read | The full text with the subparser modifications (contains hashes) |
|
|
||||||
| output | string | write | The text that will be passed to other subparsers |
|
|
||||||
| regexp | null | | |
|
|
||||||
| matches | null | | |
|
|
||||||
|
|
||||||
Usually you would want to use this event if you want to run code or perform changes to the text after the subparser was
|
|
||||||
run and it's output was hashed. Keep in mind that the input is the full text and might contain hashed elements.
|
|
||||||
|
|
||||||
|
|
||||||
### Special Events
|
|
||||||
|
|
||||||
There are some special events that are useful for *"positioning"* a listener extension in the main chain of events.
|
|
||||||
Usually these extensions introduce new syntax that, due to precedence
|
|
||||||
These events are always guaranteed to be called, regardless of options or circumstances.
|
|
||||||
|
|
||||||
1. **.before_{subparserName}**: *always runs*
|
|
||||||
|
|
||||||
Raised just before the **{subparserName} is about to be entered**.
|
|
||||||
|
|
||||||
***Properties***:
|
|
||||||
|
|
||||||
| property | type | access | description |
|
|
||||||
|----------|-----------|------------|--------------------------------------------------------------------|
|
|
||||||
| input | string | read | The full text that was passed to the subparser |
|
|
||||||
| output | string | write | The full text with modification that will be passed along the chain|
|
|
||||||
| regexp | null | | |
|
|
||||||
| matches | null | | |
|
|
||||||
|
|
||||||
2. **.after**.{subparserName}: *always runs*;
|
|
||||||
|
|
||||||
Raised when the **{subparserName} has exited** and before the next one is called.
|
|
||||||
|
|
||||||
***Properties***:
|
|
||||||
|
|
||||||
| property | type | access | description |
|
|
||||||
|----------|-----------|------------|--------------------------------------------------------------------|
|
|
||||||
| input | string | read | The partial/full text with the subparser modifications |
|
|
||||||
| output | string | write | The text that will be passed to other subparsers |
|
|
||||||
| regexp | null | | |
|
|
||||||
| matches | null | | |
|
|
||||||
|
|
||||||
|
|
||||||
### Notes
|
|
||||||
|
|
||||||
- There are 2 main differences between **before.{subparserName}** and **{subparserName}.start**.
|
|
||||||
|
|
||||||
1. **before.{subparserName}** is always guaranteed to be called, even if the subparser is disabled,
|
|
||||||
while **{subparserName}.start** doesn't.
|
|
||||||
|
|
||||||
ex: `makehtml.before.strikethrough` is always called even if the option `strikethrough` is false
|
|
||||||
|
|
||||||
2. **before.{subparserName}** is only raised once in a span context while **{subparserName}.start** is raised
|
|
||||||
everytime **{subparserName}** is called.
|
|
||||||
|
|
||||||
As a rule of thumb,
|
|
||||||
|
|
||||||
## Events List
|
|
||||||
|
|
||||||
|
|
||||||
### blockquote
|
|
||||||
|
|
||||||
####
|
|
||||||
|
|
||||||
|
|
||||||
### metadata
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Common pitfalls
|
|
||||||
|
|
||||||
### Infinite loop
|
|
||||||
|
|
||||||
If you pass the input as output in a `onCapture` event, you might trigger an infinite loop.
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
|||||||
Showdown allows you to load additional functionality via extensions. You can find a list of known Showdown extensions [here][ext-wiki].
|
Showdown allows you to load additional functionality via extensions. You can find a list of known Showdown extensions [here][ext-list].
|
||||||
|
|
||||||
You can also check the [boilerplate repo][boilerplate-repo], to create your own extension(s).
|
You can also check the [boilerplate repo][boilerplate-repo], to create your own extension(s).
|
||||||
|
|
||||||
@ -32,5 +32,5 @@ You can also check the [boilerplate repo][boilerplate-repo], to create your own
|
|||||||
showdown -e twitter -i foo.md -o bar.html
|
showdown -e twitter -i foo.md -o bar.html
|
||||||
```
|
```
|
||||||
|
|
||||||
[ext-wiki]: https://github.com/showdownjs/showdown/wiki/extensions
|
[ext-list]: extensions-list.md
|
||||||
[boilerplate-repo]: https://github.com/showdownjs/extension-boilerplate
|
[boilerplate-repo]: https://github.com/showdownjs/extension-boilerplate
|
@ -31,8 +31,7 @@ Showdown can be used on the client-side (in the browser) or server-side (with No
|
|||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
To install Showdown, follow the instructions from the [Installation guide](installation.md).
|
To install Showdown, follow the instructions from the [quickstart guide](quickstart.md).
|
||||||
|
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
@ -40,12 +39,4 @@ ShowdownJS v 2.0 is release under the MIT version.
|
|||||||
|
|
||||||
Previous versions are release under BSD.
|
Previous versions are release under BSD.
|
||||||
|
|
||||||
[sd-logo]: https://raw.githubusercontent.com/showdownjs/logo/master/dist/logo.readme.png
|
[sd-logo]: https://raw.githubusercontent.com/showdownjs/logo/master/dist/logo.readme.png
|
||||||
[wiki]: https://github.com/showdownjs/showdown/wiki
|
|
||||||
[cli-wiki]: https://github.com/showdownjs/showdown/wiki/CLI-tool
|
|
||||||
[definitely-typed]: https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/showdown
|
|
||||||
[xss-wiki]: https://github.com/showdownjs/showdown/wiki/Markdown's-XSS-Vulnerability-(and-how-to-mitigate-it)
|
|
||||||
[ext-wiki]: https://github.com/showdownjs/showdown/wiki/extensions
|
|
||||||
[coding-rules]: https://github.com/showdownjs/code-style/blob/master/README.md
|
|
||||||
[ng-commit-guide]: https://github.com/showdownjs/code-style/blob/master/README.md#commit-message-convention
|
|
||||||
[boilerplate-repo]: https://github.com/showdownjs/extension-boilerplate
|
|
42
docs/local-development.md
Normal file
42
docs/local-development.md
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
## Prerequesites
|
||||||
|
|
||||||
|
* [Node.js](https://nodejs.org/) v12+
|
||||||
|
* [npm](https://www.npmjs.com/package/npm)
|
||||||
|
* [npx](https://www.npmjs.com/package/npx)
|
||||||
|
|
||||||
|
## Build
|
||||||
|
|
||||||
|
Building your clone of the repository is easy:
|
||||||
|
|
||||||
|
1. run `npm install`.
|
||||||
|
1. run `npx grunt build` (see [`Gruntfile.js`][gruntfile]). This command:
|
||||||
|
|
||||||
|
1. Cleans the repo.
|
||||||
|
1. Checks code quality ([JSHint](https://jshint.com/) and [ESLint](https://eslint.org/)).
|
||||||
|
1. Runs tests.
|
||||||
|
1. Creates the [distributable][sd-dist] and [minified][sd-min] files in the [`dist`][dist-folder] folder.
|
||||||
|
|
||||||
|
## Test
|
||||||
|
|
||||||
|
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
|
||||||
|
```
|
||||||
|
|
||||||
|
Once installed, run tests from the project root:
|
||||||
|
|
||||||
|
```
|
||||||
|
npm test
|
||||||
|
```
|
||||||
|
|
||||||
|
You can easily add new tests:
|
||||||
|
|
||||||
|
1. Create a markdown file (ending in `.md`) that contains the markdown to test.
|
||||||
|
1. Create a `.html` file with the same name as the markdown one from the previous step. This `html` file will automatically be tested when the tests are executed with `mocha`.
|
||||||
|
|
||||||
|
[gruntfile]: https://github.com/showdownjs/showdown/blob/master/Gruntfile.js
|
||||||
|
[sd-dist]: https://github.com/showdownjs/showdown/blob/master/dist/showdown.js
|
||||||
|
[sd-min]: https://github.com/showdownjs/showdown/blob/master/dist/showdown.min.js
|
||||||
|
[dist-folder]: https://github.com/showdownjs/showdown/tree/master/dist
|
@ -30,6 +30,7 @@ site_dir: public
|
|||||||
nav:
|
nav:
|
||||||
- Home:
|
- Home:
|
||||||
- Introduction: index.md
|
- Introduction: index.md
|
||||||
|
- Contribution guide: contribution-guide.md
|
||||||
- Donations: donations.md
|
- Donations: donations.md
|
||||||
- Credits: credits.md
|
- Credits: credits.md
|
||||||
- Quickstart:
|
- Quickstart:
|
||||||
@ -42,8 +43,10 @@ nav:
|
|||||||
- Flavors: flavors.md
|
- Flavors: flavors.md
|
||||||
- CLI: cli.md
|
- CLI: cli.md
|
||||||
- Integrations: integrations.md
|
- Integrations: integrations.md
|
||||||
|
- Event system: event-system.md
|
||||||
- Extensions:
|
- Extensions:
|
||||||
- Overview: extensions.md
|
- Overview: extensions.md
|
||||||
- Create an extension: create-extension.md
|
- Create an extension: create-extension.md
|
||||||
- List of known extensions: extensions-list.md
|
- List of known extensions: extensions-list.md
|
||||||
- Tutorials: tutorials/index.md
|
- Tutorials: tutorials/index.md
|
||||||
|
- Local development: local-development.md
|
@ -134,7 +134,7 @@
|
|||||||
.replace(/¨D/g, '')
|
.replace(/¨D/g, '')
|
||||||
// replace rest of the chars (&~$ are repeated as they might have been escaped)
|
// replace rest of the chars (&~$ are repeated as they might have been escaped)
|
||||||
// borrowed from github's redcarpet (so they should produce similar results)
|
// borrowed from github's redcarpet (so they should produce similar results)
|
||||||
.replace(/[&+$,\/:;=?@"#{}|^¨~\[\]`\\*)(%.!'<>]/g, '')
|
.replace(/[&+$,\/:;=?@"#{}|^¨¿?:~\[\]`、゠=…‥『』〝〟「」\\*(){}()[]【】%.。,¡!!'<>]/g, '')
|
||||||
.toLowerCase();
|
.toLowerCase();
|
||||||
} else if (options.rawHeaderId) {
|
} else if (options.rawHeaderId) {
|
||||||
title = title
|
title = title
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
<h1 id="some-header">some header</h1>
|
<h1 id="some-header">some header</h1>
|
||||||
<h1 id="some-header-with--chars">some header with &+$,/:;=?@"#{}|^~[]`\*()%.!' chars</h1>
|
|
||||||
|
<h1 id="some-header-with--chars">some header with &+$,/:;=?@\"#{}|^¨¿?:~[]`゠=…‥『』〝〟「」\*(){}()[]【】%.。,¡!!' chars</h1>
|
||||||
|
|
||||||
<h1 id="another-header--with--chars">another header > with < chars</h1>
|
<h1 id="another-header--with--chars">another header > with < chars</h1>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
# some header
|
# some header
|
||||||
|
|
||||||
# some header with &+$,/:;=?@"#{}|^~[]`\\*()%.!' chars
|
# some header with &+$,/:;=?@\"#{}|^¨¿?:~[]`゠=…‥『』〝〟「」\\*(){}()[]【】%.。,¡!!' chars
|
||||||
|
|
||||||
# another header > with < chars
|
# another header > with < chars
|
||||||
|
Loading…
x
Reference in New Issue
Block a user