pagy 3.8.2 → 9.4.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 (152) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +1 -1
  3. data/apps/calendar.ru +737 -0
  4. data/apps/demo.ru +449 -0
  5. data/apps/index.rb +7 -0
  6. data/apps/keyset_ar.ru +228 -0
  7. data/apps/keyset_s.ru +220 -0
  8. data/apps/rails.ru +217 -0
  9. data/apps/repro.ru +182 -0
  10. data/bin/pagy +98 -0
  11. data/config/pagy.rb +220 -0
  12. data/javascripts/pagy.d.ts +5 -0
  13. data/javascripts/pagy.min.js +4 -0
  14. data/javascripts/pagy.min.js.map +10 -0
  15. data/javascripts/pagy.mjs +100 -0
  16. data/lib/optimist.rb +1022 -0
  17. data/lib/pagy/b64.rb +33 -0
  18. data/lib/pagy/backend.rb +30 -19
  19. data/lib/pagy/calendar/day.rb +41 -0
  20. data/lib/pagy/calendar/month.rb +42 -0
  21. data/lib/pagy/calendar/quarter.rb +49 -0
  22. data/lib/pagy/calendar/unit.rb +103 -0
  23. data/lib/pagy/calendar/week.rb +39 -0
  24. data/lib/pagy/calendar/year.rb +35 -0
  25. data/lib/pagy/calendar.rb +84 -0
  26. data/lib/pagy/console.rb +23 -0
  27. data/lib/pagy/countless.rb +27 -22
  28. data/lib/pagy/exceptions.rb +16 -13
  29. data/lib/pagy/extras/arel.rb +11 -14
  30. data/lib/pagy/extras/array.rb +12 -16
  31. data/lib/pagy/extras/bootstrap.rb +83 -41
  32. data/lib/pagy/extras/bulma.rb +79 -46
  33. data/lib/pagy/extras/calendar.rb +79 -0
  34. data/lib/pagy/extras/countless.rb +20 -25
  35. data/lib/pagy/extras/elasticsearch_rails.rb +59 -38
  36. data/lib/pagy/extras/gearbox.rb +55 -0
  37. data/lib/pagy/extras/headers.rb +38 -23
  38. data/lib/pagy/extras/i18n.rb +19 -18
  39. data/lib/pagy/extras/js_tools.rb +70 -0
  40. data/lib/pagy/extras/jsonapi.rb +88 -0
  41. data/lib/pagy/extras/keyset.rb +30 -0
  42. data/lib/pagy/extras/limit.rb +63 -0
  43. data/lib/pagy/extras/meilisearch.rb +57 -0
  44. data/lib/pagy/extras/metadata.rb +32 -27
  45. data/lib/pagy/extras/overflow.rb +61 -53
  46. data/lib/pagy/extras/pagy.rb +82 -0
  47. data/lib/pagy/extras/searchkick.rb +52 -41
  48. data/lib/pagy/extras/size.rb +40 -0
  49. data/lib/pagy/extras/standalone.rb +60 -0
  50. data/lib/pagy/extras/trim.rb +19 -13
  51. data/lib/pagy/frontend.rb +76 -51
  52. data/lib/pagy/i18n.rb +167 -0
  53. data/lib/pagy/keyset/active_record.rb +44 -0
  54. data/lib/pagy/keyset/sequel.rb +57 -0
  55. data/lib/pagy/keyset.rb +118 -0
  56. data/lib/pagy/shared_methods.rb +26 -0
  57. data/lib/pagy/url_helpers.rb +26 -0
  58. data/lib/pagy.rb +91 -37
  59. data/locales/ar.yml +29 -0
  60. data/locales/be.yml +25 -0
  61. data/locales/bg.yml +21 -0
  62. data/locales/bs.yml +25 -0
  63. data/locales/ca.yml +21 -0
  64. data/locales/ckb.yml +18 -0
  65. data/locales/cs.yml +23 -0
  66. data/locales/da.yml +21 -0
  67. data/locales/de.yml +21 -0
  68. data/locales/dz.yml +17 -0
  69. data/locales/en.yml +21 -0
  70. data/{lib/locales → locales}/es.yml +11 -12
  71. data/locales/fr.yml +21 -0
  72. data/locales/hr.yml +25 -0
  73. data/locales/id.yml +19 -0
  74. data/locales/it.yml +21 -0
  75. data/locales/ja.yml +19 -0
  76. data/locales/km.yml +19 -0
  77. data/locales/ko.yml +17 -0
  78. data/locales/nb.yml +21 -0
  79. data/locales/nl.yml +21 -0
  80. data/locales/nn.yml +21 -0
  81. data/locales/pl.yml +25 -0
  82. data/{lib/locales → locales}/pt-BR.yml +11 -12
  83. data/locales/pt.yml +21 -0
  84. data/locales/ru.yml +25 -0
  85. data/locales/sk.yml +23 -0
  86. data/locales/sr.yml +25 -0
  87. data/locales/sv-SE.yml +21 -0
  88. data/locales/sv.yml +21 -0
  89. data/locales/sw.yml +25 -0
  90. data/locales/ta.yml +21 -0
  91. data/locales/tr.yml +19 -0
  92. data/locales/uk.yml +25 -0
  93. data/locales/vi.yml +17 -0
  94. data/locales/zh-CN.yml +17 -0
  95. data/locales/zh-HK.yml +17 -0
  96. data/locales/zh-TW.yml +17 -0
  97. data/stylesheets/pagy.css +46 -0
  98. data/stylesheets/pagy.scss +48 -0
  99. data/stylesheets/pagy.tailwind.css +21 -0
  100. metadata +95 -67
  101. data/lib/config/pagy.rb +0 -170
  102. data/lib/javascripts/pagy.js +0 -106
  103. data/lib/locales/README.md +0 -35
  104. data/lib/locales/bg.yml +0 -22
  105. data/lib/locales/ca.yml +0 -22
  106. data/lib/locales/da.yml +0 -22
  107. data/lib/locales/de.yml +0 -22
  108. data/lib/locales/en.yml +0 -22
  109. data/lib/locales/fr.yml +0 -22
  110. data/lib/locales/id.yml +0 -20
  111. data/lib/locales/it.yml +0 -22
  112. data/lib/locales/ja.yml +0 -20
  113. data/lib/locales/km.yml +0 -19
  114. data/lib/locales/ko.yml +0 -20
  115. data/lib/locales/nb.yml +0 -22
  116. data/lib/locales/nl.yml +0 -22
  117. data/lib/locales/pl.yml +0 -24
  118. data/lib/locales/ru.yml +0 -24
  119. data/lib/locales/sv-SE.yml +0 -23
  120. data/lib/locales/sv.yml +0 -23
  121. data/lib/locales/tr.yml +0 -20
  122. data/lib/locales/utils/i18n.rb +0 -25
  123. data/lib/locales/utils/loader.rb +0 -34
  124. data/lib/locales/utils/p11n.rb +0 -80
  125. data/lib/locales/zh-CN.yml +0 -20
  126. data/lib/locales/zh-HK.yml +0 -20
  127. data/lib/locales/zh-TW.yml +0 -20
  128. data/lib/pagy/extras/foundation.rb +0 -57
  129. data/lib/pagy/extras/items.rb +0 -65
  130. data/lib/pagy/extras/materialize.rb +0 -59
  131. data/lib/pagy/extras/navs.rb +0 -38
  132. data/lib/pagy/extras/pagy_search.rb +0 -18
  133. data/lib/pagy/extras/semantic.rb +0 -55
  134. data/lib/pagy/extras/shared.rb +0 -53
  135. data/lib/pagy/extras/support.rb +0 -29
  136. data/lib/pagy/extras/uikit.rb +0 -62
  137. data/lib/templates/bootstrap_nav.html.erb +0 -24
  138. data/lib/templates/bootstrap_nav.html.haml +0 -34
  139. data/lib/templates/bootstrap_nav.html.slim +0 -34
  140. data/lib/templates/bulma_nav.html.erb +0 -24
  141. data/lib/templates/bulma_nav.html.haml +0 -32
  142. data/lib/templates/bulma_nav.html.slim +0 -32
  143. data/lib/templates/foundation_nav.html.erb +0 -24
  144. data/lib/templates/foundation_nav.html.haml +0 -34
  145. data/lib/templates/foundation_nav.html.slim +0 -34
  146. data/lib/templates/nav.html.erb +0 -22
  147. data/lib/templates/nav.html.haml +0 -30
  148. data/lib/templates/nav.html.slim +0 -29
  149. data/lib/templates/uikit_nav.html.erb +0 -15
  150. data/lib/templates/uikit_nav.html.haml +0 -28
  151. data/lib/templates/uikit_nav.html.slim +0 -28
  152. data/pagy.gemspec +0 -16
