@@ -0,0 +1,440 @@
1+{-# LANGUAGE TypeFamilies, FlexibleContexts, FlexibleInstances, MultiParamTypeClasses, RankNTypes, GADTs, ScopedTypeVariables, FunctionalDependencies, RecursiveDo, UndecidableInstances, GeneralizedNewtypeDeriving, StandaloneDeriving, EmptyDataDecls, NoMonomorphismRestriction, TemplateHaskell, PolyKinds, TypeOperators, DeriveFunctor, LambdaCase, CPP, ForeignFunctionInterface, DeriveDataTypeable, ConstraintKinds #-}
2+module Reflex.Dom.Class where
3+
4+import Prelude hiding (mapM, mapM_, sequence, concat)
5+
6+import Reflex
7+import Reflex.Host.Class
8+
9+import Control.Monad.Identity hiding (mapM, mapM_, forM, forM_, sequence)
10+import Control.Lens hiding ((<|))
11+import Data.Set (Set)
12+import qualified Data.Set as Set
13+import Data.Map (Map)
14+import qualified Data.Map as Map
15+import Data.Traversable
16+import Data.Foldable
17+import Control.Monad.Ref
18+import Control.Monad.Reader hiding (mapM, mapM_, forM, forM_, sequence)
19+import Control.Monad.State hiding (mapM, mapM_, forM, forM_, sequence)
20+import qualified Data.Dependent.Map as DMap
21+import Data.Dependent.Sum (DSum (..))
22+import Data.IORef
23+import Data.These
24+import Data.Align
25+import GHCJS.DOM.Types hiding (Event)
26+import GHCJS.DOM.Document
27+import GHCJS.DOM.Node
28+import GHCJS.DOM.NamedNodeMap
29+import GHCJS.DOM.Element
30+import GHCJS.DOM.HTMLElement
31+import GHCJS.DOM.HTMLInputElement
32+import GHCJS.DOM.HTMLSelectElement
33+import GHCJS.DOM.HTMLTextAreaElement
34+import GHCJS.DOM.UIEvent
35+import GHCJS.DOM.EventM (event, preventDefault)
36+import Data.Dependent.Map (DMap)
37+import Safe
38+
39+-- | Alias for Data.Map.singleton
40+(=:) :: k -> a -> Map k a
41+(=:) = Map.singleton
42+
43+keycodeEnter :: Int
44+keycodeEnter = 13
45+
46+keycodeEscape :: Int
47+keycodeEscape = 27
48+
49+class ( Reflex t, MonadHold t m, MonadIO m, Functor m, MonadReflexCreateTrigger t m
50+ , HasDocument m
51+ , MonadIO (WidgetHost m), Functor (WidgetHost m), MonadSample t (WidgetHost m)
52+ , HasPostGui t (GuiAction m) (WidgetHost m), HasPostGui t (GuiAction m) m, MonadRef m, MonadRef (WidgetHost m)
53+ , Ref m ~ Ref IO, Ref (WidgetHost m) ~ Ref IO --TODO: Eliminate this reliance on IO
54+ , MonadFix m
55+ ) => MonadWidget t m | m -> t where
56+ type WidgetHost m :: * -> *
57+ type GuiAction m :: * -> *
58+ askParent :: m Node
59+ subWidget :: Node -> m a -> m a
60+ schedulePostBuild :: WidgetHost m () -> m ()
61+ addVoidAction :: Event t (WidgetHost m ()) -> m ()
62+ getRunWidget :: IsNode n => m (n -> m a -> WidgetHost m (a, Event t (WidgetHost m ())))
63+
64+class Monad m => HasDocument m where
65+ askDocument :: m HTMLDocument
66+
67+instance HasDocument m => HasDocument (ReaderT r m) where
68+ askDocument = lift askDocument
69+
70+instance HasDocument m => HasDocument (StateT r m) where
71+ askDocument = lift askDocument
72+
73+class (MonadRef h, Ref h ~ Ref m, MonadRef m) => HasPostGui t h m | m -> t h where
74+ askPostGui :: m (h () -> IO ())
75+ askRunWithActions :: m ([DSum (EventTrigger t)] -> h ())
76+
77+runFrameWithTriggerRef :: (HasPostGui t h m, MonadRef m, MonadIO m) => Ref m (Maybe (EventTrigger t a)) -> a -> m ()
78+runFrameWithTriggerRef r a = do
79+ postGui <- askPostGui
80+ runWithActions <- askRunWithActions
81+ liftIO . postGui $ mapM_ (\t -> runWithActions [t :=> a]) =<< readRef r
82+
83+instance HasPostGui t h m => HasPostGui t h (ReaderT r m) where
84+ askPostGui = lift askPostGui
85+ askRunWithActions = lift askRunWithActions
86+
87+instance MonadWidget t m => MonadWidget t (ReaderT r m) where
88+ type WidgetHost (ReaderT r m) = WidgetHost m
89+ type GuiAction (ReaderT r m) = GuiAction m
90+ askParent = lift askParent
91+ subWidget n w = do
92+ r <- ask
93+ lift $ subWidget n $ runReaderT w r
94+ schedulePostBuild = lift . schedulePostBuild
95+ addVoidAction = lift . addVoidAction
96+ getRunWidget = do
97+ r <- ask
98+ runWidget <- lift getRunWidget
99+ return $ \rootElement w -> runWidget rootElement $ runReaderT w r
100+
101+performEvent_ = addVoidAction
102+
103+performEvent e = do
104+ (eResult, reResultTrigger) <- newEventWithTriggerRef
105+ addVoidAction $ ffor e $ \o -> do
106+ result <- o
107+ runFrameWithTriggerRef reResultTrigger result
108+ return eResult
109+
110+performEventAsync :: forall t m a. MonadWidget t m => Event t ((a -> IO ()) -> WidgetHost m ()) -> m (Event t a)
111+performEventAsync e = do
112+ (eResult, reResultTrigger) <- newEventWithTriggerRef
113+ addVoidAction $ ffor e $ \o -> do
114+ postGui <- askPostGui
115+ runWithActions <- askRunWithActions
116+ o $ \a -> postGui $ mapM_ (\t -> runWithActions [t :=> a]) =<< readRef reResultTrigger
117+ return eResult
118+
119+--------------------------------------------------------------------------------
120+--------------------------------------------------------------------------------
121+{-
122+
123+class HasRunFrame t m | m -> t where
124+ askRunFrame :: m (DMap (EventTrigger t) -> IO ())
125+
126+type MonadWidget t h m = (MonadWidget' t h m, MonadWidget' t h (WidgetEventM m))
127+
128+--TODO: Remove Spider hardcoding
129+class (t ~ Spider, Reflex t, MonadHold t m, ReflexHost t, HasRunFrame t h, MonadReflexHost t h, MonadIO h, MonadRef h, Ref h ~ IORef, MonadFix h, HasDocument h, MonadSample t (WidgetEventM m), WidgetEventM m ~ WidgetEventM (WidgetEventM m), MonadFix m) => MonadWidget' t h m | m -> t h where
130+
131+ type WidgetEventM m :: * -> *
132+ -- | Warning: dAttributes should not contain "id" attributes
133+ elDynAttr' :: String -> Dynamic t (Map String String) -> m a -> m (El t, a)
134+ performEvent :: Event t (h a) -> m (Event t a)
135+ performEvent_ :: Event t (h ()) -> m ()
136+ getEInit :: m (Event t ())
137+ putEChildren :: Event t [Node] -> m ()
138+ dyn :: Dynamic t (WidgetEventM m a) -> m (Event t a) --TODO: Should probably return Dynamic t a
139+ listWithKey :: (Ord k, Show k) => Dynamic t (Map k v) -> (k -> Dynamic t v -> WidgetEventM m v') -> m (Dynamic t (Map k v'))
140+ text :: String -> m ()
141+ dynText :: Dynamic t String -> m ()
142+
143+{-# INLINABLE performEventAsync #-}
144+performEventAsync :: forall t h m a. (MonadWidget t h m) => Event t ((a -> IO ()) -> h ()) -> m (Event t a)
145+performEventAsync eAction = do
146+ let setup mAction = do
147+ (eResult, reResultTrigger) <- newEventWithTriggerRef
148+ runFrame <- askRunFrame
149+ let runAction a = a $ \x -> readRef reResultTrigger >>= mapM_ (\eResultTrigger -> runFrame $ DMap.singleton eResultTrigger x)
150+ maybe (return ()) runAction mAction
151+ return (eResult, runAction)
152+ eSetup <- performEvent . fmap (setup . (^?here)) . align eAction =<< getEInit
153+ dRunAction <- holdDyn Nothing $ fmap (Just . snd) eSetup
154+ performEvent_ $ attachDynWith (\mRunAction a -> maybe (return ()) ($ a) mRunAction) dRunAction eAction -- Note: this will never fire while eInit is firing, but that situation should be handled in setup; this relies on all the results from the first performEvent being fired simultaneously; otherwise, an eAction could potentially sneak in between setup being sent to performEvent and the result coming back
155+ switchPromptly never (fmap fst eSetup)
156+
157+data TextInput t
158+ = TextInput { _textInput_value :: Dynamic t String
159+ , _textInput_keypress :: Event t Int
160+ , _textInput_keydown :: Event t Int
161+ , _textInput_keyup :: Event t Int
162+ , _textInput_hasFocus :: Dynamic t Bool
163+ , _textInput_element :: Dynamic t (Maybe HTMLInputElement)
164+ }
165+
166+textInputGetEnter :: Reflex t => TextInput t -> Event t ()
167+textInputGetEnter i = fmapMaybe (\n -> if n == keycodeEnter then Just () else Nothing) $ _textInput_keypress i
168+
169+setElementAttributes :: IsElement self => self -> Map String String -> IO ()
170+setElementAttributes e attrs = do
171+ oldAttrs <- maybe (return Set.empty) namedNodeMapGetNames =<< elementGetAttributes e
172+ forM_ (Set.toList $ oldAttrs `Set.difference` Map.keysSet attrs) $ elementRemoveAttribute e
173+ iforM_ attrs $ elementSetAttribute e
174+
175+wrapDomEvent :: (HasRunFrame t h, MonadIO m, MonadReflexHost t h, MonadIO h) => e -> (e -> m () -> IO (IO ())) -> m a -> h (Event t a)
176+wrapDomEvent self elementOnevent getValue = do
177+ runFrame <- askRunFrame
178+ e <- newEventWithTrigger $ \et -> do
179+ unsubscribe <- {-# SCC "a" #-} liftIO $ {-# SCC "b" #-} elementOnevent self $ {-# SCC "c" #-} do
180+ v <- {-# SCC "d" #-} getValue
181+ liftIO $ runFrame $ DMap.singleton et v
182+ return $ liftIO $ do
183+ {-# SCC "e" #-} unsubscribe
184+ return $! {-# SCC "f" #-} e
185+
186+{-# INLINABLE input #-}
187+input' :: MonadWidget t h m => String -> Event t String -> Dynamic t (Map String String) -> m (TextInput t)
188+input' inputType eSetValue dAttrs = do
189+ dEffectiveAttrs <- mapDyn (Map.insert "type" inputType) dAttrs
190+ let mkSelf (initialValue, initialAttrs) = do
191+ doc <- askDocument
192+ Just e <- liftIO $ liftM (fmap castToHTMLInputElement) $ documentCreateElement doc "input"
193+ liftIO $ htmlInputElementSetValue e initialValue
194+ iforM_ initialAttrs $ \attr value -> liftIO $ elementSetAttribute e attr value
195+ eChange <- wrapDomEvent e elementOninput $ liftIO $ htmlInputElementGetValue e
196+ runFrame <- askRunFrame
197+ eChangeFocus <- newEventWithTrigger $ \eChangeFocusTrigger -> do
198+ unsubscribeOnblur <- liftIO $ elementOnblur e $ liftIO $ do
199+ runFrame $ DMap.singleton eChangeFocusTrigger False
200+ unsubscribeOnfocus <- liftIO $ elementOnfocus e $ liftIO $ do
201+ runFrame $ DMap.singleton eChangeFocusTrigger True
202+ return $ liftIO $ unsubscribeOnblur >> unsubscribeOnfocus
203+ eKeypress <- wrapDomEvent e elementOnkeypress $ liftIO . uiEventGetKeyCode =<< event
204+ eKeydown <- wrapDomEvent e elementOnkeydown $ liftIO . uiEventGetKeyCode =<< event
205+ eKeyup <- wrapDomEvent e elementOnkeyup $ liftIO . uiEventGetKeyCode =<< event
206+ return (e, eChange, eKeypress, eKeydown, eKeyup, eChangeFocus)
207+ dInitialValue <- holdDyn "" eSetValue
208+ dInitial <- combineDyn (,) dInitialValue dEffectiveAttrs
209+ eCreated <- performEvent . fmap mkSelf . tagDyn dInitial =<< getEInit
210+ dMyElement <- holdDyn Nothing $ fmap (Just . (^. _1)) eCreated
211+ performEvent_ . updated =<< combineDyn (maybe (const $ return ()) $ \e attrs -> liftIO $ setElementAttributes e attrs) dMyElement dEffectiveAttrs
212+ putEChildren $ fmap ((:[]) . toNode . (^. _1)) eCreated
213+ performEvent_ $ fmapMaybe (fmap $ \(e,v) -> liftIO $ htmlInputElementSetValue e v) $ attachWith (\e v -> case e of
214+ Nothing -> Nothing
215+ Just e' -> Just (e',v)) (current dMyElement) eSetValue
216+ eChange <- liftM switch $ hold never $ fmap (^. _2) eCreated
217+ dFocus <- holdDyn False . switch =<< hold never (fmap (^. _6) eCreated) --TODO: Check that 'False' is always the correct starting value - i.e.: an element will always receive an 'onfocus' event, even if it gets focus immediately
218+ dValue <- holdDyn "" $ leftmost [eSetValue, eChange]
219+ eKeypress <- liftM switch $ hold never $ fmap (^. _3) eCreated
220+ eKeydown <- liftM switch $ hold never $ fmap (^. _4) eCreated
221+ eKeyup <- liftM switch $ hold never $ fmap (^. _5) eCreated
222+ return $ TextInput dValue eKeypress eKeydown eKeyup dFocus dMyElement
223+
224+input :: MonadWidget t h m => String -> Map String String -> m (TextInput t)
225+input t as = input' t never (constDyn as)
226+
227+data TextArea t
228+ = TextArea { _textArea_value :: Dynamic t String
229+ , _textArea_element :: Dynamic t (Maybe HTMLTextAreaElement)
230+ }
231+
232+textArea' :: MonadWidget t h m => Event t String -> Dynamic t (Map String String) -> m (TextArea t)
233+textArea' eSetValue dAttrs = do
234+ let mkSelf (initialValue, initialAttrs) = do
235+ doc <- askDocument
236+ Just e <- liftIO $ liftM (fmap castToHTMLTextAreaElement) $ documentCreateElement doc "textarea"
237+ liftIO $ htmlTextAreaElementSetValue e initialValue
238+ iforM_ initialAttrs $ \attr value -> liftIO $ elementSetAttribute e attr value
239+ eChange <- wrapDomEvent e elementOninput $ liftIO $ htmlTextAreaElementGetValue e
240+ return (e, eChange)
241+ dInitialValue <- holdDyn "" eSetValue
242+ dInitial <- combineDyn (,) dInitialValue dAttrs
243+ eCreated <- performEvent . fmap mkSelf . tagDyn dInitial =<< getEInit
244+ dMyElement <- holdDyn Nothing $ fmap (Just . fst) eCreated
245+ --performEvent . updated =<< combineDyn (maybe (const $ return ()) $ \e attrs -> liftIO $ setElementAttributes e attrs) dMyElement dAttrs
246+ putEChildren $ fmap ((:[]) . toNode . fst) eCreated
247+ performEvent_ $ fmapMaybe (fmap $ \(e,v) -> liftIO $ htmlTextAreaElementSetValue e v) $ attachWith (\e v -> case e of
248+ Nothing -> Nothing
249+ Just e' -> Just (e',v)) (current dMyElement) eSetValue
250+ eChange <- liftM switch $ hold never $ fmap snd eCreated
251+ dValue <- holdDyn "" $ leftmost [eSetValue, eChange]
252+ return $ TextArea dValue dMyElement
253+
254+
255+data Checkbox t
256+ = Checkbox { _checkbox_checked :: Dynamic t Bool
257+ }
258+
259+checkbox :: MonadWidget t h m => Bool -> Map String String -> m (Checkbox t)
260+checkbox checked attrs = do
261+ let mkSelf = do
262+ doc <- askDocument
263+ Just e <- liftIO $ liftM (fmap castToHTMLInputElement) $ documentCreateElement doc "input"
264+ liftIO $ elementSetAttribute e "type" "checkbox"
265+ iforM_ attrs $ \attr value -> liftIO $ elementSetAttribute e attr value
266+ if checked == True then liftIO $ elementSetAttribute e "checked" "true" else return ()
267+ eChange <- wrapDomEvent e elementOnclick $ liftIO $ htmlInputElementGetChecked e
268+ return ([toNode e], eChange)
269+ eCreated <- performEvent . fmap (const mkSelf) =<< getEInit
270+ putEChildren $ fmap (^. _1) eCreated
271+ eChange <- liftM switch $ hold never $ fmap (^. _2) eCreated
272+ dValue <- holdDyn checked eChange
273+ return $ Checkbox dValue
274+
275+checkboxView :: MonadWidget t h m => Dynamic t (Map String String) -> Dynamic t Bool -> m (Event t ())
276+checkboxView dAttrs dValue = do
277+ dEffectiveAttrs <- mapDyn (Map.insert "type" "checkbox") dAttrs
278+ let mkSelf (initialValue, initialAttrs) = do
279+ doc <- askDocument
280+ Just e <- liftIO $ liftM (fmap castToHTMLInputElement) $ documentCreateElement doc "input"
281+ iforM_ initialAttrs $ \attr value -> liftIO $ elementSetAttribute e attr value
282+ liftIO $ htmlInputElementSetChecked e initialValue
283+ eClicked <- wrapDomEvent e elementOnclick preventDefault
284+ return (e, eClicked)
285+ dInitial <- combineDyn (,) dValue dEffectiveAttrs
286+ eCreated <- performEvent . fmap mkSelf . tagDyn dInitial =<< getEInit
287+ putEChildren $ fmap ((:[]) . toNode . (^. _1)) eCreated
288+ dElement <- holdDyn Nothing $ fmap (Just . (^. _1)) eCreated
289+ performEvent_ . updated =<< combineDyn (\me a -> forM_ me $ \e -> liftIO $ setElementAttributes e a) dElement dEffectiveAttrs
290+ performEvent_ . updated =<< combineDyn (\v me -> maybe (return ()) (\e -> liftIO $ htmlInputElementSetChecked e v) me) dValue dElement
291+ liftM switch $ hold never $ fmap (^. _2) eCreated
292+
293+{-# INLINABLE textInput #-}
294+textInput :: MonadWidget t h m => m (TextInput t)
295+textInput = input "text" $ Map.singleton "class" "form-control"
296+
297+data Dropdown t k
298+ = Dropdown { _dropdown_value :: Dynamic t k
299+ }
300+
301+setInnerText :: (HasDocument m, IsHTMLElement self, MonadIO m) => self -> String -> m (Maybe Node)
302+setInnerText e s = do
303+ liftIO $ htmlElementSetInnerHTML e ""
304+ doc <- askDocument
305+ t <- liftIO $ documentCreateTextNode doc s
306+ liftIO $ nodeAppendChild e t
307+
308+--TODO: Retain set value when allowed values changes
309+{-# INLINABLE dropdown #-}
310+dropdown :: forall t h m k. (MonadWidget t h m, Show k, Read k) => Dynamic t (Map k String) -> m (Dropdown t (Maybe k))
311+dropdown dOptions = do
312+ let triggerChange (e, reChangeTrigger) runFrame = do
313+ v <- htmlSelectElementGetValue e
314+ readRef reChangeTrigger >>= mapM_ (\eChangeTrigger -> runFrame $ DMap.singleton eChangeTrigger $ readMay v)
315+ let mkSelf = do
316+ doc <- askDocument
317+ Just e <- liftIO $ liftM (fmap castToHTMLSelectElement) $ documentCreateElement doc "select"
318+ liftIO $ elementSetAttribute e "class" "form-control"
319+ runFrame <- askRunFrame
320+ reChangeTrigger <- newRef Nothing
321+ eChange <- newEventWithTrigger $ \eChangeTrigger -> do
322+ writeRef reChangeTrigger $ Just eChangeTrigger
323+ unsubscribe <- liftIO $ elementOnchange e $ liftIO $ triggerChange (e, reChangeTrigger) runFrame
324+ return $ do
325+ writeRef reChangeTrigger Nothing
326+ liftIO unsubscribe
327+ return ((e, reChangeTrigger), eChange)
328+ eCreated <- performEvent . fmap (const mkSelf) =<< getEInit
329+ dState <- holdDyn Nothing $ fmap (Just . (^. _1)) eCreated
330+ putEChildren $ fmap ((:[]) . toNode . fst . (^. _1)) eCreated
331+ let updateOptions :: Map k String -> Maybe (HTMLSelectElement, Ref h (Maybe (EventTrigger t (Maybe k)))) -> h ()
332+ updateOptions options = maybe (return ()) $ \myState@(selectElement, _) -> do
333+ doc <- askDocument
334+ liftIO $ htmlElementSetInnerHTML selectElement ""
335+ iforM_ options $ \k optionText -> do
336+ Just optionElement <- liftIO $ liftM (fmap castToHTMLOptionElement) $ documentCreateElement doc "option"
337+ liftIO $ elementSetAttribute optionElement "value" $ show k
338+ _ <- setInnerText optionElement optionText
339+ liftIO $ nodeAppendChild selectElement $ Just optionElement
340+ runFrame <- askRunFrame
341+ liftIO $ triggerChange myState runFrame
342+ performEvent_ . updated =<< combineDyn updateOptions dOptions dState
343+ eChange <- liftM switch $ hold never $ fmap (^. _2) eCreated
344+ dValue <- holdDyn Nothing eChange
345+ return $ Dropdown dValue
346+
347+data Link t
348+ = Link { _link_clicked :: Event t ()
349+ }
350+
351+linkClassWithExtraSetup :: MonadWidget t h m => (HTMLElement -> h ()) -> String -> String -> m (Link t)
352+linkClassWithExtraSetup extraSetup s c = do
353+ let mkSelf = do
354+ doc <- askDocument
355+ Just e <- liftIO $ liftM (fmap castToHTMLElement) $ documentCreateElement doc "a"
356+ _ <- setInnerText e s
357+ liftIO $ elementSetAttribute e "class" c
358+ eClicked <- wrapDomEvent e elementOnclick $ return ()
359+ extraSetup e
360+ return ([toNode e], eClicked)
361+ eCreated <- performEvent . fmap (const mkSelf) =<< getEInit
362+ putEChildren $ fmap (^. _1) eCreated
363+ eClicked <- liftM switch $ hold never $ fmap (^. _2) eCreated
364+ return $ Link eClicked
365+
366+{-# INLINABLE linkClass #-}
367+linkClass :: MonadWidget t h m => String -> String -> m (Link t)
368+linkClass = linkClassWithExtraSetup $ const $ return ()
369+
370+{-# INLINABLE link #-}
371+link :: MonadWidget t h m => String -> m (Link t)
372+link s = linkClass s ""
373+
374+{-# INLINABLE button #-}
375+button :: MonadWidget t h m => String -> m (Link t)
376+button s = linkClass s "btn btn-primary"
377+
378+{-# INLINABLE elAttr #-}
379+elAttr :: forall t h m a. MonadWidget t h m => String -> Map String String -> m a -> m a
380+elAttr elementTag attrs child = liftM snd $ elAttr' elementTag attrs child
381+
382+{-# INLINABLE el' #-}
383+el' :: forall t h m a. MonadWidget t h m => String -> m a -> m (El t, a)
384+el' elementTag child = elAttr' elementTag Map.empty child
385+
386+{-# INLINABLE elAttr' #-}
387+elAttr' :: forall t h m a. MonadWidget t h m => String -> Map String String -> m a -> m (El t, a)
388+elAttr' elementTag attrs child = do
389+ dAttributes <- holdDyn attrs never
390+ elDynAttr' elementTag dAttributes child
391+
392+{-# INLINABLE elDynAttr #-}
393+elDynAttr :: forall t h m a. MonadWidget t h m => String -> Dynamic t (Map String String) -> m a -> m a
394+elDynAttr elementTag dAttributes child = liftM snd $ elDynAttr' elementTag dAttributes child
395+
396+{-# INLINABLE el #-}
397+el :: forall t h m a. MonadWidget t h m => String -> m a -> m a
398+el elementTag child = elAttr elementTag Map.empty child
399+
400+newtype Workflow t m a = Workflow { unWorkflow :: m (a, Event t (Workflow t m a)) }
401+
402+workflowView :: forall t h m a. MonadWidget t h m => Workflow t (WidgetEventM m) a -> m (Event t a)
403+workflowView w0 = do
404+ rec eResult <- dyn =<< mapDyn unWorkflow =<< holdDyn w0 eReplace
405+ eReplace <- liftM switch $ hold never $ fmap snd eResult
406+ eResult `seq` eReplace `seq` return ()
407+ return $ fmap fst eResult
408+
409+insertNext :: (Ord k, Enum k) => v -> Map k v -> Map k v
410+insertNext v m =
411+ let k = case Map.maxViewWithKey m of
412+ Nothing -> toEnum 0
413+ Just ((k0, _), _) -> succ k0
414+ in Map.insert k v m
415+
416+{-# INLINABLE oldList #-}
417+oldList :: (MonadWidget t h m, MonadWidget t h (WidgetEventM m), Ord k, Show k) => Dynamic t (Map k (WidgetEventM m v')) -> m (Dynamic t (Map k ()))
418+oldList dm = el "ul" $ list dm (\dv -> el "li" (dyn dv) >> return ())
419+
420+{-# INLINABLE list #-}
421+list :: forall t m h k v v'. (MonadWidget t h m, Ord k, Show k) => Dynamic t (Map k v) -> (Dynamic t v -> WidgetEventM m v') -> m (Dynamic t (Map k v'))
422+list dm mkChild = listWithKey dm (\_ dv -> mkChild dv)
423+
424+instance MonadWidget' t h m => MonadWidget' t h (ReaderT r m) where
425+ type WidgetEventM (ReaderT r m) = ReaderT r (WidgetEventM m)
426+ elDynAttr' tag dAttrs = mapReaderT (elDynAttr' tag dAttrs)
427+ performEvent = lift . performEvent
428+ performEvent_ = lift . performEvent_
429+ getEInit = lift getEInit
430+ putEChildren = lift . putEChildren
431+ dyn d = do
432+ r <- ask
433+ lift $ dyn =<< mapDyn (flip runReaderT r) d
434+ listWithKey d w = do
435+ r <- ask
436+ lift $ listWithKey d $ \k dv -> runReaderT (w k dv) r
437+ text = lift . text
438+ dynText = lift . dynText
439+
440+-}