pagy 7.0.11 → 43.5.1

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 (211) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +1 -1
  3. data/apps/calendar.ru +741 -0
  4. data/apps/demo.ru +513 -0
  5. data/apps/enable_rails_page_segment.rb +54 -0
  6. data/apps/index.rb +9 -0
  7. data/apps/keynav+root_key.ru +316 -0
  8. data/apps/keynav.ru +255 -0
  9. data/apps/keyset.ru +219 -0
  10. data/apps/keyset_sequel.ru +212 -0
  11. data/apps/rails.ru +216 -0
  12. data/apps/repro.ru +185 -0
  13. data/bin/pagy +5 -0
  14. data/config/pagy.rb +46 -0
  15. data/javascripts/ai_widget.js +90 -0
  16. data/javascripts/pagy.js +168 -0
  17. data/javascripts/pagy.min.js +2 -0
  18. data/javascripts/pagy.mjs +161 -0
  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 +9 -12
  22. data/lib/pagy/{calendar → classes/calendar}/month.rb +7 -11
  23. data/lib/pagy/{calendar → classes/calendar}/quarter.rb +12 -16
  24. data/lib/pagy/classes/calendar/unit.rb +93 -0
  25. data/lib/pagy/{calendar → classes/calendar}/week.rb +7 -11
  26. data/lib/pagy/{calendar → classes/calendar}/year.rb +9 -9
  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 +150 -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/modules/b64.rb +35 -0
  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 +21 -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 +55 -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 +19 -0
  82. data/lib/pagy/toolbox/helpers/support/wrap_series_nav.rb +17 -0
  83. data/lib/pagy/toolbox/helpers/support/wrap_series_nav_js.rb +42 -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 +67 -131
  97. data/locales/ar.yml +32 -0
  98. data/locales/be.yml +28 -0
  99. data/locales/bg.yml +24 -0
  100. data/locales/bs.yml +28 -0
  101. data/locales/ca.yml +24 -0
  102. data/locales/ckb.yml +20 -0
  103. data/locales/cs.yml +26 -0
  104. data/locales/da.yml +24 -0
  105. data/locales/de.yml +24 -0
  106. data/locales/dz.yml +20 -0
  107. data/locales/en.yml +24 -0
  108. data/{lib/locales → locales}/es.yml +9 -6
  109. data/locales/fr.yml +24 -0
  110. data/locales/hr.yml +28 -0
  111. data/locales/id.yml +20 -0
  112. data/locales/it.yml +24 -0
  113. data/locales/ja.yml +20 -0
  114. data/locales/km.yml +20 -0
  115. data/locales/ko.yml +20 -0
  116. data/locales/nb.yml +24 -0
  117. data/locales/nl.yml +24 -0
  118. data/locales/nn.yml +24 -0
  119. data/locales/pl.yml +28 -0
  120. data/{lib/locales → locales}/pt-BR.yml +10 -7
  121. data/{lib/locales → locales}/pt.yml +10 -7
  122. data/locales/ru.yml +28 -0
  123. data/locales/sk.yml +26 -0
  124. data/locales/sr.yml +28 -0
  125. data/locales/sv-SE.yml +24 -0
  126. data/locales/sv.yml +24 -0
  127. data/locales/sw.yml +28 -0
  128. data/locales/ta.yml +24 -0
  129. data/locales/tr.yml +24 -0
  130. data/locales/uk.yml +28 -0
  131. data/locales/vi.yml +20 -0
  132. data/locales/zh-CN.yml +20 -0
  133. data/locales/zh-HK.yml +20 -0
  134. data/locales/zh-TW.yml +20 -0
  135. data/stylesheets/pagy-tailwind.css +68 -0
  136. data/stylesheets/pagy.css +83 -0
  137. metadata +185 -94
  138. data/lib/config/pagy.rb +0 -258
  139. data/lib/javascripts/pagy-dev.js +0 -112
  140. data/lib/javascripts/pagy-module.js +0 -111
  141. data/lib/javascripts/pagy.js +0 -1
  142. data/lib/locales/ar.yml +0 -30
  143. data/lib/locales/be.yml +0 -25
  144. data/lib/locales/bg.yml +0 -21
  145. data/lib/locales/bs.yml +0 -25
  146. data/lib/locales/ca.yml +0 -23
  147. data/lib/locales/ckb.yml +0 -18
  148. data/lib/locales/cs.yml +0 -23
  149. data/lib/locales/da.yml +0 -23
  150. data/lib/locales/de.yml +0 -21
  151. data/lib/locales/en.yml +0 -21
  152. data/lib/locales/fr.yml +0 -21
  153. data/lib/locales/hr.yml +0 -25
  154. data/lib/locales/id.yml +0 -19
  155. data/lib/locales/it.yml +0 -21
  156. data/lib/locales/ja.yml +0 -19
  157. data/lib/locales/km.yml +0 -19
  158. data/lib/locales/ko.yml +0 -19
  159. data/lib/locales/nb.yml +0 -21
  160. data/lib/locales/nl.yml +0 -21
  161. data/lib/locales/nn.yml +0 -21
  162. data/lib/locales/pl.yml +0 -25
  163. data/lib/locales/ru.yml +0 -27
  164. data/lib/locales/sr.yml +0 -25
  165. data/lib/locales/sv-SE.yml +0 -21
  166. data/lib/locales/sv.yml +0 -21
  167. data/lib/locales/sw.yml +0 -23
  168. data/lib/locales/ta.yml +0 -23
  169. data/lib/locales/tr.yml +0 -19
  170. data/lib/locales/uk.yml +0 -25
  171. data/lib/locales/vi.yml +0 -17
  172. data/lib/locales/zh-CN.yml +0 -19
  173. data/lib/locales/zh-HK.yml +0 -19
  174. data/lib/locales/zh-TW.yml +0 -19
  175. data/lib/pagy/backend.rb +0 -39
  176. data/lib/pagy/calendar/helper.rb +0 -65
  177. data/lib/pagy/calendar.rb +0 -126
  178. data/lib/pagy/countless.rb +0 -37
  179. data/lib/pagy/exceptions.rb +0 -25
  180. data/lib/pagy/extras/arel.rb +0 -36
  181. data/lib/pagy/extras/array.rb +0 -24
  182. data/lib/pagy/extras/bootstrap.rb +0 -108
  183. data/lib/pagy/extras/bulma.rb +0 -105
  184. data/lib/pagy/extras/calendar.rb +0 -53
  185. data/lib/pagy/extras/countless.rb +0 -37
  186. data/lib/pagy/extras/elasticsearch_rails.rb +0 -80
  187. data/lib/pagy/extras/foundation.rb +0 -105
  188. data/lib/pagy/extras/frontend_helpers.rb +0 -67
  189. data/lib/pagy/extras/gearbox.rb +0 -54
  190. data/lib/pagy/extras/headers.rb +0 -53
  191. data/lib/pagy/extras/i18n.rb +0 -26
  192. data/lib/pagy/extras/items.rb +0 -61
  193. data/lib/pagy/extras/jsonapi.rb +0 -79
  194. data/lib/pagy/extras/materialize.rb +0 -96
  195. data/lib/pagy/extras/meilisearch.rb +0 -65
  196. data/lib/pagy/extras/metadata.rb +0 -38
  197. data/lib/pagy/extras/navs.rb +0 -51
  198. data/lib/pagy/extras/overflow.rb +0 -80
  199. data/lib/pagy/extras/searchkick.rb +0 -67
  200. data/lib/pagy/extras/semantic.rb +0 -95
  201. data/lib/pagy/extras/standalone.rb +0 -60
  202. data/lib/pagy/extras/support.rb +0 -40
  203. data/lib/pagy/extras/trim.rb +0 -29
  204. data/lib/pagy/extras/uikit.rb +0 -97
  205. data/lib/pagy/frontend.rb +0 -114
  206. data/lib/pagy/i18n.rb +0 -165
  207. data/lib/pagy/url_helpers.rb +0 -27
  208. data/lib/stylesheets/pagy.css +0 -61
  209. data/lib/stylesheets/pagy.scss +0 -50
  210. data/lib/stylesheets/pagy.tailwind.scss +0 -24
  211. /data/{lib/javascripts/pagy-module.d.ts → javascripts/pagy.d.ts} +0 -0
