pagy 8.6.3 → 9.0.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (102) hide show
  1. checksums.yaml +4 -4
  2. data/apps/calendar.ru +5 -5
  3. data/apps/demo.ru +4 -4
  4. data/apps/keyset_ar.ru +236 -0
  5. data/apps/keyset_s.ru +238 -0
  6. data/apps/rails.ru +5 -5
  7. data/apps/repro.ru +4 -4
  8. data/bin/pagy +4 -2
  9. data/config/pagy.rb +17 -13
  10. data/javascripts/pagy.min.js +2 -2
  11. data/javascripts/pagy.min.js.map +2 -2
  12. data/javascripts/pagy.mjs +2 -2
  13. data/lib/pagy/b64.rb +33 -0
  14. data/lib/pagy/backend.rb +19 -19
  15. data/lib/pagy/calendar/day.rb +1 -1
  16. data/lib/pagy/calendar/month.rb +1 -1
  17. data/lib/pagy/calendar/quarter.rb +1 -1
  18. data/lib/pagy/calendar/unit.rb +7 -10
  19. data/lib/pagy/calendar/week.rb +1 -1
  20. data/lib/pagy/calendar/year.rb +1 -1
  21. data/lib/pagy/calendar.rb +5 -5
  22. data/lib/pagy/countless.rb +10 -14
  23. data/lib/pagy/extras/arel.rb +2 -10
  24. data/lib/pagy/extras/array.rb +5 -10
  25. data/lib/pagy/extras/bootstrap.rb +5 -5
  26. data/lib/pagy/extras/bulma.rb +10 -7
  27. data/lib/pagy/extras/calendar.rb +4 -5
  28. data/lib/pagy/extras/countless.rb +8 -13
  29. data/lib/pagy/extras/elasticsearch_rails.rb +16 -25
  30. data/lib/pagy/extras/gearbox.rb +18 -18
  31. data/lib/pagy/extras/headers.rb +25 -24
  32. data/lib/pagy/extras/js_tools.rb +4 -4
  33. data/lib/pagy/extras/jsonapi.rb +26 -19
  34. data/lib/pagy/extras/keyset.rb +30 -0
  35. data/lib/pagy/extras/limit.rb +63 -0
  36. data/lib/pagy/extras/meilisearch.rb +9 -17
  37. data/lib/pagy/extras/metadata.rb +2 -2
  38. data/lib/pagy/extras/overflow.rb +5 -5
  39. data/lib/pagy/extras/pagy.rb +16 -16
  40. data/lib/pagy/extras/searchkick.rb +9 -17
  41. data/lib/pagy/extras/size.rb +1 -1
  42. data/lib/pagy/extras/standalone.rb +6 -6
  43. data/lib/pagy/extras/trim.rb +2 -2
  44. data/lib/pagy/frontend.rb +32 -33
  45. data/lib/pagy/i18n.rb +2 -2
  46. data/lib/pagy/keyset/active_record.rb +38 -0
  47. data/lib/pagy/keyset/sequel.rb +51 -0
  48. data/lib/pagy/keyset.rb +98 -0
  49. data/lib/pagy/shared_methods.rb +27 -0
  50. data/lib/pagy/url_helpers.rb +4 -4
  51. data/lib/pagy.rb +51 -65
  52. data/locales/ar.yml +1 -1
  53. data/locales/be.yml +1 -1
  54. data/locales/bg.yml +1 -1
  55. data/locales/bs.yml +1 -1
  56. data/locales/ca.yml +1 -1
  57. data/locales/ckb.yml +1 -1
  58. data/locales/cs.yml +1 -1
  59. data/locales/da.yml +1 -1
  60. data/locales/de.yml +1 -1
  61. data/locales/en.yml +1 -1
  62. data/locales/es.yml +1 -1
  63. data/locales/fr.yml +1 -1
  64. data/locales/hr.yml +1 -1
  65. data/locales/id.yml +1 -1
  66. data/locales/it.yml +1 -1
  67. data/locales/ja.yml +1 -1
  68. data/locales/km.yml +1 -1
  69. data/locales/ko.yml +1 -1
  70. data/locales/nb.yml +1 -1
  71. data/locales/nl.yml +1 -1
  72. data/locales/nn.yml +1 -1
  73. data/locales/pl.yml +1 -1
  74. data/locales/pt-BR.yml +1 -1
  75. data/locales/pt.yml +1 -1
  76. data/locales/ru.yml +1 -1
  77. data/locales/sr.yml +1 -1
  78. data/locales/sv-SE.yml +1 -1
  79. data/locales/sv.yml +1 -1
  80. data/locales/sw.yml +1 -1
  81. data/locales/ta.yml +1 -1
  82. data/locales/tr.yml +1 -1
  83. data/locales/uk.yml +1 -1
  84. data/locales/vi.yml +1 -1
  85. data/locales/zh-CN.yml +1 -1
  86. data/locales/zh-HK.yml +1 -1
  87. data/locales/zh-TW.yml +1 -1
  88. metadata +12 -24
  89. data/apps/tmp/calendar.sqlite3 +0 -0
  90. data/apps/tmp/calendar.sqlite3-shm +0 -0
  91. data/apps/tmp/calendar.sqlite3-wal +0 -0
  92. data/apps/tmp/local_secret.txt +0 -1
  93. data/apps/tmp/pagy-keyset.sqlite3 +0 -0
  94. data/apps/tmp/pagy-keyset.sqlite3-shm +0 -0
  95. data/apps/tmp/pagy-keyset.sqlite3-wal +0 -0
  96. data/javascripts/pagy-module.js +0 -100
  97. data/javascripts/pagy.js +0 -4
  98. data/lib/pagy/extras/foundation.rb +0 -95
  99. data/lib/pagy/extras/items.rb +0 -64
  100. data/lib/pagy/extras/materialize.rb +0 -100
  101. data/lib/pagy/extras/semantic.rb +0 -94
  102. data/lib/pagy/extras/uikit.rb +0 -98
