j1_paginator 2019.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CODE_OF_CONDUCT.md +86 -0
- data/Gemfile +14 -0
- data/LICENSE +22 -0
- data/README-AUTOPAGES.md +141 -0
- data/README-GENERATOR.md +708 -0
- data/README.md +82 -0
- data/Rakefile +16 -0
- data/j1_paginator.gemspec +34 -0
- data/lib/j1_paginator.rb +34 -0
- data/lib/j1_paginator/autopages/autoPages.rb +77 -0
- data/lib/j1_paginator/autopages/defaults.rb +40 -0
- data/lib/j1_paginator/autopages/pages/baseAutoPage.rb +60 -0
- data/lib/j1_paginator/autopages/pages/categoryAutoPage.rb +32 -0
- data/lib/j1_paginator/autopages/pages/collectionAutoPage.rb +31 -0
- data/lib/j1_paginator/autopages/pages/tagAutoPage.rb +32 -0
- data/lib/j1_paginator/autopages/utils.rb +76 -0
- data/lib/j1_paginator/generator/compatibilityUtils.rb +121 -0
- data/lib/j1_paginator/generator/defaults.rb +27 -0
- data/lib/j1_paginator/generator/paginationGenerator.rb +146 -0
- data/lib/j1_paginator/generator/paginationIndexer.rb +116 -0
- data/lib/j1_paginator/generator/paginationModel.rb +377 -0
- data/lib/j1_paginator/generator/paginationPage.rb +66 -0
- data/lib/j1_paginator/generator/paginator.rb +107 -0
- data/lib/j1_paginator/generator/utils.rb +181 -0
- data/lib/j1_paginator/version.rb +10 -0
- data/spec/generator/defaults_spec.rb +34 -0
- data/spec/generator/paginationPage_spec.rb +12 -0
- data/spec/generator/paginator_spec.rb +197 -0
- data/spec/generator/utils_spec.rb +67 -0
- data/spec/spec_helper.rb +13 -0
- metadata +144 -0
@@ -0,0 +1,76 @@
|
|
1
|
+
module Jekyll
|
2
|
+
module J1Paginator::AutoPages
|
3
|
+
|
4
|
+
class Utils
|
5
|
+
|
6
|
+
# Static: returns a fully formatted string with the tag macro (:tag) replaced
|
7
|
+
#
|
8
|
+
def self.format_tag_macro(toFormat, tag, slugify_config=nil)
|
9
|
+
slugify_mode = slugify_config.has_key?('mode') ? slugify_config['mode'] : nil
|
10
|
+
slugify_cased = slugify_config.has_key?('cased') ? slugify_config['cased'] : false
|
11
|
+
return toFormat.sub(':tag', Jekyll::Utils.slugify(tag.to_s, mode:slugify_mode, cased:slugify_cased))
|
12
|
+
end #function format_tag_macro
|
13
|
+
|
14
|
+
# Static: returns a fully formatted string with the category macro (:cat) replaced
|
15
|
+
#
|
16
|
+
def self.format_cat_macro(toFormat, category, slugify_config=nil)
|
17
|
+
slugify_mode = slugify_config.has_key?('mode') ? slugify_config['mode'] : nil
|
18
|
+
slugify_cased = slugify_config.has_key?('cased') ? slugify_config['cased'] : false
|
19
|
+
return toFormat.sub(':cat', Jekyll::Utils.slugify(category.to_s, mode:slugify_mode, cased:slugify_cased))
|
20
|
+
end #function format_cat_macro
|
21
|
+
|
22
|
+
# Static: returns a fully formatted string with the collection macro (:coll) replaced
|
23
|
+
#
|
24
|
+
def self.format_coll_macro(toFormat, collection, slugify_config=nil)
|
25
|
+
slugify_mode = slugify_config.has_key?('mode') ? slugify_config['mode'] : nil
|
26
|
+
slugify_cased = slugify_config.has_key?('cased') ? slugify_config['cased'] : false
|
27
|
+
return toFormat.sub(':coll', Jekyll::Utils.slugify(collection.to_s, mode:slugify_mode, cased:slugify_cased))
|
28
|
+
end #function format_coll_macro
|
29
|
+
|
30
|
+
# Static: returns all documents from all collections defined in the hash of collections passed in
|
31
|
+
# excludes all pagination pages though
|
32
|
+
def self.collect_all_docs(site_collections)
|
33
|
+
coll = []
|
34
|
+
site_collections.each do |coll_name, coll_data|
|
35
|
+
if !coll_data.nil?
|
36
|
+
coll += coll_data.docs.select { |doc| !doc.data.has_key?('pagination') }.each{ |doc| doc.data['__coll'] = coll_name } # Exclude all pagination pages and then for every page store it's collection name
|
37
|
+
end
|
38
|
+
end
|
39
|
+
return coll
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.ap_index_posts_by(all_posts, index_key)
|
43
|
+
return nil if all_posts.nil?
|
44
|
+
return all_posts if index_key.nil?
|
45
|
+
index = {}
|
46
|
+
all_posts.each do |post|
|
47
|
+
next if post.data.nil?
|
48
|
+
next if !post.data.has_key?(index_key)
|
49
|
+
next if post.data[index_key].nil?
|
50
|
+
next if post.data[index_key].size <= 0
|
51
|
+
next if post.data[index_key].to_s.strip.length == 0
|
52
|
+
|
53
|
+
# Only tags and categories come as premade arrays, locale does not, so convert any data
|
54
|
+
# elements that are strings into arrays
|
55
|
+
post_data = post.data[index_key]
|
56
|
+
if post_data.is_a?(String)
|
57
|
+
post_data = post_data.split(/;|,|\s/)
|
58
|
+
end
|
59
|
+
|
60
|
+
post_data.each do |key|
|
61
|
+
key = key.to_s.strip
|
62
|
+
processed_key = key.downcase #Clean whitespace and junk
|
63
|
+
if !index.has_key?(processed_key)
|
64
|
+
# Need to store the original key value here so that I can present it to the users as a page variable they can use (unmodified, e.g. tags not being 'sci-fi' but "Sci-Fi")
|
65
|
+
# Also, only interested in storing all the keys not the pages in this case
|
66
|
+
index[processed_key] = [processed_key, key]
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
return index
|
71
|
+
end # function index_posts_by
|
72
|
+
|
73
|
+
end # class Utils
|
74
|
+
|
75
|
+
end # module J1Paginator
|
76
|
+
end # module Jekyll
|
@@ -0,0 +1,121 @@
|
|
1
|
+
module Jekyll
|
2
|
+
module J1Paginator::Generator
|
3
|
+
|
4
|
+
class CompatibilityPaginationPage < Page
|
5
|
+
def initialize(site, base, dir, template_path)
|
6
|
+
@site = site
|
7
|
+
@base = base
|
8
|
+
@dir = dir
|
9
|
+
@template = template_path
|
10
|
+
@name = 'index.html'
|
11
|
+
|
12
|
+
templ_dir = File.dirname(template_path)
|
13
|
+
templ_file = File.basename(template_path)
|
14
|
+
|
15
|
+
# Path is only used by the convertible module and accessed below when calling read_yaml
|
16
|
+
# in our case we have the path point to the original template instead of our faux new pagination page
|
17
|
+
@path = if site.in_theme_dir(base) == base # we're in a theme
|
18
|
+
site.in_theme_dir(base, templ_dir, templ_file)
|
19
|
+
else
|
20
|
+
site.in_source_dir(base, templ_dir, templ_file)
|
21
|
+
end
|
22
|
+
|
23
|
+
self.process(@name)
|
24
|
+
self.read_yaml(templ_dir, templ_file)
|
25
|
+
|
26
|
+
data.default_proc = proc do |_, key|
|
27
|
+
site.frontmatter_defaults.find(File.join(templ_dir, templ_file), type, key)
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
end # class CompatibilityPaginationPage
|
32
|
+
|
33
|
+
#
|
34
|
+
# Static utility functions that provide backwards compatibility with the old
|
35
|
+
# jekyll-paginate gem that this new version superseeds (this code is here to ensure)
|
36
|
+
# that sites still running the old gem work without problems
|
37
|
+
# (REMOVE AFTER 2018-01-01)
|
38
|
+
#
|
39
|
+
# THIS CLASS IS ADAPTED FROM THE ORIGINAL IMPLEMENTATION AND WILL BE REMOVED, THERE ARE DELIBERATELY NO TESTS FOR THIS CLASS
|
40
|
+
#
|
41
|
+
class CompatibilityUtils
|
42
|
+
|
43
|
+
# Public: Find the Jekyll::Page which will act as the pager template
|
44
|
+
#
|
45
|
+
# Returns the Jekyll::Page which will act as the pager template
|
46
|
+
def self.template_page(site_pages, config_source, config_paginate_path)
|
47
|
+
site_pages.select do |page|
|
48
|
+
CompatibilityUtils.pagination_candidate?(config_source, config_paginate_path, page)
|
49
|
+
end.sort do |one, two|
|
50
|
+
two.path.size <=> one.path.size
|
51
|
+
end.first
|
52
|
+
end
|
53
|
+
|
54
|
+
# Static: Determine if a page is a possible candidate to be a template page.
|
55
|
+
# Page's name must be `index.html` and exist in any of the directories
|
56
|
+
# between the site source and `paginate_path`.
|
57
|
+
def self.pagination_candidate?(config_source, config_paginate_path, page)
|
58
|
+
page_dir = File.dirname(File.expand_path(Utils.remove_leading_slash(page.path), config_source))
|
59
|
+
paginate_path = Utils.remove_leading_slash(config_paginate_path)
|
60
|
+
paginate_path = File.expand_path(paginate_path, config_source)
|
61
|
+
page.name == 'index.html' && CompatibilityUtils.in_hierarchy(config_source, page_dir, File.dirname(paginate_path))
|
62
|
+
end
|
63
|
+
|
64
|
+
# Determine if the subdirectories of the two paths are the same relative to source
|
65
|
+
#
|
66
|
+
# source - the site source
|
67
|
+
# page_dir - the directory of the Jekyll::Page
|
68
|
+
# paginate_path - the absolute paginate path (from root of FS)
|
69
|
+
#
|
70
|
+
# Returns whether the subdirectories are the same relative to source
|
71
|
+
def self.in_hierarchy(source, page_dir, paginate_path)
|
72
|
+
return false if paginate_path == File.dirname(paginate_path)
|
73
|
+
return false if paginate_path == Pathname.new(source).parent
|
74
|
+
page_dir == paginate_path ||
|
75
|
+
CompatibilityUtils.in_hierarchy(source, page_dir, File.dirname(paginate_path))
|
76
|
+
end
|
77
|
+
|
78
|
+
# Paginates the blog's posts. Renders the index.html file into paginated
|
79
|
+
# directories, e.g.: page2/index.html, page3/index.html, etc and adds more
|
80
|
+
# site-wide data.
|
81
|
+
#
|
82
|
+
def self.paginate(legacy_config, all_posts, page, page_add_lambda )
|
83
|
+
pages = Utils.calculate_number_of_pages(all_posts, legacy_config['per_page'].to_i)
|
84
|
+
(1..pages).each do |num_page|
|
85
|
+
pager = Paginator.new( legacy_config['per_page'], page.url, legacy_config['permalink'], all_posts, num_page, pages, '', '' )
|
86
|
+
if num_page > 1
|
87
|
+
template_full_path = File.join(page.site.source, page.path)
|
88
|
+
template_dir = File.dirname(page.path)
|
89
|
+
newpage = CompatibilityPaginationPage.new(page.site, page.site.source, template_dir, template_full_path)
|
90
|
+
newpage.pager = pager
|
91
|
+
newpage.dir = CompatibilityUtils.paginate_path(page.url, num_page, legacy_config['permalink'])
|
92
|
+
newpage.data['autogen'] = "j1_paginator" # Signals that this page is automatically generated by the pagination logic
|
93
|
+
page_add_lambda.call(newpage)
|
94
|
+
else
|
95
|
+
page.pager = pager
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
# Static: Return the pagination path of the page
|
101
|
+
#
|
102
|
+
# site - the Jekyll::Site object
|
103
|
+
# cur_page_nr - the pagination page number
|
104
|
+
# config - the current configuration in use
|
105
|
+
#
|
106
|
+
# Returns the pagination path as a string
|
107
|
+
def self.paginate_path(template_url, cur_page_nr, permalink_format)
|
108
|
+
return nil if cur_page_nr.nil?
|
109
|
+
return template_url if cur_page_nr <= 1
|
110
|
+
if permalink_format.include?(":num")
|
111
|
+
permalink_format = Utils.format_page_number(permalink_format, cur_page_nr)
|
112
|
+
else
|
113
|
+
raise ArgumentError.new("Invalid pagination path: '#{permalink_format}'. It must include ':num'.")
|
114
|
+
end
|
115
|
+
|
116
|
+
Utils.ensure_leading_slash(permalink_format)
|
117
|
+
end #function paginate_path
|
118
|
+
|
119
|
+
end # class CompatibilityUtils
|
120
|
+
end # module J1Paginator
|
121
|
+
end # module Jekyll
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Jekyll
|
2
|
+
module J1Paginator::Generator
|
3
|
+
|
4
|
+
# The default configuration for the Paginator
|
5
|
+
DEFAULT = {
|
6
|
+
'enabled' => false,
|
7
|
+
'collection' => 'posts',
|
8
|
+
'offset' => 0, # Supports skipping x number of posts from the beginning of the post list
|
9
|
+
'per_page' => 10,
|
10
|
+
'permalink' => '/page:num/', # Supports :num as customizable elements
|
11
|
+
'title' => ':title - page :num', # Supports :num as customizable elements
|
12
|
+
'page_num' => 1,
|
13
|
+
'sort_reverse' => false,
|
14
|
+
'sort_field' => 'date',
|
15
|
+
'limit' => 0, # Limit how many content objects to paginate (default: 0, means all)
|
16
|
+
'trail' => {
|
17
|
+
'before' => 0, # Limits how many links to show before the current page in the pagination trail (0, means off, default: 0)
|
18
|
+
'after' => 0, # Limits how many links to show after the current page in the pagination trail (0 means off, default: 0)
|
19
|
+
},
|
20
|
+
'indexpage' => 'index', # The default name of the index pages
|
21
|
+
'extension' => 'html', # The default extension for the output pages (ignored if indexpage is nil)
|
22
|
+
'debug' => false, # Turns on debug output for the gem
|
23
|
+
'legacy' => false # Internal value, do not use (will be removed after 2018-01-01)
|
24
|
+
}
|
25
|
+
|
26
|
+
end # module J1Paginator
|
27
|
+
end # module Jekyll
|
@@ -0,0 +1,146 @@
|
|
1
|
+
module Jekyll
|
2
|
+
module J1Paginator::Generator
|
3
|
+
|
4
|
+
#
|
5
|
+
# The main entry point into the generator, called by Jekyll
|
6
|
+
# this function extracts all the necessary information from the jekyll end and passes it into the pagination
|
7
|
+
# logic. Additionally it also contains all site specific actions that the pagination logic needs access to
|
8
|
+
# (such as how to create new pages)
|
9
|
+
#
|
10
|
+
class PaginationGenerator < Generator
|
11
|
+
# This generator is safe from arbitrary code execution.
|
12
|
+
safe true
|
13
|
+
|
14
|
+
# This generator should be passive with regard to its execution
|
15
|
+
priority :lowest
|
16
|
+
|
17
|
+
# Generate paginated pages if necessary (Default entry point)
|
18
|
+
# site - The Site.
|
19
|
+
#
|
20
|
+
# Returns nothing.
|
21
|
+
def generate(site)
|
22
|
+
#begin
|
23
|
+
# Generate the AutoPages first
|
24
|
+
J1Paginator::AutoPages.create_autopages(site)
|
25
|
+
|
26
|
+
# Retrieve and merge the pagination configuration from the site yml file
|
27
|
+
default_config = Jekyll::Utils.deep_merge_hashes(DEFAULT, site.config['pagination'] || {})
|
28
|
+
|
29
|
+
# Compatibility Note: (REMOVE AFTER 2018-01-01)
|
30
|
+
# If the legacy paginate logic is configured then read those values and merge with config
|
31
|
+
if !site.config['paginate'].nil?
|
32
|
+
Jekyll.logger.info "Pagination:","Legacy paginate configuration settings detected and will be used."
|
33
|
+
# You cannot run both the new code and the old code side by side
|
34
|
+
if !site.config['pagination'].nil?
|
35
|
+
err_msg = "The new j1_paginator and the old jekyll-paginate logic cannot both be configured in the site config at the same time. Please disable the old 'paginate:' config settings by either omitting the values or setting them to 'paginate:off'."
|
36
|
+
Jekyll.logger.error err_msg
|
37
|
+
raise ArgumentError.new(err_msg)
|
38
|
+
end
|
39
|
+
|
40
|
+
default_config['per_page'] = site.config['paginate'].to_i
|
41
|
+
default_config['legacy_source'] = site.config['source']
|
42
|
+
if !site.config['paginate_path'].nil?
|
43
|
+
default_config['permalink'] = site.config['paginate_path'].to_s
|
44
|
+
end
|
45
|
+
# In case of legacy, enable pagination by default
|
46
|
+
default_config['enabled'] = true
|
47
|
+
default_config['legacy'] = true
|
48
|
+
end # Compatibility END (REMOVE AFTER 2018-01-01)
|
49
|
+
|
50
|
+
# If disabled then simply quit
|
51
|
+
if !default_config['enabled']
|
52
|
+
Jekyll.logger.info "Pagination:","Disabled in site.config."
|
53
|
+
return
|
54
|
+
end
|
55
|
+
|
56
|
+
# Handle deprecation of settings and features
|
57
|
+
if( !default_config['title_suffix' ].nil? )
|
58
|
+
Jekyll::Deprecator.deprecation_message "Pagination: The 'title_suffix' configuration has been deprecated. Please use 'title'. See https://github.com/sverrirs/j1_paginator/blob/master/README-GENERATOR.md#site-configuration"
|
59
|
+
end
|
60
|
+
|
61
|
+
Jekyll.logger.debug "Pagination:","Starting"
|
62
|
+
|
63
|
+
################ 0 ####################
|
64
|
+
# Get all pages in the site (this will be used to find the pagination templates)
|
65
|
+
all_pages = site.pages
|
66
|
+
|
67
|
+
# Get the default title of the site (used as backup when there is no title available for pagination)
|
68
|
+
site_title = site.config['title']
|
69
|
+
|
70
|
+
################ 1 ####################
|
71
|
+
# Specify the callback function that returns the correct docs/posts based on the collection name
|
72
|
+
# "posts" are just another collection in Jekyll but a specialized version that require timestamps
|
73
|
+
# This collection is the default and if the user doesn't specify a collection in their front-matter then that is the one we load
|
74
|
+
# If the collection is not found then empty array is returned
|
75
|
+
collection_by_name_lambda = lambda do |collection_name|
|
76
|
+
coll = []
|
77
|
+
if collection_name == "all"
|
78
|
+
# the 'all' collection_name is a special case and includes all collections in the site (except posts!!)
|
79
|
+
# this is useful when you want to list items across multiple collections
|
80
|
+
site.collections.each do |coll_name, coll_data|
|
81
|
+
if( !coll_data.nil? && coll_name != 'posts')
|
82
|
+
coll += coll_data.docs.select { |doc| !doc.data.has_key?('pagination') } # Exclude all pagination pages
|
83
|
+
end
|
84
|
+
end
|
85
|
+
else
|
86
|
+
# Just the one collection requested
|
87
|
+
if !site.collections.has_key?(collection_name)
|
88
|
+
return []
|
89
|
+
end
|
90
|
+
|
91
|
+
coll = site.collections[collection_name].docs.select { |doc| !doc.data.has_key?('pagination') } # Exclude all pagination pages
|
92
|
+
end
|
93
|
+
return coll
|
94
|
+
end
|
95
|
+
|
96
|
+
################ 2 ####################
|
97
|
+
# Create the proc that constructs the real-life site page
|
98
|
+
# This is necessary to decouple the code from the Jekyll site object
|
99
|
+
page_add_lambda = lambda do | newpage |
|
100
|
+
site.pages << newpage # Add the page to the site so that it is generated correctly
|
101
|
+
return newpage # Return the site to the calling code
|
102
|
+
end
|
103
|
+
|
104
|
+
################ 2.5 ####################
|
105
|
+
# lambda that removes a page from the site pages list
|
106
|
+
page_remove_lambda = lambda do | page_to_remove |
|
107
|
+
site.pages.delete_if {|page| page == page_to_remove }
|
108
|
+
end
|
109
|
+
|
110
|
+
################ 3 ####################
|
111
|
+
# Create a proc that will delegate logging
|
112
|
+
# Decoupling Jekyll specific logging
|
113
|
+
logging_lambda = lambda do | message, type="info" |
|
114
|
+
if type == 'debug'
|
115
|
+
Jekyll.logger.debug "Pagination:","#{message}"
|
116
|
+
elsif type == 'error'
|
117
|
+
Jekyll.logger.error "Pagination:", "#{message}"
|
118
|
+
elsif type == 'warn'
|
119
|
+
Jekyll.logger.warn "Pagination:", "#{message}"
|
120
|
+
else
|
121
|
+
Jekyll.logger.info "Pagination:", "#{message}"
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
################ 4 ####################
|
126
|
+
# Now create and call the model with the real-life page creation proc and site data
|
127
|
+
model = PaginationModel.new(logging_lambda, page_add_lambda, page_remove_lambda, collection_by_name_lambda)
|
128
|
+
if( default_config['legacy'] ) #(REMOVE AFTER 2018-01-01)
|
129
|
+
Jekyll.logger.warn "Pagination:", "You are running jekyll-paginate backwards compatible pagination logic. Please ignore all earlier warnings displayed related to the old jekyll-paginate gem."
|
130
|
+
all_posts = site.site_payload['site']['posts'].reject { |post| post['hidden'] }
|
131
|
+
model.run_compatability(default_config, all_pages, site_title, all_posts) #(REMOVE AFTER 2018-01-01)
|
132
|
+
else
|
133
|
+
count = model.run(default_config, all_pages, site_title)
|
134
|
+
Jekyll.logger.info ""
|
135
|
+
Jekyll.logger.info "Pagination:", "Complete, processed #{count} pagination page(s)"
|
136
|
+
end
|
137
|
+
|
138
|
+
#rescue => ex
|
139
|
+
# puts ex.backtrace
|
140
|
+
# raise
|
141
|
+
#end
|
142
|
+
end # function generate
|
143
|
+
end # class PaginationGenerator
|
144
|
+
|
145
|
+
end # module J1Paginator
|
146
|
+
end # module Jekyll
|
@@ -0,0 +1,116 @@
|
|
1
|
+
module Jekyll
|
2
|
+
module J1Paginator::Generator
|
3
|
+
|
4
|
+
#
|
5
|
+
# Performs indexing of the posts or collection documents
|
6
|
+
# as well as filtering said collections when requested by the defined filters.
|
7
|
+
class PaginationIndexer
|
8
|
+
#
|
9
|
+
# Create a hash index for all post based on a key in the post.data table
|
10
|
+
#
|
11
|
+
def self.index_posts_by(all_posts, index_key)
|
12
|
+
return nil if all_posts.nil?
|
13
|
+
return all_posts if index_key.nil?
|
14
|
+
index = {}
|
15
|
+
all_posts.each do |post|
|
16
|
+
next if post.data.nil?
|
17
|
+
next if !post.data.has_key?(index_key)
|
18
|
+
next if post.data[index_key].nil?
|
19
|
+
next if post.data[index_key].size <= 0
|
20
|
+
next if post.data[index_key].to_s.strip.length == 0
|
21
|
+
|
22
|
+
# Only tags and categories come as premade arrays, locale does not, so convert any data
|
23
|
+
# elements that are strings into arrays
|
24
|
+
post_data = post.data[index_key]
|
25
|
+
if post_data.is_a?(String)
|
26
|
+
post_data = post_data.split(/;|,|\s/)
|
27
|
+
end
|
28
|
+
|
29
|
+
post_data.each do |key|
|
30
|
+
key = key.to_s.downcase.strip
|
31
|
+
# If the key is a delimetered list of values
|
32
|
+
# (meaning the user didn't use an array but a string with commas)
|
33
|
+
key.split(/;|,/).each do |k_split|
|
34
|
+
k_split = k_split.to_s.downcase.strip #Clean whitespace and junk
|
35
|
+
if !index.has_key?(k_split)
|
36
|
+
index[k_split.to_s] = []
|
37
|
+
end
|
38
|
+
index[k_split.to_s] << post
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
return index
|
43
|
+
end # function index_posts_by
|
44
|
+
|
45
|
+
#
|
46
|
+
# Creates an intersection (only returns common elements)
|
47
|
+
# between multiple arrays
|
48
|
+
#
|
49
|
+
def self.intersect_arrays(first, *rest)
|
50
|
+
return nil if first.nil?
|
51
|
+
return nil if rest.nil?
|
52
|
+
|
53
|
+
intersect = first
|
54
|
+
rest.each do |item|
|
55
|
+
return [] if item.nil?
|
56
|
+
intersect = intersect & item
|
57
|
+
end
|
58
|
+
return intersect
|
59
|
+
end #function intersect_arrays
|
60
|
+
|
61
|
+
#
|
62
|
+
# Filters posts based on a keyed source_posts hash of indexed posts and performs a intersection of
|
63
|
+
# the two sets. Returns only posts that are common between all collections
|
64
|
+
#
|
65
|
+
def self.read_config_value_and_filter_posts(config, config_key, posts, source_posts)
|
66
|
+
return nil if posts.nil?
|
67
|
+
return nil if source_posts.nil? # If the source is empty then simply don't do anything
|
68
|
+
return posts if config.nil?
|
69
|
+
|
70
|
+
plural_key = Utils.plural(config_key)
|
71
|
+
|
72
|
+
return posts if !config.has_key?(config_key) && !config.has_key?(plural_key)
|
73
|
+
return posts if config[config_key].nil? && config[plural_key].nil?
|
74
|
+
|
75
|
+
# Get the filter values from the config (this is the cat/tag/locale values that should be filtered on)
|
76
|
+
|
77
|
+
if config[config_key].is_a?(Hash) || config[plural_key].is_a?(Hash)
|
78
|
+
# { values: [..], matching: any|all }
|
79
|
+
config_hash = config[config_key].is_a?(Hash) ? config[config_key] : config[plural_key]
|
80
|
+
config_value = Utils.config_values(config_hash, 'value')
|
81
|
+
matching = config_hash['matching'] || 'all'
|
82
|
+
else
|
83
|
+
# Default array syntax
|
84
|
+
config_value = Utils.config_values(config, config_key)
|
85
|
+
matching = 'all'
|
86
|
+
end
|
87
|
+
|
88
|
+
matching = matching.to_s.downcase.strip
|
89
|
+
|
90
|
+
# Filter on any/all specified categories, etc.
|
91
|
+
|
92
|
+
if matching == "all"
|
93
|
+
# Now for all filter values for the config key, let's remove all items from the posts that
|
94
|
+
# aren't common for all collections that the user wants to filter on
|
95
|
+
config_value.each do |key|
|
96
|
+
key = key.to_s.downcase.strip
|
97
|
+
posts = PaginationIndexer.intersect_arrays(posts, source_posts[key])
|
98
|
+
end
|
99
|
+
|
100
|
+
elsif matching == "any"
|
101
|
+
# "or" filter: Remove posts that don't have at least one required key
|
102
|
+
posts.delete_if { |post|
|
103
|
+
post_config = Utils.config_values(post.data, config_key)
|
104
|
+
(config_value & post_config).empty?
|
105
|
+
}
|
106
|
+
|
107
|
+
# else no filter
|
108
|
+
end
|
109
|
+
|
110
|
+
# The fully filtered final post list
|
111
|
+
return posts
|
112
|
+
end #function read_config_value_and_filter_posts
|
113
|
+
end #class PaginationIndexer
|
114
|
+
|
115
|
+
end #module J1Paginator
|
116
|
+
end #module Jekyll
|