├── test ├── mocha.opts ├── .eslintrc └── index.js ├── .eslintignore ├── .eslintrc ├── .gitignore ├── .jscsrc ├── .npmignore ├── index.js ├── .travis.yml ├── lib └── generator.js ├── LICENSE ├── package.json └── README.md /test/mocha.opts: -------------------------------------------------------------------------------- 1 | --reporter spec -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | coverage/ 3 | tmp/ -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "hexo", 3 | "root": true 4 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ 3 | tmp/ 4 | *.log 5 | .idea/ 6 | coverage/ -------------------------------------------------------------------------------- /.jscsrc: -------------------------------------------------------------------------------- 1 | { 2 | "excludeFiles": ["node_modules/**", "coverage/**", "tmp/**"], 3 | "preset": "hexo" 4 | } -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | test/ 2 | tmp/ 3 | coverage/ 4 | *.log 5 | .travis.yml 6 | gulpfile.js 7 | .idea/ 8 | appveyor.yml -------------------------------------------------------------------------------- /test/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extend": "../.eslintrc", 3 | "rules": { 4 | "no-unused-expressions": 0 5 | }, 6 | "env": { 7 | "mocha": true 8 | } 9 | } -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | /* global hexo */ 2 | 3 | 'use strict'; 4 | 5 | var assign = require('object-assign'); 6 | 7 | hexo.config.index_generator = assign({ 8 | per_page: typeof hexo.config.per_page === 'undefined' ? 10 : hexo.config.per_page, 9 | order_by: '-date' 10 | }, hexo.config.index_generator); 11 | 12 | hexo.extend.generator.register('index', require('./lib/generator')); 13 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | 3 | sudo: false 4 | 5 | cache: 6 | apt: true 7 | directories: 8 | - node_modules 9 | 10 | node_js: 11 | - "6" 12 | - "node" 13 | 14 | script: 15 | - npm run eslint 16 | - npm run jscs 17 | - npm run test-cov 18 | 19 | after_script: 20 | - npm install coveralls 21 | - cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js 22 | -------------------------------------------------------------------------------- /lib/generator.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var pagination = require('hexo-pagination'); 3 | module.exports = function(locals){ 4 | var config = this.config; 5 | var posts = locals.posts; 6 | posts.data = posts.data.sort(function(a, b) { 7 | if(a.top && b.top) { // 两篇文章top都有定义 8 | if(a.top == b.top) return b.date - a.date; // 若top值一样则按照文章日期降序排 9 | else return b.top - a.top; // 否则按照top值降序排 10 | } 11 | else if(a.top && !b.top) { // 以下是只有一篇文章top有定义,那么将有top的排在前面(这里用异或操作居然不行233) 12 | return -1; 13 | } 14 | else if(!a.top && b.top) { 15 | return 1; 16 | } 17 | else return b.date - a.date; // 都没定义按照文章日期降序排 18 | }); 19 | var paginationDir = config.pagination_dir || 'page'; 20 | return pagination('', posts, { 21 | perPage: config.index_generator.per_page, 22 | layout: ['index', 'archive'], 23 | format: paginationDir + '/%d/', 24 | data: { 25 | __index: true 26 | } 27 | }); 28 | }; 29 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014 Tommy Chen 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hexo-generator-index-pin-top", 3 | "version": "0.2.2", 4 | "description": "Index generator for Hexo.(pin top version)", 5 | "main": "index", 6 | "scripts": { 7 | "eslint": "eslint .", 8 | "jscs": "jscs .", 9 | "test": "mocha test/index.js", 10 | "test-cov": "istanbul cover --print both _mocha -- test/index.js" 11 | }, 12 | "directories": { 13 | "lib": "./lib" 14 | }, 15 | "engines": { 16 | "node": ">= 0.10.0" 17 | }, 18 | "repository": "netcan/hexo-generator-index-pin-top", 19 | "homepage": "http://hexo.io/", 20 | "keywords": [ 21 | "hexo", 22 | "generator", 23 | "index", 24 | "home" 25 | ], 26 | "author": "Netcan (http://netcan666.com)", 27 | "license": "MIT", 28 | "devDependencies": { 29 | "chai": "^3.4.0", 30 | "eslint": "^1.8.0", 31 | "eslint-config-hexo": "^1.0.2", 32 | "hexo": "^3.0.0", 33 | "istanbul": "^0.4.0", 34 | "jscs": "^2.5.0", 35 | "jscs-preset-hexo": "^1.0.1", 36 | "mocha": "^2.0.1" 37 | }, 38 | "dependencies": { 39 | "hexo-pagination": "0.0.2", 40 | "object-assign": "^4.0.1" 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # hexo-generator-index-pin-top 2 | 3 | [![Build Status](https://travis-ci.org/hexojs/hexo-generator-index.svg?branch=master)](https://travis-ci.org/hexojs/hexo-generator-index) [![NPM version](https://badge.fury.io/js/hexo-generator-index.svg)](http://badge.fury.io/js/hexo-generator-index) [![Coverage Status](https://img.shields.io/coveralls/hexojs/hexo-generator-index.svg)](https://coveralls.io/r/hexojs/hexo-generator-index?branch=master) 4 | 5 | Index generator for [Hexo]. Pin top version 6 | 7 | ## Installation 8 | 9 | ``` bash 10 | $ npm uninstall hexo-generator-index --save 11 | $ npm install hexo-generator-index-pin-top --save 12 | ``` 13 | 14 | ## Feautres 15 | This version supports pin-top feature, you can add the `top: True` field to post's front-matter to pin it. 16 | 17 | ## Options 18 | Add or modify the following section to your root _config.yml file 19 | 20 | ``` yaml 21 | index_generator: 22 | path: '' 23 | per_page: 10 24 | order_by: -date 25 | ``` 26 | 27 | - **path**: Root path for your blogs index page. (default = '') 28 | - **per_page**: Posts displayed per page. (0 = disable pagination) 29 | - **order_by**: Posts order. (Order by date descending by default) 30 | 31 | ## License 32 | 33 | MIT 34 | 35 | [Hexo]: http://hexo.io/ 36 | -------------------------------------------------------------------------------- /test/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var should = require('chai').should(); // eslint-disable-line 4 | var Hexo = require('hexo'); 5 | 6 | describe('Index generator', function() { 7 | var hexo = new Hexo(__dirname, {silent: true}); 8 | var Post = hexo.model('Post'); 9 | var generator = require('../lib/generator').bind(hexo); 10 | var posts; 11 | var locals; 12 | 13 | // Default config 14 | hexo.config.index_generator = { 15 | per_page: 10, 16 | order_by: '-date' 17 | }; 18 | 19 | before(() => hexo.init().then(() => Post.insert([ 20 | {source: 'foo', slug: 'foo', date: 1e8, order: 0}, 21 | {source: 'bar', slug: 'bar', date: 1e8 + 1, order: 10}, 22 | {source: 'baz', slug: 'baz', date: 1e8 - 1, order: 1} 23 | ])).then(data => { 24 | posts = Post.sort('-date'); 25 | locals = hexo.locals.toObject(); 26 | })); 27 | 28 | it('pagination enabled', function() { 29 | hexo.config.index_generator.per_page = 2; 30 | 31 | var result = generator(locals); 32 | 33 | result.length.should.eql(2); 34 | 35 | for (var i = 0, len = result.length; i < len; i++) { 36 | result[i].layout.should.eql(['index', 'archive']); 37 | result[i].data.current.should.eql(i + 1); 38 | result[i].data.base.should.eql(''); 39 | result[i].data.total.should.eql(2); 40 | } 41 | 42 | result[0].path.should.eql(''); 43 | result[0].data.current_url.should.eql(''); 44 | result[0].data.posts.should.eql(posts.limit(2)); 45 | result[0].data.prev.should.eql(0); 46 | result[0].data.prev_link.should.eql(''); 47 | result[0].data.next.should.eql(2); 48 | result[0].data.next_link.should.eql('page/2/'); 49 | result[0].data.__index.should.be.true; 50 | 51 | result[1].path.should.eql('page/2/'); 52 | result[1].data.current_url.should.eql('page/2/'); 53 | result[1].data.posts.should.eql(posts.skip(2)); 54 | result[1].data.prev.should.eql(1); 55 | result[1].data.prev_link.should.eql(''); 56 | result[1].data.next.should.eql(0); 57 | result[1].data.next_link.should.eql(''); 58 | result[1].data.__index.should.be.true; 59 | 60 | // Restore config 61 | hexo.config.index_generator.per_page = 10; 62 | }); 63 | 64 | it('pagination disabled', function() { 65 | hexo.config.index_generator.per_page = 0; 66 | 67 | var result = generator(locals); 68 | 69 | result.length.should.eql(1); 70 | 71 | result[0].path.should.eql(''); 72 | result[0].layout.should.eql(['index', 'archive']); 73 | result[0].data.base.should.eql(''); 74 | result[0].data.total.should.eql(1); 75 | result[0].data.current.should.eql(1); 76 | result[0].data.current_url.should.eql(''); 77 | result[0].data.posts.should.eql(posts); 78 | result[0].data.prev.should.eql(0); 79 | result[0].data.prev_link.should.eql(''); 80 | result[0].data.next.should.eql(0); 81 | result[0].data.next_link.should.eql(''); 82 | result[0].data.__index.should.be.true; 83 | 84 | // Restore config 85 | hexo.config.index_generator.per_page = 10; 86 | }); 87 | 88 | describe('order', function() { 89 | it('default order', function() { 90 | var result = generator(locals); 91 | 92 | result[0].data.posts.should.eql(posts); 93 | }); 94 | 95 | it('custom order', function() { 96 | hexo.config.index_generator.order_by = '-order'; 97 | 98 | var result = generator(locals); 99 | 100 | result[0].data.posts.eq(0).source.should.eql('bar'); 101 | result[0].data.posts.eq(1).source.should.eql('baz'); 102 | result[0].data.posts.eq(2).source.should.eql('foo'); 103 | 104 | hexo.config.index_generator.order_by = 'order'; 105 | 106 | result = generator(locals); 107 | 108 | result[0].data.posts.eq(0).source.should.eql('foo'); 109 | result[0].data.posts.eq(1).source.should.eql('baz'); 110 | result[0].data.posts.eq(2).source.should.eql('bar'); 111 | 112 | // Restore config 113 | delete hexo.config.index_generator.order_by; 114 | }); 115 | 116 | it('custom order - invalid order key', function() { 117 | hexo.config.index_generator.order_by = '-something'; 118 | 119 | var result = generator(locals); 120 | 121 | result[0].data.posts.eq(0).source.should.eql('foo'); 122 | result[0].data.posts.eq(1).source.should.eql('bar'); 123 | result[0].data.posts.eq(2).source.should.eql('baz'); 124 | 125 | // Restore config 126 | delete hexo.config.index_generator.order_by; 127 | }); 128 | }); 129 | 130 | it('custom pagination_dir', function() { 131 | hexo.config.index_generator.per_page = 1; 132 | hexo.config.pagination_dir = 'yo'; 133 | 134 | var result = generator(locals); 135 | 136 | result[0].path.should.eql(''); 137 | result[1].path.should.eql('yo/2/'); 138 | result[2].path.should.eql('yo/3/'); 139 | 140 | // Restore config 141 | hexo.config.index_generator.per_page = 10; 142 | hexo.config.pagination_dir = 'page'; 143 | }); 144 | }); 145 | --------------------------------------------------------------------------------