pagy 7.0.11 → 8.6.3

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 (109) hide show
  1. checksums.yaml +4 -4
  2. data/apps/calendar.ru +745 -0
  3. data/apps/demo.ru +435 -0
  4. data/apps/rails.ru +212 -0
  5. data/apps/repro.ru +177 -0
  6. data/apps/tmp/calendar.sqlite3 +0 -0
  7. data/apps/tmp/calendar.sqlite3-shm +0 -0
  8. data/apps/tmp/calendar.sqlite3-wal +0 -0
  9. data/apps/tmp/local_secret.txt +1 -0
  10. data/apps/tmp/pagy-keyset.sqlite3 +0 -0
  11. data/apps/tmp/pagy-keyset.sqlite3-shm +0 -0
  12. data/apps/tmp/pagy-keyset.sqlite3-wal +0 -0
  13. data/bin/pagy +100 -0
  14. data/{lib/config → config}/pagy.rb +31 -73
  15. data/javascripts/pagy-module.js +100 -0
  16. data/javascripts/pagy.js +4 -0
  17. data/javascripts/pagy.min.js +4 -0
  18. data/javascripts/pagy.min.js.map +10 -0
  19. data/javascripts/pagy.mjs +100 -0
  20. data/lib/optimist.rb +1022 -0
  21. data/lib/pagy/backend.rb +8 -3
  22. data/lib/pagy/calendar/day.rb +4 -3
  23. data/lib/pagy/calendar/month.rb +4 -3
  24. data/lib/pagy/calendar/quarter.rb +4 -3
  25. data/lib/pagy/calendar/unit.rb +106 -0
  26. data/lib/pagy/calendar/week.rb +3 -3
  27. data/lib/pagy/calendar/year.rb +4 -3
  28. data/lib/pagy/calendar.rb +55 -99
  29. data/lib/pagy/console.rb +2 -2
  30. data/lib/pagy/countless.rb +15 -10
  31. data/lib/pagy/extras/arel.rb +1 -1
  32. data/lib/pagy/extras/array.rb +1 -1
  33. data/lib/pagy/extras/bootstrap.rb +52 -63
  34. data/lib/pagy/extras/bulma.rb +49 -64
  35. data/lib/pagy/extras/calendar.rb +35 -5
  36. data/lib/pagy/extras/countless.rb +2 -2
  37. data/lib/pagy/extras/foundation.rb +52 -62
  38. data/lib/pagy/extras/gearbox.rb +28 -27
  39. data/lib/pagy/extras/headers.rb +1 -1
  40. data/lib/pagy/extras/i18n.rb +1 -1
  41. data/lib/pagy/extras/items.rb +21 -18
  42. data/lib/pagy/extras/{frontend_helpers.rb → js_tools.rb} +9 -6
  43. data/lib/pagy/extras/jsonapi.rb +2 -2
  44. data/lib/pagy/extras/materialize.rb +56 -52
  45. data/lib/pagy/extras/metadata.rb +6 -2
  46. data/lib/pagy/extras/overflow.rb +5 -4
  47. data/lib/pagy/extras/pagy.rb +82 -0
  48. data/lib/pagy/extras/semantic.rb +50 -51
  49. data/lib/pagy/extras/size.rb +40 -0
  50. data/lib/pagy/extras/standalone.rb +2 -2
  51. data/lib/pagy/extras/trim.rb +12 -12
  52. data/lib/pagy/extras/uikit.rb +51 -50
  53. data/lib/pagy/frontend.rb +39 -53
  54. data/lib/pagy/url_helpers.rb +9 -10
  55. data/lib/pagy.rb +51 -82
  56. data/{lib/locales → locales}/ar.yml +10 -11
  57. data/{lib/locales → locales}/be.yml +5 -5
  58. data/{lib/locales → locales}/bg.yml +5 -5
  59. data/{lib/locales → locales}/bs.yml +5 -5
  60. data/locales/ca.yml +21 -0
  61. data/locales/ckb.yml +18 -0
  62. data/{lib/locales → locales}/cs.yml +5 -5
  63. data/locales/da.yml +21 -0
  64. data/{lib/locales → locales}/de.yml +5 -5
  65. data/{lib/locales → locales}/en.yml +5 -5
  66. data/{lib/locales → locales}/es.yml +3 -3
  67. data/{lib/locales → locales}/fr.yml +5 -5
  68. data/{lib/locales → locales}/hr.yml +5 -5
  69. data/{lib/locales → locales}/id.yml +5 -5
  70. data/{lib/locales → locales}/it.yml +5 -5
  71. data/{lib/locales → locales}/ja.yml +5 -5
  72. data/{lib/locales → locales}/km.yml +5 -5
  73. data/locales/ko.yml +17 -0
  74. data/{lib/locales → locales}/nb.yml +5 -5
  75. data/{lib/locales → locales}/nl.yml +5 -5
  76. data/{lib/locales → locales}/nn.yml +5 -5
  77. data/{lib/locales → locales}/pl.yml +5 -5
  78. data/{lib/locales → locales}/pt-BR.yml +3 -3
  79. data/{lib/locales → locales}/pt.yml +3 -3
  80. data/locales/ru.yml +25 -0
  81. data/{lib/locales → locales}/sr.yml +5 -5
  82. data/{lib/locales → locales}/sv-SE.yml +5 -5
  83. data/{lib/locales → locales}/sv.yml +5 -5
  84. data/{lib/locales → locales}/sw.yml +5 -5
  85. data/{lib/locales → locales}/ta.yml +5 -5
  86. data/{lib/locales → locales}/tr.yml +5 -5
  87. data/{lib/locales → locales}/uk.yml +5 -5
  88. data/locales/vi.yml +17 -0
  89. data/{lib/locales → locales}/zh-CN.yml +5 -5
  90. data/{lib/locales → locales}/zh-HK.yml +5 -5
  91. data/{lib/locales → locales}/zh-TW.yml +5 -5
  92. data/{lib/stylesheets → stylesheets}/pagy.css +19 -34
  93. data/{lib/stylesheets → stylesheets}/pagy.scss +17 -19
  94. data/stylesheets/pagy.tailwind.css +21 -0
  95. metadata +76 -53
  96. data/lib/javascripts/pagy-dev.js +0 -112
  97. data/lib/javascripts/pagy-module.js +0 -111
  98. data/lib/javascripts/pagy.js +0 -1
  99. data/lib/locales/ca.yml +0 -23
  100. data/lib/locales/ckb.yml +0 -18
  101. data/lib/locales/da.yml +0 -23
  102. data/lib/locales/ko.yml +0 -19
  103. data/lib/locales/ru.yml +0 -27
  104. data/lib/locales/vi.yml +0 -17
  105. data/lib/pagy/calendar/helper.rb +0 -65
  106. data/lib/pagy/extras/navs.rb +0 -51
  107. data/lib/pagy/extras/support.rb +0 -40
  108. data/lib/stylesheets/pagy.tailwind.scss +0 -24
  109. /data/{lib/javascripts/pagy-module.d.ts → javascripts/pagy.d.ts} +0 -0
