pagy 8.6.3 → 9.3.4

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 (106) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +1 -1
  3. data/apps/calendar.ru +119 -127
  4. data/apps/demo.ru +274 -260
  5. data/apps/index.rb +7 -0
  6. data/apps/keyset_ar.ru +227 -0
  7. data/apps/keyset_s.ru +219 -0
  8. data/apps/rails.ru +25 -20
  9. data/apps/repro.ru +108 -103
  10. data/bin/pagy +18 -20
  11. data/config/pagy.rb +19 -15
  12. data/javascripts/pagy.min.js +2 -2
  13. data/javascripts/pagy.min.js.map +3 -3
  14. data/javascripts/pagy.mjs +2 -2
  15. data/lib/pagy/b64.rb +33 -0
  16. data/lib/pagy/backend.rb +20 -20
  17. data/lib/pagy/calendar/day.rb +2 -2
  18. data/lib/pagy/calendar/month.rb +2 -2
  19. data/lib/pagy/calendar/quarter.rb +2 -2
  20. data/lib/pagy/calendar/unit.rb +7 -10
  21. data/lib/pagy/calendar/week.rb +2 -2
  22. data/lib/pagy/calendar/year.rb +2 -2
  23. data/lib/pagy/calendar.rb +15 -13
  24. data/lib/pagy/countless.rb +10 -14
  25. data/lib/pagy/extras/arel.rb +3 -11
  26. data/lib/pagy/extras/array.rb +5 -10
  27. data/lib/pagy/extras/bootstrap.rb +5 -5
  28. data/lib/pagy/extras/bulma.rb +10 -7
  29. data/lib/pagy/extras/calendar.rb +13 -17
  30. data/lib/pagy/extras/countless.rb +8 -13
  31. data/lib/pagy/extras/elasticsearch_rails.rb +16 -25
  32. data/lib/pagy/extras/gearbox.rb +18 -18
  33. data/lib/pagy/extras/headers.rb +25 -24
  34. data/lib/pagy/extras/i18n.rb +1 -1
  35. data/lib/pagy/extras/js_tools.rb +6 -6
  36. data/lib/pagy/extras/jsonapi.rb +30 -21
  37. data/lib/pagy/extras/keyset.rb +30 -0
  38. data/lib/pagy/extras/limit.rb +63 -0
  39. data/lib/pagy/extras/meilisearch.rb +9 -17
  40. data/lib/pagy/extras/metadata.rb +3 -3
  41. data/lib/pagy/extras/overflow.rb +9 -9
  42. data/lib/pagy/extras/pagy.rb +16 -16
  43. data/lib/pagy/extras/searchkick.rb +9 -17
  44. data/lib/pagy/extras/size.rb +1 -1
  45. data/lib/pagy/extras/standalone.rb +6 -6
  46. data/lib/pagy/extras/trim.rb +3 -3
  47. data/lib/pagy/frontend.rb +32 -33
  48. data/lib/pagy/i18n.rb +3 -2
  49. data/lib/pagy/keyset/active_record.rb +38 -0
  50. data/lib/pagy/keyset/sequel.rb +51 -0
  51. data/lib/pagy/keyset.rb +118 -0
  52. data/lib/pagy/shared_methods.rb +26 -0
  53. data/lib/pagy/url_helpers.rb +5 -5
  54. data/lib/pagy.rb +53 -67
  55. data/locales/ar.yml +1 -1
  56. data/locales/be.yml +1 -1
  57. data/locales/bg.yml +1 -1
  58. data/locales/bs.yml +1 -1
  59. data/locales/ca.yml +1 -1
  60. data/locales/ckb.yml +1 -1
  61. data/locales/cs.yml +1 -1
  62. data/locales/da.yml +1 -1
  63. data/locales/de.yml +1 -1
  64. data/locales/dz.yml +17 -0
  65. data/locales/en.yml +1 -1
  66. data/locales/es.yml +1 -1
  67. data/locales/fr.yml +1 -1
  68. data/locales/hr.yml +1 -1
  69. data/locales/id.yml +1 -1
  70. data/locales/it.yml +1 -1
  71. data/locales/ja.yml +1 -1
  72. data/locales/km.yml +1 -1
  73. data/locales/ko.yml +1 -1
  74. data/locales/nb.yml +1 -1
  75. data/locales/nl.yml +1 -1
  76. data/locales/nn.yml +1 -1
  77. data/locales/pl.yml +1 -1
  78. data/locales/pt-BR.yml +1 -1
  79. data/locales/pt.yml +1 -1
  80. data/locales/ru.yml +1 -1
  81. data/locales/sr.yml +1 -1
  82. data/locales/sv-SE.yml +1 -1
  83. data/locales/sv.yml +1 -1
  84. data/locales/sw.yml +3 -1
  85. data/locales/ta.yml +3 -1
  86. data/locales/tr.yml +1 -1
  87. data/locales/uk.yml +1 -1
  88. data/locales/vi.yml +1 -1
  89. data/locales/zh-CN.yml +7 -9
  90. data/locales/zh-HK.yml +7 -9
  91. data/locales/zh-TW.yml +7 -9
  92. metadata +14 -27
  93. data/apps/tmp/calendar.sqlite3 +0 -0
  94. data/apps/tmp/calendar.sqlite3-shm +0 -0
  95. data/apps/tmp/calendar.sqlite3-wal +0 -0
  96. data/apps/tmp/local_secret.txt +0 -1
  97. data/apps/tmp/pagy-keyset.sqlite3 +0 -0
  98. data/apps/tmp/pagy-keyset.sqlite3-shm +0 -0
  99. data/apps/tmp/pagy-keyset.sqlite3-wal +0 -0
  100. data/javascripts/pagy-module.js +0 -100
  101. data/javascripts/pagy.js +0 -4
  102. data/lib/pagy/extras/foundation.rb +0 -95
  103. data/lib/pagy/extras/items.rb +0 -64
  104. data/lib/pagy/extras/materialize.rb +0 -100
  105. data/lib/pagy/extras/semantic.rb +0 -94
  106. data/lib/pagy/extras/uikit.rb +0 -98
