pagy 7.0.11 → 43.5.1
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 +741 -0
- data/apps/demo.ru +513 -0
- data/apps/enable_rails_page_segment.rb +54 -0
- data/apps/index.rb +9 -0
- data/apps/keynav+root_key.ru +316 -0
- data/apps/keynav.ru +255 -0
- data/apps/keyset.ru +219 -0
- data/apps/keyset_sequel.ru +212 -0
- data/apps/rails.ru +216 -0
- data/apps/repro.ru +185 -0
- data/bin/pagy +5 -0
- data/config/pagy.rb +46 -0
- data/javascripts/ai_widget.js +90 -0
- data/javascripts/pagy.js +168 -0
- data/javascripts/pagy.min.js +2 -0
- data/javascripts/pagy.mjs +161 -0
- data/javascripts/wand.js +1172 -0
- data/lib/pagy/classes/calendar/calendar.rb +101 -0
- data/lib/pagy/{calendar → classes/calendar}/day.rb +9 -12
- data/lib/pagy/{calendar → classes/calendar}/month.rb +7 -11
- data/lib/pagy/{calendar → classes/calendar}/quarter.rb +12 -16
- data/lib/pagy/classes/calendar/unit.rb +93 -0
- data/lib/pagy/{calendar → classes/calendar}/week.rb +7 -11
- data/lib/pagy/{calendar → classes/calendar}/year.rb +9 -9
- 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 +150 -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/modules/b64.rb +35 -0
- 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 +21 -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 +55 -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 +19 -0
- data/lib/pagy/toolbox/helpers/support/wrap_series_nav.rb +17 -0
- data/lib/pagy/toolbox/helpers/support/wrap_series_nav_js.rb +42 -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 +67 -131
- data/locales/ar.yml +32 -0
- data/locales/be.yml +28 -0
- data/locales/bg.yml +24 -0
- data/locales/bs.yml +28 -0
- data/locales/ca.yml +24 -0
- data/locales/ckb.yml +20 -0
- data/locales/cs.yml +26 -0
- data/locales/da.yml +24 -0
- data/locales/de.yml +24 -0
- data/locales/dz.yml +20 -0
- data/locales/en.yml +24 -0
- data/{lib/locales → locales}/es.yml +9 -6
- data/locales/fr.yml +24 -0
- data/locales/hr.yml +28 -0
- data/locales/id.yml +20 -0
- data/locales/it.yml +24 -0
- data/locales/ja.yml +20 -0
- data/locales/km.yml +20 -0
- data/locales/ko.yml +20 -0
- data/locales/nb.yml +24 -0
- data/locales/nl.yml +24 -0
- data/locales/nn.yml +24 -0
- data/locales/pl.yml +28 -0
- data/{lib/locales → locales}/pt-BR.yml +10 -7
- data/{lib/locales → locales}/pt.yml +10 -7
- data/locales/ru.yml +28 -0
- data/locales/sk.yml +26 -0
- data/locales/sr.yml +28 -0
- data/locales/sv-SE.yml +24 -0
- data/locales/sv.yml +24 -0
- data/locales/sw.yml +28 -0
- data/locales/ta.yml +24 -0
- data/locales/tr.yml +24 -0
- data/locales/uk.yml +28 -0
- data/locales/vi.yml +20 -0
- data/locales/zh-CN.yml +20 -0
- data/locales/zh-HK.yml +20 -0
- data/locales/zh-TW.yml +20 -0
- data/stylesheets/pagy-tailwind.css +68 -0
- data/stylesheets/pagy.css +83 -0
- metadata +185 -94
- data/lib/config/pagy.rb +0 -258
- data/lib/javascripts/pagy-dev.js +0 -112
- data/lib/javascripts/pagy-module.js +0 -111
- data/lib/javascripts/pagy.js +0 -1
- data/lib/locales/ar.yml +0 -30
- data/lib/locales/be.yml +0 -25
- data/lib/locales/bg.yml +0 -21
- data/lib/locales/bs.yml +0 -25
- data/lib/locales/ca.yml +0 -23
- data/lib/locales/ckb.yml +0 -18
- data/lib/locales/cs.yml +0 -23
- data/lib/locales/da.yml +0 -23
- data/lib/locales/de.yml +0 -21
- data/lib/locales/en.yml +0 -21
- data/lib/locales/fr.yml +0 -21
- data/lib/locales/hr.yml +0 -25
- data/lib/locales/id.yml +0 -19
- data/lib/locales/it.yml +0 -21
- data/lib/locales/ja.yml +0 -19
- data/lib/locales/km.yml +0 -19
- data/lib/locales/ko.yml +0 -19
- data/lib/locales/nb.yml +0 -21
- data/lib/locales/nl.yml +0 -21
- data/lib/locales/nn.yml +0 -21
- data/lib/locales/pl.yml +0 -25
- data/lib/locales/ru.yml +0 -27
- data/lib/locales/sr.yml +0 -25
- data/lib/locales/sv-SE.yml +0 -21
- data/lib/locales/sv.yml +0 -21
- data/lib/locales/sw.yml +0 -23
- data/lib/locales/ta.yml +0 -23
- data/lib/locales/tr.yml +0 -19
- data/lib/locales/uk.yml +0 -25
- data/lib/locales/vi.yml +0 -17
- data/lib/locales/zh-CN.yml +0 -19
- data/lib/locales/zh-HK.yml +0 -19
- data/lib/locales/zh-TW.yml +0 -19
- data/lib/pagy/backend.rb +0 -39
- data/lib/pagy/calendar/helper.rb +0 -65
- data/lib/pagy/calendar.rb +0 -126
- data/lib/pagy/countless.rb +0 -37
- data/lib/pagy/exceptions.rb +0 -25
- data/lib/pagy/extras/arel.rb +0 -36
- data/lib/pagy/extras/array.rb +0 -24
- data/lib/pagy/extras/bootstrap.rb +0 -108
- data/lib/pagy/extras/bulma.rb +0 -105
- data/lib/pagy/extras/calendar.rb +0 -53
- data/lib/pagy/extras/countless.rb +0 -37
- data/lib/pagy/extras/elasticsearch_rails.rb +0 -80
- data/lib/pagy/extras/foundation.rb +0 -105
- data/lib/pagy/extras/frontend_helpers.rb +0 -67
- data/lib/pagy/extras/gearbox.rb +0 -54
- data/lib/pagy/extras/headers.rb +0 -53
- data/lib/pagy/extras/i18n.rb +0 -26
- data/lib/pagy/extras/items.rb +0 -61
- data/lib/pagy/extras/jsonapi.rb +0 -79
- data/lib/pagy/extras/materialize.rb +0 -96
- data/lib/pagy/extras/meilisearch.rb +0 -65
- data/lib/pagy/extras/metadata.rb +0 -38
- data/lib/pagy/extras/navs.rb +0 -51
- data/lib/pagy/extras/overflow.rb +0 -80
- data/lib/pagy/extras/searchkick.rb +0 -67
- data/lib/pagy/extras/semantic.rb +0 -95
- data/lib/pagy/extras/standalone.rb +0 -60
- data/lib/pagy/extras/support.rb +0 -40
- data/lib/pagy/extras/trim.rb +0 -29
- data/lib/pagy/extras/uikit.rb +0 -97
- data/lib/pagy/frontend.rb +0 -114
- data/lib/pagy/i18n.rb +0 -165
- data/lib/pagy/url_helpers.rb +0 -27
- data/lib/stylesheets/pagy.css +0 -61
- data/lib/stylesheets/pagy.scss +0 -50
- data/lib/stylesheets/pagy.tailwind.scss +0 -24
- /data/{lib/javascripts/pagy-module.d.ts → javascripts/pagy.d.ts} +0 -0
|
@@ -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) # keynav page param
|
|
15
|
+
page_arguments = JSON.parse(B64.urlsafe_decode(page))
|
|
16
|
+
# Restart the pagination from page 1/nil if the url has been requested from another browser
|
|
17
|
+
options[:page] = page_arguments if options[:request].cookie == page_arguments.shift
|
|
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,151 +1,87 @@
|
|
|
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
4
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
# Root pathname to get the path of Pagy files like templates or dictionaries
|
|
11
|
-
def self.root
|
|
12
|
-
@root ||= Pathname.new(__dir__).freeze
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
# Default core vars: constant for easy access, but mutable for customizable defaults
|
|
16
|
-
DEFAULT = { page: 1, # rubocop:disable Style/MutableConstant
|
|
17
|
-
items: 20,
|
|
18
|
-
outset: 0,
|
|
19
|
-
size: 7,
|
|
20
|
-
page_param: :page,
|
|
21
|
-
params: {},
|
|
22
|
-
fragment: '',
|
|
23
|
-
link_extra: '',
|
|
24
|
-
item_i18n_key: 'pagy.item_name',
|
|
25
|
-
nav_i18n_key: 'pagy.aria_label.nav',
|
|
26
|
-
cycle: false,
|
|
27
|
-
request_path: '',
|
|
28
|
-
count_args: [:all] } # AR friendly
|
|
29
|
-
|
|
30
|
-
attr_reader :count, :page, :items, :vars, :pages, :last, :offset, :in, :from, :to, :prev, :next, :params, :request_path
|
|
31
|
-
|
|
32
|
-
# Merge and validate the options, do some simple arithmetic and set the instance variables
|
|
33
|
-
def initialize(vars)
|
|
34
|
-
normalize_vars(vars)
|
|
35
|
-
setup_vars(count: 0, page: 1, outset: 0)
|
|
36
|
-
setup_items_var
|
|
37
|
-
setup_pages_var
|
|
38
|
-
setup_offset_var
|
|
39
|
-
setup_params_var
|
|
40
|
-
setup_request_path_var
|
|
41
|
-
raise OverflowError.new(self, :page, "in 1..#{@last}", @page) if @page > @last
|
|
42
|
-
|
|
43
|
-
@from = [@offset - @outset + 1, @count].min
|
|
44
|
-
@to = [@offset - @outset + @items, @count].min
|
|
45
|
-
@in = [@to - @from + 1, @count].min
|
|
46
|
-
@prev = (@page - 1 unless @page == 1)
|
|
47
|
-
@next = @page == @last ? (1 if @vars[:cycle]) : @page + 1
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
# Return the array of page numbers and :gap items e.g. [1, :gap, 7, 8, "9", 10, 11, :gap, 36]
|
|
51
|
-
def series(size: @vars[:size], **_)
|
|
52
|
-
series = []
|
|
53
|
-
if size.is_a?(Array) && size.size == 4 && size.all? { |num| !num.negative? rescue false } # rubocop:disable Style/RescueModifier
|
|
54
|
-
# This algorithm is up to ~5x faster and ~2.3x lighter than the previous one (pagy < 4.3)
|
|
55
|
-
left_gap_start = 1 + size[0]
|
|
56
|
-
left_gap_end = @page - size[1] - 1
|
|
57
|
-
right_gap_start = @page + size[2] + 1
|
|
58
|
-
right_gap_end = @last - size[3]
|
|
59
|
-
left_gap_end = right_gap_end if left_gap_end > right_gap_end
|
|
60
|
-
right_gap_start = left_gap_start if left_gap_start > right_gap_start
|
|
61
|
-
start = 1
|
|
62
|
-
if (left_gap_end - left_gap_start).positive?
|
|
63
|
-
series.push(*start...left_gap_start, :gap)
|
|
64
|
-
start = left_gap_end + 1
|
|
65
|
-
end
|
|
66
|
-
if (right_gap_end - right_gap_start).positive?
|
|
67
|
-
series.push(*start...right_gap_start, :gap)
|
|
68
|
-
start = right_gap_end + 1
|
|
69
|
-
end
|
|
70
|
-
series.push(*start..@last)
|
|
71
|
-
elsif size.is_a?(Integer) && size.positive? # only central series
|
|
72
|
-
# The simplest and fastest algorithm
|
|
73
|
-
size = @pages if size > @pages # reduce the max size to @pages
|
|
74
|
-
left = ((size - 1) / 2.0).floor # left half might be 1 page shorter for even size
|
|
75
|
-
start = if @page <= left # beginning pages
|
|
76
|
-
1
|
|
77
|
-
elsif @page > @pages - (size - left) # end pages
|
|
78
|
-
@pages - size + 1
|
|
79
|
-
else # intermediate pages
|
|
80
|
-
@page - left
|
|
81
|
-
end
|
|
82
|
-
series = (start..start + size - 1).to_a
|
|
83
|
-
else
|
|
84
|
-
return [] if size.empty?
|
|
85
|
-
|
|
86
|
-
raise VariableError.new(self, :size, 'to be a single positive Integer or an Array of 4', size)
|
|
87
|
-
end
|
|
88
|
-
series[series.index(@page)] = @page.to_s
|
|
89
|
-
series
|
|
90
|
-
end
|
|
91
|
-
|
|
92
|
-
# Label for any page. Allow the customization of the output (overridden by the calendar extra)
|
|
93
|
-
def label_for(page)
|
|
94
|
-
page.to_s
|
|
95
|
-
end
|
|
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'
|
|
96
9
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
10
|
+
# Top superclass
|
|
11
|
+
class Pagy
|
|
12
|
+
VERSION = '43.5.1'
|
|
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
|
|
101
41
|
|
|
102
42
|
protected
|
|
103
43
|
|
|
104
|
-
#
|
|
105
|
-
def
|
|
106
|
-
|
|
107
|
-
|
|
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
|
|
108
51
|
|
|
109
|
-
#
|
|
110
|
-
def
|
|
52
|
+
# Validate presence and min value of options
|
|
53
|
+
def assign_and_check(name_min)
|
|
111
54
|
name_min.each do |name, min|
|
|
112
|
-
|
|
113
|
-
unless @vars[name]&.respond_to?(:to_i) && instance_variable_set(:"@#{name}", @vars[name].to_i) >= min
|
|
114
|
-
end
|
|
115
|
-
end
|
|
55
|
+
value = @options[name]
|
|
116
56
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
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
|
|
120
63
|
end
|
|
121
64
|
|
|
122
|
-
#
|
|
123
|
-
def
|
|
124
|
-
@
|
|
125
|
-
|
|
65
|
+
# Merge all the DEFAULT constants of the class hierarchy with the options
|
|
66
|
+
def assign_options(**options)
|
|
67
|
+
@request = options.delete(:request) # internal object
|
|
68
|
+
default = {}
|
|
69
|
+
current = self.class
|
|
126
70
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
71
|
+
loop do
|
|
72
|
+
default = current::DEFAULT.merge(default)
|
|
73
|
+
current = current.superclass
|
|
74
|
+
break if current == Object
|
|
75
|
+
end
|
|
131
76
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
raise VariableError.new(self, :params, 'must be a Hash or a Proc', @params) \
|
|
135
|
-
unless (@params = @vars[:params]).is_a?(Hash) || @params.is_a?(Proc)
|
|
77
|
+
clean_options = options.delete_if { |k, v| default.key?(k) && (v.nil? || v == '') }
|
|
78
|
+
@options = default.merge!(clean_options).freeze
|
|
136
79
|
end
|
|
137
80
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
raise VariableError.new(self, :request_path, 'must be a bare path like "/foo"', request_path) \
|
|
143
|
-
if !request_path.start_with?('/') || request_path.include?('?')
|
|
144
|
-
|
|
145
|
-
@request_path = request_path
|
|
81
|
+
# Hook module for numeric UI helpers
|
|
82
|
+
module NumericHelpers
|
|
83
|
+
include NumericHelperLoader
|
|
146
84
|
end
|
|
147
85
|
end
|
|
148
86
|
|
|
149
|
-
|
|
150
|
-
require 'pagy/frontend'
|
|
151
|
-
require 'pagy/exceptions'
|
|
87
|
+
require_relative ENV['PAGY_NEXT'] == 'true' ? 'pagy/next' : 'pagy/deprecated'
|
data/locales/ar.yml
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# See https://ddnexus.github.io/pagy/resources/i18n
|
|
2
|
+
|
|
3
|
+
ar:
|
|
4
|
+
pagy:
|
|
5
|
+
p11n: 'Arabic'
|
|
6
|
+
aria_label:
|
|
7
|
+
nav:
|
|
8
|
+
zero: "لا يوجد صفحات"
|
|
9
|
+
one: "صفحة"
|
|
10
|
+
two: "صفحتين"
|
|
11
|
+
few: "صفحات"
|
|
12
|
+
many: "صفحات"
|
|
13
|
+
other: "صفحات"
|
|
14
|
+
previous: "السابق"
|
|
15
|
+
next: "التالي"
|
|
16
|
+
previous: "<"
|
|
17
|
+
next: ">"
|
|
18
|
+
gap: "…"
|
|
19
|
+
item_name:
|
|
20
|
+
zero: "صفر"
|
|
21
|
+
one: "عنصر"
|
|
22
|
+
two: "عنصرين"
|
|
23
|
+
few: "قليل"
|
|
24
|
+
many: "كثير"
|
|
25
|
+
other: "عناصر"
|
|
26
|
+
info_tag:
|
|
27
|
+
no_count: "الصفحة %{page} من %{pages}"
|
|
28
|
+
no_items: "لا يوجد %{item_name}"
|
|
29
|
+
single_page: "عرض %{count} %{item_name}"
|
|
30
|
+
multiple_pages: "عرض %{item_name} %{from}-%{to} من اجمالي %{count}"
|
|
31
|
+
input_nav_js: "الصفحة %{page_input} من %{pages}"
|
|
32
|
+
limit_tag_js: "عرض %{limit_input} %{item_name} لكل صفحة"
|
data/locales/be.yml
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# See https://ddnexus.github.io/pagy/resources/i18n
|
|
2
|
+
|
|
3
|
+
be:
|
|
4
|
+
pagy:
|
|
5
|
+
p11n: 'EastSlavic'
|
|
6
|
+
aria_label:
|
|
7
|
+
nav:
|
|
8
|
+
one: "Старонка"
|
|
9
|
+
few: "Старонкi"
|
|
10
|
+
many: "Старонкi"
|
|
11
|
+
other: "Старонкi"
|
|
12
|
+
previous: "Назад"
|
|
13
|
+
next: "Наперад"
|
|
14
|
+
previous: "<"
|
|
15
|
+
next: ">"
|
|
16
|
+
gap: "…"
|
|
17
|
+
item_name:
|
|
18
|
+
one: "запіс"
|
|
19
|
+
few: "запісы"
|
|
20
|
+
many: "запісаў"
|
|
21
|
+
other: "запісаў"
|
|
22
|
+
info_tag:
|
|
23
|
+
no_count: "Старонка %{page} з %{pages}"
|
|
24
|
+
no_items: "Пакуль %{item_name} няма"
|
|
25
|
+
single_page: "%{count} %{item_name}"
|
|
26
|
+
multiple_pages: "Усяго %{count} %{item_name}, паказаны з %{from} па %{to}"
|
|
27
|
+
input_nav_js: "Старонка %{page_input} з %{pages}"
|
|
28
|
+
limit_tag_js: "Паказаць %{limit_input} %{item_name} на старонцы"
|
data/locales/bg.yml
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# See https://ddnexus.github.io/pagy/resources/i18n
|
|
2
|
+
|
|
3
|
+
bg:
|
|
4
|
+
pagy:
|
|
5
|
+
p11n: 'OneOther'
|
|
6
|
+
aria_label:
|
|
7
|
+
nav:
|
|
8
|
+
one: "Страница"
|
|
9
|
+
other: "Страници"
|
|
10
|
+
previous: "Предишна"
|
|
11
|
+
next: "Следваща"
|
|
12
|
+
previous: "<"
|
|
13
|
+
next: ">"
|
|
14
|
+
gap: "…"
|
|
15
|
+
item_name:
|
|
16
|
+
one: "резултат"
|
|
17
|
+
other: "резултати"
|
|
18
|
+
info_tag:
|
|
19
|
+
no_count: "Страница %{page} от %{pages}"
|
|
20
|
+
no_items: "Няма намерени %{item_name}"
|
|
21
|
+
single_page: "Показани са %{count} %{item_name}"
|
|
22
|
+
multiple_pages: "Показани са %{item_name} %{from}-%{to} от %{count} общо"
|
|
23
|
+
input_nav_js: "Страница %{page_input} от %{pages}"
|
|
24
|
+
limit_tag_js: "Покажи %{limit_input} %{item_name} на страница"
|
data/locales/bs.yml
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# See https://ddnexus.github.io/pagy/resources/i18n
|
|
2
|
+
|
|
3
|
+
bs:
|
|
4
|
+
pagy:
|
|
5
|
+
p11n: 'EastSlavic'
|
|
6
|
+
aria_label:
|
|
7
|
+
nav:
|
|
8
|
+
one: "Stranica"
|
|
9
|
+
few: "Stranice"
|
|
10
|
+
many: "Stranica"
|
|
11
|
+
other: "Stranice"
|
|
12
|
+
previous: "Prethodna"
|
|
13
|
+
next: "Sljedeća"
|
|
14
|
+
previous: "<"
|
|
15
|
+
next: ">"
|
|
16
|
+
gap: "…"
|
|
17
|
+
item_name:
|
|
18
|
+
one: "stavka"
|
|
19
|
+
few: "stavke"
|
|
20
|
+
many: "stavki"
|
|
21
|
+
other: "stavki"
|
|
22
|
+
info_tag:
|
|
23
|
+
no_count: "Stranica %{page} od %{pages}"
|
|
24
|
+
no_items: "Nije pronađena %{item_name}"
|
|
25
|
+
single_page: "Prikazuje se %{count} %{item_name}"
|
|
26
|
+
multiple_pages: "Prikaz %{item_name} %{from}-%{to} od %{count} ukupno"
|
|
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
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# See https://ddnexus.github.io/pagy/resources/i18n
|
|
2
|
+
|
|
3
|
+
ca:
|
|
4
|
+
pagy:
|
|
5
|
+
p11n: 'OneOther'
|
|
6
|
+
aria_label:
|
|
7
|
+
nav:
|
|
8
|
+
one: "Pàgina"
|
|
9
|
+
other: "Pàgines"
|
|
10
|
+
previous: "Anterior"
|
|
11
|
+
next: "Següent"
|
|
12
|
+
previous: "<"
|
|
13
|
+
next: ">"
|
|
14
|
+
gap: "…"
|
|
15
|
+
item_name:
|
|
16
|
+
one: "element"
|
|
17
|
+
other: "elements"
|
|
18
|
+
info_tag:
|
|
19
|
+
no_count: "Pàgina %{page} de %{pages}"
|
|
20
|
+
no_items: "No s'ha trobat cap resultat"
|
|
21
|
+
single_page: "Mostrant %{count} %{item_name}"
|
|
22
|
+
multiple_pages: "Mostrant %{item_name} %{from}-%{to} de %{count} en total"
|
|
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
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# See https://ddnexus.github.io/pagy/resources/i18n
|
|
2
|
+
|
|
3
|
+
ckb:
|
|
4
|
+
pagy:
|
|
5
|
+
p11n: 'Other'
|
|
6
|
+
item_name: "بابەت"
|
|
7
|
+
aria_label:
|
|
8
|
+
nav: "پەڕەکان"
|
|
9
|
+
previous: "پاش"
|
|
10
|
+
next: "پێش"
|
|
11
|
+
previous: "<"
|
|
12
|
+
next: ">"
|
|
13
|
+
gap: "…"
|
|
14
|
+
info_tag:
|
|
15
|
+
no_count: "پەڕی %{page} لە %{pages}"
|
|
16
|
+
no_items: "هیچ %{item_name}ێک نەدۆزرایەوە"
|
|
17
|
+
single_page: "پیشاندانی %{count} %{item_name}"
|
|
18
|
+
multiple_pages: "پشاندانی %{item_name}ی %{from}-%{to} لە کۆی %{count} بە گشتی"
|
|
19
|
+
input_nav_js: "پەڕی %{page_input} لە %{pages}"
|
|
20
|
+
limit_tag_js: "نیشاندانی %{limit_input} %{item_name} لە هەر پەڕێک"
|