data/apps/repro.ru ADDED
@@ -0,0 +1,177 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Starting point app to try pagy or reproduce issues
4
+
5
+ # DEV USAGE
6
+ # pagy clone repro
7
+ # pagy ./repro.ru
8
+
9
+ # URL
10
+ # http://0.0.0.0:8000
11
+
12
+ # HELP
13
+ # pagy -h
14
+
15
+ # DOC
16
+ # https://ddnexus.github.io/pagy/playground/#1-repro-app
17
+
18
+ VERSION = '8.6.3'
19
+
20
+ require 'bundler/inline'
21
+ require 'bundler'
22
+ Bundler.configure
23
+ gemfile(ENV['PAGY_INSTALL_BUNDLE'] == 'true') do
24
+ source 'https://rubygems.org'
25
+ gem 'oj'
26
+ gem 'puma'
27
+ gem 'sinatra'
28
+ gem 'sinatra-contrib'
29
+ end
30
+
31
+ # Edit this section adding/removing the extras and Pagy::DEFAULT as needed
32
+ # pagy initializer
33
+ require 'pagy/extras/pagy'
34
+ require 'pagy/extras/items'
35
+ require 'pagy/extras/overflow'
36
+ Pagy::DEFAULT[:overflow] = :empty_page
37
+ Pagy::DEFAULT.freeze
38
+
39
+ require 'sinatra/base'
40
+ # Sinatra application
41
+ class PagyRepro < Sinatra::Base
42
+ configure do
43
+ enable :inline_templates
44
+ end
45
+ include Pagy::Backend
46
+
47
+ get('/javascripts/:file') do
48
+ format = params[:file].split('.').last
49
+ if format == 'js'
50
+ content_type 'application/javascript'
51
+ elsif format == 'map'
52
+ content_type 'application/json'
53
+ end
54
+ send_file Pagy.root.join('javascripts', params[:file])
55
+ end
56
+
57
+ # Edit this action as needed
58
+ get '/' do
59
+ collection = MockCollection.new
60
+ @pagy, @records = pagy(collection)
61
+ erb :main # template available in the __END__ section as @@ main
62
+ end
63
+ # Edit this section adding your own helpers as needed
64
+ helpers do
65
+ include Pagy::Frontend
66
+ end
67
+ end
68
+
69
+ # Simple array-based collection that acts as a standard DB collection.
70
+ # Use it as a simple way to get a collection that acts as a AR scope, but without any DB
71
+ # or create an ActiveRecord class or anything else that you need instead
72
+ class MockCollection < Array
73
+ def initialize(arr = Array(1..1000))
74
+ super
75
+ @collection = clone
76
+ end
77
+
78
+ def offset(value)
79
+ @collection = self[value..]
80
+ self
81
+ end
82
+
83
+ def limit(value)
84
+ @collection[0, value]
85
+ end
86
+
87
+ def count(*)
88
+ size
89
+ end
90
+ end
91
+
92
+ run PagyRepro
93
+
94
+ __END__
95
+
96
+ @@ layout
97
+ <!DOCTYPE html>
98
+ <html lang="en">
99
+ <html>
100
+ <head>
101
+ <title>Pagy Repro App</title>
102
+ <script src="javascripts/pagy.min.js"></script>
103
+ <script>
104
+ window.addEventListener("load", Pagy.init);
105
+ </script>
106
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
107
+ <style type="text/css">
108
+ @media screen { html, body {
109
+ font-size: 1rem;
110
+ line-height: 1.2s;
111
+ padding: 0;
112
+ margin: 0;
113
+ } }
114
+ body {
115
+ background: white !important;
116
+ margin: 0 !important;
117
+ font-family: sans-serif !important;
118
+ }
119
+ .content {
120
+ padding: 1rem 1.5rem 2rem !important;
121
+ }
122
+
123
+ /* Quick demo for overriding the element style attribute of certain pagy helpers
124
+ .pagy input[style] {
125
+ width: 5rem !important;
126
+ }
127
+ */
128
+
129
+ /*
130
+ If you want to customize the style,
131
+ please replace the line below with the actual file content
132
+ */
133
+ <%= Pagy.root.join('stylesheets', 'pagy.css').read %>
134
+ </style>
135
+ </head>
136
+ <body>
137
+ <%= yield %>
138
+ </body>
139
+ </html>
140
+
141
+ @@ main
142
+ <div class="content">
143
+ <h1>Pagy Repro App</h1>
144
+ <p> Self-contained, standalone Sinatra app usable to easily reproduce any pagy issue.</p>
145
+ <p>Please, report the following versions in any new issue.</p>
146
+ <h2>Versions</h4>
147
+ <ul>
148
+ <li>Ruby: <%= RUBY_VERSION %></li>
149
+ <li>Rack: <%= Rack::RELEASE %></li>
150
+ <li>Sinatra: <%= Sinatra::VERSION %></li>
151
+ <li>Pagy: <%= Pagy::VERSION %></li>
152
+ </ul>
153
+
154
+ <h3>Collection</h3>
155
+ <p id="records">@records: <%= @records.join(',') %></p>
156
+
157
+ <hr>
158
+
159
+ <h4>pagy_nav</h4>
160
+ <%= pagy_nav(@pagy, id: 'nav', aria_label: 'Pages nav') %>
161
+
162
+ <h4>pagy_nav_js</h4>
163
+ <%= pagy_nav_js(@pagy, id: 'nav-js', aria_label: 'Pages nav_js') %>
164
+
165
+ <h4>pagy_nav_js</h4>
166
+ <%= pagy_nav_js(@pagy, id: 'nav-js-responsive', aria_label: 'Pages nav_js_responsove',
167
+ steps: { 0 => 5, 500 => 7, 750 => 9, 1000 => 11 }) %>
168
+
169
+ <h4>pagy_combo_nav_js</h4>
170
+ <%= pagy_combo_nav_js(@pagy, id: 'combo-nav-js', aria_label: 'Pages combo_nav_js') %>
171
+
172
+ <h4>pagy_items_selector_js</h4>
173
+ <%= pagy_items_selector_js(@pagy, id: 'items-selector-js') %>
174
+
175
+ <h4>pagy_info</h4>
176
+ <%= pagy_info(@pagy, id: 'pagy-info') %>
177
+ </div>
Binary file
Binary file
File without changes
@@ -0,0 +1 @@
1
+ 4c57eebd7544c7f0acc9943ab614ab3da71d2461f5581ed8d41e9b8aa1bf23bff831f82e934eed96c608da0feac2c3dd21383c269d896cf01fcd6fa81aca2462
Binary file
Binary file
Binary file
data/bin/pagy ADDED
@@ -0,0 +1,100 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ VERSION = '8.6.3'
5
+ APPS = %w[repro rails demo calendar].freeze
6
+ LINUX = RbConfig::CONFIG['host_os'].include?('linux')
7
+ HOST = '0.0.0.0'
8
+ PORT = '8000'
9
+
10
+ require_relative '../lib/optimist'
11
+ opts = Optimist.options do
12
+ text <<~HEAD
13
+ Pagy #{VERSION} (https://ddnexus.github.io/pagy/playground)
14
+ Playground to showcase, clone and develop pagy APPs
15
+ APPs
16
+ repro Reproduce generic/simple issues
17
+ rails Reproduce rails related issues
18
+ demo Showcase all the helpers and styles
19
+ calendar Showcase the calendar; reproduce related issues
20
+ USAGE
21
+ pagy APP [options] Showcase APP from the installed gem
22
+ pagy clone APP Clone APP to the current dir
23
+ pagy APPFILE [options] Develop APPFILE from local path
24
+ EXAMPLES
25
+ pagy demo Showcase demo at http://#{HOST}:#{PORT}
26
+ pagy clone repro Clone repro to ./repro.ru
27
+ pagy ~/my-repro.ru Develop ~/my-repro.ru at#{HOST}:#{PORT}
28
+ HEAD
29
+ text 'Rackup options'
30
+ opt :env, 'Environment', default: 'development'
31
+ opt :host, 'Host', default: HOST, short: :o
32
+ opt :port, 'Port', default: PORT
33
+ opt :install, 'Install bundle for users', default: true
34
+ if LINUX
35
+ text 'Rerun options'
36
+ opt :rerun, 'Enable rerun for development', default: true
37
+ opt :clear, 'Clear screen before each rerun'
38
+ end
39
+ text 'Other options'
40
+ opt :quiet, 'Quiet mode for development'
41
+ version VERSION
42
+ end
43
+ Optimist.educate if ARGV.empty?
44
+
45
+ run_from_repo = File.exist?(File.expand_path('../pagy.gemspec', __dir__))
46
+
47
+ # Handles gems
48
+ require 'bundler/inline'
49
+ require 'bundler'
50
+ Bundler.configure
51
+ gemfile(opts[:install]) do
52
+ source 'https://rubygems.org'
53
+ gem 'rackup'
54
+ gem 'rerun' if LINUX
55
+ end
56
+
57
+ path = ->(app) { File.expand_path("../apps/#{app}.ru", __dir__) }
58
+ arg = ARGV.shift
59
+ if arg.eql?('clone')
60
+ arg = ARGV.shift
61
+ Optimist.die("Expected APP to be in [#{APPS.join(', ')}]; got #{arg.inspect}") unless APPS.include?(arg)
62
+ file = path.(arg)
63
+ name = File.basename(file)
64
+ if File.exist?(name)
65
+ print "Do you want to overwrite the #{name.inspect} file? (y/n)> "
66
+ answer = gets.chomp
67
+ Optimist.die("#{name.inspect} file already present") unless answer.start_with?(/y/i)
68
+ end
69
+ require 'fileutils'
70
+ FileUtils.cp(file, '.', verbose: true)
71
+ else
72
+ if APPS.include?(arg) # showcase env
73
+ opts[:env] = 'showcase'
74
+ opts[:rerun] = false
75
+ opts[:quiet] = true
76
+ # Avoid the creation of './tmp/local_secret.txt' for showcase env
77
+ ENV['SECRET_KEY_BASE'] = 'absolute secret!' if arg.eql?('rails')
78
+ file = path.(arg)
79
+ else # development env
80
+ file = arg
81
+ end
82
+ Optimist.die("#{file.inspect} app not found") unless File.exist?(file)
83
+ # Run command
84
+ gem_dir = File.expand_path('..', __dir__)
85
+ rackup = "rackup -I #{gem_dir}/lib -r pagy -o #{opts[:host]} -p #{opts[:port]} -E #{opts[:env]} #{file}"
86
+ rackup << ' -q' if opts[:quiet]
87
+ if opts[:rerun]
88
+ name = File.basename(file)
89
+ dir = File.dirname(file)
90
+ rerun = if run_from_repo # rerun app also when gem dir files change (for pagy devs)
91
+ "rerun --name #{name} -d #{dir},#{gem_dir} -p **/*.{rb,js,css,scss,ru,yml}"
92
+ else
93
+ "rerun --name #{name} -d #{dir} -p #{name}" # rerun only when app.ru changes
94
+ end
95
+ rerun << ' -q' if opts[:quiet]
96
+ rerun << ' -c' if opts[:clear]
97
+ rerun << " -- #{rackup}"
98
+ end
99
+ exec("PAGY_INSTALL_BUNDLE='#{opts[:install]}' #{rerun || rackup}")
100
+ end
@@ -1,41 +1,34 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Pagy initializer file (7.0.11)
3
+ # Pagy initializer file (8.6.3)
4
4
  # Customize only what you really need and notice that the core Pagy works also without any of the following lines.
