pagy 4.11.0 → 5.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 (41) hide show
  1. checksums.yaml +4 -4
  2. data/lib/config/pagy.rb +66 -45
  3. data/lib/javascripts/pagy.js +15 -6
  4. data/lib/pagy/backend.rb +6 -10
  5. data/lib/pagy/console.rb +5 -4
  6. data/lib/pagy/countless.rb +13 -20
  7. data/lib/pagy/exceptions.rb +2 -4
  8. data/lib/pagy/extras/arel.rb +6 -6
  9. data/lib/pagy/extras/array.rb +6 -6
  10. data/lib/pagy/extras/bootstrap.rb +32 -29
  11. data/lib/pagy/extras/bulma.rb +40 -32
  12. data/lib/pagy/extras/countless.rb +8 -9
  13. data/lib/pagy/extras/elasticsearch_rails.rb +64 -47
  14. data/lib/pagy/extras/foundation.rb +26 -26
  15. data/lib/pagy/extras/gearbox.rb +42 -0
  16. data/lib/pagy/extras/headers.rb +24 -16
  17. data/lib/pagy/extras/i18n.rb +7 -16
  18. data/lib/pagy/extras/items.rb +37 -38
  19. data/lib/pagy/extras/materialize.rb +28 -30
  20. data/lib/pagy/extras/meilisearch.rb +50 -45
  21. data/lib/pagy/extras/metadata.rb +29 -13
  22. data/lib/pagy/extras/navs.rb +24 -26
  23. data/lib/pagy/extras/overflow.rb +57 -60
  24. data/lib/pagy/extras/searchkick.rb +51 -45
  25. data/lib/pagy/extras/semantic.rb +28 -30
  26. data/lib/pagy/extras/shared.rb +44 -40
  27. data/lib/pagy/extras/standalone.rb +37 -42
  28. data/lib/pagy/extras/support.rb +14 -13
  29. data/lib/pagy/extras/trim.rb +10 -11
  30. data/lib/pagy/extras/uikit.rb +27 -28
  31. data/lib/pagy/frontend.rb +22 -47
  32. data/lib/pagy/i18n.rb +159 -0
  33. data/lib/pagy/url_helpers.rb +22 -0
  34. data/lib/pagy.rb +52 -26
  35. data/lib/templates/uikit_nav.html.erb +1 -1
  36. data/lib/templates/uikit_nav.html.slim +1 -1
  37. metadata +7 -10
  38. data/lib/locales/utils/i18n.rb +0 -17
  39. data/lib/locales/utils/loader.rb +0 -31
  40. data/lib/locales/utils/p11n.rb +0 -112
  41. data/lib/pagy/deprecation.rb +0 -27
@@ -4,8 +4,7 @@
4
4
  require 'pagy/extras/shared'
5
5
 
6
6
  class Pagy
7
- module Frontend
8
-
7
+ module BulmaExtra
9
8
  # Pagination for Bulma: it returns the html with the series of links to the pages
10
9
  def pagy_bulma_nav(pagy, pagy_id: nil, link_extra: '')
11
10
  p_id = %( id="#{pagy_id}") if pagy_id
@@ -16,67 +15,76 @@ class Pagy
16
15
  html << %(<ul class="pagination-list">)
17
16
  pagy.series.each do |item| # series example: [1, :gap, 7, 8, "9", 10, 11, :gap, 36]
18
17
  html << case item
