Code Monkey home page Code Monkey logo

markdown-it-container's Introduction

markdown-it-container

CI NPM version Coverage Status

Plugin for creating block-level custom containers for 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:

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

Markup is the same as for fenced code blocks. Difference is, that marker use another character and content is rendered as markdown markup.

Installation

node.js, browser:

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

API

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

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

markdown-it-container's People

Contributors

puzrin avatar rlidwka avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

markdown-it-container's Issues

marker characters appear within div

Given four markers:

:::: c
text
:::

I get markers after the text:

<div class="c">
   <p>text :::</p>
</div>

With current Firefox (70). I copied the code from container_plugin() into a browser <script>.

set correct nesting when adding container

To reproduce:

let md = require('markdown-it')();
let container = require('markdown-it-container');

md.use(container, 'column');

let src = `
::: column
Lorem ipsum
:::
`;

console.log(md.render(src));

gives tokens:

[
  Token {type: "container_column_open", tag: "div", attrs: null, map: Array(2), nesting: 1, …},
  Token {type: "paragraph_open", tag: "p", attrs: null, map: Array(2), nesting: 1, …}
  ...
]

Note that div and p both have nesting === 1, which is incorrect, as p is inside div.

This results in arve0/markdown-it-attrs#72, attributes on the wrong opening tag.

Dynamic class name

Is it possible to have a generic container that applies a dynamic class name?

Kind of like the info-string for fenced code blocks. I.e. if you write ```java you get a <code> with the class name language-java, but if you write ```ruby the class name will be language-ruby.

In a similar manner I would like to be able to do ::: foo and get <div class="foo"> and ::: bar and get <div class="bar">. Is this possible? It's important that all use the same opening/closing sequence (:::) and that I don't have to write anything more than just those three colons and the classname.

Feature: Add title to container block

I'd like to have an optional title text:

::: info Tips and Tricks
You may....
:::

This should be transformed to:

<div class="info">
<header>Tips and Tricks</header>
<p>You may...</p>
</div>

If no title given it should behave like now.

how could I custome the tag name

