on develop help sign in
Merge remote-tracking branch 'origin/dynamic-writer' into fix-dyn-pattern-match

Conflicts: default.nix reflex-dom.cabal src/Reflex/Dom.hs src/Reflex/Dom/Widget/Basic.hs

commit53d9e1cf56ffaa2b58b243f1ea76c447a65bf5a1 authorAli Abrar <aliabrar@gmail.com> dateThu 3 Mar 2016, 16:42 (11 years ago) parent6979655172a48c
6 files changed+47−35
README.md+6−6 default.nix+5−5 reflex-dom.cabal+5−3 src/Reflex/Dom.hs+2 src/Reflex/Dom/Widget/Basic.hs+6−3 src/Reflex/Dom/Widget/Input.hs+23−18
README.md+6−6
@@ -1,17 +1,17 @@
11## Reflex-DOM
22### A Framework for Functional Reactive Web Apps in Haskell
33
4−Reflex-DOM is a framework for building web applications in Haskell, based on the [Functional Reactive Programming](https://wiki.haskell.org/Functional_Reactive_Programming) library [Reflex](https://github.com/ryantrinkle/reflex).
4+Reflex-DOM is a framework for building web applications in Haskell, based on the [Functional Reactive Programming](https://wiki.haskell.org/Functional_Reactive_Programming) library [Reflex](https://github.com/reflex-frp/reflex).
55
6−Comprehensive documentation is still a work in progress, but a [demo](https://github.com/ryantrinkle/try-reflex) is available and an introductory talk is available at [Part 1](https://www.youtube.com/watch?v=mYvkcskJbc4) / [Part 2](https://www.youtube.com/watch?v=3qfc9XFVo2c) ([Slides](https://obsidian.systems/reflex-nyhug/)).
6+Comprehensive documentation is still a work in progress, but a [demo](https://github.com/reflex-frp/reflex-platform) is available and an introductory talk is available at [Part 1](https://www.youtube.com/watch?v=mYvkcskJbc4) / [Part 2](https://www.youtube.com/watch?v=3qfc9XFVo2c) ([Slides](https://obsidian.systems/reflex-nyhug/)).
77
88A summary of Reflex-DOM functions is available in the [quick reference](Quickref.md).
99
1010### Additional resources
11−[try reflex](https://github.com/ryantrinkle/try-reflex)
11+[Get started with Reflex](https://github.com/reflex-frp/reflex-platform)
1212
13−[reddit/r/reflexfrp](http://www.reddit.com/r/reflexfrp)
13+[/r/reflexfrp](https://www.reddit.com/r/reflexfrp)
1414
15−[reflex-examples](https://github.com/reflex-frp/reflex-examples)
15+[hackage](https://hackage.haskell.org/package/reflex)
1616
17−irc.freenode.net #reflex-frp
17+[irc.freenode.net #reflex-frp](http://webchat.freenode.net?channels=%23reflex-frp&uio=d4)
default.nix+5−5
@@ -1,9 +1,9 @@
1−{ mkDerivation, dependent-map, ghcjs-dom, lens
2−, mtl, ref-tf, reflex, safe, text, these
1+{ mkDerivation, pkgs, dependent-map, ghcjs-dom, lens
2+, mtl, ref-tf, reflex, text, these
33, transformers, data-default, semigroups, aeson
44, ghc, webkitgtk3-javascriptcore, exception-transformers
5−, webkitgtk24x, dependent-sum-template, bifunctors, zenc
6−, random, raw-strings-qq
5+, webkitgtk24x, dependent-sum-template, bifunctors, bimap
6+, raw-strings-qq, zenc, random
77}:
88
99mkDerivation {
@@ -18,7 +18,6 @@ mkDerivation {
1818 these
1919 lens
2020 ghcjs-dom
21− safe
2221 text
2322 data-default
2423 semigroups
@@ -29,6 +28,7 @@ mkDerivation {
2928 bifunctors
3029 zenc
3130 random
31+ bimap
3232 ] ++ (if (ghc.pname or null) == "ghcjs" then [ ] else [ webkitgtk3-javascriptcore raw-strings-qq ]);
3333 pkgconfigDepends = if (ghc.pname or null) == "ghcjs" then [ ] else [ webkitgtk24x webkitgtk3-javascriptcore raw-strings-qq ];
3434 license = null;
reflex-dom.cabal+5−3
@@ -13,8 +13,10 @@ Cabal-version: >=1.9.2
1313-- Deal with https://github.com/haskell/cabal/issues/2544 / https://github.com/haskell/cabal/issues/367
1414extra-source-files: src-ghc/Reflex/Dom/Internal/Foreign.hs
1515 src-ghc/Reflex/Dom/Xhr/Foreign.hs
16+ src-ghc/Reflex/Dom/WebSocket/Foreign.hs
1617 src-ghcjs/Reflex/Dom/Internal/Foreign.hs
1718 src-ghcjs/Reflex/Dom/Xhr/Foreign.hs
19+ src-ghcjs/Reflex/Dom/WebSocket/Foreign.hs
1820 src/Reflex/Dom/Xhr/ResponseType.hs
1921 src/Reflex/Dom/Xhr/Exception.hs
2022
@@ -35,7 +37,6 @@ library
3537 ghcjs-dom >= 0.2.1 && < 0.3,
3638 transformers == 0.3.* || == 0.4.*,
3739 lens >= 4.7 && < 4.14,
38− safe == 0.3.*,
3940 text == 1.2.*,
4041 bytestring == 0.10.*,
4142 data-default == 0.5.*,
@@ -45,7 +46,8 @@ library
4546 directory == 1.2.*,
4647 dependent-sum-template >= 0.0.0.4 && < 0.1,
4748 zenc == 0.1.*,
48− bifunctors >= 4.2 && < 6
49+ bifunctors >= 4.2 && < 6,
50+ bimap >= 0.3 && < 0.4
4951
5052 if impl(ghcjs)
5153 hs-source-dirs: src-ghcjs
@@ -92,4 +94,4 @@ library
9294
9395source-repository head
9496 type: git
95− location: https://github.com/ryantrinkle/reflex
97+ location: https://github.com/reflex-frp/reflex-dom
src/Reflex/Dom.hs+2
@@ -4,6 +4,7 @@ module Reflex.Dom ( module Reflex
44 , module Reflex.Dom.Widget
55 , module Reflex.Dom.Xhr
66 , module Reflex.Dom.Time
7+ , module Reflex.Dom.DynamicWriter
78 , module Reflex.Dom.WebSocket
89 , module Reflex.Dom.DynamicWriter
910 , module Reflex.Dom.Location
@@ -15,6 +16,7 @@ import Reflex.Dom.Internal
1516import Reflex.Dom.Widget
1617import Reflex.Dom.Xhr
1718import Reflex.Dom.Time
19+import Reflex.Dom.DynamicWriter
1820import Reflex.Dom.WebSocket
1921import Reflex.Dom.DynamicWriter
2022import Reflex.Dom.Location
src/Reflex/Dom/Widget/Basic.hs+6−3
@@ -130,7 +130,7 @@ display a = dynText =<< mapDyn show a
130130--TODO: Should this be renamed to 'widgetView' for consistency with 'widgetHold'?
131131-- | Given a Dynamic of widget-creating actions, create a widget that is recreated whenever the Dynamic updates.
132132-- The returned Event of widget results occurs when the Dynamic does.
133−-- Note: Often, the type 'a' is an Event, in which case the return value is an Event-of-Events that would typically be flattened.
133+-- Note: Often, the type 'a' is an Event, in which case the return value is an Event-of-Events that would typically be flattened (via 'switchPromptly').
134134dyn :: MonadWidget t m => Dynamic t (m a) -> m (Event t a)
135135dyn child = do
136136 postBuild <- getPostBuild
@@ -235,8 +235,8 @@ listHoldWithKey initialVals valsChanged mkChild = do
235235 stateRef <- liftIO $ newIORef initialState
236236 children <- holdDyn initialState newChildren
237237 tellWidgetOutput =<< mapDyn (fmap snd) children
238− mpOrig <- getParentNode endPlaceholder
239− forM_ mpOrig $ \pOrig -> insertBefore pOrig (Just dfOrig) (Just endPlaceholder)
238+ mpOrig <- liftIO $ getParentNode endPlaceholder
239+ forM_ mpOrig $ \pOrig -> liftIO $ insertBefore pOrig (Just dfOrig) (Just endPlaceholder)
240240 addVoidAction $ flip fmap valsChanged $ \newVals -> do
241241 curState <- liftIO $ readIORef stateRef
242242 --TODO: Should we remove the parent from the DOM first to avoid reflows?
@@ -827,6 +827,9 @@ workflowView w0 = do
827827 eReplace <- liftM switch $ hold never $ fmap snd eResult
828828 return $ fmap fst eResult
829829
830+mapWorkflow :: (MonadWidget t m) => (a -> b) -> Workflow t m a -> Workflow t m b
831+mapWorkflow f (Workflow x) = Workflow (fmap (\(v,e) -> (f v, fmap (mapWorkflow f) e)) x)
832+
830833divClass :: forall t m a. MonadWidget t m => String -> m a -> m a
831834divClass = elClass "div"
832835
src/Reflex/Dom/Widget/Input.hs+23−18
@@ -16,14 +16,16 @@ import GHCJS.DOM.EventM
1616import GHCJS.DOM.File
1717import qualified GHCJS.DOM.FileList as FileList
1818import Data.Monoid
19−import Data.Map as Map
20−import Control.Lens
19+import qualified Data.Map as Map
20+import Control.Lens hiding (ix)
2121import Control.Monad hiding (forM_)
2222import Control.Monad.IO.Class
23+import qualified Data.Bimap as B
2324import Data.Default
24−import Data.Maybe
25−import Safe
2625import Data.Dependent.Sum (DSum (..))
26+import Data.Map (Map)
27+import Data.Maybe
28+import Text.Read
2729
2830data TextInput t
2931 = TextInput { _textInput_value :: Dynamic t String
@@ -191,26 +193,29 @@ instance (Reflex t, Ord k, Show k, Read k) => Default (DropdownConfig t k) where
191193 }
192194
193195--TODO: We should allow the user to specify an ordering instead of relying on the ordering of the Map
194−--TODO: Get rid of Show k and Read k by indexing the possible values ourselves
195196-- | Create a dropdown box
196197-- The first argument gives the initial value of the dropdown; if it is not present in the map of options provided, it will be added with an empty string as its text
197−dropdown :: forall k t m. (MonadWidget t m, Ord k, Show k, Read k) => k -> Dynamic t (Map k String) -> DropdownConfig t k -> m (Dropdown t k)
198+dropdown :: forall k t m. (MonadWidget t m, Ord k) => k -> Dynamic t (Map k String) -> DropdownConfig t k -> m (Dropdown t k)
198199dropdown k0 options (DropdownConfig setK attrs) = do
199− (eRaw, _) <- elDynAttr' "select" attrs $ do
200− optionsWithDefault <- mapDyn (`Map.union` (k0 =: "")) options
201− listWithKey optionsWithDefault $ \k v -> do
202− elAttr "option" ("value" =: show k <> if k == k0 then "selected" =: "selected" else mempty) $ dynText v
200+ optionsWithAddedKeys <- combineDyn Map.union options <=< foldDyn Map.union (k0 =: "") $ fmap (=: "") setK
201+ defaultKey <- holdDyn k0 setK
202+ (indexedOptions, ixKeys) <- splitDyn <=< forDyn optionsWithAddedKeys $ \os ->
203+ let xs = map (\(ix, (k, v)) -> ((ix, k), ((ix, k), v))) $ zip [0::Int ..] $ Map.toList os
204+ ixVals = Map.fromList $ map snd xs
205+ ixKeys = B.fromList $ map fst xs
206+ in (ixVals, ixKeys)
207+ (eRaw, _) <- elDynAttr' "select" attrs $ listWithKey indexedOptions $ \(ix, k) v -> do
208+ optionAttrs <- mapDyn (\dk -> "value" =: show ix <> if dk == k then "selected" =: "selected" else mempty) defaultKey
209+ elDynAttr "option" optionAttrs $ dynText v
203210 let e = castToHTMLSelectElement $ _el_element eRaw
204− performEvent_ $ fmap (Select.setValue e . Just . show) setK
205− eChange <- wrapDomEvent e (`on` change) $ do
206− kStr <- fromMaybe "" <$> Select.getValue e
207− return $ readMay kStr
208− let readKey opts mk = fromMaybe k0 $ do
211+ performEvent_ $ fmap (Select.setValue e . Just . show) $ attachDynWithMaybe (flip B.lookupR) ixKeys setK
212+ eChange <- attachDynWith (\ks s -> join $ B.lookup <$> join (readMaybe <$> s) <*> pure ks) ixKeys <$> (wrapDomEvent e (`on` change) $ Select.getValue e)
213+ let readKey keys mk = fromMaybe k0 $ do
209214 k <- mk
210− guard $ Map.member k opts
215+ guard $ B.memberR k keys
211216 return k
212− dValue <- combineDyn readKey options =<< holdDyn (Just k0) (leftmost [eChange, fmap Just setK])
213− return $ Dropdown dValue (attachDynWith readKey options eChange)
217+ dValue <- combineDyn readKey ixKeys <=< holdDyn (Just k0) $ leftmost [eChange, fmap Just setK]
218+ return $ Dropdown dValue (attachDynWith readKey ixKeys eChange)
214219
215220liftM concat $ mapM makeLenses
216221 [ ''TextAreaConfig