├── .gitattributes ├── .jshintrc ├── .editorconfig ├── lib ├── anchor.js └── utils.js ├── .gitignore ├── LICENSE ├── .verb.md ├── package.json ├── index.js └── README.md /.gitattributes: -------------------------------------------------------------------------------- 1 | # Enforce Unix newlines 2 | * text eol=lf 3 | 4 | # binaries 5 | *.ai binary 6 | *.psd binary 7 | *.jpg binary 8 | *.gif binary 9 | *.png binary 10 | *.jpeg binary -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "asi": false, 3 | "boss": true, 4 | "curly": true, 5 | "eqeqeq": true, 6 | "eqnull": true, 7 | "esnext": true, 8 | "immed": true, 9 | "latedef": false, 10 | "laxcomma": false, 11 | "mocha": true, 12 | "newcap": true, 13 | "noarg": true, 14 | "node": true, 15 | "sub": true, 16 | "undef": true, 17 | "unused": true 18 | } -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | 12 | [*.md] 13 | trim_trailing_whitespace = false 14 | 15 | [test/fixtures/*] 16 | insert_final_newline = false 17 | trim_trailing_whitespace = false -------------------------------------------------------------------------------- /lib/anchor.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * grunt-assemble-navigation 3 | * 4 | * Copyright (c) 2014-2015, Jon Schlinkert. 5 | * Licensed under the MIT License. 6 | */ 7 | 8 | module.exports = [ 9 | '', 10 | '', 11 | ].join('\n'); 12 | 13 | 14 | // Needs testing 15 | var alt = [ 16 | '', 17 | ' ', 18 | ' ', 19 | '' 20 | ].join('\n'); -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Numerous always-ignore extensions 2 | *.DS_Store 3 | .ruby-version 4 | *.diff 5 | *.err 6 | *.orig 7 | *.log 8 | *.rej 9 | *.swo 10 | *.swp 11 | *.zip 12 | *.vi 13 | *~ 14 | 15 | # OS or Editor folders 16 | *.esproj 17 | *.sublime-project 18 | *.sublime-workspace 19 | ._* 20 | .cache 21 | .DS_Store 22 | .idea 23 | .project 24 | .settings 25 | .tmproj 26 | nbproject 27 | Thumbs.db 28 | 29 | # Komodo 30 | *.komodoproject 31 | .komodotools 32 | 33 | # grunt-html-validation 34 | validation-status.json 35 | validation-report.json 36 | 37 | # Folders to ignore 38 | tmp 39 | temp 40 | TODO.md 41 | docs 42 | vendor 43 | node_modules 44 | bower_components 45 | _gh_pages 46 | _site 47 | _draft 48 | 49 | # Planned 50 | content/blog 51 | content/boilerplates 52 | content/examples 53 | content/tutorials 54 | 55 | build-chain.fw.png -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014-2015, Jon Schlinkert. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /.verb.md: -------------------------------------------------------------------------------- 1 | # {%= name %} {%= badge("fury") %} 2 | 3 | > {%= description %} 4 | 5 | **Here's a preview** 6 | 7 | ![image](https://f.cloud.github.com/assets/383994/2523672/94f62414-b4d4-11e3-98c6-fc3c07bef4b4.png) 8 | 9 | *** 10 | 11 | ## Quickstart 12 | {%= include("install-npm", {save: true}) %} 13 | 14 | ## Usage 15 | Register the middleware with Assemble: 16 | 17 | ```js 18 | options: { 19 | plugins: ['{%= name %}', 'foo/*.js'] 20 | } 21 | ``` 22 | 23 | Visit the [plugins docs](http://assemble.io/plugins/) for more info or for help getting started. 24 | 25 | Add this markup where you want the navigation: 26 | 27 | ```html 28 | 31 | ``` 32 | 33 | The plugin uses page headings to construct the nav items, results in something like: 34 | 35 | ```html 36 | 48 | ``` 49 | 50 | *** 51 | 52 | ## Other grunt-assemble middleware 53 | {%= related(verb.related.list, {remove: name}) %} 54 | 55 | ## Contributing 56 | {%= include("contributing") %} 57 | 58 | ## Authors 59 | {%= include("author") %} 60 | 61 | ## License 62 | {%= copyright() %} 63 | {%= license() %} 64 | 65 | *** 66 | 67 | {%= include("footer") %} 68 | -------------------------------------------------------------------------------- /lib/utils.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * grunt-assemble-navigation 3 | * 4 | * Copyright (c) 2013-2015, Jon Schlinkert. 5 | * Licensed under the MIT License. 6 | */ 7 | 8 | // The following code for slugifying is from underscore.string: 9 | // https://github.com/epeli/underscore.string 10 | var nativeTrim = String.prototype.trim; 11 | 12 | var escapeRegExp = function (str) { 13 | if (str == null) { 14 | return ''; 15 | } 16 | return String(str).replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1'); 17 | }; 18 | 19 | var defaultToWhiteSpace = function (characters) { 20 | if (characters == null) { 21 | return '\\s'; 22 | } else if (characters.source) { 23 | return characters.source; 24 | } else { 25 | return '[' + escapeRegExp(characters) + ']'; 26 | } 27 | }; 28 | 29 | var trim = function (str, characters) { 30 | if (str == null) {return ''; } 31 | if (!characters && nativeTrim) { 32 | return nativeTrim.call(str); 33 | } 34 | characters = defaultToWhiteSpace(characters); 35 | return String(str).replace(new RegExp('^' + characters + '+|' + characters + '+$', 'g'), ''); 36 | }; 37 | var dasherize = function(str){ 38 | return trim(str).replace(/([A-Z])/g, '-$1').replace(/[-_\s]+/g, '-').toLowerCase(); 39 | }; 40 | 41 | 42 | exports.slugify = function (str) { 43 | if (str == null) { 44 | return ''; 45 | } 46 | var from = "ąàáäâãåæăćęèéëêìíïîłńòóöôõøśșțùúüûñçżź"; 47 | var to = "aaaaaaaaaceeeeeiiiilnoooooosstuuuunczz"; 48 | var regex = new RegExp(defaultToWhiteSpace(from), 'g'); 49 | str = String(str).toLowerCase().replace(regex, function (c) { 50 | var index = from.indexOf(c); 51 | return to.charAt(index) || '-'; 52 | }); 53 | return dasherize(str.replace(/[^\w\s-]/g, '')); 54 | }; -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "grunt-assemble-navigation", 3 | "description": "Assemble navigation plugin. Automatically generate Bootstrap-style, multi-level side nav. See the sidenav on assemble.io for a demonstration.", 4 | "version": "0.1.0", 5 | "homepage": "https://github.com/assemble/grunt-assemble-navigation", 6 | "author": "Jon Schlinkert (http://github.com/jonschlinkert)", 7 | "repository": { 8 | "type": "git", 9 | "url": "git://github.com/assemble/grunt-assemble-navigation.git" 10 | }, 11 | "bugs": { 12 | "url": "https://github.com/assemble/grunt-assemble-navigation/issues" 13 | }, 14 | "license": { 15 | "type": "MIT", 16 | "url": "https://github.com/assemble/grunt-assemble-navigation/blob/master/LICENSE" 17 | }, 18 | "files": [ 19 | "index.js", 20 | "lib/" 21 | ], 22 | "main": "index.js", 23 | "engines": { 24 | "node": ">=0.8" 25 | }, 26 | "dependencies": { 27 | "cheerio": "~0.15.0", 28 | "template": "~0.1.7", 29 | "verbalize": "~0.1.2" 30 | }, 31 | "keywords": [ 32 | "assemble", 33 | "assemblemiddleware", 34 | "assembleplugin", 35 | "middleware", 36 | "nav", 37 | "navigation", 38 | "side", 39 | "side-nav", 40 | "sidenav" 41 | ], 42 | "verb": { 43 | "related": { 44 | "list": [ 45 | "grunt-assemble", 46 | "grunt-assemble-anchors", 47 | "grunt-assemble-contextual", 48 | "grunt-assemble-decompress", 49 | "grunt-assemble-download", 50 | "grunt-assemble-i18n", 51 | "grunt-assemble-lunr", 52 | "grunt-assemble-navigation", 53 | "grunt-assemble-permalinks", 54 | "grunt-assemble-sitemap", 55 | "grunt-assemble-toc", 56 | "grunt-assemble-wordcount" 57 | ] 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * grunt-assemble-navigation 3 | * Thanks to @lukeapage for making this awesome! 4 | * 5 | * Copyright (c) 2014-2015, Jon Schlinkert. 6 | * Licensed under the MIT License. 7 | */ 8 | 9 | var options = { 10 | stage: 'render:post:page' 11 | }; 12 | 13 | var path = require('path'); 14 | var template = require('template'); 15 | var cheerio = require('cheerio'); 16 | var log = require('verbalize'); 17 | 18 | 19 | /** 20 | * Anchor Plugin 21 | * @param {Object} params 22 | * @param {Function} callback 23 | */ 24 | module.exports = function (params, callback) { 25 | 'use strict'; 26 | 27 | // load current page content 28 | var $ = cheerio.load(params.content); 29 | 30 | var anchorOpts = params.assemble.options.anchors || {}; 31 | var navOpts = params.assemble.options.navigation || {}; 32 | 33 | // get all the anchor tags from inside the headers 34 | var headings = $('h1[id],h2[id]'); 35 | var navigation = []; 36 | var duplicateChecker = {}; 37 | var dupesFound = false; 38 | 39 | function findLocation(navigation, depth) { 40 | if (depth === 1) { 41 | return navigation; 42 | } 43 | var loc = navigation[navigation.length - 1]; 44 | if (!loc) { 45 | loc = { 46 | children: [] 47 | }; 48 | navigation.push(loc); 49 | } else if (!loc.children) { 50 | loc.children = []; 51 | } 52 | return findLocation(loc.children, depth - 1); 53 | } 54 | 55 | headings.map(function (i, e) { 56 | var $e = $(e); 57 | var text = $e.text().trim(); 58 | var link = $e.attr('id'); 59 | var node = { 60 | text: text, 61 | link: link, 62 | $e: $e 63 | }; 64 | var level = parseInt(e.name.replace(/h/gi, ''), 10); 65 | var depth = level <= 1 ? 1 : 2; 66 | var location = findLocation(navigation, depth); 67 | location.push(node); 68 | }); 69 | 70 | /** 71 | * Build the HTML for side navigation. 72 | * @param {[type]} navigation [description] 73 | * @param {[type]} first [description] 74 | * @param {[type]} sParentLink [description] 75 | * @return {[type]} [description] 76 | */ 77 | 78 | function buildHTML(navigation, first, sParentLink) { 79 | return ''; 93 | } 94 | 95 | // if (dupesFound) { 96 | // throw new Error("Stopping, duplicates found."); 97 | // } 98 | 99 | $(navOpts.id || '#navigation').append(buildHTML(navigation, true)); 100 | 101 | // 102 | var anchorTemplate = require('./lib/anchor.js'); 103 | 104 | // If an anchor template is specified in the options, use that instead. 105 | if(anchorOpts && anchorOpts.template) { 106 | anchorOpts.template = path.resolve(anchorOpts.template); 107 | anchorTemplate = require(anchorOpts.template); 108 | } 109 | 110 | headings.map(function (i, e) { 111 | var $e = $(e); 112 | var id = $e.attr('id'); 113 | 114 | // Anchor template 115 | var anchor = template(anchorTemplate, {id: id}); 116 | $(this).append(anchor); 117 | 118 | // Adjust heading 119 | $(this).removeAttr('id').addClass('docs-heading'); 120 | 121 | if($(this).prev().children().hasClass('source-link')) { 122 | var sourceLink = $(this).prev().children('.source-link'); 123 | $(this).append(sourceLink); 124 | } 125 | }); 126 | 127 | params.content = $.html(); 128 | callback(); 129 | }; 130 | 131 | module.exports.options = options; 132 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # grunt-assemble-navigation [![NPM version](https://badge.fury.io/js/grunt-assemble-navigation.svg)](http://badge.fury.io/js/grunt-assemble-navigation) 2 | 3 | > Assemble navigation plugin. Automatically generate Bootstrap-style, multi-level side nav. See the sidenav on assemble.io for a demonstration. 4 | 5 | **Here's a preview** 6 | 7 | ![image](https://f.cloud.github.com/assets/383994/2523672/94f62414-b4d4-11e3-98c6-fc3c07bef4b4.png) 8 | 9 | *** 10 | 11 | ## Quickstart 12 | 13 | Install with [npm](https://www.npmjs.com/) 14 | 15 | ```sh 16 | $ npm i grunt-assemble-navigation --save 17 | ``` 18 | 19 | ## Usage 20 | 21 | Register the middleware with Assemble: 22 | 23 | ```js 24 | options: { 25 | plugins: ['grunt-assemble-navigation', 'foo/*.js'] 26 | } 27 | ``` 28 | 29 | Visit the [plugins docs](http://assemble.io/plugins/) for more info or for help getting started. 30 | 31 | Add this markup where you want the navigation: 32 | 33 | ```html 34 | 37 | ``` 38 | 39 | The plugin uses page headings to construct the nav items, results in something like: 40 | 41 | ```html 42 | 54 | ``` 55 | 56 | *** 57 | 58 | ## Other grunt-assemble middleware 59 | 60 | * [grunt-assemble](https://www.npmjs.com/package/grunt-assemble): Static site generator for Grunt.js, Yeoman and Node.js. Used by Zurb Foundation, Zurb Ink, H5BP/Effeckt,… [more](https://www.npmjs.com/package/grunt-assemble) | [homepage](http://assemble.io) 61 | * [grunt-assemble-anchors](https://www.npmjs.com/package/grunt-assemble-anchors): Assemble plugin for creating anchor tags from headings in generated html using Cheerio.js. | [homepage](https://github.com/assemble/grunt-assemble-anchors) 62 | * [grunt-assemble-contextual](https://www.npmjs.com/package/grunt-assemble-contextual): Generates a JSON file with the context of each page. Basic plugin to help see… [more](https://www.npmjs.com/package/grunt-assemble-contextual) | [homepage](https://github.com/assemble/grunt-assemble-contextual) 63 | * [grunt-assemble-decompress](https://www.npmjs.com/package/grunt-assemble-decompress): Assemble plugin for extracting zip, tar and tar.gz archives. | [homepage](https://github.com/assemble/grunt-assemble-decompress) 64 | * [grunt-assemble-download](https://www.npmjs.com/package/grunt-assemble-download): Assemble plugin for downloading files from GitHub. | [homepage](https://github.com/assemble/grunt-assemble-download) 65 | * [grunt-assemble-i18n](https://www.npmjs.com/package/grunt-assemble-i18n): Plugin for adding i18n support to Assemble projects. | [homepage](https://github.com/assemble/grunt-assemble-i18n) 66 | * [grunt-assemble-lunr](https://www.npmjs.com/package/grunt-assemble-lunr): Assemble plugin for adding search capabilities to your static site, with lunr.js. | [homepage](http://assemble.io) 67 | * [grunt-assemble-permalinks](https://www.npmjs.com/package/grunt-assemble-permalinks): Permalinks plugin for Assemble, the static site generator for Grunt.js, Yeoman and Node.js. This plugin… [more](https://www.npmjs.com/package/grunt-assemble-permalinks) | [homepage](https://github.com/assemble/grunt-assemble-permalinks) 68 | * [grunt-assemble-sitemap](https://www.npmjs.com/package/grunt-assemble-sitemap): Sitemap plugin for Assemble | [homepage](http://assemble.io/plugins) 69 | * [grunt-assemble-toc](https://www.npmjs.com/package/grunt-assemble-toc): Assemble middleware for adding a Table of Contents (TOC) to any HTML page. | [homepage](http://assemble.io) 70 | * [grunt-assemble-wordcount](https://www.npmjs.com/package/grunt-assemble-wordcount): Assemble plugin for displaying wordcount and average reading time to blog posts or pages. | [homepage](https://github.com/assemble/grunt-assemble-wordcount) 71 | 72 | ## Contributing 73 | 74 | Pull requests and stars are always welcome. For bugs and feature requests, [please create an issue](https://github.com/assemble/grunt-assemble-navigation/issues/new). 75 | 76 | ## Authors 77 | 78 | **Jon Schlinkert** 79 | 80 | + [github/jonschlinkert](https://github.com/jonschlinkert) 81 | + [twitter/jonschlinkert](http://twitter.com/jonschlinkert) 82 | 83 | ## License 84 | 85 | Copyright © 2015 Jon Schlinkert 86 | Released under the MIT license. 87 | 88 | *** 89 | 90 | _This file was generated by [verb-cli](https://github.com/assemble/verb-cli) on September 25, 2015._ --------------------------------------------------------------------------------