Giter VIP home page Giter VIP logo

markdown-it-anchor's Issues

Allow custom anchor attributes

It would be nice to be able to control what attributes are set on the anchor.

For example I'd like to set an aria-label so screenreader users get a useful name instead of whatever unicode symbol/icon is inside the anchor. This is kind of related to #58.

Rather than continually adding new options for each possible attribute could we support passing a permalinkAttrs object as an option? E.g.

const md = require('markdown-it')()
  .use(require('markdown-it-anchor'), {
    permalinkAttrs: { 'aria-label': 'heading permalink' }
  })

I think this would be relatively simple to implement:

  const linkTokens = [
    Object.assign(new state.Token('link_open', 'a', 1), {
      attrs: [
        ['class', opts.permalinkClass],
        ['href', opts.permalinkHref(slug, state)],
+       ...Object.entries(opts.permalinkAttrs)
      ]
    }),
    Object.assign(new state.Token('html_block', '', 0), { content: opts.permalinkSymbol }),
    new state.Token('link_close', 'a', -1)
  ]

Lambda function breaks minifying

Hi there,

I successfully use markdown-it-anchor until I try to make a production build using Webpack, along with UglifyJS plugin.

ERROR in dashboard.js from UglifyJs
Unexpected token: operator (>) [dashboard.js:98703,19]

I think I've identified what breaks minifying: the use of lambda functions (() => {})

Shouldn't this package be available as a 100% ES5 version ?

TypeError: token.attrGet is not a function

   "TypeError: token.attrGet is not a function",
    "    at /home1/user/61916c91a4e81be8/node_modules/markdown-it-anchor/index.js:79:24",
    "    at Array.forEach (native)",
    "    at Array.<anonymous> (/home1/user/61916c91a4e81be8/node_modules/markdown-it-anchor/index.js:71:8)",
    "    at Core.process (/home1/user/61916c91a4e81be8/node_modules/markdown-it/lib/parser_core.js:51:13)",
    "    at MarkdownIt.parse (/home1/user/61916c91a4e81be8/node_modules/markdown-it/lib/index.js:493:13)",
    "    at MarkdownIt.render (/home1/user/61916c91a4e81be8/node_modules/markdown-it/lib/index.js:513:36)",
    "    at decorate (/home1/user/61916c91a4e81be8/node_modules/aglio-theme-olio/lib/main.js:422:44)",
    "    at Object.exports.render (/home1/user/61916c91a4e81be8/node_modules/aglio-theme-olio/lib/main.js:646:5)",
    "    at /home1/user/61916c91a4e81be8/node_modules/aglio/lib/main.js:133:20"

The following works fine. I seem to have installed v2.5.0 some time ago.

This new version fails.

Please add enough test to verify the changes, and if some of them are breaking, always increment the major version, not the minor.

Opened a corresponding issue for aglio-theme-olio so that they always use the exact version at danielgtaylor/aglio#319.

BUG: Table of contents does not support markdown

Scenario

Given I have the following markdown string:

[[toc]]

# Introduction to American Novels
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod 
tempor incididunt ut labore.

## Literary Analysis of _Catcher in the Rye_ 
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod 
tempor incididunt ut labore.

## Understanding Race in *Huckleberry Finn*
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod 
tempor incididunt ut labore.

This will render the following table of contents:

  <div class="table-of-contents">
    <ul>
      <li>
        <a href="#introduction-to-american-novels">Introduction to American Novels</a>
        <ul>
          <li><a href="#literary-analysis-of-catcher-in-the-rye">Literary Analysis of _Catcher in the Rye_</a></li>
          <li><a href="#understanding-race-in-huckleberry-finn">Understanding Race in *Huckleberry Finn*</a></li>
        </ul>
      </li>
    </ul>
  </div>

  <h1 id="introduction-to-american-novels">Introduction to American Novels</h1>
  <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
    tempor incididunt ut labore.
  </p>
  
  <h2 id="literary-analysis-of-catcher-in-the-rye">Literary Analysis of <em>Catcher in the Rye</em></h2>
  <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
    tempor incididunt ut labore.
  </p>
  
  <h2 id="understanding-race-in-huckleberry-finn">Understanding Race in <em>Huckleberry Finn</em></h2>
  <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
    tempor incididunt ut labore.
  </p>

Problem

Notice that the ToC headers contain raw / unprocessed markdown (e.g. Literary Analysis of _Catcher in the Rye_) whereas the actual headers have converted the markdown into HTML (e.g. Literary Analysis of <em>Catcher in the Rye</em>).