data/apps/demo.ru ADDED
@@ -0,0 +1,513 @@
1
+ # frozen_string_literal: true
2
+
3
+ # DESCRIPTION
4
+ # Showcase all the helpers and styles
5
+ #
6
+ # DOC
7
+ # https://ddnexus.github.io/pagy/playground/#demo-app
8
+ #
9
+ # BIN HELP
10
+ # pagy -h
11
+ #
12
+ # DEMO USAGE
13
+ # pagy demo
14
+ #
15
+ # DEV USAGE
16
+ # pagy clone demo
17
+ # pagy ./demo.ru
18
+ #
19
+ # URL
20
+ # http://127.0.0.1:8000
21
+
22
+ VERSION = '43.5.1'
23
+
24
+ if VERSION != Pagy::VERSION
25
+ Warning.warn("\n>>> WARNING! '#{File.basename(__FILE__)}-#{VERSION}' running with 'pagy-#{Pagy::VERSION}'! <<< \n\n")
26
+ end
27
+
28
+ # Bundle
29
+ require 'bundler/inline'
30
+ gemfile(!Pagy::ROOT.join('pagy.gemspec').exist?) do
31
+ source 'https://rubygems.org'
32
+ gem 'oj'
33
+ gem 'puma'
34
+ gem 'rouge'
35
+ gem 'sinatra'
36
+ end
37
+
38
+ # pagy initializer
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
44
+
45
+ # Sinatra setup
46
+ require 'sinatra/base'
47
+
48
+ # Pagy init
49
+ Pagy::OPTIONS[:max_limit] = 100
50
+
51
+ # Sinatra application
52
+ class PagyDemo < Sinatra::Base
53
+ include Pagy::Method
54
+
55
+ get '/' do
56
+ redirect '/pagy'
57
+ end
58
+
59
+ get('/javascripts/:file') do
60
+ format = params[:file].split('.').last
61
+ if format == 'js'
62
+ content_type 'application/javascript'
63
+ elsif format == 'map'
64
+ content_type 'application/json'
65
+ end
66
+ send_file Pagy::ROOT.join('javascripts', params[:file])
67
+ end
68
+
69
+ get('/stylesheets/:file') do
70
+ content_type 'text/css'
71
+ send_file Pagy::ROOT.join('stylesheets', params[:file])
72
+ end
73
+
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
80
+
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] }
92
+ end
93
+ end
94
+
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
101
+
102
+ helpers do
103
+ def style_menu
104
+ html = +%(<div id="style-menu"> )
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
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
142
+ end
143
+
144
+ def highlight(html, format: :html)
145
+ if format == :html
146
+ html = html.gsub(/>\s*</, '><').strip # template single line no spaces around/between tags
147
+ html = Formatter.new.format(html)
148
+ end
149
+ lexer = Rouge::Lexers::ERB.new
150
+ formatter = Rouge::Formatters::HTMLInline.new('monokai.sublime')
151
+ summary = { html: 'Served HTML (pretty formatted)', erb: 'ERB Template' }
152
+ %(<details><summary>#{summary[format]}</summary><pre>\n#{
153
+ formatter.format(lexer.lex(html))
154
+ }</pre></details>)
155
+ end
156
+ end
157
+
158
+ # Views
159
+ template :layout do
160
+ <<~HTML
161
+ <!DOCTYPE html>
162
+ <html lang="en" data-theme="light">
163
+ <head>
164
+ <title>Pagy Demo App</title>
165
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
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>
175
+ @media screen { html, body {
176
+ font-size: 1rem;
177
+ line-height: 1.2;
178
+ padding: 0;
179
+ margin: 0;
180
+ } }
181
+ *,
182
+ *::before,
183
+ *::after {
184
+ box-sizing: border-box;
185
+ }
186
+ html {
187
+ background-color: transparent !important; /* Fix for Bulma */
188
+ }
189
+ body {
190
+ margin: 0 !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;
202
+ }
203
+ h1, h2 {
204
+ font-size: 1.8rem !important;
205
+ font-weight: 600 !important;
206
+ margin-top: 1rem !important;
207
+ margin-bottom: 0.7rem !important;
208
+ line-height: 1.5 !important;
209
+ color: #303030 !important;
210
+ }
211
+ h2 {
212
+ font-family: monospace;
213
+ font-size: .9rem !important;
214
+ margin-top: 1.6rem !important;
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
+ }
223
+ summary, .notes {
224
+ font-size: .8rem;
225
+ margin-top: .6rem;
226
+ font-style: italic;
227
+ cursor: pointer;
228
+ }
229
+ .notes {
230
+ font-family: sans-serif;
231
+ font-weight: normal;
232
+ }
233
+ .notes code{
234
+ background-color: rgba(255, 255, 255, .6);
235
+ padding: 0 0.3rem;
236
+ font-style: normal;
237
+ border-radius: 3px;
238
+ }
239
+ .description {
240
+ margin: 1rem 0;
241
+ }
242
+ .description a {
243
+ color: blue;
244
+ text-decoration: underline;
245
+ }
246
+ pre, pre code {
247
+ display: inline-block;
248
+ margin-top: .3rem;
249
+ margin-bottom: 1rem;
250
+ font-size: .8rem !important;
251
+ line-height: 1rem !important;
252
+ color: white;
253
+ background-color: rgb(30 30 30);
254
+ padding: 1rem;
255
+ overflow-x: auto;
256
+ max-width: 100%;
257
+ white-space: pre;
258
+ }
259
+ .main-content {
260
+ padding: 0 1.5rem 2rem !important;
261
+ }
262
+ #style-menu {
263
+ flex;
264
+ font-family: sans-serif;
265
+ font-size: 1.1rem;
266
+ line-height: 1.5rem;
267
+ white-space: nowrap;
268
+ color: white;
269
+ background-color: rgba(0,0,0,.65);
270
+ padding: .2rem 1.5rem;
271
+ }
272
+ #style-menu > :not([hidden]) ~ :not([hidden]) {
273
+ --space-reverse: 0;
274
+ margin-right: calc(0.5rem * var(--space-reverse));
275
+ margin-left: calc(0.5rem * calc(1 - var(--space-reverse)));
276
+ }
277
+ #style-menu a {
278
+ color: inherit;
279
+ text-decoration: none;
280
+ }
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;
307
+ }
308
+ </style>
309
+ </head>
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>
318
+ <!-- each different class used by each style -->
319
+ <%= style_menu %>
320
+ <div class="main-content">
321
+ <%= yield %>
322
+ </div>
323
+ </body>
324
+ </html>
325
+ HTML
326
+ end
327
+
328
+ template :page do
329
+ <<~ERB
330
+ <h1><%= title = section.to_s; title[0] = title[0].capitalize; title %></h1>
331
+
332
+ <% if css_anchor %>
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>
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>
377
+ ERB
378
+ end
379
+
380
+ template :template do
381
+ <<~ERB
382
+ <h1>Pagy Template Demo</h1>
383
+
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>
388
+
389
+ <h2>Collection</h2>
390
+ <p id="records">@records: <%= @records.join(',') %></p>
391
+
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
402
+
403
+ # Easier code highlighting
404
+ TEMPLATE = <<~ERB
405
+ <%# IMPORTANT: replace '<%=' with '<%==' if you run this in rails %>
406
+
407
+ <%# The a variable below is set to a lambda that generates the a tag %>
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">
411
+ <%# Previous page link %>
412
+ <% if pagy.previous %>
413
+ <%= a_lambda.(pagy.previous, '&lt;', aria_label: 'Previous') %>
414
+ <% else %>
415
+ <a role="link" aria-disabled="true" aria-label="Previous">&lt;</a>
416
+ <% end %>
417
+ <%# Page links (series example: [1, :gap, 7, 8, "9", 10, 11, :gap, 36]) %>
418
+ <% pagy.send(:series).each do |item| %>
419
+ <% if item.is_a?(Integer) %>
420
+ <%= a_lambda.(item) %>
421
+ <% elsif item.is_a?(String) %>
422
+ <a role="link" aria-disabled="true" aria-current="page"><%= item %></a>
423
+ <% elsif item == :gap %>
424
+ <a role="separator" aria-disabled="true">&hellip;</a>
425
+ <% end %>
426
+ <% end %>
427
+ <%# Next page link %>
428
+ <% if pagy.next %>
429
+ <%= a_lambda.(pagy.next, '&gt;', aria_label: 'Next') %>
430
+ <% else %>
431
+ <a role="link" aria-disabled="true" aria-label="Next">&lt;</a>
432
+ <% end %>
433
+ </nav>
434
+ ERB
435
+ end
436
+
437
+ # Cheap pagy formatter for helpers output
438
+ class Formatter
439
+ INDENT = ' '
440
+ TEXT_SPACE = "\u00B7"
441
+ TEXT = /^([^<>]+)(.*)/
442
+ UNPAIRED = /^(<(input|link).*?>)(.*)/
443
+ PAIRED = %r{^(<(head|nav|div|span|p|a|b|label|ul|li).*?>)(.*?)(</\2>)(.*)}
444
+ WRAPPER = /<.*?>/
445
+ DATA_PAGY = /(data-pagy="([^"]+)")/
446
+
447
+ def initialize
448
+ @formatted = +''
449
+ end
450
+
451
+ def format(input, level = 0)
452
+ process(input, level)
453
+ @formatted
454
+ end
455
+
456
+ private
457
+
458
+ def process(input, level)
459
+ push = ->(content) { @formatted << ((INDENT * level) << content << "\n") }
460
+ rest = nil
461
+ if (match = input.match(TEXT))
462
+ text, rest = match.captures
463
+ push.(text.gsub(' ', TEXT_SPACE))
464
+ elsif (match = input.match(UNPAIRED))
465
+ tag, _name, rest = match.captures
466
+ push.(tag)
467
+ elsif (match = input.match(PAIRED))
468
+ tag_start, name, block, tag_end, rest = match.captures
469
+ # Handle incomplete same-tag nesting
470
+ while block.scan(/<#{name}.*?>/).size > block.scan(tag_end).size
471
+ more, rest = rest.split(tag_end, 2)
472
+ block << (tag_end + more)
473
+ end
474
+ if (match = tag_start.match(DATA_PAGY))
475
+ search, data = match.captures
476
+ formatted = data.scan(/.{1,76}/).join("\n")
477
+ replace = %(\n#{INDENT * (level + 1)}data-pagy="#{formatted}")
478
+ tag_start.sub!(search, replace)
479
+ end
480
+ if block.match(WRAPPER)
481
+ push.(tag_start)
482
+ process(block, level + 1)
483
+ push.(tag_end)
484
+ else
485
+ push.(tag_start << (block + tag_end))
486
+ end
487
+ end
488
+ process(rest, level) if rest
489
+ end
490
+ end
491
+
492
+ # Simple array-based collection that acts as a standard DB collection.
493
+ class MockCollection < Array
494
+ def initialize(arr = Array(1..1000))
495
+ super
496
+ @collection = clone
497
+ end
498
+
499
+ def offset(value)
500
+ @collection = self[value..] || []
501
+ self
502
+ end
503
+
504
+ def limit(value)
505
+ @collection.empty? ? [] : @collection[0, value]
506
+ end
507
+
508
+ def count(*)
509
+ size
510
+ end
511
+ end
512
+
513
+ run PagyDemo
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ # ################# IMPORTANT WARNING #################
4
+ # This setup forces Pagy to use the Rails `url_for` method,
5
+ # which is significantly slower (~20x) than Pagy's native URL generation.
6
+
7
+ # Use this file ONLY if you absolutely want to support the page param as a dynamic segment.
8
+ # (e.g. get '/comments(/:page)', to: 'comments#index').
9
+ # #####################################################
10
+
11
+ # USAGE
12
+
13
+ # initializers/pagy.rb
14
+ # require Pagy::ROOT.join('apps/enable_rails_page_segment.rb')
15
+
16
+ # config/routes.rb (example)
17
+ # get '/comments(/:page)', to: 'comments#index'
18
+
19
+
20
+ # Use plain Strings tokens instead of Pagy::EscapedValue strings
21
+ Pagy.send(:remove_const, :PAGE_TOKEN) ; Pagy::PAGE_TOKEN = '___PAGY_PAGE___'
22
+ Pagy.send(:remove_const, :LIMIT_TOKEN) ; Pagy::LIMIT_TOKEN = '___PAGY_LIMIT___'
23
+
24
+ # Require the pagy sources to override
25
+ require_relative '../lib/pagy/toolbox/paginators/method'
26
+ require_relative '../lib/pagy/modules/abilities/linkable'
27
+
28
+ class Pagy
29
+ # Switch to the `request.params` to get access to rails-added path parameters
30
+ module RequestOverride
31
+ def get_params(request)
32
+ request.params
33
+ end
34
+ end
35
+ Request.prepend RequestOverride
36
+
37
+ # Inject the caller context into the Pagy instance
38
+ module MethodOverride
39
+ def pagy(...)
40
+ super.tap { _1[0].instance_variable_set(:@context, self) }
41
+ end
42
+ end
43
+ Method.prepend MethodOverride
44
+
45
+ # Compose the final URL using `url_for`.
46
+ module LinkableOverride
47
+ def compose_url(absolute, _path, params, fragment)
48
+ params[:anchor] = fragment if fragment
49
+ params[:only_path] = !absolute
50
+ @context.url_for(params)
51
+ end
52
+ end
53
+ Linkable.prepend LinkableOverride
54
+ end
data/apps/index.rb ADDED
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ # PagyApps module
4
+ module PagyApps
5
+ # Return the hash of app name/path
6
+ INDEX = Dir[File.expand_path('./*.ru', __dir__)].to_h do |f|
7
+ [File.basename(f, '.ru'), f]
8
+ end.freeze
9
+ end