pagy 5.2.2 → 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: 5cb4539d68931db35f7f2f8c9d53d9e8a63541f402f23621b92a51e6a2e77386
4
- data.tar.gz: 4adbae6e3d5213c6628bec8a35a26c5e44ce09546fa6fdd74541d5bbf2feb63b
3
+ metadata.gz: 32d028f5c02fafb87cc0bb10f1b28ebf1f49b89babf4cfcf2099367b69cf88af
4
+ data.tar.gz: c5cf934095bfaed81c66afab017340855b8d7dcc1af5cc80c620e8fb62c70054
5
5
  SHA512:
6
- metadata.gz: 277754cc4da9b7bd70c173ad052c87658eda48c7a42ad28675e1b5ce3eafae09932bf3c2a1682715890bbb4039ce3484f0a1adc7f7223e6bd3702e3cfb9b0eab
7
- data.tar.gz: 9cb4995ece3b2fe8ab5625646cb1118080d27f52ce63af8efe5fd5178a6f8e8e77e9196a7f851780057fb315368622961f70eb65f808c460d011d5d890ff69bd
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.2.2)
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
 
@@ -22,6 +22,7 @@
22
22
  # See https://ddnexus.github.io/pagy/api/pagy#other-variables
23
23
  # Pagy::DEFAULT[:size] = [1,4,4,1] # default
24
24
  # Pagy::DEFAULT[:page_param] = :page # default
25
+ # The :params can be also set as a lambda e.g ->(params){ params.exclude('useless').merge!('custom' => 'useful') }
25
26
  # Pagy::DEFAULT[:params] = {} # default
26
27
  # Pagy::DEFAULT[:fragment] = '#fragment' # example
27
28
  # Pagy::DEFAULT[:link_extra] = 'data-remote="true"' # example
@@ -42,14 +43,12 @@
42
43
  # Calendar extra: Paginate a collection by calendar Time unit (year, month, week or day)
43
44
  # See https://ddnexus.github.io/pagy/extras/calendar
44
45
  # require 'pagy/extras/calendar'
45
- # Pagy::DEFAULT[:local_minmax] = [] # Min and max local Time period must be set by the user (better not not as default)
46
- # Pagy::DEFAULT[:unit] = :month # Time unit allowed %i[year month week day]
47
- # Pagy::DEFAULT[:week_offset] = 0 # Day offset from Sunday (0: Sunday; 1: Monday;... 6: Saturday)
48
- # Pagy::DEFAULT[:order] = :asc # Time direction of pagination
49
- # Pagy::DEFAULT[:year_format] = '%Y' # strftime format for :year unit
50
- # Pagy::DEFAULT[:month_format] = '%Y-%m' # strftime format for :month unit
51
- # Pagy::DEFAULT[:week_format] = '%Y-%W' # strftime format for :week unit
52
- # 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
53
52
 
54
53
  # Countless extra: Paginate without any count, saving one query per rendering
55
54
  # See https://ddnexus.github.io/pagy/extras/countless
@@ -1,9 +1,11 @@
1
1
  // See the Pagy documentation: https://ddnexus.github.io/pagy/extras#javascript
2
2
 
3
+ // This code should be OK also with very old browsers
4
+
3
5
  // Container of the whole pagy stuff
4
6
  function Pagy(){}
5
7
 
6
- Pagy.version = '5.2.2'
8
+ Pagy.version = '5.4.0'
7
9
 
8
10
  // Used by the waitForMe function
9
11
  Pagy.delay = 100
@@ -23,10 +25,11 @@ Pagy.init =
23
25
 
24
26
  // Power the pagy*_nav_js helpers
25
27
  Pagy.nav =
