pagy 7.0.11 → 43.5.1

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 (211) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +1 -1
  3. data/apps/calendar.ru +741 -0
  4. data/apps/demo.ru +513 -0
  5. data/apps/enable_rails_page_segment.rb +54 -0
  6. data/apps/index.rb +9 -0
  7. data/apps/keynav+root_key.ru +316 -0
  8. data/apps/keynav.ru +255 -0
  9. data/apps/keyset.ru +219 -0
  10. data/apps/keyset_sequel.ru +212 -0
  11. data/apps/rails.ru +216 -0
  12. data/apps/repro.ru +185 -0
  13. data/bin/pagy +5 -0
  14. data/config/pagy.rb +46 -0
  15. data/javascripts/ai_widget.js +90 -0
  16. data/javascripts/pagy.js +168 -0
  17. data/javascripts/pagy.min.js +2 -0
  18. data/javascripts/pagy.mjs +161 -0
  19. data/javascripts/wand.js +1172 -0
  20. data/lib/pagy/classes/calendar/calendar.rb +101 -0
  21. data/lib/pagy/{calendar → classes/calendar}/day.rb +9 -12
  22. data/lib/pagy/{calendar → classes/calendar}/month.rb +7 -11
  23. data/lib/pagy/{calendar → classes/calendar}/quarter.rb +12 -16
  24. data/lib/pagy/classes/calendar/unit.rb +93 -0
  25. data/lib/pagy/{calendar → classes/calendar}/week.rb +7 -11
  26. data/lib/pagy/{calendar → classes/calendar}/year.rb +9 -9
  27. data/lib/pagy/classes/exceptions.rb +26 -0
  28. data/lib/pagy/classes/keyset/adapters/active_record.rb +50 -0
  29. data/lib/pagy/classes/keyset/adapters/sequel.rb +62 -0
  30. data/lib/pagy/classes/keyset/keynav.rb +85 -0
  31. data/lib/pagy/classes/keyset/keyset.rb +150 -0
  32. data/lib/pagy/classes/offset/countish.rb +17 -0
  33. data/lib/pagy/classes/offset/countless.rb +63 -0
  34. data/lib/pagy/classes/offset/offset.rb +63 -0
  35. data/lib/pagy/classes/offset/search.rb +34 -0
  36. data/lib/pagy/classes/request.rb +48 -0
  37. data/lib/pagy/cli.rb +122 -0
  38. data/lib/pagy/console.rb +5 -20
  39. data/lib/pagy/deprecated.rb +84 -0
  40. data/lib/pagy/modules/abilities/configurable.rb +37 -0
  41. data/lib/pagy/modules/abilities/countable.rb +23 -0
  42. data/lib/pagy/modules/abilities/linkable.rb +72 -0
  43. data/lib/pagy/modules/abilities/rangeable.rb +14 -0
  44. data/lib/pagy/modules/abilities/shiftable.rb +12 -0
  45. data/lib/pagy/modules/b64.rb +35 -0
  46. data/lib/pagy/modules/console.rb +33 -0
  47. data/lib/pagy/modules/i18n/i18n.rb +72 -0
  48. data/lib/pagy/modules/i18n/p11n/arabic.rb +30 -0
  49. data/lib/pagy/modules/i18n/p11n/east_slavic.rb +27 -0
  50. data/lib/pagy/modules/i18n/p11n/one_other.rb +15 -0
  51. data/lib/pagy/modules/i18n/p11n/one_upto_two_other.rb +15 -0
  52. data/lib/pagy/modules/i18n/p11n/other.rb +13 -0
  53. data/lib/pagy/modules/i18n/p11n/polish.rb +27 -0
  54. data/lib/pagy/modules/i18n/p11n/west_slavic.rb +22 -0
  55. data/lib/pagy/modules/i18n/p11n.rb +16 -0
  56. data/lib/pagy/modules/searcher.rb +20 -0
  57. data/lib/pagy/next.rb +25 -0
  58. data/lib/pagy/tasks/sync.rb +20 -0
  59. data/lib/pagy/toolbox/helpers/anchor_tags.rb +21 -0
  60. data/lib/pagy/toolbox/helpers/bootstrap/input_nav_js.rb +28 -0
  61. data/lib/pagy/toolbox/helpers/bootstrap/previous_next_html.rb +19 -0
  62. data/lib/pagy/toolbox/helpers/bootstrap/series_nav.rb +32 -0
  63. data/lib/pagy/toolbox/helpers/bootstrap/series_nav_js.rb +24 -0
  64. data/lib/pagy/toolbox/helpers/bulma/input_nav_js.rb +25 -0
  65. data/lib/pagy/toolbox/helpers/bulma/previous_next_html.rb +20 -0
  66. data/lib/pagy/toolbox/helpers/bulma/series_nav.rb +31 -0
  67. data/lib/pagy/toolbox/helpers/bulma/series_nav_js.rb +23 -0
  68. data/lib/pagy/toolbox/helpers/data_hash.rb +29 -0
  69. data/lib/pagy/toolbox/helpers/headers_hash.rb +30 -0
  70. data/lib/pagy/toolbox/helpers/info_tag.rb +30 -0
  71. data/lib/pagy/toolbox/helpers/input_nav_js.rb +22 -0
  72. data/lib/pagy/toolbox/helpers/limit_tag_js.rb +25 -0
  73. data/lib/pagy/toolbox/helpers/loaders.rb +55 -0
  74. data/lib/pagy/toolbox/helpers/page_url.rb +16 -0
  75. data/lib/pagy/toolbox/helpers/series_nav.rb +30 -0
  76. data/lib/pagy/toolbox/helpers/series_nav_js.rb +20 -0
  77. data/lib/pagy/toolbox/helpers/support/a_lambda.rb +36 -0
  78. data/lib/pagy/toolbox/helpers/support/data_pagy_attribute.rb +19 -0
  79. data/lib/pagy/toolbox/helpers/support/nav_aria_label_attribute.rb +10 -0
  80. data/lib/pagy/toolbox/helpers/support/series.rb +37 -0
  81. data/lib/pagy/toolbox/helpers/support/wrap_input_nav_js.rb +19 -0
  82. data/lib/pagy/toolbox/helpers/support/wrap_series_nav.rb +17 -0
  83. data/lib/pagy/toolbox/helpers/support/wrap_series_nav_js.rb +42 -0
  84. data/lib/pagy/toolbox/helpers/urls_hash.rb +12 -0
  85. data/lib/pagy/toolbox/paginators/calendar.rb +34 -0
  86. data/lib/pagy/toolbox/paginators/countish.rb +38 -0
  87. data/lib/pagy/toolbox/paginators/countless.rb +22 -0
  88. data/lib/pagy/toolbox/paginators/elasticsearch_rails.rb +56 -0
  89. data/lib/pagy/toolbox/paginators/keynav_js.rb +26 -0
  90. data/lib/pagy/toolbox/paginators/keyset.rb +15 -0
  91. data/lib/pagy/toolbox/paginators/meilisearch.rb +34 -0
  92. data/lib/pagy/toolbox/paginators/method.rb +38 -0
  93. data/lib/pagy/toolbox/paginators/offset.rb +24 -0
  94. data/lib/pagy/toolbox/paginators/searchkick.rb +34 -0
  95. data/lib/pagy/toolbox/paginators/typesense_rails.rb +34 -0
  96. data/lib/pagy.rb +67 -131
  97. data/locales/ar.yml +32 -0
  98. data/locales/be.yml +28 -0
  99. data/locales/bg.yml +24 -0
  100. data/locales/bs.yml +28 -0
  101. data/locales/ca.yml +24 -0
  102. data/locales/ckb.yml +20 -0
  103. data/locales/cs.yml +26 -0
  104. data/locales/da.yml +24 -0
  105. data/locales/de.yml +24 -0
  106. data/locales/dz.yml +20 -0
  107. data/locales/en.yml +24 -0
  108. data/{lib/locales → locales}/es.yml +9 -6
  109. data/locales/fr.yml +24 -0
  110. data/locales/hr.yml +28 -0
  111. data/locales/id.yml +20 -0
  112. data/locales/it.yml +24 -0
  113. data/locales/ja.yml +20 -0
  114. data/locales/km.yml +20 -0
  115. data/locales/ko.yml +20 -0
  116. data/locales/nb.yml +24 -0
  117. data/locales/nl.yml +24 -0
  118. data/locales/nn.yml +24 -0
  119. data/locales/pl.yml +28 -0
  120. data/{lib/locales → locales}/pt-BR.yml +10 -7
  121. data/{lib/locales → locales}/pt.yml +10 -7
  122. data/locales/ru.yml +28 -0
  123. data/locales/sk.yml +26 -0
  124. data/locales/sr.yml +28 -0
  125. data/locales/sv-SE.yml +24 -0
  126. data/locales/sv.yml +24 -0
  127. data/locales/sw.yml +28 -0
  128. data/locales/ta.yml +24 -0
  129. data/locales/tr.yml +24 -0
  130. data/locales/uk.yml +28 -0
  131. data/locales/vi.yml +20 -0
  132. data/locales/zh-CN.yml +20 -0
  133. data/locales/zh-HK.yml +20 -0
  134. data/locales/zh-TW.yml +20 -0
  135. data/stylesheets/pagy-tailwind.css +68 -0
  136. data/stylesheets/pagy.css +83 -0
  137. metadata +185 -94
  138. data/lib/config/pagy.rb +0 -258
  139. data/lib/javascripts/pagy-dev.js +0 -112
  140. data/lib/javascripts/pagy-module.js +0 -111
  141. data/lib/javascripts/pagy.js +0 -1
  142. data/lib/locales/ar.yml +0 -30
  143. data/lib/locales/be.yml +0 -25
  144. data/lib/locales/bg.yml +0 -21
  145. data/lib/locales/bs.yml +0 -25
  146. data/lib/locales/ca.yml +0 -23
  147. data/lib/locales/ckb.yml +0 -18
  148. data/lib/locales/cs.yml +0 -23
  149. data/lib/locales/da.yml +0 -23
  150. data/lib/locales/de.yml +0 -21
  151. data/lib/locales/en.yml +0 -21
  152. data/lib/locales/fr.yml +0 -21
  153. data/lib/locales/hr.yml +0 -25
  154. data/lib/locales/id.yml +0 -19
  155. data/lib/locales/it.yml +0 -21
  156. data/lib/locales/ja.yml +0 -19
  157. data/lib/locales/km.yml +0 -19
  158. data/lib/locales/ko.yml +0 -19
  159. data/lib/locales/nb.yml +0 -21
  160. data/lib/locales/nl.yml +0 -21
  161. data/lib/locales/nn.yml +0 -21
  162. data/lib/locales/pl.yml +0 -25
  163. data/lib/locales/ru.yml +0 -27
  164. data/lib/locales/sr.yml +0 -25
  165. data/lib/locales/sv-SE.yml +0 -21
  166. data/lib/locales/sv.yml +0 -21
  167. data/lib/locales/sw.yml +0 -23
  168. data/lib/locales/ta.yml +0 -23
  169. data/lib/locales/tr.yml +0 -19
  170. data/lib/locales/uk.yml +0 -25
  171. data/lib/locales/vi.yml +0 -17
  172. data/lib/locales/zh-CN.yml +0 -19
  173. data/lib/locales/zh-HK.yml +0 -19
  174. data/lib/locales/zh-TW.yml +0 -19
  175. data/lib/pagy/backend.rb +0 -39
  176. data/lib/pagy/calendar/helper.rb +0 -65
  177. data/lib/pagy/calendar.rb +0 -126
  178. data/lib/pagy/countless.rb +0 -37
  179. data/lib/pagy/exceptions.rb +0 -25
  180. data/lib/pagy/extras/arel.rb +0 -36
  181. data/lib/pagy/extras/array.rb +0 -24
  182. data/lib/pagy/extras/bootstrap.rb +0 -108
  183. data/lib/pagy/extras/bulma.rb +0 -105
  184. data/lib/pagy/extras/calendar.rb +0 -53
  185. data/lib/pagy/extras/countless.rb +0 -37
  186. data/lib/pagy/extras/elasticsearch_rails.rb +0 -80
  187. data/lib/pagy/extras/foundation.rb +0 -105
  188. data/lib/pagy/extras/frontend_helpers.rb +0 -67
  189. data/lib/pagy/extras/gearbox.rb +0 -54
  190. data/lib/pagy/extras/headers.rb +0 -53
  191. data/lib/pagy/extras/i18n.rb +0 -26
  192. data/lib/pagy/extras/items.rb +0 -61
  193. data/lib/pagy/extras/jsonapi.rb +0 -79
  194. data/lib/pagy/extras/materialize.rb +0 -96
  195. data/lib/pagy/extras/meilisearch.rb +0 -65
  196. data/lib/pagy/extras/metadata.rb +0 -38
  197. data/lib/pagy/extras/navs.rb +0 -51
  198. data/lib/pagy/extras/overflow.rb +0 -80
  199. data/lib/pagy/extras/searchkick.rb +0 -67
  200. data/lib/pagy/extras/semantic.rb +0 -95
  201. data/lib/pagy/extras/standalone.rb +0 -60
  202. data/lib/pagy/extras/support.rb +0 -40
  203. data/lib/pagy/extras/trim.rb +0 -29
  204. data/lib/pagy/extras/uikit.rb +0 -97
  205. data/lib/pagy/frontend.rb +0 -114
  206. data/lib/pagy/i18n.rb +0 -165
  207. data/lib/pagy/url_helpers.rb +0 -27
  208. data/lib/stylesheets/pagy.css +0 -61
  209. data/lib/stylesheets/pagy.scss +0 -50
  210. data/lib/stylesheets/pagy.tailwind.scss +0 -24
  211. /data/{lib/javascripts/pagy-module.d.ts → javascripts/pagy.d.ts} +0 -0