@@ -0,0 +1,55 @@
1
+ # See the Pagy documentation: https://ddnexus.github.io/pagy/docs/extras/gearbox
2
+ # frozen_string_literal: true
3
+
4
+ class Pagy # :nodoc:
5
+ DEFAULT[:gearbox_extra] = true # extra enabled by default
6
+ DEFAULT[:gearbox_limit] = [15, 30, 60, 100]
7
+
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
+ module GearboxExtra
11
+ # Assign @limit based on the :gearbox_limit variable
12
+ def assign_limit
13
+ return super if !@vars[:gearbox_extra] || @vars[:limit_extra]
14
+
15
+ gears = @vars[:gearbox_limit]
16
+ raise VariableError.new(self, :gearbox_limit, 'to be an Array of positives', gears) \
17
+ unless gears.is_a?(Array) && gears.all? { |num| num.positive? rescue false } # rubocop:disable Style/RescueModifier
18
+
19
+ @limit = gears[@page - 1] || gears.last
20
+ end
21
+
22
+ # Asgnsi @offset based on the :gearbox_limit variable
23
+ def assign_offset
24
+ return super if !@vars[:gearbox_extra] || @vars[:limit_extra]
25
+
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]
39
+ # This algorithm is thousands of times faster than the one in the geared_pagination gem
40
+ @last = (if count > (sum = gears.sum)
41
+ [((count - sum).to_f / gears.last).ceil, 1].max + gears.count
42
+ else
43
+ pages = 0
44
+ remainder = count
45
+ while remainder.positive?
46
+ pages += 1
47
+ remainder -= gears[pages - 1]
48
+ end
49
+ [pages, 1].max
50
+ end)
51
+ @last = @vars[:max_pages] if @vars[:max_pages] && @last > @vars[:max_pages]
52
+ end
53
+ end
54
+ prepend GearboxExtra
55
+ end
@@ -1,39 +1,54 @@
1
- # See the Pagy documentation: https://ddnexus.github.io/pagy/extras/headers
2
- # encoding: utf-8
1
+ # See the Pagy documentation: https://ddnexus.github.io/pagy/docs/extras/headers
3
2
  # frozen_string_literal: true
