pagy 9.4.0 → 43.5.5

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 (176) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +1 -1
  3. data/apps/calendar.ru +566 -562
  4. data/apps/demo.ru +246 -182
  5. data/apps/enable_rails_page_segment.rb +56 -0
  6. data/apps/index.rb +4 -2
  7. data/apps/keynav+root_key.ru +316 -0
  8. data/apps/keynav.ru +255 -0
  9. data/apps/{keyset_ar.ru → keyset.ru} +33 -42
  10. data/apps/{keyset_s.ru → keyset_sequel.ru} +32 -40
  11. data/apps/rails.ru +57 -58
  12. data/apps/repro.ru +54 -51
  13. data/bin/pagy +2 -95
  14. data/config/pagy.rb +33 -207
  15. data/javascripts/ai_widget.js +90 -0
  16. data/javascripts/pagy.js +166 -0
  17. data/javascripts/pagy.min.js +2 -4
  18. data/javascripts/pagy.mjs +126 -67
  19. data/javascripts/wand.js +1172 -0
  20. data/lib/pagy/classes/calendar/calendar.rb +101 -0
  21. data/lib/pagy/{calendar → classes/calendar}/day.rb +7 -11
  22. data/lib/pagy/{calendar → classes/calendar}/month.rb +5 -10
  23. data/lib/pagy/{calendar → classes/calendar}/quarter.rb +10 -15
  24. data/lib/pagy/classes/calendar/unit.rb +93 -0
  25. data/lib/pagy/{calendar → classes/calendar}/week.rb +5 -9
  26. data/lib/pagy/{calendar → classes/calendar}/year.rb +5 -6
  27. data/lib/pagy/classes/exceptions.rb +26 -0
  28. data/lib/pagy/classes/keyset/adapters/active_record.rb +50 -0
  29. data/lib/pagy/classes/keyset/adapters/sequel.rb +62 -0
  30. data/lib/pagy/classes/keyset/keynav.rb +85 -0
  31. data/lib/pagy/classes/keyset/keyset.rb +155 -0
  32. data/lib/pagy/classes/offset/countish.rb +17 -0
  33. data/lib/pagy/classes/offset/countless.rb +63 -0
  34. data/lib/pagy/classes/offset/offset.rb +63 -0
  35. data/lib/pagy/classes/offset/search.rb +34 -0
  36. data/lib/pagy/classes/request.rb +48 -0
  37. data/lib/pagy/cli.rb +122 -0
  38. data/lib/pagy/console.rb +5 -20
  39. data/lib/pagy/deprecated.rb +84 -0
  40. data/lib/pagy/modules/abilities/configurable.rb +37 -0
  41. data/lib/pagy/modules/abilities/countable.rb +23 -0
  42. data/lib/pagy/modules/abilities/linkable.rb +72 -0
  43. data/lib/pagy/modules/abilities/rangeable.rb +14 -0
  44. data/lib/pagy/modules/abilities/shiftable.rb +12 -0
  45. data/lib/pagy/{b64.rb → modules/b64.rb} +4 -2
  46. data/lib/pagy/modules/console.rb +33 -0
  47. data/lib/pagy/modules/i18n/i18n.rb +72 -0
  48. data/lib/pagy/modules/i18n/p11n/arabic.rb +30 -0
  49. data/lib/pagy/modules/i18n/p11n/east_slavic.rb +27 -0
  50. data/lib/pagy/modules/i18n/p11n/one_other.rb +15 -0
  51. data/lib/pagy/modules/i18n/p11n/one_upto_two_other.rb +15 -0
  52. data/lib/pagy/modules/i18n/p11n/other.rb +13 -0
  53. data/lib/pagy/modules/i18n/p11n/polish.rb +27 -0
  54. data/lib/pagy/modules/i18n/p11n/west_slavic.rb +22 -0
  55. data/lib/pagy/modules/i18n/p11n.rb +16 -0
  56. data/lib/pagy/modules/searcher.rb +20 -0
  57. data/lib/pagy/next.rb +25 -0
  58. data/lib/pagy/tasks/sync.rb +20 -0
  59. data/lib/pagy/toolbox/helpers/anchor_tags.rb +19 -0
  60. data/lib/pagy/toolbox/helpers/bootstrap/input_nav_js.rb +28 -0
  61. data/lib/pagy/toolbox/helpers/bootstrap/previous_next_html.rb +19 -0
  62. data/lib/pagy/toolbox/helpers/bootstrap/series_nav.rb +32 -0
  63. data/lib/pagy/toolbox/helpers/bootstrap/series_nav_js.rb +24 -0
  64. data/lib/pagy/toolbox/helpers/bulma/input_nav_js.rb +25 -0
  65. data/lib/pagy/toolbox/helpers/bulma/previous_next_html.rb +20 -0
  66. data/lib/pagy/toolbox/helpers/bulma/series_nav.rb +31 -0
  67. data/lib/pagy/toolbox/helpers/bulma/series_nav_js.rb +23 -0
  68. data/lib/pagy/toolbox/helpers/data_hash.rb +29 -0
  69. data/lib/pagy/toolbox/helpers/headers_hash.rb +30 -0
  70. data/lib/pagy/toolbox/helpers/info_tag.rb +30 -0
  71. data/lib/pagy/toolbox/helpers/input_nav_js.rb +22 -0
  72. data/lib/pagy/toolbox/helpers/limit_tag_js.rb +25 -0
  73. data/lib/pagy/toolbox/helpers/loaders.rb +58 -0
  74. data/lib/pagy/toolbox/helpers/page_url.rb +16 -0
  75. data/lib/pagy/toolbox/helpers/series_nav.rb +30 -0
  76. data/lib/pagy/toolbox/helpers/series_nav_js.rb +20 -0
  77. data/lib/pagy/toolbox/helpers/support/a_lambda.rb +36 -0
  78. data/lib/pagy/toolbox/helpers/support/data_pagy_attribute.rb +19 -0
  79. data/lib/pagy/toolbox/helpers/support/nav_aria_label_attribute.rb +10 -0
  80. data/lib/pagy/toolbox/helpers/support/series.rb +37 -0
  81. data/lib/pagy/toolbox/helpers/support/wrap_input_nav_js.rb +18 -0
  82. data/lib/pagy/toolbox/helpers/support/wrap_series_nav.rb +15 -0
  83. data/lib/pagy/toolbox/helpers/support/wrap_series_nav_js.rb +38 -0
  84. data/lib/pagy/toolbox/helpers/urls_hash.rb +12 -0
  85. data/lib/pagy/toolbox/paginators/calendar.rb +34 -0
  86. data/lib/pagy/toolbox/paginators/countish.rb +38 -0
  87. data/lib/pagy/toolbox/paginators/countless.rb +22 -0
  88. data/lib/pagy/toolbox/paginators/elasticsearch_rails.rb +56 -0
  89. data/lib/pagy/toolbox/paginators/keynav_js.rb +26 -0
  90. data/lib/pagy/toolbox/paginators/keyset.rb +15 -0
  91. data/lib/pagy/toolbox/paginators/meilisearch.rb +34 -0
  92. data/lib/pagy/toolbox/paginators/method.rb +38 -0
  93. data/lib/pagy/toolbox/paginators/offset.rb +24 -0
  94. data/lib/pagy/toolbox/paginators/searchkick.rb +34 -0
  95. data/lib/pagy/toolbox/paginators/typesense_rails.rb +34 -0
  96. data/lib/pagy.rb +79 -89
  97. data/locales/ar.yml +9 -6
  98. data/locales/be.yml +9 -6
  99. data/locales/bg.yml +9 -6
  100. data/locales/bs.yml +9 -6
  101. data/locales/ca.yml +9 -6
  102. data/locales/ckb.yml +8 -6
  103. data/locales/cs.yml +9 -6
  104. data/locales/da.yml +9 -6
  105. data/locales/de.yml +9 -6
  106. data/locales/dz.yml +9 -6
  107. data/locales/en.yml +9 -6
  108. data/locales/es.yml +9 -6
  109. data/locales/fr.yml +9 -6
  110. data/locales/hr.yml +9 -6
  111. data/locales/hu.yml +24 -0
  112. data/locales/id.yml +10 -9
  113. data/locales/it.yml +9 -6
  114. data/locales/ja.yml +10 -9
  115. data/locales/km.yml +10 -9
  116. data/locales/ko.yml +9 -6
  117. data/locales/nb.yml +9 -6
  118. data/locales/nl.yml +9 -6
  119. data/locales/nn.yml +9 -6
  120. data/locales/pl.yml +9 -6
  121. data/locales/pt-BR.yml +10 -7
  122. data/locales/pt.yml +10 -7
  123. data/locales/ru.yml +9 -6
  124. data/locales/sk.yml +9 -6
  125. data/locales/sr.yml +9 -6
  126. data/locales/sv-SE.yml +9 -6
  127. data/locales/sv.yml +9 -6
  128. data/locales/sw.yml +12 -9
  129. data/locales/ta.yml +9 -6
  130. data/locales/tr.yml +17 -12
  131. data/locales/uk.yml +9 -6
  132. data/locales/vi.yml +9 -6
  133. data/locales/zh-CN.yml +9 -6
  134. data/locales/zh-HK.yml +9 -6
  135. data/locales/zh-TW.yml +9 -6
  136. data/stylesheets/pagy-tailwind.css +68 -0
  137. data/stylesheets/pagy.css +64 -27
  138. metadata +134 -53
  139. data/javascripts/pagy.min.js.map +0 -10
  140. data/lib/optimist.rb +0 -1022
  141. data/lib/pagy/backend.rb +0 -44
  142. data/lib/pagy/calendar/unit.rb +0 -103
  143. data/lib/pagy/calendar.rb +0 -84
  144. data/lib/pagy/countless.rb +0 -38
  145. data/lib/pagy/exceptions.rb +0 -25
  146. data/lib/pagy/extras/arel.rb +0 -28
  147. data/lib/pagy/extras/array.rb +0 -19
  148. data/lib/pagy/extras/bootstrap.rb +0 -97
  149. data/lib/pagy/extras/bulma.rb +0 -93
  150. data/lib/pagy/extras/calendar.rb +0 -79
  151. data/lib/pagy/extras/countless.rb +0 -32
  152. data/lib/pagy/extras/elasticsearch_rails.rb +0 -71
  153. data/lib/pagy/extras/gearbox.rb +0 -55
  154. data/lib/pagy/extras/headers.rb +0 -54
  155. data/lib/pagy/extras/i18n.rb +0 -26
  156. data/lib/pagy/extras/js_tools.rb +0 -70
  157. data/lib/pagy/extras/jsonapi.rb +0 -88
  158. data/lib/pagy/extras/keyset.rb +0 -30
  159. data/lib/pagy/extras/limit.rb +0 -63
  160. data/lib/pagy/extras/meilisearch.rb +0 -57
  161. data/lib/pagy/extras/metadata.rb +0 -42
  162. data/lib/pagy/extras/overflow.rb +0 -81
  163. data/lib/pagy/extras/pagy.rb +0 -82
  164. data/lib/pagy/extras/searchkick.rb +0 -59
  165. data/lib/pagy/extras/size.rb +0 -40
  166. data/lib/pagy/extras/standalone.rb +0 -60
  167. data/lib/pagy/extras/trim.rb +0 -29
  168. data/lib/pagy/frontend.rb +0 -99
  169. data/lib/pagy/i18n.rb +0 -167
  170. data/lib/pagy/keyset/active_record.rb +0 -44
  171. data/lib/pagy/keyset/sequel.rb +0 -57
  172. data/lib/pagy/keyset.rb +0 -118
  173. data/lib/pagy/shared_methods.rb +0 -26
  174. data/lib/pagy/url_helpers.rb +0 -26
  175. data/stylesheets/pagy.scss +0 -48
  176. data/stylesheets/pagy.tailwind.css +0 -21
