unpoly-rails 3.14.2 → 3.15.0

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 (38) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +317 -0
  3. data/README.md +61 -40
  4. data/assets/unpoly/unpoly-bootstrap3.css.map +1 -0
  5. data/assets/unpoly/unpoly-bootstrap3.js.map +1 -0
  6. data/assets/unpoly/unpoly-bootstrap3.min.css.map +1 -0
  7. data/assets/unpoly/unpoly-bootstrap3.min.js.map +1 -0
  8. data/assets/unpoly/unpoly-bootstrap4.css.map +1 -0
  9. data/assets/unpoly/unpoly-bootstrap4.js.map +1 -0
  10. data/assets/unpoly/unpoly-bootstrap4.min.css.map +1 -0
  11. data/assets/unpoly/unpoly-bootstrap4.min.js.map +1 -0
  12. data/assets/unpoly/unpoly-bootstrap5.css.map +1 -0
  13. data/assets/unpoly/unpoly-bootstrap5.js.map +1 -0
  14. data/assets/unpoly/unpoly-bootstrap5.min.css.map +1 -0
  15. data/assets/unpoly/unpoly-bootstrap5.min.js.map +1 -0
  16. data/assets/unpoly/unpoly-migrate.js +228 -149
  17. data/assets/unpoly/unpoly-migrate.js.map +1 -0
  18. data/assets/unpoly/unpoly-migrate.min.js +1 -1
  19. data/assets/unpoly/unpoly-migrate.min.js.map +1 -0
  20. data/assets/unpoly/unpoly.css.map +1 -0
  21. data/assets/unpoly/unpoly.es6.js +666 -430
  22. data/assets/unpoly/unpoly.es6.js.map +1 -0
  23. data/assets/unpoly/unpoly.es6.min.js +1 -1
  24. data/assets/unpoly/unpoly.es6.min.js.map +1 -0
  25. data/assets/unpoly/unpoly.js +2167 -1990
  26. data/assets/unpoly/unpoly.js.map +1 -0
  27. data/assets/unpoly/unpoly.min.css.map +1 -0
  28. data/assets/unpoly/unpoly.min.js +1 -1
  29. data/assets/unpoly/unpoly.min.js.map +1 -0
  30. data/lib/unpoly/rails/change/cache.rb +4 -4
  31. data/lib/unpoly/rails/change/layer.rb +3 -0
  32. data/lib/unpoly/rails/change.rb +35 -8
  33. data/lib/unpoly/rails/controller.rb +3 -2
  34. data/lib/unpoly/rails/engine.rb +7 -0
  35. data/lib/unpoly/rails/request_echo_headers.rb +10 -3
  36. data/lib/unpoly/rails/util.rb +38 -0
  37. data/lib/unpoly/rails/version.rb +1 -1
  38. metadata +31 -8
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bf27bc74fecd262323239fb583020ddf6d4bba888f7237c10d1d99929e2ffa9c
4
- data.tar.gz: 7bf18db6c39dfa7ea1be1a285704e842137218bf36cbe62711bb685875ca8a63
3
+ metadata.gz: 46756e6ad349d23a8eb423ff84312fb7087d0cd9a264330083f4444bf9f8426f
4
+ data.tar.gz: 6ebcc0673721029309334e89e19c8e3f951885cc0aa397ea22b0d4ea8d7e077c
5
5
  SHA512:
