diff --git a/README.md b/README.md index baec8231..312eb5e6 100644 --- a/README.md +++ b/README.md @@ -642,14 +642,14 @@ let app = It is based on [Suave's Experimental Html](https://github.com/SuaveIO/suave/blob/master/src/Experimental/Html.fs) and bears some resemblance with [Elm](http://elm-lang.org/examples). #### Example: -Create a function that accepts a model and returns a `HtmlNode`: +Create a function that accepts a model and returns an `XmlNode`: ```fsharp -open Giraffe.HtmlEngine +open Giraffe.XmlViewEngine let model = { Name = "John Doe" } -let layout (content: HtmlNode list) = +let layout (content: XmlNode list) = html [] [ head [] [ title [] (encodedText "Giraffe") diff --git a/samples/SampleApp/SampleApp/HtmlViews.fs b/samples/SampleApp/SampleApp/HtmlViews.fs index 2025895c..d32ce62e 100644 --- a/samples/SampleApp/SampleApp/HtmlViews.fs +++ b/samples/SampleApp/SampleApp/HtmlViews.fs @@ -1,9 +1,9 @@ module SampleApp.HtmlViews -open Giraffe.HtmlEngine +open Giraffe.XmlViewEngine open SampleApp.Models -let layout (content: HtmlNode list) = +let layout (content: XmlNode list) = html [] [ head [] [ title [] (encodedText "Giraffe") diff --git a/src/Giraffe/Giraffe.fsproj b/src/Giraffe/Giraffe.fsproj index 12c03460..9b593059 100644 --- a/src/Giraffe/Giraffe.fsproj +++ b/src/Giraffe/Giraffe.fsproj @@ -2,7 +2,7 @@ Giraffe - 0.1.0-alpha021 + 0.1.0-alpha022 A native functional ASP.NET Core web framework for F# developers. Copyright 2017 Dustin Moris Gorski en-GB @@ -41,7 +41,7 @@ - + diff --git a/src/Giraffe/HttpHandlers.fs b/src/Giraffe/HttpHandlers.fs index 6410ef78..d19d2336 100644 --- a/src/Giraffe/HttpHandlers.fs +++ b/src/Giraffe/HttpHandlers.fs @@ -11,7 +11,7 @@ open Microsoft.Extensions.DependencyInjection open FSharp.Core.Printf open Giraffe.Common open Giraffe.FormatExpressions -open Giraffe.HtmlEngine +open Giraffe.XmlViewEngine type HttpHandlerResult = Async @@ -312,9 +312,9 @@ let htmlFile (relativeFilePath : string) = >=> setBodyAsString html) } -/// Uses the Giraffe.HtmlEngine to compile and render a HTML Document from -/// a given HtmlNode. The HTTP response is of Content-Type text/html. -let renderHtml (document : HtmlNode) = +/// Uses the Giraffe.XmlViewEngine to compile and render a HTML Document from +/// an given XmlNode. The HTTP response is of Content-Type text/html. +let renderHtml (document : XmlNode) = setHttpHeader "Content-Type" "text/html" >=> (document |> renderHtmlDocument diff --git a/src/Giraffe/HtmlEngine.fs b/src/Giraffe/XmlViewEngine.fs similarity index 76% rename from src/Giraffe/HtmlEngine.fs rename to src/Giraffe/XmlViewEngine.fs index 0487dad5..d01adda3 100644 --- a/src/Giraffe/HtmlEngine.fs +++ b/src/Giraffe/XmlViewEngine.fs @@ -14,7 +14,7 @@ /// Thanks to Suave (https://github.com/SuaveIO/suave) for letting us borrow their code /// and thanks to Florian Verdonck (https://github.com/nojaf) for porting it to Giraffe. -module Giraffe.HtmlEngine +module Giraffe.XmlViewEngine open System open System.Net @@ -27,31 +27,32 @@ open System.Net /// - https://www.w3.org/TR/html5/syntax.html#void-elements /// --------------------------- -type HtmlAttribute = string * string // Key * Value -type HtmlElement = string * HtmlAttribute[] // Name * HTML attributes +type XmlAttribute = string * string // Key * Value +type XmlElement = string * XmlAttribute[] // Name * XML attributes -type HtmlNode = - | ParentNode of HtmlElement * HtmlNode list // A HTML element which contains nested HTML elements - | VoidElement of HtmlElement // A HTML element which cannot contain nested HTML (e.g.
or
) - | EncodedText of string // HTML encoded text content - | RawText of string // Raw text content +type XmlNode = + | ParentNode of XmlElement * XmlNode list // An XML element which contains nested XML elements + | VoidElement of XmlElement // An XML element which cannot contain nested XML (e.g.
or
) + | EncodedText of string // XML encoded text content + | RawText of string // Raw text content /// --------------------------- /// Building blocks /// --------------------------- let tag (tagName : string) - (attributes : HtmlAttribute list) - (contents : HtmlNode list) = + (attributes : XmlAttribute list) + (contents : XmlNode list) = ParentNode ((tagName, Array.ofList attributes), contents) let voidTag (tagName : string) - (attributes : HtmlAttribute list) = + (attributes : XmlAttribute list) = VoidElement (tagName, Array.ofList attributes) let encodedText (content : string) = [ EncodedText content ] let rawText (content : string) = [ RawText content ] let emptyText = rawText "" +let comment (content : string) = RawText (sprintf "" content) /// --------------------------- /// Default HTML elements @@ -190,24 +191,32 @@ let menuitem = voidTag "menuitem" let summary = tag "summary" /// --------------------------- -/// Render HTML string +/// Render XML string /// --------------------------- -let rec nodeToHtmlString (node : HtmlNode) = - let startElementToString (elemName, attributes) = +let rec private nodeToString (htmlStyle : bool) (node : XmlNode) = + let startElementToString selfClosing (elemName, attributes) = + let closingBracket = + match selfClosing with + | false -> ">" + | true -> + match htmlStyle with + | false -> " />" + | true -> ">" match attributes with - | [||] -> sprintf "<%s>" elemName + | [||] -> sprintf "<%s%s" elemName closingBracket | _ -> attributes |> Array.map (fun (k, v) -> sprintf " %s=\"%s\"" k (WebUtility.HtmlEncode v)) |> String.Concat - |> sprintf "<%s%s>" elemName + |> sprintf "<%s%s%s" elemName + <| closingBracket let endElementToString (elemName, _) = sprintf "" elemName - let parentNodeToString (elem : HtmlElement, nodes : HtmlNode list) = - let innerContent = nodes |> List.map nodeToHtmlString |> String.Concat - let startTag = elem |> startElementToString + let parentNodeToString (elem : XmlElement, nodes : XmlNode list) = + let innerContent = nodes |> List.map (nodeToString htmlStyle) |> String.Concat + let startTag = elem |> startElementToString false let endTag = elem |> endElementToString sprintf "%s%s%s" startTag innerContent endTag @@ -215,9 +224,12 @@ let rec nodeToHtmlString (node : HtmlNode) = | EncodedText text -> WebUtility.HtmlEncode text | RawText text -> text | ParentNode (e, nodes) -> parentNodeToString (e, nodes) - | VoidElement e -> startElementToString e + | VoidElement e -> startElementToString true e -let renderHtmlDocument (document : HtmlNode) = +let renderXmlString = nodeToString false +let renderHtmlString = nodeToString true + +let renderHtmlDocument (document : XmlNode) = document - |> nodeToHtmlString + |> renderHtmlString |> sprintf "%s%s" Environment.NewLine \ No newline at end of file diff --git a/tests/Giraffe.Tests/Giraffe.Tests.fsproj b/tests/Giraffe.Tests/Giraffe.Tests.fsproj index 385d4e41..c06d4c99 100644 --- a/tests/Giraffe.Tests/Giraffe.Tests.fsproj +++ b/tests/Giraffe.Tests/Giraffe.Tests.fsproj @@ -26,7 +26,7 @@ - + diff --git a/tests/Giraffe.Tests/HttpHandlerTests.fs b/tests/Giraffe.Tests/HttpHandlerTests.fs index 1ef00c27..e54ec809 100644 --- a/tests/Giraffe.Tests/HttpHandlerTests.fs +++ b/tests/Giraffe.Tests/HttpHandlerTests.fs @@ -12,7 +12,7 @@ open Xunit open NSubstitute open Giraffe.HttpHandlers open Giraffe.Middleware -open Giraffe.HtmlEngine +open Giraffe.XmlViewEngine open Giraffe.DotLiquid.HttpHandlers open Giraffe.Tests.Asserts diff --git a/tests/Giraffe.Tests/HtmlEngineTests.fs b/tests/Giraffe.Tests/XmlViewEngineTests.fs similarity index 65% rename from tests/Giraffe.Tests/HtmlEngineTests.fs rename to tests/Giraffe.Tests/XmlViewEngineTests.fs index 1da4d5c2..1a28bd87 100644 --- a/tests/Giraffe.Tests/HtmlEngineTests.fs +++ b/tests/Giraffe.Tests/XmlViewEngineTests.fs @@ -1,8 +1,8 @@ -module Giraffe.HtmlEngineTests +module Giraffe.XmlViewEngineTests open System open Xunit -open Giraffe.HtmlEngine +open Giraffe.XmlViewEngine let removeNewLines (html:string):string = html.Replace(Environment.NewLine, String.Empty) @@ -20,13 +20,14 @@ let ``Single html root should compile`` () = let ``Anchor should contain href, target and content`` () = let anchor = a [ "href", "http://example.org"; "target", "_blank" ] (encodedText "Example") - let html = nodeToHtmlString anchor + let html = renderXmlString anchor Assert.Equal("Example", html) [] let ``Nested content should render correctly`` () = let nested = div [] [ + comment "this is a test" h1 [] (encodedText "Header") p [] [ EncodedText "Lorem " @@ -35,11 +36,16 @@ let ``Nested content should render correctly`` () = ] ] let html = nested - |> nodeToHtmlString + |> renderXmlString |> removeNewLines - Assert.Equal("

Header

Lorem Ipsum dollar

", html) + Assert.Equal("

Header

Lorem Ipsum dollar

", html) [] -let ``Void tag should be unary tag`` () = - let unary = br [] |> nodeToHtmlString +let ``Void tag in XML should be self closing tag`` () = + let unary = br [] |> renderXmlString + Assert.Equal("
", unary) + +[] +let ``Void tag in HTML should be unary tag`` () = + let unary = br [] |> renderHtmlString Assert.Equal("
", unary) \ No newline at end of file