pagy 3.8.2 → 9.4.0

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.
Files changed (152) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +1 -1
  3. data/apps/calendar.ru +737 -0
  4. data/apps/demo.ru +449 -0
  5. data/apps/index.rb +7 -0
  6. data/apps/keyset_ar.ru +228 -0
  7. data/apps/keyset_s.ru +220 -0
  8. data/apps/rails.ru +217 -0
  9. data/apps/repro.ru +182 -0
  10. data/bin/pagy +98 -0
  11. data/config/pagy.rb +220 -0
  12. data/javascripts/pagy.d.ts +5 -0
  13. data/javascripts/pagy.min.js +4 -0
  14. data/javascripts/pagy.min.js.map +10 -0
  15. data/javascripts/pagy.mjs +100 -0
  16. data/lib/optimist.rb +1022 -0
  17. data/lib/pagy/b64.rb +33 -0
  18. data/lib/pagy/backend.rb +30 -19
  19. data/lib/pagy/calendar/day.rb +41 -0
  20. data/lib/pagy/calendar/month.rb +42 -0
  21. data/lib/pagy/calendar/quarter.rb +49 -0
  22. data/lib/pagy/calendar/unit.rb +103 -0
  23. data/lib/pagy/calendar/week.rb +39 -0
  24. data/lib/pagy/calendar/year.rb +35 -0
  25. data/lib/pagy/calendar.rb +84 -0
  26. data/lib/pagy/console.rb +23 -0
  27. data/lib/pagy/countless.rb +27 -22
  28. data/lib/pagy/exceptions.rb +16 -13
  29. data/lib/pagy/extras/arel.rb +11 -14
  30. data/lib/pagy/extras/array.rb +12 -16
  31. data/lib/pagy/extras/bootstrap.rb +83 -41
  32. data/lib/pagy/extras/bulma.rb +79 -46
  33. data/lib/pagy/extras/calendar.rb +79 -0
  34. data/lib/pagy/extras/countless.rb +20 -25
  35. data/lib/pagy/extras/elasticsearch_rails.rb +59 -38
  36. data/lib/pagy/extras/gearbox.rb +55 -0
  37. data/lib/pagy/extras/headers.rb +38 -23
  38. data/lib/pagy/extras/i18n.rb +19 -18
  39. data/lib/pagy/extras/js_tools.rb +70 -0
  40. data/lib/pagy/extras/jsonapi.rb +88 -0
  41. data/lib/pagy/extras/keyset.rb +30 -0
  42. data/lib/pagy/extras/limit.rb +63 -0
  43. data/lib/pagy/extras/meilisearch.rb +57 -0
  44. data/lib/pagy/extras/metadata.rb +32 -27
  45. data/lib/pagy/extras/overflow.rb +61 -53
  46. data/lib/pagy/extras/pagy.rb +82 -0
  47. data/lib/pagy/extras/searchkick.rb +52 -41
  48. data/lib/pagy/extras/size.rb +40 -0
  49. data/lib/pagy/extras/standalone.rb +60 -0
  50. data/lib/pagy/extras/trim.rb +19 -13
  51. data/lib/pagy/frontend.rb +76 -51
  52. data/lib/pagy/i18n.rb +167 -0
  53. data/lib/pagy/keyset/active_record.rb +44 -0
  54. data/lib/pagy/keyset/sequel.rb +57 -0
  55. data/lib/pagy/keyset.rb +118 -0
  56. data/lib/pagy/shared_methods.rb +26 -0
  57. data/lib/pagy/url_helpers.rb +26 -0
  58. data/lib/pagy.rb +91 -37
  59. data/locales/ar.yml +29 -0
  60. data/locales/be.yml +25 -0
  61. data/locales/bg.yml +21 -0
  62. data/locales/bs.yml +25 -0
  63. data/locales/ca.yml +21 -0
  64. data/locales/ckb.yml +18 -0
  65. data/locales/cs.yml +23 -0
  66. data/locales/da.yml +21 -0
  67. data/locales/de.yml +21 -0
  68. data/locales/dz.yml +17 -0
  69. data/locales/en.yml +21 -0
  70. data/{lib/locales → locales}/es.yml +11 -12
  71. data/locales/fr.yml +21 -0
  72. data/locales/hr.yml +25 -0
  73. data/locales/id.yml +19 -0
  74. data/locales/it.yml +21 -0
  75. data/locales/ja.yml +19 -0
  76. data/locales/km.yml +19 -0
  77. data/locales/ko.yml +17 -0
  78. data/locales/nb.yml +21 -0
  79. data/locales/nl.yml +21 -0
  80. data/locales/nn.yml +21 -0
  81. data/locales/pl.yml +25 -0
  82. data/{lib/locales → locales}/pt-BR.yml +11 -12
  83. data/locales/pt.yml +21 -0
  84. data/locales/ru.yml +25 -0
  85. data/locales/sk.yml +23 -0
  86. data/locales/sr.yml +25 -0
  87. data/locales/sv-SE.yml +21 -0
  88. data/locales/sv.yml +21 -0
  89. data/locales/sw.yml +25 -0
  90. data/locales/ta.yml +21 -0
  91. data/locales/tr.yml +19 -0
  92. data/locales/uk.yml +25 -0
  93. data/locales/vi.yml +17 -0
  94. data/locales/zh-CN.yml +17 -0
  95. data/locales/zh-HK.yml +17 -0
  96. data/locales/zh-TW.yml +17 -0
  97. data/stylesheets/pagy.css +46 -0
  98. data/stylesheets/pagy.scss +48 -0
  99. data/stylesheets/pagy.tailwind.css +21 -0
  100. metadata +95 -67
  101. data/lib/config/pagy.rb +0 -170
  102. data/lib/javascripts/pagy.js +0 -106
  103. data/lib/locales/README.md +0 -35
  104. data/lib/locales/bg.yml +0 -22
  105. data/lib/locales/ca.yml +0 -22
  106. data/lib/locales/da.yml +0 -22
  107. data/lib/locales/de.yml +0 -22
  108. data/lib/locales/en.yml +0 -22
  109. data/lib/locales/fr.yml +0 -22
  110. data/lib/locales/id.yml +0 -20
  111. data/lib/locales/it.yml +0 -22
  112. data/lib/locales/ja.yml +0 -20
  113. data/lib/locales/km.yml +0 -19
  114. data/lib/locales/ko.yml +0 -20
  115. data/lib/locales/nb.yml +0 -22
  116. data/lib/locales/nl.yml +0 -22
  117. data/lib/locales/pl.yml +0 -24
  118. data/lib/locales/ru.yml +0 -24
  119. data/lib/locales/sv-SE.yml +0 -23
  120. data/lib/locales/sv.yml +0 -23
  121. data/lib/locales/tr.yml +0 -20
  122. data/lib/locales/utils/i18n.rb +0 -25
  123. data/lib/locales/utils/loader.rb +0 -34
  124. data/lib/locales/utils/p11n.rb +0 -80
  125. data/lib/locales/zh-CN.yml +0 -20
  126. data/lib/locales/zh-HK.yml +0 -20
  127. data/lib/locales/zh-TW.yml +0 -20
  128. data/lib/pagy/extras/foundation.rb +0 -57
  129. data/lib/pagy/extras/items.rb +0 -65
  130. data/lib/pagy/extras/materialize.rb +0 -59
  131. data/lib/pagy/extras/navs.rb +0 -38
  132. data/lib/pagy/extras/pagy_search.rb +0 -18
  133. data/lib/pagy/extras/semantic.rb +0 -55
  134. data/lib/pagy/extras/shared.rb +0 -53
  135. data/lib/pagy/extras/support.rb +0 -29
  136. data/lib/pagy/extras/uikit.rb +0 -62
  137. data/lib/templates/bootstrap_nav.html.erb +0 -24
  138. data/lib/templates/bootstrap_nav.html.haml +0 -34
  139. data/lib/templates/bootstrap_nav.html.slim +0 -34
  140. data/lib/templates/bulma_nav.html.erb +0 -24
  141. data/lib/templates/bulma_nav.html.haml +0 -32
  142. data/lib/templates/bulma_nav.html.slim +0 -32
  143. data/lib/templates/foundation_nav.html.erb +0 -24
  144. data/lib/templates/foundation_nav.html.haml +0 -34
  145. data/lib/templates/foundation_nav.html.slim +0 -34
  146. data/lib/templates/nav.html.erb +0 -22
  147. data/lib/templates/nav.html.haml +0 -30
  148. data/lib/templates/nav.html.slim +0 -29
  149. data/lib/templates/uikit_nav.html.erb +0 -15
  150. data/lib/templates/uikit_nav.html.haml +0 -28
  151. data/lib/templates/uikit_nav.html.slim +0 -28
  152. data/pagy.gemspec +0 -16
