pagy 5.7.5 → 8.6.2

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 (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