pagy 9.4.0 → 43.0.0.rc1

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 (168) hide show
  1. checksums.yaml +4 -4
  2. data/apps/calendar.ru +547 -551
  3. data/apps/demo.ru +221 -178
  4. data/apps/index.rb +3 -1
  5. data/apps/keynav.ru +258 -0
  6. data/apps/{keyset_ar.ru → keyset.ru} +26 -32
  7. data/apps/{keyset_s.ru → keyset_sequel.ru} +23 -29
  8. data/apps/rails.ru +51 -48
  9. data/apps/repro.ru +46 -43
  10. data/bin/pagy +20 -21
  11. data/config/pagy.rb +35 -207
  12. data/javascripts/ai_widget.js +76 -0
  13. data/javascripts/pagy.js +151 -0
  14. data/javascripts/pagy.js.map +10 -0
  15. data/javascripts/pagy.min.js +1 -4
  16. data/javascripts/pagy.mjs +111 -63
  17. data/javascripts/wand.js +1166 -0
  18. data/lib/pagy/classes/calendar/calendar.rb +98 -0
  19. data/lib/pagy/{calendar → classes/calendar}/day.rb +7 -11
  20. data/lib/pagy/{calendar → classes/calendar}/month.rb +5 -10
  21. data/lib/pagy/{calendar → classes/calendar}/quarter.rb +10 -15
  22. data/lib/pagy/classes/calendar/unit.rb +92 -0
  23. data/lib/pagy/{calendar → classes/calendar}/week.rb +5 -9
  24. data/lib/pagy/{calendar → classes/calendar}/year.rb +5 -6
  25. data/lib/pagy/classes/exceptions.rb +33 -0
  26. data/lib/pagy/classes/keyset/active_record.rb +11 -0
  27. data/lib/pagy/classes/keyset/adapters/active_record.rb +50 -0
  28. data/lib/pagy/classes/keyset/adapters/sequel.rb +63 -0
  29. data/lib/pagy/classes/keyset/keynav/active_record.rb +13 -0
  30. data/lib/pagy/classes/keyset/keynav/sequel.rb +13 -0
  31. data/lib/pagy/classes/keyset/keynav.rb +77 -0
  32. data/lib/pagy/classes/keyset/keyset.rb +126 -0
  33. data/lib/pagy/classes/keyset/sequel.rb +11 -0
  34. data/lib/pagy/classes/offset/countless.rb +56 -0
  35. data/lib/pagy/classes/offset/offset.rb +54 -0
  36. data/lib/pagy/classes/offset/search.rb +38 -0
  37. data/lib/pagy/classes/request.rb +36 -0
  38. data/lib/pagy/modules/abilities/configurable.rb +36 -0
  39. data/lib/pagy/modules/abilities/linkable.rb +59 -0
  40. data/lib/pagy/modules/abilities/rangeable.rb +15 -0
  41. data/lib/pagy/modules/abilities/shiftable.rb +12 -0
  42. data/lib/pagy/{b64.rb → modules/b64.rb} +3 -7
  43. data/lib/pagy/modules/console.rb +38 -0
  44. data/lib/pagy/modules/i18n/i18n.rb +48 -0
  45. data/lib/pagy/modules/i18n/p11n/arabic.rb +29 -0
  46. data/lib/pagy/modules/i18n/p11n/east_slavic.rb +26 -0
  47. data/lib/pagy/modules/i18n/p11n/one_other.rb +15 -0
  48. data/lib/pagy/modules/i18n/p11n/one_upto_two_other.rb +15 -0
  49. data/lib/pagy/modules/i18n/p11n/other.rb +13 -0
  50. data/lib/pagy/modules/i18n/p11n/polish.rb +26 -0
  51. data/lib/pagy/modules/i18n/p11n/west_slavic.rb +22 -0
  52. data/lib/pagy/modules/i18n/p11n.rb +16 -0
  53. data/lib/pagy/modules/searcher.rb +20 -0
  54. data/lib/pagy/toolbox/helpers/anchor_tags.rb +25 -0
  55. data/lib/pagy/toolbox/helpers/bootstrap/input_nav_js.rb +24 -0
  56. data/lib/pagy/toolbox/helpers/bootstrap/previous_next_html.rb +18 -0
  57. data/lib/pagy/toolbox/helpers/bootstrap/series_nav.rb +29 -0
  58. data/lib/pagy/toolbox/helpers/bootstrap/series_nav_js.rb +21 -0
  59. data/lib/pagy/toolbox/helpers/bulma/input_nav_js.rb +21 -0
  60. data/lib/pagy/toolbox/helpers/bulma/previous_next_html.rb +19 -0
  61. data/lib/pagy/toolbox/helpers/bulma/series_nav.rb +28 -0
  62. data/lib/pagy/toolbox/helpers/bulma/series_nav_js.rb +20 -0
  63. data/lib/pagy/toolbox/helpers/data_hash.rb +26 -0
  64. data/lib/pagy/toolbox/helpers/headers_hash.rb +20 -0
  65. data/lib/pagy/toolbox/helpers/info_tag.rb +26 -0
  66. data/lib/pagy/toolbox/helpers/input_nav_js.rb +19 -0
  67. data/lib/pagy/toolbox/helpers/limit_tag_js.rb +23 -0
  68. data/lib/pagy/toolbox/helpers/loader.rb +33 -0
  69. data/lib/pagy/toolbox/helpers/page_url.rb +23 -0
  70. data/lib/pagy/toolbox/helpers/series_nav.rb +29 -0
  71. data/lib/pagy/toolbox/helpers/series_nav_js.rb +19 -0
  72. data/lib/pagy/toolbox/helpers/support/a_lambda.rb +34 -0
  73. data/lib/pagy/toolbox/helpers/support/data_pagy_attribute.rb +15 -0
  74. data/lib/pagy/toolbox/helpers/support/nav_aria_label_attribute.rb +12 -0
  75. data/lib/pagy/toolbox/helpers/support/series.rb +38 -0
  76. data/lib/pagy/toolbox/helpers/support/wrap_input_nav_js.rb +20 -0
  77. data/lib/pagy/toolbox/helpers/support/wrap_series_nav.rb +17 -0
  78. data/lib/pagy/toolbox/helpers/support/wrap_series_nav_js.rb +36 -0
  79. data/lib/pagy/toolbox/helpers/urls_hash.rb +13 -0
  80. data/lib/pagy/toolbox/paginators/calendar.rb +30 -0
  81. data/lib/pagy/toolbox/paginators/countless.rb +25 -0
  82. data/lib/pagy/toolbox/paginators/elasticsearch_rails.rb +32 -0
  83. data/lib/pagy/toolbox/paginators/keynav_js.rb +29 -0
  84. data/lib/pagy/toolbox/paginators/keyset.rb +18 -0
  85. data/lib/pagy/toolbox/paginators/meilisearch.rb +32 -0
  86. data/lib/pagy/toolbox/paginators/method.rb +26 -0
  87. data/lib/pagy/toolbox/paginators/offset.rb +33 -0
  88. data/lib/pagy/toolbox/paginators/searchkick.rb +32 -0
  89. data/lib/pagy.rb +59 -97
  90. data/locales/ar.yml +9 -6
  91. data/locales/be.yml +9 -6
  92. data/locales/bg.yml +9 -6
  93. data/locales/bs.yml +9 -6
  94. data/locales/ca.yml +9 -6
  95. data/locales/ckb.yml +8 -6
  96. data/locales/cs.yml +9 -6
  97. data/locales/da.yml +9 -6
  98. data/locales/de.yml +9 -6
  99. data/locales/dz.yml +9 -6
  100. data/locales/en.yml +9 -6
  101. data/locales/es.yml +9 -6
  102. data/locales/fr.yml +9 -6
  103. data/locales/hr.yml +9 -6
  104. data/locales/id.yml +9 -6
  105. data/locales/it.yml +9 -6
  106. data/locales/ja.yml +9 -6
  107. data/locales/km.yml +9 -6
  108. data/locales/ko.yml +9 -6
  109. data/locales/nb.yml +9 -6
  110. data/locales/nl.yml +9 -6
  111. data/locales/nn.yml +9 -6
  112. data/locales/pl.yml +9 -6
  113. data/locales/pt-BR.yml +10 -7
  114. data/locales/pt.yml +10 -7
  115. data/locales/ru.yml +9 -6
  116. data/locales/sr.yml +9 -6
  117. data/locales/sv-SE.yml +9 -6
  118. data/locales/sv.yml +9 -6
  119. data/locales/sw.yml +12 -9
  120. data/locales/ta.yml +15 -8
  121. data/locales/tr.yml +9 -6
  122. data/locales/uk.yml +9 -6
  123. data/locales/vi.yml +9 -6
  124. data/locales/zh-CN.yml +9 -6
  125. data/locales/zh-HK.yml +9 -6
  126. data/locales/zh-TW.yml +9 -6
  127. data/stylesheets/pagy-tailwind.css +64 -0
  128. data/stylesheets/pagy.css +63 -27
  129. metadata +112 -52
  130. data/javascripts/pagy.min.js.map +0 -10
  131. data/lib/pagy/backend.rb +0 -44
  132. data/lib/pagy/calendar/unit.rb +0 -103
  133. data/lib/pagy/calendar.rb +0 -84
  134. data/lib/pagy/console.rb +0 -23
  135. data/lib/pagy/countless.rb +0 -38
  136. data/lib/pagy/exceptions.rb +0 -25
  137. data/lib/pagy/extras/arel.rb +0 -28
  138. data/lib/pagy/extras/array.rb +0 -19
  139. data/lib/pagy/extras/bootstrap.rb +0 -97
  140. data/lib/pagy/extras/bulma.rb +0 -93
  141. data/lib/pagy/extras/calendar.rb +0 -79
  142. data/lib/pagy/extras/countless.rb +0 -32
  143. data/lib/pagy/extras/elasticsearch_rails.rb +0 -71
  144. data/lib/pagy/extras/gearbox.rb +0 -55
  145. data/lib/pagy/extras/headers.rb +0 -54
  146. data/lib/pagy/extras/i18n.rb +0 -26
  147. data/lib/pagy/extras/js_tools.rb +0 -70
  148. data/lib/pagy/extras/jsonapi.rb +0 -88
  149. data/lib/pagy/extras/keyset.rb +0 -30
  150. data/lib/pagy/extras/limit.rb +0 -63
  151. data/lib/pagy/extras/meilisearch.rb +0 -57
  152. data/lib/pagy/extras/metadata.rb +0 -42
  153. data/lib/pagy/extras/overflow.rb +0 -81
  154. data/lib/pagy/extras/pagy.rb +0 -82
  155. data/lib/pagy/extras/searchkick.rb +0 -59
  156. data/lib/pagy/extras/size.rb +0 -40
  157. data/lib/pagy/extras/standalone.rb +0 -60
  158. data/lib/pagy/extras/trim.rb +0 -29
  159. data/lib/pagy/frontend.rb +0 -99
  160. data/lib/pagy/i18n.rb +0 -167
  161. data/lib/pagy/keyset/active_record.rb +0 -44
  162. data/lib/pagy/keyset/sequel.rb +0 -57
  163. data/lib/pagy/keyset.rb +0 -118
  164. data/lib/pagy/shared_methods.rb +0 -26
  165. data/lib/pagy/url_helpers.rb +0 -26
  166. data/locales/sk.yml +0 -23
  167. data/stylesheets/pagy.scss +0 -48
  168. data/stylesheets/pagy.tailwind.css +0 -21
