pagy 5.7.5 → 8.6.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (153) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +1 -1
  3. data/apps/calendar.ru +745 -0
  4. data/apps/demo.ru +435 -0
  5. data/apps/rails.ru +213 -0
  6. data/apps/repro.ru +177 -0
  7. data/apps/tmp/calendar.sqlite3 +0 -0
  8. data/apps/tmp/calendar.sqlite3-shm +0 -0
  9. data/apps/tmp/calendar.sqlite3-wal +0 -0
  10. data/apps/tmp/local_secret.txt +1 -0
  11. data/bin/pagy +100 -0
  12. data/{lib/config → config}/pagy.rb +72 -96
  13. data/javascripts/pagy-module.js +100 -0
  14. data/javascripts/pagy.d.ts +5 -0
  15. data/javascripts/pagy.js +4 -0
  16. data/javascripts/pagy.min.js +4 -0
  17. data/javascripts/pagy.min.js.map +10 -0
  18. data/javascripts/pagy.mjs +100 -0
  19. data/lib/optimist.rb +1022 -0
  20. data/lib/pagy/backend.rb +16 -4
  21. data/lib/pagy/calendar/day.rb +22 -10
  22. data/lib/pagy/calendar/month.rb +35 -9
  23. data/lib/pagy/calendar/quarter.rb +36 -10
  24. data/lib/pagy/calendar/unit.rb +106 -0
  25. data/lib/pagy/calendar/week.rb +16 -16
  26. data/lib/pagy/calendar/year.rb +15 -9
  27. data/lib/pagy/calendar.rb +60 -68
  28. data/lib/pagy/console.rb +3 -3
  29. data/lib/pagy/countless.rb +17 -12
  30. data/lib/pagy/exceptions.rb +1 -1
  31. data/lib/pagy/extras/arel.rb +2 -2
  32. data/lib/pagy/extras/array.rb +2 -2
  33. data/lib/pagy/extras/bootstrap.rb +57 -53
  34. data/lib/pagy/extras/bulma.rb +53 -57
  35. data/lib/pagy/extras/calendar.rb +54 -37
  36. data/lib/pagy/extras/countless.rb +3 -3
  37. data/lib/pagy/extras/elasticsearch_rails.rb +12 -11
  38. data/lib/pagy/extras/foundation.rb +59 -54
  39. data/lib/pagy/extras/gearbox.rb +32 -19
  40. data/lib/pagy/extras/headers.rb +11 -11
  41. data/lib/pagy/extras/i18n.rb +5 -5
  42. data/lib/pagy/extras/items.rb +34 -24
  43. data/lib/pagy/extras/{frontend_helpers.rb → js_tools.rb} +24 -24
  44. data/lib/pagy/extras/jsonapi.rb +79 -0
  45. data/lib/pagy/extras/materialize.rb +63 -47
  46. data/lib/pagy/extras/meilisearch.rb +26 -22
  47. data/lib/pagy/extras/metadata.rb +13 -9
  48. data/lib/pagy/extras/overflow.rb +13 -10
  49. data/lib/pagy/extras/pagy.rb +82 -0
  50. data/lib/pagy/extras/searchkick.rb +12 -11
  51. data/lib/pagy/extras/semantic.rb +57 -45
  52. data/lib/pagy/extras/size.rb +40 -0
  53. data/lib/pagy/extras/standalone.rb +12 -16
  54. data/lib/pagy/extras/trim.rb +13 -13
  55. data/lib/pagy/extras/uikit.rb +60 -46
  56. data/lib/pagy/frontend.rb +62 -45
  57. data/lib/pagy/i18n.rb +4 -3
  58. data/lib/pagy/url_helpers.rb +13 -25
  59. data/lib/pagy.rb +61 -59
  60. data/locales/ar.yml +28 -0
  61. data/locales/be.yml +25 -0
  62. data/locales/bg.yml +21 -0
  63. data/locales/bs.yml +25 -0
  64. data/locales/ca.yml +21 -0
  65. data/locales/ckb.yml +18 -0
  66. data/locales/cs.yml +23 -0
  67. data/locales/da.yml +21 -0
  68. data/locales/de.yml +21 -0
  69. data/locales/en.yml +21 -0
  70. data/locales/es.yml +21 -0
  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/locales/pt-BR.yml +21 -0
  83. data/locales/pt.yml +21 -0
  84. data/locales/ru.yml +25 -0
  85. data/locales/sr.yml +25 -0
  86. data/locales/sv-SE.yml +21 -0
  87. data/locales/sv.yml +21 -0
  88. data/locales/sw.yml +23 -0
  89. data/locales/ta.yml +23 -0
  90. data/locales/tr.yml +19 -0
  91. data/locales/uk.yml +25 -0
  92. data/locales/vi.yml +17 -0
  93. data/locales/zh-CN.yml +19 -0
  94. data/locales/zh-HK.yml +19 -0
  95. data/locales/zh-TW.yml +19 -0
  96. data/stylesheets/pagy.css +46 -0
  97. data/stylesheets/pagy.scss +48 -0
  98. data/stylesheets/pagy.tailwind.css +21 -0
  99. metadata +79 -66
  100. data/lib/javascripts/pagy-dev.js +0 -118
  101. data/lib/javascripts/pagy-module.d.ts +0 -30
  102. data/lib/javascripts/pagy-module.js +0 -117
  103. data/lib/javascripts/pagy.js +0 -1
  104. data/lib/locales/ar.yml +0 -26
  105. data/lib/locales/bg.yml +0 -22
  106. data/lib/locales/bs.yml +0 -24
  107. data/lib/locales/ca.yml +0 -22
  108. data/lib/locales/cs.yml +0 -22
  109. data/lib/locales/da.yml +0 -22
  110. data/lib/locales/de.yml +0 -22
  111. data/lib/locales/en.yml +0 -22
  112. data/lib/locales/es.yml +0 -22
  113. data/lib/locales/fr.yml +0 -22
  114. data/lib/locales/hr.yml +0 -24
  115. data/lib/locales/id.yml +0 -20
  116. data/lib/locales/it.yml +0 -22
  117. data/lib/locales/ja.yml +0 -20
  118. data/lib/locales/km.yml +0 -19
  119. data/lib/locales/ko.yml +0 -20
  120. data/lib/locales/nb.yml +0 -22
  121. data/lib/locales/nl.yml +0 -22
  122. data/lib/locales/pl.yml +0 -24
  123. data/lib/locales/pt-BR.yml +0 -22
  124. data/lib/locales/pt.yml +0 -22
  125. data/lib/locales/ru.yml +0 -24
  126. data/lib/locales/sr.yml +0 -23
  127. data/lib/locales/sv-SE.yml +0 -23
  128. data/lib/locales/sv.yml +0 -23
  129. data/lib/locales/sw.yml +0 -22
  130. data/lib/locales/ta.yml +0 -22
  131. data/lib/locales/tr.yml +0 -20
  132. data/lib/locales/uk.yml +0 -24
  133. data/lib/locales/zh-CN.yml +0 -20
  134. data/lib/locales/zh-HK.yml +0 -20
  135. data/lib/locales/zh-TW.yml +0 -20
  136. data/lib/pagy/calendar/month_mixin.rb +0 -49
  137. data/lib/pagy/extras/navs.rb +0 -63
  138. data/lib/pagy/extras/support.rb +0 -54
  139. data/lib/templates/bootstrap_nav.html.erb +0 -24
  140. data/lib/templates/bootstrap_nav.html.haml +0 -34
  141. data/lib/templates/bootstrap_nav.html.slim +0 -34
  142. data/lib/templates/bulma_nav.html.erb +0 -24
  143. data/lib/templates/bulma_nav.html.haml +0 -32
  144. data/lib/templates/bulma_nav.html.slim +0 -32
  145. data/lib/templates/foundation_nav.html.erb +0 -24
  146. data/lib/templates/foundation_nav.html.haml +0 -34
  147. data/lib/templates/foundation_nav.html.slim +0 -34
  148. data/lib/templates/nav.html.erb +0 -22
  149. data/lib/templates/nav.html.haml +0 -30
  150. data/lib/templates/nav.html.slim +0 -29
  151. data/lib/templates/uikit_nav.html.erb +0 -15
  152. data/lib/templates/uikit_nav.html.haml +0 -28
  153. data/lib/templates/uikit_nav.html.slim +0 -28
