jekyll-paginate-v2 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +16 -0
- data/Gemfile +8 -0
- data/LICENSE +22 -0
- data/README.md +248 -0
- data/jekyll-paginate-v2.gemspec +28 -0
- data/lib/jekyll-paginate-v2.rb +21 -0
- data/lib/jekyll-paginate-v2/defaults.rb +18 -0
- data/lib/jekyll-paginate-v2/pagination.rb +252 -0
- data/lib/jekyll-paginate-v2/paginator.rb +58 -0
- data/lib/jekyll-paginate-v2/utils.rb +58 -0
- data/lib/jekyll-paginate-v2/version.rb +5 -0
- metadata +113 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: cd4827a1c9dd80de07ba232d75d61c573b52eeaf
|
4
|
+
data.tar.gz: a6238314308d5a386f8fab3f2b28f730b51ab8a7
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 917b6eadca4c14048091ee608c8a284ba17ed3d5a8430c8723828b5cfda7918a64658dbbf7fccd53783ea25253a6e3edaf6432bce4c878c34d6a81884e151466
|
7
|
+
data.tar.gz: 72686ab7df0df3a8d2686f4c8141645df09c82248c547215f1fc2a5bbe4f4db40e19f2a672d8869abfac8a6408f36d0ce16aa983cc35736b35c50596ec93bc36
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2016 Sverrir Sigmundarson
|
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
|
+
|
data/README.md
ADDED
@@ -0,0 +1,248 @@
|
|
1
|
+
# Jekyll::Paginate V2
|
2
|
+
|
3
|
+
Pagination plugin built specially for Jekyll 3 and newer.
|
4
|
+
|
5
|
+
Enhanced replacement for the previously built-in [jekyll-paginate gem](https://github.com/jekyll/jekyll-paginate).
|
6
|
+
|
7
|
+
The code was based on the original design of [jekyll-paginate](https://github.com/jekyll/jekyll-paginate) and features were mostly drawn from discussions from the issues pages (especially https://github.com/jekyll/jekyll-paginate/issues/27) and some from the excellent [Octopress::Paginate code](https://github.com/octopress/paginate).
|
8
|
+
|
9
|
+
Thanks everybody :heart:
|
10
|
+
|
11
|
+
## Features
|
12
|
+
|
13
|
+
In addition to all the features offered by the older [jekyll-paginate gem](https://github.com/jekyll/jekyll-paginate) this new pagination plugin features include
|
14
|
+
|
15
|
+
1. Works with any type of file ending (HTML, Markdown, etc) as long as the file has front-matter and the minimum page level pagination meta (see [page-configuration](#page-configuration)).
|
16
|
+
2. Paginated files can have any file name (not just index.html).
|
17
|
+
3. Supports category, tag and locale filtering.
|
18
|
+
4. Supports any combination of category, tag and locale filtering (e.g. _all posts in the 'ruby' category written for 'en\_US'_ or _all posts in 'car' and 'cycle' category tagged with 'cool' written for 'fr\_FR'_)
|
19
|
+
5. Sorting of posts by any field. Decending or Ascending.
|
20
|
+
6. Optional limits of number of pagenated pages (e.g. _only produce 15 pages_)
|
21
|
+
7. Fully customizable permalink format. E.g `/page:num/` or `/page/:num/` or `/:num/` or really anything you want.
|
22
|
+
8. Optional title suffix for paginated pages (e.g. _Index - Page 2_)
|
23
|
+
|
24
|
+
All this while being fully backwards compatible with the old [jekyll-paginate](https://github.com/jekyll/jekyll-paginate) gem (requires minimal additional front-matter, see [page-configuration](#page-configuration)).
|
25
|
+
|
26
|
+
## Installation
|
27
|
+
|
28
|
+
Currently this plugin is in develpment mode and is not yet distributed as a gem (mostly because I don't know how).
|
29
|
+
|
30
|
+
To install, simply copy the `lib\jekyll-paginate-v2.rb` file into the `_plugins` folder under your Jekyll site root.
|
31
|
+
> If the _plugins folder does not exist simply create it.
|
32
|
+
|
33
|
+
Then add the necessary [Site YML](#site-configuration) and [Page](#page-configuration) configuration elements.
|
34
|
+
|
35
|
+
Run `jekyll serve` and you should see the pagination plugin debug messages printed during site generation:
|
36
|
+
|
37
|
+
``` bash
|
38
|
+
Generating...
|
39
|
+
Pagination: found template: pictures/bestof.md
|
40
|
+
Pagination: found template: puffins/list.html
|
41
|
+
Pagination: found template: index.html
|
42
|
+
```
|
43
|
+
|
44
|
+
## Current state
|
45
|
+
|
46
|
+
Currently this code is in dire need of feedback, code review and testing.
|
47
|
+
|
48
|
+
I also would welcome guidance on how to write automated tests for this code so that I can publish it as a Gem.
|
49
|
+
|
50
|
+
Come to think of it, I currently have no idea on how to publish a Gem... :/
|
51
|
+
|
52
|
+
> Don't worry too much about the current structure, this is just the first iteration.
|
53
|
+
> The code is currently a single file `jekyll-paginate-v2.rb` only because it makes it faster to develop and debug. As soon as I and hopefully other people test and green-light the logic I intend to break this code into separate files and distribute as a gem.
|
54
|
+
|
55
|
+
## Contributing
|
56
|
+
|
57
|
+
1. Fork it ( https://github.com/sverrirs/jekyll-paginate-v2/fork )
|
58
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
59
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
60
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
61
|
+
5. Create new Pull Request
|
62
|
+
|
63
|
+
## Site configuration
|
64
|
+
|
65
|
+
The plugin can be configured in the site's `_config.yml` file by including the `pagination` configuration element
|
66
|
+
|
67
|
+
``` yml
|
68
|
+
############################################################
|
69
|
+
# Site configuration for the Jekyll 3 Pagination Plugin
|
70
|
+
# The values here represent the defaults if nothing is set
|
71
|
+
pagination:
|
72
|
+
|
73
|
+
# Site-wide kill switch, disabled here it doesn't run at all
|
74
|
+
enabled: true
|
75
|
+
|
76
|
+
# How many objects per paginated page, used to be `paginate` (default: 0, means all)
|
77
|
+
per_page: 10
|
78
|
+
|
79
|
+
# The permalink structure for the paginated pages (this can be any level deep)
|
80
|
+
permalink: '/page/:num/'
|
81
|
+
|
82
|
+
# Optional additional suffix for the title of the paginated pages (the prefix is inherited from the template page)
|
83
|
+
title_suffix: ' - page :num'
|
84
|
+
|
85
|
+
# Limit how many pagenated pages to create (default: 0, means all)
|
86
|
+
limit: 0
|
87
|
+
|
88
|
+
# Optional, defines the field that the posts should be sorted on (omit to default to 'date')
|
89
|
+
sort_field: 'date'
|
90
|
+
|
91
|
+
# Optional, sorts the posts in reverse order (omit to default decending or sort_reverse: true)
|
92
|
+
sort_reverse: true
|
93
|
+
|
94
|
+
# The default category to use, just leave this as 'posts' to get a backwards-compatible behavior (all posts)
|
95
|
+
category: 'posts'
|
96
|
+
|
97
|
+
# Optional, the default tag to use, omit to disable
|
98
|
+
tag: 'cool'
|
99
|
+
|
100
|
+
# Optional, the default locale to use, omit to disable (depends on a field 'locale' to be specified in the posts,
|
101
|
+
# in reality this can be any value, suggested are the Microsoft locale-codes (e.g. en_US, en_GB) or simply the ISO-639 language code )
|
102
|
+
locale: 'en_US'
|
103
|
+
|
104
|
+
############################################################
|
105
|
+
```
|
106
|
+
|
107
|
+
## Page configuration
|
108
|
+
|
109
|
+
To enable pagination on a page (i.e. make that page a template for pagination) then simply include the minimal pagination configuration in the page front-matter:
|
110
|
+
|
111
|
+
``` yml
|
112
|
+
pagination:
|
113
|
+
enabled: true
|
114
|
+
```
|
115
|
+
|
116
|
+
Then you can use the normal `paginator.posts` logic to iterate through the posts.
|
117
|
+
|
118
|
+
``` html
|
119
|
+
{% for post in paginator.posts %}
|
120
|
+
<h1>{{ post.title }}</h1>
|
121
|
+
{% endfor %}
|
122
|
+
```
|
123
|
+
|
124
|
+
And to display pagination links, simply
|
125
|
+
|
126
|
+
``` html
|
127
|
+
{% if paginator.total_pages > 1 %}
|
128
|
+
<ul class="pager">
|
129
|
+
{% if paginator.previous_page %}
|
130
|
+
<li class="previous">
|
131
|
+
<a href="{{ paginator.previous_page_path | prepend: site.baseurl | replace: '//', '/' }}">Newer Posts</a>
|
132
|
+
</li>
|
133
|
+
{% endif %}
|
134
|
+
{% if paginator.next_page %}
|
135
|
+
<li class="next">
|
136
|
+
<a href="{{ paginator.next_page_path | prepend: site.baseurl | replace: '//', '/' }}">Older Posts</a>
|
137
|
+
</li>
|
138
|
+
{% endif %}
|
139
|
+
</ul>
|
140
|
+
{% endif %}
|
141
|
+
```
|
142
|
+
|
143
|
+
The code is fully backwards compatible and you will have access to all the normal paginator variables defined in the [official jekyll documentation](https://jekyllrb.com/docs/pagination/#liquid-attributes-available).
|
144
|
+
|
145
|
+
Neat!
|
146
|
+
|
147
|
+
## Paginate categories, tags, locales
|
148
|
+
|
149
|
+
Enabling pagination for specific categories, tags or locales is as simple as adding values to the pagination template front-matter and corresponding values in the posts.
|
150
|
+
|
151
|
+
### Filtering categories
|
152
|
+
|
153
|
+
Filter single category 'software'
|
154
|
+
|
155
|
+
``` yml
|
156
|
+
pagination:
|
157
|
+
enabled: true
|
158
|
+
category: software
|
159
|
+
```
|
160
|
+
|
161
|
+
Filter multiple categories (lists only posts belonging to all categories)
|
162
|
+
|
163
|
+
``` yml
|
164
|
+
pagination:
|
165
|
+
enabled: true
|
166
|
+
category: software, ruby
|
167
|
+
```
|
168
|
+
|
169
|
+
> To define categories you can either specify them in the front-matter or through the [directory structure](http://jekyllrb.com/docs/variables/#page-variables) of your jekyll site (Categories are derived from the directory structure above the \_posts directory). You can actually use both approaches to assign your pages to multiple categories.
|
170
|
+
|
171
|
+
### Filtering tags
|
172
|
+
|
173
|
+
Filter on a single tag
|
174
|
+
|
175
|
+
``` yml
|
176
|
+
pagination:
|
177
|
+
enabled: true
|
178
|
+
tag: cool
|
179
|
+
```
|
180
|
+
|
181
|
+
Filter on multiple tags
|
182
|
+
|
183
|
+
``` yml
|
184
|
+
pagination:
|
185
|
+
enabled: true
|
186
|
+
tag: cool, life
|
187
|
+
```
|
188
|
+
|
189
|
+
### Filtering locales
|
190
|
+
|
191
|
+
In the case your site offers multiple languages you can include a `locale` item in your post front matter. The paginator can then use this value to filter on
|
192
|
+
|
193
|
+
The category page front-matter would look like this
|
194
|
+
|
195
|
+
``` yml
|
196
|
+
pagination:
|
197
|
+
enabled: true
|
198
|
+
locale: en_US
|
199
|
+
```
|
200
|
+
|
201
|
+
Then for the relevant posts, include the `locale` variable in their front-matter
|
202
|
+
|
203
|
+
``` yml
|
204
|
+
locale: en_US
|
205
|
+
```
|
206
|
+
|
207
|
+
## Paginate on combination of filters
|
208
|
+
|
209
|
+
Including only posts from categories 'ruby' and 'software' written in English
|
210
|
+
|
211
|
+
``` yml
|
212
|
+
pagination:
|
213
|
+
enabled: true
|
214
|
+
category: software, ruby
|
215
|
+
locale: en_US, en_GB, en_WW
|
216
|
+
```
|
217
|
+
|
218
|
+
Only showing posts tagged with 'cool' and in category 'cars'
|
219
|
+
|
220
|
+
``` yml
|
221
|
+
pagination:
|
222
|
+
enabled: true
|
223
|
+
category: cars
|
224
|
+
tag: cool
|
225
|
+
```
|
226
|
+
|
227
|
+
... and so on and so on
|
228
|
+
|
229
|
+
## Configuration overrides
|
230
|
+
|
231
|
+
All of the configuration elements from the `_config.yml` file can be overwritten in the pagination template pages. E.g. if you want one category page to have different permalink structure simply override the item like so
|
232
|
+
|
233
|
+
``` yml
|
234
|
+
pagination:
|
235
|
+
enabled: true
|
236
|
+
category: cars
|
237
|
+
permalink: '/cars/:num/'
|
238
|
+
```
|
239
|
+
|
240
|
+
Overriding sorting to sort by the post title in ascending order for another paginated template could be done like so
|
241
|
+
|
242
|
+
``` yml
|
243
|
+
pagination:
|
244
|
+
enabled: true
|
245
|
+
category: ruby
|
246
|
+
sort_field: 'title'
|
247
|
+
sort_reverse: false
|
248
|
+
```
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'jekyll-paginate-v2/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "jekyll-paginate-v2"
|
8
|
+
spec.version = Jekyll::PaginateV2::VERSION
|
9
|
+
spec.platform = Gem::Platform::RUBY
|
10
|
+
spec.date = '2016-11-18'
|
11
|
+
spec.authors = ["Sverrir Sigmundarson"]
|
12
|
+
spec.email = ["jekyll@sverrirs.com"]
|
13
|
+
spec.homepage = "https://github.com/sverrirs/jekyll-paginate-v2"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.summary = %q{Pagination Generator for Jekyll 3}
|
17
|
+
spec.description = %q{An enhanced in-place replacement for the previously built-in jekyll-paginate gem offering full backwards compatability as well as a slew of new frequently requested features}
|
18
|
+
|
19
|
+
spec.files = `git ls-files -z`.split("\x0")
|
20
|
+
#spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
21
|
+
#spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
22
|
+
spec.require_paths = ["lib"]
|
23
|
+
|
24
|
+
spec.add_development_dependency "jekyll", ">= 3.0"
|
25
|
+
spec.add_development_dependency "bundler", "~> 1.5"
|
26
|
+
spec.add_development_dependency "rake"
|
27
|
+
spec.add_development_dependency "rspec", "~> 3.0"
|
28
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# Jekyll::Paginate V2 is a gem built for Jekyll 3 that generates pagiatation for posts, categories and tags.
|
2
|
+
#
|
3
|
+
# It is based on https://github.com/jekyll/jekyll-paginate, the original Jekyll paginator
|
4
|
+
# which was decommissioned in Jekyll 3 release onwards. This code is currently not officially
|
5
|
+
# supported on Jekyll versions < 3.0 (although it might work)
|
6
|
+
#
|
7
|
+
# Author: Sverrir Sigmundarson
|
8
|
+
# Site: https://github.com/sverrirs/jekyll-paginate-v2
|
9
|
+
# Distributed Under The MIT License (MIT) as described in the LICENSE file
|
10
|
+
# - https://opensource.org/licenses/MIT
|
11
|
+
|
12
|
+
require "jekyll-paginate-v2/version"
|
13
|
+
require "jekyll-paginate-v2/defaults"
|
14
|
+
require "jekyll-paginate-v2/utils"
|
15
|
+
require "jekyll-paginate-v2/paginator"
|
16
|
+
require "jekyll-paginate-v2/pagination"
|
17
|
+
|
18
|
+
module Jekyll
|
19
|
+
module PaginateV2
|
20
|
+
end # module PaginateV2
|
21
|
+
end # module Jekyll
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Jekyll
|
2
|
+
module PaginateV2
|
3
|
+
|
4
|
+
# The default configuration for the Paginator
|
5
|
+
DEFAULT = {
|
6
|
+
'enabled' => false,
|
7
|
+
'collection' => 'posts',
|
8
|
+
'per_page' => 10,
|
9
|
+
'permalink' => '/page:num/', # Supports :num as customizable elements
|
10
|
+
'title_suffix' => ' - page :num', # Supports :num as customizable elements
|
11
|
+
'page_num' => 1,
|
12
|
+
'sort_reverse' => false,
|
13
|
+
'sort_field' => 'date',
|
14
|
+
'limit' => 0 # Limit how many content objects to paginate (default: 0, means all)
|
15
|
+
}
|
16
|
+
|
17
|
+
end # module PaginateV2
|
18
|
+
end # module Jekyll
|
@@ -0,0 +1,252 @@
|
|
1
|
+
module Jekyll
|
2
|
+
module PaginateV2
|
3
|
+
|
4
|
+
class PaginationV2 < Generator
|
5
|
+
# This generator is safe from arbitrary code execution.
|
6
|
+
safe true
|
7
|
+
|
8
|
+
# This generator should be passive with regard to its execution
|
9
|
+
priority :lowest
|
10
|
+
|
11
|
+
# Generate paginated pages if necessary (Default entry point)
|
12
|
+
# site - The Site.
|
13
|
+
#
|
14
|
+
# Returns nothing.
|
15
|
+
def generate(site)
|
16
|
+
|
17
|
+
# Retrieve and merge the folate configuration from the site yml file
|
18
|
+
default_config = DEFAULT.merge(site.config['pagination'] || {})
|
19
|
+
|
20
|
+
# If disabled then simply quit
|
21
|
+
if !default_config['enabled']
|
22
|
+
Jekyll.logger.info "Pagination:","disabled in site.config."
|
23
|
+
return
|
24
|
+
end
|
25
|
+
|
26
|
+
Jekyll.logger.debug "Pagination:","Starting"
|
27
|
+
|
28
|
+
# By default if pagination is enabled we attempt to find all index.html pages in the site
|
29
|
+
templates = self.discover_paginate_templates(site)
|
30
|
+
if( templates.size.to_i <= 0 )
|
31
|
+
Jekyll.logger.warn "Pagination:","is enabled, but I couldn't find " +
|
32
|
+
"any index.html page to use as the pagination template. Skipping pagination."
|
33
|
+
return
|
34
|
+
end
|
35
|
+
|
36
|
+
# Get all posts that will be generated (excluding hidden posts such as drafts)
|
37
|
+
all_posts = site.site_payload['site']['posts'].reject { |post| post['hidden'] }
|
38
|
+
|
39
|
+
# Create the necessary indexes for the posts
|
40
|
+
all_categories = self.index_posts_by(all_posts, 'categories')
|
41
|
+
all_categories['posts'] = all_posts; # Popuplate a category for all posts
|
42
|
+
# (this is a default and must not be used in the category system)
|
43
|
+
all_tags = self.index_posts_by(all_posts, 'tags')
|
44
|
+
all_locales = self.index_posts_by(all_posts, 'locale')
|
45
|
+
|
46
|
+
# Now for each template page generate the paginator for it
|
47
|
+
for template in templates
|
48
|
+
|
49
|
+
# All pages that should be paginated need to include the pagination config element
|
50
|
+
if template.data['pagination'].is_a?(Hash)
|
51
|
+
template_config = default_config.merge(template.data['pagination'])
|
52
|
+
|
53
|
+
# Only paginate the template if it is explicitly enabled
|
54
|
+
# requiring this makes the logic simpler as I don't need to determine which index pages
|
55
|
+
# were generated automatically and which weren't
|
56
|
+
if( template_config['enabled'] )
|
57
|
+
Jekyll.logger.info "Pagination:","found template: "+template.path
|
58
|
+
# Now construct the pagination data for this template page
|
59
|
+
self.paginate(site, template, template_config, all_posts, all_tags, all_categories, all_locales)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end #for
|
63
|
+
|
64
|
+
end # function generate
|
65
|
+
|
66
|
+
#
|
67
|
+
# Rolls through the entire site and finds all index.html pages available
|
68
|
+
#
|
69
|
+
# site - The Site.
|
70
|
+
#
|
71
|
+
def discover_paginate_templates(site)
|
72
|
+
candidates = []
|
73
|
+
site.pages.select do |page|
|
74
|
+
# If the page has the enabled config set, supports any type of file name html or md
|
75
|
+
if page.data['pagination'].is_a?(Hash) && page.data['pagination']['enabled']
|
76
|
+
candidates << page
|
77
|
+
end
|
78
|
+
end
|
79
|
+
return candidates
|
80
|
+
end # function discover_paginate_templates
|
81
|
+
|
82
|
+
#
|
83
|
+
# Create a hash index for all post based on a key in the post.data table
|
84
|
+
#
|
85
|
+
def index_posts_by(all_posts, index_key)
|
86
|
+
return nil if all_posts.nil?
|
87
|
+
return all_posts if index_key.nil?
|
88
|
+
index = {}
|
89
|
+
for post in all_posts
|
90
|
+
next if post.data.nil?
|
91
|
+
next if !post.data.has_key?(index_key)
|
92
|
+
next if post.data[index_key].nil?
|
93
|
+
next if post.data[index_key].size <= 0
|
94
|
+
next if post.data[index_key].to_s.strip.length == 0
|
95
|
+
|
96
|
+
# Only tags and categories come as premade arrays, locale does not, so convert any data
|
97
|
+
# elements that are strings into arrays
|
98
|
+
post_data = post.data[index_key]
|
99
|
+
if post_data.is_a?(String)
|
100
|
+
post_data = post_data.split(/;|,|\s/)
|
101
|
+
end
|
102
|
+
|
103
|
+
for key in post_data
|
104
|
+
key = key.downcase.strip
|
105
|
+
# If the key is a delimetered list of values
|
106
|
+
# (meaning the user didn't use an array but a string with commas)
|
107
|
+
for k_split in key.split(/;|,/)
|
108
|
+
k_split = k_split.downcase.strip #Clean whitespace and junk
|
109
|
+
if !index.has_key?(k_split)
|
110
|
+
index[k_split.to_s] = []
|
111
|
+
end
|
112
|
+
index[k_split.to_s] << post
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
return index
|
117
|
+
end # function index_posts_by
|
118
|
+
|
119
|
+
#
|
120
|
+
# Creates an intersection (only returns common elements)
|
121
|
+
# between multiple arrays
|
122
|
+
#
|
123
|
+
def intersect_arrays(first, *rest)
|
124
|
+
return nil if first.nil?
|
125
|
+
return nil if rest.nil?
|
126
|
+
|
127
|
+
intersect = first
|
128
|
+
rest.each do |item|
|
129
|
+
return [] if item.nil?
|
130
|
+
intersect = intersect & item
|
131
|
+
end
|
132
|
+
return intersect
|
133
|
+
end #function intersect_arrays
|
134
|
+
|
135
|
+
#
|
136
|
+
# Filters posts based on a keyed source_posts hash of indexed posts and performs a intersection of
|
137
|
+
# the two sets. Returns only posts that are common between all collections
|
138
|
+
#
|
139
|
+
def read_config_value_and_filter_posts(config, config_key, posts, source_posts)
|
140
|
+
return nil if posts.nil?
|
141
|
+
return nil if source_posts.nil? # If the source is empty then simply don't do anything
|
142
|
+
return posts if config.nil?
|
143
|
+
return posts if !config.has_key?(config_key)
|
144
|
+
return posts if config[config_key].nil?
|
145
|
+
|
146
|
+
# Get the filter values from the config (this is the cat/tag/locale values that should be filtered on)
|
147
|
+
config_value = config[config_key]
|
148
|
+
|
149
|
+
# If we're dealing with a delimitered string instead of an array then let's be forgiving
|
150
|
+
if( config_value.is_a?(String))
|
151
|
+
config_value = config_value.split(/;|,/)
|
152
|
+
end
|
153
|
+
|
154
|
+
# Now for all filter values for the config key, let's remove all items from the posts that
|
155
|
+
# aren't common for all collections that the user wants to filter on
|
156
|
+
for key in config_value
|
157
|
+
key = key.downcase.strip
|
158
|
+
posts = self.intersect_arrays(posts, source_posts[key])
|
159
|
+
end
|
160
|
+
|
161
|
+
# The fully filtered final post list
|
162
|
+
return posts
|
163
|
+
end #function read_config_value_and_filter_posts
|
164
|
+
|
165
|
+
#
|
166
|
+
# Sorting routine used for ordering posts by custom fields.
|
167
|
+
# Handles Strings separately as we want a case-insenstive sorting
|
168
|
+
#
|
169
|
+
def _sort_posts(a, b)
|
170
|
+
if a.is_a?(String)
|
171
|
+
return a.downcase <=> b.downcase
|
172
|
+
end
|
173
|
+
|
174
|
+
# By default use the built in sorting for the data type
|
175
|
+
return a <=> b
|
176
|
+
end
|
177
|
+
|
178
|
+
# Paginates the blog's posts. Renders the index.html file into paginated
|
179
|
+
# directories, e.g.: page2/index.html, page3/index.html, etc and adds more
|
180
|
+
# site-wide data.
|
181
|
+
#
|
182
|
+
# site - The Site.
|
183
|
+
# template - The index.html Page that requires pagination.
|
184
|
+
# config - The configuration settings that should be used
|
185
|
+
#
|
186
|
+
def paginate(site, template, config, all_posts, all_tags, all_categories, all_locales)
|
187
|
+
|
188
|
+
# By default paginate on all posts in the site
|
189
|
+
using_posts = all_posts
|
190
|
+
|
191
|
+
# Now start filtering out any posts that the user doesn't want included in the pagination
|
192
|
+
using_posts = self.read_config_value_and_filter_posts(config, 'category', using_posts, all_categories)
|
193
|
+
using_posts = self.read_config_value_and_filter_posts(config, 'tag', using_posts, all_tags)
|
194
|
+
using_posts = self.read_config_value_and_filter_posts(config, 'locale', using_posts, all_locales)
|
195
|
+
|
196
|
+
# Apply sorting to the posts if configured, any field for the post is available for sorting
|
197
|
+
if config['sort_field']
|
198
|
+
sort_field = config['sort_field'].to_s
|
199
|
+
using_posts.sort!{ |a,b| self._sort_posts(a.data[sort_field], b.data[sort_field]) }
|
200
|
+
|
201
|
+
if config['sort_reverse']
|
202
|
+
using_posts.reverse!
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
# Calculate the max number of pagination-pages based on the configured per page value
|
207
|
+
total_pages = self.calculate_number_of_pages(using_posts, config['per_page'])
|
208
|
+
|
209
|
+
# If a upper limit is set on the number of total pagination pages then impose that now
|
210
|
+
if config['limit'] && config['limit'].to_i > 0 && config['limit'].to_i < total_pages
|
211
|
+
total_pages = config['limit'].to_i
|
212
|
+
end
|
213
|
+
|
214
|
+
# Now for each pagination page create it and configure the ranges for the collection
|
215
|
+
# This .pager member is a built in thing in Jekyll and defines the paginator implementation
|
216
|
+
# Simpy override to use mine
|
217
|
+
(1..total_pages).each do |cur_page_nr|
|
218
|
+
pager = PaginatorV2.new( config, using_posts, cur_page_nr, total_pages, template )
|
219
|
+
if( cur_page_nr > 1)
|
220
|
+
newpage = Page.new( site, site.source, template.dir, template.name)
|
221
|
+
newpage.pager = pager
|
222
|
+
newpage.dir = Utils.paginate_path(template, cur_page_nr, config)
|
223
|
+
if( config.has_key?('title_suffix'))
|
224
|
+
if( !template.data['title'] )
|
225
|
+
tmp_title = site.config['title']
|
226
|
+
else
|
227
|
+
tmp_title = template.data['title']
|
228
|
+
end
|
229
|
+
|
230
|
+
newpage.data['title'] = "#{tmp_title}#{Utils.format_page_number(config['title_suffix'], cur_page_nr)}"
|
231
|
+
end
|
232
|
+
site.pages << newpage
|
233
|
+
else
|
234
|
+
template.pager = pager
|
235
|
+
end
|
236
|
+
end
|
237
|
+
end # function paginate
|
238
|
+
|
239
|
+
# Calculate the number of pages.
|
240
|
+
#
|
241
|
+
# all_posts - The Array of all Posts.
|
242
|
+
# per_page - The Integer of entries per page.
|
243
|
+
#
|
244
|
+
# Returns the Integer number of pages.
|
245
|
+
def calculate_number_of_pages(all_posts, per_page)
|
246
|
+
(all_posts.size.to_f / per_page.to_i).ceil
|
247
|
+
end
|
248
|
+
|
249
|
+
end # class PaginationV2
|
250
|
+
|
251
|
+
end # module PaginateV2
|
252
|
+
end # module Jekyll
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module Jekyll
|
2
|
+
module PaginateV2
|
3
|
+
|
4
|
+
#
|
5
|
+
# Handles the preparation of all the posts based on the current page index
|
6
|
+
#
|
7
|
+
class PaginatorV2
|
8
|
+
attr_reader :page, :per_page, :posts, :total_posts, :total_pages,
|
9
|
+
:previous_page, :previous_page_path, :next_page, :next_page_path
|
10
|
+
|
11
|
+
# Initialize a new Paginator.
|
12
|
+
#
|
13
|
+
# site - the Jekyll::Site object
|
14
|
+
# page_nr - The Integer page number.
|
15
|
+
# all_posts - The Array of all the site's Posts.
|
16
|
+
# num_pages - The Integer number of pages or nil if you'd like the number
|
17
|
+
# of pages calculated.
|
18
|
+
def initialize(config, posts, cur_page_nr, num_pages, template )
|
19
|
+
@page = cur_page_nr
|
20
|
+
@per_page = config['per_page'].to_i
|
21
|
+
@total_pages = num_pages
|
22
|
+
|
23
|
+
if @page > @total_pages
|
24
|
+
raise RuntimeError, "page number can't be greater than total pages: #{@page} > #{@total_pages}"
|
25
|
+
end
|
26
|
+
|
27
|
+
init = (@page - 1) * @per_page
|
28
|
+
offset = (init + @per_page - 1) >= posts.size ? posts.size : (init + @per_page - 1)
|
29
|
+
|
30
|
+
@total_posts = posts.size
|
31
|
+
@posts = posts[init..offset]
|
32
|
+
@previous_page = @page != 1 ? @page - 1 : nil
|
33
|
+
@previous_page_path = Utils.paginate_path(template, @previous_page, config)
|
34
|
+
@next_page = @page != @total_pages ? @page + 1 : nil
|
35
|
+
@next_page_path = Utils.paginate_path(template, @next_page, config)
|
36
|
+
end
|
37
|
+
|
38
|
+
# Convert this Paginator's data to a Hash suitable for use by Liquid.
|
39
|
+
#
|
40
|
+
# Returns the Hash representation of this Paginator.
|
41
|
+
def to_liquid
|
42
|
+
{
|
43
|
+
'per_page' => per_page,
|
44
|
+
'posts' => posts,
|
45
|
+
'total_posts' => total_posts,
|
46
|
+
'total_pages' => total_pages,
|
47
|
+
'page' => page,
|
48
|
+
'previous_page' => previous_page,
|
49
|
+
'previous_page_path' => previous_page_path,
|
50
|
+
'next_page' => next_page,
|
51
|
+
'next_page_path' => next_page_path
|
52
|
+
}
|
53
|
+
end
|
54
|
+
|
55
|
+
end # class PaginatorV2
|
56
|
+
|
57
|
+
end # module PaginateV2
|
58
|
+
end # module Jekyll
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module Jekyll
|
2
|
+
module PaginateV2
|
3
|
+
|
4
|
+
#
|
5
|
+
# Static utility functions that are used in the code and
|
6
|
+
# don't belong in once place in particular
|
7
|
+
#
|
8
|
+
class Utils
|
9
|
+
|
10
|
+
# Static: Return the pagination path of the page
|
11
|
+
#
|
12
|
+
# site - the Jekyll::Site object
|
13
|
+
# cur_page_nr - the pagination page number
|
14
|
+
# config - the current configuration in use
|
15
|
+
#
|
16
|
+
# Returns the pagination path as a string
|
17
|
+
def self.paginate_path(template, cur_page_nr, config)
|
18
|
+
return nil if cur_page_nr.nil?
|
19
|
+
return template.url if cur_page_nr <= 1
|
20
|
+
format = config['permalink']
|
21
|
+
if format.include?(":num")
|
22
|
+
format = Utils.format_page_number(format, cur_page_nr)
|
23
|
+
else
|
24
|
+
raise ArgumentError.new("Invalid pagination path: '#{format}'. It must include ':num'.")
|
25
|
+
end
|
26
|
+
Utils.ensure_leading_slash(format)
|
27
|
+
end #function paginate_path
|
28
|
+
|
29
|
+
# Static: returns a fully formatted string with the current page number if configured
|
30
|
+
#
|
31
|
+
def self.format_page_number(toFormat, cur_page_nr)
|
32
|
+
return toFormat.sub(':num', cur_page_nr.to_s)
|
33
|
+
end #function format_page_number
|
34
|
+
|
35
|
+
# Static: Return a String version of the input which has a leading slash.
|
36
|
+
# If the input already has a forward slash in position zero, it will be
|
37
|
+
# returned unchanged.
|
38
|
+
#
|
39
|
+
# path - a String path
|
40
|
+
#
|
41
|
+
# Returns the path with a leading slash
|
42
|
+
def self.ensure_leading_slash(path)
|
43
|
+
path[0..0] == "/" ? path : "/#{path}"
|
44
|
+
end
|
45
|
+
|
46
|
+
# Static: Return a String version of the input without a leading slash.
|
47
|
+
#
|
48
|
+
# path - a String path
|
49
|
+
#
|
50
|
+
# Returns the input without the leading slash
|
51
|
+
def self.remove_leading_slash(path)
|
52
|
+
path[0..0] == "/" ? path[1..-1] : path
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
|
57
|
+
end # module PaginateV2
|
58
|
+
end # module Jekyll
|
metadata
ADDED
@@ -0,0 +1,113 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: jekyll-paginate-v2
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Sverrir Sigmundarson
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-11-18 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: jekyll
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '3.0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '3.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: bundler
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.5'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.5'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rake
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rspec
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '3.0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '3.0'
|
69
|
+
description: An enhanced in-place replacement for the previously built-in jekyll-paginate
|
70
|
+
gem offering full backwards compatability as well as a slew of new frequently requested
|
71
|
+
features
|
72
|
+
email:
|
73
|
+
- jekyll@sverrirs.com
|
74
|
+
executables: []
|
75
|
+
extensions: []
|
76
|
+
extra_rdoc_files: []
|
77
|
+
files:
|
78
|
+
- ".gitignore"
|
79
|
+
- Gemfile
|
80
|
+
- LICENSE
|
81
|
+
- README.md
|
82
|
+
- jekyll-paginate-v2.gemspec
|
83
|
+
- lib/jekyll-paginate-v2.rb
|
84
|
+
- lib/jekyll-paginate-v2/defaults.rb
|
85
|
+
- lib/jekyll-paginate-v2/pagination.rb
|
86
|
+
- lib/jekyll-paginate-v2/paginator.rb
|
87
|
+
- lib/jekyll-paginate-v2/utils.rb
|
88
|
+
- lib/jekyll-paginate-v2/version.rb
|
89
|
+
homepage: https://github.com/sverrirs/jekyll-paginate-v2
|
90
|
+
licenses:
|
91
|
+
- MIT
|
92
|
+
metadata: {}
|
93
|
+
post_install_message:
|
94
|
+
rdoc_options: []
|
95
|
+
require_paths:
|
96
|
+
- lib
|
97
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
98
|
+
requirements:
|
99
|
+
- - ">="
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: '0'
|
102
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
103
|
+
requirements:
|
104
|
+
- - ">="
|
105
|
+
- !ruby/object:Gem::Version
|
106
|
+
version: '0'
|
107
|
+
requirements: []
|
108
|
+
rubyforge_project:
|
109
|
+
rubygems_version: 2.4.8
|
110
|
+
signing_key:
|
111
|
+
specification_version: 4
|
112
|
+
summary: Pagination Generator for Jekyll 3
|
113
|
+
test_files: []
|