From 7e013f822593545a967fb0f50768e864bc88caba Mon Sep 17 00:00:00 2001 From: "Daniel J. Summers" Date: Fri, 24 Jan 2025 18:51:48 -0500 Subject: [PATCH 1/2] First cut of fixi library --- .gitignore | 3 + src/Directory.Build.props | 18 +++++ src/Giraffe.Fixi.sln | 28 +++++++ src/Library/Giraffe.Fixi.fsproj | 12 +++ src/Library/Library.fs | 116 ++++++++++++++++++++++++++++ src/Tests/Giraffe.Fixi.Tests.fsproj | 12 +++ src/Tests/Program.fs | 2 + 7 files changed, 191 insertions(+) create mode 100644 .gitignore create mode 100644 src/Directory.Build.props create mode 100644 src/Giraffe.Fixi.sln create mode 100644 src/Library/Giraffe.Fixi.fsproj create mode 100644 src/Library/Library.fs create mode 100644 src/Tests/Giraffe.Fixi.Tests.fsproj create mode 100644 src/Tests/Program.fs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a33248f --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +src/.idea +src/**/bin +src/**/obj diff --git a/src/Directory.Build.props b/src/Directory.Build.props new file mode 100644 index 0000000..149c471 --- /dev/null +++ b/src/Directory.Build.props @@ -0,0 +1,18 @@ + + + + net8.0;net9.0 + 0.2.2 + true + Initial version + danieljsummers + Bit Badger Solutions + https://git.bitbadger.solutions/bit-badger/Giraffe.Fixi + false + https://git.bitbadger.solutions/bit-badger/Giraffe.Fixi + Git + MIT License + MIT + Giraffe fixi + + diff --git a/src/Giraffe.Fixi.sln b/src/Giraffe.Fixi.sln new file mode 100644 index 0000000..815071c --- /dev/null +++ b/src/Giraffe.Fixi.sln @@ -0,0 +1,28 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.0.31903.59 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "Giraffe.Fixi", "Library\Giraffe.Fixi.fsproj", "{E450411F-C6F9-4373-B9B3-9788CBA3CA36}" +EndProject +Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "Giraffe.Fixi.Tests", "Tests\Giraffe.Fixi.Tests.fsproj", "{4C327E9B-3340-4608-8444-05770274285C}" +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 + {E450411F-C6F9-4373-B9B3-9788CBA3CA36}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E450411F-C6F9-4373-B9B3-9788CBA3CA36}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E450411F-C6F9-4373-B9B3-9788CBA3CA36}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E450411F-C6F9-4373-B9B3-9788CBA3CA36}.Release|Any CPU.Build.0 = Release|Any CPU + {4C327E9B-3340-4608-8444-05770274285C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4C327E9B-3340-4608-8444-05770274285C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4C327E9B-3340-4608-8444-05770274285C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4C327E9B-3340-4608-8444-05770274285C}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal diff --git a/src/Library/Giraffe.Fixi.fsproj b/src/Library/Giraffe.Fixi.fsproj new file mode 100644 index 0000000..f551555 --- /dev/null +++ b/src/Library/Giraffe.Fixi.fsproj @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/src/Library/Library.fs b/src/Library/Library.fs new file mode 100644 index 0000000..c65b48e --- /dev/null +++ b/src/Library/Library.fs @@ -0,0 +1,116 @@ +namespace Giraffe.Fixi + +open Microsoft.AspNetCore.Http +open Microsoft.Extensions.Primitives + +/// Module to hold extensions +[] +module Extensions = + + /// Extensions to the header dictionary + type IHeaderDictionary with + + /// Indicates that the request was generated from fixi + member this.FxRequest + with get () = not (this["FX-Request"] = StringValues.Empty) + +/// Valid values for the fx-swap attribute +type FxSwap = + + /// Replace the entire target element with the response (the default) + | OuterHtml + + /// Replace the inner HTML of the target element + | InnerHtml + + /// Insert the response before the target element + | BeforeBegin + + /// Insert the response before the first child of the target element + | AfterBegin + + /// Insert the response after the last child of the target element + | BeforeEnd + + /// Insert the response after the target element + | AfterEnd + + override this.ToString() = + match this with + | OuterHtml -> "outerHTML" + | InnerHtml -> "innerHTML" + | BeforeBegin -> "beforebegin" + | AfterBegin -> "afterbegin" + | BeforeEnd -> "beforeend" + | AfterEnd -> "afterend" + + +open Giraffe.ViewEngine + +/// Attributes and flags for fixi +[] +module FixiAttrs = + + /// Issue a request to the given URL + /// The URL to which the request should be issued + /// A configured fx-action attribute + let _fxAction url = + attr "fx-action" url + + /// Exclude this element (and below) from fixi's behavior + let _fxIgnore = + flag "fx-ignore" + + /// Specify the HTTP method for the fixi request + /// The HTTP method to use for the request + /// A configured fx-method attribute + /// Consider _fxGet, _fxPost, etc. + let _fxMethod (it: string) = + attr "fx-method" (it.ToUpperInvariant()) + + /// Specify the swap strategy + /// The swap strategy to use + /// A configured fx-swap attribute + let _fxSwap (swap: FxSwap) = + attr "fx-swap" (string swap) + + /// Specify the target for the swap + /// The CSS selector for the swap target + /// A configured fx-target attribute + let _fxTarget selector = + attr "fx-target" selector + + /// The event which should trigger this request + /// The name of the event + /// A configured fx-trigger attribute + /// The event should not start with "on"; use "click", not "onclick" + let _fxTrigger event = + attr "fx-trigger" event + +/// Canned fx-method attributes for common HTTP methods +[] +module FixiMethods = + + /// An fx-method="DELETE" attribute + let _fxDelete = + _fxMethod "DELETE" + + /// An fx-method="HEAD" attribute + let _fxHead = + _fxMethod "HEAD" + + /// An fx-method="GET" attribute + let _fxGet = + _fxMethod "GET" + + /// An fx-method="PATCH" attribute + let _fxPatch = + _fxMethod "PATCH" + + /// An fx-method="POST" attribute + let _fxPost = + _fxMethod "POST" + + /// An fx-method="PUT" attribute + let _fxPut = + _fxMethod "PUT" diff --git a/src/Tests/Giraffe.Fixi.Tests.fsproj b/src/Tests/Giraffe.Fixi.Tests.fsproj new file mode 100644 index 0000000..248c750 --- /dev/null +++ b/src/Tests/Giraffe.Fixi.Tests.fsproj @@ -0,0 +1,12 @@ + + + + Exe + net9.0 + + + + + + + diff --git a/src/Tests/Program.fs b/src/Tests/Program.fs new file mode 100644 index 0000000..d6818ab --- /dev/null +++ b/src/Tests/Program.fs @@ -0,0 +1,2 @@ +// For more information see https://aka.ms/fsharp-console-apps +printfn "Hello from F#" -- 2.47.1 From eab2ced1c712e1c076a5d1f058a2136321ca4f1f Mon Sep 17 00:00:00 2001 From: "Daniel J. Summers" Date: Tue, 28 Jan 2025 22:48:42 -0500 Subject: [PATCH 2/2] Add tests; tweak API; add pkg items --- src/Directory.Build.props | 2 +- src/Library/Giraffe.Fixi.fsproj | 8 ++ src/Library/Library.fs | 50 ++++++------ src/Library/README.md | 21 +++++ src/Library/icon.png | Bin 0 -> 4397 bytes src/Tests/Giraffe.Fixi.Tests.fsproj | 8 ++ src/Tests/Program.fs | 114 +++++++++++++++++++++++++++- 7 files changed, 175 insertions(+), 28 deletions(-) create mode 100644 src/Library/README.md create mode 100644 src/Library/icon.png diff --git a/src/Directory.Build.props b/src/Directory.Build.props index 149c471..0f399c0 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -2,7 +2,7 @@ net8.0;net9.0 - 0.2.2 + 0.5.7 true Initial version danieljsummers diff --git a/src/Library/Giraffe.Fixi.fsproj b/src/Library/Giraffe.Fixi.fsproj index f551555..698cb94 100644 --- a/src/Library/Giraffe.Fixi.fsproj +++ b/src/Library/Giraffe.Fixi.fsproj @@ -1,7 +1,15 @@  + + true + Fixi integration for Giraffe and Giraffe View Engine + README.md + + + + diff --git a/src/Library/Library.fs b/src/Library/Library.fs index c65b48e..63166f7 100644 --- a/src/Library/Library.fs +++ b/src/Library/Library.fs @@ -6,35 +6,35 @@ open Microsoft.Extensions.Primitives /// Module to hold extensions [] module Extensions = - + /// Extensions to the header dictionary type IHeaderDictionary with - + /// Indicates that the request was generated from fixi - member this.FxRequest + member this.IsFixiRequest with get () = not (this["FX-Request"] = StringValues.Empty) /// Valid values for the fx-swap attribute -type FxSwap = - +type FixiSwap = + /// Replace the entire target element with the response (the default) | OuterHtml - + /// Replace the inner HTML of the target element | InnerHtml - + /// Insert the response before the target element | BeforeBegin - + /// Insert the response before the first child of the target element | AfterBegin - + /// Insert the response after the last child of the target element | BeforeEnd - + /// Insert the response after the target element | AfterEnd - + override this.ToString() = match this with | OuterHtml -> "outerHTML" @@ -44,42 +44,42 @@ type FxSwap = | BeforeEnd -> "beforeend" | AfterEnd -> "afterend" - + open Giraffe.ViewEngine /// Attributes and flags for fixi [] module FixiAttrs = - + /// Issue a request to the given URL /// The URL to which the request should be issued /// A configured fx-action attribute let _fxAction url = attr "fx-action" url - + /// Exclude this element (and below) from fixi's behavior let _fxIgnore = flag "fx-ignore" - + /// Specify the HTTP method for the fixi request /// The HTTP method to use for the request /// A configured fx-method attribute /// Consider _fxGet, _fxPost, etc. let _fxMethod (it: string) = attr "fx-method" (it.ToUpperInvariant()) - + /// Specify the swap strategy /// The swap strategy to use /// A configured fx-swap attribute - let _fxSwap (swap: FxSwap) = + let _fxSwap (swap: FixiSwap) = attr "fx-swap" (string swap) - + /// Specify the target for the swap /// The CSS selector for the swap target /// A configured fx-target attribute let _fxTarget selector = attr "fx-target" selector - + /// The event which should trigger this request /// The name of the event /// A configured fx-trigger attribute @@ -90,27 +90,27 @@ module FixiAttrs = /// Canned fx-method attributes for common HTTP methods [] module FixiMethods = - + /// An fx-method="DELETE" attribute let _fxDelete = _fxMethod "DELETE" - + /// An fx-method="HEAD" attribute let _fxHead = _fxMethod "HEAD" - + /// An fx-method="GET" attribute let _fxGet = _fxMethod "GET" - + /// An fx-method="PATCH" attribute let _fxPatch = _fxMethod "PATCH" - + /// An fx-method="POST" attribute let _fxPost = _fxMethod "POST" - + /// An fx-method="PUT" attribute let _fxPut = _fxMethod "PUT" diff --git a/src/Library/README.md b/src/Library/README.md new file mode 100644 index 0000000..60d5a34 --- /dev/null +++ b/src/Library/README.md @@ -0,0 +1,21 @@ +# Giraffe.Fixi + +[fixi](https://github.com/bigskysoftware/fixi) is a minimalist implementation of generalized hypermedia controls. It can be considered a very slimmed-down version of libraries like [htmx](https://htmx.org). + +## Getting fixi and Giraffe.Fixi + +fixi is designed to be vendored and served with an application. There are instructions on its page that detail how to obtain a copy. Once it is in your project, either ensure it is somewhere like `wwwroot`, or otherwise add it to your project file so that it will be included in your build. + +As you are reading a NuGet package README, we will assume you know how to install this library. + +## Using + +On the server side, this library adds an `IsFixiRequest` property to `HttpContext`, which will return `true` if the request was generated from fixi. + +In the view engine, each of fixi's six attributes have counterparts; for example, to generate an `fx-action` attribute, use `_fxAction`. Each of these take a string parameter, except for `_fxSwap`, which requires an instance of `FixiSwap`; and `_fxIgnore`, which requires no parameters at all. + +Additionally, there are six attributes with the most common HTTP methods; using `_fxDelete`, `_fxHead`, `_fxGet`, `_fxPatch`, `_fxPost`, and `_fxPut` will be quicker (and less error-prone) than `_fxMethod "get"`, for example. + +## Updating + +This library was built in conjunction with fixi v0.5.7. Given the nature of its minimalist API, and the fact that there are no version-specific CDN links, this library will likely continue to work with future versions. (There may be more upgrades for .NET or Giraffe than will be required to change the fixi API.) diff --git a/src/Library/icon.png b/src/Library/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..fafbc1bacaf2132098d540a5f9599c8110a7c4cb GIT binary patch literal 4397 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 literal 0 HcmV?d00001 diff --git a/src/Tests/Giraffe.Fixi.Tests.fsproj b/src/Tests/Giraffe.Fixi.Tests.fsproj index 248c750..1d7f3a6 100644 --- a/src/Tests/Giraffe.Fixi.Tests.fsproj +++ b/src/Tests/Giraffe.Fixi.Tests.fsproj @@ -9,4 +9,12 @@ + + + + + + + + diff --git a/src/Tests/Program.fs b/src/Tests/Program.fs index d6818ab..42ebd97 100644 --- a/src/Tests/Program.fs +++ b/src/Tests/Program.fs @@ -1,2 +1,112 @@ -// For more information see https://aka.ms/fsharp-console-apps -printfn "Hello from F#" +/// Unit tests for Giraffe.Fixi +module FixiTests + +open Expecto +open Giraffe.ViewEngine + +/// Custom expectation for this test +module Expect = + /// Expect the rendered node to match the given HTML markup text + let html node markup = + Expect.equal (RenderView.AsString.htmlNode node) markup "Rendered HTML incorrect" + +open Giraffe.Fixi + +/// Tests for the FixiSwap type +let swap = + testList "FixiSwap" [ + test "OuterHtml is correct" { + Expect.equal (string FixiSwap.OuterHtml) "outerHTML" "Outer HTML swap value incorrect" + } + test "InnerHtml is correct" { + Expect.equal (string FixiSwap.InnerHtml) "innerHTML" "Inner HTML swap value incorrect" + } + test "BeforeBegin is correct" { + Expect.equal (string FixiSwap.BeforeBegin) "beforebegin" "Before Begin swap value incorrect" + } + test "BeforeEnd is correct" { + Expect.equal (string FixiSwap.BeforeEnd) "beforeend" "Before End swap value incorrect" + } + test "AfterBegin is correct" { + Expect.equal (string FixiSwap.AfterBegin) "afterbegin" "After Begin swap value incorrect" + } + test "AfterEnd is correct" { + Expect.equal (string FixiSwap.AfterEnd) "afterend" "After End swap value incorrect" + } + ] + + +/// Tests for the FixiAttrs module +let attributes = + testList "FixiAttrs" [ + test "_fxAction succeeds" { + Expect.html (div [ _fxAction "/do-this" ] []) """
""" + } + test "_fxIgnore succeeds" { + Expect.html (span [ _fxIgnore ] [ rawText "this" ]) """this""" + } + test "_fxMethod succeeds" { + Expect.html (button [ _fxMethod "options" ] []) """""" + } + test "_fxSwap succeeds" { + Expect.html (p [ _fxSwap FixiSwap.InnerHtml ] []) """

