pagy 5.2.2 → 5.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
@@ -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 = @in = @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
@@ -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
data/lib/pagy.rb CHANGED
@@ -5,7 +5,7 @@ require 'pathname'
5
5
 
6
6
  # Core class
7
7
  class Pagy
8
- VERSION = '5.2.2'
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
@@ -24,7 +24,7 @@ class Pagy
24
24
  i18n_key: 'pagy.item_name',
25
25
  cycle: false }
26
26
 
27
- attr_reader :count, :page, :items, :vars, :pages, :last, :offset, :in, :from, :to, :prev, :next
27
+ attr_reader :count, :page, :items, :vars, :pages, :last, :offset, :in, :from, :to, :prev, :next, :params
28
28
 
29
29
  # Merge and validate the options, do some simple arithmetic and set the instance variables
30
30
  def initialize(vars)
@@ -32,6 +32,7 @@ class Pagy
32
32
  setup_vars(count: 0, page: 1, outset: 0)
33
33
  setup_items_var
34
34
  setup_pages_var
35
+ setup_params_var
35
36
  raise OverflowError.new(self, :page, "in 1..#{@last}", @page) if @page > @last
36
37
 
37
38
  @offset = (@items * (@page - 1)) + @outset
@@ -43,7 +44,7 @@ class Pagy
43
44
  end
44
45
 
45
46
  # Return the array of page numbers and :gap items e.g. [1, :gap, 7, 8, "9", 10, 11, :gap, 36]
46
- def series(size = @vars[:size])
47
+ def series(size: @vars[:size])
47
48
  return [] if size.empty?
48
49
  raise VariableError.new(self, :size, 'to contain 4 items >= 0', size) \
49
50
  unless size.is_a?(Array) && size.size == 4 && size.all? { |num| !num.negative? rescue false } # rubocop:disable Style/RescueModifier
@@ -70,6 +71,15 @@ class Pagy
70
71
  series
71
72
  end
72
73
 
74
+ # Allow the customization of the output (overridden by the calendar extra)
75
+ def label_for(page)
76
+ page.to_s
77
+ end
78
+
79
+ def label
80
+ @page.to_s
81
+ end
82
+
73
83
  protected
74
84
 
75
85
  # Apply defaults, cleanup blanks and set @vars
@@ -94,6 +104,12 @@ class Pagy
94
104
  def setup_pages_var
95
105
  @pages = @last = [(@count.to_f / @items).ceil, 1].max
96
106
  end
107
+
108
+ # Setup and validates the params
109
+ def setup_params_var
110
+ raise VariableError.new(self, :params, 'must be a Hash or a Proc', @params) \
111
+ unless (@params = @vars[:params]).is_a?(Hash) || @params.is_a?(Proc)
112
+ end
97
113
  end
98
114
 
99
115
  require 'pagy/backend'
@@ -13,7 +13,7 @@
13
13
  <% end -%>
14
14
  <% pagy.series.each do |item| # series example: [1, :gap, 7, 8, "9", 10, 11, :gap, 36] -%>
15
15
  <% if item.is_a?(Integer) -%> <li><%== link.call(item) %></li>
16
- <% elsif item.is_a?(String) -%> <li class="current"><%= pagy_labeler(pagy, item) %></li>
16
+ <% elsif item.is_a?(String) -%> <li class="current"><%= pagy.label_for(item) %></li>
17
17
  <% elsif item == :gap -%> <li class="ellipsis gap" aria-hidden="true"></li>
18
18
  <% end -%>
19
19
  <% end -%>
@@ -22,7 +22,7 @@
22
22
 
23
23
  - elsif item.is_a?(String) # current page
24
24
  %li.current
25
- = pagy_labeler(pagy, item)
25
+ = pagy.label_for(item)
26
26
 
27
27
  - elsif item == :gap # page gap
28
28
  %li.ellipsis.gap{"aria-hidden" => true}
@@ -22,7 +22,7 @@ nav.pagy-foundation-nav role="navigation" aria-label="Pagination"
22
22
 
23
23
  - elsif item.is_a?(String) # current page
24
24
  li.current
25
- = pagy_labeler(pagy, item)
25
+ = pagy.label_for(item)
26
26
 
27
27
  - elsif item == :gap # page gap
28
28
  li.ellipsis.gap aria-hidden="true"
@@ -5,7 +5,7 @@
5
5
  <% end -%>
6
6
  <% pagy.series.each do |item| -%>
7
7
  <% if item.is_a?(Integer) -%> <li><%== link.call(item) %></li>
8
- <% elsif item.is_a?(String) -%> <li class="uk-active"><span><%== pagy_labeler(pagy, item) %></span></li>
8
+ <% elsif item.is_a?(String) -%> <li class="uk-active"><span><%== pagy.label_for(item) %></span></li>
9
9
  <% elsif item == :gap -%> <li class="uk-disabled"><span><%== pagy_t('pagy.nav.gap') %></span></li>
10
10
  <% end -%>
11
11
  <% end -%>
@@ -14,7 +14,7 @@
14
14
 
15
15
  - elsif item.is_a?(String)
16
16
  %li.uk-active
17
- %span!= pagy_labeler(pagy, item)
17
+ %span!= pagy.label_for(item)
18
18
 
19
19
  - elsif item == :gap
20
20
  %li.uk-disabled