pagy 5.3.1 → 5.4.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e3530b69891d7c069acdb707d6fa54e8b5d31763a80e57dae2e0fe3afafce8b2
4
- data.tar.gz: defdc75e9f60ae351e8b071fffd3bf4767e28d51edd8ec6398a1b5958d688084
3
+ metadata.gz: 32d028f5c02fafb87cc0bb10f1b28ebf1f49b89babf4cfcf2099367b69cf88af
4
+ data.tar.gz: c5cf934095bfaed81c66afab017340855b8d7dcc1af5cc80c620e8fb62c70054
5
5
  SHA512:
6
- metadata.gz: 13dc93a7f0de2f1e4a688292e1901905df218d500fe1543e4d518dab1f1e7f7d2276cc63f197c251b1ed14e8fea4b46d8be4590ccbad89cfed11d70481a769a2
7
- data.tar.gz: f6ddac95479d63445920df9bad22142f59b9b14e2a4c758303c76389eefd1a475ce49dd1e781e70519bed0a081c1b2296bb19be6ca6e50feefa0abb9660749a6
6
+ metadata.gz: 361df59b13de017f9bc99c7d4ed9c2316c265f0f50514fef3623c33f05095dbdbd8eee4be208bb420a3857ca4070dbebd75e6b30c0fc9ae827b1a7563e288aca
7
+ data.tar.gz: ba1ca8e50d010dea86cd05d65969f1815d9056e845dd0f23a17a78df6e59d7692619ae4c6899fd356bf14a8d0a5ff9dbd9ffb8ab545bad3653a10e8de0662823
data/lib/config/pagy.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Pagy initializer file (5.3.1)
3
+ # Pagy initializer file (5.4.0)
4
4
  # Customize only what you really need and notice that Pagy works also without any of the following lines.
5
5
  # Should you just cherry pick part of this file, please maintain the require-order of the extras
6
6
 
@@ -43,14 +43,12 @@
43
43
  # Calendar extra: Paginate a collection by calendar Time unit (year, month, week or day)
44
44
  # See https://ddnexus.github.io/pagy/extras/calendar
45
45
  # require 'pagy/extras/calendar'
46
- # Pagy::DEFAULT[:local_minmax] = [] # Min and max local Time period must be set by the user (better not not as default)
47
- # Pagy::DEFAULT[:unit] = :month # Time unit allowed %i[year month week day]
48
- # Pagy::DEFAULT[:week_offset] = 0 # Day offset from Sunday (0: Sunday; 1: Monday;... 6: Saturday)
49
- # Pagy::DEFAULT[:order] = :asc # Time direction of pagination
50
- # Pagy::DEFAULT[:year_format] = '%Y' # strftime format for :year unit
51
- # Pagy::DEFAULT[:month_format] = '%Y-%m' # strftime format for :month unit
52
- # Pagy::DEFAULT[:week_format] = '%Y-%W' # strftime format for :week unit
53
- # Pagy::DEFAULT[:day_format] = '%Y-%m-%d' # strftime format for :day unit
46
+ # DEFAULT[:year_format] = '%Y' # strftime format for :year unit
47
+ # DEFAULT[:month_format] = '%Y-%m' # strftime format for :month unit
48
+ # DEFAULT[:week_format] = '%Y-%W' # strftime format for :week unit
49
+ # DEFAULT[:day_format] = '%Y-%m-%d' # strftime format for :day unit
50
+ # DEFAULT[:week_offset] = 0 # Day offset from Sunday (0: Sunday; 1: Monday;... 6: Saturday)
51
+ # DEFAULT[:time_order] = :asc # Time direction of pagination
54
52
 
55
53
  # Countless extra: Paginate without any count, saving one query per rendering
56
54
  # See https://ddnexus.github.io/pagy/extras/countless
@@ -5,7 +5,7 @@
5
5
  // Container of the whole pagy stuff
6
6
  function Pagy(){}
7
7
 
8
- Pagy.version = '5.3.1'
8
+ Pagy.version = '5.4.0'
9
9
 
10
10
  // Used by the waitForMe function
11
11
  Pagy.delay = 100
data/lib/pagy/calendar.rb CHANGED
@@ -5,24 +5,33 @@ require 'pagy'
5
5
  require 'date'
6
6
 
7
7
  class Pagy # :nodoc:
8
- DEFAULT[:local_minmax] = [] # Min and max Time period must be set by the user
9
- DEFAULT[:unit] = :month # Time unit allowed %i[year month week day]
10
- DEFAULT[:week_offset] = 0 # Day offset from Sunday (0: Sunday; 1: Monday;... 6: Saturday)
11
- DEFAULT[:order] = :asc # Time direction of pagination
12
8
  DEFAULT[:year_format] = '%Y' # strftime format for :year unit
13
9
  DEFAULT[:month_format] = '%Y-%m' # strftime format for :month unit
14
10
  DEFAULT[:week_format] = '%Y-%W' # strftime format for :week unit
15
11
  DEFAULT[:day_format] = '%Y-%m-%d' # strftime format for :day unit
12
+ DEFAULT[:week_offset] = 0 # Day offset from Sunday (0: Sunday; 1: Monday;... 6: Saturday)
13
+ DEFAULT[:time_order] = :asc # Time direction of pagination
16
14
 
17
- # Paginate a Time period by units (year, month, week or day)
15
+ # Base class for time units subclasses (Year, Month, Week, Day)
18
16
  class Calendar < Pagy
19
- attr_reader :utc_from, :utc_to, :unit, :week_offset, :order
20
- attr_writer :count, :in
17
+ DAY = 60 * 60 * 24
18
+ WEEK = DAY * 7
19
+
20
+ attr_reader :utc_from, :utc_to, :time_order
21
+
22
+ # Create a subclass instance
23
+ def self.create(unit, vars)
24
+ raise InternalError, "unit must be in #{UNITS.keys.inspect}; got #{unit}" unless UNITS.key?(unit)
25
+
26
+ UNITS[unit].new(vars)
27
+ end
21
28
 
