jekyll-paginate-v3 0.1.0.alpha → 0.1.0.alpha.2
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
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 036fbbfba18f61ae73a069e4330fce833a1cb7549704c9bf396961ddd262569f
|
|
4
|
+
data.tar.gz: 061d674f1bfd29de53bb79bc5a64feb8076a80af38f59be877f3cc77443173ff
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e6561b1d072672dabdbace597b3b7d310a3f357f7d9b05a1f6815d7b29e634029faf7828ca8105edf6cc41fd1cab276e215de8343358c53e42b482e005f64235
|
|
7
|
+
data.tar.gz: 259bd8d452c747203d316a977de290141b11bc1061a39386e0bac81733f1ace2b08ef0b9c1d8092212e232544bb6f8f758e2e49327b6779f54116e555213a7d4
|
|
@@ -39,23 +39,14 @@ class PaginationGenerator < Jekyll::Generator
|
|
|
39
39
|
|
|
40
40
|
# Abstract site mutation so the model can add pages or documents
|
|
41
41
|
# without knowing where Jekyll stores each item type.
|
|
42
|
-
add_item_lambda = lambda do |item|
|
|
43
|
-
|
|
44
|
-
site.collections[item.collection.label].docs << item
|
|
45
|
-
else
|
|
46
|
-
site.pages << item
|
|
47
|
-
end
|
|
48
|
-
item
|
|
42
|
+
add_item_lambda = lambda do |item, collection_index: nil|
|
|
43
|
+
add_site_item(site, item, collection_index: collection_index)
|
|
49
44
|
end
|
|
50
45
|
|
|
51
46
|
# Mirror add_item_lambda for replacing template pages with generated
|
|
52
47
|
# paginated siblings.
|
|
53
48
|
remove_item_lambda = lambda do |item|
|
|
54
|
-
|
|
55
|
-
site.collections[item.collection.label].docs.delete_if { |doc| doc == item }
|
|
56
|
-
else
|
|
57
|
-
site.pages.delete_if { |page| page == item }
|
|
58
|
-
end
|
|
49
|
+
remove_site_item(site, item)
|
|
59
50
|
end
|
|
60
51
|
|
|
61
52
|
model = Pagination::Model.new(
|
|
@@ -87,6 +78,60 @@ class PaginationGenerator < Jekyll::Generator
|
|
|
87
78
|
|
|
88
79
|
private
|
|
89
80
|
|
|
81
|
+
# Adds one generated page/document to the appropriate site collection.
|
|
82
|
+
#
|
|
83
|
+
# `collection_index` is optional and is only used when pagination needs
|
|
84
|
+
# to replace a source collection document without disturbing the
|
|
85
|
+
# ordering of surrounding documents.
|
|
86
|
+
def add_site_item(site, item, collection_index: nil)
|
|
87
|
+
if item.is_a?(Jekyll::Document)
|
|
88
|
+
add_collection_document(site, item, collection_index: collection_index)
|
|
89
|
+
else
|
|
90
|
+
site.pages << item
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
item
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# Inserts one generated collection document either at a precise source
|
|
97
|
+
# position or at the end of the collection when no preserved position
|
|
98
|
+
# is required.
|
|
99
|
+
def add_collection_document(site, item, collection_index: nil)
|
|
100
|
+
collection_docs = site.collections[item.collection.label].docs
|
|
101
|
+
if collection_index.nil?
|
|
102
|
+
collection_docs << item
|
|
103
|
+
return
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
safe_collection_index = [[collection_index.to_i, 0].max, collection_docs.length].min
|
|
107
|
+
collection_docs.insert(safe_collection_index, item)
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
# Removes one item from the site and returns collection position
|
|
111
|
+
# metadata when the removed item came from a collection.
|
|
112
|
+
def remove_site_item(site, item)
|
|
113
|
+
if item.is_a?(Jekyll::Document)
|
|
114
|
+
return remove_collection_document(site, item)
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
site.pages.delete_if { |page| page.equal?(item) }
|
|
118
|
+
nil
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
# Removes one collection document by exact array position so the
|
|
122
|
+
# generated replacement can later reuse the same slot.
|
|
123
|
+
def remove_collection_document(site, item)
|
|
124
|
+
collection_docs = site.collections[item.collection.label].docs
|
|
125
|
+
collection_index = collection_docs.index { |document| document.equal?(item) }
|
|
126
|
+
return nil if collection_index.nil?
|
|
127
|
+
|
|
128
|
+
collection_docs.delete_at(collection_index)
|
|
129
|
+
{
|
|
130
|
+
'collection_label' => item.collection.label.to_s,
|
|
131
|
+
'index' => collection_index
|
|
132
|
+
}
|
|
133
|
+
end
|
|
134
|
+
|
|
90
135
|
# Logs one info-level summary line for each configured generate entry.
|
|
91
136
|
def log_generate_report(logger, generated_template_report)
|
|
92
137
|
report_entries = Utils.arrayify(generated_template_report['entries'])
|
|
@@ -160,6 +160,9 @@ class Model
|
|
|
160
160
|
# Captures the source items used by later `items` searches so
|
|
161
161
|
# pagination item resolution remains stable even after templates are
|
|
162
162
|
# removed and replaced by generated index pages.
|
|
163
|
+
#
|
|
164
|
+
# This frozen snapshot is the invariant that stops emitted pagination
|
|
165
|
+
# pages from feeding back into later item searches.
|
|
163
166
|
def capture_item_resolution_sources!
|
|
164
167
|
@item_resolution_pages = @site.pages.dup
|
|
165
168
|
@item_resolution_documents_by_collection = {}
|
|
@@ -436,9 +439,12 @@ class Model
|
|
|
436
439
|
# applies generic inclusion/exclusion flags.
|
|
437
440
|
#
|
|
438
441
|
# `exclude_items` is used by the pagination pipeline to remove the
|
|
439
|
-
# active source template from its own item set
|
|
440
|
-
#
|
|
441
|
-
|
|
442
|
+
# active source template from its own item set while leaving other
|
|
443
|
+
# pagination templates eligible for ordinary item searches.
|
|
444
|
+
#
|
|
445
|
+
# Emitted pagination indexes are kept out by the frozen source items
|
|
446
|
+
# captured earlier in the pipeline, rather than by ad hoc filtering.
|
|
447
|
+
def resolve_items(raw_search, include_hidden: false, exclude_items: nil)
|
|
442
448
|
entries = Query::Parser.parse(raw_search, @site_config['keywords'], split_delimiter: @split_delimiter)
|
|
443
449
|
if entries.empty?
|
|
444
450
|
log("Resolving items from search=#{raw_search.inspect} produced no parsed entries.", 'debug')
|
|
@@ -446,7 +452,7 @@ class Model
|
|
|
446
452
|
end
|
|
447
453
|
|
|
448
454
|
excluded_item_keys = excluded_item_identity_keys(exclude_items)
|
|
449
|
-
log("Resolving items from search=#{raw_search.inspect} (entries=#{entries.length},
|
|
455
|
+
log("Resolving items from search=#{raw_search.inspect} (entries=#{entries.length}, include_hidden=#{include_hidden}, exclude_items=#{excluded_item_keys.length}).", 'debug')
|
|
450
456
|
resolved = []
|
|
451
457
|
entries.each do |entry|
|
|
452
458
|
resolved.concat(resolve_entry(entry))
|
|
@@ -457,18 +463,14 @@ class Model
|
|
|
457
463
|
log("Resolved #{resolved.length} unique item(s) before exclusion filters.", 'debug')
|
|
458
464
|
log_item_path_sample('Resolved item sample before exclusions', resolved)
|
|
459
465
|
|
|
460
|
-
excluded_generated_indexes = include_generated_indexes ? 0 : resolved.count { |item| Utils.generated_index?(item) }
|
|
461
|
-
excluded_templates = include_templates ? 0 : resolved.count { |item| Utils.pagination_template?(item) }
|
|
462
466
|
excluded_hidden = include_hidden ? 0 : resolved.count { |item| item['hidden'] }
|
|
463
467
|
excluded_explicit_items = excluded_item_keys.empty? ? 0 : resolved.count { |item| excluded_item_keys.include?(item_identity_key(item)) }
|
|
464
468
|
|
|
465
|
-
resolved.select! { |item| !Utils.generated_index?(item) } unless include_generated_indexes
|
|
466
|
-
resolved.select! { |item| !Utils.pagination_template?(item) } unless include_templates
|
|
467
469
|
resolved.select! { |item| !item['hidden'] } unless include_hidden
|
|
468
470
|
resolved.select! { |item| !excluded_item_keys.include?(item_identity_key(item)) } unless excluded_item_keys.empty?
|
|
469
471
|
|
|
470
|
-
if
|
|
471
|
-
log("Excluded
|
|
472
|
+
if excluded_hidden.positive? || excluded_explicit_items.positive?
|
|
473
|
+
log("Excluded hidden=#{excluded_hidden} explicit=#{excluded_explicit_items} from resolved items.", 'debug')
|
|
472
474
|
end
|
|
473
475
|
log("Resolved #{resolved.length} item(s) after exclusion filters.", 'debug')
|
|
474
476
|
log_item_path_sample('Resolved item sample after exclusions', resolved)
|
|
@@ -25,6 +25,7 @@ class Model
|
|
|
25
25
|
|
|
26
26
|
total_paginated_items = 0
|
|
27
27
|
total_indexes = 0
|
|
28
|
+
collection_replacement_state = nil
|
|
28
29
|
|
|
29
30
|
variants.each_with_index do |variant, variant_index|
|
|
30
31
|
variant_template = variant['template']
|
|
@@ -33,8 +34,10 @@ class Model
|
|
|
33
34
|
variant_template,
|
|
34
35
|
variant_config,
|
|
35
36
|
remove_source_template: variant_index.zero?,
|
|
36
|
-
item_exclusions: item_exclusions
|
|
37
|
+
item_exclusions: item_exclusions,
|
|
38
|
+
collection_replacement_state: collection_replacement_state
|
|
37
39
|
)
|
|
40
|
+
collection_replacement_state = variant_report['collection_replacement_state']
|
|
38
41
|
total_paginated_items += variant_report['paginated_items'].to_i
|
|
39
42
|
total_indexes += variant_report['indexes'].to_i
|
|
40
43
|
end
|
|
@@ -46,9 +49,8 @@ class Model
|
|
|
46
49
|
end
|
|
47
50
|
|
|
48
51
|
# Returns the per-template item exclusions required to prevent a
|
|
49
|
-
# template from paginating over itself when
|
|
50
|
-
#
|
|
51
|
-
# templates remain excluded by normal item-resolution rules.
|
|
52
|
+
# template from paginating over itself when pagination templates are
|
|
53
|
+
# otherwise eligible during item resolution.
|
|
52
54
|
def pagination_item_exclusions_for_template(template)
|
|
53
55
|
[template]
|
|
54
56
|
end
|
|
@@ -80,7 +82,7 @@ class Model
|
|
|
80
82
|
end
|
|
81
83
|
|
|
82
84
|
# Runs pagination for one already-expanded template variant.
|
|
83
|
-
def paginate_template_variant(template, config, remove_source_template:, item_exclusions:)
|
|
85
|
+
def paginate_template_variant(template, config, remove_source_template:, item_exclusions:, collection_replacement_state:)
|
|
84
86
|
template_path = Utils.relative_item_path(template)
|
|
85
87
|
split_delimiter = config.key?('split') ? config['split'] : @split_delimiter
|
|
86
88
|
nested_separator = config['separator'] || @nested_separator
|
|
@@ -128,23 +130,30 @@ class Model
|
|
|
128
130
|
validate_numbered_permalink_template!(template, config, total_pages)
|
|
129
131
|
|
|
130
132
|
log("Template '#{template_path}': generating #{total_pages} page(s) with per_page=#{config['per_page']} limit=#{config['limit']}.", 'debug')
|
|
131
|
-
|
|
133
|
+
page_emission = emit_paginated_pages(
|
|
132
134
|
template,
|
|
133
135
|
config,
|
|
134
136
|
sorted_items,
|
|
135
137
|
page_windows,
|
|
136
|
-
remove_template: remove_source_template
|
|
138
|
+
remove_template: remove_source_template,
|
|
139
|
+
collection_replacement_state: collection_replacement_state
|
|
137
140
|
)
|
|
141
|
+
generated_pages = page_emission['pages']
|
|
142
|
+
collection_replacement_state = page_emission['collection_replacement_state']
|
|
138
143
|
register_grouped_set_if_applicable(template, config, generated_pages)
|
|
139
144
|
{
|
|
140
145
|
'paginated_items' => sorted_items.length,
|
|
141
|
-
'indexes' => generated_pages.length
|
|
146
|
+
'indexes' => generated_pages.length,
|
|
147
|
+
'collection_replacement_state' => collection_replacement_state
|
|
142
148
|
}
|
|
143
149
|
end
|
|
144
150
|
|
|
145
151
|
# Replaces a template with one synthetic page/document per page number.
|
|
146
|
-
def emit_paginated_pages(template, config, items, page_windows, remove_template: true)
|
|
147
|
-
|
|
152
|
+
def emit_paginated_pages(template, config, items, page_windows, remove_template: true, collection_replacement_state: nil)
|
|
153
|
+
if remove_template
|
|
154
|
+
removed_item_state = @remove_item_lambda.call(template)
|
|
155
|
+
collection_replacement_state = build_collection_replacement_state(template, removed_item_state)
|
|
156
|
+
end
|
|
148
157
|
|
|
149
158
|
new_pages = []
|
|
150
159
|
total_pages = page_windows.length
|
|
@@ -192,14 +201,50 @@ class Model
|
|
|
192
201
|
assign_generated_page_title!(generated, template, config, current_page, total_pages)
|
|
193
202
|
assign_generated_page_permalink!(generated, template, config, current_page, total_pages)
|
|
194
203
|
|
|
195
|
-
@add_item_lambda.call(
|
|
204
|
+
@add_item_lambda.call(
|
|
205
|
+
generated,
|
|
206
|
+
collection_index: collection_insertion_index_for_generated_item(generated, collection_replacement_state)
|
|
207
|
+
)
|
|
196
208
|
log("Emitted pagination page #{current_page}/#{total_pages} at '#{generated.url}' for template '#{Utils.relative_item_path(template)}'.", 'debug')
|
|
197
209
|
new_pages << generated
|
|
198
210
|
end
|
|
199
211
|
|
|
200
212
|
bind_paginator_references(new_pages)
|
|
201
213
|
apply_page_trail(new_pages, config)
|
|
202
|
-
|
|
214
|
+
{
|
|
215
|
+
'pages' => new_pages,
|
|
216
|
+
'collection_replacement_state' => collection_replacement_state
|
|
217
|
+
}
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
# Builds insertion state for collection-template replacement.
|
|
221
|
+
#
|
|
222
|
+
# The state stores a moving insertion cursor so any generated
|
|
223
|
+
# collection documents can occupy the template's original source slot
|
|
224
|
+
# and then continue immediately after it.
|
|
225
|
+
def build_collection_replacement_state(template, removed_item_state)
|
|
226
|
+
return nil unless collection_template?(template)
|
|
227
|
+
|
|
228
|
+
removed_item_state = Utils.safe_hash(removed_item_state)
|
|
229
|
+
return nil if removed_item_state.empty?
|
|
230
|
+
return nil if removed_item_state['collection_label'].to_s != template.collection.label.to_s
|
|
231
|
+
|
|
232
|
+
{
|
|
233
|
+
'source_collection_label' => template.collection.label.to_s,
|
|
234
|
+
'next_index' => removed_item_state['index'].to_i
|
|
235
|
+
}
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
# Returns the next insertion index for a generated document that
|
|
239
|
+
# belongs in the same collection as the template it replaced.
|
|
240
|
+
def collection_insertion_index_for_generated_item(generated, collection_replacement_state)
|
|
241
|
+
return nil if collection_replacement_state.nil?
|
|
242
|
+
return nil unless generated.is_a?(Jekyll::Document)
|
|
243
|
+
return nil if generated.collection.label.to_s != collection_replacement_state['source_collection_label'].to_s
|
|
244
|
+
|
|
245
|
+
insertion_index = collection_replacement_state['next_index'].to_i
|
|
246
|
+
collection_replacement_state['next_index'] = insertion_index + 1
|
|
247
|
+
insertion_index
|
|
203
248
|
end
|
|
204
249
|
|
|
205
250
|
# Builds one generated index object according to configured collection mode.
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: jekyll-paginate-v3
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.0.alpha
|
|
4
|
+
version: 0.1.0.alpha.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Convincible
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-03-
|
|
11
|
+
date: 2026-03-27 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: jekyll
|