changeset 1786:d794149b3713

<active>
author Adam Chlipala <adam@chlipala.net>
date Sat, 21 Jul 2012 13:55:35 -0400
parents ffd7ed3bc0b7
children 69daa6d70299
files doc/manual.tex lib/js/urweb.js lib/ur/basis.urs src/monoize.sml tests/active.ur
diffstat 5 files changed, 40 insertions(+), 3 deletions(-) [+]
line wrap: on
line diff
--- a/doc/manual.tex	Sat Jul 21 11:59:41 2012 -0400
+++ b/doc/manual.tex	Sat Jul 21 13:55:35 2012 -0400
@@ -2136,7 +2136,11 @@
 
 Currently, the only way to avoid undesired resets is to avoid regeneration of containing subtrees.  There are two main strategies for achieving that goal.  First, when changes to a subtree can be confined to CSS classes of tags, the \texttt{dynClass} pseudo-attribute may be used instead (see Section \ref{xml}), as it does not regenerate subtrees.  Second, a single \cd{<dyn>} tag may be broken into multiple tags, in a way that makes finer-grained dependency structure explicit.  This latter strategy can avoid ``spurious'' regenerations that are not actually required to achieve the intended semantics.
 
-Transactions can be run on the client by including them in attributes like the $\mt{Onclick}$ attribute of $\mt{button}$, and GUI widgets like $\mt{ctextbox}$ have $\mt{Source}$ attributes that can be used to connect them to sources, so that their values can be read by code running because of, e.g., an $\mt{Onclick}$ event.
+Transactions can be run on the client by including them in attributes like the $\mt{Onclick}$ attribute of $\mt{button}$, and GUI widgets like $\mt{ctextbox}$ have $\mt{Source}$ attributes that can be used to connect them to sources, so that their values can be read by code running because of, e.g., an $\mt{Onclick}$ event.  It is also possible to create an ``active'' HTML fragment that runs a $\mt{transaction}$ to determine its content, possibly allocating some sources in the process:
+
+$$\begin{array}{l}
+  \mt{val} \; \mt{active} : \mt{unit} \to \mt{tag} \; [\mt{Code} = \mt{transaction} \; \mt{xbody}] \; \mt{body} \; [] \; [] \; []
+\end{array}$$
 
 \subsubsection{Remote Procedure Calls}
 
--- a/lib/js/urweb.js	Sat Jul 21 11:59:41 2012 -0400
+++ b/lib/js/urweb.js	Sat Jul 21 13:55:35 2012 -0400
@@ -901,6 +901,12 @@
     runScripts(node);
 }
 
+function active(s) {
+    var span = document.createElement("span");
+    addNode(span);
+    setInnerHTML(span, execF(s));
+}
+
 function input(x, s, recreate, type, name) {
     if (name) x.name = name;
     if (type) x.type = type;
--- a/lib/ur/basis.urs	Sat Jul 21 11:59:41 2012 -0400
+++ b/lib/ur/basis.urs	Sat Jul 21 13:55:35 2012 -0400
@@ -767,6 +767,9 @@
 val dyn : ctx ::: {Unit} -> use ::: {Type} -> bind ::: {Type} -> [ctx ~ [Dyn]] => unit
           -> tag [Signal = signal (xml ([Dyn] ++ ctx) use bind)] ([Dyn] ++ ctx) [] use bind
 
+val active : unit
+             -> tag [Code = transaction xbody] body [] [] []
+
 val head : unit -> tag [] html head [] []
 val title : unit -> tag [] head [] [] []
 val link : unit -> tag [Id = id, Rel = string, Typ = string, Href = url, Media = string] head [] [] []
--- a/src/monoize.sml	Sat Jul 21 11:59:41 2012 -0400
+++ b/src/monoize.sml	Sat Jul 21 13:55:35 2012 -0400
@@ -3234,7 +3234,7 @@
                 val (style, fm) = monoExp (env, st, fm) style
                 val (dynStyle, fm) = monoExp (env, st, fm) dynStyle
 
-                val dynamics = ["dyn", "ctextbox", "ccheckbox", "cselect", "coption", "ctextarea"]
+                val dynamics = ["dyn", "ctextbox", "ccheckbox", "cselect", "coption", "ctextarea", "active"]
 
                 fun isSome (e, _) =
                     case e of
@@ -3541,9 +3541,19 @@
                                        (L'.EStrcat ((L'.EJavaScript (L'.Script, e), loc),
                                                     (L'.EPrim (Prim.String ("))</script>")), loc)), loc)), loc),
 				 fm)
-                              | _ => raise Fail "Monoize: Bad dyn attributes"
+                              | _ => raise Fail "Monoize: Bad <dyn> attributes"
 			end
 
+                      | "active" =>
+                        (case attrs of
+			     [("Code", e, _)] =>
+			     ((L'.EStrcat
+                                   ((L'.EPrim (Prim.String ("<script type=\"text/javascript\">active(execD(")), loc),
+                                    (L'.EStrcat ((L'.EJavaScript (L'.Script, e), loc),
+                                                 (L'.EPrim (Prim.String ("))</script>")), loc)), loc)), loc),
+			      fm)
+                           | _ => raise Fail "Monoize: Bad <active> attributes")
+
                       | "submit" => normal ("input type=\"submit\"", NONE)
                       | "image" => normal ("input type=\"image\"", NONE)
                       | "button" => normal ("input type=\"submit\"", NONE)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/active.ur	Sat Jul 21 13:55:35 2012 -0400
@@ -0,0 +1,14 @@
+fun counter' () =
+    s <- source 0;
+    return <xml>
+      <dyn signal={n <- signal s; return (txt n)}/>
+      <button onclick={fn _ => n <- get s; set s (n + 1)}/>
+    </xml>
+
+fun counter () = <xml><active code={counter' ()}/></xml>
+
+fun main () : transaction page = return <xml><body>
+  {counter ()}
+  <hr/>
+  {counter ()}
+</body></xml>