pagy 9.3.5 → 43.0.0.rc1
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/apps/calendar.ru +547 -551
- data/apps/demo.ru +221 -178
- data/apps/index.rb +3 -1
- data/apps/keynav.ru +258 -0
- data/apps/{keyset_ar.ru → keyset.ru} +27 -32
- data/apps/{keyset_s.ru → keyset_sequel.ru} +24 -29
- data/apps/rails.ru +51 -48
- data/apps/repro.ru +46 -43
- data/bin/pagy +20 -21
- data/config/pagy.rb +35 -207
- data/javascripts/ai_widget.js +76 -0
- data/javascripts/pagy.js +151 -0
- data/javascripts/pagy.js.map +10 -0
- data/javascripts/pagy.min.js +1 -4
- data/javascripts/pagy.mjs +111 -63
- data/javascripts/wand.js +1166 -0
- data/lib/pagy/classes/calendar/calendar.rb +98 -0
- data/lib/pagy/{calendar → classes/calendar}/day.rb +7 -11
- data/lib/pagy/{calendar → classes/calendar}/month.rb +5 -10
- data/lib/pagy/{calendar → classes/calendar}/quarter.rb +10 -15
- data/lib/pagy/classes/calendar/unit.rb +92 -0
- data/lib/pagy/{calendar → classes/calendar}/week.rb +5 -9
- data/lib/pagy/{calendar → classes/calendar}/year.rb +5 -6
- data/lib/pagy/classes/exceptions.rb +33 -0
- data/lib/pagy/classes/keyset/active_record.rb +11 -0
- data/lib/pagy/classes/keyset/adapters/active_record.rb +50 -0
- data/lib/pagy/classes/keyset/adapters/sequel.rb +63 -0
- data/lib/pagy/classes/keyset/keynav/active_record.rb +13 -0
- data/lib/pagy/classes/keyset/keynav/sequel.rb +13 -0
- data/lib/pagy/classes/keyset/keynav.rb +77 -0
- data/lib/pagy/classes/keyset/keyset.rb +126 -0
- data/lib/pagy/classes/keyset/sequel.rb +11 -0
- data/lib/pagy/classes/offset/countless.rb +56 -0
- data/lib/pagy/classes/offset/offset.rb +54 -0
- data/lib/pagy/classes/offset/search.rb +38 -0
- data/lib/pagy/classes/request.rb +36 -0
- data/lib/pagy/modules/abilities/configurable.rb +36 -0
- data/lib/pagy/modules/abilities/linkable.rb +59 -0
- data/lib/pagy/modules/abilities/rangeable.rb +15 -0
- data/lib/pagy/modules/abilities/shiftable.rb +12 -0
- data/lib/pagy/{b64.rb → modules/b64.rb} +3 -7
- data/lib/pagy/modules/console.rb +38 -0
- data/lib/pagy/modules/i18n/i18n.rb +48 -0
- data/lib/pagy/modules/i18n/p11n/arabic.rb +29 -0
- data/lib/pagy/modules/i18n/p11n/east_slavic.rb +26 -0
- data/lib/pagy/modules/i18n/p11n/one_other.rb +15 -0
- data/lib/pagy/modules/i18n/p11n/one_upto_two_other.rb +15 -0
- data/lib/pagy/modules/i18n/p11n/other.rb +13 -0
- data/lib/pagy/modules/i18n/p11n/polish.rb +26 -0
- data/lib/pagy/modules/i18n/p11n/west_slavic.rb +22 -0
- data/lib/pagy/modules/i18n/p11n.rb +16 -0
- data/lib/pagy/modules/searcher.rb +20 -0
- data/lib/pagy/toolbox/helpers/anchor_tags.rb +25 -0
- data/lib/pagy/toolbox/helpers/bootstrap/input_nav_js.rb +24 -0
- data/lib/pagy/toolbox/helpers/bootstrap/previous_next_html.rb +18 -0
- data/lib/pagy/toolbox/helpers/bootstrap/series_nav.rb +29 -0
- data/lib/pagy/toolbox/helpers/bootstrap/series_nav_js.rb +21 -0
- data/lib/pagy/toolbox/helpers/bulma/input_nav_js.rb +21 -0
- data/lib/pagy/toolbox/helpers/bulma/previous_next_html.rb +19 -0
- data/lib/pagy/toolbox/helpers/bulma/series_nav.rb +28 -0
- data/lib/pagy/toolbox/helpers/bulma/series_nav_js.rb +20 -0
- data/lib/pagy/toolbox/helpers/data_hash.rb +26 -0
- data/lib/pagy/toolbox/helpers/headers_hash.rb +20 -0
- data/lib/pagy/toolbox/helpers/info_tag.rb +26 -0
- data/lib/pagy/toolbox/helpers/input_nav_js.rb +19 -0
- data/lib/pagy/toolbox/helpers/limit_tag_js.rb +23 -0
- data/lib/pagy/toolbox/helpers/loader.rb +33 -0
- data/lib/pagy/toolbox/helpers/page_url.rb +23 -0
- data/lib/pagy/toolbox/helpers/series_nav.rb +29 -0
- data/lib/pagy/toolbox/helpers/series_nav_js.rb +19 -0
- data/lib/pagy/toolbox/helpers/support/a_lambda.rb +34 -0
- data/lib/pagy/toolbox/helpers/support/data_pagy_attribute.rb +15 -0
- data/lib/pagy/toolbox/helpers/support/nav_aria_label_attribute.rb +12 -0
- data/lib/pagy/toolbox/helpers/support/series.rb +38 -0
- data/lib/pagy/toolbox/helpers/support/wrap_input_nav_js.rb +20 -0
- data/lib/pagy/toolbox/helpers/support/wrap_series_nav.rb +17 -0
- data/lib/pagy/toolbox/helpers/support/wrap_series_nav_js.rb +36 -0
- data/lib/pagy/toolbox/helpers/urls_hash.rb +13 -0
- data/lib/pagy/toolbox/paginators/calendar.rb +30 -0
- data/lib/pagy/toolbox/paginators/countless.rb +25 -0
- data/lib/pagy/toolbox/paginators/elasticsearch_rails.rb +32 -0
- data/lib/pagy/toolbox/paginators/keynav_js.rb +29 -0
- data/lib/pagy/toolbox/paginators/keyset.rb +18 -0
- data/lib/pagy/toolbox/paginators/meilisearch.rb +32 -0
- data/lib/pagy/toolbox/paginators/method.rb +26 -0
- data/lib/pagy/toolbox/paginators/offset.rb +33 -0
- data/lib/pagy/toolbox/paginators/searchkick.rb +32 -0
- data/lib/pagy.rb +59 -97
- data/locales/ar.yml +9 -6
- data/locales/be.yml +9 -6
- data/locales/bg.yml +9 -6
- data/locales/bs.yml +9 -6
- data/locales/ca.yml +9 -6
- data/locales/ckb.yml +8 -6
- data/locales/cs.yml +9 -6
- data/locales/da.yml +9 -6
- data/locales/de.yml +9 -6
- data/locales/dz.yml +9 -6
- data/locales/en.yml +9 -6
- data/locales/es.yml +9 -6
- data/locales/fr.yml +9 -6
- data/locales/hr.yml +9 -6
- data/locales/id.yml +9 -6
- data/locales/it.yml +9 -6
- data/locales/ja.yml +9 -6
- data/locales/km.yml +9 -6
- data/locales/ko.yml +9 -6
- data/locales/nb.yml +9 -6
- data/locales/nl.yml +9 -6
- data/locales/nn.yml +9 -6
- data/locales/pl.yml +9 -6
- data/locales/pt-BR.yml +10 -7
- data/locales/pt.yml +10 -7
- data/locales/ru.yml +9 -6
- data/locales/sr.yml +9 -6
- data/locales/sv-SE.yml +9 -6
- data/locales/sv.yml +9 -6
- data/locales/sw.yml +12 -9
- data/locales/ta.yml +12 -9
- data/locales/tr.yml +9 -6
- data/locales/uk.yml +9 -6
- data/locales/vi.yml +9 -6
- data/locales/zh-CN.yml +9 -6
- data/locales/zh-HK.yml +9 -6
- data/locales/zh-TW.yml +9 -6
- data/stylesheets/pagy-tailwind.css +64 -0
- data/stylesheets/pagy.css +63 -27
- metadata +112 -51
- data/javascripts/pagy.min.js.map +0 -10
- data/lib/pagy/backend.rb +0 -44
- data/lib/pagy/calendar/unit.rb +0 -103
- data/lib/pagy/calendar.rb +0 -84
- data/lib/pagy/console.rb +0 -23
- data/lib/pagy/countless.rb +0 -38
- data/lib/pagy/exceptions.rb +0 -25
- data/lib/pagy/extras/arel.rb +0 -28
- data/lib/pagy/extras/array.rb +0 -19
- data/lib/pagy/extras/bootstrap.rb +0 -97
- data/lib/pagy/extras/bulma.rb +0 -93
- data/lib/pagy/extras/calendar.rb +0 -79
- data/lib/pagy/extras/countless.rb +0 -32
- data/lib/pagy/extras/elasticsearch_rails.rb +0 -71
- data/lib/pagy/extras/gearbox.rb +0 -55
- data/lib/pagy/extras/headers.rb +0 -54
- data/lib/pagy/extras/i18n.rb +0 -26
- data/lib/pagy/extras/js_tools.rb +0 -70
- data/lib/pagy/extras/jsonapi.rb +0 -88
- data/lib/pagy/extras/keyset.rb +0 -30
- data/lib/pagy/extras/limit.rb +0 -63
- data/lib/pagy/extras/meilisearch.rb +0 -57
- data/lib/pagy/extras/metadata.rb +0 -42
- data/lib/pagy/extras/overflow.rb +0 -81
- data/lib/pagy/extras/pagy.rb +0 -82
- data/lib/pagy/extras/searchkick.rb +0 -59
- data/lib/pagy/extras/size.rb +0 -40
- data/lib/pagy/extras/standalone.rb +0 -60
- data/lib/pagy/extras/trim.rb +0 -29
- data/lib/pagy/frontend.rb +0 -99
- data/lib/pagy/i18n.rb +0 -166
- data/lib/pagy/keyset/active_record.rb +0 -44
- data/lib/pagy/keyset/sequel.rb +0 -57
- data/lib/pagy/keyset.rb +0 -118
- data/lib/pagy/shared_methods.rb +0 -26
- data/lib/pagy/url_helpers.rb +0 -26
- data/stylesheets/pagy.scss +0 -48
- data/stylesheets/pagy.tailwind.css +0 -21
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'nav_aria_label_attribute'
|
4
|
+
require_relative 'data_pagy_attribute'
|
5
|
+
require_relative 'a_lambda' # inherited use
|
6
|
+
|
7
|
+
# Relegate internal functions. Make overriding navs easier.
|
8
|
+
class Pagy
|
9
|
+
private
|
10
|
+
|
11
|
+
# Build the input_nav_js tag, with the specific inner html for the style
|
12
|
+
def wrap_input_nav_js(html, nav_classes, id: nil, aria_label: nil, **)
|
13
|
+
%(<nav#{%( id="#{id}") if id} class="#{nav_classes}" #{
|
14
|
+
nav_aria_label_attribute(aria_label:)} #{
|
15
|
+
data = [:inj, compose_page_url(PAGE_TOKEN, **)]
|
16
|
+
data.push(@update) if keynav?
|
17
|
+
data_pagy_attribute(*data)
|
18
|
+
}>#{html}</nav>)
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'series'
|
4
|
+
require_relative 'nav_aria_label_attribute'
|
5
|
+
require_relative 'data_pagy_attribute'
|
6
|
+
require_relative 'a_lambda' # inherited use
|
7
|
+
|
8
|
+
# Relegate internal functions. Make overriding navs easier.
|
9
|
+
class Pagy
|
10
|
+
private
|
11
|
+
|
12
|
+
# Build the nav tag, with the specific inner html for the style
|
13
|
+
def wrap_series_nav(html, nav_classes, id: nil, aria_label: nil, **)
|
14
|
+
data = %( #{data_pagy_attribute(:k, @update)}) if keynav?
|
15
|
+
%(<nav#{id && %( id="#{id}")} class="#{nav_classes}" #{nav_aria_label_attribute(aria_label:)}#{data}>#{html}</nav>)
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'series'
|
4
|
+
require_relative 'nav_aria_label_attribute'
|
5
|
+
require_relative 'data_pagy_attribute'
|
6
|
+
require_relative 'a_lambda' # inherited use
|
7
|
+
|
8
|
+
# Relegate internal functions. Make overriding navs easier.
|
9
|
+
class Pagy
|
10
|
+
private
|
11
|
+
|
12
|
+
# Return the reverse sorted array of widths, series, and labels generated from the :steps hash
|
13
|
+
# If :steps is false it will use the single {0 => @options[:slots]} length
|
14
|
+
def sequels(steps: @options[:steps] || { 0 => @options[:slots] || SERIES_SLOTS }, **)
|
15
|
+
raise OptionError.new(self, :steps, 'to define the 0 width', steps) unless steps.key?(0)
|
16
|
+
|
17
|
+
widths, series = steps.sort.reverse.map { |width, slots| [width, series(slots:)] }.transpose
|
18
|
+
[widths, series, page_labels(series)]
|
19
|
+
end
|
20
|
+
|
21
|
+
# Support for the Calendar API
|
22
|
+
def page_labels(series)
|
23
|
+
series.map { |s| s.map { |item| item == :gap ? :gap : page_label(item) } } if calendar?
|
24
|
+
end
|
25
|
+
|
26
|
+
# Build the nav_js tag, with the specific tokens for the style
|
27
|
+
def wrap_series_nav_js(tokens, nav_classes, id: nil, aria_label: nil, **)
|
28
|
+
sequels = sequels(**)
|
29
|
+
%(<nav#{id && %( id="#{id}")} class="#{'pagy-rjs ' if sequels[0].size > 1}#{nav_classes}" #{
|
30
|
+
nav_aria_label_attribute(aria_label:)} #{
|
31
|
+
data = [:snj, tokens.values, sequels]
|
32
|
+
data.push(@update) if keynav?
|
33
|
+
data_pagy_attribute(*data)
|
34
|
+
}></nav>)
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Pagy
|
4
|
+
# Generte hash of the pagination links
|
5
|
+
def urls_hash(**)
|
6
|
+
url = compose_page_url(PAGE_TOKEN, **)
|
7
|
+
{ first: compose_page_url(nil, **) }.tap do |urls| # first is present, but the URL omits the nil page param
|
8
|
+
urls[:previous] = url.sub(PAGE_TOKEN, @previous.to_s) if @previous
|
9
|
+
urls[:next] = url.sub(PAGE_TOKEN, @next.to_s) if @next
|
10
|
+
urls[:last] = url.sub(PAGE_TOKEN, @last.to_s) if @count # offset and not countless
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Pagy
|
4
|
+
module CalendarPaginator
|
5
|
+
module_function
|
6
|
+
|
7
|
+
# Take a collection and a configuration Hash and return an array with 3 items: [calendar, pagy, results]
|
8
|
+
def paginate(context, collection, config)
|
9
|
+
context.instance_eval do
|
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
|
+
|
14
|
+
config[:request] = Request.new(config[:request] || request)
|
15
|
+
config[:offset] ||= {}
|
16
|
+
unless config[:disabled]
|
17
|
+
calendar, from, to =
|
18
|
+
Calendar.send(:init, config,
|
19
|
+
pagy_calendar_period(collection),
|
20
|
+
config[:request].query) do |unit, period|
|
21
|
+
pagy_calendar_counts(collection, unit, *period) if respond_to?(:pagy_calendar_counts)
|
22
|
+
end
|
23
|
+
collection = pagy_calendar_filter(collection, from, to)
|
24
|
+
end
|
25
|
+
pagy, records = pagy(:offset, collection, **config[:offset])
|
26
|
+
[calendar, pagy, records]
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Pagy
|
4
|
+
module CountlessPaginator
|
5
|
+
module_function
|
6
|
+
|
7
|
+
# Return Pagy object and records
|
8
|
+
def paginate(context, collection, **options)
|
9
|
+
context.instance_eval do
|
10
|
+
request = Request.new(options[:request] || self.request, options)
|
11
|
+
if options[:page].nil?
|
12
|
+
page = request.resolve_page(options, force_integer: false) # accept nil and strings
|
13
|
+
if page.is_a?(String)
|
14
|
+
p, l = page.split(/ /, 2).map(&:to_i)
|
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)]
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../../modules/searcher'
|
4
|
+
|
5
|
+
class Pagy
|
6
|
+
module ElasticsearchRailsPaginator
|
7
|
+
module_function
|
8
|
+
|
9
|
+
# Paginate from search object
|
10
|
+
def paginate(context, search, **options)
|
11
|
+
context.instance_eval do
|
12
|
+
if search.is_a?(Search::Arguments)
|
13
|
+
# The search is the array of pagy_search arguments
|
14
|
+
Searcher.wrap(self, search, options) do
|
15
|
+
model, query_or_payload, search_options = search
|
16
|
+
search_options[:size] = options[:limit]
|
17
|
+
search_options[:from] = options[:limit] * ((options[:page] || 1) - 1)
|
18
|
+
results = model.send(ElasticsearchRails::DEFAULT[:search_method], query_or_payload, **search_options)
|
19
|
+
options[:count] = ElasticsearchRails.total_count(results)
|
20
|
+
[ElasticsearchRails.new(**options), results]
|
21
|
+
end
|
22
|
+
else
|
23
|
+
# The search is an elasticsearch_rails response
|
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)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../../../pagy/modules/b64'
|
4
|
+
|
5
|
+
class Pagy
|
6
|
+
module KeynavJsPaginator
|
7
|
+
module_function
|
8
|
+
|
9
|
+
# Return Pagy::Keyset::Keynav object and paginated records.
|
10
|
+
# Fall back to :countless if the :page has no client data.
|
11
|
+
def paginate(context, set, **options)
|
12
|
+
context.instance_eval do
|
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
|
22
|
+
|
23
|
+
options[:limit] = request.resolve_limit(options)
|
24
|
+
pagy = Keyset::Keynav.new(set, **options, request:)
|
25
|
+
[pagy, pagy.records]
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Pagy
|
4
|
+
module KeysetPaginator
|
5
|
+
module_function
|
6
|
+
|
7
|
+
# Return Pagy::Keyset object and paginated records
|
8
|
+
def paginate(context, set, **options)
|
9
|
+
context.instance_eval do
|
10
|
+
request = Request.new(options[:request] || self.request, options)
|
11
|
+
options[:page] ||= request.resolve_page(options, force_integer: false) # allow nil
|
12
|
+
options[:limit] = request.resolve_limit(options)
|
13
|
+
pagy = Keyset.new(set, **options, request:)
|
14
|
+
[pagy, pagy.records]
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../../modules/searcher'
|
4
|
+
|
5
|
+
class Pagy
|
6
|
+
module MeilisearchPaginator
|
7
|
+
module_function
|
8
|
+
|
9
|
+
# Paginate from search object
|
10
|
+
def paginate(context, search, **options)
|
11
|
+
context.instance_eval do
|
12
|
+
if search.is_a?(Search::Arguments)
|
13
|
+
# The search is the array of pagy_search arguments
|
14
|
+
Searcher.wrap(self, search, options) do
|
15
|
+
model, term, search_options = search
|
16
|
+
search_options[:hits_per_page] = options[:limit]
|
17
|
+
search_options[:page] = options[:page]
|
18
|
+
results = model.send(Meilisearch::DEFAULT[:search_method], term, search_options)
|
19
|
+
options[:count] = results.raw_answer['totalHits']
|
20
|
+
[Meilisearch.new(**options), results]
|
21
|
+
end
|
22
|
+
else
|
23
|
+
# The search is a meilisearch results object
|
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)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../../classes/request'
|
4
|
+
|
5
|
+
class Pagy
|
6
|
+
paginators = { offset: :OffsetPaginator,
|
7
|
+
countless: :CountlessPaginator,
|
8
|
+
keyset: :KeysetPaginator,
|
9
|
+
keynav_js: :KeynavJsPaginator,
|
10
|
+
calendar: :CalendarPaginator,
|
11
|
+
elasticsearch_rails: :ElasticsearchRailsPaginator,
|
12
|
+
meilisearch: :MeilisearchPaginator,
|
13
|
+
searchkick: :SearchkickPaginator }.freeze
|
14
|
+
|
15
|
+
path = Pathname.new(__dir__)
|
16
|
+
paginators.each { |symbol, name| autoload name, path.join(symbol.to_s) }
|
17
|
+
|
18
|
+
# Defines the pagy method. Include in the app controller/view.
|
19
|
+
Method = Module.new do
|
20
|
+
protected
|
21
|
+
|
22
|
+
define_method :pagy do |paginator = :offset, collection, **options|
|
23
|
+
Pagy.const_get(paginators[paginator]).paginate(self, collection, **Pagy.options, **options)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Pagy
|
4
|
+
module OffsetPaginator
|
5
|
+
module_function
|
6
|
+
|
7
|
+
# Return instance and page of results
|
8
|
+
def paginate(context, collection, **options)
|
9
|
+
context.instance_eval do
|
10
|
+
request = Request.new(options[:request] || self.request, options)
|
11
|
+
options[:page] ||= request.resolve_page(options)
|
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
|
18
|
+
|
19
|
+
# Get the collection count
|
20
|
+
def get_count(collection, options)
|
21
|
+
return collection.count unless defined?(::ActiveRecord) && collection.is_a?(::ActiveRecord::Relation)
|
22
|
+
|
23
|
+
count = if options[:count_over] && !collection.group_values.empty?
|
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
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../../modules/searcher'
|
4
|
+
|
5
|
+
class Pagy
|
6
|
+
module SearchkickPaginator
|
7
|
+
module_function
|
8
|
+
|
9
|
+
# Paginate from search object.
|
10
|
+
def paginate(context, search, **options)
|
11
|
+
context.instance_eval do
|
12
|
+
if search.is_a?(Search::Arguments)
|
13
|
+
# The search is the array of pagy_search arguments
|
14
|
+
Searcher.wrap(self, search, options) do
|
15
|
+
model, term, search_options, block = search
|
16
|
+
search_options[:per_page] = options[:limit]
|
17
|
+
search_options[:page] = options[:page]
|
18
|
+
results = model.send(Searchkick::DEFAULT[:search_method], term || '*', **search_options, &block)
|
19
|
+
options[:count] = results.total_count
|
20
|
+
[Searchkick.new(**options), results]
|
21
|
+
end
|
22
|
+
else
|
23
|
+
# The search is a searchkick results object
|
24
|
+
options[:limit] = search.options[:per_page]
|
25
|
+
options[:page] = search.options[:page]
|
26
|
+
options[:count] = search.total_count
|
27
|
+
Searchkick.new(**options)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
data/lib/pagy.rb
CHANGED
@@ -1,106 +1,68 @@
|
|
1
|
-
# See Pagy API documentation: https://ddnexus.github.io/pagy/docs/api/pagy
|
2
1
|
# frozen_string_literal: true
|
3
2
|
|
4
3
|
require 'pathname'
|
5
|
-
require_relative 'pagy/
|
4
|
+
require_relative 'pagy/classes/exceptions'
|
5
|
+
require_relative 'pagy/modules/abilities/linkable'
|
6
|
+
require_relative 'pagy/modules/abilities/configurable'
|
7
|
+
require_relative 'pagy/toolbox/helpers/loader'
|
6
8
|
|
7
|
-
# Top superclass: it
|
9
|
+
# Top superclass: it defines only what's common to all the subclasses
|
8
10
|
class Pagy
|
9
|
-
VERSION
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
def
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
end
|
54
|
-
|
55
|
-
# Assign @prev and @next
|
56
|
-
def assign_prev_and_next
|
57
|
-
@prev = (@page - 1 unless @page == 1)
|
58
|
-
@next = @page == @last ? (1 if @vars[:cycle]) : @page + 1
|
59
|
-
end
|
60
|
-
|
61
|
-
# Checks the @page <= @last
|
62
|
-
def check_overflow
|
63
|
-
raise OverflowError.new(self, :page, "in 1..#{@last}", @page) if @page > @last
|
11
|
+
VERSION = '43.0.0.rc1'
|
12
|
+
ROOT = Pathname.new(__dir__).parent.freeze
|
13
|
+
DEFAULT = { limit: 20, limit_key: 'limit', page_key: 'page' }.freeze
|
14
|
+
PAGE_TOKEN = 'P '
|
15
|
+
LIMIT_TOKEN = 'L '
|
16
|
+
LABEL_TOKEN = 'L'
|
17
|
+
A_TAG = '<a style="display: none;">#</a>'
|
18
|
+
|
19
|
+
path = Pathname.new(__FILE__).sub_ext('')
|
20
|
+
autoload :Method, path.join('toolbox/paginators/method')
|
21
|
+
autoload :I18n, path.join('modules/i18n/i18n')
|
22
|
+
autoload :Console, path.join('modules/console')
|
23
|
+
autoload :Calendar, path.join('classes/calendar/calendar')
|
24
|
+
autoload :Offset, path.join('classes/offset/offset')
|
25
|
+
autoload :Search, path.join('classes/offset/search')
|
26
|
+
autoload :ElasticsearchRails, path.join('classes/offset/search')
|
27
|
+
autoload :Meilisearch, path.join('classes/offset/search')
|
28
|
+
autoload :Searchkick, path.join('classes/offset/search')
|
29
|
+
autoload :Keyset, path.join('classes/keyset/keyset')
|
30
|
+
|
31
|
+
def self.options = @options ||= {}
|
32
|
+
|
33
|
+
extend Configurable
|
34
|
+
include Linkable
|
35
|
+
include Loader
|
36
|
+
|
37
|
+
attr_reader :page, :next, :in, :limit, :options
|
38
|
+
|
39
|
+
protected
|
40
|
+
|
41
|
+
# Define the hierarchical identity methods, overridden by the respective classes
|
42
|
+
def offset? = false
|
43
|
+
def countless? = false
|
44
|
+
def calendar? = false
|
45
|
+
def search? = false
|
46
|
+
def keyset? = false
|
47
|
+
def keynav? = false
|
48
|
+
|
49
|
+
# Validates and assign the passed options: var must be present and value.to_i must be >= to min
|
50
|
+
def assign_and_check(name_min)
|
51
|
+
name_min.each do |name, min|
|
52
|
+
raise OptionError.new(self, name, ">= #{min}", @options[name]) \
|
53
|
+
unless @options[name].respond_to?(:to_i) && instance_variable_set(:"@#{name}", @options[name].to_i) >= min
|
54
|
+
end
|
64
55
|
end
|
65
56
|
|
66
|
-
#
|
67
|
-
def
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
return [] if size.zero?
|
77
|
-
|
78
|
-
[].tap do |series|
|
79
|
-
if size >= @last
|
80
|
-
series.push(*1..@last)
|
81
|
-
else
|
82
|
-
left = ((size - 1) / 2.0).floor # left half might be 1 page shorter for even size
|
83
|
-
start = if @page <= left # beginning pages
|
84
|
-
1
|
85
|
-
elsif @page > (@last - size + left) # end pages
|
86
|
-
@last - size + 1
|
87
|
-
else # intermediate pages
|
88
|
-
@page - left
|
89
|
-
end
|
90
|
-
series.push(*start...start + size)
|
91
|
-
# Set first and last pages plus gaps when needed, respecting the size
|
92
|
-
if vars[:ends] && size >= 7
|
93
|
-
series[0] = 1
|
94
|
-
series[1] = :gap unless series[1] == 2
|
95
|
-
series[-2] = :gap unless series[-2] == @last - 1
|
96
|
-
series[-1] = @last
|
97
|
-
end
|
98
|
-
end
|
99
|
-
series[series.index(@page)] = @page.to_s
|
100
|
-
end
|
57
|
+
# Merge all the DEFAULT constants of the class hierarchy with the options
|
58
|
+
def assign_options(**options)
|
59
|
+
@request = options.delete(:request) # internal object
|
60
|
+
default = {}
|
61
|
+
current = self.class
|
62
|
+
begin
|
63
|
+
default = current::DEFAULT.merge(default)
|
64
|
+
current = current.superclass
|
65
|
+
end until current == Object # rubocop:disable Lint/Loop -- see https://github.com/rubocop/rubocop-performance/issues/362
|
66
|
+
@options = default.merge!(options.delete_if { |k, v| default.key?(k) && (v.nil? || v == '') }).freeze
|
101
67
|
end
|
102
68
|
end
|
103
|
-
|
104
|
-
require_relative 'pagy/backend'
|
105
|
-
require_relative 'pagy/frontend'
|
106
|
-
require_relative 'pagy/exceptions'
|
data/locales/ar.yml
CHANGED
@@ -1,6 +1,8 @@
|
|
1
|
-
#
|
1
|
+
# See https://ddnexus.github.io/pagy/resources/i18n
|
2
|
+
|
2
3
|
ar:
|
3
4
|
pagy:
|
5
|
+
p11n: 'Arabic'
|
4
6
|
aria_label:
|
5
7
|
nav:
|
6
8
|
zero: "لا يوجد صفحات"
|
@@ -9,9 +11,9 @@ ar:
|
|
9
11
|
few: "صفحات"
|
10
12
|
many: "صفحات"
|
11
13
|
other: "صفحات"
|
12
|
-
|
14
|
+
previous: "السابق"
|
13
15
|
next: "التالي"
|
14
|
-
|
16
|
+
previous: "<"
|
15
17
|
next: ">"
|
16
18
|
gap: "…"
|
17
19
|
item_name:
|
@@ -21,9 +23,10 @@ ar:
|
|
21
23
|
few: "قليل"
|
22
24
|
many: "كثير"
|
23
25
|
other: "عناصر"
|
24
|
-
|
26
|
+
info_tag:
|
27
|
+
no_count: "الصفحة %{page} من %{pages}"
|
25
28
|
no_items: "لا يوجد %{item_name}"
|
26
29
|
single_page: "عرض %{count} %{item_name}"
|
27
30
|
multiple_pages: "عرض %{item_name} %{from}-%{to} من اجمالي %{count}"
|
28
|
-
|
29
|
-
|
31
|
+
input_nav_js: "الصفحة %{page_input} من %{pages}"
|
32
|
+
limit_tag_js: "عرض %{limit_input} %{item_name} لكل صفحة"
|
data/locales/be.yml
CHANGED
@@ -1,15 +1,17 @@
|
|
1
|
-
#
|
1
|
+
# See https://ddnexus.github.io/pagy/resources/i18n
|
2
|
+
|
2
3
|
be:
|
3
4
|
pagy:
|
5
|
+
p11n: 'EastSlavic'
|
4
6
|
aria_label:
|
5
7
|
nav:
|
6
8
|
one: "Старонка"
|
7
9
|
few: "Старонкi"
|
8
10
|
many: "Старонкi"
|
9
11
|
other: "Старонкi"
|
10
|
-
|
12
|
+
previous: "Назад"
|
11
13
|
next: "Наперад"
|
12
|
-
|
14
|
+
previous: "<"
|
13
15
|
next: ">"
|
14
16
|
gap: "…"
|
15
17
|
item_name:
|
@@ -17,9 +19,10 @@ be:
|
|
17
19
|
few: "запісы"
|
18
20
|
many: "запісаў"
|
19
21
|
other: "запісаў"
|
20
|
-
|
22
|
+
info_tag:
|
23
|
+
no_count: "Старонка %{page} з %{pages}"
|
21
24
|
no_items: "Пакуль %{item_name} няма"
|
22
25
|
single_page: "%{count} %{item_name}"
|
23
26
|
multiple_pages: "Усяго %{count} %{item_name}, паказаны з %{from} па %{to}"
|
24
|
-
|
25
|
-
|
27
|
+
input_nav_js: "Старонка %{page_input} з %{pages}"
|
28
|
+
limit_tag_js: "Паказаць %{limit_input} %{item_name} на старонцы"
|
data/locales/bg.yml
CHANGED
@@ -1,21 +1,24 @@
|
|
1
|
-
#
|
1
|
+
# See https://ddnexus.github.io/pagy/resources/i18n
|
2
|
+
|
2
3
|
bg:
|
3
4
|
pagy:
|
5
|
+
p11n: 'OneOther'
|
4
6
|
aria_label:
|
5
7
|
nav:
|
6
8
|
one: "Страница"
|
7
9
|
other: "Страници"
|
8
|
-
|
10
|
+
previous: "Предишна"
|
9
11
|
next: "Следваща"
|
10
|
-
|
12
|
+
previous: "<"
|
11
13
|
next: ">"
|
12
14
|
gap: "…"
|
13
15
|
item_name:
|
14
16
|
one: "резултат"
|
15
17
|
other: "резултати"
|
16
|
-
|
18
|
+
info_tag:
|
19
|
+
no_count: "Страница %{page} от %{pages}"
|
17
20
|
no_items: "Няма намерени %{item_name}"
|
18
21
|
single_page: "Показани са %{count} %{item_name}"
|
19
22
|
multiple_pages: "Показани са %{item_name} %{from}-%{to} от %{count} общо"
|
20
|
-
|
21
|
-
|
23
|
+
input_nav_js: "Страница %{page_input} от %{pages}"
|
24
|
+
limit_tag_js: "Покажи %{limit_input} %{item_name} на страница"
|