@@ -13,18 +13,15 @@ class Pagy # :nodoc:
13
13
  attr_reader :order, :from, :to
14
14
 
15
15
  # Merge and validate the options, do some simple arithmetic and set a few instance variables
16
- def initialize(vars) # rubocop:disable Lint/MissingSuper
16
+ def initialize(**vars) # rubocop:disable Lint/MissingSuper
17
17
  raise InternalError, 'Pagy::Calendar::Unit is a base class; use one of its subclasses' \
18
18
  if instance_of?(Pagy::Calendar::Unit)
19
19
 
20
- vars = self.class::DEFAULT.merge(vars) # subclass specific default
21
- normalize_vars(vars) # general default
22
- setup_vars(page: 1)
23
- setup_unit_vars
24
- raise OverflowError.new(self, :page, "in 1..#{@last}", @page) if @page > @last
25
-
26
- @prev = (@page - 1 unless @page == 1)
27
- @next = @page == @last ? (1 if @vars[:cycle]) : @page + 1
20
+ assign_vars({ **Pagy::DEFAULT, **self.class::DEFAULT }, vars)
21
+ assign_and_check(page: 1)
22
+ assign_unit_vars
23
+ check_overflow
24
+ assign_prev_and_next
28
25
  end
29
26
 
30
27
  # The label for the current page (it can pass along the I18n gem opts when it's used with the i18n extra)
@@ -63,7 +60,7 @@ class Pagy # :nodoc:
63
60
  end
64
61
 
65
62
  # Base class method for the setup of the unit variables (subclasses must implement it and call super)
66
- def setup_unit_vars
63
+ def assign_unit_vars
67
64
  raise VariableError.new(self, :format, 'to be a strftime format', @vars[:format]) unless @vars[:format].is_a?(String)
68
65
  raise VariableError.new(self, :order, 'to be in [:asc, :desc]', @order) \