5
5
  # Should you just cherry pick part of this file, please maintain the require-order of the extras
6
6
 
7
7
 
8
- # Pagy DEFAULT Variables
8
+ # Pagy Variables
9
9
  # See https://ddnexus.github.io/pagy/docs/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
10
+ # You can set any pagy variable as a Pagy::DEFAULT. They can also be overridden per instance by just passing them to
11
11
  # Pagy.new|Pagy::Countless.new|Pagy::Calendar::*.new or any of the #pagy* controller methods
12
-
13
- # Instance variables
14
- # See https://ddnexus.github.io/pagy/docs/api/pagy#instance-variables
15
- # Pagy::DEFAULT[:page] = 1 # default
16
- # Pagy::DEFAULT[:items] = 20 # default
17
- # Pagy::DEFAULT[:outset] = 0 # default
18
-
19
- # Other Variables
20
- # See https://ddnexus.github.io/pagy/docs/api/pagy#other-variables
21
- # Pagy::DEFAULT[:size] = [1,4,4,1] # default in pagy < 7.0
22
- # Pagy::DEFAULT[:page_param] = :page # default
23
- # Pagy::DEFAULT[:fragment] = '#fragment' # example
24
- # Pagy::DEFAULT[:link_extra] = 'data-remote="true"' # example
25
- # Pagy::DEFAULT[:item_i18n_key = 'pagy.item_name' # default
26
- # Pagy::DEFAULT[:nav_i18n_key] = 'pagy.aria_label.nav' # default
27
- # Pagy::DEFAULT[:cycle] = true # example
28
- # Pagy::DEFAULT[:request_path] = '/foo' # example
29
- # Pagy::DEFAULT[:count_args] = [] # example for non AR ORMs
30
- # Pagy::DEFAULT[:params] = {} # default
31
- # NOTICE: The :params can be also set as a lambda e.g:
32
- # ->(params){ params.exclude('useless').merge!('custom' => 'useful') }
12
+ # Here are the few that make more sense as DEFAULTs:
13
+ # Pagy::DEFAULT[:items] = 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
33
19
 