@@ -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?(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 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
@@ -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
 
@@ -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
@@ -38,40 +45,40 @@ class Pagy # :nodoc:
38
45
  end
39
46
 
40
47
  # Override the Backend method
41
- def pagy_get_page(vars)
42
- return super if pagy_skip_jsonapi?(vars)
43
- return 1 if params[:page].nil?
48
+ def pagy_get_page(vars, force_integer: true)
49
+ return super if pagy_skip_jsonapi?(vars) || params[:page].nil?
44
50
 
45
- [params[:page][vars[:page_param] || DEFAULT[:page_param]].to_i, 1].max
51
+ page = params[:page][vars[:page_param] || DEFAULT[:page_param]]
52
+ force_integer ? (page || 1).to_i : page
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
- return if params[:page].nil?
64
+ return unless params[:page]
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
81
+ query_params['page'][vars[:limit_param].to_s] = vars[:limit] if vars[:limit_extra]
75
82
  end
76
83
  end
77
84
  UrlHelpers.prepend UrlHelperOverride
@@ -0,0 +1,30 @@
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
+ vars[:page] ||= pagy_get_page(vars, force_integer: false) # allow nil
14
+ vars[:limit] ||= pagy_get_limit(vars)
15
+ pagy = Keyset.new(set, **vars)
16
+ [pagy, pagy.records]
17
+ end
18
+
19
+ # Return the URL string for the first page
20
+ def pagy_keyset_first_url(pagy, **vars)
21
+ pagy_url_for(pagy, nil, **vars)
22
+ end
23
+
24
+ # Return the URL string for the next page or nil
25
+ def pagy_keyset_next_url(pagy, **vars)
26
+ pagy_url_for(pagy, pagy.next, **vars) if pagy.next
27
+ end
28
+ end
29
+ Backend.prepend KeysetExtra
30
+ 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 super unless vars.key?(:limit_extra) ? vars[:limit_extra] : DEFAULT[:limit_extra] # :limit_extra is false
20
+ return super 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[:items] = results.raw_answer['hitsPerPage']
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,30 +35,22 @@ 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
+ vars[:page] ||= pagy_get_page(vars)
40
+ vars[:limit] ||= pagy_get_limit(vars)
39
41
  model, term, options = pagy_search_args
40
- vars = pagy_meilisearch_get_vars(nil, vars)
41
- options[:hits_per_page] = vars[:items]
42
+ options[:hits_per_page] = vars[:limit]
42
43
  options[:page] = vars[:page]
43
44
  results = model.send(:ms_search, term, options)
44
45
  vars[:count] = results.raw_answer['totalHits']
45
46
 
46
- pagy = ::Pagy.new(vars)
47
+ pagy = ::Pagy.new(**vars)
47
48
  # 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.merge(page: pagy.page)) \
49
+ return pagy_meilisearch(pagy_search_args, **vars, page: pagy.page) \
49
50
  if defined?(::Pagy::OverflowExtra) && pagy.overflow? && pagy.vars[:overflow] == :last_page
50
51
 
51
52
  [pagy, results]
52
53
  end
53
-
54
- # Sub-method called only by #pagy_meilisearch: here for easy customization of variables by overriding.
55
- # The _collection argument is not available when the method is called.
56
- def pagy_meilisearch_get_vars(_collection, vars)
57
- pagy_set_items_from_params(vars) if defined?(ItemsExtra)
58
- vars[:items] ||= DEFAULT[:items]
59
- vars[:page] ||= pagy_get_page(vars)
60
- vars
61
- end
62
54
  end
63
55
  Backend.prepend BackendAddOn
64
56
  end
@@ -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 items vars pages last in from to prev next series ]
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 items]
21
+ pagy.vars[:metadata] - %i[count limit]
22
22
  else