""" + } + test "_fxTarget succeeds" { + Expect.html (button [ _fxTarget "#target" ] []) """""" + } + test "_fxTrigger succeeds" { + Expect.html (strong [ _fxTrigger "blur" ] []) """""" + } + ] + +/// Tests for the FixiMethods module +let methods = + testList "FixiMethods" [ + test "_fxDelete succeeds" { + match _fxDelete with + | XmlAttribute.KeyValue(attr, value) -> + Expect.equal attr "fx-method" "The attribute key is incorrect" + Expect.equal value "DELETE" "The attribute value is incorrect" + | XmlAttribute.Boolean _ -> Expect.isTrue false "The _fxDelete attribute is incorrect" + } + test "_fxHead succeeds" { + match _fxHead with + | XmlAttribute.KeyValue(attr, value) -> + Expect.equal attr "fx-method" "The attribute key is incorrect" + Expect.equal value "HEAD" "The attribute value is incorrect" + | XmlAttribute.Boolean _ -> Expect.isTrue false "The _fxHead attribute is incorrect" + } + test "_fxGet succeeds" { + match _fxGet with + | XmlAttribute.KeyValue(attr, value) -> + Expect.equal attr "fx-method" "The attribute key is incorrect" + Expect.equal value "GET" "The attribute value is incorrect" + | XmlAttribute.Boolean _ -> Expect.isTrue false "The _fxGet attribute is incorrect" + } + test "_fxPatch succeeds" { + match _fxPatch with + | XmlAttribute.KeyValue(attr, value) -> + Expect.equal attr "fx-method" "The attribute key is incorrect" + Expect.equal value "PATCH" "The attribute value is incorrect" + | XmlAttribute.Boolean _ -> Expect.isTrue false "The _fxPatch attribute is incorrect" + } + test "_fxPost succeeds" { + match _fxPost with + | XmlAttribute.KeyValue(attr, value) -> + Expect.equal attr "fx-method" "The attribute key is incorrect" + Expect.equal value "POST" "The attribute value is incorrect" + | XmlAttribute.Boolean _ -> Expect.isTrue false "The _fxPost attribute is incorrect" + } + test "_fxPut succeeds" { + match _fxPut with + | XmlAttribute.KeyValue(attr, value) -> + Expect.equal attr "fx-method" "The attribute key is incorrect" + Expect.equal value "PUT" "The attribute value is incorrect" + | XmlAttribute.Boolean _ -> Expect.isTrue false "The _fxPut attribute is incorrect" + } + ] + +let allTests = testList "Giraffe.Fixi" [ swap; attributes; methods ] + +[] +let main args = runTestsWithCLIArgs [] args allTests -- 2.47.1