data/apps/demo.ru ADDED
@@ -0,0 +1,435 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Interactive showcase for all the pagy helpers and CSS styles
4
+
5
+ # DEMO USAGE
6
+ # pagy demo
7
+
8
+ # DEV USAGE
9
+ # pagy clone demo
10
+ # pagy ./demo.ru
11
+
12
+ # URL
13
+ # http://0.0.0.0:8000
14
+
15
+ # HELP
16
+ # pagy -h
17
+
18
+ # DOC
19
+ # https://ddnexus.github.io/pagy/playground/#3-demo-app
20
+
21
+ VERSION = '8.6.2'
22
+
23
+ require 'bundler/inline'
24
+ require 'bundler'
25
+ Bundler.configure
26
+ gemfile(ENV['PAGY_INSTALL_BUNDLE'] == 'true') do
27
+ source 'https://rubygems.org'
28
+ gem 'oj'
29
+ gem 'puma'
30
+ gem 'rouge'
31
+ gem 'sinatra'
32
+ gem 'sinatra-contrib'
33
+ end
34
+
35
+ # pagy initializer
36
+ STYLES = { pagy: { extra: 'pagy', prefix: '', css_anchor: 'pagy-scss' },
37
+ bootstrap: {},
38
+ bulma: {},
39
+ tailwind: { extra: 'pagy', prefix: '', css_anchor: 'pagy-tailwind-css' } }.freeze
40
+
41
+ STYLES.each_key do |style|
42
+ require "pagy/extras/#{STYLES[style][:extra] || style}"
43
+ end
44
+ require 'pagy/extras/items'
45
+ require 'pagy/extras/trim'
46
+ Pagy::DEFAULT[:trim_extra] = false # opt-in trim
47
+
48
+ # sinatra setup
49
+ require 'sinatra/base'
50
+
51
+ # sinatra application
52
+ class PagyDemo < Sinatra::Base
53
+ configure do
54
+ enable :inline_templates
55
+ end
56
+
57
+ include Pagy::Backend
58
+
59
+ get '/' do
60
+ redirect '/pagy'
61
+ end
62
+
63
+ get '/template' do
64
+ collection = MockCollection.new
65
+ @pagy, @records = pagy(collection, trim_extra: params['trim'])
66
+
67
+ erb :template, locals: { pagy: @pagy, style: 'pagy' }
68
+ end
69
+
70
+ get('/javascripts/:file') do
71
+ format = params[:file].split('.').last
72
+ if format == 'js'
73
+ content_type 'application/javascript'
74
+ elsif format == 'map'
75
+ content_type 'application/json'
76
+ end
77
+ send_file Pagy.root.join('javascripts', params[:file])
78
+ end
79
+
80
+ get('/stylesheets/:file') do
81
+ content_type 'text/css'
82
+ send_file Pagy.root.join('stylesheets', params[:file])
83
+ end
84
+
85
+ # one route/action per style
86
+ STYLES.each_key do |style|
87
+ prefix = STYLES[style][:prefix] || "_#{style}"
88
+
89
+ get("/#{style}/?:trim?") do
90
+ collection = MockCollection.new
91
+ @pagy, @records = pagy(collection, trim_extra: params['trim'])
92
+
93
+ erb :helpers, locals: { style:, prefix: }
94
+ end
95
+ end
96
+
97
+ helpers do
98
+ include Pagy::Frontend
99
+
100
+ def style_menu
101
+ html = +%(<div id="style-menu"> )
102
+ STYLES.each_key { |style| html << %(<a href="/#{style}">#{style}</a>) }
103
+ html << %(<a href="/template">template</a>)
104
+ html << %(</div>)
105
+ end
106
+
107
+ def highlight(html, format: :html)
108
+ if format == :html
109
+ html = html.gsub(/>[\s]*</, '><').strip # template single line no spaces around/between tags
110
+ html = Formatter.new.format(html)
111
+ end
112
+ lexer = Rouge::Lexers::ERB.new
113
+ formatter = Rouge::Formatters::HTMLInline.new('monokai.sublime')
114
+ summary = { html: 'Served HTML (pretty formatted)', erb: 'ERB Template' }
115
+ %(<details><summary>#{summary[format]}</summary><pre>\n#{
116
+ formatter.format(lexer.lex(html))
117
+ }</pre></details>)
118
+ end
119
+ end
120
+ end
121
+
122
+ # Cheap pagy formatter for helpers output
123
+ class Formatter
124
+ INDENT = ' '
125
+ TEXT_SPACE = "\u00B7"
126
+ TEXT = /^([^<>]+)(.*)/
127
+ UNPAIRED = /^(<(input|link).*?>)(.*)/
128
+ PAIRED = %r{^(<(head|nav|div|span|p|a|b|label|ul|li).*?>)(.*?)(</\2>)(.*)}
129
+ WRAPPER = /<.*?>/
130
+ DATA_PAGY = /(data-pagy="([^"]+)")/
131
+
132
+ def initialize
133
+ @formatted = +''
134
+ end
135
+
136
+ def format(input, level = 0)
137
+ process(input, level)
138
+ @formatted
139
+ end
140
+
141
+ private
142
+
143
+ def process(input, level)
144
+ push = ->(content) { @formatted << ((INDENT * level) << content << "\n") }
145
+ rest = nil
146
+ if (match = input.match(TEXT))
147
+ text, rest = match.captures
148
+ push.(text.gsub(' ', TEXT_SPACE))
149
+ elsif (match = input.match(UNPAIRED))
150
+ tag, _name, rest = match.captures
151
+ push.(tag)
152
+ elsif (match = input.match(PAIRED))
153
+ tag_start, name, block, tag_end, rest = match.captures
154
+ ## Handle incomplete same-tag nesting
155
+ while block.scan(/<#{name}.*?>/).size > block.scan(tag_end).size
156
+ more, rest = rest.split(tag_end, 2)
157
+ block << tag_end << more
158
+ end
159
+ if (match = tag_start.match(DATA_PAGY))
160
+ search, data = match.captures
161
+ formatted = data.scan(/.{1,76}/).join("\n")
162
+ replace = %(\n#{INDENT * (level + 1)}data-pagy="#{formatted}")
163
+ tag_start.sub!(search, replace)
164
+ end
165
+ if block.match(WRAPPER)
166
+ push.(tag_start)
167
+ process(block, level + 1)
168
+ push.(tag_end)
169
+ else
170
+ push.(tag_start << block << tag_end)
171
+ end
172
+ end
173
+ process(rest, level) if rest
174
+ end
175
+ end
176
+
177
+ # Simple array-based collection that acts as a standard DB collection.
178
+ class MockCollection < Array
179
+ def initialize(arr = Array(1..1000))
180
+ super
181
+ @collection = clone
182
+ end
183
+
184
+ def offset(value)
185
+ @collection = self[value..]
186
+ self
187
+ end
188
+
189
+ def limit(value)
190
+ @collection[0, value]
191
+ end
192
+
193
+ def count(*)
194
+ size
195
+ end
196
+ end
197
+
198
+ run PagyDemo
199
+
200
+ # We store the template in a constant instead of writing it inline, so we can highlight it more easily
201
+ TEMPLATE = <<~ERB
202
+ <%# IMPORTANT: use '<%== ... ' instead of '<%= ... ' if you run this in rails %>
203
+
204
+ <%# The a variable below is set to a lambda that generates the a tag %>
205
+ <%# Usage: a_tag = a.(page_number, text, classes: nil, aria_label: nil) %>
206
+ <% a = pagy_anchor(pagy) %>
207
+ <nav class="pagy nav" aria-label="Pages">
208
+ <%# Previous page link %>
209
+ <% if pagy.prev %>
210
+ <%= a.(pagy.prev, '&lt;', aria_label: 'Previous') %>
211
+ <% else %>
212
+ <a role="link" aria-disabled="true" aria-label="Previous">&lt;</a>
213
+ <% end %>
214
+ <%# Page links (series example: [1, :gap, 7, 8, "9", 10, 11, :gap, 36]) %>
215
+ <% pagy.series.each do |item| %>
216
+ <% if item.is_a?(Integer) %>
217
+ <%= a.(item) %>
218
+ <% elsif item.is_a?(String) %>
219
+ <a role="link" aria-disabled="true" aria-current="page" class="current"><%= item %></a>
220
+ <% elsif item == :gap %>
221
+ <a role="link" aria-disabled="true" class="gap">&hellip;</a>
222
+ <% end %>
223
+ <% end %>
224
+ <%# Next page link %>
225
+ <% if pagy.next %>
226
+ <%= a.(pagy.next, '&gt;', aria_label: 'Next') %>
227
+ <% else %>
228
+ <a role="link" aria-disabled="true" aria-label="Next">&lt;</a>
229
+ <% end %>
230
+ </nav>
231
+ ERB
232
+
233
+ __END__
234
+
235
+ @@ layout
236
+ <!DOCTYPE html>
237
+ <html lang="en">
238
+ <head>
239
+ <title>Pagy Demo App</title>
240
+ <script src="/javascripts/pagy.min.js"></script>
241
+ <script>
242
+ window.addEventListener("load", Pagy.init);
243
+ </script>
244
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
245
+ <%= erb :"#{style}_head" if defined?(style) %>
246
+ <style type="text/css">
247
+ @media screen { html, body {
248
+ font-size: 1rem;
249
+ line-height: 1.2s;
250
+ padding: 0;
251
+ margin: 0;
252
+ } }
253
+ body {
254
+ background: white !important;
255
+ margin: 0 !important;
256
+ font-family: sans-serif !important;
257
+ }
258
+ h1, h2 {
259
+ font-size: 1.8rem !important;
260
+ font-weight: 600 !important;
261
+ margin-top: 1rem !important;
262
+ margin-bottom: 0.7rem !important;
263
+ line-height: 1.5 !important;
264
+ color: rgb(90 90 90) !important;
265
+ }
266
+ h2 {
267
+ font-family: monospace;
268
+ font-size: .9rem !important;
269
+ margin-top: 1.6rem !important;
270
+ }
271
+ summary, .notes {
272
+ font-size: .8rem;
273
+ color: gray;
274
+ margin-top: .6rem;
275
+ font-style: italic;
276
+ cursor: pointer;
277
+ }
278
+ .notes {
279
+ font-family: sans-serif;
280
+ font-weight: normal;
281
+ }
282
+ .notes code{
283
+ background-color: #E8E8E8;
284
+ padding: 0 0.3rem;
285
+ font-style: normal;
286
+ border-radius: 3px;
287
+ }
288
+ .description {
289
+ margin: 1rem 0;
290
+ }
291
+ .description a {
292
+ color: blue;
293
+ text-decoration: underline;
294
+ }
295
+ pre, pre code {
296
+ display: block;
297
+ margin-top: .3rem;
298
+ margin-bottom: 1rem;
299
+ font-size: .8rem !important;
300
+ line-height: 1rem !important;
301
+ color: white;
302
+ background-color: rgb(30 30 30);
303
+ padding: 1rem;
304
+ overflow: auto;
305
+ }
306
+ .content {
307
+ padding: 0 1.5rem 2rem !important;
308
+ }
309
+
310
+ #style-menu {
311
+ flex;
312
+ font-family: sans-serif;
313
+ font-size: 1.1rem;
314
+ line-height: 1.5rem;
315
+ white-space: nowrap;
316
+ color: white;
317
+ background-color: gray;
318
+ padding: .2rem 1.5rem;
319
+ }
320
+ #style-menu > :not([hidden]) ~ :not([hidden]) {
321
+ --space-reverse: 0;
322
+ margin-right: calc(0.5rem * var(--space-reverse));
323
+ margin-left: calc(0.5rem * calc(1 - var(--space-reverse)));
324
+ }
325
+ #style-menu a {
326
+ color: inherit;
327
+ text-decoration: none;
328
+ }
329
+ /* Quick demo for overriding the element style attribute of certain pagy helpers
330
+ .pagy input[style] {
331
+ width: 5rem !important;
332
+ }
333
+ */
334
+ </style>
335
+ </head>
336
+ <body>
337
+ <!-- each different class used by each style -->
338
+ <%= style_menu %>
339
+ <div class="content">
340
+ <%= yield %>
341
+ </div>
342
+ </body>
343
+ </html>
344
+
345
+
346
+ @@ pagy_head
347
+ <!-- copy and paste the pagy style in order to edit it -->
348
+ <link rel="stylesheet" href="/stylesheets/pagy.css">
349
+
350
+ @@ bootstrap_head
351
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css">
352
+
353
+ @@ bulma_head
354
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@0.9.4/css/bulma.min.css">
355
+
356
+ @@ tailwind_head
357
+ <script src="https://cdn.tailwindcss.com?plugins=forms,typography,aspect-ratio"></script>
358
+ <!-- copy and paste the pagy.tailwind style in order to edit it -->
359
+ <style type="text/tailwindcss">
360
+ <%= Pagy.root.join('stylesheets', 'pagy.tailwind.css').read %>
361
+ </style>
362
+
363
+
364
+ @@ helpers
365
+ <h1><%= style %></h1>
366
+ <% extra = STYLES[style][:extra] || "#{style}" %>
367
+ <% css_anchor = STYLES[style][:css_anchor] %>
368
+
369
+ <p class="description">See the <a href="http://ddnexus.github.io/pagy/docs/extras/<%= extra %>" target="blank"><%= extra %> extra</a>
370
+ documentation
371
+ <% if css_anchor %>
372
+ and the <a href="http://ddnexus.github.io/pagy/docs/api/stylesheets/#<%= css_anchor %>" target="blank"><%= css_anchor.gsub('-', '.') %></a>
373
+ <% end %>
374
+ for details</p>
375
+
376
+ <h2>Collection</h2>
377
+ <p id="records">@records: <%= @records.join(',') %></p>
378
+
379
+ <h2>pagy<%= prefix %>_nav <span class="notes">Simple nav <code>size: 5</code></span></h2>
380
+ <%= html = send(:"pagy#{prefix}_nav", @pagy, id: 'simple-nav', aria_label: 'Pages simple-nav', size: 5) %>
381
+ <%= highlight(html) %>
382
+
383
+ <h2>pagy<%= prefix %>_nav <span class="notes">Fast nav <code>size: 7</code></span></h2>
384
+ <%= html = send(:"pagy#{prefix}_nav", @pagy, id: 'nav', aria_label: 'Pages nav') %>
385
+ <%= highlight(html) %>
386
+
387
+ <h2>pagy<%= prefix %>_nav_js <span class="notes">Fast nav <code>size: 7</code></span></h2>
388
+ <%= html = send(:"pagy#{prefix}_nav_js", @pagy, id: 'nav-js', aria_label: 'Pages nav_js') %>
389
+ <%= highlight(html) %>
390
+
391
+ <h2>pagy<%= prefix %>_nav_js <span class="notes">Responsive nav <code>steps: {...}</code> (Resize the window to see)</span></h2>
392
+ <%= html = send(:"pagy#{prefix}_nav_js", @pagy, id: 'nav-js-responsive',
393
+ aria_label: 'Pages nav_js_responsive',
394
+ steps: { 0 => 5, 500 => 7, 750 => 9, 1000 => 11 }) %>
395
+ <%= highlight(html) %>
396
+
397
+ <h2>pagy<%= prefix %>_combo_nav_js</h2>
398
+ <%= html = send(:"pagy#{prefix}_combo_nav_js", @pagy, id: 'combo-nav-js', aria_label: 'Pages combo_nav_js') %>
399
+ <%= highlight(html) %>
400
+
401
+ <h2>pagy_info</h2>
402
+ <%= html = pagy_info(@pagy, id: 'pagy-info') %>
403
+ <%= highlight(html) %>
404
+
405
+ <% if style.match(/pagy|tailwind/) %>
406
+ <h2>pagy_items_selector_js</h2>
407
+ <%= html = pagy_items_selector_js(@pagy, id: 'items-selector-js') %>
408
+ <%= highlight(html) %>
409
+
410
+ <h2>pagy_prev_a / pagy_next_a</h2>
411
+ <%= html = '<nav class="pagy" id="prev-next" aria-label="Pagy prev-next">' << pagy_prev_a(@pagy) << pagy_next_a(@pagy) << '</nav>' %>
412
+ <%= highlight(html) %>
413
+
414
+ <h2>pagy_prev_link / pagy_next_link <span class="notes">Link not rendered<span></h2>
415
+ <% html = '<head>' << (pagy_prev_link(@pagy)||'') << (pagy_next_link(@pagy)||'') << '</head>' %>
416
+ <%= highlight(html) %>
417
+ <% end %>
418
+
419
+
420
+ @@ template
421
+ <h1>Pagy Template Demo</h1>
422
+
423
+ <p class="description">
424
+ See the <a href="https://ddnexus.github.io/pagy/docs/how-to/#using-your-pagination-templates">
425
+ Custom Templates</a> documentation.
426
+ </p>
427
+ <h2>Collection</h2>
428
+ <p id="records">@records: <%= @records.join(',') %></p>
429
+
430
+ <h2>Rendered ERB template</h2>
431
+
432
+ <%# We don't inline the template here, so we can highlight it more easily %>
433
+ <%= html = ERB.new(TEMPLATE).result(binding) %>
434
+ <%= highlight(TEMPLATE, format: :erb) %>
435
+ <%= highlight(html) %>
data/apps/rails.ru ADDED
@@ -0,0 +1,213 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Starting point to reproduce rails related pagy issues
4
+
5
+ # DEV USAGE
6
+ # pagy clone rails
7
+ # pagy ./rails.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/#2-rails-app
17
+
18
+ VERSION = '8.6.2'
19
+
20
+ # Gemfile
21
+ require 'bundler/inline'
22
+ require 'bundler'
23
+ Bundler.configure
24
+ gemfile(ENV['PAGY_INSTALL_BUNDLE'] == 'true') do
25
+ source 'https://rubygems.org'
26
+ gem 'oj'
27
+ gem 'puma'
28
+ gem 'rails'
29
+ # activerecord/sqlite3_adapter.rb probably useless) constraint !!!
30
+ # https://github.com/rails/rails/blame/v7.1.3.4/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb#L14
31
+ gem 'sqlite3', '~> 1.4.0'
32
+ end
33
+
34
+ # require 'rails/all' # too much stuff
35
+ require 'action_controller/railtie'
36
+ require 'active_record'
37
+
38
+ OUTPUT = Rails.env.showcase? ? IO::NULL : $stdout
39
+
40
+ # Rails config
41
+ class PagyRails < Rails::Application # :nodoc:
42
+ config.root = __dir__
43
+ config.session_store :cookie_store, key: 'cookie_store_key'
44
+ Rails.application.credentials.secret_key_base = 'absolute_secret'
45
+
46
+ config.logger = Logger.new(OUTPUT)
47
+ Rails.logger = config.logger
48
+
49
+ routes.draw do
50
+ root to: 'comments#index'
51
+ get '/javascripts/:file', to: 'pagy#javascripts', file: /.*/
52
+ end
53
+ end
54
+
55
+ # AR config
56
+ dir = Rails.env.development? ? '.' : Dir.pwd # app dir in dev or pwd otherwise
57
+ unless File.writable?(dir)
58
+ warn "ERROR: directory #{dir.inspect} is not writable (the pagy-rails-app needs to create DB files)"
59
+ exit 1
60
+ end
61
+
62
+ # Pagy initializer
63
+ require 'pagy/extras/pagy'
64
+ require 'pagy/extras/items'
65
+ require 'pagy/extras/overflow'
66
+ Pagy::DEFAULT[:items] = 10
67
+ Pagy::DEFAULT[:overflow] = :empty_page
68
+ Pagy::DEFAULT.freeze
69
+
70
+ ActiveRecord::Base.establish_connection(adapter: 'sqlite3', database: "#{dir}/tmp/pagy-rails.sqlite3")
71
+ ActiveRecord::Schema.define do
72
+ create_table :posts, force: true do |t|
73
+ t.string :title
74
+ end
75
+
76
+ create_table :comments, force: true do |t|
77
+ t.string :body
78
+ t.integer :post_id
79
+ end
80
+ end
81
+
82
+ # Models
83
+ class Post < ActiveRecord::Base # :nodoc:
84
+ has_many :comments
85
+ end # :nodoc:
86
+
87
+ class Comment < ActiveRecord::Base # :nodoc:
88
+ belongs_to :post
89
+ end # :nodoc:
90
+
91
+ # DB seed
92
+ 1.upto(11) do |pi|
93
+ Post.create(title: "Post #{pi + 1}")
94
+ end
95
+ Post.all.each_with_index do |post, pi|
96
+ 2.times { |ci| Comment.create(post:, body: "Comment #{ci + 1} to Post #{pi + 1}") }
97
+ end
98
+
99
+ # Down here to avoid logging the DB seed above at each restart
100
+ ActiveRecord::Base.logger = Logger.new(OUTPUT)
101
+
102
+ # Helpers
103
+ module CommentsHelper
104
+ include Pagy::Frontend
105
+ end
106
+
107
+ # Controllers
108
+ class CommentsController < ActionController::Base # :nodoc:
109
+ include Rails.application.routes.url_helpers
110
+ include Pagy::Backend
111
+
112
+ def index
113
+ @pagy, @comments = pagy(Comment.all)
114
+ render inline: TEMPLATE
115
+ end
116
+ end
117
+
118
+ # You don't need this in real rails apps (see https://ddnexus.github.io/pagy/docs/api/javascript/setup/#2-configure)
119
+ class PagyController < ActionController::Base
120
+ def javascripts
121
+ format = params[:file].split('.').last
122
+ if format == 'js'
123
+ render js: Pagy.root.join('javascripts', params[:file]).read
124
+ elsif format == 'map'
125
+ render json: Pagy.root.join('javascripts', params[:file]).read
126
+ end
127
+ end
128
+ end
129
+
130
+ run PagyRails
131
+
132
+ TEMPLATE = <<~ERB
133
+ <!DOCTYPE html>
134
+ <html lang="en">
135
+ <html>
136
+ <head>
137
+ <title>Pagy Rails App</title>
138
+ <script src="/javascripts/pagy.min.js"></script>
139
+ <script>
140
+ window.addEventListener("load", Pagy.init);
141
+ </script>
142
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
143
+ <style type="text/css">
144
+ @media screen { html, body {
145
+ font-size: 1rem;
146
+ line-height: 1.2s;
147
+ padding: 0;
148
+ margin: 0;
149
+ } }
150
+ body {
151
+ background: white !important;
152
+ margin: 0 !important;
153
+ font-family: sans-serif !important;
154
+ }
155
+ .content {
156
+ padding: 1rem 1.5rem 2rem !important;
157
+ }
158
+
159
+ /* Quick demo for overriding the element style attribute of certain pagy helpers
160
+ .pagy input[style] {
161
+ width: 5rem !important;
162
+ }
163
+ */
164
+
165
+ /*
166
+ If you want to customize the style,
167
+ please replace the line below with the actual file content
168
+ */
169
+ <%== Pagy.root.join('stylesheets', 'pagy.css').read %>
170
+ </style>
171
+ </head>
172
+
173
+ <body>
174
+
175
+ <div class="content">
176
+ <h1>Pagy Rails App</h1>
177
+ <p> Self-contained, standalone Rails app usable to easily reproduce any rails related pagy issue.</p>
178
+ <p>Please, report the following versions in any new issue.</p>
179
+ <h2>Versions</h2>
180
+ <ul>
181
+ <li>Ruby: <%== RUBY_VERSION %></li>
182
+ <li>Rack: <%== Rack::RELEASE %></li>
183
+ <li>Rails: <%== Rails.version %></li>
184
+ <li>Pagy: <%== Pagy::VERSION %></li>
185
+ </ul>
186
+
187
+ <h3>Collection</h3>
188
+ <div id="records" class="collection">
189
+ <% @comments.each do |comment| %>
190
+ <p style="margin: 0;"><%= comment.body %></p>
191
+ <% end %>
192
+ </div>
193
+ <hr>
194
+
195
+ <h4>pagy_nav</h4>
196
+ <%== pagy_nav(@pagy, id: 'nav', aria_label: 'Pages nav') %>
197
+
198
+ <h4>pagy_nav_js</h4>
199
+ <%== pagy_nav_js(@pagy, id: 'nav-js', aria_label: 'Pages nav_js') %>
200
+
201
+ <h4>pagy_combo_nav_js</h4>
202
+ <%== pagy_combo_nav_js(@pagy, id: 'combo-nav-js', aria_label: 'Pages combo_nav_js') %>
203
+
204
+ <h4>pagy_items_selector_js</h4>
205
+ <%== pagy_items_selector_js(@pagy, id: 'items-selector-js') %>
206
+
207
+ <h4>pagy_info</h4>
208
+ <%== pagy_info(@pagy, id: 'pagy-info') %>
209
+ </div>
210
+
211
+ </body>
212
+ </html>
213
+ ERB