@@ -2,6 +2,8 @@
2{-# LANGUAGE FlexibleInstances #-}
2{-# LANGUAGE FlexibleInstances #-}
3{-# LANGUAGE TypeSynonymInstances #-}
3{-# LANGUAGE TypeSynonymInstances #-}
4{-# LANGUAGE ScopedTypeVariables #-}
4{-# LANGUAGE ScopedTypeVariables #-}
5+{-# LANGUAGE NoMonomorphismRestriction #-}
6+{-# LANGUAGE Rank2Types #-}
5-----------------------------------------------------------------------------
7-----------------------------------------------------------------------------
7-- Module : Language.Javascript.JSC.Object
9-- Module : Language.Javascript.JSC.Object
@@ -21,6 +23,8 @@ module Language.Javascript.JSC.Object (
21 -- * Property lookup
23 -- * Property lookup
25 -- * Setting the value of a property
29 -- * Setting the value of a property
@@ -92,6 +96,9 @@ import Graphics.UI.Gtk.WebKit.JavaScriptCore.JSValueRef
92import Graphics.UI.Gtk.WebKit.JavaScriptCore.JSContextRef
96import Graphics.UI.Gtk.WebKit.JavaScriptCore.JSContextRef
93 (jscontextgetglobalobject)
97 (jscontextgetglobalobject)
94import Language.Javascript.JSC.Properties
98import Language.Javascript.JSC.Properties
100+ (IndexPreservingGetter, to, (^.))
101+import Language.Javascript.JSC.String (textToStr)
96-- | If we already have a JSObjectRef we are fine
103-- | If we already have a JSObjectRef we are fine
97instance MakeObjectRef JSObjectRef where
104instance MakeObjectRef JSObjectRef where
@@ -106,8 +113,8 @@ instance MakeObjectRef v => MakeObjectRef (JSC v) where
106-- the lookup is delayed until we use the JSPropRef. This makes it a bit lazy compared
113-- the lookup is delayed until we use the JSPropRef. This makes it a bit lazy compared
107-- to JavaScript's @.@ operator.
114-- to JavaScript's @.@ operator.
109−-- >>> runjs $ eval "'Hello World'.length"
116+-- >>> testJSC $ eval "'Hello World'.length"
110−-- >>> runjs $ val "Hello World" ! "length"
117+-- >>> testJSC $ val "Hello World" ! "length"
112(!) :: (MakeObjectRef this, MakeStringRef name)
119(!) :: (MakeObjectRef this, MakeStringRef name)
113 => this -- ^ Object to look on
120 => this -- ^ Object to look on
@@ -115,15 +122,16 @@ instance MakeObjectRef v => MakeObjectRef (JSC v) where
115 -> JSC JSPropRef -- ^ Property reference
122 -> JSC JSPropRef -- ^ Property reference
116this ! name = do
123this ! name = do
117 rthis <- makeObjectRef this
124 rthis <- makeObjectRef this
118− rname <- makeStringRef name
119 return (JSPropRef rthis rname)
125 return (JSPropRef rthis rname)
127+ rname = makeStringRef name
121-- | Lookup a property based on its index. This function just constructs a JSPropRef
129-- | Lookup a property based on its index. This function just constructs a JSPropRef
122-- the lookup is delayed until we use the JSPropRef. This makes it a bit lazy compared
130-- the lookup is delayed until we use the JSPropRef. This makes it a bit lazy compared
123-- to JavaScript's @[]@ operator.
131-- to JavaScript's @[]@ operator.
125−-- >>> runjs $ eval "'Hello World'[6]"
133+-- >>> testJSC $ eval "'Hello World'[6]"
126−-- >>> runjs $ val "Hello World" !! 6
134+-- >>> testJSC $ val "Hello World" !! 6
128(!!) :: (MakeObjectRef this)
136(!!) :: (MakeObjectRef this)
129 => this -- ^ Object to look on
137 => this -- ^ Object to look on
@@ -133,11 +141,32 @@ this !! index = do
133 rthis <- makeObjectRef this
141 rthis <- makeObjectRef this
134 return (JSPropIndexRef rthis index)
142 return (JSPropIndexRef rthis index)
144+-- | Makes a getter for a particular property name.
146+-- > js name = to (!name)
148+-- >>> testJSC $ eval "'Hello World'.length"
149+-- >>> testJSC $ val "Hello World" ^. js "length"
151+js :: (MakeObjectRef s, MakeStringRef name)
152+ => name -- ^ Name of the property to find
153+ -> IndexPreservingGetter s (JSC JSPropRef)
156+-- | Handy way to get and hold onto a reference top level javascript
158+-- >>> testJSC $ eval "w = console; w.log('Hello World')"
159+-- >>> testJSC $ do w <- jsg "console"; w ^. js "log" # ["Hello World"]
161+jsg :: MakeStringRef a => a -> JSC JSPropRef
162+jsg name = global ! name
136-- | Call a JavaScript function
164-- | Call a JavaScript function
138−-- >>> runjs $ eval "'Hello World'.indexOf('World')"
166+-- >>> testJSC $ eval "'Hello World'.indexOf('World')"
139−-- >>> runjs $ val "Hello World" ! "indexOf" # ["World"]
167+-- >>> testJSC $ val "Hello World" ! "indexOf" # ["World"]
141(#) :: (MakePropRef prop, MakeArgRefs args)
170(#) :: (MakePropRef prop, MakeArgRefs args)
142 => prop -> args -> JSC JSValueRef
171 => prop -> args -> JSC JSValueRef
143prop # args = do
172prop # args = do
@@ -147,8 +176,8 @@ prop # args = do
148-- | Call a JavaScript function
177-- | Call a JavaScript function
150−-- >>> runjs $ eval "var j = {}; j.x = 1; j.x"
179+-- >>> testJSC $ eval "var j = {}; j.x = 1; j.x"
151−-- >>> runjs $ do {j <- eval "({})"; j!"x" <# 1; j!"x"}
180+-- >>> testJSC $ do {j <- eval "({})"; j!"x" <# 1; j!"x"}
153infixr 0 <#
182infixr 0 <#
154(<#) :: (MakePropRef prop, MakeValueRef val)
183(<#) :: (MakePropRef prop, MakeValueRef val)
@@ -162,7 +191,7 @@ prop <# val = do
163-- | Use this to create a new JavaScript object
192-- | Use this to create a new JavaScript object
165−-- >>> runjs $ new "Date" (2013, 1, 1)
194+-- >>> testJSC $ new "Date" (2013, 1, 1)
166-- "Fri Feb 01 2013 00:00:00 GMT+1300 (NZDT)"
195-- "Fri Feb 01 2013 00:00:00 GMT+1300 (NZDT)"
167new :: (MakeObjectRef constructor, MakeArgRefs args)
196new :: (MakeObjectRef constructor, MakeArgRefs args)
168 => constructor
197 => constructor
@@ -174,8 +203,8 @@ new constructor args = do
175-- | Call function with a given @this@. In most cases you should use '#'.
204-- | Call function with a given @this@. In most cases you should use '#'.
177−-- >>> runjs $ eval "(function(){return this;}).apply('Hello', [])"
206+-- >>> testJSC $ eval "(function(){return this;}).apply('Hello', [])"
178−-- >>> runjs $ do { test <- eval "(function(){return this;})"; call test (val "Hello") () }
207+-- >>> testJSC $ do { test <- eval "(function(){return this;})"; call test (val "Hello") () }
179-- "Hello"
208-- "Hello"
180call :: (MakeObjectRef function, MakeObjectRef this, MakeArgRefs args)
209call :: (MakeObjectRef function, MakeObjectRef this, MakeArgRefs args)
181 => function -> this -> args -> JSC JSValueRef
210 => function -> this -> args -> JSC JSValueRef
@@ -206,8 +235,8 @@ type JSCallAsFunction = JSValueRef -- ^ Function object
206-- | Short hand @::JSCallAsFunction@ so a haskell function can be passed to
235-- | Short hand @::JSCallAsFunction@ so a haskell function can be passed to
207-- a to a JavaScipt one.
236-- a to a JavaScipt one.
209−-- >>> runjs $ eval "(function(f) {f('Hello');})(function (a) {console.log(a)})"
238+-- >>> testJSC $ eval "(function(f) {f('Hello');})(function (a) {console.log(a)})"
210−-- >>> runjs $ call (eval "(function(f) {f('Hello');})") global [fun $ \ _ _ args -> valToText (head args) >>= (liftIO . print) ]
239+-- >>> testJSC $ call (eval "(function(f) {f('Hello');})") global [fun $ \ _ _ args -> valToText (head args) >>= (liftIO . print) ]
211-- "Hello"
240-- "Hello"
212-- "undefined"
241-- "undefined"
213fun :: JSCallAsFunction -> JSCallAsFunction
242fun :: JSCallAsFunction -> JSCallAsFunction
@@ -225,8 +254,7 @@ function :: MakeStringRef name
225function name f = do
254function name f = do
226 gctxt <- ask
255 gctxt <- ask
227 callback <- liftIO $ mkJSObjectCallAsFunctionCallback wrap
256 callback <- liftIO $ mkJSObjectCallAsFunctionCallback wrap
228− sName <- makeStringRef name
229− liftIO $ jsobjectmakefunctionwithcallback gctxt sName callback
257+ liftIO $ jsobjectmakefunctionwithcallback gctxt (makeStringRef name) callback
231 wrap ctx fobj this argc argv exception = do
259 wrap ctx fobj this argc argv exception = do
232 args <- peekArray (fromIntegral argc) argv
260 args <- peekArray (fromIntegral argc) argv
@@ -257,11 +285,11 @@ makeArray args exceptions = do
258-- | Make an JavaScript array from a list of values
286-- | Make an JavaScript array from a list of values
260−-- >>> runjs $ eval "['Hello', 'World'][1]"
288+-- >>> testJSC $ eval "['Hello', 'World'][1]"
261−-- >>> runjs $ array ["Hello", "World"] !! 1
289+-- >>> testJSC $ array ["Hello", "World"] !! 1
262-- "World"
290-- "World"
263−-- >>> runjs $ eval "['Hello', null, undefined, true, 1]"
291+-- >>> testJSC $ eval "['Hello', null, undefined, true, 1]"
264−-- >>> runjs $ array ("Hello", JSNull, (), True, 1.0::Double)
292+-- >>> testJSC $ array ("Hello", JSNull, (), True, 1.0::Double)
265-- "Hello,,,true,1"
293-- "Hello,,,true,1"
266array :: MakeArgRefs args => args -> JSC JSObjectRef
294array :: MakeArgRefs args => args -> JSC JSObjectRef
267array = rethrow . makeArray
295array = rethrow . makeArray
@@ -270,20 +298,11 @@ array = rethrow . makeArray
270global :: JSC JSObjectRef
298global :: JSC JSObjectRef
271global = ask >>= (liftIO . jscontextgetglobalobject)
299global = ask >>= (liftIO . jscontextgetglobalobject)
273−---- String global scope ----
274−-- | A string on its own is assumed to be the name of a property in the global object
275−instance MakePropRef String where
276− makePropRef name = do
278− rname <- makeStringRef name
279− return (JSPropRef this rname)
281-- | A string on its own is assumed to be the name of a property in the global object
301-- | A string on its own is assumed to be the name of a property in the global object
282instance MakeObjectRef String where
302instance MakeObjectRef String where
283 makeObjectRef name = do
303 makeObjectRef name = do
284 this <- global
304 this <- global
285− rname <- makeStringRef name
286− rethrow (objGetPropertyByName this rname) >>= valToObject
305+ rethrow (objGetPropertyByName this (makeStringRef name)) >>= valToObject
288-- | Get an array containing the property names present on a given object
307-- | Get an array containing the property names present on a given object
289copyPropertyNames :: MakeObjectRef this => this -> JSC JSPropertyNameArrayRef
308copyPropertyNames :: MakeObjectRef this => this -> JSC JSPropertyNameArrayRef