data/apps/demo.ru CHANGED
@@ -4,28 +4,30 @@
4
4
  # Showcase all the helpers and styles
5
5
  #
6
6
  # DOC
7
- # https://ddnexus.github.io/pagy/playground/#3-demo-app
7
+ # https://ddnexus.github.io/pagy/playground/#demo-app
8
8
  #
9
9
  # BIN HELP
10
- # bundle exec pagy -h
10
+ # pagy -h
11
11
  #
12
12
  # DEMO USAGE
13
- # bundle exec pagy demo
13
+ # pagy demo
14
14
  #
15
15
  # DEV USAGE
16
- # bundle exec pagy clone demo
17
- # bundle exec pagy ./demo.ru
16
+ # pagy clone demo
17
+ # pagy ./demo.ru
18
18
  #
19
19
  # URL
20
- # http://0.0.0.0:8000
20
+ # http://127.0.0.1:8000
21
21
 
22
- VERSION = '9.4.0'
22
+ VERSION = '43.5.5'
23
+
24
+ if VERSION != Pagy::VERSION
25
+ Warning.warn("\n>>> WARNING! '#{File.basename(__FILE__)}-#{VERSION}' running with 'pagy-#{Pagy::VERSION}'! <<< \n\n")
26
+ end
23
27
 
