pagy 43.0.0 → 43.3.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/LICENSE.txt +1 -1
- data/apps/calendar.ru +11 -12
- data/apps/demo.ru +5 -5
- data/apps/enable_rails_page_segment.rb +54 -0
- data/apps/index.rb +1 -1
- data/apps/keynav+root_key.ru +316 -0
- data/apps/keynav.ru +10 -13
- data/apps/keyset.ru +5 -11
- data/apps/keyset_sequel.ru +10 -12
- data/apps/rails.ru +8 -12
- data/apps/repro.ru +11 -11
- data/bin/pagy +2 -94
- data/config/pagy.rb +8 -7
- data/javascripts/ai_widget.js +65 -51
- data/javascripts/pagy.js +20 -17
- data/javascripts/pagy.js.map +3 -3
- data/javascripts/pagy.min.js +2 -1
- data/javascripts/pagy.mjs +19 -16
- data/javascripts/wand.js +15 -9
- data/lib/pagy/classes/calendar/calendar.rb +36 -31
- data/lib/pagy/classes/calendar/day.rb +1 -1
- data/lib/pagy/classes/calendar/month.rb +1 -1
- data/lib/pagy/classes/calendar/quarter.rb +1 -1
- data/lib/pagy/classes/calendar/unit.rb +12 -13
- data/lib/pagy/classes/calendar/year.rb +1 -1
- data/lib/pagy/classes/exceptions.rb +1 -8
- data/lib/pagy/classes/keyset/adapters/active_record.rb +3 -1
- data/lib/pagy/classes/keyset/adapters/sequel.rb +3 -1
- data/lib/pagy/classes/keyset/keynav.rb +9 -4
- data/lib/pagy/classes/keyset/keyset.rb +57 -32
- data/lib/pagy/classes/offset/countish.rb +17 -0
- data/lib/pagy/classes/offset/countless.rb +26 -14
- data/lib/pagy/classes/offset/offset.rb +8 -2
- data/lib/pagy/classes/offset/search.rb +6 -10
- data/lib/pagy/classes/request.rb +29 -20
- data/lib/pagy/cli.rb +135 -0
- data/lib/pagy/console.rb +6 -0
- data/lib/pagy/modules/abilities/configurable.rb +2 -2
- data/lib/pagy/modules/abilities/countable.rb +24 -0
- data/lib/pagy/modules/abilities/linkable.rb +35 -24
- data/lib/pagy/modules/abilities/rangeable.rb +3 -3
- data/lib/pagy/modules/b64.rb +9 -3
- data/lib/pagy/modules/console.rb +15 -20
- data/lib/pagy/modules/i18n/i18n.rb +38 -14
- data/lib/pagy/modules/i18n/p11n/arabic.rb +1 -0
- data/lib/pagy/modules/i18n/p11n/east_slavic.rb +1 -0
- data/lib/pagy/modules/i18n/p11n/polish.rb +1 -0
- data/lib/pagy/modules/searcher.rb +9 -8
- data/lib/pagy/toolbox/helpers/anchor_tags.rb +11 -15
- data/lib/pagy/toolbox/helpers/bootstrap/input_nav_js.rb +3 -0
- data/lib/pagy/toolbox/helpers/bootstrap/series_nav.rb +3 -1
- data/lib/pagy/toolbox/helpers/bootstrap/series_nav_js.rb +2 -0
- data/lib/pagy/toolbox/helpers/bulma/input_nav_js.rb +3 -0
- data/lib/pagy/toolbox/helpers/bulma/previous_next_html.rb +1 -1
- data/lib/pagy/toolbox/helpers/bulma/series_nav.rb +3 -1
- data/lib/pagy/toolbox/helpers/bulma/series_nav_js.rb +2 -0
- data/lib/pagy/toolbox/helpers/data_hash.rb +19 -17
- data/lib/pagy/toolbox/helpers/headers_hash.rb +15 -9
- data/lib/pagy/toolbox/helpers/info_tag.rb +2 -0
- data/lib/pagy/toolbox/helpers/input_nav_js.rb +9 -6
- data/lib/pagy/toolbox/helpers/limit_tag_js.rb +4 -3
- data/lib/pagy/toolbox/helpers/loader.rb +3 -0
- data/lib/pagy/toolbox/helpers/page_url.rb +10 -16
- data/lib/pagy/toolbox/helpers/series_nav.rb +5 -4
- data/lib/pagy/toolbox/helpers/series_nav_js.rb +2 -1
- data/lib/pagy/toolbox/helpers/support/a_lambda.rb +8 -6
- data/lib/pagy/toolbox/helpers/support/data_pagy_attribute.rb +6 -1
- data/lib/pagy/toolbox/helpers/support/series.rb +1 -2
- data/lib/pagy/toolbox/helpers/support/wrap_input_nav_js.rb +1 -1
- data/lib/pagy/toolbox/helpers/support/wrap_series_nav.rb +2 -1
- data/lib/pagy/toolbox/helpers/support/wrap_series_nav_js.rb +10 -4
- data/lib/pagy/toolbox/helpers/urls_hash.rb +7 -7
- data/lib/pagy/toolbox/paginators/calendar.rb +13 -9
- data/lib/pagy/toolbox/paginators/countish.rb +39 -0
- data/lib/pagy/toolbox/paginators/countless.rb +13 -15
- data/lib/pagy/toolbox/paginators/elasticsearch_rails.rb +43 -18
- data/lib/pagy/toolbox/paginators/keynav_js.rb +14 -15
- data/lib/pagy/toolbox/paginators/keyset.rb +7 -9
- data/lib/pagy/toolbox/paginators/meilisearch.rb +21 -18
- data/lib/pagy/toolbox/paginators/method.rb +15 -3
- data/lib/pagy/toolbox/paginators/offset.rb +14 -22
- data/lib/pagy/toolbox/paginators/searchkick.rb +21 -18
- data/lib/pagy/toolbox/paginators/typesense_rails.rb +35 -0
- data/lib/pagy.rb +23 -10
- data/locales/id.yml +1 -3
- data/locales/ja.yml +1 -3
- data/locales/km.yml +1 -3
- data/locales/sw.yml +2 -2
- data/locales/tr.yml +10 -8
- data/stylesheets/pagy-tailwind.css +1 -1
- data/stylesheets/pagy.css +1 -6
- metadata +25 -8
- data/lib/optimist.rb +0 -1022
- data/lib/pagy/classes/keyset/active_record.rb +0 -11
- data/lib/pagy/classes/keyset/keynav/active_record.rb +0 -13
- data/lib/pagy/classes/keyset/keynav/sequel.rb +0 -13
- data/lib/pagy/classes/keyset/sequel.rb +0 -11
|
@@ -12,6 +12,7 @@ class Pagy
|
|
|
12
12
|
# Build the nav tag, with the specific inner html for the style
|
|
13
13
|
def wrap_series_nav(html, nav_classes, id: nil, aria_label: nil, **)
|
|
14
14
|
data = %( #{data_pagy_attribute(:k, @update)}) if keynav?
|
|
15
|
-
|
|
15
|
+
|
|
16
|
+
%(<nav#{%( id="#{id}") if id} class="#{nav_classes}" #{nav_aria_label_attribute(aria_label:)}#{data}>#{html}</nav>)
|
|
16
17
|
end
|
|
17
18
|
end
|
|
@@ -20,15 +20,21 @@ class Pagy
|
|
|
20
20
|
|
|
21
21
|
# Support for the Calendar API
|
|
22
22
|
def page_labels(series)
|
|
23
|
-
|
|
23
|
+
return unless calendar?
|
|
24
|
+
|
|
25
|
+
series.map do |s|
|
|
26
|
+
s.map { _1 == :gap ? :gap : page_label(_1) }
|
|
27
|
+
end
|
|
24
28
|
end
|
|
25
29
|
|
|
26
30
|
# Build the nav_js tag, with the specific tokens for the style
|
|
27
31
|
def wrap_series_nav_js(tokens, nav_classes, id: nil, aria_label: nil, **)
|
|
28
|
-
sequels
|
|
29
|
-
|
|
32
|
+
sequels = sequels(**)
|
|
33
|
+
nav_classes = "pagy-rjs #{nav_classes}" if sequels[0].size > 1
|
|
34
|
+
|
|
35
|
+
%(<nav#{%( id="#{id}") if id} class="#{nav_classes}" #{
|
|
30
36
|
nav_aria_label_attribute(aria_label:)} #{
|
|
31
|
-
data = [:snj, tokens.values, sequels]
|
|
37
|
+
data = [:snj, tokens.values, PAGE_TOKEN, sequels]
|
|
32
38
|
data.push(@update) if keynav?
|
|
33
39
|
data_pagy_attribute(*data)
|
|
34
40
|
}></nav>)
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
class Pagy
|
|
4
|
-
#
|
|
4
|
+
# Generate the hash of the pagination links
|
|
5
5
|
def urls_hash(**)
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
6
|
+
template = compose_page_url(PAGE_TOKEN, **)
|
|
7
|
+
|
|
8
|
+
{ first: compose_page_url(nil, **),
|
|
9
|
+
previous: @previous && template.sub(PAGE_TOKEN, @previous.to_s),
|
|
10
|
+
next: @next && template.sub(PAGE_TOKEN, @next.to_s),
|
|
11
|
+
last: @count && template.sub(PAGE_TOKEN, @last.to_s) }.compact
|
|
12
12
|
end
|
|
13
13
|
end
|
|
@@ -8,20 +8,24 @@ class Pagy
|
|
|
8
8
|
def paginate(context, collection, config)
|
|
9
9
|
context.instance_eval do
|
|
10
10
|
allowed_options = Calendar::UNITS + %i[offset disabled request]
|
|
11
|
-
raise ArgumentError, "keys must be in #{allowed_options.inspect}" \
|
|
12
|
-
unless config.is_a?(Hash) && (config.keys - allowed_options).empty?
|
|
13
11
|
|
|
14
|
-
config
|
|
12
|
+
unless config.is_a?(Hash) && (config.keys - allowed_options).empty?
|
|
13
|
+
raise ArgumentError, "keys must be in #{allowed_options.inspect}"
|
|
14
|
+
end
|
|
15
|
+
|
|
15
16
|
config[:offset] ||= {}
|
|
17
|
+
|
|
16
18
|
unless config[:disabled]
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
19
|
+
period = pagy_calendar_period(collection)
|
|
20
|
+
params = config[:request].params
|
|
21
|
+
|
|
22
|
+
calendar, from, to = Calendar.send(:init, config, period, params) do |unit, unit_period|
|
|
23
|
+
pagy_calendar_counts(collection, unit, *unit_period) if respond_to?(:pagy_calendar_counts)
|
|
24
|
+
end
|
|
25
|
+
|
|
23
26
|
collection = pagy_calendar_filter(collection, from, to)
|
|
24
27
|
end
|
|
28
|
+
|
|
25
29
|
pagy, records = pagy(:offset, collection, **config[:offset])
|
|
26
30
|
[calendar, pagy, records]
|
|
27
31
|
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative '../../modules/abilities/countable'
|
|
4
|
+
|
|
5
|
+
class Pagy
|
|
6
|
+
module CountishPaginator
|
|
7
|
+
module_function
|
|
8
|
+
|
|
9
|
+
# Return the Offset::Countish instance and records
|
|
10
|
+
def paginate(collection, options)
|
|
11
|
+
options[:page] ||= options[:request].resolve_page(force_integer: false)
|
|
12
|
+
|
|
13
|
+
if options[:page].is_a?(String)
|
|
14
|
+
page, count, epoch = options[:page].split.map(&:to_i)
|
|
15
|
+
options[:page] = page
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
options[:limit] = options[:request].resolve_limit
|
|
19
|
+
setup_options(count, epoch, collection, options)
|
|
20
|
+
|
|
21
|
+
pagy = Offset::Countish.new(**options)
|
|
22
|
+
[pagy, pagy.records(collection)]
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# Get the count from the page and set epoch when ttl (Time To Live) requires it
|
|
26
|
+
def setup_options(count, epoch, collection, options)
|
|
27
|
+
now = Time.now.to_i
|
|
28
|
+
ongoing = !options[:ttl] || (epoch && epoch <= now && now < (epoch + options[:ttl]))
|
|
29
|
+
|
|
30
|
+
if !options[:count] && count && ongoing
|
|
31
|
+
options[:count] = count
|
|
32
|
+
options[:epoch] = epoch if options[:ttl]
|
|
33
|
+
else # recount
|
|
34
|
+
options[:count] ||= Countable.get_count(collection, options)
|
|
35
|
+
options[:epoch] = now if options[:ttl]
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -4,22 +4,20 @@ class Pagy
|
|
|
4
4
|
module CountlessPaginator
|
|
5
5
|
module_function
|
|
6
6
|
|
|
7
|
-
# Return
|
|
8
|
-
def paginate(
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
options[:page] = p if p.positive?
|
|
16
|
-
options[:last] = l if l&.positive?
|
|
17
|
-
end
|
|
18
|
-
end
|
|
19
|
-
options[:limit] = request.resolve_limit(options)
|
|
20
|
-
pagy = Offset::Countless.new(**options, request:)
|
|
21
|
-
[pagy, pagy.records(collection)]
|
|
7
|
+
# Return the Offset::Countless instance and records
|
|
8
|
+
def paginate(collection, options)
|
|
9
|
+
options[:page] ||= options[:request].resolve_page(force_integer: false) # accept nil and strings
|
|
10
|
+
|
|
11
|
+
if options[:page].is_a?(String)
|
|
12
|
+
page, last = options[:page].split.map(&:to_i) # ' ' separator, (encoded as '+' by Countless#compose_page_param)
|
|
13
|
+
options[:page] = page
|
|
14
|
+
options[:last] = last if last&.positive?
|
|
22
15
|
end
|
|
16
|
+
|
|
17
|
+
options[:limit] = options[:request].resolve_limit
|
|
18
|
+
|
|
19
|
+
pagy = Offset::Countless.new(**options)
|
|
20
|
+
[pagy, pagy.records(collection)]
|
|
23
21
|
end
|
|
24
22
|
end
|
|
25
23
|
end
|
|
@@ -7,26 +7,51 @@ class Pagy
|
|
|
7
7
|
module_function
|
|
8
8
|
|
|
9
9
|
# Paginate from the search object
|
|
10
|
-
def paginate(
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
options[:limit] = search.search.options[:size] || 10
|
|
25
|
-
options[:page] = ((search.search.options[:from] || 0) / options[:limit]) + 1
|
|
26
|
-
options[:count] = ElasticsearchRails.total_count(search)
|
|
27
|
-
ElasticsearchRails.new(**options)
|
|
10
|
+
def paginate(search, options)
|
|
11
|
+
if search.is_a?(Search::Arguments) # Active mode
|
|
12
|
+
|
|
13
|
+
Searcher.wrap(search, options) do
|
|
14
|
+
model, arguments, search_options = search
|
|
15
|
+
|
|
16
|
+
search_options[:size] = options[:limit]
|
|
17
|
+
search_options[:from] = options[:limit] * ((options[:page] || 1) - 1)
|
|
18
|
+
|
|
19
|
+
method = options[:search_method] || ElasticsearchRails::DEFAULT[:search_method]
|
|
20
|
+
response_object = model.send(method, *arguments, **search_options)
|
|
21
|
+
options[:count] = total_count_from(response_object)
|
|
22
|
+
|
|
23
|
+
[ElasticsearchRails.new(**options), response_object]
|
|
28
24
|
end
|
|
25
|
+
|
|
26
|
+
else # Passive mode
|
|
27
|
+
from, size = pagination_params_from(search)
|
|
28
|
+
options[:limit] = size
|
|
29
|
+
options[:page] = ((from || 0) / options[:limit]) + 1
|
|
30
|
+
options[:count] = total_count_from(search)
|
|
31
|
+
|
|
32
|
+
ElasticsearchRails.new(**options)
|
|
29
33
|
end
|
|
30
34
|
end
|
|
35
|
+
|
|
36
|
+
# Get from and size params from the response object, supporting different versions of ElasticsearchRails
|
|
37
|
+
def pagination_params_from(response_object)
|
|
38
|
+
definition = response_object.search.definition
|
|
39
|
+
definition = definition.to_hash if definition.respond_to?(:to_hash)
|
|
40
|
+
container = (definition.is_a?(Hash) && (definition[:body] || definition)) || response_object.search.options
|
|
41
|
+
from = (container[:from] || container['from']).to_i
|
|
42
|
+
size = (container[:size] || container['size']).to_i
|
|
43
|
+
size = 10 if size.zero?
|
|
44
|
+
|
|
45
|
+
[from, size]
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Get the count from the response object, supporting different versions of ElasticsearchRails
|
|
49
|
+
def total_count_from(response_object)
|
|
50
|
+
total = response_object.instance_eval do
|
|
51
|
+
respond_to?(:response) ? response['hits']['total'] : raw_response['hits']['total']
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
total.is_a?(Hash) ? total['value'] : total
|
|
55
|
+
end
|
|
31
56
|
end
|
|
32
57
|
end
|
|
@@ -6,24 +6,23 @@ class Pagy
|
|
|
6
6
|
module KeynavJsPaginator
|
|
7
7
|
module_function
|
|
8
8
|
|
|
9
|
-
# Return Pagy::Keyset::Keynav
|
|
9
|
+
# Return the Pagy::Keyset::Keynav instance and paginated records.
|
|
10
10
|
# Fall back to :countless if the :page has no client data.
|
|
11
|
-
def paginate(
|
|
12
|
-
|
|
13
|
-
request = Request.new(options[:request] || self.request, options)
|
|
14
|
-
page = request.resolve_page(options, force_integer: false) # allow nil
|
|
15
|
-
if page&.match(' ') # countless page -> no augmentation -> fallback
|
|
16
|
-
return pagy(:countless, set, page:, **options)
|
|
17
|
-
elsif page.is_a?(String) # keynav page param
|
|
18
|
-
page_arguments = JSON.parse(B64.urlsafe_decode(page))
|
|
19
|
-
# Restart the pagination from page 1 if the url has been requested from another browser
|
|
20
|
-
options[:page] = page_arguments if request.cookie == page_arguments.shift
|
|
21
|
-
end
|
|
11
|
+
def paginate(set, options)
|
|
12
|
+
page = options[:request].resolve_page(force_integer: false) # allow nil
|
|
22
13
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
14
|
+
return CountlessPaginator.paginate(set, page:, **options) if page&.match(' ') # countless fallback
|
|
15
|
+
|
|
16
|
+
if page.is_a?(String) # keynav page param
|
|
17
|
+
page_arguments = JSON.parse(B64.urlsafe_decode(page))
|
|
18
|
+
# Restart the pagination from page 1/nil if the url has been requested from another browser
|
|
19
|
+
options[:page] = page_arguments if options[:request].cookie == page_arguments.shift
|
|
26
20
|
end
|
|
21
|
+
|
|
22
|
+
options[:limit] = options[:request].resolve_limit
|
|
23
|
+
|
|
24
|
+
pagy = Keyset::Keynav.new(set, **options)
|
|
25
|
+
[pagy, pagy.records]
|
|
27
26
|
end
|
|
28
27
|
end
|
|
29
28
|
end
|
|
@@ -4,15 +4,13 @@ class Pagy
|
|
|
4
4
|
module KeysetPaginator
|
|
5
5
|
module_function
|
|
6
6
|
|
|
7
|
-
# Return Pagy::Keyset
|
|
8
|
-
def paginate(
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
[pagy, pagy.records]
|
|
15
|
-
end
|
|
7
|
+
# Return Pagy::Keyset instance and paginated records
|
|
8
|
+
def paginate(set, options)
|
|
9
|
+
options[:page] ||= options[:request].resolve_page(force_integer: false) # allow nil
|
|
10
|
+
options[:limit] = options[:request].resolve_limit
|
|
11
|
+
|
|
12
|
+
pagy = Keyset.new(set, **options)
|
|
13
|
+
[pagy, pagy.records]
|
|
16
14
|
end
|
|
17
15
|
end
|
|
18
16
|
end
|
|
@@ -7,25 +7,28 @@ class Pagy
|
|
|
7
7
|
module_function
|
|
8
8
|
|
|
9
9
|
# Paginate from the search object
|
|
10
|
-
def paginate(
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
options[:limit] = search.raw_answer['hitsPerPage']
|
|
25
|
-
options[:page] = search.raw_answer['page']
|
|
26
|
-
options[:count] = search.raw_answer['totalHits']
|
|
27
|
-
Meilisearch.new(**options)
|
|
10
|
+
def paginate(search, options)
|
|
11
|
+
if search.is_a?(Search::Arguments) # Active mode
|
|
12
|
+
|
|
13
|
+
Searcher.wrap(search, options) do
|
|
14
|
+
model, arguments, search_options = search
|
|
15
|
+
|
|
16
|
+
search_options[:hits_per_page] = options[:limit]
|
|
17
|
+
search_options[:page] = options[:page]
|
|
18
|
+
|
|
19
|
+
method = options[:search_method] || Meilisearch::DEFAULT[:search_method]
|
|
20
|
+
results = model.send(method, *arguments, search_options)
|
|
21
|
+
options[:count] = results.raw_answer['totalHits']
|
|
22
|
+
|
|
23
|
+
[Meilisearch.new(**options), results]
|
|
28
24
|
end
|
|
25
|
+
|
|
26
|
+
else # Passive mode
|
|
27
|
+
options[:limit] = search.raw_answer['hitsPerPage']
|
|
28
|
+
options[:page] = search.raw_answer['page']
|
|
29
|
+
options[:count] = search.raw_answer['totalHits']
|
|
30
|
+
|
|
31
|
+
Meilisearch.new(**options)
|
|
29
32
|
end
|
|
30
33
|
end
|
|
31
34
|
end
|
|
@@ -5,22 +5,34 @@ require_relative '../../classes/request'
|
|
|
5
5
|
class Pagy
|
|
6
6
|
paginators = { offset: :OffsetPaginator,
|
|
7
7
|
countless: :CountlessPaginator,
|
|
8
|
+
countish: :CountishPaginator,
|
|
8
9
|
keyset: :KeysetPaginator,
|
|
9
10
|
keynav_js: :KeynavJsPaginator,
|
|
10
11
|
calendar: :CalendarPaginator,
|
|
11
12
|
elasticsearch_rails: :ElasticsearchRailsPaginator,
|
|
12
13
|
meilisearch: :MeilisearchPaginator,
|
|
13
|
-
searchkick: :SearchkickPaginator
|
|
14
|
+
searchkick: :SearchkickPaginator,
|
|
15
|
+
typesense_rails: :TypesenseRailsPaginator }.freeze
|
|
14
16
|
|
|
15
17
|
path = Pathname.new(__dir__)
|
|
16
18
|
paginators.each { |symbol, name| autoload name, path.join(symbol.to_s) }
|
|
17
19
|
|
|
18
|
-
#
|
|
20
|
+
# Pagy::Method defines the #pagy method to be included in the app controller/view.
|
|
19
21
|
Method = Module.new do
|
|
20
22
|
protected
|
|
21
23
|
|
|
22
24
|
define_method :pagy do |paginator = :offset, collection, **options|
|
|
23
|
-
|
|
25
|
+
arguments = if paginator == :calendar
|
|
26
|
+
[self, collection, options]
|
|
27
|
+
else
|
|
28
|
+
[collection, options = Pagy::OPTIONS.merge(options)]
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
options[:root_key] = 'page' if options[:jsonapi] # enforce 'page' root_key for JSON:API
|
|
32
|
+
options[:request] ||= request # user set request or self.request
|
|
33
|
+
options[:request] = Request.new(options) # Pagy::Request
|
|
34
|
+
|
|
35
|
+
Pagy.const_get(paginators[paginator]).paginate(*arguments)
|
|
24
36
|
end
|
|
25
37
|
end
|
|
26
38
|
end
|
|
@@ -1,33 +1,25 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require_relative '../../modules/abilities/countable'
|
|
4
|
+
|
|
3
5
|
class Pagy
|
|
4
6
|
module OffsetPaginator
|
|
5
7
|
module_function
|
|
6
8
|
|
|
7
|
-
# Return instance and
|
|
8
|
-
def paginate(
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
options[:limit] = request.resolve_limit(options)
|
|
13
|
-
options[:count] ||= collection.instance_of?(Array) ? collection.size : OffsetPaginator.get_count(collection, options)
|
|
14
|
-
pagy = Offset.new(**options, request:)
|
|
15
|
-
[pagy, collection.instance_of?(Array) ? collection[pagy.offset, pagy.limit] : pagy.records(collection)]
|
|
16
|
-
end
|
|
17
|
-
end
|
|
9
|
+
# Return the Pagy::Offset instance and results
|
|
10
|
+
def paginate(collection, options)
|
|
11
|
+
options[:page] ||= options[:request].resolve_page
|
|
12
|
+
options[:limit] = options[:request].resolve_limit
|
|
13
|
+
options[:count] ||= Countable.get_count(collection, options)
|
|
18
14
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
15
|
+
pagy = Offset.new(**options)
|
|
16
|
+
records = if collection.instance_of?(Array)
|
|
17
|
+
collection[pagy.offset, pagy.limit]
|
|
18
|
+
else
|
|
19
|
+
pagy.records(collection)
|
|
20
|
+
end
|
|
22
21
|
|
|
23
|
-
|
|
24
|
-
# COUNT(*) OVER ()
|
|
25
|
-
sql = Arel.star.count.over(Arel::Nodes::Grouping.new([]))
|
|
26
|
-
collection.unscope(:order).pick(sql).to_i
|
|
27
|
-
else
|
|
28
|
-
collection.count(:all)
|
|
29
|
-
end
|
|
30
|
-
count.is_a?(Hash) ? count.size : count
|
|
22
|
+
[pagy, records]
|
|
31
23
|
end
|
|
32
24
|
end
|
|
33
25
|
end
|
|
@@ -7,25 +7,28 @@ class Pagy
|
|
|
7
7
|
module_function
|
|
8
8
|
|
|
9
9
|
# Paginate from the search object
|
|
10
|
-
def paginate(
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
options[:limit] = search.options[:per_page]
|
|
25
|
-
options[:page] = search.options[:page]
|
|
26
|
-
options[:count] = search.total_count
|
|
27
|
-
Searchkick.new(**options)
|
|
10
|
+
def paginate(search, options)
|
|
11
|
+
if search.is_a?(Search::Arguments) # Active mode
|
|
12
|
+
|
|
13
|
+
Searcher.wrap(search, options) do
|
|
14
|
+
model, arguments, search_options, block = search
|
|
15
|
+
|
|
16
|
+
search_options[:per_page] = options[:limit]
|
|
17
|
+
search_options[:page] = options[:page]
|
|
18
|
+
|
|
19
|
+
method = options[:search_method] || Searchkick::DEFAULT[:search_method]
|
|
20
|
+
results = model.send(method, *arguments || '*', **search_options, &block)
|
|
21
|
+
options[:count] = results.total_count
|
|
22
|
+
|
|
23
|
+
[Searchkick.new(**options), results]
|
|
28
24
|
end
|
|
25
|
+
|
|
26
|
+
else # Passive mode
|
|
27
|
+
options[:limit] = search.respond_to?(:options) ? search.options[:per_page] : search.per_page
|
|
28
|
+
options[:page] = search.respond_to?(:options) ? search.options[:page] : search.current_page
|
|
29
|
+
options[:count] = search.total_count
|
|
30
|
+
|
|
31
|
+
Searchkick.new(**options)
|
|
29
32
|
end
|
|
30
33
|
end
|
|
31
34
|
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative '../../modules/searcher'
|
|
4
|
+
|
|
5
|
+
class Pagy
|
|
6
|
+
module TypesenseRailsPaginator
|
|
7
|
+
module_function
|
|
8
|
+
|
|
9
|
+
# Paginate from the search object
|
|
10
|
+
def paginate(search, options)
|
|
11
|
+
if search.is_a?(Search::Arguments) # Active mode
|
|
12
|
+
|
|
13
|
+
Searcher.wrap(search, options) do
|
|
14
|
+
model, arguments, search_options = search
|
|
15
|
+
|
|
16
|
+
search_options[:per_page] = options[:limit]
|
|
17
|
+
search_options[:page] = options[:page]
|
|
18
|
+
|
|
19
|
+
method = options[:search_method] || TypesenseRails::DEFAULT[:search_method]
|
|
20
|
+
results = model.send(method, *arguments, search_options)
|
|
21
|
+
options[:count] = results.raw_answer['found']
|
|
22
|
+
|
|
23
|
+
[TypesenseRails.new(**options), results]
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
else # Passive mode
|
|
27
|
+
options[:limit] = search.raw_answer['request_params']['per_page']
|
|
28
|
+
options[:page] = search.raw_answer['page']
|
|
29
|
+
options[:count] = search.raw_answer['found']
|
|
30
|
+
|
|
31
|
+
TypesenseRails.new(**options)
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
data/lib/pagy.rb
CHANGED
|
@@ -1,18 +1,20 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require 'pathname'
|
|
4
|
+
|
|
4
5
|
require_relative 'pagy/classes/exceptions'
|
|
5
6
|
require_relative 'pagy/modules/abilities/linkable'
|
|
6
7
|
require_relative 'pagy/modules/abilities/configurable'
|
|
7
8
|
require_relative 'pagy/toolbox/helpers/loader'
|
|
8
9
|
|
|
9
10
|
# Top superclass: it defines only what's common to all the subclasses
|
|
11
|
+
# noinspection RubyMismatchedArgumentType
|
|
10
12
|
class Pagy
|
|
11
|
-
VERSION = '43.
|
|
13
|
+
VERSION = '43.3.0'
|
|
12
14
|
ROOT = Pathname.new(__dir__).parent.freeze
|
|
13
15
|
DEFAULT = { limit: 20, limit_key: 'limit', page_key: 'page' }.freeze
|
|
14
|
-
PAGE_TOKEN = 'P '
|
|
15
|
-
LIMIT_TOKEN = 'L '
|
|
16
|
+
PAGE_TOKEN = EscapedValue.new('P ')
|
|
17
|
+
LIMIT_TOKEN = EscapedValue.new('L ')
|
|
16
18
|
LABEL_TOKEN = 'L'
|
|
17
19
|
A_TAG = '<a style="display: none;">#</a>'
|
|
18
20
|
|
|
@@ -26,9 +28,11 @@ class Pagy
|
|
|
26
28
|
autoload :ElasticsearchRails, path.join('classes/offset/search')
|
|
27
29
|
autoload :Meilisearch, path.join('classes/offset/search')
|
|
28
30
|
autoload :Searchkick, path.join('classes/offset/search')
|
|
31
|
+
autoload :TypesenseRails, path.join('classes/offset/search')
|
|
29
32
|
autoload :Keyset, path.join('classes/keyset/keyset')
|
|
30
33
|
|
|
31
|
-
|
|
34
|
+
OPTIONS = {} # rubocop:disable Style/MutableConstant
|
|
35
|
+
def self.options = OPTIONS
|
|
32
36
|
|
|
33
37
|
extend Configurable
|
|
34
38
|
include Linkable
|
|
@@ -46,11 +50,16 @@ class Pagy
|
|
|
46
50
|
def keyset? = false
|
|
47
51
|
def keynav? = false
|
|
48
52
|
|
|
49
|
-
# Validates and assign the passed options:
|
|
53
|
+
# Validates and assign the passed options: they must be present and value.to_i must be >= min
|
|
50
54
|
def assign_and_check(name_min)
|
|
51
55
|
name_min.each do |name, min|
|
|
52
|
-
|
|
53
|
-
|
|
56
|
+
value = @options[name]
|
|
57
|
+
|
|
58
|
+
if value.respond_to?(:to_i) && (integer = value.to_i) >= min
|
|
59
|
+
instance_variable_set(:"@#{name}", integer)
|
|
60
|
+
else
|
|
61
|
+
raise OptionError.new(self, name, ">= #{min}", value)
|
|
62
|
+
end
|
|
54
63
|
end
|
|
55
64
|
end
|
|
56
65
|
|
|
@@ -59,10 +68,14 @@ class Pagy
|
|
|
59
68
|
@request = options.delete(:request) # internal object
|
|
60
69
|
default = {}
|
|
61
70
|
current = self.class
|
|
62
|
-
|
|
71
|
+
|
|
72
|
+
loop do
|
|
63
73
|
default = current::DEFAULT.merge(default)
|
|
64
74
|
current = current.superclass
|
|
65
|
-
|
|
66
|
-
|
|
75
|
+
break if current == Object
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
clean_options = options.delete_if { |k, v| default.key?(k) && (v.nil? || v == '') }
|
|
79
|
+
@options = default.merge!(clean_options).freeze
|
|
67
80
|
end
|
|
68
81
|
end
|
data/locales/id.yml
CHANGED
|
@@ -4,9 +4,7 @@ id:
|
|
|
4
4
|
pagy:
|
|
5
5
|
p11n: 'Other'
|
|
6
6
|
aria_label:
|
|
7
|
-
|
|
8
|
-
# posting the translation of the following "Page"/"Pages" with the plurals for this locale
|
|
9
|
-
nav: "Pages"
|
|
7
|
+
nav: "Halaman"
|
|
10
8
|
previous: "Sebelumnya"
|
|
11
9
|
next: "Selanjutnya"
|
|
12
10
|
previous: "<"
|
data/locales/ja.yml
CHANGED
|
@@ -4,9 +4,7 @@ ja:
|
|
|
4
4
|
pagy:
|
|
5
5
|
p11n: 'Other'
|
|
6
6
|
aria_label:
|
|
7
|
-
|
|
8
|
-
# posting the translation of the following "Page"/"Pages" with the plurals for this locale
|
|
9
|
-
nav: "Pages"
|
|
7
|
+
nav: "ページ"
|
|
10
8
|
previous: "前へ"
|
|
11
9
|
next: "次へ"
|
|
12
10
|
previous: "<"
|
data/locales/km.yml
CHANGED
|
@@ -4,9 +4,7 @@ km:
|
|
|
4
4
|
pagy:
|
|
5
5
|
p11n: 'Other'
|
|
6
6
|
aria_label:
|
|
7
|
-
|
|
8
|
-
# posting the translation of the following "Page"/"Pages" with the plurals for this locale
|
|
9
|
-
nav: "Pages"
|
|
7
|
+
nav: "ទំព័រ"
|
|
10
8
|
previous: "មុន"
|
|
11
9
|
next: "បន្ទាប់"
|
|
12
10
|
previous: "<"
|