4
3
 
5
- class Pagy
6
- # Add specialized backend methods to add pagination response headers
7
- module Backend ; private
4
+ require_relative '../url_helpers'
8
5
 
9
- VARS[:headers] = { page: 'Current-Page', items: 'Page-Items', count: 'Total-Count', pages: 'Total-Pages' }
6
+ class Pagy # :nodoc:
7
+ DEFAULT[:headers] = { page: 'current-page',
8
+ limit: 'page-items',
9
+ count: 'total-count',
10
+ pages: 'total-pages' }
11
+ # Add specialized backend methods to add pagination response headers
12
+ module HeadersExtra
13
+ include UrlHelpers
10
14
 
11
- include Helpers
15
+ private
12
16
 
17
+ # Merge the pagy headers into the response.headers
13
18
  def pagy_headers_merge(pagy)
14
19
  response.headers.merge!(pagy_headers(pagy))
15
20
  end
16
21
 
22
+ # Generate a hash of RFC-8288 compliant http headers
17
23
  def pagy_headers(pagy)
18
- hash = pagy_headers_hash(pagy)
19
- hash['Link'] = hash['Link'].map{|rel, link| %(<#{link}>; rel="#{rel}")}.join(', ')
20
- hash
21
- 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))
22
31
 
23
- def pagy_headers_hash(pagy)
24
- countless = defined?(Pagy::Countless) && pagy.is_a?(Pagy::Countless)
25
- rels = { 'first' => 1, 'prev' => pagy.prev, 'next' => pagy.next }; rels['last'] = pagy.last unless countless
26
- url_str = pagy_url_for(PAGE_PLACEHOLDER, pagy, :url)
27
- hash = { 'Link' => Hash[rels.map{|rel, n|[rel, url_str.sub(PAGE_PLACEHOLDER, n.to_s)] if n}.compact] }
28
- headers = pagy.vars[:headers]
29
- hash[headers[:page]] = pagy.page.to_s if headers[:page]
30
- hash[headers[:items]] = pagy.vars[:items].to_s if headers[:items]
31
- unless countless
32
- hash[headers[:pages]] = pagy.pages.to_s if headers[:pages]
33
- hash[headers[:count]] = pagy.count.to_s if headers[:count]
32
+ hash[headers[:pages]] = pagy.last.to_s if headers[:pages]
33
+ hash[headers[:count]] = pagy.count.to_s if pagy.count && headers[:count] # count may be nil with Calendar
34
34
  end
