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.
- checksums.yaml +4 -4
- data/lib/config/pagy.rb +66 -45
- data/lib/javascripts/pagy.js +15 -6
- data/lib/pagy/backend.rb +6 -10
- data/lib/pagy/console.rb +5 -4
- data/lib/pagy/countless.rb +13 -20
- data/lib/pagy/exceptions.rb +2 -4
- data/lib/pagy/extras/arel.rb +6 -6
- data/lib/pagy/extras/array.rb +6 -6
- data/lib/pagy/extras/bootstrap.rb +32 -29
- data/lib/pagy/extras/bulma.rb +40 -32
- data/lib/pagy/extras/countless.rb +8 -9
- data/lib/pagy/extras/elasticsearch_rails.rb +64 -47
- data/lib/pagy/extras/foundation.rb +26 -26
- data/lib/pagy/extras/gearbox.rb +42 -0
- data/lib/pagy/extras/headers.rb +24 -16
- data/lib/pagy/extras/i18n.rb +7 -16
- data/lib/pagy/extras/items.rb +37 -38
- data/lib/pagy/extras/materialize.rb +28 -30
- data/lib/pagy/extras/meilisearch.rb +50 -45
- data/lib/pagy/extras/metadata.rb +29 -13
- data/lib/pagy/extras/navs.rb +24 -26
- data/lib/pagy/extras/overflow.rb +57 -60
- data/lib/pagy/extras/searchkick.rb +51 -45
- data/lib/pagy/extras/semantic.rb +28 -30
- data/lib/pagy/extras/shared.rb +44 -40
- data/lib/pagy/extras/standalone.rb +37 -42
- data/lib/pagy/extras/support.rb +14 -13
- data/lib/pagy/extras/trim.rb +10 -11
- data/lib/pagy/extras/uikit.rb +27 -28
- data/lib/pagy/frontend.rb +22 -47
- data/lib/pagy/i18n.rb +159 -0
- data/lib/pagy/url_helpers.rb +22 -0
- data/lib/pagy.rb +52 -26
- data/lib/templates/uikit_nav.html.erb +1 -1
- data/lib/templates/uikit_nav.html.slim +1 -1
- metadata +7 -10
- data/lib/locales/utils/i18n.rb +0 -17
- data/lib/locales/utils/loader.rb +0 -31
- data/lib/locales/utils/p11n.rb +0 -112
- data/lib/pagy/deprecation.rb +0 -27
data/lib/pagy/extras/bulma.rb
CHANGED
@@ -4,8 +4,7 @@
|
|
4
4
|
require 'pagy/extras/shared'
|
5
5
|
|
6
6
|
class Pagy
|
7
|
-
module
|
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
|
20
|
-
|
21
|
-
when
|
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,
|
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,
|
33
|
-
|
34
|
-
'
|
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(
|
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,
|
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="#{
|
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"
|
50
|
-
|
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
|
-
|
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
|
-
|
71
|
+
}</div></nav>)
|
64
72
|
end
|
65
73
|
|
66
74
|
private
|
67
75
|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
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
|
-
|
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
|
-
[
|
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?(
|
22
|
-
vars[:page] ||= params[
|
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
|
-
|
7
|
+
module ElasticsearchRailsExtra
|
8
|
+
module_function
|
7
9
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
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
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
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
|
-
#
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
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
|
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,
|
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" #{
|
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,
|
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="#{
|
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'),
|
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
|
-
|
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
|
-
|
64
|
+
}</div></nav>)
|
65
65
|
end
|
66
66
|
|
67
67
|
private
|
68
68
|
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
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
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
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
|
data/lib/pagy/extras/headers.rb
CHANGED
@@ -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
|
7
|
-
|
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
|
-
|
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
|
25
|
-
|
26
|
-
|
27
|
-
url_str
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
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
|
data/lib/pagy/extras/i18n.rb
CHANGED
@@ -3,22 +3,13 @@
|
|
3
3
|
|
4
4
|
class Pagy
|
5
5
|
# Use ::I18n gem
|
6
|
-
module
|
7
|
-
|
8
|
-
|
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
|
data/lib/pagy/extras/items.rb
CHANGED
@@ -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
|
-
|
9
|
-
|
10
|
-
|
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?(:
|
24
|
-
return unless (items = params[vars[: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
|
-
|
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
|