{ "version": 3, "sourceRoot": "Source", "sources": ["WebSharper.UI/Abbrev.fs", "WebSharper.UI/AppendList.fs", "WebSharper.UI/DomUtility.fs", "WebSharper.UI/Trie.fs", "WebSharper.UI/Snap.fs", "WebSharper.UI/Reactive.fs", "WebSharper.UI/Models.fs", "WebSharper.UI/ReactiveExtensions.fs", "WebSharper.UI/Animation.fs", "WebSharper.UI/Attr.fs", "WebSharper.UI/Attr.Client.fs", "WebSharper.UI/Doc.fs", "WebSharper.UI/Doc.Proxy.fs", "WebSharper.UI/Templates.fs", "WebSharper.UI/Flow.fs", "WebSharper.UI/HTML.fs", "WebSharper.UI/Router.fs", "WebSharper.UI/Routing.fs", "WebSharper.UI/Input.fs"], "sourcesContent": ["// $begin{copyright}\n//\n// This file is part of WebSharper\n//\n// Copyright (c) 2008-2018 IntelliFactory\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\"); you\n// may not use this file except in compliance with the License. You may\n// obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n// implied. See the License for the specific language governing\n// permissions and limitations under the License.\n//\n// $end{copyright}\n\nnamespace WebSharper.UI\n\nopen System\nopen System.Collections.Generic\nopen WebSharper\nopen WebSharper.JavaScript\n\nmodule Array =\n\n /// Returns defaultValue if array is empty.\n /// Otherwise makes a binary tree of the array elements and uses reduction to combine\n /// all items into a single value.\n []\n let TreeReduce (defaultValue: 'A) (reduction: 'A -> 'A -> 'A) (array: 'A[]) : 'A =\n let l = array.Length\n let rec loop off len =\n match len with\n | n when n <= 0 -> defaultValue\n | 1 when off >= 0 && off < l ->\n array[off]\n | n ->\n let l2 = len / 2\n let a = loop off l2\n let b = loop (off + l2) (len - l2)\n reduction a b\n loop 0 l\n\n /// Returns defaultValue if array is empty.\n /// Otherwise makes a binary tree of the array elements and uses reduction to combine \n /// all items into a single value using the mapping function first on each item.\n []\n let MapTreeReduce (mapping: 'A -> 'B) (defaultValue: 'B) (reduction: 'B -> 'B -> 'B) (array: 'A[]) : 'B =\n let l = array.Length\n let rec loop off len =\n match len with\n | n when n <= 0 -> defaultValue\n | 1 when off >= 0 && off < l ->\n mapping array[off]\n | n ->\n let l2 = len / 2\n let a = loop off l2\n let b = loop (off + l2) (len - l2)\n reduction a b\n loop 0 l\n\n /// Same as Array.ofSeq, but if argument is an array, it does not copy it.\n []\n let ofSeqNonCopying (xs: seq<'T>) : 'T [] =\n if xs :? System.Array then\n xs :?> 'T[]\n elif xs :? _ list then\n Array.ofList (xs :?> 'T list)\n elif obj.ReferenceEquals(xs, null) then\n [||]\n else\n let q : 'T [] = [||]\n use o = xs.GetEnumerator()\n while o.MoveNext() do\n q.JS.Push(o.Current) |> ignore\n q\n\n /// Unsafe operation, modifies each element of an array by a mapping function.\n []\n let mapInPlace (f: 'T1 -> 'T2) (arr: 'T1 []) =\n if IsClient then\n for i = 0 to Array.length arr - 1 do\n arr.JS[i] <- As (f arr.JS[i])\n As<'T2[]> arr\n else Array.map f arr\n\nmodule internal String =\n\n []\n let isBlank s =\n String.forall Char.IsWhiteSpace s\n\nmodule internal List =\n\n // TODO: better impl only going to n?\n []\n let replaceFirst (k: 'A -> bool) (f: 'A -> 'A) (l: list<'A>) =\n let didIt = ref false\n l |> List.map (fun x -> if not didIt.Value && k x then f x else x)\n\n // TODO: better impl only going to n?\n []\n let maybeReplaceFirst (k: 'A -> bool) (f: 'A -> option<'A>) (l: list<'A>) =\n let didIt = ref false\n l |> List.map (fun x -> if not didIt.Value && k x then defaultArg (f x) x else x)\n\n/// Abbreviations and small utilities for this assembly.\n[]\nmodule internal Abbrev =\n\n []\n module Fresh =\n\n let mutable private counter = 0\n\n let Int () =\n counter <- counter + 1\n counter\n\n let Id () =\n counter <- counter + 1\n \"uid\" + string counter\n\n []\n module HashSet =\n\n let ToArray (set: HashSet<'T>) =\n let arr = Array.create set.Count JS.Undefined\n set.CopyTo(arr)\n arr\n\n let Except (excluded: HashSet<'T>) (included: HashSet<'T>) =\n let set = HashSet<'T>(ToArray included)\n set.ExceptWith(ToArray excluded)\n set\n\n let Intersect (a: HashSet<'T>) (b: HashSet<'T>) =\n let set = HashSet<'T>(ToArray a)\n set.IntersectWith(ToArray b)\n set\n\n let Filter (ok: 'T -> bool) (set: HashSet<'T>) =\n HashSet<'T>(ToArray set |> Array.filter ok)\n\n []\n module Dict =\n\n let ToKeyArray (d: Dictionary<_,_>) =\n let arr = Array.create d.Count JS.Undefined\n d |> Seq.iteri (fun i kv -> arr[i] <- kv.Key)\n arr\n\n let ToValueArray (d: Dictionary<_,_>) =\n let arr = Array.create d.Count JS.Undefined\n d |> Seq.iteri (fun i kv -> arr[i] <- kv.Value)\n arr\n\n module Queue =\n\n []\n let ToArray (q: Queue<_>) = q.ToArray()\n\n []\n []\n type Slot<'T,'K when 'K : equality>(key: 'T -> 'K, value: 'T) =\n member s.Value = value\n\n override s.Equals(o: obj) =\n key value = key (o :?> Slot<'T,'K>).Value\n\n override s.GetHashCode() = hash (key value)\n\n []\n type Slot =\n static member Create key value = Slot(key, value)\n\n []\n module Async =\n\n []\n let OnError (e: exn) = ()\n\n let StartTo comp k =\n Async.StartWithContinuations (comp, k, OnError, ignore)\n\n []\n module Mailbox =\n\n type MailboxState =\n | Idle = 0\n | Working = 1\n | WorkingMore = 2\n\n /// Simplified MailboxProcessor implementation.\n let StartProcessor procAsync =\n let st = ref MailboxState.Idle\n let rec work() =\n async {\n do! procAsync\n match st.Value with\n | MailboxState.Working -> \n st.Value <- MailboxState.Idle\n | MailboxState.WorkingMore ->\n st.Value <- MailboxState.Working\n return! work() \n | _ -> ()\n }\n let post() =\n match st.Value with\n | MailboxState.Idle ->\n st.Value <- MailboxState.Working\n Async.Start (work()) \n | MailboxState.Working -> \n st.Value <- MailboxState.WorkingMore\n | _ -> ()\n post\n", "// $begin{copyright}\n//\n// This file is part of WebSharper\n//\n// Copyright (c) 2008-2018 IntelliFactory\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\"); you\n// may not use this file except in compliance with the License. You may\n// obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n// implied. See the License for the specific language governing\n// permissions and limitations under the License.\n//\n// $end{copyright}\n\nnamespace WebSharper.UI\nopen WebSharper\n\nopen System.Collections.Generic\n\ntype AppendList<'T> =\n | AL0\n | AL1 of 'T\n | AL2 of AppendList<'T> * AppendList<'T>\n | AL3 of 'T []\n\n[]\nmodule AppendList =\n\n type T<'T> = AppendList<'T>\n\n let Empty<'T> : T<'T> = AL0\n\n let Append x y =\n match x, y with\n | AL0, x | x, AL0 -> x\n | _ -> AL2 (x, y)\n\n let Concat xs =\n Array.ofSeqNonCopying xs\n |> Array.TreeReduce Empty Append\n\n let Single x =\n AL1 x\n\n let ToArray xs =\n let out = Queue()\n let rec loop xs =\n match xs with\n | AL0 -> ()\n | AL1 x -> out.Enqueue x\n | AL2 (x, y) -> loop x; loop y\n | AL3 xs -> Array.iter (fun v -> out.Enqueue v) xs\n loop xs\n out.ToArray()\n\n let FromArray xs =\n match Array.length xs with\n | 0 -> AL0\n | 1 -> AL1 xs[0]\n | _ -> AL3 (Array.copy xs)\n", "// $begin{copyright}\n//\n// This file is part of WebSharper\n//\n// Copyright (c) 2008-2018 IntelliFactory\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\"); you\n// may not use this file except in compliance with the License. You may\n// obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n// implied. See the License for the specific language governing\n// permissions and limitations under the License.\n//\n// $end{copyright}\n\nnamespace WebSharper.UI\n\nopen WebSharper\nopen WebSharper.JavaScript\n\n/// Utility functions for manipulating DOM.\n[]\nmodule DomUtility =\n\n /// Creates a new DOM element.\n []\n let CreateElement (name: string) =\n JS.Document.CreateElement name\n\n /// Creates an element in the SVG namespace.\n []\n let CreateSvgElement (name: string) =\n JS.Document.CreateElementNS(\"http://www.w3.org/2000/svg\", name)\n\n /// Creates a new DOM text node with the given value.\n []\n let CreateText s =\n JS.Document.CreateTextNode(s)\n\n /// Removes a DOM attribute.\n []\n let RemoveAttr (el: Dom.Element) (attrName: string) =\n el.RemoveAttribute attrName\n\n /// Sets the value of the attribute given by\n /// `name` to `value` in element `el`.\n []\n let SetAttr (el: Dom.Element) name value =\n el.SetAttribute(name, value)\n\n []\n let private SetProperty (target: obj) (name: string) (value: string) = ()\n\n /// Sets a style property.\n []\n let SetStyle (el: Dom.Element) name value =\n SetProperty el?style name value\n\n /// Safe remove of a node\n let RemoveNode (parent: Dom.Element) (el: Dom.Node) =\n // make sure not to remove already removed nodes\n if obj.ReferenceEquals(el.ParentNode, parent) then\n parent.RemoveChild(el) |> ignore\n\n /// Position in a `children` list of a DOM Element\n /// where a node can be inserted.\n []\n type InsertPos [] private (x: Dom.Node) =\n []\n static member AtEnd = null : InsertPos\n []\n static member BeforeNode n = InsertPos n\n []\n let AtEnd = InsertPos.AtEnd\n []\n let BeforeNode n = InsertPos.BeforeNode n\n\n /// Inserts a new child node into the tree under\n /// a given `parent` at given `pos`.\n let InsertAt (parent: Dom.Element) (pos: InsertPos) (node: Dom.Node) =\n let currentPos (node: Dom.Node) =\n match node.NextSibling with\n | null -> AtEnd\n | s -> BeforeNode s\n let canSkip =\n node.ParentNode ===. parent\n && pos ===. currentPos node\n if not canSkip then\n parent.InsertBefore(node, As pos) |> ignore\n\n let private clsRE cls =\n new RegExp(@\"(\\s+|^)\" + cls + @\"(?:\\s+\" + cls + \")*(\\s+|$)\", \"g\")\n\n []\n let private isSvg (element: Dom.Element) = X\n\n let private getClass (element: Dom.Element) =\n if isSvg element then\n element.GetAttribute(\"class\")\n else\n element.ClassName\n\n let private setClass (element: Dom.Element) (value: string) =\n if isSvg element then\n element.SetAttribute(\"class\", value)\n else\n element.ClassName <- value\n\n /// Adds a class.\n let AddClass (element: Dom.Element) (cl: string) =\n let c = getClass element\n if c = \"\" then\n setClass element cl\n elif not <| (clsRE cl).Test(c) then\n setClass element (c + \" \" + cl)\n\n /// Removes a class.\n let RemoveClass (element: Dom.Element) (cl: string) =\n setClass element <|\n (clsRE cl).Replace(getClass element, FuncWithArgs(fun (_fullStr, before, after) ->\n if before = \"\" || after = \"\" then \"\" else \" \"\n ))\n\n /// Retrieve the children of an element as an array.\n let ChildrenArray (element: Dom.Element) : Dom.Node[] =\n let a = [||]\n for i = 0 to element.ChildNodes.Length - 1 do\n a.JS.Push(element.ChildNodes[i]) |> ignore\n a\n\n /// Iterate through a NodeList assuming it's all Elements.\n let IterSelector (el: Dom.Element) (selector: string) (f: Dom.Element -> unit) =\n let l = el.QuerySelectorAll(selector)\n for i = 0 to l.Length - 1 do f (l[i] :?> Dom.Element)\n\n let IterSelectorDoc (selector: string) (f: Dom.Element -> unit) =\n let l = JS.Document.QuerySelectorAll(selector)\n for i = 0 to l.Length - 1 do f (l[i] :?> Dom.Element)\n\n let private rxhtmlTag = RegExp(\"\"\"<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\\w:]+)[^>]*)\\/>\"\"\", \"gi\")\n let private rtagName = RegExp(\"\"\"<([\\w:]+)\"\"\")\n let private rhtml = RegExp(\"\"\"<|&#?\\w+;\"\"\")\n let private wrapMap =\n let table = (1, \"\", \"
\")\n Object [|\n \"option\", (1, \"\")\n \"legend\", (1, \"
\", \"
\")\n \"area\", (1, \"\", \"\")\n \"param\", (1, \"\", \"\")\n \"thead\", table\n \"tbody\", table\n \"tfoot\", table\n \"tr\", (2, \"\", \"
\")\n \"col\", (2, \"\", \"
\")\n \"td\", (3, \"\", \"
\")\n |]\n let private defaultWrap = (0, \"\", \"\")\n\n /// From https://gist.github.com/Munawwar/6e6362dbdf77c7865a99\n /// which is itself from jQuery.\n let ParseHTMLIntoFakeRoot (elem: string) : Dom.Element =\n let root = JS.Document.CreateElement(\"div\")\n if not (rhtml.Test elem) then\n root.AppendChild(JS.Document.CreateTextNode(elem)) |> ignore\n root\n else\n let tag =\n match rtagName.Exec(elem) with\n | null -> \"\"\n | res -> res[1].JS.ToLowerCase()\n let nesting, start, finish =\n let w = wrapMap[tag]\n if As w then w else defaultWrap\n root.InnerHTML <- start + rxhtmlTag.Replace(elem, \"<$1>\") + finish\n let rec unwrap (elt: Dom.Node) = function\n | 0 -> elt\n | i -> unwrap elt.LastChild (i - 1)\n unwrap root nesting :?> Dom.Element\n", "// $begin{copyright}\n//\n// This file is part of WebSharper\n//\n// Copyright (c) 2008-2018 IntelliFactory\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\"); you\n// may not use this file except in compliance with the License. You may\n// obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n// implied. See the License for the specific language governing\n// permissions and limitations under the License.\n//\n// $end{copyright}\n\nnamespace WebSharper.UI\nopen WebSharper\n\nopen System.Collections.Generic\nmodule M = Map\n\n/// Trie lookup structure.\ntype Trie<'K,'V when 'K : comparison> =\n | TrieBranch of Map<'K,Trie<'K,'V>> // invariant: not empty\n | TrieEmpty\n | TrieLeaf of 'V\n\n/// Trie combinators.\n[]\nmodule Trie =\n\n /// Branch trie, maintaining invariant.\n let TrieBranch xs =\n if M.isEmpty xs then TrieEmpty else TrieBranch xs\n\n /// Singleton trie.\n let Leaf v =\n TrieLeaf v\n\n /// Prefix a trie - becomes a branch.\n let Prefix key trie =\n TrieBranch (Map [key, trie])\n\n /// Finds a value in a multi-map.\n let MultiFind key map =\n defaultArg (M.tryFind key map) []\n\n /// Adds a value to a multi-map.\n let MultiAdd key value map =\n Map.add key (value :: MultiFind key map) map\n\n /// Makes sure all results are Some.\n let AllSome (xs: seq>) =\n let e = xs.GetEnumerator()\n let r = ResizeArray()\n let mutable ok = true\n while ok && e.MoveNext() do\n match e.Current with\n | None -> ok <- false\n | Some x -> r.Add(x)\n if ok then Some (r.ToArray() :> seq<_>) else None\n\n /// Merges multiple maps into one given a merge function on values.\n let MergeMaps merge maps =\n Seq.collect M.toSeq maps\n |> Seq.fold (fun s (k, v) -> MultiAdd k v s) M.empty\n |> M.toSeq\n |> Seq.map (fun (k, vs) -> merge vs |> Option.map (fun v -> (k, v)))\n |> AllSome\n |> Option.map Map.ofSeq\n\n /// Checks for leaves.\n let IsLeaf t =\n match t with\n | TrieLeaf _ -> true\n | _ -> false\n\n /// Merges tries.\n let rec Merge (ts: seq<_>) =\n let ts = Array.ofSeqNonCopying ts\n match ts.Length with\n | 0 -> Some TrieEmpty\n | 1 -> Some ts[0]\n | _ ->\n // leaves do not merge\n if Array.exists IsLeaf ts then None else\n ts\n |> Seq.choose (function\n | TrieBranch map -> Some map\n | _ -> None)\n |> MergeMaps Merge\n |> Option.map TrieBranch\n\n /// Inner loop for Map function.\n let rec MapLoop loc f trie =\n match trie with\n | TrieBranch mp ->\n mp\n |> M.map (fun k v -> MapLoop (loc @ [k]) f v)\n |> TrieBranch\n | TrieEmpty -> TrieEmpty\n | TrieLeaf x -> TrieLeaf (f loc x)\n\n /// Maps a function.\n let Map f trie =\n MapLoop [] f trie\n\n /// Map with a counter.\n let Mapi f trie =\n let counter = ref 0\n let next () =\n let c = counter.Value\n counter.Value <- c + 1\n c\n Map (fun x -> f (next ()) x) trie\n\n /// Collects all values.\n let ToArray trie =\n // TODO: more efficient than this.\n let all = Queue()\n Map (fun _ v -> all.Enqueue v) trie\n |> ignore\n all.ToArray()\n\n /// Result of lookup function.\n type LookupResult<'K,'V> =\n | Found of value: 'V * remainder: list<'K>\n | NotFound\n\n /// Lookup main loop.\n let rec Look key trie =\n match trie, key with\n | TrieLeaf v, _ -> Found (v, key)\n | TrieBranch map, k :: ks ->\n match M.tryFind k map with\n | Some trie -> Look ks trie\n | None -> NotFound\n | _ -> NotFound\n\n /// Looks up a value in the trie.\n let Lookup trie key =\n Look (Seq.toList key) trie\n\n /// Empty trie.\n let Empty<'K,'V when 'K : comparison> : Trie<'K,'V> =\n TrieEmpty\n\n", "// $begin{copyright}\n//\n// This file is part of WebSharper\n//\n// Copyright (c) 2008-2018 IntelliFactory\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\"); you\n// may not use this file except in compliance with the License. You may\n// obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n// implied. See the License for the specific language governing\n// permissions and limitations under the License.\n//\n// $end{copyright}\n\nnamespace WebSharper.UI\n\nopen System.Collections.Generic\nopen WebSharper\nopen WebSharper.JavaScript\n\n(*\n\nSnap implements a snapshot of a time-varying value.\n\nFinal states:\n\n Forever -- will never be obsolete\n Obsolete -- is obsolete\n\nDistinguishing Forever state is important as it avoids a class of\nmemory leaks connected with waiting on a Snap to become obsolete\nwhen it will never do so.\n\nState transitions:\n\n Waiting -> Forever // MarkForever\n Waiting -> Obsolete // MarkObsolete\n Waiting -> Ready // MarkReady\n Ready -> Obsolete // MarkObsolete\n\n*)\n\n[]\ntype ISnap =\n abstract Obsolete : unit -> unit\n abstract IsNotObsolete : unit -> bool\n\ntype OnObsoleted = Union unit>\n\n[]\ntype SnapState<'T> =\n | Forever of 'T\n | [] Obsolete\n | Ready of 'T * Queue\n | Waiting of Queue<'T -> unit> * Queue\n\n[]\nmodule SnapInternals =\n\n []\n let obs (o: OnObsoleted) doObs = \n match o with\n | Union1Of2 sn -> doObs sn\n | Union2Of2 f -> f()\n\n []\n let clean (o: OnObsoleted) doObs doFunc = \n match o with\n | Union1Of2 sn -> doObs sn\n | Union2Of2 f -> doFunc f\n\ntype Snap<'T> =\n {\n [] mutable State : SnapState<'T>\n }\n\n []\n static member Obsolete(sn: Snap<'T>) =\n match sn.State with\n | Forever _ | Obsolete -> ()\n | Ready (_, q) | Waiting (_, q) ->\n sn.State <- Obsolete\n let qa = Queue.ToArray q\n for i = 0 to qa.Length - 1 do \n obs qa[i] (fun sn -> sn.Obsolete())\n\n interface ISnap with\n member this.Obsolete() =\n Snap.Obsolete(this)\n\n member this.IsNotObsolete() =\n match this.State with\n | Obsolete -> false\n | _ -> true\n\n[)>]\ntype internal ISnapProxy =\n abstract Obsolete : unit -> unit\n []\n default this.Obsolete() =\n Snap.Obsolete(As> this)\n\n abstract IsNotObsolete : unit -> bool\n []\n default this.IsNotObsolete() = X\n\n[]\nmodule Snap =\n\n // constructors\n\n []\n let Make st = { State = st }\n\n []\n let Create () = Make (Waiting (Queue(), Queue()))\n\n []\n let CreateForever v = Make (Forever v)\n\n []\n let CreateWithValue v = Make (Ready (v, Queue()))\n\n // misc\n\n []\n let IsForever snap =\n match snap.State with\n | Forever _ -> true\n | _ -> false\n\n []\n let IsObsolete snap =\n match snap.State with\n | Obsolete -> true\n | _ -> false\n\n []\n let IsDone snap =\n match snap.State with\n | Forever _ | Ready _ -> true\n | _ -> false\n\n let TryGet snap =\n match snap.State with\n | Forever x | Ready (x, _) -> Some x\n | _ -> None\n\n // transitions\n\n let MarkForever sn v =\n match sn.State with\n | Waiting (q, _) ->\n sn.State <- Forever v\n let qa = Queue.ToArray q\n for i = 0 to qa.Length - 1 do \n qa[i] v\n | _ -> ()\n\n []\n let MarkObsolete (sn: Snap<_>) =\n (sn :> ISnap).Obsolete()\n\n let MarkReady sn v =\n match sn.State with\n | Waiting (q1, q2) ->\n sn.State <- Ready (v, q2)\n let qa = Queue.ToArray q1\n for i = 0 to qa.Length - 1 do \n qa[i] v\n | _ -> ()\n\n let MarkDone res sn v =\n if IsForever sn then\n MarkForever res v\n else\n MarkReady res v\n\n let EnqueueSafe (q: Queue<_>) x =\n q.Enqueue x\n if q.Count % 20 = 0 then\n let qcopy = q.ToArray()\n q.Clear()\n for i = 0 to qcopy.Length - 1 do\n clean qcopy[i]\n (fun sn -> if sn.IsNotObsolete() then q.Enqueue (Union1Of2 sn))\n (fun f -> q.Enqueue (Union2Of2 f)) \n\n // eliminators\n\n let When snap avail (obs: ISnap) =\n match snap.State with\n | Forever v -> avail v\n | Obsolete -> obs.Obsolete()\n | Ready (v, q1) -> EnqueueSafe q1 (Union1Of2 obs); avail v\n | Waiting (q1, q2) -> q1.Enqueue avail; EnqueueSafe q2 (Union1Of2 obs)\n\n let WhenRun snap avail obs =\n match snap.State with\n | Forever v -> avail v\n | Obsolete -> obs()\n | Ready (v, q1) -> q1.Enqueue (Union2Of2 obs); avail v\n | Waiting (q1, q2) -> q1.Enqueue avail; q2.Enqueue (Union2Of2 obs)\n\n let WhenReady snap avail =\n match snap.State with\n | Forever v\n | Ready (v, _) -> avail v\n | Obsolete -> ()\n | Waiting (q1, _) -> q1.Enqueue avail\n\n let WhenObsolete snap (obs: ISnap) =\n match snap.State with\n | Forever v -> ()\n | Obsolete -> obs.Obsolete()\n | Ready (v, q) -> EnqueueSafe q (Union1Of2 obs)\n | Waiting (q1, q2) -> EnqueueSafe q2 (Union1Of2 obs)\n\n let WhenObsoleteRun snap obs =\n match snap.State with\n | Forever v -> ()\n | Obsolete -> obs()\n | Ready (v, q) -> q.Enqueue (Union2Of2 obs)\n | Waiting (q1, q2) -> q2.Enqueue (Union2Of2 obs)\n\n let ValueAndForever snap =\n match snap.State with\n | Forever v -> Some (v, true)\n | Ready (v, _) -> Some (v, false)\n | _ -> None\n\n // combinators\n\n let Join snap =\n let res = Create ()\n let onReady x =\n let y = x ()\n When y (fun v ->\n if IsForever y && IsForever snap then\n MarkForever res v\n else\n MarkReady res v) res\n When snap onReady res\n res\n\n let JoinInner snap =\n let res = Create ()\n let onReady x =\n let y = x ()\n When y (fun v ->\n if IsForever y && IsForever snap then\n MarkForever res v\n else\n MarkReady res v) res\n WhenObsolete snap y\n When snap onReady res\n res\n\n let CreateForeverAsync a =\n let o = Make (Waiting (Queue(), Queue()))\n Async.StartTo a (MarkForever o)\n o\n\n let Sequence (snaps : seq>) =\n let snaps = Array.ofSeq snaps\n if Array.isEmpty snaps then CreateForever Seq.empty\n else\n let res = Create () : Snap>\n let w = ref (snaps.Length - 1)\n let cont _ =\n if w.Value = 0 then\n // all source snaps should have a value\n let vs = \n snaps |> Array.map (fun s -> \n match s.State with\n | Forever v | Ready (v, _) -> v\n | _ -> failwith \"value not found by View.Sequence\")\n if Array.forall IsForever snaps then\n MarkForever res (vs :> seq<_>)\n else\n MarkReady res (vs :> seq<_>)\n else\n w.Value <- w.Value - 1\n snaps\n |> Array.iter (fun s -> When s cont res)\n res\n\n let Map fn sn =\n match sn.State with\n | Forever x -> CreateForever (fn x) // optimization\n | _ ->\n let res = Create ()\n When sn (fun a -> MarkDone res sn (fn a)) res\n res\n\n let WithInit x sn =\n match sn.State with\n | Forever _\n | Obsolete -> sn // optimization\n | Ready (v, _) ->\n let res = CreateWithValue v\n WhenObsolete sn res\n res\n | Waiting _ ->\n let res = CreateWithValue x\n When sn (fun _ -> Snap.Obsolete res) res\n res\n\n let WithInitOption sn =\n match sn.State with\n | Forever x -> CreateForever (Some x) // optimization\n | Obsolete -> { State = Obsolete }\n | Ready (v, _) ->\n let res = CreateWithValue (Some v)\n WhenObsolete sn res\n res\n | Waiting _ ->\n let res = CreateWithValue None\n When sn (fun _ -> Snap.Obsolete res) res\n res\n\n let Copy sn =\n match sn.State with\n | Forever _ \n | Obsolete -> sn // optimization\n | Ready (v, _) ->\n let res = CreateWithValue v\n WhenObsolete sn res\n res\n | Waiting _ ->\n let res = Create ()\n When sn (MarkDone res sn) res\n res\n\n let MapCachedBy eq (prev: ('a * 'c) option ref) fn sn =\n let fn x =\n match prev.Value with\n | Some (x', y) when eq x x' -> y\n | _ ->\n let y = fn x\n prev.Value <- Some (x, y)\n y\n Map fn sn\n\n let Map2Opt1 fn x sn2 = Map (fun y -> fn x y) sn2\n let Map2Opt2 fn y sn1 = Map (fun x -> fn x y) sn1\n let Map2 fn sn1 sn2 =\n match sn1.State, sn2.State with\n | Forever x, Forever y -> CreateForever (fn x y) // optimization\n | Forever x, _ -> Map2Opt1 fn x sn2 // optimize for known sn1\n | _, Forever y -> Map2Opt2 fn y sn1 // optimize for known s2\n | _ ->\n let res = Create ()\n let cont _ =\n if not (IsDone res) then \n match ValueAndForever sn1, ValueAndForever sn2 with\n | Some (x, f1), Some (y, f2) ->\n if f1 && f2 then\n MarkForever res (fn x y)\n else\n MarkReady res (fn x y) \n | _ -> ()\n When sn1 cont res\n When sn2 cont res\n res\n\n let Map2Unit sn1 sn2 =\n match sn1.State, sn2.State with\n | Forever (), Forever () -> CreateForever () // optimization\n | Forever (), _ -> sn2 // optimize for known sn1\n | _, Forever () -> sn1 // optimize for known s2\n | _ ->\n let res = Create ()\n let cont () =\n if not (IsDone res) then \n match ValueAndForever sn1, ValueAndForever sn2 with\n | Some (_, f1), Some (_, f2) ->\n if f1 && f2 then\n MarkForever res ()\n else\n MarkReady res () \n | _ -> ()\n When sn1 cont res\n When sn2 cont res\n res\n\n let Map3Opt1 fn x y sn3 = Map (fun z -> fn x y z) sn3\n let Map3Opt2 fn x z sn2 = Map (fun y -> fn x y z) sn2\n let Map3Opt3 fn x sn2 sn3 = Map2 (fun y z -> fn x y z) sn2 sn3\n let Map3Opt4 fn y z sn1 = Map (fun x -> fn x y z) sn1\n let Map3Opt5 fn y sn1 sn3 = Map2 (fun x z -> fn x y z) sn1 sn3\n let Map3Opt6 fn z sn1 sn2 = Map2 (fun x y -> fn x y z) sn1 sn2\n let Map3 fn sn1 sn2 sn3 =\n match sn1.State, sn2.State, sn3.State with\n | Forever x, Forever y, Forever z -> CreateForever (fn x y z)\n | Forever x, Forever y, _ -> Map3Opt1 fn x y sn3 \n | Forever x, _, Forever z -> Map3Opt2 fn x z sn2 \n | Forever x, _, _ -> Map3Opt3 fn x sn2 sn3\n | _, Forever y, Forever z -> Map3Opt4 fn y z sn1 \n | _, Forever y, _ -> Map3Opt5 fn y sn1 sn3\n | _, _, Forever z -> Map3Opt6 fn z sn1 sn2 \n | _, _, _ ->\n let res = Create ()\n let cont _ =\n if not (IsDone res) then \n match ValueAndForever sn1, ValueAndForever sn2, ValueAndForever sn3 with\n | Some (x, f1), Some (y, f2), Some (z, f3) ->\n if f1 && f2 && f3 then\n MarkForever res (fn x y z)\n else\n MarkReady res (fn x y z) \n | _ -> ()\n When sn1 cont res\n When sn2 cont res\n When sn3 cont res\n res\n\n let SnapshotOn sn1 sn2 =\n let res = Create ()\n let cont _ =\n if not (IsDone res) then \n match ValueAndForever sn1, ValueAndForever sn2 with\n | Some (_, f1), Some (y, f2) ->\n if f1 || f2 then\n MarkForever res y \n else\n MarkReady res y\n | _ -> ()\n When sn1 cont res\n WhenReady sn2 cont\n res\n\n let MapAsync fn snap =\n let res = Create ()\n When snap\n (fun v -> Async.StartTo (fn v) (MarkDone res snap))\n res\n res\n", "// $begin{copyright}\n//\n// This file is part of WebSharper\n//\n// Copyright (c) 2008-2018 IntelliFactory\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\"); you\n// may not use this file except in compliance with the License. You may\n// obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n// implied. See the License for the specific language governing\n// permissions and limitations under the License.\n//\n// $end{copyright}\n\nnamespace WebSharper.UI\n\n#nowarn \"40\" // AsyncAwait let rec\n\nopen System.Collections.Generic\nopen WebSharper\ntype private JS = WebSharper.JavaScript.JS\n\n[]\ntype Var<'T>() =\n abstract Get : unit -> 'T\n abstract Set : 'T -> unit\n abstract SetFinal : 'T -> unit\n member this.Value\n with [] get() = this.Get()\n and [] set v = this.Set v\n abstract Update : ('T -> 'T) -> unit\n abstract UpdateMaybe : ('T -> 'T option) -> unit\n abstract View : View<'T>\n abstract Id : string\n\nand [] View<'T> =\n | View of (unit -> Snap<'T>)\n\n[]\nmodule ViewOptimization =\n open WebSharper.JavaScript\n []\n let V (x: unit -> Snap<'T>) = View x\n []\n let (|V|) (x: View<'T>) = let (View v) = x in v\n []\n let getSnapV (x: Snap>) = Snap.Map (|V|) x\n []\n let getSnapF (x: 'A -> View<'T>) = x >> (|V|)\n []\n let jsNull<'T>() = Unchecked.defaultof<'T>\n []\n let jsStack<'T>() = \"\"\n \n/// Var either holds a Snap or is in Const state.\n[]\ntype ConcreteVar<'T>(isConst: bool, initSnap: Snap<'T>, initValue: 'T) =\n inherit Var<'T>()\n\n let mutable isConst = isConst\n let mutable current = initValue\n let mutable snap = initSnap\n let view = V (fun () -> snap)\n let id = Fresh.Int()\n\n override this.Get() = current\n\n override this.Set(v) =\n if isConst then\n printfn \"WebSharper.UI: invalid attempt to change value of a Var after calling SetFinal\"\n else\n Snap.MarkObsolete snap\n current <- v\n snap <- Snap.CreateWithValue v\n\n override this.SetFinal(v) =\n if isConst then\n printfn \"WebSharper.UI: invalid attempt to change value of a Var after calling SetFinal\"\n else\n Snap.MarkObsolete snap\n isConst <- true\n current <- v\n snap <- Snap.CreateForever v\n\n override this.Update(f) =\n this.Set (f (this.Get()))\n\n override this.UpdateMaybe(f) =\n match f (this.Get()) with\n | None -> ()\n | Some v -> this.Set(v)\n\n override this.View = view\n\n override this.Id = \"uinref\" + string id\n\nand [] Var private () =\n\n []\n static let (?) x f = WebSharper.JavaScript.Pervasives.(?) x f\n\n []\n static let (?<-) x f v = WebSharper.JavaScript.Pervasives.(?<-) x f v\n\n static member Create v =\n ConcreteVar<'T>(false, Snap.CreateWithValue v, v)\n :> Var<'T>\n\n static member CreateLogged (name: string) v =\n if IsClient then\n if not (JS.Global?UINVars) then\n JS.Global?UINVars <- [||]\n let res = Var.Create v\n JS.Global?UINVars?push([| name; unbox res |])\n res\n else\n Var.Create v\n\n static member Create() =\n ConcreteVar(false, Snap.CreateWithValue(), ())\n :> Var\n\n static member CreateWaiting<'T>() =\n ConcreteVar<'T>(false, Snap.Create(), jsNull<'T>())\n :> Var<'T>\n\n []\n static member Get (var: Var<'T>) =\n var.Get()\n\n static member Set (var: Var<'T>) value =\n var.Set(value)\n\n static member SetFinal (var: Var<'T>) value =\n var.SetFinal(value)\n\n static member Update var fn =\n Var.Set var (fn (Var.Get var))\n\n []\n static member GetId (var: Var<'T>) =\n var.Id\n\ntype [] Updates = \n {\n [] mutable Current : View\n [] mutable Snap : Snap\n [] VarView : View\n }\n\n []\n member this.View = this.VarView\n\n static member Create v =\n let mutable var = jsNull()\n var <-\n {\n Current = v\n Snap = jsNull()\n VarView = \n let obs () =\n let mutable c = var.Snap\n if obj.ReferenceEquals(c, null) then\n let (V observe) = var.Current\n c <- observe() |> Snap.Copy\n var.Snap <- c\n Snap.WhenObsoleteRun c (fun () -> \n var.Snap <- jsNull())\n c\n else c\n \n V obs\n }\n var\n\n member this.Value\n with [] get() = this.Current\n and set v =\n let sn = this.Snap\n if not (obj.ReferenceEquals(sn, null)) then\n Snap.MarkObsolete sn\n this.Current <- v\n\ntype ViewNode<'A,'B> =\n {\n [] NValue : 'B\n [] NVar : Var<'A>\n [] NView : View<'A>\n }\n\ntype LazyView<'T> =\n {\n [] mutable Current : Snap<'T>\n [] mutable Observe : unit -> Snap<'T> \n } \n\n[]\n[]\ntype View =\n\n []\n static member FromVar (var: Var<'T>) =\n var.View\n\n static member CreateLazy observe =\n let lv =\n {\n Current = jsNull()\n Observe = observe \n }\n let obs () =\n let mutable c = lv.Current\n if obj.ReferenceEquals(c, null) then\n c <- lv.Observe()\n lv.Current <- c\n if Snap.IsForever c then \n lv.Observe <- jsNull()\n else\n Snap.WhenObsoleteRun c (fun () -> \n lv.Current <- jsNull()) \n c\n else c\n V obs\n\n static member Map fn (V observe) =\n View.CreateLazy (fun () ->\n observe () |> Snap.Map fn)\n\n static member MapCachedBy eq fn (V observe) =\n let vref = ref None\n View.CreateLazy (fun () ->\n observe () |> Snap.MapCachedBy eq vref fn)\n\n static member MapCached fn v =\n View.MapCachedBy (=) fn v\n\n static member Map2 fn (V o1) (V o2) =\n View.CreateLazy (fun () ->\n let s1 = o1 ()\n let s2 = o2 ()\n Snap.Map2 fn s1 s2)\n\n static member Map2Unit (V o1) (V o2) =\n View.CreateLazy (fun () ->\n let s1 = o1 ()\n let s2 = o2 ()\n Snap.Map2Unit s1 s2)\n\n static member Map3 fn (V o1) (V o2) (V o3) =\n View.CreateLazy (fun () ->\n let s1 = o1 ()\n let s2 = o2 ()\n let s3 = o3 ()\n Snap.Map3 fn s1 s2 s3)\n\n static member MapAsync fn (V observe) =\n View.CreateLazy (fun () -> observe () |> Snap.MapAsync fn)\n\n static member MapAsync2 fn v1 v2 =\n View.Map2 fn v1 v2 |> View.MapAsync id\n\n static member TryGet (V observe) =\n Snap.TryGet (observe ())\n\n static member Get (f: 'T -> unit) (V observe) =\n let ok = ref false\n let rec obs () =\n Snap.WhenRun (observe ())\n (fun v ->\n if not ok.Value then\n ok.Value <- true\n f v)\n (fun () -> if not ok.Value then obs ())\n obs ()\n\n static member WithInit (x: 'T) (V observe) =\n View.CreateLazy (fun () -> observe () |> Snap.WithInit x)\n\n static member WithInitOption (V observe) =\n View.CreateLazy (fun () -> observe () |> Snap.WithInitOption)\n\n static member GetAsync v =\n Async.FromContinuations (fun (ok, _, _) -> View.Get ok v)\n\n static member SnapshotOn def (V o1) (V o2) =\n let sInit = Snap.CreateWithValue def\n\n let obs () =\n let s1 = o1 ()\n if Snap.IsObsolete sInit then\n let s2 = o2 ()\n Snap.SnapshotOn s1 s2\n else\n Snap.WhenObsolete s1 sInit\n sInit\n\n View.CreateLazy obs\n\n // Collections --------------------------------------------------------------\n\n static member MapSeqCachedBy<'A,'B,'K,'SeqA when 'K : equality and 'SeqA :> seq<'A>>\n (key: 'A -> 'K) (conv: 'A -> 'B) (view: View<'SeqA>) =\n // Save history only for t - 1, discard older history.\n let state = ref (Dictionary())\n view\n |> View.Map (fun xs ->\n let prevState = state.Value\n let newState = Dictionary()\n let result =\n Seq.toArray xs\n |> Array.mapInPlace (fun x ->\n let k = key x\n let res =\n if prevState.ContainsKey k\n then prevState[k]\n else conv x\n newState[k] <- res\n res)\n :> seq<_>\n state.Value <- newState\n result)\n\n static member MapSeqCached conv view =\n View.MapSeqCachedBy (fun x -> x) conv view\n\n static member ConvertSeqNode conv value =\n let var = Var.Create value\n let view = View.FromVar var\n {\n NValue = conv view\n NVar = var\n NView = view\n }\n\n static member MapSeqCachedViewBy<'A,'B,'K,'SeqA when 'K : equality and 'SeqA :> seq<'A>>\n (key: 'A -> 'K) (conv: 'K -> View<'A> -> 'B) (view: View<'SeqA>) =\n // Save history only for t - 1, discard older history.\n let state = ref (Dictionary())\n view\n |> View.Map (fun xs ->\n let prevState = state.Value\n let newState = Dictionary()\n let result =\n Seq.toArray xs\n |> Array.mapInPlace (fun x ->\n let k = key x\n let node =\n if prevState.ContainsKey k then\n let n = prevState[k]\n Var.Set n.NVar x\n n\n else\n View.ConvertSeqNode (fun v -> conv k v) x\n newState[k] <- node\n node.NValue)\n :> seq<_>\n state.Value <- newState\n result)\n\n static member MapSeqCachedView conv view =\n View.MapSeqCachedViewBy (fun x -> x) (fun _ v -> conv v) view\n\n []\n static member Convert<'A, 'B when 'A : equality> (f: 'A -> 'B) v =\n View.MapSeqCached f v\n\n []\n static member ConvertBy<'A, 'B, 'K when 'K : equality> (k: 'A -> 'K) (f: 'A -> 'B) v =\n View.MapSeqCachedBy k f v\n\n []\n static member ConvertSeq<'A, 'B when 'A : equality> (f: View<'A> -> 'B) v =\n View.MapSeqCachedView f v\n\n []\n static member ConvertSeqBy<'A, 'B, 'K when 'K : equality> (k: 'A -> 'K) (f: 'K -> View<'A> -> 'B) v =\n View.MapSeqCachedViewBy k f v\n\n // More cominators ------------------------------------------------------------\n\n static member Join (V observe : View>) : View<'T> =\n View.CreateLazy (fun () ->\n Snap.Join (getSnapV (observe ())))\n\n static member Bind (fn: 'A -> View<'B>) view =\n View.Join (View.Map fn view)\n\n static member JoinInner (V observe : View>) : View<'T> =\n View.CreateLazy (fun () ->\n Snap.JoinInner (getSnapV (observe ())))\n\n static member BindInner fn view =\n View.JoinInner (View.Map fn view)\n\n static member UpdateWhile def v1 v2 =\n let value = ref def\n View.BindInner (fun pred ->\n if pred then\n View.Map (fun v ->\n value.Value <- v\n v\n ) v2 \n else View.Const value.Value\n ) v1\n\n static member Sequence views =\n View.CreateLazy(fun () ->\n views\n |> Seq.map (fun (V observe) -> observe ())\n |> Snap.Sequence)\n\n static member Const x =\n let o = Snap.CreateForever x\n V (fun () -> o)\n\n static member ConstAsync a =\n let o = Snap.CreateForeverAsync a\n V (fun () -> o)\n\n static member TryWith (f: exn -> View<'T>) (V observe: View<'T>) : View<'T> =\n View.CreateLazy (fun () ->\n try\n observe ()\n with exn ->\n let (V obs) = f exn\n obs ()\n )\n\n static member TryFinally (f: unit -> unit) (V observe: View<'T>) : View<'T> =\n View.CreateLazy (fun () ->\n try\n observe ()\n finally\n f ()\n )\n\n static member Sink act (V observe) =\n let rec loop () =\n let sn = observe ()\n Snap.WhenRun sn act (fun () ->\n Concurrency.Schedule loop)\n Concurrency.Schedule loop\n\n static member RemovableSink act (V observe) =\n let cont = ref true\n let rec loop () =\n let sn = observe ()\n Snap.WhenRun sn\n (fun x -> if cont.Value then act x)\n (fun () -> if cont.Value then Concurrency.Schedule loop)\n Concurrency.Schedule loop\n fun () -> cont.Value <- false\n\n static member AsyncAwait filter view =\n Async.FromContinuations <| fun (ok, _, _) ->\n let rec remove =\n View.RemovableSink (fun value ->\n if filter value then\n remove ()\n ok value\n ) view\n ()\n\n static member Apply fn view =\n View.Map2 (fun f x -> f x) fn view\n\ntype Var with\n\n []\n static member Lens (var: Var<_>) get update =\n let id = Fresh.Id()\n let view = var.View |> View.Map get\n\n { new Var<'V>() with\n\n member this.Get() =\n get (var.Get())\n\n member this.Set(v) =\n var.Update(fun t -> update t v)\n\n member this.SetFinal(v) =\n this.Set(v)\n\n member this.Update(f) =\n var.Update(fun t -> update t (f (get t)))\n\n member this.UpdateMaybe(f) =\n var.UpdateMaybe(fun t -> Option.map (fun x -> update t x) (f (get t)))\n\n member this.View =\n view\n\n member this.Id =\n id\n }\n\n static member MapLens<'A, 'B, 'K when 'K : equality> (getKey: 'A -> 'K) (f: Var<'A> -> 'B) (var: Var>) : View> =\n var.View |> View.MapSeqCachedViewBy getKey (fun k v ->\n let id = Fresh.Id()\n let isThis a =\n getKey a = k\n f { new Var<'A>() with\n\n member this.Get() =\n List.find isThis var.Value\n\n member this.Set(v) =\n var.Update (List.replaceFirst isThis (fun _ -> v))\n\n member this.SetFinal(v) =\n this.Set(v)\n\n member this.Update(f) =\n var.Update(List.replaceFirst isThis f)\n\n member this.UpdateMaybe(f) =\n var.Update(List.maybeReplaceFirst isThis f)\n\n member this.View =\n v\n\n member this.Id =\n id\n }\n )\n\n\n// These methods apply to any View<'A>, so we can use `type View with`\n// and they'll be compiled as normal instance methods on View<'A>.\ntype View<'T> with\n\n []\n member v.Map f = View.Map f v\n\n []\n member v.MapAsync f = View.MapAsync f v\n\n []\n member v.MapAsyncLoading x f = View.MapAsync f v |> View.WithInit x\n\n []\n member v.MapAsyncOption f = View.MapAsync f v |> View.WithInitOption\n\n []\n member v.Bind f = View.Bind f v\n\n []\n member v.BindInner f = View.BindInner f v\n\n []\n member v.SnapshotOn init v' = View.SnapshotOn init v' v\n\n []\n member v.UpdateWhile init vPred = View.UpdateWhile init vPred v\n\n []\n member v.WithInit x = View.WithInit x v\n\n []\n member v.WithInitOption() = View.WithInitOption v\n\n [)>]\n member v.V = failwith \"View<'T>.V can only be called in an argument to a V-enabled function or if 'T = Doc.\" : 'T\n\ntype Var<'T> with\n\n [)>]\n member this.V = this.View.V\n\n []\n member var.Lens get update =\n Var.Lens var get update\n\n[]\ntype FromView<'T>(view: View<'T>, set: 'T -> unit) =\n inherit Var<'T>()\n\n let id = Fresh.Int()\n let mutable current =\n match View.TryGet view with\n | Some x -> x\n | None -> jsNull<'T>()\n let view = view |> View.Map (fun x -> current <- x; x)\n\n override this.View = view\n\n override this.Get() = current\n\n override this.Set(x) = set x\n\n override this.UpdateMaybe(f) =\n view |> View.Get (fun x ->\n match f x with\n | None -> ()\n | Some x -> set x\n )\n\n override this.Update(f) =\n view |> View.Get (f >> set)\n\n override this.SetFinal(x) = set x\n\n override this.Id = \"uinref\" + string id\n\ntype Var with\n\n []\n static member Make view set =\n FromView(view, set) :> Var<_>\n\ntype ViewBuilder =\n | B\n\n []\n member b.Bind(x, f) = View.Bind f x\n\n []\n member b.Return x = View.Const x\n\n []\n member b.ReturnFrom(v: View<'T>) = v\n\n []\n member b.TryWith(v, f) = View.TryWith f v\n\n []\n member b.TryFinally(v, f) = View.TryFinally f v\n\ntype View with\n []\n static member Do = B\n\n[]\ntype Submitter<'T> (input: View<'T>, init: 'T) =\n let var = Var.Create ()\n let view = View.SnapshotOn init var.View input\n\n []\n member this.View = view\n\n member this.Trigger() = var.Value <- ()\n\n []\n member this.Input = input\n\n[]\ntype Submitter =\n\n []\n static member CreateDefault input =\n Submitter<_>(input, Unchecked.defaultof<_>)\n\n []\n static member Create input init =\n Submitter<_>(input, init)\n\n static member CreateOption input =\n Submitter<_>(View.Map Some input, None)\n\n []\n static member View (s: Submitter<_>) =\n s.View\n\n []\n static member Trigger (s: Submitter<_>) =\n s.Trigger()\n\n []\n static member Input (s: Submitter<_>) =\n s.Input\n\n[]\nmodule V =\n\n [)>]\n let V (x: 'T) = View.Const x\n\n[]\ndo ()\n", "// $begin{copyright}\n//\n// This file is part of WebSharper\n//\n// Copyright (c) 2008-2018 IntelliFactory\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\"); you\n// may not use this file except in compliance with the License. You may\n// obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n// implied. See the License for the specific language governing\n// permissions and limitations under the License.\n//\n// $end{copyright}\n\nnamespace WebSharper.UI\n\nopen System\nopen System.Collections.Generic\nopen WebSharper\n\n[]\ntype Key =\n | Key of int\n\n static member Fresh () = Key (Fresh.Int ())\n\n[]\ntype Model<'I,'M>(var: Var<'M>, view: View<'I>) =\n\n new (proj: Func<'M, 'I>, init: 'M) =\n let var = Var.Create init\n let view = View.Map proj.Invoke var.View\n Model(var, view)\n\n []\n member this.Var = var\n []\n member this.View = view\n\n[]\n[]\ntype Model =\n\n static member Create proj init =\n Model(Func<_,_>(proj), init)\n\n static member Update update (m: Model<'I, 'M>) =\n Var.Update m.Var (fun x -> update x; x)\n\n []\n static member View (m: Model<'I, 'M>) =\n m.View\n\ntype Storage<'T> =\n []\n abstract member Append : appending: 'T -> ``to``: 'T[] -> 'T[]\n []\n abstract member AppendMany : appending: seq<'T> -> ``to``: 'T[] -> 'T[]\n []\n abstract member Prepend : appending: 'T -> ``to``: 'T[] -> 'T[]\n []\n abstract member PrependMany : appending: seq<'T> -> ``to``: 'T[] -> 'T[]\n []\n abstract member Init : unit -> 'T[]\n []\n abstract member RemoveIf : ('T -> bool) -> 'T [] -> 'T[]\n []\n abstract member SetAt : int -> 'T -> 'T[] -> 'T[]\n []\n abstract member Set : 'T seq -> 'T[]\n\ntype Serializer<'T> =\n {\n Encode : 'T -> obj\n Decode : obj -> 'T\n }\n\n[]\nmodule Serializer =\n open WebSharper\n open WebSharper.JavaScript\n\n let Default =\n {\n Encode = box\n Decode = unbox\n }\n\n []\n let Typed =\n {\n Encode = WebSharper.Json.Encode<'T>\n Decode = WebSharper.Json.Decode<'T>\n }\n\n[]\nmodule Storage =\n open WebSharper\n open WebSharper.JavaScript\n \n type private ArrayStorage<'T>(init) =\n\n interface Storage<'T> with\n member x.Append i arr = arr.JS.Push i |> ignore; arr\n member x.AppendMany is arr = arr.JS.Push (Array.ofSeqNonCopying is) |> ignore; arr\n member x.Prepend i arr = arr.JS.Unshift i |> ignore; arr\n member x.PrependMany is arr = arr.JS.Unshift (Array.ofSeqNonCopying is) |> ignore; arr\n member x.Init () = init\n member x.RemoveIf pred arr = Array.filter (fun i -> not (pred i)) arr\n member x.SetAt idx elem arr = arr[idx] <- elem; arr\n member x.Set coll = Seq.toArray coll\n\n type private LocalStorageBackend<'T>(id : string, serializer : Serializer<'T>) =\n let storage = JS.Window.LocalStorage\n let set (arr : 'T[]) = \n storage.SetItem(id, arr |> Array.map (fun a -> serializer.Encode a) |> Json.Stringify)\n arr\n let clear () = storage.RemoveItem(id)\n\n interface Storage<'T> with\n member x.Append i arr = arr.JS.Push i |> ignore; set arr\n member x.AppendMany is arr = arr.JS.Push (Array.ofSeqNonCopying is) |> ignore; set arr\n member x.Prepend i arr = arr.JS.Unshift i |> ignore; set arr\n member x.PrependMany is arr = arr.JS.Unshift (Array.ofSeqNonCopying is) |> ignore; set arr\n\n member x.Init () =\n let item = storage.GetItem(id)\n if item = null then [||]\n else \n try\n let arr = As <| Json.Parse(item)\n arr |> Array.map (fun a -> serializer.Decode a)\n with _ -> [||]\n\n member x.RemoveIf pred arr = set <| Array.filter (fun i -> not (pred i)) arr\n member x.SetAt idx elem arr = arr[idx] <- elem; set arr\n member x.Set coll = set <| Seq.toArray coll\n\n let InMemory init =\n new ArrayStorage<_>(init) :> Storage<_>\n\n let LocalStorage id serializer =\n new LocalStorageBackend<_>(id, serializer) :> Storage<_>\n\ntype ListModelState<'T> =\n []\n member this.Length =\n JavaScript.Pervasives.As<'T[]>(this).Length\n []\n member this.Item\n with get i = JavaScript.Pervasives.As<'T[]>(this)[i]\n []\n member this.ToArray() = \n Array.copy (JavaScript.Pervasives.As<'T[]>(this))\n []\n member this.ToArray(pred: Predicate<'T>) =\n Array.filter pred.Invoke (JavaScript.Pervasives.As<'T[]>(this))\n interface seq<'T> with\n member this.GetEnumerator() = (JavaScript.Pervasives.As<'T[]>(this)).GetEnumerator()\n member this.GetEnumerator() = (JavaScript.Pervasives.As<'T seq>(this)).GetEnumerator()\n\n[]\ntype ListModel<'Key, 'T when 'Key : equality>\n (\n key : System.Func<'T, 'Key>,\n var: Var<'T[]>,\n storage : Storage<'T>\n ) =\n\n let v = var.View.Map(fun x -> Array.copy x :> _ seq)\n \n let it = Dictionary<'Key, Snap>>()\n\n new (key: System.Func<'T, 'Key>, init: seq<'T>) =\n let init = Seq.toArray init\n ListModel<'Key, 'T>(key, Var.Create init, Storage.InMemory init)\n\n new (key: System.Func<'T, 'Key>) =\n ListModel<'Key, 'T>(key, [||])\n\n new (key: System.Func<'T, 'Key>, storage: Storage<'T>) =\n let var =\n Seq.distinctBy key.Invoke (storage.Init ())\n |> Seq.toArray\n |> Var.Create\n ListModel<'Key, 'T>(key, var, storage)\n\n []\n member this.key x = key.Invoke x\n []\n member this.Var = var\n []\n member this.Storage = storage\n []\n member this.View = v\n []\n member this.ViewState = JavaScript.Pervasives.As>> var.View\n []\n member this.itemSnaps = it\n\n interface seq<'T> with\n member this.GetEnumerator() =\n (Seq.ofArray var.Value).GetEnumerator()\n\n member this.GetEnumerator() =\n var.Value.GetEnumerator()\n\n[]\nmodule ListModels =\n \n let Contains keyFn item xs =\n let t = keyFn item\n Array.exists (fun it -> keyFn it = t) xs\n\ntype ListModel<'Key,'T when 'Key : equality> with\n\n []\n member m.Key x = m.key x\n\n []\n member m.Add item =\n m.Append item\n\n member m.ObsoleteKey key =\n match m.itemSnaps.TryGetValue(key) with\n | true, sn ->\n Snap.MarkObsolete sn \n m.itemSnaps.Remove key |> ignore\n | _ -> ()\n\n member m.ObsoleteAll() =\n m.itemSnaps |> Seq.iter (fun ksn -> Snap.MarkObsolete ksn.Value)\n m.itemSnaps.Clear()\n\n member m.Append item =\n let v = m.Var.Value\n let t = m.Key item\n match Array.tryFindIndex (fun it -> m.Key it = t) v with\n | None -> m.Var.Value <- m.Storage.Append item v\n | Some index -> \n m.Var.Value <- m.Storage.SetAt index item v\n m.ObsoleteKey t\n\n member m.AppendMany items =\n let toAppend = ResizeArray()\n let v =\n (m.Var.Value, items)\n ||> Seq.fold (fun v item ->\n let t = m.Key item\n m.ObsoleteKey t\n match Array.tryFindIndex (fun it -> m.Key it = t) v with\n | Some index ->\n m.Storage.SetAt index item v\n | None -> toAppend.Add item; v)\n m.Var.Value <- m.Storage.AppendMany toAppend v\n\n member m.Prepend item =\n let v = m.Var.Value\n let t = m.Key item\n match Array.tryFindIndex (fun it -> m.Key it = t) v with\n | None -> m.Var.Value <- m.Storage.Prepend item v\n | Some index -> \n m.Var.Value <- m.Storage.SetAt index item v\n m.ObsoleteKey t\n\n member m.PrependMany items =\n let toPrepend = ResizeArray()\n let v =\n (m.Var.Value, items)\n ||> Seq.fold (fun v item ->\n let t = m.Key item\n m.ObsoleteKey t\n match Array.tryFindIndex (fun it -> m.Key it = t) v with\n | Some index -> \n m.Storage.SetAt index item v\n | None -> toPrepend.Add item; v)\n m.Var.Value <- m.Storage.PrependMany toPrepend v\n\n member m.Remove item =\n let v = m.Var.Value\n if ListModels.Contains m.key item v then\n let keyFn = m.key\n let k = keyFn item\n m.Var.Value <- m.Storage.RemoveIf (fun i -> keyFn i = k) v\n m.ObsoleteKey k\n\n member m.RemoveBy (f: 'T -> bool) =\n for v in m.Var.Value do\n if f v then\n m.ObsoleteKey (m.key v)\n m.Var.Value <- m.Storage.RemoveIf f m.Var.Value\n\n member m.RemoveByKey key =\n m.Var.Value <- m.Storage.RemoveIf (fun i -> m.Key i = key) m.Var.Value\n m.ObsoleteKey key\n\n member m.Iter fn =\n Array.iter fn m.Var.Value\n\n member m.Set lst =\n m.Var.Value <- m.Storage.Set lst\n m.ObsoleteAll()\n\n member m.ContainsKey key =\n Array.exists (fun it -> m.key it = key) m.Var.Value\n\n member m.ContainsKeyAsView key =\n m.Var.View |> View.Map (Array.exists (fun it -> m.key it = key))\n\n member m.Find pred =\n Array.find pred m.Var.Value\n\n member m.TryFind pred =\n Array.tryFind pred m.Var.Value\n\n member m.FindAsView pred =\n m.Var.View |> View.Map (Array.find pred)\n\n member m.TryFindAsView pred =\n m.Var.View |> View.Map (Array.tryFind pred)\n\n member m.FindByKey key =\n Array.find (fun it -> m.key it = key) m.Var.Value\n\n member m.TryFindByKey key =\n Array.tryFind (fun it -> m.key it = key) m.Var.Value\n\n member m.TryFindByKeyAsView key =\n ViewOptimization.V (fun () -> \n match m.itemSnaps.TryGetValue(key) with\n | true, snap -> snap \n | _ ->\n let it = m.TryFindByKey(key)\n let sn = Snap.CreateWithValue it\n m.itemSnaps.Add(key, sn)\n sn\n )\n\n member m.FindByKeyAsView key =\n m.TryFindByKeyAsView key |> View.Map Option.get\n\n member m.UpdateAll fn =\n m.Var.Update <| fun a ->\n a |> Array.iteri (fun i x ->\n fn x |> Option.iter (fun y -> a[i] <- y))\n m.Storage.Set a\n m.ObsoleteAll()\n\n member m.UpdateBy fn key =\n let v = m.Var.Value\n match Array.tryFindIndex (fun it -> m.key it = key) v with\n | None -> ()\n | Some index ->\n match fn v[index] with\n | None -> ()\n | Some value ->\n m.Var.Value <- m.Storage.SetAt index value v\n m.ObsoleteKey key\n\n []\n member m.UpdateByU(fn, key) =\n m.UpdateBy fn key\n\n member m.Clear () =\n m.Var.Value <- m.Storage.Set Seq.empty\n m.ObsoleteAll()\n\n member m.Length =\n m.Var.Value.Length\n\n member m.LengthAsView =\n m.Var.View |> View.Map (fun arr -> arr.Length)\n\n member private m.LensInto'(get: 'T -> 'V, update: 'T -> 'V -> 'T, key : 'Key, view: View<'V>) : Var<'V> =\n let id = Fresh.Id()\n \n { new Var<'V>() with\n\n member r.Get() =\n m.FindByKey key |> get\n\n member r.Set(v) =\n m.UpdateBy (fun i -> Some (update i v)) key\n\n member r.SetFinal(v) =\n r.Set(v)\n\n member r.Update(f) =\n m.UpdateBy (fun i -> Some (update i (f (get i)))) key\n\n member r.UpdateMaybe(f) =\n m.UpdateBy (fun i -> Option.map (fun v -> update i v) (f (get i))) key\n\n member r.View =\n view\n\n member r.Id =\n id\n }\n\n member m.LensInto (get: 'T -> 'V) (update: 'T -> 'V -> 'T) (key : 'Key) : Var<'V> =\n let view = m.FindByKeyAsView(key) |> View.Map get\n m.LensInto'(get, update, key, view)\n\n []\n member m.LensIntoU<'V> (get: 'T -> 'V, update: 'T -> 'V -> 'T, key : 'Key) : Var<'V> =\n m.LensInto get update key\n\n member m.Lens (key: 'Key) =\n m.LensInto id (fun _ -> id) key\n\n member m.Value\n with [] get () = m.Var.Value :> seq<_>\n and [] set v = m.Set(v)\n\n []\n member m.Map (f: 'T -> 'V) : View> =\n View.MapSeqCachedBy m.key f m.ViewState\n\n []\n member m.Map (f: 'Key -> View<'T> -> 'V) : View> =\n View.MapSeqCachedViewBy m.key f m.ViewState\n\n member m.MapLens (f: 'Key -> Var<'T> -> 'V) =\n let get k v =\n f k (m.LensInto'(id, (fun _ -> id), k, v))\n View.MapSeqCachedViewBy m.key get m.ViewState\n\n[]\ntype ListModel =\n\n static member CreateWithStorage<'Key,'T when 'Key : equality>\n (key: 'T -> 'Key) (storage : Storage<'T>) =\n ListModel<'Key, 'T>(key, storage)\n\n static member Create<'Key, 'T when 'Key : equality> (key: 'T -> 'Key) init =\n ListModel.CreateWithStorage key (Storage.InMemory <| Seq.toArray init)\n\n static member FromSeq init =\n ListModel.Create id init\n\n static member Wrap<'Key, 'T, 'U when 'Key : equality>\n (underlying: ListModel<'Key, 'U>)\n (extract: 'T -> 'U)\n (createItem: 'U -> 'T)\n (updateItem: 'T -> 'U -> 'T) =\n let state = ref (Dictionary<'Key, 'T>())\n let init =\n underlying.Var.Value |> Array.map (fun u ->\n let t = createItem u\n state.Value[underlying.Key u] <- t\n t)\n let var : Var<'T[]> =\n underlying.Var.Lens\n <| fun us ->\n let newState = Dictionary<'Key, 'T>()\n let ts =\n us |> Array.map (fun u ->\n let k = underlying.Key u\n let t =\n if state.Value.ContainsKey(k) then\n updateItem state.Value[k] u\n else\n createItem u\n newState[k] <- t\n t\n )\n state.Value <- newState\n ts\n <| fun us ts ->\n let newState = Dictionary<'Key, 'T>()\n let us =\n ts |> Array.map (fun t ->\n let u = extract t\n newState[underlying.Key u] <- t\n u)\n state.Value <- newState\n us\n ListModel<'Key, 'T>(Func<_,_>(extract >> underlying.Key), var, Storage.InMemory init)\n\n []\n static member View (m: ListModel<_,_>) =\n m.View\n\n []\n static member ViewState (m: ListModel<_,_>) =\n m.ViewState\n\n []\n static member Key (m: ListModel<_,_>) =\n m.key\n\n []\n static member Map f (m: ListModel<_, _>) =\n View.MapSeqCachedBy m.key f m.ViewState\n\n []\n static member MapView f (m: ListModel<_, _>) =\n View.MapSeqCachedViewBy m.key f m.ViewState\n\n []\n static member MapLens f (m: ListModel<_, _>) =\n m.MapLens f\n\ntype ListModel<'Key,'T when 'Key : equality> with\n\n member this.Wrap extract wrap update =\n ListModel.Wrap this extract wrap update\n", "// $begin{copyright}\n//\n// This file is part of WebSharper\n//\n// Copyright (c) 2008-2018 IntelliFactory\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\"); you\n// may not use this file except in compliance with the License. You may\n// obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n// implied. See the License for the specific language governing\n// permissions and limitations under the License.\n//\n// $end{copyright}\n\nnamespace WebSharper.UI\n\nopen System.Runtime.CompilerServices\nopen WebSharper\nopen WebSharper.JavaScript\ntype private KV<'K, 'V> = System.Collections.Generic.KeyValuePair<'K, 'V>\n\n[]\nmodule VarModule =\n\n [)>]\n let Lens (x: 'T) = Var.Create x\n\n// These methods apply to specific types of View (such as View> when 'A : equality)\n/// so we need to use C#-style extension methods.\n[]\ntype ReactiveExtensions() =\n\n []\n static member MapCached (v, f) = View.MapCached f v\n\n []\n static member MapSeqCached<'A, 'B when 'A : equality>\n (v: View>, f: 'A -> 'B) = View.MapSeqCached f v\n\n []\n static member MapSeqCached<'A, 'B, 'K when 'K : equality>\n (v: View>, k: 'A -> 'K, f: 'A -> 'B) = View.MapSeqCachedBy k f v\n\n []\n static member MapSeqCached<'A, 'B when 'A : equality>\n (v: View>, f: View<'A> -> 'B) = View.MapSeqCachedView f v\n\n []\n static member MapSeqCached<'A, 'B, 'K when 'K : equality>\n (v: View>, k: 'A -> 'K, f: 'K -> View<'A> -> 'B) = View.MapSeqCachedViewBy k f v\n\n []\n static member MapSeqCached<'A, 'B when 'A : equality>\n (v: View>, f: 'A -> 'B) = View.MapSeqCached f v\n\n []\n static member MapSeqCached<'A, 'B, 'K when 'K : equality>\n (v: View>, k: 'A -> 'K, f: 'A -> 'B) = View.MapSeqCachedBy k f v\n\n []\n static member MapSeqCached<'A, 'B when 'A : equality>\n (v: View>, f: View<'A> -> 'B) = View.MapSeqCachedView f v\n\n []\n static member MapSeqCached<'A, 'B, 'K when 'K : equality>\n (v: View>, k: 'A -> 'K, f: 'K -> View<'A> -> 'B) = View.MapSeqCachedViewBy k f v\n\n []\n static member MapSeqCached<'A, 'B when 'A : equality>\n (v: View>, f: 'A -> 'B) = View.MapSeqCached f v\n\n []\n static member MapSeqCached<'A, 'B, 'K when 'K : equality>\n (v: View>, k: 'A -> 'K, f: 'A -> 'B) = View.MapSeqCachedBy k f v\n\n []\n static member MapSeqCached<'A, 'B when 'A : equality>\n (v: View>, f: View<'A> -> 'B) = View.MapSeqCachedView f v\n\n []\n static member MapSeqCached<'A, 'B, 'K when 'K : equality>\n (v: View>, k: 'A -> 'K, f: 'K -> View<'A> -> 'B) = View.MapSeqCachedViewBy k f v\n\n []\n static member MapSeqCached<'A, 'B when 'A : equality>\n (v: View>, f: 'A -> 'B) = View.MapSeqCached f v\n\n []\n static member MapSeqCached<'A, 'B, 'K when 'K : equality>\n (v: View>, k: 'A -> 'K, f: 'A -> 'B) = View.MapSeqCachedBy k f v\n\n []\n static member MapSeqCached<'A, 'B when 'A : equality>\n (v: View>, f: View<'A> -> 'B) = View.MapSeqCachedView f v\n\n []\n static member MapSeqCached<'A, 'B, 'K when 'K : equality>\n (v: View>, k: 'A -> 'K, f: 'K -> View<'A> -> 'B) = View.MapSeqCachedViewBy k f v\n\n []\n static member MapSeqCached<'A, 'B, 'K when 'K : equality and 'K : comparison>\n (v: View>, f: 'K -> View<'A> -> 'B) =\n View.MapSeqCachedViewBy\n (fun (kv: KV<'K, 'A>) -> kv.Key)\n (fun k v -> f k (View.Map (fun (kv: KV<'K, 'A>) -> kv.Value) v))\n v\n\n [)>]\n static member LensAuto<'T, 'U>(ref: Var<'T>, getter: 'T -> 'U) = X>\n\n []\n static member MapLens<'A, 'B, 'K when 'K : equality>(v: Var>, k: 'A -> 'K, f: Var<'A> -> 'B) = Var.MapLens k f v\n", "// $begin{copyright}\n//\n// This file is part of WebSharper\n//\n// Copyright (c) 2008-2018 IntelliFactory\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\"); you\n// may not use this file except in compliance with the License. You may\n// obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n// implied. See the License for the specific language governing\n// permissions and limitations under the License.\n//\n// $end{copyright}\n\nnamespace WebSharper.UI\n\nopen System\nopen WebSharper\nopen WebSharper.JavaScript\nopen System.Runtime.InteropServices\n\ntype Time = double\ntype NormalizedTime = double\n\n// Interpolation --------------------------------------------------------------\n\ntype Interpolation<'T> =\n []\n abstract Interpolate : NormalizedTime -> 'T -> 'T -> 'T\n\n[]\ntype DoubleInterpolation =\n | DoubleInterpolation\n\n interface Interpolation with\n member d.Interpolate t x y =\n x + t * (y - x)\n\n[]\n[]\ntype Interpolation =\n static member Double = DoubleInterpolation :> Interpolation<_>\n\n// Easing ---------------------------------------------------------------------\n\n[]\ntype Easing (transformTime : Converter) =\n\n member this.TransformTime t = transformTime.Invoke t\n static member Custom f = Easing (fun t -> f t)\n\n[]\nmodule Easings =\n\n let CubicInOut =\n let f t =\n let t2 = t * t\n let t3 = t2 * t\n 3. * t2 - 2. * t3\n Easing.Custom f\n\ntype Easing with\n static member CubicInOut = Easings.CubicInOut\n\n// Animation ------------------------------------------------------------------\n\ntype Anim<'T> =\n private {\n Compute : Time -> 'T\n Duration : Time\n }\n\ntype Animation =\n | Finally of (unit -> unit)\n | Work of Anim\n\n[]\n[]\ntype Anim =\n | Anim of AppendList\n\n[]\nmodule Anims =\n\n let List (Anim xs) =\n xs\n\n let Finalize (Anim all) =\n AppendList.ToArray all\n |> Array.iter (function\n | Finally f -> f ()\n | _ -> ())\n\n let Def d f =\n { Compute = f; Duration = d}\n\n let Const v =\n Def 0. (fun t -> v)\n\n // \"Prolongs\" an animation to the given time by adding in several\n // no-ops after the animation finishes.\n let Prolong nextDuration anim =\n let comp = anim.Compute\n let dur = anim.Duration\n let last = lazy anim.Compute anim.Duration\n let compute t = if t >= dur then last.Value else comp t\n\n {\n Compute = compute\n Duration = nextDuration\n }\n\n let ConcatActions xs =\n let xs = Array.ofSeqNonCopying xs\n match xs.Length with\n | 0 -> Const ()\n | 1 -> xs[0]\n | _ ->\n let dur = xs |> Seq.map (fun anim -> anim.Duration) |> Seq.max\n let xs = Array.map (fun x -> Prolong dur x) xs\n Def dur (fun t -> Array.iter (fun anim -> anim.Compute t) xs)\n\n let Actions (Anim all) =\n AppendList.ToArray all\n |> Array.choose (function\n | Work w -> Some w\n | _ -> None)\n |> ConcatActions\n\n let mutable UseAnimations = true\n\ntype Anim with\n\n static member UseAnimations \n with get() = Anims.UseAnimations\n and set v = Anims.UseAnimations <- v \n\n static member Append (Anim a) (Anim b) =\n Anim (AppendList.Append a b)\n\n static member Concat xs =\n xs\n |> Seq.map Anims.List\n |> AppendList.Concat\n |> Anim\n\n static member Const v =\n Anims.Const v\n\n static member Simple (inter: Interpolation<'T>) (easing: Easing) dur x y=\n {\n Duration = dur\n Compute = fun t ->\n let t = easing.TransformTime (t / dur)\n inter.Interpolate t x y\n }\n\n static member Delayed (inter: Interpolation<'T>) (easing: Easing) dur delay x y =\n {\n Duration = dur + delay\n Compute = fun t ->\n // JavaScript.Log <| \"T: \" + (string t) + \", delay: \" + (string delay)\n if t <= delay then\n x\n else\n let normalisedTime = easing.TransformTime ((t - delay) / dur)\n inter.Interpolate normalisedTime x y\n }\n\n static member Map f anim =\n Anims.Def anim.Duration (anim.Compute >> f)\n\n static member Pack anim =\n Anim (AppendList.Single (Work anim))\n\n static member Play anim =\n async {\n do! Anims.Actions anim\n |> Anim.Run ignore\n return Anims.Finalize anim\n }\n\n static member Run k anim =\n let dur = anim.Duration\n if dur = 0. then async.Zero() else\n Async.FromContinuations <| fun (ok, _, _) ->\n let rec loop start now =\n let t = now - start\n k (anim.Compute t)\n if t <= dur then\n JS.RequestAnimationFrame (fun t -> loop start t) |> ignore\n else ok ()\n JS.RequestAnimationFrame (fun t -> loop t t) |> ignore\n\n static member WhenDone f main =\n main\n |> Anim.Append (Anim (AppendList.Single (Finally f)))\n\n static member Empty =\n Anim AppendList.Empty\n\n// Transitions ----------------------------------------------------------------\n\ntype TFlags =\n | TTrivial = 0\n | TChange = 1\n | TEnter = 2\n | TExit = 4\n\n[]\ntype Trans<'T>\n (\n change: Func<'T, 'T, Anim<'T>>,\n enter: Func<'T, Anim<'T>>,\n exit: Func<'T, Anim<'T>>,\n flags: TFlags\n ) =\n\n new () =\n Trans(\n (fun x y -> Anim.Const y),\n (fun t -> Anim.Const t),\n (fun t -> Anim.Const t),\n TFlags.TTrivial\n )\n\n new (ch: Func<'T, 'T, Anim<'T>>) =\n Trans(\n ch,\n (fun t -> Anim.Const t),\n (fun t -> Anim.Const t),\n TFlags.TChange\n )\n\n new (ch: Func<'T, 'T, Anim<'T>>, enter, exit) =\n Trans(\n ch,\n (if enter = null then Func<_,_>(fun t -> Anim.Const t) else enter),\n (if exit = null then Func<_,_>(fun t -> Anim.Const t) else exit),\n TFlags.TChange ||| \n (if enter = null then TFlags.TTrivial else TFlags.TEnter) |||\n (if exit = null then TFlags.TTrivial else TFlags.TExit)\n )\n\n member this.TChange x y = change.Invoke(x, y)\n member this.TEnter = enter.Invoke\n member this.TExit = exit.Invoke\n member this.TFlags = flags\n\n member this.Copy(?change, ?enter, ?exit, ?flags) =\n let ch = defaultArg change this.TChange\n let en = defaultArg enter this.TEnter\n let ex = defaultArg exit this.TExit\n let fl = defaultArg flags this.TFlags\n Trans(Func<_,_,_>(ch), Func<_,_>(en),\n Func<_,_>(ex), fl)\n\n[]\n[]\ntype Trans =\n\n // Using a Trans ---------------\n\n static member AnimateChange (tr: Trans<'T>) x y = tr.TChange x y\n static member AnimateEnter (tr: Trans<'T>) x = tr.TEnter x\n static member AnimateExit (tr: Trans<'T>) x = tr.TExit x\n static member CanAnimateChange (tr: Trans<'T>) = tr.TFlags.HasFlag(TFlags.TChange)\n static member CanAnimateEnter (tr: Trans<'T>) = tr.TFlags.HasFlag(TFlags.TEnter)\n static member CanAnimateExit (tr: Trans<'T>) = tr.TFlags.HasFlag(TFlags.TExit)\n\n // Creating a Trans ------------\n\n static member Trivial () =\n Trans()\n\n static member Create (ch: 'T -> 'T -> Anim<'T>) =\n Trans(Func<_,_,_>(ch))\n\n static member Change ch (tr: Trans<'T>) =\n tr.Copy(change = ch, flags = (tr.TFlags ||| TFlags.TChange))\n\n static member Enter f (tr: Trans<'T>) =\n tr.Copy(enter = f, flags = (tr.TFlags ||| TFlags.TEnter))\n\n static member Exit f (tr: Trans<'T>) =\n tr.Copy(exit = f, flags = (tr.TFlags ||| TFlags.TExit))\n", "// $begin{copyright}\n//\n// This file is part of WebSharper\n//\n// Copyright (c) 2008-2018 IntelliFactory\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\"); you\n// may not use this file except in compliance with the License. You may\n// obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n// implied. See the License for the specific language governing\n// permissions and limitations under the License.\n//\n// $end{copyright}\n\nnamespace WebSharper.UI\n\nopen System\nopen System.Linq.Expressions\nopen Microsoft.FSharp.Quotations\nopen Microsoft.FSharp.Quotations.Patterns\nopen WebSharper\nopen WebSharper.JavaScript\nopen WebSharper.Core.Resources\nmodule M = WebSharper.Core.Metadata\nmodule R = WebSharper.Core.AST.Reflection\nmodule J = WebSharper.Core.Json\nmodule P = FSharp.Quotations.Patterns\n\nmodule private Internal =\n\n open WebSharper.Core\n open WebSharper.Web.ClientSideInternals\n\n let activateNode =\n M.MethodNode(\n AST.TypeDefinition {\n Assembly = \"WebSharper.Main\"\n FullName = \"WebSharper.Activator\"\n },\n AST.Method {\n MethodName = \"Activate\"\n Parameters = []\n ReturnType = AST.VoidType\n Generics = 0\n } \n )\n\n let afterRenderNode =\n M.MethodNode(\n AST.TypeDefinition {\n Assembly = \"WebSharper.UI.Templating.Runtime\"\n FullName = \"WebSharper.UI.Templating.Runtime.Client.ClientTemplateInstanceHandlers\"\n },\n AST.Method {\n MethodName = \"AfterRenderQ2Client\"\n Parameters = [\n R.ReadType typeof\n R.ReadType typeof\n R.ReadType typeof unit>\n ]\n ReturnType = AST.VoidType\n Generics = 0\n } \n )\n\n let eventNode =\n M.MethodNode(\n AST.TypeDefinition {\n Assembly = \"WebSharper.UI.Templating.Runtime\"\n FullName = \"WebSharper.UI.Templating.Runtime.Client.ClientTemplateInstanceHandlers\"\n },\n AST.Method {\n MethodName = \"EventQ2Client\"\n Parameters = [\n R.ReadType typeof\n R.ReadType typeof\n R.ReadType typeof\n R.ReadType typeof unit>\n ]\n ReturnType = AST.VoidType\n Generics = 0\n } \n )\n\n let compile (meta: M.Info) (q: Expr) =\n let reqs = ResizeArray()\n let rec compile' (q: Expr) : option string> =\n match getLocation q with\n | Some p ->\n match meta.Quotations.TryGetValue(p) with\n | false, _ ->\n None\n | true, (declType, meth, argNames) ->\n match meta.Classes.TryGetValue declType with\n | false, _ -> failwithf \"Error in Handler: Couldn't find JavaScript address for method %s.%s\" declType.Value.FullName meth.Value.MethodName\n | true, c ->\n let argIndices = Map (argNames |> List.mapi (fun i x -> x, i))\n let args = Array.zeroCreate string> argNames.Length\n reqs.Add(M.MethodNode (declType, meth))\n reqs.Add(M.TypeNode declType)\n let setArg (name: string) (value: obj) =\n let i = argIndices[name]\n if obj.ReferenceEquals(args[i], null) then\n args[i] <-\n match value with\n | :? Expr as q ->\n compile' q |> Option.get\n | value ->\n let typ = value.GetType()\n reqs.Add(M.TypeNode (WebSharper.Core.AST.Reflection.ReadTypeDefinition typ))\n fun (json: J.Provider) ->\n let packed = json.GetEncoder(typ).Encode(value) |> json.Pack\n let s = WebSharper.Core.Json.Stringify(packed)\n match packed with\n | WebSharper.Core.Json.Object (((\"$TYPES\" | \"$DATA\"), _) :: _) ->\n \"WebSharper.Json.Activate(\" + s + \")\"\n | _ -> s\n findArgs Set.empty setArg q\n let addr =\n match c.Methods.TryGetValue meth with\n | true, (M.CompiledMember.Static x, _, _) -> x.Value\n | _ -> failwithf \"Error in Handler: Couldn't find JavaScript address for method %s.%s\" declType.Value.FullName meth.Value.MethodName\n let funcall = String.concat \".\" (List.rev addr)\n let write (json: J.Provider) =\n let args = String.concat \",\" (args |> Seq.map (fun a -> a json))\n sprintf \"%s(%s)\" funcall args\n Some write\n | None -> None\n compile' q\n |> Option.map (fun s ->\n reqs.Add(activateNode)\n s, reqs :> seq<_>\n )\n\ntype private OnAfterRenderControl private () =\n inherit Web.Control()\n\n static member val Instance = new OnAfterRenderControl(ID = \"ws.ui.oar\") :> IRequiresResources\n\n []\n override this.Body =\n let l = JS.Document.QuerySelectorAll(\"[ws-runafterrender]\")\n for i = 0 to l.Length - 1 do\n let x = l[i] :?> Dom.Element\n let attr = x.GetAttribute(\"ws-runafterrender\")\n if attr.Contains(\"AfterRenderQ2Client\") then\n x.RemoveAttribute(\"ws-runafterrender\")\n JS.Eval(attr) |> ignore\n else\n let f = JS.Eval(attr) :?> (Dom.Element -> unit)\n x.RemoveAttribute(\"ws-runafterrender\")\n f x\n { new IControlBody with member this.ReplaceInDom(_) = () }\n\n// We would have wanted to use UseNullAsTrueValue so that EmptyAttr = null,\n// which makes things much easier when it comes to optional arguments in Templating.\n// The problem is that for some reason UNATV is ignored if there are 4 or more cases.\n// So we end up having to do explicit null checks everywhere :(\ntype Attr =\n | AppendAttr of list\n | SingleAttr of string * string\n | DepAttr of string * (M.Info -> J.Provider -> string) * (M.Info -> seq) * (M.Info -> J.Provider -> list)\n\n member this.Write(meta, json, w: HtmlTextWriter, removeWsHole) =\n match this with\n | AppendAttr attrs ->\n attrs |> List.iter (fun a ->\n if not (obj.ReferenceEquals(a, null))\n then a.Write(meta, json, w, removeWsHole))\n | SingleAttr (n, v) ->\n if not (removeWsHole && n = \"ws-hole\") then\n w.WriteAttribute(n, v)\n | DepAttr (n, v, _, _) ->\n w.WriteAttribute(n, v meta json)\n\n interface IRequiresResources with\n\n member this.Requires(meta) =\n match this with\n | AppendAttr attrs ->\n attrs |> Seq.collect (fun a ->\n if obj.ReferenceEquals(a, null)\n then Seq.empty\n else (a :> IRequiresResources).Requires(meta))\n | DepAttr (_, _, reqs, _) -> reqs meta\n | SingleAttr _ -> Seq.empty\n\n member this.Encode (meta, json) =\n match this with\n | AppendAttr attrs ->\n attrs |> List.collect (fun a ->\n if obj.ReferenceEquals(a, null)\n then []\n else (a :> IRequiresResources).Encode(meta, json))\n | DepAttr (_, _, _, enc) -> enc meta json\n | SingleAttr _ -> []\n\n member this.WithName(n) =\n match this with\n | AppendAttr _ -> this\n | SingleAttr(_, v) -> SingleAttr(n, v)\n | DepAttr(_, v, d, e) -> DepAttr(n, v, d, e)\n\n static member Create name value =\n SingleAttr (name, value)\n\n static member Append a b =\n AppendAttr [a; b]\n\n static member Empty =\n AppendAttr []\n\n static member Concat (xs: seq) =\n AppendAttr (List.ofSeq xs)\n\n static member WithDependencies(name, getValue, deps) =\n DepAttr (name, getValue, deps, fun _ _ -> [])\n\n static member OnAfterRenderImpl(q: Expr unit>) =\n let value = ref None\n let init meta =\n if Option.isNone value.Value then\n value.Value <-\n let oarReqs = OnAfterRenderControl.Instance.Requires meta\n match Internal.compile meta q with\n | Some (v, m) -> Some (v, Seq.append oarReqs m)\n | _ ->\n let m =\n match q with\n | Lambda (x1, Call(None, m, [Var x2])) when x1 = x2 -> m\n | _ -> failwithf \"Invalid handler function: %A\" q\n let loc = WebSharper.Web.ClientSideInternals.getLocation' q\n let func, reqs = Attr.HandlerFallback(m, loc, id)\n Some (func meta, Seq.append oarReqs reqs)\n let getValue (meta: M.Info) (json: J.Provider) =\n init meta\n (fst (Option.get value.Value)) json\n let getReqs (meta: M.Info) =\n init meta \n snd (Option.get value.Value)\n let enc (meta: M.Info) (json: J.Provider) =\n init meta\n OnAfterRenderControl.Instance.Encode(meta, json)\n DepAttr(\"ws-runafterrender\", getValue, getReqs, enc)\n\n static member HandlerImpl(event: string, q: Expr #Dom.Event -> unit>) =\n let value = ref None\n let init meta =\n if Option.isNone value.Value then\n value.Value <-\n match Internal.compile meta q with\n | Some _ as v -> v\n | _ ->\n let m =\n match q with\n | Lambda (x1, Lambda (y1, Call(None, m, [Var x2; (Var y2 | Coerce(Var y2, _))]))) when x1 = x2 && y1 = y2 -> m\n | _ -> failwithf \"Invalid handler function: %A\" q\n let loc = WebSharper.Web.ClientSideInternals.getLocation' q\n let func, reqs = Attr.HandlerFallback(m, loc, fun s -> s + \"(this, event)\")\n Some (func meta, reqs)\n let getValue (meta: M.Info) (json: J.Provider) =\n init meta\n (fst (Option.get value.Value)) json + \"(this)(event)\"\n let getReqs (meta: M.Info) =\n init meta\n snd (Option.get value.Value)\n Attr.WithDependencies(\"on\" + event, getValue, getReqs)\n\n static member Handler (event: string) ([] q: Expr #Dom.Event -> unit>) =\n Attr.HandlerImpl(event, q)\n\n static member HandlerFallback(m, location, doCall) =\n let meth = R.ReadMethod m\n let declType = R.ReadTypeDefinition m.DeclaringType\n let reqs = [M.MethodNode (declType, meth); M.TypeNode declType]\n let value = ref None\n let fail() =\n failwithf \"Error in Handler%s: Couldn't find JavaScript address for method %s.%s\"\n location declType.Value.FullName meth.Value.MethodName\n let func (meta: M.Info) (json: J.Provider) =\n match value.Value with\n | None ->\n match meta.Classes.TryGetValue declType with\n | true, c ->\n let addr =\n match c.Methods.TryGetValue meth with\n | true, (M.CompiledMember.Static x, _, _) -> x.Value\n | _ -> fail()\n let s = String.concat \".\" (List.rev addr) |> doCall\n value.Value <- Some s\n s\n | _ -> fail()\n | Some v -> v\n func, reqs :> seq<_>\n\n static member HandlerLinqImpl(event, m, key: string, q: Expression>) =\n let value = ref None\n let init meta =\n if Option.isNone value.Value then\n value.Value <-\n match q.Body with\n | :? MethodCallExpression as b when b.Arguments.Count = 0 ->\n let func, reqs = Attr.HandlerFallback(b.Method, \"no location\", fun s -> s + \"()\")\n Some (func meta, reqs)\n | :? MethodCallExpression as b when b.Arguments.Count = 1 ->\n match b.Arguments[0] with\n | :? ParameterExpression as p when p.Type = q.Parameters[0].Type || p.Type = q.Parameters[1].Type ->\n let func, reqs =\n Attr.HandlerFallback(b.Method, \"no location\",\n fun s -> if p.Type = typeof then s + \"(event)\" else s + \"(this)\")\n Some (func meta, reqs)\n | :? ParameterExpression as p when p.Type.AssemblyQualifiedName.StartsWith \"WebSharper.UI.Templating.Runtime.Server+TemplateEvent`3\" ->\n let func, reqs =\n Attr.HandlerFallback(b.Method, \"no location\",\n fun s -> \"WebSharper.UI.Templating.Runtime.Client.ClientTemplateInstanceHandlers.EventQ2Client(\\\"\" + key + \"\\\", this, event, \" + s + \")\")\n Some (func meta, reqs)\n | _ -> failwithf \"Invalid handler function: %A\" q\n | :? MethodCallExpression as b when b.Arguments.Count = 2 ->\n match b.Arguments[0], b.Arguments[1] with\n | :? ParameterExpression, :? ParameterExpression as (p1, p2) when p1.Type = q.Parameters[0].Type && q.Parameters[1].Type.IsAssignableFrom(p2.Type) ->\n let func, reqs =\n Attr.HandlerFallback(b.Method, \"no location\", fun s -> s + \"(this, event)\")\n Some (func meta, reqs)\n | :? ParameterExpression, :? ParameterExpression as (p1, p2) when p2.Type = q.Parameters[0].Type && q.Parameters[1].Type.IsAssignableFrom(p1.Type) ->\n let func, reqs =\n Attr.HandlerFallback(b.Method, \"no location\", fun s -> s + \"(event, this)\")\n Some (func meta, reqs)\n | _ -> failwithf \"Invalid handler function: %A\" q\n | _ -> failwithf \"Invalid handler function: %A\" q\n let getValue (meta: M.Info) (json: J.Provider) =\n init meta\n (fst (Option.get value.Value)) json\n let getReqs (meta: M.Info) =\n init meta\n let reqs = snd (Option.get value.Value)\n reqs |> Seq.append (seq { Internal.eventNode })\n Attr.WithDependencies(\"on\" + event, getValue, getReqs)\n\n static member HandlerLinq (event: string) (q: Expression>) =\n let meth =\n match q.Body with\n | :? MethodCallExpression as e -> e.Method\n | _ -> failwithf \"Invalid handler function: %A\" q\n Attr.HandlerLinqImpl(event, meth, \"\", q)\n\n static member HandlerLinqWithKey (event: string) (key: string) (q: Expression>) =\n let meth =\n match q.Body with\n | :? MethodCallExpression as e -> e.Method\n | _ -> failwithf \"Invalid handler function: %A\" q\n Attr.HandlerLinqImpl(event, meth, key, q)\n\n static member OnAfterRenderLinqImpl(m, location, key: string, q: Expression>) =\n let value = ref None\n let init meta =\n if Option.isNone value.Value then\n value.Value <-\n let oarReqs = OnAfterRenderControl.Instance.Requires meta\n match q.Body with\n | :? MethodCallExpression as b when b.Arguments.Count = 0 ->\n let func, reqs = Attr.HandlerFallback(b.Method, \"no location\", id)\n Some (func meta, Seq.append oarReqs reqs)\n | :? MethodCallExpression as b when b.Arguments.Count = 1 ->\n match b.Arguments[0] with\n | :? ParameterExpression as p when p.Type = q.Parameters[0].Type ->\n let func, reqs = Attr.HandlerFallback(b.Method, \"no location\", id)\n Some (func meta, Seq.append oarReqs reqs)\n | :? ParameterExpression as p when p.Type.AssemblyQualifiedName.StartsWith \"WebSharper.UI.Templating.Runtime.Server+TemplateEvent`3\" ->\n let func, reqs =\n Attr.HandlerFallback(b.Method, \"no location\",\n fun s -> \"WebSharper.UI.Templating.Runtime.Client.ClientTemplateInstanceHandlers.AfterRenderQ2Client(\\\"\" + key + \"\\\", this, \" + s + \")\")\n Some (func meta, Seq.append oarReqs reqs)\n | _ -> failwithf \"Invalid handler function: %A\" q\n | _ -> failwithf \"Invalid handler function: %A\" q\n \n let getValue (meta: M.Info) (json: J.Provider) =\n init meta\n (fst (Option.get value.Value)) json\n let getReqs (meta: M.Info) =\n init meta \n let reqs = snd (Option.get value.Value)\n reqs |> Seq.append (seq { Internal.afterRenderNode })\n let enc (meta: M.Info) (json: J.Provider) =\n init meta\n OnAfterRenderControl.Instance.Encode(meta, json)\n DepAttr(\"ws-runafterrender\", getValue, getReqs, enc)\n\n static member OnAfterRenderLinq (key: string) (q: Expression>) =\n let meth =\n match q.Body with\n | :? MethodCallExpression as e -> e.Method\n | _ -> failwithf \"Invalid handler function: %A\" q\n Attr.OnAfterRenderLinqImpl(meth, \"\", key, q)\n", "// $begin{copyright}\n//\n// This file is part of WebSharper\n//\n// Copyright (c) 2008-2018 IntelliFactory\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\"); you\n// may not use this file except in compliance with the License. You may\n// obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n// implied. See the License for the specific language governing\n// permissions and limitations under the License.\n//\n// $end{copyright}\n\nnamespace WebSharper.UI.Client\n\nopen System.Collections.Generic\nopen Microsoft.FSharp.Quotations\nopen WebSharper\nopen WebSharper.JavaScript\nopen WebSharper.UI\nopen WebSharper.MathJS\nmodule DU = DomUtility\n\ntype IAttrNode =\n []\n abstract Changed : View\n []\n abstract GetChangeAnim : Dom.Element -> Anim\n []\n abstract GetEnterAnim : Dom.Element -> Anim\n []\n abstract GetExitAnim : Dom.Element -> Anim\n []\n abstract Sync : Dom.Element -> unit\n\n[]\ntype AnimatedAttrNode<'T>(tr: Trans<'T>, view: View<'T>, push: Dom.Element -> 'T -> unit) =\n let mutable logical : option<'T> = None // current logical value\n let mutable visible : option<'T> = None // current value pushed to the parent element\n let mutable dirty = true // logical <> visible\n\n let updates =\n view\n |> View.Map (fun x ->\n logical <- Some x\n dirty <- true)\n\n let pushVisible el v =\n visible <- Some v\n dirty <- true\n push el v\n\n let sync p =\n if dirty then\n Option.iter (fun v -> push p v) logical\n visible <- logical\n dirty <- false\n\n interface IAttrNode with\n\n member a.GetChangeAnim parent =\n match visible, logical with\n | Some v, Some l when dirty ->\n Trans.AnimateChange tr v l\n |> Anim.Map (pushVisible parent)\n |> Anim.Pack\n | _ -> Anim.Empty\n |> Anim.WhenDone (fun () -> sync parent)\n\n member a.GetEnterAnim parent =\n match visible, logical with\n | Some vi, Some lo when dirty ->\n Trans.AnimateChange tr vi lo\n |> Anim.Map (pushVisible parent)\n |> Anim.Pack\n | None, Some lo ->\n Trans.AnimateEnter tr lo\n |> Anim.Map (pushVisible parent)\n |> Anim.Pack\n | _ -> Anim.Empty\n |> Anim.WhenDone (fun () -> sync parent)\n\n member a.GetExitAnim parent =\n match visible with\n | Some cur ->\n Trans.AnimateExit tr cur\n |> Anim.Map (pushVisible parent)\n |> Anim.Pack\n | _ -> Anim.Empty\n |> Anim.WhenDone (fun () -> dirty <- true; visible <- None)\n\n /// NOTE: enter or change animation will do the sync.\n member a.Sync parent = ()\n\n member a.Changed = updates\n\n[]\ntype DynamicAttrNode<'T>(view: View<'T>, push: Dom.Element -> 'T -> unit) =\n let mutable value = JS.Undefined\n let mutable dirty = false\n let updates = view |> View.Map (fun x -> value <- x; dirty <- true)\n interface IAttrNode with\n member a.GetChangeAnim parent = Anim.Empty\n member a.GetEnterAnim parent = Anim.Empty\n member a.GetExitAnim parent = Anim.Empty\n member a.Sync parent = if dirty then push parent value; dirty <- false\n member a.Changed = updates\n\ntype AttrFlags =\n | Defaults = 0\n | HasEnterAnim = 1\n | HasExitAnim = 2\n | HasChangeAnim = 4\n\n[); Name \"WebSharper.UI.AttrProxy\"; Prototype>]\ntype internal AttrProxy =\n | [] A0\n | A1 of IAttrNode\n | A2 of AttrProxy * AttrProxy\n | A3 of init: (Dom.Element -> unit)\n | A4 of onAfterRender: (Dom.Element -> unit)\n\n[]\nmodule Attrs =\n\n type Dyn =\n {\n DynElem : Dom.Element\n DynFlags : AttrFlags\n DynNodes : IAttrNode []\n []\n OnAfterRender : option unit>\n }\n\n let HasChangeAnim attr =\n attr.DynFlags.HasFlag AttrFlags.HasChangeAnim\n\n let HasEnterAnim attr =\n attr.DynFlags.HasFlag AttrFlags.HasEnterAnim\n\n let HasExitAnim attr =\n attr.DynFlags.HasFlag AttrFlags.HasExitAnim\n\n let Flags a =\n if a !==. null && JS.HasOwnProperty a \"flags\"\n then a?flags\n else AttrFlags.Defaults\n\n let SetFlags (a: AttrProxy) (f: AttrFlags) =\n a?flags <- f\n\n /// Synchronizes dynamic attributes.\n let Sync elem dyn =\n dyn.DynNodes\n |> Array.iter (fun d ->\n d.Sync elem)\n\n /// Inserts static attributes and computes dynamic attributes.\n let Insert elem (tree: Attr) =\n let nodes = Queue()\n let oar = Queue()\n let rec loop node =\n if not (obj.ReferenceEquals(node, null)) then // work around WS issue with UseNullAsTrueValue\n match node with\n | A0 -> ()\n | A1 n -> nodes.Enqueue n\n | A2 (a, b) -> loop a; loop b\n | A3 mk -> mk elem\n | A4 cb -> oar.Enqueue cb\n loop (As tree)\n let arr = nodes.ToArray()\n {\n DynElem = elem\n DynFlags = Flags tree\n DynNodes = arr\n OnAfterRender =\n if oar.Count = 0 then None else\n Some (fun el -> Seq.iter (fun f -> f el) oar)\n }\n\n let Empty e =\n {\n DynElem = e\n DynFlags = AttrFlags.Defaults\n DynNodes = [||]\n OnAfterRender = None\n }\n\n let Updates dyn =\n dyn.DynNodes\n |> Array.MapTreeReduce (fun x -> x.Changed) (View.Const ()) View.Map2Unit\n\n let GetAnim dyn f =\n dyn.DynNodes\n |> Array.map (fun n -> f n dyn.DynElem)\n |> Anim.Concat\n\n let GetEnterAnim dyn =\n GetAnim dyn (fun n -> n.GetEnterAnim)\n\n let GetExitAnim dyn =\n GetAnim dyn (fun n -> n.GetExitAnim)\n\n let GetChangeAnim dyn =\n GetAnim dyn (fun n -> n.GetChangeAnim)\n\n []\n let GetOnAfterRender dyn =\n dyn.OnAfterRender\n\n let AppendTree a b =\n // work around WS issue with UseNullAsTrueValue\n if obj.ReferenceEquals(a, null) then b\n elif obj.ReferenceEquals(b, null) then a\n else\n let x = A2 (a, b)\n SetFlags x (Flags a ||| Flags b)\n x\n// match a, b with\n// | A0, x | x, A0 -> x\n// | _ -> A2 (a, b)\n\n let internal EmptyAttr = A0\n\n let internal Animated tr view set =\n let node = AnimatedAttrNode (tr, view, set)\n let mutable flags = AttrFlags.HasChangeAnim\n if Trans.CanAnimateEnter tr then\n flags <- flags ||| AttrFlags.HasEnterAnim\n if Trans.CanAnimateExit tr then\n flags <- flags ||| AttrFlags.HasExitAnim\n let n = A1 node\n SetFlags n flags\n n\n\n let internal Dynamic view set =\n A1 (DynamicAttrNode (view, set))\n\n let internal Static attr =\n A3 attr\n\n\ntype AttrProxy with\n\n static member Create name value =\n As (Attrs.Static (fun el -> DU.SetAttr el name value))\n\n static member Append (a: Attr) (b: Attr) =\n As (Attrs.AppendTree (As a) (As b))\n\n []\n static member Empty =\n As Attrs.EmptyAttr\n\n static member Concat (xs: seq) =\n Array.ofSeqNonCopying xs\n |> Array.TreeReduce Attr.Empty Attr.Append\n\n static member OnAfterRenderImpl(q: Expr unit>) =\n As (A4 (As q))\n\n static member HandlerImpl(event: string, q: Expr #Dom.Event-> unit>) =\n As (Attrs.Static (fun el -> el.AddEventListener(event, (As Dom.Event -> unit> q) el, false)))\n\n static member Handler (event: string) (q: Expr #Dom.Event-> unit>) =\n AttrProxy.HandlerImpl(event, q)\n\n[]\ntype CheckedInput<'T> =\n | Valid of value: 'T * inputText: string\n | Invalid of inputText: string\n | Blank of inputText: string\n\n static member Make(x: 'T) =\n Valid (x, x.ToString())\n\n member this.Input =\n match this with\n | Valid (_, x)\n | Invalid x\n | Blank x -> x\n\n[]\nmodule BindVar =\n\n []\n let CheckValidity (e: Dom.Element) = X\n\n type Init = Dom.Element -> unit\n type Set<'a> = Dom.Element -> 'a -> unit\n type Get<'a> = Dom.Element -> 'a option\n type Apply<'a> = Var<'a> -> (Init * Set<'a option> * View<'a option>)\n\n let ApplyValue (get: Get<'a>) (set: Set<'a>) : Apply<'a> = fun (var: Var<'a>) ->\n let mutable expectedValue = None\n let init (el: Dom.Element) =\n let onChange () =\n var.UpdateMaybe(fun v ->\n expectedValue <- get el\n match expectedValue with\n | Some x as o when x <> v -> o\n | _ -> None)\n el.AddEventListener(\"change\", onChange)\n el.AddEventListener(\"input\", onChange)\n el.AddEventListener(\"keypress\", onChange)\n let map v =\n match expectedValue with\n | Some x when x = v -> None\n | _ -> Some v\n init, Option.iter << set, var.View.Map map\n\n let FileApplyValue (get: Get<'a>) (set: Set<'a>) : Apply<'a> = fun (var: Var<'a>) ->\n let mutable expectedValue = None\n let init (el: Dom.Element) =\n let onChange () =\n var.UpdateMaybe(fun v ->\n expectedValue <- get el\n match expectedValue with\n | Some x as o when x !==. v -> o\n | _ -> None)\n el.AddEventListener(\"change\", onChange)\n let map v =\n match expectedValue with\n | Some x when x = v -> None\n | _ -> Some v\n init, Option.iter << set, var.View.Map map\n\n let BoolCheckedApply : Apply = fun var ->\n let init (el: Dom.Element) =\n el.AddEventListener(\"change\", fun () ->\n if var.Value <> el?``checked`` then\n var.Value <- el?``checked``)\n let set (el: Dom.Element) (v: bool option) =\n match v with\n | None -> ()\n | Some v -> el?``checked`` <- v\n init, set, var.View.Map Some\n\n let StringSet : Set = fun el s ->\n el?value <- s\n let StringGet : Get = fun el ->\n Some el?value\n let StringApply : Apply =\n ApplyValue StringGet StringSet\n\n let DateTimeSetUnchecked : Set = fun el i ->\n el?value <- string i\n let DateTimeGetUnchecked : Get = fun el ->\n let s = el?value\n if String.isBlank s then Some System.DateTime.MinValue else\n match System.DateTime.TryParse(s) with\n | false, _ -> None\n | true, v -> Some v\n let DateTimeApplyUnchecked : Apply =\n ApplyValue DateTimeGetUnchecked DateTimeSetUnchecked\n\n let FileSetUnchecked : Set = fun el i ->\n () // This should do nothing, as we should not override the values from the input\n let FileGetUnchecked : Get = fun el ->\n let files : FileList = el?files\n [| for i in 0..files.Length-1 do yield files.Item(i) |] |> Some\n let FileApplyUnchecked : Apply =\n FileApplyValue FileGetUnchecked FileSetUnchecked\n\n let IntSetUnchecked : Set = fun el i ->\n el?value <- string i\n let IntGetUnchecked : Get = fun el ->\n let s = el?value\n if String.isBlank s then Some 0 else\n let pd : int = JS.Plus s\n if pd !==. (pd >>. 0) then None else Some pd\n let IntApplyUnchecked : Apply =\n ApplyValue IntGetUnchecked IntSetUnchecked\n\n let IntSetChecked : Set> = fun el i ->\n let i = i.Input\n if el?value <> i then el?value <- i\n let IntGetChecked : Get> = fun el ->\n let s = el?value\n if String.isBlank s then\n if CheckValidity el then Blank s else Invalid s\n else\n match System.Int32.TryParse(s) with\n | true, i -> Valid (i, s)\n | false, _ -> Invalid s\n |> Some\n let IntApplyChecked : Apply> =\n ApplyValue IntGetChecked IntSetChecked\n\n let FloatSetUnchecked : Set = fun el i ->\n el?value <- string i\n let FloatGetUnchecked : Get = fun el ->\n let s = el?value\n if String.isBlank s then Some 0. else\n let pd : float = JS.Plus s\n if JS.IsNaN pd then None else Some pd\n let FloatApplyUnchecked : Apply =\n ApplyValue FloatGetUnchecked FloatSetUnchecked\n\n let FloatSetChecked : Set> = fun el i ->\n let i = i.Input\n if el?value <> i then el?value <- i\n let FloatGetChecked : Get> = fun el ->\n let s = el?value\n if String.isBlank s then\n if CheckValidity el then Blank s else Invalid s\n else\n let i = JS.Plus s\n if JS.IsNaN i then Invalid s else Valid (i, s)\n |> Some\n let FloatApplyChecked : Apply> =\n ApplyValue FloatGetChecked FloatSetChecked\n\n let DecimalSetUnchecked (el: Dom.Element) (i: decimal) =\n el?value <- string i\n let DecimalGetUnchecked (el: Dom.Element) =\n let s = el?value\n if String.isBlank s then Some 0.0m else\n match System.Decimal.TryParse(s) with\n | true, v -> Some v\n | false, _ -> None\n let DecimalApplyUnchecked v =\n ApplyValue DecimalGetUnchecked DecimalSetUnchecked v\n\n let DecimalSetChecked (el: Dom.Element) (i: CheckedInput) =\n let i = i.Input\n if el?value <> i then el?value <- i\n let DecimalGetChecked (el: Dom.Element) =\n let s = el?value\n if String.isBlank s then\n if CheckValidity el then Blank s else Invalid s\n else\n match System.Decimal.TryParse(s) with\n | true, v -> Valid (v, s)\n | false, _ -> Invalid s\n |> Some\n let DecimalApplyChecked v =\n ApplyValue DecimalGetChecked DecimalSetChecked v\n\n[]\nmodule Attr =\n\n []\n let Static f = As (Attrs.Static f)\n\n [)>]\n let Style name value =\n As (Attrs.Static (fun el -> DU.SetStyle el name value))\n\n let Animated name tr view attr =\n As (Attrs.Animated tr view (fun el v -> DU.SetAttr el name (attr v)))\n\n let AnimatedStyle name tr view attr =\n As (Attrs.Animated tr view (fun el v -> DU.SetStyle el name (attr v)))\n\n let Dynamic name view =\n As (Attrs.Dynamic view (fun el v -> DU.SetAttr el name v))\n\n let DynamicCustom set view =\n As (Attrs.Dynamic view set)\n\n let DynamicStyle name view =\n As (Attrs.Dynamic view (fun el v -> DU.SetStyle el name v))\n\n let Handler name (callback: Dom.Element -> #Dom.Event -> unit) =\n As (Attrs.Static (fun el -> el.AddEventListener(name, As unit> (callback el), false)))\n\n let HandlerView name (view: View<'T>) (callback: Dom.Element -> #Dom.Event -> 'T -> unit) =\n let init (el: Dom.Element) =\n let callback = callback el\n el.AddEventListener(name, (fun (ev: Dom.Event) -> View.Get (callback (As ev)) view), false)\n As (Attrs.Static init)\n\n let OnAfterRender (callback: Dom.Element -> unit) =\n As (A4 callback)\n\n let OnAfterRenderView (v: View<'T>) (callback: Dom.Element -> 'T -> unit) =\n let id = Fresh.Id()\n Attr.Append\n (OnAfterRender (fun el -> callback el el?(id)))\n (DynamicCustom (fun el x -> el?(id) <- x) v)\n\n let DynamicClassPred name view =\n As (Attrs.Dynamic view (fun el v ->\n if v then DU.AddClass el name else DU.RemoveClass el name))\n\n [)>]\n let ClassPred name isSet =\n As (Attrs.Static (fun el ->\n if isSet then DU.AddClass el name else DU.RemoveClass el name))\n\n let Class name = ClassPred name true\n\n let DynamicClass name view ok =\n DynamicClassPred name (View.Map ok view)\n\n let DynamicPred name predView valView =\n let viewFn el (p, v) =\n if p then\n DU.SetAttr el name v\n else\n DU.RemoveAttr el name\n let tupleView = View.Map2 (fun pred value -> (pred, value)) predView valView\n As (Attrs.Dynamic tupleView viewFn)\n\n let DynamicBool (name: string) (boolview: View) =\n let viewBool el b =\n if b then\n DU.SetAttr el name \"\"\n else\n DU.RemoveAttr el name\n As (Attrs.Dynamic boolview viewBool)\n\n\n [)>]\n let Prop name value =\n As (Attrs.Static (fun el -> el?(name) <- value))\n\n let DynamicProp name view =\n As (Attrs.Dynamic view (fun el v ->\n el?(name) <- v))\n\n let private ValueWith (bind: BindVar.Apply<'a>) (var: Var<'a>) =\n let init, set, view = bind var\n Attr.Append (Static init) (DynamicCustom set view)\n\n let CustomVar (var: Var<'a>) (set: Dom.Element -> 'a -> unit) (get: Dom.Element -> 'a option) =\n ValueWith (BindVar.ApplyValue get set) var\n\n let CustomValue (var: Var<'a>) (toString : 'a -> string) (fromString : string -> 'a option) =\n CustomVar var (fun e v -> e?value <- toString v) (fun e -> fromString e?value)\n\n let ContentEditableText (var: Var) =\n CustomVar var (fun e v -> e.TextContent <- v) (fun e -> Some e.TextContent)\n |> Attr.Append (Attr.Create \"contenteditable\" \"true\")\n\n let ContentEditableHtml (var: Var) =\n CustomVar var (fun e v -> e?innerHTML <- v) (fun e -> Some e?innerHTML)\n |> Attr.Append (Attr.Create \"contenteditable\" \"true\")\n\n let Value (var: Var) =\n ValueWith BindVar.StringApply var\n\n let DateTimeValue (var: Var) =\n ValueWith BindVar.DateTimeApplyUnchecked var\n\n let FileValue (var: Var) =\n ValueWith BindVar.FileApplyUnchecked var\n\n let IntValueUnchecked (var: Var) =\n ValueWith BindVar.IntApplyUnchecked var\n\n let IntValue (var: Var>) =\n ValueWith BindVar.IntApplyChecked var\n\n let FloatValueUnchecked (var: Var) =\n ValueWith BindVar.FloatApplyUnchecked var\n\n let FloatValue (var: Var>) =\n ValueWith BindVar.FloatApplyChecked var\n\n let DecimalValueUnchecked (var: Var) =\n ValueWith BindVar.DecimalApplyUnchecked var\n\n let DecimalValue (var: Var>) =\n ValueWith BindVar.DecimalApplyChecked var\n \n let Checked (var: Var) =\n ValueWith BindVar.BoolCheckedApply var\n\n let ValidateForm () =\n OnAfterRender Resources.H5F.Setup\n\n[]\ndo()\n", "// $begin{copyright}\n//\n// This file is part of WebSharper\n//\n// Copyright (c) 2008-2018 IntelliFactory\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\"); you\n// may not use this file except in compliance with the License. You may\n// obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n// implied. See the License for the specific language governing\n// permissions and limitations under the License.\n//\n// $end{copyright}\n\nnamespace WebSharper.UI\n\n\n#nowarn \"44\" // HTML deprecated\n\nopen System\nopen Microsoft.FSharp.Quotations\nopen System.Linq\nopen System.Linq.Expressions\nopen WebSharper\nopen WebSharper.Web\nopen WebSharper.Sitelets\nopen WebSharper.JavaScript\nopen WebSharper.Core.Resources\n\ntype SpecialHole = WebSharper.UI.Templating.AST.SpecialHole\n\nmodule SpecialHole =\n\n let RenderResources (holes: SpecialHole) (ctx: Web.Context) (reqs: seq) =\n match holes &&& SpecialHole.NonScripts with\n | SpecialHole.NonScripts ->\n ctx.GetSeparateResourcesAndScripts reqs\n | SpecialHole.Meta ->\n let r = ctx.GetSeparateResourcesAndScripts reqs\n { r with Meta = r.Meta + r.Styles; Styles = \"\" }\n | SpecialHole.Styles ->\n let r = ctx.GetSeparateResourcesAndScripts reqs\n { r with Styles = r.Meta + r.Styles; Meta = \"\" }\n | SpecialHole.None ->\n { Scripts = ctx.GetResourcesAndScripts reqs; Styles = \"\"; Meta = \"\" }\n | _ ->\n failwith \"Cannot happen\"\n\n let FromName name = WebSharper.UI.Templating.AST.SpecialHole.FromName name\n\n[]\ntype Doc() =\n\n interface IControlBody with\n member this.ReplaceInDom n = X\n\n interface INode with\n member this.Write(ctx, w) = this.Write(ctx, w, false)\n member this.IsAttribute = false\n\n interface IRequiresResources with\n member this.Encode(meta, json) = this.Encode(meta, json)\n member this.Requires(meta) = this.Requires(meta)\n\n abstract Write : Web.Context * HtmlTextWriter * res: option -> unit\n abstract Write : Web.Context * HtmlTextWriter * renderResources: bool -> unit\n abstract SpecialHoles : SpecialHole\n abstract Encode : Core.Metadata.Info * Core.Json.Provider -> list\n abstract Requires : Core.Metadata.Info -> seq\n\n default this.Write(ctx: Web.Context, w: HtmlTextWriter, renderResources: bool) =\n let resources =\n if renderResources\n then SpecialHole.RenderResources this.SpecialHoles ctx [this] |> Some\n else None\n this.Write(ctx, w, resources)\n\nand ConcreteDoc(dd: DynDoc) =\n inherit Doc()\n\n override this.Write(ctx, w, res: option) =\n match dd with\n | AppendDoc docs ->\n docs |> List.iter (fun d -> d.Write(ctx, w, res))\n | ElemDoc elt ->\n elt.Write(ctx, w, res)\n | EmptyDoc -> ()\n | TextDoc t -> w.WriteEncodedText(t)\n | VerbatimDoc t -> w.Write(t)\n | INodeDoc d -> d.Write(ctx, w)\n\n override this.SpecialHoles =\n match dd with\n | AppendDoc docs ->\n (SpecialHole.None, docs) ||> List.fold (fun h d -> h ||| d.SpecialHoles)\n | ElemDoc elt ->\n (elt :> Doc).SpecialHoles\n | _ -> SpecialHole.None\n\n override this.Encode(meta, json) =\n match dd with\n | AppendDoc docs -> docs |> List.collect (fun d -> d.Encode(meta, json))\n | INodeDoc c -> c.Encode(meta, json)\n | ElemDoc elt -> (elt :> IRequiresResources).Encode(meta, json)\n | _ -> []\n\n override this.Requires(meta) =\n match dd with\n | AppendDoc docs -> docs |> Seq.collect (fun d -> d.Requires(meta))\n | INodeDoc c -> (c :> IRequiresResources).Requires(meta)\n | ElemDoc elt -> (elt :> IRequiresResources).Requires(meta)\n | _ -> Seq.empty\n\nand DynDoc =\n | AppendDoc of list\n | ElemDoc of Elt\n | EmptyDoc\n | TextDoc of string\n | VerbatimDoc of string\n | INodeDoc of INode\n\nand HoleName = Replace | Hole\n\nand Elt\n (\n attrs: list,\n requireResources: seq, specialHoles,\n write: list -> Web.Context -> HtmlTextWriter -> option -> unit,\n write': option -> Web.Context -> HtmlTextWriter -> bool -> unit>\n ) =\n inherit Doc()\n\n let mutable attrs = attrs\n\n override this.SpecialHoles = specialHoles\n\n override this.Encode(m, j) =\n [\n for r in Seq.append requireResources (Seq.cast attrs) do\n yield! r.Encode(m, j)\n ]\n\n override this.Requires(meta) =\n Seq.append requireResources (Seq.cast attrs)\n |> Seq.collect (fun r -> r.Requires(meta))\n\n override this.Write(ctx, h, res) = write attrs ctx h res\n\n override this.Write(ctx, h, res) =\n match write' with\n | Some f -> f attrs ctx h res\n | None -> base.Write(ctx, h, res)\n\n new (tag: string, attrs: list, children: list) =\n let write attrs (ctx: Web.Context) (w: HtmlTextWriter) (res: option) =\n let hole =\n res |> Option.bind (fun res ->\n let rec findHole a =\n if obj.ReferenceEquals(a, null) then None else\n match a with\n | Attr.SingleAttr ((\"ws-replace\" | \"data-replace\"), value)\n when (value = \"scripts\" || value = \"styles\" || value = \"meta\") ->\n Some (HoleName.Replace, value, res)\n | Attr.SingleAttr ((\"ws-hole\" | \"data-hole\"), value)\n when (value = \"scripts\" || value = \"styles\" || value = \"meta\") ->\n Some (HoleName.Hole, value, res)\n | Attr.SingleAttr _ | Attr.DepAttr _ -> None\n | Attr.AppendAttr attrs -> List.tryPick findHole attrs\n List.tryPick findHole attrs\n )\n match hole with\n | Some (HoleName.Replace, name, res) -> w.Write(res[name])\n | Some (HoleName.Hole, name, res) ->\n w.WriteBeginTag(tag)\n attrs |> List.iter (fun a -> a.Write(ctx.Metadata, ctx.Json, w, true))\n w.Write(HtmlTextWriter.TagRightChar)\n w.Write(res[name])\n w.WriteEndTag(tag)\n | None ->\n w.WriteBeginTag(tag)\n attrs |> List.iter (fun a ->\n if not (obj.ReferenceEquals(a, null))\n then a.Write(ctx.Metadata, ctx.Json, w, false))\n if List.isEmpty children && HtmlTextWriter.IsSelfClosingTag tag then\n w.Write(HtmlTextWriter.SelfClosingTagEnd)\n else\n w.Write(HtmlTextWriter.TagRightChar)\n children |> List.iter (fun e -> e.Write(ctx, w, res))\n w.WriteEndTag(tag)\n\n let specialHoles =\n let rec testAttr a =\n if obj.ReferenceEquals(a, null) then SpecialHole.None else\n match a with\n | Attr.AppendAttr attrs ->\n (SpecialHole.None, attrs) ||> List.fold (fun h a -> h ||| testAttr a)\n | Attr.SingleAttr ((\"ws-replace\" | \"ws-hole\" | \"data-replace\" | \"data-hole\"), v) ->\n SpecialHole.FromName v\n | Attr.SingleAttr _\n | Attr.DepAttr _ -> SpecialHole.None\n let a = (SpecialHole.None, attrs) ||> List.fold (fun h a -> h ||| testAttr a)\n (a, children) ||> List.fold (fun h d -> h ||| d.SpecialHoles)\n\n\n Elt(attrs, Seq.cast children, specialHoles, write, None)\n\n member this.OnImpl(ev, cb) =\n attrs <- Attr.HandlerImpl(ev, cb) :: attrs\n this\n\n member this.On(ev, [] cb) =\n this.OnImpl(ev, cb)\n\n member this.OnLinq(ev, cb) =\n attrs <- Attr.HandlerLinq ev cb :: attrs\n this\n\n member this.OnAfterRender([] cb: Expr unit>) =\n attrs <- Attr.OnAfterRenderImpl(cb) :: attrs\n this\n\n member internal this.WithAttrs(a) =\n attrs <- a @ attrs\n this\n\n // {{ event\n member this.OnAbort([] cb: Expr Dom.UIEvent -> unit>) = this.OnImpl(\"abort\", cb)\n member this.OnAfterPrint([] cb: Expr Dom.Event -> unit>) = this.OnImpl(\"afterprint\", cb)\n member this.OnAnimationEnd([] cb: Expr Dom.Event -> unit>) = this.OnImpl(\"animationend\", cb)\n member this.OnAnimationIteration([] cb: Expr Dom.Event -> unit>) = this.OnImpl(\"animationiteration\", cb)\n member this.OnAnimationStart([] cb: Expr Dom.Event -> unit>) = this.OnImpl(\"animationstart\", cb)\n member this.OnAudioProcess([] cb: Expr Dom.Event -> unit>) = this.OnImpl(\"audioprocess\", cb)\n member this.OnBeforePrint([] cb: Expr Dom.Event -> unit>) = this.OnImpl(\"beforeprint\", cb)\n member this.OnBeforeUnload([] cb: Expr Dom.Event -> unit>) = this.OnImpl(\"beforeunload\", cb)\n member this.OnBeginEvent([] cb: Expr Dom.Event -> unit>) = this.OnImpl(\"beginEvent\", cb)\n member this.OnBlocked([] cb: Expr Dom.Event -> unit>) = this.OnImpl(\"blocked\", cb)\n member this.OnBlur([] cb: Expr Dom.FocusEvent -> unit>) = this.OnImpl(\"blur\", cb)\n member this.OnCached([] cb: Expr Dom.Event -> unit>) = this.OnImpl(\"cached\", cb)\n member this.OnCanPlay([] cb: Expr Dom.Event -> unit>) = this.OnImpl(\"canplay\", cb)\n member this.OnCanPlayThrough([] cb: Expr Dom.Event -> unit>) = this.OnImpl(\"canplaythrough\", cb)\n member this.OnChange([] cb: Expr Dom.Event -> unit>) = this.OnImpl(\"change\", cb)\n member this.OnChargingChange([] cb: Expr Dom.Event -> unit>) = this.OnImpl(\"chargingchange\", cb)\n member this.OnChargingTimeChange([] cb: Expr Dom.Event -> unit>) = this.OnImpl(\"chargingtimechange\", cb)\n member this.OnChecking([] cb: Expr Dom.Event -> unit>) = this.OnImpl(\"checking\", cb)\n member this.OnClick([] cb: Expr Dom.MouseEvent -> unit>) = this.OnImpl(\"click\", cb)\n member this.OnClose([] cb: Expr Dom.Event -> unit>) = this.OnImpl(\"close\", cb)\n member this.OnComplete([] cb: Expr Dom.Event -> unit>) = this.OnImpl(\"complete\", cb)\n member this.OnCompositionEnd([] cb: Expr Dom.CompositionEvent -> unit>) = this.OnImpl(\"compositionend\", cb)\n member this.OnCompositionStart([] cb: Expr Dom.CompositionEvent -> unit>) = this.OnImpl(\"compositionstart\", cb)\n member this.OnCompositionUpdate([] cb: Expr Dom.CompositionEvent -> unit>) = this.OnImpl(\"compositionupdate\", cb)\n member this.OnContextMenu([] cb: Expr Dom.MouseEvent -> unit>) = this.OnImpl(\"contextmenu\", cb)\n member this.OnCopy([] cb: Expr Dom.Event -> unit>) = this.OnImpl(\"copy\", cb)\n member this.OnCut([] cb: Expr Dom.Event -> unit>) = this.OnImpl(\"cut\", cb)\n member this.OnDblClick([] cb: Expr Dom.MouseEvent -> unit>) = this.OnImpl(\"dblclick\", cb)\n member this.OnDeviceLight([] cb: Expr Dom.Event -> unit>) = this.OnImpl(\"devicelight\", cb)\n member this.OnDeviceMotion([] cb: Expr Dom.Event -> unit>) = this.OnImpl(\"devicemotion\", cb)\n member this.OnDeviceOrientation([] cb: Expr Dom.Event -> unit>) = this.OnImpl(\"deviceorientation\", cb)\n member this.OnDeviceProximity([] cb: Expr Dom.Event -> unit>) = this.OnImpl(\"deviceproximity\", cb)\n member this.OnDischargingTimeChange([] cb: Expr Dom.Event -> unit>) = this.OnImpl(\"dischargingtimechange\", cb)\n member this.OnDOMActivate([] cb: Expr Dom.UIEvent -> unit>) = this.OnImpl(\"DOMActivate\", cb)\n member this.OnDOMAttributeNameChanged([] cb: Expr Dom.Event -> unit>) = this.OnImpl(\"DOMAttributeNameChanged\", cb)\n member this.OnDOMAttrModified([] cb: Expr Dom.MutationEvent -> unit>) = this.OnImpl(\"DOMAttrModified\", cb)\n member this.OnDOMCharacterDataModified([] cb: Expr Dom.MutationEvent -> unit>) = this.OnImpl(\"DOMCharacterDataModified\", cb)\n member this.OnDOMContentLoaded([] cb: Expr Dom.Event -> unit>) = this.OnImpl(\"DOMContentLoaded\", cb)\n member this.OnDOMElementNameChanged([] cb: Expr Dom.Event -> unit>) = this.OnImpl(\"DOMElementNameChanged\", cb)\n member this.OnDOMNodeInserted([] cb: Expr Dom.MutationEvent -> unit>) = this.OnImpl(\"DOMNodeInserted\", cb)\n member this.OnDOMNodeInsertedIntoDocument([] cb: Expr Dom.MutationEvent -> unit>) = this.OnImpl(\"DOMNodeInsertedIntoDocument\", cb)\n member this.OnDOMNodeRemoved([] cb: Expr Dom.MutationEvent -> unit>) = this.OnImpl(\"DOMNodeRemoved\", cb)\n member this.OnDOMNodeRemovedFromDocument([] cb: Expr Dom.MutationEvent -> unit>) = this.OnImpl(\"DOMNodeRemovedFromDocument\", cb)\n member this.OnDOMSubtreeModified([] cb: Expr Dom.MutationEvent -> unit>) = this.OnImpl(\"DOMSubtreeModified\", cb)\n member this.OnDownloading([] cb: Expr Dom.Event -> unit>) = this.OnImpl(\"downloading\", cb)\n member this.OnDrag([] cb: Expr Dom.Event -> unit>) = this.OnImpl(\"drag\", cb)\n member this.OnDragEnd([] cb: Expr Dom.Event -> unit>) = this.OnImpl(\"dragend\", cb)\n member this.OnDragEnter([] cb: Expr Dom.Event -> unit>) = this.OnImpl(\"dragenter\", cb)\n member this.OnDragLeave([] cb: Expr Dom.Event -> unit>) = this.OnImpl(\"dragleave\", cb)\n member this.OnDragOver([] cb: Expr Dom.Event -> unit>) = this.OnImpl(\"dragover\", cb)\n member this.OnDragStart([] cb: Expr Dom.Event -> unit>) = this.OnImpl(\"dragstart\", cb)\n member this.OnDrop([] cb: Expr Dom.Event -> unit>) = this.OnImpl(\"drop\", cb)\n member this.OnDurationChange([] cb: Expr Dom.Event -> unit>) = this.OnImpl(\"durationchange\", cb)\n member this.OnEmptied([] cb: Expr Dom.Event -> unit>) = this.OnImpl(\"emptied\", cb)\n member this.OnEnded([] cb: Expr Dom.Event -> unit>) = this.OnImpl(\"ended\", cb)\n member this.OnEndEvent([] cb: Expr Dom.Event -> unit>) = this.OnImpl(\"endEvent\", cb)\n member this.OnError([] cb: Expr Dom.Event -> unit>) = this.OnImpl(\"error\", cb)\n member this.OnFocus([] cb: Expr Dom.FocusEvent -> unit>) = this.OnImpl(\"focus\", cb)\n member this.OnFullScreenChange([] cb: Expr Dom.Event -> unit>) = this.OnImpl(\"fullscreenchange\", cb)\n member this.OnFullScreenError([] cb: Expr Dom.Event -> unit>) = this.OnImpl(\"fullscreenerror\", cb)\n member this.OnGamepadConnected([] cb: Expr Dom.Event -> unit>) = this.OnImpl(\"gamepadconnected\", cb)\n member this.OnGamepadDisconnected([] cb: Expr Dom.Event -> unit>) = this.OnImpl(\"gamepaddisconnected\", cb)\n member this.OnHashChange([] cb: Expr Dom.Event -> unit>) = this.OnImpl(\"hashchange\", cb)\n member this.OnInput([] cb: Expr Dom.Event -> unit>) = this.OnImpl(\"input\", cb)\n member this.OnInvalid([] cb: Expr Dom.Event -> unit>) = this.OnImpl(\"invalid\", cb)\n member this.OnKeyDown([] cb: Expr Dom.KeyboardEvent -> unit>) = this.OnImpl(\"keydown\", cb)\n member this.OnKeyPress([] cb: Expr Dom.KeyboardEvent -> unit>) = this.OnImpl(\"keypress\", cb)\n member this.OnKeyUp([] cb: Expr Dom.KeyboardEvent -> unit>) = this.OnImpl(\"keyup\", cb)\n member this.OnLanguageChange([] cb: Expr Dom.Event -> unit>) = this.OnImpl(\"languagechange\", cb)\n member this.OnLevelChange([] cb: Expr Dom.Event -> unit>) = this.OnImpl(\"levelchange\", cb)\n member this.OnLoad([] cb: Expr Dom.UIEvent -> unit>) = this.OnImpl(\"load\", cb)\n member this.OnLoadedData([] cb: Expr Dom.Event -> unit>) = this.OnImpl(\"loadeddata\", cb)\n member this.OnLoadedMetadata([] cb: Expr Dom.Event -> unit>) = this.OnImpl(\"loadedmetadata\", cb)\n member this.OnLoadEnd([] cb: Expr Dom.Event -> unit>) = this.OnImpl(\"loadend\", cb)\n member this.OnLoadStart([] cb: Expr Dom.Event -> unit>) = this.OnImpl(\"loadstart\", cb)\n member this.OnMessage([] cb: Expr Dom.Event -> unit>) = this.OnImpl(\"message\", cb)\n member this.OnMouseDown([] cb: Expr Dom.MouseEvent -> unit>) = this.OnImpl(\"mousedown\", cb)\n member this.OnMouseEnter([] cb: Expr Dom.MouseEvent -> unit>) = this.OnImpl(\"mouseenter\", cb)\n member this.OnMouseLeave([] cb: Expr Dom.MouseEvent -> unit>) = this.OnImpl(\"mouseleave\", cb)\n member this.OnMouseMove([] cb: Expr Dom.MouseEvent -> unit>) = this.OnImpl(\"mousemove\", cb)\n member this.OnMouseOut([] cb: Expr Dom.MouseEvent -> unit>) = this.OnImpl(\"mouseout\", cb)\n member this.OnMouseOver([] cb: Expr Dom.MouseEvent -> unit>) = this.OnImpl(\"mouseover\", cb)\n member this.OnMouseUp([] cb: Expr Dom.MouseEvent -> unit>) = this.OnImpl(\"mouseup\", cb)\n member this.OnNoUpdate([] cb: Expr Dom.Event -> unit>) = this.OnImpl(\"noupdate\", cb)\n member this.OnObsolete([] cb: Expr Dom.Event -> unit>) = this.OnImpl(\"obsolete\", cb)\n member this.OnOffline([] cb: Expr Dom.Event -> unit>) = this.OnImpl(\"offline\", cb)\n member this.OnOnline([] cb: Expr Dom.Event -> unit>) = this.OnImpl(\"online\", cb)\n member this.OnOpen([] cb: Expr Dom.Event -> unit>) = this.OnImpl(\"open\", cb)\n member this.OnOrientationChange([] cb: Expr Dom.Event -> unit>) = this.OnImpl(\"orientationchange\", cb)\n member this.OnPageHide([] cb: Expr Dom.Event -> unit>) = this.OnImpl(\"pagehide\", cb)\n member this.OnPageShow([] cb: Expr Dom.Event -> unit>) = this.OnImpl(\"pageshow\", cb)\n member this.OnPaste([] cb: Expr Dom.Event -> unit>) = this.OnImpl(\"paste\", cb)\n member this.OnPause([] cb: Expr Dom.Event -> unit>) = this.OnImpl(\"pause\", cb)\n member this.OnPlay([] cb: Expr Dom.Event -> unit>) = this.OnImpl(\"play\", cb)\n member this.OnPlaying([] cb: Expr Dom.Event -> unit>) = this.OnImpl(\"playing\", cb)\n member this.OnPointerLockChange([] cb: Expr Dom.Event -> unit>) = this.OnImpl(\"pointerlockchange\", cb)\n member this.OnPointerLockError([] cb: Expr Dom.Event -> unit>) = this.OnImpl(\"pointerlockerror\", cb)\n member this.OnPopState([] cb: Expr Dom.Event -> unit>) = this.OnImpl(\"popstate\", cb)\n member this.OnProgress([] cb: Expr Dom.Event -> unit>) = this.OnImpl(\"progress\", cb)\n member this.OnRateChange([] cb: Expr Dom.Event -> unit>) = this.OnImpl(\"ratechange\", cb)\n member this.OnReadyStateChange([] cb: Expr Dom.Event -> unit>) = this.OnImpl(\"readystatechange\", cb)\n member this.OnRepeatEvent([] cb: Expr Dom.Event -> unit>) = this.OnImpl(\"repeatEvent\", cb)\n member this.OnReset([] cb: Expr Dom.Event -> unit>) = this.OnImpl(\"reset\", cb)\n member this.OnResize([] cb: Expr Dom.UIEvent -> unit>) = this.OnImpl(\"resize\", cb)\n member this.OnScroll([] cb: Expr Dom.UIEvent -> unit>) = this.OnImpl(\"scroll\", cb)\n member this.OnSeeked([] cb: Expr Dom.Event -> unit>) = this.OnImpl(\"seeked\", cb)\n member this.OnSeeking([] cb: Expr Dom.Event -> unit>) = this.OnImpl(\"seeking\", cb)\n member this.OnSelect([] cb: Expr Dom.UIEvent -> unit>) = this.OnImpl(\"select\", cb)\n member this.OnShow([] cb: Expr Dom.MouseEvent -> unit>) = this.OnImpl(\"show\", cb)\n member this.OnStalled([] cb: Expr Dom.Event -> unit>) = this.OnImpl(\"stalled\", cb)\n member this.OnStorage([] cb: Expr Dom.Event -> unit>) = this.OnImpl(\"storage\", cb)\n member this.OnSubmit([] cb: Expr Dom.Event -> unit>) = this.OnImpl(\"submit\", cb)\n member this.OnSuccess([] cb: Expr Dom.Event -> unit>) = this.OnImpl(\"success\", cb)\n member this.OnSuspend([] cb: Expr Dom.Event -> unit>) = this.OnImpl(\"suspend\", cb)\n member this.OnSVGAbort([] cb: Expr Dom.Event -> unit>) = this.OnImpl(\"SVGAbort\", cb)\n member this.OnSVGError([] cb: Expr Dom.Event -> unit>) = this.OnImpl(\"SVGError\", cb)\n member this.OnSVGLoad([] cb: Expr Dom.Event -> unit>) = this.OnImpl(\"SVGLoad\", cb)\n member this.OnSVGResize([] cb: Expr Dom.Event -> unit>) = this.OnImpl(\"SVGResize\", cb)\n member this.OnSVGScroll([] cb: Expr Dom.Event -> unit>) = this.OnImpl(\"SVGScroll\", cb)\n member this.OnSVGUnload([] cb: Expr Dom.Event -> unit>) = this.OnImpl(\"SVGUnload\", cb)\n member this.OnSVGZoom([] cb: Expr Dom.Event -> unit>) = this.OnImpl(\"SVGZoom\", cb)\n member this.OnTimeOut([] cb: Expr Dom.Event -> unit>) = this.OnImpl(\"timeout\", cb)\n member this.OnTimeUpdate([] cb: Expr Dom.Event -> unit>) = this.OnImpl(\"timeupdate\", cb)\n member this.OnTouchCancel([] cb: Expr Dom.Event -> unit>) = this.OnImpl(\"touchcancel\", cb)\n member this.OnTouchEnd([] cb: Expr Dom.Event -> unit>) = this.OnImpl(\"touchend\", cb)\n member this.OnTouchEnter([] cb: Expr Dom.Event -> unit>) = this.OnImpl(\"touchenter\", cb)\n member this.OnTouchLeave([] cb: Expr Dom.Event -> unit>) = this.OnImpl(\"touchleave\", cb)\n member this.OnTouchMove([] cb: Expr Dom.Event -> unit>) = this.OnImpl(\"touchmove\", cb)\n member this.OnTouchStart([] cb: Expr Dom.Event -> unit>) = this.OnImpl(\"touchstart\", cb)\n member this.OnTransitionEnd([] cb: Expr Dom.Event -> unit>) = this.OnImpl(\"transitionend\", cb)\n member this.OnUnload([] cb: Expr Dom.UIEvent -> unit>) = this.OnImpl(\"unload\", cb)\n member this.OnUpdateReady([] cb: Expr Dom.Event -> unit>) = this.OnImpl(\"updateready\", cb)\n member this.OnUpgradeNeeded([] cb: Expr Dom.Event -> unit>) = this.OnImpl(\"upgradeneeded\", cb)\n member this.OnUserProximity([] cb: Expr Dom.Event -> unit>) = this.OnImpl(\"userproximity\", cb)\n member this.OnVersionChange([] cb: Expr Dom.Event -> unit>) = this.OnImpl(\"versionchange\", cb)\n member this.OnVisibilityChange([] cb: Expr Dom.Event -> unit>) = this.OnImpl(\"visibilitychange\", cb)\n member this.OnVolumeChange([] cb: Expr Dom.Event -> unit>) = this.OnImpl(\"volumechange\", cb)\n member this.OnWaiting([] cb: Expr Dom.Event -> unit>) = this.OnImpl(\"waiting\", cb)\n member this.OnWheel([] cb: Expr Dom.WheelEvent -> unit>) = this.OnImpl(\"wheel\", cb)\n // }}\n\nand [] TemplateHole () = \n abstract member Name: string\n abstract member WithName: string -> TemplateHole\n abstract member ValueObj: obj\n\n abstract member ApplyVarHole : Dom.Element -> unit\n default this.ApplyVarHole (el: Dom.Element) =\n JavaScript.Console.Warn(\"Not a var hole: \", this.Name)\n\n abstract member ForTextView : unit -> View option\n default this.ForTextView () =\n Console.Warn(\"Content hole filled with attribute data\", this.Name);\n None\n\n abstract member AddAttribute : (Dom.Element -> Attr -> unit) * Dom.Element -> unit\n default this.AddAttribute(_, _) =\n Console.Warn(\"Var hole filled with non-Var data\", this.Name)\n\n abstract member AsChoiceView : Choice>\n default this.AsChoiceView =\n Console.Warn(\"Attribute value hole filled with non-text data\", this.Name)\n Choice1Of2 \"\"\n\n\n[]\nmodule TemplateHole =\n open WebSharper.UI.Client\n\n let applyTypedVarHole (bind: BindVar.Apply<'a>) (v: Var<'a>) el =\n let init, set, view = bind v\n init el\n View.Sink (set el) view\n\n type Elt(name: string, fillWith: Doc) =\n inherit TemplateHole()\n \n override this.Name with get() = name\n member this.Value = fillWith\n override this.ValueObj = this.Value\n override this.WithName n = Elt(n, fillWith)\n \n type Text(name: string, fillWith: string) =\n inherit TemplateHole()\n \n override this.Name with get() = name\n member this.Value = fillWith\n override this.ValueObj = this.Value\n override this.WithName n = Text(n, fillWith)\n override this.AsChoiceView =\n Choice1Of2 fillWith\n \n type TextView(name: string, fillWith: View) =\n inherit TemplateHole()\n \n override this.Name with get() = name\n member this.Value = fillWith\n override this.ValueObj = this.Value\n override this.WithName n = TextView(n, fillWith)\n override this.AsChoiceView =\n Choice2Of2 fillWith\n override this.ForTextView() = fillWith |> Some\n \n type Attribute(name: string, fillWith: Attr) =\n inherit TemplateHole()\n \n override this.Name with get() = name\n member this.Value = fillWith\n override this.ValueObj = this.Value\n override this.WithName n = Attribute(n, fillWith)\n \n type Event(name: string, fillWith: (Dom.Element -> Dom.Event -> unit)) =\n inherit TemplateHole()\n \n override this.Name with get() = name\n member this.Value = fillWith\n override this.ValueObj = this.Value\n override this.WithName n = Event(n, fillWith)\n \n type EventQ(name: string, fillWith: Expr Dom.Event -> unit>) =\n inherit TemplateHole()\n \n override this.Name with get() = name\n member this.Value = fillWith\n override this.ValueObj = this.Value\n override this.WithName n = EventQ(n, fillWith)\n \n type EventE(name: string, key: string, fillWith: Expression>) =\n inherit TemplateHole()\n \n override this.Name with get() = name\n member this.Value = fillWith\n override this.ValueObj = this.Value\n override this.WithName n = EventE(n, key, fillWith)\n\n member this.Key () = key\n \n type AfterRender(name: string, fillWith: (Dom.Element -> unit)) =\n inherit TemplateHole()\n \n override this.Name with get() = name\n member this.Value = fillWith\n override this.ValueObj = this.Value\n override this.WithName n = AfterRender(n, fillWith)\n \n type AfterRenderQ(name: string, fillWith: Expr unit>) =\n inherit TemplateHole()\n \n override this.Name with get() = name\n member this.Value = fillWith\n override this.ValueObj = this.Value\n override this.WithName n = AfterRenderQ(n, fillWith)\n \n type AfterRenderE(name: string, key: string, fillWith: Expression>) =\n inherit TemplateHole()\n \n override this.Name with get() = name\n member this.Value = fillWith\n override this.ValueObj = this.Value\n override this.WithName n = AfterRenderE(n, key, fillWith)\n\n member this.Key () = key\n \n type VarStr(name: string, fillWith: Var) =\n inherit TemplateHole()\n \n override this.Name with get() = name\n member this.Value = fillWith\n override this.ValueObj = this.Value\n override this.WithName n = VarStr(n, fillWith)\n override this.ApplyVarHole (el: Dom.Element) =\n applyTypedVarHole BindVar.StringApply fillWith el\n override this.AddAttribute (addAttr, el) =\n addAttr el (Attr.Value fillWith)\n override this.AsChoiceView =\n Choice2Of2 (fillWith.View.Map string)\n override this.ForTextView() = fillWith.View |> Some\n \n type VarBool(name: string, fillWith: Var) =\n inherit TemplateHole()\n \n override this.Name with get() = name\n member this.Value = fillWith\n override this.ValueObj = this.Value\n override this.WithName n = VarBool(n, fillWith)\n override this.ApplyVarHole (el: Dom.Element) =\n applyTypedVarHole BindVar.BoolCheckedApply fillWith el\n override this.AddAttribute (addAttr, el) =\n addAttr el (Attr.Checked fillWith)\n override this.AsChoiceView =\n Choice2Of2 (fillWith.View.Map string)\n override this.ForTextView() = fillWith.View.Map string |> Some\n \n type VarDateTime(name: string, fillWith: Var) =\n inherit TemplateHole()\n \n override this.Name with get() = name\n member this.Value = fillWith\n override this.ValueObj = this.Value\n override this.WithName n = VarDateTime(n, fillWith)\n override this.ApplyVarHole (el: Dom.Element) =\n applyTypedVarHole BindVar.DateTimeApplyUnchecked fillWith el\n override this.AddAttribute (addAttr, el) =\n addAttr el (Attr.DateTimeValue fillWith)\n override this.AsChoiceView =\n Choice2Of2 (fillWith.View.Map string)\n override this.ForTextView() = fillWith.View.Map string |> Some\n \n type VarFile(name: string, fillWith: Var) =\n inherit TemplateHole()\n \n override this.Name with get() = name\n member this.Value = fillWith\n override this.ValueObj = this.Value\n override this.WithName n = VarFile(n, fillWith)\n override this.ApplyVarHole (el: Dom.Element) =\n applyTypedVarHole BindVar.FileApplyUnchecked fillWith el\n override this.AddAttribute (addAttr, el) =\n addAttr el (Attr.FileValue fillWith)\n override this.AsChoiceView =\n Choice2Of2 (fillWith.View.Map string)\n override this.ForTextView() = fillWith.View.Map string |> Some\n \n type VarDomElement(name: string, fillWith: Var) =\n inherit TemplateHole()\n \n override this.Name with get() = name\n member this.Value = fillWith\n override this.ValueObj = this.Value\n override this.WithName n = VarDomElement(n, fillWith)\n override this.ApplyVarHole (el: Dom.Element) = ()\n \n type VarInt(name: string, fillWith: Var>) =\n inherit TemplateHole()\n \n override this.Name with get() = name\n member this.Value = fillWith\n override this.ValueObj = this.Value\n override this.WithName n = VarInt(n, fillWith)\n override this.ApplyVarHole (el: Dom.Element) =\n applyTypedVarHole BindVar.IntApplyChecked fillWith el\n override this.AddAttribute (addAttr, el) =\n addAttr el (Attr.IntValue fillWith)\n override this.AsChoiceView =\n Choice2Of2 (fillWith.View.Map (fun i -> i.Input))\n override this.ForTextView() = fillWith.View.Map (fun i -> i.Input) |> Some\n \n type VarIntUnchecked(name: string, fillWith: Var) =\n inherit TemplateHole()\n \n override this.Name with get() = name\n member this.Value = fillWith\n override this.ValueObj = this.Value\n override this.WithName n = VarIntUnchecked(n, fillWith)\n override this.ApplyVarHole (el: Dom.Element) =\n applyTypedVarHole BindVar.IntApplyUnchecked fillWith el\n override this.AddAttribute (addAttr, el) =\n addAttr el (Attr.IntValueUnchecked fillWith)\n override this.AsChoiceView =\n Choice2Of2 (fillWith.View.Map string)\n override this.ForTextView() = fillWith.View.Map string |> Some\n \n type VarFloat(name: string, fillWith: Var>) =\n inherit TemplateHole()\n \n override this.Name with get() = name\n member this.Value = fillWith\n override this.ValueObj = this.Value\n override this.WithName n = VarFloat(n, fillWith)\n override this.ApplyVarHole (el: Dom.Element) =\n applyTypedVarHole BindVar.FloatApplyChecked fillWith el\n override this.AddAttribute (addAttr, el) =\n addAttr el (Attr.FloatValue fillWith)\n override this.AsChoiceView =\n Choice2Of2 (fillWith.View.Map (fun i -> i.Input))\n override this.ForTextView() = fillWith.View.Map (fun i -> i.Input) |> Some\n \n type VarFloatUnchecked(name: string, fillWith: Var) =\n inherit TemplateHole()\n \n override this.Name with get() = name\n member this.Value = fillWith\n override this.ValueObj = this.Value\n override this.WithName n = VarFloatUnchecked(n, fillWith)\n override this.ApplyVarHole (el: Dom.Element) =\n applyTypedVarHole BindVar.FloatApplyUnchecked fillWith el\n override this.AddAttribute (addAttr, el) =\n addAttr el (Attr.FloatValueUnchecked fillWith)\n override this.AsChoiceView =\n Choice2Of2 (fillWith.View.Map string)\n override this.ForTextView() = fillWith.View.Map string |> Some\n \n type VarDecimal(name: string, fillWith: Var>) =\n inherit TemplateHole()\n \n override this.Name with get() = name\n member this.Value = fillWith\n override this.ValueObj = this.Value\n override this.WithName n = VarDecimal(n, fillWith)\n override this.ApplyVarHole (el: Dom.Element) =\n applyTypedVarHole BindVar.DecimalApplyChecked fillWith el\n override this.AddAttribute (addAttr, el) =\n addAttr el (Attr.DecimalValue fillWith)\n override this.AsChoiceView =\n Choice2Of2 (fillWith.View.Map (fun i -> i.Input))\n override this.ForTextView() = fillWith.View.Map (fun i -> i.Input) |> Some\n \n type VarDecimalUnchecked(name: string, fillWith: Var) =\n inherit TemplateHole()\n \n override this.Name with get() = name\n member this.Value = fillWith\n override this.ValueObj = this.Value\n override this.WithName n = VarDecimalUnchecked(n, fillWith)\n override this.ApplyVarHole (el: Dom.Element) =\n applyTypedVarHole BindVar.DecimalApplyUnchecked fillWith el\n override this.AddAttribute (addAttr, el) =\n addAttr el (Attr.DecimalValueUnchecked fillWith)\n override this.AsChoiceView =\n Choice2Of2 (fillWith.View.Map string)\n override this.ForTextView() = fillWith.View.Map string |> Some\n \n type UninitVar(name: string, key: string) =\n inherit TemplateHole()\n \n override this.Name with get() = name\n member this.Value = key\n override this.ValueObj = key\n override this.WithName n = UninitVar(n, key)\n\ntype TemplateHole with\n []\n static member NewActionEvent<'T when 'T :> Dom.Event>(name: string, f: Action) =\n if IsClient then\n TemplateHole.Event(name, fun el ev -> f.Invoke(el, downcast ev)) :> TemplateHole\n else\n failwith <| sprintf \"%s overload is intended for client-side use only. Please use %sFromServer instead\" name name\n \n []\n static member NewEventExpr<'T when 'T :> Dom.Event>(name: string, k: string, f: Expression>) =\n let parameters =\n f.Parameters.Select(fun p -> \n if p.Type = typeof<'T> then\n Expression.Parameter(typeof, p.Name)\n else\n p\n )\n TemplateHole.EventE(name, k, Expression.Lambda>(f.Body, parameters)) :> TemplateHole\n \n []\n static member NewEventExprAction(name: string, f: Expression) =\n let elP = Expression.Parameter(typeof)\n let evP = Expression.Parameter(typeof)\n TemplateHole.EventE(name, \"\", Expression.Lambda>(f.Body, seq {elP; evP})) :> TemplateHole\n \n []\n static member NewAfterRenderExprAction(name: string, f: Expression) =\n let elP = Expression.Parameter(typeof)\n TemplateHole.AfterRenderE(name, \"\", Expression.Lambda>(f.Body, seq {elP})) :> TemplateHole\n \n \n [); Inline>]\n static member MakeText(name: string, text: string) =\n TemplateHole.Text(name, text) :> TemplateHole\n \n []\n static member MakeTextView(name: string, text: View) =\n TemplateHole.TextView(name, text) :> TemplateHole\n \n [); Inline>]\n static member MakeVarLens(name: string, v: string) =\n TemplateHole.VarStr(name, Var.Create v) :> TemplateHole\n \n []\n static member MakeVar(name: string, var: Var) =\n TemplateHole.VarStr(name, var) :> TemplateHole\n \n [); Inline>]\n static member MakeVarLens(name: string, v: bool) =\n TemplateHole.VarBool(name, Var.Create v) :> TemplateHole\n \n []\n static member MakeVar(name: string, var: Var) =\n TemplateHole.VarBool(name, var) :> TemplateHole\n \n [); Inline>]\n static member MakeVarLens(name: string, v: DateTime) =\n TemplateHole.VarDateTime(name, Var.Create v) :> TemplateHole\n \n []\n static member MakeVar(name: string, var: Var) =\n TemplateHole.VarDateTime(name, var) :> TemplateHole\n \n [); Inline>]\n static member MakeVarLens(name: string, v: File array) =\n TemplateHole.VarFile(name, Var.Create v) :> TemplateHole\n \n []\n static member MakeVar(name: string, var: Var) =\n TemplateHole.VarFile(name, var) :> TemplateHole\n \n [); Inline>]\n static member MakeVarLens(name: string, v: Client.CheckedInput) =\n TemplateHole.VarInt(name, Var.Create v) :> TemplateHole\n \n []\n static member MakeVar(name: string, var: Var>) =\n TemplateHole.VarInt(name, var) :> TemplateHole\n \n [); Inline>]\n static member MakeVarLens(name: string, v: int) =\n TemplateHole.VarIntUnchecked(name, Var.Create v) :> TemplateHole\n \n []\n static member MakeVar(name: string, var: Var) =\n TemplateHole.VarIntUnchecked(name, var) :> TemplateHole\n \n [); Inline>]\n static member MakeVarLens(name: string, v: Client.CheckedInput) =\n TemplateHole.VarFloat(name, Var.Create v) :> TemplateHole\n \n []\n static member MakeVar(name: string, var: Var>) =\n TemplateHole.VarFloat(name, var) :> TemplateHole\n \n [); Inline>]\n static member MakeVarLens(name: string, v: float) =\n TemplateHole.VarFloatUnchecked(name, Var.Create v) :> TemplateHole\n \n []\n static member MakeVar(name: string, var: Var) =\n TemplateHole.VarFloatUnchecked(name, var) :> TemplateHole\n \n [); Inline>]\n static member MakeVarLens(name: string, v: Client.CheckedInput) =\n TemplateHole.VarDecimal(name, Var.Create v) :> TemplateHole\n \n []\n static member MakeVar(name: string, var: Var>) =\n TemplateHole.VarDecimal(name, var) :> TemplateHole\n \n [); Inline>]\n static member MakeVarLens(name: string, v: decimal) =\n TemplateHole.VarDecimalUnchecked(name, Var.Create v) :> TemplateHole\n \n []\n static member MakeVar(name: string, var: Var) =\n TemplateHole.VarDecimalUnchecked(name, var) :> TemplateHole\n\n static member Value(th: TemplateHole) =\n th.ValueObj\n\ntype InlineControlWithPlaceHolder(docExpr: Expr, doc: Doc) =\n inherit InlineControl(%docExpr)\n\n []\n let doc = doc\n\n // this is needed because WebSharper.Web.Control.GetBodyNode looks at Body property on current type\n []\n override this.Body = base.Body\n\n interface INode with\n member this.Write (ctx, w) =\n w.Write(\"\"\"
\"\"\", this.ID)\n doc.Write(ctx, w, None)\n w.Write(\"
\")\n\ntype Doc with\n\n static member ListOfSeq (s: seq<'T>) =\n match s with\n | null -> []\n | s -> List.ofSeq s\n\n static member ToMixedDoc (o: obj) =\n match o with\n | :? Doc as d -> d\n | :? INode as n -> Doc.OfINode n\n | :? Expr<#IControlBody> as e -> Doc.ClientSide %e\n | :? string as t -> Doc.TextNode t\n | null -> Doc.Empty\n | o -> Doc.TextNode (string o)\n\n static member Element (tagname: string) (attrs: seq) (children: seq) =\n Elt (tagname, Doc.ListOfSeq attrs, Doc.ListOfSeq children)\n\n static member ElementMixed (tagname: string) (nodes: seq) =\n let attrs = ResizeArray()\n let children = ResizeArray()\n for n in nodes do\n match n with\n | :? Attr as a -> attrs.Add a\n | o -> children.Add (Doc.ToMixedDoc o)\n Doc.Element tagname attrs children \n\n static member SvgElement (tagname: string) (attrs: seq) (children: seq) =\n Elt (tagname, Doc.ListOfSeq attrs, Doc.ListOfSeq children)\n\n static member SvgElementMixed (tagname: string) (nodes: seq) =\n Doc.ElementMixed tagname nodes\n\n static member Empty = ConcreteDoc(EmptyDoc) :> Doc\n\n static member Append d1 d2 = ConcreteDoc(AppendDoc [ d1; d2 ]) :> Doc\n\n static member Concat (docs: seq) = ConcreteDoc(AppendDoc (Doc.ListOfSeq docs)) :> Doc\n\n static member ConcatMixed ([] docs: obj[]) = Doc.Concat (Seq.map Doc.ToMixedDoc docs)\n\n static member TextNode t = ConcreteDoc(TextDoc t) :> Doc\n\n static member ClientSideImpl(expr: Expr<#IControlBody>) =\n ConcreteDoc(INodeDoc (new Web.InlineControl<_>(%expr))) :> Doc\n\n static member ClientSide([] expr: Expr<#IControlBody>) =\n Doc.ClientSideImpl expr\n\n static member Hydrate ([] expr: Expr) =\n match expr with\n | Patterns.WithValue(doc, _, docExpr) ->\n ConcreteDoc(INodeDoc (new InlineControlWithPlaceHolder (Expr.Cast docExpr, doc :?> Doc))) :> Doc\n | _ ->\n // value missing, nothing to render on server\n Doc.ClientSideImpl expr\n \n static member ClientSideLinq (expr: System.Linq.Expressions.Expression>) =\n ConcreteDoc(INodeDoc (new Web.CSharpInlineControl(expr))) :> Doc\n\n static member Verbatim t = ConcreteDoc(VerbatimDoc t) :> Doc\n\n static member OfINode n = ConcreteDoc(INodeDoc n) :> Doc\n\n[]\ntype ClientServer =\n\n static member client ([] expr: Expr<#IControlBody>) =\n Doc.ClientSideImpl expr\n\n static member hydrate ([] expr: Expr) =\n match expr with\n | Patterns.WithValue(doc, _, docExpr) ->\n ConcreteDoc(INodeDoc (new InlineControlWithPlaceHolder (Expr.Cast docExpr, doc :?> Doc))) :> Doc\n | _ ->\n // value missing, nothing to render on server\n Doc.ClientSideImpl expr\n\n static member clientLinq (expr: System.Linq.Expressions.Expression>) =\n ConcreteDoc(INodeDoc (new Web.CSharpInlineControl(expr))) :> Doc", "// $begin{copyright}\n//\n// This file is part of WebSharper\n//\n// Copyright (c) 2008-2018 IntelliFactory\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\"); you\n// may not use this file except in compliance with the License. You may\n// obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n// implied. See the License for the specific language governing\n// permissions and limitations under the License.\n//\n// $end{copyright}\nnamespace WebSharper.UI.Client\n\n#nowarn \"44\" // HTML deprecated\n\nopen System\nopen System.Collections.Generic\nopen WebSharper\nopen WebSharper.JavaScript\nopen WebSharper.UI\n\nmodule DU = DomUtility\ntype private A = Attr\n\n[]\nmodule Settings =\n let mutable BatchUpdatesEnabled = true\n\n[]\ntype internal DocNode =\n | AppendDoc of DocNode * DocNode\n | ElemDoc of DocElemNode\n | EmbedDoc of DocEmbedNode\n | [] EmptyDoc\n | TextDoc of DocTextNode\n | TextNodeDoc of Dom.Text\n | TreeDoc of DocTreeNode\n\nand []\n []\n []\n []\n internal DocElemNode =\n {\n Attr : Attrs.Dyn\n mutable Children : DocNode\n []\n Delimiters : (Dom.Node * Dom.Node) option\n El : Dom.Element\n ElKey : int\n []\n mutable Render : option unit>\n }\n\n override this.Equals(o: obj) =\n this.ElKey = (o :?> DocElemNode).ElKey\n\n override this.GetHashCode() =\n this.ElKey\n\nand internal DocEmbedNode =\n {\n mutable Current : DocNode\n mutable Dirty : bool\n }\n\nand internal DocTextNode =\n {\n Text : Dom.Text\n mutable Dirty : bool\n mutable Value : string\n }\n\nand internal DocTreeNode =\n {\n mutable Els : Union[]\n mutable Dirty : bool\n mutable Holes : DocElemNode[]\n Attrs : (Dom.Element * Attrs.Dyn)[]\n []\n mutable Render : option unit>\n []\n El : option\n }\n\ntype EltUpdater =\n inherit Elt\n\n member this.AddUpdated(doc: Elt) = ()\n member this.RemoveUpdated(doc: Elt) = ()\n member this.RemoveAllUpdated() = ()\n\n[]\nmodule internal Docs =\n\n /// Sets of DOM nodes.\n type DomNodes =\n | DomNodes of Dom.Node[]\n\n /// Actual chidlren of an element.\n static member Children (elem: Dom.Element) (delims: option) =\n match delims with\n | None ->\n DomNodes (Array.init elem.ChildNodes.Length elem.ChildNodes.Item)\n | Some (ldelim, rdelim) ->\n let a = Array<_>()\n let mutable n = ldelim.NextSibling\n while n !==. rdelim do\n a.Push(n) |> ignore\n n <- n.NextSibling\n DomNodes (As a)\n\n /// Shallow children of an element node.\n static member DocChildren node =\n let q = Queue()\n let rec loop doc =\n match doc with\n | AppendDoc (a, b) -> loop a; loop b\n | EmbedDoc d -> loop d.Current\n | ElemDoc e -> q.Enqueue (e.El :> Dom.Node)\n | EmptyDoc -> ()\n | TextNodeDoc tn -> q.Enqueue (tn :> Dom.Node)\n | TextDoc t -> q.Enqueue (t.Text :> Dom.Node)\n | TreeDoc t ->\n t.Els |> Array.iter (function\n | Union1Of2 e -> q.Enqueue e\n | Union2Of2 n -> loop n\n )\n loop node.Children\n DomNodes (Array.ofSeqNonCopying q)\n\n /// Set difference - currently only using equality O(N^2).\n /// Can do better? Can store data on every node?\n static member Except (DomNodes excluded) (DomNodes included) =\n included\n |> Array.filter (fun n ->\n excluded\n |> Array.forall (fun k -> not (n ===. k)))\n |> DomNodes\n\n /// Iteration.\n static member Iter f (DomNodes ns) =\n Array.iter f ns\n\n /// Iteration.\n static member FoldBack f (DomNodes ns) z =\n Array.foldBack f ns z\n\n /// Inserts a node at position.\n let InsertNode parent node pos =\n DU.InsertAt parent pos node\n DU.BeforeNode node\n\n /// Inserts a doc at position.\n let rec InsertDoc parent doc pos =\n match doc with\n | AppendDoc (a, b) -> InsertDoc parent a (InsertDoc parent b pos)\n | ElemDoc e -> InsertNode parent e.El pos\n | EmbedDoc d -> d.Dirty <- false; InsertDoc parent d.Current pos\n | EmptyDoc -> pos\n | TextDoc t -> InsertNode parent t.Text pos\n | TextNodeDoc t -> InsertNode parent t pos\n | TreeDoc t ->\n Array.foldBack (fun el pos ->\n match el with\n | Union1Of2 e -> InsertNode parent e pos\n | Union2Of2 n -> InsertDoc parent n pos\n ) t.Els pos\n\n /// Synchronizes an element with its children (shallow).\n let DoSyncElement (el : DocElemNode) =\n let parent = el.El\n let rec ins doc pos =\n match doc with\n | AppendDoc (a, b) -> ins a (ins b pos)\n | ElemDoc e -> DU.BeforeNode e.El\n | EmbedDoc d ->\n if d.Dirty then\n d.Dirty <- false\n InsertDoc parent d.Current pos\n else\n ins d.Current pos\n | EmptyDoc -> pos\n | TextDoc t -> DU.BeforeNode t.Text\n | TextNodeDoc t -> DU.BeforeNode t\n | TreeDoc t ->\n if t.Dirty then t.Dirty <- false\n Array.foldBack (fun el pos ->\n match el with\n | Union1Of2 e -> DU.BeforeNode e\n | Union2Of2 n -> ins n pos\n ) t.Els pos\n let ch = DomNodes.DocChildren el\n // remove children that are not in the current set\n DomNodes.Children el.El el.Delimiters\n |> DomNodes.Except ch\n |> DomNodes.Iter (DU.RemoveNode el.El)\n // insert current children\n let pos =\n match el.Delimiters with\n | None -> DU.AtEnd\n | Some (_, rdelim) -> DU.BeforeNode rdelim\n ins el.Children pos |> ignore\n\n /// Optimized version of DoSyncElement.\n let SyncElement (el: DocElemNode) =\n /// Test if any children have changed.\n let rec hasDirtyChildren el =\n let rec dirty doc =\n match doc with\n | AppendDoc (a, b) -> dirty a || dirty b\n | EmbedDoc d -> d.Dirty || dirty d.Current\n | TreeDoc t -> t.Dirty || Array.exists hasDirtyChildren t.Holes\n | _ -> false\n dirty el.Children\n Attrs.Sync el.El el.Attr\n if hasDirtyChildren el then\n DoSyncElement el\n\n /// Links an element to children by inserting them.\n let LinkElement el children =\n InsertDoc el children DU.AtEnd |> ignore\n\n /// Links an element to previous siblings by inserting them.\n let LinkPrevElement (el: Dom.Node) children =\n InsertDoc (el.ParentNode :?> _) children (DU.BeforeNode el) |> ignore\n\n let InsertBeforeDelim (afterDelim: Dom.Node) (doc: DocNode) =\n let p = afterDelim.ParentNode\n let before = JS.Document.CreateTextNode(\"\") :> Dom.Node\n p.InsertBefore(before, afterDelim) |> ignore\n LinkPrevElement afterDelim doc\n before\n\n /// Invokes and clears an element's afterRender callback(s).\n let AfterRender (el: DocElemNode) =\n match el.Render with\n | None -> ()\n | Some f -> f el.El; el.Render <- None\n\n /// Synchronizes the document (deep).\n let rec Sync doc =\n match doc with\n | AppendDoc (a, b) -> Sync a; Sync b\n | ElemDoc el -> SyncElemNode false el\n | EmbedDoc n -> Sync n.Current\n | EmptyDoc\n | TextNodeDoc _ -> ()\n | TextDoc d ->\n if d.Dirty then\n d.Text.NodeValue <- d.Value\n d.Dirty <- false\n | TreeDoc t ->\n Array.iter (fun h -> SyncElemNode false h) t.Holes\n Array.iter (fun (e, a) -> Attrs.Sync e a) t.Attrs\n AfterRender (As t)\n\n /// Synchronizes an element node (deep).\n and SyncElemNode childrenOnly el =\n if not childrenOnly then\n SyncElement el\n Sync el.Children\n AfterRender el\n\n /// A set of node element nodes.\n type NodeSet =\n | NodeSet of HashSet\n\n /// Filters out only nodes that have on-remove animations.\n static member Filter f (NodeSet set) =\n NodeSet (HashSet.Filter f set)\n\n /// Finds all node elements in a tree.\n static member FindAll doc =\n let q = Queue()\n let rec loop node =\n match node with\n | AppendDoc (a, b) -> loop a; loop b\n | ElemDoc el -> loopEN el\n | EmbedDoc em -> loop em.Current\n | TreeDoc t -> t.Holes |> Array.iter loopEN\n | _ -> ()\n and loopEN el =\n q.Enqueue el\n loop el.Children\n loop doc\n NodeSet (HashSet q)\n\n /// Set difference.\n static member Except (NodeSet excluded) (NodeSet included) =\n NodeSet (included |> HashSet.Except excluded)\n\n /// Set intersection.\n static member Intersect (NodeSet a) (NodeSet b) =\n NodeSet (HashSet.Intersect a b)\n\n /// Checks if empty.\n static member IsEmpty (NodeSet ns) =\n ns.Count = 0\n\n /// The empty set.\n static member Empty =\n NodeSet (HashSet ())\n\n /// Converts to array.\n static member ToArray (NodeSet ns) =\n HashSet.ToArray ns\n\n /// State of the Doc.Run (updator) proces.\n type RunState =\n {\n mutable PreviousNodes : NodeSet\n Top : DocElemNode\n }\n\n /// Creates an element node.\n let CreateElemNode el attr children =\n LinkElement el children\n let attr = Attrs.Insert el attr\n {\n Attr = attr\n Children = children\n Delimiters = None\n El = el\n ElKey = Fresh.Int ()\n Render = Attrs.GetOnAfterRender attr\n }\n\n /// Creates an element node that handles a delimited subset of its children.\n let CreateDelimitedElemNode (ldelim: Dom.Node) (rdelim: Dom.Node) attr children =\n let el = ldelim.ParentNode :?> Dom.Element\n LinkPrevElement rdelim children\n let attr = Attrs.Insert el attr\n {\n Attr = attr\n Children = children\n Delimiters = Some (ldelim, rdelim)\n El = el\n ElKey = Fresh.Int ()\n Render = Attrs.GetOnAfterRender attr\n }\n\n /// Creates a new RunState.\n let CreateRunState parent doc =\n {\n PreviousNodes = NodeSet.Empty\n Top = CreateElemNode parent Attr.Empty doc\n }\n\n /// Creates a new RunState for a delimited subset of the children of a node.\n let CreateDelimitedRunState ldelim rdelim doc =\n {\n PreviousNodes = NodeSet.Empty\n Top = CreateDelimitedElemNode ldelim rdelim Attr.Empty doc\n }\n\n /// Computes the animation of nodes that animate removal.\n let ComputeExitAnim st cur =\n st.PreviousNodes\n |> NodeSet.Filter (fun n -> Attrs.HasExitAnim n.Attr)\n |> NodeSet.Except cur\n |> NodeSet.ToArray\n |> Array.map (fun n -> Attrs.GetExitAnim n.Attr)\n |> Anim.Concat\n\n /// Computes the animation for changed nodes.\n let ComputeChangeAnim st cur =\n let relevant = NodeSet.Filter (fun n -> Attrs.HasChangeAnim n.Attr)\n NodeSet.Intersect (relevant st.PreviousNodes) (relevant cur)\n |> NodeSet.ToArray\n |> Array.map (fun n -> Attrs.GetChangeAnim n.Attr)\n |> Anim.Concat\n\n /// Computes the animation for entering nodes.\n let ComputeEnterAnim st cur =\n cur\n |> NodeSet.Filter (fun n -> Attrs.HasEnterAnim n.Attr)\n |> NodeSet.Except st.PreviousNodes\n |> NodeSet.ToArray\n |> Array.map (fun n -> Attrs.GetEnterAnim n.Attr)\n |> Anim.Concat\n\n let SyncElemNodesNextFrame childrenOnly st =\n if Settings.BatchUpdatesEnabled then\n Async.FromContinuations <| fun (ok, _, _) ->\n JS.RequestAnimationFrame (fun _ ->\n SyncElemNode childrenOnly st.Top\n ok()\n ) |> ignore\n else\n async.Return(SyncElemNode childrenOnly st.Top)\n\n /// The main function: how to perform an animated top-level document update.\n let PerformAnimatedUpdate childrenOnly st doc =\n if Anim.UseAnimations then\n async {\n let cur = NodeSet.FindAll doc\n let change = ComputeChangeAnim st cur\n let enter = ComputeEnterAnim st cur\n let exit = ComputeExitAnim st cur\n do! Anim.Play (Anim.Append change exit)\n do! SyncElemNodesNextFrame childrenOnly st\n do! Anim.Play enter\n return st.PreviousNodes <- cur\n }\n else\n SyncElemNodesNextFrame childrenOnly st\n\n let PerformSyncUpdate childrenOnly st doc =\n let cur = NodeSet.FindAll doc\n SyncElemNode childrenOnly st.Top\n st.PreviousNodes <- cur\n\n /// EmbedNode constructor.\n let CreateEmbedNode () =\n {\n Current = EmptyDoc\n Dirty = false\n }\n\n /// EmbedNode update (marks dirty).\n let UpdateEmbedNode node upd =\n node.Current <- upd\n node.Dirty <- true\n\n /// Text node constructor.\n let CreateTextNode () =\n {\n Dirty = false\n Text = DU.CreateText \"\"\n Value = \"\"\n }\n\n /// Text node update (marks dirty).\n let UpdateTextNode n t =\n n.Value <- t\n n.Dirty <- true\n\n// We implement the Doc interface, the Doc module proxy and the Client.Doc module proxy\n// all in this so that it all neatly looks like Doc.* in javascript.\n[)>]\ntype internal Doc' [] (docNode, updates) =\n\n []\n member this.DocNode = docNode\n []\n member this.Updates = updates\n\n interface IControlBody with\n\n []\n member this.ReplaceInDom(elt) =\n // Insert empty text nodes that will serve as delimiters for the Doc.\n let rdelim = JS.Document.CreateTextNode \"\"\n elt.ParentNode.ReplaceChild(rdelim, elt) |> ignore\n Doc'.RunBefore rdelim this\n\n []\n static member Mk node updates =\n Doc'(node, updates)\n\n []\n static member Append (a: Doc') (b: Doc') =\n (a.Updates, b.Updates)\n ||> View.Map2Unit\n |> Doc'.Mk (AppendDoc (a.DocNode, b.DocNode))\n\n []\n static member Concat xs =\n Array.ofSeqNonCopying xs\n |> Array.TreeReduce Doc'.Empty Doc'.Append\n\n []\n static member Empty\n with get () =\n Doc'.Mk EmptyDoc (View.Const ())\n\n []\n static member Elem el attr (children: Doc') =\n Elt'.New(el, attr, children)\n\n []\n static member TextNode v =\n Doc'.Mk (TextNodeDoc (DU.CreateText v)) (View.Const ())\n\n []\n static member StaticProxy el : Elt' =\n Doc'.Elem el Attr.Empty Doc'.Empty\n\n []\n static member Static el : Elt = As (Doc'.StaticProxy el)\n\n []\n static member Verbatim html =\n let a =\n DomUtility.ParseHTMLIntoFakeRoot html\n |> DomUtility.ChildrenArray\n let elem (n: Dom.Node) =\n if n.NodeType = Dom.NodeType.Text then\n TextNodeDoc (n :?> Dom.Text)\n else\n ElemDoc (Docs.CreateElemNode (n :?> Dom.Element) Attr.Empty EmptyDoc)\n let append x y = AppendDoc (x, y)\n let es = Array.MapTreeReduce elem EmptyDoc append a\n Doc'.Mk es (View.Const ())\n\n []\n static member EmbedView (view: View) =\n let node = Docs.CreateEmbedNode ()\n view\n |> View.Bind (fun doc ->\n Docs.UpdateEmbedNode node doc.DocNode\n doc.Updates)\n |> View.Map ignore\n |> Doc'.Mk (EmbedDoc node)\n\n []\n static member BindView (f: 'T -> Doc') (view: View<'T>) =\n Doc'.EmbedView (View.Map f view)\n\n []\n static member Async (a: Async) : Doc' =\n View.Const a\n |> View.MapAsync id\n |> Doc'.EmbedView\n\n []\n static member RunBetween ldelim rdelim (doc: Doc') =\n Docs.LinkPrevElement rdelim doc.DocNode\n let st = Docs.CreateDelimitedRunState ldelim rdelim doc.DocNode\n let p =\n if Anim.UseAnimations || Settings.BatchUpdatesEnabled then\n Mailbox.StartProcessor (Docs.PerformAnimatedUpdate false st doc.DocNode)\n else\n fun () -> Docs.PerformSyncUpdate false st doc.DocNode\n View.Sink p doc.Updates\n\n []\n static member RunBefore (rdelim: Dom.Node) (doc: Doc') =\n let ldelim = JS.Document.CreateTextNode(\"\")\n rdelim.ParentNode.InsertBefore(ldelim, rdelim) |> ignore\n Doc'.RunBetween ldelim rdelim doc\n\n []\n static member RunBeforeById id doc =\n match JS.Document.GetElementById(id) with\n | null -> failwith (\"invalid id: \" + id)\n | el -> Doc'.RunBefore el doc\n\n []\n static member RunAfter (ldelim : Dom.Node) (doc: Doc') =\n let rdelim = JS.Document.CreateTextNode(\"\")\n ldelim.ParentNode.InsertBefore(rdelim, ldelim.NextSibling) |> ignore\n Doc'.RunBetween ldelim rdelim doc\n\n []\n static member RunAfterById id doc =\n match JS.Document.GetElementById(id) with\n | null -> failwith (\"invalid id: \" + id)\n | el -> Doc'.RunAfter el doc\n\n []\n static member RunAppend (parent: Dom.Element) (doc: Doc') =\n let rdelim = JS.Document.CreateTextNode \"\"\n parent.AppendChild(rdelim) |> ignore\n Doc'.RunBefore rdelim doc\n\n []\n static member RunAppendById id doc =\n match JS.Document.GetElementById(id) with\n | null -> failwith (\"invalid id: \" + id)\n | el -> Doc'.RunAppend el doc\n\n []\n static member RunPrepend (parent: Dom.Element) (doc: Doc') =\n let rdelim = JS.Document.CreateTextNode \"\"\n parent.InsertBefore(rdelim, parent.FirstChild) |> ignore\n Doc'.RunBefore rdelim doc\n\n []\n static member RunPrependById id doc =\n match JS.Document.GetElementById(id) with\n | null -> failwith (\"invalid id: \" + id)\n | el -> Doc'.RunPrepend el doc\n\n []\n static member RunInPlace childrenOnly parent (doc: Doc') =\n let d = doc.DocNode\n let st = Docs.CreateRunState parent d\n let p =\n if Anim.UseAnimations || Settings.BatchUpdatesEnabled then\n Mailbox.StartProcessor (Docs.PerformAnimatedUpdate childrenOnly st doc.DocNode)\n else\n fun () -> Docs.PerformSyncUpdate childrenOnly st doc.DocNode\n View.Sink p doc.Updates\n\n []\n static member Run parent (doc: Doc') =\n Docs.LinkElement parent doc.DocNode\n Doc'.RunInPlace false parent doc\n\n []\n static member RunById id tr =\n match JS.Document.GetElementById(id) with\n | null -> failwith (\"invalid id: \" + id)\n | el -> Doc'.Run el tr\n\n []\n static member RunReplaceById id (tr: Doc') =\n match JS.Document.GetElementById(id) with\n | null -> failwith (\"invalid id: \" + id)\n | el -> (tr :> IControlBody).ReplaceInDom(el)\n\n []\n static member TextView txt =\n let node = Docs.CreateTextNode ()\n txt\n |> View.Map (Docs.UpdateTextNode node)\n |> Doc'.Mk (TextDoc node)\n\n []\n static member Flatten view =\n view\n |> View.Map Doc'.Concat\n |> Doc'.EmbedView\n\n []\n static member Convert render view =\n View.MapSeqCached render view |> Doc'.Flatten\n\n []\n static member ConvertBy key render view =\n View.MapSeqCachedBy key render view |> Doc'.Flatten\n\n []\n static member ConvertSeq render view =\n View.MapSeqCachedView render view |> Doc'.Flatten\n\n []\n static member ConvertSeqBy key render view =\n View.MapSeqCachedViewBy key (As render) view |> Doc'.Flatten\n\n []\n static member ConvertSeqVarBy key render var =\n Var.MapLens key (As render) var |> Doc'.Flatten\n\n []\n static member InputInternal elemTy attr =\n let el = DU.CreateElement elemTy\n Doc'.Elem el (Attr.Concat (attr el)) Doc'.Empty\n\n []\n static member Input attr (var: Var) =\n Doc'.InputInternal \"input\" (fun _ ->\n Seq.append attr [| Attr.Value var |])\n\n []\n static member PasswordBox attr (var: Var) =\n Doc'.InputInternal \"input\" (fun _ ->\n Seq.append attr [|\n Attr.Value var\n Attr.Create \"type\" \"password\"\n |])\n\n []\n static member IntInputUnchecked attr (var: Var) =\n Doc'.InputInternal \"input\" (fun _ ->\n Seq.append attr [|\n (if var.Get() = 0 then Attr.Create \"value\" \"0\" else Attr.Empty)\n Attr.IntValueUnchecked var\n Attr.Create \"type\" \"number\"\n |])\n\n []\n static member IntInput attr (var: Var>) =\n Doc'.InputInternal \"input\" (fun el ->\n Seq.append attr [|\n Attr.IntValue var\n Attr.Create \"type\" \"number\"\n |])\n\n []\n static member FloatInputUnchecked attr (var: Var) =\n Doc'.InputInternal \"input\" (fun _ ->\n Seq.append attr [|\n (if var.Get() = 0. then Attr.Create \"value\" \"0\" else Attr.Empty)\n Attr.FloatValueUnchecked var\n Attr.Create \"type\" \"number\"\n |])\n\n []\n static member FloatInput attr (var: Var>) =\n Doc'.InputInternal \"input\" (fun el ->\n Seq.append attr [|\n Attr.FloatValue var\n Attr.Create \"type\" \"number\"\n |])\n\n []\n static member DecimalInputUnchecked attr (var: Var) (step: decimal)=\n Doc'.InputInternal \"input\" (fun _ ->\n Seq.append attr [|\n (if var.Get() = 0.m then Attr.Create \"value\" \"0\" else Attr.Empty)\n Attr.DecimalValueUnchecked var\n Attr.Create \"type\" \"number\"\n Attr.Create \"step\" $\"{step}\"\n |])\n\n []\n static member DecimalInput attr (var: Var>) (step: decimal)=\n Doc'.InputInternal \"input\" (fun el ->\n Seq.append attr [|\n Attr.DecimalValue var\n Attr.Create \"type\" \"number\"\n Attr.Create \"step\" $\"{step}\"\n |])\n\n []\n static member ColorInput attr (var: Var) =\n Doc'.InputInternal \"input\" (fun el ->\n Seq.append attr [|\n Attr.Value var\n Attr.Create \"type\" \"color\"\n |])\n\n []\n static member DateInput attr (var: Var) =\n Doc'.InputInternal \"input\" (fun el ->\n Seq.append attr [|\n Attr.Value var\n Attr.Create \"type\" \"datetime\"\n |])\n\n []\n static member DateTimeLocalInput attr (var: Var) =\n Doc'.InputInternal \"input\" (fun el ->\n Seq.append attr [|\n Attr.DateTimeValue var\n Attr.Create \"type\" \"datetime-local\"\n |])\n\n []\n static member EmailInput attr (var: Var) =\n Doc'.InputInternal \"input\" (fun el ->\n Seq.append attr [|\n Attr.Value var\n Attr.Create \"type\" \"email\"\n |])\n\n []\n static member FileInput attr (var: Var) =\n Doc'.InputInternal \"input\" (fun el ->\n Seq.append attr [|\n Attr.FileValue var\n Attr.Create \"type\" \"file\"\n |])\n\n []\n static member MonthInput attr (var: Var) =\n Doc'.InputInternal \"input\" (fun el ->\n Seq.append attr [|\n Attr.Value var\n Attr.Create \"type\" \"month\"\n |])\n\n []\n static member SearchInput attr (var: Var) =\n Doc'.InputInternal \"input\" (fun el ->\n Seq.append attr [|\n Attr.Value var\n Attr.Create \"type\" \"search\"\n |])\n\n []\n static member TelInput attr (var: Var) =\n Doc'.InputInternal \"input\" (fun el ->\n Seq.append attr [|\n Attr.Value var\n Attr.Create \"type\" \"tel\"\n |])\n\n []\n static member TimeInput attr (var: Var) =\n Doc'.InputInternal \"input\" (fun el ->\n Seq.append attr [|\n Attr.Value var\n Attr.Create \"type\" \"time\"\n |])\n\n []\n static member UrlInput attr (var: Var) =\n Doc'.InputInternal \"input\" (fun el ->\n Seq.append attr [|\n Attr.Value var\n Attr.Create \"type\" \"url\"\n |])\n\n []\n static member WeekInput attr (var: Var) =\n Doc'.InputInternal \"input\" (fun el ->\n Seq.append attr [|\n Attr.Value var\n Attr.Create \"type\" \"week\"\n |])\n\n []\n static member RangeInput attr (var: Var) =\n Doc'.InputInternal \"input\" (fun el ->\n Seq.append attr [|\n Attr.IntValueUnchecked var\n Attr.Create \"type\" \"range\"\n |])\n\n []\n static member InputArea attr (var: Var) =\n Doc'.InputInternal \"textarea\" (fun _ ->\n Seq.append attr [| Attr.Value var |])\n\n []\n static member SelectImpl attrs (show: 'T -> string) (optionElements) (current: Var<'T>) =\n let options = ref []\n let getIndex (el: Dom.Element) =\n el?selectedIndex : int\n let setIndex (el: Dom.Element) (i: int) =\n el?selectedIndex <- i\n let getSelectedItem el =\n let i = getIndex el\n options.Value[i]\n let itemIndex x =\n List.findIndex ((=) x) options.Value\n let setSelectedItem (el: Dom.Element) item =\n setIndex el (itemIndex item)\n let el = DU.CreateElement \"select\"\n let selectedItemAttr =\n current.View\n |> Attr.DynamicCustom setSelectedItem\n let onChange (x: Dom.Event) =\n current.UpdateMaybe(fun x ->\n let y = getSelectedItem el\n if x = y then None else Some y\n )\n el.AddEventListener(\"change\", onChange, false)\n let attrs =\n Attr.Concat attrs\n |> Attr.Append selectedItemAttr\n |> Attr.Append (Attr.OnAfterRender (fun el -> \n setSelectedItem el <| current.Get()))\n Doc'.Elem el attrs (optionElements options)\n\n []\n static member SelectDyn attrs (show: 'T -> string) (vOptions: View>) (current: Var<'T>) =\n let optionElements (options: 'T list ref) =\n vOptions\n |> View.Map (fun l ->\n options.Value <- l\n l |> Seq.mapi (fun i x -> i, x)\n )\n |> Doc'.Convert (fun (i, o) ->\n Doc'.Element \"option\" [\n Attr.Create \"value\" (string i)\n ] [Doc'.TextNode (show o)]\n :> Doc'\n )\n Doc'.SelectImpl attrs show optionElements current\n\n []\n static member Select attrs show options current =\n let optionElements (rOptions: 'T list ref) =\n rOptions.Value <- options\n options\n |> List.mapi (fun i o ->\n Doc'.Element \"option\" [\n Attr.Create \"value\" (string i)\n ] [Doc'.TextNode (show o)]\n :> Doc'\n )\n |> Doc'.Concat\n Doc'.SelectImpl attrs show optionElements current\n\n []\n static member SelectOptional attrs noneText show options current =\n Doc'.Select attrs\n (function None -> noneText | Some x -> show x)\n (None :: List.map Some options)\n current\n\n []\n static member SelectDynOptional attrs noneText show vOptions current =\n Doc'.SelectDyn attrs\n (function None -> noneText | Some x -> show x)\n (vOptions |> View.Map (fun options -> None :: List.map Some options))\n current\n\n []\n static member CheckBox attrs (chk: Var) =\n Doc'.InputInternal \"input\" (fun _ ->\n Seq.append attrs [\n Attr.Create \"type\" \"checkbox\"\n Attr.Checked chk\n ])\n\n []\n static member CheckBoxGroup attrs (item: 'T) (chk: Var>) =\n let rv =\n chk.Lens\n (List.exists ((=) item))\n (fun l b ->\n if b then\n if List.exists ((=) item) l then l else item :: l\n else\n List.filter ((<>) item) l\n )\n Doc'.CheckBox attrs rv\n\n []\n static member Clickable elem action =\n let el = DU.CreateElement elem\n el.AddEventListener(\"click\", (fun (ev: Dom.Event) ->\n ev.PreventDefault()\n action ()), false)\n el\n\n []\n static member Button caption attrs action =\n let attrs = Attr.Concat attrs\n let el = Doc'.Clickable \"button\" action\n Doc'.Elem el attrs (Doc'.TextNode caption)\n\n []\n static member ButtonView caption attrs view action =\n let evAttr = Attr.HandlerView \"click\" view (fun _ _ -> action)\n let attrs = Attr.Concat (Seq.append [|evAttr|] attrs)\n Doc'.Elem (DU.CreateElement \"button\") attrs (Doc'.TextNode caption)\n\n []\n static member Link caption attrs action =\n let attrs = Attr.Concat attrs |> Attr.Append (Attr.Create \"href\" \"#\")\n let el = Doc'.Clickable \"a\" action\n Doc'.Elem el attrs (Doc'.TextNode caption)\n\n []\n static member LinkView caption attrs view action =\n let evAttr = Attr.HandlerView \"click\" view (fun _ _ -> action)\n let attrs = Attr.Concat (Seq.append [|evAttr; Attr.Create \"href\" \"#\"|] attrs)\n Doc'.Elem (DU.CreateElement \"a\") attrs (Doc'.TextNode caption)\n\n []\n static member Radio attrs value (var: Var<_>) =\n // Radio buttons work by taking a common var, which is given a unique ID.\n // This ID is serialised and used as the name, giving us the \"grouping\"\n // behaviour.\n let el = DU.CreateElement \"input\"\n el.AddEventListener(\"click\", (fun (x : Dom.Event) -> var.Set value), false)\n let predView = View.Map (fun x -> x = value) var.View\n let valAttr = Attr.DynamicProp \"checked\" predView\n let (==>) k v = Attr.Create k v\n let attr =\n [\n \"type\" ==> \"radio\"\n \"name\" ==> var.Id\n valAttr\n ] @ (List.ofSeq attrs) |> Attr.Concat\n Doc'.Elem el attr Doc'.Empty\n\n // Actual proxy members\n\n []\n static member Element (name: string) (attr: seq) (children: seq) : Elt' =\n let attr = Attr.Concat attr\n let children = Doc'.Concat children\n Doc'.Elem (DU.CreateElement name) attr children\n\n static member ToMixedDoc (o: obj) =\n match o with\n | :? Doc' as d -> d\n | :? string as t -> Doc'.TextNode t\n | :? Dom.Element as e -> Doc'.StaticProxy e :> Doc'\n | :? Function as v ->\n Doc'.EmbedView ((As>v).Map Doc'.ToMixedDoc)\n | :? Var as v ->\n Doc'.EmbedView (v.View.Map Doc'.ToMixedDoc)\n | null -> Doc'.Empty\n | o -> Doc'.TextNode (string o)\n\n static member MixedNodes (nodes: seq) =\n let attrs = ResizeArray()\n let children = ResizeArray()\n for n in nodes do\n match n with\n | :? Attr as a -> attrs.Add a\n | _ -> children.Add (Doc'.ToMixedDoc n)\n attrs :> _ seq, children :> _ seq \n\n static member ConcatMixed (elts: obj[]) =\n Doc'.Concat (Seq.map Doc'.ToMixedDoc elts)\n\n []\n static member ElementMixed (tagname: string) (nodes: seq) =\n let attrs, children = Doc'.MixedNodes nodes\n Doc'.Element tagname attrs children \n\n []\n static member SvgElement (name: string) (attr: seq) (children: seq) : Elt' =\n let attr = Attr.Concat attr\n let children = Doc'.Concat children\n Doc'.Elem (DU.CreateSvgElement name) attr children\n\n []\n static member SvgElementMixed (tagname: string) (nodes: seq) =\n let attrs, children = Doc'.MixedNodes nodes\n Doc'.SvgElement tagname attrs children \n\n []\n static member ClientSide (expr: Microsoft.FSharp.Quotations.Expr<#IControlBody>) : Doc' =\n As expr\n\nand [); Name \"WebSharper.UI.Elt\">]\n internal Elt'(docNode, updates, elt: Dom.Element, rvUpdates: Updates) =\n inherit Doc'(docNode, updates)\n\n static member New(el: Dom.Element, attr: Attr, children: Doc') =\n let node = Docs.CreateElemNode el attr children.DocNode\n let rvUpdates = Updates.Create children.Updates\n let attrUpdates = Attrs.Updates node.Attr\n let updates = View.Map2Unit attrUpdates rvUpdates.View\n new Elt'(ElemDoc node, updates, el, rvUpdates)\n\n /// Assumes tree.Els = [| Union1Of2 someDomElement |]\n static member TreeNode(tree: DocTreeNode, updates) =\n let rvUpdates = Updates.Create updates\n let attrUpdates =\n tree.Attrs\n |> Array.map (fun (_, a) -> Attrs.Updates a)\n |> Array.TreeReduce (View.Const ()) View.Map2Unit\n let updates = View.Map2Unit attrUpdates rvUpdates.View\n new Elt'(TreeDoc tree, updates, tree.Els[0].Value1 :?> _, rvUpdates)\n\n []\n member this.Element = elt\n\n member this.on (ev: string, cb: Dom.Element -> #Dom.Event -> unit) =\n elt.AddEventListener(ev, (fun (ev: Dom.Event) -> cb elt (ev :?> _)), false)\n this\n\n member this.onView (ev: string, view: View<'T>, cb: Dom.Element -> #Dom.Event -> 'T -> unit) =\n let cb = cb elt\n elt.AddEventListener(ev, (fun (ev: Dom.Event) -> View.Get (cb (ev :?> _)) view), false)\n this\n\n []\n member this.onExpr (ev: string, cb: Microsoft.FSharp.Quotations.Expr #Dom.Event -> unit>) =\n this.on (ev, As<_ -> _ -> _> cb)\n\n member this.OnAfterRender' (cb: Dom.Element -> unit) =\n match docNode with\n | ElemDoc e ->\n e.Render <-\n match e.Render with\n | None -> Some cb\n | Some f -> Some (fun el -> f el; cb el)\n | TreeDoc e ->\n e.Render <-\n match e.Render with\n | None -> Some cb\n | Some f -> Some (fun el -> f el; cb el)\n | _ -> failwith \"Invalid docNode in Elt\"\n this\n\n member this.OnAfterRender (cb: Microsoft.FSharp.Quotations.Expr unit>) =\n this.OnAfterRender' (As unit> cb)\n\n member this.OnAfterRenderView (view: View<'T>, cb: Dom.Element -> 'T -> unit) =\n let id = Fresh.Id()\n this.AppendDoc(Doc'.BindView (fun x -> this.Element?(id) <- x; Doc'.Empty) view)\n this.OnAfterRender'(fun e -> cb e e?(id))\n\n abstract AddHole : DocElemNode -> unit \n default this.AddHole h = \n match docNode with\n | TreeDoc e ->\n e.Holes.JS.Push h |> ignore\n | _ -> ()\n\n abstract ClearHoles : unit -> unit \n default this.ClearHoles() = \n match docNode with\n | TreeDoc e ->\n e.Holes <- [||]\n | _ -> ()\n\n []\n member this.AppendDoc(doc: Doc') =\n match docNode with\n | ElemDoc e ->\n e.Children <- AppendDoc(e.Children, doc.DocNode)\n Docs.InsertDoc elt doc.DocNode DU.AtEnd |> ignore\n | TreeDoc e ->\n let after = elt.AppendChild(JS.Document.CreateTextNode \"\")\n let before = Docs.InsertBeforeDelim after doc.DocNode\n this.AddHole {\n El = elt\n Attr = Attrs.Empty elt\n Children = doc.DocNode\n Delimiters = Some (before, after)\n ElKey = Fresh.Int()\n Render = None\n } \n | _ -> failwith \"Invalid docNode in Elt\"\n rvUpdates.Value <- View.Map2Unit rvUpdates.Value doc.Updates\n\n []\n member this.PrependDoc(doc: Doc') =\n match docNode with\n | ElemDoc e ->\n e.Children <- AppendDoc(doc.DocNode, e.Children)\n let pos =\n match elt.FirstChild with\n | null -> DU.AtEnd\n | n -> DU.BeforeNode n\n Docs.InsertDoc elt doc.DocNode pos |> ignore\n | TreeDoc e ->\n let after = elt.InsertBefore(JS.Document.CreateTextNode \"\", elt.FirstChild)\n let before = Docs.InsertBeforeDelim after doc.DocNode\n this.AddHole {\n El = elt\n Attr = Attrs.Empty elt\n Children = doc.DocNode\n Delimiters = Some (before, after)\n ElKey = Fresh.Int()\n Render = None\n }\n | _ -> failwith \"Invalid docNode in Elt\"\n rvUpdates.Value <- View.Map2Unit rvUpdates.Value doc.Updates\n\n []\n member this.Clear'() =\n match docNode with\n | ElemDoc e ->\n e.Children <- EmptyDoc\n | TreeDoc e ->\n e.Els <- [||]\n this.ClearHoles()\n | _ -> failwith \"Invalid docNode in Elt\"\n rvUpdates.Value <- View.Const()\n while (elt.HasChildNodes()) do elt.RemoveChild(elt.FirstChild) |> ignore\n\n []\n member this.ToUpdater() =\n let docTreeNode : DocTreeNode =\n match docNode with\n | ElemDoc e ->\n {\n Els = [| Union1Of2 (upcast elt) |]\n Holes = [||]\n Attrs = [| elt, e.Attr |]\n Render = None\n Dirty = true\n El = Some elt\n }\n | TreeDoc e -> e\n | _ -> failwith \"Invalid docNode in Elt\"\n\n EltUpdater'(docTreeNode, updates, elt, rvUpdates, Var.Create [||])\n\n []\n member this.Html'() : string =\n elt?outerHTML\n\n []\n member this.Id'() : string =\n elt?id\n\n []\n member this.GetValue() : string =\n elt?value\n\n []\n member this.SetValue(v: string) : unit =\n elt?value <- v\n\n []\n member this.GetText() : string =\n elt.TextContent\n\n []\n member this.SetText(v: string) : unit =\n match docNode with\n | ElemDoc e ->\n e.Children <- EmptyDoc\n | TreeDoc e ->\n e.Els <- [||]\n this.ClearHoles()\n | _ -> failwith \"Invalid docNode in Elt\"\n rvUpdates.Value <- View.Const()\n elt.TextContent <- v\n\n []\n member this.SetAttribute'(name: string, value: string) =\n elt.SetAttribute(name, value)\n\n []\n member this.GetAttribute'(name) =\n elt.GetAttribute(name)\n\n []\n member this.HasAttribute'(name) =\n elt.HasAttribute(name)\n\n []\n member this.RemoveAttribute'(name) =\n elt.RemoveAttribute(name)\n\n []\n member this.SetProperty'(name: string, value: 'T) =\n elt?(name) <- value\n\n []\n member this.GetProperty'(name: string) : 'T =\n elt?(name)\n\n []\n member this.AddClass'(cls: string) =\n DU.AddClass elt cls\n\n []\n member this.RemoveClass'(cls: string) =\n DU.RemoveClass elt cls\n\n []\n member this.HasClass'(cls: string) =\n (new RegExp(@\"(\\s|^)\" + cls + @\"(\\s|$)\")).Test(elt?className)\n\n []\n member this.SetStyle'(style: string, value: string) =\n elt?style?(style) <- value\n\n // {{ event\n []\n member this.OnAbort(cb: Microsoft.FSharp.Quotations.Expr Dom.UIEvent -> unit>) = this.onExpr(\"abort\", cb)\n []\n member this.OnAfterPrint(cb: Microsoft.FSharp.Quotations.Expr Dom.Event -> unit>) = this.onExpr(\"afterprint\", cb)\n []\n member this.OnAnimationEnd(cb: Microsoft.FSharp.Quotations.Expr Dom.Event -> unit>) = this.onExpr(\"animationend\", cb)\n []\n member this.OnAnimationIteration(cb: Microsoft.FSharp.Quotations.Expr Dom.Event -> unit>) = this.onExpr(\"animationiteration\", cb)\n []\n member this.OnAnimationStart(cb: Microsoft.FSharp.Quotations.Expr Dom.Event -> unit>) = this.onExpr(\"animationstart\", cb)\n []\n member this.OnAudioProcess(cb: Microsoft.FSharp.Quotations.Expr Dom.Event -> unit>) = this.onExpr(\"audioprocess\", cb)\n []\n member this.OnBeforePrint(cb: Microsoft.FSharp.Quotations.Expr Dom.Event -> unit>) = this.onExpr(\"beforeprint\", cb)\n []\n member this.OnBeforeUnload(cb: Microsoft.FSharp.Quotations.Expr Dom.Event -> unit>) = this.onExpr(\"beforeunload\", cb)\n []\n member this.OnBeginEvent(cb: Microsoft.FSharp.Quotations.Expr Dom.Event -> unit>) = this.onExpr(\"beginEvent\", cb)\n []\n member this.OnBlocked(cb: Microsoft.FSharp.Quotations.Expr Dom.Event -> unit>) = this.onExpr(\"blocked\", cb)\n []\n member this.OnBlur(cb: Microsoft.FSharp.Quotations.Expr Dom.FocusEvent -> unit>) = this.onExpr(\"blur\", cb)\n []\n member this.OnCached(cb: Microsoft.FSharp.Quotations.Expr Dom.Event -> unit>) = this.onExpr(\"cached\", cb)\n []\n member this.OnCanPlay(cb: Microsoft.FSharp.Quotations.Expr Dom.Event -> unit>) = this.onExpr(\"canplay\", cb)\n []\n member this.OnCanPlayThrough(cb: Microsoft.FSharp.Quotations.Expr Dom.Event -> unit>) = this.onExpr(\"canplaythrough\", cb)\n []\n member this.OnChange(cb: Microsoft.FSharp.Quotations.Expr Dom.Event -> unit>) = this.onExpr(\"change\", cb)\n []\n member this.OnChargingChange(cb: Microsoft.FSharp.Quotations.Expr Dom.Event -> unit>) = this.onExpr(\"chargingchange\", cb)\n []\n member this.OnChargingTimeChange(cb: Microsoft.FSharp.Quotations.Expr Dom.Event -> unit>) = this.onExpr(\"chargingtimechange\", cb)\n []\n member this.OnChecking(cb: Microsoft.FSharp.Quotations.Expr Dom.Event -> unit>) = this.onExpr(\"checking\", cb)\n []\n member this.OnClick(cb: Microsoft.FSharp.Quotations.Expr Dom.MouseEvent -> unit>) = this.onExpr(\"click\", cb)\n []\n member this.OnClose(cb: Microsoft.FSharp.Quotations.Expr Dom.Event -> unit>) = this.onExpr(\"close\", cb)\n []\n member this.OnComplete(cb: Microsoft.FSharp.Quotations.Expr Dom.Event -> unit>) = this.onExpr(\"complete\", cb)\n []\n member this.OnCompositionEnd(cb: Microsoft.FSharp.Quotations.Expr Dom.CompositionEvent -> unit>) = this.onExpr(\"compositionend\", cb)\n []\n member this.OnCompositionStart(cb: Microsoft.FSharp.Quotations.Expr Dom.CompositionEvent -> unit>) = this.onExpr(\"compositionstart\", cb)\n []\n member this.OnCompositionUpdate(cb: Microsoft.FSharp.Quotations.Expr Dom.CompositionEvent -> unit>) = this.onExpr(\"compositionupdate\", cb)\n []\n member this.OnContextMenu(cb: Microsoft.FSharp.Quotations.Expr Dom.MouseEvent -> unit>) = this.onExpr(\"contextmenu\", cb)\n []\n member this.OnCopy(cb: Microsoft.FSharp.Quotations.Expr Dom.Event -> unit>) = this.onExpr(\"copy\", cb)\n []\n member this.OnCut(cb: Microsoft.FSharp.Quotations.Expr Dom.Event -> unit>) = this.onExpr(\"cut\", cb)\n []\n member this.OnDblClick(cb: Microsoft.FSharp.Quotations.Expr Dom.MouseEvent -> unit>) = this.onExpr(\"dblclick\", cb)\n []\n member this.OnDeviceLight(cb: Microsoft.FSharp.Quotations.Expr Dom.Event -> unit>) = this.onExpr(\"devicelight\", cb)\n []\n member this.OnDeviceMotion(cb: Microsoft.FSharp.Quotations.Expr Dom.Event -> unit>) = this.onExpr(\"devicemotion\", cb)\n []\n member this.OnDeviceOrientation(cb: Microsoft.FSharp.Quotations.Expr Dom.Event -> unit>) = this.onExpr(\"deviceorientation\", cb)\n []\n member this.OnDeviceProximity(cb: Microsoft.FSharp.Quotations.Expr Dom.Event -> unit>) = this.onExpr(\"deviceproximity\", cb)\n []\n member this.OnDischargingTimeChange(cb: Microsoft.FSharp.Quotations.Expr Dom.Event -> unit>) = this.onExpr(\"dischargingtimechange\", cb)\n []\n member this.OnDOMActivate(cb: Microsoft.FSharp.Quotations.Expr Dom.UIEvent -> unit>) = this.onExpr(\"DOMActivate\", cb)\n []\n member this.OnDOMAttributeNameChanged(cb: Microsoft.FSharp.Quotations.Expr Dom.Event -> unit>) = this.onExpr(\"DOMAttributeNameChanged\", cb)\n []\n member this.OnDOMAttrModified(cb: Microsoft.FSharp.Quotations.Expr Dom.MutationEvent -> unit>) = this.onExpr(\"DOMAttrModified\", cb)\n []\n member this.OnDOMCharacterDataModified(cb: Microsoft.FSharp.Quotations.Expr Dom.MutationEvent -> unit>) = this.onExpr(\"DOMCharacterDataModified\", cb)\n []\n member this.OnDOMContentLoaded(cb: Microsoft.FSharp.Quotations.Expr Dom.Event -> unit>) = this.onExpr(\"DOMContentLoaded\", cb)\n []\n member this.OnDOMElementNameChanged(cb: Microsoft.FSharp.Quotations.Expr Dom.Event -> unit>) = this.onExpr(\"DOMElementNameChanged\", cb)\n []\n member this.OnDOMNodeInserted(cb: Microsoft.FSharp.Quotations.Expr Dom.MutationEvent -> unit>) = this.onExpr(\"DOMNodeInserted\", cb)\n []\n member this.OnDOMNodeInsertedIntoDocument(cb: Microsoft.FSharp.Quotations.Expr Dom.MutationEvent -> unit>) = this.onExpr(\"DOMNodeInsertedIntoDocument\", cb)\n []\n member this.OnDOMNodeRemoved(cb: Microsoft.FSharp.Quotations.Expr Dom.MutationEvent -> unit>) = this.onExpr(\"DOMNodeRemoved\", cb)\n []\n member this.OnDOMNodeRemovedFromDocument(cb: Microsoft.FSharp.Quotations.Expr Dom.MutationEvent -> unit>) = this.onExpr(\"DOMNodeRemovedFromDocument\", cb)\n []\n member this.OnDOMSubtreeModified(cb: Microsoft.FSharp.Quotations.Expr Dom.MutationEvent -> unit>) = this.onExpr(\"DOMSubtreeModified\", cb)\n []\n member this.OnDownloading(cb: Microsoft.FSharp.Quotations.Expr Dom.Event -> unit>) = this.onExpr(\"downloading\", cb)\n []\n member this.OnDrag(cb: Microsoft.FSharp.Quotations.Expr Dom.Event -> unit>) = this.onExpr(\"drag\", cb)\n []\n member this.OnDragEnd(cb: Microsoft.FSharp.Quotations.Expr Dom.Event -> unit>) = this.onExpr(\"dragend\", cb)\n []\n member this.OnDragEnter(cb: Microsoft.FSharp.Quotations.Expr Dom.Event -> unit>) = this.onExpr(\"dragenter\", cb)\n []\n member this.OnDragLeave(cb: Microsoft.FSharp.Quotations.Expr Dom.Event -> unit>) = this.onExpr(\"dragleave\", cb)\n []\n member this.OnDragOver(cb: Microsoft.FSharp.Quotations.Expr Dom.Event -> unit>) = this.onExpr(\"dragover\", cb)\n []\n member this.OnDragStart(cb: Microsoft.FSharp.Quotations.Expr Dom.Event -> unit>) = this.onExpr(\"dragstart\", cb)\n []\n member this.OnDrop(cb: Microsoft.FSharp.Quotations.Expr Dom.Event -> unit>) = this.onExpr(\"drop\", cb)\n []\n member this.OnDurationChange(cb: Microsoft.FSharp.Quotations.Expr Dom.Event -> unit>) = this.onExpr(\"durationchange\", cb)\n []\n member this.OnEmptied(cb: Microsoft.FSharp.Quotations.Expr Dom.Event -> unit>) = this.onExpr(\"emptied\", cb)\n []\n member this.OnEnded(cb: Microsoft.FSharp.Quotations.Expr Dom.Event -> unit>) = this.onExpr(\"ended\", cb)\n []\n member this.OnEndEvent(cb: Microsoft.FSharp.Quotations.Expr Dom.Event -> unit>) = this.onExpr(\"endEvent\", cb)\n []\n member this.OnError(cb: Microsoft.FSharp.Quotations.Expr Dom.Event -> unit>) = this.onExpr(\"error\", cb)\n []\n member this.OnFocus(cb: Microsoft.FSharp.Quotations.Expr Dom.FocusEvent -> unit>) = this.onExpr(\"focus\", cb)\n []\n member this.OnFullScreenChange(cb: Microsoft.FSharp.Quotations.Expr Dom.Event -> unit>) = this.onExpr(\"fullscreenchange\", cb)\n []\n member this.OnFullScreenError(cb: Microsoft.FSharp.Quotations.Expr Dom.Event -> unit>) = this.onExpr(\"fullscreenerror\", cb)\n []\n member this.OnGamepadConnected(cb: Microsoft.FSharp.Quotations.Expr Dom.Event -> unit>) = this.onExpr(\"gamepadconnected\", cb)\n []\n member this.OnGamepadDisconnected(cb: Microsoft.FSharp.Quotations.Expr Dom.Event -> unit>) = this.onExpr(\"gamepaddisconnected\", cb)\n []\n member this.OnHashChange(cb: Microsoft.FSharp.Quotations.Expr Dom.Event -> unit>) = this.onExpr(\"hashchange\", cb)\n []\n member this.OnInput(cb: Microsoft.FSharp.Quotations.Expr Dom.Event -> unit>) = this.onExpr(\"input\", cb)\n []\n member this.OnInvalid(cb: Microsoft.FSharp.Quotations.Expr Dom.Event -> unit>) = this.onExpr(\"invalid\", cb)\n []\n member this.OnKeyDown(cb: Microsoft.FSharp.Quotations.Expr Dom.KeyboardEvent -> unit>) = this.onExpr(\"keydown\", cb)\n []\n member this.OnKeyPress(cb: Microsoft.FSharp.Quotations.Expr Dom.KeyboardEvent -> unit>) = this.onExpr(\"keypress\", cb)\n []\n member this.OnKeyUp(cb: Microsoft.FSharp.Quotations.Expr Dom.KeyboardEvent -> unit>) = this.onExpr(\"keyup\", cb)\n []\n member this.OnLanguageChange(cb: Microsoft.FSharp.Quotations.Expr Dom.Event -> unit>) = this.onExpr(\"languagechange\", cb)\n []\n member this.OnLevelChange(cb: Microsoft.FSharp.Quotations.Expr Dom.Event -> unit>) = this.onExpr(\"levelchange\", cb)\n []\n member this.OnLoad(cb: Microsoft.FSharp.Quotations.Expr Dom.UIEvent -> unit>) = this.onExpr(\"load\", cb)\n []\n member this.OnLoadedData(cb: Microsoft.FSharp.Quotations.Expr Dom.Event -> unit>) = this.onExpr(\"loadeddata\", cb)\n []\n member this.OnLoadedMetadata(cb: Microsoft.FSharp.Quotations.Expr Dom.Event -> unit>) = this.onExpr(\"loadedmetadata\", cb)\n []\n member this.OnLoadEnd(cb: Microsoft.FSharp.Quotations.Expr Dom.Event -> unit>) = this.onExpr(\"loadend\", cb)\n []\n member this.OnLoadStart(cb: Microsoft.FSharp.Quotations.Expr Dom.Event -> unit>) = this.onExpr(\"loadstart\", cb)\n []\n member this.OnMessage(cb: Microsoft.FSharp.Quotations.Expr Dom.Event -> unit>) = this.onExpr(\"message\", cb)\n []\n member this.OnMouseDown(cb: Microsoft.FSharp.Quotations.Expr Dom.MouseEvent -> unit>) = this.onExpr(\"mousedown\", cb)\n []\n member this.OnMouseEnter(cb: Microsoft.FSharp.Quotations.Expr Dom.MouseEvent -> unit>) = this.onExpr(\"mouseenter\", cb)\n []\n member this.OnMouseLeave(cb: Microsoft.FSharp.Quotations.Expr Dom.MouseEvent -> unit>) = this.onExpr(\"mouseleave\", cb)\n []\n member this.OnMouseMove(cb: Microsoft.FSharp.Quotations.Expr Dom.MouseEvent -> unit>) = this.onExpr(\"mousemove\", cb)\n []\n member this.OnMouseOut(cb: Microsoft.FSharp.Quotations.Expr Dom.MouseEvent -> unit>) = this.onExpr(\"mouseout\", cb)\n []\n member this.OnMouseOver(cb: Microsoft.FSharp.Quotations.Expr Dom.MouseEvent -> unit>) = this.onExpr(\"mouseover\", cb)\n []\n member this.OnMouseUp(cb: Microsoft.FSharp.Quotations.Expr Dom.MouseEvent -> unit>) = this.onExpr(\"mouseup\", cb)\n []\n member this.OnNoUpdate(cb: Microsoft.FSharp.Quotations.Expr Dom.Event -> unit>) = this.onExpr(\"noupdate\", cb)\n []\n member this.OnObsolete(cb: Microsoft.FSharp.Quotations.Expr Dom.Event -> unit>) = this.onExpr(\"obsolete\", cb)\n []\n member this.OnOffline(cb: Microsoft.FSharp.Quotations.Expr Dom.Event -> unit>) = this.onExpr(\"offline\", cb)\n []\n member this.OnOnline(cb: Microsoft.FSharp.Quotations.Expr Dom.Event -> unit>) = this.onExpr(\"online\", cb)\n []\n member this.OnOpen(cb: Microsoft.FSharp.Quotations.Expr Dom.Event -> unit>) = this.onExpr(\"open\", cb)\n []\n member this.OnOrientationChange(cb: Microsoft.FSharp.Quotations.Expr Dom.Event -> unit>) = this.onExpr(\"orientationchange\", cb)\n []\n member this.OnPageHide(cb: Microsoft.FSharp.Quotations.Expr Dom.Event -> unit>) = this.onExpr(\"pagehide\", cb)\n []\n member this.OnPageShow(cb: Microsoft.FSharp.Quotations.Expr Dom.Event -> unit>) = this.onExpr(\"pageshow\", cb)\n []\n member this.OnPaste(cb: Microsoft.FSharp.Quotations.Expr Dom.Event -> unit>) = this.onExpr(\"paste\", cb)\n []\n member this.OnPause(cb: Microsoft.FSharp.Quotations.Expr Dom.Event -> unit>) = this.onExpr(\"pause\", cb)\n []\n member this.OnPlay(cb: Microsoft.FSharp.Quotations.Expr Dom.Event -> unit>) = this.onExpr(\"play\", cb)\n []\n member this.OnPlaying(cb: Microsoft.FSharp.Quotations.Expr Dom.Event -> unit>) = this.onExpr(\"playing\", cb)\n []\n member this.OnPointerLockChange(cb: Microsoft.FSharp.Quotations.Expr Dom.Event -> unit>) = this.onExpr(\"pointerlockchange\", cb)\n []\n member this.OnPointerLockError(cb: Microsoft.FSharp.Quotations.Expr Dom.Event -> unit>) = this.onExpr(\"pointerlockerror\", cb)\n []\n member this.OnPopState(cb: Microsoft.FSharp.Quotations.Expr Dom.Event -> unit>) = this.onExpr(\"popstate\", cb)\n []\n member this.OnProgress(cb: Microsoft.FSharp.Quotations.Expr Dom.Event -> unit>) = this.onExpr(\"progress\", cb)\n []\n member this.OnRateChange(cb: Microsoft.FSharp.Quotations.Expr Dom.Event -> unit>) = this.onExpr(\"ratechange\", cb)\n []\n member this.OnReadyStateChange(cb: Microsoft.FSharp.Quotations.Expr Dom.Event -> unit>) = this.onExpr(\"readystatechange\", cb)\n []\n member this.OnRepeatEvent(cb: Microsoft.FSharp.Quotations.Expr Dom.Event -> unit>) = this.onExpr(\"repeatEvent\", cb)\n []\n member this.OnReset(cb: Microsoft.FSharp.Quotations.Expr Dom.Event -> unit>) = this.onExpr(\"reset\", cb)\n []\n member this.OnResize(cb: Microsoft.FSharp.Quotations.Expr Dom.UIEvent -> unit>) = this.onExpr(\"resize\", cb)\n []\n member this.OnScroll(cb: Microsoft.FSharp.Quotations.Expr Dom.UIEvent -> unit>) = this.onExpr(\"scroll\", cb)\n []\n member this.OnSeeked(cb: Microsoft.FSharp.Quotations.Expr Dom.Event -> unit>) = this.onExpr(\"seeked\", cb)\n []\n member this.OnSeeking(cb: Microsoft.FSharp.Quotations.Expr Dom.Event -> unit>) = this.onExpr(\"seeking\", cb)\n []\n member this.OnSelect(cb: Microsoft.FSharp.Quotations.Expr Dom.UIEvent -> unit>) = this.onExpr(\"select\", cb)\n []\n member this.OnShow(cb: Microsoft.FSharp.Quotations.Expr Dom.MouseEvent -> unit>) = this.onExpr(\"show\", cb)\n []\n member this.OnStalled(cb: Microsoft.FSharp.Quotations.Expr Dom.Event -> unit>) = this.onExpr(\"stalled\", cb)\n []\n member this.OnStorage(cb: Microsoft.FSharp.Quotations.Expr Dom.Event -> unit>) = this.onExpr(\"storage\", cb)\n []\n member this.OnSubmit(cb: Microsoft.FSharp.Quotations.Expr Dom.Event -> unit>) = this.onExpr(\"submit\", cb)\n []\n member this.OnSuccess(cb: Microsoft.FSharp.Quotations.Expr Dom.Event -> unit>) = this.onExpr(\"success\", cb)\n []\n member this.OnSuspend(cb: Microsoft.FSharp.Quotations.Expr Dom.Event -> unit>) = this.onExpr(\"suspend\", cb)\n []\n member this.OnSVGAbort(cb: Microsoft.FSharp.Quotations.Expr Dom.Event -> unit>) = this.onExpr(\"SVGAbort\", cb)\n []\n member this.OnSVGError(cb: Microsoft.FSharp.Quotations.Expr Dom.Event -> unit>) = this.onExpr(\"SVGError\", cb)\n []\n member this.OnSVGLoad(cb: Microsoft.FSharp.Quotations.Expr Dom.Event -> unit>) = this.onExpr(\"SVGLoad\", cb)\n []\n member this.OnSVGResize(cb: Microsoft.FSharp.Quotations.Expr Dom.Event -> unit>) = this.onExpr(\"SVGResize\", cb)\n []\n member this.OnSVGScroll(cb: Microsoft.FSharp.Quotations.Expr Dom.Event -> unit>) = this.onExpr(\"SVGScroll\", cb)\n []\n member this.OnSVGUnload(cb: Microsoft.FSharp.Quotations.Expr Dom.Event -> unit>) = this.onExpr(\"SVGUnload\", cb)\n []\n member this.OnSVGZoom(cb: Microsoft.FSharp.Quotations.Expr Dom.Event -> unit>) = this.onExpr(\"SVGZoom\", cb)\n []\n member this.OnTimeOut(cb: Microsoft.FSharp.Quotations.Expr Dom.Event -> unit>) = this.onExpr(\"timeout\", cb)\n []\n member this.OnTimeUpdate(cb: Microsoft.FSharp.Quotations.Expr Dom.Event -> unit>) = this.onExpr(\"timeupdate\", cb)\n []\n member this.OnTouchCancel(cb: Microsoft.FSharp.Quotations.Expr Dom.Event -> unit>) = this.onExpr(\"touchcancel\", cb)\n []\n member this.OnTouchEnd(cb: Microsoft.FSharp.Quotations.Expr Dom.Event -> unit>) = this.onExpr(\"touchend\", cb)\n []\n member this.OnTouchEnter(cb: Microsoft.FSharp.Quotations.Expr Dom.Event -> unit>) = this.onExpr(\"touchenter\", cb)\n []\n member this.OnTouchLeave(cb: Microsoft.FSharp.Quotations.Expr Dom.Event -> unit>) = this.onExpr(\"touchleave\", cb)\n []\n member this.OnTouchMove(cb: Microsoft.FSharp.Quotations.Expr Dom.Event -> unit>) = this.onExpr(\"touchmove\", cb)\n []\n member this.OnTouchStart(cb: Microsoft.FSharp.Quotations.Expr Dom.Event -> unit>) = this.onExpr(\"touchstart\", cb)\n []\n member this.OnTransitionEnd(cb: Microsoft.FSharp.Quotations.Expr Dom.Event -> unit>) = this.onExpr(\"transitionend\", cb)\n []\n member this.OnUnload(cb: Microsoft.FSharp.Quotations.Expr Dom.UIEvent -> unit>) = this.onExpr(\"unload\", cb)\n []\n member this.OnUpdateReady(cb: Microsoft.FSharp.Quotations.Expr Dom.Event -> unit>) = this.onExpr(\"updateready\", cb)\n []\n member this.OnUpgradeNeeded(cb: Microsoft.FSharp.Quotations.Expr Dom.Event -> unit>) = this.onExpr(\"upgradeneeded\", cb)\n []\n member this.OnUserProximity(cb: Microsoft.FSharp.Quotations.Expr Dom.Event -> unit>) = this.onExpr(\"userproximity\", cb)\n []\n member this.OnVersionChange(cb: Microsoft.FSharp.Quotations.Expr Dom.Event -> unit>) = this.onExpr(\"versionchange\", cb)\n []\n member this.OnVisibilityChange(cb: Microsoft.FSharp.Quotations.Expr Dom.Event -> unit>) = this.onExpr(\"visibilitychange\", cb)\n []\n member this.OnVolumeChange(cb: Microsoft.FSharp.Quotations.Expr Dom.Event -> unit>) = this.onExpr(\"volumechange\", cb)\n []\n member this.OnWaiting(cb: Microsoft.FSharp.Quotations.Expr Dom.Event -> unit>) = this.onExpr(\"waiting\", cb)\n []\n member this.OnWheel(cb: Microsoft.FSharp.Quotations.Expr Dom.WheelEvent -> unit>) = this.onExpr(\"wheel\", cb)\n // }}\n\nand [)>] \n internal EltUpdater'(treeNode : DocTreeNode, updates, elt, rvUpdates: Updates, holeUpdates: Var<(int * View)[]>) =\n inherit Elt'(\n TreeDoc treeNode, \n View.Map2Unit updates (holeUpdates.View |> View.BindInner (Array.map snd >> Array.TreeReduce (View.Const ()) View.Map2Unit)),\n elt, rvUpdates)\n\n let mutable origHoles = treeNode.Holes\n\n override this.AddHole h =\n origHoles.JS.Push h |> ignore\n treeNode.Holes <- Array.append treeNode.Holes [| h |]\n\n override this.ClearHoles() =\n origHoles <- [||]\n treeNode.Holes <- [||]\n holeUpdates.Value <- [||]\n\n member this.AddUpdated(doc: Elt') =\n match doc.DocNode with\n | ElemDoc e ->\n treeNode.Holes <- Array.append treeNode.Holes [| e |]\n let hu = holeUpdates.Value\n hu.JS.Push ((e.ElKey, doc.Updates)) |> ignore\n holeUpdates.Value <- hu\n | _ -> failwith \"DocUpdater.AddUpdated expects a single element node\"\n\n member this.RemoveUpdated(doc: Elt') =\n match doc.DocNode with\n | ElemDoc e ->\n let k = e.ElKey\n treeNode.Holes <-\n treeNode.Holes |> Array.filter (fun h -> h.ElKey <> k)\n holeUpdates.Value <-\n holeUpdates.Value |> Array.filter (function\n | uk, _ when uk = k -> false\n | _ -> true\n ) \n | _ -> failwith \"DocUpdater.RemoveUpdated expects a single element node\"\n\n member this.RemoveAllUpdated() =\n treeNode.Holes <- origHoles\n holeUpdates.Value <- [||]\n", "// $begin{copyright}\n//\n// This file is part of WebSharper\n//\n// Copyright (c) 2008-2018 IntelliFactory\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\"); you\n// may not use this file except in compliance with the License. You may\n// obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n// implied. See the License for the specific language governing\n// permissions and limitations under the License.\n//\n// $end{copyright}\nnamespace WebSharper.UI.Client\n\nopen System\nopen System.Collections.Generic\nopen WebSharper\nopen WebSharper.JavaScript\nopen WebSharper.UI\n\n[]\nmodule internal Templates =\n\n let LoadedTemplates = Dictionary>()\n let LoadedTemplateFile name =\n match LoadedTemplates.TryGetValue name with\n | true, d -> d\n | false, _ ->\n let d = Dictionary()\n LoadedTemplates[name] <- d\n d\n let mutable LocalTemplatesLoaded = false\n\n let mutable GlobalHoles = Dictionary()\n\n let TextHoleRE = \"\"\"\\${([^}]+)}\"\"\"\n\n /// Run `f` on all descendants of `root` that match `selector`\n /// and aren't descendants of an element with a ws-preserve attribute\n /// nor have a ws-preserve attribute themselves.\n [)>]\n let foreachNotPreserved (root: Dom.Element) (selector: string) (f: Dom.Element -> unit) =\n DomUtility.IterSelector root selector <| fun p ->\n if isNull (p.Closest(\"[ws-preserve]\")) then\n f p\n\n [)>]\n let foreachNotPreservedwsDOM (selector: string) (f: Dom.Element -> unit) =\n DomUtility.IterSelectorDoc selector <| fun p ->\n if isNull (p.Closest(\"[ws-preserve]\")) then\n f p\n\n let InlineTemplate (el: Dom.Element) (fillWith: seq) =\n let holes : DocElemNode[] = [||]\n let updates : View[] = [||]\n let attrs : (Dom.Element * Attrs.Dyn)[] = [||]\n let afterRender : (Dom.Element -> unit)[] = [||]\n let fw = Dictionary()\n for x in fillWith do fw[x.Name] <- x\n let els = As[]> (DomUtility.ChildrenArray el)\n let addAttr (el: Dom.Element) (attr: Attr) =\n let attr = Attrs.Insert el attr\n updates.JS.Push (Attrs.Updates attr) |> ignore\n attrs.JS.Push ((el, attr)) |> ignore\n match Attrs.GetOnAfterRender attr with\n | Some f -> afterRender.JS.Push(fun _ -> f el) |> ignore\n | None -> ()\n let tryGetAsDoc name =\n match fw.TryGetValue(name) with\n | true, th ->\n match th with\n | :? TemplateHole.Elt as th ->\n Some (As th.Value)\n | :? TemplateHole.Text as th ->\n Some (Doc'.TextNode th.Value)\n | _ ->\n th.ForTextView () |> Option.map (Doc'.TextView)\n | false, _ -> None\n\n foreachNotPreserved el \"[ws-hole]\" <| fun p ->\n let name = p.GetAttribute(\"ws-hole\")\n p.RemoveAttribute(\"ws-hole\")\n while (p.HasChildNodes()) do\n p.RemoveChild(p.LastChild) |> ignore\n match tryGetAsDoc name with\n | None -> ()\n | Some doc ->\n Docs.LinkElement p doc.DocNode\n holes.JS.Push {\n Attr = Attrs.Empty p\n Children = doc.DocNode\n Delimiters = None\n El = p\n ElKey = Fresh.Int()\n Render = None\n }\n |> ignore\n updates.JS.Push doc.Updates |> ignore\n\n foreachNotPreserved el \"[ws-replace]\" <| fun e ->\n let name = e.GetAttribute(\"ws-replace\")\n match tryGetAsDoc name with\n | None -> ()\n | Some doc ->\n let p = e.ParentNode :?> Dom.Element\n let after = JS.Document.CreateTextNode(\"\") :> Dom.Node\n p.ReplaceChild(after, e) |> ignore\n let before = Docs.InsertBeforeDelim after doc.DocNode\n els\n |> Array.tryFindIndex ((===.) e)\n |> Option.iter (fun i -> els[i] <- Union2Of2 doc.DocNode)\n holes.JS.Push {\n Attr = Attrs.Empty p\n Children = doc.DocNode\n Delimiters = Some (before, after)\n El = p\n ElKey = Fresh.Int()\n Render = None\n }\n |> ignore\n updates.JS.Push doc.Updates |> ignore\n\n // Initializing slot elements on template instantiation\n let mutable isDefaultSlotProcessed = false\n foreachNotPreserved el \"slot\" <| fun p ->\n let name = p.GetAttribute(\"name\")\n let name = if name = \"\" || name = null then \"default\" else name.ToLower()\n if isDefaultSlotProcessed && name = \"default\" || el.ParentElement <> null then\n ()\n else\n while (p.HasChildNodes()) do\n p.RemoveChild(p.LastChild) |> ignore\n if name = \"default\" then isDefaultSlotProcessed <- true\n match tryGetAsDoc name with\n | None -> ()\n | Some doc ->\n Docs.LinkElement p doc.DocNode\n holes.JS.Push {\n Attr = Attrs.Empty p\n Children = doc.DocNode\n Delimiters = None\n El = p\n ElKey = Fresh.Int()\n Render = None\n }\n |> ignore\n updates.JS.Push doc.Updates |> ignore\n\n foreachNotPreserved el \"[ws-attr]\" <| fun e ->\n let name = e.GetAttribute(\"ws-attr\")\n e.RemoveAttribute(\"ws-attr\")\n match fw.TryGetValue(name) with\n | true, th ->\n match th with\n | :? TemplateHole.Attribute as th ->\n addAttr e th.Value\n | _ -> Console.Warn(\"Attribute hole filled with non-attribute data\", name)\n | false, _ -> ()\n\n foreachNotPreserved el \"[ws-on]\" <| fun e ->\n e.GetAttribute(\"ws-on\").Split([|' '|], StringSplitOptions.RemoveEmptyEntries)\n |> Array.choose (fun x ->\n let a = x.Split([|':'|], StringSplitOptions.RemoveEmptyEntries)\n match fw.TryGetValue(a[1]) with\n | true, th ->\n match th with\n | :? TemplateHole.Event as th -> Some (Attr.Handler a[0] th.Value)\n | :? TemplateHole.EventQ as th -> Some (A.Handler a[0] th.Value)\n | _ ->\n Console.Warn(\"Event hole on\" + a[0] + \" filled with non-event data\", a[1])\n None\n | false, _ -> None\n )\n |> Attr.Concat\n |> addAttr e\n e.RemoveAttribute(\"ws-on\")\n\n foreachNotPreserved el \"[ws-onafterrender]\" <| fun e ->\n let name = e.GetAttribute(\"ws-onafterrender\")\n match fw.TryGetValue(name) with\n | true, th ->\n match th with\n | :? TemplateHole.AfterRender as th ->\n e.RemoveAttribute(\"ws-onafterrender\")\n addAttr e (Attr.OnAfterRender th.Value)\n | :? TemplateHole.AfterRenderQ as th ->\n e.RemoveAttribute(\"ws-onafterrender\")\n addAttr e (Attr.OnAfterRender (As th.Value))\n | _ -> Console.Warn(\"onafterrender hole filled with non-onafterrender data\", name)\n | false, _ -> ()\n\n foreachNotPreserved el \"[ws-var]\" <| fun e ->\n let name = e.GetAttribute(\"ws-var\")\n e.RemoveAttribute(\"ws-var\")\n match fw.TryGetValue(name) with\n | true, th ->\n th.AddAttribute(addAttr, e)\n | false, _ -> ()\n\n let wsdomHandling () =\n foreachNotPreservedwsDOM \"[ws-dom]\" <| fun e ->\n let name = e.GetAttribute(\"ws-dom\")\n match fw.TryGetValue(name.ToLower()) with\n | true, th ->\n match th with\n | :? TemplateHole.VarDomElement as th ->\n let var = th.Value\n e.RemoveAttribute(\"ws-dom\")\n let mutable toWatch = e\n let mo =\n JavaScript.Dom.MutationObserver(\n (fun (mrs, mo) ->\n mrs\n |> Array.iter (fun mr ->\n mr.RemovedNodes.ForEach((fun (x, _, _, _) ->\n if x ===. toWatch && mr.AddedNodes.Length <> 1 then\n var.SetFinal None\n mo.Disconnect()\n ), null)\n )\n )\n )\n if e.ParentElement !==. null then\n mo.Observe(e.ParentElement, Dom.MutationObserverInit(ChildList = true))\n var.Set (Some e)\n var.View\n |> View.Sink (fun nel ->\n match nel with\n | None ->\n toWatch.Remove()\n mo.Disconnect()\n | Some nel ->\n if toWatch ===. nel then\n ()\n else\n toWatch.ReplaceWith nel\n toWatch <- nel\n )\n | _ -> ()\n | _ -> ()\n\n foreachNotPreserved el \"[ws-attr-holes]\" <| fun e ->\n let re = new RegExp(TextHoleRE, \"g\")\n let holeAttrs = e.GetAttribute(\"ws-attr-holes\").Split([|' '|], StringSplitOptions.RemoveEmptyEntries)\n e.RemoveAttribute(\"ws-attr-holes\")\n for attrName in holeAttrs do\n let s = e.GetAttribute(attrName)\n let mutable m = null\n let mutable lastIndex = 0\n let res : (string * string)[] = [||]\n while (m <- re.Exec s; m !==. null) do\n let textBefore = s[lastIndex .. re.LastIndex-m[0].Length-1]\n lastIndex <- re.LastIndex\n let holeName = m[1]\n res.JS.Push((textBefore, holeName)) |> ignore\n let finalText = s[lastIndex..]\n re.LastIndex <- 0\n let value =\n Array.foldBack (fun (textBefore, holeName: string) (textAfter, views) ->\n let holeContent =\n match fw.TryGetValue(holeName) with\n | true, th ->\n th.AsChoiceView\n | false, _ -> Choice1Of2 \"\"\n match holeContent with\n | Choice1Of2 text -> textBefore + text + textAfter, views\n | Choice2Of2 v ->\n let v =\n if textAfter = \"\" then v else\n View.Map (fun s -> s + textAfter) v\n textBefore, v :: views\n ) res (finalText, [])\n match value with\n | s, [] -> Attr.Create attrName s\n | \"\", [v] -> Attr.Dynamic attrName v\n | s, [v] -> Attr.Dynamic attrName (View.Map (fun v -> s + v) v)\n | s, [v1; v2] -> Attr.Dynamic attrName (View.Map2 (fun v1 v2 -> s + v1 + v2) v1 v2)\n | s, [v1; v2; v3] -> Attr.Dynamic attrName (View.Map3 (fun v1 v2 v3 -> s + v1 + v2 + v3) v1 v2 v3)\n | s, vs ->\n View.Sequence vs\n |> View.Map (fun vs -> s + String.concat \"\" vs)\n |> Attr.Dynamic attrName\n |> addAttr e\n\n let docTreeNode : DocTreeNode =\n {\n Els = els\n Holes = holes\n Attrs = attrs\n Render =\n if Array.isEmpty afterRender\n then Some (fun el ->\n wsdomHandling ()\n )\n else Some (fun el -> wsdomHandling (); Array.iter (fun f -> f el) afterRender)\n Dirty = true\n El =\n match els with\n | [| Union1Of2 (:? Dom.Element as el) |] -> Some el\n | _ -> None\n }\n let updates =\n updates |> Array.TreeReduce (View.Const ()) View.Map2Unit\n docTreeNode, updates\n\n let ChildrenTemplate (el: Dom.Element) (fillWith: seq) =\n let fillWith = Seq.append fillWith GlobalHoles.Values\n let docTreeNode, updates = InlineTemplate el fillWith\n match docTreeNode.Els with\n | [| Union1Of2 e |] when e.NodeType = Dom.NodeType.Element ->\n Elt'.TreeNode(docTreeNode, updates) :> Doc'\n | _ ->\n Doc'.Mk (TreeDoc docTreeNode) updates\n\n let FakeRoot (parent: Dom.Element) =\n let fakeroot = JS.Document.CreateElement(\"div\")\n while parent.HasChildNodes() do fakeroot.AppendChild parent.FirstChild |> ignore\n fakeroot\n\n let FakeRootFromHTMLTemplate (parent: HTMLTemplateElement) =\n let fakeroot = JS.Document.CreateElement(\"div\")\n let content = parent.Content\n for i in 0..content.ChildNodes.Length-1 do\n fakeroot.AppendChild (content.ChildNodes.Item(i).CloneNode(true)) |> ignore\n fakeroot\n\n let FakeRootSingle (el: Dom.Element) =\n el.RemoveAttribute(\"ws-template\")\n match el.GetAttribute(\"ws-replace\") with\n | null -> ()\n | replace ->\n el.RemoveAttribute(\"ws-replace\")\n match el.ParentNode with\n | null -> ()\n | p ->\n let n = JS.Document.CreateElement(el.TagName)\n n.SetAttribute(\"ws-replace\", replace)\n p.ReplaceChild(n, el) |> ignore\n let fakeroot = JS.Document.CreateElement(\"div\")\n fakeroot.AppendChild(el) |> ignore\n fakeroot\n\n module private Prepare =\n\n let convertAttrs (el: Dom.Element) =\n let attrs = el.Attributes\n let toRemove = [||]\n let events = [||]\n let holedAttrs = [||]\n for i = 0 to attrs.Length - 1 do\n let a = attrs[i]\n if a.NodeName.StartsWith \"ws-on\" && a.NodeName <> \"ws-onafterrender\" && a.NodeName <> \"ws-on\" then\n toRemove.JS.Push(a.NodeName) |> ignore\n events.JS.Push(a.NodeName[\"ws-on\".Length..] + \":\" + a.NodeValue.ToLower()) |> ignore\n elif not (a.NodeName.StartsWith \"ws-\") && RegExp(TextHoleRE).Test(a.NodeValue) then\n a.NodeValue <-\n RegExp(TextHoleRE, \"g\")\n .Replace(a.NodeValue, FuncWithArgs (fun (_, h: string) ->\n \"${\" + h.ToLower() + \"}\"))\n holedAttrs.JS.Push(a.NodeName) |> ignore\n if not (Array.isEmpty events) then\n el.SetAttribute(\"ws-on\", String.concat \" \" events)\n if not (Array.isEmpty holedAttrs) then\n el.SetAttribute(\"ws-attr-holes\", String.concat \" \" holedAttrs)\n let lowercaseAttr name =\n match el.GetAttribute(name) with\n | null -> ()\n | x -> el.SetAttribute(name, x.ToLower())\n lowercaseAttr \"ws-hole\"\n lowercaseAttr \"ws-replace\"\n lowercaseAttr \"ws-attr\"\n lowercaseAttr \"ws-onafterrender\"\n lowercaseAttr \"ws-var\"\n Array.iter (fun a -> el.RemoveAttribute a) toRemove\n\n let convertTextNode (n: Dom.Node) =\n let mutable m = null\n let mutable li = 0\n let s = n.TextContent\n let strRE = RegExp(TextHoleRE, \"g\")\n while (m <- strRE.Exec s; m !==. null) do\n n.ParentNode.InsertBefore(JS.Document.CreateTextNode(s[li..strRE.LastIndex-m[0].Length-1]), n) |> ignore\n li <- strRE.LastIndex\n let hole = JS.Document.CreateElement(\"span\")\n hole.SetAttribute(\"ws-replace\", m[1].ToLower())\n n.ParentNode.InsertBefore(hole, n) |> ignore\n strRE.LastIndex <- 0\n n.TextContent <- s[li..]\n\n let mapHoles (t: Dom.Element) (mappings: Dictionary) =\n let run attrName =\n foreachNotPreserved t (\"[\" + attrName + \"]\") <| fun e ->\n match mappings.TryGetValue(e.GetAttribute(attrName).ToLower()) with\n | true, m -> e.SetAttribute(attrName, m)\n | false, _ -> ()\n run \"ws-hole\"\n run \"ws-replace\"\n run \"ws-attr\"\n run \"ws-onafterrender\"\n run \"ws-var\"\n foreachNotPreserved t \"[ws-on]\" <| fun e ->\n let a =\n e.GetAttribute(\"ws-on\").Split([|' '|], StringSplitOptions.RemoveEmptyEntries)\n |> Array.map (fun x ->\n let a = x.Split([|':'|], StringSplitOptions.RemoveEmptyEntries)\n match mappings.TryGetValue(a[1]) with\n | true, x -> a[0] + \":\" + x\n | false, _ -> x\n )\n |> String.concat \" \"\n e.SetAttribute(\"ws-on\", a)\n foreachNotPreserved t \"[ws-attr-holes]\" <| fun e ->\n let holeAttrs = e.GetAttribute(\"ws-attr-holes\").Split([|' '|], StringSplitOptions.RemoveEmptyEntries)\n for attrName in holeAttrs do\n let s =\n (e.GetAttribute(attrName), mappings)\n ||> Seq.fold (fun s (KeyValue(a, m)) ->\n RegExp(\"\\\\${\" + a + \"}\", \"ig\").Replace(s, \"${\" + m + \"}\")\n )\n e.SetAttribute(attrName, s)\n\n let fillInstanceAttrs (instance: Dom.Element) (fillWith: Dom.Element) =\n convertAttrs fillWith\n let name = fillWith.NodeName.ToLower()\n match instance.QuerySelector(\"[ws-attr=\" + name + \"]\") with\n | null -> Console.Warn(\"Filling non-existent attr hole\", name)\n | e ->\n e.RemoveAttribute(\"ws-attr\")\n for i = 0 to fillWith.Attributes.Length - 1 do\n let a = fillWith.Attributes[i]\n if a.Name = \"class\" && e.HasAttribute(\"class\") then\n e.SetAttribute(\"class\", e.GetAttribute(\"class\") + \" \" + a.NodeValue)\n else\n e.SetAttribute(a.Name, a.NodeValue)\n\n let removeHolesExcept (instance: Dom.Element) (dontRemove: HashSet) =\n let run attrName =\n foreachNotPreserved instance (\"[\" + attrName + \"]\") <| fun e ->\n if not (dontRemove.Contains(e.GetAttribute attrName)) then\n e.RemoveAttribute(attrName)\n run \"ws-attr\"\n run \"ws-onafterrender\"\n run \"ws-var\"\n foreachNotPreserved instance \"[ws-hole]\" <| fun e ->\n if not (dontRemove.Contains(e.GetAttribute \"ws-hole\")) then\n e.RemoveAttribute(\"ws-hole\")\n while e.HasChildNodes() do\n e.RemoveChild(e.LastChild) |> ignore\n foreachNotPreserved instance \"[ws-replace]\" <| fun e ->\n if not (dontRemove.Contains(e.GetAttribute \"ws-replace\")) then\n e.ParentNode.RemoveChild(e) |> ignore\n foreachNotPreserved instance \"[ws-on]\" <| fun e ->\n let a =\n e.GetAttribute(\"ws-on\").Split([|' '|], StringSplitOptions.RemoveEmptyEntries)\n |> Array.filter (fun x ->\n let a = x.Split([|':'|], StringSplitOptions.RemoveEmptyEntries)\n dontRemove.Contains a[1]\n )\n |> String.concat \" \"\n e.SetAttribute(\"ws-on\", a)\n foreachNotPreserved instance \"[ws-attr-holes]\" <| fun e ->\n let holeAttrs = e.GetAttribute(\"ws-attr-holes\").Split([|' '|], StringSplitOptions.RemoveEmptyEntries)\n for attrName in holeAttrs do\n let s =\n RegExp(TextHoleRE, \"g\")\n .Replace(e.GetAttribute(attrName), FuncWithArgs(fun (full: string, h: string) ->\n if dontRemove.Contains h then full else \"\"\n ))\n e.SetAttribute(attrName, s)\n\n let fillTextHole (instance: Dom.Element) (fillWith: string) (templateName: string) =\n match instance.QuerySelector \"[ws-replace]\" with\n | null ->\n Console.Warn(\"Filling non-existent text hole\", templateName)\n None\n | n ->\n n.ParentNode.ReplaceChild(JS.Document.CreateTextNode fillWith, n) |> ignore\n Some <| n.GetAttribute(\"ws-replace\")\n\n let rec fill (fillWith: Dom.Element) (p: Dom.Node) n =\n if fillWith.HasChildNodes() then\n fill fillWith p (p.InsertBefore(fillWith.LastChild, n))\n\n let failNotLoaded (name: string) =\n Console.Warn(\"Instantiating non-loaded template\", name)\n\n let rec PrepareTemplateStrict (baseName: string) (name: option) (fakeroot: Dom.Element) (prepareLocalTemplate: option unit>) =\n let processedHTML5Templates = HashSet()\n let rec fillDocHole (instance: Dom.Element) (fillWith: Dom.Element) =\n let name = fillWith.NodeName.ToLower()\n let fillHole (p: Dom.Node) (n: Dom.Node) =\n // The \"title\" node is treated specially by HTML, its content is considered pure text,\n // so we need to re-parse it.\n if name = \"title\" && fillWith.HasChildNodes() then\n let parsed = DomUtility.ParseHTMLIntoFakeRoot fillWith.TextContent\n fillWith.RemoveChild(fillWith.FirstChild) |> ignore\n while parsed.HasChildNodes() do\n fillWith.AppendChild(parsed.FirstChild) |> ignore\n convertElement fillWith\n Prepare.fill fillWith p n\n foreachNotPreserved instance \"[ws-attr-holes]\" <| fun e ->\n let holeAttrs = e.GetAttribute(\"ws-attr-holes\").Split([|' '|], StringSplitOptions.RemoveEmptyEntries)\n for attrName in holeAttrs do\n e.SetAttribute(attrName,\n RegExp(\"\\\\${\" + name + \"}\", \"ig\").\n Replace(e.GetAttribute(attrName), fillWith.TextContent)\n )\n match instance.QuerySelector(\"[ws-hole=\" + name + \"]\") with\n | null ->\n match instance.QuerySelector(\"[ws-replace=\" + name + \"]\") with\n | null ->\n match instance.QuerySelector(\"slot[name=\" + name + \"]\") with\n | e when instance.TagName.ToLower() = \"template\" ->\n fillHole e.ParentNode e\n e.ParentNode.RemoveChild(e) |> ignore\n | _ -> ()\n | e ->\n fillHole e.ParentNode e\n e.ParentNode.RemoveChild(e) |> ignore\n | e ->\n while e.HasChildNodes() do\n e.RemoveChild(e.LastChild) |> ignore\n e.RemoveAttribute(\"ws-hole\")\n fillHole e null\n\n and convertElement (el: Dom.Element) =\n if not (el.HasAttribute \"ws-preserve\") then\n if el.NodeName.ToLower().StartsWith \"ws-\" then\n convertInstantiation el\n else\n Prepare.convertAttrs el\n convertNodeAndSiblings el.FirstChild\n\n and convertNodeAndSiblings (n: Dom.Node) =\n if n !==. null then\n let next = n.NextSibling\n if n.NodeType = Dom.NodeType.Text then\n Prepare.convertTextNode n\n elif n.NodeType = Dom.NodeType.Element then\n convertElement (n :?> Dom.Element)\n convertNodeAndSiblings next\n\n and convertInstantiation (el: Dom.Element) =\n let name = el.NodeName[3..].ToLower()\n let instBaseName, instName =\n match name.IndexOf('.') with\n | -1 -> baseName, name\n | n -> name[..n-1], name[n+1..]\n if instBaseName <> \"\" && not (LoadedTemplates.ContainsKey instBaseName) then\n Prepare.failNotLoaded instName\n else\n if instBaseName = \"\" && prepareLocalTemplate.IsSome then\n prepareLocalTemplate.Value instName\n let d = LoadedTemplates[instBaseName]\n if not (d.ContainsKey instName) then Prepare.failNotLoaded instName else\n let t = d[instName]\n let instance = t.CloneNode(true) :?> Dom.Element\n let usedHoles = HashSet()\n let mappings = Dictionary()\n // 1. gather mapped and filled holes.\n let attrs = el.Attributes\n for i = 0 to attrs.Length - 1 do\n let name = attrs[i].Name.ToLower()\n let mappedName = match attrs[i].NodeValue with \"\" -> name | s -> s.ToLower()\n mappings[name] <- mappedName\n if not (usedHoles.Add(name)) then\n Console.Warn(\"Hole mapped twice\", name)\n for i = 0 to el.ChildNodes.Length - 1 do\n let n = el.ChildNodes[i]\n if n.NodeType = Dom.NodeType.Element then\n let n = n :?> Dom.Element\n if not (usedHoles.Add(n.NodeName.ToLower())) then\n Console.Warn(\"Hole filled twice\", instName)\n // 2. If single text hole, apply it.\n let singleTextFill = el.ChildNodes.Length = 1 && el.FirstChild.NodeType = Dom.NodeType.Text\n if singleTextFill then\n Prepare.fillTextHole instance el.FirstChild.TextContent instName\n |> Option.iter (usedHoles.Add >> ignore)\n // 3. eliminate non-mapped/filled holes.\n Prepare.removeHolesExcept instance usedHoles\n // 4. apply mappings/fillings.\n if not singleTextFill then\n for i = 0 to el.ChildNodes.Length - 1 do\n let n = el.ChildNodes[i]\n if n.NodeType = Dom.NodeType.Element then\n let n = n :?> Dom.Element\n if n.HasAttributes() then\n Prepare.fillInstanceAttrs instance n\n else\n fillDocHole instance n\n Prepare.mapHoles instance mappings\n // 5. insert result.\n Prepare.fill instance el.ParentNode el\n el.ParentNode.RemoveChild(el) |> ignore\n\n let rec convertNestedTemplates (el: Dom.Element) =\n match el.QuerySelector \"[ws-template]\" with\n | null ->\n match el.QuerySelector \"[ws-children-template]\" with\n | null ->\n let idTemplates = el.QuerySelectorAll \"template[id]\"\n for i in 1..idTemplates.Length-1 do\n let n = idTemplates.[i] :?> Dom.Element\n if processedHTML5Templates.Contains(n) then\n ()\n else\n let name = n.GetAttribute \"id\"\n PrepareTemplateStrict baseName (Some name) n None\n processedHTML5Templates.Add n |> ignore\n let nameTemplates = el.QuerySelectorAll \"template[name]\"\n for i in 1..nameTemplates.Length-1 do\n let n = nameTemplates.[i] :?> Dom.Element\n if processedHTML5Templates.Contains(n) then\n ()\n else\n let name = n.GetAttribute \"name\"\n PrepareTemplateStrict baseName (Some name) n None\n processedHTML5Templates.Add n |> ignore\n ()\n | n ->\n let name = n.GetAttribute \"ws-children-template\"\n n.RemoveAttribute \"ws-children-template\"\n PrepareTemplateStrict baseName (Some name) n None\n convertNestedTemplates el\n | n ->\n let name = n.GetAttribute \"ws-template\"\n PrepareSingleTemplate baseName (Some name) n None\n convertNestedTemplates el\n\n let name = (defaultArg name \"\").ToLower()\n LoadedTemplateFile(baseName)[name] <- fakeroot\n if fakeroot.HasChildNodes() then\n convertNestedTemplates fakeroot\n convertNodeAndSiblings fakeroot.FirstChild\n\n and PrepareSingleTemplate (baseName: string) (name: option) (el: Dom.Element) =\n let root = FakeRootSingle el\n PrepareTemplateStrict baseName name root\n\n let PrepareTemplate (baseName: string) (name: option) (fakeroot: unit -> Dom.Element) =\n if not (LoadedTemplateFile(baseName).ContainsKey(defaultArg name \"\")) then\n PrepareTemplateStrict baseName name (fakeroot()) None\n\n /// Load all the templates declared nested under `root` into `baseName`.\n let LoadNestedTemplates (root: Dom.Element) baseName =\n let loadedTpls = LoadedTemplateFile baseName\n let rawTpls = Dictionary()\n let wsTemplates = root.QuerySelectorAll \"[ws-template]\"\n for i = 0 to wsTemplates.Length - 1 do\n let node = wsTemplates[i] :?> Dom.Element\n let name = node.GetAttribute(\"ws-template\").ToLower()\n node.RemoveAttribute(\"ws-template\")\n rawTpls[name] <- FakeRootSingle node\n let wsChildrenTemplates = root.QuerySelectorAll \"[ws-children-template]\"\n for i = 0 to wsChildrenTemplates.Length - 1 do\n let node = wsChildrenTemplates[i] :?> Dom.Element\n let name = node.GetAttribute(\"ws-children-template\").ToLower()\n node.RemoveAttribute(\"ws-children-template\")\n rawTpls[name] <- FakeRoot node\n let html5TemplateBasedTemplates = root.QuerySelectorAll \"template[id]\"\n for i = 0 to html5TemplateBasedTemplates.Length - 1 do\n let node = html5TemplateBasedTemplates[i] :?> HTMLTemplateElement\n let name = node.GetAttribute(\"id\").ToLower()\n rawTpls[name] <- FakeRootFromHTMLTemplate node\n let html5TemplateBasedTemplates = root.QuerySelectorAll \"template[name]\"\n for i = 0 to html5TemplateBasedTemplates.Length - 1 do\n let node = html5TemplateBasedTemplates[i] :?> HTMLTemplateElement\n let name = node.GetAttribute(\"name\").ToLower()\n rawTpls[name] <- FakeRootFromHTMLTemplate node\n let instantiated = HashSet()\n let rec prepareTemplate name =\n if not (loadedTpls.ContainsKey name) then\n match rawTpls.TryGetValue(name) with\n | false, _ ->\n Console.Warn(\n if instantiated.Contains(name)\n then \"Encountered loop when instantiating \" + name\n else \"Local template does not exist: \" + name)\n | true, root ->\n instantiated.Add(name) |> ignore\n rawTpls.Remove(name) |> ignore\n PrepareTemplateStrict baseName (Some name) root (Some prepareTemplate)\n while rawTpls.Count > 0 do\n prepareTemplate (Seq.head rawTpls.Keys)\n\n let LoadLocalTemplates (baseName: string) =\n if not LocalTemplatesLoaded then\n LocalTemplatesLoaded <- true\n LoadNestedTemplates JS.Document.Body \"\"\n LoadedTemplates[baseName] <- LoadedTemplateFile(\"\")\n\n let mutable RenderedFullDocTemplate = None\n\n let RunFullDocTemplate (fillWith: seq) =\n match RenderedFullDocTemplate with\n | Some d -> d\n | None ->\n let d =\n LoadLocalTemplates \"\"\n PrepareTemplateStrict \"\" None JS.Document.Body None\n ChildrenTemplate JS.Document.Body fillWith\n |>! Doc'.RunInPlace true JS.Document.Body\n RenderedFullDocTemplate <- Some d\n d\n\n let NamedTemplate (baseName: string) (name: option) (fillWith: seq) =\n match LoadedTemplateFile(baseName).TryGetValue(defaultArg name \"\") with\n | true, t -> ChildrenTemplate (t.CloneNode(true) :?> Dom.Element) fillWith\n | false, _ -> Console.Warn(\"Local template doesn't exist\", name); Doc'.Empty\n\n let GetOrLoadTemplate (baseName: string) (name: option) (fakeroot: unit -> Dom.Element) (fillWith: seq) =\n LoadLocalTemplates \"\"\n PrepareTemplate baseName name fakeroot\n NamedTemplate baseName name fillWith\n", "// $begin{copyright}\n//\n// This file is part of WebSharper\n//\n// Copyright (c) 2008-2018 IntelliFactory\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\"); you\n// may not use this file except in compliance with the License. You may\n// obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n// implied. See the License for the specific language governing\n// permissions and limitations under the License.\n//\n// $end{copyright}\n\nnamespace WebSharper.UI\nopen WebSharper\n\nopen System\nopen WebSharper.UI.Client\n\n[]\ntype Flow<'T>(render: Var -> ('T -> unit) -> unit) =\n\n new (define: Func, Doc>) =\n Flow(fun var cont -> Var.Set var (define.Invoke (Func<_,_>(cont))))\n\n member this.Render = render\n\n[]\n[]\ntype Flow =\n\n static member Map f (x: Flow<'A>) =\n Flow(fun var cont -> x.Render var (fun r -> (f r) |> cont))\n\n // \"Unwrap\" the value from the flowlet, use it as an argument to the\n // continuation k, and return the value of the applied continuation.\n\n // Semantically, what we're doing here is running the form (or other\n // input mechanism, but let's stick with thinking about forms), getting\n // the result, and then using this as an input to the continuation.\n static member Bind (m: Flow<'A>) (k: 'A -> Flow<'B>) =\n Flow(fun var cont -> m.Render var (fun r -> (k r).Render var cont))\n\n static member Return x =\n Flow(fun var cont -> cont x)\n\n static member Embed (fl: Flow<'A>) =\n let var = Var.Create Doc.Empty\n fl.Render var ignore\n Doc.EmbedView var.View\n\n static member Define (f: ('A -> unit) -> Doc) =\n Flow(Func<_,_>(fun (x: Func<'A, unit>) -> f x.Invoke))\n\n static member Static doc =\n Flow(fun var cont -> Var.Set var doc; cont ())\n\n[]\n[]\ntype FlowBuilder() =\n member x.Bind(comp, func) = Flow.Bind comp func\n member x.Return(value) = Flow.Return value\n member x.ReturnFrom(inner: Flow<'A>) = inner\n\ntype Flow with\n\n static member Do =\n FlowBuilder()\n", "// $begin{copyright}\n//\n// This file is part of WebSharper\n//\n// Copyright (c) 2008-2018 IntelliFactory\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\"); you\n// may not use this file except in compliance with the License. You may\n// obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n// implied. See the License for the specific language governing\n// permissions and limitations under the License.\n//\n// $end{copyright}\n\nnamespace WebSharper.UI\n\n#nowarn \"44\" // HTML deprecated\n\nopen WebSharper\nopen WebSharper.JavaScript\n\n/// This is an auto-generated module providing HTML5 vocabulary.\n/// Generated using tags.csv from WebSharper;\n/// See tools/UpdateElems.fsx for the code-generation logic.\n// Warning: don't mark this module as JavaScript: some submodules _must_ not\n// be JavaScript because they are proxied.\n[]\nmodule Html =\n\n /// Create a text node with constant content, or with dynamic content using `view.V`.\n [)>]\n let text t = Doc.TextNode t\n\n /// Create a text node with dynamic content.\n []\n let textView v = Client.Doc.TextView v\n\n /// Insert a client-side Doc.\n []\n [.\">]\n let client ([] q) = Doc.ClientSide %q\n\n module Elt =\n\n // {{ tag normal colliding deprecated [elt]\n /// Create an HTML element with attributes and children.\n []\n let a ats ch = Doc.Element \"a\" ats ch\n /// Create an HTML element with attributes and children.\n []\n let abbr ats ch = Doc.Element \"abbr\" ats ch\n /// Create an HTML element with attributes and children.\n []\n let acronym ats ch = Doc.Element \"acronym\" ats ch\n /// Create an HTML element
with attributes and children.\n []\n let address ats ch = Doc.Element \"address\" ats ch\n /// Create an HTML element with attributes and children.\n []\n let applet ats ch = Doc.Element \"applet\" ats ch\n /// Create an HTML element with attributes and children.\n []\n let area ats ch = Doc.Element \"area\" ats ch\n /// Create an HTML element
with attributes and children.\n []\n let article ats ch = Doc.Element \"article\" ats ch\n /// Create an HTML element