pagy 3.10.0 → 5.7.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/LICENSE.txt +1 -1
- data/lib/config/pagy.rb +121 -52
- data/lib/javascripts/pagy-dev.js +117 -0
- data/lib/javascripts/pagy.js +1 -106
- data/lib/javascripts/pagy.mjs +118 -0
- data/lib/locales/ar.yml +26 -0
- data/lib/locales/bg.yml +2 -2
- data/lib/locales/bs.yml +24 -0
- data/lib/locales/ca.yml +2 -2
- data/lib/locales/cs.yml +2 -2
- data/lib/locales/da.yml +2 -2
- data/lib/locales/de.yml +2 -2
- data/lib/locales/en.yml +2 -2
- data/lib/locales/es.yml +2 -2
- data/lib/locales/fr.yml +2 -2
- data/lib/locales/hr.yml +24 -0
- data/lib/locales/id.yml +2 -2
- data/lib/locales/it.yml +2 -2
- data/lib/locales/ja.yml +2 -2
- data/lib/locales/km.yml +2 -2
- data/lib/locales/ko.yml +2 -2
- data/lib/locales/nb.yml +2 -2
- data/lib/locales/nl.yml +2 -2
- data/lib/locales/pl.yml +2 -2
- data/lib/locales/pt-BR.yml +2 -2
- data/lib/locales/pt.yml +2 -2
- data/lib/locales/ru.yml +2 -2
- data/lib/locales/sr.yml +23 -0
- data/lib/locales/sv-SE.yml +2 -2
- data/lib/locales/sv.yml +2 -2
- data/lib/locales/sw.yml +22 -0
- data/lib/locales/ta.yml +22 -0
- data/lib/locales/tr.yml +2 -2
- data/lib/locales/uk.yml +24 -0
- data/lib/locales/zh-CN.yml +2 -2
- data/lib/locales/zh-HK.yml +2 -2
- data/lib/locales/zh-TW.yml +3 -3
- data/lib/pagy/backend.rb +11 -12
- data/lib/pagy/calendar/day.rb +29 -0
- data/lib/pagy/calendar/month.rb +16 -0
- data/lib/pagy/calendar/month_mixin.rb +49 -0
- data/lib/pagy/calendar/quarter.rb +23 -0
- data/lib/pagy/calendar/week.rb +39 -0
- data/lib/pagy/calendar/year.rb +29 -0
- data/lib/pagy/calendar.rb +90 -0
- data/lib/pagy/console.rb +23 -0
- data/lib/pagy/countless.rb +23 -19
- data/lib/pagy/exceptions.rb +16 -13
- data/lib/pagy/extras/arel.rb +12 -7
- data/lib/pagy/extras/array.rb +10 -9
- data/lib/pagy/extras/bootstrap.rb +77 -39
- data/lib/pagy/extras/bulma.rb +77 -43
- data/lib/pagy/extras/calendar.rb +66 -0
- data/lib/pagy/extras/countless.rb +17 -17
- data/lib/pagy/extras/elasticsearch_rails.rb +66 -37
- data/lib/pagy/extras/foundation.rb +74 -41
- data/lib/pagy/extras/frontend_helpers.rb +70 -0
- data/lib/pagy/extras/gearbox.rb +42 -0
- data/lib/pagy/extras/headers.rb +32 -18
- data/lib/pagy/extras/i18n.rb +18 -17
- data/lib/pagy/extras/items.rb +42 -53
- data/lib/pagy/extras/materialize.rb +68 -43
- data/lib/pagy/extras/meilisearch.rb +61 -0
- data/lib/pagy/extras/metadata.rb +27 -26
- data/lib/pagy/extras/navs.rb +54 -29
- data/lib/pagy/extras/overflow.rb +57 -52
- data/lib/pagy/extras/searchkick.rb +54 -36
- data/lib/pagy/extras/semantic.rb +66 -39
- data/lib/pagy/extras/standalone.rb +64 -0
- data/lib/pagy/extras/support.rb +34 -17
- data/lib/pagy/extras/trim.rb +18 -12
- data/lib/pagy/extras/uikit.rb +66 -44
- data/lib/pagy/frontend.rb +61 -53
- data/lib/pagy/i18n.rb +164 -0
- data/lib/pagy/url_helpers.rb +38 -0
- data/lib/pagy.rb +96 -30
- data/lib/templates/bootstrap_nav.html.erb +1 -1
- data/lib/templates/bootstrap_nav.html.haml +1 -1
- data/lib/templates/bootstrap_nav.html.slim +1 -1
- data/lib/templates/foundation_nav.html.erb +1 -1
- data/lib/templates/foundation_nav.html.haml +1 -1
- data/lib/templates/foundation_nav.html.slim +1 -1
- data/lib/templates/uikit_nav.html.erb +2 -2
- data/lib/templates/uikit_nav.html.haml +1 -1
- data/lib/templates/uikit_nav.html.slim +2 -2
- metadata +37 -16
- data/lib/locales/README.md +0 -35
- data/lib/locales/utils/i18n.rb +0 -25
- data/lib/locales/utils/loader.rb +0 -34
- data/lib/locales/utils/p11n.rb +0 -88
- data/lib/pagy/extras/pagy_search.rb +0 -18
- data/lib/pagy/extras/shared.rb +0 -53
- data/pagy.gemspec +0 -16
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3b065a7027d07b5bc504cbd2b80389a2e25168a075a7485d6a0155bd54b36bf4
|
4
|
+
data.tar.gz: 345c15d964cf6511adcbdf60514f605c64b83e51dd172849f98d337fcff67696
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 16b5e3b3cee1cde9f609260324ad045e45b97ecbb457eb648044b726fcc0735dd16f7909f49066ae21c01589e3dafdf303be19a865d0d71fcebe3e9b325e9fe1
|
7
|
+
data.tar.gz: df2a7604efbd881c69977e05a23b4b4125eaf0660410d619dbeafbfed7f42de2f4382f01b91f591bd66a6a799c8f5970deb782ea6ca48e9cb8fe95c018428feb
|
data/LICENSE.txt
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
The MIT License (MIT)
|
2
2
|
|
3
|
-
Copyright (c) 2017-
|
3
|
+
Copyright (c) 2017-2022 Domizio Demichelis
|
4
4
|
|
5
5
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
6
|
of this software and associated documentation files (the "Software"), to deal
|
data/lib/config/pagy.rb
CHANGED
@@ -1,11 +1,35 @@
|
|
1
|
-
# encoding: utf-8
|
2
1
|
# frozen_string_literal: true
|
3
2
|
|
4
|
-
# Pagy initializer file (
|
5
|
-
# Customize only what you really need and notice that Pagy works also without any of the following lines.
|
3
|
+
# Pagy initializer file (5.7.3)
|
4
|
+
# Customize only what you really need and notice that the core Pagy works also without any of the following lines.
|
6
5
|
# Should you just cherry pick part of this file, please maintain the require-order of the extras
|
7
6
|
|
8
7
|
|
8
|
+
# Pagy DEFAULT Variables
|
9
|
+
# See https://ddnexus.github.io/pagy/api/pagy#variables
|
10
|
+
# All the Pagy::DEFAULT are set for all the Pagy instances but can be overridden per instance by just passing them to
|
11
|
+
# Pagy.new|Pagy::Countless.new|Pagy::Calendar::*.new or any of the #pagy* controller methods
|
12
|
+
|
13
|
+
|
14
|
+
# Instance variables
|
15
|
+
# See https://ddnexus.github.io/pagy/api/pagy#instance-variables
|
16
|
+
# Pagy::DEFAULT[:page] = 1 # default
|
17
|
+
# Pagy::DEFAULT[:items] = 20 # default
|
18
|
+
# Pagy::DEFAULT[:outset] = 0 # default
|
19
|
+
|
20
|
+
|
21
|
+
# Other Variables
|
22
|
+
# See https://ddnexus.github.io/pagy/api/pagy#other-variables
|
23
|
+
# Pagy::DEFAULT[:size] = [1,4,4,1] # default
|
24
|
+
# Pagy::DEFAULT[:page_param] = :page # default
|
25
|
+
# The :params can be also set as a lambda e.g ->(params){ params.exclude('useless').merge!('custom' => 'useful') }
|
26
|
+
# Pagy::DEFAULT[:params] = {} # default
|
27
|
+
# Pagy::DEFAULT[:fragment] = '#fragment' # example
|
28
|
+
# Pagy::DEFAULT[:link_extra] = 'data-remote="true"' # example
|
29
|
+
# Pagy::DEFAULT[:i18n_key] = 'pagy.item_name' # default
|
30
|
+
# Pagy::DEFAULT[:cycle] = true # example
|
31
|
+
|
32
|
+
|
9
33
|
# Extras
|
10
34
|
# See https://ddnexus.github.io/pagy/extras
|
11
35
|
|
@@ -16,18 +40,77 @@
|
|
16
40
|
# See https://ddnexus.github.io/pagy/extras/array
|
17
41
|
# require 'pagy/extras/array'
|
18
42
|
|
43
|
+
# Calendar extra: Add pagination filtering by calendar time unit (year, quarter, month, week, day)
|
44
|
+
# See https://ddnexus.github.io/pagy/extras/calendar
|
45
|
+
# require 'pagy/extras/calendar'
|
46
|
+
# Default for each unit
|
47
|
+
# Pagy::Calendar::Year::DEFAULT[:order] = :asc # Time direction of pagination
|
48
|
+
# Pagy::Calendar::Year::DEFAULT[:format] = '%Y' # strftime format
|
49
|
+
#
|
50
|
+
# Pagy::Calendar::Quarter::DEFAULT[:order] = :asc # Time direction of pagination
|
51
|
+
# Pagy::Calendar::Quarter::DEFAULT[:format] = '%Y-Q%q' # strftime format
|
52
|
+
#
|
53
|
+
# Pagy::Calendar::Month::DEFAULT[:order] = :asc # Time direction of pagination
|
54
|
+
# Pagy::Calendar::Month::DEFAULT[:format] = '%Y-%m' # strftime format
|
55
|
+
#
|
56
|
+
# Pagy::Calendar::Week::DEFAULT[:order] = :asc # Time direction of pagination
|
57
|
+
# Pagy::Calendar::Week::DEFAULT[:format] = '%Y-%W' # strftime format
|
58
|
+
# Pagy::Calendar::Week::DEFAULT[:offset] = 0 # Day offset from Sunday (0: Sunday; 1: Monday;... 6: Saturday)
|
59
|
+
#
|
60
|
+
# Pagy::Calendar::Day::DEFAULT[:order] = :asc # Time direction of pagination
|
61
|
+
# Pagy::Calendar::Day::DEFAULT[:format] = '%Y-%m-%d' # strftime format
|
62
|
+
#
|
63
|
+
# Uncomment the following lines, if you need calendar localization without using the I18n extra
|
64
|
+
# module LocalizePagyCalendar
|
65
|
+
# def localize(time, opts)
|
66
|
+
# ::I18n.l(time, **opts)
|
67
|
+
# end
|
68
|
+
# end
|
69
|
+
# Pagy::Calendar.prepend LocalizePagyCalendar
|
70
|
+
|
19
71
|
# Countless extra: Paginate without any count, saving one query per rendering
|
20
72
|
# See https://ddnexus.github.io/pagy/extras/countless
|
21
73
|
# require 'pagy/extras/countless'
|
22
|
-
# Pagy::
|
74
|
+
# Pagy::DEFAULT[:countless_minimal] = false # default (eager loading)
|
23
75
|
|
24
76
|
# Elasticsearch Rails extra: Paginate `ElasticsearchRails::Results` objects
|
25
77
|
# See https://ddnexus.github.io/pagy/extras/elasticsearch_rails
|
78
|
+
# default :pagy_search method: change only if you use also
|
79
|
+
# the searchkick or meilisearch extra that defines the same
|
80
|
+
# Pagy::DEFAULT[:elasticsearch_rails_search_method] = :pagy_search
|
26
81
|
# require 'pagy/extras/elasticsearch_rails'
|
27
82
|
|
83
|
+
# Headers extra: http response headers (and other helpers) useful for API pagination
|
84
|
+
# See http://ddnexus.github.io/pagy/extras/headers
|
85
|
+
# require 'pagy/extras/headers'
|
86
|
+
# Pagy::DEFAULT[:headers] = { page: 'Current-Page',
|
87
|
+
# items: 'Page-Items',
|
88
|
+
# count: 'Total-Count',
|
89
|
+
# pages: 'Total-Pages' } # default
|
90
|
+
|
91
|
+
# Meilisearch extra: Paginate `Meilisearch` result objects
|
92
|
+
# See https://ddnexus.github.io/pagy/extras/meilisearch
|
93
|
+
# default :pagy_search method: change only if you use also
|
94
|
+
# the elasticsearch_rails or searchkick extra that define the same method
|
95
|
+
# Pagy::DEFAULT[:meilisearch_search_method] = :pagy_search
|
96
|
+
# require 'pagy/extras/meilisearch'
|
97
|
+
|
98
|
+
# Metadata extra: Provides the pagination metadata to Javascript frameworks like Vue.js, react.js, etc.
|
99
|
+
# See https://ddnexus.github.io/pagy/extras/metadata
|
100
|
+
# you must require the shared internal extra (BEFORE the metadata extra) ONLY if you need also the :sequels
|
101
|
+
# require 'pagy/extras/shared'
|
102
|
+
# require 'pagy/extras/metadata'
|
103
|
+
# For performance reasons, you should explicitly set ONLY the metadata you use in the frontend
|
104
|
+
# Pagy::DEFAULT[:metadata] = %i[scaffold_url page prev next last] # example
|
105
|
+
|
28
106
|
# Searchkick extra: Paginate `Searchkick::Results` objects
|
29
107
|
# See https://ddnexus.github.io/pagy/extras/searchkick
|
108
|
+
# default :pagy_search method: change only if you use also
|
109
|
+
# the elasticsearch_rails or meilisearch extra that defines the same
|
110
|
+
# DEFAULT[:searchkick_search_method] = :pagy_search
|
30
111
|
# require 'pagy/extras/searchkick'
|
112
|
+
# uncomment if you are going to use Searchkick.pagy_search
|
113
|
+
# Searchkick.extend Pagy::Searchkick
|
31
114
|
|
32
115
|
|
33
116
|
# Frontend Extras
|
@@ -64,63 +147,45 @@
|
|
64
147
|
|
65
148
|
# Multi size var used by the *_nav_js helpers
|
66
149
|
# See https://ddnexus.github.io/pagy/extras/navs#steps
|
67
|
-
# Pagy::
|
150
|
+
# Pagy::DEFAULT[:steps] = { 0 => [2,3,3,2], 540 => [3,5,5,3], 720 => [5,7,7,5] } # example
|
68
151
|
|
69
152
|
|
70
153
|
# Feature Extras
|
71
154
|
|
72
|
-
#
|
73
|
-
# See
|
74
|
-
# require 'pagy/extras/
|
75
|
-
#
|
76
|
-
|
77
|
-
#
|
78
|
-
# See https://ddnexus.github.io/pagy/extras/support
|
79
|
-
# require 'pagy/extras/support'
|
155
|
+
# Gearbox extra: Automatically change the number of items per page depending on the page number
|
156
|
+
# See https://ddnexus.github.io/pagy/extras/gearbox
|
157
|
+
# require 'pagy/extras/gearbox'
|
158
|
+
# set to false only if you want to make :gearbox_extra an opt-in variable
|
159
|
+
# Pagy::DEFAULT[:gearbox_extra] = false # default true
|
160
|
+
# Pagy::DEFAULT[:gearbox_items] = [15, 30, 60, 100] # default
|
80
161
|
|
81
162
|
# Items extra: Allow the client to request a custom number of items per page with an optional selector UI
|
82
163
|
# See https://ddnexus.github.io/pagy/extras/items
|
83
164
|
# require 'pagy/extras/items'
|
84
|
-
#
|
85
|
-
# Pagy::
|
165
|
+
# set to false only if you want to make :items_extra an opt-in variable
|
166
|
+
# Pagy::DEFAULT[:items_extra] = false # default true
|
167
|
+
# Pagy::DEFAULT[:items_param] = :items # default
|
168
|
+
# Pagy::DEFAULT[:max_items] = 100 # default
|
86
169
|
|
87
170
|
# Overflow extra: Allow for easy handling of overflowing pages
|
88
171
|
# See https://ddnexus.github.io/pagy/extras/overflow
|
89
172
|
# require 'pagy/extras/overflow'
|
90
|
-
# Pagy::
|
173
|
+
# Pagy::DEFAULT[:overflow] = :empty_page # default (other options: :last_page and :exception)
|
91
174
|
|
92
|
-
#
|
93
|
-
# See https://ddnexus.github.io/pagy/extras/
|
94
|
-
#
|
95
|
-
# require 'pagy/extras/shared'
|
96
|
-
# require 'pagy/extras/metadata'
|
97
|
-
# For performance reason, you should explicitly set ONLY the metadata you use in the frontend
|
98
|
-
# Pagy::VARS[:metadata] = [:scaffold_url, :count, :page, :prev, :next, :last] # example
|
175
|
+
# Support extra: Extra support for features like: incremental, infinite, auto-scroll pagination
|
176
|
+
# See https://ddnexus.github.io/pagy/extras/support
|
177
|
+
# require 'pagy/extras/support'
|
99
178
|
|
100
179
|
# Trim extra: Remove the page=1 param from links
|
101
180
|
# See https://ddnexus.github.io/pagy/extras/trim
|
102
181
|
# require 'pagy/extras/trim'
|
182
|
+
# set to false only if you want to make :trim_extra an opt-in variable
|
183
|
+
# Pagy::DEFAULT[:trim_extra] = false # default true
|
103
184
|
|
104
|
-
|
105
|
-
|
106
|
-
#
|
107
|
-
#
|
108
|
-
# All the Pagy::VARS are set for all the Pagy instances but can be overridden
|
109
|
-
# per instance by just passing them to Pagy.new or the #pagy controller method
|
110
|
-
|
111
|
-
|
112
|
-
# Instance variables
|
113
|
-
# See https://ddnexus.github.io/pagy/api/pagy#instance-variables
|
114
|
-
# Pagy::VARS[:items] = 20 # default
|
115
|
-
|
116
|
-
|
117
|
-
# Other Variables
|
118
|
-
# See https://ddnexus.github.io/pagy/api/pagy#other-variables
|
119
|
-
# Pagy::VARS[:size] = [1,4,4,1] # default
|
120
|
-
# Pagy::VARS[:page_param] = :page # default
|
121
|
-
# Pagy::VARS[:params] = {} # default
|
122
|
-
# Pagy::VARS[:anchor] = '#anchor' # example
|
123
|
-
# Pagy::VARS[:link_extra] = 'data-remote="true"' # example
|
185
|
+
# Standalone extra: Use pagy in non Rack environment/gem
|
186
|
+
# See https://ddnexus.github.io/pagy/extras/standalone
|
187
|
+
# require 'pagy/extras/standalone'
|
188
|
+
# Pagy::DEFAULT[:url] = 'http://www.example.com/subdir' # optional default
|
124
189
|
|
125
190
|
|
126
191
|
# Rails
|
@@ -147,18 +212,18 @@
|
|
147
212
|
#
|
148
213
|
# load the "de", "en" and "es" built-in locales:
|
149
214
|
# (the first passed :locale will be used also as the default_locale)
|
150
|
-
# Pagy::I18n.load({locale: 'de'},
|
151
|
-
# {locale: 'en'},
|
152
|
-
# {locale: 'es'})
|
215
|
+
# Pagy::I18n.load({ locale: 'de' },
|
216
|
+
# { locale: 'en' },
|
217
|
+
# { locale: 'es' })
|
153
218
|
#
|
154
219
|
# load the "en" built-in locale, a custom "es" locale,
|
155
220
|
# and a totally custom locale complete with a custom :pluralize proc:
|
156
221
|
# (the first passed :locale will be used also as the default_locale)
|
157
|
-
# Pagy::I18n.load({locale: 'en'},
|
158
|
-
# {locale: 'es', filepath: 'path/to/pagy-es.yml'},
|
159
|
-
# {locale: 'xyz', # not built-in
|
160
|
-
#
|
161
|
-
#
|
222
|
+
# Pagy::I18n.load({ locale: 'en' },
|
223
|
+
# { locale: 'es', filepath: 'path/to/pagy-es.yml' },
|
224
|
+
# { locale: 'xyz', # not built-in
|
225
|
+
# filepath: 'path/to/pagy-xyz.yml',
|
226
|
+
# pluralize: lambda{ |count| ... } )
|
162
227
|
|
163
228
|
|
164
229
|
# I18n extra: uses the standard i18n gem which is ~18x slower using ~10x more memory
|
@@ -167,4 +232,8 @@
|
|
167
232
|
# require 'pagy/extras/i18n'
|
168
233
|
|
169
234
|
# Default i18n key
|
170
|
-
# Pagy::
|
235
|
+
# Pagy::DEFAULT[:i18n_key] = 'pagy.item_name' # default
|
236
|
+
|
237
|
+
|
238
|
+
# When you are done setting your own default freeze it, so it will not get changed accidentally
|
239
|
+
Pagy::DEFAULT.freeze
|
@@ -0,0 +1,117 @@
|
|
1
|
+
// The Pagy object
|
2
|
+
const Pagy = {
|
3
|
+
version: "5.7.3",
|
4
|
+
// Scan for "data-pagy-json" elements, parse their JSON content and call their init functions
|
5
|
+
init(arg) {
|
6
|
+
const target = arg instanceof Element ? arg : document;
|
7
|
+
const elements = target.querySelectorAll("[data-pagy-json]");
|
8
|
+
const warn = (el, err) => console.warn("Pagy.init() skipped element: %o\n%s", el, err);
|
9
|
+
for (const element of elements) {
|
10
|
+
const json = element.getAttribute("data-pagy-json");
|
11
|
+
try {
|
12
|
+
const [keyword, ...args] = JSON.parse(json);
|
13
|
+
if (keyword === "nav") {
|
14
|
+
Pagy.initNav(element, args);
|
15
|
+
}
|
16
|
+
else if (keyword === "combo") {
|
17
|
+
Pagy.initCombo(element, args);
|
18
|
+
}
|
19
|
+
else if (keyword === "selector") {
|
20
|
+
Pagy.initSelector(element, args);
|
21
|
+
}
|
22
|
+
else {
|
23
|
+
warn(element, `Illegal PagyJSON keyword: expected "nav"|"combo"|"selector", got "${keyword}"`);
|
24
|
+
}
|
25
|
+
}
|
26
|
+
catch (err) {
|
27
|
+
warn(element, err);
|
28
|
+
}
|
29
|
+
}
|
30
|
+
},
|
31
|
+
// Init the *_nav_js helpers
|
32
|
+
initNav(el, [tags, sequels, labelSequels, trimParam]) {
|
33
|
+
const container = el.parentElement ?? el;
|
34
|
+
const widths = Object.getOwnPropertyNames(sequels).map(w => parseInt(w)).sort((a, b) => b - a);
|
35
|
+
let lastWidth = -1;
|
36
|
+
const fillIn = (link, page, label) => link.replace(/__pagy_page__/g, page).replace(/__pagy_label__/g, label);
|
37
|
+
(el.pagyRender = function () {
|
38
|
+
const width = widths.find(w => w < container.clientWidth) || 0;
|
39
|
+
if (width === lastWidth) {
|
40
|
+
return;
|
41
|
+
} // no change: abort
|
42
|
+
let html = tags.before;
|
43
|
+
const series = sequels[width.toString()];
|
44
|
+
const labels = labelSequels?.[width.toString()] ?? series.map(l => l.toString());
|
45
|
+
for (const i in series) {
|
46
|
+
const item = series[i];
|
47
|
+
const label = labels[i];
|
48
|
+
if (typeof trimParam === "string" && item === 1) {
|
49
|
+
html += Pagy.trim(fillIn(tags.link, item.toString(), label), trimParam);
|
50
|
+
}
|
51
|
+
else if (typeof item === "number") {
|
52
|
+
html += fillIn(tags.link, item.toString(), label);
|
53
|
+
}
|
54
|
+
else if (item === "gap") {
|
55
|
+
html += tags.gap;
|
56
|
+
}
|
57
|
+
else { // active page
|
58
|
+
html += fillIn(tags.active, item, label);
|
59
|
+
}
|
60
|
+
}
|
61
|
+
html += tags.after; // eslint-disable-line align-assignments/align-assignments
|
62
|
+
el.innerHTML = "";
|
63
|
+
el.insertAdjacentHTML("afterbegin", html);
|
64
|
+
lastWidth = width;
|
65
|
+
})();
|
66
|
+
if (el.classList.contains("pagy-rjs")) {
|
67
|
+
Pagy.rjsObserver.observe(container);
|
68
|
+
}
|
69
|
+
},
|
70
|
+
// The observer instance for responsive navs
|
71
|
+
rjsObserver: new ResizeObserver(entries => {
|
72
|
+
entries.filter(e => e.contentBoxSize)
|
73
|
+
.forEach(e => e.target.querySelectorAll(".pagy-rjs")
|
74
|
+
.forEach(rjs => rjs.pagyRender()));
|
75
|
+
}),
|
76
|
+
// Init the *_combo_nav_js helpers
|
77
|
+
initCombo(el, [link, trimParam]) {
|
78
|
+
Pagy.initInput(el, inputValue => [inputValue, link.replace(/__pagy_page__/, inputValue)], trimParam);
|
79
|
+
},
|
80
|
+
// Init the items_selector_js helper
|
81
|
+
initSelector(el, [from, link, trimParam]) {
|
82
|
+
Pagy.initInput(el, inputValue => {
|
83
|
+
const page = Math.max(Math.ceil(from / parseInt(inputValue)), 1).toString();
|
84
|
+
const html = link.replace(/__pagy_page__/, page).replace(/__pagy_items__/, inputValue);
|
85
|
+
return [page, html];
|
86
|
+
}, trimParam);
|
87
|
+
},
|
88
|
+
// Init the input element
|
89
|
+
initInput(el, getVars, trimParam) {
|
90
|
+
const input = el.querySelector("input");
|
91
|
+
const initial = input.value;
|
92
|
+
const action = function () {
|
93
|
+
if (input.value === initial) {
|
94
|
+
return;
|
95
|
+
} // not changed
|
96
|
+
const [min, val, max] = [input.min, input.value, input.max].map(n => parseInt(n) || 0);
|
97
|
+
if (val < min || val > max) { // reset invalid/out-of-range
|
98
|
+
input.value = initial;
|
99
|
+
input.select();
|
100
|
+
return;
|
101
|
+
}
|
102
|
+
let [page, html] = getVars(input.value); // eslint-disable-line prefer-const
|
103
|
+
if (typeof trimParam === "string" && page === "1") {
|
104
|
+
html = Pagy.trim(html, trimParam);
|
105
|
+
}
|
106
|
+
el.insertAdjacentHTML("afterbegin", html);
|
107
|
+
el.querySelector("a").click();
|
108
|
+
};
|
109
|
+
["change", "focus"].forEach(e => input.addEventListener(e, input.select)); // auto-select
|
110
|
+
input.addEventListener("focusout", action); // trigger action
|
111
|
+
input.addEventListener("keypress", e => { if (e.key === "Enter") {
|
112
|
+
action();
|
113
|
+
} }); // trigger action
|
114
|
+
},
|
115
|
+
// Trim the ${page-param}=1 params in links
|
116
|
+
trim: (link, param) => link.replace(new RegExp(`[?&]${param}=1\\b(?!&)|\\b${param}=1&`), "")
|
117
|
+
};
|
data/lib/javascripts/pagy.js
CHANGED
@@ -1,106 +1 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
function Pagy(){}
|
4
|
-
|
5
|
-
Pagy.version = '3.10.0';
|
6
|
-
|
7
|
-
Pagy.init = function(arg){
|
8
|
-
var target = arg instanceof Event || arg === undefined ? document : arg,
|
9
|
-
jsonTags = target.getElementsByClassName('pagy-json');
|
10
|
-
if (target === document) { // reset resize-listeners on page load (#163)
|
11
|
-
for (var id in Pagy.navResizeListeners) { window.removeEventListener('resize', Pagy.navResizeListeners[id], true) }
|
12
|
-
Pagy.navResizeListeners = {};
|
13
|
-
}
|
14
|
-
for (var i = 0, len = jsonTags.length; i < len; i++) {
|
15
|
-
var args = JSON.parse(jsonTags[i].innerHTML);
|
16
|
-
Pagy[args.shift()].apply(null, args);
|
17
|
-
}
|
18
|
-
};
|
19
|
-
|
20
|
-
Pagy.nav = function(id, tags, sequels, param){
|
21
|
-
var pagyEl = document.getElementById(id),
|
22
|
-
lastWidth = undefined,
|
23
|
-
timeoutId = 0,
|
24
|
-
pageREg = new RegExp(/__pagy_page__/g),
|
25
|
-
widths = [],
|
26
|
-
rendering = function(){ clearTimeout(timeoutId); timeoutId = setTimeout(pagyEl.render, 150) }; // suppress rapid firing rendering
|
27
|
-
|
28
|
-
for (var width in sequels) { widths.push(parseInt(width)) } // fine with sequels structure
|
29
|
-
widths.sort(function(a, b){return b-a});
|
30
|
-
|
31
|
-
pagyEl.render = function(){
|
32
|
-
if (this.parentElement.clientWidth === 0) { rendering() }
|
33
|
-
var width, i, len;
|
34
|
-
for (i = 0, len = widths.length; i < len; i++) {
|
35
|
-
if (this.parentElement.clientWidth > widths[i]) { width = widths[i]; break }
|
36
|
-
}
|
37
|
-
if (width !== lastWidth) {
|
38
|
-
var html = tags.before,
|
39
|
-
series = sequels[width];
|
40
|
-
for (i = 0, len = series.length; i < len; i++) {
|
41
|
-
var item = series[i];
|
42
|
-
if (typeof(param) === 'string' && item === 1) { html += Pagy.trim(tags.link.replace(pageREg, item), param) }
|
43
|
-
else if (typeof(item) === 'number') { html += tags.link.replace(pageREg, item) }
|
44
|
-
else if (item === 'gap') { html += tags.gap }
|
45
|
-
else if (typeof(item) === 'string') { html += tags.active.replace(pageREg, item) }
|
46
|
-
}
|
47
|
-
html += tags.after;
|
48
|
-
this.innerHTML = '';
|
49
|
-
this.insertAdjacentHTML('afterbegin', html);
|
50
|
-
lastWidth = width;
|
51
|
-
}
|
52
|
-
}.bind(pagyEl);
|
53
|
-
|
54
|
-
if (widths.length > 1) {
|
55
|
-
// refresh the window resize listener (avoiding rendering multiple times)
|
56
|
-
window.removeEventListener('resize', Pagy.navResizeListeners[id], true); // needed for AJAX init
|
57
|
-
window.addEventListener('resize', rendering, true);
|
58
|
-
Pagy.navResizeListeners[id] = rendering;
|
59
|
-
}
|
60
|
-
pagyEl.render();
|
61
|
-
};
|
62
|
-
|
63
|
-
Pagy.combo_nav = function(id, page, link, param){
|
64
|
-
var pagyEl = document.getElementById(id),
|
65
|
-
input = pagyEl.getElementsByTagName('input')[0],
|
66
|
-
go = function(){
|
67
|
-
if (page !== input.value) {
|
68
|
-
var html = link.replace(/__pagy_page__/, input.value);
|
69
|
-
if (typeof(param) === 'string' && input.value === '1') { html = Pagy.trim(html, param) }
|
70
|
-
pagyEl.insertAdjacentHTML('afterbegin', html);
|
71
|
-
pagyEl.getElementsByTagName('a')[0].click();
|
72
|
-
}
|
73
|
-
};
|
74
|
-
Pagy.addInputEventListeners(input, go);
|
75
|
-
};
|
76
|
-
|
77
|
-
Pagy.items_selector = function(id, from, link, param){
|
78
|
-
var pagyEl = document.getElementById(id),
|
79
|
-
input = pagyEl.getElementsByTagName('input')[0],
|
80
|
-
current = input.value,
|
81
|
-
go = function(){
|
82
|
-
var items = input.value;
|
83
|
-
if (current !== items) {
|
84
|
-
var page = Math.max(Math.ceil(from / items),1),
|
85
|
-
html = link.replace(/__pagy_page__/, page).replace(/__pagy_items__/, items);
|
86
|
-
if (typeof(param) === 'string' && page === 1){ html = Pagy.trim(html, param) }
|
87
|
-
pagyEl.insertAdjacentHTML('afterbegin', html);
|
88
|
-
pagyEl.getElementsByTagName('a')[0].click();
|
89
|
-
}
|
90
|
-
};
|
91
|
-
Pagy.addInputEventListeners(input, go);
|
92
|
-
};
|
93
|
-
|
94
|
-
Pagy.addInputEventListeners = function(input, handler){
|
95
|
-
// select the content on click: easier for typing a number
|
96
|
-
input.addEventListener('click', function(){ this.select() });
|
97
|
-
// go when the input looses focus
|
98
|
-
input.addEventListener('focusout', handler);
|
99
|
-
// … and when pressing enter inside the input
|
100
|
-
input.addEventListener('keyup', function(e){ if (e.which === 13) handler() }.bind(this));
|
101
|
-
};
|
102
|
-
|
103
|
-
Pagy.trim = function(html, param){
|
104
|
-
var re = new RegExp('[?&]' + param + '=1\\b(?!&)|\\b' + param + '=1&');
|
105
|
-
return html.replace(re, '');
|
106
|
-
};
|
1
|
+
!function(){function t(t){if(Array.isArray(t))return t}function n(t){if(Symbol.iterator in Object(t)||"[object Arguments]"===Object.prototype.toString.call(t))return Array.from(t)}function e(){throw new TypeError("Invalid attempt to destructure non-iterable instance")}function r(r,i){return t(r)||n(r)||e()}var i={version:"5.7.3",init:function(r){var a,o=(r instanceof Element?r:document).querySelectorAll("[data-pagy-json]"),c=function(t,n){return console.warn("Pagy.init() skipped element: %o\n%s",t,n)},u=!0,l=!1,f=void 0;try{for(var p,s=o[Symbol.iterator]();!(u=(p=s.next()).done);u=!0){var v=p.value,g=v.getAttribute("data-pagy-json");try{var y=t(a=JSON.parse(g))||n(a)||e(),d=y[0],m=y.slice(1);"nav"===d?i.initNav(v,m):"combo"===d?i.initCombo(v,m):"selector"===d?i.initSelector(v,m):c(v,'Illegal PagyJSON keyword: expected "nav"|"combo"|"selector", got "'.concat(d,'"'))}catch(t){c(v,t)}}}catch(t){l=!0,f=t}finally{try{u||null==s.return||s.return()}finally{if(l)throw f}}},initNav:function(t,n){var e,a=r(n),o=a[0],c=a[1],u=a[2],l=a[3],f=null!==(e=t.parentElement)&&void 0!==e?e:t,p=Object.getOwnPropertyNames(c).map((function(t){return parseInt(t)})).sort((function(t,n){return n-t})),s=-1,v=function(t,n,e){return t.replace(/__pagy_page__/g,n).replace(/__pagy_label__/g,e)};(t.pagyRender=function(){var n=p.find((function(t){return t<f.clientWidth}))||0;if(n!==s){var e,r=o.before,a=c[n.toString()],g=null!==(e=null==u?void 0:u[n.toString()])&&void 0!==e?e:a.map((function(t){return t.toString()}));for(var y in a){var d=a[y],m=g[y];r+="string"==typeof l&&1===d?i.trim(v(o.link,d.toString(),m),l):"number"==typeof d?v(o.link,d.toString(),m):"gap"===d?o.gap:v(o.active,d,m)}r+=o.after,t.innerHTML="",t.insertAdjacentHTML("afterbegin",r),s=n}})(),t.classList.contains("pagy-rjs")&&i.rjsObserver.observe(f)},rjsObserver:new ResizeObserver((function(t){t.filter((function(t){return t.contentBoxSize})).forEach((function(t){return t.target.querySelectorAll(".pagy-rjs").forEach((function(t){return t.pagyRender()}))}))})),initCombo:function(t,n){var e=r(n),a=e[0],o=e[1];i.initInput(t,(function(t){return[t,a.replace(/__pagy_page__/,t)]}),o)},initSelector:function(t,n){var e=r(n),a=e[0],o=e[1],c=e[2];i.initInput(t,(function(t){var n=Math.max(Math.ceil(a/parseInt(t)),1).toString();return[n,o.replace(/__pagy_page__/,n).replace(/__pagy_items__/,t)]}),c)},initInput:function(t,n,e){var a=t.querySelector("input"),o=a.value,c=function(){if(a.value!==o){var c=r([a.min,a.value,a.max].map((function(t){return parseInt(t)||0}))),u=c[0],l=c[1],f=c[2];if(l<u||l>f)return a.value=o,void a.select();var p=r(n(a.value)),s=p[0],v=p[1];"string"==typeof e&&"1"===s&&(v=i.trim(v,e)),t.insertAdjacentHTML("afterbegin",v),t.querySelector("a").click()}};["change","focus"].forEach((function(t){return a.addEventListener(t,a.select)})),a.addEventListener("focusout",c),a.addEventListener("keypress",(function(t){"Enter"===t.key&&c()}))},trim:function(t,n){return t.replace(new RegExp("[?&]".concat(n,"=1\\b(?!&)|\\b").concat(n,"=1&")),"")}},a=i;window.Pagy=a}();
|
@@ -0,0 +1,118 @@
|
|
1
|
+
// The Pagy object
|
2
|
+
const Pagy = {
|
3
|
+
version: "5.7.3",
|
4
|
+
// Scan for "data-pagy-json" elements, parse their JSON content and call their init functions
|
5
|
+
init(arg) {
|
6
|
+
const target = arg instanceof Element ? arg : document;
|
7
|
+
const elements = target.querySelectorAll("[data-pagy-json]");
|
8
|
+
const warn = (el, err) => console.warn("Pagy.init() skipped element: %o\n%s", el, err);
|
9
|
+
for (const element of elements) {
|
10
|
+
const json = element.getAttribute("data-pagy-json");
|
11
|
+
try {
|
12
|
+
const [keyword, ...args] = JSON.parse(json);
|
13
|
+
if (keyword === "nav") {
|
14
|
+
Pagy.initNav(element, args);
|
15
|
+
}
|
16
|
+
else if (keyword === "combo") {
|
17
|
+
Pagy.initCombo(element, args);
|
18
|
+
}
|
19
|
+
else if (keyword === "selector") {
|
20
|
+
Pagy.initSelector(element, args);
|
21
|
+
}
|
22
|
+
else {
|
23
|
+
warn(element, `Illegal PagyJSON keyword: expected "nav"|"combo"|"selector", got "${keyword}"`);
|
24
|
+
}
|
25
|
+
}
|
26
|
+
catch (err) {
|
27
|
+
warn(element, err);
|
28
|
+
}
|
29
|
+
}
|
30
|
+
},
|
31
|
+
// Init the *_nav_js helpers
|
32
|
+
initNav(el, [tags, sequels, labelSequels, trimParam]) {
|
33
|
+
const container = el.parentElement ?? el;
|
34
|
+
const widths = Object.getOwnPropertyNames(sequels).map(w => parseInt(w)).sort((a, b) => b - a);
|
35
|
+
let lastWidth = -1;
|
36
|
+
const fillIn = (link, page, label) => link.replace(/__pagy_page__/g, page).replace(/__pagy_label__/g, label);
|
37
|
+
(el.pagyRender = function () {
|
38
|
+
const width = widths.find(w => w < container.clientWidth) || 0;
|
39
|
+
if (width === lastWidth) {
|
40
|
+
return;
|
41
|
+
} // no change: abort
|
42
|
+
let html = tags.before;
|
43
|
+
const series = sequels[width.toString()];
|
44
|
+
const labels = labelSequels?.[width.toString()] ?? series.map(l => l.toString());
|
45
|
+
for (const i in series) {
|
46
|
+
const item = series[i];
|
47
|
+
const label = labels[i];
|
48
|
+
if (typeof trimParam === "string" && item === 1) {
|
49
|
+
html += Pagy.trim(fillIn(tags.link, item.toString(), label), trimParam);
|
50
|
+
}
|
51
|
+
else if (typeof item === "number") {
|
52
|
+
html += fillIn(tags.link, item.toString(), label);
|
53
|
+
}
|
54
|
+
else if (item === "gap") {
|
55
|
+
html += tags.gap;
|
56
|
+
}
|
57
|
+
else { // active page
|
58
|
+
html += fillIn(tags.active, item, label);
|
59
|
+
}
|
60
|
+
}
|
61
|
+
html += tags.after; // eslint-disable-line align-assignments/align-assignments
|
62
|
+
el.innerHTML = "";
|
63
|
+
el.insertAdjacentHTML("afterbegin", html);
|
64
|
+
lastWidth = width;
|
65
|
+
})();
|
66
|
+
if (el.classList.contains("pagy-rjs")) {
|
67
|
+
Pagy.rjsObserver.observe(container);
|
68
|
+
}
|
69
|
+
},
|
70
|
+
// The observer instance for responsive navs
|
71
|
+
rjsObserver: new ResizeObserver(entries => {
|
72
|
+
entries.filter(e => e.contentBoxSize)
|
73
|
+
.forEach(e => e.target.querySelectorAll(".pagy-rjs")
|
74
|
+
.forEach(rjs => rjs.pagyRender()));
|
75
|
+
}),
|
76
|
+
// Init the *_combo_nav_js helpers
|
77
|
+
initCombo(el, [link, trimParam]) {
|
78
|
+
Pagy.initInput(el, inputValue => [inputValue, link.replace(/__pagy_page__/, inputValue)], trimParam);
|
79
|
+
},
|
80
|
+
// Init the items_selector_js helper
|
81
|
+
initSelector(el, [from, link, trimParam]) {
|
82
|
+
Pagy.initInput(el, inputValue => {
|
83
|
+
const page = Math.max(Math.ceil(from / parseInt(inputValue)), 1).toString();
|
84
|
+
const html = link.replace(/__pagy_page__/, page).replace(/__pagy_items__/, inputValue);
|
85
|
+
return [page, html];
|
86
|
+
}, trimParam);
|
87
|
+
},
|
88
|
+
// Init the input element
|
89
|
+
initInput(el, getVars, trimParam) {
|
90
|
+
const input = el.querySelector("input");
|
91
|
+
const initial = input.value;
|
92
|
+
const action = function () {
|
93
|
+
if (input.value === initial) {
|
94
|
+
return;
|
95
|
+
} // not changed
|
96
|
+
const [min, val, max] = [input.min, input.value, input.max].map(n => parseInt(n) || 0);
|
97
|
+
if (val < min || val > max) { // reset invalid/out-of-range
|
98
|
+
input.value = initial;
|
99
|
+
input.select();
|
100
|
+
return;
|
101
|
+
}
|
102
|
+
let [page, html] = getVars(input.value); // eslint-disable-line prefer-const
|
103
|
+
if (typeof trimParam === "string" && page === "1") {
|
104
|
+
html = Pagy.trim(html, trimParam);
|
105
|
+
}
|
106
|
+
el.insertAdjacentHTML("afterbegin", html);
|
107
|
+
el.querySelector("a").click();
|
108
|
+
};
|
109
|
+
["change", "focus"].forEach(e => input.addEventListener(e, input.select)); // auto-select
|
110
|
+
input.addEventListener("focusout", action); // trigger action
|
111
|
+
input.addEventListener("keypress", e => { if (e.key === "Enter") {
|
112
|
+
action();
|
113
|
+
} }); // trigger action
|
114
|
+
},
|
115
|
+
// Trim the ${page-param}=1 params in links
|
116
|
+
trim: (link, param) => link.replace(new RegExp(`[?&]${param}=1\\b(?!&)|\\b${param}=1&`), "")
|
117
|
+
};
|
118
|
+
export default Pagy;
|
data/lib/locales/ar.yml
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# :arabic pluralization (see https://github.com/ddnexus/pagy/blob/master/lib/locales/utils/p11n.rb)
|
2
|
+
|
3
|
+
ar:
|
4
|
+
pagy:
|
5
|
+
|
6
|
+
item_name:
|
7
|
+
zero: "صفر"
|
8
|
+
one: "عنصر"
|
9
|
+
two: "عنصرين"
|
10
|
+
few: "قليل"
|
11
|
+
many: "كثير"
|
12
|
+
other: "عناصر"
|
13
|
+
|
14
|
+
nav:
|
15
|
+
prev: "‹ السابق"
|
16
|
+
next: "التالي ›"
|
17
|
+
gap: "…"
|
18
|
+
|
19
|
+
info:
|
20
|
+
no_items: "لا يوجد %{item_name}"
|
21
|
+
single_page: "عرض <b>%{count}</b> %{item_name}"
|
22
|
+
multiple_pages: "عرض %{item_name} <b>%{from}-%{to}</b> من اجمالي <b>%{count}</b>"
|
23
|
+
|
24
|
+
combo_nav_js: "الصفحة %{page_input} من %{pages}"
|
25
|
+
|
26
|
+
items_selector_js: "عرض %{items_input} %{item_name} لكل صفحة"
|
data/lib/locales/bg.yml
CHANGED
@@ -17,6 +17,6 @@ bg:
|
|
17
17
|
single_page: "Показани са <b>%{count}</b> %{item_name}"
|
18
18
|
multiple_pages: "Показани са %{item_name} <b>%{from}-%{to}</b> от <b>%{count}</b> общо"
|
19
19
|
|
20
|
-
combo_nav_js: "
|
20
|
+
combo_nav_js: "<label>Страница %{page_input} от %{pages}</label>"
|
21
21
|
|
22
|
-
items_selector_js: "
|
22
|
+
items_selector_js: "<label>Покажи %{items_input} %{item_name} на страница</label>"
|