pagy 9.3.5 → 43.0.0.rc2

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} +27 -32
  7. data/apps/{keyset_s.ru → keyset_sequel.ru} +24 -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/sk.yml +26 -0
  117. data/locales/sr.yml +9 -6
  118. data/locales/sv-SE.yml +9 -6
  119. data/locales/sv.yml +9 -6
  120. data/locales/sw.yml +12 -9
  121. data/locales/ta.yml +12 -13
  122. data/locales/tr.yml +9 -6
  123. data/locales/uk.yml +9 -6
  124. data/locales/vi.yml +9 -6
  125. data/locales/zh-CN.yml +9 -6
  126. data/locales/zh-HK.yml +9 -6
  127. data/locales/zh-TW.yml +9 -6
  128. data/stylesheets/pagy-tailwind.css +64 -0
  129. data/stylesheets/pagy.css +63 -27
  130. metadata +113 -51
  131. data/javascripts/pagy.min.js.map +0 -10
  132. data/lib/pagy/backend.rb +0 -44
  133. data/lib/pagy/calendar/unit.rb +0 -103
  134. data/lib/pagy/calendar.rb +0 -84
  135. data/lib/pagy/console.rb +0 -23
  136. data/lib/pagy/countless.rb +0 -38
  137. data/lib/pagy/exceptions.rb +0 -25
  138. data/lib/pagy/extras/arel.rb +0 -28
  139. data/lib/pagy/extras/array.rb +0 -19
  140. data/lib/pagy/extras/bootstrap.rb +0 -97
  141. data/lib/pagy/extras/bulma.rb +0 -93
  142. data/lib/pagy/extras/calendar.rb +0 -79
  143. data/lib/pagy/extras/countless.rb +0 -32
  144. data/lib/pagy/extras/elasticsearch_rails.rb +0 -71
  145. data/lib/pagy/extras/gearbox.rb +0 -55
  146. data/lib/pagy/extras/headers.rb +0 -54
  147. data/lib/pagy/extras/i18n.rb +0 -26
  148. data/lib/pagy/extras/js_tools.rb +0 -70
  149. data/lib/pagy/extras/jsonapi.rb +0 -88
  150. data/lib/pagy/extras/keyset.rb +0 -30
  151. data/lib/pagy/extras/limit.rb +0 -63
  152. data/lib/pagy/extras/meilisearch.rb +0 -57
  153. data/lib/pagy/extras/metadata.rb +0 -42
  154. data/lib/pagy/extras/overflow.rb +0 -81
  155. data/lib/pagy/extras/pagy.rb +0 -82
  156. data/lib/pagy/extras/searchkick.rb +0 -59
  157. data/lib/pagy/extras/size.rb +0 -40
  158. data/lib/pagy/extras/standalone.rb +0 -60
  159. data/lib/pagy/extras/trim.rb +0 -29
  160. data/lib/pagy/frontend.rb +0 -99
  161. data/lib/pagy/i18n.rb +0 -166
  162. data/lib/pagy/keyset/active_record.rb +0 -44
  163. data/lib/pagy/keyset/sequel.rb +0 -57
  164. data/lib/pagy/keyset.rb +0 -118
  165. data/lib/pagy/shared_methods.rb +0 -26
  166. data/lib/pagy/url_helpers.rb +0 -26
  167. data/stylesheets/pagy.scss +0 -48
  168. data/stylesheets/pagy.tailwind.css +0 -21
