Mercurial > gui
diff remotePager.ur @ 16:2e397d373289
Add RemotePager.
author | Karn Kallio <kkallio@eka> |
---|---|
date | Thu, 18 Aug 2011 12:53:17 -0430 |
parents | |
children | b5432d74841a |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/remotePager.ur Thu Aug 18 12:53:17 2011 -0430 @@ -0,0 +1,170 @@ +type formatCtl = {Width : int, + RangeCtl : $(mapU (transaction {} -> xbody) [First, Back, Next, Last]), + PageCtl : $(mapU (int -> transaction {} -> xbody) [Unsel, Sel]), + WrapPageCtl : xbody -> xbody, + Wrap : $(mapU xbody [First, Back, Pages, Next, Last]) -> xbody} + +style firstCtl +style backCtl +style nextCtl +style lastCtl +style curPage +style rangeCtl + +fun defaultFormatLbl {First = fLbl, Back = bLbl, Next = nLbl, Last = lLbl} = + let + fun mkLink c txt = fn a => <xml><li onclick={a} class={c}><a class={c} onclick={return ()}>{[txt]}</a></li></xml> + in + {Width = 5, + RangeCtl = {First = mkLink firstCtl fLbl, + Back = mkLink backCtl bLbl, + Next = mkLink nextCtl nLbl, + Last = mkLink lastCtl lLbl}, + PageCtl = {Unsel = fn n a => <xml><li onclick={a}><a onclick={return ()}>{[n + 1]}</a></li></xml>, + Sel = fn n a => <xml><li onclick={a} class={curPage}><a class={curPage} onclick={return ()}>{[n + 1]}</a></li></xml>}, + WrapPageCtl = fn x => x, + Wrap = fn {First = f, Back = b, Pages = p, Next = n, Last = l} => <xml><ul class={rangeCtl}>{f}{b}{p}{n}{l}</ul></xml>} + end + +val defaultFormat = defaultFormatLbl {First = "<<", Back = "<", Next = ">", Last = ">>"} + +type pageData = {Content : xbody, Available : int} +datatype response err = Good of pageData | Bad of err + +functor Make(M : sig + type errorMarker + type pageGroup + val initPage : pageGroup -> transaction pageData + val getPage : pageGroup -> int -> transaction (response errorMarker) + end) : sig + type t + val createFmt : formatCtl -> M.pageGroup -> transaction t + val create : M.pageGroup -> transaction t + val onError : t -> (M.errorMarker -> transaction {}) -> transaction {} + val panelXml : t -> xbody + val ctlXml : t -> xbody +end = struct + open M + + type t = {FormatCtl : formatCtl, + PageGroup : pageGroup, + OnError : source (errorMarker -> transaction {}), + CurrentPage : source int, + RangeStart : source int, + Available : source int, + Content : source xbody} + + fun max x y = if x > y then x else y + fun min x y = if x < y then x else y + + fun loadPage t pg = + ret <- rpc (getPage t.PageGroup pg); + + case ret of + Good pageData => + let + val lst = max 0 (pageData.Available - 1) + val rgtRange = max 0 (pageData.Available - t.FormatCtl.Width) + in + if pg > lst then + loadPage t lst + else + rg <- get t.RangeStart; + (if rg > rgtRange then + set t.RangeStart rgtRange + else + return ()); + set t.CurrentPage pg; + set t.Content pageData.Content; + set t.Available pageData.Available + end + | Bad e => + handler <- get t.OnError; + handler e + + fun createFmt fmt grp = + pg <- source 0; + rg <- source 0; + + pageData <- initPage grp; + + av <- source (pageData.Available); + c <- source (pageData.Content); + + e <- source (fn _ => return {}); + + return {FormatCtl = fmt, + PageGroup = grp, + OnError = e, + CurrentPage = pg, + RangeStart = rg, + Available = av, + Content = c} + + val create = createFmt defaultFormat + + fun onError t f = + set t.OnError f + + fun panelXml t = + <xml> + <dyn signal={signal t.Content}/> + </xml> + + fun ctlXml t = + let + val fmt = t.FormatCtl + val width = fmt.Width + + fun floor pg = + return (max 0 pg) + + fun lastPage () = + av <- get t.Available; + floor (av - 1) + + fun rightRange () = + lst <- lastPage (); + floor (lst - width + 1) + + fun ceil pg = + rgt <- rightRange (); + return (min rgt pg) + + fun setRange startPage = + startPage <- ceil startPage; + startPage <- floor startPage; + set t.RangeStart startPage + + fun printLinks start cur available = + let + val wanted = start + width - 1 + val have = max 0 (available - 1) + val lst = min wanted have + + fun printLinks' n (acc : xbody) = + if n > lst then + acc + else + printLinks' (n + 1) + <xml>{acc}{(if n = cur then + fmt.PageCtl.Sel + else + fmt.PageCtl.Unsel) n (loadPage t n)}</xml> + in + printLinks' start <xml/> + end + in + fmt.Wrap {First = fmt.RangeCtl.First (setRange 0), + Back = fmt.RangeCtl.Back (pg <- get t.RangeStart; setRange (pg - 1)), + Pages = fmt.WrapPageCtl + <xml> + <dyn signal={start <- signal t.RangeStart; + av <- signal t.Available; + cur <- signal t.CurrentPage; + return (printLinks start cur av)}/> + </xml>, + Next = fmt.RangeCtl.Next (pg <- get t.RangeStart; setRange (pg + 1)), + Last = fmt.RangeCtl.Last (pg <- rightRange (); setRange pg)} + end +end