69
66
  unless %i[asc desc].include?(@order = @vars[:order])
@@ -10,8 +10,8 @@ class Pagy # :nodoc:
10
10
 
11
11
  protected
12
12
 
13
- # Setup the calendar variables
14
- def setup_unit_vars
13
+ # Set up the calendar variables
14
+ def assign_unit_vars
15
15
  super
16
16
  @initial = @starting.beginning_of_week
17
17
  @final = @ending.next_week.beginning_of_week
@@ -12,8 +12,8 @@ class Pagy # :nodoc:
12
12
 
13
13
  protected
14
14
 
15
- # Setup the calendar variables
16
- def setup_unit_vars
15
+ # Set up the calendar variables
16
+ def assign_unit_vars
17
17
  super
18
18
  @initial = @starting.beginning_of_year
19
19
  @final = @ending.next_year.beginning_of_year
data/lib/pagy/calendar.rb CHANGED
@@ -17,17 +17,17 @@ class Pagy # :nodoc:
17
17
  private
18
18
 
19
19
  # Create a unit subclass instance by using the unit name (internal use)
20
- def create(unit, vars)
20
+ def create(unit, **vars)
21
21
  raise InternalError, "unit must be in #{UNITS.inspect}; got #{unit}" unless UNITS.include?(unit)
22
22
 
23
23
  name = unit.to_s
24
24
  name[0] = name[0].capitalize
25
- Object.const_get("Pagy::Calendar::#{name}").new(vars)
25
+ Object.const_get("Pagy::Calendar::#{name}").new(**vars)
26
26
  end
27
27
 
28
28
  # Return calendar, from, to
29
- def init(conf, period, params)
30
- new.send(:init, conf, period, params)
29
+ def init(...)
30
+ new.send(:init, ...)
31
31
  end
32
32
  end
33
33
 
@@ -47,18 +47,20 @@ class Pagy # :nodoc:
47
47
  @period = period
48
48
  @params = params
49
49
  @page_param = conf[:pagy][:page_param] || DEFAULT[:page_param]
50
- @units.each do |unit| # set all the :page_param vars for later deletion
51
- unit_page_param = :"#{unit}_#{@page_param}"
52
- conf[unit][:page_param] = unit_page_param
53
- conf[unit][:page] = @params[unit_page_param]
54
- end
50
+ # set all the :page_param vars for later deletion
51
+ @units.each { |unit| conf[unit][:page_param] = :"#{unit}_#{@page_param}" }
55
52
  calendar = {}
56
53
  object = nil
57
54
  @units.each_with_index do |unit, index|
58
55
  params_to_delete = @units[(index + 1), @units.size].map { |sub| conf[sub][:page_param] } + [@page_param]
59
- conf[unit][:params] = lambda { |up| up.except(*params_to_delete.map(&:to_s)) } # rubocop:disable Style/Lambda
56
+ conf[unit][:params] = ->(up) { up.except(*params_to_delete.map(&:to_s)) }
60
57
  conf[unit][:period] = object&.send(:active_period) || @period
61
- calendar[unit] = object = Calendar.send(:create, unit, conf[unit])
58
+ conf[unit][:page] = @params[:"#{unit}_#{@page_param}"] # requested page
59
+ # :nocov:
60
+ conf[unit][:counts] = yield(unit, conf[unit][:period]) if block_given? # nocov doesn't need to fail block_given?
61
+ # :nocov:
62
+ calendar[unit] = object \
63
+ = Calendar.send(:create, unit, **conf[unit])
62
64
  end
63
65
  [replace(calendar), object.from, object.to]
64
66
  end
@@ -70,10 +72,10 @@ class Pagy # :nodoc:
70
72
  @units.inject(nil) do |object, unit|
71
73
  conf[unit][:period] = object&.send(:active_period) || @period
72
74
  conf[unit][:page] = page_params[:"#{unit}_#{@page_param}"] \
