pagy 9.3.4 → 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 (167) 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 +22 -23
  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 +12 -9
  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 +114 -53
  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 -166
  161. data/lib/pagy/keyset/active_record.rb +0 -38
  162. data/lib/pagy/keyset/sequel.rb +0 -51
  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/stylesheets/pagy.scss +0 -48
  167. data/stylesheets/pagy.tailwind.css +0 -21
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'nav_aria_label_attribute'
4
+ require_relative 'data_pagy_attribute'
5
+ require_relative 'a_lambda' # inherited use
6
+
7
+ # Relegate internal functions. Make overriding navs easier.
8
+ class Pagy
9
+ private
10
+
11
+ # Build the input_nav_js tag, with the specific inner html for the style
12
+ def wrap_input_nav_js(html, nav_classes, id: nil, aria_label: nil, **)
13
+ %(<nav#{%( id="#{id}") if id} class="#{nav_classes}" #{
14
+ nav_aria_label_attribute(aria_label:)} #{
15
+ data = [:inj, compose_page_url(PAGE_TOKEN, **)]
16
+ data.push(@update) if keynav?
17
+ data_pagy_attribute(*data)
18
+ }>#{html}</nav>)
19
+ end
20
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'series'
4
+ require_relative 'nav_aria_label_attribute'
5
+ require_relative 'data_pagy_attribute'
6
+ require_relative 'a_lambda' # inherited use
7
+
8
+ # Relegate internal functions. Make overriding navs easier.
9
+ class Pagy
10
+ private
11
+
12
+ # Build the nav tag, with the specific inner html for the style
13
+ def wrap_series_nav(html, nav_classes, id: nil, aria_label: nil, **)
14
+ data = %( #{data_pagy_attribute(:k, @update)}) if keynav?
15
+ %(<nav#{id && %( id="#{id}")} class="#{nav_classes}" #{nav_aria_label_attribute(aria_label:)}#{data}>#{html}</nav>)
16
+ end
17
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'series'
4
+ require_relative 'nav_aria_label_attribute'
5
+ require_relative 'data_pagy_attribute'
6
+ require_relative 'a_lambda' # inherited use
7
+
8
+ # Relegate internal functions. Make overriding navs easier.
9
+ class Pagy
10
+ private
11
+
12
+ # Return the reverse sorted array of widths, series, and labels generated from the :steps hash
13
+ # If :steps is false it will use the single {0 => @options[:slots]} length
14
+ def sequels(steps: @options[:steps] || { 0 => @options[:slots] || SERIES_SLOTS }, **)
15
+ raise OptionError.new(self, :steps, 'to define the 0 width', steps) unless steps.key?(0)
16
+
17
+ widths, series = steps.sort.reverse.map { |width, slots| [width, series(slots:)] }.transpose
18
+ [widths, series, page_labels(series)]
19
+ end
20
+
21
+ # Support for the Calendar API
22
+ def page_labels(series)
23
+ series.map { |s| s.map { |item| item == :gap ? :gap : page_label(item) } } if calendar?
24
+ end
25
+
26
+ # Build the nav_js tag, with the specific tokens for the style
27
+ def wrap_series_nav_js(tokens, nav_classes, id: nil, aria_label: nil, **)
28
+ sequels = sequels(**)
29
+ %(<nav#{id && %( id="#{id}")} class="#{'pagy-rjs ' if sequels[0].size > 1}#{nav_classes}" #{
30
+ nav_aria_label_attribute(aria_label:)} #{
31
+ data = [:snj, tokens.values, sequels]
32
+ data.push(@update) if keynav?
33
+ data_pagy_attribute(*data)
34
+ }></nav>)
35
+ end
36
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Pagy
4
+ # Generte hash of the pagination links
5
+ def urls_hash(**)
6
+ url = compose_page_url(PAGE_TOKEN, **)
7
+ { first: compose_page_url(nil, **) }.tap do |urls| # first is present, but the URL omits the nil page param
8
+ urls[:previous] = url.sub(PAGE_TOKEN, @previous.to_s) if @previous
9
+ urls[:next] = url.sub(PAGE_TOKEN, @next.to_s) if @next
10
+ urls[:last] = url.sub(PAGE_TOKEN, @last.to_s) if @count # offset and not countless
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Pagy
4
+ module CalendarPaginator
5
+ module_function
6
+
7
+ # Take a collection and a configuration Hash and return an array with 3 items: [calendar, pagy, results]
8
+ def paginate(context, collection, config)
9
+ context.instance_eval do
10
+ allowed_options = Calendar::UNITS + %i[offset disabled request]
11
+ raise ArgumentError, "keys must be in #{allowed_options.inspect}" \
12
+ unless config.is_a?(Hash) && (config.keys - allowed_options).empty?
13
+
14
+ config[:request] = Request.new(config[:request] || request)
15
+ config[:offset] ||= {}
16
+ unless config[:disabled]
17
+ calendar, from, to =
18
+ Calendar.send(:init, config,
19
+ pagy_calendar_period(collection),
20
+ config[:request].query) do |unit, period|
21
+ pagy_calendar_counts(collection, unit, *period) if respond_to?(:pagy_calendar_counts)
22
+ end
23
+ collection = pagy_calendar_filter(collection, from, to)
24
+ end
25
+ pagy, records = pagy(:offset, collection, **config[:offset])
26
+ [calendar, pagy, records]
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Pagy
4
+ module CountlessPaginator
5
+ module_function
6
+
7
+ # Return Pagy object and records
8
+ def paginate(context, collection, **options)
9
+ context.instance_eval do
10
+ request = Request.new(options[:request] || self.request, options)
11
+ if options[:page].nil?
12
+ page = request.resolve_page(options, force_integer: false) # accept nil and strings
13
+ if page.is_a?(String)
14
+ p, l = page.split(/ /, 2).map(&:to_i)
15
+ options[:page] = p if p.positive?
16
+ options[:last] = l if l&.positive?
17
+ end
18
+ end
19
+ options[:limit] = request.resolve_limit(options)
20
+ pagy = Offset::Countless.new(**options, request:)
21
+ [pagy, pagy.records(collection)]
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../modules/searcher'
4
+
5
+ class Pagy
6
+ module ElasticsearchRailsPaginator
7
+ module_function
8
+
9
+ # Paginate from search object
10
+ def paginate(context, search, **options)
11
+ context.instance_eval do
12
+ if search.is_a?(Search::Arguments)
13
+ # The search is the array of pagy_search arguments
14
+ Searcher.wrap(self, search, options) do
15
+ model, query_or_payload, search_options = search
16
+ search_options[:size] = options[:limit]
17
+ search_options[:from] = options[:limit] * ((options[:page] || 1) - 1)
18
+ results = model.send(ElasticsearchRails::DEFAULT[:search_method], query_or_payload, **search_options)
19
+ options[:count] = ElasticsearchRails.total_count(results)
20
+ [ElasticsearchRails.new(**options), results]
21
+ end
22
+ else
23
+ # The search is an elasticsearch_rails response
24
+ options[:limit] = search.search.options[:size] || 10
25
+ options[:page] = ((search.search.options[:from] || 0) / options[:limit]) + 1
26
+ options[:count] = ElasticsearchRails.total_count(search)
27
+ ElasticsearchRails.new(**options)
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../../pagy/modules/b64'
4
+
5
+ class Pagy
6
+ module KeynavJsPaginator
7
+ module_function
8
+
9
+ # Return Pagy::Keyset::Keynav object and paginated records.
10
+ # Fall back to :countless if the :page has no client data.
11
+ def paginate(context, set, **options)
12
+ context.instance_eval do
13
+ request = Request.new(options[:request] || self.request, options)
14
+ page = request.resolve_page(options, force_integer: false) # allow nil
15
+ if page&.match(' ') # countless page -> no augmentation -> fallback
16
+ return pagy(:countless, set, page:, **options)
17
+ elsif page.is_a?(String) # keynav page param
18
+ page_arguments = JSON.parse(B64.urlsafe_decode(page))
19
+ # Restart the pagination from page 1 if the url has been requested from another browser
20
+ options[:page] = page_arguments if request.cookie == page_arguments.shift
21
+ end
22
+
23
+ options[:limit] = request.resolve_limit(options)
24
+ pagy = Keyset::Keynav.new(set, **options, request:)
25
+ [pagy, pagy.records]
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Pagy
4
+ module KeysetPaginator
5
+ module_function
6
+
7
+ # Return Pagy::Keyset object and paginated records
8
+ def paginate(context, set, **options)
9
+ context.instance_eval do
10
+ request = Request.new(options[:request] || self.request, options)
11
+ options[:page] ||= request.resolve_page(options, force_integer: false) # allow nil
12
+ options[:limit] = request.resolve_limit(options)
13
+ pagy = Keyset.new(set, **options, request:)
14
+ [pagy, pagy.records]
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../modules/searcher'
4
+
5
+ class Pagy
6
+ module MeilisearchPaginator
7
+ module_function
8
+
9
+ # Paginate from search object
10
+ def paginate(context, search, **options)
11
+ context.instance_eval do
12
+ if search.is_a?(Search::Arguments)
13
+ # The search is the array of pagy_search arguments
14
+ Searcher.wrap(self, search, options) do
15
+ model, term, search_options = search
16
+ search_options[:hits_per_page] = options[:limit]
17
+ search_options[:page] = options[:page]
18
+ results = model.send(Meilisearch::DEFAULT[:search_method], term, search_options)
19
+ options[:count] = results.raw_answer['totalHits']
20
+ [Meilisearch.new(**options), results]
21
+ end
22
+ else
23
+ # The search is a meilisearch results object
24
+ options[:limit] = search.raw_answer['hitsPerPage']
25
+ options[:page] = search.raw_answer['page']
26
+ options[:count] = search.raw_answer['totalHits']
27
+ Meilisearch.new(**options)
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../classes/request'
4
+
5
+ class Pagy
6
+ paginators = { offset: :OffsetPaginator,
7
+ countless: :CountlessPaginator,
8
+ keyset: :KeysetPaginator,
9
+ keynav_js: :KeynavJsPaginator,
10
+ calendar: :CalendarPaginator,
11
+ elasticsearch_rails: :ElasticsearchRailsPaginator,
12
+ meilisearch: :MeilisearchPaginator,
13
+ searchkick: :SearchkickPaginator }.freeze
14
+
15
+ path = Pathname.new(__dir__)
16
+ paginators.each { |symbol, name| autoload name, path.join(symbol.to_s) }
17
+
18
+ # Defines the pagy method. Include in the app controller/view.
19
+ Method = Module.new do
20
+ protected
21
+
22
+ define_method :pagy do |paginator = :offset, collection, **options|
23
+ Pagy.const_get(paginators[paginator]).paginate(self, collection, **Pagy.options, **options)
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Pagy
4
+ module OffsetPaginator
5
+ module_function
6
+
7
+ # Return instance and page of results
8
+ def paginate(context, collection, **options)
9
+ context.instance_eval do
10
+ request = Request.new(options[:request] || self.request, options)
11
+ options[:page] ||= request.resolve_page(options)
12
+ options[:limit] = request.resolve_limit(options)
13
+ options[:count] ||= collection.instance_of?(Array) ? collection.size : OffsetPaginator.get_count(collection, options)
14
+ pagy = Offset.new(**options, request:)
15
+ [pagy, collection.instance_of?(Array) ? collection[pagy.offset, pagy.limit] : pagy.records(collection)]
16
+ end
17
+ end
18
+
19
+ # Get the collection count
20
+ def get_count(collection, options)
21
+ return collection.count unless defined?(::ActiveRecord) && collection.is_a?(::ActiveRecord::Relation)
22
+
23
+ count = if options[:count_over] && !collection.group_values.empty?
24
+ # COUNT(*) OVER ()
25
+ sql = Arel.star.count.over(Arel::Nodes::Grouping.new([]))
26
+ collection.unscope(:order).pick(sql).to_i
27
+ else
28
+ collection.count(:all)
29
+ end
30
+ count.is_a?(Hash) ? count.size : count
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../modules/searcher'
4
+
5
+ class Pagy
6
+ module SearchkickPaginator
7
+ module_function
8
+
9
+ # Paginate from search object.
10
+ def paginate(context, search, **options)
11
+ context.instance_eval do
12
+ if search.is_a?(Search::Arguments)
13
+ # The search is the array of pagy_search arguments
14
+ Searcher.wrap(self, search, options) do
15
+ model, term, search_options, block = search
16
+ search_options[:per_page] = options[:limit]
17
+ search_options[:page] = options[:page]
18
+ results = model.send(Searchkick::DEFAULT[:search_method], term || '*', **search_options, &block)
19
+ options[:count] = results.total_count
20
+ [Searchkick.new(**options), results]
21
+ end
22
+ else
23
+ # The search is a searchkick results object
24
+ options[:limit] = search.options[:per_page]
25
+ options[:page] = search.options[:page]
26
+ options[:count] = search.total_count
27
+ Searchkick.new(**options)
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
data/lib/pagy.rb CHANGED
@@ -1,106 +1,68 @@
1
- # See Pagy API documentation: https://ddnexus.github.io/pagy/docs/api/pagy
2
1
  # frozen_string_literal: true