data/bin/pagy ADDED
@@ -0,0 +1,98 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ VERSION = '9.4.0'
5
+ LINUX = RbConfig::CONFIG['host_os'].include?('linux')
6
+ HOST = '0.0.0.0'
7
+ PORT = '8000'
8
+
9
+ require_relative '../lib/optimist'
10
+ require_relative '../apps/index'
11
+ apps = PagyApps::INDEX
12
+ opts = Optimist.options do
13
+ text <<~HEAD
14
+ Pagy #{VERSION} (https://ddnexus.github.io/pagy/playground)
15
+ Playground to showcase, clone and develop pagy APPs
16
+ APPs
17
+ #{ apps.map do |name, path|
18
+ " #{name}#{' ' * (27 - name.length)}#{File.readlines(path)[3].sub('# ', '').strip}"
19
+ end.join("\n")
20
+ }
21
+ USAGE
22
+ pagy APP [options] Showcase APP from the installed gem
23
+ pagy clone APP Clone APP to the current dir
24
+ pagy APPFILE [options] Develop APPFILE from local path
25
+ EXAMPLES
26
+ pagy demo Showcase demo at http://#{HOST}:#{PORT}
27
+ pagy clone repro Clone repro to ./repro.ru
28
+ pagy ~/my-repro.ru Develop ~/my-repro.ru at#{HOST}:#{PORT}
29
+ HEAD
30
+ text 'Rackup options'
31
+ opt :env, 'Environment', default: 'development'
32
+ opt :host, 'Host', default: HOST, short: :o
33
+ opt :port, 'Port', default: PORT
34
+ opt :install, 'Install bundle for users', default: true
35
+ if LINUX
36
+ text 'Rerun options'
37
+ opt :rerun, 'Enable rerun for development', default: true
38
+ opt :clear, 'Clear screen before each rerun'
39
+ end
40
+ text 'Other options'
41
+ opt :quiet, 'Quiet mode for development'
42
+ version VERSION
43
+ end
44
+ Optimist.educate if ARGV.empty?
45
+
46
+ run_from_repo = File.exist?(File.expand_path('../pagy.gemspec', __dir__))
47
+
48
+ # Bundle
49
+ require 'bundler/inline'
50
+ require 'bundler'
51
+ Bundler.configure
52
+ gemfile(opts[:install]) do
53
+ source 'https://rubygems.org'
54
+ gem 'rackup'
55
+ gem 'rerun' if LINUX
56
+ end
57
+
58
+ arg = ARGV.shift
59
+ if arg.eql?('clone')
60
+ name = ARGV.shift
61
+ Optimist.die("Expected APP to be in [#{apps.keys.join(', ')}]; got #{name.inspect}") unless apps.key?(name)
62
+ if File.exist?(name)
63
+ print "Do you want to overwrite the #{name.inspect} file? (y/n)> "
64
+ answer = gets.chomp
65
+ Optimist.die("#{name.inspect} file already present") unless answer.start_with?(/y/i)
66
+ end
67
+ require 'fileutils'
68
+ FileUtils.cp(apps[name], '.', verbose: true)
69
+ else
70
+ if apps.key?(arg) # showcase env
71
+ opts[:env] = 'showcase'
72
+ opts[:rerun] = false
73
+ opts[:quiet] = true
74
+ # Avoid the creation of './tmp/local_secret.txt' for showcase env
75
+ ENV['SECRET_KEY_BASE'] = 'absolute secret!' if arg.eql?('rails')
76
+ file = apps[arg]
77
+ else # development env
78
+ file = arg
79
+ end
80
+ Optimist.die("#{file.inspect} app not found") unless File.exist?(file)
81
+ # Run command
82
+ gem_dir = File.expand_path('..', __dir__)
83
+ rackup = "rackup -I #{gem_dir}/lib -r pagy -o #{opts[:host]} -p #{opts[:port]} -E #{opts[:env]} #{file}"
84
+ rackup << ' -q' if opts[:quiet]
85
+ if opts[:rerun]
86
+ name = File.basename(file)
87
+ dir = File.dirname(file)
88
+ rerun = if run_from_repo # rerun app also when gem dir files change (for pagy devs)
89
+ "rerun --name #{name} -d #{dir},#{gem_dir} -p **/*.{rb,js,css,scss,ru,yml}"
90
+ else
91
+ "rerun --name #{name} -d #{dir} -p #{name}" # rerun only when app.ru changes
92
+ end
93
+ rerun << ' -q' if opts[:quiet]
94
+ rerun << ' -c' if opts[:clear]
95
+ rerun << " -- #{rackup}"
96
+ end
97
+ exec("PAGY_INSTALL_BUNDLE='#{opts[:install]}' #{rerun || rackup}")
98
+ end
data/config/pagy.rb ADDED
@@ -0,0 +1,220 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Pagy initializer file (9.4.0)
4
+ # Customize only what you really need and notice that the core Pagy works also without any of the following lines.
5
+ # Should you just cherry pick part of this file, please maintain the require-order of the extras
6
+
7
+
8
+ # Pagy Variables
9
+ # See https://ddnexus.github.io/pagy/docs/api/pagy#variables
10
+ # You can set any pagy variable as a Pagy::DEFAULT. They can also 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
+ # Here are the few that make more sense as DEFAULTs:
13
+ # Pagy::DEFAULT[:limit] = 20 # default
14
+ # Pagy::DEFAULT[:size] = 7 # default
15
+ # Pagy::DEFAULT[:ends] = true # default
16
+ # Pagy::DEFAULT[:page_param] = :page # default
17
+ # Pagy::DEFAULT[:count_args] = [] # example for non AR ORMs
18
+ # Pagy::DEFAULT[:max_pages] = 3000 # example
19
+
20
+
21
+ # Extras
22
+ # See https://ddnexus.github.io/pagy/categories/extra
23
+
24
+
25
+ # Legacy Compatibility Extras
26
+
27
+ # Size extra: Enable the Array type for the `:size` variable (e.g. `size: [1,4,4,1]`)
28
+ # See https://ddnexus.github.io/pagy/docs/extras/size
29
+ # require 'pagy/extras/size' # must be required before the other extras
30
+
31
+
32
+ # Backend Extras
33
+
34
+ # Arel extra: For better performance utilizing grouped ActiveRecord collections:
35
+ # See: https://ddnexus.github.io/pagy/docs/extras/arel
36
+ # require 'pagy/extras/arel'
37
+
38
+ # Array extra: Paginate arrays efficiently, avoiding expensive array-wrapping and without overriding
39
+ # See https://ddnexus.github.io/pagy/docs/extras/array
40
+ # require 'pagy/extras/array'
41
+
42
+ # Calendar extra: Add pagination filtering by calendar time unit (year, quarter, month, week, day)
43
+ # See https://ddnexus.github.io/pagy/docs/extras/calendar
44
+ # require 'pagy/extras/calendar'
45
+ # Default for each calendar unit class in IRB:
46
+ # >> Pagy::Calendar::Year::DEFAULT
47
+ # >> Pagy::Calendar::Quarter::DEFAULT
48
+ # >> Pagy::Calendar::Month::DEFAULT
49
+ # >> Pagy::Calendar::Week::DEFAULT
50
+ # >> Pagy::Calendar::Day::DEFAULT
51
+ #
52
+ # Uncomment the following lines, if you need calendar localization without using the I18n extra
53
+ # module LocalizePagyCalendar
54
+ # def localize(time, opts)
55
+ # ::I18n.l(time, **opts)
56
+ # end
57
+ # end
58
+ # Pagy::Calendar.prepend LocalizePagyCalendar
59
+
60
+ # Countless extra: Paginate without any count, saving one query per rendering
61
+ # See https://ddnexus.github.io/pagy/docs/extras/countless
62
+ # require 'pagy/extras/countless'
63
+ # Pagy::DEFAULT[:countless_minimal] = false # default (eager loading)
64
+
65
+ # Elasticsearch Rails extra: Paginate `ElasticsearchRails::Results` objects
66
+ # See https://ddnexus.github.io/pagy/docs/extras/elasticsearch_rails
67
+ # Default :pagy_search method: change only if you use also
68
+ # the searchkick or meilisearch extra that defines the same
69
+ # Pagy::DEFAULT[:elasticsearch_rails_pagy_search] = :pagy_search
70
+ # Default original :search method called internally to do the actual search
71
+ # Pagy::DEFAULT[:elasticsearch_rails_search] = :search
72
+ # require 'pagy/extras/elasticsearch_rails'
73
+
74
+ # Headers extra: http response headers (and other helpers) useful for API pagination
75
+ # See https://ddnexus.github.io/pagy/docs/extras/headers
76
+ # require 'pagy/extras/headers'
77
+ # Pagy::DEFAULT[:headers] = { page: 'Current-Page',
78
+ # limit: 'Page-Items',
79
+ # count: 'Total-Count',
80
+ # pages: 'Total-Pages' } # default
81
+
82
+ # Keyset extra: Paginate with the Pagy keyset pagination technique
83
+ # See https://ddnexus.github.io/pagy/docs/extras/keyset
84
+ # require 'pagy/extras/keyset'
85
+
86
+ # Meilisearch extra: Paginate `Meilisearch` result objects
87
+ # See https://ddnexus.github.io/pagy/docs/extras/meilisearch
88
+ # Default :pagy_search method: change only if you use also
89
+ # the elasticsearch_rails or searchkick extra that define the same method
90
+ # Pagy::DEFAULT[:meilisearch_pagy_search] = :pagy_search
91
+ # Default original :search method called internally to do the actual search
92
+ # Pagy::DEFAULT[:meilisearch_search] = :ms_search
93
+ # require 'pagy/extras/meilisearch'
94
+
95
+ # Metadata extra: Provides the pagination metadata to Javascript frameworks like Vue.js, react.js, etc.
96
+ # See https://ddnexus.github.io/pagy/docs/extras/metadata
97
+ # you must require the JS Tools internal extra (BEFORE the metadata extra) ONLY if you need also the :sequels
98
+ # require 'pagy/extras/js_tools'
99
+ # require 'pagy/extras/metadata'
100
+ # For performance reasons, you should explicitly set ONLY the metadata you use in the frontend
101
+ # Pagy::DEFAULT[:metadata] = %i[scaffold_url page prev next last] # example
102
+
103
+ # Searchkick extra: Paginate `Searchkick::Results` objects
104
+ # See https://ddnexus.github.io/pagy/docs/extras/searchkick
105
+ # Default :pagy_search method: change only if you use also
106
+ # the elasticsearch_rails or meilisearch extra that defines the same
107
+ # Pagy::DEFAULT[:searchkick_pagy_search] = :pagy_search
108
+ # Default original :search method called internally to do the actual search
109
+ # Pagy::DEFAULT[:searchkick_search] = :search
110
+ # require 'pagy/extras/searchkick'
111
+ # uncomment if you are going to use Searchkick.pagy_search
112
+ # Searchkick.extend Pagy::Searchkick
113
+
114
+
115
+ # Frontend Extras
116
+
117
+ # Bootstrap extra: Add nav, nav_js and combo_nav_js helpers and templates for Bootstrap pagination
118
+ # See https://ddnexus.github.io/pagy/docs/extras/bootstrap
119
+ # require 'pagy/extras/bootstrap'
120
+
121
+ # Bulma extra: Add nav, nav_js and combo_nav_js helpers and templates for Bulma pagination
122
+ # See https://ddnexus.github.io/pagy/docs/extras/bulma
123
+ # require 'pagy/extras/bulma'
124
+
125
+ # Pagy extra: Add the pagy styled versions of the javascript-powered navs
126
+ # and a few other components to the Pagy::Frontend module.
127
+ # See https://ddnexus.github.io/pagy/docs/extras/pagy
128
+ # require 'pagy/extras/pagy'
129
+
130
+ # Multi size var used by the *_nav_js helpers
131
+ # See https://ddnexus.github.io/pagy/docs/extras/pagy#steps
132
+ # Pagy::DEFAULT[:steps] = { 0 => 5, 540 => 7, 720 => 9 } # example
133
+
134
+
135
+ # Feature Extras
136
+
137
+ # Gearbox extra: Automatically change the limit per page depending on the page number
138
+ # See https://ddnexus.github.io/pagy/docs/extras/gearbox
139
+ # require 'pagy/extras/gearbox'
140
+ # set to false only if you want to make :gearbox_extra an opt-in variable
141
+ # Pagy::DEFAULT[:gearbox_extra] = false # default true
142
+ # Pagy::DEFAULT[:gearbox_limit] = [15, 30, 60, 100] # default
143
+
144
+ # Limit extra: Allow the client to request a custom limit per page with an optional selector UI
145
+ # See https://ddnexus.github.io/pagy/docs/extras/limit
146
+ # require 'pagy/extras/limit'
147
+ # set to false only if you want to make :limit_extra an opt-in variable
148
+ # Pagy::DEFAULT[:limit_extra] = false # default true
149
+ # Pagy::DEFAULT[:limit_param] = :limit # default
150
+ # Pagy::DEFAULT[:limit_max] = 100 # default
151
+
152
+ # Overflow extra: Allow for easy handling of overflowing pages
153
+ # See https://ddnexus.github.io/pagy/docs/extras/overflow
154
+ # require 'pagy/extras/overflow'
155
+ # Pagy::DEFAULT[:overflow] = :empty_page # default (other options: :last_page and :exception)
156
+
157
+ # Trim extra: Remove the page=1 param from links
158
+ # See https://ddnexus.github.io/pagy/docs/extras/trim
159
+ # require 'pagy/extras/trim'
160
+ # set to false only if you want to make :trim_extra an opt-in variable
161
+ # Pagy::DEFAULT[:trim_extra] = false # default true
162
+
163
+ # Standalone extra: Use pagy in non Rack environment/gem
164
+ # See https://ddnexus.github.io/pagy/docs/extras/standalone
165
+ # require 'pagy/extras/standalone'
166
+ # Pagy::DEFAULT[:url] = 'http://www.example.com/subdir' # optional default
167
+
168
+ # Jsonapi extra: Implements JSON:API specifications
169
+ # See https://ddnexus.github.io/pagy/docs/extras/jsonapi
170
+ # require 'pagy/extras/jsonapi' # must be required after the other extras
171
+ # set to false only if you want to make :jsonapi an opt-in variable
172
+ # Pagy::DEFAULT[:jsonapi] = false # default true
173
+
174
+ # Rails
175
+ # Enable the .js file required by the helpers that use javascript
176
+ # (pagy*_nav_js, pagy*_combo_nav_js, and pagy_limit_selector_js)
177
+ # See https://ddnexus.github.io/pagy/docs/api/javascript
178
+
179
+ # With the asset pipeline
180
+ # Sprockets need to look into the pagy javascripts dir, so add it to the assets paths
181
+ # Rails.application.config.assets.paths << Pagy.root.join('javascripts')
182
+
183
+ # I18n
184
+
185
+ # Pagy internal I18n: ~18x faster using ~10x less memory than the i18n gem
186
+ # See https://ddnexus.github.io/pagy/docs/api/i18n
187
+ # Notice: No need to configure anything in this section if your app uses only "en"
188
+ # or if you use the i18n extra below
189
+ #
190
+ # Examples:
191
+ # load the "de" built-in locale:
192
+ # Pagy::I18n.load(locale: 'de')
193
+ #
194
+ # load the "de" locale defined in the custom file at :filepath:
195
+ # Pagy::I18n.load(locale: 'de', filepath: 'path/to/pagy-de.yml')
196
+ #
197
+ # load the "de", "en" and "es" built-in locales:
198
+ # (the first passed :locale will be used also as the default_locale)
199
+ # Pagy::I18n.load({ locale: 'de' },
200
+ # { locale: 'en' },
201
+ # { locale: 'es' })
202
+ #
203
+ # load the "en" built-in locale, a custom "es" locale,
204
+ # and a totally custom locale complete with a custom :pluralize proc:
205
+ # (the first passed :locale will be used also as the default_locale)
206
+ # Pagy::I18n.load({ locale: 'en' },
207
+ # { locale: 'es', filepath: 'path/to/pagy-es.yml' },
208
+ # { locale: 'xyz', # not built-in
209
+ # filepath: 'path/to/pagy-xyz.yml',
210
+ # pluralize: lambda{ |count| ... } )
211
+
212
+
213
+ # I18n extra: uses the standard i18n gem which is ~18x slower using ~10x more memory
214
+ # than the default pagy internal i18n (see above)
215
+ # See https://ddnexus.github.io/pagy/docs/extras/i18n
216
+ # require 'pagy/extras/i18n'
217
+
218
+
219
+ # When you are done setting your own default freeze it, so it will not get changed accidentally
220
+ Pagy::DEFAULT.freeze
@@ -0,0 +1,5 @@
1
+ declare const Pagy: {
2
+ version: string;
3
+ init(arg?: Element | never): void;
4
+ };
5
+ export default Pagy;
@@ -0,0 +1,4 @@
1
+ window.Pagy=(()=>{const j=new ResizeObserver((B)=>B.forEach((D)=>D.target.querySelectorAll(".pagy-rjs").forEach((E)=>E.pagyRender()))),x=(B,[D,E,z,G])=>{const F=B.parentElement??B,K=Object.keys(E).map((H)=>parseInt(H)).sort((H,M)=>M-H);let L=-1;const T=(H,M,R)=>H.replace(/__pagy_page__/g,M).replace(/__pagy_label__/g,R);if((B.pagyRender=function(){const H=K.find((Q)=>Q<F.clientWidth)||0;if(H===L)return;let M=D.before;const R=E[H.toString()],X=z?.[H.toString()]??R.map((Q)=>Q.toString());R.forEach((Q,J)=>{const $=X[J];let U;if(typeof Q==="number")U=T(D.a,Q.toString(),$);else if(Q==="gap")U=D.gap;else U=T(D.current,Q,$);M+=typeof G==="string"&&Q==1?Z(U,G):U}),M+=D.after,B.innerHTML="",B.insertAdjacentHTML("afterbegin",M),L=H})(),B.classList.contains("pagy-rjs"))j.observe(F)},A=(B,[D,E])=>Y(B,(z)=>[z,D.replace(/__pagy_page__/,z)],E),C=(B,[D,E,z])=>{Y(B,(G)=>{const F=Math.max(Math.ceil(D/parseInt(G)),1).toString(),K=E.replace(/__pagy_page__/,F).replace(/__pagy_limit__/,G);return[F,K]},z)},Y=(B,D,E)=>{const z=B.querySelector("input"),G=B.querySelector("a"),F=z.value,K=function(){if(z.value===F)return;const[L,T,H]=[z.min,z.value,z.max].map((X)=>parseInt(X)||0);if(T<L||T>H){z.value=F,z.select();return}let[M,R]=D(z.value);if(typeof E==="string"&&M==="1")R=Z(R,E);G.href=R,G.click()};["change","focus"].forEach((L)=>z.addEventListener(L,()=>z.select())),z.addEventListener("focusout",K),z.addEventListener("keypress",(L)=>{if(L.key==="Enter")K()})},Z=(B,D)=>B.replace(new RegExp(`[?&]${D}=1\\b(?!&)|\\b${D}=1&`),"");return{version:"9.4.0",init(B){const E=(B instanceof Element?B:document).querySelectorAll("[data-pagy]");for(let z of E)try{const G=Uint8Array.from(atob(z.getAttribute("data-pagy")),(L)=>L.charCodeAt(0)),[F,...K]=JSON.parse(new TextDecoder().decode(G));if(F==="nav")x(z,K);else if(F==="combo")A(z,K);else if(F==="selector")C(z,K);else console.warn("Skipped Pagy.init() for: %o\nUnknown keyword '%s'",z,F)}catch(G){console.warn("Skipped Pagy.init() for: %o\n%s",z,G)}}}})();
2
+
3
+ //# debugId=CBA26BF804D8ECA064756E2164756E21
4
+ //# sourceMappingURL=pagy.min.js.map
@@ -0,0 +1,10 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/pagy.ts"],
4
+ "sourcesContent": [
5
+ "type NavArgs = readonly [Tokens, Sequels, null | LabelSequels, string?]\ntype ComboArgs = readonly [string, string?]\ntype SelectorArgs = readonly [number, string, string?]\ntype JsonArgs = ['nav', NavArgs] | ['combo', ComboArgs] | ['selector', SelectorArgs]\n\ninterface Tokens {\n readonly before:string\n readonly a:string\n readonly current:string\n readonly gap:string\n readonly after:string\n}\ninterface Sequels {readonly [width:string]:(string | number)[]}\ninterface LabelSequels {readonly [width:string]:string[]}\ninterface NavElement extends Element {pagyRender():void}\n\nconst Pagy = (() => {\n // The observer instance for responsive navs\n const rjsObserver = new ResizeObserver(\n entries => entries.forEach(e => e.target.querySelectorAll<NavElement>(\".pagy-rjs\")\n .forEach(el => el.pagyRender())));\n // Init the *_nav_js helpers\n const initNav = (el:NavElement, [tokens, sequels, labelSequels, trimParam]:NavArgs) => {\n const container = el.parentElement ?? el;\n const widths = Object.keys(sequels).map(w => parseInt(w)).sort((a, b) => b - a);\n let lastWidth = -1;\n const fillIn = (a:string, page:string, label:string):string =>\n a.replace(/__pagy_page__/g, page).replace(/__pagy_label__/g, label);\n (el.pagyRender = function () {\n const width = widths.find(w => w < container.clientWidth) || 0;\n if (width === lastWidth) { return } // no change: abort\n let html = tokens.before; // already trimmed in html\n const series = sequels[width.toString()];\n const labels = labelSequels?.[width.toString()] ?? series.map(l => l.toString());\n series.forEach((item, i) => {\n const label = labels[i];\n let filled;\n if (typeof item === \"number\") {\n filled = fillIn(tokens.a, item.toString(), label);\n } else if (item === \"gap\") {\n filled = tokens.gap;\n } else { // active page\n filled = fillIn(tokens.current, item, label);\n }\n html += (typeof trimParam === \"string\" && item == 1) ? trim(filled, trimParam) : filled;\n });\n html += tokens.after;\n el.innerHTML = \"\";\n el.insertAdjacentHTML(\"afterbegin\", html);\n lastWidth = width;\n })();\n if (el.classList.contains(\"pagy-rjs\")) { rjsObserver.observe(container) }\n };\n\n // Init the *_combo_nav_js helpers\n const initCombo = (el:Element, [url_token, trimParam]:ComboArgs) =>\n initInput(el, inputValue => [inputValue, url_token.replace(/__pagy_page__/, inputValue)], trimParam);\n\n // Init the limit_selector_js helper\n const initSelector = (el:Element, [from, url_token, trimParam]:SelectorArgs) => {\n initInput(el, inputValue => {\n const page = Math.max(Math.ceil(from / parseInt(inputValue)), 1).toString();\n const url = url_token.replace(/__pagy_page__/, page).replace(/__pagy_limit__/, inputValue);\n return [page, url];\n }, trimParam);\n };\n\n // Init the input element\n const initInput = (el:Element, getVars:(v:string) => [string, string], trimParam?:string) => {\n const input = el.querySelector(\"input\") as HTMLInputElement;\n const link = el.querySelector(\"a\") as HTMLAnchorElement;\n const initial = input.value;\n const action = function () {\n if (input.value === initial) { return } // not changed\n const [min, val, max] = [input.min, input.value, input.max].map(n => parseInt(n) || 0);\n if (val < min || val > max) { // reset invalid/out-of-range\n input.value = initial;\n input.select();\n return;\n }\n let [page, url] = getVars(input.value); // eslint-disable-line prefer-const\n if (typeof trimParam === \"string\" && page === \"1\") { url = trim(url, trimParam) }\n link.href = url;\n link.click();\n };\n [\"change\", \"focus\"].forEach(e => input.addEventListener(e, () => input.select())); // auto-select\n input.addEventListener(\"focusout\", action); // trigger action\n input.addEventListener(\"keypress\", e => { if (e.key === \"Enter\") { action() } }); // trigger action\n };\n\n // Trim the ${page-param}=1 params in links\n const trim = (a:string, param:string) =>\n a.replace(new RegExp(`[?&]${param}=1\\\\b(?!&)|\\\\b${param}=1&`), \"\");\n\n // Public interface\n return {\n version: \"9.4.0\",\n\n // Scan for elements with a \"data-pagy\" attribute and call their init functions with the decoded args\n init(arg?:Element) {\n const target = arg instanceof Element ? arg : document;\n const elements = target.querySelectorAll(\"[data-pagy]\");\n for (const el of elements) {\n try {\n const uint8array = Uint8Array.from(atob(el.getAttribute(\"data-pagy\") as string), c => c.charCodeAt(0));\n const [keyword, ...args] = JSON.parse((new TextDecoder()).decode(uint8array)) as JsonArgs; // base64-utf8 -> JSON -> Array\n if (keyword === \"nav\") {\n initNav(el as NavElement, args as unknown as NavArgs);\n } else if (keyword === \"combo\") {\n initCombo(el, args as unknown as ComboArgs);\n } else if (keyword === \"selector\") {\n initSelector(el, args as unknown as SelectorArgs);\n } else {\n console.warn(\"Skipped Pagy.init() for: %o\\nUnknown keyword '%s'\", el, keyword);\n }\n } catch (err) { console.warn(\"Skipped Pagy.init() for: %o\\n%s\", el, err) }\n }\n }\n };\n})();\n\nexport default Pagy;\n"
6
+ ],
7
+ "mappings": "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",
8
+ "debugId": "CBA26BF804D8ECA064756E2164756E21",
9
+ "names": []
10
+ }
@@ -0,0 +1,100 @@
1
+ const Pagy = (() => {
2
+ const rjsObserver = new ResizeObserver((entries) => entries.forEach((e) => e.target.querySelectorAll(".pagy-rjs").forEach((el) => el.pagyRender())));
3
+ const initNav = (el, [tokens, sequels, labelSequels, trimParam]) => {
4
+ const container = el.parentElement ?? el;
5
+ const widths = Object.keys(sequels).map((w) => parseInt(w)).sort((a, b) => b - a);
6
+ let lastWidth = -1;
7
+ const fillIn = (a, page, label) => a.replace(/__pagy_page__/g, page).replace(/__pagy_label__/g, label);
8
+ (el.pagyRender = function() {
9
+ const width = widths.find((w) => w < container.clientWidth) || 0;
10
+ if (width === lastWidth) {
11
+ return;
12
+ }
13
+ let html = tokens.before;
14
+ const series = sequels[width.toString()];
15
+ const labels = labelSequels?.[width.toString()] ?? series.map((l) => l.toString());
16
+ series.forEach((item, i) => {
17
+ const label = labels[i];
18
+ let filled;
19
+ if (typeof item === "number") {
20
+ filled = fillIn(tokens.a, item.toString(), label);
21
+ } else if (item === "gap") {
22
+ filled = tokens.gap;
23
+ } else {
24
+ filled = fillIn(tokens.current, item, label);
25
+ }
26
+ html += typeof trimParam === "string" && item == 1 ? trim(filled, trimParam) : filled;
27
+ });
28
+ html += tokens.after;
29
+ el.innerHTML = "";
30
+ el.insertAdjacentHTML("afterbegin", html);
31
+ lastWidth = width;
32
+ })();
33
+ if (el.classList.contains("pagy-rjs")) {
34
+ rjsObserver.observe(container);
35
+ }
36
+ };
37
+ const initCombo = (el, [url_token, trimParam]) => initInput(el, (inputValue) => [inputValue, url_token.replace(/__pagy_page__/, inputValue)], trimParam);
38
+ const initSelector = (el, [from, url_token, trimParam]) => {
39
+ initInput(el, (inputValue) => {
40
+ const page = Math.max(Math.ceil(from / parseInt(inputValue)), 1).toString();
41
+ const url = url_token.replace(/__pagy_page__/, page).replace(/__pagy_limit__/, inputValue);
42
+ return [page, url];
43
+ }, trimParam);
44
+ };
45
+ const initInput = (el, getVars, trimParam) => {
46
+ const input = el.querySelector("input");
47
+ const link = el.querySelector("a");
48
+ const initial = input.value;
49
+ const action = function() {
50
+ if (input.value === initial) {
51
+ return;
52
+ }
53
+ const [min, val, max] = [input.min, input.value, input.max].map((n) => parseInt(n) || 0);
54
+ if (val < min || val > max) {
55
+ input.value = initial;
56
+ input.select();
57
+ return;
58
+ }
59
+ let [page, url] = getVars(input.value);
60
+ if (typeof trimParam === "string" && page === "1") {
61
+ url = trim(url, trimParam);
62
+ }
63
+ link.href = url;
64
+ link.click();
65
+ };
66
+ ["change", "focus"].forEach((e) => input.addEventListener(e, () => input.select()));
67
+ input.addEventListener("focusout", action);
68
+ input.addEventListener("keypress", (e) => {
69
+ if (e.key === "Enter") {
70
+ action();
71
+ }
72
+ });
73
+ };
74
+ const trim = (a, param) => a.replace(new RegExp(`[?&]${param}=1\\b(?!&)|\\b${param}=1&`), "");
75
+ return {
76
+ version: "9.4.0",
77
+ init(arg) {
78
+ const target = arg instanceof Element ? arg : document;
79
+ const elements = target.querySelectorAll("[data-pagy]");
80
+ for (const el of elements) {
81
+ try {
82
+ const uint8array = Uint8Array.from(atob(el.getAttribute("data-pagy")), (c) => c.charCodeAt(0));
83
+ const [keyword, ...args] = JSON.parse(new TextDecoder().decode(uint8array));
84
+ if (keyword === "nav") {
85
+ initNav(el, args);
86
+ } else if (keyword === "combo") {
87
+ initCombo(el, args);
88
+ } else if (keyword === "selector") {
89
+ initSelector(el, args);
90
+ } else {
91
+ console.warn("Skipped Pagy.init() for: %o\nUnknown keyword '%s'", el, keyword);
92
+ }
93
+ } catch (err) {
94
+ console.warn("Skipped Pagy.init() for: %o\n%s", el, err);
95
+ }
96
+ }
97
+ }
98
+ };
99
+ })();
100
+ export default Pagy;