73
- = Calendar.send(:create, unit, conf[unit]).send(:page_at, time, **opts)
75
+ = Calendar.send(:create, unit, **conf[unit]).send(:page_at, time, **opts)
74
76
  conf[unit][:params] ||= {}
75
77
  conf[unit][:params].merge!(page_params)
76
- Calendar.send(:create, unit, conf[unit])
78
+ Calendar.send(:create, unit, **conf[unit])
77
79
  end
78
80
  end
79
81
  end
@@ -1,32 +1,28 @@
1
1
  # See Pagy::Countless API documentation: https://ddnexus.github.io/pagy/docs/api/countless
2
2
  # frozen_string_literal: true
3
3
 
4
- require_relative '../pagy'
5
-
6
4
  class Pagy # :nodoc:
7
5
  # No need to know the count to paginate
8
6
  class Countless < Pagy
9
7
  # Merge and validate the options, do some simple arithmetic and set a few instance variables
10
- def initialize(vars = {}) # rubocop:disable Lint/MissingSuper
11
- normalize_vars(vars)
12
- setup_vars(page: 1, outset: 0)
13
- setup_items_var
14
- setup_offset_var
8
+ def initialize(**vars) # rubocop:disable Lint/MissingSuper
9
+ assign_vars(DEFAULT, vars)
10
+ assign_and_check(page: 1, outset: 0)
11
+ assign_limit
12
+ assign_offset
15
13
  end
16
14
 
17
15
  # Finalize the instance variables based on the fetched size
18
16
  def finalize(fetched_size)
19
17
  raise OverflowError.new(self, :page, "to be < #{@page}", @page) if fetched_size.zero? && @page > 1
20
18
 
21
- @last = fetched_size > @items ? @page + 1 : @page
22
- @last = vars[:max_pages] if vars[:max_pages] && @last > vars[:max_pages]
23
- raise OverflowError.new(self, :page, "in 1..#{@last}", @page) if @page > @last
24
-
25
- @in = [fetched_size, @items].min
19
+ @last = fetched_size > @limit ? @page + 1 : @page
20
+ @last = @vars[:max_pages] if @vars[:max_pages] && @last > @vars[:max_pages]
21
+ check_overflow
22
+ @in = [fetched_size, @limit].min
26
23
  @from = @in.zero? ? 0 : @offset - @outset + 1
27
24
  @to = @offset - @outset + @in
28
- @prev = (@page - 1 unless @page == 1)
29
- @next = @page == @last ? (1 if @vars[:cycle]) : @page + 1
25
+ assign_prev_and_next
30
26
  self
31
27
  end
32
28
  end
@@ -7,17 +7,9 @@ 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))
12
- [pagy, pagy_get_items(collection, pagy)]
13
- end
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)
10
+ def pagy_arel(collection, **vars)
18
11
  vars[:count] ||= pagy_arel_count(collection)
19
- vars[:page] ||= pagy_get_page(vars)
20
- vars
12
+ pagy(collection, **vars)
21
13
  end
22
14
 
23
15
  # Count using Arel when grouping
@@ -28,7 +20,7 @@ class Pagy # :nodoc:
28
20
  else
29
21
  # COUNT(*) OVER ()
30
22
  sql = Arel.star.count.over(Arel::Nodes::Grouping.new([]))
31
- collection.unscope(:order).limit(1).pluck(sql).first.to_i
23
+ collection.unscope(:order).pick(sql).to_i
32
24
  end
33
25
  end
34
26
  end
@@ -7,17 +7,12 @@ 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]]
13
- end
14
-
15
- # Sub-method called only by #pagy_array: here for easy customization of variables by overriding
16
- def pagy_array_get_vars(array, vars)
17
- pagy_set_items_from_params(vars) if defined?(ItemsExtra)
18
- vars[:count] ||= array.size
10
+ def pagy_array(array, **vars)
11
+ vars[:limit] ||= pagy_get_limit(vars)
19
12
  vars[:page] ||= pagy_get_page(vars)
20
- vars
13
+ vars[:count] ||= array.size
14
+ pagy = Pagy.new(**vars)
15
+ [pagy, array[pagy.offset, pagy.limit]]
21
16
  end