24
28
  # Bundle
25
29
  require 'bundler/inline'
26
- require 'bundler'
27
- Bundler.configure
28
- gemfile(ENV['PAGY_INSTALL_BUNDLE'] == 'true') do
30
+ gemfile(!Pagy::ROOT.join('pagy.gemspec').exist?) do
29
31
  source 'https://rubygems.org'
30
32
  gem 'oj'
31
33
  gem 'puma'
@@ -34,36 +36,26 @@ gemfile(ENV['PAGY_INSTALL_BUNDLE'] == 'true') do
34
36
  end
35
37
 
36
38
  # pagy initializer
37
- STYLES = { pagy: { extra: 'pagy', prefix: '', css_anchor: 'pagy-scss' },
38
- bootstrap: {},
39
- bulma: {},
40
- tailwind: { extra: 'pagy', prefix: '', css_anchor: 'pagy-tailwind-css' } }.freeze
41
-
42
- STYLES.each_key do |style|
43
- require "pagy/extras/#{STYLES[style][:extra] || style}"
44
- end
45
- require 'pagy/extras/limit'
46
- require 'pagy/extras/trim'
47
- Pagy::DEFAULT[:trim_extra] = false # opt-in trim
39
+ SECTIONS = { pagy: { css_anchor: 'pagy-css' },
40
+ tailwind: { css_anchor: 'pagy-tailwind-css' },
41
+ bootstrap: { style: :bootstrap, classes: 'pagination pagination-sm' },
42
+ bulma: { style: :bulma, classes: 'pagination is-small' },
43
+ template: { css_anchor: 'pagy-css', template: :template } }.freeze
48
44
 
49
45
  # Sinatra setup
50
46
  require 'sinatra/base'
51
47
 
48
+ # Pagy init
49
+ Pagy::OPTIONS[:max_limit] = 100
50
+
52
51
  # Sinatra application
