pagy 8.4.0 → 9.0.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.
Files changed (108) hide show
  1. checksums.yaml +4 -4
  2. data/apps/calendar.ru +682 -2137
  3. data/apps/demo.ru +17 -13
  4. data/apps/keyset_ar.ru +236 -0
  5. data/apps/keyset_s.ru +238 -0
  6. data/apps/rails.ru +19 -15
  7. data/apps/repro.ru +17 -14
  8. data/apps/tmp/calendar.sqlite3 +0 -0
  9. data/apps/tmp/calendar.sqlite3-shm +0 -0
  10. data/apps/tmp/calendar.sqlite3-wal +0 -0
  11. data/apps/tmp/local_secret.txt +1 -0
  12. data/apps/tmp/pagy-keyset-ar.sqlite3 +0 -0
  13. data/apps/tmp/pagy-keyset-ar.sqlite3-shm +0 -0
  14. data/apps/tmp/pagy-keyset-ar.sqlite3-wal +0 -0
  15. data/apps/tmp/pagy-keyset-s.sqlite3 +0 -0
  16. data/bin/pagy +17 -12
  17. data/config/pagy.rb +32 -33
  18. data/javascripts/pagy-module.js +94 -107
  19. data/javascripts/pagy.js +4 -1
  20. data/javascripts/pagy.min.js +4 -0
  21. data/javascripts/pagy.min.js.map +10 -0
  22. data/javascripts/pagy.mjs +100 -0
  23. data/lib/optimist.rb +1 -1
  24. data/lib/pagy/b64.rb +33 -0
  25. data/lib/pagy/backend.rb +21 -17
  26. data/lib/pagy/calendar/day.rb +4 -3
  27. data/lib/pagy/calendar/month.rb +4 -3
  28. data/lib/pagy/calendar/quarter.rb +4 -3
  29. data/lib/pagy/calendar/unit.rb +103 -0
  30. data/lib/pagy/calendar/week.rb +3 -3
  31. data/lib/pagy/calendar/year.rb +4 -3
  32. data/lib/pagy/calendar.rb +54 -97
  33. data/lib/pagy/countless.rb +15 -16
  34. data/lib/pagy/extras/arel.rb +8 -10
  35. data/lib/pagy/extras/array.rb +4 -6
  36. data/lib/pagy/extras/bootstrap.rb +5 -5
  37. data/lib/pagy/extras/bulma.rb +10 -7
  38. data/lib/pagy/extras/calendar.rb +34 -5
  39. data/lib/pagy/extras/countless.rb +6 -13
  40. data/lib/pagy/extras/elasticsearch_rails.rb +15 -15
  41. data/lib/pagy/extras/gearbox.rb +26 -26
  42. data/lib/pagy/extras/headers.rb +25 -24
  43. data/lib/pagy/extras/i18n.rb +1 -1
  44. data/lib/pagy/extras/js_tools.rb +9 -9
  45. data/lib/pagy/extras/jsonapi.rb +26 -16
  46. data/lib/pagy/extras/keyset.rb +26 -0
  47. data/lib/pagy/extras/limit.rb +63 -0
  48. data/lib/pagy/extras/meilisearch.rb +11 -11
  49. data/lib/pagy/extras/metadata.rb +6 -2
  50. data/lib/pagy/extras/overflow.rb +9 -8
  51. data/lib/pagy/extras/pagy.rb +16 -16
  52. data/lib/pagy/extras/searchkick.rb +11 -11
  53. data/lib/pagy/extras/size.rb +40 -0
  54. data/lib/pagy/extras/standalone.rb +6 -6
  55. data/lib/pagy/extras/trim.rb +3 -3
  56. data/lib/pagy/frontend.rb +38 -36
  57. data/lib/pagy/i18n.rb +1 -1
  58. data/lib/pagy/keyset/active_record.rb +38 -0
  59. data/lib/pagy/keyset/sequel.rb +51 -0
  60. data/lib/pagy/keyset.rb +99 -0
  61. data/lib/pagy/url_helpers.rb +5 -5
  62. data/lib/pagy.rb +92 -94
  63. data/locales/ar.yml +9 -10
  64. data/locales/be.yml +2 -2
  65. data/locales/bg.yml +2 -2
  66. data/locales/bs.yml +2 -2
  67. data/locales/ca.yml +5 -7
  68. data/locales/ckb.yml +2 -2
  69. data/locales/cs.yml +2 -2
  70. data/locales/da.yml +2 -2
  71. data/locales/de.yml +2 -2
  72. data/locales/en.yml +2 -2
  73. data/locales/es.yml +2 -2
  74. data/locales/fr.yml +2 -2
  75. data/locales/hr.yml +2 -2
  76. data/locales/id.yml +2 -2
  77. data/locales/it.yml +2 -2
  78. data/locales/ja.yml +2 -2
  79. data/locales/km.yml +2 -2
  80. data/locales/ko.yml +2 -2
  81. data/locales/nb.yml +2 -2
  82. data/locales/nl.yml +2 -2
  83. data/locales/nn.yml +2 -2
  84. data/locales/pl.yml +2 -2
  85. data/locales/pt-BR.yml +2 -2
  86. data/locales/pt.yml +2 -2
  87. data/locales/ru.yml +2 -2
  88. data/locales/sr.yml +2 -2
  89. data/locales/sv-SE.yml +2 -2
  90. data/locales/sv.yml +2 -2
  91. data/locales/sw.yml +2 -2
  92. data/locales/ta.yml +2 -2
  93. data/locales/tr.yml +2 -2
  94. data/locales/uk.yml +2 -2
  95. data/locales/vi.yml +2 -2
  96. data/locales/zh-CN.yml +2 -2
  97. data/locales/zh-HK.yml +2 -2
  98. data/locales/zh-TW.yml +2 -2
  99. data/pkg/pagy-9.0.0.gem +0 -0
  100. metadata +27 -17
  101. data/javascripts/pagy-dev.js +0 -114
  102. data/lib/pagy/calendar/helper.rb +0 -65
  103. data/lib/pagy/extras/foundation.rb +0 -95
  104. data/lib/pagy/extras/items.rb +0 -64
  105. data/lib/pagy/extras/materialize.rb +0 -100
  106. data/lib/pagy/extras/semantic.rb +0 -94
  107. data/lib/pagy/extras/uikit.rb +0 -98
  108. /data/javascripts/{pagy-module.d.ts → pagy.d.ts} +0 -0