@@ -1,97 +0,0 @@
1
- # See the Pagy documentation: https://ddnexus.github.io/pagy/docs/extras/bootstrap
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 BootstrapExtra
10
- # Pagination for bootstrap: it returns the html with the series of links to the pages
11
- def pagy_bootstrap_nav(pagy, id: nil, classes: 'pagination', aria_label: nil, **vars)
12
- id = %( id="#{id}") if id
13
- a = pagy_anchor(pagy, **vars)
14
-
15
- html = %(<nav#{id} class="pagy-bootstrap nav" #{nav_aria_label(pagy, aria_label:)}><ul class="#{classes}">#{
16
- bootstrap_prev_html(pagy, a)})
17
- pagy.series(**vars).each do |item| # series example: [1, :gap, 7, 8, "9", 10, 11, :gap, 36]
18
- html << case item
19
- when Integer
20
- %(<li class="page-item">#{a.(item, classes: 'page-link')}</li>)
21
- when String
22
- %(<li class="page-item active"><a role="link" class="page-link" aria-current="page" aria-disabled="true">#{
23
- pagy.label_for(item)}</a></li>)
24
- when :gap
25
- %(<li class="page-item gap disabled"><a role="link" class="page-link" aria-disabled="true">#{
26
- pagy_t('pagy.gap')}</a></li>)
27
- else raise InternalError, "expected item types in series to be Integer, String or :gap; got #{item.inspect}"
28
- end
29
- end
30
- html << %(#{bootstrap_next_html(pagy, a)}</ul></nav>)
31
- end
32
-
33
- # Javascript pagination for bootstrap: it returns a nav with a data-pagy attribute used by the pagy.js file
34
- def pagy_bootstrap_nav_js(pagy, id: nil, classes: 'pagination', aria_label: nil, **vars)
35
- sequels = pagy.sequels(**vars)
36
- id = %( id="#{id}") if id
37
- a = pagy_anchor(pagy, **vars)
38
- tokens = { 'before' => %(<ul class="#{classes}">#{bootstrap_prev_html(pagy, a)}),
39
- 'a' => %(<li class="page-item">#{a.(PAGE_TOKEN, LABEL_TOKEN, classes: 'page-link')}</li>),
40
- 'current' => %(<li class="page-item active"><a role="link" class="page-link" ) +
41
- %(aria-current="page" aria-disabled="true">#{LABEL_TOKEN}</a></li>),
42
- 'gap' => %(<li class="page-item gap disabled"><a role="link" class="page-link" aria-disabled="true">#{
43
- pagy_t('pagy.gap')}</a></li>),
44
- 'after' => %(#{bootstrap_next_html pagy, a}</ul>) }
45
-
46
- %(<nav#{id} class="#{'pagy-rjs ' if sequels.size > 1}pagy-bootstrap nav-js" #{
47
- nav_aria_label(pagy, aria_label:)} #{
48
- pagy_data(pagy, :nav, tokens, sequels, pagy.label_sequels(sequels))
49
- }></nav>)
50
- end
51
-
52
- # Javascript combo pagination for bootstrap: it returns a nav with a data-pagy attribute used by the pagy.js file
53
- def pagy_bootstrap_combo_nav_js(pagy, id: nil, classes: 'pagination', aria_label: nil, **vars)
54
- id = %( id="#{id}") if id
55
- a = pagy_anchor(pagy, **vars)
56
- pages = pagy.pages
57
-
58
- page_input = %(<input name="page" type="number" min="1" max="#{pages}" value="#{pagy.page}" aria-current="page" ) <<
59
- %(style="text-align: center; width: #{pages.to_s.length + 1}rem; padding: 0; ) <<
60
- %(border: none; display: inline-block;" class="page-link active">#{JSTools::A_TAG})
61
-
62
- %(<nav#{id} class="pagy-bootstrap combo-nav-js" #{
63
- nav_aria_label(pagy, aria_label:)} #{
64
- pagy_data(pagy, :combo, pagy_url_for(pagy, PAGE_TOKEN, **vars))
65
- }><ul class="#{classes}">#{
66
- bootstrap_prev_html(pagy, a)
67
- }<li class="page-item pagy-bootstrap"><label class="page-link">#{
68
- pagy_t('pagy.combo_nav_js', page_input:, pages:)
69
- }</label></li>#{
70
- bootstrap_next_html(pagy, a)
71
- }</ul></nav>)
72
- end
73
-
74
- private
75
-
76
- def bootstrap_prev_html(pagy, a)
77
- if (p_prev = pagy.prev)
78
- %(<li class="page-item prev">#{
79
- a.(p_prev, pagy_t('pagy.prev'), classes: 'page-link', aria_label: pagy_t('pagy.aria_label.prev'))}</li>)
80
- else
81
- %(<li class="page-item prev disabled"><a role="link" class="page-link" aria-disabled="true" aria-label="#{
82
- pagy_t('pagy.aria_label.prev')}">#{pagy_t('pagy.prev')}</a></li>)
83
- end
84
- end
85
-
86
- def bootstrap_next_html(pagy, a)
87
- if (p_next = pagy.next)
88
- %(<li class="page-item next">#{
89
- a.(p_next, pagy_t('pagy.next'), classes: 'page-link', aria_label: pagy_t('pagy.aria_label.next'))}</li>)
90
- else
91
- %(<li class="page-item next disabled"><a role="link" class="page-link" aria-disabled="true" aria-label="#{
92
- pagy_t('pagy.aria_label.next')}">#{pagy_t('pagy.next')}</a></li>)
93
- end
94
- end
95
- end
96
- Frontend.prepend BootstrapExtra
97
- end
@@ -1,93 +0,0 @@
1
- # See the Pagy documentation: https://ddnexus.github.io/pagy/docs/extras/bulma
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 BulmaExtra
10
- # Pagination for bulma: it returns the html with the series of links to the pages
11
- def pagy_bulma_nav(pagy, id: nil, classes: 'pagy-bulma nav pagination is-centered',
12
- aria_label: nil, **vars)
13
- id = %( id="#{id}") if id
14
- a = pagy_anchor(pagy, **vars)
15
-
16
- html = %(<nav#{id} class="#{classes}" #{nav_aria_label(pagy, aria_label:)}>)
17
- html << bulma_prev_next_html(pagy, a)
18
- html << %(<ul class="pagination-list">)
19
- pagy.series(**vars).each do |item| # series example: [1, :gap, 7, 8, "9", 10, 11, :gap, 36]
20
- html << case item
21
- when Integer
22
- %(<li>#{a.(item, pagy.label_for(item), classes: 'pagination-link')}</li>)
23
- when String
24
- %(<li><a role="link" class="pagination-link is-current" aria-current="page" aria-disabled="true">#{
25
- pagy.label_for(item)}</a></li>)
26
- when :gap
27
- %(<li><span class="pagination-ellipsis">#{pagy_t 'pagy.gap'}</span></li>)
28
- else raise InternalError, "expected item types in series to be Integer, String or :gap; got #{item.inspect}"
29
- end
30
- end
31
- html << %(</ul></nav>)
32
- end
33
-
34
- # Javascript pagination for bulma: it returns a nav with a data-pagy attribute used by the Pagy.nav javascript
35
- def pagy_bulma_nav_js(pagy, id: nil, classes: 'pagy-bulma nav-js pagination is-centered',
36
- aria_label: nil, **vars)
37
- sequels = pagy.sequels(**vars)
38
- id = %( id="#{id}") if id
39
- a = pagy_anchor(pagy, **vars)
40
- tokens = { 'before' => %(#{bulma_prev_next_html(pagy, a)}<ul class="pagination-list">),
41
- 'a' => %(<li>#{a.(PAGE_TOKEN, LABEL_TOKEN, classes: 'pagination-link')}</li>),
42
- 'current' => %(<li><a role="link" class="pagination-link is-current" aria-current="page" aria-disabled="true">#{
43
- LABEL_TOKEN}</a></li>),
44
- 'gap' => %(<li><span class="pagination-ellipsis">#{pagy_t 'pagy.gap'}</span></li>),
45
- 'after' => '</ul>' }
46
-
47
- %(<nav#{id} class="#{'pagy-rjs ' if sequels.size > 1}#{classes}" #{
48
- nav_aria_label(pagy, aria_label:)} #{
49
- pagy_data(pagy, :nav, tokens, sequels, pagy.label_sequels(sequels))
50
- }></nav>)
51
- end
52
-
53
- # Javascript combo pagination for bulma: it returns a nav with a data-pagy attribute used by the pagy.js file
54
- def pagy_bulma_combo_nav_js(pagy, id: nil, classes: 'pagy-bulma combo-nav-js pagination is-centered',
55
- aria_label: nil, **vars)
56
- id = %( id="#{id}") if id
57
- a = pagy_anchor(pagy, **vars)
58
- pages = pagy.pages
59
-
60
- page_input = %(<input name="page" type="number" min="1" max="#{pages}" value="#{pagy.page}" aria-current="page") <<
61
- %(style="text-align: center; width: #{pages.to_s.length + 1}rem; height: 1.7rem; margin:0 0.3rem; ) <<
62
- %(border: none; border-radius: 4px; padding: 0; font-size: 1.1rem; color: white; ) <<
63
- %(background-color: #485fc7;">#{JSTools::A_TAG})
64
-
65
- %(<nav#{id} class="#{classes}" #{
66
- nav_aria_label(pagy, aria_label:)} #{
67
- pagy_data(pagy, :combo, pagy_url_for(pagy, PAGE_TOKEN, **vars))
68
- }>#{
69
- bulma_prev_next_html(pagy, a)
70
- }<ul class="pagination-list"><li class="pagination-link"><label>#{
71
- pagy_t('pagy.combo_nav_js', page_input:, pages:)
72
- }</label></li></ul></nav>)
73
- end
74
-
75
- private
76
-
77
- def bulma_prev_next_html(pagy, a)
78
- html = if (p_prev = pagy.prev)
79
- a.(p_prev, pagy_t('pagy.prev'), classes: 'pagination-previous', aria_label: pagy_t('pagy.aria_label.prev'))
80
- else
81
- %(<a role="link" class="pagination-previous" disabled aria-disabled="true" aria-label="#{
82
- pagy_t('pagy.aria_label.prev')}">#{pagy_t 'pagy.prev'}</a>)
83
- end
84
- html << if (p_next = pagy.next)
85
- a.(p_next, pagy_t('pagy.next'), classes: 'pagination-next', aria_label: pagy_t('pagy.aria_label.next'))
86
- else
87
- %(<a role="link" class="pagination-next" disabled aria-disabled="true" aria-label="#{
88
- pagy_t('pagy.aria_label.next')}">#{pagy_t('pagy.next')}</a>)
89
- end
90
- end
91
- end
92
- Frontend.prepend BulmaExtra
93
- end
@@ -1,79 +0,0 @@
1
- # See the Pagy documentation: https://ddnexus.github.io/pagy/docs/extras/calendar
2
- # frozen_string_literal: true
3
-
4
- require_relative '../calendar'
5
-
6
- class Pagy # :nodoc:
7
- # Add pagination filtering by calendar unit (:year, :quarter, :month, :week, :day) to the regular pagination
8
- module CalendarExtra
9
- # Additions for the Backend module
10
- module BackendAddOn
11
- CONF_KEYS = (Calendar::UNITS + %i[pagy active]).freeze
12
-
13
- private
14
-
15
- # Take a collection and a conf Hash with keys in CONF_KEYS and return an array with 3 items: [calendar, pagy, results]
16
- def pagy_calendar(collection, conf)
17
- raise ArgumentError, "keys must be in #{CONF_KEYS.inspect}" \
18
- unless conf.is_a?(Hash) && (conf.keys - CONF_KEYS).empty?
19
-
20
- conf[:pagy] ||= {}
21
- unless conf.key?(:active) && !conf[:active]
22
- calendar, from, to = Calendar.send(:init, conf, pagy_calendar_period(collection), params) do |unit, period|
23
- pagy_calendar_counts(collection, unit, *period) if respond_to?(:pagy_calendar_counts)
24
- end
25
- collection = pagy_calendar_filter(collection, from, to)
26
- end
27
- pagy, results = send(conf[:pagy][:backend] || :pagy, collection, **conf[:pagy]) # use backend: :pagy when omitted
28
- [calendar, pagy, results]
29
- end
30
-
31
- # This method must be implemented by the application
32
- def pagy_calendar_period(*)
33
- raise NoMethodError, 'the pagy_calendar_period method must be implemented by the application ' \
34
- '(see https://ddnexus.github.io/pagy/docs/extras/calendar/#pagy-calendar-period-collection)'
35
- end
36
-
37
- # This method must be implemented by the application
38
- def pagy_calendar_filter(*)
39
- raise NoMethodError, 'the pagy_calendar_filter method must be implemented by the application ' \
40
- '(see https://ddnexus.github.io/pagy/docs/extras/calendar/#pagy-calendar-filter-collection-from-to)'
41
- end
42
- end
43
-
44
- # Override the pagy_anchor
45
- module FrontendOverride
46
- # Consider the vars[:counts]
47
- def pagy_anchor(pagy, anchor_string: nil)
48
- return super unless (counts = pagy.vars[:counts])
49
-
50
- anchor_string &&= %( #{anchor_string})
51
- left, right = %(<a#{anchor_string} href="#{pagy_url_for(pagy, PAGE_TOKEN)}").split(PAGE_TOKEN, 2)
52
- # lambda used by all the helpers
53
- lambda do |page, text = pagy.label_for(page), classes: nil, aria_label: nil|
54
- count = counts[page - 1]
55
- if count.zero?
56
- classes = "#{classes && (classes + ' ')}empty-page"
57
- info_key = 'pagy.info.no_items'
58
- else
59
- info_key = 'pagy.info.single_page'
60
- end
61
- title = %( title="#{pagy_t(info_key, item_name: pagy_t('pagy.item_name', count:), count:)}")
62
- classes = %( class="#{classes}") if classes
63
- aria_label = %( aria-label="#{aria_label}") if aria_label
64
- %(#{left}#{page}#{right}#{title}#{classes}#{aria_label}>#{text}</a>)
65
- end
66
- end
67
- end
68
-
69
- # Additions for the Frontend module
70
- module UrlHelperAddOn
71
- # Return the url for the calendar page at time
72
- def pagy_calendar_url_at(calendar, time, **opts)
73
- pagy_url_for(calendar.send(:calendar_at, time, **opts), 1, **opts)
74
- end
75
- end
76
- end
77
- Backend.prepend CalendarExtra::BackendAddOn, CalendarExtra::UrlHelperAddOn
78
- Frontend.prepend CalendarExtra::UrlHelperAddOn, CalendarExtra::FrontendOverride
79
- end
@@ -1,32 +0,0 @@
1
- # See the Pagy documentation: https://ddnexus.github.io/pagy/docs/extras/countless
2
- # frozen_string_literal: true
3
-
4
- require_relative '../countless'
5
-
6
- class Pagy # :nodoc:
7
- DEFAULT[:countless_minimal] = false
8
-
9
- # Paginate without the need of any count, saving one query per rendering
10
- module CountlessExtra
11
- private
12
-
13
- # Return Pagy object and records
14
- def pagy_countless(collection, **vars)
15
- vars[:limit] ||= pagy_get_limit(vars)
16
- vars[:page] ||= pagy_get_page(vars)
17
- pagy = Countless.new(**vars)
18
- [pagy, pagy_countless_get_items(collection, pagy)]
19
- end
20
-
21
- # Sub-method called only by #pagy_countless: here for easy customization of record-extraction by overriding
22
- # You may need to override this method for collections without offset|limit
23
- def pagy_countless_get_items(collection, pagy)
24
- return collection.offset(pagy.offset).limit(pagy.limit) if pagy.vars[:countless_minimal]
25
-
26
- fetched = collection.offset(pagy.offset).limit(pagy.limit + 1).to_a # eager load limit + 1
27
- pagy.finalize(fetched.size) # finalize the pagy object
28
- fetched[0, pagy.limit] # ignore eventual extra item
29
- end
30
- end
31
- Backend.prepend CountlessExtra
32
- end
@@ -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