3
2
 
4
3
  require 'pathname'
5
- require_relative 'pagy/shared_methods'
4
+ require_relative 'pagy/classes/exceptions'
5
+ require_relative 'pagy/modules/abilities/linkable'
6
+ require_relative 'pagy/modules/abilities/configurable'
7
+ require_relative 'pagy/toolbox/helpers/loader'
6
8
 
7
- # Top superclass: it should define only what's common to all the subclasses
9
+ # Top superclass: it defines only what's common to all the subclasses
8
10
  class Pagy
9
- VERSION = '9.3.4'
10
-
11
- # Core default: constant for easy access, but mutable for customizable defaults
12
- DEFAULT = { count_args: [:all], # rubocop:disable Style/MutableConstant
13
- ends: true,
14
- limit: 20,
15
- outset: 0,
16
- page: 1,
17
- page_param: :page,
18
- size: 7 } # AR friendly
19
-
20
- # Gem root pathname to get the path of Pagy files stylesheets, javascripts, apps, locales, etc.
21
- def self.root
22
- @root ||= Pathname.new(__dir__).parent.freeze
23
- end
24
-
25
- include SharedMethods
26
-
27
- attr_reader :count, :from, :in, :last, :next, :offset, :prev, :to
28
- alias pages last
29
-
30
- # Merge and validate the options, do some simple arithmetic and set the instance variables
31
- def initialize(**vars)
32
- assign_vars(DEFAULT, vars)
33
- assign_and_check(count: 0, page: 1, outset: 0)
34
- assign_limit
35
- assign_offset
36
- assign_last
37
- check_overflow
38
- @from = [@offset - @outset + 1, @count].min
39
- @to = [@offset - @outset + @limit, @count].min
40
- @in = [@to - @from + 1, @count].min
41
- assign_prev_and_next
42
- end
43
-
44
- # Setup @last (overridden by the gearbox extra)
45
- def assign_last
46
- @last = [(@count.to_f / @limit).ceil, 1].max
47
- @last = @vars[:max_pages] if @vars[:max_pages] && @last > vars[:max_pages]
48
- end
49
-
50
- # Assign @offset (overridden by the gearbox extra)
51
- def assign_offset
52
- @offset = (@limit * (@page - 1)) + @outset # may be already set from gear_box
53
- end
54
-
55
- # Assign @prev and @next
56
- def assign_prev_and_next
57
- @prev = (@page - 1 unless @page == 1)
58
- @next = @page == @last ? (1 if @vars[:cycle]) : @page + 1
59
- end
60
-
61
- # Checks the @page <= @last
62
- def check_overflow
63
- raise OverflowError.new(self, :page, "in 1..#{@last}", @page) if @page > @last
11
+ VERSION = '43.0.0.rc1'
12
+ ROOT = Pathname.new(__dir__).parent.freeze
13
+ DEFAULT = { limit: 20, limit_key: 'limit', page_key: 'page' }.freeze
14
+ PAGE_TOKEN = 'P '
15
+ LIMIT_TOKEN = 'L '
16
+ LABEL_TOKEN = 'L'
17
+ A_TAG = '<a style="display: none;">#</a>'
18
+
19
+ path = Pathname.new(__FILE__).sub_ext('')
20
+ autoload :Method, path.join('toolbox/paginators/method')
21
+ autoload :I18n, path.join('modules/i18n/i18n')
22
+ autoload :Console, path.join('modules/console')
23
+ autoload :Calendar, path.join('classes/calendar/calendar')
24
+ autoload :Offset, path.join('classes/offset/offset')
25
+ autoload :Search, path.join('classes/offset/search')
26
+ autoload :ElasticsearchRails, path.join('classes/offset/search')
27
+ autoload :Meilisearch, path.join('classes/offset/search')
28
+ autoload :Searchkick, path.join('classes/offset/search')
29
+ autoload :Keyset, path.join('classes/keyset/keyset')
30
+
31
+ def self.options = @options ||= {}
32
+
33
+ extend Configurable
34
+ include Linkable
35
+ include Loader
36
+
37
+ attr_reader :page, :next, :in, :limit, :options
38
+
39
+ protected
40
+
41
+ # Define the hierarchical identity methods, overridden by the respective classes
42
+ def offset? = false
43
+ def countless? = false
44
+ def calendar? = false
45
+ def search? = false
46
+ def keyset? = false
47
+ def keynav? = false
48
+
49
+ # Validates and assign the passed options: var must be present and value.to_i must be >= to min
50
+ def assign_and_check(name_min)
51
+ name_min.each do |name, min|
52
+ raise OptionError.new(self, name, ">= #{min}", @options[name]) \
53
+ unless @options[name].respond_to?(:to_i) && instance_variable_set(:"@#{name}", @options[name].to_i) >= min
54
+ end
64
55
  end