35
- hash
36
35
  end
37
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(', ') }
51
+ end
38
52
  end
53
+ Backend.prepend HeadersExtra
39
54
  end
@@ -1,25 +1,26 @@
1
- # See the Pagy documentation: https://ddnexus.github.io/pagy/extras/i18n
2
- # encoding: utf-8
1
+ # See the Pagy documentation: https://ddnexus.github.io/pagy/docs/extras/i18n
3
2
  # frozen_string_literal: true
4
3
 
5
- class Pagy
4
+ class Pagy # :nodoc:
6
5
  # Use ::I18n gem
7
- module Frontend
8
-
9
- ::I18n.load_path += Dir[Pagy.root.join('locales', '*.yml')]
10
-
11
- Pagy::I18n.clear.instance_eval { undef :load; undef :t } # unload the pagy default constant for efficiency
12
-
13
- alias_method :pagy_without_i18n, :pagy_t
14
- if Gem::Version.new(::I18n::VERSION) < Gem::Version.new('1.6.0')
15
- def pagy_t_with_i18n(*args) ::I18n.t(*args) end
16
- else
17
- # keep 1.9 compatibility by hiding 2.0+ syntax in string
18
- module_eval <<-RUBY
19
- def pagy_t_with_i18n(key, **opts) ::I18n.t(key, **opts) end
20
- RUBY
6
+ module I18nExtra
7
+ # Frontend overriding for translation
8
+ module FrontendOverride
9
+ def pagy_t(key, **opts)
10
+ ::I18n.t(key, **opts)
11
+ end
21
12
  end
22
- alias_method :pagy_t, :pagy_t_with_i18n
13
+ Frontend.prepend I18nExtra::FrontendOverride
23
14
 
15
+ # Calendar overriding for localization (see also the block in the calendar section of the config/pagy.rb initializer)
16
+ module CalendarOverride
17
+ def localize(time, opts)
18
+ ::I18n.l(time, **opts)
19
+ end
20
+ end
24
21
  end
