on develop help sign in
Fix WebSocket, Location and Xhr functions
commit00c773be07693f38d981d6b99fac4a0571d45bd0 authorHamish Mackenzie <Hamish.K.Mackenzie@googlemail.com> dateFri 16 Dec 2016, 02:37 (10 years ago) parentd984274
14 files changed+163−761
.gitignore+1 reflex-dom.cabal+11−17 src-ghc/Reflex/Dom/Internal/Foreign.hs−189 src-ghc/Reflex/Dom/WebSocket/Foreign.hs−129 src-ghc/Reflex/Dom/Xhr/Foreign.hs−246 src-ghcjs/Reflex/Dom/Internal/Foreign.hs−48 src/Foreign/JavaScript/TH.hs−2 src/Reflex/Dom/Builder/Immediate.hs+3−3 src/Reflex/Dom/Location.hs+8−7 src/Reflex/Dom/WebSocket.hs+20−19 src-ghcjs/Reflex/Dom/WebSocket/Foreign.hs → src/Reflex/Dom/WebSocket/Foreign.hs+37−29 src/Reflex/Dom/Xhr.hs+29−28 src-ghcjs/Reflex/Dom/Xhr/Foreign.hs → src/Reflex/Dom/Xhr/Foreign.hs+53−43 src/Reflex/Dom/Xhr/ResponseType.hs+1−1
.gitignore+1
@@ -38,3 +38,4 @@ cabal.sandbox.config
3838codex.tags
3939*.dump-*
4040*.verbose-core2core
41+*.lkshf
reflex-dom.cabal+11−17
@@ -11,11 +11,8 @@ Category: FRP, Web, GUI, HTML, Javascript, Reactive, Reactivity, User Interfaces
1111Build-type: Simple
1212Cabal-version: >=1.9.2
1313-- Deal with https://github.com/haskell/cabal/issues/2544 / https://github.com/haskell/cabal/issues/367
14−extra-source-files: src-ghc/Reflex/Dom/Xhr/Foreign.hs
15− src-ghc/Reflex/Dom/WebSocket/Foreign.hs
16− src-ghcjs/Reflex/Dom/Internal/Foreign.hs
17− src-ghcjs/Reflex/Dom/Xhr/Foreign.hs
18− src-ghcjs/Reflex/Dom/WebSocket/Foreign.hs
14+extra-source-files: src/Reflex/Dom/Xhr/Foreign.hs
15+ src/Reflex/Dom/WebSocket/Foreign.hs
1916 src/Reflex/Dom/Xhr/ResponseType.hs
2017 src/Reflex/Dom/Xhr/Exception.hs
2118
@@ -45,7 +42,7 @@ library
4542 directory == 1.2.*,
4643 exception-transformers == 0.4.*,
4744 ghcjs-dom >= 0.7.0.2 && < 0.8,
48− jsaddle >=0.7.0.0 && <0.8,
45+ jsaddle >=0.8.0.1 && <0.9,
4946 -- keycode-0.2 has a bug on firefox
5047 keycode >= 0.2.1 && < 0.3,
5148 lens >= 4.7 && < 5,
@@ -65,12 +62,10 @@ library
6562 zenc == 0.1.*
6663
6764 if impl(ghcjs)
68− hs-source-dirs: src-ghcjs
6965 build-depends:
7066 ghcjs-base,
7167 hashable == 1.2.*
7268 else
73− hs-source-dirs: src-ghc
7469 if !os(windows)
7570 build-depends: unix == 2.7.*
7671
@@ -84,22 +79,21 @@ library
8479 Reflex.Dom.Builder.Static
8580 Reflex.Dom.Class
8681 Reflex.Dom.Internal
87−-- Reflex.Dom.Internal.Foreign
88−-- Reflex.Dom.Location
82+ Reflex.Dom.Location
8983 Reflex.Dom.Old
9084 Reflex.Dom.Time
91−-- Reflex.Dom.WebSocket
85+ Reflex.Dom.WebSocket
9286 Reflex.Dom.Widget
9387 Reflex.Dom.Widget.Basic
9488 Reflex.Dom.Widget.Input
9589 Reflex.Dom.Widget.Lazy
9690 Reflex.Dom.Widget.Resize
97−-- Reflex.Dom.Xhr
98−-- other-modules:
99−-- Reflex.Dom.WebSocket.Foreign
100−-- Reflex.Dom.Xhr.Foreign
101−-- Reflex.Dom.Xhr.ResponseType
102−-- Reflex.Dom.Xhr.Exception
91+ Reflex.Dom.Xhr
92+ other-modules:
93+ Reflex.Dom.WebSocket.Foreign
94+ Reflex.Dom.Xhr.Foreign
95+ Reflex.Dom.Xhr.ResponseType
96+ Reflex.Dom.Xhr.Exception
10397
10498 ghc-options: -Wall -fwarn-tabs -funbox-strict-fields -O2 -ferror-spans
10599
src-ghc/Reflex/Dom/Internal/Foreign.hsdeleted−189
@@ -1,189 +0,0 @@
1−{-# LANGUAGE CPP #-}
2−{-# LANGUAGE LambdaCase #-}
3−{-# LANGUAGE OverloadedStrings #-}
4−{-# LANGUAGE ScopedTypeVariables #-}
5−{-# LANGUAGE PatternSynonyms #-}
6−module Reflex.Dom.Internal.Foreign where
7−
8−import Control.Concurrent
9−import Control.Exception (bracket)
10−import Control.Lens hiding (set)
11−import Control.Monad
12−import Control.Monad.State.Strict hiding (forM, forM_, get, mapM, mapM_, sequence, sequence_)
13−import Data.ByteString (ByteString)
14−import qualified Data.ByteString as BS
15−import Data.Maybe
16−import Data.Monoid
17−import Data.Text (Text)
18−import qualified Data.Text as T
19−import Foreign.Marshal hiding (void)
20−import Foreign.Ptr
21−import GHCJS.DOM hiding (runWebGUI)
22−import GHCJS.DOM.Types (runJSM, askJSM, JSContextRef(..))
23−import GHCJS.DOM.Navigator
24−import GHCJS.DOM.Window
25−import System.Directory
26−import qualified GI.Gtk.Functions as Gtk (init, main)
27−import GI.WebKit2
28− (settingsSetEnableAccelerated2dCanvas, webInspectorShow,
29− webViewLoadUri, webViewLoadHtml, webViewGetInspector,
30− onWebViewLoadChanged, webViewSetSettings,
31− settingsSetEnableDeveloperExtras, settingsSetUserAgent,
32− settingsGetUserAgent, webViewGetSettings, webViewNew, WebView)
33−
34−#ifndef mingw32_HOST_OS
35−import System.Posix.Signals
36−#endif
37−import GI.GLib.Functions (timeoutAdd, idleAdd)
38−import GI.GLib.Constants (pattern PRIORITY_DEFAULT, pattern PRIORITY_HIGH)
39−import GI.Gtk.Objects.Widget
40− (widgetShowAll, onWidgetDestroy, widgetDestroy, widgetGetToplevel)
41−import GI.Gtk.Objects.Window
42− (windowSetPosition, windowSetDefaultSize, windowNew)
43−import GI.Gtk.Enums (WindowType(..), WindowPosition(..))
44−import GI.Gtk.Objects.ScrolledWindow (scrolledWindowNew)
45−import GI.Gtk.Objects.Adjustment (noAdjustment)
46−import GI.Gtk.Objects.Container (containerAdd)
47−import GI.Gtk.Functions (mainQuit)
48−import Control.Monad.Trans.Reader (ask)
49−
50−quitWebView :: WebView -> IO ()
51−quitWebView wv = void . idleAdd PRIORITY_DEFAULT $ do --TODO: Shouldn't this be Sync?
52− w <- widgetGetToplevel wv
53− widgetDestroy w
54− return False
55−
56−installQuitHandler :: WebView -> IO ()
57−#ifdef mingw32_HOST_OS
58−installQuitHandler wv = return () -- TODO: Maybe figure something out here for Windows users.
59−#else
60−installQuitHandler wv = void $ installHandler keyboardSignal (Catch (quitWebView wv)) Nothing
61−#endif
62−
63−runWebGUI :: ((WebView, JSContextRef) -> IO ()) -> IO ()
64−runWebGUI main = do
65− _ <- Gtk.init Nothing
66− window <- windowNew WindowTypeToplevel
67− _ <- timeoutAdd PRIORITY_HIGH 10 (yield >> return True)
68− windowSetDefaultSize window 900 600
69− windowSetPosition window WindowPositionCenter
70− scrollWin <- scrolledWindowNew noAdjustment noAdjustment
71− webView <- webViewNew
72− putStrLn "forking server!"
73− _ <- forkIO $ run 3706 $ do
74− ctx <- askJSM
75−-- liftIO $ forkIO $ forever $ do
76−-- threadDelay 1000000
77−-- runJSM syncPoint ctx
78− liftIO $ threadDelay 2000000
79− idleAdd PRIORITY_DEFAULT $ do
80− liftIO $ main (webView, ctx)
81− liftIO $ putStrLn "main exited"
82− return False
83− -- return False
84− forever $ do
85− liftIO $ threadDelay 100000
86− runJSM syncPoint ctx
87− settings <- webViewGetSettings webView
88− -- TODO settingsSetEnableUniversalAccessFromFileUris settings True
89− settingsSetEnableDeveloperExtras settings True
90− settingsSetEnableAccelerated2dCanvas settings False
91− webViewSetSettings webView settings
92− window `containerAdd` scrollWin
93− scrollWin `containerAdd` webView
94− _ <- onWidgetDestroy window mainQuit
95− widgetShowAll window
96−-- _ <- onWebViewLoadChanged webView $ \_ ->
97−-- -- TODO run jsaddle.js when load is finished
98−-- return ()
99− inspector <- webViewGetInspector webView
100− webInspectorShow inspector
101−-- _ <- inspector `on` inspectWebView $ \_ -> do
102−-- inspectorWindow <- windowNew
103−-- windowSetDefaultSize inspectorWindow 900 600
104−-- inspectorScrollWin <- scrolledWindowNew noAdjustment noAdjustment
105−-- inspectorWebView <- webViewNew
106−-- inspectorWindow `containerAdd` inspectorScrollWin
107−-- inspectorScrollWin `containerAdd` inspectorWebView
108−-- widgetShowAll inspectorWindow
109−-- return inspectorWebView
110− pwd <- getCurrentDirectory
111−-- webViewLoadHtml webView "" . Just $ "file://" <> T.pack pwd <> "/"
112− webViewLoadUri webView "http://localhost:3706/"
113− installQuitHandler webView
114− Gtk.main
115−
116−--foreign import ccall "wrapper"
117−-- wrapper :: JSObjectCallAsFunctionCallback' -> IO JSObjectCallAsFunctionCallback
118−--
119−--toJSObject :: JSContextRef -> [Ptr OpaqueJSValue] -> IO JSObjectRef
120−--toJSObject ctx args = do
121−-- o <- jsobjectmake ctx nullPtr nullPtr
122−-- iforM_ args $ \n a -> do
123−-- prop <- jsstringcreatewithutf8cstring $ show n
124−-- jsobjectsetproperty ctx o prop a 1 nullPtr
125−-- return o
126−--
127−--fromJSStringMaybe :: JSContextRef -> JSValueRef -> IO (Maybe Text)
128−--fromJSStringMaybe c t = do
129−-- isNull <- jsvalueisnull c t
130−-- if isNull then return Nothing else do
131−-- j <- jsvaluetostringcopy c t nullPtr
132−-- l <- jsstringgetmaximumutf8cstringsize j
133−-- s <- allocaBytes (fromIntegral l) $ \ps -> do
134−-- _ <- jsstringgetutf8cstring'_ j ps (fromIntegral l)
135−-- peekCString ps
136−-- return $ Just $ T.pack s
137−--
138−--fromJSBoolMaybe :: JSContextRef -> JSValueRef -> IO (Maybe Bool)
139−--fromJSBoolMaybe c t = do
140−-- isBool <- jsvalueisboolean c t
141−-- if not isBool then return Nothing else
142−-- Just <$> jsvaluetoboolean c t
143−--
144−--fromJSNumMaybe :: JSContextRef -> JSValueRef -> IO (Maybe Double)
145−--fromJSNumMaybe c t = do
146−-- isNum <- jsvalueisnumber c t
147−-- if not isNum then return Nothing else
148−-- Just <$> jsvaluetonumber c t nullPtr
149−--
150−--getLocationHost :: WebView -> IO Text
151−--getLocationHost wv = withWebViewContext wv $ \c -> do
152−-- script <- jsstringcreatewithutf8cstring "location.host"
153−-- lh <- jsevaluatescript c script nullPtr nullPtr 1 nullPtr
154−-- lh' <- fromJSStringMaybe c lh
155−-- return $ fromMaybe "" lh'
156−--
157−--getLocationProtocol :: WebView -> IO Text
158−--getLocationProtocol wv = withWebViewContext wv $ \c -> do
159−-- script <- jsstringcreatewithutf8cstring "location.protocol"
160−-- lp <- jsevaluatescript c script nullPtr nullPtr 1 nullPtr
161−-- lp' <- fromJSStringMaybe c lp
162−-- return $ fromMaybe "" lp'
163−--
164−--bsToArrayBuffer :: JSContextRef -> ByteString -> IO JSValueRef
165−--bsToArrayBuffer c bs = do
166−-- elems <- forM (BS.unpack bs) $ \x -> jsvaluemakenumber c $ fromIntegral x
167−-- let numElems = length elems
168−-- bracket (mallocArray numElems) free $ \elemsArr -> do
169−-- pokeArray elemsArr elems
170−-- a <- jsobjectmakearray c (fromIntegral numElems) elemsArr nullPtr
171−-- newUint8Array <- jsstringcreatewithutf8cstring "new Uint8Array(this)"
172−-- jsevaluatescript c newUint8Array a nullPtr 1 nullPtr
173−--
174−--bsFromArrayBuffer :: JSContextRef -> JSValueRef -> IO ByteString
175−--bsFromArrayBuffer c a = do
176−-- let getIntegral = fmap round . (\x -> jsvaluetonumber c x nullPtr)
177−-- getByteLength <- jsstringcreatewithutf8cstring "this.byteLength"
178−-- byteLength <- getIntegral =<< jsevaluatescript c getByteLength a nullPtr 1 nullPtr
179−-- toUint8Array <- jsstringcreatewithutf8cstring "new Uint8Array(this)"
180−-- uint8Array <- jsevaluatescript c toUint8Array a nullPtr 1 nullPtr
181−-- getIx <- jsstringcreatewithutf8cstring "this[0][this[1]]"
182−-- let arrayLookup i = do
183−-- i' <- jsvaluemakenumber c (fromIntegral i)
184−-- args <- toJSObject c [uint8Array, i']
185−-- getIntegral =<< jsevaluatescript c getIx args nullPtr 1 nullPtr
186−-- BS.pack <$> forM [0..byteLength-1] arrayLookup
187−--
188−--withWebViewContext :: WebView -> (JSContextRef -> IO a) -> IO a
189−--withWebViewContext wv f = f =<< webFrameGetGlobalContext =<< webViewGetMainFrame wv
src-ghc/Reflex/Dom/WebSocket/Foreign.hsdeleted−129
@@ -1,129 +0,0 @@
1−{-# LANGUAGE AllowAmbiguousTypes #-}
2−{-# LANGUAGE ConstraintKinds #-}
3−{-# LANGUAGE FlexibleContexts #-}
4−{-# LANGUAGE FlexibleInstances #-}
5−{-# LANGUAGE GADTs #-}
6−{-# LANGUAGE JavaScriptFFI #-}
7−{-# LANGUAGE MultiParamTypeClasses #-}
8−{-# LANGUAGE NoMonomorphismRestriction #-}
9−{-# LANGUAGE PolyKinds #-}
10−{-# LANGUAGE RankNTypes #-}
11−{-# LANGUAGE ScopedTypeVariables #-}
12−{-# LANGUAGE TemplateHaskell #-}
13−{-# LANGUAGE TypeFamilies #-}
14−{-# LANGUAGE UndecidableInstances #-}
15−
16−module Reflex.Dom.WebSocket.Foreign where
17−
18−import Prelude hiding (all, concat, concatMap, div, mapM, mapM_, sequence, span)
19−
20−import Control.Exception
21−import Control.Monad.State
22−import Data.ByteString (ByteString)
23−import qualified Data.ByteString as BS
24−import Data.Maybe (fromMaybe)
25−import Data.Text (Text)
26−import qualified Data.Text as T
27−import Data.Text.Encoding
28−import Foreign.Marshal hiding (void)
29−import Foreign.Ptr
30−import Foreign.Storable
31−import Graphics.UI.Gtk.WebKit.JavaScriptCore.JSBase
32−import Graphics.UI.Gtk.WebKit.JavaScriptCore.JSObjectRef
33−import Graphics.UI.Gtk.WebKit.JavaScriptCore.JSStringRef
34−import Graphics.UI.Gtk.WebKit.JavaScriptCore.JSValueRef
35−import Graphics.UI.Gtk.WebKit.WebView
36−
37−import Foreign.JavaScript.TH
38−
39−data JSWebSocket = JSWebSocket { wsValue :: JSValueRef
40− , wsContext :: JSContextRef
41− }
42−
43−importJS Unsafe "this[0]['send'](this[1])" "_sendWSTextData" [t| forall x m. MonadJS x m => JSRef x -> String -> m () |]
44−
45−sendWSTextData :: JSWebSocket -> String -> IO ()
46−sendWSTextData (JSWebSocket ws c) str = runWithJSContext (_sendWSTextData (JSRef_JavaScriptCore ws) str) c
47−
48−class IsWebSocketMessage a where
49− webSocketSend :: JSWebSocket -> a -> IO ()
50−
51−-- Use binary websocket communication for ByteString
52−instance IsWebSocketMessage ByteString where
53− webSocketSend (JSWebSocket ws c) bs = do
54− elems <- forM (BS.unpack bs) $ \x -> jsvaluemakenumber c $ fromIntegral x
55− let numElems = length elems
56− bs' <- bracket (mallocArray numElems) free $ \elemsArr -> do
57− pokeArray elemsArr elems
58− a <- jsobjectmakearray c (fromIntegral numElems) elemsArr nullPtr
59− newUint8Array <- jsstringcreatewithutf8cstring "new Uint8Array(this)"
60− jsevaluatescript c newUint8Array a nullPtr 1 nullPtr
61− send <- jsstringcreatewithutf8cstring ""
62− sendArgs <- toJSObject c [ws, bs']
63− _ <- jsevaluatescript c send sendArgs nullPtr 1 nullPtr
64− return ()
65−
66−-- Use plaintext websocket communication for Text
67−instance IsWebSocketMessage Text where
68− webSocketSend jws t = sendWSTextData jws (T.unpack t)
69−
70−importJS Unsafe "this[0]['close'](this[1], this[2])" "_closeWS" [t| forall x m. MonadJS x m => JSRef x -> Double -> String -> m () |]
71−
72−closeWebSocket :: JSWebSocket -> Double -> Text -> IO ()
73−closeWebSocket (JSWebSocket ws c) code reason = do
74− runWithJSContext (_closeWS (JSRef_JavaScriptCore ws) code (T.unpack reason)) c
75−
76−newWebSocket
77− :: WebView
78− -> Text -- url
79− -> (Either ByteString a -> IO ()) -- onmessage
80− -> IO () -- onopen
81− -> IO () -- onerror
82− -> ((Bool, Word, Text) -> IO ()) -- onclose
83− -> IO JSWebSocket
84−newWebSocket wv url onMessage onOpen onError onClose = withWebViewContext wv $ \c -> do
85− url' <- jsvaluemakestring c =<< jsstringcreatewithutf8cstring (T.unpack url)
86− newWSArgs <- toJSObject c [url']
87− newWS <- jsstringcreatewithutf8cstring "(function(that) { var ws = new WebSocket(that[0]); ws['binaryType'] = 'arraybuffer'; return ws; })(this)"
88− ws <- jsevaluatescript c newWS newWSArgs nullPtr 1 nullPtr
89− onMessage' <- wrapper $ \_ _ _ _ args _ -> do
90− e <- peekElemOff args 0
91− dataProp <- jsstringcreatewithutf8cstring "data"
92− msg <- jsobjectgetproperty c e dataProp nullPtr
93− msg' <- fromJSStringMaybe c msg
94− case msg' of
95− Nothing -> return ()
96− Just m -> onMessage $ Left $ encodeUtf8 m
97− jsvaluemakeundefined c
98− onMessageCb <- jsobjectmakefunctionwithcallback c nullPtr onMessage'
99− onOpen' <- wrapper $ \_ _ _ _ _ _ -> do
100− onOpen
101− jsvaluemakeundefined c
102− onOpenCb <- jsobjectmakefunctionwithcallback c nullPtr onOpen'
103− onError' <- wrapper $ \_ _ _ _ _ _ -> do
104− onError
105− jsvaluemakeundefined c
106− onErrorCb <- jsobjectmakefunctionwithcallback c nullPtr onError'
107− onClose' <- wrapper $ \_ _ _ _ args _ -> do
108− e <- peekElemOff args 0
109− propWasClean <- jsstringcreatewithutf8cstring "wasClean"
110− propCode <- jsstringcreatewithutf8cstring "code"
111− propReason <- jsstringcreatewithutf8cstring "reason"
112− wasClean <- fmap (fromMaybe False) $ fromJSBoolMaybe c
113− =<< jsobjectgetproperty c e propWasClean nullPtr
114− code <- fmap (fromMaybe 1000) $ fromJSNumMaybe c
115− =<< jsobjectgetproperty c e propCode nullPtr
116− reason <- fmap (fromMaybe mempty) $ fromJSStringMaybe c
117− =<< jsobjectgetproperty c e propReason nullPtr
118− onClose (wasClean, truncate code, reason)
119− jsvaluemakeundefined c
120− onCloseCb <- jsobjectmakefunctionwithcallback c nullPtr onClose'
121− o <- toJSObject c [ws, onMessageCb, onOpenCb, onErrorCb, onCloseCb]
122− addCbs <- jsstringcreatewithutf8cstring "this[0]['onmessage'] = this[1]; this[0]['onopen'] = this[2]; this[0]['onerror'] = this[3]; this[0]['onclose'] = this[4];"
123− _ <- jsevaluatescript c addCbs o nullPtr 1 nullPtr
124− return $ JSWebSocket ws c
125−
126−onBSMessage :: Either ByteString b -> ByteString
127−onBSMessage = either id (error "onBSMessage: ghc env expects ByteString.")
128−
129−type JSVal = ()
src-ghc/Reflex/Dom/Xhr/Foreign.hsdeleted−246
@@ -1,246 +0,0 @@
1−{-# LANGUAGE FlexibleInstances #-}
2−{-# LANGUAGE OverloadedStrings #-}
3−{-# LANGUAGE QuasiQuotes #-}
4−{-# LANGUAGE TypeSynonymInstances #-}
5−module Reflex.Dom.Xhr.Foreign ( module Reflex.Dom.Xhr.Foreign
6− , XhrResponseType
7− ) where
8−
9−import Control.Concurrent.MVar
10−import Control.Exception.Base
11−import Control.Monad
12−import Data.Text (Text)
13−import qualified Data.Text as T
14−import GHCJS.DOM.File
15−import Graphics.UI.Gtk.WebKit.JavaScriptCore.JSBase
16−import Graphics.UI.Gtk.WebKit.JavaScriptCore.JSObjectRef
17−import Graphics.UI.Gtk.WebKit.JavaScriptCore.JSStringRef
18−import Graphics.UI.Gtk.WebKit.JavaScriptCore.JSValueRef
19−import Graphics.UI.Gtk.WebKit.Types hiding (Text)
20−import Reflex.Dom.Xhr.Exception
21−import Reflex.Dom.Xhr.ResponseType
22−import System.Glib.FFI
23−
24−import Text.RawString.QQ
25−
26−data XMLHttpRequest
27− = XMLHttpRequest { xhrValue :: JSValueRef
28− , xhrContext :: JSContextRef --TODO: Get rid of this
29− }
30− deriving (Eq, Ord)
31−
32−class IsXhrPayload a where
33− xmlHttpRequestSend :: XMLHttpRequest -> a -> IO ()
34−
35−instance IsXhrPayload () where
36− xmlHttpRequestSend xhr _ = xmlHttpRequestSendPayload xhr Nothing
37−
38−instance IsXhrPayload Text where
39− xmlHttpRequestSend xhr = xmlHttpRequestSendPayload xhr . Just
40−
41−instance IsXhrPayload String where
42− xmlHttpRequestSend xhr = xmlHttpRequestSendPayload xhr . Just . T.pack
43−
44−instance IsXhrPayload File where
45− xmlHttpRequestSend = error "xmlHttpRequestSend{File}: not implemented"
46−
47−stringToJSValue :: JSContextRef -> Text -> IO JSValueRef
48−stringToJSValue ctx s = jsvaluemakestring ctx =<< jsstringcreatewithutf8cstring (T.unpack s)
49−
50−fromResponseType :: XhrResponseType -> Text
51−fromResponseType XhrResponseType_Default = ""
52−fromResponseType XhrResponseType_ArrayBuffer = "arraybuffer"
53−fromResponseType XhrResponseType_Blob = "blob"
54−fromResponseType XhrResponseType_Text = "text"
55−
56−toResponseType :: Text -> Maybe XhrResponseType
57−toResponseType "" = Just XhrResponseType_Default
58−toResponseType "arraybuffer" = Just XhrResponseType_ArrayBuffer
59−toResponseType "blob" = Just XhrResponseType_Blob
60−toResponseType "text" = Just XhrResponseType_Text
61−toResponseType _ = Nothing
62−
63−xmlHttpRequestNew :: WebView -> IO XMLHttpRequest
64−xmlHttpRequestNew wv = withWebViewContext wv $ \jsContext -> do
65− xhrScript <- jsstringcreatewithutf8cstring "new XMLHttpRequest()"
66− xhr' <- jsevaluatescript jsContext xhrScript nullPtr nullPtr 1 nullPtr
67− jsvalueprotect jsContext xhr'
68− return $ XMLHttpRequest xhr' jsContext
69−
70−xmlHttpRequestOpen :: XMLHttpRequest -> Text -> Text -> Bool -> Text -> Text -> IO ()
71−xmlHttpRequestOpen xhr method url async user password = do
72− let c = xhrContext xhr
73− method' <- stringToJSValue c method
74− url' <- stringToJSValue c url
75− async' <- jsvaluemakeboolean (xhrContext xhr) async
76− user' <- stringToJSValue c user
77− password' <- stringToJSValue c password
78− o <- toJSObject c [xhrValue xhr, method', url', async', user', password']
79− script <- jsstringcreatewithutf8cstring "this[0].open(this[1], this[2], this[3], this[4], this[5])"
80− _ <- jsevaluatescript c script o nullPtr 1 nullPtr
81− return ()
82−
83−xmlHttpRequestOnreadystatechange :: XMLHttpRequest -> IO () -> IO ()
84−xmlHttpRequestOnreadystatechange xhr userCallback = do
85− let c = xhrContext xhr
86− fp <- wrapper $ \_ _ _ _ _ _ -> do
87− userCallback
88− jsvaluemakeundefined c
89− cb <- jsobjectmakefunctionwithcallback c nullPtr fp
90− o <- toJSObject c [xhrValue xhr, cb]
91− script <- jsstringcreatewithutf8cstring "this[0].onreadystatechange=this[1]"
92− _ <- jsevaluatescript c script o nullPtr 1 nullPtr
93− return ()
94−
95−xmlHttpRequestGetReadyState :: XMLHttpRequest -> IO Word
96−xmlHttpRequestGetReadyState xhr = do
97− let c = xhrContext xhr
98− script <- jsstringcreatewithutf8cstring "this.readyState"
99− rs <- jsevaluatescript c script (xhrValue xhr) nullPtr 1 nullPtr
100− d <- jsvaluetonumber c rs nullPtr
101− return $ truncate d
102−
103−xmlHttpRequestGetResponseType :: XMLHttpRequest -> IO (Maybe XhrResponseType)
104−xmlHttpRequestGetResponseType xhr = do
105− script <- jsstringcreatewithutf8cstring "this.responseType"
106− rt <- jsevaluatescript (xhrContext xhr) script (xhrValue xhr) nullPtr 1 nullPtr
107− ms <- fromJSStringMaybe (xhrContext xhr) rt
108− return $ join $ fmap toResponseType ms
109−
110−xmlHttpRequestGetResponse :: XMLHttpRequest -> IO (Maybe XhrResponseBody)
111−xmlHttpRequestGetResponse xhr = do
112− let c = xhrContext xhr
113− mrt <- xmlHttpRequestGetResponseType xhr
114− script <- jsstringcreatewithutf8cstring "this.response"
115− t <- jsevaluatescript c script (xhrValue xhr) nullPtr 1 nullPtr
116− isNull <- jsvalueisnull c t
117− if isNull then return Nothing else case mrt of
118− Just XhrResponseType_ArrayBuffer -> Just . XhrResponseBody_ArrayBuffer <$> bsFromArrayBuffer c t
119− Just XhrResponseType_Blob -> Just . XhrResponseBody_Blob . Blob . castForeignPtr <$> newForeignPtr_ t
120− Just XhrResponseType_Default -> fmap XhrResponseBody_Default <$> fromJSStringMaybe c t
121− Just XhrResponseType_Text -> fmap XhrResponseBody_Text <$> fromJSStringMaybe c t
122− _ -> return Nothing
123−
124−xmlHttpRequestGetResponseText :: XMLHttpRequest -> IO (Maybe Text)
125−xmlHttpRequestGetResponseText xhr = do
126− let c = xhrContext xhr
127− script <- jsstringcreatewithutf8cstring "this.responseText"
128− t <- jsevaluatescript c script (xhrValue xhr) nullPtr 1 nullPtr
129− fromJSStringMaybe c t
130−
131−xmlHttpRequestSendPayload :: XMLHttpRequest -> Maybe Text -> IO ()
132−xmlHttpRequestSendPayload xhr payload = do
133− let c = xhrContext xhr
134− result <- newEmptyMVar
135− let wrapper' x = wrapper $ \_ _ _ _ _ _ -> putMVar result x >> jsvaluemakeundefined c
136− bracket (wrapper' $ Just XhrException_Aborted) freeHaskellFunPtr $ \a -> do
137− onAbort <- jsobjectmakefunctionwithcallback c nullPtr a
138− bracket (wrapper' $ Just XhrException_Error) freeHaskellFunPtr $ \e -> do
139− onError <- jsobjectmakefunctionwithcallback c nullPtr e
140− bracket (wrapper' Nothing) freeHaskellFunPtr $ \l -> do
141− onLoad <- jsobjectmakefunctionwithcallback c nullPtr l
142− d <- case payload of
143− Nothing -> jsvaluemakeundefined c
144− Just payload' -> stringToJSValue c payload'
145− o <- toJSObject c [xhrValue xhr, d, onError, onAbort, onLoad]
146− s <- jsstringcreatewithutf8cstring send
147− _ <- jsevaluatescript c s o nullPtr 1 nullPtr
148− takeMVar result >>= mapM_ throwIO
149− where
150− send = [r|
151− (function (xhr, d, onError, onAbort, onLoad) {
152− var clear;
153− var error = function () {
154− clear(); onError();
155− };
156− var abort = function () {
157− clear(); onAbort();
158− };
159− var load = function () {
160− clear(); onLoad();
161− };
162− clear = function () {
163− xhr.removeEventListener('error', error);
164− xhr.removeEventListener('abort', abort);
165− xhr.removeEventListener('load', load);
166− }
167− xhr.addEventListener('error', error);
168− xhr.addEventListener('abort', abort);
169− xhr.addEventListener('load', load);
170− if(d) {
171− xhr.send(d);
172− } else {
173− xhr.send();
174− }
175− })(this[0], this[1], this[2], this[3], this[4])
176− |]
177−
178−xmlHttpRequestSetRequestHeader :: XMLHttpRequest -> Text -> Text -> IO ()
179−xmlHttpRequestSetRequestHeader xhr header value = do
180− let c = xhrContext xhr
181− header' <- stringToJSValue c header
182− value' <- stringToJSValue c value
183− o <- toJSObject c [xhrValue xhr, header', value']
184− script <- jsstringcreatewithutf8cstring "this[0].setRequestHeader(this[1], this[2])"
185− _ <- jsevaluatescript c script o nullPtr 1 nullPtr
186− return ()
187−
188−xmlHttpRequestSetResponseType :: XMLHttpRequest -> Text -> IO ()
189−xmlHttpRequestSetResponseType xhr t = do
190− let c = xhrContext xhr
191− t' <- stringToJSValue c t
192− o <- toJSObject c [xhrValue xhr, t']
193− script <- jsstringcreatewithutf8cstring "this[0].responseType = this[1]"
194− _ <- jsevaluatescript c script o nullPtr 1 nullPtr
195− return ()
196−
197−xmlHttpRequestGetStatus :: XMLHttpRequest -> IO Word
198−xmlHttpRequestGetStatus xhr = do
199− let c = xhrContext xhr
200− script <- jsstringcreatewithutf8cstring "this.status"
201− s <- jsevaluatescript c script (xhrValue xhr) nullPtr 1 nullPtr
202− d <- jsvaluetonumber c s nullPtr
203− return $ truncate d
204−
205−xmlHttpRequestGetStatusText :: XMLHttpRequest -> IO Text
206−xmlHttpRequestGetStatusText xhr =
207− xmlAuxHttpRequestGetWithJS xhr "this.statusText"
208−
209−xmlHttpRequestSetWithCredentials :: XMLHttpRequest -> Bool -> IO ()
210−xmlHttpRequestSetWithCredentials xhr b = do
211− let c = xhrContext xhr
212− b' <- jsvaluemakeboolean c b
213− o <- toJSObject c [xhrValue xhr, b']
214− script <- jsstringcreatewithutf8cstring "this[0].withCredentials = this[1]"
215− _ <- jsevaluatescript c script o nullPtr 1 nullPtr
216− return ()
217−
218−xmlHttpRequestGetAllResponseHeaders :: XMLHttpRequest -> IO Text
219−xmlHttpRequestGetAllResponseHeaders xhr =
220− xmlAuxHttpRequestGetWithJS xhr "this.getAllResponseHeaders()"
221−
222−xmlHttpRequestGetResponseHeader :: XMLHttpRequest -> Text -> IO Text
223−xmlHttpRequestGetResponseHeader xhr hdr = do
224− let c = xhrContext xhr
225− t' <- stringToJSValue c hdr
226− o <- toJSObject c [xhrValue xhr, t']
227− script <- jsstringcreatewithutf8cstring "this[0].getResponseHeader(this[1])"
228− t <- jsevaluatescript c script o nullPtr 1 nullPtr
229− xmlAuxJsGetString c t
230−
231−xmlAuxHttpRequestGetWithJS :: XMLHttpRequest -> String -> IO Text
232−xmlAuxHttpRequestGetWithJS xhr jsScript = do
233− let c = xhrContext xhr
234− script <- jsstringcreatewithutf8cstring jsScript
235− t <- jsevaluatescript c script (xhrValue xhr) nullPtr 1 nullPtr
236− xmlAuxJsGetString c t
237−
238−xmlAuxJsGetString :: JSContextRef -> JSValueRef -> IO Text
239−xmlAuxJsGetString c t = do
240− j <- jsvaluetostringcopy c t nullPtr
241− l <- jsstringgetmaximumutf8cstringsize j
242− s <- allocaBytes (fromIntegral l) $ \ps -> do
243− _ <- jsstringgetutf8cstring'_ j ps (fromIntegral l)
244− peekCString ps
245− return $ T.pack s
246−
src-ghcjs/Reflex/Dom/Internal/Foreign.hsdeleted−48
@@ -1,48 +0,0 @@
1−{-# LANGUAGE ForeignFunctionInterface #-}
2−{-# LANGUAGE JavaScriptFFI #-}
3−module Reflex.Dom.Internal.Foreign ( runWebGUI
4− , WebView
5− ) where
6−
7−import Data.ByteString (ByteString)
8−import qualified Data.ByteString as BS
9−import Foreign
10−import Foreign.C
11−import qualified GHCJS.Buffer as JS
12−import GHCJS.DOM
13−import GHCJS.DOM.Types
14−import qualified GHCJS.Marshal.Pure as JS
15−import GHCJS.Types
16−import JavaScript.TypedArray.ArrayBuffer as JS
17−
18−data WebView = WebView
19−
20−runWebGUI :: ((WebView, JSContextRef) -> IO ()) -> IO ()
21−runWebGUI main = main (WebView, ())
22−
23−quitWebView :: WebView -> IO ()
24−quitWebView = error "quitWebView: unimplemented in GHCJS"
25−
26−foreign import javascript unsafe "location['host']" getLocationHost_ :: IO JSString
27−
28−getLocationHost :: FromJSString r => a -> IO r
29−getLocationHost _ = fmap fromJSString getLocationHost_
30−
31−foreign import javascript unsafe "location['protocol']" getLocationProtocol_ :: IO JSString
32−
33−getLocationProtocol :: FromJSString r => a -> IO r
34−getLocationProtocol _ = fmap fromJSString getLocationProtocol_
35−
36−withWebViewContext :: a -> (a -> IO b) -> IO b
37−withWebViewContext a f = f a
38−
39−foreign import javascript safe "new DataView($3,$1,$2)" js_dataView :: Int -> Int -> JSVal -> JSVal
40−
41−foreign import javascript unsafe "new Uint8Array($1_1['buf'], $1_2, $2)['buffer']" extractByteArray :: Ptr CChar -> Int -> IO JSVal
42−
43−bsToArrayBuffer :: a -> ByteString -> IO JSVal
44−bsToArrayBuffer _ bs = BS.useAsCString bs $ \cStr -> do
45− extractByteArray cStr $ BS.length bs
46−
47−bsFromArrayBuffer :: a -> JSVal -> IO ByteString
48−bsFromArrayBuffer _ ab = fmap (JS.toByteString 0 Nothing . JS.createFromArrayBuffer) $ JS.unsafeFreeze $ JS.pFromJSVal ab
src/Foreign/JavaScript/TH.hs−2
@@ -60,8 +60,6 @@ import Data.Word
6060import Foreign.C.Types
6161import Foreign.Ptr
6262import Text.Encoding.Z
63−
64−import Reflex.Dom.Internal.Foreign (WebView)
6563#else
6664import Data.Word (Word8)
6765import Control.Lens.Operators ((^.))
src/Reflex/Dom/Builder/Immediate.hs+3−3
@@ -65,13 +65,13 @@ import qualified GHCJS.DOM.HTMLInputElement as Input
6565import qualified GHCJS.DOM.HTMLSelectElement as Select
6666import qualified GHCJS.DOM.HTMLTextAreaElement as TextArea
6767import GHCJS.DOM.MouseEvent
68−import GHCJS.DOM.Node (appendChild_, getOwnerDocumentUnchecked, getParentNodeUnchecked, getPreviousSiblingUnchecked,
69− removeChild_, setNodeValue, toNode)
68+import GHCJS.DOM.Node (appendChild_, getOwnerDocumentUnchecked, getParentNodeUnchecked,
69+ setNodeValue, toNode)
7070import qualified GHCJS.DOM.Node as DOM (insertBefore_)
7171import GHCJS.DOM.Types
7272 (liftJSM, askJSM, runJSM, JSM, MonadJSM(..),
7373 FocusEvent, IsElement, IsEvent, IsNode, KeyboardEvent, Node,
74− ToDOMString, TouchEvent, WheelEvent, strictEqual, uncheckedCastTo)
74+ ToDOMString, TouchEvent, WheelEvent, uncheckedCastTo)
7575import qualified GHCJS.DOM.Types as DOM
7676import GHCJS.DOM.UIEvent
7777import qualified GHCJS.DOM.Window as Window
src/Reflex/Dom/Location.hs+8−7
@@ -1,12 +1,13 @@
11module Reflex.Dom.Location (getLocationHost, getLocationProtocol) where
22
33import Data.Text (Text)
4−import Reflex.Dom.Class
4+import GHCJS.DOM.Types (MonadJSM)
5+import GHCJS.DOM (currentWindowUnchecked)
6+import GHCJS.DOM.Window (getLocationUnchecked)
7+import GHCJS.DOM.Location (getProtocol, getHost)
58
6−import Control.Monad.IO.Class
9+getLocationHost :: (MonadJSM m) => m Text
10+getLocationHost = currentWindowUnchecked >>= getLocationUnchecked >>= getHost
711
8−getLocationHost :: (MonadIO m) => WebViewSingleton x -> m Text
9−getLocationHost (WebViewSingleton wv) = liftIO $ F.getLocationHost wv
10−
11−getLocationProtocol :: (MonadIO m) => WebViewSingleton x -> m Text
12−getLocationProtocol (WebViewSingleton wv) = liftIO $ F.getLocationProtocol wv
12+getLocationProtocol :: (MonadJSM m) => m Text
13+getLocationProtocol = currentWindowUnchecked >>= getLocationUnchecked >>= getProtocol
src/Reflex/Dom/WebSocket.hs+20−19
@@ -32,7 +32,7 @@ import Reflex.TriggerEvent.Class
3232
3333import Control.Concurrent
3434import Control.Concurrent.STM
35−import Control.Exception (SomeException, catch)
35+import Control.Exception (SomeException)
3636import Control.Lens
3737import Control.Monad hiding (forM, forM_, mapM, mapM_, sequence)
3838import Control.Monad.IO.Class
@@ -42,6 +42,8 @@ import Data.Default
4242import Data.IORef
4343import Data.Maybe (isJust)
4444import Data.Text
45+import GHCJS.DOM.Types (runJSM, askJSM, MonadJSM, liftJSM, JSM)
46+import qualified Language.Javascript.JSaddle.Monad as JS (catch)
4547
4648data WebSocketConfig t a
4749 = WebSocketConfig { _webSocketConfig_send :: Event t [a]
@@ -72,12 +74,12 @@ instance (IsWebSocketMessage a, IsWebSocketMessage b) => IsWebSocketMessage (Eit
7274 webSocketSend jws (Right a) = webSocketSend jws a
7375
7476
75−webSocket :: (MonadIO m, MonadIO (Performable m), HasWebView m, PerformEvent t m, TriggerEvent t m, PostBuild t m, IsWebSocketMessage a) => Text -> WebSocketConfig t a -> m (WebSocket t)
77+webSocket :: (MonadJSM m, MonadJSM (Performable m), HasJSContext m, PerformEvent t m, TriggerEvent t m, PostBuild t m, IsWebSocketMessage a) => Text -> WebSocketConfig t a -> m (WebSocket t)
7678webSocket url config = webSocket' url config onBSMessage
7779
78−webSocket' :: (MonadIO m, MonadIO (Performable m), HasWebView m, PerformEvent t m, TriggerEvent t m, PostBuild t m, IsWebSocketMessage a) => Text -> WebSocketConfig t a -> (Either ByteString JSVal -> b) -> m (RawWebSocket t b)
80+webSocket' :: (MonadJSM m, MonadJSM (Performable m), HasJSContext m, PerformEvent t m, TriggerEvent t m, PostBuild t m, IsWebSocketMessage a) => Text -> WebSocketConfig t a -> (Either ByteString JSVal -> JSM b) -> m (RawWebSocket t b)
7981webSocket' url config onRawMessage = do
80− wv <- fmap unWebViewSingleton askWebView
82+ wv <- fmap unJSContextSingleton askJSContext
8183 (eRecv, onMessage) <- newTriggerEvent
8284 currentSocketRef <- liftIO $ newIORef Nothing
8385 (eOpen, triggerEOpen) <- newTriggerEventWithOnComplete
@@ -88,27 +90,26 @@ webSocket' url config onRawMessage = do
8890 let onOpen = triggerEOpen () $ liftIO $ void $ atomically $ tryPutTMVar isOpen ()
8991 onError = triggerEError ()
9092 onClose args = do
91− triggerEClose args
92− --TODO: Is the fork necessary, or do event handlers run in their own threads automatically?
93− void $ forkIO $ do
94− _ <- liftIO $ atomically $ tryTakeTMVar isOpen
95− liftIO $ writeIORef currentSocketRef Nothing
96− when (_webSocketConfig_reconnect config) $ do
97− liftIO $ threadDelay 1000000
98− start
93+ liftIO $ triggerEClose args
94+ _ <- liftIO $ atomically $ tryTakeTMVar isOpen
95+ liftIO $ writeIORef currentSocketRef Nothing
96+ when (_webSocketConfig_reconnect config) $ do
97+ liftIO $ threadDelay 1000000
98+ start
9999 start = do
100− ws <- liftIO $ newWebSocket wv url (onMessage . onRawMessage) onOpen onError onClose
100+ ws <- newWebSocket wv url (onRawMessage >=> liftIO . onMessage) (liftIO onOpen) (liftIO onError) onClose
101101 liftIO $ writeIORef currentSocketRef $ Just ws
102102 return ()
103− performEvent_ . (liftIO start <$) =<< getPostBuild
103+ performEvent_ . (liftJSM start <$) =<< getPostBuild
104104 performEvent_ $ ffor (_webSocketConfig_send config) $ \payloads -> forM_ payloads $ \payload ->
105105 liftIO $ atomically $ writeTQueue payloadQueue payload
106− performEvent_ $ ffor (_webSocketConfig_close config) $ \(code,reason) -> liftIO $ do
107− mws <- readIORef currentSocketRef
106+ performEvent_ $ ffor (_webSocketConfig_close config) $ \(code,reason) -> liftJSM $ do
107+ mws <- liftIO $ readIORef currentSocketRef
108108 case mws of
109109 Nothing -> return ()
110110 Just ws -> closeWebSocket ws (fromIntegral code) reason
111111
112+ ctx <- askJSM
112113 _ <- liftIO $ forkIO $ forever $ do
113114 payload <- atomically $ do
114115 pl <- readTQueue payloadQueue
@@ -118,9 +119,9 @@ webSocket' url config onRawMessage = do
118119 mws <- liftIO $ readIORef currentSocketRef
119120 success <- case mws of
120121 Nothing -> return False
121− Just ws -> liftIO ((webSocketSend ws payload >> return True)
122− `catch`
123− (\(_ :: SomeException) -> return False))
122+ Just ws -> runJSM ((webSocketSend ws payload >> return True)
123+ `JS.catch`
124+ (\(_ :: SomeException) -> return False)) ctx
124125 unless success $ atomically $ unGetTQueue payloadQueue payload
125126 return $ RawWebSocket eRecv eOpen eError eClose
126127
src-ghcjs/Reflex/Dom/WebSocket/Foreign.hs → src/Reflex/Dom/WebSocket/Foreign.hsrenamed+37−29
@@ -1,5 +1,9 @@
1+{-# LANGUAGE CPP #-}
2+#ifdef ghcjs_HOST_OS
13{-# LANGUAGE ForeignFunctionInterface #-}
24{-# LANGUAGE JavaScriptFFI #-}
5+#endif
6+{-# LANGUAGE LambdaCase #-}
37
48module Reflex.Dom.WebSocket.Foreign
59 ( module Reflex.Dom.WebSocket.Foreign
@@ -8,7 +12,6 @@ module Reflex.Dom.WebSocket.Foreign
812
913import Prelude hiding (all, concat, concatMap, div, mapM, mapM_, sequence, span)
1014
11−import Control.Monad.IO.Class
1215import Control.Monad.Reader
1316import Data.ByteString (ByteString)
1417import qualified Data.ByteString as BS
@@ -18,72 +21,77 @@ import Data.Text.Encoding
1821import GHCJS.Buffer
1922import GHCJS.DOM.CloseEvent
2023import GHCJS.DOM.EventM (on)
21−import GHCJS.DOM.EventTargetClosures (EventName, unsafeEventName)
2224import GHCJS.DOM.MessageEvent
2325import GHCJS.DOM.Types hiding (Text)
2426import qualified GHCJS.DOM.WebSocket as GD
25−import GHCJS.Foreign.Internal
26−import GHCJS.Marshal.Pure
27+import GHCJS.Foreign (JSType(..), jsTypeOf)
2728import GHCJS.Types
2829import JavaScript.TypedArray.ArrayBuffer as JS
30+import Language.Javascript.JSaddle.Helper (mutableArrayBufferFromJSVal)
31+import Language.Javascript.JSaddle.Types (ghcjsPure)
32+#ifndef ghcjs_HOST_OS
33+import Language.Javascript.JSaddle.Object (new, jsg)
34+#endif
2935
3036data JSWebSocket = JSWebSocket { unWebSocket :: WebSocket }
3137
3238class IsWebSocketMessage a where
33− webSocketSend :: JSWebSocket -> a -> IO ()
39+ webSocketSend :: JSWebSocket -> a -> JSM ()
3440
3541-- Use binary websocket communication for ByteString
3642-- Note: Binary websockets may not work correctly in IE 11 and below
3743instance IsWebSocketMessage ByteString where
3844 webSocketSend (JSWebSocket ws) bs = do
39− let (b, off, len) = fromByteString bs
45+ (b, off, len) <- ghcjsPure $ fromByteString bs
4046 ab <- ArrayBuffer <$> if BS.length bs == 0 --TODO: remove this logic when https://github.com/ghcjs/ghcjs-base/issues/49 is fixed
41− then jsval . getArrayBuffer <$> create 0
42− else return $ js_dataView off len $ jsval $ getArrayBuffer b
47+ then create 0 >>= ghcjsPure . getArrayBuffer >>= ghcjsPure . jsval
48+ else do
49+ ref <- ghcjsPure (getArrayBuffer b) >>= ghcjsPure . jsval
50+ js_dataView off len ref -- new (jsg "DataView") (ref, off, len)
4351 GD.send ws $ Just ab
4452
4553-- Use plaintext websocket communication for Text, and String
4654instance IsWebSocketMessage Text where
4755 webSocketSend (JSWebSocket ws) = GD.sendString ws . T.unpack
4856
49−closeWebSocket :: JSWebSocket -> Word -> Text -> IO ()
57+closeWebSocket :: JSWebSocket -> Word -> Text -> JSM ()
5058closeWebSocket (JSWebSocket ws) = GD.close ws
5159
52−-- TODO: remove after upgrade to ghcjs-dom >= 0.3
53−-- in ghcjs-dom 0.2 this has type Event, we want CloseEvent
54−closeEvent :: EventName WebSocket CloseEvent
55−closeEvent = unsafeEventName (toJSString "close")
56−
5760newWebSocket
5861 :: a
5962 -> Text -- url
60− -> (Either ByteString JSVal -> IO ()) -- onmessage
61− -> IO () -- onopen
62− -> IO () -- onerror
63− -> ((Bool, Word, Text) -> IO ()) -- onclose
64− -> IO JSWebSocket
63+ -> (Either ByteString JSVal -> JSM ()) -- onmessage
64+ -> JSM () -- onopen
65+ -> JSM () -- onerror
66+ -> ((Bool, Word, Text) -> JSM ()) -- onclose
67+ -> JSM JSWebSocket
6568newWebSocket _ url onMessage onOpen onError onClose = do
6669 ws <- GD.newWebSocket url (Just [] :: Maybe [Text])
6770 GD.setBinaryType ws "arraybuffer"
68− _ <- on ws GD.open $ liftIO onOpen
69− _ <- on ws GD.error $ liftIO onError
70− _ <- on ws closeEvent $ do
71+ _ <- on ws GD.open $ liftJSM onOpen
72+ _ <- on ws GD.error $ liftJSM onError
73+ _ <- on ws GD.closeEvent $ do
7174 e <- ask
7275 wasClean <- getWasClean e
7376 code <- getCode e
7477 reason <- getReason e
75− liftIO $ onClose (wasClean, code, reason)
78+ liftJSM $ onClose (wasClean, code, reason)
7679 _ <- on ws GD.message $ do
7780 e <- ask
7881 d <- getData e
79− liftIO $ case jsTypeOf d of
82+ liftJSM $ ghcjsPure (jsTypeOf d) >>= \case
8083 String -> onMessage $ Right d
8184 _ -> do
82− ab <- unsafeFreeze $ pFromJSVal d
83− onMessage $ Left $ toByteString 0 Nothing $ createFromArrayBuffer ab
85+ ab <- mutableArrayBufferFromJSVal d >>= unsafeFreeze
86+ ghcjsPure (createFromArrayBuffer ab) >>= ghcjsPure . toByteString 0 Nothing >>= onMessage . Left
8487 return $ JSWebSocket ws
8588
86−foreign import javascript safe "new DataView($3,$1,$2)" js_dataView :: Int -> Int -> JSVal -> JSVal
89+#ifdef ghcjs_HOST_OS
90+foreign import javascript safe "new DataView($3,$1,$2)" js_dataView :: Int -> Int -> JSVal -> IO JSVal
91+#else
92+js_dataView :: Int -> Int -> JSVal -> JSM JSVal
93+js_dataView off len ref = new (jsg "DataView") (ref, off, len)
94+#endif
8795
88−onBSMessage :: Either ByteString JSVal -> ByteString
89−onBSMessage = either id (encodeUtf8 . pFromJSVal)
96+onBSMessage :: Either ByteString JSVal -> JSM ByteString
97+onBSMessage = either return (\v -> encodeUtf8 <$> fromJSValUnchecked v)
src/Reflex/Dom/Xhr.hs+29−28
@@ -63,6 +63,9 @@ import Reflex.Class
6363import Reflex.Dom.Class
6464import Reflex.PerformEvent.Class
6565import Reflex.TriggerEvent.Class
66+import Reflex.Dom.Xhr.Exception
67+import Reflex.Dom.Xhr.Foreign
68+import Reflex.Dom.Xhr.ResponseType
6669
6770import Control.Concurrent
6871import Control.Exception (handle)
@@ -89,11 +92,8 @@ import qualified Data.Text.Lazy as LT
8992import qualified Data.Text.Lazy.Builder as B
9093import Data.Traversable
9194import Data.Typeable
92−import Reflex.Dom.Xhr.ResponseType
93− (XhrResponseBody, XhrResponseType)
94−import Foreign.JavaScript.TH (HasWebView)
95−import Reflex.Dom.Xhr.Foreign (IsXhrPayload)
96−import Reflex.Dom.Xhr.Exception (XhrException)
95+
96+import Language.Javascript.JSaddle.Monad (JSM, askJSM, runJSM, MonadJSM, liftJSM)
9797
9898data XhrRequest a
9999 = XhrRequest { _xhrRequest_method :: Text
@@ -157,18 +157,19 @@ xhrRequest = XhrRequest
157157-- the XHR connection), and will pass an exception ('XhrException') to the
158158-- continuation if the connection cannot be made (or is aborted).
159159newXMLHttpRequestWithError
160− :: (HasWebView m, MonadIO m, IsXhrPayload a)
160+ :: (HasJSContext m, MonadJSM m, IsXhrPayload a)
161161 => XhrRequest a
162162 -- ^ The request to make.
163− -> (Either XhrException XhrResponse -> IO ())
163+ -> (Either XhrException XhrResponse -> JSM ())
164164 -- ^ A continuation to be called once a response comes back, or in
165165 -- case of error.
166166 -> m XMLHttpRequest
167167 -- ^ The XHR request, which could for example be aborted.
168168newXMLHttpRequestWithError req cb = do
169− wv <- askWebView
170− xhr <- liftIO $ xmlHttpRequestNew $ unWebViewSingleton wv
171− void $ liftIO $ forkIO $ handle (cb . Left) $ void $ do
169+ wv <- askJSContext
170+ xhr <- xmlHttpRequestNew
171+ ctx <- askJSM
172+ void $ liftIO $ forkIO $ handle ((`runJSM` ctx) . cb . Left) $ void . (`runJSM` ctx) $ do
172173 let c = _xhrRequest_config req
173174 rt = _xhrRequestConfig_responseType c
174175 creds = _xhrRequestConfig_withCredentials c
@@ -183,20 +184,20 @@ newXMLHttpRequestWithError req cb = do
183184 maybe (return ()) (xmlHttpRequestSetResponseType xhr . fromResponseType) rt
184185 xmlHttpRequestSetWithCredentials xhr creds
185186 _ <- xmlHttpRequestOnreadystatechange xhr $ do
186− readyState <- liftIO $ xmlHttpRequestGetReadyState xhr
187− status <- liftIO $ xmlHttpRequestGetStatus xhr
188− statusText <- liftIO $ xmlHttpRequestGetStatusText xhr
187+ readyState <- xmlHttpRequestGetReadyState xhr
188+ status <- xmlHttpRequestGetStatus xhr
189+ statusText <- xmlHttpRequestGetStatusText xhr
189190 when (readyState == 4) $ do
190191 t <- if rt == Just XhrResponseType_Text || isNothing rt
191− then liftIO $ xmlHttpRequestGetResponseText xhr
192+ then xmlHttpRequestGetResponseText xhr
192193 else return Nothing
193− r <- liftIO $ xmlHttpRequestGetResponse xhr
194+ r <- xmlHttpRequestGetResponse xhr
194195 h <- case _xhrRequestConfig_responseHeaders c of
195− AllHeaders -> liftIO $ parseAllHeadersString <$>
196+ AllHeaders -> parseAllHeadersString <$>
196197 xmlHttpRequestGetAllResponseHeaders xhr
197− OnlyHeaders xs -> liftIO $ traverse (xmlHttpRequestGetResponseHeader xhr)
198+ OnlyHeaders xs -> traverse (xmlHttpRequestGetResponseHeader xhr)
198199 (Map.fromSet id xs)
199− _ <- liftIO $ cb $ Right
200+ _ <- liftJSM $ cb $ Right
200201 XhrResponse { _xhrResponse_status = status
201202 , _xhrResponse_statusText = statusText
202203 , _xhrResponse_response = r
@@ -213,7 +214,7 @@ parseAllHeadersString s = Map.fromList $ fmap (stripBoth . T.span (/=':')) $
213214 L.dropWhileEnd T.null $ T.splitOn (T.pack "\r\n") s
214215 where stripBoth (txt1, txt2) = (T.strip txt1, T.strip $ T.drop 1 txt2)
215216
216−newXMLHttpRequest :: (HasWebView m, MonadIO m, IsXhrPayload a) => XhrRequest a -> (XhrResponse -> IO ()) -> m XMLHttpRequest
217+newXMLHttpRequest :: (HasJSContext m, MonadJSM m, IsXhrPayload a) => XhrRequest a -> (XhrResponse -> JSM ()) -> m XMLHttpRequest
217218newXMLHttpRequest req cb = newXMLHttpRequestWithError req $ mapM_ cb
218219
219220-- | Given Event of requests, issue them when the Event fires.
@@ -222,20 +223,20 @@ newXMLHttpRequest req cb = newXMLHttpRequestWithError req $ mapM_ cb
222223-- The request is processed asynchronously, therefore handling does
223224-- not block or cause a delay while creating the connection.
224225performRequestAsyncWithError
225− :: (MonadIO (Performable m), HasWebView (Performable m), PerformEvent t m, TriggerEvent t m, IsXhrPayload a)
226+ :: (MonadJSM (Performable m), HasJSContext (Performable m), PerformEvent t m, TriggerEvent t m, IsXhrPayload a)
226227 => Event t (XhrRequest a)
227228 -> m (Event t (Either XhrException XhrResponse))
228229performRequestAsyncWithError = performRequestAsync' newXMLHttpRequestWithError . fmap return
229230
230231-- | Given Event of request, issue them when the Event fires. Returns Event of corresponding response.
231−performRequestAsync :: (MonadIO (Performable m), HasWebView (Performable m), PerformEvent t m, TriggerEvent t m, IsXhrPayload a) => Event t (XhrRequest a) -> m (Event t XhrResponse)
232+performRequestAsync :: (MonadJSM (Performable m), HasJSContext (Performable m), PerformEvent t m, TriggerEvent t m, IsXhrPayload a) => Event t (XhrRequest a) -> m (Event t XhrResponse)
232233performRequestAsync = performRequestAsync' newXMLHttpRequest . fmap return
233234
234235-- | Given Event with an action that creates a request, build and issue the request when the Event fires. Returns Event of corresponding response.
235−performMkRequestAsync :: (MonadIO (Performable m), HasWebView (Performable m), PerformEvent t m, TriggerEvent t m, IsXhrPayload a) => Event t (Performable m (XhrRequest a)) -> m (Event t XhrResponse)
236+performMkRequestAsync :: (MonadJSM (Performable m), HasJSContext (Performable m), PerformEvent t m, TriggerEvent t m, IsXhrPayload a) => Event t (Performable m (XhrRequest a)) -> m (Event t XhrResponse)
236237performMkRequestAsync = performRequestAsync' newXMLHttpRequest
237238
238−performRequestAsync' :: (MonadIO (Performable m), PerformEvent t m, TriggerEvent t m) => (XhrRequest p -> (a -> IO ()) -> Performable m XMLHttpRequest) -> Event t (Performable m (XhrRequest p)) -> m (Event t a)
239+performRequestAsync' :: (MonadJSM (Performable m), PerformEvent t m, TriggerEvent t m) => (XhrRequest p -> (a -> JSM ()) -> Performable m XMLHttpRequest) -> Event t (Performable m (XhrRequest p)) -> m (Event t a)
239240performRequestAsync' newXhr req = performEventAsync $ ffor req $ \hr cb -> do
240241 r <- hr
241242 _ <- newXhr r $ liftIO . cb
@@ -251,19 +252,19 @@ performRequestAsync' newXhr req = performEventAsync $ ffor req $ \hr cb -> do
251252-- Order of request execution and completion is not guaranteed, but
252253-- order of creation and the collection result is preserved.
253254performRequestsAsyncWithError
254− :: (MonadIO (Performable m), HasWebView (Performable m), PerformEvent t m, TriggerEvent t m, Traversable f, IsXhrPayload a)
255+ :: (MonadJSM (Performable m), HasJSContext (Performable m), PerformEvent t m, TriggerEvent t m, Traversable f, IsXhrPayload a)
255256 => Event t (f (XhrRequest a)) -> m (Event t (f (Either XhrException XhrResponse)))
256257performRequestsAsyncWithError = performRequestsAsync' newXMLHttpRequestWithError . fmap return
257258
258259-- | Issues a collection of requests when the supplied Event fires. When ALL requests from a given firing complete, the results are collected and returned via the return Event.
259−performRequestsAsync :: (MonadIO (Performable m), HasWebView (Performable m), PerformEvent t m, TriggerEvent t m, Traversable f, IsXhrPayload a) => Event t (f (XhrRequest a)) -> m (Event t (f XhrResponse))
260+performRequestsAsync :: (MonadJSM (Performable m), HasJSContext (Performable m), PerformEvent t m, TriggerEvent t m, Traversable f, IsXhrPayload a) => Event t (f (XhrRequest a)) -> m (Event t (f XhrResponse))
260261performRequestsAsync = performRequestsAsync' newXMLHttpRequest . fmap return
261262
262263-- | Builds and issues a collection of requests when the supplied Event fires. When ALL requests from a given firing complete, the results are collected and returned via the return Event.
263−performMkRequestsAsync :: (MonadIO (Performable m), HasWebView (Performable m), PerformEvent t m, TriggerEvent t m, Traversable f, IsXhrPayload a) => Event t (Performable m (f (XhrRequest a))) -> m (Event t (f XhrResponse))
264+performMkRequestsAsync :: (MonadJSM (Performable m), HasJSContext (Performable m), PerformEvent t m, TriggerEvent t m, Traversable f, IsXhrPayload a) => Event t (Performable m (f (XhrRequest a))) -> m (Event t (f XhrResponse))
264265performMkRequestsAsync = performRequestsAsync' newXMLHttpRequest
265266
266−performRequestsAsync' :: (MonadIO (Performable m), PerformEvent t m, TriggerEvent t m, Traversable f) => (XhrRequest b -> (a -> IO ()) -> Performable m XMLHttpRequest) -> Event t (Performable m (f (XhrRequest b))) -> m (Event t (f a))
267+performRequestsAsync' :: (MonadJSM (Performable m), PerformEvent t m, TriggerEvent t m, Traversable f) => (XhrRequest b -> (a -> JSM ()) -> Performable m XMLHttpRequest) -> Event t (Performable m (f (XhrRequest b))) -> m (Event t (f a))
267268performRequestsAsync' newXhr req = performEventAsync $ ffor req $ \hrs cb -> do
268269 rs <- hrs
269270 resps <- forM rs $ \r -> do
@@ -274,7 +275,7 @@ performRequestsAsync' newXhr req = performEventAsync $ ffor req $ \hrs cb -> do
274275 return ()
275276
276277-- | Simplified interface to "GET" URLs and return decoded results.
277−getAndDecode :: (MonadIO m, MonadIO (Performable m), PerformEvent t m, HasWebView (Performable m), TriggerEvent t m, FromJSON a) => Event t Text -> m (Event t (Maybe a))
278+getAndDecode :: (MonadIO m, MonadJSM (Performable m), PerformEvent t m, HasJSContext (Performable m), TriggerEvent t m, FromJSON a) => Event t Text -> m (Event t (Maybe a))
278279getAndDecode url = do
279280 r <- performRequestAsync $ fmap (\x -> XhrRequest "GET" x def) url
280281 return $ fmap decodeXhrResponse r
src-ghcjs/Reflex/Dom/Xhr/Foreign.hs → src/Reflex/Dom/Xhr/Foreign.hsrenamed+53−43
@@ -10,28 +10,35 @@ module Reflex.Dom.Xhr.Foreign (
1010) where
1111
1212import Control.Exception (catch, throwIO)
13+import Control.Monad (join)
14+import Control.Monad.IO.Class (MonadIO(..))
1315import Data.Maybe (fromMaybe)
1416import Data.Text (Text)
17+import Data.ByteString (ByteString)
18+import GHCJS.Marshal (fromJSValUnchecked)
1519import GHCJS.DOM
1620import GHCJS.DOM.Enums
1721import GHCJS.DOM.EventM (EventM, on)
1822import GHCJS.DOM.EventTarget (dispatchEvent)
1923import GHCJS.DOM.Types hiding (Text)
2024import GHCJS.DOM.XMLHttpRequest
21−import GHCJS.Types
25+-- import GHCJS.Types
2226import Prelude hiding (error)
2327import Reflex.Dom.Xhr.Exception
2428import Reflex.Dom.Xhr.ResponseType
29+import Language.Javascript.JSaddle.Types (ghcjsPure)
30+import qualified Language.Javascript.JSaddle.Monad as JS (catch)
31+import qualified GHCJS.Buffer as JS
32+ (createFromArrayBuffer, toByteString)
33+import qualified JavaScript.TypedArray.ArrayBuffer as JS
34+ (unsafeFreeze, MutableArrayBuffer)
2535
26−prepareWebView :: WebView -> IO ()
27−prepareWebView _ = return ()
28−
29−xmlHttpRequestNew :: a -> IO XMLHttpRequest
30−xmlHttpRequestNew _ = newXMLHttpRequest
36+xmlHttpRequestNew :: MonadJSM m => m XMLHttpRequest
37+xmlHttpRequestNew = newXMLHttpRequest
3138
3239xmlHttpRequestOpen ::
33− (ToJSString method, ToJSString url, ToJSString user, ToJSString password) =>
34− XMLHttpRequest -> method -> url -> Bool -> user -> password -> IO ()
40+ (ToJSString method, ToJSString url, ToJSString user, ToJSString password, MonadJSM m) =>
41+ XMLHttpRequest -> method -> url -> Bool -> user -> password -> m ()
3542xmlHttpRequestOpen = open
3643
3744convertException :: XHRError -> XhrException
@@ -40,7 +47,7 @@ convertException e = case e of
4047 XHRAborted -> XhrException_Aborted
4148
4249class IsXhrPayload a where
43− sendXhrPayload :: XMLHttpRequest -> a -> IO ()
50+ sendXhrPayload :: MonadJSM m => XMLHttpRequest -> a -> m ()
4451
4552instance IsXhrPayload () where
4653 sendXhrPayload xhr _ = send xhr
@@ -63,79 +70,79 @@ instance IsXhrPayload Blob where
6370newtype XhrPayload = XhrPayload { unXhrPayload :: JSVal }
6471
6572-- This used to be a non blocking call, but now it uses an interruptible ffi
66−xmlHttpRequestSend :: IsXhrPayload payload => XMLHttpRequest -> payload -> IO ()
67−xmlHttpRequestSend self p = sendXhrPayload self p `catch` (throwIO . convertException)
73+xmlHttpRequestSend :: IsXhrPayload payload => XMLHttpRequest -> payload -> JSM ()
74+xmlHttpRequestSend self p = sendXhrPayload self p `JS.catch` (liftIO . throwIO . convertException)
6875
6976
70−xmlHttpRequestSetRequestHeader :: (ToJSString header, ToJSString value)
71− => XMLHttpRequest -> header -> value -> IO ()
77+xmlHttpRequestSetRequestHeader :: (ToJSString header, ToJSString value, MonadJSM m)
78+ => XMLHttpRequest -> header -> value -> m ()
7279xmlHttpRequestSetRequestHeader = setRequestHeader
7380
74−xmlHttpRequestAbort :: XMLHttpRequest -> IO ()
81+xmlHttpRequestAbort :: MonadJSM m => XMLHttpRequest -> m ()
7582xmlHttpRequestAbort = abort
7683
77−xmlHttpRequestGetAllResponseHeaders :: XMLHttpRequest -> IO Text
84+xmlHttpRequestGetAllResponseHeaders :: MonadJSM m => XMLHttpRequest -> m Text
7885xmlHttpRequestGetAllResponseHeaders self = fromMaybe "" <$> getAllResponseHeaders self
7986
80−xmlHttpRequestGetResponseHeader :: (ToJSString header)
81− => XMLHttpRequest -> header -> IO Text
87+xmlHttpRequestGetResponseHeader :: (ToJSString header, MonadJSM m)
88+ => XMLHttpRequest -> header -> m Text
8289xmlHttpRequestGetResponseHeader self header = fromMaybe "" <$> getResponseHeader self header
8390
84−xmlHttpRequestOverrideMimeType :: ToJSString override => XMLHttpRequest -> override -> IO ()
91+xmlHttpRequestOverrideMimeType :: (ToJSString override, MonadJSM m) => XMLHttpRequest -> override -> m ()
8592xmlHttpRequestOverrideMimeType = overrideMimeType
8693
87−xmlHttpRequestDispatchEvent :: IsEvent evt => XMLHttpRequest -> Maybe evt -> IO Bool
94+xmlHttpRequestDispatchEvent :: (IsEvent evt, MonadJSM m) => XMLHttpRequest -> Maybe evt -> m Bool
8895xmlHttpRequestDispatchEvent = dispatchEvent
8996
90−xmlHttpRequestOnabort :: XMLHttpRequest -> EventM XMLHttpRequest XMLHttpRequestProgressEvent () -> IO (IO ())
97+xmlHttpRequestOnabort :: XMLHttpRequest -> EventM XMLHttpRequest XMLHttpRequestProgressEvent () -> JSM (JSM ())
9198xmlHttpRequestOnabort = (`on` abortEvent)
9299
93−xmlHttpRequestOnerror :: XMLHttpRequest -> EventM XMLHttpRequest XMLHttpRequestProgressEvent () -> IO (IO ())
100+xmlHttpRequestOnerror :: XMLHttpRequest -> EventM XMLHttpRequest XMLHttpRequestProgressEvent () -> JSM (JSM ())
94101xmlHttpRequestOnerror = (`on` error)
95102
96−xmlHttpRequestOnload :: XMLHttpRequest -> EventM XMLHttpRequest XMLHttpRequestProgressEvent () -> IO (IO ())
103+xmlHttpRequestOnload :: XMLHttpRequest -> EventM XMLHttpRequest XMLHttpRequestProgressEvent () -> JSM (JSM ())
97104xmlHttpRequestOnload = (`on` load)
98105
99−xmlHttpRequestOnloadend :: XMLHttpRequest -> EventM XMLHttpRequest ProgressEvent () -> IO (IO ())
106+xmlHttpRequestOnloadend :: XMLHttpRequest -> EventM XMLHttpRequest ProgressEvent () -> JSM (JSM ())
100107xmlHttpRequestOnloadend = (`on` loadEnd)
101108
102−xmlHttpRequestOnloadstart :: XMLHttpRequest -> EventM XMLHttpRequest ProgressEvent () -> IO (IO ())
109+xmlHttpRequestOnloadstart :: XMLHttpRequest -> EventM XMLHttpRequest ProgressEvent () -> JSM (JSM ())
103110xmlHttpRequestOnloadstart = (`on` loadStart)
104111
105−xmlHttpRequestOnprogress :: XMLHttpRequest -> EventM XMLHttpRequest XMLHttpRequestProgressEvent () -> IO (IO ())
112+xmlHttpRequestOnprogress :: XMLHttpRequest -> EventM XMLHttpRequest XMLHttpRequestProgressEvent () -> JSM (JSM ())
106113xmlHttpRequestOnprogress = (`on` progress)
107114
108−xmlHttpRequestOntimeout :: XMLHttpRequest -> EventM XMLHttpRequest ProgressEvent () -> IO (IO ())
115+xmlHttpRequestOntimeout :: XMLHttpRequest -> EventM XMLHttpRequest ProgressEvent () -> JSM (JSM ())
109116xmlHttpRequestOntimeout = (`on` timeout)
110117
111−xmlHttpRequestOnreadystatechange :: XMLHttpRequest -> EventM XMLHttpRequest Event () -> IO (IO ())
118+xmlHttpRequestOnreadystatechange :: XMLHttpRequest -> EventM XMLHttpRequest Event () -> JSM (JSM ())
112119xmlHttpRequestOnreadystatechange = (`on` readyStateChange)
113120
114−xmlHttpRequestSetTimeout :: XMLHttpRequest -> Word -> IO ()
121+xmlHttpRequestSetTimeout :: MonadJSM m => XMLHttpRequest -> Word -> m ()
115122xmlHttpRequestSetTimeout = setTimeout
116123
117−xmlHttpRequestGetTimeout :: XMLHttpRequest -> IO Word
124+xmlHttpRequestGetTimeout :: MonadJSM m => XMLHttpRequest -> m Word
118125xmlHttpRequestGetTimeout = getTimeout
119126
120−xmlHttpRequestGetReadyState :: XMLHttpRequest -> IO Word
127+xmlHttpRequestGetReadyState :: MonadJSM m => XMLHttpRequest -> m Word
121128xmlHttpRequestGetReadyState = getReadyState
122129
123−xmlHttpRequestSetWithCredentials :: XMLHttpRequest -> Bool -> IO ()
130+xmlHttpRequestSetWithCredentials :: MonadJSM m => XMLHttpRequest -> Bool -> m ()
124131xmlHttpRequestSetWithCredentials = setWithCredentials
125132
126−xmlHttpRequestGetWithCredentials :: XMLHttpRequest -> IO Bool
133+xmlHttpRequestGetWithCredentials :: MonadJSM m => XMLHttpRequest -> m Bool
127134xmlHttpRequestGetWithCredentials = getWithCredentials
128135
129−xmlHttpRequestGetUpload :: XMLHttpRequest -> IO (Maybe XMLHttpRequestUpload)
136+xmlHttpRequestGetUpload :: MonadJSM m => XMLHttpRequest -> m (Maybe XMLHttpRequestUpload)
130137xmlHttpRequestGetUpload = getUpload
131138
132−xmlHttpRequestGetResponseText :: FromJSString result => XMLHttpRequest -> IO (Maybe result)
139+xmlHttpRequestGetResponseText :: (FromJSString result, MonadJSM m) => XMLHttpRequest -> m (Maybe result)
133140xmlHttpRequestGetResponseText = getResponseText
134141
135−xmlHttpRequestGetResponseXML :: XMLHttpRequest -> IO (Maybe Document)
142+xmlHttpRequestGetResponseXML :: MonadJSM m => XMLHttpRequest -> m (Maybe Document)
136143xmlHttpRequestGetResponseXML = getResponseXML
137144
138−xmlHttpRequestSetResponseType :: XMLHttpRequest -> XMLHttpRequestResponseType -> IO ()
145+xmlHttpRequestSetResponseType :: MonadJSM m => XMLHttpRequest -> XMLHttpRequestResponseType -> m ()
139146xmlHttpRequestSetResponseType = setResponseType
140147
141148fromResponseType :: XhrResponseType -> XMLHttpRequestResponseType
@@ -151,28 +158,31 @@ toResponseType XMLHttpRequestResponseTypeBlob = Just XhrResponseType_Blob
151158toResponseType XMLHttpRequestResponseTypeText = Just XhrResponseType_Text
152159toResponseType _ = Nothing
153160
154−xmlHttpRequestGetResponseType :: XMLHttpRequest -> IO (Maybe XhrResponseType)
161+xmlHttpRequestGetResponseType :: MonadJSM m => XMLHttpRequest -> m (Maybe XhrResponseType)
155162xmlHttpRequestGetResponseType = fmap toResponseType . getResponseType
156163
157−xmlHttpRequestGetStatus :: XMLHttpRequest -> IO Word
164+xmlHttpRequestGetStatus :: MonadJSM m => XMLHttpRequest -> m Word
158165xmlHttpRequestGetStatus = getStatus
159166
160−xmlHttpRequestGetStatusText :: FromJSString result => XMLHttpRequest -> IO result
167+xmlHttpRequestGetStatusText :: MonadJSM m => FromJSString result => XMLHttpRequest -> m result
161168xmlHttpRequestGetStatusText = getStatusText
162169
163−xmlHttpRequestGetResponseURL :: FromJSString result => XMLHttpRequest -> IO result
170+xmlHttpRequestGetResponseURL :: (FromJSString result, MonadJSM m) => XMLHttpRequest -> m result
164171xmlHttpRequestGetResponseURL = getResponseURL
165172
166−xmlHttpRequestGetResponse :: XMLHttpRequest -> IO (Maybe XhrResponseBody)
173+xmlHttpRequestGetResponse :: MonadJSM m => XMLHttpRequest -> m (Maybe XhrResponseBody)
167174xmlHttpRequestGetResponse xhr = do
168175 mr <- getResponse xhr
169176 rt <- xmlHttpRequestGetResponseType xhr
170177 case rt of
171− Just XhrResponseType_Blob -> return $ XhrResponseBody_Blob . castToBlob <$> mr
178+ Just XhrResponseType_Blob -> fmap XhrResponseBody_Blob . join <$> mapM (castTo Blob) mr
172179 Just XhrResponseType_Text -> Just . XhrResponseBody_Text <$> xmlHttpRequestGetStatusText xhr
173180 Just XhrResponseType_Default -> Just . XhrResponseBody_Text <$> xmlHttpRequestGetStatusText xhr
174181 Just XhrResponseType_ArrayBuffer -> case fmap unGObject mr of
175182 Nothing -> return Nothing
176− Just ptr -> Just . XhrResponseBody_ArrayBuffer <$> bsFromArrayBuffer ptr ptr
183+ Just ptr -> Just . XhrResponseBody_ArrayBuffer <$> bsFromArrayBuffer (pFromJSVal ptr)
177184 _ -> return Nothing
178185
186+bsFromArrayBuffer :: MonadJSM m => JS.MutableArrayBuffer -> m ByteString
187+bsFromArrayBuffer ab = liftJSM $ JS.unsafeFreeze ab >>=
188+ ghcjsPure . JS.createFromArrayBuffer >>= ghcjsPure . JS.toByteString 0 Nothing
src/Reflex/Dom/Xhr/ResponseType.hs+1−1
@@ -17,5 +17,5 @@ data XhrResponseBody = XhrResponseBody_Default Text
1717 | XhrResponseBody_Text Text
1818 | XhrResponseBody_Blob Blob
1919 | XhrResponseBody_ArrayBuffer ByteString
20− deriving (Eq)
20+-- deriving (Eq)
2121