34
20
 
35
21
  # Extras
36
22
  # See https://ddnexus.github.io/pagy/categories/extra
37
23
 
38
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
+
39
32
  # Backend Extras
40
33
 
41
34
  # Arel extra: For better performance utilizing grouped ActiveRecord collections:
@@ -49,21 +42,12 @@
49
42
  # Calendar extra: Add pagination filtering by calendar time unit (year, quarter, month, week, day)
50
43
  # See https://ddnexus.github.io/pagy/docs/extras/calendar
51
44
  # require 'pagy/extras/calendar'
52
- # Default for each unit
53
- # Pagy::Calendar::Year::DEFAULT[:order] = :asc # Time direction of pagination
54
- # Pagy::Calendar::Year::DEFAULT[:format] = '%Y' # strftime format
55
- #
56
- # Pagy::Calendar::Quarter::DEFAULT[:order] = :asc # Time direction of pagination
57
- # Pagy::Calendar::Quarter::DEFAULT[:format] = '%Y-Q%q' # strftime format
58
- #
59
- # Pagy::Calendar::Month::DEFAULT[:order] = :asc # Time direction of pagination
60
- # Pagy::Calendar::Month::DEFAULT[:format] = '%Y-%m' # strftime format
61
- #
62
- # Pagy::Calendar::Week::DEFAULT[:order] = :asc # Time direction of pagination
63
- # Pagy::Calendar::Week::DEFAULT[:format] = '%Y-%W' # strftime format
64
- #
65
- # Pagy::Calendar::Day::DEFAULT[:order] = :asc # Time direction of pagination
66
- # Pagy::Calendar::Day::DEFAULT[:format] = '%Y-%m-%d' # strftime format
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
67
51
  #
