├── .gitattributes
├── .travis.yml
├── .editorconfig
├── .gitignore
├── test
├── fixtures
│ ├── bar.md
│ ├── baz.md
│ ├── fez.md
│ ├── foo.md
│ ├── qux.md
│ └── zzz.md
└── test.js
├── LICENSE
├── lib
└── helpers.js
├── package.json
├── index.js
├── .github
└── contributing.md
├── .eslintrc.json
├── .verb.md
└── 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
11 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | sudo: false
2 | os:
3 | - linux
4 | - osx
5 | language: node_js
6 | node_js:
7 | - node
8 | - '6'
9 | - '4'
10 | matrix:
11 | allow_failures:
12 | - node_js: '4'
13 | - node_js: '0.12'
14 | - node_js: '0.10'
15 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | indent_style = space
5 | end_of_line = lf
6 | charset = utf-8
7 | indent_size = 2
8 | trim_trailing_whitespace = true
9 | insert_final_newline = true
10 |
11 | [{**/{actual,fixtures,expected,templates}/**,*.md}]
12 | trim_trailing_whitespace = false
13 | insert_final_newline = false
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # always ignore files
2 | *.DS_Store
3 | *.sublime-*
4 |
5 | # test related, or directories generated by tests
6 | test/actual
7 | actual
8 | coverage
9 | .nyc*
10 |
11 | # npm
12 | node_modules
13 | npm-debug.log
14 |
15 | # yarn
16 | yarn.lock
17 | yarn-error.log
18 |
19 | # misc
20 | _gh_pages
21 | _draft
22 | _drafts
23 | bower_components
24 | vendor
25 | temp
26 | tmp
27 | TODO.md
28 |
--------------------------------------------------------------------------------
/test/fixtures/bar.md:
--------------------------------------------------------------------------------
1 | {{#pager}}
2 |
3 | Prev
4 | Next
5 | {{/pager}}
6 |
7 |
8 | Prev
9 | Next
10 |
11 |
12 | Prev
13 | Next
14 |
15 |
16 | {{> prev }}
17 | {{> next }}
18 |
19 |
20 |
21 | {{> pager }}
22 |
23 |
--------------------------------------------------------------------------------
/test/fixtures/baz.md:
--------------------------------------------------------------------------------
1 | {{#pager}}
2 |
3 | Prev
4 | Next
5 | {{/pager}}
6 |
7 |
8 | Prev
9 | Next
10 |
11 |
12 | Prev
13 | Next
14 |
15 |
16 | {{> prev }}
17 | {{> next }}
18 |
19 |
20 |
21 | {{> pager }}
22 |
23 |
--------------------------------------------------------------------------------
/test/fixtures/fez.md:
--------------------------------------------------------------------------------
1 | {{#pager}}
2 |
3 | Prev
4 | Next
5 | {{/pager}}
6 |
7 |
8 | Prev
9 | Next
10 |
11 |
12 | Prev
13 | Next
14 |
15 |
16 | {{> prev }}
17 | {{> next }}
18 |
19 |
20 |
21 | {{> pager }}
22 |
23 |
--------------------------------------------------------------------------------
/test/fixtures/foo.md:
--------------------------------------------------------------------------------
1 | {{#pager}}
2 |
3 | Prev
4 | Next
5 | {{/pager}}
6 |
7 |
8 | Prev
9 | Next
10 |
11 |
12 | Prev
13 | Next
14 |
15 |
16 | {{> prev }}
17 | {{> next }}
18 |
19 |
20 |
21 | {{> pager }}
22 |
23 |
--------------------------------------------------------------------------------
/test/fixtures/qux.md:
--------------------------------------------------------------------------------
1 | {{#pager}}
2 |
3 | Prev
4 | Next
5 | {{/pager}}
6 |
7 |
8 | Prev
9 | Next
10 |
11 |
12 | Prev
13 | Next
14 |
15 |
16 | {{> prev }}
17 | {{> next }}
18 |
19 |
20 |
21 | {{> pager }}
22 |
23 |
--------------------------------------------------------------------------------
/test/fixtures/zzz.md:
--------------------------------------------------------------------------------
1 | {{#pager}}
2 |
3 | Prev
4 | Next
5 | {{/pager}}
6 |
7 |
8 | Prev
9 | Next
10 |
11 |
12 | Prev
13 | Next
14 |
15 |
16 | {{> prev }}
17 | {{> next }}
18 |
19 |
20 |
21 | {{> pager }}
22 |
23 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2017 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 all
13 | 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 THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/lib/helpers.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var relative = require('relative');
4 | var helpers = module.exports;
5 |
6 | function relativePath(from, to) {
7 | return relative(from.data.path, to.data.path);
8 | }
9 |
10 | /**
11 | * Stringify attributes on the options `hash`.
12 | *
13 | * @param {Object} `options`
14 | * @return {String}
15 | * @api public
16 | */
17 |
18 | helpers.attr = function(options) {
19 | return ' ' + Object.keys(options.hash).map(function(key) {
20 | return key + '="' + options.hash[key] + '"';
21 | }).join(' ');
22 | };
23 |
24 | helpers.relative = function(from, to) {
25 | return relativePath(from, to);
26 | };
27 |
28 | helpers.ifFirst = function(pager, str) {
29 | if (!pager.isPager) {
30 | return this.context.pager.isFirst ? pager : '';
31 | }
32 | return pager.isFirst ? str : '';
33 | };
34 |
35 | helpers.ifLast = function(pager, str) {
36 | if (!pager.isPager) {
37 | return this.context.pager.isLast ? pager : '';
38 | }
39 | return pager.isLast ? str : '';
40 | };
41 |
42 | helpers.next = function(pager) {
43 | // if defined as `{{next}}` inside a `{{#pager}}` block
44 | if (!pager.isPager) pager = this.context.pager;
45 | // or, if defined as `{{next pager}}`
46 | return pager.next ? relativePath(pager.current, pager.next) : '#';
47 | };
48 |
49 | helpers.prev = function(pager) {
50 | // if defined as `{{prev}}` inside a `{{#pager}}` block
51 | if (!pager.isPager) pager = this.context.pager;
52 | // or, if defined as `{{prev pager}}`
53 | return pager.prev ? relativePath(pager.current, pager.prev) : '#';
54 | };
55 |
56 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "assemble-pager",
3 | "description": "Assemble plugin that adds prev/next pager information to the context.",
4 | "version": "0.1.2",
5 | "homepage": "https://github.com/assemble/assemble-pager",
6 | "author": "Jon Schlinkert (https://github.com/jonschlinkert)",
7 | "repository": "assemble/assemble-pager",
8 | "bugs": {
9 | "url": "https://github.com/assemble/assemble-pager/issues"
10 | },
11 | "license": "MIT",
12 | "files": [
13 | "index.js",
14 | "lib"
15 | ],
16 | "main": "index.js",
17 | "engines": {
18 | "node": ">=4"
19 | },
20 | "scripts": {
21 | "test": "mocha"
22 | },
23 | "dependencies": {
24 | "extend-shallow": "^2.0.1",
25 | "is-valid-app": "^0.2.1",
26 | "plugin-error": "^0.1.2",
27 | "relative": "^3.0.2",
28 | "through2": "^2.0.3"
29 | },
30 | "devDependencies": {
31 | "assemble": "^0.22.0",
32 | "assemble-fs": "^1.0.0",
33 | "gulp-format-md": "^0.1.11",
34 | "mocha": "^3.2.0"
35 | },
36 | "keywords": [
37 | "assemble",
38 | "assembleplugin",
39 | "boilerplate",
40 | "build",
41 | "cli",
42 | "cli-app",
43 | "command-line",
44 | "create",
45 | "dev",
46 | "development",
47 | "framework",
48 | "front",
49 | "frontend",
50 | "pager",
51 | "paginate",
52 | "pagination",
53 | "paging",
54 | "plugin",
55 | "project",
56 | "projects",
57 | "scaffold",
58 | "scaffolder",
59 | "scaffolding",
60 | "template",
61 | "templates",
62 | "webapp",
63 | "yeoman",
64 | "yo"
65 | ],
66 | "verb": {
67 | "toc": true,
68 | "layout": "default",
69 | "tasks": [
70 | "readme"
71 | ],
72 | "plugins": [
73 | "gulp-format-md"
74 | ],
75 | "lint": {
76 | "reflinks": true
77 | }
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var isValid = require('is-valid-app');
4 | var extend = require('extend-shallow');
5 | var PluginError = require('plugin-error');
6 | var through = require('through2');
7 |
8 | /**
9 | * Add `prev`/`next` paging information to the context for files
10 | * in the current stream.
11 | *
12 | * @name plugin
13 | * @param {Object} [options]
14 | * @param {String|Array} [options.sortBy]
15 | * @return {Stream} Returns a [vinyl][] stream
16 | * @api public
17 | */
18 |
19 | module.exports = function(config) {
20 | return function(app) {
21 | if (!isValid(app, 'assemble-pager')) return;
22 |
23 | /**
24 | * Add `prev`/`next` paging information to the context for files
25 | * in the current stream.
26 | *
27 | * @name .pager
28 | * @param {Object} [options]
29 | * @param {String|Array} [options.sortBy]
30 | * @return {Stream} Returns a [vinyl][] stream
31 | * @api public
32 | */
33 |
34 | app.define('pager', function(options) {
35 | var opts = extend({}, config, options);
36 | var list = new app.List({pager: true});
37 |
38 | return through.obj(function(file, enc, next) {
39 | if (file.isNull()) {
40 | next(null, file);
41 | return;
42 | }
43 |
44 | if (!file.isView) {
45 | next(new PluginError('assemble-pager', 'expected an assemble view', {showStack: true}));
46 | return;
47 | }
48 |
49 | if (file.data.pager === false) {
50 | next(null, file);
51 | return;
52 | }
53 |
54 | if (opts.collection && file.options.collection !== opts.collection) {
55 | next(null, file);
56 | return;
57 | }
58 |
59 | list.addItem(file);
60 | next();
61 | }, function(cb) {
62 | if (opts.sortBy) {
63 | list = list.sortBy(opts.sortBy);
64 | }
65 |
66 | for (var i = 0; i < list.items.length; i++) {
67 | this.push(list.items[i]);
68 | }
69 | cb();
70 | });
71 | });
72 | };
73 | };
74 |
75 | /**
76 | * Expose helpers
77 | */
78 |
79 | module.exports.helpers = require('./lib/helpers');
80 |
--------------------------------------------------------------------------------
/test/test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | require('mocha');
4 | var utils = require('assemble-fs/utils');
5 | var assemble = require('assemble');
6 | var assert = require('assert');
7 | var pager = require('..');
8 | var app;
9 |
10 | var partials = {
11 | prev: `Prev`,
12 | next: `\nNext`,
13 | pager: '{{> prev }}\n{{> next }}'
14 | };
15 |
16 | describe('assemble-pager', function() {
17 | beforeEach(function() {
18 | app = assemble();
19 | app.use(pager());
20 | app.partials(partials);
21 |
22 | app.onLoad(/\.(md|hbs)$/, function(view, next) {
23 | view.extname = '.html';
24 | next();
25 | });
26 | });
27 |
28 | it('should load helpers', function() {
29 | app.helpers(pager.helpers);
30 | assert(app._.helpers.sync.relative);
31 | assert(app._.helpers.sync.next);
32 | assert(app._.helpers.sync.prev);
33 | assert(app._.helpers.sync.ifFirst);
34 | assert(app._.helpers.sync.ifLast);
35 | });
36 |
37 | it('should render pager info for each item in a collection', function(cb) {
38 | app = assemble();
39 | app.use(pager());
40 | app.partials(partials);
41 | app.helpers(pager.helpers);
42 |
43 | utils.prepareDest(app, 'foo', {});
44 |
45 | app.onLoad(/\.(md|hbs)$/, function(view, next) {
46 | view.extname = '.html';
47 | next();
48 | });
49 |
50 | var files = [];
51 |
52 | var stream = app.src('fixtures/*.md', {cwd: __dirname})
53 | .pipe(app.pager())
54 | .pipe(app.renderFile())
55 | .on('data', function(file) {
56 | assert(file.data.pager);
57 | assert.equal(typeof file.data.pager.index, 'number');
58 | files.push(file);
59 | })
60 | .on('end', function() {
61 | files.forEach(function(file, i) {
62 | assert.equal(file.data.pager.index, i);
63 | assert.equal(file.data.pager.current, file);
64 | assert.equal(file.data.pager.prev, files[i - 1]);
65 | assert.equal(file.data.pager.next, files[i + 1]);
66 | assert.equal(file.data.pager.first, files[0]);
67 | assert.equal(file.data.pager.last, files[files.length - 1]);
68 |
69 | switch (i) {
70 | case 0:
71 |
72 | assert(file.data.pager.isFirst);
73 | assert(!file.data.pager.isLast);
74 | break;
75 | case (files.length - 1):
76 |
77 | assert(file.data.pager.isLast);
78 | assert(!file.data.pager.isFist);
79 | break;
80 | default: {
81 |
82 | assert(!file.data.pager.isLast);
83 | assert(!file.data.pager.isFist);
84 | break;
85 | }
86 | }
87 | });
88 |
89 | cb();
90 | });
91 |
92 | });
93 | });
94 |
--------------------------------------------------------------------------------
/.github/contributing.md:
--------------------------------------------------------------------------------
1 | # Contributing to assemble-pager
2 |
3 | First and foremost, thank you! We appreciate that you want to contribute to assemble-pager, your time is valuable, and your contributions mean a lot to us.
4 |
5 | **What does "contributing" mean?**
6 |
7 | Creating an issue is the simplest form of contributing to a project. But there are many ways to contribute, including the following:
8 |
9 | - Updating or correcting documentation
10 | - Feature requests
11 | - Bug reports
12 |
13 | If you'd like to learn more about contributing in general, the [Guide to Idiomatic Contributing](https://github.com/jonschlinkert/idiomatic-contributing) has a lot of useful information.
14 |
15 | **Showing support for assemble-pager**
16 |
17 | Please keep in mind that open source software is built by people like you, who spend their free time creating things the rest the community can use.
18 |
19 | Don't have time to contribute? No worries, here are some other ways to show your support for assemble-pager:
20 |
21 | - star the [project](https://github.com/jonschlinkert/assemble-pager)
22 | - tweet your support for assemble-pager
23 |
24 | ## Issues
25 |
26 | ### Before creating an issue
27 |
28 | Please try to determine if the issue is caused by an underlying library, and if so, create the issue there. Sometimes this is difficult to know. We only ask that you attempt to give a reasonable attempt to find out. Oftentimes the readme will have advice about where to go to create issues.
29 |
30 | Try to follow these guidelines
31 |
32 | - **Investigate the issue**:
33 | - **Check the readme** - oftentimes you will find notes about creating issues, and where to go depending on the type of issue.
34 | - Create the issue in the appropriate repository.
35 |
36 | ### Creating an issue
37 |
38 | Please be as descriptive as possible when creating an issue. Give us the information we need to successfully answer your question or address your issue by answering the following in your issue:
39 |
40 | - **version**: please note the version of assemble-pager are you using
41 | - **extensions, plugins, helpers, etc** (if applicable): please list any extensions you're using
42 | - **error messages**: please paste any error messages into the issue, or a [gist](https://gist.github.com/)
43 |
44 | ## Above and beyond
45 |
46 | Here are some tips for creating idiomatic issues. Taking just a little bit extra time will make your issue easier to read, easier to resolve, more likely to be found by others who have the same or similar issue in the future.
47 |
48 | - read the [Guide to Idiomatic Contributing](https://github.com/jonschlinkert/idiomatic-contributing)
49 | - take some time to learn basic markdown. This [markdown cheatsheet](https://gist.github.com/jonschlinkert/5854601) is super helpful, as is the GitHub guide to [basic markdown](https://help.github.com/articles/markdown-basics/).
50 | - Learn about [GitHub Flavored Markdown](https://help.github.com/articles/github-flavored-markdown/). And if you want to really go above and beyond, read [mastering markdown](https://guides.github.com/features/mastering-markdown/).
51 | - use backticks to wrap code. This ensures that code will retain its format, making it much more readable to others
52 | - use syntax highlighting by adding the correct language name after the first "code fence"
53 |
54 |
55 | [node-glob]: https://github.com/isaacs/node-glob
56 | [micromatch]: https://github.com/jonschlinkert/micromatch
57 | [so]: http://stackoverflow.com/questions/tagged/assemble-pager
--------------------------------------------------------------------------------
/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "ecmaFeatures": {
3 | "modules": true,
4 | "experimentalObjectRestSpread": true
5 | },
6 |
7 | "env": {
8 | "browser": false,
9 | "es6": true,
10 | "node": true,
11 | "mocha": true
12 | },
13 |
14 | "globals": {
15 | "document": false,
16 | "navigator": false,
17 | "window": false
18 | },
19 |
20 | "rules": {
21 | "accessor-pairs": 2,
22 | "arrow-spacing": [2, { "before": true, "after": true }],
23 | "block-spacing": [2, "always"],
24 | "brace-style": [2, "1tbs", { "allowSingleLine": true }],
25 | "comma-dangle": [2, "never"],
26 | "comma-spacing": [2, { "before": false, "after": true }],
27 | "comma-style": [2, "last"],
28 | "constructor-super": 2,
29 | "curly": [2, "multi-line"],
30 | "dot-location": [2, "property"],
31 | "eol-last": 2,
32 | "eqeqeq": [2, "allow-null"],
33 | "generator-star-spacing": [2, { "before": true, "after": true }],
34 | "handle-callback-err": [2, "^(err|error)$" ],
35 | "indent": [2, 2, { "SwitchCase": 1 }],
36 | "key-spacing": [2, { "beforeColon": false, "afterColon": true }],
37 | "keyword-spacing": [2, { "before": true, "after": true }],
38 | "new-cap": [2, { "newIsCap": true, "capIsNew": false }],
39 | "new-parens": 2,
40 | "no-array-constructor": 2,
41 | "no-caller": 2,
42 | "no-class-assign": 2,
43 | "no-cond-assign": 2,
44 | "no-const-assign": 2,
45 | "no-control-regex": 2,
46 | "no-debugger": 2,
47 | "no-delete-var": 2,
48 | "no-dupe-args": 2,
49 | "no-dupe-class-members": 2,
50 | "no-dupe-keys": 2,
51 | "no-duplicate-case": 2,
52 | "no-empty-character-class": 2,
53 | "no-eval": 2,
54 | "no-ex-assign": 2,
55 | "no-extend-native": 2,
56 | "no-extra-bind": 2,
57 | "no-extra-boolean-cast": 2,
58 | "no-extra-parens": [2, "functions"],
59 | "no-fallthrough": 2,
60 | "no-floating-decimal": 2,
61 | "no-func-assign": 2,
62 | "no-implied-eval": 2,
63 | "no-inner-declarations": [2, "functions"],
64 | "no-invalid-regexp": 2,
65 | "no-irregular-whitespace": 2,
66 | "no-iterator": 2,
67 | "no-label-var": 2,
68 | "no-labels": 2,
69 | "no-lone-blocks": 2,
70 | "no-mixed-spaces-and-tabs": 2,
71 | "no-multi-spaces": 2,
72 | "no-multi-str": 2,
73 | "no-multiple-empty-lines": [2, { "max": 1 }],
74 | "no-native-reassign": 0,
75 | "no-negated-in-lhs": 2,
76 | "no-new": 2,
77 | "no-new-func": 2,
78 | "no-new-object": 2,
79 | "no-new-require": 2,
80 | "no-new-wrappers": 2,
81 | "no-obj-calls": 2,
82 | "no-octal": 2,
83 | "no-octal-escape": 2,
84 | "no-proto": 0,
85 | "no-redeclare": 2,
86 | "no-regex-spaces": 2,
87 | "no-return-assign": 2,
88 | "no-self-compare": 2,
89 | "no-sequences": 2,
90 | "no-shadow-restricted-names": 2,
91 | "no-spaced-func": 2,
92 | "no-sparse-arrays": 2,
93 | "no-this-before-super": 2,
94 | "no-throw-literal": 2,
95 | "no-trailing-spaces": 0,
96 | "no-undef": 2,
97 | "no-undef-init": 2,
98 | "no-unexpected-multiline": 2,
99 | "no-unneeded-ternary": [2, { "defaultAssignment": false }],
100 | "no-unreachable": 2,
101 | "no-unused-vars": [2, { "vars": "all", "args": "none" }],
102 | "no-useless-call": 0,
103 | "no-with": 2,
104 | "one-var": [0, { "initialized": "never" }],
105 | "operator-linebreak": [0, "after", { "overrides": { "?": "before", ":": "before" } }],
106 | "padded-blocks": [0, "never"],
107 | "quotes": [2, "single", "avoid-escape"],
108 | "radix": 2,
109 | "semi": [2, "always"],
110 | "semi-spacing": [2, { "before": false, "after": true }],
111 | "space-before-blocks": [2, "always"],
112 | "space-before-function-paren": [2, "never"],
113 | "space-in-parens": [2, "never"],
114 | "space-infix-ops": 2,
115 | "space-unary-ops": [2, { "words": true, "nonwords": false }],
116 | "spaced-comment": [0, "always", { "markers": ["global", "globals", "eslint", "eslint-disable", "*package", "!", ","] }],
117 | "use-isnan": 2,
118 | "valid-typeof": 2,
119 | "wrap-iife": [2, "any"],
120 | "yoda": [2, "never"]
121 | }
122 | }
123 |
--------------------------------------------------------------------------------
/.verb.md:
--------------------------------------------------------------------------------
1 | Adds data to the context to enable creating pagers that work like this:
2 |
3 | 
4 |
5 |
6 | ## Usage
7 |
8 | ```js
9 | var assemble = require('assemble');
10 | var pager = require('{%= name %}');
11 | var app = assemble();
12 |
13 | // register the plugin
14 | app.use(pager());
15 |
16 | app.task('site', function() {
17 | return app.src('src/*.md')
18 | .pipe(app.pager()) // then add "app.pager()" before "app.renderFile()"
19 | .pipe(app.renderFile())
20 | .pipe(app.dest('blog'));
21 | });
22 | ```
23 |
24 |
25 | When `app.pager()` is called, it adds the `pager` variable to the context so that it's available to all views in the collection being rendered.
26 |
27 |
28 | ## Specify a collection
29 |
30 | ```js
31 | // only add paging to the "posts" collection
32 | .pipe(app.pager({collection: 'posts'}))
33 | ```
34 |
35 |
36 | ## Excluding files
37 |
38 | If you don't [specify a collection](#specify-a-collection), all files in the stream will be buffered and included. However, you can selectively exclude files by setting `file.data.pager` to `false`, either in another plugin, middleware, or by defining it on yaml front-matter.
39 |
40 | **Examples**
41 |
42 | ```js
43 | // plugin, defined before `app.pager()`
44 | .pipe(through.obj(function(file, enc, next) {
45 | file.data.pager = false;
46 | next(null, file);
47 | }))
48 |
49 | // middleware
50 | app.onLoad(/\.foo$/, function(file, next) {
51 | file.data.pager = false;
52 | next();
53 | });
54 | ```
55 |
56 | Or yaml front-matter
57 |
58 | ```handlebars
59 | ---
60 | pager: false
61 | ---
62 |
63 | This is a page that should be skipped by `app.pager()`
64 | ```
65 |
66 |
67 | ## Template usage
68 |
69 | The `pager` variable is an object with the following properties:
70 |
71 | - `pager.prev` **{Object}** - the previous view that was rendered. This is an actual view, so you can get any data you need from it (like `pager.prev.path` or `pager.prev.data.title`, etc)
72 | - `pager.next` **{Object}** - the next view to be rendered. This is an actual view, so you can get any data you need from it (like `pager.next.path` or `pager.next.data.title`, etc)
73 | - `pager.current` **{Object}** - the view that is currently being rendered
74 | - `pager.first` **{Object}** - Returns the first file in the list
75 | - `pager.last` **{Object}** - Returns the last file in the list
76 | - `pager.isFirst` **{Boolean}** - returns true if the "current" file is the first to be rendered
77 | - `pager.isLast` **{Boolean}** - returns true if the "current" file is the last to be rendered
78 | - `pager.index` **{Number}** - the list index of the current file being rendered
79 |
80 | ### Helpers
81 |
82 | Some helpers are included with this plugin. To use them, do the following:
83 |
84 | ```js
85 | var pager = require('assemble-pager');
86 | app.helpers(pager.helpers);
87 | ```
88 |
89 | Which adds the following helpers:
90 |
91 | - `relative`- calculates the relative path from file `A` to file `B` (e.g. "current" file to next or previous file)
92 | - `ifFirst`- returns true if the current file being rendered is the first file
93 | - `ifLast`- returns true if the current file being rendered is the last file
94 | - `next`- used in `href=""`, returns either the relative path to the "next" file, or `#` if the current file being rendered is the last file
95 | - `prev`- used in `href=""`, returns either the relative path to the "previous" file, or `#` if the current file being rendered is the first file
96 | - `attr`- stringify the options hash arguments to HTML attributes. For example, you can use this to conditionally add a class for a disabled next/prev link: `{{ifFirst (attr class="disabled")}}`, or `{{ifLast (attr class="disabled")}}` etc.
97 |
98 |
99 | **Overriding helpers**
100 |
101 | Helpers are exposed as an object so that you can choose to register them if you want, and/or override them if necessary:
102 |
103 | For example, this is how the included "relative" helper works:
104 |
105 | ```js
106 | var relative = require('relative');
107 |
108 | app.helper('relative', function(from, to) {
109 | return relative(from.data.path, to.data.path);
110 | });
111 | ```
112 |
113 | ### Example usage
114 |
115 | Since `pager` is just another variable on the context, you can do anything you normally would with a variable in your handlebars templates.
116 |
117 |
118 | ```handlebars
119 |
121 | Prev
122 | ```
123 |
124 | Or you can create a block:
125 |
126 | ```handlebars
127 | {{#pager}}
128 |
129 | Prev
130 | {{/pager}}
131 | ```
132 |
133 | **Partials**
134 |
135 | To simplify paging even more, you can define partials like the following:
136 |
137 | ```js
138 | app.partial('prev', 'Prev');
139 | app.partial('next', '\nNext');
140 | app.partial('pager', '{{> prev }}\n{{> next }}');
141 | ```
142 |
143 | ### Troubleshooting
144 |
145 | The easiest way to see how this works is to log out the `pager` variables, to see what's on the context. You can use the built-in `log` helper to do this:
146 |
147 | ```handlebars
148 | {{log pager}}
149 | ```
150 |
151 | ## How it works
152 |
153 | This is really all the plugin does, with the addition of error and options handling (a commented version is below). You can copy this and create your own plugin if you need to:
154 |
155 | ```js
156 | function pagerPlugin() {
157 | var list = new app.List({pager: true});
158 | return through.obj(function(file, enc, next) {
159 | list.addItem(file);
160 | next();
161 | }, function(cb) {
162 | for (var i = 0; i < list.items.length; i++) {
163 | this.push(item);
164 | }
165 | cb();
166 | });
167 | }
168 | ```
169 |
170 | With comments:
171 |
172 | ```js
173 | function pagerPlugin() {
174 | // create a new assemble `List`. Lists are like collections,
175 | // but the items are stored as an array, versus an object
176 | var list = new app.List({pager: true});
177 |
178 | return through.obj(function(file, enc, next) {
179 | // add files to the list as they come through the stream
180 | list.addItem(file);
181 |
182 | // don't pass the file through, we'll do
183 | // that in the flush function
184 | next();
185 | }, function(cb) {
186 |
187 | // all of the files have now been buffered onto the
188 | // `list.items` array. We can now loop over that array
189 | // and push the items back into the stream (it's important
190 | // for all the items to be buffered this way so that all
191 | // items are available on the context before anything is
192 | // rendered, or items will be missing)
193 | for (var i = 0; i < list.items.length; i++) {
194 | this.push(item); //<= push the item into the stream
195 | }
196 | cb();
197 | });
198 | }
199 | ```
200 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # assemble-pager [](https://www.npmjs.com/package/assemble-pager) [](https://npmjs.org/package/assemble-pager) [](https://npmjs.org/package/assemble-pager) [](https://travis-ci.org/assemble/assemble-pager)
2 |
3 | > Assemble plugin that adds prev/next pager information to the context.
4 |
5 | ## Table of Contents
6 |
7 | - [Install](#install)
8 | - [Usage](#usage)
9 | - [Specify a collection](#specify-a-collection)
10 | - [Excluding files](#excluding-files)
11 | - [Template usage](#template-usage)
12 | * [Helpers](#helpers)
13 | * [Example usage](#example-usage)
14 | * [Troubleshooting](#troubleshooting)
15 | - [How it works](#how-it-works)
16 | - [About](#about)
17 |
18 | _(TOC generated by [verb](https://github.com/verbose/verb) using [markdown-toc](https://github.com/jonschlinkert/markdown-toc))_
19 |
20 | ## Install
21 |
22 | Install with [npm](https://www.npmjs.com/):
23 |
24 | ```sh
25 | $ npm install --save assemble-pager
26 | ```
27 |
28 | Adds data to the context to enable creating pagers that work like this:
29 |
30 | 
31 |
32 | ## Usage
33 |
34 | ```js
35 | var assemble = require('assemble');
36 | var pager = require('assemble-pager');
37 | var app = assemble();
38 |
39 | // register the plugin
40 | app.use(pager());
41 |
42 | app.task('site', function() {
43 | return app.src('src/*.md')
44 | .pipe(app.pager()) // then add "app.pager()" before "app.renderFile()"
45 | .pipe(app.renderFile())
46 | .pipe(app.dest('blog'));
47 | });
48 | ```
49 |
50 | When `app.pager()` is called, it adds the `pager` variable to the context so that it's available to all views in the collection being rendered.
51 |
52 | ## Specify a collection
53 |
54 | ```js
55 | // only add paging to the "posts" collection
56 | .pipe(app.pager({collection: 'posts'}))
57 | ```
58 |
59 | ## Excluding files
60 |
61 | If you don't [specify a collection](#specify-a-collection), all files in the stream will be buffered and included. However, you can selectively exclude files by setting `file.data.pager` to `false`, either in another plugin, middleware, or by defining it on yaml front-matter.
62 |
63 | **Examples**
64 |
65 | ```js
66 | // plugin, defined before `app.pager()`
67 | .pipe(through.obj(function(file, enc, next) {
68 | file.data.pager = false;
69 | next(null, file);
70 | }))
71 |
72 | // middleware
73 | app.onLoad(/\.foo$/, function(file, next) {
74 | file.data.pager = false;
75 | next();
76 | });
77 | ```
78 |
79 | Or yaml front-matter
80 |
81 | ```handlebars
82 | ---
83 | pager: false
84 | ---
85 |
86 | This is a page that should be skipped by `app.pager()`
87 | ```
88 |
89 | ## Template usage
90 |
91 | The `pager` variable is an object with the following properties:
92 |
93 | * `pager.prev` **{Object}** - the previous view that was rendered. This is an actual view, so you can get any data you need from it (like `pager.prev.path` or `pager.prev.data.title`, etc)
94 | * `pager.next` **{Object}** - the next view to be rendered. This is an actual view, so you can get any data you need from it (like `pager.next.path` or `pager.next.data.title`, etc)
95 | * `pager.current` **{Object}** - the view that is currently being rendered
96 | * `pager.first` **{Object}** - Returns the first file in the list
97 | * `pager.last` **{Object}** - Returns the last file in the list
98 | * `pager.isFirst` **{Boolean}** - returns true if the "current" file is the first to be rendered
99 | * `pager.isLast` **{Boolean}** - returns true if the "current" file is the last to be rendered
100 | * `pager.index` **{Number}** - the list index of the current file being rendered
101 |
102 | ### Helpers
103 |
104 | Some helpers are included with this plugin. To use them, do the following:
105 |
106 | ```js
107 | var pager = require('assemble-pager');
108 | app.helpers(pager.helpers);
109 | ```
110 |
111 | Which adds the following helpers:
112 |
113 | * `relative`- calculates the relative path from file `A` to file `B` (e.g. "current" file to next or previous file)
114 | * `ifFirst`- returns true if the current file being rendered is the first file
115 | * `ifLast`- returns true if the current file being rendered is the last file
116 | * `next`- used in `href=""`, returns either the relative path to the "next" file, or `#` if the current file being rendered is the last file
117 | * `prev`- used in `href=""`, returns either the relative path to the "previous" file, or `#` if the current file being rendered is the first file
118 | * `attr`- stringify the options hash arguments to HTML attributes. For example, you can use this to conditionally add a class for a disabled next/prev link: `{{ifFirst (attr class="disabled")}}`, or `{{ifLast (attr class="disabled")}}` etc.
119 |
120 | **Overriding helpers**
121 |
122 | Helpers are exposed as an object so that you can choose to register them if you want, and/or override them if necessary:
123 |
124 | For example, this is how the included "relative" helper works:
125 |
126 | ```js
127 | var relative = require('relative');
128 |
129 | app.helper('relative', function(from, to) {
130 | return relative(from.data.path, to.data.path);
131 | });
132 | ```
133 |
134 | ### Example usage
135 |
136 | Since `pager` is just another variable on the context, you can do anything you normally would with a variable in your handlebars templates.
137 |
138 | ```handlebars
139 |
141 | Prev
142 | ```
143 |
144 | Or you can create a block:
145 |
146 | ```handlebars
147 | {{#pager}}
148 |
149 | Prev
150 | {{/pager}}
151 | ```
152 |
153 | **Partials**
154 |
155 | To simplify paging even more, you can define partials like the following:
156 |
157 | ```js
158 | app.partial('prev', 'Prev');
159 | app.partial('next', '\nNext');
160 | app.partial('pager', '{{> prev }}\n{{> next }}');
161 | ```
162 |
163 | ### Troubleshooting
164 |
165 | The easiest way to see how this works is to log out the `pager` variables, to see what's on the context. You can use the built-in `log` helper to do this:
166 |
167 | ```handlebars
168 | {{log pager}}
169 | ```
170 |
171 | ## How it works
172 |
173 | This is really all the plugin does, with the addition of error and options handling (a commented version is below). You can copy this and create your own plugin if you need to:
174 |
175 | ```js
176 | function pagerPlugin() {
177 | var list = new app.List({pager: true});
178 | return through.obj(function(file, enc, next) {
179 | list.addItem(file);
180 | next();
181 | }, function(cb) {
182 | for (var i = 0; i < list.items.length; i++) {
183 | this.push(item);
184 | }
185 | cb();
186 | });
187 | }
188 | ```
189 |
190 | With comments:
191 |
192 | ```js
193 | function pagerPlugin() {
194 | // create a new assemble `List`. Lists are like collections,
195 | // but the items are stored as an array, versus an object
196 | var list = new app.List({pager: true});
197 |
198 | return through.obj(function(file, enc, next) {
199 | // add files to the list as they come through the stream
200 | list.addItem(file);
201 |
202 | // don't pass the file through, we'll do
203 | // that in the flush function
204 | next();
205 | }, function(cb) {
206 |
207 | // all of the files have now been buffered onto the
208 | // `list.items` array. We can now loop over that array
209 | // and push the items back into the stream (it's important
210 | // for all the items to be buffered this way so that all
211 | // items are available on the context before anything is
212 | // rendered, or items will be missing)
213 | for (var i = 0; i < list.items.length; i++) {
214 | this.push(item); //<= push the item into the stream
215 | }
216 | cb();
217 | });
218 | }
219 | ```
220 |
221 | ## About
222 |
223 | ### Contributing
224 |
225 | Pull requests and stars are always welcome. For bugs and feature requests, [please create an issue](../../issues/new).
226 |
227 | Please read the [contributing guide](.github/contributing.md) for advice on opening issues, pull requests, and coding standards.
228 |
229 | ### Building docs
230 |
231 | _(This project's readme.md is generated by [verb](https://github.com/verbose/verb-generate-readme), please don't edit the readme directly. Any changes to the readme must be made in the [.verb.md](.verb.md) readme template.)_
232 |
233 | To generate the readme, run the following command:
234 |
235 | ```sh
236 | $ npm install -g verbose/verb#dev verb-generate-readme && verb
237 | ```
238 |
239 | ### Running tests
240 |
241 | Running and reviewing unit tests is a great way to get familiarized with a library and its API. You can install dependencies and run tests with the following command:
242 |
243 | ```sh
244 | $ npm install && npm test
245 | ```
246 |
247 | ### Author
248 |
249 | **Jon Schlinkert**
250 |
251 | * [github/jonschlinkert](https://github.com/jonschlinkert)
252 | * [twitter/jonschlinkert](https://twitter.com/jonschlinkert)
253 |
254 | ### License
255 |
256 | Copyright © 2017, [Jon Schlinkert](https://github.com/jonschlinkert).
257 | MIT
258 |
259 | ***
260 |
261 | _This file was generated by [verb-generate-readme](https://github.com/verbose/verb-generate-readme), v0.4.2, on February 09, 2017._
--------------------------------------------------------------------------------