Skip to content

✨NEW: Add containers plugin #27

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Aug 11, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -138,5 +138,6 @@ __pycache__/
.ropeproject/
*.egg-info/
.vscode/
.DS_Store

docs/api/
11 changes: 10 additions & 1 deletion docs/plugins.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,16 @@ Other plugins are then available *via* the `markdown_it.extensions` package:
---
```

- [containers](https://github.com/markdown-it/markdown-it-container) is a plugin for creating block-level custom containers:

```md
::::: name
:::: name
*markdown*
::::
:::::
```

- [texmath](https://github.com/goessner/markdown-it-texmath) parses TeX math equations set inside opening and closing delimiters:

```md
Expand All @@ -56,7 +66,6 @@ There are also many other plugins which could easily be ported (and hopefully wi
- [definition list](https://github.com/markdown-it/markdown-it-deflist)
- [abbreviation](https://github.com/markdown-it/markdown-it-abbr)
- [emoji](https://github.com/markdown-it/markdown-it-emoji)
- [custom container](https://github.com/markdown-it/markdown-it-container)
- [insert](https://github.com/markdown-it/markdown-it-ins)
- [mark](https://github.com/markdown-it/markdown-it-mark)
- ... and [others](https://www.npmjs.org/browse/keyword/markdown-it-plugin)
22 changes: 22 additions & 0 deletions markdown_it/extensions/container/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
Copyright (c) 2015 Vitaly Puzrin, Alex Kocharin.

Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
95 changes: 95 additions & 0 deletions markdown_it/extensions/container/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
# markdown-it-container

[![Build Status](https://img.shields.io/travis/markdown-it/markdown-it-container/master.svg?style=flat)](https://travis-ci.org/markdown-it/markdown-it-container)
[![NPM version](https://img.shields.io/npm/v/markdown-it-container.svg?style=flat)](https://www.npmjs.org/package/markdown-it-container)
[![Coverage Status](https://img.shields.io/coveralls/markdown-it/markdown-it-container/master.svg?style=flat)](https://coveralls.io/r/markdown-it/markdown-it-container?branch=master)

> Plugin for creating block-level custom containers for [markdown-it](https://github.com/markdown-it/markdown-it) markdown parser.

__v2.+ requires `markdown-it` v5.+, see changelog.__

With this plugin you can create block containers like:

```
::: warning
*here be dragons*
:::
```

.... and specify how they should be rendered. If no renderer defined, `<div>` with
container name class will be created:

```html
<div class="warning">
<em>here be dragons</em>
</div>
```

Markup is the same as for [fenced code blocks](http://spec.commonmark.org/0.18/#fenced-code-blocks).
Difference is, that marker use another character and content is rendered as markdown markup.


## Installation

node.js, browser:

```bash
$ npm install markdown-it-container --save
$ bower install markdown-it-container --save
```


## API

```js
var md = require('markdown-it')()
.use(require('markdown-it-container'), name [, options]);
```

Params:

- __name__ - container name (mandatory)
- __options:__
- __validate__ - optional, function to validate tail after opening marker, should
return `true` on success.
- __render__ - optional, renderer function for opening/closing tokens.
- __marker__ - optional (`:`), character to use in delimiter.


## Example

```js
var md = require('markdown-it')();

md.use(require('markdown-it-container'), 'spoiler', {

validate: function(params) {
return params.trim().match(/^spoiler\s+(.*)$/);
},

render: function (tokens, idx) {
var m = tokens[idx].info.trim().match(/^spoiler\s+(.*)$/);

if (tokens[idx].nesting === 1) {
// opening tag
return '<details><summary>' + md.utils.escapeHtml(m[1]) + '</summary>\n';

} else {
// closing tag
return '</details>\n';
}
}
});

console.log(md.render('::: spoiler click me\n*content*\n:::\n'));

// Output:
//
// <details><summary>click me</summary>
// <p><em>content</em></p>
// </details>
```

## License

[MIT](https://github.com/markdown-it/markdown-it-container/blob/master/LICENSE)
1 change: 1 addition & 0 deletions markdown_it/extensions/container/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from .index import container_plugin # noqa F401
142 changes: 142 additions & 0 deletions markdown_it/extensions/container/index.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
"""Process block-level custom containers."""
from math import floor

from markdown_it import MarkdownIt
from markdown_it.common.utils import charCodeAt
from markdown_it.rules_block import StateBlock


def container_plugin(md: MarkdownIt, name, **options):
"""Second param may be useful,
if you decide to increase minimal allowed marker length
"""

def validateDefault(params: str, *args):
return params.strip().split(" ", 2)[0] == name

def renderDefault(self, tokens, idx, _options, env):
# add a class to the opening tag
if tokens[idx].nesting == 1:
tokens[idx].attrJoin("class", name)

return self.renderToken(tokens, idx, _options, env)

min_markers = 3
marker_str = options.get("marker", ":")
marker_char = charCodeAt(marker_str, 0)
marker_len = len(marker_str)
validate = options.get("validate", validateDefault)
render = options.get("render", renderDefault)

def container_func(state: StateBlock, startLine: int, endLine: int, silent: bool):

auto_closed = False
start = state.bMarks[startLine] + state.tShift[startLine]
maximum = state.eMarks[startLine]

# Check out the first character quickly,
# this should filter out most of non-containers
if marker_char != charCodeAt(state.src, start):
return False

# Check out the rest of the marker string
pos = start + 1
while pos <= maximum:
if marker_str[(pos - start) % marker_len] != state.src[pos]:
break
pos += 1

marker_count = floor((pos - start) / marker_len)
if marker_count < min_markers:
return False
pos -= (pos - start) % marker_len

markup = state.src[start:pos]
params = state.src[pos:maximum]
if not validate(params, markup):
return False

# Since start is found, we can report success here in validation mode
if silent:
return True

# Search for the end of the block
nextLine = startLine

while True:
nextLine += 1
if nextLine >= endLine:
# unclosed block should be autoclosed by end of document.
# also block seems to be autoclosed by end of parent
break

start = state.bMarks[nextLine] + state.tShift[nextLine]
maximum = state.eMarks[nextLine]

if start < maximum and state.sCount[nextLine] < state.blkIndent:
# non-empty line with negative indent should stop the list:
# - ```
# test
break

if marker_char != charCodeAt(state.src, start):
continue

if state.sCount[nextLine] - state.blkIndent >= 4:
# closing fence should be indented less than 4 spaces
continue

pos = start + 1
while pos <= maximum:
if marker_str[(pos - start) % marker_len] != state.src[pos]:
break
pos += 1

# closing code fence must be at least as long as the opening one
if floor((pos - start) / marker_len) < marker_count:
continue

# make sure tail has spaces only
pos -= (pos - start) % marker_len
pos = state.skipSpaces(pos)

if pos < maximum:
continue

# found!
auto_closed = True
break

old_parent = state.parentType
old_line_max = state.lineMax
state.parentType = "container"

# this will prevent lazy continuations from ever going past our end marker
state.lineMax = nextLine

token = state.push(f"container_{name}_open", "div", 1)
token.markup = markup
token.block = True
token.info = params
token.map = [startLine, nextLine]

state.md.block.tokenize(state, startLine + 1, nextLine)

token = state.push(f"container_{name}_close", "div", -1)
token.markup = state.src[start:pos]
token.block = True

state.parentType = old_parent
state.lineMax = old_line_max
state.line = nextLine + (1 if auto_closed else 0)

return True

md.block.ruler.before(
"fence",
"container_" + name,
container_func,
{"alt": ["paragraph", "reference", "blockquote", "list"]},
)
md.add_render_rule(f"container_{name}_open", render)
md.add_render_rule(f"container_{name}_close", render)
5 changes: 5 additions & 0 deletions markdown_it/extensions/container/port.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
- package: markdown-it-container
commit: adb3defde3a1c56015895b47ce4c6591b8b1e3a2
date: Jun 2, 2020
version: 3.0.0
changes:
Empty file.
Loading