19
- when Integer then %(<li>#{link.call item, item, %(class="pagination-link" aria-label="goto page #{item}") }</li>) # page link
20
- when String then %(<li>#{link.call item, item, %(class="pagination-link is-current" aria-label="page #{item}" aria-current="page")}</li>) # active page
21
- when :gap then %(<li><span class="pagination-ellipsis">#{pagy_t 'pagy.nav.gap'}</span></li>) # page gap
18
+ when Integer
19
+ %(<li>#{link.call item, item, %(class="pagination-link" aria-label="goto page #{item}")}</li>)
20
+ when String
21
+ %(<li>#{link.call item, item,
22
+ %(class="pagination-link is-current" aria-label="page #{item}" aria-current="page")}</li>)
23
+ when :gap
24
+ %(<li><span class="pagination-ellipsis">#{pagy_t 'pagy.nav.gap'}</span></li>)
22
25
  end
23
26
  end
24
27
  html << %(</ul></nav>)
25
28
  end
26
29
 
27
- def pagy_bulma_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
30
+ def pagy_bulma_nav_js(pagy, pagy_id: nil, link_extra: '', steps: nil)
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_bulma_prev_next_html(pagy, link)}<ul class="pagination-list">),
32
- 'link' => %(<li>#{link.call PAGE_PLACEHOLDER, PAGE_PLACEHOLDER, %(class="pagination-link" aria-label="goto page #{PAGE_PLACEHOLDER}")}</li>),
33
- 'active' => %(<li>#{link.call PAGE_PLACEHOLDER, PAGE_PLACEHOLDER, %(class="pagination-link is-current" aria-current="page" aria-label="page #{PAGE_PLACEHOLDER}")}</li>),
34
- 'gap' => %(<li><span class="pagination-ellipsis">#{pagy_t 'pagy.nav.gap' }</span></li>),
34
+ 'link' => %(<li>#{link.call PAGE_PLACEHOLDER, PAGE_PLACEHOLDER,
35
+ %(class="pagination-link" aria-label="goto page #{PAGE_PLACEHOLDER}")}</li>),
36
+ 'active' => %(<li>#{link.call PAGE_PLACEHOLDER, PAGE_PLACEHOLDER,
37
+ %(class="pagination-link is-current" aria-current="page" aria-label="page #{
38
+ PAGE_PLACEHOLDER}")}</li>),
39
+ 'gap' => %(<li><span class="pagination-ellipsis">#{pagy_t 'pagy.nav.gap'}</span></li>),
35
40
  'after' => '</ul>' }
36
41
 
37
- %(<nav#{p_id} class="pagy-njs pagy-bulma-nav-js pagination is-centered" aria-label="pagination" #{pagy_json_attr(pagy, :nav, tags, pagy.sequels(steps))}></nav>)
42
+ %(<nav#{p_id} class="pagy-njs pagy-bulma-nav-js pagination is-centered" aria-label="pagination" #{pagy_json_attr(
43
+ pagy, :nav, tags, pagy.sequels(steps)
44
+ )}></nav>)
38
45
  end
39
46
 
40
47
  # Javascript combo pagination for Bulma: it returns a nav and a JSON tag used by the Pagy.combo_nav javascript
41
- def pagy_bulma_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
48
+ def pagy_bulma_combo_nav_js(pagy, pagy_id: nil, link_extra: '')
43
49
  p_id = %( id="#{pagy_id}") if pagy_id
44
50
  link = pagy_link_proc(pagy, link_extra: link_extra)
45
51
  p_page = pagy.page
46
52
  p_pages = pagy.pages
47
- input = %(<input class="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;">)
53
+ input = %(<input class="input" type="number" min="1" max="#{p_pages}" value="#{
54
+ p_page}" style="padding: 0; text-align: center; width: #{p_pages.to_s.length + 1}rem; margin:0 0.3rem;">)
48
55
 
49
- %(<nav#{p_id} class="pagy-bulma-combo-nav-js" aria-label="pagination"><div class="field is-grouped is-grouped-centered" role="group" #{
50
- pagy_json_attr pagy, :combo_nav, p_page, pagy_marked_link(link)
51
- }>#{
56
+ html = %(<nav#{p_id} class="pagy-bulma-combo-nav-js" aria-label="pagination">)
57
+ %(#{html}<div class="field is-grouped is-grouped-centered" role="group" #{
58
+ pagy_json_attr pagy, :combo_nav, p_page, pagy_marked_link(link)}>#{
52
59
  if (p_prev = pagy.prev)
53
60
  %(<p class="control">#{link.call p_prev, pagy_t('pagy.nav.prev'), 'class="button" aria-label="previous page"'}</p>)
54
61
  else
55
62
  %(<p class="control"><a class="button" disabled>#{pagy_t 'pagy.nav.prev'}</a></p>)
56
63
  end
57
- }<div class="pagy-combo-input control level is-mobile">#{pagy_t 'pagy.combo_nav_js', page_input: input, count: p_page, pages: p_pages}</div>#{
64
+ }<div class="pagy-combo-input control level is-mobile">#{
65
+ pagy_t 'pagy.combo_nav_js', page_input: input, count: p_page, pages: p_pages}</div>#{
58
66
  if (p_next = pagy.next)
59
67
  %(<p class="control">#{link.call p_next, pagy_t('pagy.nav.next'), 'class="button" aria-label="next page"'}</p>)
60
68
  else
61
69
  %(<p class="control"><a class="button" disabled>#{pagy_t 'pagy.nav.next'}</a></p>)
62
70
  end
63
- }</div></nav>)
71
+ }</div></nav>)
64
72
  end
65
73
 
66
74
  private
67
75
 
68
- def pagy_bulma_prev_next_html(pagy, link)
69
- html = +if (p_prev = pagy.prev)
70
- link.call p_prev, pagy_t('pagy.nav.prev'), 'class="pagination-previous" aria-label="previous page"'
71
- else
72
- %(<a class="pagination-previous" disabled>#{pagy_t 'pagy.nav.prev'}</a>)
73
- end
74
- html << if (p_next = pagy.next)
75
- link.call p_next, pagy_t('pagy.nav.next'), 'class="pagination-next" aria-label="next page"'
76
- else
77
- %(<a class="pagination-next" disabled>#{pagy_t 'pagy.nav.next' }</a>)
78
- end
79
- end
80
-
76
+ def pagy_bulma_prev_next_html(pagy, link)
77
+ html = +if (p_prev = pagy.prev)
78
+ link.call p_prev, pagy_t('pagy.nav.prev'), 'class="pagination-previous" aria-label="previous page"'
79
+ else
80
+ %(<a class="pagination-previous" disabled>#{pagy_t 'pagy.nav.prev'}</a>)
81
+ end
82
+ html << if (p_next = pagy.next)
83
+ link.call p_next, pagy_t('pagy.nav.next'), 'class="pagination-next" aria-label="next page"'
84
+ else
85
+ %(<a class="pagination-next" disabled>#{pagy_t 'pagy.nav.next'}</a>)
86
+ end
87
+ end
81
88
  end
89
+ Frontend.prepend BulmaExtra
82
90
  end
@@ -4,22 +4,21 @@
4
4
  require 'pagy/countless'
5
5
 
6
6
  class Pagy
7
+ DEFAULT[:countless_minimal] = false
7
8
 
8
- VARS[:countless_minimal] = false
9
-
10
- module Backend
11
- private # the whole module is private so no problem with including it in a controller
9
+ module CountlessExtra
10
+ private
12
11
 
13
12
  # Return Pagy object and items
14
- def pagy_countless(collection, vars={})
13
+ def pagy_countless(collection, vars = {})
15
14
  pagy = Pagy::Countless.new(pagy_countless_get_vars(collection, vars))
16
- [ pagy, pagy_countless_get_items(collection, pagy) ]
15
+ [pagy, pagy_countless_get_items(collection, pagy)]
17
16
  end
18
17
 
19
18
  # Sub-method called only by #pagy_countless: here for easy customization of variables by overriding
20
19
  def pagy_countless_get_vars(_collection, vars)
21
- pagy_set_items_from_params(vars) if defined?(UseItemsExtra)
22
- vars[:page] ||= params[ vars[:page_param] || VARS[:page_param] ]
20
+ pagy_set_items_from_params(vars) if defined?(ItemsExtra)
21
+ vars[:page] ||= params[vars[:page_param] || DEFAULT[:page_param]]
23
22
  vars
24
23
  end
25
24
 
@@ -35,6 +34,6 @@ class Pagy
35
34
  pagy.finalize(items_size)
36
35
  items
37
36
  end
38
-
39
37
  end
38
+ Backend.prepend CountlessExtra
40
39
  end
@@ -2,60 +2,77 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  class Pagy
5
+ DEFAULT[:elasticsearch_rails_search_method] ||= :pagy_search
5
6
 
6
- VARS[:elasticsearch_rails_search_method] ||= :pagy_search
7
+ module ElasticsearchRailsExtra
8
+ module_function
7
9
 
8
- module ElasticsearchRails
9
- # returns an array used to delay the call of #search
10
- # after the pagination variables are merged to the options
11
- # it also pushes to the same array an eventually called method
12
- def pagy_elasticsearch_rails(query_or_payload, **options)
13
- [self, query_or_payload, options].tap do |args|
14
- args.define_singleton_method(:method_missing){|*a| args += a}
15
- end
10
+ # Get the count from different version of ElasticsearchRails
11
+ def total_count(response)
12
+ total = if response.respond_to?(:raw_response)
13
+ response.raw_response['hits']['total']
14
+ else
15
+ response.response['hits']['total']
16
+ end
17
+ total.is_a?(Hash) ? total['value'] : total
16
18
  end
17
- alias_method VARS[:elasticsearch_rails_search_method], :pagy_elasticsearch_rails
18
- end
19
-
20
- # create a Pagy object from an Elasticsearch::Model::Response::Response object
21
- def self.new_from_elasticsearch_rails(response, vars={})
22
- vars[:items] = response.search.options[:size] || 10
23
- vars[:page] = (response.search.options[:from] || 0) / vars[:items] + 1
24
- total = response.respond_to?(:raw_response) ? response.raw_response['hits']['total'] : response.response['hits']['total']
25
- vars[:count] = total.is_a?(Hash) ? total['value'] : total
26
- new(vars)
27
- end
28
19
 
29
- # Add specialized backend methods to paginate ElasticsearchRails searches
30
- module Backend
31
- private
32
-
33
- # Return Pagy object and items
34
- def pagy_elasticsearch_rails(pagy_search_args, vars={})
35
- model, query_or_payload, options, *called = pagy_search_args
36
- vars = pagy_elasticsearch_rails_get_vars(nil, vars)
37
- options[:size] = vars[:items]
38
- options[:from] = vars[:items] * (vars[:page] - 1)
39
- response = model.search(query_or_payload, **options)
40
- total = response.respond_to?(:raw_response) ? response.raw_response['hits']['total'] : response.response['hits']['total']
41
- vars[:count] = total.is_a?(Hash) ? total['value'] : total
42
-
43
- pagy = Pagy.new(vars)
44
- # with :last_page overflow we need to re-run the method in order to get the hits
45
- return pagy_elasticsearch_rails(pagy_search_args, vars.merge(page: pagy.page)) \
46
- if defined?(Pagy::UseOverflowExtra) && pagy.overflow? && pagy.vars[:overflow] == :last_page
47
-
48
- [ pagy, called.empty? ? response : response.send(*called) ]
20
+ module ElasticsearchRails
21
+ # Return an array used to delay the call of #search
22
+ # after the pagination variables are merged to the options
23
+ # it also pushes to the same array an eventually called method
24
+ def pagy_elasticsearch_rails(query_or_payload, **options)
25
+ [self, query_or_payload, options].tap do |args|
26
+ args.define_singleton_method(:method_missing) { |*a| args += a }
27
+ end
28
+ end
29
+ alias_method Pagy::DEFAULT[:elasticsearch_rails_search_method], :pagy_elasticsearch_rails
49
30
  end
50
31
 
51
- # Sub-method called only by #pagy_elasticsearch_rails: here for easy customization of variables by overriding
52
- # the _collection argument is not available when the method is called
53
- def pagy_elasticsearch_rails_get_vars(_collection, vars)
54
- pagy_set_items_from_params(vars) if defined?(UseItemsExtra)
55
- vars[:items] ||= VARS[:items]
56
- vars[:page] ||= (params[ vars[:page_param] || VARS[:page_param] ] || 1).to_i
57
- vars
32
+ # Additions for the Pagy class
33
+ module Pagy
34
+ # Create a Pagy object from an Elasticsearch::Model::Response::Response object
35
+ def new_from_elasticsearch_rails(response, vars = {})
36
+ vars[:items] = response.search.options[:size] || 10
37
+ vars[:page] = ((response.search.options[:from] || 0) / vars[:items]) + 1
38
+ vars[:count] = ElasticsearchRailsExtra.total_count(response)
39
+ new(vars)
40
+ end
58
41
  end
59
42
 
43
+ # Add specialized backend methods to paginate ElasticsearchRails searches
44
+ module Backend
45
+ private
46
+
47
+ # Return Pagy object and items
48
+ def pagy_elasticsearch_rails(pagy_search_args, vars = {})
49
+ model, query_or_payload,
50
+ options, *called = pagy_search_args
51
+ vars = pagy_elasticsearch_rails_get_vars(nil, vars)
52
+ options[:size] = vars[:items]
53
+ options[:from] = vars[:items] * (vars[:page] - 1)
54
+ response = model.search(query_or_payload, **options)
55
+ vars[:count] = ElasticsearchRailsExtra.total_count(response)
56
+
57
+ pagy = ::Pagy.new(vars)
58
+ # with :last_page overflow we need to re-run the method in order to get the hits
59
+ return pagy_elasticsearch_rails(pagy_search_args, vars.merge(page: pagy.page)) \
60
+ if defined?(::Pagy::OverflowExtra) && pagy.overflow? && pagy.vars[:overflow] == :last_page
61
+
62
+ [pagy, called.empty? ? response : response.send(*called)]
63
+ end
64
+
65
+ # Sub-method called only by #pagy_elasticsearch_rails: here for easy customization of variables by overriding
66
+ # the _collection argument is not available when the method is called
67
+ def pagy_elasticsearch_rails_get_vars(_collection, vars)
68
+ pagy_set_items_from_params(vars) if defined?(ItemsExtra)
69
+ vars[:items] ||= DEFAULT[:items]
70
+ vars[:page] ||= (params[vars[:page_param] || DEFAULT[:page_param]] || 1).to_i
71
+ vars
72
+ end
73
+ end
60
74
  end
75
+ ElasticsearchRails = ElasticsearchRailsExtra::ElasticsearchRails
76
+ extend ElasticsearchRailsExtra::Pagy
77
+ Backend.prepend ElasticsearchRailsExtra::Backend
61
78
  end
@@ -4,8 +4,7 @@
4
4
  require 'pagy/extras/shared'
5
5
 
6
6
  class Pagy
7
- module Frontend
8
-
7
+ module FoundationExtra
9
8
  # Pagination for Foundation: it returns the html with the series of links to the pages
10
9
  def pagy_foundation_nav(pagy, pagy_id: nil, link_extra: '')
11
10
  p_id = %( id="#{pagy_id}") if pagy_id
@@ -25,8 +24,7 @@ class Pagy
25
24
  end
26
25
 
27
26
  # Javascript pagination for foundation: it returns a nav and a JSON tag used by the Pagy.nav javascript
28
- def pagy_foundation_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
27
+ def pagy_foundation_nav_js(pagy, pagy_id: nil, link_extra: '', steps: nil)
30
28
  p_id = %( id="#{pagy_id}") if pagy_id
31
29
  link = pagy_link_proc(pagy, link_extra: link_extra)
32
30
  tags = { 'before' => %(<ul class="pagination">#{pagy_foundation_prev_html pagy, link}),
@@ -35,52 +33,54 @@ class Pagy
35
33
  'gap' => %(<li class="ellipsis gap" aria-hidden="true"></li>),
36
34
  'after' => %(#{pagy_foundation_next_html pagy, link}</ul>) }
37
35
 
38
- %(<nav#{p_id} class="pagy-njs pagy-foundation-nav-js" aria-label="Pagination" #{pagy_json_attr(pagy, :nav, tags, pagy.sequels(steps))}></nav>)
36
+ %(<nav#{p_id} class="pagy-njs pagy-foundation-nav-js" aria-label="Pagination" #{
37
+ pagy_json_attr(pagy, :nav, tags, pagy.sequels(steps))}></nav>)
39
38
  end
40
39
 
41
40
  # Javascript combo pagination for Foundation: it returns a nav and a JSON tag used by the Pagy.combo_nav javascript
42
- def pagy_foundation_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
41
+ def pagy_foundation_combo_nav_js(pagy, pagy_id: nil, link_extra: '')
44
42
  p_id = %( id="#{pagy_id}") if pagy_id
45
43
  link = pagy_link_proc(pagy, link_extra: link_extra)
46
44
  p_page = pagy.page
47
45
  p_pages = pagy.pages
48
- input = %(<input class="input-group-field cell shrink" type="number" min="1" max="#{p_pages}" value="#{p_page}" style="width: #{p_pages.to_s.length+1}rem; padding: 0 0.3rem; margin: 0 0.3rem;">)
46
+ input = %(<input class="input-group-field cell shrink" type="number" min="1" max="#{
47
+ p_pages}" value="#{p_page}" style="width: #{
48
+ p_pages.to_s.length + 1}rem; padding: 0 0.3rem; margin: 0 0.3rem;">)
49
49
 
50
50
  %(<nav#{p_id} class="pagy-foundation-combo-nav-js" aria-label="Pagination"><div class="input-group" #{
51
- pagy_json_attr pagy, :combo_nav, p_page, pagy_marked_link(link)
52
- }>#{
51
+ pagy_json_attr pagy, :combo_nav, p_page, pagy_marked_link(link)}>#{
53
52
  if (p_prev = pagy.prev)
54
- link.call p_prev, pagy_t('pagy.nav.prev'), 'style="margin-bottom: 0" aria-label="previous" class="prev button primary"'
53
+ link.call p_prev, pagy_t('pagy.nav.prev'),
54
+ 'style="margin-bottom: 0" aria-label="previous" class="prev button primary"'
55
55
  else
56
56
  %(<a style="margin-bottom: 0" class="prev button primary disabled" href="#">#{pagy_t 'pagy.nav.prev'}</a>)
57
57
  end
58
- }<span class="input-group-label">#{pagy_t 'pagy.combo_nav_js', page_input: input, count: p_page, pages: p_pages}</span>#{
58
+ }<span class="input-group-label">#{pagy_t 'pagy.combo_nav_js', page_input: input, count: p_page, pages: p_pages}</span>#{
59
59
  if (p_next = pagy.next)
60
60
  link.call p_next, pagy_t('pagy.nav.next'), 'style="margin-bottom: 0" aria-label="next" class="next button primary"'
61
61
  else
62
62
  %(<a style="margin-bottom: 0" class="next button primary disabled" href="#">#{pagy_t 'pagy.nav.next'}</a>)
63
63
  end
64
- }</div></nav>)
64
+ }</div></nav>)
65
65
  end
66
66
 
67
67
  private
68
68
 
69
- def pagy_foundation_prev_html(pagy, link)
70
- if (p_prev = pagy.prev)
71
- %(<li class="prev">#{link.call p_prev, pagy_t('pagy.nav.prev'), 'aria-label="previous"'}</li>)
72
- else
73
- %(<li class="prev disabled">#{pagy_t 'pagy.nav.prev' }</li>)
74
- end
69
+ def pagy_foundation_prev_html(pagy, link)
70
+ if (p_prev = pagy.prev)
71
+ %(<li class="prev">#{link.call p_prev, pagy_t('pagy.nav.prev'), 'aria-label="previous"'}</li>)
72
+ else
73
+ %(<li class="prev disabled">#{pagy_t 'pagy.nav.prev'}</li>)
75
74
  end
75
+ end
76
76
 
77
- def pagy_foundation_next_html(pagy, link)
78
- if (p_next = pagy.next)
79
- %(<li class="next">#{link.call p_next, pagy_t('pagy.nav.next'), 'aria-label="next"'}</li>)
80
- else
81
- %(<li class="next disabled">#{pagy_t 'pagy.nav.next'}</li>)
82
- end
77
+ def pagy_foundation_next_html(pagy, link)
78
+ if (p_next = pagy.next)
79
+ %(<li class="next">#{link.call p_next, pagy_t('pagy.nav.next'), 'aria-label="next"'}</li>)
80
+ else
81
+ %(<li class="next disabled">#{pagy_t 'pagy.nav.next'}</li>)
83
82
  end
84
-
83
+ end
85
84
  end
85
+ Frontend.prepend FoundationExtra
86
86
  end
@@ -0,0 +1,42 @@
1
+ # See the Pagy documentation: https://ddnexus.github.io/pagy/extras/gearbox
2
+ # frozen_string_literal: true
3
+
4
+ class Pagy
5
+ DEFAULT[:gearbox_extra] = true # extra enabled by default
6
+ DEFAULT[:gearbox_items] = [15, 30, 60, 100]
7
+
8
+ # Automatically change the number of items per page depending on the page number
9
+ # accepts an array as the :gearbox_items variable, that will determine the items for the first pages
10
+ module GearboxExtra
11
+ # Setup @items based on the :items variable
12
+ def setup_items_var
13
+ return super if !@vars[:gearbox_extra] || @vars[:items_extra]
14
+
15
+ gearbox_items = @vars[:gearbox_items]
16
+ raise VariableError.new(self), "expected :gearbox_items to be an Array of positives; got #{gearbox_items.inspect}" \
17
+ unless gearbox_items.is_a?(Array) && gearbox_items.all? { |num| num.positive? rescue false } # rubocop:disable Style/RescueModifier
18
+
19
+ @items = gearbox_items[@page - 1] || gearbox_items.last
20
+ end
21
+
22
+ # Setup @pages and @last based on the :items variable
23
+ def setup_pages_var
24
+ return super if !@vars[:gearbox_extra] || @vars[:items_extra]
25
+
26
+ gearbox_items = @vars[:gearbox_items]
27
+ # This algorithm is thousands of times faster than the one in the geared_pagination gem
28
+ @pages = @last = (if @count > (sum = gearbox_items.sum)
29
+ [((@count - sum).to_f / gearbox_items.last).ceil, 1].max + gearbox_items.count
30
+ else
31
+ pages = 0
32
+ reminder = @count
33
+ while reminder.positive?
34
+ pages += 1
35
+ reminder -= gearbox_items[pages - 1]
36
+ end
37
+ [pages, 1].max
38
+ end)
39
+ end
40
+ end
41
+ prepend GearboxExtra
42
+ end
@@ -1,35 +1,43 @@
1
1
  # See the Pagy documentation: https://ddnexus.github.io/pagy/extras/headers
2
2
  # frozen_string_literal: true
3
3
 
4
+ require 'pagy/url_helpers'
5
+
4
6
  class Pagy
7
+ DEFAULT[:headers] = { page: 'Current-Page',
8
+ items: 'Page-Items',
9
+ count: 'Total-Count',
10
+ pages: 'Total-Pages' }
5
11
  # Add specialized backend methods to add pagination response headers
6
- module Backend
7
- private
8
-
9
- VARS[:headers] = { page: 'Current-Page', items: 'Page-Items', count: 'Total-Count', pages: 'Total-Pages' }
12
+ module HeadersExtra
13
+ include UrlHelpers
10
14
 
11
- include Helpers
15
+ private
12
16
 
17
+ # Merge the pagy headers into the response.headers
13
18
  def pagy_headers_merge(pagy)
14
19
  response.headers.merge!(pagy_headers(pagy))
15
20
  end
16
21
 
22
+ # Generate a hash of RFC-8288 compliant http headers
17
23
  def pagy_headers(pagy)
18
24
  pagy_headers_hash(pagy).tap do |hash|
19
- hash['Link'] = hash['Link'].map{|rel, link| %(<#{link}>; rel="#{rel}")}.join(', ')
25
+ hash['Link'] = hash['Link'].map { |rel, link| %(<#{link}>; rel="#{rel}") }.join(', ')
20
26
  end
21
27
  end
22
28
 
29
+ # Generates a hash structure of the headers
23
30
  def pagy_headers_hash(pagy)
24
- countless = defined?(Pagy::Countless) && pagy.is_a?(Pagy::Countless)
25
- rels = { 'first' => 1, 'prev' => pagy.prev, 'next' => pagy.next }
26
- rels['last'] = pagy.last unless countless
27
- url_str = pagy_url_for(pagy, PAGE_PLACEHOLDER, absolute: true)
28
- hash = { 'Link' => rels.map do |rel, num| # filter_map if ruby >=2.7
29
- next unless num
30
- [ rel, url_str.sub(PAGE_PLACEHOLDER, num.to_s) ]
31
- end.compact.to_h }
32
- headers = pagy.vars[:headers]
31
+ countless = defined?(Pagy::Countless) && pagy.is_a?(Pagy::Countless)
32
+ rel = { 'first' => 1, 'prev' => pagy.prev, 'next' => pagy.next }
33
+ rel['last'] = pagy.last unless countless
34
+ url_str = pagy_url_for(pagy, PAGE_PLACEHOLDER, absolute: true)
35
+ link = rel.map do |r, num| # filter_map if ruby >=2.7
36
+ next unless num # rubocop:disable Layout/EmptyLineAfterGuardClause
37
+ [r, url_str.sub(PAGE_PLACEHOLDER, num.to_s)]
38
+ end.compact.to_h
39
+ hash = { 'Link' => link }
40
+ headers = pagy.vars[:headers]
33
41
  hash[headers[:page]] = pagy.page.to_s if headers[:page]
34
42
  hash[headers[:items]] = pagy.vars[:items].to_s if headers[:items]
35
43
  unless countless
@@ -38,6 +46,6 @@ class Pagy
38
46
  end
39
47
  hash
40
48
  end
41
-
42
49
  end
50
+ Backend.prepend HeadersExtra
43
51
  end
@@ -3,22 +3,13 @@
3
3
 
4
4
  class Pagy
5
5
  # Use ::I18n gem
6
- module Frontend
7
-
8
- ::I18n.load_path += Dir[Pagy.root.join('locales', '*.yml')]
9
-
10
- # unload the pagy default constant for efficiency
11
- Pagy::I18n.clear.instance_eval do
12
- undef :load
13
- undef :t
14
- end
15
-
16
- module UseI18nGem
17
- def pagy_t(key, **opts)
18
- ::I18n.t(key, **opts)
19
- end
6
+ module I18nExtra
7
+ def pagy_t(key, **opts)
8
+ ::I18n.t(key, **opts)
20
9
  end
21
- prepend UseI18nGem
22
-
23
10
  end
11
+ Frontend.prepend I18nExtra
12
+
13
+ # Add the pagy locales to the I18n.load_path
14
+ ::I18n.load_path += Dir[Pagy.root.join('locales', '*.yml')]
24
15
  end
@@ -3,50 +3,49 @@
3
3
 
4
4
  require 'pagy/extras/shared'
5
5
 
6
- class Pagy
6
+ class Pagy # Default variables for this extra
7
+ DEFAULT[:items_param] = :items
8
+ DEFAULT[:max_items] = 100
9
+ DEFAULT[:items_extra] = true # extra enabled by default
7
10
 
8
- # Default variables for this extra
9
- VARS[:items_param] = :items
10
- VARS[:max_items] = 100
11
-
12
- VARS[:enable_items_extra] = true
13
-
14
- ITEMS_PLACEHOLDER = '__pagy_items__'
15
-
16
- module UseItemsExtra; end
17
-
18
- module Backend
19
- private
11
+ module ItemsExtra
12
+ module Backend
13
+ private
20
14
 
15
+ # Set the items variable considering the params and other pagy variables
21
16
  def pagy_set_items_from_params(vars)
22
17
  return if vars[:items]
23
- return unless vars.key?(:enable_item_extra) ? vars[:enable_item_extra] : VARS[:enable_items_extra]
24
- return unless (items = params[vars[:items_param] || VARS[:items_param]]) # :items from :items_param
25
- vars[:items] = [items.to_i, vars.key?(:max_items) ? vars[:max_items] : VARS[:max_items]].compact.min # :items capped to :max_items
26
- end
18
+ return unless vars.key?(:items_extra) ? vars[:items_extra] : DEFAULT[:items_extra]
19
+ return unless (items = params[vars[:items_param] || DEFAULT[:items_param]])
27
20
 
28
- end
29
-
30
- module Frontend
31
-
32
- # Return the items selector HTML. For example "Show [20] items per page"
33
- def pagy_items_selector_js(pagy, deprecated_id=nil, pagy_id: nil, item_name: nil, i18n_key: nil, link_extra: '')
34
- return '' unless pagy.vars[:enable_items_extra]
35
- pagy_id = Pagy.deprecated_arg(:id, deprecated_id, :pagy_id, pagy_id) if deprecated_id
36
- p_id = %( id="#{pagy_id}") if pagy_id
37
- p_vars = pagy.vars
38
- p_items = p_vars[:items]
39
- p_vars[:items] = ITEMS_PLACEHOLDER
40
- link = pagy_marked_link(pagy_link_proc(pagy, link_extra: link_extra))
41
- p_vars[:items] = p_items # restore the items
42
-
43
- html = +%(<span#{p_id} class="pagy-items-selector-js" #{pagy_json_attr pagy, :items_selector, pagy.from, link}>)
44
- input = %(<input type="number" min="1" max="#{p_vars[:max_items]}" value="#{p_items}" style="padding: 0; text-align: center; width: #{p_items.to_s.length+1}rem;">)
45
- html << pagy_t('pagy.items_selector_js', item_name: item_name || pagy_t(i18n_key || p_vars[:i18n_key], count: p_items),
46
- items_input: input,
47
- count: p_items)
48
- html << %(</span>)
21
+ vars[:items] = [items.to_i, vars.key?(:max_items) ? vars[:max_items] : DEFAULT[:max_items]].compact.min
22
+ end
49
23
  end
50
24
 
25
+ module Frontend
26
+ ITEMS_PLACEHOLDER = '__pagy_items__'
27
+
28
+ # Return the items selector HTML. For example "Show [20] items per page"
29
+ def pagy_items_selector_js(pagy, pagy_id: nil, item_name: nil, i18n_key: nil, link_extra: '')
30
+ return '' unless pagy.vars[:items_extra]
31
+
32
+ p_id = %( id="#{pagy_id}") if pagy_id
33
+ p_vars = pagy.vars
34
+ p_items = p_vars[:items]
35
+ p_vars[:items] = ITEMS_PLACEHOLDER
36
+ link = pagy_marked_link(pagy_link_proc(pagy, link_extra: link_extra))
37
+ p_vars[:items] = p_items # restore the items
38
+
39
+ html = +%(<span#{p_id} class="pagy-items-selector-js" #{pagy_json_attr pagy, :items_selector, pagy.from, link}>)
40
+ input = %(<input type="number" min="1" max="#{p_vars[:max_items]}" value="#{
41
+ p_items}" style="padding: 0; text-align: center; width: #{p_items.to_s.length + 1}rem;">)
42
+ html << pagy_t('pagy.items_selector_js', item_name: item_name || pagy_t(i18n_key || p_vars[:i18n_key], count: p_items),
43
+ items_input: input,
44
+ count: p_items)
45
+ html << %(</span>)
46
+ end
47
+ end
51
48
  end
49
+ Backend.prepend ItemsExtra::Backend
50
+ Frontend.prepend ItemsExtra::Frontend
52
51
  end