26
- function(pagyEl, tags, sequels, trimParam) {
27
- var lastWidth,
28
- pageREg = new RegExp(/__pagy_page__/g),
29
- widths = []
28
+ function(pagyEl, tags, sequels, label_sequels, trimParam ) {
29
+ label_sequels = (label_sequels === null) ? sequels : label_sequels
30
+ var widths = [], lastWidth,
31
+ fill = function(string, item, label) { return string.replace(/__pagy_page__/g, item)
32
+ .replace(/__pagy_label__/g, label) }
30
33
  for (var width in sequels) {
31
34
  if (sequels.hasOwnProperty(width)) { widths.push(parseInt(width, 10)) }
32
35
  }
@@ -40,13 +43,15 @@ Pagy.nav =
40
43
  }
41
44
  if (width !== lastWidth) {
42
45
  var html = tags.before,
43
- series = sequels[width]
46
+ series = sequels[width],
47
+ labels = label_sequels[width]
44
48
  for (i = 0, len = series.length; i < len; i++) {
45
- var item = series[i]
46
- if (typeof(trimParam) === 'string' && item === 1) { html += Pagy.trim(tags.link.replace(pageREg, item), trimParam) }
47
- else if (typeof(item) === 'number') { html += tags.link.replace(pageREg, item) }
49
+ var item = series[i],
50
+ label = labels[i]
51
+ if (typeof(trimParam) === 'string' && item === 1) { html += Pagy.trim(fill(tags.link, item, label), trimParam) }
52
+ else if (typeof(item) === 'number') { html += fill(tags.link, item, label) }
48
53
  else if (item === 'gap') { html += tags.gap }
49
- else if (typeof(item) === 'string') { html += tags.active.replace(pageREg, item) }
54
+ else if (typeof(item) === 'string') { html += fill(tags.active, item, label) }
50
55
  }
51
56
  html += tags.after
52
57
  this.insertAdjacentHTML('afterbegin', html)
data/lib/pagy/calendar.rb CHANGED
@@ -5,144 +5,183 @@ 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
36
+ setup_params_var
27
37
  raise OverflowError.new(self, :page, "in 1..#{@last}", @page) if @page > @last
28
38
 
29
39
  @prev = (@page - 1 unless @page == 1)
30
40
  @next = @page == @last ? (1 if @vars[:cycle]) : @page + 1
31
41
  end
32
42
 
33
- # Generate a label for each page, with the specific `Time` period it refers to
34
- def page_label(num = @page, format = nil)
35
- snap = snap(num.to_i)
36
- format ||= @vars[:"#{@unit}_format"]
37
- case @unit
38
- when :year then new_time(@initial.year + snap)
39
- when :month then bump_month(@initial, snap)
40
- when :week then @initial + (snap * WEEK)
41
- when :day then @initial + (snap * DAY)
42
- else raise InternalError, "expected @unit to be in [:year, :month, :week, :day]; got #{@unit.inspect}"
43
- end.strftime(format)
43
+ # The label for the current page (it can pass along the I18n gem opts when it's used with the i18n extra)
44
+ def label(**opts)
45
+ label_for(@page, **opts)
44
46
  end
45
47
 
46
- def current_page_label(format = nil)
47
- page_label(@page, format)
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)]
48
51
  end
49
52
 
50
- DAY = 60 * 60 * 24
51
- WEEK = DAY * 7
52
-
53
53
  protected
54
54
 
55
- def setup_unit_vars
56
- (units = %i[year month week day]).each do |unit|
57
- raise VariableError.new(self, :format, 'to be a strftime format', @vars[:"#{unit}_format"]) \
58
- unless @vars[:"#{unit}_format"].is_a?(String)
59
- end
60
- raise VariableError.new(self, :unit, "to be in #{units.inspect}", @unit) \
61
- unless units.include?(@unit = @vars[:unit])
62
- raise VariableError.new(self, :order, 'to be in [:asc, :desc]', @order) \
63
- unless %i[asc desc].include?(@order = @vars[:order])
64
-
65
- min, max = @vars[:local_minmax]
66
- raise VariableError.new(self, :local_minmax, 'to be a an Array of min and max local Time instances', @vars[:local_minmax]) \
67
- unless min.is_a?(Time) && max.is_a?(Time) && !min.utc? && !min.utc? && min <= max \
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])
59
+
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]) \
62
+ unless min.is_a?(Time) && max.is_a?(Time) && !min.utc? && !max.utc? && min <= max \
68
63
  && (@utc_offset = min.utc_offset) == max.utc_offset
69
64
 
70
- send :"setup_#{@unit}_vars", min, max
65
+ [min, max]
71
66
  end
72
67
 