53
52
  class PagyDemo < Sinatra::Base
54
- include Pagy::Backend
53
+ include Pagy::Method
55
54
 
56
55
  get '/' do
57
56
  redirect '/pagy'
58
57
  end
59
58
 
60
- get '/template' do
61
- collection = MockCollection.new
62
- @pagy, @records = pagy(collection, trim_extra: params['trim'])
63
-
64
- erb :template, locals: { pagy: @pagy, style: 'pagy' }
65
- end
66
-
67
59
  get('/javascripts/:file') do
68
60
  format = params[:file].split('.').last
69
61
  if format == 'js'
@@ -71,74 +63,142 @@ class PagyDemo < Sinatra::Base
71
63
  elsif format == 'map'
72
64
  content_type 'application/json'
73
65
  end
74
- send_file Pagy.root.join('javascripts', params[:file])
66
+ send_file Pagy::ROOT.join('javascripts', params[:file])
75
67
  end
76
68
 
77
69
  get('/stylesheets/:file') do
78
70
  content_type 'text/css'
79
- send_file Pagy.root.join('stylesheets', params[:file])
71
+ send_file Pagy::ROOT.join('stylesheets', params[:file])
80
72
  end
81
73
 
82
- # One route/action per style
83
- STYLES.each_key do |style|
84
- prefix = STYLES[style][:prefix] || "_#{style}"
85
-
86
- get("/#{style}/?:trim?") do
87
- collection = MockCollection.new
88
- @pagy, @records = pagy(collection, trim_extra: params['trim'])
74
+ if ENV['E2E_TEST']
75
+ get('/assets/:file') do
76
+ content_type 'text/css'
77
+ send_file Pagy::ROOT.join('../test/e2e/assets', params[:file])
78
+ end
79
+ end
89
80
 
90
- erb :helpers, locals: { style:, prefix: }
81
+ # One route/action per style
82
+ SECTIONS.each do |section, value|
83
+ get("/#{section}") do
84
+ collection = MockCollection.new
85
+ @pagy, @records = pagy(:offset, collection)
86
+ erb value[:template] || :page,
87
+ locals: { section:,
88
+ pagy: @pagy,
89
+ style: value[:style],
90
+ classes: value[:classes],
91
+ css_anchor: value[:css_anchor] }
91
92
  end
92
93
  end
93
94
 
94
- helpers do
95
- include Pagy::Frontend
95
+ PAGY_LIKE_HEAD =
96
+ %(#{Pagy.dev_tools unless ENV['E2E_TEST']}
97
+ <style>
98
+ /* black/white backdrop color based on --B */
99
+ .pagy { background-color: hsl(0 0 calc(100 * var(--B))) !important; }
100
+ </style>).freeze
96
101
 
102
+ helpers do
97
103
  def style_menu
98
104
  html = +%(<div id="style-menu"> )
