pagy 9.4.0 → 43.5.5

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 (176) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +1 -1
  3. data/apps/calendar.ru +566 -562
  4. data/apps/demo.ru +246 -182
  5. data/apps/enable_rails_page_segment.rb +56 -0
  6. data/apps/index.rb +4 -2
  7. data/apps/keynav+root_key.ru +316 -0
  8. data/apps/keynav.ru +255 -0
  9. data/apps/{keyset_ar.ru → keyset.ru} +33 -42
  10. data/apps/{keyset_s.ru → keyset_sequel.ru} +32 -40
  11. data/apps/rails.ru +57 -58
  12. data/apps/repro.ru +54 -51
  13. data/bin/pagy +2 -95
  14. data/config/pagy.rb +33 -207
  15. data/javascripts/ai_widget.js +90 -0
  16. data/javascripts/pagy.js +166 -0
  17. data/javascripts/pagy.min.js +2 -4
  18. data/javascripts/pagy.mjs +126 -67
  19. data/javascripts/wand.js +1172 -0
  20. data/lib/pagy/classes/calendar/calendar.rb +101 -0
  21. data/lib/pagy/{calendar → classes/calendar}/day.rb +7 -11
  22. data/lib/pagy/{calendar → classes/calendar}/month.rb +5 -10
  23. data/lib/pagy/{calendar → classes/calendar}/quarter.rb +10 -15
  24. data/lib/pagy/classes/calendar/unit.rb +93 -0
  25. data/lib/pagy/{calendar → classes/calendar}/week.rb +5 -9
  26. data/lib/pagy/{calendar → classes/calendar}/year.rb +5 -6
  27. data/lib/pagy/classes/exceptions.rb +26 -0
  28. data/lib/pagy/classes/keyset/adapters/active_record.rb +50 -0
  29. data/lib/pagy/classes/keyset/adapters/sequel.rb +62 -0
  30. data/lib/pagy/classes/keyset/keynav.rb +85 -0
  31. data/lib/pagy/classes/keyset/keyset.rb +155 -0
  32. data/lib/pagy/classes/offset/countish.rb +17 -0
  33. data/lib/pagy/classes/offset/countless.rb +63 -0
  34. data/lib/pagy/classes/offset/offset.rb +63 -0
  35. data/lib/pagy/classes/offset/search.rb +34 -0
  36. data/lib/pagy/classes/request.rb +48 -0
  37. data/lib/pagy/cli.rb +122 -0
  38. data/lib/pagy/console.rb +5 -20
  39. data/lib/pagy/deprecated.rb +84 -0
  40. data/lib/pagy/modules/abilities/configurable.rb +37 -0
  41. data/lib/pagy/modules/abilities/countable.rb +23 -0
  42. data/lib/pagy/modules/abilities/linkable.rb +72 -0
  43. data/lib/pagy/modules/abilities/rangeable.rb +14 -0
  44. data/lib/pagy/modules/abilities/shiftable.rb +12 -0
  45. data/lib/pagy/{b64.rb → modules/b64.rb} +4 -2
  46. data/lib/pagy/modules/console.rb +33 -0
  47. data/lib/pagy/modules/i18n/i18n.rb +72 -0
  48. data/lib/pagy/modules/i18n/p11n/arabic.rb +30 -0
  49. data/lib/pagy/modules/i18n/p11n/east_slavic.rb +27 -0
  50. data/lib/pagy/modules/i18n/p11n/one_other.rb +15 -0
  51. data/lib/pagy/modules/i18n/p11n/one_upto_two_other.rb +15 -0
  52. data/lib/pagy/modules/i18n/p11n/other.rb +13 -0
  53. data/lib/pagy/modules/i18n/p11n/polish.rb +27 -0
  54. data/lib/pagy/modules/i18n/p11n/west_slavic.rb +22 -0
  55. data/lib/pagy/modules/i18n/p11n.rb +16 -0
  56. data/lib/pagy/modules/searcher.rb +20 -0
  57. data/lib/pagy/next.rb +25 -0
  58. data/lib/pagy/tasks/sync.rb +20 -0
  59. data/lib/pagy/toolbox/helpers/anchor_tags.rb +19 -0
  60. data/lib/pagy/toolbox/helpers/bootstrap/input_nav_js.rb +28 -0
  61. data/lib/pagy/toolbox/helpers/bootstrap/previous_next_html.rb +19 -0
  62. data/lib/pagy/toolbox/helpers/bootstrap/series_nav.rb +32 -0
  63. data/lib/pagy/toolbox/helpers/bootstrap/series_nav_js.rb +24 -0
  64. data/lib/pagy/toolbox/helpers/bulma/input_nav_js.rb +25 -0
  65. data/lib/pagy/toolbox/helpers/bulma/previous_next_html.rb +20 -0
  66. data/lib/pagy/toolbox/helpers/bulma/series_nav.rb +31 -0
  67. data/lib/pagy/toolbox/helpers/bulma/series_nav_js.rb +23 -0
  68. data/lib/pagy/toolbox/helpers/data_hash.rb +29 -0
  69. data/lib/pagy/toolbox/helpers/headers_hash.rb +30 -0
  70. data/lib/pagy/toolbox/helpers/info_tag.rb +30 -0
  71. data/lib/pagy/toolbox/helpers/input_nav_js.rb +22 -0
  72. data/lib/pagy/toolbox/helpers/limit_tag_js.rb +25 -0
  73. data/lib/pagy/toolbox/helpers/loaders.rb +58 -0
  74. data/lib/pagy/toolbox/helpers/page_url.rb +16 -0
  75. data/lib/pagy/toolbox/helpers/series_nav.rb +30 -0
  76. data/lib/pagy/toolbox/helpers/series_nav_js.rb +20 -0
  77. data/lib/pagy/toolbox/helpers/support/a_lambda.rb +36 -0
  78. data/lib/pagy/toolbox/helpers/support/data_pagy_attribute.rb +19 -0
  79. data/lib/pagy/toolbox/helpers/support/nav_aria_label_attribute.rb +10 -0
  80. data/lib/pagy/toolbox/helpers/support/series.rb +37 -0
  81. data/lib/pagy/toolbox/helpers/support/wrap_input_nav_js.rb +18 -0
  82. data/lib/pagy/toolbox/helpers/support/wrap_series_nav.rb +15 -0
  83. data/lib/pagy/toolbox/helpers/support/wrap_series_nav_js.rb +38 -0
  84. data/lib/pagy/toolbox/helpers/urls_hash.rb +12 -0
  85. data/lib/pagy/toolbox/paginators/calendar.rb +34 -0
  86. data/lib/pagy/toolbox/paginators/countish.rb +38 -0
  87. data/lib/pagy/toolbox/paginators/countless.rb +22 -0
  88. data/lib/pagy/toolbox/paginators/elasticsearch_rails.rb +56 -0
  89. data/lib/pagy/toolbox/paginators/keynav_js.rb +26 -0
  90. data/lib/pagy/toolbox/paginators/keyset.rb +15 -0
  91. data/lib/pagy/toolbox/paginators/meilisearch.rb +34 -0
  92. data/lib/pagy/toolbox/paginators/method.rb +38 -0
  93. data/lib/pagy/toolbox/paginators/offset.rb +24 -0
  94. data/lib/pagy/toolbox/paginators/searchkick.rb +34 -0
  95. data/lib/pagy/toolbox/paginators/typesense_rails.rb +34 -0
  96. data/lib/pagy.rb +79 -89
  97. data/locales/ar.yml +9 -6
  98. data/locales/be.yml +9 -6
  99. data/locales/bg.yml +9 -6
  100. data/locales/bs.yml +9 -6
  101. data/locales/ca.yml +9 -6
  102. data/locales/ckb.yml +8 -6
  103. data/locales/cs.yml +9 -6
  104. data/locales/da.yml +9 -6
  105. data/locales/de.yml +9 -6
  106. data/locales/dz.yml +9 -6
  107. data/locales/en.yml +9 -6
  108. data/locales/es.yml +9 -6
  109. data/locales/fr.yml +9 -6
  110. data/locales/hr.yml +9 -6
  111. data/locales/hu.yml +24 -0
  112. data/locales/id.yml +10 -9
  113. data/locales/it.yml +9 -6
  114. data/locales/ja.yml +10 -9
  115. data/locales/km.yml +10 -9
  116. data/locales/ko.yml +9 -6
  117. data/locales/nb.yml +9 -6
  118. data/locales/nl.yml +9 -6
  119. data/locales/nn.yml +9 -6
  120. data/locales/pl.yml +9 -6
  121. data/locales/pt-BR.yml +10 -7
  122. data/locales/pt.yml +10 -7
  123. data/locales/ru.yml +9 -6
  124. data/locales/sk.yml +9 -6
  125. data/locales/sr.yml +9 -6
  126. data/locales/sv-SE.yml +9 -6
  127. data/locales/sv.yml +9 -6
  128. data/locales/sw.yml +12 -9
  129. data/locales/ta.yml +9 -6
  130. data/locales/tr.yml +17 -12
  131. data/locales/uk.yml +9 -6
  132. data/locales/vi.yml +9 -6
  133. data/locales/zh-CN.yml +9 -6
  134. data/locales/zh-HK.yml +9 -6
  135. data/locales/zh-TW.yml +9 -6
  136. data/stylesheets/pagy-tailwind.css +68 -0
  137. data/stylesheets/pagy.css +64 -27
  138. metadata +134 -53
  139. data/javascripts/pagy.min.js.map +0 -10
  140. data/lib/optimist.rb +0 -1022
  141. data/lib/pagy/backend.rb +0 -44
  142. data/lib/pagy/calendar/unit.rb +0 -103
  143. data/lib/pagy/calendar.rb +0 -84
  144. data/lib/pagy/countless.rb +0 -38
  145. data/lib/pagy/exceptions.rb +0 -25
  146. data/lib/pagy/extras/arel.rb +0 -28
  147. data/lib/pagy/extras/array.rb +0 -19
  148. data/lib/pagy/extras/bootstrap.rb +0 -97
  149. data/lib/pagy/extras/bulma.rb +0 -93
  150. data/lib/pagy/extras/calendar.rb +0 -79
  151. data/lib/pagy/extras/countless.rb +0 -32
  152. data/lib/pagy/extras/elasticsearch_rails.rb +0 -71
  153. data/lib/pagy/extras/gearbox.rb +0 -55
  154. data/lib/pagy/extras/headers.rb +0 -54
  155. data/lib/pagy/extras/i18n.rb +0 -26
  156. data/lib/pagy/extras/js_tools.rb +0 -70
  157. data/lib/pagy/extras/jsonapi.rb +0 -88
  158. data/lib/pagy/extras/keyset.rb +0 -30
  159. data/lib/pagy/extras/limit.rb +0 -63
  160. data/lib/pagy/extras/meilisearch.rb +0 -57
  161. data/lib/pagy/extras/metadata.rb +0 -42
  162. data/lib/pagy/extras/overflow.rb +0 -81
  163. data/lib/pagy/extras/pagy.rb +0 -82
  164. data/lib/pagy/extras/searchkick.rb +0 -59
  165. data/lib/pagy/extras/size.rb +0 -40
  166. data/lib/pagy/extras/standalone.rb +0 -60
  167. data/lib/pagy/extras/trim.rb +0 -29
  168. data/lib/pagy/frontend.rb +0 -99
  169. data/lib/pagy/i18n.rb +0 -167
  170. data/lib/pagy/keyset/active_record.rb +0 -44
  171. data/lib/pagy/keyset/sequel.rb +0 -57
  172. data/lib/pagy/keyset.rb +0 -118
  173. data/lib/pagy/shared_methods.rb +0 -26
  174. data/lib/pagy/url_helpers.rb +0 -26
  175. data/stylesheets/pagy.scss +0 -48
  176. data/stylesheets/pagy.tailwind.css +0 -21
