{-| Module : Web.Framework.Plzwrk.Asterius Description : Asterius bindings for plzwrk Copyright : (c) Mike Solomon 2020 License : GPL-3 Maintainer : mike@meeshkan.com Stability : experimental Portability : POSIX, Windows This module exports a single function called @asteriusBrowser@ that you can use to build your DOM with asterius (see the examples in the README.md). Unfortunately, due to the way cabal compiles this documentation, it does not appear on this page. Instead, a dummy function called @ignoreMe@ appears. This is because @asteriusBrowser@ can only be created by using `ahc-cabal`, and haddock uses `cabal` as a default. -} {-# LANGUAGE CPP #-} #if defined(PLZWRK_ENABLE_ASTERIUS) {-# LANGUAGE InterruptibleFFI #-} module Web.Framework.Plzwrk.Asterius (asteriusBrowser) where import Asterius.Aeson import Asterius.ByteString import Asterius.Types import Data.ByteString.Internal ( ByteString ) import qualified Data.ByteString as BS import Data.ByteString.Unsafe import Data.HashMap.Strict as HM import Data.Coerce import Foreign.Ptr import Web.Framework.Plzwrk.JSEnv asteriusBrowser :: IO (JSEnv JSVal) asteriusBrowser = return JSEnv { castToArray = _castToArray , castToBool = _castToBool , castToByteString = _castToByteString , castToDouble = _castToDouble , castToInt = _castToInt , castToString = _castToString , consoleLog = _consoleLog , defaultRequestInit = _defaultRequestInit , documentCreateElement = _documentCreateElement , documentCreateTextNode = _documentCreateTextNode , documentBody = _documentBody , documentGetElementById = _documentGetElementById , documentHead = _documentHead , fetch = _fetch , _freeCallback = __freeCallback , getPropertyAsOpaque = _getPropertyAsOpaque , jsValFromArray = _jsValFromArray , jsValFromBool = _jsValFromBool , jsValFromByteString = _jsValFromByteString , jsValFromDouble = _jsValFromDouble , jsValFromInt = _jsValFromInt , jsValFromString = _jsValFromString , invokeOn0 = _invokeOn0 , makeObject = _makeObject , setValue = _setValue , invokeOn1 = _invokeOn1 , invokeOn2 = _invokeOn2 , _makeHaskellCallback1 = __makeHaskellCallback1 , _makeHaskellCallback2 = __makeHaskellCallback2 , _makeHaskellCallback3 = __makeHaskellCallback3 , mathRandom = _mathRandom } _documentCreateElement :: String -> IO JSVal _documentCreateElement = js_documentCreateElement . toJSString _getPropertyAsOpaque :: JSVal -> String -> IO (Maybe JSVal) _getPropertyAsOpaque n k = do isUndef <- js_null_or_undef n if isUndef then pure Nothing else (do v <- _js_getPropertyAsOpaque n (toJSString k) isUndef' <- js_null_or_undef v if isUndef' then pure Nothing else pure (Just v) ) _castToString :: JSVal -> IO (Maybe String) _castToString v = pure $ (Just . fromJSString . JSString) v _castToByteString :: JSVal -> IO (Maybe ByteString) _castToByteString v = pure $ (Just . byteStringFromJSUint8Array . JSUint8Array) v _castToBool :: JSVal -> IO (Maybe Bool) _castToBool n = _castGeneric (\v -> (jsonFromJSVal v) :: Either String Bool) n _castToInt :: JSVal -> IO (Maybe Int) _castToInt n = _castGeneric (\v -> (jsonFromJSVal v) :: Either String Int) n _castToDouble :: JSVal -> IO (Maybe Double) _castToDouble n = _castGeneric (\v -> (jsonFromJSVal v) :: Either String Double) n _castGeneric :: (JSVal -> Either String a) -> JSVal -> IO (Maybe a) _castGeneric f v = do isUndef' <- js_null_or_undef v if isUndef' then pure Nothing else (let q = f v in either (\_ -> pure Nothing) (pure . Just) q) _defaultRequestInit = RequestInit { _ri_method = Nothing , _ri_headers = Nothing , _ri_body = Nothing , _ri_mode = Nothing , _ri_credentials = Nothing , _ri_cache = Nothing , _ri_redirect = Nothing , _ri_referrer = Nothing , _ri_integrity = Nothing } _s2v :: JSString -> JSVal _s2v (JSString v) = v _b2v :: JSUint8Array -> JSVal _b2v (JSUint8Array v) = v makeBody :: FetchBody JSVal -> IO JSVal makeBody (FormDataBody formData) = do _fd <- _formData mapM (\(x, y) -> _invokeOn2 _fd "append" (_s2v . toJSString $ x) y) (HM.toList formData) return _fd makeBody (StringBody str) = pure (_s2v . toJSString $ str) makeBody (BlobBody blob) = pure blob makeBody (URLSearchParamsBody searchParams) = do _usp <- _urlSearchParams mapM (\(x, y) -> _invokeOn2 _usp "append" (_s2v . toJSString $ x) (_s2v . toJSString $ y)) (HM.toList searchParams) return _usp makeBody (Uint8Array bs) = pure $ (_b2v . byteStringToJSUint8Array $ bs) kvToJSVal :: (String, String) -> IO (JSVal, JSVal) kvToJSVal (k, v) = do _k <- _jsValFromString k _v <- _jsValFromString v return $ (_k, _v) requestInitToJSVal :: RequestInit JSVal -> IO JSVal requestInitToJSVal ri = do obj <- _makeObject maybe (pure ()) (_setValue' obj "method") (_ri_method ri) maybe (pure ()) (\hds -> do __headers <- _headers kvs <- mapM kvToJSVal (HM.toList hds) mapM (\(x, y) -> _invokeOn2 __headers "append" x y) kvs _setValue obj "headers" __headers) (_ri_headers ri) maybe (pure ()) (\body -> do _body <- makeBody body _setValue obj "body" _body) (_ri_body ri) maybe (pure ()) (_setValue' obj "mode") (_ri_mode ri) maybe (pure ()) (_setValue' obj "credentials") (_ri_credentials ri) maybe (pure ()) (_setValue' obj "cache") (_ri_cache ri) maybe (pure ()) (_setValue' obj "redirect") (_ri_redirect ri) maybe (pure ()) (_setValue' obj "referrer") (_ri_referrer ri) maybe (pure ()) (_setValue' obj "integrity") (_ri_integrity ri) return obj _fetch :: String -> RequestInit JSVal -> IO JSVal _fetch url ri = do _ri <- requestInitToJSVal ri _js_fetch (toJSString url) _ri _documentCreateTextNode :: String -> IO JSVal _documentCreateTextNode = js_documentCreateTextNode . toJSString _invokeOn0 :: JSVal -> String -> IO JSVal _invokeOn0 e s = _js_invokeOn0 e (toJSString s) _invokeOn1 :: JSVal -> String -> JSVal -> IO JSVal _invokeOn1 e s v0 = _js_invokeOn1 e (toJSString s) v0 _invokeOn2 :: JSVal -> String -> JSVal -> JSVal -> IO JSVal _invokeOn2 e s v0 v1 = _js_invokeOn2 e (toJSString s) v0 v1 _documentGetElementById :: String -> IO (Maybe JSVal) _documentGetElementById k = do v <- js_documentGetElementById (toJSString k) u <- js_null_or_undef v return $ if u then Nothing else Just v getJSVal :: JSFunction -> JSVal getJSVal (JSFunction x) = x _castToArray :: JSVal -> IO (Maybe [JSVal]) _castToArray v = pure $ (Just . fromJSArray . JSArray) v _jsValFromString :: String -> IO JSVal _jsValFromString v = pure $ (x . toJSString) v where x (JSString s) = s _jsValFromByteString :: ByteString -> IO JSVal _jsValFromByteString v = pure $ (x . byteStringToJSUint8Array) v where x (JSUint8Array bs) = bs _jsValFromArray :: [JSVal] -> IO JSVal _jsValFromArray v = pure $ (x . toJSArray) v where x (JSArray bs) = bs _setValue :: JSVal -> String -> JSVal -> IO () _setValue a b c = _js_setValue a (toJSString b) c _setValue' :: JSVal -> String -> String -> IO () _setValue' a b c = _js_setValue a (toJSString b) $ _s2v (toJSString c) __makeHaskellCallback1 :: (JSVal -> IO ()) -> IO JSVal __makeHaskellCallback1 a = do x <- makeHaskellCallback1 a return $ getJSVal x __makeHaskellCallback2 :: (JSVal -> JSVal -> IO ()) -> IO JSVal __makeHaskellCallback2 a = do x <- makeHaskellCallback2 a return $ getJSVal x __makeHaskellCallback3 :: (JSVal -> JSVal -> JSVal -> IO ()) -> IO JSVal __makeHaskellCallback3 a = do x <- makeHaskellCallback3 a return $ getJSVal x __freeCallback :: JSVal -> IO () __freeCallback v = freeHaskellCallback (JSFunction v) foreign import javascript "{}" _makeObject :: IO JSVal foreign import javascript "new Headers()" _headers :: IO JSVal foreign import javascript "new URLSearchParams()" _urlSearchParams :: IO JSVal foreign import javascript "new FormData()" _formData :: IO JSVal foreign import javascript "$1[$2]=$3" _js_setValue :: JSVal -> JSString -> JSVal -> IO () foreign import javascript "$1" _jsValFromBool :: Bool -> IO JSVal foreign import javascript interruptible "fetch($1, $2)" _js_fetch :: JSString -> JSVal -> IO JSVal foreign import javascript "$1" _jsValFromInt :: Int -> IO JSVal foreign import javascript "$1" _jsValFromDouble :: Double -> IO JSVal foreign import javascript "console.log($1)" _consoleLog :: JSVal -> IO () foreign import javascript "$1[$2]()" _js_invokeOn0 :: JSVal -> JSString -> IO JSVal foreign import javascript "$1[$2]($3)" _js_invokeOn1 :: JSVal -> JSString -> JSVal -> IO JSVal foreign import javascript "$1[$2]($3,$4)" _js_invokeOn2 :: JSVal -> JSString -> JSVal -> JSVal -> IO JSVal foreign import javascript "$1[$2]" _js_getPropertyAsOpaque :: JSVal -> JSString -> IO JSVal foreign import javascript "document.createElement($1)" js_documentCreateElement :: JSString -> IO JSVal foreign import javascript "Math.random()" _mathRandom :: IO Double foreign import javascript "document.body" _documentBody :: IO JSVal foreign import javascript "document.head" _documentHead :: IO JSVal foreign import javascript "($1 == null) || ($1 == undefined)" js_null_or_undef :: JSVal -> IO Bool foreign import javascript "document.createTextNode($1)" js_documentCreateTextNode :: JSString -> IO JSVal foreign import javascript "document.getElementById($1)" js_documentGetElementById :: JSString -> IO JSVal foreign import javascript "wrapper" makeHaskellCallback1 :: (JSVal -> IO ()) -> IO JSFunction foreign import javascript "wrapper" makeHaskellCallback2 :: (JSVal -> JSVal -> IO ()) -> IO JSFunction foreign import javascript "wrapper" makeHaskellCallback3 :: (JSVal -> JSVal -> JSVal -> IO ()) -> IO JSFunction # else module Web.Framework.Plzwrk.Asterius where ignoreMe :: IO () ignoreMe = print "ignore me" # endif