htmx 2.3.0 → 2.4.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.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/README.adoc +114 -22
- data/htmx.gemspec +1 -1
- data/lib/htmx/headers/request.rb +16 -24
- data/lib/htmx/headers/response.rb +6 -28
- data/lib/htmx.rb +38 -0
- data.tar.gz.sig +0 -0
- metadata +2 -2
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ee8016cd8fd02737e4aad162cb344f30e3b2b87a86758551ef7eb8af1e95987a
|
4
|
+
data.tar.gz: e8dbf7897d7a0acf0403c8e828aac1934c63f9c95843c0c7a6e81fba458bb393
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b030354b85254e808ae6dd58d87f388a428a2a1997e89912647cf3a0bcdff2335b28dc98b788dfc8aa0b17d415df6957773c1658f8826cfd60c7ffc6f2214024
|
7
|
+
data.tar.gz: bdeed94be9d9ba5c4d794955fbe289616b946eebe531518fcb91a4bbe6dca32eec0fcb64bde9eb77f3c10f51c20ae741d9a49d1b4a270c8a0e8393669110a899
|
checksums.yaml.gz.sig
CHANGED
Binary file
|
data/README.adoc
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
:toclevels: 5
|
3
3
|
:figure-caption!:
|
4
4
|
|
5
|
-
:htmx_link: link:https://htmx.org[
|
5
|
+
:htmx_link: link:https://htmx.org[htmx]
|
6
6
|
:hypermedia_systems_link: link:https://hypermedia.systems[Hypermedia Systems]
|
7
7
|
:hanami_link: link:https://hanamirb.org[Hanami]
|
8
8
|
:roda_link: link:http://roda.jeremyevans.net[Roda]
|
@@ -22,14 +22,12 @@ already in hand
|
|
22
22
|
...and from {hypermedia_systems_link}:
|
23
23
|
|
24
24
|
____
|
25
|
-
The goal of [
|
25
|
+
The goal of [htmx] is not less JavaScript, but less code, more readable and hypermedia-friendly code.
|
26
26
|
____
|
27
27
|
|
28
28
|
|
29
29
|
This gem provides native Ruby support for the {htmx_link} JavaScript library so you can build sophisticated web applications using pure Hypermedia REST APIs while avoiding unnecessary bloat and complexity common with the JavaScript ecosystem. By building upon the original foundations of Hypermedia REST APIs, you can build rich web applications with no additional JavaScript!
|
30
30
|
|
31
|
-
At the moment, the functionality of this gem is still in the early stages of development but the goal of this gem is to aid with the development of {htmx_link} applications.
|
32
|
-
|
33
31
|
💡 This is used with the {hanamismith_link} gem when building {hanami_link} applications. Even better, you can play with the link:https://github.com/bkuhlmann/hemo[Hanami demo application] to learn more. Enjoy!
|
34
32
|
|
35
33
|
toc::[]
|
@@ -80,7 +78,7 @@ require "htmx"
|
|
80
78
|
|
81
79
|
== Usage
|
82
80
|
|
83
|
-
One of the first tasks you'll want to tackle, when working with the {htmx_link} library, is building
|
81
|
+
One of the first tasks you'll want to tackle, when working with the {htmx_link} library, is building htmx specific HTML attributes. This can be accomplished by using the `.[]` method. For example, when implementing a {hanami_link} view part, you could use the following:
|
84
82
|
|
85
83
|
[source,ruby]
|
86
84
|
----
|
@@ -101,11 +99,11 @@ The above would produce the following:
|
|
101
99
|
</button>
|
102
100
|
----
|
103
101
|
|
104
|
-
Notice the appropriate
|
102
|
+
Notice the appropriate htmx `hx-target` and `hx-delete` attributes are built which are compatible with the {htmx_link} library while not having to manually prefix each one of these attributes with the `hx-` prefix. You can use symbols, strings, or a mix of both as well.
|
105
103
|
|
106
104
|
=== HTML Attribute Prefixes
|
107
105
|
|
108
|
-
As shown above, building
|
106
|
+
As shown above, building htmx attributes takes minimal effort but if you'd prefer the HTML `data-` prefix, which the {htmx_link} library supports, you can customize by using the following:
|
109
107
|
|
110
108
|
[source,ruby]
|
111
109
|
----
|
@@ -132,7 +130,7 @@ This would then produce the following HTML code:
|
|
132
130
|
</button>
|
133
131
|
----
|
134
132
|
|
135
|
-
As you can see, the `data-hx-target` and `data-hx-delete` keys are used. These are definitely more verbose than the `hx-` keys. By the way, the `HTMX::Prefixer` is called when using the
|
133
|
+
As you can see, the `data-hx-target` and `data-hx-delete` keys are used. These are definitely more verbose than the `hx-` keys. By the way, the `HTMX::Prefixer` is called when using the htmx `.[]` as shown earlier. This means the following are equivalent:
|
136
134
|
|
137
135
|
[source,ruby]
|
138
136
|
----
|
@@ -151,7 +149,7 @@ HTMX::Prefixer.new "bogus"
|
|
151
149
|
# Invalid prefix: "bogus". Use: "hx" or "data-hx". (HTMX::Error)
|
152
150
|
----
|
153
151
|
|
154
|
-
Some {htmx_link} attributes use dashes. For those situations, you can use strings for keys or underscored symbols to produce the correct
|
152
|
+
Some {htmx_link} attributes use dashes. For those situations, you can use strings for keys or underscored symbols to produce the correct htmx syntax. Here's an example using both a string and symbol for keys:
|
155
153
|
|
156
154
|
[source,ruby]
|
157
155
|
----
|
@@ -161,15 +159,15 @@ HTMX["swap-oob" => true, push_url: "/demo/123"]
|
|
161
159
|
|
162
160
|
=== HTTP Headers
|
163
161
|
|
164
|
-
When working with HTTP requests/responses, especially HTTP headers, there are a
|
162
|
+
When working with HTTP requests/responses, especially HTTP headers, there are a couple of methods that can parse and make the data easier to work with. Here's how to use them.
|
165
163
|
|
166
|
-
====
|
164
|
+
==== Requests
|
167
165
|
|
168
|
-
The request object allows you to obtain a {data_link} object to interact with when parsing link:https://htmx.org/reference/#request_headers[
|
166
|
+
The request object allows you to obtain a {data_link} object to interact with when parsing link:https://htmx.org/reference/#request_headers[htmx HTTP request headers]. Example:
|
169
167
|
|
170
168
|
[source,ruby]
|
171
169
|
----
|
172
|
-
HTMX
|
170
|
+
HTMX.request
|
173
171
|
|
174
172
|
# <data HTMX::Headers::Request boosted=nil,
|
175
173
|
# current_url=nil,
|
@@ -186,11 +184,18 @@ Notice you get a {data_link} instance where all members have the `HX-` prefix re
|
|
186
184
|
|
187
185
|
[source,ruby]
|
188
186
|
----
|
189
|
-
HTMX
|
187
|
+
HTMX.request "HTTP_HX_BOOSTED" => "true",
|
188
|
+
"HTTP_HX_CURRENT_URL" => "/demo",
|
189
|
+
"HTTP_HX_HISTORY_RESTORE_REQUEST" => "false",
|
190
|
+
"HTTP_HX_PROMPT" => "Yes",
|
191
|
+
"HTTP_HX_REQUEST" => "true",
|
192
|
+
"HTTP_HX_TARGET" => "demo",
|
193
|
+
"HTTP_HX_TRIGGER_NAME" => "save",
|
194
|
+
"HTTP_HX_TRIGGER" => "demo"
|
190
195
|
|
191
196
|
# <data HTMX::Headers::Request boosted="true",
|
192
197
|
# current_url="/demo",
|
193
|
-
# history_restore_request=
|
198
|
+
# history_restore_request="false",
|
194
199
|
# prompt="Yes",
|
195
200
|
# request="true",
|
196
201
|
# target="demo",
|
@@ -199,15 +204,60 @@ HTMX::Headers::Request.for request.env
|
|
199
204
|
# >
|
200
205
|
----
|
201
206
|
|
202
|
-
|
207
|
+
As you can see, this method only plucks out the htmx specific headers which may or may not have values. Extra header keys, which are not specific to {htmx_link}, are ignored.
|
208
|
+
|
209
|
+
As an added convenience, you can use predicate methods for boolean values. Example:
|
203
210
|
|
204
|
-
|
211
|
+
[source,ruby]
|
212
|
+
----
|
213
|
+
headers = HTMX.request "HTTP_HX_BOOSTED" => "true",
|
214
|
+
"HTTP_HX_CURRENT_URL" => "/demo",
|
215
|
+
"HTTP_HX_HISTORY_RESTORE_REQUEST" => "false",
|
216
|
+
"HTTP_HX_PROMPT" => "Yes",
|
217
|
+
"HTTP_HX_REQUEST" => "true",
|
218
|
+
"HTTP_HX_TARGET" => "demo",
|
219
|
+
"HTTP_HX_TRIGGER_NAME" => "save",
|
220
|
+
"HTTP_HX_TRIGGER" => "demo"
|
205
221
|
|
206
|
-
|
222
|
+
headers.boosted? # true
|
223
|
+
headers.confirmed? # true
|
224
|
+
headers.history_restore_request? # false
|
225
|
+
headers.request? # true
|
226
|
+
----
|
227
|
+
|
228
|
+
Use of `#confirmed?` is the only unique predicate method since it answers a boolean based on the truthiness of the `HTTP_HX_PROMPT` header. For further details, see `String#truthy?` as provided by the link:https://alchemists.io/projects/refinements#_truthy[Refinements] gem.
|
229
|
+
|
230
|
+
Due to `HTML.request` delegating to the `HTMX::Headers::Request`, this means you can use the object directly. Specifically, you can obtain the record, key, or header depending on your needs. Example:
|
207
231
|
|
208
232
|
[source,ruby]
|
209
233
|
----
|
210
|
-
HTMX::Headers::
|
234
|
+
HTMX::Headers::Request.for(**headers) # Identical to `HTMX.request`.
|
235
|
+
HTMX::Headers::Request.key_for "HTTP_HX_CURRENT_URL" # :current_url
|
236
|
+
HTMX::Headers::Request.header_for :current_url # "HTTP_HX_CURRENT_URL"
|
237
|
+
----
|
238
|
+
|
239
|
+
Should you not want to use `HTMX::Headers::Request`, you can use the request predicate methods instead. Example:
|
240
|
+
|
241
|
+
[source,ruby]
|
242
|
+
----
|
243
|
+
headers = {}
|
244
|
+
|
245
|
+
HTMX.request! headers, boosted: true, prompt: "Yes"
|
246
|
+
# {"HTTP_HX_BOOSTED" => true, "HTTP_HX_PROMPT" => "Yes"}
|
247
|
+
|
248
|
+
HTMX.request? headers, :prompt, "Yes" # true
|
249
|
+
HTMX.request? headers, :prompt, "On" # false
|
250
|
+
----
|
251
|
+
|
252
|
+
💡 `HTMX.request!` is designed to mutate your original headers. Unknown attributes are merged as is.
|
253
|
+
|
254
|
+
==== Responses
|
255
|
+
|
256
|
+
The response object allows you to obtain a {data_link} object to interact with when parsing link:https://htmx.org/reference/#response_headers[htmx HTTP response headers]. Example:
|
257
|
+
|
258
|
+
[source,ruby]
|
259
|
+
----
|
260
|
+
HTMX.response
|
211
261
|
|
212
262
|
# <data HTMX::Headers::Response location=nil,
|
213
263
|
# push_url=nil,
|
@@ -226,7 +276,16 @@ Notice you get a {data_link} instance where all members have the `HX-` prefix re
|
|
226
276
|
|
227
277
|
[source,ruby]
|
228
278
|
----
|
229
|
-
HTMX
|
279
|
+
HTMX.response "HX-Location" => "/",
|
280
|
+
"HX-Push-Url" => "/demo",
|
281
|
+
"HX-Redirect" => "/demo",
|
282
|
+
"HX-Refresh" => "true",
|
283
|
+
"HX-Replace-Url" => "/demo",
|
284
|
+
"HX-Reswap" => "none",
|
285
|
+
"HX-Retarget" => ".demo",
|
286
|
+
"HX-Trigger" => "demo",
|
287
|
+
"HX-Trigger-After-Settle" => "demo",
|
288
|
+
"HX-Trigger-After-Swap" => "demo"
|
230
289
|
|
231
290
|
# <data HTMX::Headers::Response location="/",
|
232
291
|
# push_url="/demo",
|
@@ -241,11 +300,44 @@ HTMX::Headers::Response.for response.headers
|
|
241
300
|
# >
|
242
301
|
----
|
243
302
|
|
244
|
-
|
303
|
+
As you can see, this method only plucks out the htmx specific headers which may or may not have values. Extra header keys, which are not specific to {htmx_link}, are ignored.
|
304
|
+
|
305
|
+
There is also a refresh predicate method that'll answer a boolean for convenience. Example:
|
306
|
+
|
307
|
+
[source,ruby]
|
308
|
+
----
|
309
|
+
headers = HTMX.response "HX-Refresh" => "true"
|
310
|
+
|
311
|
+
headers.refresh? # true
|
312
|
+
----
|
313
|
+
|
314
|
+
Due to `HTML.response` delegating to the `HTMX::Headers::Response`, this means you can use the object directly. Specifically, you can obtain the record, key, or header depending on your needs. Example:
|
315
|
+
|
316
|
+
[source,ruby]
|
317
|
+
----
|
318
|
+
HTMX::Headers::Response.for(**headers) # Identical to `HTMX.response`.
|
319
|
+
HTMX::Headers::Response.key_for "HX-Location" # :location
|
320
|
+
HTMX::Headers::Response.header_for :location # "HX-Location"
|
321
|
+
----
|
322
|
+
|
323
|
+
Should you not want to use `HTMX::Headers::Response`, you can use the response predicate methods instead. Example:
|
324
|
+
|
325
|
+
[source,ruby]
|
326
|
+
----
|
327
|
+
headers = {}
|
328
|
+
|
329
|
+
HTMX.response! headers, location: "/", push_url: "/test"
|
330
|
+
# {"HX-Location" => "/", "HX-Push-Url" => "/test"}
|
331
|
+
|
332
|
+
HTMX.response? headers, :push_url, "/test" # true
|
333
|
+
HTMX.response? headers, :push_url, "/other" # false
|
334
|
+
----
|
335
|
+
|
336
|
+
💡 `HTMX.response!` is designed to mutate your original headers. Unknown attributes are merged as is.
|
245
337
|
|
246
338
|
=== Errors
|
247
339
|
|
248
|
-
|
340
|
+
Any/all errors issued by this gem will be an instance of the `HTMX::Error` class which inherits from `StandardError`. You can use this classification to catch and deal with these errors in your own implementation as desired.
|
249
341
|
|
250
342
|
== Development
|
251
343
|
|
data/htmx.gemspec
CHANGED
data/lib/htmx/headers/request.rb
CHANGED
@@ -1,36 +1,20 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "refinements/string"
|
4
|
+
|
3
5
|
module HTMX
|
4
6
|
module Headers
|
5
|
-
REQUEST_KEY_MAP = {
|
6
|
-
"HTTP_HX_BOOSTED" => :boosted,
|
7
|
-
"HTTP_HX_CURRENT_URL" => :current_url,
|
8
|
-
"HTTP_HX_HISTORY_RESTORE_REQUEST" => :history_restore_request,
|
9
|
-
"HTTP_HX_PROMPT" => :prompt,
|
10
|
-
"HTTP_HX_REQUEST" => :request,
|
11
|
-
"HTTP_HX_TARGET" => :target,
|
12
|
-
"HTTP_HX_TRIGGER_NAME" => :trigger_name,
|
13
|
-
"HTTP_HX_TRIGGER" => :trigger
|
14
|
-
}.freeze
|
15
|
-
|
16
7
|
# Models the supported HTMX request headers.
|
17
|
-
Request = Data.define(
|
18
|
-
|
19
|
-
|
20
|
-
:
|
21
|
-
:prompt,
|
22
|
-
:request,
|
23
|
-
:target,
|
24
|
-
:trigger_name,
|
25
|
-
:trigger
|
26
|
-
) do
|
27
|
-
def self.for(key_map: REQUEST_KEY_MAP, **attributes)
|
8
|
+
Request = Data.define(*REQUEST_MAP.keys) do
|
9
|
+
using Refinements::String
|
10
|
+
|
11
|
+
def self.for(key_map: REQUEST_MAP.invert, **attributes)
|
28
12
|
new(**attributes.slice(*key_map.keys).transform_keys!(key_map))
|
29
13
|
end
|
30
14
|
|
31
|
-
def self.key_for(header, key_map:
|
15
|
+
def self.key_for(header, key_map: REQUEST_MAP.invert) = key_map.fetch header
|
32
16
|
|
33
|
-
def self.header_for(key, key_map:
|
17
|
+
def self.header_for(key, key_map: REQUEST_MAP) = key_map.fetch key
|
34
18
|
|
35
19
|
def initialize boosted: nil,
|
36
20
|
current_url: nil,
|
@@ -42,6 +26,14 @@ module HTMX
|
|
42
26
|
trigger: nil
|
43
27
|
super
|
44
28
|
end
|
29
|
+
|
30
|
+
def boosted? = boosted == "true"
|
31
|
+
|
32
|
+
def confirmed? = prompt ? prompt.truthy? : false
|
33
|
+
|
34
|
+
def history_restore_request? = history_restore_request == "true"
|
35
|
+
|
36
|
+
def request? = request == "true"
|
45
37
|
end
|
46
38
|
end
|
47
39
|
end
|
@@ -2,39 +2,15 @@
|
|
2
2
|
|
3
3
|
module HTMX
|
4
4
|
module Headers
|
5
|
-
RESPONSE_KEY_MAP = {
|
6
|
-
"HX-Location" => :location,
|
7
|
-
"HX-Push-Url" => :push_url,
|
8
|
-
"HX-Redirect" => :redirect,
|
9
|
-
"HX-Refresh" => :refresh,
|
10
|
-
"HX-Replace-Url" => :replace_url,
|
11
|
-
"HX-Reswap" => :reswap,
|
12
|
-
"HX-Retarget" => :retarget,
|
13
|
-
"HX-Trigger" => :trigger,
|
14
|
-
"HX-Trigger-After-Settle" => :trigger_after_settle,
|
15
|
-
"HX-Trigger-After-Swap" => :trigger_after_swap
|
16
|
-
}.freeze
|
17
|
-
|
18
5
|
# Models the supported HTMX response headers.
|
19
|
-
Response = Data.define(
|
20
|
-
:
|
21
|
-
:push_url,
|
22
|
-
:redirect,
|
23
|
-
:refresh,
|
24
|
-
:replace_url,
|
25
|
-
:reswap,
|
26
|
-
:retarget,
|
27
|
-
:trigger,
|
28
|
-
:trigger_after_settle,
|
29
|
-
:trigger_after_swap
|
30
|
-
) do
|
31
|
-
def self.for(key_map: RESPONSE_KEY_MAP, **attributes)
|
6
|
+
Response = Data.define(*RESPONSE_MAP.keys) do
|
7
|
+
def self.for(key_map: RESPONSE_MAP.invert, **attributes)
|
32
8
|
new(**attributes.slice(*key_map.keys).transform_keys!(key_map))
|
33
9
|
end
|
34
10
|
|
35
|
-
def self.key_for(header, key_map:
|
11
|
+
def self.key_for(header, key_map: RESPONSE_MAP.invert) = key_map.fetch header
|
36
12
|
|
37
|
-
def self.header_for(key, key_map:
|
13
|
+
def self.header_for(key, key_map: RESPONSE_MAP) = key_map.fetch key
|
38
14
|
|
39
15
|
def initialize location: nil,
|
40
16
|
push_url: nil,
|
@@ -48,6 +24,8 @@ module HTMX
|
|
48
24
|
trigger_after_swap: nil
|
49
25
|
super
|
50
26
|
end
|
27
|
+
|
28
|
+
def refresh? = refresh == "true"
|
51
29
|
end
|
52
30
|
end
|
53
31
|
end
|
data/lib/htmx.rb
CHANGED
@@ -11,6 +11,30 @@ end
|
|
11
11
|
|
12
12
|
# Main namespace.
|
13
13
|
module HTMX
|
14
|
+
REQUEST_MAP = {
|
15
|
+
boosted: "HTTP_HX_BOOSTED",
|
16
|
+
current_url: "HTTP_HX_CURRENT_URL",
|
17
|
+
history_restore_request: "HTTP_HX_HISTORY_RESTORE_REQUEST",
|
18
|
+
prompt: "HTTP_HX_PROMPT",
|
19
|
+
request: "HTTP_HX_REQUEST",
|
20
|
+
target: "HTTP_HX_TARGET",
|
21
|
+
trigger_name: "HTTP_HX_TRIGGER_NAME",
|
22
|
+
trigger: "HTTP_HX_TRIGGER"
|
23
|
+
}.freeze
|
24
|
+
|
25
|
+
RESPONSE_MAP = {
|
26
|
+
location: "HX-Location",
|
27
|
+
push_url: "HX-Push-Url",
|
28
|
+
redirect: "HX-Redirect",
|
29
|
+
refresh: "HX-Refresh",
|
30
|
+
replace_url: "HX-Replace-Url",
|
31
|
+
reswap: "HX-Reswap",
|
32
|
+
retarget: "HX-Retarget",
|
33
|
+
trigger: "HX-Trigger",
|
34
|
+
trigger_after_settle: "HX-Trigger-After-Settle",
|
35
|
+
trigger_after_swap: "HX-Trigger-After-Swap"
|
36
|
+
}.freeze
|
37
|
+
|
14
38
|
def self.loader registry = Zeitwerk::Registry
|
15
39
|
@loader ||= registry.loaders.each.find { |loader| loader.tag == File.basename(__FILE__, ".rb") }
|
16
40
|
end
|
@@ -19,4 +43,18 @@ module HTMX
|
|
19
43
|
@prefixer ||= Prefixer.new
|
20
44
|
@prefixer.call(...)
|
21
45
|
end
|
46
|
+
|
47
|
+
def self.request(**) = Headers::Request.for(**)
|
48
|
+
|
49
|
+
def self.request!(headers, **attributes) = headers.merge! attributes.transform_keys!(REQUEST_MAP)
|
50
|
+
|
51
|
+
def self.request?(headers, key, value) = headers[REQUEST_MAP[key]] == value
|
52
|
+
|
53
|
+
def self.response(**) = Headers::Response.for(**)
|
54
|
+
|
55
|
+
def self.response!(headers, **attributes)
|
56
|
+
headers.merge! attributes.transform_keys!(RESPONSE_MAP)
|
57
|
+
end
|
58
|
+
|
59
|
+
def self.response?(headers, key, value) = headers[RESPONSE_MAP[key]] == value
|
22
60
|
end
|
data.tar.gz.sig
CHANGED
Binary file
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: htmx
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Brooke Kuhlmann
|
@@ -104,7 +104,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
104
104
|
- !ruby/object:Gem::Version
|
105
105
|
version: '0'
|
106
106
|
requirements: []
|
107
|
-
rubygems_version: 3.
|
107
|
+
rubygems_version: 3.7.1
|
108
108
|
specification_version: 4
|
109
109
|
summary: An augmenter and companion to the HTMX JavaScript library.
|
110
110
|
test_files: []
|
metadata.gz.sig
CHANGED
Binary file
|