pagy 7.0.10 → 8.0.0

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