99
- STYLES.each_key { |style| html << %(<a href="/#{style}">#{style}</a>) }
100
- html << %(<a href="/template">template</a>)
105
+ SECTIONS.each_key do |section|
106
+ name = section.to_s
107
+ name[0] = name[0].capitalize
108
+ html << %(<a href="/#{section}">#{name}</a>)
109
+ end
101
110
  html << %(</div>)
111
+ html
112
+ end
113
+
114
+ def head_for(section)
115
+ case section
116
+ when :pagy, :template
117
+ %(#{PAGY_LIKE_HEAD}
118
+ <link rel="stylesheet" href="/stylesheets/pagy.css">)
119
+ when :tailwind
120
+ %(#{PAGY_LIKE_HEAD}
121
+ #{if ENV['E2E_TEST']
122
+ '<script src="/assets/tailwind.js"></script>'
123
+ else
124
+ '<script src="https://cdn.tailwindcss.com?plugins=forms,typography,aspect-ratio"></script>'
125
+ end}
126
+ <style type="text/tailwindcss">
127
+ #{Pagy::ROOT.join('stylesheets/pagy-tailwind.css').read}
128
+ </style>)
129
+ when :bootstrap
130
+ if ENV['E2E_TEST']
131
+ '<link rel="stylesheet" href="/assets/bootstrap.min.css">'
132
+ else
133
+ '<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5/dist/css/bootstrap.min.css">'
134
+ end
135
+ when :bulma
136
+ if ENV['E2E_TEST']
137
+ '<link rel="stylesheet" href="/assets/bulma.min.css">'
138
+ else
139
+ '<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@1/css/bulma.min.css">'
140
+ end
141
+ end
102
142
  end
103
143
 
104
144
  def highlight(html, format: :html)
105
145
  if format == :html
106
- html = html.gsub(/>[\s]*</, '><').strip # template single line no spaces around/between tags
146
+ html = html.gsub(/>\s*</, '><').strip # template single line no spaces around/between tags
107
147
  html = Formatter.new.format(html)
108
148
  end
109
149
  lexer = Rouge::Lexers::ERB.new
110
150
  formatter = Rouge::Formatters::HTMLInline.new('monokai.sublime')
111
151
  summary = { html: 'Served HTML (pretty formatted)', erb: 'ERB Template' }
112
152
  %(<details><summary>#{summary[format]}</summary><pre>\n#{
113
- formatter.format(lexer.lex(html))
153
+ formatter.format(lexer.lex(html))
114
154
  }</pre></details>)
115
155
  end
116
156
  end
117
157
 
118
158
  # Views
119
159
  template :layout do
120
- <<~'ERB'
160
+ <<~HTML
121
161
  <!DOCTYPE html>
122
- <html lang="en">
162
+ <html lang="en" data-theme="light">
123
163
  <head>
124
164
  <title>Pagy Demo App</title>
125
- <script src="/javascripts/pagy.min.js"></script>
126
- <script>
127
- window.addEventListener("load", Pagy.init);
128
- </script>
129
165
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
130
- <%= erb :"#{style}_head" if defined?(style) %>
131
- <style type="text/css">
166
+ <%= head_for(section) %>
167
+ <script src="/javascripts/pagy.js"></script>
168
+ <script>window.addEventListener("load", Pagy.init);</script>
169
+ <% unless ENV['E2E_TEST'] %>
170
+ <link rel="preconnect" href="https://fonts.googleapis.com">
171
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
172
+ <link href="https://fonts.googleapis.com/css2?family=Nunito+Sans:ital,opsz,wght@0,6..12,200..1000;1,6..12,200..1000&display=swap" rel="stylesheet">
173
+ <% end %>
174
+ <style>
132
175
  @media screen { html, body {
133
176
  font-size: 1rem;
134
- line-height: 1.2s;
177
+ line-height: 1.2;
135
178
  padding: 0;
136
179
  margin: 0;
137
180
  } }
181
+ *,
182
+ *::before,
183
+ *::after {
184
+ box-sizing: border-box;
185
+ }
186
+ html {
187
+ background-color: transparent !important; /* Fix for Bulma */
188
+ }
138
189
  body {
139
- background: white !important;
140
190
  margin: 0 !important;
141
- font-family: sans-serif !important;
191
+ font-family: <%= '"Nunito Sans", ' unless ENV['E2E_TEST'] %>"Helvetica Neue", Helvetica, Arial, sans-serif !important;
192
+ color: #303030 !important;
193
+ background-color: #f5f5f5 !important;
194
+ }
195
+ svg {
196
+ position: fixed;
197
+ top: 0;
198
+ left: 0;
199
+ width: 100vw;
200
+ height: 100vh;
201
+ z-index: -10;
142
202
  }
143
203
  h1, h2 {
144
204
  font-size: 1.8rem !important;
@@ -146,16 +206,22 @@ class PagyDemo < Sinatra::Base
146
206
  margin-top: 1rem !important;
147
207
  margin-bottom: 0.7rem !important;
148
208
  line-height: 1.5 !important;
149
- color: rgb(90 90 90) !important;
209
+ color: #303030 !important;
150
210
  }
151
211
  h2 {
152
212
  font-family: monospace;
153
213
  font-size: .9rem !important;
154
214
  margin-top: 1.6rem !important;
155
215
  }
216
+ hr {
217
+ height: 0;
218
+ color: inherit;
219
+ border-top-width: 1px;
220
+ border-top-color: gray;
221
+ margin: 8px 0 !important;
222
+ }
156
223
  summary, .notes {
157
224
  font-size: .8rem;
158
- color: gray;
159
225
  margin-top: .6rem;
160
226
  font-style: italic;
161
227
  cursor: pointer;
@@ -165,7 +231,7 @@ class PagyDemo < Sinatra::Base
165
231
  font-weight: normal;
166
232
  }
167
233
  .notes code{
168
- background-color: #E8E8E8;
234
+ background-color: rgba(255, 255, 255, .6);
169
235
  padding: 0 0.3rem;
170
236
  font-style: normal;
171
237
  border-radius: 3px;
@@ -178,7 +244,7 @@ class PagyDemo < Sinatra::Base
178
244
  text-decoration: underline;
179
245
  }
180
246
  pre, pre code {
181
- display: block;
247
+ display: inline-block;
182
248
  margin-top: .3rem;
183
249
  margin-bottom: 1rem;
184
250
  font-size: .8rem !important;
@@ -186,12 +252,13 @@ class PagyDemo < Sinatra::Base
186
252
  color: white;
187
253
  background-color: rgb(30 30 30);
188
254
  padding: 1rem;
189
- overflow: auto;
255
+ overflow-x: auto;
256
+ max-width: 100%;
257
+ white-space: pre;
190
258
  }
191
- .content {
259
+ .main-content {
192
260
  padding: 0 1.5rem 2rem !important;
193
261
  }
194
-
195
262
  #style-menu {
196
263
  flex;
197
264
  font-family: sans-serif;
@@ -199,7 +266,7 @@ class PagyDemo < Sinatra::Base
199
266
  line-height: 1.5rem;
200
267
  white-space: nowrap;
201
268
  color: white;
202
- background-color: gray;
269
+ background-color: rgba(0,0,0,.65);
203
270
  padding: .2rem 1.5rem;
204
271
  }
205
272
  #style-menu > :not([hidden]) ~ :not([hidden]) {
@@ -211,158 +278,155 @@ class PagyDemo < Sinatra::Base
211
278
  color: inherit;
212
279
  text-decoration: none;
213
280
  }
