@@ -37,8 +37,8 @@ module Reflex.Dom.Builder.Hydration
37 , HydrationMode (..)
37 , HydrationMode (..)
38 , HydrationRunnerT (..)
38 , HydrationRunnerT (..)
39 , runHydrationRunnerT
39 , runHydrationRunnerT
40− , DOM(..), runDOMForest
40+ , addHydrationStepWithSetup
41− , hydrateDOM
41+ , addHydrationStep
42 , hydrateNode
42 , hydrateNode
43 , getPreviousNode, setPreviousNode
43 , getPreviousNode, setPreviousNode
44 , runHydrationDomBuilderT
44 , runHydrationDomBuilderT
@@ -47,7 +47,6 @@ module Reflex.Dom.Builder.Hydration
48 , textNodeInternal
48 , textNodeInternal
49 , SupportsHydrationDomBuilder
49 , SupportsHydrationDomBuilder
50− , EventFilterTriggerRef (..)
52 , makeElement
51 , makeElement
53 , drawChildUpdate
52 , drawChildUpdate
@@ -127,6 +126,7 @@ import GHCJS.DOM.Node (appendChild_, getChildNodes, getOwnerDocumentUnchecked, g
127import qualified GHCJS.DOM.Node as DOM (insertBefore_)
126import qualified GHCJS.DOM.Node as DOM (insertBefore_)
128import qualified GHCJS.DOM.Node as Node
127import qualified GHCJS.DOM.Node as Node
129import qualified GHCJS.DOM.NodeList as NodeList
128import qualified GHCJS.DOM.NodeList as NodeList
129+import qualified GHCJS.DOM.Text as DOM
130import GHCJS.DOM.Types
130import GHCJS.DOM.Types
131 (liftJSM, askJSM, runJSM, JSM, MonadJSM,
131 (liftJSM, askJSM, runJSM, JSM, MonadJSM,
132 FocusEvent, IsElement, IsEvent, IsNode, KeyboardEvent, Node,
132 FocusEvent, IsElement, IsEvent, IsNode, KeyboardEvent, Node,
@@ -185,7 +185,7 @@ instance DomSpace HydrationDomSpace where
185 in DMap.alter f' en $ _ghcjsEventSpec_filters es
185 in DMap.alter f' en $ _ghcjsEventSpec_filters es
188−data HydrationDomBuilderEnv = HydrationDomBuilderEnv
188+data HydrationDomBuilderEnv t = HydrationDomBuilderEnv
189 { _hydrationDomBuilderEnv_document :: {-# UNPACK #-} !Document
189 { _hydrationDomBuilderEnv_document :: {-# UNPACK #-} !Document
190 -- ^ Reference to the document
190 -- ^ Reference to the document
191 , _hydrationDomBuilderEnv_parent :: {-# UNPACK #-} !(IORef Node)
191 , _hydrationDomBuilderEnv_parent :: {-# UNPACK #-} !(IORef Node)
@@ -197,34 +197,9 @@ data HydrationDomBuilderEnv = HydrationDomBuilderEnv
197 -- ^ Action to take when all children are ready --TODO: we should probably get rid of this once we invoke it
197 -- ^ Action to take when all children are ready --TODO: we should probably get rid of this once we invoke it
198 , _hydrationDomBuilderEnv_hydrationMode :: {-# UNPACK #-} !(IORef HydrationMode)
198 , _hydrationDomBuilderEnv_hydrationMode :: {-# UNPACK #-} !(IORef HydrationMode)
199 -- ^ In hydration mode? Should be switched to `HydrationMode_Immediate` after hydration is finished
199 -- ^ In hydration mode? Should be switched to `HydrationMode_Immediate` after hydration is finished
200+ , _hydrationDomBuilderEnv_switchover :: {-# UNPACK #-} !(Event t ())
203− = DOM_Element (HydrationRunnerT t m Node) [DOM t m]
204− -- ^ Nodes with children, the action returns the node for the children to use as a parent
205− | DOM_Node (HydrationRunnerT t m ())
206− -- ^ Nodes without children
207− | DOM_Replace (HydrationRunnerT t m ()) (HydrationRunnerT t m ()) (Behavior t [DOM t m])
208− -- ^ First and second fields setup the start and end markers respectively, the
209− -- third contains the actual content which changes over time
212− :: (Ref m ~ IORef, PerformEvent t m, MonadFix m, MonadReflexCreateTrigger t m, DOM.MonadJSM m, DOM.MonadJSM (Performable m), MonadRef m, MonadSample t m)
214− -> HydrationRunnerT t m ()
215−runDOMForest = foldl' (\acc d -> runDOMTree d >> acc) (pure ())
218− :: (Ref m ~ IORef, PerformEvent t m, MonadFix m, MonadReflexCreateTrigger t m, DOM.MonadJSM m, DOM.MonadJSM (Performable m), MonadRef m, MonadSample t m)
219− => DOM t m -> HydrationRunnerT t m ()
222− DOM_Element m children -> m >>= localRunner (runDOMForest children) Nothing
223− DOM_Replace start end b -> do
225− runDOMForest =<< lift (sample b)
228-- | The monad which performs the delayed actions to reuse prerendered nodes and set up events
203-- | The monad which performs the delayed actions to reuse prerendered nodes and set up events
229-- State contains reference to the previous node sibling, if any.
204-- State contains reference to the previous node sibling, if any.
230newtype HydrationRunnerT t m a = HydrationRunnerT { unHydrationRunnerT :: StateT (Maybe Node) (ReaderT Node (DomRenderHookT t m)) a }
205newtype HydrationRunnerT t m a = HydrationRunnerT { unHydrationRunnerT :: StateT (Maybe Node) (ReaderT Node (DomRenderHookT t m)) a }
@@ -234,13 +209,13 @@ newtype HydrationRunnerT t m a = HydrationRunnerT { unHydrationRunnerT :: StateT
237−localRunner :: Monad m => HydrationRunnerT t m a -> Maybe Node -> Node -> HydrationRunnerT t m a
212+localRunner :: (MonadJSM m, Monad m) => HydrationRunnerT t m a -> Maybe Node -> Node -> HydrationRunnerT t m a
238−localRunner (HydrationRunnerT m) prev parent = HydrationRunnerT . lift $ local (\_ -> parent) (evalStateT m prev)
213+localRunner (HydrationRunnerT m) s parent = HydrationRunnerT . lift $ local (\_ -> parent) (evalStateT m s)
240runHydrationRunnerT
215runHydrationRunnerT
241 :: (MonadRef m, Ref m ~ IORef, Monad m, PerformEvent t m, MonadFix m, MonadReflexCreateTrigger t m, MonadJSM m, MonadJSM (Performable m))
216 :: (MonadRef m, Ref m ~ IORef, Monad m, PerformEvent t m, MonadFix m, MonadReflexCreateTrigger t m, MonadJSM m, MonadJSM (Performable m))
242 => HydrationRunnerT t m a -> Maybe Node -> Node -> Chan [DSum (EventTriggerRef t) TriggerInvocation] -> m a
217 => HydrationRunnerT t m a -> Maybe Node -> Node -> Chan [DSum (EventTriggerRef t) TriggerInvocation] -> m a
243−runHydrationRunnerT (HydrationRunnerT m) prev parent = runDomRenderHookT (runReaderT (evalStateT m prev) parent)
218+runHydrationRunnerT (HydrationRunnerT m) s parent = runDomRenderHookT (runReaderT (evalStateT m s) parent)
245instance MonadReflexCreateTrigger t m => MonadReflexCreateTrigger t (HydrationRunnerT t m) where
220instance MonadReflexCreateTrigger t m => MonadReflexCreateTrigger t (HydrationRunnerT t m) where
246 {-# INLINABLE newEventWithTrigger #-}
221 {-# INLINABLE newEventWithTrigger #-}
@@ -251,17 +226,32 @@ instance MonadReflexCreateTrigger t m => MonadReflexCreateTrigger t (HydrationRu
251instance MonadTrans (HydrationRunnerT t) where
226instance MonadTrans (HydrationRunnerT t) where
252 lift = HydrationRunnerT . lift . lift . lift
227 lift = HydrationRunnerT . lift . lift . lift
229+instance MonadSample t m => MonadSample t (HydrationRunnerT t m) where
230+ sample = lift . sample
232+-- | Add a hydration step which depends on some computation that should only be
233+-- done *before* the switchover to immediate mode - this is most likely some
234+-- form of 'hold' which we want to remove after hydration is done
254−hydrateDOM :: MonadIO m => DOM t m -> HydrationDomBuilderT t m ()
235+addHydrationStepWithSetup :: (Adjustable t m, MonadIO m) => m a -> (a -> HydrationRunnerT t m ()) -> HydrationDomBuilderT t m ()
255−hydrateDOM dom = getHydrationMode >>= \case
236+addHydrationStepWithSetup setup f = getHydrationMode >>= \case
256− HydrationMode_Hydrating -> HydrationDomBuilderT $ modify (dom :)
257 HydrationMode_Immediate -> pure ()
237 HydrationMode_Immediate -> pure ()
238+ HydrationMode_Hydrating -> do
239+ pb <- HydrationDomBuilderT $ asks _hydrationDomBuilderEnv_switchover -- Use postBuild as a proxy for switchover to immediate mode TODO is this correct?
240+ (s, _) <- lift $ runWithReplace setup $ return () <$ pb
241+ HydrationDomBuilderT $ modify' (>> f s)
243+-- | Add a hydration step
244+addHydrationStep :: MonadIO m => HydrationRunnerT t m () -> HydrationDomBuilderT t m ()
245+addHydrationStep m = getHydrationMode >>= \case
246+ HydrationMode_Immediate -> pure ()
247+ HydrationMode_Hydrating -> HydrationDomBuilderT $ modify' (>> m)
259-- | A monad for DomBuilder which just gets the results of children and pushes
249-- | A monad for DomBuilder which just gets the results of children and pushes
260-- work into an action that is delayed until after postBuild (to match the
250-- work into an action that is delayed until after postBuild (to match the
261-- static builder). The action runs in 'HydrationRunnerT', which performs the
251-- static builder). The action runs in 'HydrationRunnerT', which performs the
262-- DOM takeover and sets up the events, after which point this monad will
252-- DOM takeover and sets up the events, after which point this monad will
263-- continue in the vein of 'ImmediateDomBuilderT'.
253-- continue in the vein of 'ImmediateDomBuilderT'.
264−newtype HydrationDomBuilderT t m a = HydrationDomBuilderT { unHydrationDomBuilderT :: ReaderT HydrationDomBuilderEnv (StateT [DOM t m] (DomRenderHookT t m)) a }
254+newtype HydrationDomBuilderT t m a = HydrationDomBuilderT { unHydrationDomBuilderT :: ReaderT (HydrationDomBuilderEnv t) (StateT (HydrationRunnerT t m ()) (DomRenderHookT t m)) a }
265 deriving (Functor, Applicative, Monad, MonadFix, MonadIO, MonadException
255 deriving (Functor, Applicative, Monad, MonadFix, MonadIO, MonadException
266#if MIN_VERSION_base(4,9,1)
256#if MIN_VERSION_base(4,9,1)
267 , MonadAsyncException
257 , MonadAsyncException
@@ -332,17 +322,17 @@ runHydrationDomBuilderT
332 , Ref m ~ IORef
322 , Ref m ~ IORef
334 => HydrationDomBuilderT t m a
324 => HydrationDomBuilderT t m a
335− -> HydrationDomBuilderEnv
325+ -> HydrationDomBuilderEnv t
336 -> Chan [DSum (EventTriggerRef t) TriggerInvocation]
326 -> Chan [DSum (EventTriggerRef t) TriggerInvocation]
337− -> m (a, [DOM t m])
327+ -> m (a, HydrationRunnerT t m ())
338−runHydrationDomBuilderT (HydrationDomBuilderT a) env events = runDomRenderHookT (runStateT (runReaderT a env) []) events
328+runHydrationDomBuilderT (HydrationDomBuilderT a) env events = runDomRenderHookT (runStateT (runReaderT a env) (pure ())) events
340instance Monad m => HasDocument (HydrationDomBuilderT t m) where
330instance Monad m => HasDocument (HydrationDomBuilderT t m) where
341 {-# INLINABLE askDocument #-}
331 {-# INLINABLE askDocument #-}
342 askDocument = HydrationDomBuilderT $ asks _hydrationDomBuilderEnv_document
332 askDocument = HydrationDomBuilderT $ asks _hydrationDomBuilderEnv_document
344{-# INLINABLE localEnv #-}
334{-# INLINABLE localEnv #-}
345−localEnv :: Monad m => (HydrationDomBuilderEnv -> HydrationDomBuilderEnv) -> HydrationDomBuilderT t m a -> HydrationDomBuilderT t m a
335+localEnv :: Monad m => (HydrationDomBuilderEnv t -> HydrationDomBuilderEnv t) -> HydrationDomBuilderT t m a -> HydrationDomBuilderT t m a
346localEnv f = HydrationDomBuilderT . local f . unHydrationDomBuilderT
336localEnv f = HydrationDomBuilderT . local f . unHydrationDomBuilderT
348{-# INLINABLE append #-}
338{-# INLINABLE append #-}
@@ -425,7 +415,6 @@ hydrateNode check constructor = do
425 liftIO $ putStr $ "Node failed check, skipping... "
415 liftIO $ putStr $ "Node failed check, skipping... "
426 go (Just node)
416 go (Just node)
427 n <- go lastHydrationNode
417 n <- go lastHydrationNode
428− liftIO $ putStrLn ""
429 setPreviousNode $ Just $ toNode n
418 setPreviousNode $ Just $ toNode n
@@ -518,7 +507,7 @@ makeElement elementTag cfg child = do
518 parent <- liftIO $ newIORef $ error "Parent not yet initialized"
507 parent <- liftIO $ newIORef $ error "Parent not yet initialized"
519 env <- HydrationDomBuilderT ask
508 env <- HydrationDomBuilderT ask
520 let env' = env { _hydrationDomBuilderEnv_parent = parent}
509 let env' = env { _hydrationDomBuilderEnv_parent = parent}
521− (result, childDom) <- HydrationDomBuilderT $ lift $ lift $ runStateT (runReaderT (unHydrationDomBuilderT child) env') []
510+ (result, childDom) <- HydrationDomBuilderT $ lift $ lift $ runStateT (runReaderT (unHydrationDomBuilderT child) env') (pure ())
522 wrapResult <- liftIO newEmptyMVar
511 wrapResult <- liftIO newEmptyMVar
523 let activateElement = do
512 let activateElement = do
524 e <- hydrateNode hasSSRAttribute DOM.Element
513 e <- hydrateNode hasSSRAttribute DOM.Element
@@ -528,7 +517,7 @@ makeElement elementTag cfg child = do
528 refs <- wrap events e $ extractRawElementConfig cfg
517 refs <- wrap events e $ extractRawElementConfig cfg
529 liftIO $ putMVar wrapResult (e, refs)
518 liftIO $ putMVar wrapResult (e, refs)
530 pure $ toNode e
519 pure $ toNode e
531− hydrateDOM $ DOM_Element activateElement childDom
520+ addHydrationStep $ activateElement >>= localRunner childDom Nothing
533 -- We need the EventSelector to switch to the real event handler after activation
522 -- We need the EventSelector to switch to the real event handler after activation
534 es <- newFanEventWithTrigger $ \(WrapArg en) t -> do
523 es <- newFanEventWithTrigger $ \(WrapArg en) t -> do
@@ -553,7 +542,7 @@ makeElement elementTag cfg child = do
553 return ((Element es (), result), error "makeElement: DOM.Element")
542 return ((Element es (), result), error "makeElement: DOM.Element")
555{-# INLINABLE textNodeInternal #-}
544{-# INLINABLE textNodeInternal #-}
556−textNodeInternal :: (MonadJSM m, MonadFix m, ToDOMString contents, Reflex t) => contents -> Maybe (Event t contents) -> HydrationDomBuilderT t m DOM.Text
545+textNodeInternal :: (Adjustable t m, MonadHold t m, MonadJSM m, MonadFix m, Reflex t) => Text -> Maybe (Event t Text) -> HydrationDomBuilderT t m DOM.Text
557textNodeInternal !t mSetContents = getHydrationMode >>= \case
546textNodeInternal !t mSetContents = getHydrationMode >>= \case
558 HydrationMode_Immediate -> do
547 HydrationMode_Immediate -> do
559 n <- makeNodeInternal (askDocument >>= \doc -> createTextNode doc t)
548 n <- makeNodeInternal (askDocument >>= \doc -> createTextNode doc t)
@@ -561,15 +550,45 @@ textNodeInternal !t mSetContents = getHydrationMode >>= \case
562 HydrationMode_Hydrating -> do
551 HydrationMode_Hydrating -> do
563 doc <- askDocument
552 doc <- askDocument
564− let activateText = do
553+ addHydrationStepWithSetup (maybe (pure $ pure t) (hold t) mSetContents) $ \currentText -> do
565− liftIO $ putStrLn $ "Action: Text: " <> show (DOM.toJSString t)
554+ n <- hydrateTextNode =<< sample currentText
566− n <- hydrateNode (const $ pure True) DOM.Text
567− mapM_ (requestDomAction_ . fmap (setNodeValue n . Just)) mSetContents
555+ mapM_ (requestDomAction_ . fmap (setNodeValue n . Just)) mSetContents
568− hydrateDOM $ DOM_Node activateText
569 pure $ error "textNodeInternal: DOM.Text"
556 pure $ error "textNodeInternal: DOM.Text"
558+-- | The static builder mashes adjacent text nodes into one node: we check the
559+-- text content of each node we come to, comparing it to the content we
560+-- expect. We also have a special case for empty text nodes - we always create
561+-- the and add them after the previous node reference.
562+{-# INLINABLE hydrateTextNode #-}
563+hydrateTextNode :: MonadJSM m => Text -> HydrationRunnerT t m DOM.Text
564+hydrateTextNode t@"" = do
565+ doc <- Node.getOwnerDocumentUnchecked =<< askParent
566+ textNode <- createTextNode doc t
567+ insertAfterPreviousNode textNode
569+hydrateTextNode t = do
570+ n <- join $ go <$> askParent <*> getPreviousNode
571+ setPreviousNode $ Just $ toNode n
574+ go parent mLastNode = do
575+ node <- maybe (Node.getFirstChildUnchecked parent) Node.getNextSiblingUnchecked mLastNode
576+ DOM.castTo DOM.Text node >>= \case
577+ Nothing -> go parent $ Just node
578+ Just originalNode -> do
579+ originalText <- Node.getTextContentUnchecked originalNode
580+ case T.stripPrefix t originalText of
581+ Just "" -> return originalNode
583+ -- If we have the right prefix, we split the text node into a node containing the
584+ -- required text and a subsequent sibling node containing the rest of the text.
585+ DOM.splitText_ originalNode $ fromIntegral $ T.length t
587+ Nothing -> go parent $ Just $ toNode originalNode
571{-# INLINABLE commentNodeInternal #-}
590{-# INLINABLE commentNodeInternal #-}
572−commentNodeInternal :: (MonadJSM m, MonadFix m, ToDOMString contents, Reflex t) => contents -> Maybe (Event t contents) -> HydrationDomBuilderT t m DOM.Comment
591+commentNodeInternal :: (MonadJSM m, MonadFix m, ToDOMString contents, Reflex t, Adjustable t m) => contents -> Maybe (Event t contents) -> HydrationDomBuilderT t m DOM.Comment
573commentNodeInternal !t mSetContents = getHydrationMode >>= \case
592commentNodeInternal !t mSetContents = getHydrationMode >>= \case
574 HydrationMode_Immediate -> do
593 HydrationMode_Immediate -> do
575 n <- makeNodeInternal (askDocument >>= \doc -> createComment doc t)
594 n <- makeNodeInternal (askDocument >>= \doc -> createComment doc t)
@@ -577,17 +596,16 @@ commentNodeInternal !t mSetContents = getHydrationMode >>= \case
578 HydrationMode_Hydrating -> do
597 HydrationMode_Hydrating -> do
579 doc <- askDocument
598 doc <- askDocument
580− let activateComment = do
599+ addHydrationStep $ do
581− liftIO $ putStrLn $ "Action: Comment: " <> show (DOM.toJSString t)
600+ liftIO $ putStrLn $ "Action: Comment: " <> show (DOM.toJSString t)
582− n <- hydrateNode (const $ pure True) DOM.Comment
601+ n <- hydrateNode (const $ pure True) DOM.Comment
583− mapM_ (requestDomAction_ . fmap (setNodeValue n . Just)) mSetContents
602+ mapM_ (requestDomAction_ . fmap (setNodeValue n . Just)) mSetContents
584− hydrateDOM $ DOM_Node activateComment
585 pure $ error "commentNodeInternal: DOM.Comment"
603 pure $ error "commentNodeInternal: DOM.Comment"
587-- | We leave markers in the static builder as comments, and rip these comments
605-- | We leave markers in the static builder as comments, and rip these comments
588-- out at hydration time, replacing them with empty text nodes.
606-- out at hydration time, replacing them with empty text nodes.
589skipToAndReplaceComment
607skipToAndReplaceComment
590− :: (MonadJSM m, Reflex t, MonadFix m)
608+ :: (MonadJSM m, Reflex t, MonadFix m, Adjustable t m, MonadHold t m)
592 -> IORef Text
610 -> IORef Text
593 -> HydrationDomBuilderT t m (HydrationRunnerT t m (), IORef DOM.Text, IORef Text)
611 -> HydrationDomBuilderT t m (HydrationRunnerT t m (), IORef DOM.Text, IORef Text)
@@ -632,10 +650,10 @@ skipToAndReplaceComment prefix key0Ref = getHydrationMode >>= \case
632 writeIORef keyRef key
650 writeIORef keyRef key
633 pure (switchComment, textNodeRef, keyRef)
651 pure (switchComment, textNodeRef, keyRef)
635−skipToReplaceStart :: (MonadJSM m, Reflex t, MonadFix m) => HydrationDomBuilderT t m (HydrationRunnerT t m (), IORef DOM.Text, IORef Text)
653+skipToReplaceStart :: (MonadJSM m, Reflex t, MonadFix m, Adjustable t m, MonadHold t m) => HydrationDomBuilderT t m (HydrationRunnerT t m (), IORef DOM.Text, IORef Text)
636skipToReplaceStart = skipToAndReplaceComment "replace-start" =<< liftIO (newIORef "")
654skipToReplaceStart = skipToAndReplaceComment "replace-start" =<< liftIO (newIORef "")
638−skipToReplaceEnd :: (MonadJSM m, Reflex t, MonadFix m) => IORef Text -> HydrationDomBuilderT t m (HydrationRunnerT t m (), IORef DOM.Text)
656+skipToReplaceEnd :: (MonadJSM m, Reflex t, MonadFix m, Adjustable t m, MonadHold t m) => IORef Text -> HydrationDomBuilderT t m (HydrationRunnerT t m (), IORef DOM.Text)
639skipToReplaceEnd key = fmap (\(m,e,_) -> (m,e)) $ skipToAndReplaceComment "replace-end" key
657skipToReplaceEnd key = fmap (\(m,e,_) -> (m,e)) $ skipToAndReplaceComment "replace-end" key
641instance SupportsHydrationDomBuilder t m => NotReady t (HydrationDomBuilderT t m) where
659instance SupportsHydrationDomBuilder t m => NotReady t (HydrationDomBuilderT t m) where
@@ -823,7 +841,7 @@ instance (Reflex t, Monad m, Adjustable t m, MonadHold t m, MonadFix m) => Adjus
823 traverseDMapWithKeyWithAdjust f m = DomRenderHookT . traverseDMapWithKeyWithAdjust (\k -> unDomRenderHookT . f k) m
841 traverseDMapWithKeyWithAdjust f m = DomRenderHookT . traverseDMapWithKeyWithAdjust (\k -> unDomRenderHookT . f k) m
824 traverseDMapWithKeyWithAdjustWithMove f m = DomRenderHookT . traverseDMapWithKeyWithAdjustWithMove (\k -> unDomRenderHookT . f k) m
842 traverseDMapWithKeyWithAdjustWithMove f m = DomRenderHookT . traverseDMapWithKeyWithAdjustWithMove (\k -> unDomRenderHookT . f k) m
826−instance (Reflex t, Adjustable t m, MonadJSM m, MonadHold t m, MonadFix m, PrimMonad m, Ref m ~ IORef, PerformEvent t m, MonadReflexCreateTrigger t m, MonadJSM (Performable m), MonadRef m) => Adjustable t (HydrationDomBuilderT t m) where
844+instance (Reflex t, Adjustable t m, MonadJSM m, MonadHold t m, MonadFix m, PrimMonad m, Ref m ~ IORef, MonadReflexCreateTrigger t m, MonadJSM (Performable m), MonadRef m) => Adjustable t (HydrationDomBuilderT t m) where
827 {-# INLINABLE runWithReplace #-}
845 {-# INLINABLE runWithReplace #-}
828 runWithReplace a0 a' = do
846 runWithReplace a0 a' = do
829 initialEnv <- HydrationDomBuilderT ask
847 initialEnv <- HydrationDomBuilderT ask
@@ -858,7 +876,7 @@ instance (Reflex t, Adjustable t m, MonadJSM m, MonadHold t m, MonadFix m, PrimM
859 insertBefore p' =<< liftIO (readIORef after)
877 insertBefore p' =<< liftIO (readIORef after)
861− (result, dom) <- flip runStateT [] $ runReaderT (unHydrationDomBuilderT a0') initialEnv
879+ (result, dom) <- flip runStateT (pure ()) $ runReaderT (unHydrationDomBuilderT a0') initialEnv
862 { _hydrationDomBuilderEnv_unreadyChildren = unreadyChildren
880 { _hydrationDomBuilderEnv_unreadyChildren = unreadyChildren
863 , _hydrationDomBuilderEnv_commitAction = myCommitAction
881 , _hydrationDomBuilderEnv_commitAction = myCommitAction
864 , _hydrationDomBuilderEnv_parent = p
882 , _hydrationDomBuilderEnv_parent = p
@@ -884,7 +902,7 @@ instance (Reflex t, Adjustable t m, MonadJSM m, MonadHold t m, MonadFix m, PrimM
884 insertBefore p' after'
902 insertBefore p' after'
885 liftIO $ writeIORef currentCohort cohortId
903 liftIO $ writeIORef currentCohort cohortId
886 myCommitAction
904 myCommitAction
887− (result, dom) <- flip runStateT [] $ runReaderT (unHydrationDomBuilderT child) $ initialEnv
905+ (result, dom) <- flip runStateT (pure ()) $ runReaderT (unHydrationDomBuilderT child) $ initialEnv
888 { _hydrationDomBuilderEnv_unreadyChildren = unreadyChildren
906 { _hydrationDomBuilderEnv_unreadyChildren = unreadyChildren
889 , _hydrationDomBuilderEnv_commitAction = case h of
907 , _hydrationDomBuilderEnv_commitAction = case h of
890 HydrationMode_Hydrating -> myCommitAction
908 HydrationMode_Hydrating -> myCommitAction
@@ -900,7 +918,10 @@ instance (Reflex t, Adjustable t m, MonadJSM m, MonadHold t m, MonadFix m, PrimM
900 HydrationMode_Immediate -> Right commitActionToRunNow
918 HydrationMode_Immediate -> Right commitActionToRunNow
901 return (actions, result)
919 return (actions, result)
902 let (hydrate', commitAction) = fanEither $ fmap fst child'
920 let (hydrate', commitAction) = fanEither $ fmap fst child'
903− hydrateDOM . DOM_Replace hydrateStart hydrateEnd =<< hold hydrate0 hydrate'
921+ addHydrationStepWithSetup (hold hydrate0 hydrate') $ \contents -> do
923+ join $ sample contents
904 requestDomAction_ $ fmapMaybe id commitAction
925 requestDomAction_ $ fmapMaybe id commitAction
905 return (result0, snd <$> child')
926 return (result0, snd <$> child')
@@ -910,8 +931,8 @@ instance (Reflex t, Adjustable t m, MonadJSM m, MonadHold t m, MonadFix m, PrimM
910 traverseDMapWithKeyWithAdjust = traverseDMapWithKeyWithAdjust'
931 traverseDMapWithKeyWithAdjust = traverseDMapWithKeyWithAdjust'
911 {-# INLINABLE traverseDMapWithKeyWithAdjustWithMove #-}
932 {-# INLINABLE traverseDMapWithKeyWithAdjustWithMove #-}
912 traverseDMapWithKeyWithAdjustWithMove = do
933 traverseDMapWithKeyWithAdjustWithMove = do
913− let updateChildUnreadiness (p :: PatchDMapWithMove k (Compose ((,,,,) (DOM t m) DOM.DocumentFragment DOM.Text (IORef (ChildReadyState k))) v')) old = do
934+ let updateChildUnreadiness (p :: PatchDMapWithMove k (Compose ((,,,,) (HydrationRunnerT t m ()) DOM.DocumentFragment DOM.Text (IORef (ChildReadyState k))) v')) old = do
914− let new :: forall a. k a -> PatchDMapWithMove.NodeInfo k (Compose ((,,,,) (DOM t m) DOM.DocumentFragment DOM.Text (IORef (ChildReadyState k))) v') a -> IO (PatchDMapWithMove.NodeInfo k (Constant (IORef (ChildReadyState k))) a)
935+ let new :: forall a. k a -> PatchDMapWithMove.NodeInfo k (Compose ((,,,,) (HydrationRunnerT t m ()) DOM.DocumentFragment DOM.Text (IORef (ChildReadyState k))) v') a -> IO (PatchDMapWithMove.NodeInfo k (Constant (IORef (ChildReadyState k))) a)
915 new k = PatchDMapWithMove.nodeInfoMapFromM $ \case
936 new k = PatchDMapWithMove.nodeInfoMapFromM $ \case
916 PatchDMapWithMove.From_Insert (Compose (_, _, _, sRef, _)) -> do
937 PatchDMapWithMove.From_Insert (Compose (_, _, _, sRef, _)) -> do
917 readIORef sRef >>= \case
938 readIORef sRef >>= \case
@@ -928,11 +949,11 @@ instance (Reflex t, Adjustable t m, MonadJSM m, MonadHold t m, MonadFix m, PrimM
928 p' <- fmap unsafePatchDMapWithMove $ DMap.traverseWithKey new $ unPatchDMapWithMove p
949 p' <- fmap unsafePatchDMapWithMove $ DMap.traverseWithKey new $ unPatchDMapWithMove p
929 _ <- DMap.traverseWithKey deleteOrMove $ PatchDMapWithMove.getDeletionsAndMoves p old
950 _ <- DMap.traverseWithKey deleteOrMove $ PatchDMapWithMove.getDeletionsAndMoves p old
930 return $ applyAlways p' old
951 return $ applyAlways p' old
931− hoistTraverseWithKeyWithAdjust traverseDMapWithKeyWithAdjustWithMove mapPatchDMapWithMove updateChildUnreadiness $ \placeholders lastPlaceholderRef (p_ :: PatchDMapWithMove k (Compose ((,,,,) (DOM t m) DOM.DocumentFragment DOM.Text (IORef (ChildReadyState k))) v')) -> do
952+ hoistTraverseWithKeyWithAdjust traverseDMapWithKeyWithAdjustWithMove mapPatchDMapWithMove updateChildUnreadiness $ \placeholders lastPlaceholderRef (p_ :: PatchDMapWithMove k (Compose ((,,,,) (HydrationRunnerT t m ()) DOM.DocumentFragment DOM.Text (IORef (ChildReadyState k))) v')) -> do
932 let p = unPatchDMapWithMove p_
953 let p = unPatchDMapWithMove p_
933 phsBefore <- liftIO $ readIORef placeholders
954 phsBefore <- liftIO $ readIORef placeholders
934 lastPlaceholder <- liftIO $ readIORef lastPlaceholderRef
955 lastPlaceholder <- liftIO $ readIORef lastPlaceholderRef
935− let collectIfMoved :: forall a. k a -> PatchDMapWithMove.NodeInfo k (Compose ((,,,,) (DOM t m) DOM.DocumentFragment DOM.Text (IORef (ChildReadyState k))) v') a -> JSM (Constant (Maybe DOM.DocumentFragment) a)
956+ let collectIfMoved :: forall a. k a -> PatchDMapWithMove.NodeInfo k (Compose ((,,,,) (HydrationRunnerT t m ()) DOM.DocumentFragment DOM.Text (IORef (ChildReadyState k))) v') a -> JSM (Constant (Maybe DOM.DocumentFragment) a)
936 collectIfMoved k e = do
957 collectIfMoved k e = do
937 let mThisPlaceholder = Map.lookup (Some.This k) phsBefore -- Will be Nothing if this element wasn't present before
958 let mThisPlaceholder = Map.lookup (Some.This k) phsBefore -- Will be Nothing if this element wasn't present before
938 nextPlaceholder = maybe lastPlaceholder snd $ Map.lookupGT (Some.This k) phsBefore
959 nextPlaceholder = maybe lastPlaceholder snd $ Map.lookupGT (Some.This k) phsBefore
@@ -944,7 +965,7 @@ instance (Reflex t, Adjustable t m, MonadJSM m, MonadHold t m, MonadFix m, PrimM
944 Constant <$> mapM (`collectUpTo` nextPlaceholder) mThisPlaceholder
965 Constant <$> mapM (`collectUpTo` nextPlaceholder) mThisPlaceholder
945 collected <- DMap.traverseWithKey collectIfMoved p
966 collected <- DMap.traverseWithKey collectIfMoved p
946 let !phsAfter = fromMaybe phsBefore $ apply (weakenPatchDMapWithMoveWith (\(Compose (_, _, ph, _, _)) -> ph) p_) phsBefore --TODO: Don't recompute this
967 let !phsAfter = fromMaybe phsBefore $ apply (weakenPatchDMapWithMoveWith (\(Compose (_, _, ph, _, _)) -> ph) p_) phsBefore --TODO: Don't recompute this
947− let placeFragment :: forall a. k a -> PatchDMapWithMove.NodeInfo k (Compose ((,,,,) (DOM t m) DOM.DocumentFragment DOM.Text (IORef (ChildReadyState k))) v') a -> JSM (Constant () a)
968+ let placeFragment :: forall a. k a -> PatchDMapWithMove.NodeInfo k (Compose ((,,,,) (HydrationRunnerT t m ()) DOM.DocumentFragment DOM.Text (IORef (ChildReadyState k))) v') a -> JSM (Constant () a)
948 placeFragment k e = do
969 placeFragment k e = do
949 let nextPlaceholder = maybe lastPlaceholder snd $ Map.lookupGT (Some.This k) phsAfter
970 let nextPlaceholder = maybe lastPlaceholder snd $ Map.lookupGT (Some.This k) phsAfter
950 case PatchDMapWithMove._nodeInfo_from e of
971 case PatchDMapWithMove._nodeInfo_from e of
@@ -967,8 +988,8 @@ traverseDMapWithKeyWithAdjust'
967 -> Event t (PatchDMap k v)
988 -> Event t (PatchDMap k v)
968 -> HydrationDomBuilderT t m (DMap k v', Event t (PatchDMap k v'))
989 -> HydrationDomBuilderT t m (DMap k v', Event t (PatchDMap k v'))
969traverseDMapWithKeyWithAdjust' = do
990traverseDMapWithKeyWithAdjust' = do
970− let updateChildUnreadiness (p :: PatchDMap k (Compose ((,,,,) (DOM t m) DOM.DocumentFragment DOM.Text (IORef (ChildReadyState k))) v')) old = do
991+ let updateChildUnreadiness (p :: PatchDMap k (Compose ((,,,,) (HydrationRunnerT t m ()) DOM.DocumentFragment DOM.Text (IORef (ChildReadyState k))) v')) old = do
971− let new :: forall a. k a -> ComposeMaybe (Compose ((,,,,) (DOM t m) DOM.DocumentFragment DOM.Text (IORef (ChildReadyState k))) v') a -> IO (ComposeMaybe (Constant (IORef (ChildReadyState k))) a)
992+ let new :: forall a. k a -> ComposeMaybe (Compose ((,,,,) (HydrationRunnerT t m ()) DOM.DocumentFragment DOM.Text (IORef (ChildReadyState k))) v') a -> IO (ComposeMaybe (Constant (IORef (ChildReadyState k))) a)
972 new k (ComposeMaybe m) = ComposeMaybe <$> case m of
993 new k (ComposeMaybe m) = ComposeMaybe <$> case m of
973 Nothing -> return Nothing
994 Nothing -> return Nothing
974 Just (Compose (_, _, _, sRef, _)) -> do
995 Just (Compose (_, _, _, sRef, _)) -> do
@@ -1000,8 +1021,8 @@ traverseIntMapWithKeyWithAdjust'
1000 -> Event t (PatchIntMap v)
1021 -> Event t (PatchIntMap v)
1001 -> HydrationDomBuilderT t m (IntMap v', Event t (PatchIntMap v'))
1022 -> HydrationDomBuilderT t m (IntMap v', Event t (PatchIntMap v'))
1002traverseIntMapWithKeyWithAdjust' = do
1023traverseIntMapWithKeyWithAdjust' = do
1003− let updateChildUnreadiness (p@(PatchIntMap pInner) :: PatchIntMap (DOM t m, DOM.DocumentFragment, DOM.Text, IORef ChildReadyStateInt, v')) old = do
1024+ let updateChildUnreadiness (p@(PatchIntMap pInner) :: PatchIntMap (HydrationRunnerT t m (), DOM.DocumentFragment, DOM.Text, IORef ChildReadyStateInt, v')) old = do
1004− let new :: IntMap.Key -> Maybe (DOM t m, DOM.DocumentFragment, DOM.Text, IORef ChildReadyStateInt, v') -> IO (Maybe (IORef ChildReadyStateInt))
1025+ let new :: IntMap.Key -> Maybe (HydrationRunnerT t m (), DOM.DocumentFragment, DOM.Text, IORef ChildReadyStateInt, v') -> IO (Maybe (IORef ChildReadyStateInt))
1005 new k m = case m of
1026 new k m = case m of
1006 Nothing -> return Nothing
1027 Nothing -> return Nothing
1007 Just (_, _, _, sRef, _) -> do
1028 Just (_, _, _, sRef, _) -> do
@@ -1032,19 +1053,19 @@ hoistTraverseIntMapWithKeyWithAdjust :: forall v v' t m p.
1032 , MonadJSM m
1053 , MonadJSM m
1033 , MonadFix m
1054 , MonadFix m
1034 , PrimMonad m
1055 , PrimMonad m
1035− , Monoid (p (DOM t m, DOM.DocumentFragment, DOM.Text, IORef ChildReadyStateInt, v'))
1056+ , Monoid (p (HydrationRunnerT t m (), DOM.DocumentFragment, DOM.Text, IORef ChildReadyStateInt, v'))
1036 , Functor p
1057 , Functor p
1037− , PatchTarget (p (DOM t m)) ~ IntMap (DOM t m)
1058+ , PatchTarget (p (HydrationRunnerT t m ())) ~ IntMap (HydrationRunnerT t m ())
1038 , MonadHold t m
1059 , MonadHold t m
1039− , Patch (p (DOM t m))
1060+ , Patch (p (HydrationRunnerT t m ()))
1041− => ( (IntMap.Key -> v -> DomRenderHookT t m (DOM t m, DOM.DocumentFragment, DOM.Text, IORef ChildReadyStateInt, v'))
1062+ => ( (IntMap.Key -> v -> DomRenderHookT t m (HydrationRunnerT t m (), DOM.DocumentFragment, DOM.Text, IORef ChildReadyStateInt, v'))
1042 -> IntMap v
1063 -> IntMap v
1043 -> Event t (p v)
1064 -> Event t (p v)
1044− -> DomRenderHookT t m (IntMap (DOM t m, DOM.DocumentFragment, DOM.Text, IORef ChildReadyStateInt, v'), Event t (p (DOM t m, DOM.DocumentFragment, DOM.Text, IORef ChildReadyStateInt, v')))
1065+ -> DomRenderHookT t m (IntMap (HydrationRunnerT t m (), DOM.DocumentFragment, DOM.Text, IORef ChildReadyStateInt, v'), Event t (p (HydrationRunnerT t m (), DOM.DocumentFragment, DOM.Text, IORef ChildReadyStateInt, v')))
1045 ) -- ^ The base monad's traversal
1066 ) -- ^ The base monad's traversal
1046− -> (p (DOM t m, DOM.DocumentFragment, DOM.Text, IORef ChildReadyStateInt, v') -> IntMap (IORef ChildReadyStateInt) -> IO (IntMap (IORef ChildReadyStateInt))) -- ^ Given a patch for the children DOM elements, produce a patch for the childrens' unreadiness state
1067+ -> (p (HydrationRunnerT t m (), DOM.DocumentFragment, DOM.Text, IORef ChildReadyStateInt, v') -> IntMap (IORef ChildReadyStateInt) -> IO (IntMap (IORef ChildReadyStateInt))) -- ^ Given a patch for the children DOM elements, produce a patch for the childrens' unreadiness state
1047− -> (IORef (IntMap DOM.Text) -> IORef DOM.Text -> p (DOM t m, DOM.DocumentFragment, DOM.Text, IORef ChildReadyStateInt, v') -> JSM ()) -- ^ Apply a patch to the DOM
1068+ -> (IORef (IntMap DOM.Text) -> IORef DOM.Text -> p (HydrationRunnerT t m (), DOM.DocumentFragment, DOM.Text, IORef ChildReadyStateInt, v') -> JSM ()) -- ^ Apply a patch to the DOM
1048 -> (IntMap.Key -> v -> HydrationDomBuilderT t m v')
1069 -> (IntMap.Key -> v -> HydrationDomBuilderT t m v')
1049 -> IntMap v
1070 -> IntMap v
1050 -> Event t (p v)
1071 -> Event t (p v)
@@ -1053,7 +1074,7 @@ hoistTraverseIntMapWithKeyWithAdjust base updateChildUnreadiness applyDomUpdate_
1053 (hydrateStart, _, key) <- skipToReplaceStart
1074 (hydrateStart, _, key) <- skipToReplaceStart
1054 initialEnv <- HydrationDomBuilderT ask
1075 initialEnv <- HydrationDomBuilderT ask
1055 let parentUnreadyChildren = _hydrationDomBuilderEnv_unreadyChildren initialEnv
1076 let parentUnreadyChildren = _hydrationDomBuilderEnv_unreadyChildren initialEnv
1056− pendingChange :: IORef (IntMap (IORef ChildReadyStateInt), p (DOM t m, DOM.DocumentFragment, DOM.Text, IORef ChildReadyStateInt, v')) <- liftIO $ newIORef mempty
1077+ pendingChange :: IORef (IntMap (IORef ChildReadyStateInt), p (HydrationRunnerT t m (), DOM.DocumentFragment, DOM.Text, IORef ChildReadyStateInt, v')) <- liftIO $ newIORef mempty
1057 haveEverBeenReady <- liftIO $ newIORef False
1078 haveEverBeenReady <- liftIO $ newIORef False
1058 placeholders <- liftIO $ newIORef $ error "placeholders not yet initialized"
1079 placeholders <- liftIO $ newIORef $ error "placeholders not yet initialized"
1059 lastPlaceholderRef <- liftIO $ newIORef $ error "lastPlaceholderRef not yet initialized"
1080 lastPlaceholderRef <- liftIO $ newIORef $ error "lastPlaceholderRef not yet initialized"
@@ -1100,22 +1121,19 @@ hoistTraverseIntMapWithKeyWithAdjust base updateChildUnreadiness applyDomUpdate_
1100 writeIORef pendingChange (initialUnready, mempty) -- The patch is always empty because it got applied implicitly when we ran the children the first time
1121 writeIORef pendingChange (initialUnready, mempty) -- The patch is always empty because it got applied implicitly when we ran the children the first time
1101 let result0 = IntMap.map (\(_, _, _, _, v) -> v) children0
1122 let result0 = IntMap.map (\(_, _, _, _, v) -> v) children0
1102 placeholders0 = fmap (\(_, _, ph, _, _) -> ph) children0
1123 placeholders0 = fmap (\(_, _, ph, _, _) -> ph) children0
1103− delayed0 :: IntMap (DOM t m)
1124+ delayed0 :: IntMap (HydrationRunnerT t m ())
1104 delayed0 = IntMap.map (\(delayed, _, _, _, _) -> delayed) children0
1125 delayed0 = IntMap.map (\(delayed, _, _, _, _) -> delayed) children0
1105− delayed' :: Event t (p (DOM t m))
1126+ delayed' :: Event t (p (HydrationRunnerT t m ()))
1106 delayed' = ffor children' $ fmap $ \(delayed, _, _, _, _) -> delayed
1127 delayed' = ffor children' $ fmap $ \(delayed, _, _, _, _) -> delayed
1107 result' = ffor children' $ fmap $ \(_, _, _, _, r) -> r
1128 result' = ffor children' $ fmap $ \(_, _, _, _, r) -> r
1108− delayed <- accumMaybeB (flip apply) delayed0 delayed'
1109 doc <- askDocument
1129 doc <- askDocument
1110 let setFinalPlaceholder = do
1130 let setFinalPlaceholder = do
1111 ph <- createTextNode doc ("" :: Text)
1131 ph <- createTextNode doc ("" :: Text)
1112− parent <- askParent
1132+ insertAfterPreviousNode ph
1113− pn <- runMaybeT $ MaybeT . Node.getNextSibling =<< MaybeT getPreviousNode
1114− Node.insertBefore_ parent ph pn
1115 liftIO $ writeIORef lastPlaceholderRef ph
1133 liftIO $ writeIORef lastPlaceholderRef ph
1116− setPreviousNode $ Just $ toNode ph
1134+ addHydrationStepWithSetup (accumMaybeB (flip apply) delayed0 delayed') $ \delayed -> do
1117− hydrateDOM $ DOM_Replace (pure ()) setFinalPlaceholder
1118− (reverse . IntMap.elems <$> delayed)
1135+ join $ sample (sequence . IntMap.elems <$> delayed)
1136+ setFinalPlaceholder
1119 liftIO $ writeIORef placeholders $! placeholders0
1137 liftIO $ writeIORef placeholders $! placeholders0
1120 getHydrationMode >>= \case
1138 getHydrationMode >>= \case
1121 HydrationMode_Immediate -> void $ IntMap.traverseWithKey (\_ (_, df, _, _, _) -> void $ append $ toNode df) children0
1139 HydrationMode_Immediate -> void $ IntMap.traverseWithKey (\_ (_, df, _, _, _) -> void $ append $ toNode df) children0
@@ -1130,6 +1148,13 @@ hoistTraverseIntMapWithKeyWithAdjust base updateChildUnreadiness applyDomUpdate_
1130 applyDomUpdate newP
1148 applyDomUpdate newP
1131 return (result0, result')
1149 return (result0, result')
1151+insertAfterPreviousNode :: (Monad m, MonadJSM m) => DOM.IsNode node => node -> HydrationRunnerT t m ()
1152+insertAfterPreviousNode node = do
1153+ parent <- askParent
1154+ nextNode <- maybe (Node.getFirstChild parent) Node.getNextSibling =<< getPreviousNode
1155+ Node.insertBefore_ parent node nextNode
1156+ setPreviousNode $ Just $ toNode node
1133{-# INLINABLE hoistTraverseWithKeyWithAdjust #-}
1158{-# INLINABLE hoistTraverseWithKeyWithAdjust #-}
1134hoistTraverseWithKeyWithAdjust :: forall (k :: * -> *) v v' t m p.
1159hoistTraverseWithKeyWithAdjust :: forall (k :: * -> *) v v' t m p.
1135 ( Adjustable t m
1160 ( Adjustable t m
@@ -1141,9 +1166,9 @@ hoistTraverseWithKeyWithAdjust :: forall (k :: * -> *) v v' t m p.
1141 , MonadFix m
1166 , MonadFix m
1142 , Patch (p k v)
1167 , Patch (p k v)
1143 , PatchTarget (p k (Constant Int)) ~ DMap k (Constant Int)
1168 , PatchTarget (p k (Constant Int)) ~ DMap k (Constant Int)
1144− , Patch (p k (Const (DOM t m)))
1169+ , Patch (p k (Const (HydrationRunnerT t m ())))
1145− , PatchTarget (p k (Const (DOM t m))) ~ DMap k (Const (DOM t m))
1170+ , PatchTarget (p k (Const (HydrationRunnerT t m ()))) ~ DMap k (Const (HydrationRunnerT t m ()))
1146− , Monoid (p k (Compose ((,,,,) (DOM t m) DOM.DocumentFragment DOM.Text (IORef (ChildReadyState k))) v'))
1171+ , Monoid (p k (Compose ((,,,,) (HydrationRunnerT t m ()) DOM.DocumentFragment DOM.Text (IORef (ChildReadyState k))) v'))
1147 , Patch (p k (Constant Int))
1172 , Patch (p k (Constant Int))
1149 => (forall vv vv'.
1174 => (forall vv vv'.
@@ -1153,8 +1178,8 @@ hoistTraverseWithKeyWithAdjust :: forall (k :: * -> *) v v' t m p.
1153 -> DomRenderHookT t m (DMap k vv', Event t (p k vv'))
1178 -> DomRenderHookT t m (DMap k vv', Event t (p k vv'))
1154 ) -- ^ The base monad's traversal
1179 ) -- ^ The base monad's traversal
1155 -> (forall vv vv'. (forall a. vv a -> vv' a) -> p k vv -> p k vv') -- ^ A way of mapping over the patch type
1180 -> (forall vv vv'. (forall a. vv a -> vv' a) -> p k vv -> p k vv') -- ^ A way of mapping over the patch type
1156− -> (p k (Compose ((,,,,) (DOM t m) 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
1181+ -> (p k (Compose ((,,,,) (HydrationRunnerT t m ()) 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
1157− -> (IORef (Map.Map (Some.Some k) DOM.Text) -> IORef DOM.Text -> p k (Compose ((,,,,) (DOM t m) DOM.DocumentFragment DOM.Text (IORef (ChildReadyState k))) v') -> JSM ()) -- ^ Apply a patch to the DOM
1182+ -> (IORef (Map.Map (Some.Some k) DOM.Text) -> IORef DOM.Text -> p k (Compose ((,,,,) (HydrationRunnerT t m ()) DOM.DocumentFragment DOM.Text (IORef (ChildReadyState k))) v') -> JSM ()) -- ^ Apply a patch to the DOM
1158 -> (forall a. k a -> v a -> HydrationDomBuilderT t m (v' a))
1183 -> (forall a. k a -> v a -> HydrationDomBuilderT t m (v' a))
1159 -> DMap k v
1184 -> DMap k v
1160 -> Event t (p k v)
1185 -> Event t (p k v)
@@ -1163,7 +1188,7 @@ hoistTraverseWithKeyWithAdjust base mapPatch updateChildUnreadiness applyDomUpda
1163-- (hydrateStart, _, key) <- skipToReplaceStart -- TODO
1188-- (hydrateStart, _, key) <- skipToReplaceStart -- TODO
1164 initialEnv <- HydrationDomBuilderT ask
1189 initialEnv <- HydrationDomBuilderT ask
1165 let parentUnreadyChildren = _hydrationDomBuilderEnv_unreadyChildren initialEnv
1190 let parentUnreadyChildren = _hydrationDomBuilderEnv_unreadyChildren initialEnv
1166− pendingChange :: IORef (DMap k (Constant (IORef (ChildReadyState k))), p k (Compose ((,,,,) (DOM t m) DOM.DocumentFragment DOM.Text (IORef (ChildReadyState k))) v')) <- liftIO $ newIORef mempty
1191+ pendingChange :: IORef (DMap k (Constant (IORef (ChildReadyState k))), p k (Compose ((,,,,) (HydrationRunnerT t m ()) DOM.DocumentFragment DOM.Text (IORef (ChildReadyState k))) v')) <- liftIO $ newIORef mempty
1167 haveEverBeenReady <- liftIO $ newIORef False
1192 haveEverBeenReady <- liftIO $ newIORef False
1168 placeholders <- liftIO $ newIORef $ error "placeholders not yet initialized"
1193 placeholders <- liftIO $ newIORef $ error "placeholders not yet initialized"
1169 lastPlaceholderRef <- liftIO $ newIORef $ error "lastPlaceholderRef not yet initialized"
1194 lastPlaceholderRef <- liftIO $ newIORef $ error "lastPlaceholderRef not yet initialized"
@@ -1210,22 +1235,19 @@ hoistTraverseWithKeyWithAdjust base mapPatch updateChildUnreadiness applyDomUpda
1210 writeIORef pendingChange (initialUnready, mempty) -- The patch is always empty because it got applied implicitly when we ran the children the first time
1235 writeIORef pendingChange (initialUnready, mempty) -- The patch is always empty because it got applied implicitly when we ran the children the first time
1211 let result0 = DMap.map (\(Compose (_, _, _, _, v)) -> v) children0
1236 let result0 = DMap.map (\(Compose (_, _, _, _, v)) -> v) children0
1212 placeholders0 = weakenDMapWith (\(Compose (_, _, ph, _, _)) -> ph) children0
1237 placeholders0 = weakenDMapWith (\(Compose (_, _, ph, _, _)) -> ph) children0
1213− delayed0 :: DMap k (Const (DOM t m))
1238+ delayed0 :: DMap k (Const (HydrationRunnerT t m ()))
1214 delayed0 = DMap.map (\(Compose (delayed, _, _, _, _)) -> Const delayed) children0
1239 delayed0 = DMap.map (\(Compose (delayed, _, _, _, _)) -> Const delayed) children0
1215− delayed' :: Event t (p k (Const (DOM t m)))
1240+ delayed' :: Event t (p k (Const (HydrationRunnerT t m ())))
1216 delayed' = ffor children' $ mapPatch $ \(Compose (d, _, _, _, _)) -> Const d
1241 delayed' = ffor children' $ mapPatch $ \(Compose (d, _, _, _, _)) -> Const d
1217 result' = ffor children' $ mapPatch $ \(Compose (_, _, _, _, r)) -> r
1242 result' = ffor children' $ mapPatch $ \(Compose (_, _, _, _, r)) -> r
1218− delayed <- accumMaybeB (flip apply) delayed0 delayed'
1219 doc <- askDocument
1243 doc <- askDocument
1220 let setFinalPlaceholder = do
1244 let setFinalPlaceholder = do
1221 ph <- createTextNode doc ("" :: Text)
1245 ph <- createTextNode doc ("" :: Text)
1222− parent <- askParent
1246+ insertAfterPreviousNode ph
1223− pn <- runMaybeT $ MaybeT . Node.getNextSibling =<< MaybeT getPreviousNode
1224− Node.insertBefore_ parent ph pn
1225 liftIO $ writeIORef lastPlaceholderRef ph
1247 liftIO $ writeIORef lastPlaceholderRef ph
1226− setPreviousNode $ Just $ toNode ph
1248+ addHydrationStepWithSetup (accumMaybeB (flip apply) delayed0 delayed') $ \delayed -> do
1227− hydrateDOM $ DOM_Replace (pure ()) setFinalPlaceholder
1228− (fmap (\(_ :=> Const d) -> d) . reverse . DMap.toList <$> delayed)
1249+ join $ sample (sequence . fmap (\(_ :=> Const d) -> d) . DMap.toList <$> delayed)
1250+ setFinalPlaceholder
1229 liftIO $ writeIORef placeholders $! placeholders0
1251 liftIO $ writeIORef placeholders $! placeholders0
1230 getHydrationMode >>= \case
1252 getHydrationMode >>= \case
1231 HydrationMode_Immediate -> void $ DMap.traverseWithKey (\_ (Compose (_, df, _, _, _)) -> Constant () <$ append (toNode df)) children0
1253 HydrationMode_Immediate -> void $ DMap.traverseWithKey (\_ (Compose (_, df, _, _, _)) -> Constant () <$ append (toNode df)) children0
@@ -1241,10 +1263,10 @@ hoistTraverseWithKeyWithAdjust base mapPatch updateChildUnreadiness applyDomUpda
1242{-# INLINABLE drawChildUpdate #-}
1264{-# INLINABLE drawChildUpdate #-}
1243drawChildUpdate :: (MonadIO m, MonadJSM m, Reflex t)
1265drawChildUpdate :: (MonadIO m, MonadJSM m, Reflex t)
1244− => HydrationDomBuilderEnv
1266+ => HydrationDomBuilderEnv t
1245 -> (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
1267 -> (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
1246 -> HydrationDomBuilderT t m (v' a)
1268 -> HydrationDomBuilderT t m (v' a)
1247− -> DomRenderHookT t m (Compose ((,,,,) (DOM t m) DOM.DocumentFragment DOM.Text (IORef (ChildReadyState k))) v' a)
1269+ -> DomRenderHookT t m (Compose ((,,,,) (HydrationRunnerT t m ()) DOM.DocumentFragment DOM.Text (IORef (ChildReadyState k))) v' a)
1248drawChildUpdate initialEnv markReady child = do
1270drawChildUpdate initialEnv markReady child = do
1249 childReadyState <- liftIO $ newIORef $ ChildReadyState_Unready Nothing
1271 childReadyState <- liftIO $ newIORef $ ChildReadyState_Unready Nothing
1250 let doc = _hydrationDomBuilderEnv_document initialEnv
1272 let doc = _hydrationDomBuilderEnv_document initialEnv
@@ -1254,19 +1276,14 @@ drawChildUpdate initialEnv markReady child = do
1254 (p, delayed) <- case hydrationMode of
1276 (p, delayed) <- case hydrationMode of
1255 HydrationMode_Hydrating -> pure
1277 HydrationMode_Hydrating -> pure
1256 ( Left $ _hydrationDomBuilderEnv_parent initialEnv
1278 ( Left $ _hydrationDomBuilderEnv_parent initialEnv
1257− , do
1279+ , insertAfterPreviousNode placeholder
1258− parent <- askParent
1259− getPreviousNode >>= \case
1260− Nothing -> Node.getFirstChild parent >>= Node.insertBefore_ parent placeholder
1261− Just pn -> Node.getNextSibling pn >>= Node.insertBefore_ parent placeholder
1262− setPreviousNode $ Just $ toNode placeholder
1264 HydrationMode_Immediate -> do
1281 HydrationMode_Immediate -> do
1265 df <- createDocumentFragment doc
1282 df <- createDocumentFragment doc
1266 Node.appendChild_ df placeholder
1283 Node.appendChild_ df placeholder
1267 pure (Right df, pure ())
1284 pure (Right df, pure ())
1268 p' <- either pure (liftIO . newIORef . toNode) p
1285 p' <- either pure (liftIO . newIORef . toNode) p
1269− (result, finalState) <- flip runStateT [] $ runReaderT (unHydrationDomBuilderT child) initialEnv
1286+ (result, finalState) <- flip runStateT (pure ()) $ runReaderT (unHydrationDomBuilderT child) initialEnv
1270 { _hydrationDomBuilderEnv_parent = p'
1287 { _hydrationDomBuilderEnv_parent = p'
1271 , _hydrationDomBuilderEnv_unreadyChildren = unreadyChildren
1288 , _hydrationDomBuilderEnv_unreadyChildren = unreadyChildren
1272 , _hydrationDomBuilderEnv_commitAction = markReady childReadyState
1289 , _hydrationDomBuilderEnv_commitAction = markReady childReadyState
@@ -1274,17 +1291,17 @@ drawChildUpdate initialEnv markReady child = do
1274 u <- liftIO $ readIORef unreadyChildren
1291 u <- liftIO $ readIORef unreadyChildren
1275 when (u == 0) $ liftIO $ writeIORef childReadyState ChildReadyState_Ready
1292 when (u == 0) $ liftIO $ writeIORef childReadyState ChildReadyState_Ready
1276 return $ Compose
1293 return $ Compose
1277− ( DOM_Replace delayed (pure ()) (pure finalState)
1294+ ( delayed >> finalState
1278 , either (const $ error "drawChildUpdate: Tried to use document fragment in hydration mode") id p
1295 , either (const $ error "drawChildUpdate: Tried to use document fragment in hydration mode") id p
1279 , placeholder, childReadyState, result
1296 , placeholder, childReadyState, result
1282{-# INLINABLE drawChildUpdateInt #-}
1299{-# INLINABLE drawChildUpdateInt #-}
1283drawChildUpdateInt :: (MonadIO m, MonadJSM m, Reflex t)
1300drawChildUpdateInt :: (MonadIO m, MonadJSM m, Reflex t)
1284− => HydrationDomBuilderEnv
1301+ => HydrationDomBuilderEnv t
1285 -> (IORef ChildReadyStateInt -> JSM ()) -- This will NOT be called if the child is ready at initialization time; instead, the ChildReadyState return value will be ChildReadyState_Ready
1302 -> (IORef ChildReadyStateInt -> JSM ()) -- This will NOT be called if the child is ready at initialization time; instead, the ChildReadyState return value will be ChildReadyState_Ready
1286 -> HydrationDomBuilderT t m v'
1303 -> HydrationDomBuilderT t m v'
1287− -> DomRenderHookT t m (DOM t m, DOM.DocumentFragment, DOM.Text, IORef ChildReadyStateInt, v')
1304+ -> DomRenderHookT t m (HydrationRunnerT t m (), DOM.DocumentFragment, DOM.Text, IORef ChildReadyStateInt, v')
1288drawChildUpdateInt initialEnv markReady child = do
1305drawChildUpdateInt initialEnv markReady child = do
1289 childReadyState <- liftIO $ newIORef $ ChildReadyStateInt_Unready Nothing
1306 childReadyState <- liftIO $ newIORef $ ChildReadyStateInt_Unready Nothing
1290 let doc = _hydrationDomBuilderEnv_document initialEnv
1307 let doc = _hydrationDomBuilderEnv_document initialEnv
@@ -1294,19 +1311,14 @@ drawChildUpdateInt initialEnv markReady child = do
1294 (p, delayed) <- case hydrationMode of
1311 (p, delayed) <- case hydrationMode of
1295 HydrationMode_Hydrating -> pure
1312 HydrationMode_Hydrating -> pure
1296 ( Left $ _hydrationDomBuilderEnv_parent initialEnv
1313 ( Left $ _hydrationDomBuilderEnv_parent initialEnv
1297− , do
1314+ , insertAfterPreviousNode placeholder
1298− parent <- askParent
1299− getPreviousNode >>= \case
1300− Nothing -> Node.getFirstChild parent >>= Node.insertBefore_ parent placeholder
1301− Just pn -> Node.getNextSibling pn >>= Node.insertBefore_ parent placeholder
1302− setPreviousNode $ Just $ toNode placeholder
1304 HydrationMode_Immediate -> do
1316 HydrationMode_Immediate -> do
1305 df <- createDocumentFragment doc
1317 df <- createDocumentFragment doc
1306 Node.appendChild_ df placeholder
1318 Node.appendChild_ df placeholder
1307 pure (Right df, pure ())
1319 pure (Right df, pure ())
1308 p' <- either pure (liftIO . newIORef . toNode) p
1320 p' <- either pure (liftIO . newIORef . toNode) p
1309− (result, finalState) <- flip runStateT [] $ runReaderT (unHydrationDomBuilderT child) initialEnv
1321+ (result, finalState) <- flip runStateT (pure ()) $ runReaderT (unHydrationDomBuilderT child) initialEnv
1310 { _hydrationDomBuilderEnv_parent = p'
1322 { _hydrationDomBuilderEnv_parent = p'
1311 , _hydrationDomBuilderEnv_unreadyChildren = unreadyChildren
1323 , _hydrationDomBuilderEnv_unreadyChildren = unreadyChildren
1312 , _hydrationDomBuilderEnv_commitAction = markReady childReadyState
1324 , _hydrationDomBuilderEnv_commitAction = markReady childReadyState
@@ -1314,17 +1326,11 @@ drawChildUpdateInt initialEnv markReady child = do
1314 u <- liftIO $ readIORef unreadyChildren
1326 u <- liftIO $ readIORef unreadyChildren
1315 when (u == 0) $ liftIO $ writeIORef childReadyState ChildReadyStateInt_Ready
1327 when (u == 0) $ liftIO $ writeIORef childReadyState ChildReadyStateInt_Ready
1317− ( DOM_Replace delayed (pure ()) (pure finalState)
1329+ ( delayed >> finalState
1318 , either (const $ error "drawChildUpdateInt: Tried to use document fragment in hydration mode") id p
1330 , either (const $ error "drawChildUpdateInt: Tried to use document fragment in hydration mode") id p
1319 , placeholder, childReadyState, result
1331 , placeholder, childReadyState, result
1322−insertAfter :: (MonadJSM m, IsNode new, IsNode existing) => new -> existing -> m ()
1323−insertAfter new existing = do
1324− liftIO $ putStrLn "insertAfter"
1325− p <- getParentNodeUnchecked existing
1326− Node.getNextSibling existing >>= DOM.insertBefore_ p new
1328instance PerformEvent t m => PerformEvent t (HydrationDomBuilderT t m) where
1334instance PerformEvent t m => PerformEvent t (HydrationDomBuilderT t m) where
1329 type Performable (HydrationDomBuilderT t m) = Performable m
1335 type Performable (HydrationDomBuilderT t m) = Performable m
1330 {-# INLINABLE performEvent_ #-}
1336 {-# INLINABLE performEvent_ #-}