Mercurial > urweb
diff demo/more/grid.ur @ 915:5e8b6fa5b48f
Start 'more' demo with dbgrid
author | Adam Chlipala <adamc@hcoop.net> |
---|---|
date | Tue, 08 Sep 2009 07:48:57 -0400 |
parents | |
children | 2422360c78a3 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/demo/more/grid.ur Tue Sep 08 07:48:57 2009 -0400 @@ -0,0 +1,170 @@ +con colMeta' = fn (row :: Type) (t :: Type) => + {Header : string, + Project : row -> transaction t, + Update : row -> t -> transaction row, + Display : t -> xbody, + Edit : t -> xbody, + Validate : t -> signal bool} + +con colMeta = fn (row :: Type) (global_t :: (Type * Type)) => + {Initialize : transaction global_t.1, + Handlers : global_t.1 -> colMeta' row global_t.2} + +functor Make(M : sig + type row + val list : transaction (list row) + val new : transaction row + val save : {Old : row, New : row} -> transaction unit + val delete : row -> transaction unit + + con cols :: {(Type * Type)} + val cols : $(map (colMeta row) cols) + + val folder : folder cols + end) = struct + style tabl + style tr + style th + style td + + fun make (row : M.row) [t] (m : colMeta' M.row t) : transaction t = m.Project row + + fun makeAll cols row = @@Monad.exec [transaction] _ [map snd M.cols] + (map2 [fst] [colMeta M.row] [fn p :: (Type * Type) => transaction p.2] + (fn [p] data meta => make row [_] (meta.Handlers data)) + [_] M.folder cols M.cols) + (@@Folder.mp [_] [_] M.folder) + + fun addRow cols rows row = + rowS <- source row; + cols <- makeAll cols row; + colsS <- source cols; + ud <- source False; + Monad.ignore (Dlist.append rows {Row = rowS, + Cols = colsS, + Updating = ud}) + + type grid = {Cols : $(map fst M.cols), + Rows : Dlist.dlist {Row : source M.row, Cols : source ($(map snd M.cols)), Updating : source bool}} + + val createMetas = Monad.mapR [colMeta M.row] [fst] + (fn [nm :: Name] [p :: (Type * Type)] meta => meta.Initialize) + [_] M.folder M.cols + + val grid = + cols <- createMetas; + rows <- Dlist.create; + return {Cols = cols, Rows = rows} + + fun sync {Cols = cols, Rows = rows} = + Dlist.clear rows; + init <- rpc M.list; + List.app (addRow cols rows) init + + fun render grid = <xml> + <table class={tabl}> + <tr class={tr}> + <th/> <th/> + {foldRX2 [fst] [colMeta M.row] [_] + (fn [nm :: Name] [p :: (Type * Type)] [rest :: {(Type * Type)}] [[nm] ~ rest] + data (meta : colMeta M.row p) => + <xml><th class={th}>{[(meta.Handlers data).Header]}</th></xml>) + [_] M.folder grid.Cols M.cols} + </tr> + + {Dlist.render (fn {Row = rowS, Cols = colsS, Updating = ud} pos => + let + val delete = + Dlist.delete pos; + row <- get rowS; + rpc (M.delete row) + + val update = set ud True + + val cancel = + set ud False; + row <- get rowS; + cols <- makeAll grid.Cols row; + set colsS cols + + val save = + cols <- get colsS; + errors <- Monad.foldR3 [fst] [colMeta M.row] [snd] [fn _ => option string] + (fn [nm :: Name] [p :: (Type * Type)] [rest :: {(Type * Type)}] + [[nm] ~ rest] data meta v errors => + b <- current ((meta.Handlers data).Validate v); + return (if b then + errors + else + case errors of + None => Some ((meta.Handlers data).Header) + | Some s => Some ((meta.Handlers data).Header + ^ ", " ^ s))) + None [_] M.folder grid.Cols M.cols cols; + + case errors of + Some s => alert ("Can't save because the following columns have invalid values:\n" + ^ s) + | None => + set ud False; + row <- get rowS; + row' <- Monad.foldR3 [fst] [colMeta M.row] [snd] [fn _ => M.row] + (fn [nm :: Name] [t :: (Type * Type)] + [rest :: {(Type * Type)}] + [[nm] ~ rest] data meta v row' => + (meta.Handlers data).Update row' v) + row [_] M.folder grid.Cols M.cols cols; + rpc (M.save {Old = row, New = row'}); + set rowS row'; + + cols <- makeAll grid.Cols row'; + set colsS cols + in + <xml><tr class={tr}> + <td> + <dyn signal={b <- signal ud; + return (if b then + <xml><button value="Save" onclick={save}/></xml> + else + <xml><button value="Update" onclick={update}/></xml>)}/> + </td> + <td><dyn signal={b <- signal ud; + return (if b then + <xml><button value="Cancel" onclick={cancel}/></xml> + else + <xml><button value="Delete" onclick={delete}/></xml>)}/> + </td> + + <dyn signal={cols <- signal colsS; + return (foldRX3 [fst] [colMeta M.row] [snd] [_] + (fn [nm :: Name] [t :: (Type * Type)] + [rest :: {(Type * Type)}] + [[nm] ~ rest] data meta v => + <xml><td class={td}> + <dyn signal={b <- signal ud; + return (if b then + (meta.Handlers data).Edit v + else + (meta.Handlers data).Display + v)}/> + <dyn signal={b <- signal ud; + if b then + valid <- + (meta.Handlers data).Validate v; + return (if valid then + <xml/> + else + <xml>!</xml>) + else + return <xml/>}/> + </td></xml>) + [_] M.folder grid.Cols M.cols cols)}/> + </tr></xml> + end) grid.Rows} + </table> + + <button value="New row" onclick={row <- rpc M.new; + addRow grid.Cols grid.Rows row}/> + <button value="Refresh" onclick={sync grid}/> + </xml> +end