Finish view engine helpers
This commit is contained in:
parent
1eecabd5dd
commit
dc06b06b1f
|
@ -15,6 +15,19 @@ module Encoding =
|
|||
Assert.Equal ("multipart/form-data", HxEncoding.MultipartForm)
|
||||
|
||||
|
||||
/// Tests for the HxHeaders module
|
||||
module Headers =
|
||||
|
||||
[<Fact>]
|
||||
let ``From succeeds with an empty list`` () =
|
||||
Assert.Equal ("{ }", HxHeaders.From [])
|
||||
|
||||
[<Fact>]
|
||||
let ``From succeeds and escapes quotes`` () =
|
||||
Assert.Equal ("{ \"test\": \"one two three\", \"again\": \"four \\\"five\\\" six\" }",
|
||||
HxHeaders.From [ "test", "one two three"; "again", "four \"five\" six" ])
|
||||
|
||||
|
||||
/// Tests for the HxParams module
|
||||
module Params =
|
||||
|
||||
|
@ -51,6 +64,43 @@ module Params =
|
|||
Assert.Equal ("not blue,green", HxParams.Except [ "blue"; "green" ])
|
||||
|
||||
|
||||
/// Tests for the HxRequest module
|
||||
module Request =
|
||||
|
||||
[<Fact>]
|
||||
let ``Configure succeeds with an empty list`` () =
|
||||
Assert.Equal ("{ }", HxRequest.Configure [])
|
||||
|
||||
[<Fact>]
|
||||
let ``Configure succeeds with a non-empty list`` () =
|
||||
Assert.Equal ("{ \"a\": \"b\", \"c\": \"d\" }", HxRequest.Configure [ "\"a\": \"b\""; "\"c\": \"d\"" ])
|
||||
|
||||
[<Fact>]
|
||||
let ``Configure succeeds with all known params configured`` () =
|
||||
Assert.Equal ("{ \"timeout\": 1000, \"credentials\": false, \"noHeaders\": true }",
|
||||
HxRequest.Configure [ HxRequest.Timeout 1000; HxRequest.Credentials false; HxRequest.NoHeaders true ])
|
||||
|
||||
[<Fact>]
|
||||
let ``Timeout succeeds`` () =
|
||||
Assert.Equal ("\"timeout\": 50", HxRequest.Timeout 50)
|
||||
|
||||
[<Fact>]
|
||||
let ``Credentials succeeds when set to true`` () =
|
||||
Assert.Equal ("\"credentials\": true", HxRequest.Credentials true)
|
||||
|
||||
[<Fact>]
|
||||
let ``Credentials succeeds when set to false`` () =
|
||||
Assert.Equal ("\"credentials\": false", HxRequest.Credentials false)
|
||||
|
||||
[<Fact>]
|
||||
let ``NoHeaders succeeds when set to true`` () =
|
||||
Assert.Equal ("\"noHeaders\": true", HxRequest.NoHeaders true)
|
||||
|
||||
[<Fact>]
|
||||
let ``NoHeaders succeeds when set to false`` () =
|
||||
Assert.Equal ("\"noHeaders\": false", HxRequest.NoHeaders false)
|
||||
|
||||
|
||||
/// Tests for the HxSwap module
|
||||
module Swap =
|
||||
|
||||
|
@ -94,6 +144,14 @@ module Trigger =
|
|||
let ``Load is correct`` () =
|
||||
Assert.Equal ("load", HxTrigger.Load)
|
||||
|
||||
[<Fact>]
|
||||
let ``Revealed is correct`` () =
|
||||
Assert.Equal ("revealed", HxTrigger.Revealed)
|
||||
|
||||
[<Fact>]
|
||||
let ``Every succeeds`` () =
|
||||
Assert.Equal ("every 3s", HxTrigger.Every "3s")
|
||||
|
||||
[<Fact>]
|
||||
let ``Filter.Alt succeeds`` () =
|
||||
Assert.Equal ("click[altKey]", HxTrigger.Filter.Alt HxTrigger.Click)
|
||||
|
@ -122,6 +180,147 @@ module Trigger =
|
|||
let ``Filter.AltShift succeeds`` () =
|
||||
Assert.Equal ("click[altKey&&shiftKey]", HxTrigger.Filter.AltShift HxTrigger.Click)
|
||||
|
||||
[<Fact>]
|
||||
let ``Once succeeds when it is the first modifier`` () =
|
||||
Assert.Equal ("once", HxTrigger.Once "")
|
||||
|
||||
[<Fact>]
|
||||
let ``Once succeeds when it is not the first modifier`` () =
|
||||
Assert.Equal ("click once", HxTrigger.Once "click")
|
||||
|
||||
[<Fact>]
|
||||
let ``Changed succeeds when it is the first modifier`` () =
|
||||
Assert.Equal ("changed", HxTrigger.Changed "")
|
||||
|
||||
[<Fact>]
|
||||
let ``Changed succeeds when it is not the first modifier`` () =
|
||||
Assert.Equal ("click changed", HxTrigger.Changed "click")
|
||||
|
||||
[<Fact>]
|
||||
let ``Delay succeeds when it is the first modifier`` () =
|
||||
Assert.Equal ("delay:1s", HxTrigger.Delay "1s" "")
|
||||
|
||||
[<Fact>]
|
||||
let ``Delay succeeds when it is not the first modifier`` () =
|
||||
Assert.Equal ("click delay:2s", HxTrigger.Delay "2s" "click")
|
||||
|
||||
[<Fact>]
|
||||
let ``Throttle succeeds when it is the first modifier`` () =
|
||||
Assert.Equal ("throttle:4s", HxTrigger.Throttle "4s" "")
|
||||
|
||||
[<Fact>]
|
||||
let ``Throttle succeeds when it is not the first modifier`` () =
|
||||
Assert.Equal ("click throttle:7s", HxTrigger.Throttle "7s" "click")
|
||||
|
||||
[<Fact>]
|
||||
let ``From succeeds when it is the first modifier`` () =
|
||||
Assert.Equal ("from:.nav", HxTrigger.From ".nav" "")
|
||||
|
||||
[<Fact>]
|
||||
let ``From succeeds when it is not the first modifier`` () =
|
||||
Assert.Equal ("click from:#somewhere", HxTrigger.From "#somewhere" "click")
|
||||
|
||||
[<Fact>]
|
||||
let ``FromDocument succeeds when it is the first modifier`` () =
|
||||
Assert.Equal ("from:document", HxTrigger.FromDocument "")
|
||||
|
||||
[<Fact>]
|
||||
let ``FromDocument succeeds when it is not the first modifier`` () =
|
||||
Assert.Equal ("click from:document", HxTrigger.FromDocument "click")
|
||||
|
||||
[<Fact>]
|
||||
let ``FromWindow succeeds when it is the first modifier`` () =
|
||||
Assert.Equal ("from:window", HxTrigger.FromWindow "")
|
||||
|
||||
[<Fact>]
|
||||
let ``FromWindow succeeds when it is not the first modifier`` () =
|
||||
Assert.Equal ("click from:window", HxTrigger.FromWindow "click")
|
||||
|
||||
[<Fact>]
|
||||
let ``FromClosest succeeds when it is the first modifier`` () =
|
||||
Assert.Equal ("from:closest div", HxTrigger.FromClosest "div" "")
|
||||
|
||||
[<Fact>]
|
||||
let ``FromClosest succeeds when it is not the first modifier`` () =
|
||||
Assert.Equal ("click from:closest p", HxTrigger.FromClosest "p" "click")
|
||||
|
||||
[<Fact>]
|
||||
let ``FromFind succeeds when it is the first modifier`` () =
|
||||
Assert.Equal ("from:find li", HxTrigger.FromFind "li" "")
|
||||
|
||||
[<Fact>]
|
||||
let ``FromFind succeeds when it is not the first modifier`` () =
|
||||
Assert.Equal ("click from:find .spot", HxTrigger.FromFind ".spot" "click")
|
||||
|
||||
[<Fact>]
|
||||
let ``Target succeeds when it is the first modifier`` () =
|
||||
Assert.Equal ("target:main", HxTrigger.Target "main" "")
|
||||
|
||||
[<Fact>]
|
||||
let ``Target succeeds when it is not the first modifier`` () =
|
||||
Assert.Equal ("click target:footer", HxTrigger.Target "footer" "click")
|
||||
|
||||
[<Fact>]
|
||||
let ``Consume succeeds when it is the first modifier`` () =
|
||||
Assert.Equal ("consume", HxTrigger.Consume "")
|
||||
|
||||
[<Fact>]
|
||||
let ``Consume succeeds when it is not the first modifier`` () =
|
||||
Assert.Equal ("click consume", HxTrigger.Consume "click")
|
||||
|
||||
[<Fact>]
|
||||
let ``Queue succeeds when it is the first modifier`` () =
|
||||
Assert.Equal ("queue:abc", HxTrigger.Queue "abc" "")
|
||||
|
||||
[<Fact>]
|
||||
let ``Queue succeeds when it is not the first modifier`` () =
|
||||
Assert.Equal ("click queue:def", HxTrigger.Queue "def" "click")
|
||||
|
||||
[<Fact>]
|
||||
let ``QueueFirst succeeds when it is the first modifier`` () =
|
||||
Assert.Equal ("queue:first", HxTrigger.QueueFirst "")
|
||||
|
||||
[<Fact>]
|
||||
let ``QueueFirst succeeds when it is not the first modifier`` () =
|
||||
Assert.Equal ("click queue:first", HxTrigger.QueueFirst "click")
|
||||
|
||||
[<Fact>]
|
||||
let ``QueueLast succeeds when it is the first modifier`` () =
|
||||
Assert.Equal ("queue:last", HxTrigger.QueueLast "")
|
||||
|
||||
[<Fact>]
|
||||
let ``QueueLast succeeds when it is not the first modifier`` () =
|
||||
Assert.Equal ("click queue:last", HxTrigger.QueueLast "click")
|
||||
|
||||
[<Fact>]
|
||||
let ``QueueAll succeeds when it is the first modifier`` () =
|
||||
Assert.Equal ("queue:all", HxTrigger.QueueAll "")
|
||||
|
||||
[<Fact>]
|
||||
let ``QueueAll succeeds when it is not the first modifier`` () =
|
||||
Assert.Equal ("click queue:all", HxTrigger.QueueAll "click")
|
||||
|
||||
[<Fact>]
|
||||
let ``QueueNone succeeds when it is the first modifier`` () =
|
||||
Assert.Equal ("queue:none", HxTrigger.QueueNone "")
|
||||
|
||||
[<Fact>]
|
||||
let ``QueueNone succeeds when it is not the first modifier`` () =
|
||||
Assert.Equal ("click queue:none", HxTrigger.QueueNone "click")
|
||||
|
||||
|
||||
/// Tests for the HxVals module
|
||||
module Vals =
|
||||
|
||||
[<Fact>]
|
||||
let ``From succeeds with an empty list`` () =
|
||||
Assert.Equal ("{ }", HxVals.From [])
|
||||
|
||||
[<Fact>]
|
||||
let ``From succeeds and escapes quotes`` () =
|
||||
Assert.Equal ("{ \"test\": \"a \\\"b\\\" c\", \"2\": \"d e f\" }",
|
||||
HxVals.From [ "test", "a \"b\" c"; "2", "d e f" ])
|
||||
|
||||
|
||||
/// Tests for the HtmxAttrs module
|
||||
module Attributes =
|
||||
|
|
|
@ -1,5 +1,13 @@
|
|||
module Giraffe.ViewEngine.Htmx
|
||||
|
||||
/// Serialize a list of key/value pairs to JSON (very rudimentary)
|
||||
let private toJson (kvps : (string * string) list) =
|
||||
kvps
|
||||
|> List.map (fun kvp -> sprintf "\"%s\": \"%s\"" (fst kvp) ((snd kvp).Replace ("\"", "\\\"")))
|
||||
|> String.concat ", "
|
||||
|> sprintf "{ %s }"
|
||||
|
||||
|
||||
/// Valid values for the `hx-encoding` attribute
|
||||
[<RequireQualifiedAccess>]
|
||||
module HxEncoding =
|
||||
|
@ -8,7 +16,13 @@ module HxEncoding =
|
|||
/// A multipart form (used for file uploads)
|
||||
let MultipartForm = "multipart/form-data"
|
||||
|
||||
// TODO: hx-header helper
|
||||
|
||||
/// Helper to create the `hx-headers` attribute
|
||||
[<RequireQualifiedAccess>]
|
||||
module HxHeaders =
|
||||
/// Create headers from a list of key/value pairs
|
||||
let From = toJson
|
||||
|
||||
|
||||
/// Values / helpers for the `hx-params` attribute
|
||||
[<RequireQualifiedAccess>]
|
||||
|
@ -22,7 +36,25 @@ module HxParams =
|
|||
/// Exclude the specified parameters
|
||||
let Except fields = With fields |> sprintf "not %s"
|
||||
|
||||
// TODO: hx-request helper
|
||||
|
||||
/// Helpers to define `hx-request` attribute values
|
||||
[<RequireQualifiedAccess>]
|
||||
module HxRequest =
|
||||
/// Convert a boolean to its lowercase string equivalent
|
||||
let private toLowerBool (it : bool) =
|
||||
(string it).ToLowerInvariant ()
|
||||
/// Configure the request with various options
|
||||
let Configure (opts : string list) =
|
||||
opts
|
||||
|> String.concat ", "
|
||||
|> sprintf "{ %s }"
|
||||
/// Set a timeout (in milliseconds)
|
||||
let Timeout (ms : int) = $"\"timeout\": {ms}"
|
||||
/// Include or exclude credentials from the request
|
||||
let Credentials = toLowerBool >> sprintf "\"credentials\": %s"
|
||||
/// Exclude or include headers from the request
|
||||
let NoHeaders = toLowerBool >> sprintf "\"noHeaders\": %s"
|
||||
|
||||
|
||||
/// Valid values for the `hx-swap` attribute (may be combined with swap/settle/scroll/show config)
|
||||
[<RequireQualifiedAccess>]
|
||||
|
@ -42,6 +74,7 @@ module HxSwap =
|
|||
/// Does not append content from response (out of band items will still be processed).
|
||||
let None = "none"
|
||||
|
||||
|
||||
/// Helpers for the `hx-trigger` attribute
|
||||
[<RequireQualifiedAccess>]
|
||||
module HxTrigger =
|
||||
|
@ -53,9 +86,13 @@ module HxTrigger =
|
|||
$"{parts.[0]}[{parts.[1]}&&{filter}]"
|
||||
| false -> $"{trigger}[{filter}]"
|
||||
/// Trigger the event on a click
|
||||
let Click = "click"
|
||||
let Click = "click"
|
||||
/// Trigger the event on page load
|
||||
let Load = "load"
|
||||
let Load = "load"
|
||||
/// Trigger the event when the item is visible
|
||||
let Revealed = "revealed"
|
||||
/// Trigger this event every [timing declaration]
|
||||
let Every (duration : string) = $"every {duration}"
|
||||
/// Helpers for defining filters
|
||||
module Filter =
|
||||
/// Only trigger the event if the `ALT` key is pressed
|
||||
|
@ -72,10 +109,48 @@ module HxTrigger =
|
|||
let CtrlAltShift = CtrlAlt >> Shift
|
||||
/// Only trigger the event if `ALT+SHIFT` are pressed
|
||||
let AltShift = Alt >> Shift
|
||||
|
||||
// TODO: more stuff for the hx-trigger helper
|
||||
/// Append a modifier to the current trigger
|
||||
let private appendModifier modifier current =
|
||||
match current with "" -> modifier | _ -> $"{current} {modifier}"
|
||||
/// Only trigger once
|
||||
let Once = appendModifier "once"
|
||||
/// Trigger when changed
|
||||
let Changed = appendModifier "changed"
|
||||
/// Delay execution; resets every time the event is seen
|
||||
let Delay = sprintf "delay:%s" >> appendModifier
|
||||
/// Throttle execution; ignore other events, fire when duration passes
|
||||
let Throttle = sprintf "throttle:%s" >> appendModifier
|
||||
/// Trigger this event from a CSS selector
|
||||
let From = sprintf "from:%s" >> appendModifier
|
||||
/// Trigger this event from the `document` object
|
||||
let FromDocument = From "document"
|
||||
/// Trigger this event from the `window` object
|
||||
let FromWindow = From "window"
|
||||
/// Trigger this event from the closest parent CSS selector
|
||||
let FromClosest = sprintf "closest %s" >> From
|
||||
/// Trigger this event from the closest child CSS selector
|
||||
let FromFind = sprintf "find %s" >> From
|
||||
/// Target the given CSS selector with the results of this event
|
||||
let Target = sprintf "target:%s" >> appendModifier
|
||||
/// Prevent any further events from occurring after this one fires
|
||||
let Consume = appendModifier "consume"
|
||||
/// Configure queueing when events fire when others are in flight; if unspecified, the default is "last"
|
||||
let Queue = sprintf "queue:%s" >> appendModifier
|
||||
/// Queue the first event, discard all others (i.e., a FIFO queue of 1)
|
||||
let QueueFirst = Queue "first"
|
||||
/// Queue the last event; discards current when another is received (i.e., a LIFO queue of 1)
|
||||
let QueueLast = Queue "last"
|
||||
/// Queue all events; discard none
|
||||
let QueueAll = Queue "all"
|
||||
/// Queue no events; discard all
|
||||
let QueueNone = Queue "none"
|
||||
|
||||
// TODO: hx-vals helper
|
||||
|
||||
/// Helper to create the `hx-vals` attribute
|
||||
[<RequireQualifiedAccess>]
|
||||
module HxVals =
|
||||
/// Create values from a list of key/value pairs
|
||||
let From = toJson
|
||||
|
||||
|
||||
/// Attributes and flags for HTMX
|
||||
|
|
Loading…
Reference in New Issue
Block a user