pagy 5.2.3 → 5.5.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.
@@ -4,43 +4,73 @@
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 active].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: :active];
16
+ # The calendar is active by default, but it can be explicitly inactivated with `active: false`
17
+ # Return a hash with 3 items:
18
+ # 0. Array of pagy calendar unit objects
19
+ # 1. Pagy object
20
+ # 2. Array of results
21
+ def pagy_calendar(collection, conf)
22
+ unless conf.is_a?(Hash) && (conf.keys - CONF_KEYS).empty? && conf.all? { |k, v| v.is_a?(Hash) || k == :active }
23
+ raise ArgumentError, "keys must be in #{CONF_KEYS.inspect} and object values must be Hashes; got #{conf.inspect}"
24
+ end
25
+
26
+ conf[:pagy] = {} unless conf[:pagy] # use default Pagy object when omitted
27
+ calendar, collection = pagy_setup_calendar(collection, conf) unless conf.key?(:active) && !conf[:active]
28
+ pagy, result = send(conf[:pagy][:backend] || :pagy, collection, conf[:pagy]) # use backend: :pagy when omitted
29
+ [calendar, pagy, result]
17
30
  end
18
31
 
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
32
+ # Setup and return the calendar objects and the filtered collection
33
+ def pagy_setup_calendar(collection, conf)
34
+ units = Calendar::UNITS.keys & conf.keys
35
+ page_param = conf[:pagy][:page_param] || DEFAULT[:page_param]
36
+ units.each do |unit| # set all the :page_param vars for later deletion
37
+ unit_page_param = :"#{unit}_#{page_param}"
38
+ conf[unit][:page_param] = unit_page_param
39
+ conf[unit][:page] = params[unit_page_param]
40
+ end
41
+ calendar = {}
42
+ period = pagy_calendar_period(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) } # Hash#except missing from 2.5 baseline
47
+ params
48
+ end
49
+ conf[unit][:period] = period
50
+ calendar[unit] = Calendar.create(unit, conf[unit])
51
+ period = calendar[unit].active_period # set the period for the next unit
52
+ end
53
+ [calendar, pagy_calendar_filter(collection, calendar[units.last].from, calendar[units.last].to)]
25
54
  end
26
55
 
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'
56
+ # This method must be implemented by the application.
57
+ # It must return the the starting and ending local Time objects defining the calendar :period
58
+ def pagy_calendar_period(*)
59
+ # return_period_array_using(collection)
60
+ raise NoMethodError, 'the pagy_calendar_period method must be implemented by the application and must return ' \
61
+ 'the starting and ending local Time objects array defining the calendar :period'
33
62
  end
34
- end
35
63
 
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
64
+ # This method must be implemented by the application.
65
+ # It receives the main collection and must return a filtered version of it.
66
+ # The filter logic must be equivalent to {storage_time >= from && storage_time < to}
67
+ def pagy_calendar_filter(*)
68
+ # return_filtered_collection_using(collection, from, to)
69
+ raise NoMethodError, 'the pagy_calendar_filter method must be implemented by the application and must return the ' \
70
+ 'collection filtered by a logic equivalent to '\
71
+ '{storage_time >= from && storage_time < to}'
41
72
  end
42
73
  end
43
74
  end
44
75
  Backend.prepend CalendarExtra::Backend
45
- Frontend.prepend CalendarExtra::Frontend
46
76
  end