data/lib/pagy/backend.rb DELETED
@@ -1,39 +0,0 @@
1
- # See Pagy::Backend API documentation: https://ddnexus.github.io/pagy/docs/api/backend
2
- # frozen_string_literal: true
3
-
4
- class Pagy
5
- # Define a few generic methods to paginate a collection out of the box,
6
- # or any collection by overriding pagy_get_items and/or pagy_get_vars in your controller
7
- # See also the extras if you need specialized methods to paginate Arrays or other collections
8
- module Backend
9
- private
10
-
11
- # Return Pagy object and paginated items/results
12
- def pagy(collection, vars = {})
13
- pagy = Pagy.new(pagy_get_vars(collection, vars))
14
- [pagy, pagy_get_items(collection, pagy)]
15
- end
16
-
17
- # Sub-method called only by #pagy: here for easy customization of variables by overriding
18
- # You may need to override the count call for non AR collections
19
- def pagy_get_vars(collection, vars)
20
- pagy_set_items_from_params(vars) if defined?(ItemsExtra)
21
- count_args = vars[:count_args] || DEFAULT[:count_args]
22
- vars[:count] ||= (count = collection.count(*count_args)).is_a?(Hash) ? count.size : count
23
- vars[:page] ||= pagy_get_page(vars)
24
- vars
25
- end
26
-
27
- # Get the page integer from the params
28
- # Overridable by the jsonapi extra
29
- def pagy_get_page(vars)
30
- (params[vars[:page_param] || DEFAULT[:page_param]] || 1).to_i
31
- end
32
-
33
- # Sub-method called only by #pagy: here for easy customization of record-extraction by overriding
34
- # You may need to override this method for collections without offset|limit
35
- def pagy_get_items(collection, pagy)
36
- collection.offset(pagy.offset).limit(pagy.items)
37
- end
38
- end
39
- end
@@ -1,65 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class Pagy # :nodoc:
4
- class Calendar # :nodoc:
5
- # Initializes the calendar objects, reducing complexity in the extra
6
- # The returned calendar is a simple hash of units/objects
7
- class Helper < Hash
8
- class << self
9
- private
10
-
11
- def init(conf, period, params)
12
- new.send(:init, conf, period, params)
13
- end
14
- end
15
-
16
- private
17
-
18
- # Create the calendar
19
- def init(conf, period, params)
20
- @conf = Marshal.load(Marshal.dump(conf)) # store a copy
21
- @units = Calendar::UNITS & @conf.keys # get the units in time length desc order
22
- raise ArgumentError, 'no calendar unit found in pagy_calendar @configuration' if @units.empty?
23
-
24
- @period = period
25
- @params = params
26
- @page_param = conf[:pagy][:page_param] || DEFAULT[:page_param]
27
- @units.each do |unit| # set all the :page_param vars for later deletion
28
- unit_page_param = :"#{unit}_#{@page_param}"
29
- conf[unit][:page_param] = unit_page_param
30
- conf[unit][:page] = @params[unit_page_param]
31
- end
32
- calendar = {}
33
- object = nil
34
- @units.each_with_index do |unit, index|
35
- params_to_delete = @units[(index + 1), @units.size].map { |sub| conf[sub][:page_param] } + [@page_param]
36
- conf[unit][:params] = lambda { |up| up.except(*params_to_delete.map(&:to_s)) } # rubocop:disable Style/Lambda
37
- conf[unit][:period] = object&.send(:active_period) || @period
38
- calendar[unit] = object = Calendar.send(:create, unit, conf[unit])
39
- end
40
- [replace(calendar), object.from, object.to]
41
- end
42
-
43
- # Return the calendar object at time
44
- def calendar_at(time, **opts)
45
- conf = Marshal.load(Marshal.dump(@conf))
46
- page_params = {}
47
- @units.inject(nil) do |object, unit|
48
- conf[unit][:period] = object&.send(:active_period) || @period
49
- conf[unit][:page] = page_params[:"#{unit}_#{@page_param}"] \
50
- = Calendar.send(:create, unit, conf[unit]).send(:page_at, time, **opts)
51
- conf[unit][:params] ||= {}
52
- conf[unit][:params].merge!(page_params)
53
- Calendar.send(:create, unit, conf[unit])
54
- end
55
- end
56
-
57
- public
58
-
59
- # Return the current time of the smallest time unit shown
60
- def showtime
61
- self[@units.last].from
62
- end
63
- end
64
- end
65
- end
data/lib/pagy/calendar.rb DELETED
@@ -1,126 +0,0 @@
1
- # See Pagy::Countless API documentation: https://ddnexus.github.io/pagy/docs/api/calendar
2
- # frozen_string_literal: true
3
-
4
- require 'active_support'
5
- require 'active_support/core_ext/time'
6
- require 'active_support/core_ext/date_and_time/calculations'
7
- require 'active_support/core_ext/numeric/time'
8
- require 'active_support/core_ext/integer/time'
9
-
10
- require 'pagy'
11
-
12
- class Pagy # :nodoc:
13
- # Base class for time units subclasses (Year, Quarter, Month, Week, Day)
14
- class Calendar < Pagy
15
- # Specific out of range error
16
- class OutOfRangeError < VariableError; end
17
-
18
- # List of units in desc order of duration. It can be used for custom units.
19
- UNITS = %i[year quarter month week day] # rubocop:disable Style/MutableConstant
20
-
21
- attr_reader :order, :from, :to
22
-
23
- # Merge and validate the options, do some simple arithmetic and set a few instance variables
24
- def initialize(vars) # rubocop:disable Lint/MissingSuper
25
- raise InternalError, 'Pagy::Calendar is a base class; use one of its subclasses' if instance_of?(Pagy::Calendar)
26
-
27
- vars = self.class::DEFAULT.merge(vars) # subclass specific default
28
- normalize_vars(vars) # general default
29
- setup_vars(page: 1)
30
- setup_unit_vars
31
- setup_params_var
32
- raise OverflowError.new(self, :page, "in 1..#{@last}", @page) if @page > @last
33
-
34
- @prev = (@page - 1 unless @page == 1)
35
- @next = @page == @last ? (1 if @vars[:cycle]) : @page + 1
36
- end
37
-
38
- # The label for the current page (it can pass along the I18n gem opts when it's used with the i18n extra)
39
- def label(opts = {})
40
- label_for(@page, opts)
41
- end
42
-
43
- # The label for any page (it can pass along the I18n gem opts when it's used with the i18n extra)
44
- def label_for(page, opts = {})
45
- opts[:format] ||= @vars[:format]
46
- localize(starting_time_for(page.to_i), opts) # page could be a string
47
- end
48
-
49
- protected
50
-
51
- # The page that includes time
52
- # In case of out of range time, the :fit_time option avoids the outOfRangeError
53
- # and returns the closest page to the passed time argument (first or last page)
54
- def page_at(time, **opts)
55
- fit_time = time
56
- fit_final = @final - 1
57
- unless time.between?(@initial, fit_final)
58
- raise OutOfRangeError.new(self, :time, "between #{@initial} and #{fit_final}", time) unless opts[:fit_time]
59
-
60
- if time < @final
61
- fit_time = @initial
62
- ordinal = 'first'
63
- else
64
- fit_time = fit_final
65
- ordinal = 'last'
66
- end
67
- Warning.warn "Pagy::Calendar#page_at: Rescued #{time} out of range by returning the #{ordinal} page."
68
- end
69
- offset = page_offset_at(fit_time) # offset starts from 0
70
- @order == :asc ? offset + 1 : @pages - offset
71
- end
72
-
73
- # Base class method for the setup of the unit variables (subclasses must implement it and call super)
74
- def setup_unit_vars
75
- raise VariableError.new(self, :format, 'to be a strftime format', @vars[:format]) unless @vars[:format].is_a?(String)
76
- raise VariableError.new(self, :order, 'to be in [:asc, :desc]', @order) \
77
- unless %i[asc desc].include?(@order = @vars[:order])
78
-
79
- @starting, @ending = @vars[:period]
80
- raise VariableError.new(self, :period, 'to be a an Array of min and max TimeWithZone instances', @vars[:period]) \
81
- unless @starting.is_a?(ActiveSupport::TimeWithZone) \
82
- && @ending.is_a?(ActiveSupport::TimeWithZone) && @starting <= @ending
83
- end
84
-
85
- # Apply the strftime format to the time (overridden by the i18n extra when localization is required)
86
- def localize(time, opts)
87
- time.strftime(opts[:format])
88
- end
89
-
90
- # Number of time units to offset from the @initial time, in order to get the ordered starting time for the page.
91
- # Used in starting_time_for(page) where page starts from 1 (e.g. page to starting_time means subtracting 1)
92
- def time_offset_for(page)
93
- @order == :asc ? page - 1 : @pages - page
94
- end
95
-
96
- # Period of the active page (used internally for nested units)
97
- def active_period
98
- [[@starting, @from].max, [@to - 1, @ending].min] # -1 sec: include only last unit day
99
- end
100
-
101
- # :nocov:
102
- # This method must be implemented by the unit subclass
103
- def starting_time_for(*)
104
- raise NoMethodError, 'the starting_time_for method must be implemented by the unit subclass'
105
- end
106
-
107
- # This method must be implemented by the unit subclass
108
- def page_offset_at(*)
109
- raise NoMethodError, 'the page_offset_at method must be implemented by the unit subclass'
110
- end
111
- # :nocov:
112
-
113
- class << self
114
- # Create a subclass instance by unit name (internal use)
115
- def create(unit, vars)
116
- raise InternalError, "unit must be in #{UNITS.inspect}; got #{unit}" unless UNITS.include?(unit)
117
-
118
- name = unit.to_s
119
- name[0] = name[0].capitalize
120
- Object.const_get("Pagy::Calendar::#{name}").new(vars)
121
- end
122
- end
123
- end
124
- # Require the subclass files in UNITS (no custom unit at this point yet)
125
- Calendar::UNITS.each { |unit| require "pagy/calendar/#{unit}" }
126
- end
@@ -1,37 +0,0 @@
1
- # See Pagy::Countless API documentation: https://ddnexus.github.io/pagy/docs/api/countless
2
- # frozen_string_literal: true
3
-
4
- require 'pagy'
5
-
6
- class Pagy
7
- # No need to know the count to paginate
8
- class Countless < Pagy
9
- # Merge and validate the options, do some simple arithmetic and set a few instance variables
10
- def initialize(vars = {}) # rubocop:disable Lint/MissingSuper
11
- normalize_vars(vars)
12
- setup_vars(page: 1, outset: 0)
13
- setup_items_var
14
- setup_offset_var
15
- setup_params_var
16
- end
17
-
18
- # Finalize the instance variables based on the fetched size
19
- def finalize(fetched_size)
20
- raise OverflowError.new(self, :page, "to be < #{@page}", @page) if fetched_size.zero? && @page > 1
21
-
22
- @pages = @last = (fetched_size > @items ? @page + 1 : @page)
23
- @in = [fetched_size, @items].min
24
- @from = @in.zero? ? 0 : @offset - @outset + 1
25
- @to = @offset - @outset + @in
26
- @prev = (@page - 1 unless @page == 1)
27
- @next = @page == @last ? (1 if @vars[:cycle]) : @page + 1
28
- self
29
- end
30
-
31
- # Override the original series.
32
- # Return nil if :countless_minimal is enabled
33
- def series(*, **)
34
- super unless @vars[:countless_minimal]
35
- end
36
- end
37
- end
@@ -1,25 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class Pagy
4
- # Generic variable error
5
- class VariableError < ArgumentError
6
- attr_reader :pagy, :variable, :value
7
-
8
- # Set the variables and prepare the message
9
- def initialize(pagy, variable, description, value)
10
- @pagy = pagy
11
- @variable = variable
12
- @value = value
13
- super("expected :#{@variable} #{description}; got #{@value.inspect}")
14
- end
15
- end
16
-
17
- # Specific overflow error
18
- class OverflowError < VariableError; end
19
-
20
- # I18n configuration error
21
- class I18nError < StandardError; end
22
-
23
- # Generic internal error
24
- class InternalError < StandardError; end
25
- end
@@ -1,36 +0,0 @@
1
- # See the Pagy documentation: https://ddnexus.github.io/pagy/docs/extras/arel
2
- # frozen_string_literal: true
3
-
4
- class Pagy # :nodoc:
5
- # Better performance of grouped ActiveRecord collections
6
- module ArelExtra
7
- private
8
-
9
- # Return Pagy object and paginated collection/results
10
- def pagy_arel(collection, vars = {})
11
- pagy = Pagy.new(pagy_arel_get_vars(collection, vars))
12
- [pagy, pagy_get_items(collection, pagy)]
13
- end
14
-
15
- # Sub-method called only by #pagy_arel: here for easy customization of variables by overriding
16
- def pagy_arel_get_vars(collection, vars)
17
- pagy_set_items_from_params(vars) if defined?(ItemsExtra)
18
- vars[:count] ||= pagy_arel_count(collection)
19
- vars[:page] ||= params[vars[:page_param] || DEFAULT[:page_param]]
20
- vars
21
- end
22
-
23
- # Count using Arel when grouping
24
- def pagy_arel_count(collection)
25
- if collection.group_values.empty?
26
- # COUNT(*)
27
- collection.count(:all)
28
- else
29
- # COUNT(*) OVER ()
30
- sql = Arel.star.count.over(Arel::Nodes::Grouping.new([]))
31
- collection.unscope(:order).limit(1).pluck(sql).first.to_i
32
- end
33
- end
34
- end
35
- Backend.prepend ArelExtra
36
- end
@@ -1,24 +0,0 @@
1
- # See the Pagy documentation: https://ddnexus.github.io/pagy/docs/extras/array
2
- # frozen_string_literal: true
3
-
4
- class Pagy # :nodoc:
5
- # Paginate arrays efficiently, avoiding expensive array-wrapping and without overriding
6
- module ArrayExtra
7
- private
8
-
9
- # Return Pagy object and paginated items
10
- def pagy_array(array, vars = {})
11
- pagy = Pagy.new(pagy_array_get_vars(array, vars))
12
- [pagy, array[pagy.offset, pagy.items]]
13
- end
14
-
15
- # Sub-method called only by #pagy_array: here for easy customization of variables by overriding
16
- def pagy_array_get_vars(array, vars)
17
- pagy_set_items_from_params(vars) if defined?(ItemsExtra)
18
- vars[:count] ||= array.size
19
- vars[:page] ||= params[vars[:page_param] || DEFAULT[:page_param]]
20
- vars
21
- end
22
- end
23
- Backend.prepend ArrayExtra
24
- end
@@ -1,108 +0,0 @@
1
- # See the Pagy documentation: https://ddnexus.github.io/pagy/docs/extras/bootstrap
2
- # frozen_string_literal: true
3
-
4
- require 'pagy/extras/frontend_helpers'
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, pagy_id: nil, link_extra: '',
12
- nav_aria_label: nil, nav_i18n_key: nil, **vars)
13
- p_id = %( id="#{pagy_id}") if pagy_id
14
- link = pagy_link_proc(pagy, link_extra: %(class="page-link" #{link_extra}))
15
-
16
- html = +%(<nav#{p_id} class="pagy-bootstrap-nav" #{
17
- nav_aria_label_attr(pagy, nav_aria_label, nav_i18n_key)}><ul class="pagination">)
18
- html << bootstrap_prev_html(pagy, link)
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 class="page-item">#{link.call(item)}</li>)
23
- when String
24
- %(<li class="page-item active"><a role="link" class="page-link" aria-current="page" aria-disabled="true">#{
25
- pagy.label_for(item)}</a></li>)
26
- when :gap
27
- %(<li class="page-item gap disabled"><a role="link" class="page-link" aria-disabled="true">#{
28
- pagy_t 'pagy.gap'}</a></li>)
29
- else raise InternalError, "expected item types in series to be Integer, String or :gap; got #{item.inspect}"
30
- end
31
- end
32
- html << bootstrap_next_html(pagy, link)
33
- html << %(</ul></nav>)
34
- end
35
-
36
- # Javascript pagination for bootstrap: it returns a nav and a JSON tag used by the pagy.js file
37
- def pagy_bootstrap_nav_js(pagy, pagy_id: nil, link_extra: '',
38
- nav_aria_label: nil, nav_i18n_key: nil, **vars)
39
- sequels = pagy.sequels(**vars)
40
- p_id = %( id="#{pagy_id}") if pagy_id
41
- link = pagy_link_proc(pagy, link_extra: %(class="page-link" #{link_extra}))
42
- tags = { 'before' => %(<ul class="pagination">#{bootstrap_prev_html pagy, link}),
43
- 'link' => %(<li class="page-item">#{link.call(PAGE_TOKEN, LABEL_TOKEN)}</li>),
44
- 'active' => %(<li class="page-item active"><a role="link" class="page-link" ) +
45
- %(aria-current="page" aria-disabled="true">#{LABEL_TOKEN}</a></li>),
46
- 'gap' => %(<li class="page-item gap disabled"><a role="link" class="page-link" aria-disabled="true">#{
47
- pagy_t 'pagy.gap'}</a></li>),
48
- 'after' => %(#{bootstrap_next_html pagy, link}</ul>) }
49
-
50
- %(<nav#{p_id} class="#{'pagy-rjs ' if sequels.size > 1}pagy-bootstrap-nav-js" #{
51
- nav_aria_label_attr(pagy, nav_aria_label, nav_i18n_key)} #{
52
- pagy_data(pagy, :nav, tags, sequels, pagy.label_sequels(sequels))
53
- }></nav>)
54
- end
55
-
56
- # Javascript combo pagination for bootstrap: it returns a nav and a JSON tag used by the pagy.js file
57
- def pagy_bootstrap_combo_nav_js(pagy, pagy_id: nil, link_extra: '',
58
- nav_aria_label: nil, nav_i18n_key: nil)
59
- p_id = %( id="#{pagy_id}") if pagy_id
60
- link = pagy_link_proc(pagy, link_extra:)
61
- p_page = pagy.page
62
- p_pages = pagy.pages
63
- input = %(<input name="page" type="number" min="1" max="#{p_pages}" value="#{
64
- p_page}" style="padding: 0; border: none; text-align: center; width: #{
65
- p_pages.to_s.length + 1}rem;" aria-current="page">)
66
-
67
- %(<nav#{p_id} class="pagy-bootstrap-combo-nav-js pagination" #{
68
- nav_aria_label_attr(pagy, nav_aria_label, nav_i18n_key)} #{
69
- pagy_data(pagy, :combo, pagy_url_for(pagy, PAGE_TOKEN)) }><div class="btn-group" role="group">#{
70
- if (p_prev = pagy.prev)
71
- link.call(p_prev, pagy_t('pagy.prev'), %(class="prev btn btn-primary" #{prev_aria_label_attr}))
72
- else
73
- %(<a role="link" class="prev btn btn-primary disabled" aria-disabled="true" #{
74
- prev_aria_label_attr}>#{pagy_t('pagy.prev')}</a>)
75
- end
76
- }<div class="pagy-combo-input btn btn-secondary" style="white-space: nowrap;">#{
77
- pagy_t 'pagy.combo_nav_js', page_input: input, count: p_page, pages: p_pages}</div>#{
78
- if (p_next = pagy.next)
79
- link.call(p_next, pagy_t('pagy.next'), %(class="next btn btn-primary" #{next_aria_label_attr}))
80
- else
81
- %(<a role="link" class="next btn btn-primary disabled" aria-disabled="true" #{
82
- next_aria_label_attr}>#{pagy_t 'pagy.next'}</a>)
83
- end
84
- }</div></nav>)
85
- end
86
-
87
- private
88
-
89
- def bootstrap_prev_html(pagy, link)
90
- if (p_prev = pagy.prev)
91
- %(<li class="page-item prev">#{link.call(p_prev, pagy_t('pagy.prev'), prev_aria_label_attr)}</li>)
92
- else
93
- %(<li class="page-item prev disabled"><a role="link" class="page-link" aria-disabled="true" #{
94
- prev_aria_label_attr}>#{pagy_t('pagy.prev')}</a></li>)
95
- end
96
- end
97
-
98
- def bootstrap_next_html(pagy, link)
99
- if (p_next = pagy.next)
100
- %(<li class="page-item next">#{link.call p_next, pagy_t('pagy.next'), next_aria_label_attr}</li>)
101
- else
102
- %(<li class="page-item next disabled"><a role="link" class="page-link" aria-disabled="true" #{
103
- next_aria_label_attr}>#{pagy_t('pagy.next')}</a></li>)
104
- end
105
- end
106
- end
107
- Frontend.prepend BootstrapExtra
108
- end
@@ -1,105 +0,0 @@
1
- # See the Pagy documentation: https://ddnexus.github.io/pagy/docs/extras/bulma
2
- # frozen_string_literal: true
3
-
4
- require 'pagy/extras/frontend_helpers'
5
-
6
- class Pagy # :nodoc:
7
- DEFAULT[:bulma_nav_classes] = 'is-centered'
8
-
9
- # Frontend modules are specially optimized for performance.
10
- # The resulting code may not look very elegant, but produces the best benchmarks
11
- module BulmaExtra
12
- # Pagination for bulma: it returns the html with the series of links to the pages
13
- def pagy_bulma_nav(pagy, pagy_id: nil, link_extra: '',
14
- nav_aria_label: nil, nav_i18n_key: nil, **vars)
15
- p_id = %( id="#{pagy_id}") if pagy_id
16
- link = pagy_link_proc(pagy, link_extra:)
17
-
18
- html = +%(<nav#{p_id} class="pagy-bulma-nav pagination #{DEFAULT[:bulma_nav_classes]}" #{
19
- nav_aria_label_attr(pagy, nav_aria_label, nav_i18n_key)}>)
20
- html << bulma_prev_next_html(pagy, link)
21
- html << %(<ul class="pagination-list">)
22
- pagy.series(**vars).each do |item| # series example: [1, :gap, 7, 8, "9", 10, 11, :gap, 36]
23
- html << case item
24
- when Integer
25
- %(<li>#{link.call(item, pagy.label_for(item), %(class="pagination-link"))}</li>)
26
- when String
27
- %(<li><a role="link" class="pagination-link is-current" aria-current="page" aria-disabled="true">#{
28
- pagy.label_for(item)}</a></li>)
29
- when :gap
30
- %(<li><span class="pagination-ellipsis">#{pagy_t 'pagy.gap'}</span></li>)
31
- else raise InternalError, "expected item types in series to be Integer, String or :gap; got #{item.inspect}"
32
- end
33
- end
34
- html << %(</ul></nav>)
35
- end
36
-
37
- # Javascript pagination for bulma: it returns a nav and a JSON tag used by the Pagy.nav javascript
38
- def pagy_bulma_nav_js(pagy, pagy_id: nil, link_extra: '',
39
- nav_aria_label: nil, nav_i18n_key: nil, **vars)
40
- sequels = pagy.sequels(**vars)
41
- p_id = %( id="#{pagy_id}") if pagy_id
42
- link = pagy_link_proc(pagy, link_extra:)
43
- tags = { 'before' => %(#{bulma_prev_next_html(pagy, link)}<ul class="pagination-list">),
44
- 'link' => %(<li>#{link.call(PAGE_TOKEN, LABEL_TOKEN, %(class="pagination-link"))}</li>),
45
- 'active' => %(<li><a role="link" class="pagination-link is-current" aria-current="page" aria-disabled="true">#{
46
- LABEL_TOKEN}</a></li>),
47
- 'gap' => %(<li><span class="pagination-ellipsis">#{pagy_t 'pagy.gap'}</span></li>),
48
- 'after' => '</ul>' }
49
-
50
- %(<nav#{p_id} class="#{'pagy-rjs ' if sequels.size > 1}pagy-bulma-nav-js pagination #{DEFAULT[:bulma_nav_classes]}" #{
51
- nav_aria_label_attr(pagy, nav_aria_label, nav_i18n_key)}#{
52
- pagy_data(pagy, :nav, tags, sequels, pagy.label_sequels(sequels))}></nav>)
53
- end
54
-
55
- # Javascript combo pagination for bulma: it returns a nav and a JSON tag used by the pagy.js file
56
- def pagy_bulma_combo_nav_js(pagy, pagy_id: nil, link_extra: '',
57
- nav_aria_label: nil, nav_i18n_key: nil)
58
- p_id = %( id="#{pagy_id}") if pagy_id
59
- link = pagy_link_proc(pagy, link_extra:)
60
- p_page = pagy.page
61
- p_pages = pagy.pages
62
- input = %(<input name="page" class="input" type="number" min="1" max="#{p_pages}" value="#{
63
- p_page}" style="padding: 0; text-align: center; width: #{
64
- p_pages.to_s.length + 1}rem; margin:0 0.3rem;" aria-current="page">)
65
-
66
- html = %(<nav#{p_id} class="pagy-bulma-combo-nav-js #{DEFAULT[:bulma_nav_classes]}" #{
67
- nav_aria_label_attr(pagy, nav_aria_label, nav_i18n_key)} #{
68
- pagy_data(pagy, :combo, pagy_url_for(pagy, PAGE_TOKEN))}>)
69
- %(#{html}<div class="field is-grouped is-grouped-centered" role="group">#{
70
- if (p_prev = pagy.prev)
71
- %(<p class="control">#{link.call(p_prev, pagy_t('pagy.prev'), %(class="button" #{prev_aria_label_attr}))}</p>)
72
- else
73
- %(<p class="control"><a role="link" class="button" disabled aria-disabled="true" #{
74
- prev_aria_label_attr}>#{pagy_t 'pagy.prev'}</a></p>)
75
- end
76
- }<div class="pagy-combo-input control level is-mobile">#{
77
- pagy_t 'pagy.combo_nav_js', page_input: input, count: p_page, pages: p_pages}</div>#{
78
- if (p_next = pagy.next)
79
- %(<p class="control">#{link.call(p_next, pagy_t('pagy.next'), %(class="button" #{next_aria_label_attr}))}</p>)
80
- else
81
- %(<p class="control"><a role="link" class="button" disabled aria-disabled="true"#{
82
- next_aria_label_attr}>#{pagy_t 'pagy.next'}</a></p>)
83
- end
84
- }</div></nav>)
85
- end
86
-
87
- private
88
-
89
- def bulma_prev_next_html(pagy, link)
90
- html = +if (p_prev = pagy.prev)
91
- link.call(p_prev, pagy_t('pagy.prev'), %(#{prev_aria_label_attr} class="pagination-previous"))
92
- else
93
- %(<a role="link" class="pagination-previous" disabled aria-disabled="true" #{
94
- prev_aria_label_attr}>#{pagy_t 'pagy.prev'}</a>)
95
- end
96
- html << if (p_next = pagy.next)
97
- link.call(p_next, pagy_t('pagy.next'), %(#{next_aria_label_attr} class="pagination-next"))
98
- else
99
- %(<a role="link" class="pagination-next" disabled aria-disabled="true" #{
100
- next_aria_label_attr}>#{pagy_t('pagy.next')}</a>)
101
- end
102
- end
103
- end
104
- Frontend.prepend BulmaExtra
105
- end
@@ -1,53 +0,0 @@
1
- # See the Pagy documentation: https://ddnexus.github.io/pagy/docs/extras/calendar
2
- # frozen_string_literal: true
3
-
4
- require 'pagy/calendar'
5
- require 'pagy/calendar/helper'
6
-
7
- class Pagy # :nodoc:
8
- # Add pagination filtering by calendar unit (:year, :quarter, :month, :week, :day) to the regular pagination
9
- module CalendarExtra
10
- # Additions for the Backend module
11
- module BackendAddOn
12
- CONF_KEYS = (Calendar::UNITS + %i[pagy active]).freeze
13
-
14
- private
15
-
16
- # Take a collection and a conf Hash with keys in CONF_KEYS and return an array with 3 items: [calendar, pagy, results]
17
- def pagy_calendar(collection, conf)
18
- raise ArgumentError, "keys must be in #{CONF_KEYS.inspect}" \
19
- unless conf.is_a?(Hash) && (conf.keys - CONF_KEYS).empty?
20
-
21
- conf[:pagy] ||= {}
22
- unless conf.key?(:active) && !conf[:active]
23
- calendar, from, to = Calendar::Helper.send(:init, conf, pagy_calendar_period(collection), params)
24
- collection = pagy_calendar_filter(collection, from, to)
25
- end
26
- pagy, results = send(conf[:pagy][:backend] || :pagy, collection, conf[:pagy]) # use backend: :pagy when omitted
27
- [calendar, pagy, results]
28
- end
29
-
30
- # This method must be implemented by the application
31
- def pagy_calendar_period(*)
32
- raise NoMethodError, 'the pagy_calendar_period method must be implemented by the application ' \
33
- '(see https://ddnexus.github.io/pagy/docs/extras/calendar/#pagy-calendar-period-collection)'
34
- end
35
-
36
- # This method must be implemented by the application
37
- def pagy_calendar_filter(*)
38
- raise NoMethodError, 'the pagy_calendar_filter method must be implemented by the application ' \
39
- '(see https://ddnexus.github.io/pagy/docs/extras/calendar/#pagy-calendar-filter-collection-from-to)'
40
- end
41
- end
42
-
43
- # Additions for the Frontend module
44
- module UrlHelperAddOn
45
- # Return the url for the calendar page at time
46
- def pagy_calendar_url_at(calendar, time, **opts)
47
- pagy_url_for(calendar.send(:calendar_at, time, **opts), 1, **opts)
48
- end
49
- end
50
- end
51
- Backend.prepend CalendarExtra::BackendAddOn, CalendarExtra::UrlHelperAddOn
52
- Frontend.prepend CalendarExtra::UrlHelperAddOn
53
- end
@@ -1,37 +0,0 @@
1
- # See the Pagy documentation: https://ddnexus.github.io/pagy/docs/extras/countless
2
- # frozen_string_literal: true
3
-
4
- require 'pagy/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 items
14
- def pagy_countless(collection, vars = {})
15
- pagy = Countless.new(pagy_countless_get_vars(collection, vars))
16
- [pagy, pagy_countless_get_items(collection, pagy)]
17
- end
18
-
19
- # Sub-method called only by #pagy_countless: here for easy customization of variables by overriding
20
- def pagy_countless_get_vars(_collection, vars)
21
- pagy_set_items_from_params(vars) if defined?(ItemsExtra)
22
- vars[:page] ||= params[vars[:page_param] || DEFAULT[:page_param]]
23
- vars
24
- end
25
-
26
- # Sub-method called only by #pagy_countless: here for easy customization of record-extraction by overriding
27
- # You may need to override this method for collections without offset|limit
28
- def pagy_countless_get_items(collection, pagy)
29
- return collection.offset(pagy.offset).limit(pagy.items) if pagy.vars[:countless_minimal]
30
-
31
- fetched = collection.offset(pagy.offset).limit(pagy.items + 1).to_a # eager load items + 1
32
- pagy.finalize(fetched.size) # finalize the pagy object
33
- fetched[0, pagy.items] # ignore eventual extra item
34
- end
35
- end
36
- Backend.prepend CountlessExtra
37
- end