@@ -40,13 +40,13 @@ import Data.Default
40import Data.Dependent.Map (DMap)
40import Data.Dependent.Map (DMap)
41import qualified Data.Dependent.Map as DMap
41import qualified Data.Dependent.Map as DMap
42import Data.Dependent.Sum
42import Data.Dependent.Sum
43+import Data.Functor.Compose
44+import Data.Functor.Constant
43import Data.Functor.Misc
45import Data.Functor.Misc
44import Data.IORef
46import Data.IORef
46import qualified Data.Map as Map
47import qualified Data.Map as Map
47import Data.Maybe
48import Data.Maybe
48import Data.Monoid
49import Data.Monoid
49−import Data.Some (Some)
50import qualified Data.Some as Some
50import qualified Data.Some as Some
51import Data.Text (Text)
51import Data.Text (Text)
52import GHCJS.DOM.Document (Document, createDocumentFragment, createElement, createElementNS, createTextNode)
52import GHCJS.DOM.Document (Document, createDocumentFragment, createElement, createElementNS, createTextNode)
@@ -65,8 +65,8 @@ import qualified GHCJS.DOM.Touch as Touch
65import qualified GHCJS.DOM.TouchEvent as TouchEvent
65import qualified GHCJS.DOM.TouchEvent as TouchEvent
66import qualified GHCJS.DOM.TouchList as TouchList
66import qualified GHCJS.DOM.TouchList as TouchList
68−import GHCJS.DOM.Node (appendChild, getOwnerDocument, getParentNode, getPreviousSibling, removeChild,
68+import GHCJS.DOM.Node (appendChild, getOwnerDocument, getParentNode, getPreviousSibling, getNextSibling,
69− setNodeValue, toNode)
69+ removeChild, setNodeValue, toNode)
70import qualified GHCJS.DOM.Node as DOM
70import qualified GHCJS.DOM.Node as DOM
71import GHCJS.DOM.Types (FocusEvent, IsElement, IsEvent, IsNode, KeyboardEvent, Node, ToDOMString, TouchEvent,
71import GHCJS.DOM.Types (FocusEvent, IsElement, IsEvent, IsNode, KeyboardEvent, Node, ToDOMString, TouchEvent,
72 WheelEvent, castToHTMLInputElement, castToHTMLSelectElement,
72 WheelEvent, castToHTMLInputElement, castToHTMLSelectElement,
@@ -165,6 +165,12 @@ deleteUpTo s e = do
165 Nothing -> return () --TODO: Is this the right behavior?
165 Nothing -> return () --TODO: Is this the right behavior?
166 Just currentParent -> deleteUpToGivenParent currentParent s e
166 Just currentParent -> deleteUpToGivenParent currentParent s e
168+{-# INLINABLE collectUpTo #-}
169+collectUpTo :: (MonadIO m, IsNode start, IsNode end) => start -> end -> m DOM.DocumentFragment
171+ Just currentParent <- getParentNode e -- May be different than it was at initial construction, e.g., because the parent may have dumped us in from a DocumentFragment
172+ collectUpToGivenParent currentParent s e
168{-# INLINABLE deleteUpToGivenParent #-}
174{-# INLINABLE deleteUpToGivenParent #-}
169deleteUpToGivenParent :: (MonadIO m, IsNode parent, IsNode start, IsNode end) => parent -> start -> end -> m ()
175deleteUpToGivenParent :: (MonadIO m, IsNode parent, IsNode start, IsNode end) => parent -> start -> end -> m ()
170deleteUpToGivenParent currentParent s e = do
176deleteUpToGivenParent currentParent s e = do
@@ -173,6 +179,18 @@ deleteUpToGivenParent currentParent s e = do
173 _ <- removeChild currentParent $ Just x
179 _ <- removeChild currentParent $ Just x
174 when (toNode s /= toNode x) loop
180 when (toNode s /= toNode x) loop
182+{-# INLINABLE collectUpToGivenParent #-}
183+collectUpToGivenParent :: (MonadIO m, IsNode parent, IsNode start, IsNode end) => parent -> start -> end -> m DOM.DocumentFragment
184+collectUpToGivenParent currentParent s e = do
185+ Just doc <- getOwnerDocument currentParent
186+ Just df <- createDocumentFragment doc
187+ let loop this = when (toNode e /= this) $ do
188+ Just next <- getNextSibling this -- This can't be Nothing because we should hit 'e' first
189+ _ <- appendChild df $ Just this -- This will also remove 'this' from its current parent
176type SupportsImmediateDomBuilder t m = (Reflex t, MonadIO m, MonadIO (Performable m), MonadHold t m, MonadFix m, PerformEvent t m, MonadReflexCreateTrigger t m, MonadRef m, Ref m ~ Ref IO, MonadAdjust t m)
194type SupportsImmediateDomBuilder t m = (Reflex t, MonadIO m, MonadIO (Performable m), MonadHold t m, MonadFix m, PerformEvent t m, MonadReflexCreateTrigger t m, MonadRef m, Ref m ~ Ref IO, MonadAdjust t m)
178newtype EventFilterTriggerRef t er (en :: EventTag) = EventFilterTriggerRef (IORef (Maybe (EventTrigger t (er en))))
196newtype EventFilterTriggerRef t er (en :: EventTag) = EventFilterTriggerRef (IORef (Maybe (EventTrigger t (er en))))
@@ -416,36 +434,78 @@ instance (Reflex t, MonadAdjust t m, MonadIO m, MonadHold t m, PerformEvent t m,
416 insertBefore df after
434 insertBefore df after
417 return result
435 return result
418 return (result0, result')
436 return (result0, result')
419− sequenceDMapWithAdjust (dm0 :: DMap k (ImmediateDomBuilderT t m)) dm' = do
437+ traverseDMapWithKeyWithAdjust (f :: forall a. k a -> v a -> ImmediateDomBuilderT t m (v' a)) (dm0 :: DMap k v) dm' = do
420 initialEnv <- ImmediateDomBuilderT ask
438 initialEnv <- ImmediateDomBuilderT ask
421− let drawChildInitial :: ImmediateDomBuilderT t m a -> m (DOM.DocumentFragment, DOM.Text, a)
422− 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.
423− drawChildUpdate :: ImmediateDomBuilderT t m a -> m (DOM.DocumentFragment, DOM.Text, a)
439+ let drawChildUpdate :: forall a. ImmediateDomBuilderT t m (v' a) -> m (Compose ((,,) DOM.DocumentFragment DOM.Text) v' a)
424 drawChildUpdate child = do
440 drawChildUpdate child = do
425 Just df <- createDocumentFragment $ _immediateDomBuilderEnv_document initialEnv
441 Just df <- createDocumentFragment $ _immediateDomBuilderEnv_document initialEnv
426− runImmediateDomBuilderT ((,,) <$> pure df <*> textNodeInternal ("" :: Text) <*> child) $ initialEnv
442+ runImmediateDomBuilderT (Compose <$> ((,,) <$> pure df <*> textNodeInternal ("" :: Text) <*> child)) $ initialEnv
427 { _immediateDomBuilderEnv_parent = toNode df
443 { _immediateDomBuilderEnv_parent = toNode df
429− updateChildren = ffor dm' $ \(PatchDMap p) -> PatchDMap $
445+ (children0, children') <- lift $ traverseDMapWithKeyWithAdjust (\k v -> drawChildUpdate $ f k v) dm0 dm'
430− mapKeyValuePairsMonotonic (\(k :=> ComposeMaybe mv) -> WrapArg k :=> ComposeMaybe (fmap drawChildUpdate mv)) p
431− (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
432− let result0 = mapKeyValuePairsMonotonic (\(WrapArg k :=> Identity (_, _, v)) -> k :=> Identity v) children0
446+ let result0 = DMap.map (\(Compose (_, _, v)) -> v) children0
433− placeholders0 = dmapToMap $ mapKeyValuePairsMonotonic (\(WrapArg k :=> Identity (_, ph, _)) -> Const2 (Some.This k) :=> Identity ph) children0
447+ placeholders0 = weakenDMapWith (\(Compose (_, ph, _)) -> ph) children0
434− result' = ffor children' $ \(PatchDMap p) -> PatchDMap $
448+ result' = ffor children' $ mapPatchDMap $ \(Compose (_, _, r)) -> r
435− mapKeyValuePairsMonotonic (\(WrapArg k :=> v) -> k :=> fmap (\(_, _, r) -> r) v) p
449+ placeholders' = fforCheap children' $ weakenPatchDMapWith $ \(Compose (_, ph, _)) -> ph
436− placeholders' = ffor children' $ \(PatchDMap p) -> PatchMap $
437− dmapToMap $ mapKeyValuePairsMonotonic (\(WrapArg k :=> v) -> Const2 (Some.This k) :=> Identity (fmap ((\(_, ph, _) -> ph) . runIdentity) (getComposeMaybe v))) p
438− placeholders :: Behavior t (Map (Some k) DOM.Text) <- current . incrementalToDynamic <$> holdIncremental placeholders0 placeholders'
450+ placeholders <- current . incrementalToDynamic <$> holdIncremental placeholders0 placeholders'
451+ _ <- DMap.traverseWithKey (\_ (Compose (df, _, _)) -> Constant () <$ append df) children0
439 lastPlaceholder <- textNodeInternal ("" :: Text)
452 lastPlaceholder <- textNodeInternal ("" :: Text)
440 performEvent_ $ flip push children' $ \(PatchDMap p) -> do
453 performEvent_ $ flip push children' $ \(PatchDMap p) -> do
441 phs <- sample placeholders
454 phs <- sample placeholders
442 if DMap.null p then return Nothing else return $ Just $ do
455 if DMap.null p then return Nothing else return $ Just $ do
443− let f :: DSum (WrapArg ((,,) DOM.DocumentFragment DOM.Text) k) (ComposeMaybe Identity) -> Performable m ()
456+ let g :: DSum k (ComposeMaybe (Compose ((,,) DOM.DocumentFragment DOM.Text) v')) -> Performable m ()
444− f (WrapArg k :=> ComposeMaybe mv) = do
457+ g (k :=> ComposeMaybe mv) = do
445 let nextPlaceholder = maybe lastPlaceholder snd $ Map.lookupGT (Some.This k) phs
458 let nextPlaceholder = maybe lastPlaceholder snd $ Map.lookupGT (Some.This k) phs
446 forM_ (Map.lookup (Some.This k) phs) $ \thisPlaceholder -> thisPlaceholder `deleteUpTo` nextPlaceholder
459 forM_ (Map.lookup (Some.This k) phs) $ \thisPlaceholder -> thisPlaceholder `deleteUpTo` nextPlaceholder
447− forM_ mv $ \(Identity (df, _, _)) -> df `insertBefore` nextPlaceholder
460+ forM_ mv $ \(Compose (df, _, _)) -> df `insertBefore` nextPlaceholder
448− mapM_ f $ DMap.toList p
461+ mapM_ g $ DMap.toList p
462+ return (result0, result')
463+ traverseDMapWithKeyWithAdjustWithMove (f :: forall a. k a -> v a -> ImmediateDomBuilderT t m (v' a)) (dm0 :: DMap k v) dm' = do
464+ initialEnv <- ImmediateDomBuilderT ask
465+ let drawChildUpdate :: forall a. ImmediateDomBuilderT t m (v' a) -> m (Compose ((,,) DOM.DocumentFragment DOM.Text) v' a)
466+ drawChildUpdate child = do
467+ Just df <- createDocumentFragment $ _immediateDomBuilderEnv_document initialEnv
468+ runImmediateDomBuilderT (Compose <$> ((,,) <$> pure df <*> textNodeInternal ("" :: Text) <*> child)) $ initialEnv
469+ { _immediateDomBuilderEnv_parent = toNode df
471+ (children0, children') <- lift $ traverseDMapWithKeyWithAdjustWithMove (\k v -> drawChildUpdate $ f k v) dm0 dm'
472+ let result0 = DMap.map (\(Compose (_, _, v)) -> v) children0
473+ placeholders0 = weakenDMapWith (\(Compose (_, ph, _)) -> ph) children0
474+ result' = ffor children' $ mapPatchDMapWithMove $ \(Compose (_, _, r)) -> r
475+ placeholders' = fforCheap children' $ weakenPatchDMapWithMoveWith $ \(Compose (_, ph, _)) -> ph
476+ placeholders <- current . incrementalToDynamic <$> holdIncremental placeholders0 placeholders'
477+ _ <- DMap.traverseWithKey (\_ (Compose (df, _, _)) -> Constant () <$ append df) children0
478+ lastPlaceholder <- textNodeInternal ("" :: Text)
479+ performEvent_ $ flip push children' $ \p_ -> do
480+ let p = unPatchDMapWithMove p_
481+ phsBefore <- sample placeholders
482+ if DMap.null p then return Nothing else return $ Just $ do
483+ let collectIfMoved :: forall a. k a -> DMapEdit k (Compose ((,,) DOM.DocumentFragment DOM.Text) v') a -> Performable m (Constant (Maybe DOM.DocumentFragment) a)
484+ collectIfMoved k e = do
485+ Just thisPlaceholder <- return $ Map.lookup (Some.This k) phsBefore
486+ let nextPlaceholder = maybe lastPlaceholder snd $ Map.lookupGT (Some.This k) phsBefore
487+ case dmapEditMoved e of
489+ thisPlaceholder `deleteUpTo` nextPlaceholder
490+ return $ Constant Nothing
492+ Constant . Just <$> thisPlaceholder `collectUpTo` nextPlaceholder
493+ collected <- DMap.traverseWithKey collectIfMoved p
494+ let phsAfter = fromMaybe phsBefore $ apply (weakenPatchDMapWithMoveWith (\(Compose (_, ph, _)) -> ph) p_) phsBefore --TODO: Don't recompute this
495+ let placeFragment :: forall a. k a -> DMapEdit k (Compose ((,,) DOM.DocumentFragment DOM.Text) v') a -> Performable m (Constant () a)
496+ placeFragment k e = do
497+ let nextPlaceholder = maybe lastPlaceholder snd $ Map.lookupGT (Some.This k) phsAfter
499+ DMapEdit_Insert _ (Compose (df, _, _)) -> do
500+ df `insertBefore` nextPlaceholder
501+ DMapEdit_Delete _ -> do
503+ DMapEdit_Move _ fromKey -> do
504+ Just (Constant (Just df)) <- return $ DMap.lookup fromKey collected
505+ df `insertBefore` nextPlaceholder
506+ return $ Constant ()
507+ 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
449 return (result0, result')
509 return (result0, result')
451mkHasFocus :: (MonadHold t m, Reflex t) => Element er d t -> m (Dynamic t Bool)
511mkHasFocus :: (MonadHold t m, Reflex t) => Element er d t -> m (Dynamic t Bool)