22
29
  # Merge and validate the options, do some simple arithmetic and set a few instance variables
23
30
  def initialize(vars) # rubocop:disable Lint/MissingSuper
31
+ raise InternalError, 'Pagy::Calendar is a base class; use one of its subclasses.' if instance_of?(Pagy::Calendar)
32
+
24
33
  normalize_vars(vars)
25
- setup_vars(page: 1, week_offset: 0)
34
+ setup_vars(page: 1)
26
35
  setup_unit_vars
27
36
  setup_params_var
28
37
  raise OverflowError.new(self, :page, "in 1..#{@last}", @page) if @page > @last
@@ -31,129 +40,148 @@ class Pagy # :nodoc:
31
40
  @next = @page == @last ? (1 if @vars[:cycle]) : @page + 1
32
41
  end
33
42
 
34
- # Generate a label for each page, with the specific `Time` period it refers to
35
- # (it can pass along the I18n gem opts when it's used with the i18n extra)
36
- def label_for(page, **opts)
37
- snap = snap(page.to_i)
38
- time = case @unit
39
- when :year then new_time(@initial.year + snap)
40
- when :month then bump_month(@initial, snap)
41
- when :week then @initial + (snap * WEEK)
42
- when :day then @initial + (snap * DAY)
43
- else raise InternalError, "expected @unit to be in [:year, :month, :week, :day]; got #{@unit.inspect}"
44
- end
45
- opts[:format] ||= @vars[:"#{@unit}_format"]
46
- localize(time, **opts)
47
- end
48
-
49
- # The label for the current page
50
- # (it can pass along the I18n gem opts when it's used with the i18n extra)
43
+ # The label for the current page (it can pass along the I18n gem opts when it's used with the i18n extra)
51
44
  def label(**opts)
52
45
  label_for(@page, **opts)
53
46
  end
54
47
 
55
- DAY = 60 * 60 * 24
56
- WEEK = DAY * 7
48
+ # Return the minmax of the current page/unit (used by the extra for the next level minmax)
49
+ def current_unit_minmax
50
+ [@utc_from.getlocal(@utc_offset), @utc_to.getlocal(@utc_offset)]
51
+ end
57
52
 
58
53
  protected
59
54
 
60
- def setup_unit_vars
61
- (units = %i[year month week day]).each do |unit|
62
- raise VariableError.new(self, :format, 'to be a strftime format', @vars[:"#{unit}_format"]) \
63
- unless @vars[:"#{unit}_format"].is_a?(String)
64
- end
65
- raise VariableError.new(self, :unit, "to be in #{units.inspect}", @unit) \
66
- unless units.include?(@unit = @vars[:unit])
67
- raise VariableError.new(self, :order, 'to be in [:asc, :desc]', @order) \
68
- unless %i[asc desc].include?(@order = @vars[:order])
55
+ def setup_unit_vars(format)
56
+ raise VariableError.new(self, format, 'to be a strftime format', @vars[format]) unless @vars[format].is_a?(String)
57
+ raise VariableError.new(self, :time_order, 'to be in [:asc, :desc]', @time_order) \
58
+ unless %i[asc desc].include?(@time_order = @vars[:time_order])
69
59
 
70
- min, max = @vars[:local_minmax]
71
- raise VariableError.new(self, :local_minmax, 'to be a an Array of min and max local Time instances', @vars[:local_minmax]) \
60
+ min, max = @vars[:minmax]
61
+ raise VariableError.new(self, :minmax, 'to be a an Array of min and max local Time instances', @vars[:minmax]) \
72
62
  unless min.is_a?(Time) && max.is_a?(Time) && !min.utc? && !max.utc? && min <= max \
73
63
  && (@utc_offset = min.utc_offset) == max.utc_offset
74
64
 
75
- send :"setup_#{@unit}_vars", min, max
65
+ [min, max]
76
66
  end
77
67
 
78
- # IMPORTANT: all the Time objects created and passed as arguments MUST be local!
79
-
80
- # @initial: beginning of the first day of the period that encloses the min local time
81
- # @final: beginning of the first day of the NEXT period AFTER the period that encloses the max local time
82
- # @utc_from: beginning of the first day of the period of the current page as UTC time
83
- # @utc_to: beginning of the first day of the NEXT period AFTER the current page as UTC time
84
-
85
- # Setup the calendar vars when the unit is :year
86
- def setup_year_vars(min, max)
87
- @initial = new_time(min.year)
88
- @final = new_time(max.year + 1)
89
- @pages = @last = @final.year - @initial.year
90
- @utc_from = new_time(@initial.year + snap).utc
91
- @utc_to = new_time(@initial.year + snap + 1).utc
68
+ # Apply the strftime format to the time (overridden by the i18n extra when localization is required)
69
+ def localize(time, opts)
70
+ time.strftime(opts[:format])
92
71
  end
93
72
 
94
- # Setup the calendar vars when the unit is :month
95
- def setup_month_vars(min, max)
96
- @initial = new_time(min.year, min.month)
97
- @final = bump_month(max)
98
- @pages = @last = months(@final) - months(@initial)
99
- @utc_from = bump_month(@initial, snap).utc
100
- @utc_to = bump_month(@initial, snap + 1).utc
73
+ # Simple trick to snap the page into its ordered position, without actually reordering anything in the internal structure
74
+ def snap(page = @page)
75
+ @time_order == :asc ? page - 1 : @pages - page
101
76
  end
102
77
 
103
- # Setup the calendar vars when the unit is :week
104
- def setup_week_vars(min, max)
105
- @initial = week_start(min)
106
- @final = week_start(max) + WEEK
107
- @pages = @last = (@final - @initial).to_i / WEEK
108
- @utc_from = (@initial + (snap * WEEK)).utc
109
- @utc_to = @utc_from + WEEK
78
+ # Create a new local time at the beginning of the day
79
+ def new_time(year, month = 1, day = 1)
80
+ Time.new(year, month, day, 0, 0, 0, @utc_offset)
110
81
  end
111
82
 
