Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d4a7e0c9ce | |||
| de75672bb3 |
@@ -6,8 +6,6 @@
|
|||||||
|
|
||||||
htmx uses attributes and HTTP headers to attain its interactivity; the libraries here contain extensions to both Giraffe and Giraffe View Engine to enable strongly-typed development of htmx applications.
|
htmx uses attributes and HTTP headers to attain its interactivity; the libraries here contain extensions to both Giraffe and Giraffe View Engine to enable strongly-typed development of htmx applications.
|
||||||
|
|
||||||
> **NOTE** htmx v4 is curently in beta; this library is supporting it on the [`htmx-v4` branch](https://git.bitbadger.solutions/bit-badger/Giraffe.Htmx/src/branch/htmx-v4/). Beta versions of the v4 library include warnings about obsolete constructs. The htmx project intends to continue supporting the 2.x line (just as they still do the 1.x line, which we track on the [`htmx-v1` branch](https://git.bitbadger.solutions/bit-badger/Giraffe.Htmx/src/branch/htmx-v1/)); the upgrade is available, not forced. See the [htmx v4 migration docs](https://four.htmx.org/docs#migration) for more information.
|
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
`Giraffe.Htmx` provides extensions that facilitate using htmx on the server side, primarily reading and setting headers. `Giraffe.ViewEngine.Htmx` provides attributes and helpers to produce views that utilize htmx. Both can be installed from NuGet via standard methods.
|
`Giraffe.Htmx` provides extensions that facilitate using htmx on the server side, primarily reading and setting headers. `Giraffe.ViewEngine.Htmx` provides attributes and helpers to produce views that utilize htmx. Both can be installed from NuGet via standard methods.
|
||||||
|
|||||||
+52
-14
@@ -3,7 +3,7 @@
|
|||||||
module Giraffe.Htmx.Common
|
module Giraffe.Htmx.Common
|
||||||
|
|
||||||
/// <summary>The version of htmx embedded in the package</summary>
|
/// <summary>The version of htmx embedded in the package</summary>
|
||||||
let HtmxVersion = "2.0.10"
|
let HtmxVersion = "4.0.0-alpha8"
|
||||||
|
|
||||||
/// <summary>The path for the provided htmx script</summary>
|
/// <summary>The path for the provided htmx script</summary>
|
||||||
let internal htmxLocalScript = $"/_content/Giraffe.Htmx.Common/htmx.min.js?ver={HtmxVersion}"
|
let internal htmxLocalScript = $"/_content/Giraffe.Htmx.Common/htmx.min.js?ver={HtmxVersion}"
|
||||||
@@ -25,35 +25,73 @@ let internal toLowerBool (boolValue: bool) =
|
|||||||
|
|
||||||
|
|
||||||
/// <summary>Valid values for the <c>hx-swap</c> attribute / <c>HX-Reswap</c> header</summary>
|
/// <summary>Valid values for the <c>hx-swap</c> attribute / <c>HX-Reswap</c> header</summary>
|
||||||
/// <remarks>May be combined with <c>swap</c> / <c>settle</c> / <c>scroll</c> / <c>show</c> config)</remarks>
|
/// <remarks>May be combined with <c>swap</c> / <c>scroll</c> / <c>show</c> config)</remarks>
|
||||||
/// <seealso href="https://htmx.org/attributes/hx-swap/">Documentation</seealso>
|
/// <seealso href="https://four.htmx.org/attributes/hx-swap/">Documentation</seealso>
|
||||||
[<RequireQualifiedAccess>]
|
[<RequireQualifiedAccess>]
|
||||||
module HxSwap =
|
module HxSwap =
|
||||||
|
|
||||||
/// <summary>The default, replace the inner HTML of the target element</summary>
|
/// <summary>The default, replace the inner HTML of the target element</summary>
|
||||||
[<Literal>]
|
[<Literal>]
|
||||||
let InnerHtml = "innerHTML"
|
let InnerHtml = "innerHTML"
|
||||||
|
|
||||||
/// <summary>Replace the entire target element with the response</summary>
|
/// <summary>Replace the entire target element with the response</summary>
|
||||||
[<Literal>]
|
[<Literal>]
|
||||||
let OuterHtml = "outerHTML"
|
let OuterHtml = "outerHTML"
|
||||||
|
|
||||||
|
/// <summary>Morph the inner HTML of the target to the new content</summary>
|
||||||
|
[<Literal>]
|
||||||
|
let InnerMorph = "innerMorph"
|
||||||
|
|
||||||
|
/// <summary>Morph the outer HTML of the target to the new content</summary>
|
||||||
|
[<Literal>]
|
||||||
|
let OuterMorph = "innerMorph"
|
||||||
|
|
||||||
|
/// <summary>Replace the text content of the target without parsing the response as HTML</summary>
|
||||||
|
[<Literal>]
|
||||||
|
let TextContent = "textContent"
|
||||||
|
|
||||||
/// <summary>Insert the response before the target element</summary>
|
/// <summary>Insert the response before the target element</summary>
|
||||||
[<Literal>]
|
[<Literal>]
|
||||||
let BeforeBegin = "beforebegin"
|
let Before = "before"
|
||||||
|
|
||||||
|
/// <summary>Insert the response before the target element (pre-v4 name)</summary>
|
||||||
|
[<Literal>]
|
||||||
|
let BeforeBegin = Before
|
||||||
|
|
||||||
/// <summary>Insert the response before the first child of the target element</summary>
|
/// <summary>Insert the response before the first child of the target element</summary>
|
||||||
[<Literal>]
|
[<Literal>]
|
||||||
let AfterBegin = "afterbegin"
|
let Prepend = "prepend"
|
||||||
|
|
||||||
|
/// <summary>Insert the response before the first child of the target element (pre-v4 name)</summary>
|
||||||
|
[<Literal>]
|
||||||
|
let AfterBegin = Prepend
|
||||||
|
|
||||||
/// <summary>Insert the response after the last child of the target element</summary>
|
/// <summary>Insert the response after the last child of the target element</summary>
|
||||||
[<Literal>]
|
[<Literal>]
|
||||||
let BeforeEnd = "beforeend"
|
let Append = "append"
|
||||||
|
|
||||||
|
/// <summary>Insert the response after the last child of the target element (pre-v4 name)</summary>
|
||||||
|
[<Literal>]
|
||||||
|
let BeforeEnd = Append
|
||||||
|
|
||||||
/// <summary>Insert the response after the target element</summary>
|
/// <summary>Insert the response after the target element</summary>
|
||||||
[<Literal>]
|
[<Literal>]
|
||||||
let AfterEnd = "afterend"
|
let After = "after"
|
||||||
|
|
||||||
/// <summary>Does not append content from response (out of band items will still be processed).</summary>
|
/// <summary>Insert the response after the target element (pre-v4 name)</summary>
|
||||||
|
[<Literal>]
|
||||||
|
let AfterEnd = After
|
||||||
|
|
||||||
|
/// <summary>Delete the target element regardless of response</summary>
|
||||||
|
[<Literal>]
|
||||||
|
let Delete = "delete"
|
||||||
|
|
||||||
|
/// <summary>Does not append content from response (out of band items will still be processed)</summary>
|
||||||
[<Literal>]
|
[<Literal>]
|
||||||
let None = "none"
|
let None = "none"
|
||||||
|
|
||||||
|
/// <summary>Update existing elements by <c>id</c> and add new ones</summary>
|
||||||
|
/// <remarks>This requires the <c>upsert</c> extension</remarks>
|
||||||
|
/// <seealso href="https://four.htmx.org/extensions/upsert">Extension</seealso>
|
||||||
|
[<Literal>]
|
||||||
|
let Upsert = "upsert"
|
||||||
|
|||||||
@@ -2,4 +2,6 @@
|
|||||||
|
|
||||||
This package contains common code shared between [`Giraffe.Htmx`](https://www.nuget.org/packages/Giraffe.Htmx) and [`Giraffe.ViewEngine.Htmx`](https://www.nuget.org/packages/Giraffe.ViewEngine.Htmx), and will be automatically installed when you install either one. It also contains htmx as a static web asset, allowing it to be loaded from your local (or published) project.
|
This package contains common code shared between [`Giraffe.Htmx`](https://www.nuget.org/packages/Giraffe.Htmx) and [`Giraffe.ViewEngine.Htmx`](https://www.nuget.org/packages/Giraffe.ViewEngine.Htmx), and will be automatically installed when you install either one. It also contains htmx as a static web asset, allowing it to be loaded from your local (or published) project.
|
||||||
|
|
||||||
**htmx version: 2.0.10**
|
**htmx version: 4.0.0-alpha8**
|
||||||
|
|
||||||
|
_**NOTE:** Pay special attention to breaking changes highlighted in the packages listed above._
|
||||||
Vendored
+1
-1
File diff suppressed because one or more lines are too long
@@ -2,11 +2,14 @@
|
|||||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFrameworks>net8.0;net9.0;net10.0</TargetFrameworks>
|
<TargetFrameworks>net8.0;net9.0;net10.0</TargetFrameworks>
|
||||||
<VersionPrefix>2.0.10</VersionPrefix>
|
<VersionPrefix>4.0.0</VersionPrefix>
|
||||||
|
<VersionSuffix>alpha8</VersionSuffix>
|
||||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||||
<PackageReleaseNotes>- Updates provided script and CDN links to serve htmx 2.0.10 (no header or attribute changes)
|
<PackageReleaseNotes>Update htmx 4 to alpha8
|
||||||
|
- [Common] Update provided htmx 4 to 4.0.0-alpha8
|
||||||
|
- [View Engine] Updated script tags to pull htmx 4.0.0-alpha8
|
||||||
|
|
||||||
NOTE: As of 2.0.6, the CDN for htmx changed from unpkg.com to cdn.jsdelivr.net; sites with Content-Security-Policy headers will want to update their allowed script-src domains accordingly
|
See package and prior alpha release READMEs; v2 to v4 is not an update-and-forget-it release
|
||||||
</PackageReleaseNotes>
|
</PackageReleaseNotes>
|
||||||
<Authors>danieljsummers</Authors>
|
<Authors>danieljsummers</Authors>
|
||||||
<Company>Bit Badger Solutions</Company>
|
<Company>Bit Badger Solutions</Company>
|
||||||
|
|||||||
@@ -0,0 +1,40 @@
|
|||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
# Visual Studio Version 16
|
||||||
|
VisualStudioVersion = 16.0.30114.105
|
||||||
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
|
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "Giraffe.Htmx", "Htmx\Giraffe.Htmx.fsproj", "{8AB3085C-5236-485A-8565-A09106E72E1E}"
|
||||||
|
EndProject
|
||||||
|
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "Giraffe.ViewEngine.Htmx", "ViewEngine.Htmx\Giraffe.ViewEngine.Htmx.fsproj", "{F718B3C1-EE01-4F04-ABCE-BF2AE700FDA9}"
|
||||||
|
EndProject
|
||||||
|
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "Giraffe.Htmx.Common", "Common\Giraffe.Htmx.Common.fsproj", "{75D66845-F93A-4463-AD29-A8B16E4D4BA9}"
|
||||||
|
EndProject
|
||||||
|
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "Tests", "Tests\Tests.fsproj", "{39823773-4311-4E79-9CA0-F9DDC40CAF6A}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
Release|Any CPU = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{8AB3085C-5236-485A-8565-A09106E72E1E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{8AB3085C-5236-485A-8565-A09106E72E1E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{8AB3085C-5236-485A-8565-A09106E72E1E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{8AB3085C-5236-485A-8565-A09106E72E1E}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{F718B3C1-EE01-4F04-ABCE-BF2AE700FDA9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{F718B3C1-EE01-4F04-ABCE-BF2AE700FDA9}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{F718B3C1-EE01-4F04-ABCE-BF2AE700FDA9}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{F718B3C1-EE01-4F04-ABCE-BF2AE700FDA9}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{75D66845-F93A-4463-AD29-A8B16E4D4BA9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{75D66845-F93A-4463-AD29-A8B16E4D4BA9}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{75D66845-F93A-4463-AD29-A8B16E4D4BA9}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{75D66845-F93A-4463-AD29-A8B16E4D4BA9}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{39823773-4311-4E79-9CA0-F9DDC40CAF6A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{39823773-4311-4E79-9CA0-F9DDC40CAF6A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{39823773-4311-4E79-9CA0-F9DDC40CAF6A}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{39823773-4311-4E79-9CA0-F9DDC40CAF6A}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
<Solution>
|
|
||||||
<Project Path="Common/Giraffe.Htmx.Common.fsproj" />
|
|
||||||
<Project Path="Htmx/Giraffe.Htmx.fsproj" />
|
|
||||||
<Project Path="Tests/Tests.fsproj" />
|
|
||||||
<Project Path="ViewEngine.Htmx/Giraffe.ViewEngine.Htmx.fsproj" />
|
|
||||||
</Solution>
|
|
||||||
@@ -24,6 +24,7 @@ type IHeaderDictionary with
|
|||||||
with get () = hdr this "HX-History-Restore-Request" |> Option.map bool.Parse
|
with get () = hdr this "HX-History-Restore-Request" |> Option.map bool.Parse
|
||||||
|
|
||||||
/// <summary>The user response to an <c>hx-prompt</c></summary>
|
/// <summary>The user response to an <c>hx-prompt</c></summary>
|
||||||
|
[<Obsolete "hx-prompt is removed in v4">]
|
||||||
member this.HxPrompt
|
member this.HxPrompt
|
||||||
with get () = hdr this "HX-Prompt"
|
with get () = hdr this "HX-Prompt"
|
||||||
|
|
||||||
@@ -31,15 +32,29 @@ type IHeaderDictionary with
|
|||||||
member this.HxRequest
|
member this.HxRequest
|
||||||
with get () = hdr this "HX-Request" |> Option.map bool.Parse
|
with get () = hdr this "HX-Request" |> Option.map bool.Parse
|
||||||
|
|
||||||
|
/// <summary>The tag name (fst) and <c>id</c> attribute (snd) of the element triggering this request</summary>
|
||||||
|
member this.HxSource
|
||||||
|
with get () =
|
||||||
|
match hdr this "HX-Source" with
|
||||||
|
| Some src ->
|
||||||
|
let parts = src.Split "#"
|
||||||
|
if parts.Length = 1 then
|
||||||
|
Some (parts[0], None)
|
||||||
|
else
|
||||||
|
Some (parts[0], if parts[1] <> "" then Some parts[1] else None)
|
||||||
|
| None -> None
|
||||||
|
|
||||||
/// <summary>The <c>id</c> attribute of the target element if it exists</summary>
|
/// <summary>The <c>id</c> attribute of the target element if it exists</summary>
|
||||||
member this.HxTarget
|
member this.HxTarget
|
||||||
with get () = hdr this "HX-Target"
|
with get () = hdr this "HX-Target"
|
||||||
|
|
||||||
/// <summary>The <c>id</c> attribute of the triggered element if it exists</summary>
|
/// <summary>The <c>id</c> attribute of the triggered element if it exists</summary>
|
||||||
|
[<Obsolete "HX-Trigger is removed in v4; use the second item of HX-Source">]
|
||||||
member this.HxTrigger
|
member this.HxTrigger
|
||||||
with get () = hdr this "HX-Trigger"
|
with get () = hdr this "HX-Trigger"
|
||||||
|
|
||||||
/// <summary>The <c>name</c> attribute of the triggered element if it exists</summary>
|
/// <summary>The <c>name</c> attribute of the triggered element if it exists</summary>
|
||||||
|
[<Obsolete "HX-Trigger-Name is removed in v4; may be available via extension, but will be removed from this library">]
|
||||||
member this.HxTriggerName
|
member this.HxTriggerName
|
||||||
with get () = hdr this "HX-Trigger-Name"
|
with get () = hdr this "HX-Trigger-Name"
|
||||||
|
|
||||||
|
|||||||
+7
-5
@@ -2,9 +2,11 @@
|
|||||||
|
|
||||||
This package enables server-side support for [htmx](https://htmx.org) within [Giraffe](https://giraffe.wiki) and ASP.NET's `HttpContext`.
|
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.10**
|
**htmx version: 4.0.0-alpha8**
|
||||||
|
|
||||||
_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.*._
|
_Upgrading from v2.x: the [migration guide](https://four.htmx.org/migration-guide-htmx-4/) lists changes for v4. For this package, the `HX-Trigger` and `HX-Trigger-Name` headers are marked obsolete. They are replaced by `HX-Source`, which provides the triggering tag name and `id` attribute. The `HX-Prompt` header has also been marked as obsolete, as the `hx-prompt` attribute which generated its content has been removed._
|
||||||
|
|
||||||
|
_Obsolete elements will be removed in the first production v4 release._
|
||||||
|
|
||||||
### Setup
|
### Setup
|
||||||
|
|
||||||
@@ -18,9 +20,9 @@ To obtain a request header, using the `IHeaderDictionary` extension properties:
|
|||||||
```fsharp
|
```fsharp
|
||||||
let myHandler : HttpHander =
|
let myHandler : HttpHander =
|
||||||
fun next ctx ->
|
fun next ctx ->
|
||||||
match ctx.HxPrompt with
|
match ctx.Target with
|
||||||
| Some prompt -> ... // do something with the text the user provided
|
| Some elt -> ... // do something with id of the target element
|
||||||
| None -> ... // no text provided
|
| None -> ... // no target element provided
|
||||||
```
|
```
|
||||||
|
|
||||||
To set a response header:
|
To set a response header:
|
||||||
|
|||||||
+34
-7
@@ -6,7 +6,7 @@ open Giraffe.Htmx
|
|||||||
/// Test to ensure the version was updated
|
/// Test to ensure the version was updated
|
||||||
let version =
|
let version =
|
||||||
test "HtmxVersion is correct" {
|
test "HtmxVersion is correct" {
|
||||||
Expect.equal HtmxVersion "2.0.10" "htmx version incorrect"
|
Expect.equal HtmxVersion "4.0.0-alpha8" "htmx version incorrect"
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Tests for the HxSwap module
|
/// Tests for the HxSwap module
|
||||||
@@ -18,21 +18,48 @@ let swap =
|
|||||||
test "OuterHtml is correct" {
|
test "OuterHtml is correct" {
|
||||||
Expect.equal HxSwap.OuterHtml "outerHTML" "Outer HTML swap value incorrect"
|
Expect.equal HxSwap.OuterHtml "outerHTML" "Outer HTML swap value incorrect"
|
||||||
}
|
}
|
||||||
test "BeforeBegin is correct" {
|
test "InnerMorph is correct" {
|
||||||
Expect.equal HxSwap.BeforeBegin "beforebegin" "Before Begin swap value incorrect"
|
Expect.equal HxSwap.InnerMorph "innerMorph" "Inner Morph swap value incorrect"
|
||||||
}
|
}
|
||||||
test "BeforeEnd is correct" {
|
test "OuterMorph is correct" {
|
||||||
Expect.equal HxSwap.BeforeEnd "beforeend" "Before End swap value incorrect"
|
Expect.equal HxSwap.OuterMorph "innerMorph" "Outer Morph swap value incorrect"
|
||||||
|
}
|
||||||
|
test "TextContent is correct" {
|
||||||
|
Expect.equal HxSwap.TextContent "textContent" "Text Content swap value incorrect"
|
||||||
|
}
|
||||||
|
test "Before is correct" {
|
||||||
|
Expect.equal HxSwap.Before "before" "Before swap value incorrect"
|
||||||
|
}
|
||||||
|
test "BeforeBegin is correct" {
|
||||||
|
Expect.equal HxSwap.BeforeBegin HxSwap.Before "Before Begin swap value incorrect"
|
||||||
|
}
|
||||||
|
test "Prepend is correct" {
|
||||||
|
Expect.equal HxSwap.Prepend "prepend" "Prepend swap value incorrect"
|
||||||
}
|
}
|
||||||
test "AfterBegin is correct" {
|
test "AfterBegin is correct" {
|
||||||
Expect.equal HxSwap.AfterBegin "afterbegin" "After Begin swap value incorrect"
|
Expect.equal HxSwap.AfterBegin HxSwap.Prepend "Prepend swap value incorrect"
|
||||||
|
}
|
||||||
|
test "Append is correct" {
|
||||||
|
Expect.equal HxSwap.Append "append" "Append swap value incorrect"
|
||||||
|
}
|
||||||
|
test "BeforeEnd is correct" {
|
||||||
|
Expect.equal HxSwap.BeforeEnd HxSwap.Append "Before End swap value incorrect"
|
||||||
|
}
|
||||||
|
test "After is correct" {
|
||||||
|
Expect.equal HxSwap.After "after" "After swap value incorrect"
|
||||||
}
|
}
|
||||||
test "AfterEnd is correct" {
|
test "AfterEnd is correct" {
|
||||||
Expect.equal HxSwap.AfterEnd "afterend" "After End swap value incorrect"
|
Expect.equal HxSwap.AfterEnd HxSwap.After "After End swap value incorrect"
|
||||||
|
}
|
||||||
|
test "Delete is correct" {
|
||||||
|
Expect.equal HxSwap.Delete "delete" "Delete swap value incorrect"
|
||||||
}
|
}
|
||||||
test "None is correct" {
|
test "None is correct" {
|
||||||
Expect.equal HxSwap.None "none" "None swap value incorrect"
|
Expect.equal HxSwap.None "none" "None swap value incorrect"
|
||||||
}
|
}
|
||||||
|
test "Upsert is correct" {
|
||||||
|
Expect.equal HxSwap.Upsert "upsert" "Upsert swap value incorrect"
|
||||||
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
/// All tests for this module
|
/// All tests for this module
|
||||||
|
|||||||
+93
-51
@@ -3,7 +3,6 @@ module Htmx
|
|||||||
open System
|
open System
|
||||||
open Expecto
|
open Expecto
|
||||||
open Giraffe.Htmx
|
open Giraffe.Htmx
|
||||||
open Microsoft.AspNetCore.Html
|
|
||||||
open Microsoft.AspNetCore.Http
|
open Microsoft.AspNetCore.Http
|
||||||
open NSubstitute
|
open NSubstitute
|
||||||
|
|
||||||
@@ -74,21 +73,6 @@ let dictExtensions =
|
|||||||
ctx.Request.Headers.HxHistoryRestoreRequest.Value "The header should have been false"
|
ctx.Request.Headers.HxHistoryRestoreRequest.Value "The header should have been false"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
testList "HxPrompt" [
|
|
||||||
test "succeeds when the header is not present" {
|
|
||||||
let ctx = Substitute.For<HttpContext>()
|
|
||||||
ctx.Request.Headers.ReturnsForAnyArgs(HeaderDictionary()) |> ignore
|
|
||||||
Expect.isNone ctx.Request.Headers.HxPrompt "There should not have been a header returned"
|
|
||||||
}
|
|
||||||
test "succeeds when the header is present" {
|
|
||||||
let ctx = Substitute.For<HttpContext>()
|
|
||||||
let dic = HeaderDictionary()
|
|
||||||
dic.Add("HX-Prompt", "of course")
|
|
||||||
ctx.Request.Headers.ReturnsForAnyArgs dic |> ignore
|
|
||||||
Expect.isSome ctx.Request.Headers.HxPrompt "There should be a header present"
|
|
||||||
Expect.equal ctx.Request.Headers.HxPrompt.Value "of course" "The header value was incorrect"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
testList "HxRequest" [
|
testList "HxRequest" [
|
||||||
test "succeeds when the header is not present" {
|
test "succeeds when the header is not present" {
|
||||||
let ctx = Substitute.For<HttpContext>()
|
let ctx = Substitute.For<HttpContext>()
|
||||||
@@ -112,6 +96,44 @@ let dictExtensions =
|
|||||||
Expect.isFalse ctx.Request.Headers.HxRequest.Value "The header should have been false"
|
Expect.isFalse ctx.Request.Headers.HxRequest.Value "The header should have been false"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
testList "HxSource" [
|
||||||
|
test "succeeds when the header is not present" {
|
||||||
|
let ctx = Substitute.For<HttpContext>()
|
||||||
|
ctx.Request.Headers.ReturnsForAnyArgs(HeaderDictionary()) |> ignore
|
||||||
|
Expect.isNone ctx.Request.Headers.HxSource "There should not have been a header returned"
|
||||||
|
}
|
||||||
|
test "succeeds when the header is present and both parts exist" {
|
||||||
|
let ctx = Substitute.For<HttpContext>()
|
||||||
|
let dic = HeaderDictionary()
|
||||||
|
dic.Add("HX-Source", "button#theId")
|
||||||
|
ctx.Request.Headers.ReturnsForAnyArgs dic |> ignore
|
||||||
|
let hdr = ctx.Request.Headers.HxSource
|
||||||
|
Expect.isSome hdr "There should be a header present"
|
||||||
|
Expect.equal (fst hdr.Value) "button" "The source tag was incorrect"
|
||||||
|
Expect.isSome (snd hdr.Value) "There should be a source ID present"
|
||||||
|
Expect.equal (snd hdr.Value).Value "theId" "The source ID was incorrect"
|
||||||
|
}
|
||||||
|
test "succeeds when the header is present and ID is blank" {
|
||||||
|
let ctx = Substitute.For<HttpContext>()
|
||||||
|
let dic = HeaderDictionary()
|
||||||
|
dic.Add("HX-Source", "a#")
|
||||||
|
ctx.Request.Headers.ReturnsForAnyArgs dic |> ignore
|
||||||
|
let hdr = ctx.Request.Headers.HxSource
|
||||||
|
Expect.isSome hdr "There should be a header present"
|
||||||
|
Expect.equal (fst hdr.Value) "a" "The source tag was incorrect"
|
||||||
|
Expect.isNone (snd hdr.Value) "There should not be a source ID present"
|
||||||
|
}
|
||||||
|
test "succeeds when the header is present and ID is missing" {
|
||||||
|
let ctx = Substitute.For<HttpContext>()
|
||||||
|
let dic = HeaderDictionary()
|
||||||
|
dic.Add("HX-Source", "form")
|
||||||
|
ctx.Request.Headers.ReturnsForAnyArgs dic |> ignore
|
||||||
|
let hdr = ctx.Request.Headers.HxSource
|
||||||
|
Expect.isSome hdr "There should be a header present"
|
||||||
|
Expect.equal (fst hdr.Value) "form" "The source tag was incorrect"
|
||||||
|
Expect.isNone (snd hdr.Value) "There should not be a source ID present"
|
||||||
|
}
|
||||||
|
]
|
||||||
testList "HxTarget" [
|
testList "HxTarget" [
|
||||||
test "succeeds when the header is not present" {
|
test "succeeds when the header is not present" {
|
||||||
let ctx = Substitute.For<HttpContext>()
|
let ctx = Substitute.For<HttpContext>()
|
||||||
@@ -127,36 +149,6 @@ let dictExtensions =
|
|||||||
Expect.equal ctx.Request.Headers.HxTarget.Value "#leItem" "The header value was incorrect"
|
Expect.equal ctx.Request.Headers.HxTarget.Value "#leItem" "The header value was incorrect"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
testList "HxTrigger" [
|
|
||||||
test "succeeds when the header is not present" {
|
|
||||||
let ctx = Substitute.For<HttpContext>()
|
|
||||||
ctx.Request.Headers.ReturnsForAnyArgs (HeaderDictionary ()) |> ignore
|
|
||||||
Expect.isNone ctx.Request.Headers.HxTrigger "There should not have been a header returned"
|
|
||||||
}
|
|
||||||
test "succeeds when the header is present" {
|
|
||||||
let ctx = Substitute.For<HttpContext>()
|
|
||||||
let dic = HeaderDictionary()
|
|
||||||
dic.Add("HX-Trigger", "#trig")
|
|
||||||
ctx.Request.Headers.ReturnsForAnyArgs dic |> ignore
|
|
||||||
Expect.isSome ctx.Request.Headers.HxTrigger "There should be a header present"
|
|
||||||
Expect.equal ctx.Request.Headers.HxTrigger.Value "#trig" "The header value was incorrect"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
testList "HxTriggerName" [
|
|
||||||
test "succeeds when the header is not present" {
|
|
||||||
let ctx = Substitute.For<HttpContext>()
|
|
||||||
ctx.Request.Headers.ReturnsForAnyArgs(HeaderDictionary()) |> ignore
|
|
||||||
Expect.isNone ctx.Request.Headers.HxTriggerName "There should not have been a header returned"
|
|
||||||
}
|
|
||||||
test "HxTriggerName succeeds when the header is present" {
|
|
||||||
let ctx = Substitute.For<HttpContext>()
|
|
||||||
let dic = HeaderDictionary()
|
|
||||||
dic.Add("HX-Trigger-Name", "click")
|
|
||||||
ctx.Request.Headers.ReturnsForAnyArgs dic |> ignore
|
|
||||||
Expect.isSome ctx.Request.Headers.HxTriggerName "There should be a header present"
|
|
||||||
Expect.equal ctx.Request.Headers.HxTriggerName.Value "click" "The header value was incorrect"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
]
|
]
|
||||||
|
|
||||||
/// Tests for the HttpRequest extension properties
|
/// Tests for the HttpRequest extension properties
|
||||||
@@ -167,7 +159,7 @@ let reqExtensions =
|
|||||||
let ctx = Substitute.For<HttpContext>()
|
let ctx = Substitute.For<HttpContext>()
|
||||||
ctx.Request.Headers.ReturnsForAnyArgs(HeaderDictionary()) |> ignore
|
ctx.Request.Headers.ReturnsForAnyArgs(HeaderDictionary()) |> ignore
|
||||||
Expect.isFalse ctx.Request.IsHtmx "The request should not be an htmx request"
|
Expect.isFalse ctx.Request.IsHtmx "The request should not be an htmx request"
|
||||||
}
|
}
|
||||||
test "succeeds when request is from htmx" {
|
test "succeeds when request is from htmx" {
|
||||||
let ctx = Substitute.For<HttpContext>()
|
let ctx = Substitute.For<HttpContext>()
|
||||||
let dic = HeaderDictionary()
|
let dic = HeaderDictionary()
|
||||||
@@ -204,7 +196,7 @@ open System.Threading.Tasks
|
|||||||
|
|
||||||
/// Dummy "next" parameter to get the pipeline to execute/terminate
|
/// Dummy "next" parameter to get the pipeline to execute/terminate
|
||||||
let next (ctx: HttpContext) = Task.FromResult(Some ctx)
|
let next (ctx: HttpContext) = Task.FromResult(Some ctx)
|
||||||
|
|
||||||
/// Tests for the HttpHandler functions provided in the Handlers module
|
/// Tests for the HttpHandler functions provided in the Handlers module
|
||||||
let handlers =
|
let handlers =
|
||||||
testList "HandlerTests" [
|
testList "HandlerTests" [
|
||||||
@@ -281,7 +273,7 @@ let handlers =
|
|||||||
let! _ = withHxReselect "#test" next ctx
|
let! _ = withHxReselect "#test" next ctx
|
||||||
Expect.isTrue (dic.ContainsKey "HX-Reselect") "The HX-Reselect header should be present"
|
Expect.isTrue (dic.ContainsKey "HX-Reselect") "The HX-Reselect header should be present"
|
||||||
Expect.equal dic["HX-Reselect"].[0] "#test" "The HX-Reselect value was incorrect"
|
Expect.equal dic["HX-Reselect"].[0] "#test" "The HX-Reselect value was incorrect"
|
||||||
}
|
}
|
||||||
testTask "withHxReswap succeeds" {
|
testTask "withHxReswap succeeds" {
|
||||||
let ctx = Substitute.For<HttpContext>()
|
let ctx = Substitute.For<HttpContext>()
|
||||||
let dic = HeaderDictionary()
|
let dic = HeaderDictionary()
|
||||||
@@ -289,7 +281,7 @@ let handlers =
|
|||||||
let! _ = withHxReswap HxSwap.BeforeEnd next ctx
|
let! _ = withHxReswap HxSwap.BeforeEnd next ctx
|
||||||
Expect.isTrue (dic.ContainsKey "HX-Reswap") "The HX-Reswap header should be present"
|
Expect.isTrue (dic.ContainsKey "HX-Reswap") "The HX-Reswap header should be present"
|
||||||
Expect.equal dic["HX-Reswap"].[0] HxSwap.BeforeEnd "The HX-Reswap value was incorrect"
|
Expect.equal dic["HX-Reswap"].[0] HxSwap.BeforeEnd "The HX-Reswap value was incorrect"
|
||||||
}
|
}
|
||||||
testTask "withHxRetarget succeeds" {
|
testTask "withHxRetarget succeeds" {
|
||||||
let ctx = Substitute.For<HttpContext>()
|
let ctx = Substitute.For<HttpContext>()
|
||||||
let dic = HeaderDictionary()
|
let dic = HeaderDictionary()
|
||||||
@@ -366,5 +358,55 @@ let script =
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
#nowarn 44 // Obsolete items still have tests
|
||||||
|
let dictExtensionsObs =
|
||||||
|
testList "IHeaderDictionaryExtensions (Obsolete)" [
|
||||||
|
testList "HxPrompt" [
|
||||||
|
test "succeeds when the header is not present" {
|
||||||
|
let ctx = Substitute.For<HttpContext>()
|
||||||
|
ctx.Request.Headers.ReturnsForAnyArgs(HeaderDictionary()) |> ignore
|
||||||
|
Expect.isNone ctx.Request.Headers.HxPrompt "There should not have been a header returned"
|
||||||
|
}
|
||||||
|
test "succeeds when the header is present" {
|
||||||
|
let ctx = Substitute.For<HttpContext>()
|
||||||
|
let dic = HeaderDictionary()
|
||||||
|
dic.Add("HX-Prompt", "of course")
|
||||||
|
ctx.Request.Headers.ReturnsForAnyArgs dic |> ignore
|
||||||
|
Expect.isSome ctx.Request.Headers.HxPrompt "There should be a header present"
|
||||||
|
Expect.equal ctx.Request.Headers.HxPrompt.Value "of course" "The header value was incorrect"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
testList "HxTrigger" [
|
||||||
|
test "succeeds when the header is not present" {
|
||||||
|
let ctx = Substitute.For<HttpContext>()
|
||||||
|
ctx.Request.Headers.ReturnsForAnyArgs (HeaderDictionary ()) |> ignore
|
||||||
|
Expect.isNone ctx.Request.Headers.HxTrigger "There should not have been a header returned"
|
||||||
|
}
|
||||||
|
test "succeeds when the header is present" {
|
||||||
|
let ctx = Substitute.For<HttpContext>()
|
||||||
|
let dic = HeaderDictionary()
|
||||||
|
dic.Add("HX-Trigger", "#trig")
|
||||||
|
ctx.Request.Headers.ReturnsForAnyArgs dic |> ignore
|
||||||
|
Expect.isSome ctx.Request.Headers.HxTrigger "There should be a header present"
|
||||||
|
Expect.equal ctx.Request.Headers.HxTrigger.Value "#trig" "The header value was incorrect"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
testList "HxTriggerName" [
|
||||||
|
test "succeeds when the header is not present" {
|
||||||
|
let ctx = Substitute.For<HttpContext>()
|
||||||
|
ctx.Request.Headers.ReturnsForAnyArgs(HeaderDictionary()) |> ignore
|
||||||
|
Expect.isNone ctx.Request.Headers.HxTriggerName "There should not have been a header returned"
|
||||||
|
}
|
||||||
|
test "HxTriggerName succeeds when the header is present" {
|
||||||
|
let ctx = Substitute.For<HttpContext>()
|
||||||
|
let dic = HeaderDictionary()
|
||||||
|
dic.Add("HX-Trigger-Name", "click")
|
||||||
|
ctx.Request.Headers.ReturnsForAnyArgs dic |> ignore
|
||||||
|
Expect.isSome ctx.Request.Headers.HxTriggerName "There should be a header present"
|
||||||
|
Expect.equal ctx.Request.Headers.HxTriggerName.Value "click" "The header value was incorrect"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
]
|
||||||
|
|
||||||
/// All tests for this module
|
/// All tests for this module
|
||||||
let allTests = testList "Htmx" [ dictExtensions; reqExtensions; handlers; script ]
|
let allTests = testList "Htmx" [ dictExtensions; reqExtensions; handlers; script; dictExtensionsObs ]
|
||||||
|
|||||||
+675
-413
File diff suppressed because it is too large
Load Diff
+391
-209
File diff suppressed because it is too large
Load Diff
@@ -2,9 +2,13 @@
|
|||||||
|
|
||||||
This package enables [htmx](https://htmx.org) support within the [Giraffe](https://giraffe.wiki) view engine.
|
This package enables [htmx](https://htmx.org) support within the [Giraffe](https://giraffe.wiki) view engine.
|
||||||
|
|
||||||
**htmx version: 2.0.10**
|
**htmx version: 4.0.0-alpha8**
|
||||||
|
|
||||||
_Upgrading from v1.x: see [the migration guide](https://htmx.org/migration-guide-htmx-1/) for changes_
|
_Upgrading from v2.x: see [the migration guide](https://four.htmx.org/migration-guide-htmx-4/) for changes, which are plentiful. htmx switches from `XMLHTTPRequest` to `fetch`, and many changes are related to the new event cycle._
|
||||||
|
|
||||||
|
_Inheritance is now explicit; to have an attribute's value inherited to its children, wrap the attribute in `hxInherited` (ex. `hxInherited (_hxTarget "#main")`). Values can be appended to inherited values as well using the `hxAppend` modifier._
|
||||||
|
|
||||||
|
_Several constructs have been marked obsolete in this release, and will be removed from the first production release of v4. With the exception of `_hxDisable`, though (which now functions as the deprecated `_hxDisabledElt` did), this should not introduce compile errors. Rather, this package will raise warnings for deprecated constructs, along with suggestions of what to use instead._
|
||||||
|
|
||||||
### Setup
|
### Setup
|
||||||
|
|
||||||
@@ -21,10 +25,11 @@ let autoload =
|
|||||||
```
|
```
|
||||||
|
|
||||||
Support modules include:
|
Support modules include:
|
||||||
|
- `HxConfig` _(new in v4)_
|
||||||
- `HxEncoding`
|
- `HxEncoding`
|
||||||
- `HxHeaders`
|
- `HxHeaders`
|
||||||
- `HxParams`
|
- ~~`HxParams`~~ _(removed in v4)_
|
||||||
- `HxRequest`
|
- ~~`HxRequest`~~ _(renamed to `HxConfig`)_
|
||||||
- `HxSwap` (requires `open Giraffe.Htmx`)
|
- `HxSwap` (requires `open Giraffe.Htmx`)
|
||||||
- `HxTrigger`
|
- `HxTrigger`
|
||||||
- `HxVals`
|
- `HxVals`
|
||||||
|
|||||||
Reference in New Issue
Block a user