pagy 4.11.0 → 6.0.0

Sign up to get free protection for your applications and to get access to all the features.
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