I would expect to see the markdown be converted into HTML in both locations.

Next steps

Looking at your code, I think the md object may have access to the underlying rendering functions. For example, I wrote a markdown-it extension which did something like:

this.env.md.renderInline("Some text which _may have formatting_")

And this allowed me to process markdown text within my extension – which I think is what we want in this case as well.

I'm not 100% sure how this would work in your code, but I think it's possible (and probably pretty easy). If you need help, lemme know and could probably make a PR.

Doesn't work with markdown-it-toc

If I use markdown-it-toc after, your plugin just do nothing.
And if I use it before, your plugin add anchor, but something seems broken

<h2>
  <a id="Installation_3"></a>
  <a class="markdownIt-Header-anchor" href="#installation">#</a>
  Installation
</h2>

Any idea how to get anchor links + toc ?

My options

markdownIt({
html: true,
  linkify: true,
  typographer: true,
  highlight: (code, lang) => {
    code = code.trim()
    // language is recognized by highlight.js
    if (lang && hljs.getLanguage(lang)) {
      return hljs.highlight(lang, code).value
    }
    // fallback to auto
    return hljs.highlightAuto(code).value
  })
        .use(markdownItToc)
        .use(markdownItAnchor, {
          permalink: true,
          permalinkClass: "markdownIt-Header-anchor",
          permalinkSymbol: "#",
          permalinkBefore: true,
        })

TypeError: plugin.apply is not a function

...\node_modules\markdown-it\lib\index.js:477
  plugin.apply(plugin, args);
         ^

TypeError: plugin.apply is not a function

Seems like the babel upgrade uses exports.default, which node does not load as a function:

$ npm install markdown-it-anchor
$ node
> require("markdown-it-anchor")
{ default:
   { [Function: anchor]
     defaults:
      { level: 1,
        slugify: [Function: slugify],
        permalink: false,
        renderPermalink: [Function: renderPermalink],
        permalinkClass: 'header-anchor',
        permalinkSymbol: '',
        permalinkBefore: false } } }

Which breaks md.use(require('markdown-it-anchor')).

How about add ES Modules support?

Build failed when integrated with React:

Creating an optimized production build...
Failed to compile.

Failed to minify the code from this file:

 	./node_modules/markdown-it-anchor/index.js:1

Read more here: http://bit.ly/2tRViJ9

How to add prefix to id?

In your documentation you mentioned that by using slugify we can create custo id but it uses jquery.
SO I wonder is there any way to add custom prefix to Id?

Headers with special characters between words should be converted to "-"

Bug report

When creating headers with special characters between words, is it expected that the special character will be changed to "-"

Steps to reproduce

Create duplicated Headers (same name) inside a markdown file

# header & header

What is expected?

The anchor link for the header should be:

#header--header

What is actually happening?

It is generating the following anchor links:

#header-header

2.5.1 and newer are not tagged, no release notes exist

I’ve just found that 3.0.0 is out, however, I can’t find any reference to any changes, and I can’t seem to glean from the commit history exactly what’s changed. 2.5.1 and up are also missing from tags, so I can’t tell what changed between them either.

Is 3.0.0 really a major API change?

TypeError: plugin.apply is not a function with v5.2.3

Running into "TypeError: plugin.apply is not a function" with version 5.2.3.

TypeError: plugin.apply is not a function
    at MarkdownIt.push../node_modules/markdown-it/lib/index.js.MarkdownIt.use (vendors.._src_components_pages_blog__year__month__day__post.._src_components_pages_index.js:13325)
    at _callee$ (._src_components_pages_blog__year__month__day__post.js:553)
    at tryCatch (commons.app.js:6771)
    at Generator.invoke [as _invoke] (commons.app.js:6997)
    at Generator.prototype.<computed> [as next] (commons.app.js:6823)
    at asyncGeneratorStep (vendors.app.js:31)
    at _next (vendors.app.js:53)
    at vendors.app.js:60
    at new Promise (<anonymous>)
    at vendors.app.js:49

Reproducible using this repo.

2.7.0 not working for strange reason

Hello, I have your package as dependency of aglio-theme-olio,

When I try to gulp build, I have a strange error:

/build/proj/api/node_modules/markdown-it-anchor/index.js:79
      var slug = token.attrGet('id');
                       ^

TypeError: token.attrGet is not a function
    at /build/proj/api/node_modules/markdown-it-anchor/index.js:79:24
    at Array.forEach (native)
    at Array.<anonymous> (/build/proj/api/node_modules/markdown-it-anchor/index.js:71:8)
    at Core.process (/build/proj/api/node_modules/markdown-it/lib/parser_core.js:51:13)
    at MarkdownIt.parse (/build/proj/api/node_modules/markdown-it/lib/index.js:493:13)
    at MarkdownIt.render (/build/proj/api/node_modules/markdown-it/lib/index.js:513:36)
    at decorate (/build/proj/api/node_modules/aglio-theme-olio/lib/main.js:404:32)
    at Object.exports.render (/build/proj/api/node_modules/aglio-theme-olio/lib/main.js:646:5)
    at /build/proj/api/node_modules/aglio/lib/main.js:133:20

If I force install 2.6.0 version - all works ok.

Repeated problem with anchor

version: v5.0.1
device:macbook pro
description:
Using the markdown-it-anchor plugin and tui-editor combined, using react, when publishing the edited content, it is found that each release adds an anchor.

tui.Editor.markdownit.use(
    mdAnchor,
    {
        level: [1, 2, 3, 4, 5, 6],
        permalink: true,
        permalinkSymbol: '#',
        slugify: s => slug(s)
    }
);

As shown in the figure below, multiple anchors will be generated, but I only need one.

Z7nlMd.png

I found the problem is that when you execute renderPermalink , you will continue to add anchors. So, is there any good solution?

Specifying a base URL in a Nuxt app breaks the links

Hello,

After doing something like this in nuxt.config.js:

router: {
    base: process.env.NODE_ENV === 'production'
      ? '/zeta/'
      : '/'
  }

All header anchors break and direct the user to the root of the app.
Is there anything I can configure so it works as it should?

Live article that exhibits the behaviour:
https://lobotuerto.com/zeta/blog/vuejs-components-inside-markdown

Try clicking on anything on the TOC, or the § links besides the headers in the main content.

Add callback option

I'm interested in generating data for a table of contents and would like to make use of this plugin if possible. Ideally, I could provide a callback that was called with the heading level (or the token itself), the title, and the slug. This would be enough to generate a table of contents using the id attributes added by this plugin.

I could use the existing slugify option to gather titles, but the return value may not be used as the id (given the call to uniqueSlug), and knowing the heading level would make for a nicer table of contents.

I could also use the existing renderPermalink option, but that would require repeating a lot of what this plugin does to get the same permalink rendering (plus I'd have to redo the title generation).

Would you be in favor of adding support for a callback(token, slug, title) option (or the second arg could be info with slug and title properties)?

Reverse level

Doesn't level works as opposite as its supposed to?

For example, i want to give an id attribute to my main headers, h1, h2 and h3, but i can't use the level attribute to control that. How i'm supposed to exclude the h4 ones? It should work the opposite :/

level: 3 <- minimum header level of 3 to apply the functionality.

But right now that's just adding the attributes to h3-h6 tags, which is... weird.

Duplicated Headers generates wrong anchor links (incremented by 1)

Bug report

When creating duplicated headers, is it expected that the duplicated anchor links will increase starting from "xxxx-1".
It starts from "xxxx-2".

Steps to reproduce

Create duplicated Headers (same name) inside a markdown file

# header

# header

# header

What is expected?

The anchor link for each header should be:

#header
#header-1
#header-2

What is actually happening?

It is generating the following anchor links:

#header
#header-2
#header-3

permalinkAttrs is not working

I'm tring to add custom attribute to the anchor link but it is not working. This is the code I'm using:

import markdownIt from 'markdown-it';
import markdownItAnchor from 'markdown-it-anchor';

const md = new markdownIt().use(markdownItAnchor, {
  permalinkAttrs: () => ({ "aria-hidden":  false })
});

I've cloned this repository and when I run the tests with yarn test it returns an error.

`id`'s for Paragraphs Too?

Question

Have you considered allowing id's to be applied to paragraphs---not just headings?

Problem

  • For a lot of my blog posts/writing (especially short passages of text), I don't use headings.
  • In those situations, it would be nice to permalink to a specific area of my post/writing, rather than just link to the entire post itself.

Suggestions

You could implement it in a similar way as you do for headings.

  • You could leverage slugify in the same way
  • Have it take up to the first five words and create a string from that
    • If the paragraph has less than five words, just create an id with as many words as the paragraph has
      • If the paragraph has only four words, make the id with those four words
    • If a paragraph has more than five words, take the first five words and create a id from that
    • If two paragraphs have the same first five words, add a sixth word, and so on

Example

Consider the following Markdown source:

# Heading <!-- What `markdown-it-anchor` does already -->

This is a paragraph. <!-- Four words only -->

This is yet another paragraph. <!-- Five words -->

This is yet another paragraph that has more than five words. <!-- More than five words, and the first five are the same as the above example paragraph -->

This could be parsed to the following:

<h1 id="heading">Heading</h1> <!-- Expected default/current behavior -->

<p id="this-is-a-paragraph">This is a paragraph.</p> <!-- Since the Markdown source is a paragraph with only four words, those four words are incorporated into the `id` -->

<p id="this-is-yet-another-paragraph">This is yet another paragraph.</p> <!-- Five words, so the `id` gets those exact five words -->

<p id="this-is-yet-another-paragraph-that">This is yet another paragraph that has more than five words.</p> <!-- The Markdown source has more than five words, so the first five would be incorporated into the `id`. But since the previous paragraph would have that same `id`, `markdown-it-anchor` should add a sixth word. If another `id` with that string exists already, add another word (so the `id` would have seven words), etc. -->

Dave Winer made this concept famous: WinerLinks (there's even a WordPress plugin)!

But I know markdown-it-anchor could have a more intelligent approach than the WordPress plugin.

I'd like to know your thoughts :)

How to work in Angular

Hi,
Is it possible to work in Angular?
I did this below:
import * as MarkdownAnchor from 'markdown-it-anchor';
But it doesn't work when running.

Bigfoot.js Footnotes Broken

Bigfoot.js is a JavaScript tool used to render footnote popups in lieu of regular-style 'bounce-around-the-page' footnotes.

I am using Casey Liss's node-based blogging engine Camel, and have found that when viewing the source for a rendered page, the footnote placeholders become <undefined> in the HTML.

Here is a snippet parsed HTML showing the <undefined> element, in the place of where a footnote identifier/class should be.

<li id="fn10"  class="footnote-item"><undefined>And the pictures in the article only show the flappy box <a href="#fnref10" class="footnote-backref"></a><undefined></li>

Ideas?

plugin.apply is not a function

I'm using markdown-it v10.0.0 and markdown-it-anchor v5.2.7. My code is

const md = require('markdown-it')({ linkify: true, xhtmlOut: true,  typographer: true });
md.use(require('markdown-it-anchor'), { permalink: true, permalinkBefore: true, permalinkSymbol: '§' })

the error is: Uncaught TypeError: plugin.apply is not a function. And the error still exist when the options { permalink: true, permalinkBefore: true, permalinkSymbol: '§' } is removed.

Does someone know what the problem is?

Anchor links only working in chrome

For some reason, the anchor links are only working properly in chrome. When I test in Firefox or Safari, the page is scrolled to the top.

TypeError: plugin.apply is not a function with v5.2.4

Running into "TypeError: plugin.apply is not a function" with version 5.2.4.

./node_modules/markdown-it/lib/index.js.MarkdownIt.use
./node_modules/markdown-it/lib/index.js:496
  493 |  **/
  494 | MarkdownIt.prototype.use = function (plugin /*, params, ... */) {
  495 |   var args = [ this ].concat(Array.prototype.slice.call(arguments, 1));
> 496 |   plugin.apply(plugin, args);
  497 |   return this;
  498 | };
  499 | 

TypeError: require(...).use is not a function

I use it as the README.md said, but got such errors:

const md = require('markdown-it').use(require('markdown-it-anchor'))({
                                  ^

TypeError: require(...).use is not a function
    at Object.<anonymous> (D:\workspace\mobi.css\gulpfile.js:15:35)
    at Module._compile (module.js:571:32)
    at Object.Module._extensions..js (module.js:580:10)
    at Module.load (module.js:488:32)
    at tryModuleLoad (module.js:447:12)
    at Function.Module._load (module.js:439:3)
    at Module.require (module.js:498:17)
    at require (internal/module.js:20:19)
    at Liftoff.handleArguments (D:\workspace\mobi.css\node_modules\gulp\bin\gulp.js:116:3)
    at Liftoff.<anonymous> (D:\workspace\mobi.css\node_modules\liftoff\index.js:198:16)

I think the README.md should update to something like this:

const md = require('markdown-it')()
  .use(require('markdown-it-anchor'), opts)

GitHub inspired permalink rendering

If possible, could we get permalinks to render just like GitHub does for Readme's?

e.g. the hover and the entire header is a link itself?

Possible feature? target anchor rather than header id

It turns out that the best way to handle a fixed top toolbar for anchors (ie creating a top offset to avoid scrolling to a position under the toolbar), is to use a target anchor rather than a header id for the target.

So I've forked markdown-it-anchor to accommodate that. Thought you might be interested.

Basically: I've modified the processing logic as follows:

        if (slug == null) {
          slug = uniqueSlug(opts.slugify(title), slugs)
          token.attrPush(['class',opts.headerClassName])
          token.attrPush(['style','position:relative;padding-left:16px;margin-left:-16px;'])

          if (opts.useTargetlink) {

            opts.renderTargetlink(slug, opts, state, tokens.indexOf(token),title,token.tag)

          } else {

            token.attrPush(['id', slug])

          }
        }

        if (opts.permalink) {
          opts.renderPermalink(slug, opts, state, tokens.indexOf(token))
        }

some new options:

let defaults = {
  level: 1,
  slugify,
  permalink: false,
  renderPermalink,
  permalinkClass: 'header-anchor',
  permalinkSymbol: '¶',
  permalinkBefore: false,
  permalinkHref,
 // new...
  useTargetlink:false,
  renderTargetlink,
  targetlinkClass: 'target-anchor',
  headerClassName:'content-header',
}

To create the renderTargetLink I just copied and modified your renderPermalink.

Congrats on a well-written utility! It was very straightforward to fork and extend it.

Just thought you might be interested in case you want to accommodate this use case in your excellent plugin.

Option to remove aria-hidden from output

I believe that adding aria-hidden is incorrect for these links. These links should be accessible and would be useful to screen reader users too!

Notably this throws an error when using the axe-core accessibility linting tool.

Violation of "aria-hidden-focus" with 6 occurrences!
Ensures aria-hidden elements do not contain focusable elements. Correct invalid elements at:

The options to fix here are to remove aria-hidden (thus, this issue) or to set tabindex="-1" on the link, which wouldn’t be right either. I want these links to be focusable.

Thank you!

Error thrown when headers below level are present

When rendering a document with headers that are below the specified level, an error is thrown. The below example illustrates the problem.

If the # Title declaration is removed, the error is no longer thrown. So it appears that headers below the specified level cause this error.

markdownIt = require('markdown-it')

content = """
# Title

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.

## Sub Title

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.

### Sub Sub Title

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
"""

rendered = markdownIt()
  .use require('markdown-it-anchor'), level: 2, permalink: true
  .render(content)

console.log rendered

Create package

Would be great to see this available packaged up on bower, preferably precompiled to ES5.

Edit: I just saw it's on npm, this only leaves bower then.

Nested anchor slugs

Is there an option to use nesting when generating slugs? ie:

# Tacos

## Beef

# Burritos

## Beef

resulting in:

<h1 id="tacos">Tacos</h1>
<h2 id="taco-beef"Beef</h2>
<h1 id="burritos">Burritos</h1>
<h2 id="burritos-beef"Beef</h2>

TypeError: linkTokens[position[(!opts.permalinkBefore)]](...) is not a function

I've added this plugin to my rollup build (by npm) and I get the following error when enabling the permlinks:

TypeError: linkTokens[position[(!opts.permalinkBefore)]](...) is not a function

This happens in line https://github.com/valeriangalliat/markdown-it-anchor/blob/master/index.js#L33

The rollup output of those lines are:

linkTokens[position[!opts.permalinkBefore]](space())
(ref = state.tokens[idx + 1].children)[position[opts.permalinkBefore]].apply(ref, linkTokens);

a simple semicolon after the first line would solve this issue:

linkTokens[position[!opts.permalinkBefore]](space());

not support Chinese language

.md
## [# 添加权限](#ss)
result
<h2><a href="#ss"># 添加权限</a></h2>

.md
## [# 添加权限role](#ss)
result
<h2 id="role-2"><a href="#ss"># 添加权限role</a></h2>

is there a way to solve?

Add anchor after heading text

Right now, the anchor is always added before the heading text:

<!-- Currently -->
<h1><a href="...">P</a>I am a header</h1>

<!-- What I would like to see -->
<h1>I am a header<a href="...">P</a></h1>

This makes is easy to hide the anchor until mouse over and doesn't require shifting headings outside of their container to keep alignment on the left side (for LTR text). Ultimately it should probably just be an option.

Is this something you'd be willing to add? Otherwise I think this plugin is great!

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.