214
- /* Quick demo for overriding the element style attribute of certain pagy helpers
215
- .pagy input[style] {
216
- width: 5rem !important;
281
+ .pagy, .pagy-bootstrap, .pagy-bulma {
282
+ background-color: white;
283
+ padding: 1.5em;
284
+ margin: .3em 0;
285
+ width: fit-content;
286
+ box-shadow: 8px 8px 18px 0px rgba(0,0,0,0.25);
287
+ }
288
+ span.pagy {
289
+ display: block;
290
+ }
291
+ .pagy-bootstrap .pagination {
292
+ margin: 0;
293
+ }
294
+ /* Demo app custom style */
295
+ .pagy {
296
+ --B: 1;
297
+ --H: 109;
298
+ --S: 40;
299
+ --L: 70;
300
+ --spacing: 0.125rem;
301
+ --padding: 0.75rem;
302
+ --rounding: 0.8125rem;
303
+ --border-width: 0.03125rem;
304
+ --font-size: 0.875rem;
305
+ --font-weight: 450;
306
+ --line-height: 1.75;
217
307
  }
218
- */
219
308
  </style>
220
309
  </head>
221
310
  <body>
311
+ <svg xmlns="http://www.w3.org/2000/svg" width="0" height="0">
312
+ <filter id="noiseFilter">
313
+ <feTurbulence type="fractalNoise" baseFrequency="0.6" numOctaves="100" stitchTiles="stitch" />
314
+ <feColorMatrix type="matrix" values="0.5 0 0 0 0, 0.5 0 0 0 0, 0.5 0 0 0 0, 0 0 0 0.5 0" />
315
+ </filter>
316
+ <rect width="100%" height="100%" filter="url(#noiseFilter)" fill="rgb(255, 255, 255)" />
317
+ </svg>
222
318
  <!-- each different class used by each style -->
223
319
  <%= style_menu %>
224
- <div class="content">
320
+ <div class="main-content">
225
321
  <%= yield %>
226
322
  </div>
227
323
  </body>
228
324
  </html>
229
- ERB
325
+ HTML
230
326
  end
231
327
 
232
- template :pagy_head do
328
+ template :page do
233
329
  <<~ERB
234
- <!-- copy and paste the pagy style in order to edit it -->
235
- <link rel="stylesheet" href="/stylesheets/pagy.css">
236
- ERB
237
- end
330
+ <h1><%= title = section.to_s; title[0] = title[0].capitalize; title %></h1>
238
331
 
239
- template :bootstrap_head do
240
- <<~ERB
241
- <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css">
242
- ERB
243
- end
244
-
245
- template :bulma_head do
246
- <<~ERB
247
- <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@0.9.4/css/bulma.min.css">
248
- ERB
249
- end
250
-
251
- template :tailwind_head do
252
- <<~ERB
253
- <script src="https://cdn.tailwindcss.com?plugins=forms,typography,aspect-ratio"></script>
254
- <!-- copy and paste the pagy.tailwind style in order to edit it -->
255
- <style type="text/tailwindcss">
256
- <%= Pagy.root.join('stylesheets', 'pagy.tailwind.css').read %>
257
- </style>
258
- ERB
259
- end
260
-
261
- template :helpers do
262
- <<~'ERB'
263
- <h1><%= style %></h1>
264
- <% extra = STYLES[style][:extra] || "#{style}" %>
265
- <% css_anchor = STYLES[style][:css_anchor] %>
266
-
267
- <p class="description">See the <a href="http://ddnexus.github.io/pagy/docs/extras/<%= extra %>" target="blank"><%= extra %> extra</a>
268
- documentation
269
332
  <% if css_anchor %>