@@ -1,23 +1,23 @@
1
1
  # See the Pagy documentation: https://ddnexus.github.io/pagy/extras/foundation
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 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
- when String then %(<li class="current">#{pagy_labeler(pagy, item)}</li>) # active page
20
+ when String then %(<li class="current">#{pagy.label_for(item)}</li>) # active page
21
21
  when :gap then %(<li class="ellipsis gap" aria-hidden="true"></li>) # page gap
22
22
  else raise InternalError, "expected item types in series to be Integer, String or :gap; got #{item.inspect}"
23
23
  end
@@ -27,17 +27,17 @@ 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}),
34
- 'link' => %(<li>#{link.call PAGE_PLACEHOLDER}</li>),
35
- 'active' => %(<li class="current">#{pagy.page}</li>),
34
+ 'link' => %(<li>#{link.call(PAGE_PLACEHOLDER, LABEL_PLACEHOLDER)}</li>),
35
+ 'active' => %(<li class="current">#{LABEL_PLACEHOLDER}</li>),
36
36
  'gap' => %(<li class="ellipsis gap" aria-hidden="true"></li>),
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, pagy.sequels(steps))}></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
@@ -5,7 +5,8 @@ require 'digest'
5
5
  class Pagy # :nodoc:
6
6
  DEFAULT[:steps] = false # default false will use {0 => @vars[:size]}
7
7
 
8
- module SharedExtra
8
+ # Private module documented in the main classes
9
+ module FrontendHelpers
9
10
  # Additions for the Pagy class
10
11
  module Pagy
11
12
  # `Pagy` instance method used by the `pagy*_nav_js` helpers.
@@ -17,12 +18,25 @@ class Pagy # :nodoc:
17
18
  # "350" => [1, 2, :gap, 17, 18, 19, "20", 21, 22, 23, :gap, 49, 50],
18
19
  # "550" => [1, 2, 3, :gap, 16, 17, 18, 19, "20", 21, 22, 23, 24, :gap, 48, 49, 50] }
19
20
  # Notice: if :steps is false it will use the single {0 => @vars[:size]} size
20
- def sequels(steps = nil)
21
- steps ||= @vars[:steps] || { 0 => @vars[:size] }
21
+ def sequels(steps: @vars[:steps] || { 0 => @vars[:size] })
22
22
  raise VariableError.new(self, :steps, 'to define the 0 width', steps) unless steps.key?(0)
23
23
 
24
24
  {}.tap do |sequels|
25
- steps.each { |width, size| sequels[width.to_s] = series(size) }
25
+ steps.each { |width, step_size| sequels[width.to_s] = series(size: step_size) }
26
+ end
27
+ end
28
+
29
+ # Support for the Calendar API
30
+ def label_sequels(*); end
31
+ end
32
+
33
+ # Additions for Calendar class
34
+ module Calendar
35
+ def label_sequels(sequels = self.sequels)
36
+ {}.tap do |label_sequels|
37
+ sequels.each do |width, series|
38
+ label_sequels[width] = series.map { |item| item == :gap ? :gap : label_for(item) }
39
+ end
26
40
  end
27
41
  end
28
42
  end
@@ -50,6 +64,7 @@ class Pagy # :nodoc:
50
64
  end
51
65
  end
52
66
  end
53
- prepend SharedExtra::Pagy
54
- Frontend.prepend SharedExtra::Frontend
67
+ prepend FrontendHelpers::Pagy
68
+ Calendar.prepend FrontendHelpers::Calendar if defined?(Calendar)
69
+ Frontend.prepend FrontendHelpers::Frontend
55
70
  end
@@ -4,11 +4,22 @@
4
4
  class Pagy # :nodoc:
5
5
  # Use ::I18n gem
6
6
  module I18nExtra
7
- def pagy_t(key, **opts)
8
- ::I18n.t(key, **opts)
7
+ # Frontend overriding
8
+ module Frontend
9
+ def pagy_t(key, **opts)
10
+ ::I18n.t(key, **opts)
11
+ end
12
+ end
13
+
14
+ # Calendar overriding
15
+ module Calendar
16
+ def localize(time, opts)
17
+ ::I18n.l(time, **opts)
18
+ end
9
19
  end
10
20
  end
11
- Frontend.prepend I18nExtra
21
+ Frontend.prepend I18nExtra::Frontend
22
+ Calendar.prepend I18nExtra::Calendar if defined?(Calendar)
12
23
 
13
24
  # Add the pagy locales to the I18n.load_path
14
25
  ::I18n.load_path += Dir[Pagy.root.join('locales', '*.yml')]
@@ -1,7 +1,7 @@
1
1
  # See the Pagy documentation: https://ddnexus.github.io/pagy/extras/items
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
  DEFAULT[:items_param] = :items
@@ -1,20 +1,20 @@
1
1
  # See the Pagy documentation: https://ddnexus.github.io/pagy/extras/materialize
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 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,18 +27,18 @@ 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
 
34
34
  tags = { 'before' => %(<ul class="pagination">#{pagy_materialize_prev_html pagy, link}),
35
- 'link' => %(<li class="waves-effect">#{mark = link.call(PAGE_PLACEHOLDER)}</li>),
35
+ 'link' => %(<li class="waves-effect">#{mark = link.call(PAGE_PLACEHOLDER, LABEL_PLACEHOLDER)}</li>),
36
36
  'active' => %(<li class="active">#{mark}</li>),
37
37
  'gap' => %(<li class="gap disabled"><a href="#">#{pagy_t 'pagy.nav.gap'}</a></li>),
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, pagy.sequels(steps))}></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
@@ -1,24 +1,24 @@
1
1
  # See the Pagy documentation: https://ddnexus.github.io/pagy/extras/navs
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 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),
15
- 'link' => %(<span class="page">#{link.call(PAGE_PLACEHOLDER)}</span> ),
16
- 'active' => %(<span class="page active">#{pagy.page}</span> ),
15
+ 'link' => %(<span class="page">#{link.call(PAGE_PLACEHOLDER, LABEL_PLACEHOLDER)}</span> ),
16
+ 'active' => %(<span class="page active">#{LABEL_PLACEHOLDER}</span> ),
17
17
  'gap' => %(<span class="page gap">#{pagy_t 'pagy.nav.gap'}</span> ),
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, pagy.sequels(steps))}></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
@@ -29,8 +29,8 @@ class Pagy # :nodoc:
29
29
  when :empty_page
30
30
  @offset = @items = @from = @to = 0 # vars relative to the actual page
31
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)
32
+ edge = @order == :asc ? @final : @initial # get the edge of the overflow side (neat, but any time would do)
33
+ @from = @to = edge # set both to the edge utc time (a >=&&< query will get no records)
34
34
  end
35
35
  @prev = @last # prev relative to the actual page
36
36
  extend Series # special series for :empty_page
@@ -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
@@ -63,7 +63,7 @@ class Pagy # :nodoc:
63
63
  when :exception
64
64
  raise # same as without the extra
65
65
  when :empty_page
66
- @offset = @in = @from = @to = 0 # vars relative to the actual page
66
+ @offset = @items = @from = @to = 0 # vars relative to the actual page
67
67
  @vars[:size] = [] # no page in the series
68
68
  self
69
69
  else
@@ -1,23 +1,23 @@
1
1
  # See the Pagy documentation: https://ddnexus.github.io/pagy/extras/semantic
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 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
- when String then %(<a class="item active">#{pagy_labeler(pagy, item)}</a>)
20
+ when String then %(<a class="item active">#{pagy.label_for(item)}</a>)
21
21
  when :gap then %(<div class="disabled item">#{pagy_t 'pagy.nav.gap'}</div>)
22
22
  else raise InternalError, "expected item types in series to be Integer, String or :gap; got #{item.inspect}"
23
23
  end
@@ -27,17 +27,17 @@ 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),
34
- 'link' => link.call(PAGE_PLACEHOLDER),
35
- 'active' => %(<a class="item active">#{pagy.page}</a>),
34
+ 'link' => link.call(PAGE_PLACEHOLDER, LABEL_PLACEHOLDER),
35
+ 'active' => %(<a class="item active">#{LABEL_PLACEHOLDER}</a>),
36
36
  'gap' => %(<div class="disabled item">#{pagy_t('pagy.nav.gap')}</div>),
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, pagy.sequels(steps))}></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
@@ -37,15 +37,18 @@ class Pagy # :nodoc:
37
37
  # it works exactly as the regular #pagy_url_for, relying on the params method and Rack.
38
38
  # If there is a defined pagy.vars[:url] variable it does not need the params method nor Rack.
39
39
  def pagy_url_for(pagy, page, absolute: nil)
40
- vars = pagy.vars
41
- return super unless (url = vars[:url])
40
+ return super unless pagy.vars[:url]
42
41
 
43
- params = vars[:params].clone # safe when it gets reused
44
- params[vars[:page_param]] = page
45
- params[vars[:items_param]] = vars[:items] if vars[:items_extra]
46
-
47
- query_string = "?#{QueryUtils.build_nested_query(pagy_massage_params(params))}"
48
- "#{url}#{query_string}#{vars[:fragment]}"
42
+ vars = pagy.vars
43
+ page_param = vars[:page_param].to_s
44
+ items_param = vars[:items_param].to_s
45
+ params = pagy.params.is_a?(Hash) ? pagy.params.clone : {} # safe when it gets reused
46
+ params[page_param] = page
47
+ params[items_param] = vars[:items] if vars[:items_extra]
48
+ query_string = "?#{QueryUtils.build_nested_query(pagy_deprecated_params(pagy, params))}" # remove in 6.0
49
+ # params = pagy.params.call(params) if pagy.params.is_a?(Proc) # add in 6.0
50
+ # query_string = "?#{Rack::Utils.build_nested_query(params)}" # add in 6.0
51
+ "#{vars[:url]}#{query_string}#{vars[:fragment]}"
49
52
  end
50
53
  end
51
54
  # In ruby 3+ `UrlHelpers.prepend StandaloneExtra` would be enough instead of using the next 2 lines
@@ -12,9 +12,9 @@ class Pagy # :nodoc:
12
12
  link_proc = super(pagy, link_extra: link_extra)
13
13
  return link_proc unless pagy.vars[:trim_extra]
14
14
 
15
- lambda do |num, text = num, extra = ''|
16
- link = +link_proc.call(num, text, extra)
17
- return link unless num == 1
15
+ lambda do |page, text = pagy.label_for(page), extra = ''|
16
+ link = +link_proc.call(page, text, extra)
17
+ return link unless page == 1
18
18
 
19
19
  pagy_trim(pagy, link)
20
20
  end
@@ -1,22 +1,22 @@
1
1
  # See the Pagy documentation: https://ddnexus.github.io/pagy/extras/uikit
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 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
- when String then %(<li class="uk-active"><span>#{pagy_labeler(pagy, item)}</span></li>)
19
+ when String then %(<li class="uk-active"><span>#{pagy.label_for(item)}</span></li>)
20
20
  when :gap then %(<li class="uk-disabled"><span>#{pagy_t 'pagy.nav.gap'}</span></li>)
21
21
  else raise InternalError, "expected item types in series to be Integer, String or :gap; got #{item.inspect}"
22
22
  end
@@ -26,17 +26,17 @@ 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),
33
- 'link' => %(<li>#{link.call(PAGE_PLACEHOLDER)}</li>),
34
- 'active' => %(<li class="uk-active"><span>#{PAGE_PLACEHOLDER}</span></li>),
33
+ 'link' => %(<li>#{link.call(PAGE_PLACEHOLDER, LABEL_PLACEHOLDER)}</li>),
34
+ 'active' => %(<li class="uk-active"><span>#{LABEL_PLACEHOLDER}</span></li>),
35
35
  'gap' => %(<li class="uk-disabled"><span>#{pagy_t 'pagy.nav.gap'}</span></li>),
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, pagy.sequels(steps))}></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
@@ -6,7 +6,8 @@ require 'pagy/i18n'
6
6
 
7
7
  class Pagy
8
8
  # Used for search and replace, hardcoded also in the pagy.js file
9
- PAGE_PLACEHOLDER = '__pagy_page__'
9
+ PAGE_PLACEHOLDER = '__pagy_page__'
10
+ LABEL_PLACEHOLDER = '__pagy_label__'
10
11
 
11
12
  # Frontend modules are specially optimized for performance.
12
13
  # The resulting code may not look very elegant, but produces the best benchmarks
@@ -14,7 +15,7 @@ class Pagy
14
15
  include UrlHelpers
15
16
 
16
17
  # Generic pagination: it returns the html with the series of links to the pages
17
- def pagy_nav(pagy, pagy_id: nil, link_extra: '')
18
+ def pagy_nav(pagy, pagy_id: nil, link_extra: '', **vars)
18
19
  p_id = %( id="#{pagy_id}") if pagy_id
19
20
  link = pagy_link_proc(pagy, link_extra: link_extra)
20
21
  p_prev = pagy.prev
@@ -26,10 +27,10 @@ class Pagy
26
27
  else
27
28
  %(<span class="page prev disabled">#{pagy_t('pagy.nav.prev')}</span> )
28
29
  end
29
- 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]
30
31
  html << case item
31
32
  when Integer then %(<span class="page">#{link.call item}</span> )
32
- when String then %(<span class="page active">#{pagy_labeler(pagy, item)}</span> )
33
+ when String then %(<span class="page active">#{pagy.label_for(item)}</span> )
33
34
  when :gap then %(<span class="page gap">#{pagy_t('pagy.nav.gap')}</span> )
34
35
  else raise InternalError, "expected item types in series to be Integer, String or :gap; got #{item.inspect}"
35
36
  end
@@ -64,20 +65,15 @@ class Pagy
64
65
  p_next = pagy.next
65
66
  left, right = %(<a href="#{pagy_url_for pagy, PAGE_PLACEHOLDER}" #{
66
67
  pagy.vars[:link_extra]} #{link_extra}).split(PAGE_PLACEHOLDER, 2)
67
- lambda do |num, text = pagy_labeler(pagy, num), extra_attrs = ''|
68
- %(#{left}#{num}#{right}#{ case num
69
- when p_prev then ' rel="prev"'
70
- when p_next then ' rel="next"'
71
- else ''
72
- end } #{extra_attrs}>#{text}</a>)
68
+ lambda do |page, text = pagy.label_for(page), extra_attrs = ''|
69
+ %(#{left}#{page}#{right}#{ case page
70
+ when p_prev then ' rel="prev"'
71
+ when p_next then ' rel="next"'
72
+ else ''
73
+ end } #{extra_attrs}>#{text}</a>)
73
74
  end
74
75
  end
75
76
 
76
- # Allow customization of the output by overriding (used by the calendar extra)
77
- def pagy_labeler(_pagy, num)
78
- num
79
- end
80
-
81
77
  # Similar to I18n.t: just ~18x faster using ~10x less memory
82
78
  # (@pagy_locale explicitly initialized in order to avoid warning)
83
79
  def pagy_t(key, **opts)
@@ -7,18 +7,32 @@ class Pagy
7
7
  # It supports all Rack-based frameworks (Sinatra, Padrino, Rails, ...).
8
8
  # For non-rack environments you can use the standalone extra
9
9
  def pagy_url_for(pagy, page, absolute: nil)
10
- vars = pagy.vars
11
- params = request.GET.merge(vars[:params].transform_keys(&:to_s))
12
- params[vars[:page_param].to_s] = page
13
- params[vars[:items_param].to_s] = vars[:items] if vars[:items_extra]
14
-
15
- query_string = "?#{Rack::Utils.build_nested_query(pagy_massage_params(params))}"
10
+ vars = pagy.vars
11
+ page_param = vars[:page_param].to_s
12
+ items_param = vars[:items_param].to_s
13
+ params = pagy.params.is_a?(Hash) ? pagy.params.transform_keys(&:to_s) : {}
14
+ params = request.GET.merge(params)
15
+ params[page_param] = page
16
+ params[items_param] = vars[:items] if vars[:items_extra]
17
+ query_string = "?#{Rack::Utils.build_nested_query(pagy_deprecated_params(pagy, params))}" # remove in 6.0
18
+ # params = pagy.params.call(params) if pagy.params.is_a?(Proc) # add in 6.0
19
+ # query_string = "?#{Rack::Utils.build_nested_query(params)}" # add in 6.0
16
20
  "#{request.base_url if absolute}#{request.path}#{query_string}#{vars[:fragment]}"
17
21
  end
18
22
 
19
- # Sub-method called only by #pagy_url_for: here for easy customization of params by overriding
20
- def pagy_massage_params(params)
21
- params
23
+ private
24
+
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
27
+ if pagy.params.is_a?(Proc) # new code
28
+ pagy.params.call(params)
29
+ elsif respond_to?(:pagy_massage_params) # deprecated code
30
+ Warning.warn '[PAGY WARNING] The pagy_massage_params method has been deprecated and it will be ignored from version 6. ' \
31
+ 'Set the :params variable to a Proc with the same code as the pagy_massage_params method.'
32
+ pagy_massage_params(params)
33
+ else
34
+ params # no massage params
35
+ end
22
36
  end
23
37
  end
24
38
  end