@@ -7,19 +7,11 @@ class Pagy # :nodoc:
7
7
  private
8
8
 
9
9
  # Return Pagy object and paginated collection/results
10
- def pagy_arel(collection, vars = {})
11
- pagy = Pagy.new(pagy_arel_get_vars(collection, vars))
10
+ def pagy_arel(collection, **vars)
11
+ pagy = Pagy.new(**pagy_arel_get_vars(collection, vars))
12
12
  [pagy, pagy_get_items(collection, pagy)]
13
13
  end
14
14
 
15
- # Sub-method called only by #pagy_arel: here for easy customization of variables by overriding
16
- def pagy_arel_get_vars(collection, vars)
17
- pagy_set_items_from_params(vars) if defined?(ItemsExtra)
18
- vars[:count] ||= pagy_arel_count(collection)
19
- vars[:page] ||= pagy_get_page(vars)
20
- vars
21
- end
22
-
23
15
  # Count using Arel when grouping
24
16
  def pagy_arel_count(collection)
25
17
  if collection.group_values.empty?
@@ -31,6 +23,12 @@ class Pagy # :nodoc:
31
23
  collection.unscope(:order).limit(1).pluck(sql).first.to_i
32
24
  end
33
25
  end
26
+
27
+ # Sub-method called only by #pagy_arel: here for easy customization of variables by overriding
28
+ def pagy_arel_get_vars(collection, vars)
29
+ vars[:count] ||= pagy_arel_count(collection)
30
+ pagy_get_vars(collection, vars)
31
+ end
34
32
  end
35
33
  Backend.prepend ArelExtra
36
34
  end
@@ -7,17 +7,15 @@ class Pagy # :nodoc:
7
7
  private
8
8
 
9
9
  # Return Pagy object and paginated items
10
- def pagy_array(array, vars = {})
11
- pagy = Pagy.new(pagy_array_get_vars(array, vars))
12
- [pagy, array[pagy.offset, pagy.items]]
10
+ def pagy_array(array, **vars)
11
+ pagy = Pagy.new(**pagy_array_get_vars(array, vars))
12
+ [pagy, array[pagy.offset, pagy.limit]]
13
13
  end
14
14
 
15
15
  # Sub-method called only by #pagy_array: here for easy customization of variables by overriding
16
16
  def pagy_array_get_vars(array, vars)