68
52
  # Uncomment the following lines, if you need calendar localization without using the I18n extra
69
53
  # module LocalizePagyCalendar
@@ -106,8 +90,8 @@
106
90
 
107
91
  # Metadata extra: Provides the pagination metadata to Javascript frameworks like Vue.js, react.js, etc.
108
92
  # See https://ddnexus.github.io/pagy/docs/extras/metadata
109
- # you must require the frontend helpers internal extra (BEFORE the metadata extra) ONLY if you need also the :sequels
110
- # require 'pagy/extras/frontend_helpers'
93
+ # you must require the JS Tools internal extra (BEFORE the metadata extra) ONLY if you need also the :sequels
94
+ # require 'pagy/extras/js_tools'
111
95
  # require 'pagy/extras/metadata'
112
96
  # For performance reasons, you should explicitly set ONLY the metadata you use in the frontend
113
97
  # Pagy::DEFAULT[:metadata] = %i[scaffold_url page prev next last] # example
@@ -133,33 +117,15 @@
133
117
  # Bulma extra: Add nav, nav_js and combo_nav_js helpers and templates for Bulma pagination
134
118
  # See https://ddnexus.github.io/pagy/docs/extras/bulma
135
119
  # require 'pagy/extras/bulma'
136
- # DEFAULT[:bulma_nav_classes] = 'is-centered' # default
137
120
 