112
- # Setup the calendar vars when the unit is :day
113
- def setup_day_vars(min, max)
114
- @initial = new_time(min.year, min.month, min.day)
115
- @final = new_time(max.year, max.month, max.day) + DAY
116
- @pages = @last = (@final - @initial).to_i / DAY
117
- @utc_from = (@initial + (snap * DAY)).utc
118
- @utc_to = @utc_from + DAY
119
- end
83
+ # Calendar year subclass
84
+ class Year < Calendar
85
+ # Setup the calendar vars when the unit is :year
86
+ def setup_unit_vars
87
+ min, max = super(:year_format)
88
+ @initial = new_time(min.year)
89
+ @final = new_time(max.year + 1)
90
+ @pages = @last = @final.year - @initial.year
91
+ @utc_from = new_time(@initial.year + snap).utc
92
+ @utc_to = new_time(@initial.year + snap + 1).utc
93
+ end
120
94
 
121
- # Apply the strftime format to the time
122
- # (overridden by the i18n extra when localization is required)
123
- def localize(time, **opts)
124
- time.strftime(opts[:format])
95
+ # Generate a label for each page (it can pass along the I18n gem opts when it's used with the i18n extra)
96
+ def label_for(page, **opts)
97
+ opts[:format] ||= @vars[:year_format]
98
+ localize(new_time(@initial.year + snap(page.to_i)), **opts)
99
+ end
125
100
  end
126
101
 
127
- private
102
+ # Calendar month subclass
103
+ class Month < Calendar
104
+ # Setup the calendar vars when the unit is :month
105
+ def setup_unit_vars
106
+ min, max = super(:month_format)
107
+ @initial = new_time(min.year, min.month)
108
+ @final = bump_month(max)
109
+ @pages = @last = months(@final) - months(@initial)
110
+ @utc_from = bump_month(@initial, snap).utc
111
+ @utc_to = bump_month(@initial, snap + 1).utc
112
+ end
128
113
 
129
- # Simple trick to snap the page into its ordered position,
130
- # without actually reordering anything in the internal structure
131
- def snap(page = @page)
132
- @order == :asc ? page - 1 : @pages - page
133
- end
114
+ # Generate a label for each page (it can pass along the I18n gem opts when it's used with the i18n extra)
115
+ def label_for(page, **opts)
116
+ opts[:format] ||= @vars[:month_format]
117
+ localize(bump_month(@initial, snap(page.to_i)), **opts)
118
+ end
134
119
 
135
- # Create a new local time at the beginning of the day
136
- def new_time(year, month = 1, day = 1)
137
- Time.new(year, month, day, 0, 0, 0, @utc_offset)
138
- end
120
+ private
139
121
 
140
- # Months in local time
141
- def months(time)
142
- (time.year * 12) + time.month
122
+ # Months in local time
123
+ def months(time)
124
+ (time.year * 12) + time.month
125
+ end
126
+
127
+ # Add 1 or more months to local time
128
+ def bump_month(time, months = 1)
129
+ months += months(time)
130
+ year = months / 12
131
+ month = months % 12
132
+ month.zero? ? new_time(year - 1, 12) : new_time(year, month)
133
+ end
143
134
  end
144
135
 
145
- # Add 1 or more months to local time
146
- def bump_month(time, months = 1)
147
- months += months(time)
148
- year = months / 12
149
- month = months % 12
150
- month.zero? ? new_time(year - 1, 12) : new_time(year, month)
136
+ # Calendar week subclass
137
+ class Week < Calendar
138
+ attr_reader :week_offset
139
+
140
+ # Setup the calendar vars when the unit is :week
141
+ def setup_unit_vars
142
+ setup_vars(week_offset: 0)
143
+ min, max = super(:week_format)
144
+ @initial = week_start(min)
145
+ @final = week_start(max) + WEEK
146
+ @pages = @last = (@final - @initial).to_i / WEEK
147
+ @utc_from = (@initial + (snap * WEEK)).utc
148
+ @utc_to = @utc_from + WEEK
149
+ end
150
+
151
+ # Generate a label for each page (it can pass along the I18n gem opts when it's used with the i18n extra)
152
+ def label_for(page, **opts)
153
+ opts[:format] ||= @vars[:week_format]
154
+ localize(@initial + (snap(page.to_i) * WEEK), **opts)
155
+ end
156
+
157
+ private
158
+
159
+ # Return the start of the week for local time
160
+ def week_start(time)
161
+ start = time - (((time.wday - @week_offset) * DAY) % WEEK)
162
+ new_time(start.year, start.month, start.day)
163
+ end
151
164
  end
152
165
 
153
- # Return the start of the week for local time
154
- def week_start(time)
155
- start = time - (((time.wday - @week_offset) * DAY) % WEEK)
156
- new_time(start.year, start.month, start.day)
166
+ # Calendar day subclass
167
+ class Day < Calendar
168
+ # Setup the calendar vars when the unit is :day
169
+ def setup_unit_vars
170
+ min, max = super(:day_format)
171
+ @initial = new_time(min.year, min.month, min.day)
172
+ @final = new_time(max.year, max.month, max.day) + DAY
173
+ @pages = @last = (@final - @initial).to_i / DAY
174
+ @utc_from = (@initial + (snap * DAY)).utc
175
+ @utc_to = @utc_from + DAY
176
+ end
177
+
178
+ # Generate a label for each page (it can pass along the I18n gem opts when it's used with the i18n extra)
179
+ def label_for(page, **opts)
180
+ opts[:format] ||= @vars[:day_format]
181
+ localize(@initial + (snap(page.to_i) * DAY), **opts)
182
+ end
157
183
  end
184
+ # After all the subclasses are defined
185
+ UNITS = { year: Year, month: Month, week: Week, day: Day }.freeze
158
186
  end
159
187
  end
@@ -30,7 +30,7 @@ class Pagy
30
30
 
31
31
  # Override the original series.
32
32
  # Return nil if :countless_minimal is enabled
33
- def series(_size = @vars[:size])
33
+ def series(*)
34
34
  super unless @vars[:countless_minimal]
35
35
  end
36
36
  end