65
56
 
66
- # Label for the current page. Allow the customization of the output (overridden by the calendar extra)
67
- def label = @page.to_s
68
-
69
- # Label for any page. Allow the customization of the output (overridden by the calendar extra)
70
- def label_for(page) = page.to_s
71
-
72
- # Return the array of page numbers and :gap e.g. [1, :gap, 8, "9", 10, :gap, 36]
73
- def series(size: @vars[:size], **_)
74
- raise VariableError.new(self, :size, 'to be an Integer >= 0', size) \
75
- unless size.is_a?(Integer) && size >= 0
76
- return [] if size.zero?
77
-
78
- [].tap do |series|
79
- if size >= @last
80
- series.push(*1..@last)
81
- else
82
- left = ((size - 1) / 2.0).floor # left half might be 1 page shorter for even size
83
- start = if @page <= left # beginning pages
84
- 1
85
- elsif @page > (@last - size + left) # end pages
86
- @last - size + 1
87
- else # intermediate pages
88
- @page - left
89
- end
90
- series.push(*start...start + size)
91
- # Set first and last pages plus gaps when needed, respecting the size
92
- if vars[:ends] && size >= 7
93
- series[0] = 1
94
- series[1] = :gap unless series[1] == 2
95
- series[-2] = :gap unless series[-2] == @last - 1
96
- series[-1] = @last
97
- end
98
- end
99
- series[series.index(@page)] = @page.to_s
100
- end
57
+ # Merge all the DEFAULT constants of the class hierarchy with the options
58
+ def assign_options(**options)
59
+ @request = options.delete(:request) # internal object
60
+ default = {}
61
+ current = self.class
62
+ begin
63
+ default = current::DEFAULT.merge(default)
64
+ current = current.superclass
65
+ end until current == Object # rubocop:disable Lint/Loop -- see https://github.com/rubocop/rubocop-performance/issues/362
66
+ @options = default.merge!(options.delete_if { |k, v| default.key?(k) && (v.nil? || v == '') }).freeze
101
67
  end