138
- # Foundation extra: Add nav, nav_js and combo_nav_js helpers and templates for Foundation pagination
139
- # See https://ddnexus.github.io/pagy/docs/extras/foundation
140
- # require 'pagy/extras/foundation'
141
-
142
- # Materialize extra: Add nav, nav_js and combo_nav_js helpers for Materialize pagination
143
- # See https://ddnexus.github.io/pagy/docs/extras/materialize
144
- # require 'pagy/extras/materialize'
145
-
146
- # Navs extra: Add nav_js and combo_nav_js javascript helpers
147
- # Notice: the other frontend extras add their own framework-styled versions,
148
- # so require this extra only if you need the unstyled version
149
- # See https://ddnexus.github.io/pagy/docs/extras/navs
150
- # require 'pagy/extras/navs'
151
-
152
- # Semantic extra: Add nav, nav_js and combo_nav_js helpers for Semantic UI pagination
153
- # See https://ddnexus.github.io/pagy/docs/extras/semantic
154
- # require 'pagy/extras/semantic'
155
-
156
- # UIkit extra: Add nav helper and templates for UIkit pagination
157
- # See https://ddnexus.github.io/pagy/docs/extras/uikit
158
- # require 'pagy/extras/uikit'
121
+ # Pagy extra: Add the pagy styled versions of the javascript-powered navs
122
+ # and a few other components to the Pagy::Frontend module.
123
+ # See https://ddnexus.github.io/pagy/docs/extras/pagy
124
+ # require 'pagy/extras/pagy'
159
125
 