17
- pagy_set_items_from_params(vars) if defined?(ItemsExtra)
18
17
  vars[:count] ||= array.size
19
- vars[:page] ||= pagy_get_page(vars)
20
- vars
18
+ pagy_get_vars(array, vars)
21
19
  end
22
20
  end
23
21
  Backend.prepend ArrayExtra
@@ -10,7 +10,7 @@ class Pagy # :nodoc:
10
10
  # Pagination for bootstrap: it returns the html with the series of links to the pages
11
11
  def pagy_bootstrap_nav(pagy, id: nil, classes: 'pagination', aria_label: nil, **vars)
12
12
  id = %( id="#{id}") if id
13
- a = pagy_anchor(pagy)
13
+ a = pagy_anchor(pagy, **vars)
14
14
 
15
15
  html = %(<nav#{id} class="pagy-bootstrap nav" #{nav_aria_label(pagy, aria_label:)}><ul class="#{classes}">#{
16
16
  bootstrap_prev_html(pagy, a)})
@@ -34,7 +34,7 @@ class Pagy # :nodoc:
34
34
  def pagy_bootstrap_nav_js(pagy, id: nil, classes: 'pagination', aria_label: nil, **vars)
35
35
  sequels = pagy.sequels(**vars)
36
36
  id = %( id="#{id}") if id
