├── .gitignore
├── README.md
├── UNLICENSE
├── index.js
├── package.json
└── test
└── all.js
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | npm-debug.log
3 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Markdown-it Named Headers
2 |
3 | A plugin for [markdown-it](https://github.com/markdown-it/markdown-it). Makes header elments have identifer attributes.
4 |
5 | ```
6 | # Example Header -->
7 | ```
8 |
9 | By default, it uses [string.js](http://stringjs.com/)'s [slugify](http://stringjs.com/#methods/slugify) to translate header text into a url safe name. You can override this. See _Options_.
10 |
11 | Cribbed heavily from https://github.com/valeriangalliat/markdown-it-anchor
12 |
13 | ## Install
14 |
15 | ```
16 | npm install --save-dev markdown-it-named-headers
17 | ```
18 |
19 | ## Usage
20 |
21 | Use with plain old node:
22 |
23 | ```js
24 | var md = require('markdown-it'),
25 | mdnh = require('markdown-it-named-headers');
26 |
27 | md.use(mdnh, options);
28 | ```
29 |
30 | Use as part of a Gulp workflow: (Note: You don't need to require named-headers in your gulpfile. gulp-markdown-it takes care of that for you).
31 |
32 | ```js
33 | var gulp = require('gulp'),
34 | md = require('gulp-markdown-it');
35 | gulp.task('md', [], function() {
36 | return gulp.src( '**/*.md' )
37 | .pipe(md({
38 | plugins: ['markdown-it-named-headers']
39 | }))
40 | .pipe(gulp.dest('dist'));
41 | });
42 | ```
43 |
44 |
45 | ### Options
46 |
47 |
48 | #### Slugify
49 |
50 | ```js
51 | {
52 | slugify: my_slug_function
53 | }
54 | ```
55 |
56 | If string.js's slugify doesn't fit your needs, you can simply pass in your own slugify function. Basically, the API is: accept any string, return a string suitable for a name attribute. Example:
57 |
58 | ```js
59 | function slugify(input_string) {
60 | var output_string = my_transform_logic(input_string);
61 | return output_string;
62 | }
63 | ```
64 |
65 | Since we use IDs, we should avoid duplicating them. A second parameter is passed. It is an empty object that will persist across a single call to render. In other words, you can use it to maintain a hash of used_headers per page.
66 |
67 | The default slugify method looks something like this:
68 |
69 | ```js
70 | function slugify(input_string, used_headers) {
71 | var slug = string(input_string).slugify().toString();
72 | if( used_headers[slug] ) {
73 | used_headers[slug]++;
74 | slug += used_headers[slug];
75 | } else {
76 | used_headers[slug] += '-' + 1;
77 | }
78 | return slug;
79 | }
80 | ```
81 |
--------------------------------------------------------------------------------
/UNLICENSE:
--------------------------------------------------------------------------------
1 | This is free and unencumbered software released into the public domain.
2 |
3 | Anyone is free to copy, modify, publish, use, compile, sell, or
4 | distribute this software, either in source code form or as a compiled
5 | binary, for any purpose, commercial or non-commercial, and by any
6 | means.
7 |
8 | In jurisdictions that recognize copyright laws, the author or authors
9 | of this software dedicate any and all copyright interest in the
10 | software to the public domain. We make this dedication for the benefit
11 | of the public at large and to the detriment of our heirs and
12 | successors. We intend this dedication to be an overt act of
13 | relinquishment in perpetuity of all present and future rights to this
14 | software under copyright law.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 | OTHER DEALINGS IN THE SOFTWARE.
23 |
24 | For more information, please refer to
25 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | (function(){
2 |
3 | var string = require('string');
4 |
5 | var default_slugify = function(s, used_headers) {
6 | var slug = string(s).slugify().toString();
7 | if( used_headers[slug] ) {
8 | used_headers[slug]++;
9 | slug += used_headers[slug];
10 | } else {
11 | used_headers[slug] += '-' + 1;
12 | }
13 | return slug;
14 | };
15 |
16 | var namedheaders = function(md, opts) {
17 | var slugify = (opts && opts.slugify) ? opts.slugify : default_slugify;
18 | var originalHeadingOpen = md.renderer.rules.heading_open;
19 |
20 | md.renderer.rules.heading_open = function (tokens, idx, something, somethingelse, self) {
21 | var used_headers = {};
22 |
23 | tokens[idx].attrs = tokens[idx].attrs || [];
24 |
25 | var title = tokens[idx + 1].children.reduce(function (acc, t) {
26 | return acc + t.content;
27 | }, '');
28 |
29 | var slug = slugify(title, used_headers);
30 | tokens[idx].attrs.push(['id', slug]);
31 |
32 | if (originalHeadingOpen) {
33 | return originalHeadingOpen.apply(this, arguments);
34 | } else {
35 | return self.renderToken.apply(self, arguments);
36 | }
37 | };
38 | };
39 |
40 | module.exports = namedheaders;
41 |
42 | })();
43 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "markdown-it-named-headers",
3 | "version": "0.0.4",
4 | "description": "Headers have name attributes for markdown-it.",
5 | "keywords": [
6 | "markdown-it-plugin"
7 | ],
8 | "homepage": "https://github.com/leff/markdown-it-named-headers",
9 | "license": {
10 | "type": "Unlicense",
11 | "url": "http://unlicense.org/"
12 | },
13 | "author": {
14 | "name": "Jason Brackins",
15 | "url": ""
16 | },
17 | "files": [
18 | "README.md",
19 | "UNLICENSE",
20 | "index.js"
21 | ],
22 | "repository": {
23 | "type": "git",
24 | "url": "https://github.com/leff/markdown-it-named-headers"
25 | },
26 | "dependencies": {
27 | "string": "^3.0.1"
28 | },
29 | "devDependencies": {
30 | "markdown-it": "^4.0.1",
31 | "mocha": "^2.2.1",
32 | "test": ">=0.0.1"
33 | },
34 | "scripts": {
35 | "test": "node_modules/.bin/mocha test/all.js"
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/test/all.js:
--------------------------------------------------------------------------------
1 | var assert = require('assert'),
2 | MarkdownIt = require('markdown-it'),
3 | md_nh = require('../');
4 |
5 |
6 | describe('MarkdownIt', function() {
7 | describe('#named-headers', function() {
8 | var md = MarkdownIt().use(md_nh);
9 |
10 | describe('#render()', function(){
11 | it('one word headers should have names', function(){
12 | assert.equal( md.render('# test'), 'test
\n');
13 | });
14 |
15 | it('case should be normalized', function(){
16 | assert.equal( md.render('# Test'), 'Test
\n');
17 | });
18 |
19 | it('spaces should be dashes', function(){
20 | assert.equal( md.render('# test string'), 'test string
\n');
21 | });
22 |
23 | it('header levels 1 to 6 should be supported', function(){
24 | assert.equal( md.render('# test'), 'test
\n');
25 | assert.equal( md.render('## test'), 'test
\n');
26 | assert.equal( md.render('### test'), 'test
\n');
27 | assert.equal( md.render('#### test'), 'test
\n');
28 | assert.equal( md.render('##### test'), 'test
\n');
29 | assert.equal( md.render('###### test'), 'test
\n');
30 | });
31 |
32 | it('identical headers should have unique ids', function(){
33 | assert.equal( md.render('# test\n# test'), 'test
\ntest
\n');
34 | assert.equal( md.render('# test\n## test'), 'test
\ntest
\n');
35 | });
36 | });
37 |
38 | });
39 | });
40 |
--------------------------------------------------------------------------------