102
68
  end
103
-
104
- require_relative 'pagy/backend'
105
- require_relative 'pagy/frontend'
106
- require_relative 'pagy/exceptions'
data/locales/ar.yml CHANGED
@@ -1,6 +1,8 @@
1
- # :arabic pluralization (see https://github.com/ddnexus/pagy/blob/master/gem/lib/pagy/i18n.rb)
1
+ # See https://ddnexus.github.io/pagy/resources/i18n
2
+
2
3
  ar:
3
4
  pagy:
5
+ p11n: 'Arabic'
4
6
  aria_label:
5
7
  nav:
6
8
  zero: "لا يوجد صفحات"
@@ -9,9 +11,9 @@ ar:
9
11
  few: "صفحات"
10
12
  many: "صفحات"
11
13
  other: "صفحات"
12
- prev: "السابق"
14
+ previous: "السابق"
13
15
  next: "التالي"
14
- prev: "&lt;"
16
+ previous: "&lt;"
15
17
  next: "&gt;"
16
18
  gap: "&hellip;"
17
19
  item_name:
@@ -21,9 +23,10 @@ ar:
21
23
  few: "قليل"
22
24
  many: "كثير"
23
25
  other: "عناصر"
24
- info:
26
+ info_tag:
27
+ no_count: "الصفحة %{page} من %{pages}"
25
28
  no_items: "لا يوجد %{item_name}"