22
+ Calendar::Unit.prepend I18nExtra::CalendarOverride if defined?(::Pagy::Calendar::Unit)
23
+
24
+ # Add the pagy locales to the I18n.load_path
25
+ ::I18n.load_path += Dir[Pagy.root.join('locales', '*.yml')]
25
26
  end
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../b64'
4
+
5
+ class Pagy # :nodoc:
6
+ DEFAULT[:steps] = false # default false will use {0 => @vars[:size]}
7
+
8
+ # Private module documented in the main classes
9
+ module JSTools
10
+ # Dummy tag for input helpers: needed because Turbo does not intercept window.location changes
11
+ A_TAG = '<a href="#" style="display: none;">#</a>'
12
+
13
+ # Additions for the Pagy class
14
+ module PagyAddOn
15
+ # `Pagy` instance method used by the `pagy*_nav_js` helpers.
16
+ # It returns the sequels of width/series generated from the :steps hash
17
+ # Example:
18
+ # >> pagy = Pagy.new(count:1000, page: 20, steps: {0 => 5, 350 => 7, 550 => 9})
19
+ # >> pagy.sequels
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] }
23
+ # Notice: if :steps is false it will use the single {0 => @vars[:size]} size
24
+ def sequels(steps: @vars[:steps] || { 0 => @vars[:size] }, **_)
25
+ raise VariableError.new(self, :steps, 'to define the 0 width', steps) unless steps.key?(0)
26
+
27
+ {}.tap do |sequels|
28
+ steps.each { |width, step_size| sequels[width.to_s] = series(size: step_size) }
29
+ end
30
+ end
31
+
32
+ # Support for the Calendar API
33
+ def label_sequels(*); end
34
+ end
35
+ Pagy.prepend PagyAddOn
36
+
37
+ # Additions for Calendar class
38
+ module CalendarOverride
39
+ def label_sequels(sequels = self.sequels)
40
+ {}.tap do |label_sequels|
41
+ sequels.each do |width, series|
42
+ label_sequels[width] = series.map { |item| item == :gap ? :gap : label_for(item) }
43
+ end
44
+ end
45
+ end
46
+ end
47
+ Calendar::Unit.prepend CalendarOverride if defined?(::Pagy::Calendar::Unit)
48
+
49
+ # Additions for the Frontend
50
+ module FrontendAddOn
51
+ if defined?(::Oj)
52
+ # Return a data tag with the base64 encoded JSON-serialized args generated with the faster oj gem
53
+ # Base64 encoded JSON is smaller than HTML escaped JSON
54
+ def pagy_data(pagy, *args)
55
+ args << pagy.vars[:page_param] if pagy.vars[:trim_extra]
56
+ %(data-pagy="#{B64.encode(Oj.dump(args, mode: :strict))}")
57
+ end
58
+ else
59
+ require 'json'
60
+ # Return a data tag with the base64 encoded JSON-serialized args generated with the slower to_json
61
+ # Base64 encoded JSON is smaller than HTML escaped JSON
62
+ def pagy_data(pagy, *args)
63
+ args << pagy.vars[:page_param] if pagy.vars[:trim_extra]
64
+ %(data-pagy="#{B64.encode(args.to_json)}")
65
+ end
66
+ end
67
+ end
68
+ Frontend.prepend FrontendAddOn
69
+ end
70
+ end
@@ -0,0 +1,88 @@
1
+ # See the Pagy documentation: https://ddnexus.github.io/pagy/docs/extras/jsonapi
2
+ # frozen_string_literal: true
3
+
4
+ require_relative '../url_helpers'
5
+
6
+ class Pagy # :nodoc:
7
+ DEFAULT[:jsonapi] = true
8
+
9
+ # Add a specialized backend method compliant with JSON:API
10
+ module JsonApiExtra
11
+ # JsonApi :page param error
12
+ class ReservedParamError < StandardError
13
+ # Inform about the actual value
14
+ def initialize(value)
15
+ super("expected reserved :page param to be nil or Hash-like; got #{value.inspect}")
16
+ end
17
+ end
18
+
19
+ # Module overriding Backend
20
+ module BackendOverride
21
+ include UrlHelpers
22
+
23
+ private(*UrlHelpers.instance_methods)
24
+
25
+ private
26
+
27
+ # Return the jsonapi links
28
+ def pagy_jsonapi_links(pagy, **opts)
29
+ if defined?(::Pagy::Keyset) && pagy.is_a?(Keyset)
30
+ { first: pagy_url_for(pagy, nil, **opts),
31
+ last: nil,
32
+ prev: nil,
33
+ next: pagy.next ? pagy_url_for(pagy, pagy.next, **opts) : nil }
34
+ else
35
+ { first: pagy_url_for(pagy, 1, **opts),
36
+ last: pagy_url_for(pagy, pagy.last, **opts),
37
+ prev: pagy.prev ? pagy_url_for(pagy, pagy.prev, **opts) : nil,
38
+ next: pagy.next ? pagy_url_for(pagy, pagy.next, **opts) : nil }
39
+ end
40
+ end
41
+
42
+ # Should skip the jsonapi
43
+ def pagy_skip_jsonapi?(vars)
44
+ return true if vars[:jsonapi] == false || (vars[:jsonapi].nil? && DEFAULT[:jsonapi] == false)
45
+ # check the reserved :page param
46
+ raise ReservedParamError, params[:page] unless params[:page].respond_to?(:fetch) || params[:page].nil?
47
+ end
48
+
49
+ # Override the Backend method
50
+ def pagy_get_page(vars, force_integer: true)
51
+ return super if pagy_skip_jsonapi?(vars) || params[:page].nil?
52
+
53
+ page = params[:page][vars[:page_param] || DEFAULT[:page_param]]
54
+ force_integer ? (page || 1).to_i : page
55
+ end
56
+ end
57
+ Backend.prepend BackendOverride
58
+
59
+ # Module overriding LimitExtra
60
+ module LimitExtraOverride
61
+ private
62
+
63
+ # Override the LimitExtra::Backend method
64
+ def pagy_get_limit_param(vars)
65
+ return super if pagy_skip_jsonapi?(vars)
66
+ return unless params[:page]
67
+
68
+ params[:page][vars[:limit_param] || DEFAULT[:limit_param]]
69
+ end
70
+ end
71
+ # :nocov:
72
+ LimitExtra::BackendAddOn.prepend LimitExtraOverride if defined?(::Pagy::LimitExtra::BackendAddOn)
73
+ # :nocov:
74
+
75
+ # Module overriding UrlHelper
76
+ module UrlHelperOverride
77
+ # Override UrlHelper method
78
+ def pagy_set_query_params(page, vars, query_params)
79
+ return super unless vars[:jsonapi]
80
+
81
+ query_params['page'] ||= {}
82
+ query_params['page'][vars[:page_param].to_s] = page
83
+ query_params['page'][vars[:limit_param].to_s] = vars[:limit] if vars[:limit_extra]
84
+ end
85
+ end
86
+ UrlHelpers.prepend UrlHelperOverride
87
+ end
88
+ end
@@ -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
@@ -0,0 +1,57 @@
1
+ # See the Pagy documentation: https://ddnexus.github.io/pagy/docs/extras/meilisearch
2
+ # frozen_string_literal: true
3
+
4
+ class Pagy # :nodoc:
5
+ DEFAULT[:meilisearch_search] ||= :ms_search
6
+ DEFAULT[:meilisearch_pagy_search] ||= :pagy_search
7
+
8
+ # Paginate Meilisearch results
9
+ module MeilisearchExtra
10
+ module ModelExtension # :nodoc:
11
+ # Return an array used to delay the call of #search
12
+ # after the pagination variables are merged to the options
13
+ def pagy_meilisearch(query, params = {})
14
+ [self, query, params]
15
+ end
16
+ alias_method DEFAULT[:meilisearch_pagy_search], :pagy_meilisearch
17
+ end
18
+ Pagy::Meilisearch = ModelExtension
19
+
20
+ # Extension for the Pagy class
21
+ module PagyExtension
22
+ # Create a Pagy object from a Meilisearch results
23
+ def new_from_meilisearch(results, **vars)
24
+ vars[:limit] = results.raw_answer['hitsPerPage']
25
+ vars[:page] = results.raw_answer['page']
26
+ vars[:count] = results.raw_answer['totalHits']
27
+
28
+ new(**vars)
29
+ end
30
+ end
31
+ Pagy.extend PagyExtension
32
+
33
+ # Add specialized backend methods to paginate Meilisearch results
34
+ module BackendAddOn
35
+ private
36
+
37
+ # Return Pagy object and results
38
+ def pagy_meilisearch(pagy_search_args, **vars)
39
+ vars[:page] ||= pagy_get_page(vars)
40
+ vars[:limit] ||= pagy_get_limit(vars)
41
+ model, term, options = pagy_search_args
42
+ options[:hits_per_page] = vars[:limit]
43
+ options[:page] = vars[:page]
44
+ results = model.send(:ms_search, term, options)
45
+ vars[:count] = results.raw_answer['totalHits']
46
+
47
+ pagy = ::Pagy.new(**vars)
48
+ # with :last_page overflow we need to re-run the method in order to get the hits
49
+ return pagy_meilisearch(pagy_search_args, **vars, page: pagy.page) \
50
+ if defined?(::Pagy::OverflowExtra) && pagy.overflow? && pagy.vars[:overflow] == :last_page
51
+
52
+ [pagy, results]
53
+ end
54
+ end
55
+ Backend.prepend BackendAddOn
56
+ end
57
+ end
@@ -1,37 +1,42 @@
1
- # See the Pagy documentation: https://ddnexus.github.io/pagy/extras/metadata
2
- # encoding: utf-8
1
+ # See the Pagy documentation: https://ddnexus.github.io/pagy/docs/extras/metadata
3
2
  # frozen_string_literal: true