@@ -8,13 +8,13 @@ class Pagy # :nodoc:
8
8
  # The resulting code may not look very elegant, but produces the best benchmarks
9
9
  module BootstrapExtra
10
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: '')
11
+ def pagy_bootstrap_nav(pagy, pagy_id: nil, link_extra: '', **vars)
12
12
  p_id = %( id="#{pagy_id}") if pagy_id
13
13
  link = pagy_link_proc(pagy, link_extra: %(class="page-link" #{link_extra}))
14
14
 
15
15
  html = +%(<nav#{p_id} class="pagy-bootstrap-nav" aria-label="pager"><ul class="pagination">)
16
16
  html << pagy_bootstrap_prev_html(pagy, link)
17
- pagy.series.each do |item| # series example: [1, :gap, 7, 8, "9", 10, 11, :gap, 36]
17
+ pagy.series(**vars).each do |item| # series example: [1, :gap, 7, 8, "9", 10, 11, :gap, 36]
18
18
  html << case item
19
19
  when Integer
20
20
  %(<li class="page-item">#{link.call item}</li>)
@@ -30,7 +30,7 @@ class Pagy # :nodoc:
30
30
  end
31
31
 
32
32
  # Javascript pagination for bootstrap: it returns a nav and a JSON tag used by the Pagy.nav javascript
33
- def pagy_bootstrap_nav_js(pagy, pagy_id: nil, link_extra: '', steps: nil)
33
+ def pagy_bootstrap_nav_js(pagy, pagy_id: nil, link_extra: '', **vars)
34
34
  p_id = %( id="#{pagy_id}") if pagy_id
35
35
  link = pagy_link_proc(pagy, link_extra: %(class="page-link" #{link_extra}))
36
36
  tags = { 'before' => %(<ul class="pagination">#{pagy_bootstrap_prev_html pagy, link}),
@@ -40,7 +40,7 @@ class Pagy # :nodoc:
40
40
  'after' => %(#{pagy_bootstrap_next_html pagy, link}</ul>) }
41
41
 
42
42
  %(<nav#{p_id} class="pagy-njs pagy-bootstrap-nav-js" aria-label="pager" #{
43
- pagy_json_attr(pagy, :nav, tags, (sequels = pagy.sequels(steps)), pagy.label_sequels(sequels))}></nav>)
43
+ pagy_json_attr(pagy, :nav, tags, (sequels = pagy.sequels(**vars)), pagy.label_sequels(sequels))}></nav>)
44
44
  end
45
45
 
46
46
  # Javascript combo pagination for bootstrap: it returns a nav and a JSON tag used by the Pagy.combo_nav javascript
@@ -8,14 +8,14 @@ class Pagy # :nodoc:
8
8
  # The resulting code may not look very elegant, but produces the best benchmarks
9
9
  module BulmaExtra
10
10
  # Pagination for Bulma: it returns the html with the series of links to the pages
11
- def pagy_bulma_nav(pagy, pagy_id: nil, link_extra: '')
11
+ def pagy_bulma_nav(pagy, pagy_id: nil, link_extra: '', **vars)
12
12
  p_id = %( id="#{pagy_id}") if pagy_id
13
13
  link = pagy_link_proc(pagy, link_extra: link_extra)
14
14
 
15
15
  html = +%(<nav#{p_id} class="pagy-bulma-nav pagination is-centered" aria-label="pagination">)
16
16
  html << pagy_bulma_prev_next_html(pagy, link)
17
17
  html << %(<ul class="pagination-list">)
18
- pagy.series.each do |item| # series example: [1, :gap, 7, 8, "9", 10, 11, :gap, 36]
18
+ pagy.series(**vars).each do |item| # series example: [1, :gap, 7, 8, "9", 10, 11, :gap, 36]
19
19
  html << case item
20
20
  when Integer
21
21
  %(<li>#{link.call item, pagy.label_for(item), %(class="pagination-link" aria-label="goto page #{item}")}</li>)
@@ -30,7 +30,7 @@ class Pagy # :nodoc:
30
30
  html << %(</ul></nav>)
31
31
  end
32
32
 
33
- def pagy_bulma_nav_js(pagy, pagy_id: nil, link_extra: '', steps: nil)
33
+ def pagy_bulma_nav_js(pagy, pagy_id: nil, link_extra: '', **vars)
34
34
  p_id = %( id="#{pagy_id}") if pagy_id
35
35
  link = pagy_link_proc(pagy, link_extra: link_extra)
36
36
  tags = { 'before' => %(#{pagy_bulma_prev_next_html(pagy, link)}<ul class="pagination-list">),
@@ -43,7 +43,7 @@ class Pagy # :nodoc:
43
43
  'after' => '</ul>' }
44
44
 
45
45
  %(<nav#{p_id} class="pagy-njs pagy-bulma-nav-js pagination is-centered" aria-label="pagination" #{
46
- pagy_json_attr(pagy, :nav, tags, (sequels = pagy.sequels(steps)), pagy.label_sequels(sequels))}></nav>)
46
+ pagy_json_attr(pagy, :nav, tags, (sequels = pagy.sequels(**vars)), pagy.label_sequels(sequels))}></nav>)
47
47
  end
48
48
 
49
49
  # Javascript combo pagination for Bulma: it returns a nav and a JSON tag used by the Pagy.combo_nav javascript
@@ -4,32 +4,72 @@
4
4
  require 'pagy/calendar'
5
5
 
6
6
  class Pagy # :nodoc:
7
- # Paginate based on calendar periods (year month week day)
7
+ # Paginate based on calendar periods (year month week day) plus the regular pagination
8
8
  module CalendarExtra
9
9
  # Additions for the Backend module
10
10
  module Backend
11
+ CONF_KEYS = %i[year month week day pagy skip].freeze
12
+
11
13
  private
12
14
 
13
- # Return Pagy object and items
14
- def pagy_calendar(collection, vars = {})
15
- pagy = Calendar.new(pagy_calendar_get_vars(collection, vars))
16
- [pagy, pagy_calendar_get_items(collection, pagy)]
15
+ # Take a collection and a conf Hash with keys in [:year, :month: week, :day, :pagy] and Hash values of pagy variables
16
+ # Return a hash with 3 items:
17
+ # 0. Array of pagy calendar unit objects
18
+ # 1. Pagy object
19
+ # 2. Array of results
20
+ def pagy_calendar(collection, conf)
21
+ unless conf.is_a?(Hash) && (conf.keys - CONF_KEYS).empty? && conf.all? { |k, v| v.is_a?(Hash) || k == :skip }
22
+ raise ArgumentError, "keys must be in #{CONF_KEYS.inspect} and object values must be Hashes; got #{conf.inspect}"
23
+ end
24
+
25
+ conf[:pagy] = {} unless conf[:pagy] # use default Pagy object when omitted
26
+ calendar, collection = pagy_setup_calendar(collection, conf) unless conf[:skip]
27
+ pagy, result = send(conf[:pagy][:backend] || :pagy, collection, conf[:pagy]) # use backend: :pagy when omitted
28
+ [calendar, pagy, result]
29
+ end
30
+
31
+ # Setup the calendar objects and return them with the filtered collection
32
+ def pagy_setup_calendar(collection, conf)
33
+ units = Calendar::UNITS.keys & conf.keys
34
+ page_param = conf[:pagy][:page_param] || DEFAULT[:page_param]
35
+ units.each do |unit| # set all the :page_param vars for later deletion
36
+ unit_page_param = :"#{unit}_#{page_param}"
37
+ conf[unit][:page_param] = unit_page_param
38
+ conf[unit][:page] = params[unit_page_param]
39
+ end
40
+ calendar = {}
41
+ last_calendar = nil
42
+ last_minmax = minmax = pagy_calendar_minmax(collection)
43
+ units.each_with_index do |unit, index|
44
+ params_to_delete = units[(index + 1), units.size].map { |sub| conf[sub][:page_param] } + [page_param]
45
+ conf[unit][:params] = lambda do |params| # delete page_param from the sub-units
46
+ params_to_delete.each { |p| params.delete(p.to_s) } # except implemented after 2.5
47
+ params
48
+ end
49
+ conf[unit][:minmax] = [[minmax.first, last_minmax.first].max, [minmax.last, last_minmax.last].min]
50
+ calendar[unit] = last_calendar = Calendar.create(unit, conf[unit])
51
+ last_minmax = calendar[unit].current_unit_minmax # set the minmax for the next unit
52
+ end
53
+ filtered = pagy_calendar_filtered(collection, last_calendar.utc_from, last_calendar.utc_to)
54
+ [calendar, filtered]
17
55
  end
18
56
 
19
- # Sub-method called only by #pagy_calendar: here for easy customization of variables by overriding.
20
- # You may want to override it in order to implement the dynamic set of the :minmax variable.
21
- def pagy_calendar_get_vars(_collection, vars)
22
- # vars[:minmax] ||= your_own_method_to_get_the_period_from(collection)
23
- vars[:page] ||= params[vars[:page_param] || DEFAULT[:page_param]]
24
- vars
57
+ # This method must be implemented by the application.
58
+ # It must return an Array with the minimum and maximum Time objects from the collection,
59
+ # converted to the local time of the user
60
+ def pagy_calendar_minmax(*)
61
+ # collection.your_own_method_to_get_the_minmax
62
+ raise NoMethodError, 'the pagy_calendar_minmax method must be implemented by the application and must return ' \
63
+ 'an Array with the minimum and maximum local Time objects of the collection'
25
64
  end
26
65
 
27
- # This method should be implemented in the application and should return the records
28
- # for the unit by selecting the records with Time from pagy.utc_from to pagy.utc_to
29
- def pagy_calendar_get_items(_collection, _pagy)
30
- # collection.your_own_method_to_get_the_items_with(pagy.utc_from, pagy.utc_to)
31
- raise NoMethodError, 'The pagy_calendar_get_items method must be implemented in the application and must return ' \
32
- 'the items for the unit by selecting the records with Time from pagy.utc_from to pagy.utc_to'
66
+ # This method must be implemented by the application.
67
+ # It receives the main collection argument and must return a filtered version of it.
68
+ # The filter logic must be equivalent to {utc_time >= pagy.utc_from && utc_time < pagy.utc_to}
69
+ def pagy_calendar_filtered(*)
70
+ # collection.your_own_method_to_filter_with(pagy.utc_from, pagy.utc_to)
71
+ raise NoMethodError, 'the pagy_calendar_filtered method must be implemented by the application and must return the ' \
72
+ 'collection filtered by a logic equivalent to {utc_time >= pagy.utc_from && utc_time < pagy.utc_to}'
33
73
  end
34
74
  end
35
75
  end
@@ -8,13 +8,13 @@ class Pagy # :nodoc:
8
8
  # The resulting code may not look very elegant, but produces the best benchmarks
9
9
  module FoundationExtra
10
10
  # Pagination for Foundation: it returns the html with the series of links to the pages
11
- def pagy_foundation_nav(pagy, pagy_id: nil, link_extra: '')
11
+ def pagy_foundation_nav(pagy, pagy_id: nil, link_extra: '', **vars)
12
12
  p_id = %( id="#{pagy_id}") if pagy_id
13
13
  link = pagy_link_proc(pagy, link_extra: link_extra)
14
14
 
15
15
  html = +%(<nav#{p_id} class="pagy-foundation-nav" aria-label="Pagination"><ul class="pagination">)
16
16
  html << pagy_foundation_prev_html(pagy, link)
17
- pagy.series.each do |item| # series example: [1, :gap, 7, 8, "9", 10, 11, :gap, 36]
17
+ pagy.series(**vars).each do |item| # series example: [1, :gap, 7, 8, "9", 10, 11, :gap, 36]
18
18
  html << case item
19
19
  when Integer then %(<li>#{link.call item}</li>) # page link
20
20
  when String then %(<li class="current">#{pagy.label_for(item)}</li>) # active page
@@ -27,7 +27,7 @@ class Pagy # :nodoc:
27
27
  end
28
28
 
29
29
  # Javascript pagination for foundation: it returns a nav and a JSON tag used by the Pagy.nav javascript
30
- def pagy_foundation_nav_js(pagy, pagy_id: nil, link_extra: '', steps: nil)
30
+ def pagy_foundation_nav_js(pagy, pagy_id: nil, link_extra: '', **vars)
31
31
  p_id = %( id="#{pagy_id}") if pagy_id
32
32
  link = pagy_link_proc(pagy, link_extra: link_extra)
33
33
  tags = { 'before' => %(<ul class="pagination">#{pagy_foundation_prev_html pagy, link}),
@@ -37,7 +37,7 @@ class Pagy # :nodoc:
37
37
  'after' => %(#{pagy_foundation_next_html pagy, link}</ul>) }
38
38
 
39
39
  %(<nav#{p_id} class="pagy-njs pagy-foundation-nav-js" aria-label="Pagination" #{
40
- pagy_json_attr(pagy, :nav, tags, (sequels = pagy.sequels(steps)), pagy.label_sequels(sequels))}></nav>)
40
+ pagy_json_attr(pagy, :nav, tags, (sequels = pagy.sequels(**vars)), pagy.label_sequels(sequels))}></nav>)
41
41
  end
42
42
 
43
43
  # Javascript combo pagination for Foundation: it returns a nav and a JSON tag used by the Pagy.combo_nav javascript
@@ -18,12 +18,11 @@ class Pagy # :nodoc:
18
18
  # "350" => [1, 2, :gap, 17, 18, 19, "20", 21, 22, 23, :gap, 49, 50],
19
19
  # "550" => [1, 2, 3, :gap, 16, 17, 18, 19, "20", 21, 22, 23, 24, :gap, 48, 49, 50] }
20
20
  # Notice: if :steps is false it will use the single {0 => @vars[:size]} size
21
- def sequels(steps = nil)
22
- steps ||= @vars[:steps] || { 0 => @vars[:size] }
21
+ def sequels(steps: @vars[:steps] || { 0 => @vars[:size] })
23
22
  raise VariableError.new(self, :steps, 'to define the 0 width', steps) unless steps.key?(0)
24
23
 
25
24
  {}.tap do |sequels|
26
- steps.each { |width, size| sequels[width.to_s] = series(size) }
25
+ steps.each { |width, step_size| sequels[width.to_s] = series(size: step_size) }
27
26
  end
28
27
  end
29
28
 
@@ -13,7 +13,7 @@ class Pagy # :nodoc:
13
13
 
14
14
  # Calendar overriding
15
15
  module Calendar
16
- def localize(time, **opts)
16
+ def localize(time, opts)
17
17
  ::I18n.l(time, **opts)
18
18
  end
19
19
  end
@@ -8,13 +8,13 @@ class Pagy # :nodoc:
8
8
  # The resulting code may not look very elegant, but produces the best benchmarks
9
9
  module MaterializeExtra
10
10
  # Pagination for materialize: it returns the html with the series of links to the pages
11
- def pagy_materialize_nav(pagy, pagy_id: nil, link_extra: '')
11
+ def pagy_materialize_nav(pagy, pagy_id: nil, link_extra: '', **vars)
12
12
  p_id = %( id="#{pagy_id}") if pagy_id
13
13
  link = pagy_link_proc(pagy, link_extra: link_extra)
14
14
 
15
15
  html = +%(<div#{p_id} class="pagy-materialize-nav pagination" role="navigation" aria-label="pager"><ul class="pagination">)
16
16
  html << pagy_materialize_prev_html(pagy, link)
17
- pagy.series.each do |item| # series example: [1, :gap, 7, 8, "9", 10, 11, :gap, 36]
17
+ pagy.series(**vars).each do |item| # series example: [1, :gap, 7, 8, "9", 10, 11, :gap, 36]
18
18
  html << case item
19
19
  when Integer then %(<li class="waves-effect">#{link.call item}</li>) # page link
20
20
  when String then %(<li class="active">#{link.call item}</li>) # active page
@@ -27,7 +27,7 @@ class Pagy # :nodoc:
27
27
  end
28
28
 
29
29
  # Javascript pagination for materialize: it returns a nav and a JSON tag used by the Pagy.nav javascript
30
- def pagy_materialize_nav_js(pagy, pagy_id: nil, link_extra: '', steps: nil)
30
+ def pagy_materialize_nav_js(pagy, pagy_id: nil, link_extra: '', **vars)
31
31
  p_id = %( id="#{pagy_id}") if pagy_id
32
32
  link = pagy_link_proc(pagy, link_extra: link_extra)
33
33
 
@@ -38,7 +38,7 @@ class Pagy # :nodoc:
38
38
  'after' => %(#{pagy_materialize_next_html pagy, link}</ul>) }
39
39
 
40
40
  %(<div#{p_id} class="pagy-njs pagy-materialize-nav-js" role="navigation" aria-label="pager" #{
41
- pagy_json_attr(pagy, :nav, tags, (sequels = pagy.sequels(steps)), pagy.label_sequels(sequels))}></div>)
41
+ pagy_json_attr(pagy, :nav, tags, (sequels = pagy.sequels(**vars)), pagy.label_sequels(sequels))}></div>)
42
42
  end
43
43
 
44
44
  # Javascript combo pagination for materialize: it returns a nav and a JSON tag used by the Pagy.combo_nav javascript
@@ -8,7 +8,7 @@ class Pagy # :nodoc:
8
8
  # The resulting code may not look very elegant, but produces the best benchmarks
9
9
  module NavsExtra
10
10
  # Javascript pagination: it returns a nav and a JSON tag used by the Pagy.nav javascript
11
- def pagy_nav_js(pagy, pagy_id: nil, link_extra: '', steps: nil)
11
+ def pagy_nav_js(pagy, pagy_id: nil, link_extra: '', **vars)
12
12
  p_id = %( id="#{pagy_id}") if pagy_id
13
13
  link = pagy_link_proc(pagy, link_extra: link_extra)
14
14
  tags = { 'before' => pagy_nav_prev_html(pagy, link),
@@ -18,7 +18,7 @@ class Pagy # :nodoc:
18
18
  'after' => pagy_nav_next_html(pagy, link) }
19
19
 
20
20
  %(<nav#{p_id} class="pagy-njs pagy-nav-js pagination" aria-label="pager" #{
21
- pagy_json_attr(pagy, :nav, tags, (sequels = pagy.sequels(steps)), pagy.label_sequels(sequels))}></nav>)
21
+ pagy_json_attr(pagy, :nav, tags, (sequels = pagy.sequels(**vars)), pagy.label_sequels(sequels))}></nav>)
22
22
  end
23
23
 
24
24
  # Javascript combo pagination: it returns a nav and a JSON tag used by the Pagy.combo_nav javascript
@@ -15,25 +15,25 @@ class Pagy # :nodoc:
15
15
 
16
16
  # Add rescue clause for different behaviors
17
17
  def initialize(vars)
18
- @overflow ||= false # still true if :last_page re-run the method after an overflow
18
+ @overflow ||= false # still true if :last_page re-run the method after an overflow
19
19
  super
20
20
  rescue OverflowError
21
- @overflow = true # add the overflow flag
21
+ @overflow = true # add the overflow flag
22
22
  case @vars[:overflow]
23
23
  when :exception
24
- raise # same as without the extra
24
+ raise # same as without the extra
25
25
  when :last_page
26
- requested_page = @vars[:page] # save the requested page (even after re-run)
27
- initialize vars.merge!(page: @last) # re-run with the last page
28
- @vars[:page] = requested_page # restore the requested page
26
+ requested_page = @vars[:page] # save the requested page (even after re-run)
27
+ initialize vars.merge!(page: @last) # re-run with the last page
28
+ @vars[:page] = requested_page # restore the requested page
29
29
  when :empty_page
30
- @offset = @items = @from = @to = 0 # vars relative to the actual page
31
- if defined?(Calendar) && is_a?(Calendar) # only for Calendar instances
32
- edge = @order == :asc ? @final : @initial # get the edge of the overflow side (neat, but it would work with any time)
33
- @utc_from = @utc_to = edge.getutc # set both to the edge utc time (a query with >= && < will get no record)
30
+ @offset = @items = @from = @to = 0 # vars relative to the actual page
31
+ if defined?(Calendar) && is_a?(Calendar) # only for Calendar instances
32
+ edge = @time_order == :asc ? @final : @initial # get the edge of the overflow side (neat, but any time would do)
33
+ @utc_from = @utc_to = edge.getutc # set both to the edge utc time (a >=&&< query will get no records)
34
34
  end
35
- @prev = @last # prev relative to the actual page
36
- extend Series # special series for :empty_page
35
+ @prev = @last # prev relative to the actual page
36
+ extend Series # special series for :empty_page
37
37
  else
38
38
  raise VariableError.new(self, :overflow, 'to be in [:last_page, :empty_page, :exception]', @vars[:overflow])
39
39
  end
@@ -41,9 +41,9 @@ class Pagy # :nodoc:
41
41
 
42
42
  # Special series for empty page
43
43
  module Series
44
- def series(size = @vars[:size])
44
+ def series(*)
45
45
  @page = @last # series for last page
46
- super(size).tap do |s| # call original series
46
+ super.tap do |s| # call original series
47
47
  s[s.index(@page.to_s)] = @page # string to integer (i.e. no current page)
48
48
  @page = @vars[:page] # restore the actual page
49
49
  end
@@ -8,13 +8,13 @@ class Pagy # :nodoc:
8
8
  # The resulting code may not look very elegant, but produces the best benchmarks
9
9
  module SemanticExtra
10
10
  # Pagination for semantic: it returns the html with the series of links to the pages
11
- def pagy_semantic_nav(pagy, pagy_id: nil, link_extra: '')
11
+ def pagy_semantic_nav(pagy, pagy_id: nil, link_extra: '', **vars)
12
12
  p_id = %( id="#{pagy_id}") if pagy_id
13
13
  link = pagy_link_proc(pagy, link_extra: %(class="item" #{link_extra}))
14
14
 
15
15
  html = +%(<div#{p_id} class="pagy-semantic-nav ui pagination menu">)
16
16
  html << pagy_semantic_prev_html(pagy, link)
17
- pagy.series.each do |item| # series example: [1, :gap, 7, 8, "9", 10, 11, :gap, 36]
17
+ pagy.series(**vars).each do |item| # series example: [1, :gap, 7, 8, "9", 10, 11, :gap, 36]
18
18
  html << case item
19
19
  when Integer then link.call item
20
20
  when String then %(<a class="item active">#{pagy.label_for(item)}</a>)
@@ -27,7 +27,7 @@ class Pagy # :nodoc:
27
27
  end
28
28
 
29
29
  # Javascript pagination for semantic: it returns a nav and a JSON tag used by the Pagy.nav javascript
30
- def pagy_semantic_nav_js(pagy, pagy_id: nil, link_extra: '', steps: nil)
30
+ def pagy_semantic_nav_js(pagy, pagy_id: nil, link_extra: '', **vars)
31
31
  p_id = %( id="#{pagy_id}") if pagy_id
32
32
  link = pagy_link_proc(pagy, link_extra: %(class="item" #{link_extra}))
33
33
  tags = { 'before' => pagy_semantic_prev_html(pagy, link),
@@ -37,7 +37,7 @@ class Pagy # :nodoc:
37
37
  'after' => pagy_semantic_next_html(pagy, link) }
38
38
 
39
39
  %(<div#{p_id} class="pagy-njs pagy-semantic-nav-js ui pagination menu" role="navigation" #{
40
- pagy_json_attr(pagy, :nav, tags, (sequels = pagy.sequels(steps)), pagy.label_sequels(sequels))}></div>)
40
+ pagy_json_attr(pagy, :nav, tags, (sequels = pagy.sequels(**vars)), pagy.label_sequels(sequels))}></div>)
41
41
  end
42
42
 
43
43
  # Combo pagination for semantic: it returns a nav and a JSON tag used by the Pagy.combo_nav javascript
@@ -8,12 +8,12 @@ class Pagy # :nodoc:
8
8
  # The resulting code may not look very elegant, but produces the best benchmarks
9
9
  module UikitExtra
10
10
  # Pagination for uikit: it returns the html with the series of links to the pages
11
- def pagy_uikit_nav(pagy, pagy_id: nil, link_extra: '')
11
+ def pagy_uikit_nav(pagy, pagy_id: nil, link_extra: '', **vars)
12
12
  p_id = %( id="#{pagy_id}") if pagy_id
13
13
  link = pagy_link_proc(pagy, link_extra: link_extra)
14
14
 
15
15
  html = +%(<ul#{p_id} class="pagy-uikit-nav uk-pagination uk-flex-center">#{pagy_uikit_prev_html pagy, link})
16
- pagy.series.each do |item|
16
+ pagy.series(**vars).each do |item| # series example: [1, :gap, 7, 8, "9", 10, 11, :gap, 36]
17
17
  html << case item
18
18
  when Integer then %(<li>#{link.call item}</li>)
19
19
  when String then %(<li class="uk-active"><span>#{pagy.label_for(item)}</span></li>)
@@ -26,7 +26,7 @@ class Pagy # :nodoc:
26
26
  end
27
27
 
28
28
  # Javascript pagination for uikit: it returns a nav and a JSON tag used by the Pagy.nav javascript
29
- def pagy_uikit_nav_js(pagy, pagy_id: nil, link_extra: '', steps: nil)
29
+ def pagy_uikit_nav_js(pagy, pagy_id: nil, link_extra: '', **vars)
30
30
  p_id = %( id="#{pagy_id}") if pagy_id
31
31
  link = pagy_link_proc(pagy, link_extra: link_extra)
32
32
  tags = { 'before' => pagy_uikit_prev_html(pagy, link),
@@ -36,7 +36,7 @@ class Pagy # :nodoc:
36
36
  'after' => pagy_uikit_next_html(pagy, link) }
37
37
 
38
38
  %(<ul#{p_id} class="pagy-njs pagy-uikit-nav-js uk-pagination uk-flex-center" #{
39
- pagy_json_attr(pagy, :nav, tags, (sequels = pagy.sequels(steps)), pagy.label_sequels(sequels))}></ul>)
39
+ pagy_json_attr(pagy, :nav, tags, (sequels = pagy.sequels(**vars)), pagy.label_sequels(sequels))}></ul>)
40
40
  end
41
41
 
42
42
  # Javascript combo pagination for uikit: it returns a nav and a JSON tag used by the Pagy.combo_nav javascript
data/lib/pagy/frontend.rb CHANGED
@@ -15,7 +15,7 @@ class Pagy
15
15
  include UrlHelpers
16
16
 
17
17
  # Generic pagination: it returns the html with the series of links to the pages
18
- def pagy_nav(pagy, pagy_id: nil, link_extra: '')
18
+ def pagy_nav(pagy, pagy_id: nil, link_extra: '', **vars)
19
19
  p_id = %( id="#{pagy_id}") if pagy_id
20
20
  link = pagy_link_proc(pagy, link_extra: link_extra)
21
21
  p_prev = pagy.prev
@@ -27,7 +27,7 @@ class Pagy
27
27
  else
28
28
  %(<span class="page prev disabled">#{pagy_t('pagy.nav.prev')}</span> )
29
29
  end
30
- pagy.series.each do |item| # series example: [1, :gap, 7, 8, "9", 10, 11, :gap, 36]
30
+ pagy.series(**vars).each do |item| # series example: [1, :gap, 7, 8, "9", 10, 11, :gap, 36]
31
31
  html << case item
32
32
  when Integer then %(<span class="page">#{link.call item}</span> )
33
33
  when String then %(<span class="page active">#{pagy.label_for(item)}</span> )
@@ -23,7 +23,7 @@ class Pagy
23
23
  private
24
24
 
25
25
  # Transitional code to handle params deprecations. It will be removed in version 6.0
26
- def pagy_deprecated_params(pagy, params) # remove in 6.0
26
+ def pagy_deprecated_params(pagy, params) # remove in 6.0
27
27
  if pagy.params.is_a?(Proc) # new code
28
28
  pagy.params.call(params)
29
29
  elsif respond_to?(:pagy_massage_params) # deprecated code
data/lib/pagy.rb CHANGED
@@ -5,7 +5,7 @@ require 'pathname'
5
5
 
6
6
  # Core class
7
7
  class Pagy
8
- VERSION = '5.3.1'
8
+ VERSION = '5.4.0'
9
9
 
10
10
  # Root pathname to get the path of Pagy files like templates or dictionaries
11
11
  def self.root
@@ -44,7 +44,7 @@ class Pagy
44
44
  end
45
45
 
46
46
  # Return the array of page numbers and :gap items e.g. [1, :gap, 7, 8, "9", 10, 11, :gap, 36]
47
- def series(size = @vars[:size])
47
+ def series(size: @vars[:size])
48
48
  return [] if size.empty?
49
49
  raise VariableError.new(self, :size, 'to contain 4 items >= 0', size) \
50
50
  unless size.is_a?(Array) && size.size == 4 && size.all? { |num| !num.negative? rescue false } # rubocop:disable Style/RescueModifier
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pagy
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.3.1
4
+ version: 5.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Domizio Demichelis
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-11-12 00:00:00.000000000 Z
11
+ date: 2021-11-17 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Agnostic pagination in plain ruby. It does it all. Better.
14
14
  email:
@@ -102,7 +102,8 @@ files:
102
102
  homepage: https://github.com/ddnexus/pagy
103
103
  licenses:
104
104
  - MIT
105
- metadata: {}
105
+ metadata:
106
+ rubygems_mfa_required: 'true'
106
107
  post_install_message:
107
108
  rdoc_options: []
108
109
  require_paths: