@@ -46,13 +46,13 @@ import Data.Default
4646import Data.Dependent.Map (DMap)
4747import qualified Data.Dependent.Map as DMap
4848import Data.Dependent.Sum
49+import Data.Functor.Compose
50+import Data.Functor.Constant
4951import Data.Functor.Misc
5052import Data.IORef
51−import Data.Map (Map)
5253import qualified Data.Map as Map
5354import Data.Maybe
5455import Data.Monoid
55−import Data.Some (Some)
5656import qualified Data.Some as Some
5757import Data.Text (Text)
5858import qualified Data.Text as T
@@ -70,8 +70,7 @@ import GHCJS.DOM.MouseEvent
7070import qualified GHCJS.DOM.Touch as Touch
7171import qualified GHCJS.DOM.TouchEvent as TouchEvent
7272import qualified GHCJS.DOM.TouchList as TouchList
73−import GHCJS.DOM.Node (appendChild_, getOwnerDocumentUnchecked, getParentNodeUnchecked,
74− setNodeValue, toNode)
73+import GHCJS.DOM.Node (appendChild_, getOwnerDocumentUnchecked, getParentNodeUnchecked, setNodeValue, toNode)
7574import qualified GHCJS.DOM.Node as DOM (insertBefore_)
7675import GHCJS.DOM.Types
7776 (liftJSM, askJSM, runJSM, JSM, MonadJSM(..),
@@ -190,6 +189,20 @@ extractUpTo df s e = liftJSM $ do
190189
191190type SupportsImmediateDomBuilder t m = (Reflex t, MonadJSM m, MonadJSM (Performable m), MonadHold t m, MonadFix m, PerformEvent t m, MonadReflexCreateTrigger t m, MonadRef m, Ref m ~ Ref JSM, MonadAdjust t m)
192191
192+{-# INLINABLE collectUpTo #-}
193+collectUpTo :: (MonadJSM m, IsNode start, IsNode end) => start -> end -> m DOM.DocumentFragment
194+collectUpTo s e = do
195+ currentParent <- getParentNodeUnchecked e -- May be different than it was at initial construction, e.g., because the parent may have dumped us in from a DocumentFragment
196+ collectUpToGivenParent currentParent s e
197+
198+{-# INLINABLE collectUpToGivenParent #-}
199+collectUpToGivenParent :: (MonadJSM m, IsNode parent, IsNode start, IsNode end) => parent -> start -> end -> m DOM.DocumentFragment
200+collectUpToGivenParent currentParent s e = do
201+ doc <- getOwnerDocumentUnchecked currentParent
202+ df <- createDocumentFragmentUnchecked doc
203+ extractUpTo df s e
204+ return df
205+
193206newtype EventFilterTriggerRef t er (en :: EventTag) = EventFilterTriggerRef (IORef (Maybe (EventTrigger t (er en))))
194207
195208wrap :: forall m er t. SupportsImmediateDomBuilder t m => RawElement GhcjsDomSpace -> RawElementConfig er t (ImmediateDomBuilderT t m) -> ImmediateDomBuilderT t m (Element er GhcjsDomSpace t)
@@ -450,37 +463,72 @@ instance (Reflex t, MonadAdjust t m, MonadJSM m, MonadHold t m, PerformEvent t m
450463 insertBefore df after
451464 return result
452465 return (result0, result')
453− sequenceDMapWithAdjust (dm0 :: DMap k (ImmediateDomBuilderT t m)) dm' = do
466+ traverseDMapWithKeyWithAdjust (f :: forall a. k a -> v a -> ImmediateDomBuilderT t m (v' a)) (dm0 :: DMap k v) dm' = do
454467 initialEnv <- ImmediateDomBuilderT ask
455− let drawChildInitial :: ImmediateDomBuilderT t m a -> m (DOM.DocumentFragment, DOM.Text, a)
456− drawChildInitial child = runImmediateDomBuilderT ((,,) <$> pure (error "sequenceDMapWithAdjust{ImmediateDomBuilderT}: drawChildInitial: DocumentFragment evaluated") <*> textNodeInternal ("" :: Text) <*> child) initialEnv --TODO: Don't return a DocumentFragment at all here; this will require that sequenceDMapWithAdjust accept differently-typed values for the constant and Event arguments.
457− drawChildUpdate :: ImmediateDomBuilderT t m a -> m (DOM.DocumentFragment, DOM.Text, a)
458− drawChildUpdate child = do
459− df <- createDocumentFragmentUnchecked $ _immediateDomBuilderEnv_document initialEnv
460− runImmediateDomBuilderT ((,,) <$> pure df <*> textNodeInternal ("" :: Text) <*> child) $ initialEnv
461− { _immediateDomBuilderEnv_parent = toNode df
462− }
463− updateChildren = ffor dm' $ \(PatchDMap p) -> PatchDMap $
464− mapKeyValuePairsMonotonic (\(k :=> ComposeMaybe mv) -> WrapArg k :=> ComposeMaybe (fmap drawChildUpdate mv)) p
465− (children0, children') <- lift $ sequenceDMapWithAdjust (mapKeyValuePairsMonotonic (\(k :=> v) -> WrapArg k :=> drawChildInitial v) dm0) (updateChildren :: Event t (PatchDMap (WrapArg ((,,) DOM.DocumentFragment DOM.Text) k) m)) --TODO: Update stuff
466− let result0 = mapKeyValuePairsMonotonic (\(WrapArg k :=> Identity (_, _, v)) -> k :=> Identity v) children0
467− placeholders0 = dmapToMap $ mapKeyValuePairsMonotonic (\(WrapArg k :=> Identity (_, ph, _)) -> Const2 (Some.This k) :=> Identity ph) children0
468− result' = ffor children' $ \(PatchDMap p) -> PatchDMap $
469− mapKeyValuePairsMonotonic (\(WrapArg k :=> v) -> k :=> fmap (\(_, _, r) -> r) v) p
470− placeholders' = ffor children' $ \(PatchDMap p) -> PatchMap $
471− dmapToMap $ mapKeyValuePairsMonotonic (\(WrapArg k :=> v) -> Const2 (Some.This k) :=> Identity (fmap ((\(_, ph, _) -> ph) . runIdentity) (getComposeMaybe v))) p
472− placeholders :: Behavior t (Map (Some k) DOM.Text) <- current . incrementalToDynamic <$> holdIncremental placeholders0 placeholders'
468+ (children0, children') <- lift $ traverseDMapWithKeyWithAdjust (\k v -> drawChildUpdate initialEnv $ f k v) dm0 dm'
469+ let result0 = DMap.map (\(Compose (_, _, v)) -> v) children0
470+ placeholders0 = weakenDMapWith (\(Compose (_, ph, _)) -> ph) children0
471+ result' = ffor children' $ mapPatchDMap $ \(Compose (_, _, r)) -> r
472+ placeholders' = fforCheap children' $ weakenPatchDMapWith $ \(Compose (_, ph, _)) -> ph
473+ placeholders <- current . incrementalToDynamic <$> holdIncremental placeholders0 placeholders'
474+ _ <- DMap.traverseWithKey (\_ (Compose (df, _, _)) -> Constant () <$ append df) children0
473475 lastPlaceholder <- textNodeInternal ("" :: Text)
474476 performEvent_ $ flip push children' $ \(PatchDMap p) -> do
475477 phs <- sample placeholders
476478 if DMap.null p then return Nothing else return $ Just $ do
477− let f :: DSum (WrapArg ((,,) DOM.DocumentFragment DOM.Text) k) (ComposeMaybe Identity) -> Performable m ()
478− f (WrapArg k :=> ComposeMaybe mv) = do
479+ let g :: DSum k (ComposeMaybe (Compose ((,,) DOM.DocumentFragment DOM.Text) v')) -> Performable m ()
480+ g (k :=> ComposeMaybe mv) = do
479481 let nextPlaceholder = maybe lastPlaceholder snd $ Map.lookupGT (Some.This k) phs
480482 forM_ (Map.lookup (Some.This k) phs) $ \thisPlaceholder -> thisPlaceholder `deleteUpTo` nextPlaceholder
481− forM_ mv $ \(Identity (df, _, _)) -> df `insertBefore` nextPlaceholder
482− mapM_ f $ DMap.toList p
483+ forM_ mv $ \(Compose (df, _, _)) -> df `insertBefore` nextPlaceholder
484+ mapM_ g $ DMap.toList p
483485 return (result0, result')
486+ traverseDMapWithKeyWithAdjustWithMove (f :: forall a. k a -> v a -> ImmediateDomBuilderT t m (v' a)) (dm0 :: DMap k v) dm' = do
487+ initialEnv <- ImmediateDomBuilderT ask
488+ (children0, children') <- lift $ traverseDMapWithKeyWithAdjustWithMove (\k v -> drawChildUpdate initialEnv $ f k v) dm0 dm'
489+ let result0 = DMap.map (\(Compose (_, _, v)) -> v) children0
490+ placeholders0 = weakenDMapWith (\(Compose (_, ph, _)) -> ph) children0
491+ result' = ffor children' $ mapPatchDMapWithMove $ \(Compose (_, _, r)) -> r
492+ placeholders' = fforCheap children' $ weakenPatchDMapWithMoveWith $ \(Compose (_, ph, _)) -> ph
493+ placeholders <- current . incrementalToDynamic <$> holdIncremental placeholders0 placeholders'
494+ _ <- DMap.traverseWithKey (\_ (Compose (df, _, _)) -> Constant () <$ append df) children0
495+ lastPlaceholder <- textNodeInternal ("" :: Text)
496+ performEvent_ $ flip push children' $ \p_ -> do
497+ let p = unPatchDMapWithMove p_
498+ phsBefore <- sample placeholders
499+ if DMap.null p then return Nothing else return $ Just $ do
500+ let collectIfMoved :: forall a. k a -> DMapEdit k (Compose ((,,) DOM.DocumentFragment DOM.Text) v') a -> Performable m (Constant (Maybe DOM.DocumentFragment) a)
501+ collectIfMoved k e = do
502+ let mThisPlaceholder = Map.lookup (Some.This k) phsBefore -- Will be Nothing if this element wasn't present before
503+ nextPlaceholder = maybe lastPlaceholder snd $ Map.lookupGT (Some.This k) phsBefore
504+ case dmapEditMoved e of
505+ False -> do
506+ mapM_ (`deleteUpTo` nextPlaceholder) mThisPlaceholder
507+ return $ Constant Nothing
508+ True -> do
509+ Constant <$> mapM (`collectUpTo` nextPlaceholder) mThisPlaceholder
510+ collected <- DMap.traverseWithKey collectIfMoved p
511+ let phsAfter = fromMaybe phsBefore $ apply (weakenPatchDMapWithMoveWith (\(Compose (_, ph, _)) -> ph) p_) phsBefore --TODO: Don't recompute this
512+ let placeFragment :: forall a. k a -> DMapEdit k (Compose ((,,) DOM.DocumentFragment DOM.Text) v') a -> Performable m (Constant () a)
513+ placeFragment k e = do
514+ let nextPlaceholder = maybe lastPlaceholder snd $ Map.lookupGT (Some.This k) phsAfter
515+ case e of
516+ DMapEdit_Insert _ (Compose (df, _, _)) -> do
517+ df `insertBefore` nextPlaceholder
518+ DMapEdit_Delete _ -> do
519+ return ()
520+ DMapEdit_Move _ fromKey -> do
521+ Just (Constant mdf) <- return $ DMap.lookup fromKey collected
522+ mapM_ (`insertBefore` nextPlaceholder) mdf
523+ return $ Constant ()
524+ mapM_ (\(k :=> v) -> void $ placeFragment k v) $ DMap.toDescList p -- We need to go in reverse order here, to make sure the placeholders are in the right spot at the right time
525+ return ()
526+ return (result0, result')
527+
528+drawChildUpdate :: MonadJSM m => ImmediateDomBuilderEnv t -> ImmediateDomBuilderT t m (v' a) -> m (Compose ((,,) DOM.DocumentFragment DOM.Text) v' a)
529+drawChildUpdate initialEnv child = do
530+ df <- createDocumentFragmentUnchecked $ _immediateDomBuilderEnv_document initialEnv
531+ runImmediateDomBuilderT (Compose <$> ((,,) <$> pure df <*> textNodeInternal ("" :: Text) <*> child)) $ initialEnv { _immediateDomBuilderEnv_parent = toNode df }
484532
485533mkHasFocus :: (MonadHold t m, Reflex t) => Element er d t -> m (Dynamic t Bool)
486534mkHasFocus e = do