22
17
  end
23
18
  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>#{
@@ -19,15 +19,12 @@ class Pagy # :nodoc:
19
19
 
20
20
  conf[:pagy] ||= {}
21
21
  unless conf.key?(:active) && !conf[:active]
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
22
+ calendar, from, to = Calendar.send(:init, conf, pagy_calendar_period(collection), params) do |unit, period|
23
+ pagy_calendar_counts(collection, unit, *period) if respond_to?(:pagy_calendar_counts)
24
+ end
28
25
  collection = pagy_calendar_filter(collection, from, to)
29
26
  end
30
- pagy, results = send(conf[:pagy][:backend] || :pagy, collection, conf[:pagy]) # use backend: :pagy when omitted
27
+ pagy, results = send(conf[:pagy][:backend] || :pagy, collection, **conf[:pagy]) # use backend: :pagy when omitted
31
28
  [calendar, pagy, results]
32
29
  end
33
30
 
@@ -46,23 +43,22 @@ class Pagy # :nodoc:
46
43
 
47
44
  # Override the pagy_anchor
48
45
  module FrontendOverride
49
- # Consider the vars[:count]
50
- def pagy_anchor(pagy)
46
+ # Consider the vars[:counts]
47
+ def pagy_anchor(pagy, anchor_string: nil)
51
48
  return super unless (counts = pagy.vars[:counts])
52
49
 