160
126
  # Multi size var used by the *_nav_js helpers
161
- # See https://ddnexus.github.io/pagy/docs/extras/navs#steps
162
- # Pagy::DEFAULT[:steps] = { 0 => [2,3,3,2], 540 => [3,5,5,3], 720 => [5,7,7,5] } # example
127
+ # See https://ddnexus.github.io/pagy/docs/extras/pagy#steps
128
+ # Pagy::DEFAULT[:steps] = { 0 => 5, 540 => 7, 720 => 9 } # example
163
129
 
164
130
 
165
131
  # Feature Extras
@@ -184,10 +150,6 @@
184
150
  # require 'pagy/extras/overflow'
185
151
  # Pagy::DEFAULT[:overflow] = :empty_page # default (other options: :last_page and :exception)
186
152
 
187
- # Support extra: Extra support for features like: incremental, infinite, auto-scroll pagination
188
- # See https://ddnexus.github.io/pagy/docs/extras/support
189
- # require 'pagy/extras/support'
190
-
191
153
  # Trim extra: Remove the page=1 param from links
192
154
  # See https://ddnexus.github.io/pagy/docs/extras/trim
193
155
  # require 'pagy/extras/trim'
@@ -205,7 +167,6 @@
205
167
  # set to false only if you want to make :jsonapi an opt-in variable
206
168
  # Pagy::DEFAULT[:jsonapi] = false # default true
207
169
 
208
-
209
170
  # Rails
210
171
  # Enable the .js file required by the helpers that use javascript
211
172
  # (pagy*_nav_js, pagy*_combo_nav_js, and pagy_items_selector_js)
@@ -250,9 +211,6 @@
250
211
  # See https://ddnexus.github.io/pagy/docs/extras/i18n
251
212
  # require 'pagy/extras/i18n'
252
213
 
253
- # Default i18n key
254
- # Pagy::DEFAULT[:item_i18n_key] = 'pagy.item_name' # default
255
-
256
214
 
257
215
  # When you are done setting your own default freeze it, so it will not get changed accidentally
258
216
  Pagy::DEFAULT.freeze
@@ -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_items__/, 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: "8.6.3",
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;
@@ -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_items__/,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:"8.6.3",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=B9DC02765C7A5B6764756E2164756E21
4
+ //# sourceMappingURL=pagy.min.js.map
@@ -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_items__/,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:"8.6.3",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=B9DC02765C7A5B6764756E2164756E21
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 items_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_items__/, 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: \"8.6.3\",\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": "B9DC02765C7A5B6764756E2164756E21",
9
+ "names": []
10
+ }