pagy 8.6.0 → 9.0.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 +4 -4
- data/apps/calendar.ru +5 -5
- data/apps/demo.ru +8 -9
- data/apps/keyset_ar.ru +236 -0
- data/apps/keyset_s.ru +238 -0
- data/apps/rails.ru +7 -9
- data/apps/repro.ru +5 -6
- data/apps/tmp/calendar.sqlite3 +0 -0
- data/apps/tmp/calendar.sqlite3-shm +0 -0
- data/apps/tmp/calendar.sqlite3-wal +0 -0
- data/apps/tmp/local_secret.txt +1 -1
- data/apps/tmp/pagy-keyset-ar.sqlite3 +0 -0
- data/apps/tmp/{pagy-rails.sqlite3 → pagy-keyset-ar.sqlite3-shm} +0 -0
- data/apps/tmp/pagy-keyset-ar.sqlite3-wal +0 -0
- data/apps/tmp/pagy-keyset-s.sqlite3 +0 -0
- data/bin/pagy +4 -2
- data/config/pagy.rb +34 -31
- data/javascripts/pagy-module.js +1 -1
- data/javascripts/pagy.js +2 -2
- data/javascripts/pagy.min.js +2 -2
- data/javascripts/pagy.min.js.map +3 -3
- data/javascripts/pagy.mjs +2 -2
- data/lib/pagy/b64.rb +33 -0
- data/lib/pagy/backend.rb +21 -17
- data/lib/pagy/calendar/day.rb +1 -1
- data/lib/pagy/calendar/month.rb +1 -1
- data/lib/pagy/calendar/quarter.rb +1 -1
- data/lib/pagy/calendar/unit.rb +7 -10
- data/lib/pagy/calendar/week.rb +1 -1
- data/lib/pagy/calendar/year.rb +1 -1
- data/lib/pagy/calendar.rb +5 -5
- data/lib/pagy/countless.rb +11 -15
- data/lib/pagy/extras/arel.rb +8 -10
- data/lib/pagy/extras/array.rb +4 -6
- data/lib/pagy/extras/bootstrap.rb +5 -5
- data/lib/pagy/extras/bulma.rb +10 -7
- data/lib/pagy/extras/calendar.rb +4 -5
- data/lib/pagy/extras/countless.rb +15 -13
- data/lib/pagy/extras/elasticsearch_rails.rb +15 -15
- data/lib/pagy/extras/gearbox.rb +26 -26
- data/lib/pagy/extras/headers.rb +25 -24
- data/lib/pagy/extras/js_tools.rb +8 -8
- data/lib/pagy/extras/jsonapi.rb +26 -16
- data/lib/pagy/extras/keyset.rb +36 -0
- data/lib/pagy/extras/limit.rb +63 -0
- data/lib/pagy/extras/meilisearch.rb +11 -11
- data/lib/pagy/extras/metadata.rb +2 -2
- data/lib/pagy/extras/overflow.rb +6 -6
- data/lib/pagy/extras/pagy.rb +16 -16
- data/lib/pagy/extras/searchkick.rb +11 -11
- data/lib/pagy/extras/size.rb +2 -2
- data/lib/pagy/extras/standalone.rb +6 -6
- data/lib/pagy/extras/trim.rb +2 -2
- data/lib/pagy/frontend.rb +32 -33
- data/lib/pagy/i18n.rb +1 -1
- data/lib/pagy/keyset/active_record.rb +38 -0
- data/lib/pagy/keyset/sequel.rb +51 -0
- data/lib/pagy/keyset.rb +98 -0
- data/lib/pagy/shared_methods.rb +27 -0
- data/lib/pagy/url_helpers.rb +4 -4
- data/lib/pagy.rb +54 -68
- data/locales/ar.yml +2 -1
- data/locales/be.yml +1 -1
- data/locales/bg.yml +1 -1
- data/locales/bs.yml +1 -1
- data/locales/ca.yml +1 -1
- data/locales/ckb.yml +1 -1
- data/locales/cs.yml +1 -1
- data/locales/da.yml +1 -1
- data/locales/de.yml +1 -1
- data/locales/en.yml +1 -1
- data/locales/es.yml +1 -1
- data/locales/fr.yml +1 -1
- data/locales/hr.yml +1 -1
- data/locales/id.yml +1 -1
- data/locales/it.yml +1 -1
- data/locales/ja.yml +1 -1
- data/locales/km.yml +1 -1
- data/locales/ko.yml +1 -1
- data/locales/nb.yml +1 -1
- data/locales/nl.yml +1 -1
- data/locales/nn.yml +1 -1
- data/locales/pl.yml +1 -1
- data/locales/pt-BR.yml +1 -1
- data/locales/pt.yml +1 -1
- data/locales/ru.yml +1 -1
- data/locales/sr.yml +1 -1
- data/locales/sv-SE.yml +1 -1
- data/locales/sv.yml +1 -1
- data/locales/sw.yml +1 -1
- data/locales/ta.yml +1 -1
- data/locales/tr.yml +1 -1
- data/locales/uk.yml +1 -1
- data/locales/vi.yml +1 -1
- data/locales/zh-CN.yml +1 -1
- data/locales/zh-HK.yml +1 -1
- data/locales/zh-TW.yml +1 -1
- metadata +16 -16
- data/lib/pagy/extras/foundation.rb +0 -95
- data/lib/pagy/extras/items.rb +0 -64
- data/lib/pagy/extras/materialize.rb +0 -100
- data/lib/pagy/extras/semantic.rb +0 -94
- data/lib/pagy/extras/uikit.rb +0 -98
data/lib/pagy/extras/bulma.rb
CHANGED
@@ -8,9 +8,10 @@ class Pagy # :nodoc:
|
|
8
8
|
# The resulting code may not look very elegant, but produces the best benchmarks
|
9
9
|
module BulmaExtra
|
10
10
|
# Pagination for bulma: it returns the html with the series of links to the pages
|
11
|
-
def pagy_bulma_nav(pagy, id: nil, classes: 'pagy-bulma nav pagination is-centered',
|
11
|
+
def pagy_bulma_nav(pagy, id: nil, classes: 'pagy-bulma nav pagination is-centered',
|
12
|
+
aria_label: nil, **vars)
|
12
13
|
id = %( id="#{id}") if id
|
13
|
-
a = pagy_anchor(pagy)
|
14
|
+
a = pagy_anchor(pagy, **vars)
|
14
15
|
|
15
16
|
html = %(<nav#{id} class="#{classes}" #{nav_aria_label(pagy, aria_label:)}>)
|
16
17
|
html << bulma_prev_next_html(pagy, a)
|
@@ -31,10 +32,11 @@ class Pagy # :nodoc:
|
|
31
32
|
end
|
32
33
|
|
33
34
|
# Javascript pagination for bulma: it returns a nav with a data-pagy attribute used by the Pagy.nav javascript
|
34
|
-
def pagy_bulma_nav_js(pagy, id: nil, classes: 'pagy-bulma nav-js pagination is-centered',
|
35
|
+
def pagy_bulma_nav_js(pagy, id: nil, classes: 'pagy-bulma nav-js pagination is-centered',
|
36
|
+
aria_label: nil, **vars)
|
35
37
|
sequels = pagy.sequels(**vars)
|
36
38
|
id = %( id="#{id}") if id
|
37
|
-
a = pagy_anchor(pagy)
|
39
|
+
a = pagy_anchor(pagy, **vars)
|
38
40
|
tokens = { 'before' => %(#{bulma_prev_next_html(pagy, a)}<ul class="pagination-list">),
|
39
41
|
'a' => %(<li>#{a.(PAGE_TOKEN, LABEL_TOKEN, classes: 'pagination-link')}</li>),
|
40
42
|
'current' => %(<li><a role="link" class="pagination-link is-current" aria-current="page" aria-disabled="true">#{
|
@@ -49,9 +51,10 @@ class Pagy # :nodoc:
|
|
49
51
|
end
|
50
52
|
|
51
53
|
# Javascript combo pagination for bulma: it returns a nav with a data-pagy attribute used by the pagy.js file
|
52
|
-
def pagy_bulma_combo_nav_js(pagy, id: nil, classes: 'pagy-bulma combo-nav-js pagination is-centered',
|
54
|
+
def pagy_bulma_combo_nav_js(pagy, id: nil, classes: 'pagy-bulma combo-nav-js pagination is-centered',
|
55
|
+
aria_label: nil, **vars)
|
53
56
|
id = %( id="#{id}") if id
|
54
|
-
a = pagy_anchor(pagy)
|
57
|
+
a = pagy_anchor(pagy, **vars)
|
55
58
|
pages = pagy.pages
|
56
59
|
|
57
60
|
page_input = %(<input name="page" type="number" min="1" max="#{pages}" value="#{pagy.page}" aria-current="page") <<
|
@@ -61,7 +64,7 @@ class Pagy # :nodoc:
|
|
61
64
|
|
62
65
|
%(<nav#{id} class="#{classes}" #{
|
63
66
|
nav_aria_label(pagy, aria_label:)} #{
|
64
|
-
pagy_data(pagy, :combo, pagy_url_for(pagy, PAGE_TOKEN))
|
67
|
+
pagy_data(pagy, :combo, pagy_url_for(pagy, PAGE_TOKEN, **vars))
|
65
68
|
}>#{
|
66
69
|
bulma_prev_next_html(pagy, a)
|
67
70
|
}<ul class="pagination-list"><li class="pagination-link"><label>#{
|
data/lib/pagy/extras/calendar.rb
CHANGED
@@ -27,7 +27,7 @@ class Pagy # :nodoc:
|
|
27
27
|
end
|
28
28
|
collection = pagy_calendar_filter(collection, from, to)
|
29
29
|
end
|
30
|
-
pagy, results = send(conf[:pagy][:backend] || :pagy, collection, conf[:pagy]) # use backend: :pagy when omitted
|
30
|
+
pagy, results = send(conf[:pagy][:backend] || :pagy, collection, **conf[:pagy]) # use backend: :pagy when omitted
|
31
31
|
[calendar, pagy, results]
|
32
32
|
end
|
33
33
|
|
@@ -47,12 +47,11 @@ class Pagy # :nodoc:
|
|
47
47
|
# Override the pagy_anchor
|
48
48
|
module FrontendOverride
|
49
49
|
# Consider the vars[:count]
|
50
|
-
def pagy_anchor(pagy)
|
50
|
+
def pagy_anchor(pagy, anchor_string: nil)
|
51
51
|
return super unless (counts = pagy.vars[:counts])
|
52
52
|
|
53
|
-
|
54
|
-
|
55
|
-
left, right = %(<a#{a_string} href="#{pagy_url_for(pagy, PAGE_TOKEN)}").split(PAGE_TOKEN, 2)
|
53
|
+
anchor_string &&= %( #{anchor_string})
|
54
|
+
left, right = %(<a#{anchor_string} href="#{pagy_url_for(pagy, PAGE_TOKEN)}").split(PAGE_TOKEN, 2)
|
56
55
|
# lambda used by all the helpers
|
57
56
|
lambda do |page, text = pagy.label_for(page), classes: nil, aria_label: nil|
|
58
57
|
count = counts[page - 1]
|
@@ -10,27 +10,29 @@ class Pagy # :nodoc:
|
|
10
10
|
module CountlessExtra
|
11
11
|
private
|
12
12
|
|
13
|
-
# Return Pagy object and
|
14
|
-
def pagy_countless(collection, vars
|
15
|
-
pagy = Countless.new(pagy_countless_get_vars(collection, vars))
|
13
|
+
# Return Pagy object and records
|
14
|
+
def pagy_countless(collection, **vars)
|
15
|
+
pagy = Countless.new(**pagy_countless_get_vars(collection, vars))
|
16
16
|
[pagy, pagy_countless_get_items(collection, pagy)]
|
17
17
|
end
|
18
18
|
|
19
|
-
# Sub-method called only by #pagy_countless: here for easy customization of variables by overriding
|
20
|
-
def pagy_countless_get_vars(_collection, vars)
|
21
|
-
pagy_set_items_from_params(vars) if defined?(ItemsExtra)
|
22
|
-
vars[:page] ||= pagy_get_page(vars)
|
23
|
-
vars
|
24
|
-
end
|
25
|
-
|
26
19
|
# Sub-method called only by #pagy_countless: here for easy customization of record-extraction by overriding
|
27
20
|
# You may need to override this method for collections without offset|limit
|
28
21
|
def pagy_countless_get_items(collection, pagy)
|
29
|
-
return collection.offset(pagy.offset).limit(pagy.
|
22
|
+
return collection.offset(pagy.offset).limit(pagy.limit) if pagy.vars[:countless_minimal]
|
30
23
|
|
31
|
-
fetched = collection.offset(pagy.offset).limit(pagy.
|
24
|
+
fetched = collection.offset(pagy.offset).limit(pagy.limit + 1).to_a # eager load limit + 1
|
32
25
|
pagy.finalize(fetched.size) # finalize the pagy object
|
33
|
-
fetched[0, pagy.
|
26
|
+
fetched[0, pagy.limit] # ignore eventual extra item
|
27
|
+
end
|
28
|
+
|
29
|
+
# Sub-method called only by #pagy: here for easy customization of variables by overriding
|
30
|
+
# You may need to override the count call for non AR collections
|
31
|
+
def pagy_countless_get_vars(_collection, vars)
|
32
|
+
vars.tap do |v|
|
33
|
+
v[:limit] ||= pagy_get_limit(v)
|
34
|
+
v[:page] ||= pagy_get_page(v)
|
35
|
+
end
|
34
36
|
end
|
35
37
|
end
|
36
38
|
Backend.prepend CountlessExtra
|
@@ -28,18 +28,18 @@ class Pagy # :nodoc:
|
|
28
28
|
args.define_singleton_method(:method_missing) { |*a| args += a }
|
29
29
|
end
|
30
30
|
end
|
31
|
-
alias_method
|
31
|
+
alias_method DEFAULT[:elasticsearch_rails_pagy_search], :pagy_elasticsearch_rails
|
32
32
|
end
|
33
33
|
Pagy::ElasticsearchRails = ModelExtension
|
34
34
|
|
35
35
|
# Additions for the Pagy class
|
36
36
|
module PagyAddOn
|
37
37
|
# Create a Pagy object from an Elasticsearch::Model::Response::Response object
|
38
|
-
def new_from_elasticsearch_rails(response, vars
|
39
|
-
vars[:
|
40
|
-
vars[:page] = ((response.search.options[:from] || 0) / vars[:
|
38
|
+
def new_from_elasticsearch_rails(response, **vars)
|
39
|
+
vars[:limit] = response.search.options[:size] || 10
|
40
|
+
vars[:page] = ((response.search.options[:from] || 0) / vars[:limit]) + 1
|
41
41
|
vars[:count] = ElasticsearchRailsExtra.total_count(response)
|
42
|
-
new(vars)
|
42
|
+
Pagy.new(**vars)
|
43
43
|
end
|
44
44
|
end
|
45
45
|
Pagy.extend PagyAddOn
|
@@ -48,19 +48,19 @@ class Pagy # :nodoc:
|
|
48
48
|
module BackendAddOn
|
49
49
|
private
|
50
50
|
|
51
|
-
# Return Pagy object and
|
52
|
-
def pagy_elasticsearch_rails(pagy_search_args, vars
|
51
|
+
# Return Pagy object and records
|
52
|
+
def pagy_elasticsearch_rails(pagy_search_args, **vars)
|
53
53
|
model, query_or_payload,
|
54
54
|
options, *called = pagy_search_args
|
55
55
|
vars = pagy_elasticsearch_rails_get_vars(nil, vars)
|
56
|
-
options[:size] = vars[:
|
57
|
-
options[:from] = vars[:
|
56
|
+
options[:size] = vars[:limit]
|
57
|
+
options[:from] = vars[:limit] * ((vars[:page] || 1) - 1)
|
58
58
|
response = model.send(DEFAULT[:elasticsearch_rails_search], query_or_payload, **options)
|
59
59
|
vars[:count] = ElasticsearchRailsExtra.total_count(response)
|
60
60
|
|
61
|
-
pagy = ::Pagy.new(vars)
|
61
|
+
pagy = ::Pagy.new(**vars)
|
62
62
|
# with :last_page overflow we need to re-run the method in order to get the hits
|
63
|
-
return pagy_elasticsearch_rails(pagy_search_args, vars
|
63
|
+
return pagy_elasticsearch_rails(pagy_search_args, **vars, page: pagy.page) \
|
64
64
|
if defined?(::Pagy::OverflowExtra) && pagy.overflow? && pagy.vars[:overflow] == :last_page
|
65
65
|
|
66
66
|
[pagy, called.empty? ? response : response.send(*called)]
|
@@ -69,10 +69,10 @@ class Pagy # :nodoc:
|
|
69
69
|
# Sub-method called only by #pagy_elasticsearch_rails: here for easy customization of variables by overriding
|
70
70
|
# the _collection argument is not available when the method is called
|
71
71
|
def pagy_elasticsearch_rails_get_vars(_collection, vars)
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
72
|
+
vars.tap do |v|
|
73
|
+
v[:page] ||= pagy_get_page(v)
|
74
|
+
v[:limit] ||= pagy_get_limit(v) || DEFAULT[:limit]
|
75
|
+
end
|
76
76
|
end
|
77
77
|
end
|
78
78
|
Backend.prepend BackendAddOn
|
data/lib/pagy/extras/gearbox.rb
CHANGED
@@ -3,27 +3,39 @@
|
|
3
3
|
|
4
4
|
class Pagy # :nodoc:
|
5
5
|
DEFAULT[:gearbox_extra] = true # extra enabled by default
|
6
|
-
DEFAULT[:
|
6
|
+
DEFAULT[:gearbox_limit] = [15, 30, 60, 100]
|
7
7
|
|
8
|
-
# Automatically change the
|
9
|
-
# accepts an array as the :
|
8
|
+
# Automatically change the limit depending on the page number
|
9
|
+
# accepts an array as the :gearbox_limit variable, that will determine the limit for the first pages
|
10
10
|
module GearboxExtra
|
11
|
-
#
|
12
|
-
def
|
13
|
-
return super if !@vars[:gearbox_extra] || @vars[:
|
11
|
+
# Assign @limit based on the :gearbox_limit variable
|
12
|
+
def assign_limit
|
13
|
+
return super if !@vars[:gearbox_extra] || @vars[:limit_extra]
|
14
14
|
|
15
|
-
gears = @vars[:
|
16
|
-
raise VariableError.new(self, :
|
15
|
+
gears = @vars[:gearbox_limit]
|
16
|
+
raise VariableError.new(self, :gearbox_limit, 'to be an Array of positives', gears) \
|
17
17
|
unless gears.is_a?(Array) && gears.all? { |num| num.positive? rescue false } # rubocop:disable Style/RescueModifier
|
18
18
|
|
19
|
-
@
|
19
|
+
@limit = gears[@page - 1] || gears.last
|
20
20
|
end
|
21
21
|
|
22
|
-
#
|
23
|
-
def
|
24
|
-
return super if !@vars[:gearbox_extra] || @vars[:
|
22
|
+
# Asgnsi @offset based on the :gearbox_limit variable
|
23
|
+
def assign_offset
|
24
|
+
return super if !@vars[:gearbox_extra] || @vars[:limit_extra]
|
25
25
|
|
26
|
-
gears
|
26
|
+
gears = @vars[:gearbox_limit]
|
27
|
+
@offset = if @page <= gears.count
|
28
|
+
gears[0, @page - 1].sum
|
29
|
+
else
|
30
|
+
gears.sum + (gears.last * (@page - gears.count - 1))
|
31
|
+
end + @outset
|
32
|
+
end
|
33
|
+
|
34
|
+
# Assign @last based on the :gearbox_limit variable and @count
|
35
|
+
def assign_last
|
36
|
+
return super if !@vars[:gearbox_extra] || @vars[:limit_extra]
|
37
|
+
|
38
|
+
gears = @vars[:gearbox_limit]
|
27
39
|
# This algorithm is thousands of times faster than the one in the geared_pagination gem
|
28
40
|
@last = (if count > (sum = gears.sum)
|
29
41
|
[((count - sum).to_f / gears.last).ceil, 1].max + gears.count
|
@@ -36,19 +48,7 @@ class Pagy # :nodoc:
|
|
36
48
|
end
|
37
49
|
[pages, 1].max
|
38
50
|
end)
|
39
|
-
@last = vars[:max_pages] if vars[:max_pages] && @last > vars[:max_pages]
|
40
|
-
end
|
41
|
-
|
42
|
-
# Setup @offset based on the :gearbox_items variable
|
43
|
-
def setup_offset_var
|
44
|
-
return super if !@vars[:gearbox_extra] || @vars[:items_extra]
|
45
|
-
|
46
|
-
gears = @vars[:gearbox_items]
|
47
|
-
@offset = if @page <= gears.count
|
48
|
-
gears[0, @page - 1].sum
|
49
|
-
else
|
50
|
-
gears.sum + (gears.last * (@page - gears.count - 1))
|
51
|
-
end + @outset
|
51
|
+
@last = @vars[:max_pages] if @vars[:max_pages] && @last > @vars[:max_pages]
|
52
52
|
end
|
53
53
|
end
|
54
54
|
prepend GearboxExtra
|
data/lib/pagy/extras/headers.rb
CHANGED
@@ -5,7 +5,7 @@ require_relative '../url_helpers'
|
|
5
5
|
|
6
6
|
class Pagy # :nodoc:
|
7
7
|
DEFAULT[:headers] = { page: 'current-page',
|
8
|
-
|
8
|
+
limit: 'page-items',
|
9
9
|
count: 'total-count',
|
10
10
|
pages: 'total-pages' }
|
11
11
|
# Add specialized backend methods to add pagination response headers
|
@@ -21,32 +21,33 @@ class Pagy # :nodoc:
|
|
21
21
|
|
22
22
|
# Generate a hash of RFC-8288 compliant http headers
|
23
23
|
def pagy_headers(pagy)
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
24
|
+
headers = pagy.vars[:headers]
|
25
|
+
pagy_link_header(pagy).tap do |hash|
|
26
|
+
hash[headers[:page]] = pagy.page.to_s if pagy.page && headers[:page]
|
27
|
+
hash[headers[:limit]] = pagy.limit.to_s \
|
28
|
+
if headers[:limit] && !(defined?(Calendar) && pagy.is_a?(Calendar::Unit))
|
29
|
+
return hash if (defined?(Countless) && pagy.is_a?(Countless)) || \
|
30
|
+
(defined?(Keyset) && pagy.is_a?(Keyset))
|
28
31
|
|
29
|
-
|
30
|
-
def pagy_headers_hash(pagy)
|
31
|
-
countless = defined?(Countless) && pagy.is_a?(Countless)
|
32
|
-
rel = { 'first' => 1, 'prev' => pagy.prev, 'next' => pagy.next }
|
33
|
-
rel['last'] = pagy.last unless countless
|
34
|
-
url_str = pagy_url_for(pagy, PAGE_TOKEN, absolute: true)
|
35
|
-
link = rel.filter_map do |r, num|
|
36
|
-
next unless num # rubocop:disable Layout/EmptyLineAfterGuardClause
|
37
|
-
[r, url_str.sub(PAGE_TOKEN, num.to_s)]
|
38
|
-
end.compact.to_h
|
39
|
-
hash = { 'link' => link }
|
40
|
-
headers = pagy.vars[:headers]
|
41
|
-
hash[headers[:page]] = pagy.page.to_s if headers[:page]
|
42
|
-
if headers[:items] && !(defined?(Calendar) && pagy.is_a?(Calendar)) # items is not for Calendar
|
43
|
-
hash[headers[:items]] = pagy.vars[:items].to_s
|
44
|
-
end
|
45
|
-
unless countless
|
46
|
-
hash[headers[:pages]] = pagy.pages.to_s if headers[:pages]
|
32
|
+
hash[headers[:pages]] = pagy.last.to_s if headers[:pages]
|
47
33
|
hash[headers[:count]] = pagy.count.to_s if pagy.count && headers[:count] # count may be nil with Calendar
|
48
34
|
end
|
49
|
-
|
35
|
+
end
|
36
|
+
|
37
|
+
def pagy_link_header(pagy)
|
38
|
+
{ 'link' => [].tap do |link|
|
39
|
+
if defined?(Keyset) && pagy.is_a?(Keyset)
|
40
|
+
link << %(<#{pagy_url_for(pagy, nil, absolute: true)}>; rel="first")
|
41
|
+
link << %(<#{pagy_url_for(pagy, pagy.next, absolute: true)}>; rel="next") if pagy.next
|
42
|
+
else
|
43
|
+
url_str = pagy_url_for(pagy, PAGE_TOKEN, absolute: true)
|
44
|
+
link << %(<#{url_str.sub(PAGE_TOKEN, '1')}>; rel="first")
|
45
|
+
link << %(<#{url_str.sub(PAGE_TOKEN, pagy.prev.to_s)}>; rel="prev") if pagy.prev
|
46
|
+
link << %(<#{url_str.sub(PAGE_TOKEN, pagy.next.to_s)}>; rel="next") if pagy.next
|
47
|
+
link << %(<#{url_str.sub(PAGE_TOKEN, pagy.last.to_s)}>; rel="last") \
|
48
|
+
unless defined?(Countless) && pagy.is_a?(Countless)
|
49
|
+
end
|
50
|
+
end.join(', ') }
|
50
51
|
end
|
51
52
|
end
|
52
53
|
Backend.prepend HeadersExtra
|
data/lib/pagy/extras/js_tools.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require_relative '../b64'
|
4
|
+
|
3
5
|
class Pagy # :nodoc:
|
4
6
|
DEFAULT[:steps] = false # default false will use {0 => @vars[:size]}
|
5
7
|
|
@@ -13,11 +15,11 @@ class Pagy # :nodoc:
|
|
13
15
|
# `Pagy` instance method used by the `pagy*_nav_js` helpers.
|
14
16
|
# It returns the sequels of width/series generated from the :steps hash
|
15
17
|
# Example:
|
16
|
-
# >> pagy = Pagy.new(count:1000, page: 20, steps: {0 =>
|
18
|
+
# >> pagy = Pagy.new(count:1000, page: 20, steps: {0 => 5, 350 => 7, 550 => 9})
|
17
19
|
# >> pagy.sequels
|
18
|
-
# #=> { "0" => [
|
19
|
-
# "350" => [1,
|
20
|
-
# "550" => [1
|
20
|
+
# #=> { "0" => [18, 19, "20", 21, 22],
|
21
|
+
# "350" => [1, :gap, 19, "20", 21, :gap, 50],
|
22
|
+
# "550" => [1 :gap, 18, 19, "20", 21, 22, :gap, 50] }
|
21
23
|
# Notice: if :steps is false it will use the single {0 => @vars[:size]} size
|
22
24
|
def sequels(steps: @vars[:steps] || { 0 => @vars[:size] }, **_)
|
23
25
|
raise VariableError.new(self, :steps, 'to define the 0 width', steps) unless steps.key?(0)
|
@@ -51,8 +53,7 @@ class Pagy # :nodoc:
|
|
51
53
|
# Base64 encoded JSON is smaller than HTML escaped JSON
|
52
54
|
def pagy_data(pagy, *args)
|
53
55
|
args << pagy.vars[:page_param] if pagy.vars[:trim_extra]
|
54
|
-
|
55
|
-
%(data-pagy="#{strict_base64_encoded}")
|
56
|
+
%(data-pagy="#{B64.encode(Oj.dump(args, mode: :strict))}")
|
56
57
|
end
|
57
58
|
else
|
58
59
|
require 'json'
|
@@ -60,8 +61,7 @@ class Pagy # :nodoc:
|
|
60
61
|
# Base64 encoded JSON is smaller than HTML escaped JSON
|
61
62
|
def pagy_data(pagy, *args)
|
62
63
|
args << pagy.vars[:page_param] if pagy.vars[:trim_extra]
|
63
|
-
|
64
|
-
%(data-pagy="#{strict_base64_encoded}")
|
64
|
+
%(data-pagy="#{B64.encode(args.to_json)}")
|
65
65
|
end
|
66
66
|
end
|
67
67
|
end
|
data/lib/pagy/extras/jsonapi.rb
CHANGED
@@ -24,10 +24,17 @@ class Pagy # :nodoc:
|
|
24
24
|
|
25
25
|
# Return the jsonapi links
|
26
26
|
def pagy_jsonapi_links(pagy, **opts)
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
27
|
+
if defined?(Pagy::Keyset) && pagy.is_a?(Pagy::Keyset)
|
28
|
+
{ first: pagy_url_for(pagy, nil, **opts),
|
29
|
+
last: nil,
|
30
|
+
prev: nil,
|
31
|
+
next: pagy.next ? pagy_url_for(pagy, pagy.next, **opts) : nil }
|
32
|
+
else
|
33
|
+
{ first: pagy_url_for(pagy, 1, **opts),
|
34
|
+
last: pagy_url_for(pagy, pagy.last, **opts),
|
35
|
+
prev: pagy.prev ? pagy_url_for(pagy, pagy.prev, **opts) : nil,
|
36
|
+
next: pagy.next ? pagy_url_for(pagy, pagy.next, **opts) : nil }
|
37
|
+
end
|
31
38
|
end
|
32
39
|
|
33
40
|
# Should skip the jsonapi
|
@@ -40,38 +47,41 @@ class Pagy # :nodoc:
|
|
40
47
|
# Override the Backend method
|
41
48
|
def pagy_get_page(vars)
|
42
49
|
return super if pagy_skip_jsonapi?(vars)
|
43
|
-
return
|
50
|
+
return if params[:page].nil?
|
44
51
|
|
45
|
-
|
52
|
+
params[:page][vars[:page_param] || DEFAULT[:page_param]]
|
46
53
|
end
|
47
54
|
end
|
48
55
|
Backend.prepend BackendOverride
|
49
56
|
|
50
|
-
# Module overriding
|
51
|
-
module
|
57
|
+
# Module overriding LimitExtra
|
58
|
+
module LimitExtraOverride
|
52
59
|
private
|
53
60
|
|
54
|
-
# Override the
|
55
|
-
def
|
61
|
+
# Override the LimitExtra::Backend method
|
62
|
+
def pagy_get_limit_param(vars)
|
56
63
|
return super if pagy_skip_jsonapi?(vars)
|
57
64
|
return if params[:page].nil?
|
58
65
|
|
59
|
-
params[:page][vars[:
|
66
|
+
params[:page][vars[:limit_param] || DEFAULT[:limit_param]]
|
60
67
|
end
|
61
68
|
end
|
62
69
|
# :nocov:
|
63
|
-
|
70
|
+
LimitExtra::BackendAddOn.prepend LimitExtraOverride if defined?(LimitExtra::BackendAddOn)
|
64
71
|
# :nocov:
|
65
72
|
|
66
73
|
# Module overriding UrlHelper
|
67
74
|
module UrlHelperOverride
|
68
75
|
# Override UrlHelper method
|
69
|
-
def pagy_set_query_params(page, vars,
|
76
|
+
def pagy_set_query_params(page, vars, query_params)
|
70
77
|
return super unless vars[:jsonapi]
|
71
78
|
|
72
|
-
|
73
|
-
|
74
|
-
|
79
|
+
query_params['page'] ||= {}
|
80
|
+
query_params['page'][vars[:page_param].to_s] = page if page
|
81
|
+
query_params['page'][vars[:limit_param].to_s] = vars[:limit] if vars[:limit_extra]
|
82
|
+
# :nocov:
|
83
|
+
query_params.delete(:page) if query_params['page'].empty?
|
84
|
+
# :nocov:
|
75
85
|
end
|
76
86
|
end
|
77
87
|
UrlHelpers.prepend UrlHelperOverride
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# See the Pagy documentation: https://ddnexus.github.io/pagy/docs/extras/keyset
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require_relative '../keyset'
|
5
|
+
|
6
|
+
class Pagy # :nodoc:
|
7
|
+
# Add keyset pagination
|
8
|
+
module KeysetExtra
|
9
|
+
private
|
10
|
+
|
11
|
+
# Return Pagy::Keyset object and paginated records
|
12
|
+
def pagy_keyset(set, **vars)
|
13
|
+
pagy = Keyset.new(set, **pagy_keyset_get_vars(vars))
|
14
|
+
[pagy, pagy.records]
|
15
|
+
end
|
16
|
+
|
17
|
+
# Sub-method called only by #pagy_keyset: here for easy customization of variables by overriding
|
18
|
+
def pagy_keyset_get_vars(vars)
|
19
|
+
vars.tap do |v|
|
20
|
+
v[:page] ||= pagy_get_page(v)
|
21
|
+
v[:limit] ||= pagy_get_limit(v)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# Return the URL string for the first page
|
26
|
+
def pagy_keyset_first_url(pagy, **vars)
|
27
|
+
pagy_url_for(pagy, nil, **vars)
|
28
|
+
end
|
29
|
+
|
30
|
+
# Return the URL string for the next page or nil
|
31
|
+
def pagy_keyset_next_url(pagy, **vars)
|
32
|
+
pagy_url_for(pagy, pagy.next, **vars) if pagy.next
|
33
|
+
end
|
34
|
+
end
|
35
|
+
Backend.prepend KeysetExtra
|
36
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
# See the Pagy documentation: https://ddnexus.github.io/pagy/docs/extras/limit
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require_relative 'js_tools'
|
5
|
+
|
6
|
+
class Pagy # :nodoc:
|
7
|
+
DEFAULT[:limit_param] = :limit
|
8
|
+
DEFAULT[:limit_max] = 100
|
9
|
+
DEFAULT[:limit_extra] = true # extra enabled by default
|
10
|
+
|
11
|
+
# Allow the client to request a custom limit per page with an optional selector UI
|
12
|
+
module LimitExtra
|
13
|
+
# Additions for the Backend module
|
14
|
+
module BackendAddOn
|
15
|
+
private
|
16
|
+
|
17
|
+
# Set the limit variable considering the params and other pagy variables
|
18
|
+
def pagy_get_limit(vars)
|
19
|
+
return unless vars.key?(:limit_extra) ? vars[:limit_extra] : DEFAULT[:limit_extra] # :limit_extra is false
|
20
|
+
return unless (limit_count = pagy_get_limit_param(vars)) # no limit from request params
|
21
|
+
|
22
|
+
vars[:limit] = [limit_count.to_i, vars.key?(:limit_max) ? vars[:limit_max] : DEFAULT[:limit_max]].compact.min
|
23
|
+
end
|
24
|
+
|
25
|
+
# Get the limit count from the params
|
26
|
+
# Overridable by the jsonapi extra
|
27
|
+
def pagy_get_limit_param(vars)
|
28
|
+
params[vars[:limit_param] || DEFAULT[:limit_param]]
|
29
|
+
end
|
30
|
+
end
|
31
|
+
Backend.prepend LimitExtra::BackendAddOn
|
32
|
+
|
33
|
+
# Additions for the Frontend module
|
34
|
+
module FrontendAddOn
|
35
|
+
LIMIT_TOKEN = '__pagy_limit__'
|
36
|
+
|
37
|
+
# Return the limit selector HTML. For example "Show [20] items per page"
|
38
|
+
def pagy_limit_selector_js(pagy, id: nil, item_name: nil)
|
39
|
+
return '' unless pagy.vars[:limit_extra]
|
40
|
+
|
41
|
+
id = %( id="#{id}") if id
|
42
|
+
vars = pagy.vars
|
43
|
+
limit = vars[:limit]
|
44
|
+
vars[:limit] = LIMIT_TOKEN
|
45
|
+
url_token = pagy_url_for(pagy, PAGE_TOKEN)
|
46
|
+
vars[:limit] = limit # restore the limit
|
47
|
+
|
48
|
+
limit_input = %(<input name="limit" type="number" min="1" max="#{vars[:limit_max]}" value="#{
|
49
|
+
limit}" style="padding: 0; text-align: center; width: #{limit.to_s.length + 1}rem;">#{JSTools::A_TAG})
|
50
|
+
|
51
|
+
%(<span#{id} class="pagy limit-selector-js" #{
|
52
|
+
pagy_data(pagy, :selector, pagy.from, url_token)
|
53
|
+
}><label>#{
|
54
|
+
pagy_t('pagy.limit_selector_js',
|
55
|
+
item_name: item_name || pagy_t('pagy.item_name', count: limit),
|
56
|
+
limit_input:,
|
57
|
+
count: limit)
|
58
|
+
}</label></span>)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
Frontend.prepend LimitExtra::FrontendAddOn
|
62
|
+
end
|
63
|
+
end
|
@@ -20,12 +20,12 @@ class Pagy # :nodoc:
|
|
20
20
|
# Extension for the Pagy class
|
21
21
|
module PagyExtension
|
22
22
|
# Create a Pagy object from a Meilisearch results
|
23
|
-
def new_from_meilisearch(results, vars
|
24
|
-
vars[:
|
23
|
+
def new_from_meilisearch(results, **vars)
|
24
|
+
vars[:limit] = results.raw_answer['hitsPerPage']
|
25
25
|
vars[:page] = results.raw_answer['page']
|
26
26
|
vars[:count] = results.raw_answer['totalHits']
|
27
27
|
|
28
|
-
new(vars)
|
28
|
+
new(**vars)
|
29
29
|
end
|
30
30
|
end
|
31
31
|
Pagy.extend PagyExtension
|
@@ -35,17 +35,17 @@ class Pagy # :nodoc:
|
|
35
35
|
private
|
36
36
|
|
37
37
|
# Return Pagy object and results
|
38
|
-
def pagy_meilisearch(pagy_search_args, vars
|
38
|
+
def pagy_meilisearch(pagy_search_args, **vars)
|
39
39
|
model, term, options = pagy_search_args
|
40
40
|
vars = pagy_meilisearch_get_vars(nil, vars)
|
41
|
-
options[:hits_per_page] = vars[:
|
41
|
+
options[:hits_per_page] = vars[:limit]
|
42
42
|
options[:page] = vars[:page]
|
43
43
|
results = model.send(:ms_search, term, options)
|
44
44
|
vars[:count] = results.raw_answer['totalHits']
|
45
45
|
|
46
|
-
pagy = ::Pagy.new(vars)
|
46
|
+
pagy = ::Pagy.new(**vars)
|
47
47
|
# with :last_page overflow we need to re-run the method in order to get the hits
|
48
|
-
return pagy_meilisearch(pagy_search_args, vars
|
48
|
+
return pagy_meilisearch(pagy_search_args, **vars, page: pagy.page) \
|
49
49
|
if defined?(::Pagy::OverflowExtra) && pagy.overflow? && pagy.vars[:overflow] == :last_page
|
50
50
|
|
51
51
|
[pagy, results]
|
@@ -54,10 +54,10 @@ class Pagy # :nodoc:
|
|
54
54
|
# Sub-method called only by #pagy_meilisearch: here for easy customization of variables by overriding.
|
55
55
|
# The _collection argument is not available when the method is called.
|
56
56
|
def pagy_meilisearch_get_vars(_collection, vars)
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
57
|
+
vars.tap do |v|
|
58
|
+
v[:page] ||= pagy_get_page(v)
|
59
|
+
v[:limit] ||= pagy_get_limit(v) || DEFAULT[:limit]
|
60
|
+
end
|
61
61
|
end
|
62
62
|
end
|
63
63
|
Backend.prepend BackendAddOn
|
data/lib/pagy/extras/metadata.rb
CHANGED
@@ -5,7 +5,7 @@ require_relative '../url_helpers'
|
|
5
5
|
|
6
6
|
class Pagy # :nodoc:
|
7
7
|
DEFAULT[:metadata] = %i[ scaffold_url first_url prev_url page_url next_url last_url
|
8
|
-
count page
|
8
|
+
count page limit vars pages last in from to prev next series ]
|
9
9
|
|
10
10
|
# Add a specialized backend method for pagination metadata
|
11
11
|
module MetadataExtra
|
@@ -18,7 +18,7 @@ class Pagy # :nodoc:
|
|
18
18
|
scaffold_url = pagy_url_for(pagy, PAGE_TOKEN, absolute:)
|
19
19
|
{}.tap do |metadata|
|
20
20
|
keys = if defined?(Calendar::Unit) && pagy.is_a?(Calendar::Unit)
|
21
|
-
pagy.vars[:metadata] - %i[count
|
21
|
+
pagy.vars[:metadata] - %i[count limit]
|
22
22
|
else
|
23
23
|
pagy.vars[:metadata]
|
24
24
|
end
|
data/lib/pagy/extras/overflow.rb
CHANGED
@@ -14,7 +14,7 @@ class Pagy # :nodoc:
|
|
14
14
|
end
|
15
15
|
|
16
16
|
# Add rescue clause for different behaviors
|
17
|
-
def initialize(vars)
|
17
|
+
def initialize(**vars)
|
18
18
|
@overflow ||= false # still true if :last_page re-run the method after an overflow
|
19
19
|
super
|
20
20
|
rescue OverflowError
|
@@ -24,10 +24,10 @@ class Pagy # :nodoc:
|
|
24
24
|
raise # same as without the extra
|
25
25
|
when :last_page
|
26
26
|
requested_page = @vars[:page] # save the requested page (even after re-run)
|
27
|
-
initialize
|
27
|
+
initialize(**vars, page: @last) # re-run with the last page
|
28
28
|
@vars[:page] = requested_page # restore the requested page
|
29
29
|
when :empty_page
|
30
|
-
@offset = @
|
30
|
+
@offset = @limit = @in = @from = @to = 0 # vars relative to the actual page
|
31
31
|
if defined?(Calendar::Unit) \
|
32
32
|
&& is_a?(Calendar::Unit) # only for Calendar::Units instances
|
33
33
|
edge = @order == :asc ? @final : @initial # get the edge of the overflow side (neat, but any time would do)
|
@@ -57,7 +57,7 @@ class Pagy # :nodoc:
|
|
57
57
|
# Support for Pagy::Countless class
|
58
58
|
module CountlessOverride
|
59
59
|
# Add rescue clause for different behaviors
|
60
|
-
def finalize(
|
60
|
+
def finalize(fetched_size)
|
61
61
|
@overflow = false
|
62
62
|
super
|
63
63
|
rescue OverflowError
|
@@ -66,8 +66,8 @@ class Pagy # :nodoc:
|
|
66
66
|
when :exception
|
67
67
|
raise # same as without the extra
|
68
68
|
when :empty_page
|
69
|
-
@offset = @
|
70
|
-
@vars[:size] =
|
69
|
+
@offset = @limit = @from = @to = 0 # vars relative to the actual page
|
70
|
+
@vars[:size] = 0 # no page in the series
|
71
71
|
self
|
72
72
|
else
|
73
73
|
raise VariableError.new(self, :overflow, 'to be in [:empty_page, :exception]', @vars[:overflow])
|