diff options
-rw-r--r-- | doc/manual.tex | 8 | ||||
-rw-r--r-- | lib/js/urweb.js | 9 | ||||
-rw-r--r-- | lib/ur/basis.urs | 1 | ||||
-rw-r--r-- | src/settings.sml | 9 | ||||
-rw-r--r-- | tests/focus.ur | 14 |
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> |