pagy 4.11.0 → 5.0.0

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