{-# LANGUAGE TypeFamilies #-} {-# LANGUAGE DataKinds #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE UndecidableInstances #-} -- | Provides a more specific type for arrays in Javascript -- (together with basic operations on them). module Language.Sunroof.JS.Array ( JSArray , array, newArray , length' , lookup' , insert' , push, pop , shift, unshift , forEach , empty ) where import Prelude hiding ( lookup, length ) import Data.List ( intercalate ) import Data.Boolean ( BooleanOf, IfB(..) ) import Language.Sunroof.JavaScript ( Expr, showExpr, literal ) import Language.Sunroof.Types import Language.Sunroof.Classes ( Sunroof(..), SunroofValue(..), SunroofArgument(..) ) import Language.Sunroof.Selector ( JSSelector, index, (!) ) import Language.Sunroof.JS.Bool ( JSBool, jsIfB ) import Language.Sunroof.JS.Number ( JSNumber ) -- ------------------------------------------------------------- -- JSArray Type -- ------------------------------------------------------------- -- | Type if arrays in Javascript. The type parameter -- given the entry type. data JSArray a = JSArray Expr -- | Show the Javascript. instance Show (JSArray a) where show (JSArray v) = showExpr False v -- | Arrays are first-class Javascript values. instance (Sunroof a) => Sunroof (JSArray a) where box = JSArray unbox (JSArray o) = o -- | The boolean of arrays are 'JSBool'. type instance BooleanOf (JSArray a) = JSBool -- | You can write branches that return arrays. instance (Sunroof a) => IfB (JSArray a) where ifB = jsIfB -- ------------------------------------------------------------- -- JSArray Combinators -- ------------------------------------------------------------- -- | Create a literal array from a Haskell list. array :: (SunroofValue a, Sunroof (ValueOf a)) => [a] -> JS t (JSArray (ValueOf a)) array l = evaluate $ box $ literal $ "[" ++ intercalate "," (fmap (showExpr False . unbox . js) l) ++ "]" -- | Create a new array object containing the given values. newArray :: (SunroofArgument args, Sunroof a) => args -> JS t (JSArray a) newArray args = cast `fmap` new "Array" args -- | The empty array. empty :: (Sunroof a) => JS t (JSArray a) empty = evaluate $ box $ literal "[]" -- | The @length@ property of arrays. length' :: JSSelector JSNumber length' = attr "length" -- | A type-safe version of array lookup. lookup' :: (Sunroof a) => JSNumber -> JSArray a -> a lookup' n e = e ! index n -- | A type-safe version of array insert. insert' :: (Sunroof a) => JSNumber -> a -> JSArray a -> JS t () insert' n a e = e # index n := a -- | Push a element into the array as if it was a stack. -- Returns nothing instead of the new length. -- See . push :: (SunroofArgument a, Sunroof a) => a -> JSArray a -> JS t () push a = invoke "push" a -- | Adds a new element to the beginning of the array (queue). -- Returns nothing instead of the new length. -- See . unshift :: (SunroofArgument a, Sunroof a) => a -> JSArray a -> JS t () unshift a = invoke "unshift" a -- | Pop a element from the array as if it was a stack. -- See . pop :: (Sunroof a) => JSArray a -> JS t a pop = invoke "pop" () -- | Removes and return the first element of an array (dequeue). -- See . shift :: (Sunroof a) => JSArray a -> JS t a shift = invoke "shift" () -- | Foreach iteration method provided by most browsers. -- Execute the given action on each element of the array. -- See -- , -- . forEach :: (Sunroof a, SunroofArgument a) => (a -> JS A ()) -> JSArray a -> JS t () forEach body arr = do f <- function body arr # invoke "forEach" f :: JS t () return ()