pagy 4.11.0 → 6.0.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.
Files changed (68) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +1 -1
  3. data/lib/config/pagy.rb +119 -58
  4. data/lib/javascripts/pagy-dev.js +114 -0
  5. data/lib/javascripts/pagy-module.d.ts +5 -0
  6. data/lib/javascripts/pagy-module.js +113 -0
  7. data/lib/javascripts/pagy.js +1 -121
  8. data/lib/locales/de.yml +1 -1
  9. data/lib/locales/ko.yml +1 -1
  10. data/lib/locales/nn.yml +22 -0
  11. data/lib/locales/ta.yml +22 -0
  12. data/lib/pagy/backend.rb +10 -13
  13. data/lib/pagy/calendar/day.rb +39 -0
  14. data/lib/pagy/calendar/helper.rb +61 -0
  15. data/lib/pagy/calendar/month.rb +40 -0
  16. data/lib/pagy/calendar/quarter.rb +47 -0
  17. data/lib/pagy/calendar/week.rb +39 -0
  18. data/lib/pagy/calendar/year.rb +33 -0
  19. data/lib/pagy/calendar.rb +100 -0
  20. data/lib/pagy/console.rb +6 -4
  21. data/lib/pagy/countless.rb +22 -23
  22. data/lib/pagy/exceptions.rb +14 -16
  23. data/lib/pagy/extras/arel.rb +11 -7
  24. data/lib/pagy/extras/array.rb +9 -9
  25. data/lib/pagy/extras/bootstrap.rb +45 -38
  26. data/lib/pagy/extras/bulma.rb +50 -38
  27. data/lib/pagy/extras/calendar.rb +49 -0
  28. data/lib/pagy/extras/countless.rb +15 -18
  29. data/lib/pagy/extras/elasticsearch_rails.rb +67 -48
  30. data/lib/pagy/extras/foundation.rb +39 -35
  31. data/lib/pagy/extras/frontend_helpers.rb +72 -0
  32. data/lib/pagy/extras/gearbox.rb +54 -0
  33. data/lib/pagy/extras/headers.rb +30 -20
  34. data/lib/pagy/extras/i18n.rb +15 -13
  35. data/lib/pagy/extras/items.rb +42 -40
  36. data/lib/pagy/extras/materialize.rb +40 -38
  37. data/lib/pagy/extras/meilisearch.rb +53 -44
  38. data/lib/pagy/extras/metadata.rb +15 -20
  39. data/lib/pagy/extras/navs.rb +35 -34
  40. data/lib/pagy/extras/overflow.rb +62 -61
  41. data/lib/pagy/extras/searchkick.rb +54 -46
  42. data/lib/pagy/extras/semantic.rb +42 -40
  43. data/lib/pagy/extras/standalone.rb +50 -46
  44. data/lib/pagy/extras/support.rb +24 -16
  45. data/lib/pagy/extras/trim.rb +15 -14
  46. data/lib/pagy/extras/uikit.rb +41 -38
  47. data/lib/pagy/frontend.rb +36 -59
  48. data/lib/pagy/i18n.rb +164 -0
  49. data/lib/pagy/url_helpers.rb +24 -0
  50. data/lib/pagy.rb +90 -31
  51. data/lib/templates/bootstrap_nav.html.erb +2 -2
  52. data/lib/templates/bootstrap_nav.html.haml +2 -2
  53. data/lib/templates/bootstrap_nav.html.slim +2 -2
  54. data/lib/templates/foundation_nav.html.erb +1 -1
  55. data/lib/templates/foundation_nav.html.haml +1 -1
  56. data/lib/templates/foundation_nav.html.slim +1 -1
  57. data/lib/templates/nav.html.erb +1 -1
  58. data/lib/templates/nav.html.haml +1 -1
  59. data/lib/templates/nav.html.slim +1 -1
  60. data/lib/templates/uikit_nav.html.erb +2 -2
  61. data/lib/templates/uikit_nav.html.haml +1 -1
  62. data/lib/templates/uikit_nav.html.slim +2 -2
  63. metadata +29 -13
  64. data/lib/locales/utils/i18n.rb +0 -17
  65. data/lib/locales/utils/loader.rb +0 -31
  66. data/lib/locales/utils/p11n.rb +0 -112
  67. data/lib/pagy/deprecation.rb +0 -27
  68. data/lib/pagy/extras/shared.rb +0 -52
@@ -1,80 +1,82 @@
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'
5
-
6
- class Pagy
7
- module Frontend
4
+ require 'pagy/extras/frontend_helpers'
8
5
 
6
+ class Pagy # :nodoc:
7
+ # Frontend modules are specially optimized for performance.
8
+ # The resulting code may not look very elegant, but produces the best benchmarks
9
+ module SemanticExtra
9
10
  # Pagination for semantic: it returns the html with the series of links to the pages
