pagy 9.4.0 → 43.5.5
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 +566 -562
- data/apps/demo.ru +246 -182
- data/apps/enable_rails_page_segment.rb +56 -0
- data/apps/index.rb +4 -2
- data/apps/keynav+root_key.ru +316 -0
- data/apps/keynav.ru +255 -0
- data/apps/{keyset_ar.ru → keyset.ru} +33 -42
- data/apps/{keyset_s.ru → keyset_sequel.ru} +32 -40
- data/apps/rails.ru +57 -58
- data/apps/repro.ru +54 -51
- data/bin/pagy +2 -95
- data/config/pagy.rb +33 -207
- data/javascripts/ai_widget.js +90 -0
- data/javascripts/pagy.js +166 -0
- data/javascripts/pagy.min.js +2 -4
- data/javascripts/pagy.mjs +126 -67
- data/javascripts/wand.js +1172 -0
- data/lib/pagy/classes/calendar/calendar.rb +101 -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 +93 -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 +26 -0
- data/lib/pagy/classes/keyset/adapters/active_record.rb +50 -0
- data/lib/pagy/classes/keyset/adapters/sequel.rb +62 -0
- data/lib/pagy/classes/keyset/keynav.rb +85 -0
- data/lib/pagy/classes/keyset/keyset.rb +155 -0
- data/lib/pagy/classes/offset/countish.rb +17 -0
- data/lib/pagy/classes/offset/countless.rb +63 -0
- data/lib/pagy/classes/offset/offset.rb +63 -0
- data/lib/pagy/classes/offset/search.rb +34 -0
- data/lib/pagy/classes/request.rb +48 -0
- data/lib/pagy/cli.rb +122 -0
- data/lib/pagy/console.rb +5 -20
- data/lib/pagy/deprecated.rb +84 -0
- data/lib/pagy/modules/abilities/configurable.rb +37 -0
- data/lib/pagy/modules/abilities/countable.rb +23 -0
- data/lib/pagy/modules/abilities/linkable.rb +72 -0
- data/lib/pagy/modules/abilities/rangeable.rb +14 -0
- data/lib/pagy/modules/abilities/shiftable.rb +12 -0
- data/lib/pagy/{b64.rb → modules/b64.rb} +4 -2
- data/lib/pagy/modules/console.rb +33 -0
- data/lib/pagy/modules/i18n/i18n.rb +72 -0
- data/lib/pagy/modules/i18n/p11n/arabic.rb +30 -0
- data/lib/pagy/modules/i18n/p11n/east_slavic.rb +27 -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 +27 -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/next.rb +25 -0
- data/lib/pagy/tasks/sync.rb +20 -0
- data/lib/pagy/toolbox/helpers/anchor_tags.rb +19 -0
- data/lib/pagy/toolbox/helpers/bootstrap/input_nav_js.rb +28 -0
- data/lib/pagy/toolbox/helpers/bootstrap/previous_next_html.rb +19 -0
- data/lib/pagy/toolbox/helpers/bootstrap/series_nav.rb +32 -0
- data/lib/pagy/toolbox/helpers/bootstrap/series_nav_js.rb +24 -0
- data/lib/pagy/toolbox/helpers/bulma/input_nav_js.rb +25 -0
- data/lib/pagy/toolbox/helpers/bulma/previous_next_html.rb +20 -0
- data/lib/pagy/toolbox/helpers/bulma/series_nav.rb +31 -0
- data/lib/pagy/toolbox/helpers/bulma/series_nav_js.rb +23 -0
- data/lib/pagy/toolbox/helpers/data_hash.rb +29 -0
- data/lib/pagy/toolbox/helpers/headers_hash.rb +30 -0
- data/lib/pagy/toolbox/helpers/info_tag.rb +30 -0
- data/lib/pagy/toolbox/helpers/input_nav_js.rb +22 -0
- data/lib/pagy/toolbox/helpers/limit_tag_js.rb +25 -0
- data/lib/pagy/toolbox/helpers/loaders.rb +58 -0
- data/lib/pagy/toolbox/helpers/page_url.rb +16 -0
- data/lib/pagy/toolbox/helpers/series_nav.rb +30 -0
- data/lib/pagy/toolbox/helpers/series_nav_js.rb +20 -0
- data/lib/pagy/toolbox/helpers/support/a_lambda.rb +36 -0
- data/lib/pagy/toolbox/helpers/support/data_pagy_attribute.rb +19 -0
- data/lib/pagy/toolbox/helpers/support/nav_aria_label_attribute.rb +10 -0
- data/lib/pagy/toolbox/helpers/support/series.rb +37 -0
- data/lib/pagy/toolbox/helpers/support/wrap_input_nav_js.rb +18 -0
- data/lib/pagy/toolbox/helpers/support/wrap_series_nav.rb +15 -0
- data/lib/pagy/toolbox/helpers/support/wrap_series_nav_js.rb +38 -0
- data/lib/pagy/toolbox/helpers/urls_hash.rb +12 -0
- data/lib/pagy/toolbox/paginators/calendar.rb +34 -0
- data/lib/pagy/toolbox/paginators/countish.rb +38 -0
- data/lib/pagy/toolbox/paginators/countless.rb +22 -0
- data/lib/pagy/toolbox/paginators/elasticsearch_rails.rb +56 -0
- data/lib/pagy/toolbox/paginators/keynav_js.rb +26 -0
- data/lib/pagy/toolbox/paginators/keyset.rb +15 -0
- data/lib/pagy/toolbox/paginators/meilisearch.rb +34 -0
- data/lib/pagy/toolbox/paginators/method.rb +38 -0
- data/lib/pagy/toolbox/paginators/offset.rb +24 -0
- data/lib/pagy/toolbox/paginators/searchkick.rb +34 -0
- data/lib/pagy/toolbox/paginators/typesense_rails.rb +34 -0
- data/lib/pagy.rb +79 -89
- 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/hu.yml +24 -0
- data/locales/id.yml +10 -9
- data/locales/it.yml +9 -6
- data/locales/ja.yml +10 -9
- data/locales/km.yml +10 -9
- 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/sk.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 +9 -6
- data/locales/tr.yml +17 -12
- 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 +68 -0
- data/stylesheets/pagy.css +64 -27
- metadata +134 -53
- data/javascripts/pagy.min.js.map +0 -10
- data/lib/optimist.rb +0 -1022
- 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/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 -167
- 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,56 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative '../../modules/searcher'
|
|
4
|
+
|
|
5
|
+
class Pagy
|
|
6
|
+
module ElasticsearchRailsPaginator
|
|
7
|
+
module_function
|
|
8
|
+
|
|
9
|
+
def paginate(search, options)
|
|
10
|
+
if search.is_a?(Search::Arguments) # Active mode
|
|
11
|
+
|
|
12
|
+
Searcher.wrap(search, options) do
|
|
13
|
+
model, arguments, search_options = search
|
|
14
|
+
|
|
15
|
+
search_options[:size] = options[:limit]
|
|
16
|
+
search_options[:from] = options[:limit] * ((options[:page] || 1) - 1)
|
|
17
|
+
|
|
18
|
+
method = options[:search_method] || ElasticsearchRails::DEFAULT[:search_method]
|
|
19
|
+
response_object = model.send(method, *arguments, **search_options)
|
|
20
|
+
options[:count] = total_count_from(response_object)
|
|
21
|
+
|
|
22
|
+
[ElasticsearchRails.new(**options), response_object]
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
else # Passive mode
|
|
26
|
+
from, size = pagination_params_from(search)
|
|
27
|
+
options[:limit] = size
|
|
28
|
+
options[:page] = ((from || 0) / options[:limit]) + 1
|
|
29
|
+
options[:count] = total_count_from(search)
|
|
30
|
+
|
|
31
|
+
ElasticsearchRails.new(**options)
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Support different versions of ElasticsearchRails
|
|
36
|
+
def pagination_params_from(response_object)
|
|
37
|
+
definition = response_object.search.definition
|
|
38
|
+
definition = definition.to_hash if definition.respond_to?(:to_hash)
|
|
39
|
+
container = (definition.is_a?(Hash) && (definition[:body] || definition)) || response_object.search.options
|
|
40
|
+
from = (container[:from] || container['from']).to_i
|
|
41
|
+
size = (container[:size] || container['size']).to_i
|
|
42
|
+
size = 10 if size.zero?
|
|
43
|
+
|
|
44
|
+
[from, size]
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# Support different versions of ElasticsearchRails
|
|
48
|
+
def total_count_from(response_object)
|
|
49
|
+
total = response_object.instance_eval do
|
|
50
|
+
respond_to?(:response) ? response['hits']['total'] : raw_response['hits']['total']
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
total.is_a?(Hash) ? total['value'] : total
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative '../../../pagy/modules/b64'
|
|
4
|
+
|
|
5
|
+
class Pagy
|
|
6
|
+
module KeynavJsPaginator
|
|
7
|
+
module_function
|
|
8
|
+
|
|
9
|
+
def paginate(set, options)
|
|
10
|
+
page = options[:request].resolve_page(force_integer: false) # allow nil
|
|
11
|
+
|
|
12
|
+
return CountlessPaginator.paginate(set, page:, **options) if page&.match(' ') # countless fallback
|
|
13
|
+
|
|
14
|
+
if page.is_a?(String) && (page_arguments = Keyset.decode(page))
|
|
15
|
+
# Restart the pagination from page 1/nil if the url has been requested from another browser
|
|
16
|
+
options[:page] = page_arguments \
|
|
17
|
+
if options[:request].cookie == page_arguments.shift # rubocop:disable Style/SoleNestedConditional
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
options[:limit] = options[:request].resolve_limit
|
|
21
|
+
|
|
22
|
+
pagy = Keyset::Keynav.new(set, **options)
|
|
23
|
+
[pagy, pagy.records]
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class Pagy
|
|
4
|
+
module KeysetPaginator
|
|
5
|
+
module_function
|
|
6
|
+
|
|
7
|
+
def paginate(set, options)
|
|
8
|
+
options[:page] ||= options[:request].resolve_page(force_integer: false) # allow nil
|
|
9
|
+
options[:limit] = options[:request].resolve_limit
|
|
10
|
+
|
|
11
|
+
pagy = Keyset.new(set, **options)
|
|
12
|
+
[pagy, pagy.records]
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative '../../modules/searcher'
|
|
4
|
+
|
|
5
|
+
class Pagy
|
|
6
|
+
module MeilisearchPaginator
|
|
7
|
+
module_function
|
|
8
|
+
|
|
9
|
+
def paginate(search, options)
|
|
10
|
+
if search.is_a?(Search::Arguments) # Active mode
|
|
11
|
+
|
|
12
|
+
Searcher.wrap(search, options) do
|
|
13
|
+
model, arguments, search_options = search
|
|
14
|
+
|
|
15
|
+
search_options[:hits_per_page] = options[:limit]
|
|
16
|
+
search_options[:page] = options[:page]
|
|
17
|
+
|
|
18
|
+
method = options[:search_method] || Meilisearch::DEFAULT[:search_method]
|
|
19
|
+
results = model.send(method, *arguments, search_options)
|
|
20
|
+
options[:count] = results.raw_answer['totalHits']
|
|
21
|
+
|
|
22
|
+
[Meilisearch.new(**options), results]
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
else # Passive mode
|
|
26
|
+
options[:limit] = search.raw_answer['hitsPerPage']
|
|
27
|
+
options[:page] = search.raw_answer['page']
|
|
28
|
+
options[:count] = search.raw_answer['totalHits']
|
|
29
|
+
|
|
30
|
+
Meilisearch.new(**options)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative '../../classes/request'
|
|
4
|
+
|
|
5
|
+
class Pagy
|
|
6
|
+
paginators = { offset: :OffsetPaginator,
|
|
7
|
+
countless: :CountlessPaginator,
|
|
8
|
+
countish: :CountishPaginator,
|
|
9
|
+
keyset: :KeysetPaginator,
|
|
10
|
+
keynav_js: :KeynavJsPaginator,
|
|
11
|
+
calendar: :CalendarPaginator,
|
|
12
|
+
elasticsearch_rails: :ElasticsearchRailsPaginator,
|
|
13
|
+
meilisearch: :MeilisearchPaginator,
|
|
14
|
+
searchkick: :SearchkickPaginator,
|
|
15
|
+
typesense_rails: :TypesenseRailsPaginator }.freeze
|
|
16
|
+
|
|
17
|
+
path = Pathname.new(__dir__)
|
|
18
|
+
paginators.each { |symbol, name| autoload name, path.join(symbol.to_s) }
|
|
19
|
+
|
|
20
|
+
# Pagy::Method defines the #pagy method to be included in the app controller/view.
|
|
21
|
+
Method = Module.new do
|
|
22
|
+
protected
|
|
23
|
+
|
|
24
|
+
define_method :pagy do |paginator = :offset, collection, **options|
|
|
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 # custom request Hash or self.request
|
|
33
|
+
options[:request] = Request.new(options) # Pagy::Request
|
|
34
|
+
|
|
35
|
+
Pagy.const_get(paginators[paginator]).paginate(*arguments)
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative '../../modules/abilities/countable'
|
|
4
|
+
|
|
5
|
+
class Pagy
|
|
6
|
+
module OffsetPaginator
|
|
7
|
+
module_function
|
|
8
|
+
|
|
9
|
+
def paginate(collection, options)
|
|
10
|
+
options[:page] ||= options[:request].resolve_page
|
|
11
|
+
options[:limit] = options[:request].resolve_limit
|
|
12
|
+
options[:count] ||= Countable.get_count(collection, options)
|
|
13
|
+
|
|
14
|
+
pagy = Offset.new(**options)
|
|
15
|
+
records = if collection.instance_of?(Array)
|
|
16
|
+
collection[pagy.offset, pagy.limit]
|
|
17
|
+
else
|
|
18
|
+
pagy.records(collection)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
[pagy, records]
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative '../../modules/searcher'
|
|
4
|
+
|
|
5
|
+
class Pagy
|
|
6
|
+
module SearchkickPaginator
|
|
7
|
+
module_function
|
|
8
|
+
|
|
9
|
+
def paginate(search, options)
|
|
10
|
+
if search.is_a?(Search::Arguments) # Active mode
|
|
11
|
+
|
|
12
|
+
Searcher.wrap(search, options) do
|
|
13
|
+
model, arguments, search_options, block = search
|
|
14
|
+
|
|
15
|
+
search_options[:per_page] = options[:limit]
|
|
16
|
+
search_options[:page] = options[:page]
|
|
17
|
+
|
|
18
|
+
method = options[:search_method] || Searchkick::DEFAULT[:search_method]
|
|
19
|
+
results = model.send(method, *arguments || '*', **search_options, &block)
|
|
20
|
+
options[:count] = results.total_count
|
|
21
|
+
|
|
22
|
+
[Searchkick.new(**options), results]
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
else # Passive mode
|
|
26
|
+
options[:limit] = search.respond_to?(:options) ? search.options[:per_page] : search.per_page
|
|
27
|
+
options[:page] = search.respond_to?(:options) ? search.options[:page] : search.current_page
|
|
28
|
+
options[:count] = search.total_count
|
|
29
|
+
|
|
30
|
+
Searchkick.new(**options)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative '../../modules/searcher'
|
|
4
|
+
|
|
5
|
+
class Pagy
|
|
6
|
+
module TypesenseRailsPaginator
|
|
7
|
+
module_function
|
|
8
|
+
|
|
9
|
+
def paginate(search, options)
|
|
10
|
+
if search.is_a?(Search::Arguments) # Active mode
|
|
11
|
+
|
|
12
|
+
Searcher.wrap(search, options) do
|
|
13
|
+
model, arguments, search_options = search
|
|
14
|
+
|
|
15
|
+
search_options[:per_page] = options[:limit]
|
|
16
|
+
search_options[:page] = options[:page]
|
|
17
|
+
|
|
18
|
+
method = options[:search_method] || TypesenseRails::DEFAULT[:search_method]
|
|
19
|
+
results = model.send(method, *arguments, search_options)
|
|
20
|
+
options[:count] = results.raw_answer['found']
|
|
21
|
+
|
|
22
|
+
[TypesenseRails.new(**options), results]
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
else # Passive mode
|
|
26
|
+
options[:limit] = search.raw_answer['request_params']['per_page']
|
|
27
|
+
options[:page] = search.raw_answer['page']
|
|
28
|
+
options[:count] = search.raw_answer['found']
|
|
29
|
+
|
|
30
|
+
TypesenseRails.new(**options)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
data/lib/pagy.rb
CHANGED
|
@@ -1,106 +1,96 @@
|
|
|
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/shared_methods'
|
|
6
4
|
|
|
7
|
-
|
|
5
|
+
require_relative 'pagy/classes/exceptions'
|
|
6
|
+
require_relative 'pagy/modules/abilities/linkable'
|
|
7
|
+
require_relative 'pagy/modules/abilities/configurable'
|
|
8
|
+
require_relative 'pagy/toolbox/helpers/loaders'
|
|
9
|
+
|
|
10
|
+
# Top superclass
|
|
8
11
|
class Pagy
|
|
9
|
-
VERSION
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
12
|
+
VERSION = '43.5.5'
|
|
13
|
+
ROOT = Pathname.new(__dir__).parent.freeze
|
|
14
|
+
DEFAULT = { limit: 20, limit_key: 'limit', page_key: 'page' }.freeze
|
|
15
|
+
PAGE_TOKEN = EscapedValue.new('P ')
|
|
16
|
+
LIMIT_TOKEN = EscapedValue.new('L ')
|
|
17
|
+
LABEL_TOKEN = 'L'
|
|
18
|
+
A_TAG = '<a style="display: none;">#</a>'
|
|
19
|
+
|
|
20
|
+
path = Pathname.new(__FILE__).sub_ext('')
|
|
21
|
+
autoload :Method, path.join('toolbox/paginators/method')
|
|
22
|
+
autoload :I18n, path.join('modules/i18n/i18n')
|
|
23
|
+
autoload :Console, path.join('modules/console')
|
|
24
|
+
autoload :Calendar, path.join('classes/calendar/calendar')
|
|
25
|
+
autoload :Offset, path.join('classes/offset/offset')
|
|
26
|
+
autoload :Search, path.join('classes/offset/search')
|
|
27
|
+
autoload :ElasticsearchRails, path.join('classes/offset/search')
|
|
28
|
+
autoload :Meilisearch, path.join('classes/offset/search')
|
|
29
|
+
autoload :Searchkick, path.join('classes/offset/search')
|
|
30
|
+
autoload :TypesenseRails, path.join('classes/offset/search')
|
|
31
|
+
autoload :Keyset, path.join('classes/keyset/keyset')
|
|
32
|
+
autoload :SyncTask, path.join('tasks/sync')
|
|
33
|
+
|
|
34
|
+
OPTIONS = {} # rubocop:disable Style/MutableConstant
|
|
35
|
+
|
|
36
|
+
extend Configurable
|
|
37
|
+
include Linkable
|
|
38
|
+
include HelperLoader
|
|
39
|
+
|
|
40
|
+
attr_reader :page, :next, :in, :limit, :options
|
|
41
|
+
|
|
42
|
+
protected
|
|
43
|
+
|
|
44
|
+
# Instance identity methods, overridden by the respective classes
|
|
45
|
+
def offset? = false
|
|
46
|
+
def countless? = false
|
|
47
|
+
def calendar? = false
|
|
48
|
+
def search? = false
|
|
49
|
+
def keyset? = false
|
|
50
|
+
def keynav? = false
|
|
51
|
+
|
|
52
|
+
# Validate presence and min value of options
|
|
53
|
+
def assign_and_check(name_min)
|
|
54
|
+
name_min.each do |name, min|
|
|
55
|
+
value = @options[name]
|
|
56
|
+
|
|
57
|
+
if value.respond_to?(:to_i) && (integer = value.to_i) >= min
|
|
58
|
+
instance_variable_set(:"@#{name}", integer)
|
|
59
|
+
else
|
|
60
|
+
raise OptionError.new(self, name, ">= #{min}", value)
|
|
61
|
+
end
|
|
62
|
+
end
|
|
23
63
|
end
|
|
24
64
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
# Merge and validate the options, do some simple arithmetic and set the instance variables
|
|
31
|
-
def initialize(**vars)
|
|
32
|
-
assign_vars(DEFAULT, vars)
|
|
33
|
-
assign_and_check(count: 0, page: 1, outset: 0)
|
|
34
|
-
assign_limit
|
|
35
|
-
assign_offset
|
|
36
|
-
assign_last
|
|
37
|
-
check_overflow
|
|
38
|
-
@from = [@offset - @outset + 1, @count].min
|
|
39
|
-
@to = [@offset - @outset + @limit, @count].min
|
|
40
|
-
@in = [@to - @from + 1, @count].min
|
|
41
|
-
assign_prev_and_next
|
|
65
|
+
def validate_string_values(options)
|
|
66
|
+
(options.keys & %i[page_key limit_key]).each do |key|
|
|
67
|
+
raise OptionError.new(self, key, 'to be String', options[key]) \
|
|
68
|
+
unless options[key].is_a?(String)
|
|
69
|
+
end
|
|
42
70
|
end
|
|
43
71
|
|
|
44
|
-
#
|
|
45
|
-
def
|
|
46
|
-
@
|
|
47
|
-
|
|
48
|
-
end
|
|
72
|
+
# Merge all the DEFAULT constants of the class hierarchy with the options
|
|
73
|
+
def assign_options(**options)
|
|
74
|
+
@request = options.delete(:request) # internal object
|
|
75
|
+
validate_string_values(options)
|
|
49
76
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
@offset = (@limit * (@page - 1)) + @outset # may be already set from gear_box
|
|
53
|
-
end
|
|
77
|
+
default = {}
|
|
78
|
+
current = self.class
|
|
54
79
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
80
|
+
loop do
|
|
81
|
+
default = current::DEFAULT.merge(default)
|
|
82
|
+
current = current.superclass
|
|
83
|
+
break if current == Object
|
|
84
|
+
end
|
|
60
85
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
raise OverflowError.new(self, :page, "in 1..#{@last}", @page) if @page > @last
|
|
86
|
+
clean_options = options.delete_if { |k, v| default.key?(k) && (v.nil? || v == '') }
|
|
87
|
+
@options = default.merge!(clean_options).freeze
|
|
64
88
|
end
|
|
65
89
|
|
|
66
|
-
#
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
# Label for any page. Allow the customization of the output (overridden by the calendar extra)
|
|
70
|
-
def label_for(page) = page.to_s
|
|
71
|
-
|
|
72
|
-
# Return the array of page numbers and :gap e.g. [1, :gap, 8, "9", 10, :gap, 36]
|
|
73
|
-
def series(size: @vars[:size], **_)
|
|
74
|
-
raise VariableError.new(self, :size, 'to be an Integer >= 0', size) \
|
|
75
|
-
unless size.is_a?(Integer) && size >= 0
|
|
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
|
|
90
|
+
# Hook module for numeric UI helpers
|
|
91
|
+
module NumericHelpers
|
|
92
|
+
include NumericHelperLoader
|
|
101
93
|
end
|
|
102
94
|
end
|
|
103
95
|
|
|
104
|
-
require_relative 'pagy/
|
|
105
|
-
require_relative 'pagy/frontend'
|
|
106
|
-
require_relative 'pagy/exceptions'
|
|
96
|
+
require_relative ENV['PAGY_NEXT'] == 'true' ? 'pagy/next' : 'pagy/deprecated'
|
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} на страница"
|
data/locales/bs.yml
CHANGED
|
@@ -1,15 +1,17 @@
|
|
|
1
|
-
#
|
|
1
|
+
# See https://ddnexus.github.io/pagy/resources/i18n
|
|
2
|
+
|
|
2
3
|
bs:
|
|
3
4
|
pagy:
|
|
5
|
+
p11n: 'EastSlavic'
|
|
4
6
|
aria_label:
|
|
5
7
|
nav:
|
|
6
8
|
one: "Stranica"
|
|
7
9
|
few: "Stranice"
|
|
8
10
|
many: "Stranica"
|
|
9
11
|
other: "Stranice"
|
|
10
|
-
|
|
12
|
+
previous: "Prethodna"
|
|
11
13
|
next: "Sljedeća"
|
|
12
|
-
|
|
14
|
+
previous: "<"
|
|
13
15
|
next: ">"
|
|
14
16
|
gap: "…"
|
|
15
17
|
item_name:
|
|
@@ -17,9 +19,10 @@ bs:
|
|
|
17
19
|
few: "stavke"
|
|
18
20
|
many: "stavki"
|
|
19
21
|
other: "stavki"
|
|
20
|
-
|
|
22
|
+
info_tag:
|
|
23
|
+
no_count: "Stranica %{page} od %{pages}"
|
|
21
24
|
no_items: "Nije pronađena %{item_name}"
|
|
22
25
|
single_page: "Prikazuje se %{count} %{item_name}"
|
|
23
26
|
multiple_pages: "Prikaz %{item_name} %{from}-%{to} od %{count} ukupno"
|
|
24
|
-
|
|
25
|
-
|
|
27
|
+
input_nav_js: "Stranica %{page_input} od %{pages}"
|
|
28
|
+
limit_tag_js: "Prikaži %{limit_input} %{item_name} po stranici"
|
data/locales/ca.yml
CHANGED
|
@@ -1,21 +1,24 @@
|
|
|
1
|
-
#
|
|
1
|
+
# See https://ddnexus.github.io/pagy/resources/i18n
|
|
2
|
+
|
|
2
3
|
ca:
|
|
3
4
|
pagy:
|
|
5
|
+
p11n: 'OneOther'
|
|
4
6
|
aria_label:
|
|
5
7
|
nav:
|
|
6
8
|
one: "Pàgina"
|
|
7
9
|
other: "Pàgines"
|
|
8
|
-
|
|
10
|
+
previous: "Anterior"
|
|
9
11
|
next: "Següent"
|
|
10
|
-
|
|
12
|
+
previous: "<"
|
|
11
13
|
next: ">"
|
|
12
14
|
gap: "…"
|
|
13
15
|
item_name:
|
|
14
16
|
one: "element"
|
|
15
17
|
other: "elements"
|
|
16
|
-
|
|
18
|
+
info_tag:
|
|
19
|
+
no_count: "Pàgina %{page} de %{pages}"
|
|
17
20
|
no_items: "No s'ha trobat cap resultat"
|
|
18
21
|
single_page: "Mostrant %{count} %{item_name}"
|
|
19
22
|
multiple_pages: "Mostrant %{item_name} %{from}-%{to} de %{count} en total"
|
|
20
|
-
|
|
21
|
-
|
|
23
|
+
input_nav_js: "Pàgina %{page_input} de %{pages}"
|
|
24
|
+
limit_tag_js: "Mostra %{limit_input} %{item_name} per pàgina"
|
data/locales/ckb.yml
CHANGED
|
@@ -1,18 +1,20 @@
|
|
|
1
|
-
#
|
|
1
|
+
# See https://ddnexus.github.io/pagy/resources/i18n
|
|
2
2
|
|
|
3
3
|
ckb:
|
|
4
4
|
pagy:
|
|
5
|
+
p11n: 'Other'
|
|
5
6
|
item_name: "بابەت"
|
|
6
7
|
aria_label:
|
|
7
8
|
nav: "پەڕەکان"
|
|
8
|
-
|
|
9
|
+
previous: "پاش"
|
|
9
10
|
next: "پێش"
|
|
10
|
-
|
|
11
|
+
previous: "<"
|
|
11
12
|
next: ">"
|
|
12
13
|
gap: "…"
|
|
13
|
-
|
|
14
|
+
info_tag:
|
|
15
|
+
no_count: "پەڕی %{page} لە %{pages}"
|
|
14
16
|
no_items: "هیچ %{item_name}ێک نەدۆزرایەوە"
|
|
15
17
|
single_page: "پیشاندانی %{count} %{item_name}"
|
|
16
18
|
multiple_pages: "پشاندانی %{item_name}ی %{from}-%{to} لە کۆی %{count} بە گشتی"
|
|
17
|
-
|
|
18
|
-
|
|
19
|
+
input_nav_js: "پەڕی %{page_input} لە %{pages}"
|
|
20
|
+
limit_tag_js: "نیشاندانی %{limit_input} %{item_name} لە هەر پەڕێک"
|