@@ -22,7 +22,7 @@
22{-# LANGUAGE TypeOperators #-}
22{-# LANGUAGE TypeOperators #-}
23{-# LANGUAGE UndecidableInstances #-}
23{-# LANGUAGE UndecidableInstances #-}
24module Reflex.Dom.Builder.Immediate
24module Reflex.Dom.Builder.Immediate
25− ( TriggerRef (..)
25+ ( EventTriggerRef (..)
26 , ImmediateDomBuilderEnv (..)
26 , ImmediateDomBuilderEnv (..)
27 , ImmediateDomBuilderT (..)
27 , ImmediateDomBuilderT (..)
28 , runImmediateDomBuilderT
28 , runImmediateDomBuilderT
@@ -87,9 +87,10 @@ import qualified Reflex.Patch.DMapWithMove as PatchDMapWithMove
87import Reflex.PerformEvent.Class
87import Reflex.PerformEvent.Class
88import Reflex.PostBuild.Class
88import Reflex.PostBuild.Class
89import Reflex.TriggerEvent.Base hiding (askEvents)
89import Reflex.TriggerEvent.Base hiding (askEvents)
90+import qualified Reflex.TriggerEvent.Base as TriggerEventT (askEvents)
90import Reflex.TriggerEvent.Class
91import Reflex.TriggerEvent.Class
92−import Control.Concurrent.Chan
93+import Control.Concurrent
93import Control.Lens hiding (element, ix)
94import Control.Lens hiding (element, ix)
94import Control.Monad.Exception
95import Control.Monad.Exception
95import Control.Monad.Primitive
96import Control.Monad.Primitive
@@ -115,6 +116,8 @@ import Data.Some (Some)
115import qualified Data.Some as Some
116import qualified Data.Some as Some
116import Data.Text (Text)
117import Data.Text (Text)
117import qualified Data.Text as T
118import qualified Data.Text as T
119+import qualified GHCJS.DOM as DOM
120+import GHCJS.DOM.RequestAnimationFrameCallback
118import GHCJS.DOM.Document (Document, createDocumentFragmentUnchecked, createElementUnchecked, createElementNSUnchecked, createTextNodeUnchecked)
121import GHCJS.DOM.Document (Document, createDocumentFragmentUnchecked, createElementUnchecked, createElementNSUnchecked, createTextNodeUnchecked)
119import GHCJS.DOM.Element (getScrollTop, removeAttribute, removeAttributeNS, setAttribute, setAttributeNS)
122import GHCJS.DOM.Element (getScrollTop, removeAttribute, removeAttributeNS, setAttribute, setAttributeNS)
120import qualified GHCJS.DOM.Element as Element
123import qualified GHCJS.DOM.Element as Element
@@ -142,18 +145,17 @@ import Language.Javascript.JSaddle (call, eval)
143import Reflex.Requester.Base
146import Reflex.Requester.Base
144import Reflex.Requester.Class
147import Reflex.Requester.Class
145−
148+import Foreign.JavaScript.Internal.Utils
146−data TriggerRef t a = TriggerRef { unTriggerRef :: IORef (Maybe (EventTrigger t a)) }
148data ImmediateDomBuilderEnv t
150data ImmediateDomBuilderEnv t
149 = ImmediateDomBuilderEnv { _immediateDomBuilderEnv_document :: Document
151 = ImmediateDomBuilderEnv { _immediateDomBuilderEnv_document :: Document
150 , _immediateDomBuilderEnv_parent :: Node
152 , _immediateDomBuilderEnv_parent :: Node
151− , _immediateDomBuilderEnv_events :: Chan [DSum (TriggerRef t) TriggerInvocation]
152 , _immediateDomBuilderEnv_unreadyChildren :: IORef Word -- Number of children who still aren't fully rendered
153 , _immediateDomBuilderEnv_unreadyChildren :: IORef Word -- Number of children who still aren't fully rendered
153 , _immediateDomBuilderEnv_commitAction :: JSM () -- Action to take when all children are ready --TODO: we should probably get rid of this once we invoke it
154 , _immediateDomBuilderEnv_commitAction :: JSM () -- Action to take when all children are ready --TODO: we should probably get rid of this once we invoke it
156−newtype ImmediateDomBuilderT t m a = ImmediateDomBuilderT { unImmediateDomBuilderT :: ReaderT (ImmediateDomBuilderEnv t) (RequesterT t JSM Identity m) a } deriving (Functor, Applicative, Monad, MonadFix, MonadIO, MonadException, MonadAsyncException)
157+newtype ImmediateDomBuilderT t m a = ImmediateDomBuilderT { unImmediateDomBuilderT :: ReaderT (ImmediateDomBuilderEnv t) (RequesterT t JSM Identity (TriggerEventT t m)) a }
158+ deriving (Functor, Applicative, Monad, MonadFix, MonadIO, MonadException, MonadAsyncException)
158#ifndef __GHCJS__
160#ifndef __GHCJS__
159instance MonadJSM m => MonadJSM (ImmediateDomBuilderT t m) where
161instance MonadJSM m => MonadJSM (ImmediateDomBuilderT t m) where
@@ -165,7 +167,7 @@ instance PrimMonad m => PrimMonad (ImmediateDomBuilderT x m) where
165 primitive = lift . primitive
167 primitive = lift . primitive
167instance MonadTrans (ImmediateDomBuilderT t) where
169instance MonadTrans (ImmediateDomBuilderT t) where
168− lift = ImmediateDomBuilderT . lift . lift
170+ lift = ImmediateDomBuilderT . lift . lift . lift
170instance (Reflex t, PrimMonad m) => DomRenderHook t (ImmediateDomBuilderT t m) where
172instance (Reflex t, PrimMonad m) => DomRenderHook t (ImmediateDomBuilderT t m) where
171 withRenderHook hook (ImmediateDomBuilderT a) = do
173 withRenderHook hook (ImmediateDomBuilderT a) = do
@@ -177,11 +179,34 @@ instance (Reflex t, PrimMonad m) => DomRenderHook t (ImmediateDomBuilderT t m) w
177 requestDomAction_ = ImmediateDomBuilderT . lift . requesting_
179 requestDomAction_ = ImmediateDomBuilderT . lift . requesting_
179{-# INLINABLE runImmediateDomBuilderT #-}
181{-# INLINABLE runImmediateDomBuilderT #-}
180−runImmediateDomBuilderT :: (Reflex t, MonadFix m, PerformEvent t m, MonadJSM (Performable m)) => ImmediateDomBuilderT t m a -> ImmediateDomBuilderEnv t -> m a
182+runImmediateDomBuilderT
186+ , MonadReflexCreateTrigger t m
188+ , MonadJSM (Performable m)
192+ => ImmediateDomBuilderT t m a
193+ -> ImmediateDomBuilderEnv t
194+ -> Chan [DSum (EventTriggerRef t) TriggerInvocation]
181−runImmediateDomBuilderT (ImmediateDomBuilderT a) env = do
196+runImmediateDomBuilderT (ImmediateDomBuilderT a) env eventChan = flip runTriggerEventT eventChan $ do
197+ win <- DOM.currentWindowUnchecked
182 rec (x, req) <- runRequesterT (runReaderT a env) rsp
198 rec (x, req) <- runRequesterT (runReaderT a env) rsp
199+ rsp <- performEventAsync $ ffor req $ \rm f -> liftJSM $ runInAnimationFrame win f $
183− rsp <- performEvent $ ffor req $ \rm -> liftJSM $ DMap.traverseWithKey (\_ r -> Identity <$> r) rm
200+ DMap.traverseWithKey (\_ r -> Identity <$> r) rm
203+ runInAnimationFrame win f x = do
204+ rec cb <- newRequestAnimationFrameCallbackSync $ \_ -> do
205+ v <- synchronously x
207+ freeRequestAnimationFrameCallback cb
208+ _ <- Window.requestAnimationFrame win $ Just cb
186{-# INLINABLE askDocument #-}
211{-# INLINABLE askDocument #-}
187askDocument :: Monad m => ImmediateDomBuilderT t m Document
212askDocument :: Monad m => ImmediateDomBuilderT t m Document
@@ -192,8 +217,8 @@ askParent :: Monad m => ImmediateDomBuilderT t m Node
192askParent = ImmediateDomBuilderT $ asks _immediateDomBuilderEnv_parent
217askParent = ImmediateDomBuilderT $ asks _immediateDomBuilderEnv_parent
194{-# INLINABLE askEvents #-}
219{-# INLINABLE askEvents #-}
195−askEvents :: Monad m => ImmediateDomBuilderT t m (Chan [DSum (TriggerRef t) TriggerInvocation])
220+askEvents :: Monad m => ImmediateDomBuilderT t m (Chan [DSum (EventTriggerRef t) TriggerInvocation])
196−askEvents = ImmediateDomBuilderT $ asks _immediateDomBuilderEnv_events
221+askEvents = ImmediateDomBuilderT . lift . lift $ TriggerEventT.askEvents
198localEnv :: Monad m => (ImmediateDomBuilderEnv t -> ImmediateDomBuilderEnv t) -> ImmediateDomBuilderT t m a -> ImmediateDomBuilderT t m a
223localEnv :: Monad m => (ImmediateDomBuilderEnv t -> ImmediateDomBuilderEnv t) -> ImmediateDomBuilderT t m a -> ImmediateDomBuilderT t m a
199localEnv f = ImmediateDomBuilderT . local f . unImmediateDomBuilderT
224localEnv f = ImmediateDomBuilderT . local f . unImmediateDomBuilderT
@@ -296,7 +321,7 @@ wrap e cfg = do
296 Propagation_Stop -> withIsEvent en DOM.stopPropagation
321 Propagation_Stop -> withIsEvent en DOM.stopPropagation
297 Propagation_StopImmediate -> withIsEvent en DOM.stopImmediatePropagation
322 Propagation_StopImmediate -> withIsEvent en DOM.stopImmediatePropagation
298 mv <- liftJSM k --TODO: Only do this when the event is subscribed
323 mv <- liftJSM k --TODO: Only do this when the event is subscribed
299− liftIO $ forM_ mv $ \v -> writeChan events [TriggerRef triggerRef :=> TriggerInvocation v (return ())]
324+ liftIO $ forM_ mv $ \v -> writeChan events [EventTriggerRef triggerRef :=> TriggerInvocation v (return ())]
300 return $ en :=> EventFilterTriggerRef triggerRef
325 return $ en :=> EventFilterTriggerRef triggerRef
302 let h :: GhcjsEventHandler er
327 let h :: GhcjsEventHandler er
@@ -316,7 +341,7 @@ wrap e cfg = do
316 Just v -> liftIO $ do
341 Just v -> liftIO $ do
317 --TODO: I don't think this is quite right: if a new trigger is created between when this is enqueued and when it fires, this may not work quite right
342 --TODO: I don't think this is quite right: if a new trigger is created between when this is enqueued and when it fires, this may not work quite right
318 ref <- newIORef $ Just t
343 ref <- newIORef $ Just t
319− writeChan events [TriggerRef ref :=> TriggerInvocation v (return ())])
344+ writeChan events [EventTriggerRef ref :=> TriggerInvocation v (return ())])
320 return $ Element
345 return $ Element
321 { _element_events = es
346 { _element_events = es
322 , _element_raw = e
347 , _element_raw = e
@@ -723,10 +748,10 @@ hoistTraverseWithKeyWithAdjust :: forall (k :: * -> *) v v' t m p.
723 , Patch (p k (Constant Int))
748 , Patch (p k (Constant Int))
725 => (forall vv vv'.
750 => (forall vv vv'.
726− (forall a. k a -> vv a -> RequesterT t JSM Identity m (vv' a))
751+ (forall a. k a -> vv a -> RequesterT t JSM Identity (TriggerEventT t m) (vv' a))
727 -> DMap k vv
752 -> DMap k vv
728 -> Event t (p k vv)
753 -> Event t (p k vv)
729− -> RequesterT t JSM Identity m (DMap k vv', Event t (p k vv'))
754+ -> RequesterT t JSM Identity (TriggerEventT t m) (DMap k vv', Event t (p k vv'))
730 ) -- ^ The base monad's traversal
755 ) -- ^ The base monad's traversal
731 -> (forall vv vv'. (forall a. vv a -> vv' a) -> p k vv -> p k vv') -- ^ A way of mapping over the patch type
756 -> (forall vv vv'. (forall a. vv a -> vv' a) -> p k vv -> p k vv') -- ^ A way of mapping over the patch type
732 -> (p k (Compose ((,,,) DOM.DocumentFragment DOM.Text (IORef (ChildReadyState k))) v') -> DMap k (Constant (IORef (ChildReadyState k))) -> IO (DMap k (Constant (IORef (ChildReadyState k))))) -- ^ Given a patch for the children DOM elements, produce a patch for the childrens' unreadiness state
757 -> (p k (Compose ((,,,) DOM.DocumentFragment DOM.Text (IORef (ChildReadyState k))) v') -> DMap k (Constant (IORef (ChildReadyState k))) -> IO (DMap k (Constant (IORef (ChildReadyState k))))) -- ^ Given a patch for the children DOM elements, produce a patch for the childrens' unreadiness state
@@ -802,7 +827,7 @@ drawChildUpdate :: (MonadIO m, MonadJSM m)
802 => ImmediateDomBuilderEnv t
827 => ImmediateDomBuilderEnv t
803 -> (IORef (ChildReadyState k) -> JSM ()) -- This will NOT be called if the child is ready at initialization time; instead, the ChildReadyState return value will be ChildReadyState_Ready
828 -> (IORef (ChildReadyState k) -> JSM ()) -- This will NOT be called if the child is ready at initialization time; instead, the ChildReadyState return value will be ChildReadyState_Ready
804 -> ImmediateDomBuilderT t m (v' a)
829 -> ImmediateDomBuilderT t m (v' a)
805− -> RequesterT t JSM Identity m (Compose ((,,,) DOM.DocumentFragment DOM.Text (IORef (ChildReadyState k))) v' a)
830+ -> RequesterT t JSM Identity (TriggerEventT t m) (Compose ((,,,) DOM.DocumentFragment DOM.Text (IORef (ChildReadyState k))) v' a)
806drawChildUpdate initialEnv markReady child = do
831drawChildUpdate initialEnv markReady child = do
807 childReadyState <- liftIO $ newIORef $ ChildReadyState_Unready Nothing
832 childReadyState <- liftIO $ newIORef $ ChildReadyState_Unready Nothing
808 unreadyChildren <- liftIO $ newIORef 0
833 unreadyChildren <- liftIO $ newIORef 0
@@ -848,20 +873,11 @@ instance MonadReflexCreateTrigger t m => MonadReflexCreateTrigger t (ImmediateDo
849instance (Monad m, MonadRef m, Ref m ~ Ref IO, MonadReflexCreateTrigger t m) => TriggerEvent t (ImmediateDomBuilderT t m) where
874instance (Monad m, MonadRef m, Ref m ~ Ref IO, MonadReflexCreateTrigger t m) => TriggerEvent t (ImmediateDomBuilderT t m) where
850 {-# INLINABLE newTriggerEvent #-}
875 {-# INLINABLE newTriggerEvent #-}
851− newTriggerEvent = do
876+ newTriggerEvent = ImmediateDomBuilderT . lift . lift $ newTriggerEvent
852− (e, t) <- newTriggerEventWithOnComplete
853− return (e, \a -> t a $ return ())
854 {-# INLINABLE newTriggerEventWithOnComplete #-}
877 {-# INLINABLE newTriggerEventWithOnComplete #-}
855− newTriggerEventWithOnComplete = do
878+ newTriggerEventWithOnComplete = ImmediateDomBuilderT . lift . lift $ newTriggerEventWithOnComplete
857− (eResult, reResultTrigger) <- lift newEventWithTriggerRef
858− return $ (,) eResult $ \a cb -> writeChan events [TriggerRef reResultTrigger :=> TriggerInvocation a (liftIO cb)]
859 {-# INLINABLE newEventWithLazyTriggerWithOnComplete #-}
879 {-# INLINABLE newEventWithLazyTriggerWithOnComplete #-}
860− newEventWithLazyTriggerWithOnComplete f = do
880+ newEventWithLazyTriggerWithOnComplete f = ImmediateDomBuilderT . lift . lift $ newEventWithLazyTriggerWithOnComplete f
862− lift $ newEventWithTrigger $ \t -> f $ \a cb -> do
863− reResultTrigger <- newIORef $ Just t
864− writeChan events [TriggerRef reResultTrigger :=> TriggerInvocation a (liftIO cb)]
866instance HasJSContext m => HasJSContext (ImmediateDomBuilderT t m) where
882instance HasJSContext m => HasJSContext (ImmediateDomBuilderT t m) where
867 type JSContextPhantom (ImmediateDomBuilderT t m) = JSContextPhantom m
883 type JSContextPhantom (ImmediateDomBuilderT t m) = JSContextPhantom m
@@ -1238,7 +1254,7 @@ wrapDomEvent el elementOnevent getValue = wrapDomEventMaybe el elementOnevent $
1238{-# INLINABLE subscribeDomEvent #-}
1254{-# INLINABLE subscribeDomEvent #-}
1239subscribeDomEvent :: (EventM e event () -> JSM (JSM ()))
1255subscribeDomEvent :: (EventM e event () -> JSM (JSM ()))
1240 -> EventM e event (Maybe a)
1256 -> EventM e event (Maybe a)
1241− -> Chan [DSum (TriggerRef t) TriggerInvocation]
1257+ -> Chan [DSum (EventTriggerRef t) TriggerInvocation]
1242 -> EventTrigger t a
1258 -> EventTrigger t a
1243 -> JSM (JSM ())
1259 -> JSM (JSM ())
1244subscribeDomEvent elementOnevent getValue eventChan et = elementOnevent $ do
1260subscribeDomEvent elementOnevent getValue eventChan et = elementOnevent $ do
@@ -1246,7 +1262,7 @@ subscribeDomEvent elementOnevent getValue eventChan et = elementOnevent $ do
1246 forM_ mv $ \v -> liftIO $ do
1262 forM_ mv $ \v -> liftIO $ do
1247 --TODO: I don't think this is quite right: if a new trigger is created between when this is enqueued and when it fires, this may not work quite right
1263 --TODO: I don't think this is quite right: if a new trigger is created between when this is enqueued and when it fires, this may not work quite right
1248 etr <- newIORef $ Just et
1264 etr <- newIORef $ Just et
1249− writeChan eventChan [TriggerRef etr :=> TriggerInvocation v (return ())]
1265+ writeChan eventChan [EventTriggerRef etr :=> TriggerInvocation v (return ())]
1251{-# INLINABLE wrapDomEventMaybe #-}
1267{-# INLINABLE wrapDomEventMaybe #-}
1252wrapDomEventMaybe :: (TriggerEvent t m, MonadJSM m)
1268wrapDomEventMaybe :: (TriggerEvent t m, MonadJSM m)