26
29
  single_page: "عرض %{count} %{item_name}"
27
30
  multiple_pages: "عرض %{item_name} %{from}-%{to} من اجمالي %{count}"
28
- combo_nav_js: "الصفحة %{page_input} من %{pages}"
29
- limit_selector_js: "عرض %{limit_input} %{item_name} لكل صفحة"
31
+ input_nav_js: "الصفحة %{page_input} من %{pages}"
32
+ limit_tag_js: "عرض %{limit_input} %{item_name} لكل صفحة"
data/locales/be.yml CHANGED
@@ -1,15 +1,17 @@
1
- # :east_slavic pluralization (see https://github.com/ddnexus/pagy/blob/master/gem/lib/pagy/i18n.rb)
1
+ # See https://ddnexus.github.io/pagy/resources/i18n
2
+
2
3
  be:
3
4
  pagy:
5
+ p11n: 'EastSlavic'
4
6
  aria_label:
5
7
  nav:
6
8
  one: "Старонка"
7
9
  few: "Старонкi"
8
10
  many: "Старонкi"
9
11
  other: "Старонкi"
10
- prev: "Назад"
12
+ previous: "Назад"
11
13
  next: "Наперад"
12
- prev: "&lt;"
14
+ previous: "&lt;"
13
15
  next: "&gt;"
