v2.0.6 (#15)
- Adds XML documentation (#13) - Adds `HxSync` module and attribute helper - Updates script version to 2.0.6 - Drops .NET 6 support (#14 ) Reviewed-on: #15
This commit was merged in pull request #15.
This commit is contained in:
@@ -4,6 +4,7 @@
|
||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||
<Description>htmx header extensions and helpers for Giraffe</Description>
|
||||
<PackageReadmeFile>README.md</PackageReadmeFile>
|
||||
<DocumentationFile>bin\$(Configuration)\$(TargetFramework)\$(AssemblyName).xml</DocumentationFile>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
193
src/Htmx/Htmx.fs
193
src/Htmx/Htmx.fs
@@ -11,121 +11,162 @@ let private hdr (headers : IHeaderDictionary) hdr =
|
||||
/// Extensions to the header dictionary
|
||||
type IHeaderDictionary with
|
||||
|
||||
/// Indicates that the request is via an element using `hx-boost`
|
||||
member this.HxBoosted with get () = hdr this "HX-Boosted" |> Option.map bool.Parse
|
||||
/// <summary>Indicates that the request is via an element using <c>hx-boost</c></summary>
|
||||
member this.HxBoosted
|
||||
with get () = hdr this "HX-Boosted" |> Option.map bool.Parse
|
||||
|
||||
/// The current URL of the browser _(note that this does not update until after settle)_
|
||||
member this.HxCurrentUrl with get () = hdr this "HX-Current-URL" |> Option.map Uri
|
||||
/// <summary>The current URL of the browser <em>(note that this does not update until after settle)</em></summary>
|
||||
member this.HxCurrentUrl
|
||||
with get () = hdr this "HX-Current-URL" |> Option.map Uri
|
||||
|
||||
/// `true` if the request is for history restoration after a miss in the local history cache
|
||||
member this.HxHistoryRestoreRequest with get () = hdr this "HX-History-Restore-Request" |> Option.map bool.Parse
|
||||
/// <summary><c>true</c> if the request is for history restoration after a miss in the local history cache</summary>
|
||||
member this.HxHistoryRestoreRequest
|
||||
with get () = hdr this "HX-History-Restore-Request" |> Option.map bool.Parse
|
||||
|
||||
/// The user response to an `hx-prompt`
|
||||
member this.HxPrompt with get () = hdr this "HX-Prompt"
|
||||
/// <summary>The user response to an <c>hx-prompt</c></summary>
|
||||
member this.HxPrompt
|
||||
with get () = hdr this "HX-Prompt"
|
||||
|
||||
/// `true` if the request came from HTMX
|
||||
member this.HxRequest with get () = hdr this "HX-Request" |> Option.map bool.Parse
|
||||
/// <summary><c>true</c> if the request came from htmx</summary>
|
||||
member this.HxRequest
|
||||
with get () = hdr this "HX-Request" |> Option.map bool.Parse
|
||||
|
||||
/// The `id` of the target element if it exists
|
||||
member this.HxTarget with get () = hdr this "HX-Target"
|
||||
/// <summary>The <c>id</c> attribute of the target element if it exists</summary>
|
||||
member this.HxTarget
|
||||
with get () = hdr this "HX-Target"
|
||||
|
||||
/// The `id` of the triggered element if it exists
|
||||
member this.HxTrigger with get () = hdr this "HX-Trigger"
|
||||
/// <summary>The <c>id</c> attribute of the triggered element if it exists</summary>
|
||||
member this.HxTrigger
|
||||
with get () = hdr this "HX-Trigger"
|
||||
|
||||
/// The `name` of the triggered element if it exists
|
||||
member this.HxTriggerName with get () = hdr this "HX-Trigger-Name"
|
||||
/// <summary>The <c>name</c> attribute of the triggered element if it exists</summary>
|
||||
member this.HxTriggerName
|
||||
with get () = hdr this "HX-Trigger-Name"
|
||||
|
||||
|
||||
/// Extensions for the request object
|
||||
type HttpRequest with
|
||||
|
||||
/// Whether this request was initiated from htmx
|
||||
member this.IsHtmx with get () = this.Headers.HxRequest |> Option.defaultValue false
|
||||
/// <summary>Whether this request was initiated from htmx</summary>
|
||||
member this.IsHtmx
|
||||
with get () = this.Headers.HxRequest |> Option.defaultValue false
|
||||
|
||||
/// Whether this request is an htmx history-miss refresh request
|
||||
member this.IsHtmxRefresh with get () =
|
||||
this.IsHtmx && (this.Headers.HxHistoryRestoreRequest |> Option.defaultValue false)
|
||||
/// <summary>Whether this request is an htmx history-miss refresh request</summary>
|
||||
member this.IsHtmxRefresh
|
||||
with get () = this.IsHtmx && (this.Headers.HxHistoryRestoreRequest |> Option.defaultValue false)
|
||||
|
||||
|
||||
/// HTTP handlers for setting output headers
|
||||
/// <summary>HTTP handlers for setting output headers</summary>
|
||||
[<AutoOpen>]
|
||||
module Handlers =
|
||||
|
||||
/// Convert a boolean to lowercase `true` or `false`
|
||||
let private toLowerBool (trueOrFalse : bool) =
|
||||
(string trueOrFalse).ToLowerInvariant ()
|
||||
open Giraffe.Htmx.Common
|
||||
|
||||
/// <summary>Instruct htmx to perform a client-side redirect for content</summary>
|
||||
/// <param name="path">The path where the content should be found</param>
|
||||
/// <returns>An HTTP handler with the <c>HX-Location</c> header set</returns>
|
||||
/// <seealso href="https://htmx.org/headers/hx-location/">Documentation</seealso>
|
||||
let withHxLocation (path: string) : HttpHandler =
|
||||
setHttpHeader "HX-Location" path
|
||||
|
||||
/// <summary>Pushes a new url into the history stack</summary>
|
||||
/// <param name="url">The URL to be pushed</param>
|
||||
/// <returns>An HTTP handler with the <c>HX-Push-Url</c> header set</returns>
|
||||
/// <remarks>Use <see cref="withHxNoPushUrl" /> to explicitly not push a new URL</remarks>
|
||||
/// <seealso href="https://htmx.org/headers/hx-push-url/">Documentation</seealso>
|
||||
let withHxPushUrl (url: string) : HttpHandler =
|
||||
setHttpHeader "HX-Push-Url" url
|
||||
|
||||
/// Serialize a list of key/value pairs to JSON (very rudimentary)
|
||||
let private toJson (evts : (string * string) list) =
|
||||
evts
|
||||
|> List.map (fun evt -> sprintf "\"%s\": \"%s\"" (fst evt) ((snd evt).Replace ("\"", "\\\"")))
|
||||
|> String.concat ", "
|
||||
|> sprintf "{ %s }"
|
||||
|
||||
/// Pushes a new url into the history stack
|
||||
let withHxPushUrl : string -> HttpHandler =
|
||||
setHttpHeader "HX-Push-Url"
|
||||
|
||||
/// Explicitly do not push a new URL into the history stack
|
||||
/// <summary>Explicitly do not push a new URL into the history stack</summary>
|
||||
/// <returns>An HTTP handler with the <c>HX-Push-Url</c> header set to <c>false</c></returns>
|
||||
/// <seealso href="https://htmx.org/headers/hx-push-url/">Documentation</seealso>
|
||||
let withHxNoPushUrl : HttpHandler =
|
||||
toLowerBool false |> withHxPushUrl
|
||||
|
||||
/// Pushes a new url into the history stack
|
||||
[<Obsolete "Use withHxPushUrl; HX-Push was replaced by HX-Push-Url in v1.8.0">]
|
||||
let withHxPush = withHxPushUrl
|
||||
|
||||
/// Explicitly do not push a new URL into the history stack
|
||||
[<Obsolete "Use withHxNoPushUrl; HX-Push was replaced by HX-Push-Url in v1.8.0">]
|
||||
let withHxNoPush = withHxNoPushUrl
|
||||
|
||||
/// Can be used to do a client-side redirect to a new location
|
||||
let withHxRedirect : string -> HttpHandler =
|
||||
setHttpHeader "HX-Redirect"
|
||||
/// <summary>Can be used to do a client-side redirect to a new location</summary>
|
||||
/// <param name="url">The URL to which the client should be redirected</param>
|
||||
/// <returns>An HTTP handler with the <c>HX-Redirect</c> header set</returns>
|
||||
/// <seealso href="https://htmx.org/headers/hx-redirect/">Documentation</seealso>
|
||||
let withHxRedirect (url: string) : HttpHandler =
|
||||
setHttpHeader "HX-Redirect" url
|
||||
|
||||
/// If set to `true` the client side will do a a full refresh of the page
|
||||
let withHxRefresh : bool -> HttpHandler =
|
||||
toLowerBool >> setHttpHeader "HX-Refresh"
|
||||
/// <summary>If set to <c>true</c> the client side will do a full refresh of the page</summary>
|
||||
/// <param name="shouldRefresh">Whether the client should refresh their page</param>
|
||||
/// <returns>An HTTP handler with the <c>HX-Refresh</c> header set</returns>
|
||||
let withHxRefresh shouldRefresh : HttpHandler =
|
||||
(toLowerBool >> setHttpHeader "HX-Refresh") shouldRefresh
|
||||
|
||||
/// Replaces the current URL in the history stack
|
||||
let withHxReplaceUrl : string -> HttpHandler =
|
||||
setHttpHeader "HX-Replace-Url"
|
||||
/// <summary>Replaces the current URL in the history stack</summary>
|
||||
/// <param name="url">The URL to place in the history stack in place of the current one</param>
|
||||
/// <returns>An HTTP handler with the <c>HX-Replace-URL</c> header set</returns>
|
||||
/// <remarks>Use <see cref="withHxNoRelaceUrl" /> to explicitly not replace the current URL</remarks>
|
||||
/// <seealso href="https://htmx.org/headers/hx-replace-url/">Documentation</seealso>
|
||||
let withHxReplaceUrl url : HttpHandler =
|
||||
setHttpHeader "HX-Replace-Url" url
|
||||
|
||||
/// Explicitly do not replace the current URL in the history stack
|
||||
/// <summary>Explicitly do not replace the current URL in the history stack</summary>
|
||||
/// <returns>An HTTP handler with the <c>HX-Replace-URL</c> header set to <c>false</c></returns>
|
||||
/// <seealso href="https://htmx.org/headers/hx-replace-url/">Documentation</seealso>
|
||||
let withHxNoReplaceUrl : HttpHandler =
|
||||
toLowerBool false |> withHxReplaceUrl
|
||||
|
||||
/// Override which portion of the response will be swapped into the target document
|
||||
let withHxReselect : string -> HttpHandler =
|
||||
setHttpHeader "HX-Reselect"
|
||||
/// <summary>Override which portion of the response will be swapped into the target document</summary>
|
||||
/// <param name="target">The selector for the new response target</param>
|
||||
/// <returns>An HTTP handler with the <c>HX-Reselect</c> header set</returns>
|
||||
let withHxReselect (target: string) : HttpHandler =
|
||||
setHttpHeader "HX-Reselect" target
|
||||
|
||||
/// Override the `hx-swap` attribute from the initiating element
|
||||
let withHxReswap : string -> HttpHandler =
|
||||
setHttpHeader "HX-Reswap"
|
||||
/// <summary>Override the <c>hx-swap</c> attribute from the initiating element</summary>
|
||||
/// <param name="swap">The swap value to override</param>
|
||||
/// <returns>An HTTP handler with the <c>HX-Reswap</c> header set</returns>
|
||||
/// <remarks>Use <see cref="T:Giraffe.Htmx.Common.HxSwap">HxSwap</see> constants for best results</remarks>
|
||||
let withHxReswap (swap: string) : HttpHandler =
|
||||
setHttpHeader "HX-Reswap" swap
|
||||
|
||||
/// Allows you to override the `hx-target` attribute
|
||||
let withHxRetarget : string -> HttpHandler =
|
||||
setHttpHeader "HX-Retarget"
|
||||
/// <summary>Allows you to override the <c>hx-target</c> attribute</summary>
|
||||
/// <param name="target">The new target for the response</param>
|
||||
/// <returns>An HTTP handler with the <c>HX-Retarget</c> header set</returns>
|
||||
let withHxRetarget (target: string) : HttpHandler =
|
||||
setHttpHeader "HX-Retarget" target
|
||||
|
||||
/// Allows you to trigger a single client side event
|
||||
let withHxTrigger : string -> HttpHandler =
|
||||
setHttpHeader "HX-Trigger"
|
||||
/// <summary>Allows you to trigger a single client side event</summary>
|
||||
/// <param name="evt">The call to the event that should be triggered</param>
|
||||
/// <returns>An HTTP handler with the <c>HX-Trigger</c> header set</returns>
|
||||
/// <seealso href="https://htmx.org/headers/hx-trigger/">Documentation</seealso>
|
||||
let withHxTrigger (evt: string) : HttpHandler =
|
||||
setHttpHeader "HX-Trigger" evt
|
||||
|
||||
/// Allows you to trigger multiple client side events
|
||||
/// <summary>Allows you to trigger multiple client side events</summary>
|
||||
/// <param name="evts">The calls to events that should be triggered</param>
|
||||
/// <returns>An HTTP handler with the <c>HX-Trigger</c> header set for all given events</returns>
|
||||
/// <seealso href="https://htmx.org/headers/hx-trigger/">Documentation</seealso>
|
||||
let withHxTriggerMany evts : HttpHandler =
|
||||
toJson evts |> setHttpHeader "HX-Trigger"
|
||||
|
||||
/// Allows you to trigger a single client side event after changes have settled
|
||||
let withHxTriggerAfterSettle : string -> HttpHandler =
|
||||
setHttpHeader "HX-Trigger-After-Settle"
|
||||
/// <summary>Allows you to trigger a single client side event after changes have settled</summary>
|
||||
/// <param name="evt">The call to the event that should be triggered</param>
|
||||
/// <returns>An HTTP handler with the <c>HX-Trigger-After-Settle</c> header set</returns>
|
||||
/// <seealso href="https://htmx.org/headers/hx-trigger/">Documentation</seealso>
|
||||
let withHxTriggerAfterSettle (evt: string) : HttpHandler =
|
||||
setHttpHeader "HX-Trigger-After-Settle" evt
|
||||
|
||||
/// Allows you to trigger multiple client side events after changes have settled
|
||||
/// <summary>Allows you to trigger multiple client side events after changes have settled</summary>
|
||||
/// <param name="evts">The calls to events that should be triggered</param>
|
||||
/// <returns>An HTTP handler with the <c>HX-Trigger-After-Settle</c> header set for all given events</returns>
|
||||
/// <seealso href="https://htmx.org/headers/hx-trigger/">Documentation</seealso>
|
||||
let withHxTriggerManyAfterSettle evts : HttpHandler =
|
||||
toJson evts |> setHttpHeader "HX-Trigger-After-Settle"
|
||||
|
||||
/// Allows you to trigger a single client side event after DOM swapping occurs
|
||||
let withHxTriggerAfterSwap : string -> HttpHandler =
|
||||
setHttpHeader "HX-Trigger-After-Swap"
|
||||
/// <summary>Allows you to trigger a single client side event after DOM swapping occurs</summary>
|
||||
/// <param name="evt">The call to the event that should be triggered</param>
|
||||
/// <returns>An HTTP handler with the <c>HX-Trigger-After-Swap</c> header set</returns>
|
||||
/// <seealso href="https://htmx.org/headers/hx-trigger/">Documentation</seealso>
|
||||
let withHxTriggerAfterSwap (evt: string) : HttpHandler =
|
||||
setHttpHeader "HX-Trigger-After-Swap" evt
|
||||
|
||||
/// Allows you to trigger multiple client side events after DOM swapping occurs
|
||||
/// <summary>Allows you to trigger multiple client side events after DOM swapping occurs</summary>
|
||||
/// <param name="evts">The calls to events that should be triggered</param>
|
||||
/// <returns>An HTTP handler with the <c>HX-Trigger-After-Swap</c> header set for all given events</returns>
|
||||
/// <seealso href="https://htmx.org/headers/hx-trigger/">Documentation</seealso>
|
||||
let withHxTriggerManyAfterSwap evts : HttpHandler =
|
||||
toJson evts |> setHttpHeader "HX-Trigger-After-Swap"
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
This package enables server-side support for [htmx](https://htmx.org) within [Giraffe](https://giraffe.wiki) and ASP.NET's `HttpContext`.
|
||||
|
||||
**htmx version: 2.0.4**
|
||||
**htmx version: 2.0.6**
|
||||
|
||||
_Upgrading from v1.x: the [migration guide](https://htmx.org/migration-guide-htmx-1/) does not currently specify any request or response header changes. This means that there are no required code changes in moving from v1.* to v2.*._
|
||||
|
||||
|
||||
Reference in New Issue
Block a user