73
- # IMPORTANT: all the Time objects created and passed as arguments MUST be local!
74
-
75
- # @initial: beginning of the first day of the period that encloses the min local time
76
- # @final: beginning of the first day of the NEXT period AFTER the period that encloses the max local time
77
- # @utc_from: beginning of the first day of the period of the current page as UTC time
78
- # @utc_to: beginning of the first day of the NEXT period AFTER the current page as UTC time
79
-
80
- # Setup the calendar vars when the unit is :year
81
- def setup_year_vars(min, max)
82
- @initial = new_time(min.year)
83
- @final = new_time(max.year + 1)
84
- @pages = @last = @final.year - @initial.year
85
- @utc_from = new_time(@initial.year + snap).utc
86
- @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])
87
71
  end
88
72
 
89
- # Setup the calendar vars when the unit is :month
90
- def setup_month_vars(min, max)
91
- @initial = new_time(min.year, min.month)
92
- @final = bump_month(max)
93
- @pages = @last = months(@final) - months(@initial)
94
- @utc_from = bump_month(@initial, snap).utc
95
- @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
96
76
  end
97
77
 
98
- # Setup the calendar vars when the unit is :week
99
- def setup_week_vars(min, max)
100
- @initial = week_start(min)
101
- @final = week_start(max) + WEEK
102
- @pages = @last = (@final - @initial).to_i / WEEK
103
- @utc_from = (@initial + (snap * WEEK)).utc
104
- @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)
105
81
  end
106
82
 
107
- # Setup the calendar vars when the unit is :day
108
- def setup_day_vars(min, max)
109
- @initial = new_time(min.year, min.month, min.day)
110
- @final = new_time(max.year, max.month, max.day) + DAY
111
- @pages = @last = (@final - @initial).to_i / DAY
112
- @utc_from = (@initial + (snap * DAY)).utc
113
- @utc_to = @utc_from + DAY
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
94
+
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
114
100
  end
115
101
 
116
- 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
117
113
 
118
- # Simple trick to snap the page into its ordered position,
119
- # without actually reordering anything in the internal structure
120
- def snap(page = @page)
121
- @order == :asc ? page - 1 : @pages - page
122
- 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
123
119
 
124
- # Create a new local time at the beginning of the day
125
- def new_time(year, month = 1, day = 1)
126
- Time.new(year, month, day, 0, 0, 0, @utc_offset)
127
- end
120
+ private
121
+
122
+ # Months in local time
123
+ def months(time)
124
+ (time.year * 12) + time.month
125
+ end
128
126
 
129
- # Months in local time
130
- def months(time)
131
- (time.year * 12) + time.month
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
132
134
  end
133
135
 
134
- # Add 1 or more months to local time
135
- def bump_month(time, months = 1)
136
- months += months(time)
137
- year = months / 12
138
- month = months % 12
139
- 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
140
164
  end
141
165
 
142
- # Return the start of the week for local time
143
- def week_start(time)
144
- start = time - (((time.wday - @week_offset) * DAY) % WEEK)
145
- 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
146
183
  end
184
+ # After all the subclasses are defined
185
+ UNITS = { year: Year, month: Month, week: Week, day: Day }.freeze
147
186
  end
148
187
  end
@@ -11,6 +11,7 @@ class Pagy
11
11
  normalize_vars(vars)
12
12
  setup_vars(page: 1, outset: 0)
13
13
  setup_items_var
14
+ setup_params_var
14
15
  @offset = (@items * (@page - 1)) + @outset
15
16
  end
16
17
 
@@ -29,7 +30,7 @@ class Pagy
29
30
 
30
31
  # Override the original series.
31
32
  # Return nil if :countless_minimal is enabled
32
- def series(_size = @vars[:size])
33
+ def series(*)
33
34
  super unless @vars[:countless_minimal]
34
35
  end
35
36
  end
@@ -1,20 +1,20 @@
1
1
  # See the Pagy documentation: https://ddnexus.github.io/pagy/extras/bootstrap
2
2
  # frozen_string_literal: true
3
3
 
4
- require 'pagy/extras/shared'
4
+ require 'pagy/extras/frontend_helpers'
5
5
 
6
6
  class Pagy # :nodoc:
