# HG changeset patch # User Adam Chlipala # Date 1354139805 18000 # Node ID be0c4e2e488abb8620be8260c2b10c1d865c2301 # Parent 373e2c3f03b2b64fad87f0f7f9a34694cbbd1da1 Allow any FFI module to declare new HTML tags diff -r 373e2c3f03b2 -r be0c4e2e488a demo/more/grid.ur --- a/demo/more/grid.ur Wed Nov 28 11:45:46 2012 -0500 +++ b/demo/more/grid.ur Wed Nov 28 16:56:45 2012 -0500 @@ -40,10 +40,10 @@ val pageLength : option int end) = struct - style tabl - style tr - style th - style td + style tab + style row + style header + style data style agg fun make (row : M.row) [input] [filter] (m : colMeta' M.row input filter) : transaction input = m.Project row @@ -122,13 +122,13 @@ M.folder M.cols grid.Cols grid.Filters row fun render (grid : grid) = - - +
+ {@mapX2 [fst3] [colMeta M.row] [tr] (fn [nm :: Name] [p :: (Type * Type * Type)] [rest :: {(Type * Type * Type)}] [[nm] ~ rest] data (meta : colMeta M.row p) => - +
+ {case (meta.Handlers data).Sort of None => txt (meta.Handlers data).Header | sort =>
- + [[nm] ~ rest] dat meta v => + else diff -r 373e2c3f03b2 -r be0c4e2e488a demo/more/grid.urs --- a/demo/more/grid.urs Wed Nov 28 11:45:46 2012 -0500 +++ b/demo/more/grid.urs Wed Nov 28 16:56:45 2012 -0500 @@ -49,9 +49,9 @@ val showSelection : grid -> source bool val selection : grid -> signal (list M.row) - style tabl - style tr - style th - style td + style tab + style row + style header + style data style agg end diff -r 373e2c3f03b2 -r be0c4e2e488a demo/more/out/grid.css --- a/demo/more/out/grid.css Wed Nov 28 11:45:46 2012 -0500 +++ b/demo/more/out/grid.css Wed Nov 28 16:56:45 2012 -0500 @@ -1,16 +1,16 @@ -.Grid1_tabl { +.Grid1_tab { border-style: solid } -.Grid1_th { +.Grid1_header { border-style: solid } -.Grid1_tr { +.Grid1_row { border-style: solid } -.Grid1_td { +.Grid1_data { border-style: solid } diff -r 373e2c3f03b2 -r be0c4e2e488a demo/subforms.ur --- a/demo/subforms.ur Wed Nov 28 11:45:46 2012 -0500 +++ b/demo/subforms.ur Wed Nov 28 16:56:45 2012 -0500 @@ -13,7 +13,7 @@ end -fun subforms n = +fun subfrms n = if n <= 0 then else @@ -22,13 +22,13 @@
  • {[n]}:
  • - {subforms (n - 1)} + {subfrms (n - 1)}
    fun form n = return
    - {subforms n} + {subfrms n} diff -r 373e2c3f03b2 -r be0c4e2e488a doc/manual.tex --- a/doc/manual.tex Wed Nov 28 11:45:46 2012 -0500 +++ b/doc/manual.tex Wed Nov 28 16:56:45 2012 -0500 @@ -2482,6 +2482,12 @@ \item It is possible to use the more standard ``IDs and mutation'' style of JavaScript coding, though that style is unidiomatic for Ur/Web and should be avoided wherever possible. Recall the abstract type $\mt{id}$ and its constructor $\mt{fresh}$, which can be used to generate new unique IDs in Ur/Web code. Values of this type are represented as strings in JavaScript, and a function \cd{fresh()} is available to generate new unique IDs. Application-specific ID generation schemes may cause bad interactions with Ur/Web code that also generates IDs, so the recommended approach is to produce IDs only via calls to \cd{fresh()}. FFI code shouldn't depend on the ID generation scheme (on either server side or client side), but it is safe to include these IDs in tag attributes (in either server-side or client-side code) and manipulate the associated DOM nodes in the standard way (in client-side code). Be forewarned that this kind of imperative DOM manipulation may confuse the Ur/Web runtime system and interfere with proper behavior of tags like \cd{}! \end{itemize} +\subsection{Introducing New HTML Tags} + +FFI modules may introduce new tags as values with $\mt{Basis.tag}$ types. See \texttt{basis.urs} for examples of how tags are declared. The identifier of a tag value is used as its rendering in HTML. The Ur/Web syntax sugar for XML literals desugars each use of a tag into a reference to an identifier with the same name. There is no need to provide implementations (i.e., in C or JavaScript code) for such identifiers. + +The onus is on the coder of a new tag's interface to think about consequences for code injection attacks, messing with the DOM in ways that may break Ur/Web reactive programming, etc. + \section{Compiler Phases} diff -r 373e2c3f03b2 -r be0c4e2e488a src/monoize.sml --- a/src/monoize.sml Wed Nov 28 11:45:46 2012 -0500 +++ b/src/monoize.sml Wed Nov 28 16:56:45 2012 -0500 @@ -3203,7 +3203,7 @@ let fun getTag' (e, _) = case e of - L.EFfi ("Basis", tag) => (tag, []) + L.EFfi (_, tag) => (tag, []) | L.ECApp (e, t) => let val (tag, ts) = getTag' e in @@ -3215,7 +3215,7 @@ fun getTag (e, _) = case e of - L.EFfiApp ("Basis", tag, [((L.ERecord [], _), _)]) => (tag, []) + L.EFfiApp (_, tag, [((L.ERecord [], _), _)]) => (tag, []) | L.EApp (e, (L.ERecord [], _)) => getTag' e | _ => (E.errorAt loc "Non-constant XML tag"; Print.eprefaces' [("Expression", CorePrint.p_exp env tag)]; diff -r 373e2c3f03b2 -r be0c4e2e488a src/urweb.grm --- a/src/urweb.grm Wed Nov 28 11:45:46 2012 -0500 +++ b/src/urweb.grm Wed Nov 28 16:56:45 2012 -0500 @@ -1608,7 +1608,7 @@ val pos = s (BEGIN_TAGleft, BEGIN_TAGright) in (bt, - (EVar (["Basis"], bt, Infer), pos)) + (EVar ([], bt, Infer), pos)) end) | tagHead LBRACE cexp RBRACE (#1 tagHead, (ECApp (#2 tagHead, cexp), s (tagHeadleft, RBRACEright))) diff -r 373e2c3f03b2 -r be0c4e2e488a tests/ffitag.ur --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/ffitag.ur Wed Nov 28 16:56:45 2012 -0500 @@ -0,0 +1,3 @@ +open Tagffi + +fun main () : transaction page = return test diff -r 373e2c3f03b2 -r be0c4e2e488a tests/ffitag.urp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/ffitag.urp Wed Nov 28 16:56:45 2012 -0500 @@ -0,0 +1,4 @@ +ffi tagffi +rewrite all Ffitag/* + +ffitag diff -r 373e2c3f03b2 -r be0c4e2e488a tests/tagffi.urs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/tagffi.urs Wed Nov 28 16:56:45 2012 -0500 @@ -0,0 +1,1 @@ +val funky : bodyTag boxAttrs