Complete doc work; add HxSync module
This commit is contained in:
parent
cede486099
commit
6677892859
@ -25,22 +25,29 @@ let internal toLowerBool (boolValue: bool) =
|
||||
module HxSwap =
|
||||
|
||||
/// <summary>The default, replace the inner HTML of the target element</summary>
|
||||
[<Literal>]
|
||||
let InnerHtml = "innerHTML"
|
||||
|
||||
/// <summary>Replace the entire target element with the response</summary>
|
||||
[<Literal>]
|
||||
let OuterHtml = "outerHTML"
|
||||
|
||||
/// <summary>Insert the response before the target element</summary>
|
||||
[<Literal>]
|
||||
let BeforeBegin = "beforebegin"
|
||||
|
||||
/// <summary>Insert the response before the first child of the target element</summary>
|
||||
[<Literal>]
|
||||
let AfterBegin = "afterbegin"
|
||||
|
||||
/// <summary>Insert the response after the last child of the target element</summary>
|
||||
[<Literal>]
|
||||
let BeforeEnd = "beforeend"
|
||||
|
||||
/// <summary>Insert the response after the target element</summary>
|
||||
[<Literal>]
|
||||
let AfterEnd = "afterend"
|
||||
|
||||
/// <summary>Does not append content from response (out of band items will still be processed).</summary>
|
||||
[<Literal>]
|
||||
let None = "none"
|
||||
|
@ -497,6 +497,32 @@ let hxRequest =
|
||||
]
|
||||
]
|
||||
|
||||
/// Tests for the HxSync module
|
||||
let hxSync =
|
||||
testList "HxSync" [
|
||||
test "Drop is correct" {
|
||||
Expect.equal HxSync.Drop "drop" "Drop is incorrect"
|
||||
}
|
||||
test "Abort is correct" {
|
||||
Expect.equal HxSync.Abort "abort" "Abort is incorrect"
|
||||
}
|
||||
test "Replace is correct" {
|
||||
Expect.equal HxSync.Replace "replace" "Replace is incorrect"
|
||||
}
|
||||
test "Queue is correct" {
|
||||
Expect.equal HxSync.Queue "queue" "Queue is incorrect"
|
||||
}
|
||||
test "QueueFirst is correct" {
|
||||
Expect.equal HxSync.QueueFirst "queue first" "QueueFirst is incorrect"
|
||||
}
|
||||
test "QueueLast is correct" {
|
||||
Expect.equal HxSync.QueueLast "queue last" "QueueLast is incorrect"
|
||||
}
|
||||
test "QueueAll is correct" {
|
||||
Expect.equal HxSync.QueueAll "queue all" "QueueAll is incorrect"
|
||||
}
|
||||
]
|
||||
|
||||
/// Tests for the HxTrigger module
|
||||
let hxTrigger =
|
||||
testList "HxTrigger" [
|
||||
@ -636,6 +662,9 @@ let hxTrigger =
|
||||
test "succeeds when it is not the first modifier" {
|
||||
Expect.equal (HxTrigger.Queue "def" "click") "click queue:def" "Queue modifier incorrect"
|
||||
}
|
||||
test "succeeds when no type of queueing is given" {
|
||||
Expect.equal (HxTrigger.Queue "" "blur") "blur queue" "Queue modifier incorrect"
|
||||
}
|
||||
]
|
||||
testList "QueueFirst" [
|
||||
test "succeeds when it is the first modifier" {
|
||||
@ -757,7 +786,7 @@ let attributes =
|
||||
hr [ _hxPost "/hear-ye-hear-ye" ] |> shouldRender """<hr hx-post="/hear-ye-hear-ye">"""
|
||||
}
|
||||
test "_hxPreserve succeeds" {
|
||||
img [ _hxPreserve ] |> shouldRender """<img hx-preserve="true">"""
|
||||
img [ _hxPreserve ] |> shouldRender """<img hx-preserve>"""
|
||||
}
|
||||
test "_hxPrompt succeeds" {
|
||||
strong [ _hxPrompt "Who goes there?" ] []
|
||||
@ -792,7 +821,8 @@ let attributes =
|
||||
li [ _hxSwapOob "true" ] [] |> shouldRender """<li hx-swap-oob="true"></li>"""
|
||||
}
|
||||
test "_hxSync succeeds" {
|
||||
nav [ _hxSync "closest form:abort" ] [] |> shouldRender """<nav hx-sync="closest form:abort"></nav>"""
|
||||
nav [ _hxSync "closest form" HxSync.Abort ] []
|
||||
|> shouldRender """<nav hx-sync="closest form:abort"></nav>"""
|
||||
}
|
||||
test "_hxTarget succeeds" {
|
||||
header [ _hxTarget "#somewhereElse" ] [] |> shouldRender """<header hx-target="#somewhereElse"></header>"""
|
||||
@ -986,6 +1016,7 @@ let allTests =
|
||||
hxHeaders
|
||||
hxParams
|
||||
hxRequest
|
||||
hxSync
|
||||
hxTrigger
|
||||
hxVals
|
||||
attributes
|
||||
|
@ -6,9 +6,11 @@ module Giraffe.ViewEngine.Htmx
|
||||
module HxEncoding =
|
||||
|
||||
/// <summary>A standard HTTP form</summary>
|
||||
[<Literal>]
|
||||
let Form = "application/x-www-form-urlencoded"
|
||||
|
||||
/// <summary>A multipart form (used for file uploads)</summary>
|
||||
[<Literal>]
|
||||
let MultipartForm = "multipart/form-data"
|
||||
|
||||
|
||||
@ -213,9 +215,11 @@ module HxHeaders =
|
||||
module HxParams =
|
||||
|
||||
/// <summary>Include all parameters</summary>
|
||||
[<Literal>]
|
||||
let All = "*"
|
||||
|
||||
/// <summary>Include no parameters</summary>
|
||||
[<Literal>]
|
||||
let None = "none"
|
||||
|
||||
/// <summary>Include the specified parameters</summary>
|
||||
@ -267,7 +271,46 @@ module HxRequest =
|
||||
(toLowerBool >> sprintf "\"noHeaders\": %s") exclude
|
||||
|
||||
|
||||
/// <summary>Helpers for the <c>hx-sync</c> attribute</summary>
|
||||
/// <seealso href="https://htmx.org/attributes/hx-sync/">Documentation</seealso>
|
||||
[<RequireQualifiedAccess>]
|
||||
module HxSync =
|
||||
|
||||
/// <summary>Drop (ignore) this request if a request is already in flight</summary>
|
||||
/// <remarks>This is the default for <c>hx-sync</c></remarks>
|
||||
[<Literal>]
|
||||
let Drop = "drop"
|
||||
|
||||
/// <summary>
|
||||
/// Drop (ignore) this request if a request is already in flight, and if another request occurs while this one is in
|
||||
/// flight, abort this request
|
||||
/// </summary>
|
||||
[<Literal>]
|
||||
let Abort = "abort"
|
||||
|
||||
/// <summary>Abort any current in-flight request and replace it with this one</summary>
|
||||
[<Literal>]
|
||||
let Replace = "replace"
|
||||
|
||||
/// <summary>Place this request in an element-associated queue</summary>
|
||||
[<Literal>]
|
||||
let Queue = "queue"
|
||||
|
||||
/// <summary>Queue only the first request received while another request is in flight</summary>
|
||||
[<Literal>]
|
||||
let QueueFirst = "queue first"
|
||||
|
||||
/// <summary>Queue only the last request received while another request is in flight</summary>
|
||||
[<Literal>]
|
||||
let QueueLast = "queue last"
|
||||
|
||||
/// <summary>Queue all requests received while another request is in flight</summary>
|
||||
[<Literal>]
|
||||
let QueueAll = "queue all"
|
||||
|
||||
|
||||
/// <summary>Helpers for the <c>hx-trigger</c> attribute</summary>
|
||||
/// <seealso href="https://htmx.org/attributes/hx-trigger/">Documentation</seealso>
|
||||
[<RequireQualifiedAccess>]
|
||||
module HxTrigger =
|
||||
|
||||
@ -279,93 +322,160 @@ module HxTrigger =
|
||||
$"{parts[0]}[{parts[1]}&&{filter}]"
|
||||
| false -> $"{trigger}[{filter}]"
|
||||
|
||||
/// Trigger the event on a click
|
||||
/// <summary>Trigger the event on a click</summary>
|
||||
[<Literal>]
|
||||
let Click = "click"
|
||||
|
||||
/// Trigger the event on page load
|
||||
/// <summary>Trigger the event on page load</summary>
|
||||
[<Literal>]
|
||||
let Load = "load"
|
||||
|
||||
/// Trigger the event when the item is visible
|
||||
/// <summary>Trigger the event when the item is visible</summary>
|
||||
[<Literal>]
|
||||
let Revealed = "revealed"
|
||||
|
||||
/// Trigger this event every [timing declaration]
|
||||
let Every (duration : string) = $"every {duration}"
|
||||
/// <summary>Trigger this event every [timing declaration]</summary>
|
||||
/// <param name="duration">The duration on which this trigger should fire (e.g., "1s", "500ms")</param>
|
||||
/// <returns>A trigger timing specification</returns>
|
||||
let Every duration =
|
||||
$"every %s{duration}"
|
||||
|
||||
/// Helpers for defining filters
|
||||
/// <summary>Helpers for defining filters</summary>
|
||||
module Filter =
|
||||
|
||||
/// Only trigger the event if the `ALT` key is pressed
|
||||
/// <summary>Only trigger the event if the <c>ALT</c> key is pressed</summary>
|
||||
let Alt = appendFilter "altKey"
|
||||
|
||||
/// Only trigger the event if the `CTRL` key is pressed
|
||||
/// <summary>Only trigger the event if the <c>CTRL</c> key is pressed</summary>
|
||||
let Ctrl = appendFilter "ctrlKey"
|
||||
|
||||
/// Only trigger the event if the `SHIFT` key is pressed
|
||||
/// <summary>Only trigger the event if the <c>SHIFT</c> key is pressed</summary>
|
||||
let Shift = appendFilter "shiftKey"
|
||||
|
||||
/// Only trigger the event if `CTRL+ALT` are pressed
|
||||
/// <summary>Only trigger the event if <c>CTRL</c> and <c>ALT</c> are pressed</summary>
|
||||
let CtrlAlt = Ctrl >> Alt
|
||||
|
||||
/// Only trigger the event if `CTRL+SHIFT` are pressed
|
||||
/// <summary>Only trigger the event if <c>CTRL</c> and <c>SHIFT</c> are pressed</summary>
|
||||
let CtrlShift = Ctrl >> Shift
|
||||
|
||||
/// Only trigger the event if `CTRL+ALT+SHIFT` are pressed
|
||||
/// <summary>Only trigger the event if <c>CTRL</c>, <c>ALT</c>, and <c>SHIFT</c> are pressed</summary>
|
||||
let CtrlAltShift = CtrlAlt >> Shift
|
||||
|
||||
/// Only trigger the event if `ALT+SHIFT` are pressed
|
||||
/// <summary>Only trigger the event if <c>ALT</c> and <c>SHIFT</c> are pressed</summary>
|
||||
let AltShift = Alt >> Shift
|
||||
|
||||
/// Append a modifier to the current trigger
|
||||
let private appendModifier modifier current =
|
||||
if current = "" then modifier else $"{current} {modifier}"
|
||||
|
||||
/// Only trigger once
|
||||
let Once = appendModifier "once"
|
||||
/// <summary>Only trigger once</summary>
|
||||
/// <param name="action">The action which should only be fired once</param>
|
||||
/// <returns>A trigger spec to fire the given action once</returns>
|
||||
let Once action =
|
||||
appendModifier "once" action
|
||||
|
||||
/// Trigger when changed
|
||||
let Changed = appendModifier "changed"
|
||||
/// <summary>Trigger when changed</summary>
|
||||
/// <param name="elt">The element from which the <c>onchange</c> event will be emitted</param>
|
||||
/// <returns>A trigger spec to fire when the given element changes</returns>
|
||||
let Changed elt =
|
||||
appendModifier "changed" elt
|
||||
|
||||
/// Delay execution; resets every time the event is seen
|
||||
let Delay = sprintf "delay:%s" >> appendModifier
|
||||
/// <summary>Delay execution; resets every time the event is seen</summary>
|
||||
/// <param name="duration">The duration for the delay (e.g., "1s", "500ms")</param>
|
||||
/// <param name="action">The action which should be fired after the given delay</param>
|
||||
/// <returns>A trigger spec to fire the given action after the specified delay</returns>
|
||||
let Delay duration action =
|
||||
appendModifier $"delay:%s{duration}" action
|
||||
|
||||
/// Throttle execution; ignore other events, fire when duration passes
|
||||
let Throttle = sprintf "throttle:%s" >> appendModifier
|
||||
/// <summary>Throttle execution; ignore other events, fire when duration passes</summary>
|
||||
/// <param name="duration">The duration for the throttling (e.g., "1s", "500ms")</param>
|
||||
/// <param name="action">The action which should be fired after the given duration</param>
|
||||
/// <returns>A trigger spec to fire the given action after the specified duration</returns>
|
||||
let Throttle duration action =
|
||||
appendModifier $"throttle:%s{duration}" action
|
||||
|
||||
/// Trigger this event from a CSS selector
|
||||
let From = sprintf "from:%s" >> appendModifier
|
||||
/// <summary>Trigger this event from a CSS selector</summary>
|
||||
/// <param name="selector">A CSS selector to identify elements which may fire this trigger</param>
|
||||
/// <param name="action">The action to be fired</param>
|
||||
/// <returns>A trigger spec to fire from the given element(s)</returns>
|
||||
let From selector action =
|
||||
appendModifier $"from:%s{selector}" action
|
||||
|
||||
/// Trigger this event from the `document` object
|
||||
let FromDocument = From "document"
|
||||
/// <summary>Trigger this event from the <c>document</c> object</summary>
|
||||
/// <param name="action">The action to be fired</param>
|
||||
/// <returns>A trigger spec to fire from the <c>document</c> element</returns>
|
||||
let FromDocument action =
|
||||
From "document" action
|
||||
|
||||
/// Trigger this event from the `window` object
|
||||
let FromWindow = From "window"
|
||||
/// <summary>Trigger this event from the <c>window</c> object</summary>
|
||||
/// <param name="action">The action to be fired</param>
|
||||
/// <returns>A trigger spec to fire from the <c>window</c> object</returns>
|
||||
let FromWindow action =
|
||||
From "window" action
|
||||
|
||||
/// Trigger this event from the closest parent CSS selector
|
||||
let FromClosest = sprintf "closest %s" >> From
|
||||
/// <summary>Trigger this event from the closest parent CSS selector</summary>
|
||||
/// <param name="selector">The CSS selector from which the action should be fired</param>
|
||||
/// <param name="action">The action to be fired</param>
|
||||
/// <returns>A trigger spec to fire from the closest element</returns>
|
||||
let FromClosest selector action =
|
||||
From $"closest %s{selector}" action
|
||||
|
||||
/// Trigger this event from the closest child CSS selector
|
||||
let FromFind = sprintf "find %s" >> From
|
||||
/// <summary>Trigger this event from the closest child CSS selector</summary>
|
||||
/// <param name="selector">The child CSS selector from which the action should be fired</param>
|
||||
/// <param name="action">The action to be fired</param>
|
||||
/// <returns>A trigger spec to fire from the closest child element</returns>
|
||||
let FromFind selector action =
|
||||
From $"find %s{selector}" action
|
||||
|
||||
/// Target the given CSS selector with the results of this event
|
||||
let Target = sprintf "target:%s" >> appendModifier
|
||||
/// <summary>Target the given CSS selector with the results of this event</summary>
|
||||
/// <param name="selector">The CSS selector to which the result of the action will be applied</param>
|
||||
/// <param name="action">The action to be fired</param>
|
||||
/// <returns>A trigger spec to target the given selector</returns>
|
||||
let Target selector action =
|
||||
appendModifier $"target:%s{selector}" action
|
||||
|
||||
/// Prevent any further events from occurring after this one fires
|
||||
let Consume = appendModifier "consume"
|
||||
/// <summary>Prevent any further events from occurring after this one fires</summary>
|
||||
/// <param name="action">The action to be fired</param>
|
||||
/// <returns>A trigger spec to fire the given action and prevent further events</returns>
|
||||
let Consume action =
|
||||
appendModifier "consume" action
|
||||
|
||||
/// Configure queueing when events fire when others are in flight; if unspecified, the default is "last"
|
||||
let Queue = sprintf "queue:%s" >> appendModifier
|
||||
/// <summary>
|
||||
/// Configure queueing when events fire when others are in flight; if unspecified, the default is <c>last</c>
|
||||
/// </summary>
|
||||
/// <param name="how">
|
||||
/// How the request should be queued (consider <see cref="QueueFirst" />, <see cref="QueueLast" />,
|
||||
/// <see cref="QueueAll" />, and <see cref="QueueNone" />)
|
||||
/// </param>
|
||||
/// <param name="action">The action to be fired</param>
|
||||
/// <returns>A trigger spec to queue the given action</returns>
|
||||
let Queue how action =
|
||||
let qSpec = if how = "" then "" else $":{how}"
|
||||
appendModifier $"queue{qSpec}" action
|
||||
|
||||
/// Queue the first event, discard all others (i.e., a FIFO queue of 1)
|
||||
let QueueFirst = Queue "first"
|
||||
/// <summary>Queue the first event, discard all others (i.e., a FIFO queue of 1)</summary>
|
||||
/// <param name="action">The action to be fired</param>
|
||||
/// <returns>A trigger spec to queue the given action</returns>
|
||||
let QueueFirst action =
|
||||
Queue "first" action
|
||||
|
||||
/// Queue the last event; discards current when another is received (i.e., a LIFO queue of 1)
|
||||
let QueueLast = Queue "last"
|
||||
/// <summary>Queue the last event; discards current when another is received (i.e., a LIFO queue of 1)</summary>
|
||||
/// <param name="action">The action to be fired</param>
|
||||
/// <returns>A trigger spec to queue the given action</returns>
|
||||
let QueueLast action =
|
||||
Queue "last" action
|
||||
|
||||
/// Queue all events; discard none
|
||||
let QueueAll = Queue "all"
|
||||
/// <summary>Queue all events; discard none</summary>
|
||||
/// <param name="action">The action to be fired</param>
|
||||
/// <returns>A trigger spec to queue the given action</returns>
|
||||
let QueueAll action =
|
||||
Queue "all" action
|
||||
|
||||
/// Queue no events; discard all
|
||||
let QueueNone = Queue "none"
|
||||
/// <summary>Queue no events; discard all</summary>
|
||||
/// <param name="action">The action to be fired</param>
|
||||
/// <returns>A trigger spec to queue the given action</returns>
|
||||
let QueueNone action =
|
||||
Queue "none" action
|
||||
|
||||
|
||||
/// <summary>Helper to create the <c>hx-vals</c> attribute</summary>
|
||||
@ -623,8 +733,14 @@ module HtmxAttrs =
|
||||
let _hxSwapOob swap =
|
||||
attr "hx-swap-oob" swap
|
||||
|
||||
/// Synchronize events based on another element
|
||||
let _hxSync = attr "hx-sync"
|
||||
/// <summary>Synchronize events based on another element</summary>
|
||||
/// <param name="selector">A CSS selector for the element with which this one should sync</param>
|
||||
/// <param name="action">The request synchronization action to perform (use <c>HxSync</c> values)</param>
|
||||
/// <returns>A configured <c>hx-sync</c> attribute</returns>
|
||||
/// <seealso cref="HxSync" />
|
||||
/// <seealso href="https://htmx.org/attributes/hx-sync/">Documentation</seealso>
|
||||
let _hxSync selector action =
|
||||
attr "hx-sync" $"%s{selector}:%s{action}"
|
||||
|
||||
/// <summary>Specifies the target element to be swapped</summary>
|
||||
/// <param name="selector">A CSS selector or relative reference (or both) to identify the target</param>
|
||||
@ -633,8 +749,13 @@ module HtmxAttrs =
|
||||
let _hxTarget selector =
|
||||
attr "hx-target" selector
|
||||
|
||||
/// Specifies the event that triggers the request
|
||||
let _hxTrigger = attr "hx-trigger"
|
||||
/// <summary>Specifies the event that triggers the request</summary>
|
||||
/// <param name="spec">The trigger specification (use <c>HxTrigger</c> to create)</param>
|
||||
/// <returns>A configured <c>hx-trigger</c> attribute</returns>
|
||||
/// <seealso cref="HxTrigger" />
|
||||
/// <seealso href="https://htmx.org/attributes/hx-trigger/">Documentation</seealso>
|
||||
let _hxTrigger spec =
|
||||
attr "hx-trigger" spec
|
||||
|
||||
/// <summary>Validate an input element (uses HTML5 validation API)</summary>
|
||||
/// <seealso href="https://htmx.org/attributes/hx-validate/">Documentation</seealso>
|
||||
|
Loading…
x
Reference in New Issue
Block a user