23
23
  pagy.vars[:metadata]
24
24
  end
@@ -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 vars.merge!(page: @last) # re-run with the last page
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 = @items = @in = @from = @to = 0 # vars relative to the actual page
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(items)
60
+ def finalize(fetched_size)
61
61
  @overflow = false
62
62
  super
63
63
  rescue OverflowError
@@ -66,7 +66,7 @@ class Pagy # :nodoc:
66
66
  when :exception
67
67
  raise # same as without the extra
68
68
  when :empty_page
69
- @offset = @items = @from = @to = 0 # vars relative to the actual page
69
+ @offset = @limit = @from = @to = 0 # vars relative to the actual page
70
70
  @vars[:size] = 0 # no page in the series
71
71
  self
72
72
  else
@@ -12,7 +12,7 @@ class Pagy # :nodoc:
12
12
  def pagy_nav_js(pagy, id: nil, aria_label: nil, **vars)
13
13
  sequels = pagy.sequels(**vars)
14
14
  id = %( id="#{id}") if id
15
- a = pagy_anchor(pagy)
15
+ a = pagy_anchor(pagy, **vars)
16
16
  tokens = { 'before' => prev_a(pagy, a),
17
17
  'a' => a.(PAGE_TOKEN, LABEL_TOKEN),
18
18
  'current' => %(<a class="current" role="link" aria-current="page" aria-disabled="true">#{
@@ -27,9 +27,9 @@ class Pagy # :nodoc:
27
27
  end
28
28
 
29
29
  # Javascript combo pagination: it returns a nav with a data-pagy attribute used by the pagy.js file
30
- def pagy_combo_nav_js(pagy, id: nil, aria_label: nil)
30
+ def pagy_combo_nav_js(pagy, id: nil, aria_label: nil, **vars)
31
31
  id = %( id="#{id}") if id
32
- a = pagy_anchor(pagy)
32
+ a = pagy_anchor(pagy, **vars)
33
33
  pages = pagy.pages
34
34
 
35
35
  page_input = %(<input name="page" type="number" min="1" max="#{pages}" value="#{pagy.page}" aria-current="page" ) <<
@@ -37,7 +37,7 @@ class Pagy # :nodoc:
37
37
 
38
38
  %(<nav#{id} class="pagy combo-nav-js" #{
39
39
  nav_aria_label(pagy, aria_label:)} #{
40
- pagy_data(pagy, :combo, pagy_url_for(pagy, PAGE_TOKEN))}>#{
40
+ pagy_data(pagy, :combo, pagy_url_for(pagy, PAGE_TOKEN, **vars))}>#{
41
41
  prev_a(pagy, a)
42
42
  }<label>#{
43
43
  pagy_t('pagy.combo_nav_js', page_input:, pages:)
@@ -47,35 +47,35 @@ class Pagy # :nodoc:
47
47
  end
48
48
 
49
49
  # Return the previous page URL string or nil
50
- def pagy_prev_url(pagy, absolute: false)
51
- pagy_url_for(pagy, pagy.prev, absolute:) if pagy.prev
50
+ def pagy_prev_url(pagy, **vars)
51
+ pagy_url_for(pagy, pagy.prev, **vars) if pagy.prev
52
52
  end
53
53
 
54
54
  # Return the next page URL string or nil
55
- def pagy_next_url(pagy, absolute: false)
56
- pagy_url_for(pagy, pagy.next, absolute:) if pagy.next
55
+ def pagy_next_url(pagy, **vars)
56
+ pagy_url_for(pagy, pagy.next, **vars) if pagy.next
57
57
  end
58
58
 
59
59
  # Return the enabled/disabled previous page anchor tag
60
- def pagy_prev_a(pagy, text: pagy_t('pagy.prev'), aria_label: pagy_t('pagy.aria_label.prev'))
61
- a = pagy_anchor(pagy)
60
+ def pagy_prev_a(pagy, text: pagy_t('pagy.prev'), aria_label: pagy_t('pagy.aria_label.prev'), **vars)
61
+ a = pagy_anchor(pagy, **vars)
62
62
  prev_a(pagy, a, text:, aria_label:)