270
- and the <a href="http://ddnexus.github.io/pagy/docs/api/stylesheets/#<%= css_anchor %>" target="blank"><%= css_anchor.gsub('-', '.') %></a>
271
- <% end %>
272
- for details</p>
273
-
274
- <h2>Collection</h2>
275
- <p id="records">@records: <%= @records.join(',') %></p>
276
-
277
- <h2>pagy<%= prefix %>_nav <span class="notes">Simple nav <code>size: 5</code></span></h2>
278
- <%= html = send(:"pagy#{prefix}_nav", @pagy, id: 'simple-nav', aria_label: 'Pages simple-nav', size: 5) %>
279
- <%= highlight(html) %>
280
-
281
- <h2>pagy<%= prefix %>_nav <span class="notes">Fast nav <code>size: 7</code></span></h2>
282
- <%= html = send(:"pagy#{prefix}_nav", @pagy, id: 'nav', aria_label: 'Pages nav') %>
283
- <%= highlight(html) %>
284
-
285
- <h2>pagy<%= prefix %>_nav_js <span class="notes">Fast nav <code>size: 7</code></span></h2>
286
- <%= html = send(:"pagy#{prefix}_nav_js", @pagy, id: 'nav-js', aria_label: 'Pages nav_js') %>
287
- <%= highlight(html) %>
288
-
289
- <h2>pagy<%= prefix %>_nav_js <span class="notes">Responsive nav <code>steps: {...}</code> (Resize the window to see)</span></h2>
290
- <%= html = send(:"pagy#{prefix}_nav_js", @pagy, id: 'nav-js-responsive',
291
- aria_label: 'Pages nav_js_responsive',
292
- steps: { 0 => 5, 500 => 7, 750 => 9, 1000 => 11 }) %>
293
- <%= highlight(html) %>
294
-
295
- <h2>pagy<%= prefix %>_combo_nav_js</h2>
296
- <%= html = send(:"pagy#{prefix}_combo_nav_js", @pagy, id: 'combo-nav-js', aria_label: 'Pages combo_nav_js') %>
297
- <%= highlight(html) %>
298
-
299
- <h2>pagy_info</h2>
300
- <%= html = pagy_info(@pagy, id: 'pagy-info') %>
301
- <%= highlight(html) %>
302
-
303
- <% if style.match(/pagy|tailwind/) %>
304
- <h2>pagy_limit_selector_js</h2>
305
- <%= html = pagy_limit_selector_js(@pagy, id: 'limit-selector-js') %>
306
- <%= highlight(html) %>
307
-
308
- <h2>pagy_prev_a / pagy_next_a</h2>
309
- <%= html = '<nav class="pagy" id="prev-next" aria-label="Pagy prev-next">' << pagy_prev_a(@pagy) << pagy_next_a(@pagy) << '</nav>' %>
310
- <%= highlight(html) %>
311
-
312
- <h2>pagy_prev_link / pagy_next_link <span class="notes">Link not rendered<span></h2>
313
- <% html = '<head>' << (pagy_prev_link(@pagy)||'') << (pagy_next_link(@pagy)||'') << '</head>' %>
314
- <%= highlight(html) %>
333
+ <p>Check the <u><i><b><a href="http://ddnexus.github.io/pagy/resources/stylesheets/#<%= css_anchor %>" target="blank"><%= css_anchor.gsub('-', '.') %></a></b></u></i>
334
+ for details.</p>
315
335
  <% end %>
336
+ </p>
337
+ <div id="main-container">
338
+ <div id="content">
339
+ <hr id="top-hr">
340
+ <h2>@records</h2>
341
+ <p id="records"><%= @records.join(',') %></p>
342
+
343
+ <h2>@pagy.series_nav<br/>
344
+ <span class="notes">Series nav <code>{slots: 7}</code></span>
345
+ </h2>
346
+ <%= html = @pagy.series_nav(style, classes:,
347
+ id: 'series-nav',
348
+ aria_label: 'Pages series_nav') %>
349
+ <%= highlight(html) %>
350
+
351
+ <h2>@pagy.series_nav_js<br/>
352
+ <span class="notes">Responsive nav: <code>{steps: {0 => 5, 500 => 7, 600 => 9, 700 => 11}}</code><br/>
353
+ (Resize the window to see)
354
+ </span>
355
+ </h2>
356
+ <%= html = @pagy.series_nav_js(style, classes:,
357
+ id: 'series-nav-js-responsive',
358
+ aria_label: 'Pages series_nav_js_responsive',
359
+ steps: { 0 => 5, 500 => 7, 600 => 9, 700 => 11 }) %>
360
+ <%= highlight(html) %>
361
+
362
+ <h2>@pagy.input_nav_js</h2>
363
+ <%= html = @pagy.input_nav_js(style, classes:,
364
+ id: 'input-nav-js',
365
+ aria_label: 'Pages inpup_nav_js') %>
366
+ <%= highlight(html) %>
367
+
368
+ <h2>@pagy.limit_tag_js</h2>
369
+ <%= html = @pagy.limit_tag_js(id: 'limit-tag-js') %>
370
+ <%= highlight(html) %>
371
+
372
+ <h2>@pagy.info_tag</h2>
373
+ <%= html = @pagy.info_tag(id: 'pagy-info') %>
374
+ <%= highlight(html) %>
375
+ </div>
376
+ </div>
316
377
  ERB
317
378
  end
318
379
 
319
380
  template :template do
320
- <<~ERB
321
- <h1>Pagy Template Demo</h1>
381
+ <<~ERB
382
+ <h1>Pagy Template Demo</h1>
322
383
 
323
- <p class="description">
324
- See the <a href="https://ddnexus.github.io/pagy/docs/how-to/#using-your-pagination-templates">
325
- Custom Templates</a> documentation.
326
- </p>
327
- <h2>Collection</h2>
328
- <p id="records">@records: <%= @records.join(',') %></p>
384
+ <p class="description">
385
+ See the <a href="https://ddnexus.github.io/pagy/docs/how-to/#using-your-pagination-templates">
386
+ Custom Templates</a> documentation.
387
+ </p>
329
388
 
330
- <h2>Rendered ERB template</h2>
389
+ <h2>Collection</h2>
390
+ <p id="records">@records: <%= @records.join(',') %></p>
331
391
 