6
- metadata.gz: fe6bf77ff3a7619a84748dd77d928be65b1ec5b4b021f2249c9f2f4bdbe748be318297f58985ceb81f6da609a3eba291f7e04a371125806613ae2ed3faf2f942
7
- data.tar.gz: 1f7e0ede5f94a1759f789c02047098c8e238723a2b5f8040fe606f18817449acc19b113e439ad995cc8f96becd65d5085b611af42ae913be5883163c4dbcf514
6
+ metadata.gz: 6c553354ea601cdb7e99537508cc2b334471006b54d49b2e8164e577f68a62e81355b21781b5ef816e744b892c84da94a2f2a58d6905c38a65e7c9c849dfe7f5
7
+ data.tar.gz: 492853bd0eb78efcd1c07a9da731ffb9d2a69006ab60cf0bbf5c15c8979d40dc586d112290e4d59d271d896dd026f6d871bcada14c82e338b4964a9ee9f5170c
data/CHANGELOG.md ADDED
@@ -0,0 +1,317 @@
1
+ # Changelog
2
+
3
+ Changes to the unpoly-rails gem. For changes to Unpoly itself, see https://unpoly.com/changes.
4
+
5
+ Each release also bundles Unpoly's frontend files for the asset pipeline. If your app installs Unpoly from npm, only the server-side changes matter to you, and any recent gem version will do.
6
+
7
+
8
+ ## 3.15.0
9
+
10
+ - Bundles Unpoly 3.15.0 for the asset pipeline.
11
+ - `up.layer.open` converts snake_case option names to Unpoly's camelCase names, e.g. `:on_accepted_reload` becomes `onAcceptedReload`. Keys inside the `:context` option are passed through unchanged.
12
+ - Fix Unpoly params being lost when redirecting to a URL with a `#hash`. The params were appended after the hash, so changes like a new target, events or context changes did not survive the redirect.
13
+ - A `#hash` in a redirect URL is kept for fragment updates, e.g. `redirect_to post_path(@post, anchor: 'comments')`. The gem passes it as a `_up_location_hash` param and echoes it in the [`X-Up-Location`](https://unpoly.com/api/X-Up-Location) header after the redirect. Unpoly then reveals the element with that ID and shows the `#hash` in the address bar. Requires Unpoly 3.15 or later.
14
+ - The gem now includes source maps for the bundled frontend files.
15
+ - The gem's metadata links to unpoly.com, the changelog, the source code and the issue tracker.
16
+ - Fix deprecated helpers like `up.cache.clear` or `up.render_nothing` raising a `NoMethodError` on Rails 7.2+. On Rails 7.1+, the gem's deprecation warnings now follow your app's deprecation settings.
17
+
18
+
19
+ ## 3.14.3
20
+
21
+ - Bundles Unpoly 3.14.3 for the asset pipeline.
22
+
23
+
24
+ ## 3.14.2
25
+
26
+ - Bundles Unpoly 3.14.2 for the asset pipeline.
27
+
28
+
29
+ ## 3.14.1
30
+
31
+ - Bundles Unpoly 3.14.1 for the asset pipeline.
32
+
33
+
34
+ ## 3.14.0
35
+
36
+ - Bundles Unpoly 3.14.0 for the asset pipeline.
37
+
38
+
39
+ ## 3.12.0
40
+
41
+ - Bundles Unpoly 3.12.0 for the asset pipeline.
42
+
43
+
44
+ ## 3.11.0
45
+
46
+ - New `up.layer.open` renders the response in a new overlay, using an [`X-Up-Open-Layer`](https://unpoly.com/api/X-Up-Open-Layer) header. Overlay options like `mode: 'drawer'` can be passed as keyword arguments.
47
+ - New `up.origin_layer.mode`, `up.origin_layer.root?` and `up.origin_layer.overlay?` tell you about the layer that caused the request, using the [`X-Up-Origin-Mode`](https://unpoly.com/api/X-Up-Origin-Mode) header.
48
+ - `up.cache.keep`, `up.cache.expire(false)` and `up.cache.evict(false)` no longer set a response header and print a deprecation warning. The server can no longer prevent the client-side cache from being expired or evicted.
49
+ - Bundles Unpoly 3.11.0 for the asset pipeline.
50
+
51
+
52
+ ## 3.10.2
53
+
54
+ - Bundles Unpoly 3.10.2 for the asset pipeline.
55
+
56
+
57
+ ## 3.10.0
58
+
59
+ - No longer send empty response headers like `X-Up-Events: []`.
60
+ - When redirecting, no longer add empty params like `_up_context_changes=%7B%7D` or `_up_events=%5B%5D` to the redirect URL.
61
+ - Bundles Unpoly 3.10.0 for the asset pipeline.
62
+
63
+
64
+ ## 3.9.5
65
+
66
+ - Bundles Unpoly 3.9.5 for the asset pipeline.
67
+
68
+
69
+ ## 3.9.3.1
70
+
71
+ - Preserve an `X-Up-Target` changed by the server through a redirect. The original target, which the browser re-sends with the redirected request, no longer overrides it.
72
+
73
+
74
+ ## 3.9.3
75
+
76
+ - Bundles Unpoly 3.9.3 for the asset pipeline.
77
+
78
+
79
+ ## 3.9.2.1
80
+
81
+ - Ignore nested values in `_up_*` params (e.g. `_up_context_changes[foo]=bar`) instead of raising an error. These are often sent by security scanners. The value is logged as an error.
82
+
83
+
84
+ ## 3.9.2
85
+
86
+ - Bundles Unpoly 3.9.2 for the asset pipeline.
87
+
88
+
89
+ ## 3.9.1
90
+
91
+ - Bundles Unpoly 3.9.1 for the asset pipeline.
92
+
93
+
94
+ ## 3.9.0
95
+
96
+ - Bundles Unpoly 3.9.0 for the asset pipeline.
97
+
98
+
99
+ ## 3.8.0.1
100
+
101
+ - Loading the gem no longer loads `ActionController::Base` early, before your app's configuration is applied. The controller extensions are now added with `ActiveSupport.on_load(:action_controller_base)`.
102
+
103
+
104
+ ## 3.8.0
105
+
106
+ - Bundles Unpoly 3.8.0 for the asset pipeline.
107
+
108
+
109
+ ## 3.7.3.2
110
+
111
+ - `up.target?` now returns `true` for optional targets, e.g. when the request targets `#foo:maybe` and you test for `#foo`.
112
+
113
+
114
+ ## 3.7.3.1
115
+
116
+ - When an `X-Up-*` header that should contain a JSON object contains another JSON value (like an array or a string), log an error and use an empty hash.
117
+
118
+
119
+ ## 3.7.3
120
+
121
+ - Bundles Unpoly 3.7.3 for the asset pipeline.
122
+
123
+
124
+ ## 3.7.2
125
+
126
+ - Bundles Unpoly 3.7.2 for the asset pipeline.
127
+
128
+
129
+ ## 3.7.1
130
+
131
+ - Bundles Unpoly 3.7.1 for the asset pipeline.
132
+
133
+
134
+ ## 3.7.0.1
135
+
136
+ - Re-release of 3.7.0 without changes, to make RubyGems redistribute the gem.
137
+
138
+
139
+ ## 3.7.0
140
+
141
+ - Bundles Unpoly 3.7.0 for the asset pipeline.
142
+
143
+
144
+ ## 3.6.1.1
145
+
146
+ - Parse `X-Up-Target` and `Vary` headers without a regular expression that could be slow for long header values.
147
+
148
+
149
+ ## 3.6.1
150
+
151
+ - Bundles Unpoly 3.6.1 for the asset pipeline.
152
+
153
+
154
+ ## 3.6.0
155
+
156
+ - Fix an error for requests whose URL contains `_up_` in its path, but has no query string.
157
+ - Bundles Unpoly 3.6.0 for the asset pipeline.
158
+
159
+
160
+ ## 3.5.2
161
+
162
+ - Bundles Unpoly 3.5.2 for the asset pipeline.
163
+
164
+
165
+ ## 3.5.1
166
+
167
+ - Bundles Unpoly 3.5.1 for the asset pipeline.
168
+
169
+
170
+ ## 3.5.0
171
+
172
+ - Bundles Unpoly 3.5.0 for the asset pipeline.
173
+
174
+
175
+ ## 3.3.0.1
176
+
177
+ - Malformed JSON in `X-Up-*` headers no longer raises an error. It is logged as an error and ignored. Security scanners often send such headers.
178
+
179
+
180
+ ## 3.3.0
181
+
182
+ - Bundles Unpoly 3.3.0 for the asset pipeline.
183
+
184
+
185
+ ## 3.2.2.1
186
+
187
+ - New `up.validate_name?('email')` tests whether a given field is being [validated](https://unpoly.com/api/X-Up-Validate).
188
+ - Fix `up.validate_name` raising a `NameError` (broken since 3.0.0).
189
+
190
+
191
+ ## 3.2.2
192
+
193
+ - Bundles Unpoly 3.2.2 for the asset pipeline.
194
+
195
+
196
+ ## 3.2.1
197
+
198
+ - Bundles Unpoly 3.2.1 for the asset pipeline.
199
+
200
+
201
+ ## 3.2.0
202
+
203
+ - Bundles Unpoly 3.2.0 for the asset pipeline.
204
+
205
+
206
+ ## 3.1.1
207
+
208
+ - Bundles Unpoly 3.1.1 for the asset pipeline.
209
+
210
+
211
+ ## 3.1.0
212
+
213
+ - Bundles Unpoly 3.1.0 for the asset pipeline.
214
+
215
+
216
+ ## 3.0.0
217
+
218
+ - New `up.validate_names` returns the names of all fields that triggered a [validation](https://unpoly.com/api/X-Up-Validate). Unpoly 3 may batch multiple validations into a single request.
219
+ - Removed `up.validate`. Use `up.validate_name` or `up.validate_names` instead.
220
+ - New `up.cache.expire` and `up.cache.evict` control the client-side cache, using the [`X-Up-Expire-Cache`](https://unpoly.com/api/X-Up-Expire-Cache) and [`X-Up-Evict-Cache`](https://unpoly.com/api/X-Up-Evict-Cache) headers. Expired pages can still be rendered and are then revalidated. Evicted pages are erased from the cache.
221
+ - Deprecated `up.cache.clear`. Use `up.cache.expire` instead.
222
+ - Deprecated `up.cache.keep`. Use `up.cache.expire(false)` instead.
223
+ - Reading an Unpoly request header through a helper like `up.target` or `up.layer.mode` now adds that header to the `Vary` response header. To read a header without setting `Vary`, e.g. for logging, wrap your code in an `up.no_vary { ... }` block.
224
+ - Deprecated `up.render_nothing`. Use `head(:no_content)` instead. `up.render_nothing` now responds with `204 No Content` by default.
225
+ - Deprecated `up.reload?` and `up.reload_from_time`. Unpoly sends standard `If-Modified-Since` and `If-None-Match` headers when reloading a fragment, so you can use Rails' conditional GET helpers like `fresh_when` or `stale?`.
226
+ - `X-Up-Title` is now sent as a JSON-encoded string, so non-ASCII characters can be escaped.
227
+ - When redirecting, only headers set by the server (like events, context changes, cache commands or a changed target) are preserved as `_up_*` params. Request headers set by Unpoly are re-sent by the browser.
228
+ - Includes the fixes from 2.7.1.1 to 2.7.2.2.
229
+ - Bundles Unpoly 3.0.0 for the asset pipeline.
230
+
231
+
232
+ ## 2.7.2.2
233
+
234
+ - Only send an `X-Up-Location` header when the request URL contains `_up_*` params that must be removed.
235
+
236
+
237
+ ## 2.7.2.1
238
+
239
+ - Escape non-ASCII characters in JSON response headers like `X-Up-Events`, `X-Up-Context` or `X-Up-Accept-Layer`, so they can be transported over HTTP.
240
+
241
+
242
+ ## 2.7.2
243
+
244
+ - Bundles Unpoly 2.7.2 for the asset pipeline.
245
+
246
+
247
+ ## 2.7.1.1
248
+
249
+ - Fix the serialization of array params (like `ids[]=1&ids[]=2`) in the `X-Up-Location` header.
250
+
251
+
252
+ ## 2.7.1
253
+
254
+ - Bundles Unpoly 2.7.1 for the asset pipeline.
255
+
256
+
257
+ ## 2.7.0
258
+
259
+ - Bundles Unpoly 2.7.0 for the asset pipeline.
260
+
261
+
262
+ ## 2.6.1
263
+
264
+ - Bundles Unpoly 2.6.1 for the asset pipeline.
265
+
266
+
267
+ ## 2.6.0
268
+
269
+ - Bundles Unpoly 2.6.0 for the asset pipeline.
270
+
271
+
272
+ ## 2.5.3
273
+
274
+ - Bundles Unpoly 2.5.3 for the asset pipeline.
275
+
276
+
277
+ ## 2.5.2
278
+
279
+ - Bundles Unpoly 2.5.2 for the asset pipeline.
280
+
281
+
282
+ ## 2.5.1
283
+
284
+ - Bundles Unpoly 2.5.1 for the asset pipeline.
285
+
286
+
287
+ ## 2.5.0
288
+
289
+ - Bundles Unpoly 2.5.0 for the asset pipeline.
290
+
291
+
292
+ ## 2.4.1
293
+
294
+ - Bundles Unpoly 2.4.1 for the asset pipeline.
295
+
296
+
297
+ ## 2.4.0
298
+
299
+ - Bundles Unpoly 2.4.0 for the asset pipeline.
300
+
301
+
302
+ ## 2.3.0
303
+
304
+ - New `up.safe_callback` helper prefixes a JavaScript callback with the response's CSP nonce. This lets callback attributes like `[up-on-loaded]` run with a [strict Content Security Policy](https://unpoly.com/learn/script-security).
305
+ - Bundles Unpoly 2.3.0 for the asset pipeline.
306
+
307
+
308
+ ## 2.2.1
309
+
310
+ - Bundles Unpoly 2.2.1 for the asset pipeline.
311
+
312
+
313
+ ## 2.2.0
314
+
315
+ - First release from the separate unpoly-rails repository.
316
+ - Supports Rails 3.2 again. Version 2.1.0 required Rails 4.2.
317
+ - Bundles Unpoly 2.2.0 for the asset pipeline.
data/README.md CHANGED
@@ -1,11 +1,11 @@
1
1
  unpoly-rails: Ruby on Rails bindings for Unpoly
2
2
  ===============================================
3
3
 
4
- [Unpoly](https://unpoly.com) is an [unobtrusive JavaScript](https://en.wikipedia.org/wiki/Unobtrusive_JavaScript) framework for server-side web applications.
4
+ [Unpoly](https://unpoly.com) is the missing application layer for HTML. It expands what links, forms and server-rendered pages can do, while your application stays on the server.
5
5
 
6
- The `unpoly-rails` gem helps integrating Unpoly with [Ruby on Rails](https://rubyonrails.org/) applications.
6
+ The `unpoly-rails` gem helps you integrate Unpoly with [Ruby on Rails](https://rubyonrails.org/) applications.
7
7
 
8
- This branch tracks the next major version, Unpoly **3.x**.\
8
+ This branch is for Unpoly **3.x**.\
9
9
  If you're using Unpoly **2.x**, use the [`2.x-stable`](https://github.com/unpoly/unpoly-rails/tree/2.x-stable) branch.\
10
10
  If you're using Unpoly **1.x** or **0.x**, use the [`1.x-stable`](https://github.com/unpoly/unpoly/tree/1.x-stable/lib/unpoly/rails) branch in the [`unpoly`](https://github.com/unpoly/unpoly-rails/tree/2.x-stable) repository.
11
11
 
@@ -27,7 +27,7 @@ Installing frontend assets
27
27
 
28
28
  ### With npm
29
29
 
30
- If you're using a build tool like [esbuild](https://esbuild.github.io/) or [Webpacker](https://edgeguides.rubyonrails.org/webpacker.html), install the [`unpoly` npm package](https://unpoly.com/install/npm) to get Unpoly's frontend files.
30
+ If you're using a build tool like [esbuild](https://esbuild.github.io/) or [Webpacker](https://edgeguides.rubyonrails.org/webpacker.html), install the [`unpoly` npm package](https://unpoly.com/learn/install#npm) to get Unpoly's frontend files.
31
31
 
32
32
  Now `import` Unpoly from your `application.js` pack:
33
33
 
@@ -36,7 +36,7 @@ import 'unpoly/unpoly.js'
36
36
  import 'unpoly/unpoly.css'
37
37
  ```
38
38
 
39
- You may need to import [additional files](https://unpoly.com/install), e.g. when migrating from an old Unpoly version.
39
+ You may need to import [additional files](https://unpoly.com/learn/install), e.g. when migrating from an old Unpoly version.
40
40
 
41
41
 
42
42
  ### With the Asset Pipeline
@@ -57,24 +57,24 @@ Also add the following line to your `application.css` manifest:
57
57
  */
58
58
  ```
59
59
 
60
- You may need to require [additional files](https://unpoly.com/install), e.g. when migrating from an old Unpoly version.
60
+ You may need to require [additional files](https://unpoly.com/learn/install), e.g. when migrating from an old Unpoly version.
61
61
 
62
62
 
63
63
  Server protocol helpers
64
64
  -----------------------
65
65
 
66
- This `unpoly-rails` gem implements the <a href="https://unpoly.com/up.protocol">optional server protocol</a> by providing the following helper methods to your controllers, views and helpers.
66
+ This `unpoly-rails` gem implements the <a href="https://unpoly.com/api/up.protocol">optional server protocol</a> by providing the following helper methods to your controllers, views and helpers.
67
67
 
68
68
 
69
69
  ### Detecting a fragment update
70
70
 
71
- Use `up?` to test whether the current request is a [fragment update](https://unpoly.com/up.link):
71
+ Use `up?` to test whether the current request is a [fragment update](https://unpoly.com/api/up.link):
72
72
 
73
73
  ```ruby
74
74
  up? # => true or false
75
75
  ```
76
76
 
77
- To retrieve the CSS selector that is being [updated](https://unpoly.com/up.link), use `up.target`:
77
+ To retrieve the CSS selector that is being [updated](https://unpoly.com/api/up.link), use `up.target`:
78
78
 
79
79
  ```ruby
80
80
  up.target # => '.content'
@@ -158,7 +158,7 @@ class UsersController < ApplicationController
158
158
  end
159
159
  ```
160
160
 
161
- If you wish to emit an event on the current [layer](https://unpoly.com/up.layer)
161
+ If you wish to emit an event on the current [layer](https://unpoly.com/api/up.layer)
162
162
  instead of the `document`, use `up.layer.emit`:
163
163
 
164
164
  ```ruby
@@ -174,7 +174,7 @@ end
174
174
 
175
175
  ### Detecting an Unpoly form validation
176
176
 
177
- To test whether the current request is a [form validation](https://unpoly.com/input-up-validate):
177
+ To test whether the current request is a [form validation](https://unpoly.com/api/up-validate):
178
178
 
179
179
  ```ruby
180
180
  up.validate?
@@ -201,7 +201,7 @@ class UsersController < ApplicationController
201
201
  end
202
202
  ```
203
203
 
204
- You may also access the [names of the fields that triggered the validation request](https://unpoly.com/X-Up-Validate):
204
+ You may also access the [names of the fields that triggered the validation request](https://unpoly.com/api/X-Up-Validate):
205
205
 
206
206
  ```ruby
207
207
  up.validate_names # => ['email', 'password']
@@ -216,7 +216,7 @@ up.validate_name?('email') # => true
216
216
 
217
217
  ### Detecting a fragment reload
218
218
 
219
- When Unpoly [reloads](https://unpoly.com/up.reload) or [polls](https://unpoly.com/up-poll) a fragment, the server will often render the same HTML. You can configure your controller actions to only render HTML if the underlying content changed since an earlier request.
219
+ When Unpoly [reloads](https://unpoly.com/api/up.reload) or [polls](https://unpoly.com/api/up-poll) a fragment, the server will often render the same HTML. You can configure your controller actions to only render HTML if the underlying content changed since an earlier request.
220
220
 
221
221
  Only rendering when needed saves <b>CPU time</b> on your server, which spends most of its response time rendering HTML. This also reduces the <b>bandwidth cost</b> for a request/response exchange to **~1 KB**.
222
222
 
@@ -244,7 +244,7 @@ end
244
244
 
245
245
  ### Allowing callbacks with a strict CSP
246
246
 
247
- When your Content Security Policy disallows `eval()`, Unpoly cannot directly run callbacks HTML attributes. This affects `[up-]` attributes like `[up-on-loaded]` or `[up-on-accepted]`. See [Unpoly's CSP guide](https://unpoly.com/csp) for details.
247
+ When your Content Security Policy disallows `eval()`, Unpoly cannot directly run callbacks HTML attributes. This affects `[up-]` attributes like `[up-on-loaded]` or `[up-on-accepted]`. See [Unpoly's CSP guide](https://unpoly.com/learn/script-security) for details.
248
248
 
249
249
  The following callback would crash the fragment update with an error like `Uncaught EvalError: call to Function() blocked by CSP`:
250
250
 
@@ -278,7 +278,7 @@ Note that fragment updates may target different layers for successful (HTTP stat
278
278
 
279
279
  #### `up.layer.mode`
280
280
 
281
- Returns the [mode](https://unpoly.com/up.layer.mode) of the targeted layer (e.g. `"root"` or `"modal"`).
281
+ Returns the [mode](https://unpoly.com/api/up.layer.mode) of the targeted layer (e.g. `"root"` or `"modal"`).
282
282
 
283
283
  #### `up.layer.root?`
284
284
 
@@ -290,12 +290,12 @@ Returns whether the targeted layer is an overlay (not the root layer).
290
290
 
291
291
  #### `up.layer.context`
292
292
 
293
- Returns the [context](https://unpoly.com/up.context) object of the targeted layer.
293
+ Returns the [context](https://unpoly.com/api/up.context) object of the targeted layer.
294
294
  See documentation for `up.context`, which is an alias for `up.layer.context`.
295
295
 
296
296
  #### `up.layer.accept(value)`
297
297
 
298
- [Accepts](https://unpoly.com/up.layer.accept) the current overlay.
298
+ [Accepts](https://unpoly.com/api/up.layer.accept) the current overlay.
299
299
 
300
300
  Does nothing if the root layer is targeted.
301
301
 
@@ -304,7 +304,7 @@ Your action should either call `up.render_nothing` or respond with `text/html` c
304
304
 
305
305
  #### `up.layer.dismiss(value)`
306
306
 
307
- [Dismisses](https://unpoly.com/up.layer.dismisses) the current overlay.
307
+ [Dismisses](https://unpoly.com/api/up.layer.dismiss) the current overlay.
308
308
 
309
309
  Does nothing if the root layer is targeted.
310
310
 
@@ -313,11 +313,11 @@ Your action should either call `up.render_nothing` or respond with `text/html` c
313
313
 
314
314
  #### `up.layer.emit(type, options)`
315
315
 
316
- [Emits an event](https://unpoly.com/up.layer.emit) on the targeted layer.
316
+ [Emits an event](https://unpoly.com/api/up.layer.emit) on the targeted layer.
317
317
 
318
318
  #### `up.fail_layer.mode`
319
319
 
320
- Returns the [mode](https://unpoly.com/up.layer.mode) of the layer targeted for a failed response.
320
+ Returns the [mode](https://unpoly.com/api/up.layer.mode) of the layer targeted for a failed response.
321
321
 
322
322
  #### `up.fail_layer.root?`
323
323
 
@@ -329,11 +329,11 @@ Returns whether the layer targeted for a failed response is an overlay.
329
329
 
330
330
  #### `up.fail_layer.context`
331
331
 
332
- Returns the [context](https://unpoly.com/up.context) object of the layer targeted for a failed response.
332
+ Returns the [context](https://unpoly.com/api/up.context) object of the layer targeted for a failed response.
333
333
 
334
334
  #### `up.origin_layer.mode`
335
335
 
336
- Returns the [mode](https://unpoly.com/up.layer.mode) of the layer that caused the request.
336
+ Returns the [mode](https://unpoly.com/api/up.layer.mode) of the layer that caused the request.
337
337
 
338
338
  #### `up.origin_layer.root?`
339
339
 
@@ -346,40 +346,57 @@ Returns whether the layer that caused the request is an overlay.
346
346
 
347
347
  ### Opening a new overlay
348
348
 
349
- You can request the frontend to [render your response in a new overlay](https://unpoly.com/X-Up-Open-Layer):
349
+ You can request the frontend to [render your response in a new overlay](https://unpoly.com/api/X-Up-Open-Layer):
350
350
 
351
351
  ```ruby
352
352
  up.layer.open
353
353
  ```
354
354
 
355
355
  This will discard the [initial request target](#detecting-a-fragment-update)
356
- and render your response into [`:main`](https://unpoly.com/main). You can pass an explicit
356
+ and render your response into [`:main`](https://unpoly.com/api/main). You can pass an explicit
357
357
  target as a `:target` option:
358
358
 
359
359
  ```ruby
360
360
  up.layer.open(target: '#overlay')
361
361
  ```
362
362
 
363
- Any [visual layer options](https://unpoly.com/customizing-overlays) can be also be passed as keyword arguments:
363
+ Any [visual layer options](https://unpoly.com/learn/customizing-overlays) can also be passed as keyword arguments:
364
364
 
365
365
 
366
366
  ```ruby
367
367
  up.layer.open(mode: 'drawer', position: 'right')
368
368
  ```
369
369
 
370
+ To run code when the overlay is accepted, pass a [callback](https://unpoly.com/api/X-Up-Open-Layer#callbacks) as a string of JavaScript.
371
+ Wrap it in [`up.safe_callback`](#allowing-callbacks-with-a-strict-csp) so it also runs with a strict CSP:
372
+
373
+ ```ruby
374
+ up.layer.open(on_accepted: up.safe_callback("up.reload('.company-list')"))
375
+ ```
376
+
377
+ To only reload an element after the overlay is accepted, pass its selector as `:on_accepted_reload`.
378
+ This runs no JavaScript, so it needs no `up.safe_callback`:
379
+
380
+ ```ruby
381
+ up.layer.open(on_accepted_reload: '.company-list')
382
+ ```
383
+
384
+ Option names are converted to Unpoly's camelCase names, e.g. `:on_accepted_reload` becomes `onAcceptedReload`.
385
+ Keys inside the `:context` option are passed through unchanged.
386
+
370
387
 
371
388
  ### Expiring the client-side cache
372
389
 
373
- The Unpoly frontend [caches server responses](https://unpoly.com/caching) for a few minutes, making requests to these URLs return instantly.
374
- Only `GET` requests are cached. The entire cache is expired after every non-`GET` request (like `POST` or `PUT`).
390
+ The Unpoly frontend [caches server responses](https://unpoly.com/learn/caching) for a few minutes, making requests to these URLs return instantly.
391
+ Only `GET` requests are cached. When the frontend sends a non-`GET` request (like `POST` or `PUT`), it expires the entire cache.
375
392
 
376
- The server may override these defaults. For instance, the server can expire Unpoly's client-side response cache, even for `GET` requests:
393
+ The server can expire additional cache entries, even after a `GET` request:
377
394
 
378
395
  ```ruby
379
396
  up.cache.expire
380
397
  ```
381
398
 
382
- You may also expire a single URL or [URL pattern](https://unpoly.com/url-patterns):
399
+ You may also expire a single URL or [URL pattern](https://unpoly.com/api/url-patterns):
383
400
 
384
401
  ```ruby
385
402
  up.cache.expire('/notes/*')
@@ -388,9 +405,7 @@ up.cache.expire('/notes/*')
388
405
 
389
406
  ### Evicting pages from the client-side cache
390
407
 
391
- Instead of *expiring* pages from the cache you may also *evict*. The difference is that expired pages can still be rendered instantly and are then [revalidated](/caching#revalidation) with the server. Evicted pages are erased from the cache.
392
-
393
- You may also expire all entries matching an [URL pattern](https://unpoly.com/url-patterns):
408
+ Instead of *expiring* pages from the cache you may also *evict*. The difference is that expired pages can still be rendered instantly and are then [revalidated](https://unpoly.com/learn/caching#revalidation) with the server. Evicted pages are erased from the cache.
394
409
 
395
410
  To evict the entire client-side cache:
396
411
 
@@ -398,7 +413,7 @@ To evict the entire client-side cache:
398
413
  up.cache.evict
399
414
  ```
400
415
 
401
- You may also evict a single URL or [URL pattern](https://unpoly.com/url-patterns):
416
+ You may also evict a single URL or [URL pattern](https://unpoly.com/api/url-patterns):
402
417
 
403
418
  ```ruby
404
419
  up.cache.evict('/notes/*')
@@ -408,12 +423,16 @@ up.cache.evict('/notes/*')
408
423
  ### Unpoly headers are preserved through redirects
409
424
 
410
425
  `unpoly-rails` patches [`redirect_to`](https://api.rubyonrails.org/classes/ActionController/Redirecting.html#method-i-redirect_to)
411
- so [Unpoly-related request and response headers](https://unpoly.com/up.protocol) are preserved for the action you redirect to.
426
+ so [Unpoly-related request and response headers](https://unpoly.com/api/up.protocol) are preserved for the action you redirect to.
427
+
428
+ A `#hash` in the redirect URL is also kept for fragment updates, e.g. `redirect_to post_path(@post, anchor: 'comments')`.
429
+ Unpoly could otherwise not see it, as the browser follows the redirect in the background.
430
+ With Unpoly 3.15 or later, the element with that ID is revealed and the `#hash` shows in the address bar.
412
431
 
413
432
 
414
433
  ### Accessing Unpoly request headers automatically sets a `Vary` response header
415
434
 
416
- Accessing [Unpoly-related request headers](https://unpoly.com/up.protocol) through helper methods like `up.target` will automatically add a [`Vary`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Vary) response header. This is to indicate that the request header influenced the response and the response should be cached separately for each request header value.
435
+ Accessing [Unpoly-related request headers](https://unpoly.com/api/up.protocol) through helper methods like `up.target` will automatically add a [`Vary`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Vary) response header. This is to indicate that the request header influenced the response and the response should be cached separately for each request header value.
417
436
 
418
437
  For example, a controller may access the request's `X-Up-Mode` through the `up.layer.mode` helper:
419
438
 
@@ -467,11 +486,11 @@ The reason for this is that some browsers remember the method of the initial pag
467
486
 
468
487
  ### Working with context
469
488
 
470
- Calling `up.context` will return the [context](https://unpoly.com/up.context) object of the targeted layer.
489
+ Calling `up.context` will return the [context](https://unpoly.com/api/up.context) object of the targeted layer.
471
490
 
472
491
  The context is a JSON object shared between the frontend and the server.
473
492
  It persists for a series of Unpoly navigation, but is cleared when the user makes a full page load.
474
- Different Unpoly [layers](https://unpoly.com/up.layer) will usually have separate context objects,
493
+ Different Unpoly [layers](https://unpoly.com/api/up.layer) will usually have separate context objects,
475
494
  although layers may choose to share their context scope.
476
495
 
477
496
  You may read and change the context object. Changes will be sent to the frontend with your response.
@@ -516,7 +535,7 @@ What you still need to do manually
516
535
 
517
536
  ### Failed form submissions must return a non-200 status code
518
537
 
519
- Unpoly lets you submit forms via AJAX by using the [`form[up-submit]`](https://unpoly.com/form-up-submit) selector or [`up.submit()`](https://unpoly.com/up.submit) function.
538
+ Unpoly lets you submit forms via AJAX by using the [`form[up-submit]`](https://unpoly.com/api/up-submit) selector or [`up.submit()`](https://unpoly.com/api/up.submit) function.
520
539
 
521
540
  For Unpoly to be able to detect a failed form submission,
522
541
  the form must be re-rendered with a non-200 HTTP status code.
@@ -549,13 +568,15 @@ Before you create a pull request, please have some discussion about the proposed
549
568
 
550
569
  ### Running tests
551
570
 
552
- - Install the Ruby version from `.ruby-version` (currently 2.3.8)
553
- - Install Bundler by running `gem install bundler`
571
+ - Install the Ruby version from `.ruby-version` (currently 3.4.12)
572
+ - Install the Bundler version from `Gemfile.lock` by running `gem install bundler -v 2.6.9` (Ruby 3.4 already ships with it)
554
573
  - Install dependencies by running `bundle install`
555
574
  - Run `bundle exec rspec`
556
575
 
557
576
  The tests run against a minimal Rails app that lives in `spec/dummy`.
558
577
 
578
+ GitHub Actions runs the tests on every push and pull request (see `.github/workflows/test.yml`).
579
+
559
580
  ### Making a new release
560
581
 
561
582
  Install the `unpoly-rails` and [`unpoly`](https://github.com/unpoly/unpoly) repositories into the same parent folder:
@@ -0,0 +1 @@
1
+ {"version":3,"file":"unpoly-bootstrap3.css","mappings":"AAGE;;;;;;EAEE;EACA;EACA;AAEJ,C","sources":["webpack://unpoly/./src/unpoly-bootstrap3.sass"],"sourcesContent":["up-modal,\nup-drawer,\nup-popup\n .container,\n .container-fluid\n padding-left: 0 // the overlay box already has a padding\n padding-right: 0 // the overlay box already has a padding\n max-width: none // the overlay box already as a max-width\n"],"names":[],"sourceRoot":""}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"unpoly-bootstrap3.js","mappings":";;;;;;;;AAAA;;;;;;UCAA;UACA;;UAEA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;;UAEA;UACA;;UAEA;UACA;UACA;;;;;WCtBA;WACA;WACA;WACA,uDAAuD,iBAAiB;WACxE;WACA,gDAAgD,aAAa;WAC7D,E;;;;;;;ACLA,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,cAAc,CAAC,IAAI,CAAC,QAAQ,CAAC;AAG9C,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC,QAAQ,CAAC;AAE7C,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,MAAM,EAAE,SAAS,CAAC;AAErD,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC,OAAO,CAAC,aAAa,CAAC;AAEpD,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,iBAAiB,CAAC,IAAI,CAAC,mBAAmB,CAAC;AAC9D,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,oBAAoB,CAAC,IAAI,CAAC,sBAAsB,CAAC;AACpE,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,sBAAsB,CAAC,IAAI,CAAC,mBAAmB,EAAE,sBAAsB,CAAC;AAE3F,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,gBAAgB,CAAC,IAAI,CACtC,KAAK,EACL,gCAAgC,CACjC;AAED,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,uBAAuB,CAAC,IAAI,CAC1C,sBAAsB,EACtB,wBAAwB,EACxB,8BAA8B,CAC/B;AAED,mBAAO,CAAC,CAA0B,CAAC","sources":["webpack://unpoly/./src/unpoly-bootstrap3.sass?1785","webpack://unpoly/webpack/bootstrap","webpack://unpoly/webpack/runtime/make namespace object","webpack://unpoly/./src/unpoly-bootstrap3.js"],"sourcesContent":["// extracted by mini-css-extract-plugin\nexport {};","// The module cache\nvar __webpack_module_cache__ = {};\n\n// The require function\nfunction __webpack_require__(moduleId) {\n\t// Check if module is in cache\n\tvar cachedModule = __webpack_module_cache__[moduleId];\n\tif (cachedModule !== undefined) {\n\t\treturn cachedModule.exports;\n\t}\n\t// Create a new module (and put it into the cache)\n\tvar module = __webpack_module_cache__[moduleId] = {\n\t\t// no module.id needed\n\t\t// no module.loaded needed\n\t\texports: {}\n\t};\n\n\t// Execute the module function\n\t__webpack_modules__[moduleId](module, module.exports, __webpack_require__);\n\n\t// Return the exports of the module\n\treturn module.exports;\n}\n\n","// define __esModule on exports\n__webpack_require__.r = (exports) => {\n\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n\t}\n\tObject.defineProperty(exports, '__esModule', { value: true });\n};","// Bootstrap uses the class `active` to highlight the current section of a navigation bar.\nup.status.config.currentClasses.push('active')\n\n// Bootstrap uses the class `active` to force a button's active state.\nup.status.config.activeClasses.push('active')\n\nup.status.config.navSelectors.push('.nav', '.navbar')\n\nup.form.config.groupSelectors.unshift('.form-group')\n\nup.viewport.config.fixedTopSelectors.push('.navbar-fixed-top')\nup.viewport.config.fixedBottomSelectors.push('.navbar-fixed-bottom')\nup.viewport.config.anchoredRightSelectors.push('.navbar-fixed-top', '.navbar-fixed-bottom')\n\nup.fragment.config.badTargetClasses.push(\n 'row',\n /^col(-xs|-sm|-md|-lg)?(-\\d+)?$/\n)\n\nup.layer.config.foreignOverlaySelectors.push(\n '.modal:not(up-modal)',\n '.popover:not(up-popup)',\n '.dropdown-menu:not(up-popup)'\n)\n\nrequire('./unpoly-bootstrap3.sass')\n"],"names":[],"sourceRoot":""}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"unpoly-bootstrap3.min.css","mappings":"AAGE,4IAEE,eACA,gBACA,e","sources":["webpack://unpoly/./src/unpoly-bootstrap3.sass"],"sourcesContent":["up-modal,\nup-drawer,\nup-popup\n .container,\n .container-fluid\n padding-left: 0 // the overlay box already has a padding\n padding-right: 0 // the overlay box already has a padding\n max-width: none // the overlay box already as a max-width\n"],"names":[],"sourceRoot":""}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"unpoly-bootstrap3.min.js","mappings":"8CACIA,EAA2B,CAAC,EAGhC,SAASC,EAAoBC,GAE5B,IAAIC,EAAeH,EAAyBE,GAC5C,QAAqBE,IAAjBD,EACH,OAAOA,EAAaE,QAGrB,IAAIC,EAASN,EAAyBE,GAAY,CAGjDG,QAAS,CAAC,GAOX,OAHAE,EAAoBL,GAAUI,EAAQA,EAAOD,QAASJ,GAG/CK,EAAOD,OACf,CCrBAJ,EAAoBO,EAAKH,IACH,oBAAXI,QAA0BA,OAAOC,aAC1CC,OAAOC,eAAeP,EAASI,OAAOC,YAAa,CAAEG,MAAO,WAE7DF,OAAOC,eAAeP,EAAS,IAAc,CAAEQ,OAAO,KCJvDC,GAAGC,OAAOC,OAAOC,eAAeC,KAAK,UAGrCJ,GAAGC,OAAOC,OAAOG,cAAcD,KAAK,UAEpCJ,GAAGC,OAAOC,OAAOI,aAAaF,KAAK,OAAQ,WAE3CJ,GAAGO,KAAKL,OAAOM,eAAeC,QAAQ,eAEtCT,GAAGU,SAASR,OAAOS,kBAAkBP,KAAK,qBAC1CJ,GAAGU,SAASR,OAAOU,qBAAqBR,KAAK,wBAC7CJ,GAAGU,SAASR,OAAOW,uBAAuBT,KAAK,oBAAqB,wBAEpEJ,GAAGc,SAASZ,OAAOa,iBAAiBX,KAClC,MACA,kCAGFJ,GAAGgB,MAAMd,OAAOe,wBAAwBb,KACtC,uBACA,yBACA,gCAGF,EAAQ,I","sources":["webpack://unpoly/webpack/bootstrap","webpack://unpoly/webpack/runtime/make namespace object","webpack://unpoly/./src/unpoly-bootstrap3.js"],"sourcesContent":["// The module cache\nvar __webpack_module_cache__ = {};\n\n// The require function\nfunction __webpack_require__(moduleId) {\n\t// Check if module is in cache\n\tvar cachedModule = __webpack_module_cache__[moduleId];\n\tif (cachedModule !== undefined) {\n\t\treturn cachedModule.exports;\n\t}\n\t// Create a new module (and put it into the cache)\n\tvar module = __webpack_module_cache__[moduleId] = {\n\t\t// no module.id needed\n\t\t// no module.loaded needed\n\t\texports: {}\n\t};\n\n\t// Execute the module function\n\t__webpack_modules__[moduleId](module, module.exports, __webpack_require__);\n\n\t// Return the exports of the module\n\treturn module.exports;\n}\n\n","// define __esModule on exports\n__webpack_require__.r = (exports) => {\n\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n\t}\n\tObject.defineProperty(exports, '__esModule', { value: true });\n};","// Bootstrap uses the class `active` to highlight the current section of a navigation bar.\nup.status.config.currentClasses.push('active')\n\n// Bootstrap uses the class `active` to force a button's active state.\nup.status.config.activeClasses.push('active')\n\nup.status.config.navSelectors.push('.nav', '.navbar')\n\nup.form.config.groupSelectors.unshift('.form-group')\n\nup.viewport.config.fixedTopSelectors.push('.navbar-fixed-top')\nup.viewport.config.fixedBottomSelectors.push('.navbar-fixed-bottom')\nup.viewport.config.anchoredRightSelectors.push('.navbar-fixed-top', '.navbar-fixed-bottom')\n\nup.fragment.config.badTargetClasses.push(\n 'row',\n /^col(-xs|-sm|-md|-lg)?(-\\d+)?$/\n)\n\nup.layer.config.foreignOverlaySelectors.push(\n '.modal:not(up-modal)',\n '.popover:not(up-popup)',\n '.dropdown-menu:not(up-popup)'\n)\n\nrequire('./unpoly-bootstrap3.sass')\n"],"names":["__webpack_module_cache__","__webpack_require__","moduleId","cachedModule","undefined","exports","module","__webpack_modules__","r","Symbol","toStringTag","Object","defineProperty","value","up","status","config","currentClasses","push","activeClasses","navSelectors","form","groupSelectors","unshift","viewport","fixedTopSelectors","fixedBottomSelectors","anchoredRightSelectors","fragment","badTargetClasses","layer","foreignOverlaySelectors"],"sourceRoot":""}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"unpoly-bootstrap4.css","mappings":"AAGE;;;;;;EAEE;EACA;EACA;AAEJ,C","sources":["webpack://unpoly/./src/unpoly-bootstrap4.sass"],"sourcesContent":["up-modal,\nup-drawer,\nup-popup\n .container,\n .container-fluid\n padding-left: 0 // the overlay box already has a padding\n padding-right: 0 // the overlay box already has a padding\n max-width: none // the overlay box already as a max-width\n"],"names":[],"sourceRoot":""}