j1_paginator 2019.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|