Skip to content

Instantly share code, notes, and snippets.

@Tarmil
Created June 30, 2013 10:14
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Tarmil/5894620 to your computer and use it in GitHub Desktop.
Save Tarmil/5894620 to your computer and use it in GitHub Desktop.
module XmlCE
open IntelliFactory.WebSharper
// I don't want to open IF.WS.Html here, because I'm defining my own HTML combinators
type IPagelet = IntelliFactory.WebSharper.Html.IPagelet
module E = IntelliFactory.WebSharper.Html.Events
/// The type of XML attributes.
/// I added a couple DOM events to show that we can have more
/// than just key/value attributes.
type Attribute =
| Attribute of string * string
| OnAfterRender of (IPagelet -> unit)
| OnClick of (IPagelet -> E.MouseEvent -> unit)
/// The type of XML nodes, which is also the computation expression builder.
type Node =
/// Node(tagName, attributes, children)
| Node of string * Attribute list * Node list
/// Text(content)
| Text of string
/// Start with no added children or attributes.
[<JavaScript>]
member this.Zero() = []
/// Add a node.
[<JavaScript>]
member this.Sequence(x: Node, l: Node list) =
x :: l
/// Add a sequence of nodes.
[<JavaScript>]
member this.Sequence(x: seq<Node>, l: Node list) =
List.ofSeq x @ l
/// Add an attribute.
[<JavaScript>]
member this.Sequence(x: Attribute, l: Attribute list) =
x :: l
/// Add a sequence of attributes.
[<JavaScript>]
member this.Sequence(x: seq<Attribute>, l: Attribute list) =
List.ofSeq x @ l
/// Add a text node. Just a shortcut for this.Sequence(Text x, l).
[<JavaScript>]
member this.Sequence(x: string, l) =
Text x :: l
/// Add a sequence of children or attributes using for.
[<JavaScript>]
member this.For(s, f) =
List.ofSeq (Seq.collect f s)
/// Combine two sequences of new children or attributes.
[<JavaScript>]
member this.Combine(x, l) =
x @ l
/// This does nothing remarkable, but for some reason it must be present.
[<JavaScript>]
[<Inline>]
member this.Delay f = f()
/// Build a new node with the collected attributes.
[<JavaScript>]
member this.Run(attrs) =
match this with
| Node(name, a, children) -> Node(name, a @ attrs, children)
| Text s -> Node("span", attrs, [this])
/// Build a new node with the collected children.
[<JavaScript>]
member this.Run(children) =
match this with
| Node(name, attrs, c) -> Node(name, attrs, c @ children)
| Text s -> Node("span", [], this :: children)
/// Helper constructors.
[<JavaScript>]
let attr n v = Attribute(n, v)
[<JavaScript>]
let node n = Node(n, [], [])
/// A bunch of HTML nodes.
/// I'm not going to implement the whole standard here, you get the idea :)
[<JavaScript>]
let Div = node "div"
[<JavaScript>]
let H1 = node "h1"
[<JavaScript>]
let Span = node "span"
[<JavaScript>]
let A = node "a"
[<JavaScript>]
let Table = node "table"
[<JavaScript>]
let TR = node "tr"
[<JavaScript>]
let TD = node "td"
[<JavaScript>]
let TH = node "th"
[<JavaScript>]
let HR = node "hr"
/// A few attributes as well. Same remark applies.
[<JavaScript>]
let Style = attr "style"
[<JavaScript>]
let HRef = attr "href"
module Example =
type Person =
{
FirstName: string
LastName: string
ProfileUrl: string
Age: int
}
[<JavaScript>]
let showPeople people =
Div {
H1 { "People" }
HR
Table { Style "border-collapse: collapse;" } {
TR {
TH { "First Name" }
TH { "Last Name" }
TH { "Age" }
}
for person in people do
let myTd = TD { Style "border: solid 1px #888; width: 200px" }
let nameFields = [
myTd { person.FirstName }
myTd { person.LastName }
]
TR {
nameFields
myTd { string person.Age }
myTd {
"See "
A { HRef person.ProfileUrl } { "Profile" }
}
}
}
}
module Client =
open IntelliFactory.WebSharper
open IntelliFactory.WebSharper.Html
[<JavaScript>]
let rec Render (x: Node) =
match x with
| Node(name, attrs, children) ->
let children = children |> List.map Render
let t = Tags.NewTag name children
attrs |> List.iter (function
| Attribute(n, v) -> t.Append(NewAttr n v)
| OnAfterRender f -> OnAfterRender f t
| OnClick f -> OnClick f t)
t :> IPagelet
| Text t -> Text t
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment