pagy 3.10.0 → 5.7.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (94) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +1 -1
  3. data/lib/config/pagy.rb +121 -52
  4. data/lib/javascripts/pagy-dev.js +117 -0
  5. data/lib/javascripts/pagy.js +1 -106
  6. data/lib/javascripts/pagy.mjs +118 -0
  7. data/lib/locales/ar.yml +26 -0
  8. data/lib/locales/bg.yml +2 -2
  9. data/lib/locales/bs.yml +24 -0
  10. data/lib/locales/ca.yml +2 -2
  11. data/lib/locales/cs.yml +2 -2
  12. data/lib/locales/da.yml +2 -2
  13. data/lib/locales/de.yml +2 -2
  14. data/lib/locales/en.yml +2 -2
  15. data/lib/locales/es.yml +2 -2
  16. data/lib/locales/fr.yml +2 -2
  17. data/lib/locales/hr.yml +24 -0
  18. data/lib/locales/id.yml +2 -2
  19. data/lib/locales/it.yml +2 -2
  20. data/lib/locales/ja.yml +2 -2
  21. data/lib/locales/km.yml +2 -2
  22. data/lib/locales/ko.yml +2 -2
  23. data/lib/locales/nb.yml +2 -2
  24. data/lib/locales/nl.yml +2 -2
  25. data/lib/locales/pl.yml +2 -2
  26. data/lib/locales/pt-BR.yml +2 -2
  27. data/lib/locales/pt.yml +2 -2
  28. data/lib/locales/ru.yml +2 -2
  29. data/lib/locales/sr.yml +23 -0
  30. data/lib/locales/sv-SE.yml +2 -2
  31. data/lib/locales/sv.yml +2 -2
  32. data/lib/locales/sw.yml +22 -0
  33. data/lib/locales/ta.yml +22 -0
  34. data/lib/locales/tr.yml +2 -2
  35. data/lib/locales/uk.yml +24 -0
  36. data/lib/locales/zh-CN.yml +2 -2
  37. data/lib/locales/zh-HK.yml +2 -2
  38. data/lib/locales/zh-TW.yml +3 -3
  39. data/lib/pagy/backend.rb +11 -12
  40. data/lib/pagy/calendar/day.rb +29 -0
  41. data/lib/pagy/calendar/month.rb +16 -0
  42. data/lib/pagy/calendar/month_mixin.rb +49 -0
  43. data/lib/pagy/calendar/quarter.rb +23 -0
  44. data/lib/pagy/calendar/week.rb +39 -0
  45. data/lib/pagy/calendar/year.rb +29 -0
  46. data/lib/pagy/calendar.rb +90 -0
  47. data/lib/pagy/console.rb +23 -0
  48. data/lib/pagy/countless.rb +23 -19
  49. data/lib/pagy/exceptions.rb +16 -13
  50. data/lib/pagy/extras/arel.rb +12 -7
  51. data/lib/pagy/extras/array.rb +10 -9
  52. data/lib/pagy/extras/bootstrap.rb +77 -39
  53. data/lib/pagy/extras/bulma.rb +77 -43
  54. data/lib/pagy/extras/calendar.rb +66 -0
  55. data/lib/pagy/extras/countless.rb +17 -17
  56. data/lib/pagy/extras/elasticsearch_rails.rb +66 -37
  57. data/lib/pagy/extras/foundation.rb +74 -41
  58. data/lib/pagy/extras/frontend_helpers.rb +70 -0
  59. data/lib/pagy/extras/gearbox.rb +42 -0
  60. data/lib/pagy/extras/headers.rb +32 -18
  61. data/lib/pagy/extras/i18n.rb +18 -17
  62. data/lib/pagy/extras/items.rb +42 -53
  63. data/lib/pagy/extras/materialize.rb +68 -43
  64. data/lib/pagy/extras/meilisearch.rb +61 -0
  65. data/lib/pagy/extras/metadata.rb +27 -26
  66. data/lib/pagy/extras/navs.rb +54 -29
  67. data/lib/pagy/extras/overflow.rb +57 -52
  68. data/lib/pagy/extras/searchkick.rb +54 -36
  69. data/lib/pagy/extras/semantic.rb +66 -39
  70. data/lib/pagy/extras/standalone.rb +64 -0
  71. data/lib/pagy/extras/support.rb +34 -17
  72. data/lib/pagy/extras/trim.rb +18 -12
  73. data/lib/pagy/extras/uikit.rb +66 -44
  74. data/lib/pagy/frontend.rb +61 -53
  75. data/lib/pagy/i18n.rb +164 -0
  76. data/lib/pagy/url_helpers.rb +38 -0
  77. data/lib/pagy.rb +96 -30
  78. data/lib/templates/bootstrap_nav.html.erb +1 -1
  79. data/lib/templates/bootstrap_nav.html.haml +1 -1
  80. data/lib/templates/bootstrap_nav.html.slim +1 -1
  81. data/lib/templates/foundation_nav.html.erb +1 -1
  82. data/lib/templates/foundation_nav.html.haml +1 -1
  83. data/lib/templates/foundation_nav.html.slim +1 -1
  84. data/lib/templates/uikit_nav.html.erb +2 -2
  85. data/lib/templates/uikit_nav.html.haml +1 -1
  86. data/lib/templates/uikit_nav.html.slim +2 -2
  87. metadata +37 -16
  88. data/lib/locales/README.md +0 -35
  89. data/lib/locales/utils/i18n.rb +0 -25
  90. data/lib/locales/utils/loader.rb +0 -34
  91. data/lib/locales/utils/p11n.rb +0 -88
  92. data/lib/pagy/extras/pagy_search.rb +0 -18
  93. data/lib/pagy/extras/shared.rb +0 -53
  94. data/pagy.gemspec +0 -16
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9ce66549213b7c1a7f89755a31d5faec46f09372f5b854d7f7ede99fb329b5d0
4
- data.tar.gz: 35071f34f9a15378e91efb38f060e1178ccc2d7609ff2bdc99b435f8f9242417
3
+ metadata.gz: 3b065a7027d07b5bc504cbd2b80389a2e25168a075a7485d6a0155bd54b36bf4
4
+ data.tar.gz: 345c15d964cf6511adcbdf60514f605c64b83e51dd172849f98d337fcff67696
5
5
  SHA512:
6
- metadata.gz: d0a3520386cf1b796c5e26fe13c65ebc158d6fccbb24547a37bfcd5ef39ede686e1d3cb771c6ce23303d83529a075d03fc5e0288704b26bd0be17e0e641f1553
7
- data.tar.gz: 7ef28712f3e38fc05fbbebb5445d25d7f0ec97d61bebbd0c1a45830345c4bd5ba1be202b5a7417bc23d8f822d85408cd0051d1d3de22d66e6c6ee10c49caedbd
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-2020 Domizio Demichelis
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 (3.10.0)
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::VARS[:cycle] = false # default
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::VARS[:steps] = { 0 => [2,3,3,2], 540 => [3,5,5,3], 720 => [5,7,7,5] } # example
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
- # Headers extra: http response headers (and other helpers) useful for API pagination
73
- # See http://ddnexus.github.io/pagy/extras/headers
74
- # require 'pagy/extras/headers'
75
- # Pagy::VARS[:headers] = { page: 'Current-Page', items: 'Page-Items', count: 'Total-Count', pages: 'Total-Pages' } # default
76
-
77
- # Support extra: Extra support for features like: incremental, infinite, auto-scroll pagination
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
- # Pagy::VARS[:items_param] = :items # default
85
- # Pagy::VARS[:max_items] = 100 # default
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::VARS[:overflow] = :empty_page # default (other options: :last_page and :exception)
173
+ # Pagy::DEFAULT[:overflow] = :empty_page # default (other options: :last_page and :exception)
91
174
 
92
- # Metadata extra: Provides the pagination metadata to Javascript frameworks like Vue.js, react.js, etc.
93
- # See https://ddnexus.github.io/pagy/extras/metadata
94
- # you must require the shared internal extra (BEFORE the metadata extra) ONLY if you need also the :sequels
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
- # Pagy Variables
107
- # See https://ddnexus.github.io/pagy/api/pagy#variables
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
- # filepath: 'path/to/pagy-xyz.yml',
161
- # pluralize: lambda{|count| ... } )
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::VARS[:i18n_key] = 'pagy.item_name' # default
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
+ };
@@ -1,106 +1 @@
1
- // See the Pagy documentation: https://ddnexus.github.io/pagy/extras#javascript
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;
@@ -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: "&lsaquo;&nbsp;السابق"
16
+ next: "التالي&nbsp;&rsaquo;"
17
+ gap: "&hellip;"
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: "Страница %{page_input} от %{pages}"
20
+ combo_nav_js: "<label>Страница %{page_input} от %{pages}</label>"
21
21
 
22
- items_selector_js: "Покажи %{items_input} %{item_name} на страница"
22
+ items_selector_js: "<label>Покажи %{items_input} %{item_name} на страница</label>"