I want to control the tag name of rendered html, e.g. z-deep/section instead of div.

        .use(require('markdown-it-container'), 'decorate' , {
            validate: function(params) {
                return params.trim().match(/^(z-deep|section)$/);
            },

            render: function (tokens, idx) {
                var m = tokens[idx].info.trim().match(/^(z-deep|section)$/);

                var tag=m[1]||'div';

                if (tokens[idx].nesting === 1) {
                    // opening tag

                    return '<' + tag  + ' >\n';

                } else {
                    // closing tag
                    console.log('tag ',tag)
                    return '</'+tag+'>\n';
                }
            }

but the closing tag always is 'div', for example

::: z-deep
ok
:::

output:

<z-deep>
<p>ok</p>
</div>

Specify multiple container names?

I would like configure multiple container names to all use the default renderer. I am able to accomplish this with

md.use(require('markdown-it-container'), 'container-1');
md.use(require('markdown-it-container'), 'container-2');

Is there any downside to calling the require method more than once like this?

I am wondering if there is a simpler way. Maybe something like this?

md.use(require('markdown-it-container'), ['container-1', container-2']));

feature: Container Ids

Hello there,

I would like to add ids to my containers, but at the moment only classes can be added.
The syntax I would like to use is a hash (#) followed by the id, like so:

::: #container
:::

However this currently renders as a class rather than the id as I would like.

<div class="#container">
</div>

This is what I would like:

<div id="container">
</div>

How easy would this feature be to add and do you this is would be a useful addition?

Need some details about changing default "div" to "aside"

Hi.

I use browser version. This is what I currently have to init the plugin:

.use(markdownitContainer, 'aside', {
    render: function (tokens, idx) {
        var m = tokens[idx].info.trim().match(/^aside\s+(.*)$/);
        if (tokens[idx].nesting === 1) {
            return '<aside><p class="aside-title">' + md.utils.escapeHtml(m[1]) + '</p>\n';
        } else {
            return '</aside>\n';
        }
    }
});

It successfully works, so

::: aside Note
text
:::

would be converted to

<aside>
    <p class="aside-title">Note</p>
    <p>text</p>
</aside>

But if it possible to get rid of "aside" in Markdown markup?

That's mean,

::: Note
text
:::

should be converted to:

<aside>
    <p class="aside-title">Note</p>
    <p>text</p>
</aside>

As you see, now there is no word "aside" in the Markdown markup, but it was rendered as "aside" in HTML.

Is there way to achieve it? Thanks.

Paragraph **p** surround image

Hi everyone,
below I report my configurations:

// ...
const markdownItAttrs = require('markdown-it-attrs')
const markDownItContainer = require('markdown-it-container')
var blockImagePlugin = require("markdown-it-block-image")
const Markdown = require('markdown-it')({
    html: true,
    breaks: true,
    typographer: true,
    linkify: true
})
.use(markdownItAttrs)
.use(blockImagePlugin)
.use(markDownItContainer, 'htmlblock')
// ...

When I render my web page:

<!DOCTYPE html>
<html>
    <body>
    <h1>My First Heading</h1>
    <p>My first paragraph.</p>
    {% markdown %}
    ::: htmlblock {.red} 
    ![img](img.png)
    ::: 
    {% endmarkdown %}
    </body>
</html>

I get that image will be surrounded by tag p

<html>
<head>
</head>
<body>
    <h1>My First Heading</h1>
    <p>My first paragraph.</p>
    <div class="htmlblock">
        <p>
             <img src="img.png" alt="img">
      </p>
    </div>
</body>
</html>

Is this normal or I did something wrong? Is there a method to avoid this behavior?

Thanks a lot.

How can I customize the rendering of content inside block?

I'm trying to make a markdown-it tabs plugin.

::: tabs SOME_ID

# tab1 title
tab1 content

---

#tab2 title
tab2 **content**

:::

How can I control the rendering of the content inside the custom block?

I want the output as:

<div class="md-tabs" id="SOME_ID">
  <ul>
    <li><a href="#SOME_ID_tab1-title">tab1 title</a></li>
    <li><a href="#SOME_ID_tab2-title">tab2 title</a></li>
  </ul>

  <div class="tab" id="SOME_ID_tab1-title">
    <h1>tab1 title</h1>
    <div class="tab-content">
      <p>tab 1 content</p>
    </div>
  </div>
  <div class="tab" id="SOME_ID_tab2-title">
    <h1>tab2 title</h1>
    <div class="tab-content">
      <p>tab 2 <strong>content</strong></p>
    </div>
  </div>
  
</div>

Incorrect parsing of one-line container

I want to use containers as file format descriptors. Since containers can't be nested as of now, I use empty container as separator of larger parts of the document, in a format like this
::: meta :::

::: type
type
:::

::: tags
tag1
tag2
:::

::: end_meta :::

However, if container uses only one line, it's end container token generated only after next ::: on separate line (for the above format - after container_type_close).

{
"type":"container_meta_open",
"tag":"div",
"attrs":null,
"map":[
2,
6
],
"nesting":1,
"level":0,
"children":null,
"content":"",
"markup":":::",
"info":" meta",
"meta":null,
"block":true,
"hidden":false
},
{
"type":"container_type_open",
"tag":"div",
"attrs":null,
"map":[
4,
6
],
"nesting":1,
"level":1,
"children":null,
"content":"",
"markup":":::",
"info":" slugs",
"meta":null,
"block":true,
"hidden":false
},
...
...
...
{
"type":"container_type_close",
"tag":"div",
"attrs":null,
"map":null,
"nesting":-1,
"level":1,
"children":null,
"content":"",
"markup":"",
"info":"",
"meta":null,
"block":true,
"hidden":false
},
{
"type":"container_meta_close",
"tag":"div",
"attrs":null,
"map":null,
"nesting":-1,
"level":0,
"children":null,
"content":"",
"markup":":::",
"info":"",
"meta":null,
"block":true,
"hidden":false
},

Can you fix that?

Why elements inside are paragraphed?

This is my custom container:

md.use(MarkdownItContainer, '', {
  render(tokens, idx) {
    return (tokens[idx].nesting === 1) ? '<pre><samp>\n' : '</samp></pre>\n'
  },
  marker: '´',
})

I know the name is empty, it's intended. Because i'm using a custom and unique marker, it won't collide with other containers and i think i don't need a name. If i'm wrong please tell me.

With this code:

´´´
[Parsed_cropdetect_0 @ 000000000268d400] x1:0 x2:719 y1:74 y2:501 w:720 h:416 x:0 y:80 pts:1814400 t:20.160000 crop=720:416:0:80

[Parsed_cropdetect_0 @ 000000000268d400] x1:0 x2:719 y1:74 y2:501 w:720 h:416 x:0 y:80 pts:1814400 t:20.160000 crop=720:416:0:80
´´´

It kinda works, but i'm getting this result:

<pre><samp>
<p>[Parsed_cropdetect_0 @ 000000000268d400] x1:0 x2:719 y1:74 y2:501 w:720 h:416 x:0 y:80 pts:1814400 t:20.160000 crop=720:416:0:80</p>
<p>[Parsed_cropdetect_0 @ 000000000268d400] x1:0 x2:719 y1:74 y2:501 w:720 h:416 x:0 y:80 pts:1814400 t:20.160000 crop=720:416:0:80</p>
</samp></pre>

Why the

wrapping ?

Init for multiple similar containers

Is there a clever way to "repeat" this code for multiple similar containers, so I can create "note", "warning" and "important" asides?

(Currently it works only for "note"). Yes, I understand that I can simply copy and paste all this code block for "warning" and "important" containers (so it will be 30 lines of code instead of current 10), but I think there should be more compact form... Any help is appreciated.

.use(markdownitContainer, 'note', {
	render: function (tokens, idx) {
		var m = tokens[idx].info.trim().match(/^aside\s+(.*)$/);
		if (tokens[idx].nesting === 1) {
			return '<aside class="' + tokens[idx].info.trim() + '">\n';
		} else {
			return '</aside>\n';
		}
	}
})

// ::: note        <aside class="note">
// Text       =>   <p>Text</p>
// :::             </aside>

How to use in browser

How to use this in browser instead using require module. I try this but doesn't seem to work

var container = window.markdownitContainer;
md.use(container);

Add option to omit content output

I was trying to use markdown-it-container for get block content and render myself with some transformations, and I could append it to "opening tag" return, but the content is still rendering on output.

Aside "validate", "render" and "marker", it could have option to omit output (eg.: "output: false").

It give more options to dev, to do thigs like I described above.

Multiline complex container?

Hello, I've looked through the documentation, and I'm having a hard time figuring out how to do what I need. I think part of the problem is that the example only works when the markdown is all on a singleline, but the other example is on multilines:

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

Basically, with the following:

::: warning
## Beware!
*here be dragons*
_seriously, there are._
:::

I'd like to render out the following HTML:

<div class="warning">
  <div class="left-col"><h2>Beware!</h2></div>
  <div class="middle"><em>here be dragons</em></div>
  <div class="right"><em>seriously, there are.</em></div>
</div>

Allowing arbitrary container names (i.e., not specified in advance)?

If I write Markdown, I’d love to be able to use any CSS class I like – without the parser having to know about it in advance.

If someone needs more control, they can use method .validate().

Use cases:

  • Creating colored boxes in text.
  • Using Markdown for slides (where fenced divs can set up various layouts).

With html: true, HTML escaping differ from embedded HTML escaping

Hi.

I'm not sure if this is a bug, but this behaviour surprised me.

There are some reproduction steps:

$ cat repro.js
#!/usr/bin/env node
require('fs').readFile(process.argv[2], 'utf8', function (err, input) {
  var md = require('markdown-it')({html: true})
    .use(require('markdown-it-container'), 'container');
  process.stdout.write(md.render(input));
});

$ cat test.md
<div class="embedded-html">
A: "
</div>
<div class="embedded-html">
B: \"
</div>
<div class="embedded-html">
C: \\"
</div>

::: container
A: "
:::
::: container
B: \"
:::
::: container
C: \\"
:::

$ ./repro.js test.md
<div class="embedded-html">
A: "
</div>
<div class="embedded-html">
B: \"
</div>
<div class="embedded-html">
C: \\"
</div>
<div class="container">
<p>A: &quot;</p>
</div>
<div class="container">
<p>B: &quot;</p>
</div>
<div class="container">
<p>C: \&quot;</p>
</div>

It looks like when markdown-it html: true parameter is used, divs generated by markdown-it-container HTML escape their content one more time than div s "simply" embedded as HTML code.

Do you think markdown-it-container could avoid this extra-escaping ? Maybe by detecting if html: true is set ?

How to write multiple container

here's a stupid question, how do you add multiple container

var md = require('markdown-it')();
var container = require('markdown-it-container');
md.use(container, 'spoiler', {})
md.use(container,'spoiler2', {})

Is this how to do it?

Incompatibility with markdown-it-attrs

With markdown-it-attrs, a paragraph element is styled like so:

# some heading

This is a paragraph {.some-class-name}
<h1>some heading</h1>
<p class="some-class-name">This is a paragraph</p>

However, in a container, the attribute is swallowed or not applied:

::: my-container
# some heading

This is a paragraph {.some-class-name}
:::
<div class="my-container">
  <h1>some heading</h1>
  <p>This is a paragraph</p>
</div>

Strangely, other methods of using markdown-it-attrs works fine, eg, spans:

::: my-container
This is a paragraph [this is a span]{.some-class-name}
:::
<div class="my-container">
  <p>This is a paragraph <span class="some-class-name">this is a span</span></p>
</div>

How to nest with the same marker?

Hi, this example given in #25 doesn't work because the markers are the same. Only left-col is placed inside the warning div.

::: warning
:::: left-col
::::
:::: middle
::::
:::: right
::::
:::

Results in:

<div class="warning">
    <div class="left-col"></div>
</div>
<div class="middle"></div>
<div class="right"></div>
<p>:::</p>

Is the only correct way to do this by giving left-col, midlde and right different markers? This makes for very messy markdown.

An rendering bug when using <p> tag.

My options is like this:

md.use(...cssHelpersPlugin(md))

/* cssHelpersPlugin's source code: */

const RE = /^(tip|warning|danger)$/

export default md => ([
  containerPlugiin,
  'css-helper',
  {
    validate (params) {
      console.log(params)
      return params.trim().match(RE)
    },

    render(tokens, idx) {
      const [, helperType] = tokens[idx].info.trim().match(RE) || []
      if (tokens[idx].nesting === 1) {
        return `<p class="${helperType}">\n` // opening tag
      }
      return '</p>\n' // closing tag
    }
  }
])

Whose render result will be:

<p class="warning"></p>
<p><em>here be dragons</em></p>
<p></p>

The expected result should be like this instead.

<p class="warning">
     <em>here be dragons</em>
<p>

Nesting of different containers

First of all, I really like this extension and use it in combination with marp for creating (my) lecture slides.

Here is my question:
Is there a possibility to allow the nesting of different containers or can this extension be extended to enable that?

As an example, I want to create something like the following:

::: 2-columns
::: left-column
...content
:::
::: right-column
...content
:::
:::

The sweet spot here is that multi-columns can be implemented in markdown slides using the flexbox-module where the "2-columns"-div is the parent container and "left-" and "right-column" its flexbox items.

Container inside code blocks

Hi,

Is there a way to use a container inside a code block? I'm hoping to use it for some example code combined with a markdown condition - e.g.:

```js
::: handlebars {{#if selfHostedDocs}}
// Do 1
::: handlebars {{else}}
// Do 2
::: handlebars {{/if}}
```

I know I could put the container outside the code block, but it then goes on to to other code stuff that isn't conditional, so this would simplify things.

Many thanks!

The same, but for <span>?

I find this plugin very useful – I plan to use it to layout Markdown-based slides.

How could one achieve the same functionality, but for <span>?

Specify different open close markers?

Is it possible currently to specify different open/close markers? I have a specific use case that may not be worth the bother but I welcome your thoughts:

I have a book in markdown that is consumed by Leanpub and converted to eBook by their parser. I want to re-use the same markdown to generate a free HTML version of the book. Part of the 'custom' syntax Leanpub has is the ability to write an info box like this:

I> Here is an info box

And that creates an info box of that text until the next new line in the outputted eBook.

I'd like to use this plugin to achieve the same kind of thing but in HTML. For example, given the above in markdown, I'd like to generate this in HTML:

<aside class="info">Here is an info box</aside>

Is it possible to set a marker for the beginning of the container as I> and an end as a newline \n - even if as regex (rather than just change the character used for the three character marker e.g. :::)?

Thanks again and appreciate this is probably a very specific request/question :)

Hints at how to fork for inline and custom labels needed.

Hi,
I'm trying to make pretty sidenotes. To get by with just CSS I need something like the following behaviour (I just invented some markup):

  • not just a [^1] as an indicator for a sidenote, but a section of the text (like a link has link-text)
  • the actual sidenote inline
My text has [pretty *sidenotes*](^pretty_sidenote) inline.

[^pretty_sidenote]: 
  # I am a big sidenote

parsing to:

<p>
  My text has <span class="sidenote_text">pretty <b>sidenotes</b><div class="sidenote">
    <h1>I am a big sidenote</h1>
  </div> inline.
</p>

Now my troubles:

  • This plugin relies heavily on character positions at the beginning of the [^...] tag, I don't know how to add the second argument ("link"-text)
  • I'm not sure when the actual markdown parsing happens where
  • I could live without markdown in the "link-text"

I'm actually close to attempting to hack together some [insert_sidenote_open_tag] and search+replace it with html and than do the sidenote via js :/
Or use the bigfoot.js and try to adapt it to permanently visible sidenotes.

Here some dirty working sidenotes I made (with some other markdown parser): http://malea.lacerta.uberspace.de/quickup/testi/

They don't support markdown though and they have to be written inline...

Thanks for the help and the library itself!

Nested containers don't work

Hello,

The nested containers seem to not work 😞

::: header

# My company

::: address
@street1

@street2

@zipCode @city

@country
:::

::: contact
Phone number: @phone1 @phone2

E-mail: @email
:::

:::

It displays ::: after E-mail: @email and header container doesn't contain address, contact containers.

Thanks

Adding multiple classes

I am referring to #23 in requesting if it is possible to add a toggle that enables/disables multiple classes as the generated div name. I already checked the source code, but I think it would be better not to make each user customize the code, but rather providing standard options and toggles. In my case, I lack the knowledge to directly manipulate the JavaScript of this extension.

E.g.

::: yellow box
### Hello
:::
<div class='yellow box'>
<h4>Hello</h4>
</div>

Nested elements not working

Hi,
I cannot render nested elements correctly.

For instance in this md code

:::slide

:::slide
## Resources

:::

:::

the last ::: is not rendered as a closing tag.

Is it possible to nest elements?

plugin not functioning

I am using @noraesae/pen so I can see the markdown-it rendered in a browser window. I added 3 plugins to the system: markdown-it-footnotes, markdown-it-attrs, and markdown-it-container. The first two work fine but the container one does not work at all. I added the required line .use(require('markdown-it-container'), 'div') as the others are working it seems like it should work but does not for some reason.
Also how do I specify a different markup character? Like this .use(require('markdown-it-container'), 'div', '~'). Your example is more complex and does not help me.
It may not be a container problem but seems to be since the others work.
Installed markdown-it plugins that come preinstalled with pen are: anchor, checkbox, emoji, highlightjs maybe there is a conflict with one of these but that seems unlikely.

Any thoughts?

Ian

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.