10
- def pagy_semantic_nav(pagy, pagy_id: nil, link_extra: '')
11
+ def pagy_semantic_nav(pagy, pagy_id: nil, link_extra: '', **vars)
11
12
  p_id = %( id="#{pagy_id}") if pagy_id
12
13
  link = pagy_link_proc(pagy, link_extra: %(class="item" #{link_extra}))
13
14
 
14
15
  html = +%(<div#{p_id} class="pagy-semantic-nav ui pagination menu">)
15
16
  html << pagy_semantic_prev_html(pagy, link)
16
- 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]
17
18
  html << case item
18
- when Integer then link.call item # page link
19
- when String then %(<a class="item active">#{item}</a>) # current page
20
- when :gap then %(<div class="disabled item">#{pagy_t 'pagy.nav.gap'}</div>) # page gap
19
+ when Integer then link.call item
20
+ when String then %(<a class="item active">#{pagy.label_for(item)}</a>)
21
+ when :gap then %(<div class="disabled item">#{pagy_t 'pagy.nav.gap'}</div>)
22
+ else raise InternalError, "expected item types in series to be Integer, String or :gap; got #{item.inspect}"
21
23
  end
22
24
  end
23
25
  html << pagy_semantic_next_html(pagy, link)
24
26
  html << %(</div>)
25
27
  end
26
28
 
27
- # Javascript pagination for semantic: it returns a nav and a JSON tag used by the Pagy.nav javascript
28
- def pagy_semantic_nav_js(pagy, deprecated_id=nil, pagy_id: nil, link_extra: '', steps: nil)
29
- pagy_id = Pagy.deprecated_arg(:id, deprecated_id, :pagy_id, pagy_id) if deprecated_id
29
+ # Javascript pagination for semantic: it returns a nav and a JSON tag used by the pagy.js file
30
+ def pagy_semantic_nav_js(pagy, pagy_id: nil, link_extra: '', **vars)
31
+ sequels = pagy.sequels(**vars)
30
32
  p_id = %( id="#{pagy_id}") if pagy_id
31
33
  link = pagy_link_proc(pagy, link_extra: %(class="item" #{link_extra}))
32
34
  tags = { 'before' => pagy_semantic_prev_html(pagy, link),
33
- 'link' => link.call(PAGE_PLACEHOLDER),
34
- 'active' => %(<a class="item active">#{pagy.page}</a>),
35
+ 'link' => link.call(PAGE_PLACEHOLDER, LABEL_PLACEHOLDER),
36
+ 'active' => %(<a class="item active">#{LABEL_PLACEHOLDER}</a>),
35
37
  'gap' => %(<div class="disabled item">#{pagy_t('pagy.nav.gap')}</div>),
36
38
  'after' => pagy_semantic_next_html(pagy, link) }
37
39
 
38
- %(<div#{p_id} class="pagy-njs pagy-semantic-nav-js ui pagination menu" role="navigation" #{pagy_json_attr(pagy, :nav, tags, pagy.sequels(steps))}></div>)
40
+ %(<div#{p_id} class="#{'pagy-rjs ' if sequels.size > 1}pagy-semantic-nav-js ui pagination menu" role="navigation" #{
41
+ pagy_data(pagy, :nav, tags, sequels, pagy.label_sequels(sequels))}></div>)
39
42
  end
40
43
 
41
- # Combo pagination for semantic: it returns a nav and a JSON tag used by the Pagy.combo_nav javascript
42
- def pagy_semantic_combo_nav_js(pagy, deprecated_id=nil, pagy_id: nil, link_extra: '')
43
- pagy_id = Pagy.deprecated_arg(:id, deprecated_id, :pagy_id, pagy_id) if deprecated_id
44
+ # Combo pagination for semantic: it returns a nav and a JSON tag used by the pagy.js file
45
+ def pagy_semantic_combo_nav_js(pagy, pagy_id: nil, link_extra: '')
44
46
  p_id = %( id="#{pagy_id}") if pagy_id
45
47
  link = pagy_link_proc(pagy, link_extra: %(class="item" #{link_extra}))
46
48
  p_page = pagy.page
47
49
  p_pages = pagy.pages
48
- input = %(<input type="number" min="1" max="#{p_pages}" value="#{p_page}" style="padding: 0; text-align: center; width: #{p_pages.to_s.length+1}rem; margin: 0 0.3rem">)
50
+ input = %(<input type="number" min="1" max="#{p_pages}" value="#{
51
+ p_page}" style="padding: 0; text-align: center; width: #{p_pages.to_s.length + 1}rem; margin: 0 0.3rem">)
49
52
 
50
53
  %(<div#{p_id} class="pagy-semantic-combo-nav-js ui compact menu" role="navigation" #{
51
- pagy_json_attr pagy, :combo_nav, p_page, pagy_marked_link(link)
52
- }>#{
53
- pagy_semantic_prev_html pagy, link
54
- }<div class="pagy-combo-input item">#{
55
- pagy_t 'pagy.combo_nav_js', page_input: input, count: p_page, pages: p_pages
56
- }</div> #{
57
- pagy_semantic_next_html pagy, link
58
- }</div>)
54
+ pagy_data(pagy, :combo, pagy_marked_link(link))}>#{
55
+ pagy_semantic_prev_html pagy, link
56
+ }<div class="pagy-combo-input item">#{
57
+ pagy_t 'pagy.combo_nav_js', page_input: input, count: p_page, pages: p_pages
58
+ }</div> #{
59
+ pagy_semantic_next_html pagy, link
60
+ }</div>)
59
61
  end
60
62
 
61
63
  private
62
64
 
63
- def pagy_semantic_prev_html(pagy, link)
64
- if (p_prev = pagy.prev)
65
- link.call p_prev, '<i class="left small chevron icon"></i>', 'aria-label="previous"'
66
- else
67
- +%(<div class="item disabled"><i class="left small chevron icon"></i></div>)
68
- end
65
+ def pagy_semantic_prev_html(pagy, link)
66
+ if (p_prev = pagy.prev)
67
+ link.call p_prev, '<i class="left small chevron icon"></i>', 'aria-label="previous"'
68
+ else
69
+ +%(<div class="item disabled"><i class="left small chevron icon"></i></div>)
69
70
  end
71
+ end
70
72
 
71
- def pagy_semantic_next_html(pagy, link)
72
- if (p_next = pagy.next)
73
- link.call p_next, '<i class="right small chevron icon"></i>', 'aria-label="next"'
74
- else
75
- +%(<div class="item disabled"><i class="right small chevron icon"></i></div>)
76
- end
73
+ def pagy_semantic_next_html(pagy, link)
74
+ if (p_next = pagy.next)
75
+ link.call p_next, '<i class="right small chevron icon"></i>', 'aria-label="next"'
76
+ else
77
+ +%(<div class="item disabled"><i class="right small chevron icon"></i></div>)
77
78
  end
78
-
79
+ end
79
80
  end
81
+ Frontend.prepend SemanticExtra
80
82
  end
@@ -2,61 +2,65 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require 'uri'
5
- class Pagy
6
5
 
7
- # extracted from Rack::Utils and reformatted for rubocop
8
- module QueryUtils
9
- module_function
10
- def escape(str)
11
- URI.encode_www_form_component(str)
12
- end
13
- def build_nested_query(value, prefix = nil)
14
- case value
15
- when Array
16
- value.map { |v| build_nested_query(v, "#{prefix}[]") }.join('&')
17
- when Hash
18
- value.map { |k, v| build_nested_query(v, prefix ? "#{prefix}[#{escape(k)}]" : escape(k)) }.delete_if(&:empty?).join('&')
19
- when nil
20
- prefix
21
- else
22
- raise ArgumentError, 'value must be a Hash' if prefix.nil?
23
- "#{prefix}=#{escape(value)}"
6
+ class Pagy # :nodoc:
7
+ # Use pagy without any request object, nor Rack environment/gem, nor any defined params method,
8
+ # even in the irb/rails console without any app or config.
9
+ module StandaloneExtra
10
+ # Extracted from Rack::Utils and reformatted for rubocop
11
+ # :nocov:
12
+ module QueryUtils
13
+ module_function
14
+
15
+ def escape(str)
16
+ URI.encode_www_form_component(str)
24
17
  end
25
- end
26
- end
27
18
 
28
- module UseStandaloneExtra
29
- # without any :url var it works exactly as the regular #pagy_url_for;
30
- # with a defined :url variable it does not use rack/request
31
- def pagy_url_for(pagy, page, deprecated_url=nil, absolute: nil)
32
- absolute = Pagy.deprecated_arg(:url, deprecated_url, :absolute, absolute) if deprecated_url
33
- pagy, page = Pagy.deprecated_order(pagy, page) if page.is_a?(Pagy)
34
- p_vars = pagy.vars
35
- if p_vars[:url]
36
- url_string = p_vars[:url]
37
- params = {}
38
- else
39
- url_string = "#{request.base_url if absolute}#{request.path}"
40
- params = request.GET
19
+ def build_nested_query(value, prefix = nil)
20
+ case value
21
+ when Array
22
+ value.map { |v| build_nested_query(v, "#{prefix}[]") }.join('&')
23
+ when Hash
24
+ value.map do |k, v|
25
+ build_nested_query(v, prefix ? "#{prefix}[#{escape(k)}]" : escape(k))
26
+ end.delete_if(&:empty?).join('&')
27
+ when nil
28
+ prefix
29
+ else
30
+ raise ArgumentError, 'value must be a Hash' if prefix.nil?
31
+
32
+ "#{prefix}=#{escape(value)}"
33
+ end
41
34
  end
42
- params = params.merge(p_vars[:params])
43
- params[p_vars[:page_param].to_s] = page
44
- params[p_vars[:items_param].to_s] = p_vars[:items] if defined?(UseItemsExtra)
45
- query_string = "?#{QueryUtils.build_nested_query(pagy_get_params(params))}" unless params.empty?
46
- "#{url_string}#{query_string}#{p_vars[:fragment]}"
47
35
  end
48
- end
36
+ # :nocov:
49
37
 
50
- # single line in order to avoid complicating simplecov already tested with other GitHub Actions
51
- Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('3.0.0') \
52
- && Helpers.prepend(UseStandaloneExtra) \
53
- || ( Frontend.prepend(UseStandaloneExtra); Backend.prepend(UseStandaloneExtra) if defined?(Pagy::Backend::METADATA) ) # rubocop:disable Style/Semicolon
38
+ # Return the URL for the page. If there is no pagy.vars[:url]
39
+ # it works exactly as the regular #pagy_url_for, relying on the params method and Rack.
40
+ # If there is a defined pagy.vars[:url] variable it does not need the params method nor Rack.
41
+ def pagy_url_for(pagy, page, absolute: false, html_escaped: false)
42
+ return super unless pagy.vars[:url]
54
43
 
55
- # defines a dummy #params method if not already defined in the including module
44
+ vars = pagy.vars
45
+ page_param = vars[:page_param].to_s
46
+ items_param = vars[:items_param].to_s
47
+ params = pagy.params.is_a?(Hash) ? pagy.params.clone : {} # safe when it gets reused
48
+ params[page_param] = page
49
+ params[items_param] = vars[:items] if vars[:items_extra]
50
+ params = pagy.params.call(params) if pagy.params.is_a?(Proc)
51
+ query_string = "?#{Rack::Utils.build_nested_query(params)}"
52
+ query_string = query_string.gsub('&', '&amp;') if html_escaped # the only unescaped entity
53
+ "#{vars[:url]}#{query_string}#{vars[:fragment]}"
54
+ end
55
+ end
56
+ # In ruby 3+ `UrlHelpers.prepend StandaloneExtra` would be enough instead of using the next 2 lines
57
+ Frontend.prepend StandaloneExtra
58
+ Backend.prepend StandaloneExtra
59
+
60
+ # Define a dummy params method if it's not already defined in the including module
56
61
  module Backend
57
62
  def self.included(controller)
58
- controller.define_method(:params){{}} unless controller.method_defined?(:params)
63
+ controller.define_method(:params) { {} } unless controller.method_defined?(:params)
59
64
  end
60
65
  end
61
-
62
66
  end
@@ -1,46 +1,54 @@
1
1
  # See the Pagy documentation: https://ddnexus.github.io/pagy/extras/support
2
2
  # frozen_string_literal: true
3
3
 
4
- class Pagy
5
-
6
- module Frontend
7
-
4
+ class Pagy # :nodoc:
5
+ # Extra support for features like: incremental, auto-incremental and infinite pagination
6
+ module SupportExtra
7
+ # Return the previous page URL string or nil
8
8
  def pagy_prev_url(pagy)
9
9
  pagy_url_for(pagy, pagy.prev) if pagy.prev
10
10
  end
11
11
 
12
+ # Return the next page URL string or nil
12
13
  def pagy_next_url(pagy)
13
14
  pagy_url_for(pagy, pagy.next) if pagy.next
14
15
  end
15
16
 
16
- def pagy_prev_link(pagy, deprecated_text=nil, deprecated_link_extra=nil, text: pagy_t('pagy.nav.prev'), link_extra: '')
17
- text = Pagy.deprecated_arg(:text, deprecated_text, :text, text) if deprecated_text
18
- link_extra = Pagy.deprecated_arg(:link_extra, deprecated_link_extra, :link_extra, link_extra) if deprecated_link_extra
17
+ # Return the HTML string for the previous page link
18
+ def pagy_prev_link(pagy, text: pagy_t('pagy.nav.prev'), link_extra: '')
19
19
  if pagy.prev
20
- %(<span class="page prev"><a href="#{pagy_url_for(pagy, pagy.prev)}" rel="prev" aria-label="previous" #{pagy.vars[:link_extra]} #{link_extra}>#{text}</a></span>)
20
+ %(<span class="page prev"><a href="#{
21
+ pagy_url_for(pagy, pagy.prev, html_escaped: true)
22
+ }" rel="prev" aria-label="previous" #{
23
+ pagy.vars[:link_extra]
24
+ } #{link_extra}>#{text}</a></span>)
21
25
  else
22
26
  %(<span class="page prev disabled">#{text}</span>)
23
27
  end
24
28
  end
25
29
 
26
- def pagy_next_link(pagy, deprecated_text=nil, deprecated_link_extra=nil, text: pagy_t('pagy.nav.next'), link_extra: '')
27
- text = Pagy.deprecated_arg(:text, deprecated_text, :text, text) if deprecated_text
28
- link_extra = Pagy.deprecated_arg(:link_extra, deprecated_link_extra, :link_extra, link_extra) if deprecated_link_extra
30
+ # Return the HTML string for the next page link
31
+ def pagy_next_link(pagy, text: pagy_t('pagy.nav.next'), link_extra: '')
29
32
  if pagy.next
30
- %(<span class="page next"><a href="#{pagy_url_for(pagy, pagy.next)}" rel="next" aria-label="next" #{pagy.vars[:link_extra]} #{link_extra}>#{text}</a></span>)
33
+ %(<span class="page next"><a href="#{
34
+ pagy_url_for(pagy, pagy.next, html_escaped: true)
35
+ }" rel="next" aria-label="next" #{
36
+ pagy.vars[:link_extra]
37
+ } #{link_extra}>#{text}</a></span>)
31
38
  else
32
39
  %(<span class="page next disabled">#{text}</span>)
33
40
  end
34
41
  end
35
42
 
43
+ # Return the HTML link tag for the previous page or nil
36
44
  def pagy_prev_link_tag(pagy)
37
- %(<link href="#{pagy_url_for(pagy, pagy.prev)}" rel="prev"/>) if pagy.prev
45
+ %(<link href="#{pagy_url_for(pagy, pagy.prev, html_escaped: true)}" rel="prev"/>) if pagy.prev
38
46
  end
39
47
 
48
+ # Return the HTML link tag for the next page or nil
40
49
  def pagy_next_link_tag(pagy)
41
- %(<link href="#{pagy_url_for(pagy, pagy.next)}" rel="next"/>) if pagy.next
50
+ %(<link href="#{pagy_url_for(pagy, pagy.next, html_escaped: true)}" rel="next"/>) if pagy.next
42
51
  end
43
-
44
52
  end
45
-
53
+ Frontend.prepend SupportExtra
46
54
  end
@@ -1,28 +1,29 @@
1
1
  # See the Pagy documentation: https://ddnexus.github.io/pagy/extras/trim
2
2
  # frozen_string_literal: true
3
3
 
4
- class Pagy
4
+ class Pagy # :nodoc:
5
+ DEFAULT[:trim_extra] = true # extra enabled by default
5
6
 
6
- VARS[:enable_trim_extra] = true
7
+ # Remove the page=1 param from the first page link
8
+ module TrimExtra
9
+ # Override the original pagy_link_proc.
10
+ # Call the pagy_trim method if the trim_extra is enabled.
11
+ def pagy_link_proc(pagy, link_extra: '')
12
+ link_proc = super(pagy, link_extra: link_extra)
13
+ return link_proc unless pagy.vars[:trim_extra]
7
14
 
8
- module UseTrimExtra
15
+ lambda do |page, text = pagy.label_for(page), extra = ''|
16
+ link = +link_proc.call(page, text, extra)
17
+ return link unless page == 1
9
18
 
10
- def pagy_link_proc(pagy, deprecated_link_extra=nil, link_extra: '')
11
- link_extra = Pagy.deprecated_arg(:link_extra, deprecated_link_extra, :link_extra, link_extra) if deprecated_link_extra
12
- link_proc = super(pagy, link_extra: link_extra)
13
- return link_proc unless pagy.vars[:enable_trim_extra]
14
- lambda do |num, text=num, extra=''|
15
- link = +link_proc.call(num, text, extra)
16
- return link unless num == 1
17
19
  pagy_trim(pagy, link)
18
20
  end
19
21
  end
20
22
 
23
+ # Remove the the :page_param param from the first page link
21
24
  def pagy_trim(pagy, link)
22
- link.sub!(/[?&]#{pagy.vars[:page_param]}=1\b(?!&)|\b#{pagy.vars[:page_param]}=1&/, '')
25
+ link.sub!(/(\?|&amp;)#{pagy.vars[:page_param]}=1\b(?!&amp;)|\b#{pagy.vars[:page_param]}=1&amp;/, '')
23
26
  end
24
-
25
27
  end
26
- Frontend.prepend UseTrimExtra
27
-
28
+ Frontend.prepend TrimExtra
28
29
  end
@@ -1,81 +1,84 @@
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'
5
-
6
- class Pagy
7
- module Frontend
4
+ require 'pagy/extras/frontend_helpers'
8
5
 
6
+ class Pagy # :nodoc:
7
+ # Frontend modules are specially optimized for performance.
8
+ # The resulting code may not look very elegant, but produces the best benchmarks
9
+ module UikitExtra
9
10
  # Pagination for uikit: it returns the html with the series of links to the pages
10
- def pagy_uikit_nav(pagy, pagy_id: nil, link_extra: '')
11
+ def pagy_uikit_nav(pagy, pagy_id: nil, link_extra: '', **vars)
11
12
  p_id = %( id="#{pagy_id}") if pagy_id
12
13
  link = pagy_link_proc(pagy, link_extra: link_extra)
13
14
 
14
15
  html = +%(<ul#{p_id} class="pagy-uikit-nav uk-pagination uk-flex-center">#{pagy_uikit_prev_html pagy, link})
15
- pagy.series.each do |item|
16
- html << case item
16
+ pagy.series(**vars).each do |item| # series example: [1, :gap, 7, 8, "9", 10, 11, :gap, 36]
17
+ html << case item
17
18
  when Integer then %(<li>#{link.call item}</li>)
18
- when String then %(<li class="uk-active"><span>#{item}</span></li>)
19
+ when String then %(<li class="uk-active"><span>#{pagy.label_for(item)}</span></li>)
19
20
  when :gap then %(<li class="uk-disabled"><span>#{pagy_t 'pagy.nav.gap'}</span></li>)
21
+ else raise InternalError, "expected item types in series to be Integer, String or :gap; got #{item.inspect}"
20
22
  end
21
23
  end
22
24
  html << pagy_uikit_next_html(pagy, link)
23
25
  html << %(</ul>)
24
26
  end
25
27
 
26
- # Javascript pagination for uikit: it returns a nav and a JSON tag used by the Pagy.nav javascript
27
- def pagy_uikit_nav_js(pagy, deprecated_id=nil, pagy_id: nil, link_extra: '', steps: nil)
28
- pagy_id = Pagy.deprecated_arg(:id, deprecated_id, :pagy_id, pagy_id) if deprecated_id
28
+ # Javascript pagination for uikit: it returns a nav and a JSON tag used by the pagy.js file
29
+ def pagy_uikit_nav_js(pagy, pagy_id: nil, link_extra: '', **vars)
30
+ sequels = pagy.sequels(**vars)
29
31
  p_id = %( id="#{pagy_id}") if pagy_id
30
32
  link = pagy_link_proc(pagy, link_extra: link_extra)
31
33
  tags = { 'before' => pagy_uikit_prev_html(pagy, link),
32
- 'link' => %(<li>#{link.call(PAGE_PLACEHOLDER)}</li>),
33
- 'active' => %(<li class="uk-active"><span>#{PAGE_PLACEHOLDER}</span></li>),
34
+ 'link' => %(<li>#{link.call(PAGE_PLACEHOLDER, LABEL_PLACEHOLDER)}</li>),
35
+ 'active' => %(<li class="uk-active"><span>#{LABEL_PLACEHOLDER}</span></li>),
34
36
  'gap' => %(<li class="uk-disabled"><span>#{pagy_t 'pagy.nav.gap'}</span></li>),
35
37
  'after' => pagy_uikit_next_html(pagy, link) }
36
38
 
37
- %(<ul#{p_id} class="pagy-njs pagy-uikit-nav-js uk-pagination uk-flex-center" #{pagy_json_attr(pagy, :nav, tags, pagy.sequels(steps))}></ul>)
39
+ %(<ul#{p_id} class="#{'pagy-rjs ' if sequels.size > 1}pagy-uikit-nav-js uk-pagination uk-flex-center" #{
40
+ pagy_data(pagy, :nav, tags, sequels, pagy.label_sequels(sequels))}></ul>)
38
41
  end
39
42
 
40
- # Javascript combo pagination for uikit: it returns a nav and a JSON tag used by the Pagy.combo_nav javascript
41
- def pagy_uikit_combo_nav_js(pagy, deprecated_id=nil, pagy_id: nil, link_extra: '')
42
- pagy_id = Pagy.deprecated_arg(:id, deprecated_id, :pagy_id, pagy_id) if deprecated_id
43
+ # Javascript combo pagination for uikit: it returns a nav and a JSON tag used by the pagy.js file
44
+ def pagy_uikit_combo_nav_js(pagy, pagy_id: nil, link_extra: '')
43
45
  p_id = %( id="#{pagy_id}") if pagy_id
44
46
  link = pagy_link_proc(pagy, link_extra: link_extra)
45
47
  p_page = pagy.page
46
48
  p_pages = pagy.pages
47
- input = %(<input type="number" min="1" max="#{p_pages}" value="#{p_page}" style="text-align: center; width: #{p_pages.to_s.length+1}rem;">)
49
+ input = %(<input type="number" min="1" max="#{p_pages}" value="#{
50
+ p_page}" style="text-align: center; width: #{p_pages.to_s.length + 1}rem;">)
48
51
 
49
52
  %(<ul#{p_id} class="pagy-uikit-combo-nav-js uk-button-group uk-pagination uk-flex-center" #{
50
- pagy_json_attr pagy, :combo_nav, p_page, pagy_marked_link(link)
51
- }>#{
53
+ pagy_data(pagy, :combo, pagy_marked_link(link))
54
+ }>#{
52
55
  pagy_uikit_prev_html pagy, link
53
- }<li>#{
56
+ }<li>#{
54
57
  pagy_t 'pagy.combo_nav_js', page_input: input, count: p_page, pages: p_pages
55
- }</li>#{
58
+ }</li>#{
56
59
  pagy_uikit_next_html pagy, link
57
- }</ul>)
60
+ }</ul>)
58
61
  end
59
62
 
60
63
  private
61
64
 
62
- def pagy_uikit_prev_html(pagy, link)
63
- previous_span = %(<span uk-pagination-previous>#{pagy_t 'pagy.nav.prev'}</span>)
64
- if (p_prev = pagy.prev)
65
- %(<li>#{link.call p_prev, previous_span}</li>)
66
- else
67
- %(<li class="uk-disabled"><a href="#">#{previous_span}</a></li>)
68
- end
65
+ def pagy_uikit_prev_html(pagy, link)
66
+ previous_span = %(<span uk-pagination-previous>#{pagy_t 'pagy.nav.prev'}</span>)
67
+ if (p_prev = pagy.prev)
68
+ %(<li>#{link.call p_prev, previous_span}</li>)
69
+ else
70
+ %(<li class="uk-disabled"><a href="#">#{previous_span}</a></li>)
69
71
  end
72
+ end
70
73
 
71
- def pagy_uikit_next_html(pagy, link)
72
- next_span = %(<span uk-pagination-next>#{pagy_t 'pagy.nav.next'}</span>)
73
- if (p_next = pagy.next)
74
- %(<li>#{link.call p_next, next_span}</li>)
75
- else
76
- %(<li class="uk-disabled"><a href="#">#{next_span}</a></li>)
77
- end
74
+ def pagy_uikit_next_html(pagy, link)
75
+ next_span = %(<span uk-pagination-next>#{pagy_t 'pagy.nav.next'}</span>)
76
+ if (p_next = pagy.next)
77
+ %(<li>#{link.call p_next, next_span}</li>)
78
+ else
79
+ %(<li class="uk-disabled"><a href="#">#{next_span}</a></li>)
78
80
  end
79
-
81
+ end
80
82
  end
83
+ Frontend.include UikitExtra
81
84
  end
data/lib/pagy/frontend.rb CHANGED
@@ -1,59 +1,38 @@
1
1
  # See Pagy::Frontend API documentation: https://ddnexus.github.io/pagy/api/frontend
2
2
  # frozen_string_literal: true
3
3
 
4
- require 'yaml'
4
+ require 'pagy/url_helpers'
5
+ require 'pagy/i18n'
5
6
 
6
7
  class Pagy
8
+ # Used for search and replace, hardcoded also in the pagy.js file
9
+ PAGE_PLACEHOLDER = '__pagy_page__'
10
+ LABEL_PLACEHOLDER = '__pagy_label__'
7
11
 
8
- PAGE_PLACEHOLDER = '__pagy_page__' # string used for search and replace, hardcoded also in the pagy.js file
9
-
10
- # I18n static hash loaded at startup, used as default alternative to the i18n gem.
11
- # see https://ddnexus.github.io/pagy/api/frontend#i18n
12
- I18n = eval Pagy.root.join('locales', 'utils', 'i18n.rb').read #rubocop:disable Security/Eval
13
-
14
- module Helpers
15
- # This works with all Rack-based frameworks (Sinatra, Padrino, Rails, ...)
16
- def pagy_url_for(pagy, page, deprecated_url=nil, absolute: nil)
17
- absolute = Pagy.deprecated_arg(:url, deprecated_url, :absolute, absolute) if deprecated_url
18
- pagy, page = Pagy.deprecated_order(pagy, page) if page.is_a?(Pagy)
19
- p_vars = pagy.vars
20
- params = request.GET.merge(p_vars[:params])
21
- params[p_vars[:page_param].to_s] = page
22
- params[p_vars[:items_param].to_s] = p_vars[:items] if defined?(UseItemsExtra)
23
- query_string = "?#{Rack::Utils.build_nested_query(pagy_get_params(params))}" unless params.empty?
24
- "#{request.base_url if absolute}#{request.path}#{query_string}#{p_vars[:fragment]}"
25
- end
26
-
27
- # Sub-method called only by #pagy_url_for: here for easy customization of params by overriding
28
- def pagy_get_params(params)
29
- params
30
- end
31
- end
32
-
33
- # All the code here has been optimized for performance: it may not look very pretty
34
- # (as most code dealing with many long strings), but its performance makes it very sexy! ;)
12
+ # Frontend modules are specially optimized for performance.
13
+ # The resulting code may not look very elegant, but produces the best benchmarks
35
14
  module Frontend
36
-
37
- include Helpers
15
+ include UrlHelpers
38
16
 
39
17
  # Generic pagination: it returns the html with the series of links to the pages
40
- def pagy_nav(pagy, pagy_id: nil, link_extra: '')
18
+ def pagy_nav(pagy, pagy_id: nil, link_extra: '', **vars)
41
19
  p_id = %( id="#{pagy_id}") if pagy_id
42
20
  link = pagy_link_proc(pagy, link_extra: link_extra)
43
21
  p_prev = pagy.prev
44
22
  p_next = pagy.next
45
23
 
46
- html = +%(<nav#{p_id} class="pagy-nav pagination" aria-label="pager">)
24
+ html = +%(<nav#{p_id} class="pagy-nav pagination">)
47
25
  html << if p_prev
48
26
  %(<span class="page prev">#{link.call p_prev, pagy_t('pagy.nav.prev'), 'aria-label="previous"'}</span> )
49
27
  else
50
28
  %(<span class="page prev disabled">#{pagy_t('pagy.nav.prev')}</span> )
51
29
  end
52
- 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]
53
31
  html << case item
54
- when Integer then %(<span class="page">#{link.call item}</span> ) # page link
55
- when String then %(<span class="page active">#{item}</span> ) # current page
56
- when :gap then %(<span class="page gap">#{pagy_t('pagy.nav.gap')}</span> ) # page gap
32
+ when Integer then %(<span class="page">#{link.call item}</span> )
33
+ when String then %(<span class="page active">#{pagy.label_for(item)}</span> )
34
+ when :gap then %(<span class="page gap">#{pagy_t('pagy.nav.gap')}</span> )
35
+ else raise InternalError, "expected item types in series to be Integer, String or :gap; got #{item.inspect}"
57
36
  end
58
37
  end
59
38
  html << if p_next
@@ -64,43 +43,41 @@ class Pagy
64
43
  html << %(</nav>)
65
44
  end
66
45
 
67
- # Return examples: "Displaying items 41-60 of 324 in total" of "Displaying Products 41-60 of 324 in total"
68
- def pagy_info(pagy, deprecated_item_name=nil, pagy_id: nil, item_name: nil, i18n_key: nil)
69
- p_id = %( id="#{pagy_id}") if pagy_id
70
- item_name = Pagy.deprecated_arg(:item_name, deprecated_item_name, :item_name, item_name) if deprecated_item_name
46
+ # Return examples: "Displaying items 41-60 of 324 in total" or "Displaying Products 41-60 of 324 in total"
47
+ def pagy_info(pagy, pagy_id: nil, item_name: nil, i18n_key: nil)
48
+ p_id = %( id="#{pagy_id}") if pagy_id
71
49
  p_count = pagy.count
72
50
  key = if p_count.zero? then 'pagy.info.no_items'
73
51
  elsif pagy.pages == 1 then 'pagy.info.single_page'
74
- else 'pagy.info.multiple_pages'
52
+ else 'pagy.info.multiple_pages' # rubocop:disable Lint/ElseLayout
75
53
  end
76
54
 
77
55
  %(<span#{p_id} class="pagy-info">#{
78
- pagy_t key, item_name: item_name || pagy_t(i18n_key || pagy.vars[:i18n_key], count: p_count),
79
- count: p_count, from: pagy.from, to: pagy.to
80
- }</span>)
56
+ pagy_t key, item_name: item_name || pagy_t(i18n_key || pagy.vars[:i18n_key], count: p_count),
57
+ count: p_count, from: pagy.from, to: pagy.to
58
+ }</span>)
81
59
  end
82
60
 
83
- # Returns a performance optimized proc to generate the HTML links
61
+ # Return a performance optimized proc to generate the HTML links
84
62
  # Benchmarked on a 20 link nav: it is ~22x faster and uses ~18x less memory than rails' link_to
85
- def pagy_link_proc(pagy, deprecated_link_extra=nil, link_extra: '')
86
- link_extra = Pagy.deprecated_arg(:link_extra, deprecated_link_extra, :link_extra, link_extra) if deprecated_link_extra
87
- p_prev = pagy.prev
88
- p_next = pagy.next
89
- left, right = %(<a href="#{pagy_url_for pagy, PAGE_PLACEHOLDER}" #{pagy.vars[:link_extra]} #{link_extra}).split(PAGE_PLACEHOLDER, 2)
90
- lambda do |num, text=num, extra_attrs=''|
91
- %(#{left}#{num}#{right}#{ case num
92
- when p_prev then ' rel="prev"'
93
- when p_next then ' rel="next"'
94
- else ''
95
- end } #{extra_attrs}>#{text}</a>)
63
+ def pagy_link_proc(pagy, link_extra: '')
64
+ p_prev = pagy.prev
65
+ p_next = pagy.next
66
+ left, right = %(<a href="#{pagy_url_for(pagy, PAGE_PLACEHOLDER, html_escaped: true)}" #{
67
+ pagy.vars[:link_extra]} #{link_extra}).split(PAGE_PLACEHOLDER, 2)
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>)
96
74
  end
97
75
  end
98
76
 
99
77
  # Similar to I18n.t: just ~18x faster using ~10x less memory
100
78
  # (@pagy_locale explicitly initialized in order to avoid warning)
101
- def pagy_t(key, **opts)
102
- Pagy::I18n.t @pagy_locale||=nil, key, **opts
79
+ def pagy_t(key, opts = {})
80
+ Pagy::I18n.translate(@pagy_locale ||= nil, key, opts)
103
81
  end
104
-
105
82
  end
106
83
  end