@@ -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
@@ -1,82 +0,0 @@
1
- # See the Pagy documentation: https://ddnexus.github.io/pagy/docs/extras/pagy
2
- # frozen_string_literal: true
3
-
4
- require_relative 'js_tools'
5
-
6
- class Pagy # :nodoc:
7
- # Frontend modules are specially optimized for performance.
8
- # The resulting code may not look very elegant, but produces the best benchmarks
9
- module PagyExtra
10
- # pagy_nav is defined in the Frontend itself
11
- # Javascript pagination: it returns a nav with a data-pagy attribute used by the pagy.js file
12
- def pagy_nav_js(pagy, id: nil, aria_label: nil, **vars)
13
- sequels = pagy.sequels(**vars)
14
- id = %( id="#{id}") if id
15
- a = pagy_anchor(pagy, **vars)
16
- tokens = { 'before' => prev_a(pagy, a),
17
- 'a' => a.(PAGE_TOKEN, LABEL_TOKEN),
18
- 'current' => %(<a class="current" role="link" aria-current="page" aria-disabled="true">#{
19
- LABEL_TOKEN}</a>),
20
- 'gap' => %(<a class="gap" role="link" aria-disabled="true">#{pagy_t('pagy.gap')}</a>),
21
- 'after' => next_a(pagy, a) }
22
-
23
- %(<nav#{id} class="#{'pagy-rjs ' if sequels.size > 1}pagy nav-js" #{
24
- nav_aria_label(pagy, aria_label:)} #{
25
- pagy_data(pagy, :nav, tokens, sequels, pagy.label_sequels(sequels))
26
- }></nav>)
27
- end
28
-
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, **vars)
31
- id = %( id="#{id}") if id
32
- a = pagy_anchor(pagy, **vars)
33
- pages = pagy.pages
34
-
35
- page_input = %(<input name="page" type="number" min="1" max="#{pages}" value="#{pagy.page}" aria-current="page" ) <<
36
- %(style="text-align: center; width: #{pages.to_s.length + 1}rem; padding: 0;">#{JSTools::A_TAG})
37
-
38
- %(<nav#{id} class="pagy combo-nav-js" #{
39
- nav_aria_label(pagy, aria_label:)} #{
40
- pagy_data(pagy, :combo, pagy_url_for(pagy, PAGE_TOKEN, **vars))}>#{
41
- prev_a(pagy, a)
42
- }<label>#{
43
- pagy_t('pagy.combo_nav_js', page_input:, pages:)
44
- }</label>#{
45
- next_a(pagy, a)
46
- }</nav>)
47
- end
48
-
49
- # Return the previous page URL string or nil
50
- def pagy_prev_url(pagy, **vars)
51
- pagy_url_for(pagy, pagy.prev, **vars) if pagy.prev
52
- end
53
-
54
- # Return the next page URL string or nil
55
- def pagy_next_url(pagy, **vars)
56
- pagy_url_for(pagy, pagy.next, **vars) if pagy.next
57
- end
58
-
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'), **vars)
61
- a = pagy_anchor(pagy, **vars)
62
- prev_a(pagy, a, text:, aria_label:)
63
- end
64
-
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'), **vars)
67
- a = pagy_anchor(pagy, **vars)
68
- next_a(pagy, a, text:, aria_label:)
69
- end
70
-
71
- # Conditionally return the previous page link tag
72
- def pagy_prev_link(pagy, **vars)
73
- %(<link href="#{pagy_url_for(pagy, pagy.prev, **vars)}"/>) if pagy.prev
74
- end
75
-
76
- # Conditionally return the next page link tag
77
- def pagy_next_link(pagy, **vars)
78
- %(<link href="#{pagy_url_for(pagy, pagy.next, **vars)}"/>) if pagy.next
79
- end
80
- end
81
- Frontend.prepend PagyExtra
82
- end
@@ -1,59 +0,0 @@
1
- # See the Pagy documentation: https://ddnexus.github.io/pagy/docs/extras/searchkick
2
- # frozen_string_literal: true
3
-
4
- class Pagy # :nodoc:
5
- DEFAULT[:searchkick_search] ||= :search
6
- DEFAULT[:searchkick_pagy_search] ||= :pagy_search
7
-
8
- # Paginate Searchkick::Results objects
9
- module SearchkickExtra
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
- # It also pushes to the same array an optional method call.
14
- def pagy_searchkick(term = '*', **options, &block)
15
- [self, term, options, block].tap do |args|
16
- args.define_singleton_method(:method_missing) { |*a| args += a }
17
- end
18
- end
19
- alias_method Pagy::DEFAULT[:searchkick_pagy_search], :pagy_searchkick
20
- end
21
- Pagy::Searchkick = ModelExtension
22
-
23
- # Additions for the Pagy class
24
- module PagyExtension
25
- # Create a Pagy object from a Searchkick::Results object
26
- def new_from_searchkick(results, **vars)
27
- vars[:limit] = results.options[:per_page]
28
- vars[:page] = results.options[:page]
29
- vars[:count] = results.total_count
30
- new(**vars)
31
- end
32
- end
33
- Pagy.extend PagyExtension
34
-
35
- # Add specialized backend methods to paginate Searchkick::Results
36
- module BackendAddOn
37
- private
38
-
39
- # Return Pagy object and results
40
- def pagy_searchkick(pagy_search_args, **vars)
41
- vars[:page] ||= pagy_get_page(vars)
42
- vars[:limit] ||= pagy_get_limit(vars)
43
- model, term, options, block, *called = pagy_search_args
44
- options[:per_page] = vars[:limit]
45
- options[:page] = vars[:page]
46
- results = model.send(DEFAULT[:searchkick_search], term, **options, &block)
47
- vars[:count] = results.total_count
48
-
49
- pagy = ::Pagy.new(**vars)
50
- # with :last_page overflow we need to re-run the method in order to get the hits
51
- return pagy_searchkick(pagy_search_args, **vars, page: pagy.page) \
52
- if defined?(::Pagy::OverflowExtra) && pagy.overflow? && pagy.vars[:overflow] == :last_page
53
-
54
- [pagy, called.empty? ? results : results.send(*called)]
55
- end
56
- end
57
- Backend.prepend BackendAddOn
58
- end
59
- end
@@ -1,40 +0,0 @@
1
- # See the Pagy documentation: https://ddnexus.github.io/pagy/docs/extras/size
2
- # frozen_string_literal: true
3
-
4
- class Pagy # :nodoc:
5
- # Implement the legacy bar using the array size.
6
- # Unless you have very specific requirements, use the faster and better looking default bar.
7
- module SizeExtra
8
- # Implements the old series algorithm
9
- def series(size: @vars[:size], **_)
10
- return super unless size.is_a?(Array)
11
- return [] if size == []
12
- raise VariableError.new(self, :size, 'to be an Array of 4 Integers or []', size) \
13
- unless size.is_a?(Array) && size.size == 4 && size.all? { |num| !num.negative? rescue false } # rubocop:disable Style/RescueModifier
14
-
15
- [].tap do |series|
16
- # This algorithm is up to ~5x faster and ~2.3x lighter than the previous one (pagy < 4.3)
17
- # However the behavior of the legacy nav bar was taken straight from WillPaginate and Kaminari:
18
- # it's ill-concieved and complicates the experience of devs and users.
19
- left_gap_start = 1 + size[0]
20
- left_gap_end = @page - size[1] - 1
21
- right_gap_start = @page + size[2] + 1
22
- right_gap_end = @last - size[3]
23
- left_gap_end = right_gap_end if left_gap_end > right_gap_end
24
- right_gap_start = left_gap_start if left_gap_start > right_gap_start
25
- start = 1
26
- if (left_gap_end - left_gap_start).positive?
27
- series.push(*start...left_gap_start, :gap)
28
- start = left_gap_end + 1
29
- end
30
- if (right_gap_end - right_gap_start).positive?
31
- series.push(*start...right_gap_start, :gap)
32
- start = right_gap_end + 1
33
- end
34
- series.push(*start..@last)
35
- series[series.index(@page)] = @page.to_s
36
- end
37
- end
38
- end
39
- prepend SizeExtra
40
- end
@@ -1,60 +0,0 @@
1
- # See the Pagy documentation: https://ddnexus.github.io/pagy/docs/extras/standalone
2
- # frozen_string_literal: true
3
-
4
- require 'uri'
5
-
6
- class Pagy # :nodoc:
7
- # Use pagy without any request object, nor Rack environment/gem, nor any defined params method,
8
- # even in the irb/rails console without any app or config.
9
- module StandaloneExtra
10
- # Extracted from Rack::Utils and reformatted for rubocop
11
- # :nocov:
12
- module QueryUtils
13
- module_function
14
-
15
- def build_nested_query(value, prefix = nil)
16
- case value
17
- when Array
18
- value.map { |v| build_nested_query(v, "#{prefix}[]") }.join('&')
19
- when Hash
20
- value.map do |k, v|
21
- build_nested_query(v, prefix ? "#{prefix}[#{escape(k)}]" : escape(k))
22
- end.delete_if(&:empty?).join('&')
23
- when nil
24
- escape(prefix)
25
- else
26
- raise ArgumentError, 'value must be a Hash' if prefix.nil?
27
-
28
- "#{escape(prefix)}=#{escape(value)}"
29
- end
30
- end
31
-
32
- def escape(str)
33
- URI.encode_www_form_component(str)
34
- end
35
- end
36
- # :nocov:
37
-
38
- # Return the URL for the page. If there is no pagy.vars[:url]
39
- # it works exactly as the regular #pagy_url_for, relying on the params method and Rack.
40
- # If there is a defined pagy.vars[:url] variable it does not need the params method nor Rack.
41
- def pagy_url_for(pagy, page, fragment: nil, **_)
42
- return super unless pagy.vars[:url]
43
-
44
- vars = pagy.vars
45
- params = vars[:params].is_a?(Hash) ? vars[:params].clone : {} # safe when it gets reused
46
- pagy_set_query_params(page, vars, params)
47
- params = vars[:params].(params) if vars[:params].is_a?(Proc)
48
- query_string = "?#{QueryUtils.build_nested_query(params)}"
49
- "#{vars[:url]}#{query_string}#{fragment}"
50
- end
51
- end
52
- UrlHelpers.prepend StandaloneExtra
53
-
54
- # Define a dummy params method if it's not already defined in the including module
55
- module Backend
56
- def self.included(controller)
57
- controller.define_method(:params) { {} } unless controller.method_defined?(:params)
58
- end
59
- end
60
- end
@@ -1,29 +0,0 @@
1
- # See the Pagy documentation: https://ddnexus.github.io/pagy/docs/extras/trim
2
- # frozen_string_literal: true
3
-
4
- class Pagy # :nodoc:
5
- DEFAULT[:trim_extra] = true # extra enabled by default
6
-
7
- # Remove the page=1 param from the first page link
8
- module TrimExtra
9
- # Override the original pagy_anchor.
10
- # Call the pagy_trim method for page 1 if the trim_extra is enabled
11
- def pagy_anchor(pagy, **_)
12
- a_proc = super
13
- return a_proc unless pagy.vars[:trim_extra]
14
-
15
- lambda do |page, text = pagy.label_for(page), **opts|
16
- a = +a_proc.(page, text, **opts)
17
- return a unless page.to_s == '1'
18
-
19
- pagy_trim(pagy, a) # in method for isolated testing
20
- end
21
- end
22
-
23
- # Remove the :page_param param from the first page anchor
24
- def pagy_trim(pagy, a)
25
- a.sub!(/[?&]#{pagy.vars[:page_param]}=1\b(?!&)|\b#{pagy.vars[:page_param]}=1&/, '')
26
- end
27
- end
28
- Frontend.prepend TrimExtra
29
- end
data/lib/pagy/frontend.rb DELETED
@@ -1,99 +0,0 @@
1
- # See Pagy::Frontend API documentation: https://ddnexus.github.io/pagy/docs/api/frontend
2
- # frozen_string_literal: true
3
-
4
- require_relative 'i18n'
5
- require_relative 'url_helpers'
6
-
7
- class Pagy
8
- # Used for search and replace, hardcoded also in the pagy.js file
9
- PAGE_TOKEN = '__pagy_page__'
10
- LABEL_TOKEN = '__pagy_label__'
11
-
12
- # Frontend modules are specially optimized for performance.
13
- # The resulting code may not look very elegant, but produces the best benchmarks
14
- module Frontend
15
- include UrlHelpers
16
-
17
- # Return a performance optimized lambda to generate the HTML anchor element (a tag)
18
- # Benchmarked on a 20 link nav: it is ~22x faster and uses ~18x less memory than rails' link_to
19
- def pagy_anchor(pagy, anchor_string: nil, **vars)
20
- anchor_string &&= %( #{anchor_string})
21
- left, right = %(<a#{anchor_string} href="#{pagy_url_for(pagy, PAGE_TOKEN, **vars)}").split(PAGE_TOKEN, 2)
22
- # lambda used by all the helpers
23
- lambda do |page, text = pagy.label_for(page), classes: nil, aria_label: nil|
24
- classes = %( class="#{classes}") if classes
25
- aria_label = %( aria-label="#{aria_label}") if aria_label
26
- %(#{left}#{page}#{right}#{classes}#{aria_label}>#{text}</a>)
27
- end
28
- end
29
-
30
- # Return examples: "Displaying items 41-60 of 324 in total" or "Displaying Products 41-60 of 324 in total"
31
- def pagy_info(pagy, id: nil, item_name: nil)
32
- id = %( id="#{id}") if id
33
- p_count = pagy.count
34
- key = if p_count.zero?
35
- 'pagy.info.no_items'
36
- elsif pagy.pages == 1
37
- 'pagy.info.single_page'
38
- else
39
- 'pagy.info.multiple_pages'
40
- end
41
-
42
- %(<span#{id} class="pagy info">#{
43
- pagy_t key, item_name: item_name || pagy_t('pagy.item_name', count: p_count),
44
- count: p_count, from: pagy.from, to: pagy.to
45
- }</span>)
46
- end
47
-
48
- # Generic pagination: it returns the html with the series of links to the pages
49
- def pagy_nav(pagy, id: nil, aria_label: nil, **vars)
50
- id = %( id="#{id}") if id
51
- a = pagy_anchor(pagy, **vars)
52
-
53
- html = %(<nav#{id} class="pagy nav" #{nav_aria_label(pagy, aria_label:)}>#{
54
- prev_a(pagy, a)})
55
- pagy.series(**vars).each do |item| # series example: [1, :gap, 7, 8, "9", 10, 11, :gap, 36]
56
- html << case item
57
- when Integer
58
- a.(item)
59
- when String
60
- %(<a role="link" aria-disabled="true" aria-current="page" class="current">#{pagy.label_for(item)}</a>)
61
- when :gap
62
- %(<a role="link" aria-disabled="true" class="gap">#{pagy_t('pagy.gap')}</a>)
63
- else
64
- raise InternalError, "expected item types in series to be Integer, String or :gap; got #{item.inspect}"
65
- end
66
- end
67
- html << %(#{next_a(pagy, a)}</nav>)
68
- end
69
-
70
- # Similar to I18n.t: just ~18x faster using ~10x less memory
71
- # (@pagy_locale explicitly initialized in order to avoid warning)
72
- def pagy_t(key, **opts)
73
- Pagy::I18n.translate(@pagy_locale ||= nil, key, **opts)
74
- end
75
-
76
- private
77
-
78
- def nav_aria_label(pagy, aria_label: nil)
79
- aria_label ||= pagy_t('pagy.aria_label.nav', count: pagy.pages)
80
- %(aria-label="#{aria_label}")
81
- end
82
-
83
- def prev_a(pagy, a, text: pagy_t('pagy.prev'), aria_label: pagy_t('pagy.aria_label.prev'))
84
- if (p_prev = pagy.prev)
85
- a.(p_prev, text, aria_label:)
86
- else
87
- %(<a role="link" aria-disabled="true" aria-label="#{aria_label}">#{text}</a>)
88
- end
89
- end
90
-
91
- def next_a(pagy, a, text: pagy_t('pagy.next'), aria_label: pagy_t('pagy.aria_label.next'))
92
- if (p_next = pagy.next)
93
- a.(p_next, text, aria_label:)
94
- else
95
- %(<a role="link" aria-disabled="true" aria-label="#{aria_label}">#{text}</a>)
96
- end
97
- end
98
- end
99
- end