packages feed

javascript-extras-0.1.0.0: src/JavaScript/Extras.hs

{-# LANGUAGE GeneralizedNewtypeDeriving #-}

module JavaScript.Extras
    ( strval
    , Property
    , getProperty
    , setProperty
    , PureJSVal(..)
    , toMaybeJSObject
    , toJSObject
    ) where

import Data.Foldable
import qualified Data.JSString as J
import qualified GHCJS.Marshal.Pure as J
import qualified GHCJS.Types as J
import qualified JavaScript.Object as JO

-- | This makes it easier to use OverloadedStrings with inputs that accept a JSVal that could be a JSString
strval :: J.JSString -> J.JSVal
strval = J.jsval

type Property = (J.JSString, J.JSVal)

-- | throws an exception if undefined or null
foreign import javascript unsafe
  "$2[$1]"
  js_unsafeGetProperty :: J.JSString -> J.JSVal -> IO J.JSVal

-- | throws an exception if undefined or null
foreign import javascript unsafe
  "$3[$1] = $2;"
  js_unsafeSetProperty :: J.JSString -> J.JSVal -> J.JSVal -> IO ()

-- | get a property of any JSVal. If a null or undefined is queried, the result will also be null
getProperty :: J.JSString -> J.JSVal -> IO J.JSVal
getProperty k x = let k' = J.pToJSVal k
                  in if J.isUndefined x || J.isNull x
                         || J.isUndefined k' || J.isNull k'
                     then pure J.nullRef
                     else js_unsafeGetProperty k x

-- | set a property of any JSVal
setProperty :: Property -> J.JSVal -> IO ()
setProperty (k, v) x = let k' = J.pToJSVal k
                    in if J.isUndefined x || J.isNull x
                          || J.isUndefined k' || J.isNull k'
                       then pure ()
                       else js_unsafeSetProperty k v x

-- | This is to enable conversion between equivalent classes 'IsJSVal' and 'PToJSVal'
-- So you can convert ((PureJSVal Object) to JSVal with pToJSVal without requiring IO)
newtype PureJSVal a = PureJSVal a
    deriving J.IsJSVal

instance J.IsJSVal a => J.PToJSVal (PureJSVal a) where
    pToJSVal (PureJSVal a) = J.jsval a

toMaybeJSObject :: [Property] -> IO (Maybe JO.Object)
toMaybeJSObject [] = pure Nothing
toMaybeJSObject xs = Just <$> toJSObject xs

toJSObject :: [Property] -> IO JO.Object
toJSObject [] = JO.create
toJSObject xs = do
    obj <- JO.create
    traverse_ (\(k, v) -> JO.unsafeSetProp k v obj) xs
    pure obj