4
3
 
5
- class Pagy
6
- # Add a specialized backend method for pagination metadata
7
- module Backend ; private
4
+ require_relative '../url_helpers'
8
5
 
9
- METADATA = [ :scaffold_url, :first_url, :prev_url, :page_url, :next_url, :last_url,
10
- :count, :page, :items, :vars, :pages, :last, :from, :to, :prev, :next, :series ]
11
- METADATA << :sequels if VARS.key?(:steps) # :steps gets defined along with the #sequels method
6
+ class Pagy # :nodoc:
7
+ DEFAULT[:metadata] = %i[ scaffold_url first_url prev_url page_url next_url last_url
8
+ count page limit vars pages last in from to prev next series ]
12
9
 
13
- VARS[:metadata] = METADATA.dup
10
+ # Add a specialized backend method for pagination metadata
11
+ module MetadataExtra
12
+ private
14
13
 
15
- include Helpers
14
+ include UrlHelpers
16
15
 
17
- def pagy_metadata(pagy, url=false)
18
- names = pagy.vars[:metadata]
19
- (unknown = names - METADATA).empty? or raise(VariableError.new(pagy), "unknown metadata #{unknown.inspect}")
20
- scaffold_url = pagy_url_for(PAGE_PLACEHOLDER, pagy, url)
21
- metadata = {}
22
- names.each do |key|
23
- metadata[key] = case key
24
- when :scaffold_url ; scaffold_url
25
- when :first_url ; scaffold_url.sub(PAGE_PLACEHOLDER, 1.to_s)
26
- when :prev_url ; scaffold_url.sub(PAGE_PLACEHOLDER, pagy.prev.to_s)
27
- when :page_url ; scaffold_url.sub(PAGE_PLACEHOLDER, pagy.page.to_s)
28
- when :next_url ; scaffold_url.sub(PAGE_PLACEHOLDER, pagy.next.to_s)
29
- when :last_url ; scaffold_url.sub(PAGE_PLACEHOLDER, pagy.last.to_s)
30
- else pagy.send(key)
31
- end
16
+ # Return the metadata hash
17
+ def pagy_metadata(pagy, absolute: nil)
18
+ scaffold_url = pagy_url_for(pagy, PAGE_TOKEN, absolute:)
19
+ {}.tap do |metadata|
20
+ keys = if defined?(::Pagy::Calendar::Unit) && pagy.is_a?(Calendar::Unit)
21
+ pagy.vars[:metadata] - %i[count limit]
22
+ else
23
+ pagy.vars[:metadata]
24
+ end
25
+ keys.each do |key|
26
+ metadata[key] = case key
27
+ when :scaffold_url then scaffold_url
28
+ when :first_url then scaffold_url.sub(PAGE_TOKEN, 1.to_s)
29
+ when :prev_url then scaffold_url.sub(PAGE_TOKEN, pagy.prev.to_s)
30
+ when :page_url then scaffold_url.sub(PAGE_TOKEN, pagy.page.to_s)
31
+ when :next_url then scaffold_url.sub(PAGE_TOKEN, pagy.next.to_s)
32
+ when :last_url then scaffold_url.sub(PAGE_TOKEN, pagy.last.to_s)
33
+ else pagy.send(key)
34
+ end
35
+ rescue NoMethodError
36
+ raise VariableError.new(pagy, :metadata, 'to contain known keys', key)
37
+ end
32
38
  end
33
- metadata
34
39
  end
35
-
36
40
  end
41
+ Backend.prepend MetadataExtra
37
42
  end