0 | module Web.Async.Util
5 | import Web.Async.Event
6 | import Web.Internal.Types
8 | import public FS.Concurrent.Signal
9 | import public IO.Async.JS
11 | import public Text.HTML
19 | %foreign "javascript:lambda:x=>x.length"
20 | prim__buflen : Buffer -> Bits32
22 | %foreign "browser:lambda:(w)=>window"
23 | prim__window : PrimIO Window
25 | %foreign "browser:lambda:(w)=>document"
26 | prim__document : PrimIO Document
28 | %foreign "browser:lambda:(w)=>document.body"
29 | prim__body : PrimIO (Nullable HTMLElement)
31 | %foreign "browser:lambda:(x,w)=>document.getElementById(x)"
32 | prim__getElementById : String -> PrimIO (Nullable Element)
34 | %foreign "browser:lambda:(x,s,w)=>x.setCustomValidity(s)"
35 | prim__setCustomValidity : Element -> String -> PrimIO ()
37 | %foreign "browser:lambda:(x,s,w)=> {x.value = s;}"
38 | prim__setValue : Element -> String -> PrimIO ()
40 | %foreign "browser:lambda:(x,w)=> x.click()"
41 | prim__click : HTMLElement -> PrimIO ()
43 | %foreign "browser:lambda:(x,n,w)=>x.replaceChildren(n)"
44 | prim__replaceChildren : ParentNode -> Node -> PrimIO ()
47 | %foreign "browser:lambda:(x,n,w)=>x.append(n)"
48 | prim__append : ParentNode -> Node -> PrimIO ()
51 | %foreign "browser:lambda:(x,n,w)=>x.append(n)"
52 | prim__appendTxt : ParentNode -> String -> PrimIO ()
54 | %foreign "browser:lambda:(x,n,w)=>x.prepend(n)"
55 | prim__prepend : ParentNode -> Node -> PrimIO ()
57 | %foreign "browser:lambda:(x,n,w)=>x.after(n)"
58 | prim__after : ChildNode -> Node -> PrimIO ()
60 | %foreign "browser:lambda:(x,n,w)=>x.before(n)"
61 | prim__before : ChildNode -> Node -> PrimIO ()
63 | %foreign "browser:lambda:(x,n,w)=>x.replaceWith(n)"
64 | prim__replace : ChildNode -> Node -> PrimIO ()
67 | %foreign "browser:lambda:(x,w)=>x.remove()"
68 | prim__remove : ChildNode -> PrimIO ()
71 | %foreign "browser:lambda:(s,w)=>document.createElement(s)"
72 | prim__createElement : String -> PrimIO Element
75 | %foreign "browser:lambda:(x,a,b,w)=>x.setAttribute(a,b)"
76 | prim__setAttribute : Element -> String -> String -> PrimIO ()
79 | %foreign "browser:lambda:(x,a,w)=>x.removeAttribute(a)"
80 | prim__removeAttribute : Element -> String -> PrimIO ()
83 | %foreign "browser:lambda:(x,w)=>x.innerHTML"
84 | prim__innerHTML : InnerHTML -> PrimIO String
87 | %foreign "browser:lambda:(x,v,w)=>{x.innerHTML = v}"
88 | prim__setInnerHTML : InnerHTML -> String -> PrimIO ()
91 | %foreign "browser:lambda:(x,w)=>x.content"
92 | prim__content : HTMLTemplateElement -> PrimIO DocumentFragment
95 | %foreign "browser:lambda:w=>document.createDocumentFragment()"
96 | prim__createDocumentFragment : PrimIO DocumentFragment
99 | %foreign "browser:lambda:(x,v,w)=>{x.checked = v}"
100 | prim__setChecked : HTMLInputElement -> Boolean -> PrimIO ()
103 | %foreign "browser:lambda:(x,v,w)=>x.checked?1:0"
104 | prim__checked : HTMLInputElement -> PrimIO Bool
106 | %foreign "browser:lambda:(x,w)=>x.blur()"
107 | prim__blur : HTMLOrSVGElement -> PrimIO ()
109 | %foreign "browser:lambda:(x,w)=>x.focus()"
110 | prim__focus : HTMLOrSVGElement -> PrimIO ()
113 | %foreign "javascript:lambda:(w) => BigInt(new Date().getTime())"
114 | prim__time : PrimIO Integer
116 | %foreign "browser:lambda:(s,w) => navigator.clipboard.writeText(s)"
117 | prim__writeToClipboard : String -> PrimIO ()
119 | %foreign "browser:lambda:(i,w) => navigator.clipboard.write([i])"
120 | prim__itemToClipboard : ClipboardItem -> PrimIO (Promise ())
122 | %foreign "browser:lambda:(m,s,w) => new ClipboardItem({[m]: s})"
123 | prim__clipboardItem : (mimeType, content : String) -> PrimIO ClipboardItem
125 | %foreign "browser:lambda:(f,w) => navigator.clipboard.readText().then(s => f(s)(w))"
126 | prim__readFromClipboard : (String -> PrimIO ()) -> PrimIO ()
128 | %foreign "browser:lambda:(e,w) => e.getBoundingClientRect()"
129 | prim__getBoundingClientRect : Element -> PrimIO DOMRect
131 | %foreign "browser:lambda:(e,w) => e.show()"
132 | prim__dialogShow : HTMLDialogElement -> PrimIO ()
134 | %foreign "browser:lambda:(e,w) => e.close()"
135 | prim__dialogClose : HTMLDialogElement -> PrimIO ()
137 | %foreign "browser:lambda:(e,w) => e.showModal()"
138 | prim__showModal : HTMLDialogElement -> PrimIO ()
140 | %foreign "browser:lambda:(p,s,w) => new Blob(p, {type:s})"
141 | prim__blob : AnyPtr -> String -> PrimIO Blob
143 | %foreign "browser:lambda:(b,w) => b.bytes()"
144 | prim__blobBytes : Blob -> PrimIO (Promise Buffer)
146 | %foreign "browser:lambda:(b,w) => URL.createObjectURL(b)"
147 | prim__blobURL : Blob -> PrimIO String
149 | %foreign "browser:lambda:(u,w) => URL.revokeObjectURL(u)"
150 | prim__revokeObjectURL : String -> PrimIO ()
158 | window : HasIO io => io Window
159 | window = primIO prim__window
163 | document : HasIO io => io Document
164 | document = primIO prim__document
170 | getBody : HasIO io => io (Maybe HTMLElement)
171 | getBody = nullableToMaybe <$> primIO prim__body
175 | click : HasIO io => HTMLElement -> io ()
176 | click x = primIO (prim__click x)
180 | replaceChildren : HasIO io => ParentNode -> Node -> io ()
181 | replaceChildren el n = primIO $
prim__replaceChildren el n
185 | append : HasIO io => ParentNode -> Node -> io ()
186 | append el n = primIO $
prim__append el n
190 | prepend : HasIO io => ParentNode -> Node -> io ()
191 | prepend el n = primIO $
prim__prepend el n
195 | after : HasIO io => ChildNode -> Node -> io ()
196 | after el n = primIO $
prim__after el n
200 | before : HasIO io => ChildNode -> Node -> io ()
201 | before el n = primIO $
prim__before el n
205 | replace : HasIO io => ChildNode -> Node -> io ()
206 | replace el n = primIO $
prim__replace el n
210 | remove : HasIO io => ChildNode -> io ()
211 | remove el = primIO $
prim__remove el
215 | createElement : HasIO io => String -> io Element
216 | createElement s = primIO $
prim__createElement s
220 | setAttribute : HasIO io => Element -> (name, value : String) -> io ()
221 | setAttribute el n v = primIO $
prim__setAttribute el n v
225 | removeAttribute : HasIO io => Element -> (name : String) -> io ()
226 | removeAttribute el n = primIO $
prim__removeAttribute el n
230 | innerHTML : HasIO io => InnerHTML -> io String
231 | innerHTML n = primIO $
prim__innerHTML n
235 | setInnerHTML : HasIO io => InnerHTML -> String -> io ()
236 | setInnerHTML n s = primIO $
prim__setInnerHTML n s
240 | focus : HasIO io => HTMLElement -> io ()
241 | focus el = primIO (prim__focus $
up el)
245 | blur : HasIO io => HTMLElement -> io ()
246 | blur el = primIO (prim__blur $
up el)
250 | currentTime : HasIO io => io Integer
251 | currentTime = primIO prim__time
255 | timed : HasIO io => io t -> io (t,Integer)
263 | timed' : HasIO io => io () -> io Integer
264 | timed' = map snd . timed
268 | toClipboard : HasIO io => String -> io ()
269 | toClipboard s = primIO (prim__writeToClipboard s)
273 | itemToClipboard : Elem JSErr es => ClipboardItem -> Async JS es ()
274 | itemToClipboard ci = do
275 | p <- primIO (prim__itemToClipboard ci)
280 | clipboardItem : HasIO io => (mimetype, content : String) -> io ClipboardItem
281 | clipboardItem m s = primIO (prim__clipboardItem m s)
285 | dataToClipboard : Elem JSErr es => (mimetype, content : String) -> Async JS es ()
286 | dataToClipboard m c = clipboardItem m c >>= itemToClipboard
289 | readFromClipboard1 : HasIO io => (String -> IO1 ()) -> io ()
290 | readFromClipboard1 cb = primIO $
prim__readFromClipboard (\s => primRun (cb s))
293 | readFromClipboard : Async e es String
294 | readFromClipboard =
295 | primAsync_ $
\cb =>
296 | ffi $
prim__readFromClipboard (\s => primRun (cb $
Right s))
300 | dialogShow : HasIO io => HTMLDialogElement -> io ()
301 | dialogShow el = primIO (prim__dialogShow el)
305 | dialogClose : HasIO io => HTMLDialogElement -> io ()
306 | dialogClose el = primIO (prim__dialogClose el)
310 | showModal : HasIO io => HTMLDialogElement -> io ()
311 | showModal el = primIO (prim__showModal el)
318 | interface ToBlob a where
319 | toBlob : a -> AnyPtr
322 | ToBlob (IArray k String) where
323 | toBlob = unsafeToPtr
326 | ToBlob (Indexed.Array String) where
327 | toBlob (A _ arr) = toBlob arr
330 | ToBlob (List String) where
331 | toBlob s = toBlob (arrayL s)
334 | ToBlob String where
335 | toBlob s = toBlob $
array [s]
338 | blob : {0 a : _} -> HasIO io => ToBlob a => a -> (mimetype : String) -> io Blob
339 | blob v mimetype = primIO (prim__blob (toBlob v) mimetype)
345 | record ObjectURL where
350 | Resource (Async JS) ObjectURL where
351 | cleanup (OU u) = primIO (prim__revokeObjectURL u)
354 | Cast ObjectURL String where cast = url
361 | blobURL : HasIO io => Blob -> io ObjectURL
362 | blobURL b = OU <$> primIO (prim__blobURL b)
366 | blobBytes : Has JSErr es => Blob -> Async JS es AnyBuffer
367 | blobBytes b = Prelude.do
368 | pbuf <- primIO (prim__blobBytes b)
369 | buf <- promise pbuf
370 | pure $
AB (cast $
prim__buflen buf) (unsafeMakeBuffer buf)
378 | 0 ElemType : Ref t -> Type
379 | ElemType (Id _) = Element
380 | ElemType (Elem _) = Element
381 | ElemType Body = HTMLElement
382 | ElemType Document = Document
383 | ElemType Window = Window
386 | 0 JS : List Type -> Type -> Type
389 | nodeList : DocumentFragment -> List (HSum [Node,String])
390 | nodeList df = [inject $
df :> Node]
396 | parameters {auto has : Has JSErr es}
399 | js : JSIO t -> JS es t
400 | js = injectIO . runEitherT
403 | jsCast : SafeCast t => String -> s -> JS es t
404 | jsCast msg = js . tryCast msg
407 | unmaybe : Lazy String -> Maybe t -> JS es t
408 | unmaybe msg = maybe (throw $
Caught msg) pure
411 | body : JS es HTMLElement
412 | body = getBody >>= unmaybe "document.body returned `Nothing`"
420 | getElementById : SafeCast t => Maybe String -> (id : String) -> JS es t
421 | getElementById mtag id = do
422 | e <- primIO (prim__getElementById id)
423 | unmaybe msg $
nullableToMaybe e >>= castTo t
425 | %inline tag, msg : String
426 | tag = fromMaybe "element" mtag
427 | msg = "getElementById: Could not find \{tag} with id \{id}"
434 | getHTMLElementById : (tag,id : String) -> JS es HTMLElement
435 | getHTMLElementById = getElementById . Just
443 | getElementByRef : (r : Ref t) -> JS es (ElemType r)
444 | getElementByRef (Id {tag} id) = getElementById (Just tag) id
445 | getElementByRef (Elem id) = getElementById Nothing id
446 | getElementByRef Body = body
447 | getElementByRef Document = document
448 | getElementByRef Window = window
451 | err = "Web.Async.getElementByRef"
459 | castElementByRef : {0 x : k} -> SafeCast t => Ref x -> JS es t
460 | castElementByRef ref = getElementByRef ref >>= jsCast err
469 | validityMessage : Ref t -> (0 p : ValidityTag t) => String -> JS es ()
470 | validityMessage r s =
471 | castElementByRef r >>= \e => primIO (prim__setCustomValidity e s)
475 | validate : Ref t -> (0 p : ValidityTag t) => Either String b -> JS es ()
476 | validate r (Left s) = validityMessage r s
477 | validate r (Right s) = validityMessage r ""
484 | setValue : Ref t -> (0 p : ValueTag t) => String -> JS es ()
485 | setValue r s = castElementByRef r >>= \e => primIO (prim__setValue e s)
492 | 0 Act : Type -> Type
493 | Act = Async JS [JSErr]
496 | 0 JSPull : Type -> Type -> Type
497 | JSPull o r = Pull (Async JS) o [JSErr] r
500 | 0 JSStream : Type -> Type
501 | JSStream o = Pull (Async JS) o [JSErr] ()
504 | pullErr : AsyncStream f es Void -> Async f es ()
506 | weakenErrors (pull s) >>= \case
507 | Error err => fail err
510 | export covering %inline
511 | runJS : JS [JSErr] () -> IO ()
512 | runJS = app . handle [putStrLn . dispErr]
514 | export covering %inline
515 | runProg : JSStream Void -> IO ()
516 | runProg = runJS . pullErr
519 | mvcActEvs : JSStream e -> s -> (e -> s -> Act s) -> JSStream Void
520 | mvcActEvs evs ini act = evs |> P.evalScans1 ini (flip act) |> drain
522 | parameters (ev : e)
526 | mvcAct : (Sink e => e -> s -> Act s) -> JSStream Void
528 | E evs <- exec $
eventFrom ev
529 | mvcActEvs evs ini act
532 | mvc : (e -> s -> s) -> (Sink e => e -> s -> Act ()) -> JSStream Void
534 | mvcAct (\v,x => let y := upd v x in disp v y $> y)
541 | getClientRect : LIO f => Element -> f Rect
542 | getClientRect el = Prelude.do
543 | r <- lift1 $
ffi (prim__getBoundingClientRect el)