14
16
  gap: "&hellip;"
15
17
  item_name:
@@ -17,9 +19,10 @@ be:
17
19
  few: "запісы"
18
20
  many: "запісаў"
19
21
  other: "запісаў"
20
- info:
22
+ info_tag:
23
+ no_count: "Старонка %{page} з %{pages}"
21
24
  no_items: "Пакуль %{item_name} няма"
22
25
  single_page: "%{count} %{item_name}"
23
26
  multiple_pages: "Усяго %{count} %{item_name}, паказаны з %{from} па %{to}"
24
- combo_nav_js: "Старонка %{page_input} з %{pages}"
25
- limit_selector_js: "Паказаць %{limit_input} %{item_name} на старонцы"
27
+ input_nav_js: "Старонка %{page_input} з %{pages}"
28
+ limit_tag_js: "Паказаць %{limit_input} %{item_name} на старонцы"
data/locales/bg.yml CHANGED
@@ -1,21 +1,24 @@
1
- # :one_other pluralization (see https://github.com/ddnexus/pagy/blob/master/gem/lib/pagy/i18n.rb)
1
+ # See https://ddnexus.github.io/pagy/resources/i18n
2
+
2
3
  bg:
3
4
  pagy:
5
+ p11n: 'OneOther'
4
6
  aria_label:
5
7
  nav:
6
8
  one: "Страница"
7
9
  other: "Страници"
8
- prev: "Предишна"
10
+ previous: "Предишна"
9
11
  next: "Следваща"
10
- prev: "&lt;"
12
+ previous: "&lt;"
11
13
  next: "&gt;"
12
14
  gap: "&hellip;"
13
15
  item_name:
14
16
  one: "резултат"
15
17
  other: "резултати"
16
- info:
18
+ info_tag:
19
+ no_count: "Страница %{page} от %{pages}"
17
20
  no_items: "Няма намерени %{item_name}"
18
21
  single_page: "Показани са %{count} %{item_name}"
19
22
  multiple_pages: "Показани са %{item_name} %{from}-%{to} от %{count} общо"
20
- combo_nav_js: "Страница %{page_input} от %{pages}"
21
- limit_selector_js: "Покажи %{limit_input} %{item_name} на страница"
23
+ input_nav_js: "Страница %{page_input} от %{pages}"
24
+ limit_tag_js: "Покажи %{limit_input} %{item_name} на страница"