@@ -1,71 +0,0 @@
1
- # See the Pagy documentation: https://ddnexus.github.io/pagy/docs/extras/elasticsearch_rails
2
- # frozen_string_literal: true
3
-
4
- class Pagy # :nodoc:
5
- DEFAULT[:elasticsearch_rails_search] ||= :search
6
- DEFAULT[:elasticsearch_rails_pagy_search] ||= :pagy_search
7
-
8
- # Paginate ElasticsearchRails response objects
9
- module ElasticsearchRailsExtra
10
- module_function
11
-
12
- # Get the count from different version of ElasticsearchRails
13
- def total_count(response)
14
- total = if response.respond_to?(:raw_response)
15
- response.raw_response['hits']['total']
16
- else
17
- response.response['hits']['total']
18
- end
19
- total.is_a?(Hash) ? total['value'] : total
20
- end
21
-
22
- module ModelExtension # :nodoc:
23
- # Return an array used to delay the call of #search
24
- # after the pagination variables are merged to the options.
25
- # It also pushes to the same array an optional method call.
26
- def pagy_elasticsearch_rails(query_or_payload, **options)
27
- [self, query_or_payload, options].tap do |args|
28
- args.define_singleton_method(:method_missing) { |*a| args += a }
29
- end
30
- end
31
- alias_method DEFAULT[:elasticsearch_rails_pagy_search], :pagy_elasticsearch_rails
32
- end
33
- Pagy::ElasticsearchRails = ModelExtension
34
-
35
- # Additions for the Pagy class
36
- module PagyAddOn
37
- # Create a Pagy object from an Elasticsearch::Model::Response::Response object
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
- vars[:count] = ElasticsearchRailsExtra.total_count(response)
42
- Pagy.new(**vars)
43
- end
44
- end
45
- Pagy.extend PagyAddOn
46
-
47
- # Add specialized backend methods to paginate ElasticsearchRails searches
48
- module BackendAddOn
49
- private
50
-
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
-
61
- pagy = ::Pagy.new(**vars)
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, page: pagy.page) \
64
- if defined?(::Pagy::OverflowExtra) && pagy.overflow? && pagy.vars[:overflow] == :last_page
65
-
66
- [pagy, called.empty? ? response : response.send(*called)]
67
- end
68
- end
69
- Backend.prepend BackendAddOn
70
- end
71
- end
@@ -1,55 +0,0 @@
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,54 +0,0 @@
1
- # See the Pagy documentation: https://ddnexus.github.io/pagy/docs/extras/headers
2
- # frozen_string_literal: true
3
-
4
- require_relative '../url_helpers'
5
-
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
14
-
15
- private
16
-
17
- # Merge the pagy headers into the response.headers
18
- def pagy_headers_merge(pagy)
19
- response.headers.merge!(pagy_headers(pagy))
20
- end
21
-
22
- # Generate a hash of RFC-8288 compliant http headers
23
- def pagy_headers(pagy)
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))
31
-
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
- end
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(', ') }
51
- end
52
- end
53
- Backend.prepend HeadersExtra
54
- end
@@ -1,26 +0,0 @@
1
- # See the Pagy documentation: https://ddnexus.github.io/pagy/docs/extras/i18n
2
- # frozen_string_literal: true
3
-
4
- class Pagy # :nodoc:
5
- # Use ::I18n gem
6
- module I18nExtra
7
- # Frontend overriding for translation
8
- module FrontendOverride
9
- def pagy_t(key, **opts)
10
- ::I18n.t(key, **opts)
11
- end
12
- end
13
- Frontend.prepend I18nExtra::FrontendOverride
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
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')]
26
- end
@@ -1,70 +0,0 @@
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
@@ -1,88 +0,0 @@
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
@@ -1,30 +0,0 @@
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
@@ -1,63 +0,0 @@
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
@@ -1,57 +0,0 @@
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,42 +0,0 @@
1
- # See the Pagy documentation: https://ddnexus.github.io/pagy/docs/extras/metadata
2
- # frozen_string_literal: true
3
-
4
- require_relative '../url_helpers'
5
-
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 ]
9
-
10
- # Add a specialized backend method for pagination metadata
11
- module MetadataExtra
12
- private
13
-
14
- include UrlHelpers
15
-
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
38
- end
39
- end
40
- end
41
- Backend.prepend MetadataExtra
42
- end
@@ -1,81 +0,0 @@
1
- # See the Pagy documentation: https://ddnexus.github.io/pagy/docs/extras/overflow
2
- # frozen_string_literal: true
3
-
4
- class Pagy # :nodoc:
5
- DEFAULT[:overflow] = :empty_page
6
-
7
- # Handles OverflowError exceptions for different classes with different options
8
- module OverflowExtra
9
- # Support for Pagy class
10
- module PagyOverride
11
- # Is the requested page overflowing?
12
- def overflow?
13
- @overflow
14
- end
15
-
16
- # Add rescue clause for different behaviors
17
- def initialize(**vars)
18
- @overflow ||= false # still true if :last_page re-run the method after an overflow
19
- super
20
- rescue OverflowError
21
- @overflow = true # add the overflow flag
22
- case @vars[:overflow]
23
- when :exception
24
- raise # same as without the extra
25
- when :last_page
26
- requested_page = @vars[:page] # save the requested page (even after re-run)
27
- initialize(**vars, page: @last) # re-run with the last page
28
- @vars[:page] = requested_page # restore the requested page
29
- when :empty_page
30
- @in = @from = @to = 0 # vars relative to the actual page
31
- if defined?(::Pagy::Calendar::Unit) \
32
- && is_a?(Calendar::Unit) # only for Calendar::Units instances
33
- edge = @order == :asc ? @final : @initial # get the edge of the overflow side (neat, but any time would do)
34
- @from = @to = edge # set both to the edge time (a >=&&< query will get no records)
35
- end
36
- @prev = @last # prev relative to the actual page
37
- extend Series # special series for :empty_page
38
- else
39
- raise VariableError.new(self, :overflow, 'to be in [:last_page, :empty_page, :exception]', @vars[:overflow])
40
- end
41
- end
42
-
43
- # Special series for empty page
44
- module Series
45
- def series(*, **)
46
- @page = @last # series for last page
47
- super.tap do |s| # call original series
48
- s[s.index(@page.to_s)] = @page # string to integer (i.e. no current page)
49
- @page = @vars[:page] # restore the actual page
50
- end
51
- end
52
- end
53
- end
54
- Pagy.prepend PagyOverride
55
- Pagy::Calendar::Unit.prepend PagyOverride if defined?(::Pagy::Calendar::Unit)
56
-
57
- # Support for Pagy::Countless class
58
- module CountlessOverride
59
- # Add rescue clause for different behaviors
60
- def finalize(fetched_size)
61
- @overflow = false
62
- super
63
- rescue OverflowError
64
- @overflow = true # add the overflow flag
65
- case @vars[:overflow]
66
- when :exception
67
- raise # same as without the extra
68
- when :empty_page
69
- @offset = @limit = @from = @to = 0 # vars relative to the actual page
70
- @vars[:size] = 0 # no page in the series
71
- self
72
- else
73
- raise VariableError.new(self, :overflow, 'to be in [:empty_page, :exception]', @vars[:overflow])
74
- end
75
- end
76
- end
77
- # :nocov:
78
- Pagy::Countless.prepend CountlessOverride if defined?(::Pagy::Countless)
79
- # :nocov:
80
- end
81
- end