summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/manual.tex8
-rw-r--r--lib/js/urweb.js9
-rw-r--r--lib/ur/basis.urs1
-rw-r--r--src/settings.sml9
-rw-r--r--tests/focus.ur14
5 files changed, 37 insertions, 4 deletions
diff --git a/doc/manual.tex b/doc/manual.tex
index ceb012bc..00d2bc55 100644
--- a/doc/manual.tex
+++ b/doc/manual.tex
@@ -2093,7 +2093,13 @@ $$\begin{array}{l}
\mt{val} \; \mt{fresh} : \mt{transaction} \; \mt{id}
\end{array}$$
-The \cd{fresh} function is allowed on both server and client, but there is no other way to create IDs, which includes lack of a way to force an ID to match a particular string. The only semantic importance of IDs within Ur/Web is in uses of the HTML \cd{<label>} tag. IDs play a much more central role in mainstream JavaScript programming, but Ur/Web uses a very different model to enable changes to particular nodes of a page tree, as the next manual subsection explains. IDs may still be useful in interfacing with JavaScript code (for instance, through Ur/Web's FFI).
+The \cd{fresh} function is allowed on both server and client, but there is no other way to create IDs, which includes lack of a way to force an ID to match a particular string. The main semantic importance of IDs within Ur/Web is in uses of the HTML \cd{<label>} tag. IDs play a much more central role in mainstream JavaScript programming, but Ur/Web uses a very different model to enable changes to particular nodes of a page tree, as the next manual subsection explains. IDs may still be useful in interfacing with JavaScript code (for instance, through Ur/Web's FFI).
+
+One further use of IDs is as handles for requesting that \emph{focus} be given to specific tags.
+
+$$\begin{array}{l}
+ \mt{val} \; \mt{giveFocus} : \mt{id} \to \mt{transaction} \; \mt{unit}
+\end{array}$$
\subsubsection{\label{signals}Functional-Reactive Page Generation}
diff --git a/lib/js/urweb.js b/lib/js/urweb.js
index 5846863a..35023924 100644
--- a/lib/js/urweb.js
+++ b/lib/js/urweb.js
@@ -1824,5 +1824,14 @@ function fresh() {
return "uw" + (--nextId);
}
+function giveFocus(id) {
+ var node = document.getElementById(id);
+
+ if (node)
+ node.focus();
+ else
+ er("Tried to give focus to ID not used in document: " + id);
+}
+
// App-specific code
diff --git a/lib/ur/basis.urs b/lib/ur/basis.urs
index cd38c783..7f254a2f 100644
--- a/lib/ur/basis.urs
+++ b/lib/ur/basis.urs
@@ -762,6 +762,7 @@ val redirect : t ::: Type -> url -> transaction t
type id
val fresh : transaction id
+val giveFocus : id -> transaction unit
val dyn : ctx ::: {Unit} -> use ::: {Type} -> bind ::: {Type} -> [ctx ~ [Dyn]] => unit
-> tag [Signal = signal (xml ([Dyn] ++ ctx) use bind)] ([Dyn] ++ ctx) [] use bind
diff --git a/src/settings.sml b/src/settings.sml
index 66bc7238..dcaf392d 100644
--- a/src/settings.sml
+++ b/src/settings.sml
@@ -177,7 +177,8 @@ val benignBase = basis ["get_cookie",
"onMouseup",
"preventDefault",
"stopPropagation",
- "fresh"]
+ "fresh",
+ "giveFocus"]
val benign = ref benignBase
fun setBenignEffectful ls = benign := S.addList (benignBase, ls)
@@ -205,7 +206,8 @@ val clientBase = basis ["get_client_source",
"onMousedown",
"onMouseup",
"preventDefault",
- "stopPropagation"]
+ "stopPropagation",
+ "giveFocus"]
val client = ref clientBase
fun setClientOnly ls = client := S.addList (clientBase, ls)
fun isClientOnly x = S.member (!client, x)
@@ -322,7 +324,8 @@ val jsFuncsBase = basisM [("alert", "alert"),
("atom", "atom"),
("css_url", "css_url"),
- ("property", "property")]
+ ("property", "property"),
+ ("giveFocus", "giveFocus")]
val jsFuncs = ref jsFuncsBase
fun setJsFuncs ls = jsFuncs := foldl (fn ((k, v), m) => M.insert (m, k, v)) jsFuncsBase ls
fun jsFunc x = M.find (!jsFuncs, x)
diff --git a/tests/focus.ur b/tests/focus.ur
new file mode 100644
index 00000000..9d1f5b8c
--- /dev/null
+++ b/tests/focus.ur
@@ -0,0 +1,14 @@
+fun main () : transaction page =
+ id1 <- fresh;
+ id2 <- fresh;
+ s1 <- source "";
+ s2 <- source "";
+ which <- source False;
+
+ return <xml><body>
+ <ctextbox id={id1} source={s1}/>
+ <ctextbox id={id2} source={s2}/>
+ <button onclick={fn _ => w <- get which;
+ set which (not w);
+ giveFocus (if w then id1 else id2)}/>
+ </body></xml>