37
- a = pagy_anchor(pagy)
37
+ a = pagy_anchor(pagy, **vars)
38
38
  tokens = { 'before' => %(<ul class="#{classes}">#{bootstrap_prev_html(pagy, a)}),
39
39
  'a' => %(<li class="page-item">#{a.(PAGE_TOKEN, LABEL_TOKEN, classes: 'page-link')}</li>),
40
40
  'current' => %(<li class="page-item active"><a role="link" class="page-link" ) +
@@ -50,9 +50,9 @@ class Pagy # :nodoc:
50
50
  end
51
51
 
52
52
  # Javascript combo pagination for bootstrap: it returns a nav with a data-pagy attribute used by the pagy.js file
53
- def pagy_bootstrap_combo_nav_js(pagy, id: nil, classes: 'pagination', aria_label: nil)
53
+ def pagy_bootstrap_combo_nav_js(pagy, id: nil, classes: 'pagination', aria_label: nil, **vars)
54
54
  id = %( id="#{id}") if id
55
- a = pagy_anchor(pagy)
55
+ a = pagy_anchor(pagy, **vars)
56
56
  pages = pagy.pages
57
57
 
58
58
  page_input = %(<input name="page" type="number" min="1" max="#{pages}" value="#{pagy.page}" aria-current="page" ) <<
@@ -61,7 +61,7 @@ class Pagy # :nodoc:
61
61
 
62
62
  %(<nav#{id} class="pagy-bootstrap combo-nav-js" #{
63
63
  nav_aria_label(pagy, aria_label:)} #{
64
- pagy_data(pagy, :combo, pagy_url_for(pagy, PAGE_TOKEN))
64
+ pagy_data(pagy, :combo, pagy_url_for(pagy, PAGE_TOKEN, **vars))
65
65
  }><ul class="#{classes}">#{
66
66
  bootstrap_prev_html(pagy, a)
67
67
  }<li class="page-item pagy-bootstrap"><label class="page-link">#{
@@ -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', aria_label: nil, **vars)
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', aria_label: nil, **vars)
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', aria_label: nil)
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>#{
@@ -2,7 +2,6 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require_relative '../calendar'
5
- require_relative '../calendar/helper'
6
5
 
7
6
  class Pagy # :nodoc:
8
7
  # Add pagination filtering by calendar unit (:year, :quarter, :month, :week, :day) to the regular pagination
@@ -20,10 +19,15 @@ class Pagy # :nodoc:
20
19
 
21
20
  conf[:pagy] ||= {}
22
21
  unless conf.key?(:active) && !conf[:active]
23
- calendar, from, to = Calendar::Helper.send(:init, conf, pagy_calendar_period(collection), params)
24
- collection = pagy_calendar_filter(collection, from, to)
22
+ calendar, from, to = Calendar.send(:init, conf, pagy_calendar_period(collection), params)
23
+ if respond_to?(:pagy_calendar_counts)
24
+ calendar.each_key do |unit|
25
+ calendar[unit].vars[:counts] = pagy_calendar_counts(collection, unit, *calendar[unit].vars[:period])
26
+ end
27
+ end
28
+ collection = pagy_calendar_filter(collection, from, to)
25
29
  end
26
- 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
27
31
  [calendar, pagy, results]
28
32
  end
29
33
 
@@ -40,6 +44,31 @@ class Pagy # :nodoc:
40
44
  end
41
45
  end
42
46
 
47
+ # Override the pagy_anchor
48
+ module FrontendOverride
49
+ # Consider the vars[:count]
50
+ def pagy_anchor(pagy, anchor_string: nil)
51
+ return super unless (counts = pagy.vars[:counts])
52
+
53
+ anchor_string &&= %( #{anchor_string})
54
+ left, right = %(<a#{anchor_string} href="#{pagy_url_for(pagy, PAGE_TOKEN)}").split(PAGE_TOKEN, 2)
55
+ # lambda used by all the helpers
56
+ lambda do |page, text = pagy.label_for(page), classes: nil, aria_label: nil|
57
+ count = counts[page - 1]
58
+ item_name = pagy_t('pagy.item_name', count:)
59
+ if count.zero?
60
+ classes = "#{classes && (classes + ' ')}empty-page"
61
+ title = %( title="#{pagy_t('pagy.info.no_items', item_name:, count:)}")
62
+ else
63
+ title = %( title="#{pagy_t('pagy.info.single_page', item_name:, count:)}")
64
+ end
65
+ classes = %( class="#{classes}") if classes
66
+ aria_label = %( aria-label="#{aria_label}") if aria_label
67
+ %(#{left}#{page}#{right}#{title}#{classes}#{aria_label}>#{text}</a>)
68
+ end
69
+ end
70
+ end
71
+
43
72
  # Additions for the Frontend module
44
73
  module UrlHelperAddOn
45
74
  # Return the url for the calendar page at time
@@ -49,5 +78,5 @@ class Pagy # :nodoc:
49
78
  end
50
79
  end
51
80
  Backend.prepend CalendarExtra::BackendAddOn, CalendarExtra::UrlHelperAddOn
52
- Frontend.prepend CalendarExtra::UrlHelperAddOn
81
+ Frontend.prepend CalendarExtra::UrlHelperAddOn, CalendarExtra::FrontendOverride
53
82
  end
@@ -10,27 +10,20 @@ class Pagy # :nodoc:
10
10
  module CountlessExtra
11
11
  private
12
12
 
13
- # Return Pagy object and items
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_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.items) if pagy.vars[:countless_minimal]
22
+ return collection.offset(pagy.offset).limit(pagy.limit) if pagy.vars[:countless_minimal]
30
23
 
31
- fetched = collection.offset(pagy.offset).limit(pagy.items + 1).to_a # eager load items + 1
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.items] # ignore eventual extra item
26
+ fetched[0, pagy.limit] # ignore eventual extra item
34
27
  end
35
28
  end
36
29
  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 Pagy::DEFAULT[:elasticsearch_rails_pagy_search], :pagy_elasticsearch_rails
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[:items] = response.search.options[:size] || 10
40
- vars[:page] = ((response.search.options[:from] || 0) / vars[:items]) + 1
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 items
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[:items]
57
- options[:from] = vars[:items] * (vars[:page] - 1)
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.merge(page: pagy.page)) \
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
- pagy_set_items_from_params(vars) if defined?(ItemsExtra)
73
- vars[:items] ||= DEFAULT[:items]
74
- vars[:page] ||= pagy_get_page(vars)
75
- vars
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
@@ -3,27 +3,39 @@
3
3
 
4
4
  class Pagy # :nodoc:
5
5
  DEFAULT[:gearbox_extra] = true # extra enabled by default
6
- DEFAULT[:gearbox_items] = [15, 30, 60, 100]
6
+ DEFAULT[:gearbox_limit] = [15, 30, 60, 100]
7
7
 
8
- # Automatically change the number of items per page depending on the page number
9
- # accepts an array as the :gearbox_items variable, that will determine the items for the first pages
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
- # Setup @items based on the :gearbox_items variable
12
- def setup_items_var
13
- return super if !@vars[:gearbox_extra] || @vars[:items_extra]
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[:gearbox_items]
16
- raise VariableError.new(self, :gearbox_items, 'to be an Array of positives', gears) \
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
- @items = gears[@page - 1] || gears.last
19
+ @limit = gears[@page - 1] || gears.last
20
20
  end
21
21
 
22
- # Setup Pagy @last based on the :gearbox_items variable and @count
23
- def setup_last_var
24
- return super if !@vars[:gearbox_extra] || @vars[:items_extra]
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 = @vars[:gearbox_items]
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
@@ -5,7 +5,7 @@ require_relative '../url_helpers'
5
5
 
6
6
  class Pagy # :nodoc:
7
7
  DEFAULT[:headers] = { page: 'current-page',
8
- items: 'page-items',
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
- pagy_headers_hash(pagy).tap do |hash|
25
- hash['link'] = hash['link'].map { |rel, link| %(<#{link}>; rel="#{rel}") }.join(', ')
26
- end
27
- end
24
+ headers = pagy.vars[:headers]
25
+ { 'link' => link(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
- # Generates a hash structure of the headers
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
- hash
35
+ end
36
+
37
+ def link(pagy)
38
+ [].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
@@ -19,7 +19,7 @@ class Pagy # :nodoc:
19
19
  end
20
20
  end
21
21
  end
22
- Calendar.prepend I18nExtra::CalendarOverride if defined?(Calendar)
22
+ Calendar::Unit.prepend I18nExtra::CalendarOverride if defined?(Calendar::Unit)
23
23
 
24
24
  # Add the pagy locales to the I18n.load_path
25
25
  ::I18n.load_path += Dir[Pagy.root.join('locales', '*.yml')]
@@ -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 => [1,2,2,1], 350 => [2,3,3,2], 550 => [3,4,4,3]})
18
+ # >> pagy = Pagy.new(count:1000, page: 20, steps: {0 => 5, 350 => 7, 550 => 9})
17
19
  # >> pagy.sequels
18
- # #=> { "0" => [1, :gap, 18, 19, "20", 21, 22, :gap, 50],
19
- # "350" => [1, 2, :gap, 17, 18, 19, "20", 21, 22, 23, :gap, 49, 50],
20
- # "550" => [1, 2, 3, :gap, 16, 17, 18, 19, "20", 21, 22, 23, 24, :gap, 48, 49, 50] }
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)
@@ -42,7 +44,7 @@ class Pagy # :nodoc:
42
44
  end
43
45
  end
44
46
  end
45
- Calendar.prepend CalendarOverride if defined?(Calendar)
47
+ Calendar::Unit.prepend CalendarOverride if defined?(Calendar::Unit)
46
48
 
47
49
  # Additions for the Frontend
48
50
  module FrontendAddOn
@@ -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
- strict_base64_encoded = [Oj.dump(args, mode: :strict)].pack('m0')
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
- strict_base64_encoded = [args.to_json].pack('m0')
64
- %(data-pagy="#{strict_base64_encoded}")
64
+ %(data-pagy="#{B64.encode(args.to_json)}")
65
65
  end
66
66
  end
67
67
  end
@@ -24,10 +24,17 @@ class Pagy # :nodoc:
24
24
 
25
25
  # Return the jsonapi links
26
26
  def pagy_jsonapi_links(pagy, **opts)
27
- { first: pagy_url_for(pagy, 1, **opts),
28
- last: pagy_url_for(pagy, pagy.last, **opts),
29
- prev: pagy.prev ? pagy_url_for(pagy, pagy.prev, **opts) : nil,
30
- next: pagy.next ? pagy_url_for(pagy, pagy.next, **opts) : nil }
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 1 if params[:page].nil?
50
+ return if params[:page].nil?
44
51
 
45
- [params[:page][vars[:page_param] || DEFAULT[:page_param]].to_i, 1].max
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 ItemsExtra
51
- module ItemsExtraOverride
57
+ # Module overriding LimitExtra
58
+ module LimitExtraOverride
52
59
  private
53
60
 
54
- # Override the ItemsExtra::Backend method
55
- def pagy_get_items_size(vars)
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[:items_param] || DEFAULT[:items_param]]
66
+ params[:page][vars[:limit_param] || DEFAULT[:limit_param]]
60
67
  end
61
68
  end
62
69
  # :nocov:
63
- ItemsExtra::BackendAddOn.prepend ItemsExtraOverride if defined?(ItemsExtra::BackendAddOn)
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, params)
76
+ def pagy_set_query_params(page, vars, query_params)
70
77
  return super unless vars[:jsonapi]
71
78
 
72
- params['page'] ||= {}
73
- params['page'][vars[:page_param].to_s] = page
74
- params['page'][vars[:items_param].to_s] = vars[:items] if vars[:items_extra]
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,26 @@
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
+ end
25
+ Backend.prepend KeysetExtra
26
+ end