63
63
  end
64
64
 
65
65
  # Return the enabled/disabled next page anchor tag
66
- def pagy_next_a(pagy, text: pagy_t('pagy.next'), aria_label: pagy_t('pagy.aria_label.next'))
67
- a = pagy_anchor(pagy)
66
+ def pagy_next_a(pagy, text: pagy_t('pagy.next'), aria_label: pagy_t('pagy.aria_label.next'), **vars)
67
+ a = pagy_anchor(pagy, **vars)
68
68
  next_a(pagy, a, text:, aria_label:)
69
69
  end
70
70
 
71
71
  # Conditionally return the previous page link tag
72
- def pagy_prev_link(pagy, absolute: false)
73
- %(<link href="#{pagy_url_for(pagy, pagy.prev, absolute:)}"/>) if pagy.prev
72
+ def pagy_prev_link(pagy, **vars)
73
+ %(<link href="#{pagy_url_for(pagy, pagy.prev, **vars)}"/>) if pagy.prev
74
74
  end
75
75
 
76
76
  # Conditionally return the next page link tag
77
- def pagy_next_link(pagy, absolute: false)
78
- %(<link href="#{pagy_url_for(pagy, pagy.next, absolute:)}"/>) if pagy.next
77
+ def pagy_next_link(pagy, **vars)
78
+ %(<link href="#{pagy_url_for(pagy, pagy.next, **vars)}"/>) if pagy.next
79
79
  end
80
80
  end
81
81
  Frontend.prepend PagyExtra
@@ -23,11 +23,11 @@ class Pagy # :nodoc:
23
23
  # Additions for the Pagy class
24
24
  module PagyExtension
25
25
  # Create a Pagy object from a Searchkick::Results object
26
- def new_from_searchkick(results, vars = {})
27
- vars[:items] = results.options[:per_page]
26
+ def new_from_searchkick(results, **vars)
27
+ vars[:limit] = results.options[:per_page]
28
28
  vars[:page] = results.options[:page]
29
29
  vars[:count] = results.total_count
30
- new(vars)
30
+ new(**vars)
31
31
  end
32
32
  end
33
33
  Pagy.extend PagyExtension
@@ -37,30 +37,22 @@ class Pagy # :nodoc:
37
37
  private
38
38
 
39
39
  # Return Pagy object and results
40
- def pagy_searchkick(pagy_search_args, vars = {})
40
+ def pagy_searchkick(pagy_search_args, **vars)
41
+ vars[:page] ||= pagy_get_page(vars)
42
+ vars[:limit] ||= pagy_get_limit(vars)
41
43
  model, term, options, block, *called = pagy_search_args
42
- vars = pagy_searchkick_get_vars(nil, vars)
43
- options[:per_page] = vars[:items]
44
+ options[:per_page] = vars[:limit]
44
45
  options[:page] = vars[:page]
45
46
  results = model.send(DEFAULT[:searchkick_search], term, **options, &block)
46
47
  vars[:count] = results.total_count
47
48
 
48
- pagy = ::Pagy.new(vars)
49
+ pagy = ::Pagy.new(**vars)
49
50
  # with :last_page overflow we need to re-run the method in order to get the hits
50
- return pagy_searchkick(pagy_search_args, vars.merge(page: pagy.page)) \
51
+ return pagy_searchkick(pagy_search_args, **vars, page: pagy.page) \
51
52
  if defined?(::Pagy::OverflowExtra) && pagy.overflow? && pagy.vars[:overflow] == :last_page
52
53
 
53
54
  [pagy, called.empty? ? results : results.send(*called)]
54
55
  end
55
-
56
- # Sub-method called only by #pagy_searchkick: here for easy customization of variables by overriding
57
- # the _collection argument is not available when the method is called
58
- def pagy_searchkick_get_vars(_collection, vars)
59
- pagy_set_items_from_params(vars) if defined?(ItemsExtra)
60
- vars[:items] ||= DEFAULT[:items]
61
- vars[:page] ||= pagy_get_page(vars)
62
- vars
63
- end
64
56
  end
65
57
  Backend.prepend BackendAddOn
66
58
  end
@@ -5,7 +5,7 @@ class Pagy # :nodoc:
5
5
  # Implement the legacy bar using the array size.
6
6
  # Unless you have very specific requirements, use the faster and better looking default bar.
7
7
  module SizeExtra
8
- # Setup @items based on the :gearbox_items variable
8
+ # Implements the old series algorithm
9
9
  def series(size: @vars[:size], **_)
10
10
  return super unless size.is_a?(Array)
11
11
  return [] if size == []