53
- a_string = pagy.vars[:anchor_string]
54
- a_string = %( #{a_string}) if a_string
55
- left, right = %(<a#{a_string} href="#{pagy_url_for(pagy, PAGE_TOKEN)}").split(PAGE_TOKEN, 2)
50
+ anchor_string &&= %( #{anchor_string})
51
+ left, right = %(<a#{anchor_string} href="#{pagy_url_for(pagy, PAGE_TOKEN)}").split(PAGE_TOKEN, 2)
56
52
  # lambda used by all the helpers
57
53
  lambda do |page, text = pagy.label_for(page), classes: nil, aria_label: nil|
58
- count = counts[page - 1]
59
- item_name = pagy_t('pagy.item_name', count:)
54
+ count = counts[page - 1]
60
55
  if count.zero?
61
- classes = "#{classes && (classes + ' ')}empty-page"
62
- title = %( title="#{pagy_t('pagy.info.no_items', item_name:, count:)}")
56
+ classes = "#{classes && (classes + ' ')}empty-page"
57
+ info_key = 'pagy.info.no_items'
63
58
  else
64
- title = %( title="#{pagy_t('pagy.info.single_page', item_name:, count:)}")
59
+ info_key = 'pagy.info.single_page'
65
60
  end
61
+ title = %( title="#{pagy_t(info_key, item_name: pagy_t('pagy.item_name', count:), count:)}")
66
62
  classes = %( class="#{classes}") if classes
67
63
  aria_label = %( aria-label="#{aria_label}") if aria_label
68
64
  %(#{left}#{page}#{right}#{title}#{classes}#{aria_label}>#{text}</a>)
@@ -10,27 +10,22 @@ 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
+ vars[:limit] ||= pagy_get_limit(vars)
16
+ vars[:page] ||= pagy_get_page(vars)
17
+ pagy = Countless.new(**vars)
16
18
  [pagy, pagy_countless_get_items(collection, pagy)]
17
19
  end
18
20
 
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
21
  # Sub-method called only by #pagy_countless: here for easy customization of record-extraction by overriding
27
22
  # You may need to override this method for collections without offset|limit
28
23
  def pagy_countless_get_items(collection, pagy)
29
- return collection.offset(pagy.offset).limit(pagy.items) if pagy.vars[:countless_minimal]
24
+ return collection.offset(pagy.offset).limit(pagy.limit) if pagy.vars[:countless_minimal]
30
25
 
31
- fetched = collection.offset(pagy.offset).limit(pagy.items + 1).to_a # eager load items + 1
26
+ fetched = collection.offset(pagy.offset).limit(pagy.limit + 1).to_a # eager load limit + 1
32
27
  pagy.finalize(fetched.size) # finalize the pagy object
33
- fetched[0, pagy.items] # ignore eventual extra item
28
+ fetched[0, pagy.limit] # ignore eventual extra item
34
29
  end
35
30
  end
36
31
  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,32 +48,23 @@ 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 = {})
53
- model, query_or_payload,
54
- options, *called = pagy_search_args
55
- vars = pagy_elasticsearch_rails_get_vars(nil, vars)
56
- options[:size] = vars[:items]
57
- options[:from] = vars[:items] * (vars[:page] - 1)
58
- response = model.send(DEFAULT[:elasticsearch_rails_search], query_or_payload, **options)
59
- vars[:count] = ElasticsearchRailsExtra.total_count(response)
51
+ # Return Pagy object and records
52
+ def pagy_elasticsearch_rails(pagy_search_args, **vars)
53
+ vars[:page] ||= pagy_get_page(vars)
54
+ vars[:limit] ||= pagy_get_limit(vars)
55
+ model, query_or_payload, options, *called = pagy_search_args
56
+ options[:size] = vars[:limit]
57
+ options[:from] = vars[:limit] * ((vars[:page] || 1) - 1)
58
+ response = model.send(DEFAULT[:elasticsearch_rails_search], query_or_payload, **options)
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)]
67
67
  end
68
-
69
- # Sub-method called only by #pagy_elasticsearch_rails: here for easy customization of variables by overriding
70
- # the _collection argument is not available when the method is called
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
76
- end
77
68
  end
78
69
  Backend.prepend BackendAddOn
79
70
  end
@@ -3,27 +3,27 @@
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 @offset based on the :gearbox_items variable
23
- def setup_offset_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
27
  @offset = if @page <= gears.count
28
28
  gears[0, @page - 1].sum
29
29
  else
@@ -31,11 +31,11 @@ class Pagy # :nodoc:
31
31
  end + @outset
32
32
  end
33
33
 
34
- # Setup Pagy @last based on the :gearbox_items variable and @count
35
- def setup_last_var
36
- return super if !@vars[:gearbox_extra] || @vars[:items_extra]
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
37
 
38
- gears = @vars[:gearbox_items]
38
+ gears = @vars[:gearbox_limit]
39
39
  # This algorithm is thousands of times faster than the one in the geared_pagination gem
40
40
  @last = (if count > (sum = gears.sum)
41
41
  [((count - sum).to_f / gears.last).ceil, 1].max + gears.count
@@ -48,7 +48,7 @@ class Pagy # :nodoc:
48
48
  end
49
49
  [pages, 1].max
50
50
  end)
51
- @last = vars[:max_pages] if vars[:max_pages] && @last > vars[:max_pages]
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
+ 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?(::Pagy::Calendar) && pagy.is_a?(Calendar::Unit))
29
+ return hash if (defined?(::Pagy::Countless) && pagy.is_a?(Countless)) || \
30
+ (defined?(::Pagy::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 pagy_link_header(pagy)
38
+ { 'link' => [].tap do |link|
39
+ if defined?(::Pagy::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?(::Pagy::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::Unit.prepend I18nExtra::CalendarOverride if defined?(Calendar::Unit)
22
+ Calendar::Unit.prepend I18nExtra::CalendarOverride if defined?(::Pagy::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
 
@@ -42,17 +44,16 @@ class Pagy # :nodoc:
42
44
  end
43
45
  end
44
46
  end
45
- Calendar::Unit.prepend CalendarOverride if defined?(Calendar::Unit)
47
+ Calendar::Unit.prepend CalendarOverride if defined?(::Pagy::Calendar::Unit)
46
48
 
47
49
  # Additions for the Frontend
48
50
  module FrontendAddOn
49
- if defined?(Oj)
51
+ if defined?(::Oj)
50
52
  # Return a data tag with the base64 encoded JSON-serialized args generated with the faster oj gem
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