332
- <%# We don't inline the template here, so we can highlight it more easily %>
333
- <%= html = ERB.new(TEMPLATE).result(binding) %>
334
- <%= highlight(TEMPLATE, format: :erb) %>
335
- <%= highlight(html) %>
336
- ERB
337
- end
392
+ <h2>Rendered ERB template</h2>
393
+
394
+ <div class="backdrop">
395
+ <%# We don't inline the template here, so we can highlight it more easily %>
396
+ <%= html = ERB.new(TEMPLATE).result(binding) %>
397
+ </div>
398
+ <%= highlight(TEMPLATE, format: :erb) %>
399
+ <%= highlight(html) %>
400
+ ERB
401
+ end
338
402
 
339
403
  # Easier code highlighting
340
404
  TEMPLATE = <<~ERB
341
405
  <%# IMPORTANT: replace '<%=' with '<%==' if you run this in rails %>
342
406
 
343
407
  <%# The a variable below is set to a lambda that generates the a tag %>
344
- <%# Usage: a_tag = a.(page_number, text, classes: nil, aria_label: nil) %>
345
- <% a = pagy_anchor(pagy) %>
346
- <nav class="pagy nav" aria-label="Pages">
408
+ <%# Usage: anchor_tag = a_lambda.(page_number, text, classes: nil, aria_label: nil) %>
409
+ <% a_lambda = @pagy.send(:a_lambda) %>
410
+ <nav class="pagy series-nav" aria-label="Pages">
347
411
  <%# Previous page link %>
348
- <% if pagy.prev %>
349
- <%= a.(pagy.prev, '&lt;', aria_label: 'Previous') %>
412
+ <% if pagy.previous %>
413
+ <%= a_lambda.(pagy.previous, '&lt;', aria_label: 'Previous') %>
350
414
  <% else %>
351
415
  <a role="link" aria-disabled="true" aria-label="Previous">&lt;</a>
352
416
  <% end %>
353
417
  <%# Page links (series example: [1, :gap, 7, 8, "9", 10, 11, :gap, 36]) %>
354
- <% pagy.series.each do |item| %>
418
+ <% pagy.send(:series).each do |item| %>
355
419
  <% if item.is_a?(Integer) %>
356
- <%= a.(item) %>
420
+ <%= a_lambda.(item) %>
357
421
  <% elsif item.is_a?(String) %>
358
- <a role="link" aria-disabled="true" aria-current="page" class="current"><%= item %></a>
422
+ <a role="link" aria-disabled="true" aria-current="page"><%= item %></a>
359
423
  <% elsif item == :gap %>
360
- <a role="link" aria-disabled="true" class="gap">&hellip;</a>
424
+ <a role="separator" aria-disabled="true">&hellip;</a>
361
425
  <% end %>
362
426
  <% end %>
363
427
  <%# Next page link %>
364
428
  <% if pagy.next %>
365
- <%= a.(pagy.next, '&gt;', aria_label: 'Next') %>
429
+ <%= a_lambda.(pagy.next, '&gt;', aria_label: 'Next') %>
366
430
  <% else %>
367
431
  <a role="link" aria-disabled="true" aria-label="Next">&lt;</a>
368
432
  <% end %>
@@ -402,15 +466,15 @@ class Formatter
402
466
  push.(tag)
403
467
  elsif (match = input.match(PAIRED))
404
468
  tag_start, name, block, tag_end, rest = match.captures
405
- ## Handle incomplete same-tag nesting
469
+ # Handle incomplete same-tag nesting
406
470
  while block.scan(/<#{name}.*?>/).size > block.scan(tag_end).size
407
471
  more, rest = rest.split(tag_end, 2)
408
- block << tag_end << more
472
+ block << (tag_end + more)
409
473
  end
410
474
  if (match = tag_start.match(DATA_PAGY))
411
475
  search, data = match.captures
412
- formatted = data.scan(/.{1,76}/).join("\n")
413
- replace = %(\n#{INDENT * (level + 1)}data-pagy="#{formatted}")
476
+ formatted = data.scan(/.{1,76}/).join("\n")
477
+ replace = %(\n#{INDENT * (level + 1)}data-pagy="#{formatted}")
414
478
  tag_start.sub!(search, replace)
415
479
  end
416
480
  if block.match(WRAPPER)
@@ -418,7 +482,7 @@ class Formatter
418
482
  process(block, level + 1)
419
483
  push.(tag_end)
420
484
  else
421
- push.(tag_start << block << tag_end)
485
+ push.(tag_start << (block + tag_end))
422
486
  end
423
487
  end
424
488
  process(rest, level) if rest
@@ -433,12 +497,12 @@ class MockCollection < Array
433
497
  end
434
498
 
435
499
  def offset(value)
436
- @collection = self[value..]
500
+ @collection = self[value..] || []
437
501
  self
438
502
  end
439
503
 
440
504
  def limit(value)
441
- @collection[0, value]
505
+ @collection.empty? ? [] : @collection[0, value]
442
506
  end
443
507
 
444
508
  def count(*)