/+ sr=sortug /* kaji-js %js /lib/kaji-min/js /* kaji-css %css /lib/kaji/css |% +$ kbowl $: src=@p now=@da mob=? == +$ eyre-order [id=@ta req=inbound-request:eyre] +$ req-line $: pat=(pole knot) :: path ext=(unit @ta) :: extension par=(map @t @t) :: params mob=? :: is-mobile == +$ form-data [action=@t input=(map @t @t)] ++ enc |= a=* ^- tape (scow:parsing:sr %uw (jam a)) ++ dec |* [a=@t m=mold] ^- (unit m) =/ hash (slaw:parsing:sr %uw a) ?~ hash ~ ((soft m) (cue u.hash)) ++ dec-i |* [i=(map @t @t) key=@t =mold] ^- (unit mold) =/ val (~(get by i) key) ?~ val ~ =/ atm (slaw:parsing:sr %uw u.val) ?~ atm ~ ((soft mold) (cue u.atm)) :: ++ dec-form |* [=form-data d=(list [key=@t =mold])] :: =| res=* :: |- :: ?~ d res :: =/ val (~(get by in) key.i.d) :: ?~ val ~ :: =/ uw (scow %uw u.val) :: ?~ uw :: =/ is-t ((sane @t) (crip u.val)) :: ?. is-t ~| "%kaji.- passed value {u.val} of wrong format" ~ :: it's a @t :: ${res [res (crip u.val), d t.d] :: =/ dec-res ((soft mold.i.d) (cue u.uw)) :: ?~ dec-res ~| "Failed to decode {(trip key.i.d)}" ~ :: =/ nr [res u.dec-res] :: $(res nr, d t.d) :: =df |* wer=(list [key=@t =mold]) :: |= in=(map @t @t) :: ?~ wer ~ :: :_ ((df t.wer) in) :: =/ val (~(get by in) key.i.wer) :: ?~ val ~| "key {(trip key.i.wer)} not found in map" ~ :: =/ uw (slaw %uw u.val) ?~ uw :: ~& uw=uw :: =/ is-t ((sane %t) u.val) :: ~& is-t=is-t :: ?. is-t ~| "%kaji.- passed value {u.val} of wrong format" ~ :: u.val :: =/ dec-res ((soft mold.i.wer) (cue u.uw)) :: ?~ dec-res ~| "Failed to decode {(trip key.i.wer)}" ~ :: u.dec-res :: =df |* [in=(map @t @t) d=(list [key=@t =mold])] :: =| res=(unit) :: |- :: ~& res=res :: ?~ d res :: ~& key=key.i.d :: =/ val (~(get by in) key.i.d) :: ~& val=val :: ?~ val ~ :: =/ uw (slaw %uw u.val) ?~ uw :: ~& uw=uw :: =/ is-t ((sane %t) u.val) :: ~& is-t=is-t :: ?. is-t ~| "%kaji.- passed value {u.val} of wrong format" ~ :: =/ nr ?~ res (some u.val) (some [(need res) u.val]) :: $(res nr, d t.d) :: =/ dec-res ((soft mold.i.d) (cue u.uw)) :: ~& dec-res=dec-res :: ?~ dec-res ~| "Failed to decode {(trip key.i.d)}" ~ :: =/ nr ?~ res (some u.dec-res) (some [(need res) u.dec-res]) :: $(res nr, d t.d) :: =m (malt `(list [@t @t])`~[['a' 'alpha'] ['b' (scot %uw (jam [our now]))]]) :: =d `(list [@t mold])`~[['a' @] ['b' ,[@p @da]]] +$ kaji-res $% [%res eyre-res] [%sse sse-res] == +$ sse-res $: wire=kaji-wire e=(list effect) == +$ kaji-wire $% [%tab ~] [%custom p=(list wire)] [%all ~] == +$ eyre-res $% [%full p=simple-payload:http] [%page p=manx] [%html p=manx] :: fragment [%mime type=path p=@t] [%glob p=mime] == +$ where $% [%top ~] [%bottom ~] [%before sibling=@t] == +$ effect $% [%redi url=@t] :: redirects; will replace the whole html of the site and update the tab history [%swap =manx sel=@t inner=?] :: swaps a selector [%add =manx container=@t =where] :: adds marl to a div [%focus sel=@t] :: focuses on some selector [%scroll sel=@t] :: scrolls to some selector [%url url=@t] :: updates the url bar [%modal =manx] :: opens a modal [%alert =manx dur=@ud] :: opens an alert for given duration in ms [%refresh ~] [%custom =manx data=json] :: custom, you can set a handle for the 'kaji-fact' event in JS == +$ sse-card [%give %fact (list path) [%kaji vase]] ++ ui-fact |= [tab=@t res=(list effect)] ^- sse-card =/ wire /sse/[tab] [%give %fact ~[wire] [%kaji !>(res)]] ++ live-fact |= res=(list effect) ^- sse-card [%give %fact ~[/ui] [%kaji !>(res)]] ++ give-fact |= [wires=(list path) res=(list effect)] ^- sse-card [%give %fact wires [%kaji !>(res)]] :: sse templates ++ ui |_ tab-id=@t ++ fact |= res=(list effect) (ui-fact tab-id res) ++ alert =/ dur 2.000 |= a=tape =/ manx ;span:"{a}" %+ ui-fact tab-id [%alert manx dur]^~ ++ refresh-card :: wipe browser cache %+ ui-fact tab-id [%refresh ~]^~ -- :: :: response builders :: eyre responses ++ error-response |= code=@ud ^- eyre-res :- %html (error-page code) :: inline sse commands :: some helpers :: manx builders ++ wrap-marl |= m=marl ^- manx ;div ;* m == ++ error-page |= code=@ud ;html ;body ;p:"Error {}" == == ++ fetch |= pat=path ;div(kaji "fetch", src "{(trip (spat pat))}"); ++ add-error |= m=manx ^- manx =. a.g.m (snoc a.g.m [%kaji-error "true"]) m ++ hide-manx |= m=manx ^- manx =. a.g.m :_ a.g.m [n=%hidden v=""] m ++ modal |= children=marl ^- manx ;div#kaji-modal-bg ;div#kaji-modal-fg ;* children == == :: ++ parse-formdata |= body=(unit octs) ^- (unit (list [key=@t val=@t])) ?~ body ~ (rush q.u.body yquy:de-purl:html) ++ get-redirect |= redirect=cord ^- simple-payload:http [[303 ['location' redirect]~] ~] ++ doctype "" ++ is-mobile |= req=inbound-request:eyre ^- ? =/ headers (malt header-list.request.req) =/ ua (~(get by headers) 'user-agent') =/ swidth (~(get by headers) 'x-kaji-vw') ?~ ua ?~ swidth .n =/ width (rush u.swidth dem) ?~ width .n (lte u.width 800) ?| (cfind:sr 'android' u.ua .n) (cfind:sr 'iphone' u.ua .n) :: (cfind:sr 'ipad' u.ua .n) == :: core functionality +$ request-line-s $: [ext=(unit @ta) site=(list @t)] args=(list [key=@t value=@t]) == ++ parse-req |= req=inbound-request:eyre ^- req-line =/ rl=(unit request-line-s) (rush url.request.req ;~(plug apat:de-purl:html yque:de-purl:html)) ?~ rl ~& >>> url-parsing-failed=url.request.req !! =/ is-mob (is-mobile req) [path=site.u.rl ext.u.rl (malt args.u.rl) is-mob] ++ manx-to-cord |= [is-fragment=? =manx] ^- @t %- crip ?. is-fragment %- en-xml:html manx :: %+ weld doctype %- en-xml:html manx ++ send-eyre-res |= [eyre-id=@ta =simple-payload:http] ^- (list card:agent:gall) =/ header-cage [%http-response-header !>(response-header.simple-payload)] =/ data-cage [%http-response-data !>(data.simple-payload)] :~ [%give %fact ~[/http-response/[eyre-id]] header-cage] [%give %fact ~[/http-response/[eyre-id]] data-cage] [%give %kick ~[/http-response/[eyre-id]] ~] == ++ glob-payload =| cache=_| |= =mime ^- simple-payload:http =/ content-type (rsh 3 (crip )) =/ cache-header ?: cache ['cache-control' 'max-age=86400'] ['cache-control' 'no-cache, no-store, must-revalidate'] :: ~& >>> ends-in=`@t`(swp 3 (end [3 5] (swp 3 q.q.mime))) :_ `q.mime [200 [['content-type' content-type] cache-header ~]] ++ http-payload =| cache=_| |= [mime-type=path t=@t] ^- simple-payload:http =/ content-type (rsh 3 (crip )) =/ octs (as-octs:mimes:html t) =/ cache-header ?: cache ['cache-control' 'max-age=86400'] ['cache-control' 'no-cache, no-store, must-revalidate'] :_ `octs [200 [['content-type' content-type] cache-header ~]] :: ++ js |% ++ collapsible ^~ %- trip ''' function createCollapsible(el){ console.log("creating collapsible") const targetID = el.getAttribute("target"); const targetEl = document.getElementById(targetID); targetEl.classList.toggle("hide"); let show = false; el.addEventListener('click', () => { console.log(show, "clicked on toggle") console.log(targetID) console.log(targetEl) show = !show; // el.classList.toggle("") TODO would need to toggle the button itself targetEl.classList.toggle("not-hide") targetEl.classList.toggle("hide") }) } document.querySelectorAll(".toggle").forEach(createCollapsible) console.log(document.querySelectorAll(".toggle")) ''' -- ++ payload-bail ^- simple-payload:http %+ http-payload /text/plain 'Error' ++ init |* [=bowl:gall app-state=mold kaji-req=mold] |% +$ request $% [%eyre p=eyre-order] [%kaji tab=@t req=kaji-req] == +$ router $-([request bowl:gall app-state] kaji-res) ++ route |= [=router r=request state=app-state] |^ ^- (list card:agent:gall) ?- -.r %eyre =/ =req-line (parse-req req.p.r) %+ send-eyre-res id.p.r ?+ [pat ext]:req-line :: default case =/ resp (router r bowl state) ?. ?=(%res -.resp) payload-bail ?- +<.resp %full p.resp %page (http-payload /text/html (manx-to-cord .n (inject-head p.resp))) %html (http-payload /text/html (manx-to-cord .y p.resp)) %mime (http-payload type.resp p.resp) %glob (glob-payload p.resp) == [[%session ~] [~ %js]] (http-payload /text/javascript docket-session-js) [[%kaji-session ~] [~ %js]] (http-payload /text/javascript session-js) [[%kaji ~] [~ %js]] (http-payload /text/javascript kaji-js) [[%kaji ~] [~ %css]] (http-payload /text/css kaji-css) == %kaji =/ resp (router r bowl state) ?. ?=(%sse -.resp) ~ :_ ~ ?- -.wire.resp %all (live-fact e.resp) %tab (ui-fact tab.r e.resp) %custom (give-fact p.wire.resp e.resp) == == ++ inject-head |= m=manx ^- manx =/ sip (scow %p src.bowl) =/ dap (trip dap.bowl) =/ tags=marl :~ ;link/"/kaji.css"(rel "stylesheet"); ;script@"/kaji.js"; ;script@"/kaji-session.js?ship={sip}&dap={dap}"; == |- ?~ c.m m ?: .=(%head n.g.i.c.m) =. c.i.c.m (weld c.i.c.m tags) m $(c.m t.c.m) ++ docket-session-js ^~ (rap 3 'window.ship = "' (rsh 3 (scot %p our.bowl)) '";' ~) ++ session-js ^~ %- crip =/ ship (scow %p our.bowl) =/ app (trip dap.bowl) =/ live-ui "/ui" """ window.ship = '{ship}' window.app = '{app}' window.liveUI = '{live-ui}'; """ -- -- --