7
7
  # Frontend modules are specially optimized for performance.
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,17 +30,17 @@ 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}),
37
- 'link' => %(<li class="page-item">#{mark = link.call(PAGE_PLACEHOLDER)}</li>),
37
+ 'link' => %(<li class="page-item">#{mark = link.call(PAGE_PLACEHOLDER, LABEL_PLACEHOLDER)}</li>),
38
38
  'active' => %(<li class="page-item active">#{mark}</li>),
39
39
  'gap' => %(<li class="page-item gap disabled"><a href="#" class="page-link">#{pagy_t 'pagy.nav.gap'}</a></li>),
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, pagy.sequels(steps))}></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
@@ -1,26 +1,26 @@
1
1
  # See the Pagy documentation: https://ddnexus.github.io/pagy/extras/bulma
2
2
  # frozen_string_literal: true
3
3
 
4
- require 'pagy/extras/shared'
4
+ require 'pagy/extras/frontend_helpers'
5
5
 
6
6
  class Pagy # :nodoc:
7
7
  # Frontend modules are specially optimized for performance.
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
- %(<li>#{link.call item, item, %(class="pagination-link" aria-label="goto page #{item}")}</li>)
21
+ %(<li>#{link.call item, pagy.label_for(item), %(class="pagination-link" aria-label="goto page #{item}")}</li>)
22
22
  when String
23
- %(<li>#{link.call item, item,
23
+ %(<li>#{link.call item, pagy.label_for(item),
24
24
  %(class="pagination-link is-current" aria-label="page #{item}" aria-current="page")}</li>)
25
25
  when :gap
26
26
  %(<li><span class="pagination-ellipsis">#{pagy_t 'pagy.nav.gap'}</span></li>)
@@ -30,21 +30,20 @@ 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">),
37
- 'link' => %(<li>#{link.call PAGE_PLACEHOLDER, PAGE_PLACEHOLDER,
37
+ 'link' => %(<li>#{link.call PAGE_PLACEHOLDER, LABEL_PLACEHOLDER,
38
38
  %(class="pagination-link" aria-label="goto page #{PAGE_PLACEHOLDER}")}</li>),
39
- 'active' => %(<li>#{link.call PAGE_PLACEHOLDER, PAGE_PLACEHOLDER,
39
+ 'active' => %(<li>#{link.call PAGE_PLACEHOLDER, LABEL_PLACEHOLDER,
40
40
  %(class="pagination-link is-current" aria-current="page" aria-label="page #{
41
41
  PAGE_PLACEHOLDER}")}</li>),
42
42
  'gap' => %(<li><span class="pagination-ellipsis">#{pagy_t 'pagy.nav.gap'}</span></li>),
43
43
  'after' => '</ul>' }
44
44
 
45
- %(<nav#{p_id} class="pagy-njs pagy-bulma-nav-js pagination is-centered" aria-label="pagination" #{pagy_json_attr(
46
- pagy, :nav, tags, pagy.sequels(steps)
47
- )}></nav>)
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(**vars)), pagy.label_sequels(sequels))}></nav>)
48
47
  end
49
48
 
50
49
  # Javascript combo pagination for Bulma: it returns a nav and a JSON tag used by the Pagy.combo_nav javascript
@@ -4,43 +4,74 @@
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]
17
29
  end
18
30
 
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
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]
25
55
  end
26
56
 
27
- # This method should be implemented in the application and should return the records
28
- # for the unit by selecting the records with DateTime from pagy.from to pagy.to
29
- def pagy_calendar_get_items(_collection, _pagy)
30
- # collection.your_own_method_to_get_the_items_with(pagy.from, pagy.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.from to pagy.to'
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'
33
64
  end
34
- end
35
65
 
36
- # Additions for the Frontend module
37
- module Frontend
38
- # Change the text shown in the nav bar links to the actual unit of each page.
39
- def pagy_labeler(pagy, num)
40
- pagy.is_a?(Calendar) ? pagy.page_label(num) : num
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}'
41
73
  end
42
74
  end
43
75
  end
44
76
  Backend.prepend CalendarExtra::Backend
45
- Frontend.prepend CalendarExtra::Frontend
46
77
  end