on develop help sign in
Merge branch 'refactor' of github.com:reflex-frp/reflex-dom into refactor
commitcc768a7016244cdbfe25c0259c6649f98123dab7 authorRyan Trinkle <ryan.trinkle@gmail.com> dateWed 27 Jul 2016, 12:34 (10 years ago) parent63e6c60eade9ef
38 files changed+941−645
.gitignore+1 .stylish-haskell.yaml+154 default.nix+32−19 reflex-dom.cabal+9−1 src-ghc/Reflex/Dom/Internal/Foreign.hs+22−19 src-ghc/Reflex/Dom/WebSocket/Foreign.hs+17−5 src-ghc/Reflex/Dom/Xhr/Foreign.hs+22−28 src-ghcjs/Reflex/Dom/Internal/Foreign.hs+8−8 src-ghcjs/Reflex/Dom/WebSocket/Foreign.hs+14−13 src-ghcjs/Reflex/Dom/Xhr/Foreign.hs+16−13 src/Foreign/JavaScript/TH.hs+46−32 src/Reflex/Dom.hs+16−31 src/Reflex/Dom/Builder/Class.hs+34−14 src/Reflex/Dom/Builder/Class/Events.hs+6−1 src/Reflex/Dom/Builder/Immediate.hs+56−43 src/Reflex/Dom/Builder/Static.hs+46−23 src/Reflex/Dom/Class.hs+11−6 src/Reflex/Dom/Deletable/Class.hs+4−1 src/Reflex/Dom/DynamicWriter.hs+22−12 src/Reflex/Dom/Internal.hs+33−62 src/Reflex/Dom/Location.hs+1−1 src/Reflex/Dom/Old.hs+3−1 src/Reflex/Dom/PerformEvent/Base.hs+28−16 src/Reflex/Dom/PerformEvent/Class.hs+9−1 src/Reflex/Dom/PostBuild/Class.hs+18−8 src/Reflex/Dom/Time.hs+16−11 src/Reflex/Dom/WebSocket.hs+26−9 src/Reflex/Dom/Widget.hs+5−9 src/Reflex/Dom/Widget/Basic.hs+95−72 src/Reflex/Dom/Widget/Input.hs+51−93 src/Reflex/Dom/Widget/Lazy.hs+30−23 src/Reflex/Dom/Widget/Resize.hs+18−12 src/Reflex/Dom/Xhr.hs+35−30 src/Reflex/Dom/Xhr/Exception.hs+1−1 src/Reflex/Dom/Xhr/ResponseType.hs+2−2 test/BrokenHaltSpec.hs+9−10 test/HaltSpec.hs+13−15 test/hlint.hs+12
.gitignore+1
@@ -1,4 +1,5 @@
11dist
2+dist-*
23cabal-dev
34*.o
45*.hi
.stylish-haskell.yamlnew file+154
@@ -0,0 +1,154 @@
1+# stylish-haskell configuration file
2+# ==================================
3+
4+# The stylish-haskell tool is mainly configured by specifying steps. These steps
5+# are a list, so they have an order, and one specific step may appear more than
6+# once (if needed). Each file is processed by these steps in the given order.
7+steps:
8+ # Convert some ASCII sequences to their Unicode equivalents. This is disabled
9+ # by default.
10+ # - unicode_syntax:
11+ # # In order to make this work, we also need to insert the UnicodeSyntax
12+ # # language pragma. If this flag is set to true, we insert it when it's
13+ # # not already present. You may want to disable it if you configure
14+ # # language extensions using some other method than pragmas. Default:
15+ # # true.
16+ # add_language_pragma: true
17+
18+ # Import cleanup
19+ - imports:
20+ # There are different ways we can align names and lists.
21+ #
22+ # - global: Align the import names and import list throughout the entire
23+ # file.
24+ #
25+ # - file: Like global, but don't add padding when there are no qualified
26+ # imports in the file.
27+ #
28+ # - group: Only align the imports per group (a group is formed by adjacent
29+ # import lines).
30+ #
31+ # - none: Do not perform any alignment.
32+ #
33+ # Default: global.
34+ align: none
35+
36+ # Folowing options affect only import list alignment.
37+ #
38+ # List align has following options:
39+ #
40+ # - after_alias: Import list is aligned with end of import including
41+ # 'as' and 'hiding' keywords.
42+ #
43+ # > import qualified Data.List as List (concat, foldl, foldr, head,
44+ # > init, last, length)
45+ #
46+ # - with_alias: Import list is aligned with start of alias or hiding.
47+ #
48+ # > import qualified Data.List as List (concat, foldl, foldr, head,
49+ # > init, last, length)
50+ #
51+ # - new_line: Import list starts always on new line.
52+ #
53+ # > import qualified Data.List as List
54+ # > (concat, foldl, foldr, head, init, last, length)
55+ #
56+ # Default: after alias
57+ list_align: after_alias
58+
59+ # Long list align style takes effect when import is too long. This is
60+ # determined by 'columns' setting.
61+ #
62+ # - inline: This option will put as much specs on same line as possible.
63+ #
64+ # - new_line: Import list will start on new line.
65+ #
66+ # - new_line_multiline: Import list will start on new line when it's
67+ # short enough to fit to single line. Otherwise it'll be multiline.
68+ #
69+ # - multiline: One line per import list entry.
70+ # Type with contructor list acts like single import.
71+ #
72+ # > import qualified Data.Map as M
73+ # > ( empty
74+ # > , singleton
75+ # > , ...
76+ # > , delete
77+ # > )
78+ #
79+ # Default: inline
80+ long_list_align: inline
81+
82+ # List padding determines indentation of import list on lines after import.
83+ # This option affects 'list_align' and 'long_list_align'.
84+ list_padding: 2
85+
86+ # Separate lists option affects formating of import list for type
87+ # or class. The only difference is single space between type and list
88+ # of constructors, selectors and class functions.
89+ #
90+ # - true: There is single space between Foldable type and list of it's
91+ # functions.
92+ #
93+ # > import Data.Foldable (Foldable (fold, foldl, foldMap))
94+ #
95+ # - false: There is no space between Foldable type and list of it's
96+ # functions.
97+ #
98+ # > import Data.Foldable (Foldable(fold, foldl, foldMap))
99+ #
100+ # Default: true
101+ separate_lists: true
102+
103+ # Language pragmas
104+ - language_pragmas:
105+ # We can generate different styles of language pragma lists.
106+ #
107+ # - vertical: Vertical-spaced language pragmas, one per line.
108+ #
109+ # - compact: A more compact style.
110+ #
111+ # - compact_line: Similar to compact, but wrap each line with
112+ # `{-#LANGUAGE #-}'.
113+ #
114+ # Default: vertical.
115+ style: vertical
116+
117+ # Align affects alignment of closing pragma brackets.
118+ #
119+ # - true: Brackets are aligned in same collumn.
120+ #
121+ # - false: Brackets are not aligned together. There is only one space
122+ # between actual import and closing bracket.
123+ #
124+ # Default: true
125+ align: false
126+
127+ # stylish-haskell can detect redundancy of some language pragmas. If this
128+ # is set to true, it will remove those redundant pragmas. Default: true.
129+ remove_redundant: true
130+
131+ # Align the types in record declarations
132+ # - records: {}
133+
134+ # Replace tabs by spaces. This is disabled by default.
135+ # - tabs:
136+ # # Number of spaces to use for each tab. Default: 8, as specified by the
137+ # # Haskell report.
138+ # spaces: 8
139+
140+ # Remove trailing whitespace
141+ - trailing_whitespace: {}
142+
143+# A common setting is the number of columns (parts of) code will be wrapped
144+# to. Different steps take this into account. Default: 80.
145+columns: 110
146+
147+# Sometimes, language extensions are specified in a cabal file or from the
148+# command line instead of using language pragmas in the file. stylish-haskell
149+# needs to be aware of these, so it can parse the file correctly.
150+#
151+# No language extensions are enabled by default.
152+# language_extensions:
153+ # - TemplateHaskell
154+ # - QuasiQuotes
default.nix+32−19
@@ -3,7 +3,8 @@
33, transformers, data-default, semigroups, blaze-builder, aeson
44, ghc, webkitgtk3-javascriptcore, exception-transformers
55, webkitgtk24x, dependent-sum-template, bifunctors, bimap
6−, raw-strings-qq, zenc, random, monad-control
6+, raw-strings-qq, zenc, random, monad-control, keycode, hlint
7+, unbounded-delays
78}:
89
910mkDerivation {
@@ -11,27 +12,39 @@ mkDerivation {
1112 version = "0.3";
1213 src = builtins.filterSource (path: type: baseNameOf path != ".git") ./.;
1314 buildDepends = [
14− reflex
15− dependent-map
16− mtl
17− transformers
18− these
19− lens
20− ghcjs-dom
21− text
22− data-default
23− semigroups
24− ref-tf
25− blaze-builder
2615 aeson
27− exception-transformers
28− dependent-sum-template
2916 bifunctors
30− zenc
31− random
3217 bimap
18+ blaze-builder
19+ data-default
20+ dependent-map
21+ dependent-sum-template
22+ exception-transformers
23+ ghcjs-dom
24+ keycode
25+ lens
3326 monad-control
34− ] ++ (if (ghc.pname or null) == "ghcjs" then [ ] else [ webkitgtk3-javascriptcore raw-strings-qq ]);
35− pkgconfigDepends = if (ghc.pname or null) == "ghcjs" then [ ] else [ webkitgtk24x webkitgtk3-javascriptcore raw-strings-qq ];
27+ mtl
28+ random
29+ ref-tf
30+ reflex
31+ semigroups
32+ text
33+ these
34+ transformers
35+ zenc
36+ unbounded-delays
37+ ] ++ (if ghc.isGhcjs or false then [] else [
38+ raw-strings-qq
39+ webkitgtk3-javascriptcore
40+ ]);
41+ testDepends = if ghc.isGhcjs or false then [] else [
42+ hlint
43+ ];
44+ pkgconfigDepends = if ghc.isGhcjs or false then [] else [
45+ raw-strings-qq
46+ webkitgtk24x
47+ webkitgtk3-javascriptcore
48+ ];
3649 license = null;
3750}
reflex-dom.cabal+9−1
@@ -50,7 +50,9 @@ library
5050 zenc == 0.1.*,
5151 bifunctors >= 4.2 && < 6,
5252 bimap >= 0.3 && < 0.4,
53− monad-control >= 1.0.1 && < 1.1
53+ monad-control >= 1.0.1 && < 1.1,
54+ keycode == 0.2.*,
55+ unbounded-delays == 0.1.0.9
5456
5557 if impl(ghcjs)
5658 hs-source-dirs: src-ghcjs
@@ -104,6 +106,12 @@ library
104106 other-extensions: TemplateHaskell
105107 ghc-options: -Wall -fwarn-tabs -funbox-strict-fields -O2 -ferror-spans
106108
109+test-suite hlint
110+ build-depends: base, hlint == 1.9.*
111+ hs-source-dirs: test
112+ main-is: hlint.hs
113+ type: exitcode-stdio-1.0
114+
107115source-repository head
108116 type: git
109117 location: https://github.com/reflex-frp/reflex-dom
src-ghc/Reflex/Dom/Internal/Foreign.hs+22−19
@@ -1,12 +1,21 @@
1−{-# LANGUAGE CPP, ForeignFunctionInterface, ScopedTypeVariables, LambdaCase, OverloadedStrings #-}
1+{-# LANGUAGE CPP #-}
2+{-# LANGUAGE ForeignFunctionInterface #-}
3+{-# LANGUAGE LambdaCase #-}
4+{-# LANGUAGE OverloadedStrings #-}
5+{-# LANGUAGE ScopedTypeVariables #-}
26module Reflex.Dom.Internal.Foreign where
37
48import Control.Concurrent
59import Control.Exception (bracket)
610import Control.Lens hiding (set)
711import Control.Monad
8−import Control.Monad.State.Strict hiding (mapM, mapM_, forM, forM_, sequence, sequence_, get)
12+import Control.Monad.State.Strict hiding (forM, forM_, get, mapM, mapM_, sequence, sequence_)
913import Data.ByteString (ByteString)
14+import qualified Data.ByteString as BS
15+import Data.Maybe
16+import Data.Monoid
17+import Data.Text (Text)
18+import qualified Data.Text as T
1019import Foreign.Marshal hiding (void)
1120import Foreign.Ptr
1221import GHCJS.DOM hiding (runWebGUI)
@@ -18,17 +27,13 @@ import Graphics.UI.Gtk.WebKit.JavaScriptCore.JSObjectRef
1827import Graphics.UI.Gtk.WebKit.JavaScriptCore.JSStringRef
1928import Graphics.UI.Gtk.WebKit.JavaScriptCore.JSValueRef
2029import Graphics.UI.Gtk.WebKit.JavaScriptCore.WebFrame
21−import Graphics.UI.Gtk.WebKit.Types hiding (Event, Widget, Text)
30+import Graphics.UI.Gtk.WebKit.Types hiding (Event, Text, Widget)
2231import Graphics.UI.Gtk.WebKit.WebFrame
2332import Graphics.UI.Gtk.WebKit.WebInspector
2433import Graphics.UI.Gtk.WebKit.WebSettings
2534import Graphics.UI.Gtk.WebKit.WebView
2635import System.Directory
2736import System.Glib.FFI hiding (void)
28−import qualified Data.ByteString as BS
29−import Data.Monoid
30−import Data.Text (Text)
31−import qualified Data.Text as T
3237
3338#ifndef mingw32_HOST_OS
3439import System.Posix.Signals
@@ -113,29 +118,27 @@ toJSObject ctx args = do
113118fromJSStringMaybe :: JSContextRef -> JSValueRef -> IO (Maybe Text)
114119fromJSStringMaybe c t = do
115120 isNull <- jsvalueisnull c t
116− case isNull of
117− True -> return Nothing
118− False -> do
119− j <- jsvaluetostringcopy c t nullPtr
120− l <- jsstringgetmaximumutf8cstringsize j
121− s <- allocaBytes (fromIntegral l) $ \ps -> do
122− _ <- jsstringgetutf8cstring'_ j ps (fromIntegral l)
123− peekCString ps
124− return $ Just $ T.pack s
121+ if isNull then return Nothing else do
122+ j <- jsvaluetostringcopy c t nullPtr
123+ l <- jsstringgetmaximumutf8cstringsize j
124+ s <- allocaBytes (fromIntegral l) $ \ps -> do
125+ _ <- jsstringgetutf8cstring'_ j ps (fromIntegral l)
126+ peekCString ps
127+ return $ Just $ T.pack s
125128
126129getLocationHost :: WebView -> IO Text
127130getLocationHost wv = withWebViewContext wv $ \c -> do
128131 script <- jsstringcreatewithutf8cstring "location.host"
129132 lh <- jsevaluatescript c script nullPtr nullPtr 1 nullPtr
130133 lh' <- fromJSStringMaybe c lh
131− return $ maybe "" id lh'
134+ return $ fromMaybe "" lh'
132135
133136getLocationProtocol :: WebView -> IO Text
134137getLocationProtocol wv = withWebViewContext wv $ \c -> do
135138 script <- jsstringcreatewithutf8cstring "location.protocol"
136139 lp <- jsevaluatescript c script nullPtr nullPtr 1 nullPtr
137140 lp' <- fromJSStringMaybe c lp
138− return $ maybe "" id lp'
141+ return $ fromMaybe "" lp'
139142
140143bsToArrayBuffer :: JSContextRef -> ByteString -> IO JSValueRef
141144bsToArrayBuffer c bs = do
@@ -159,7 +162,7 @@ bsFromArrayBuffer c a = do
159162 i' <- jsvaluemakenumber c (fromIntegral i)
160163 args <- toJSObject c [uint8Array, i']
161164 getIntegral =<< jsevaluatescript c getIx args nullPtr 1 nullPtr
162− fmap BS.pack $ forM [0..byteLength-1] arrayLookup
165+ BS.pack <$> forM [0..byteLength-1] arrayLookup
163166
164167withWebViewContext :: WebView -> (JSContextRef -> IO a) -> IO a
165168withWebViewContext wv f = f =<< webFrameGetGlobalContext =<< webViewGetMainFrame wv
src-ghc/Reflex/Dom/WebSocket/Foreign.hs+17−5
@@ -1,12 +1,27 @@
1−{-# LANGUAGE ForeignFunctionInterface, JavaScriptFFI, CPP, TemplateHaskell, NoMonomorphismRestriction, EmptyDataDecls, RankNTypes, GADTs, RecursiveDo, ScopedTypeVariables, FlexibleInstances, MultiParamTypeClasses, TypeFamilies, FlexibleContexts, DeriveDataTypeable, GeneralizedNewtypeDeriving, StandaloneDeriving, ConstraintKinds, UndecidableInstances, PolyKinds, AllowAmbiguousTypes #-}
1+{-# LANGUAGE AllowAmbiguousTypes #-}
2+{-# LANGUAGE ConstraintKinds #-}
3+{-# LANGUAGE FlexibleContexts #-}
4+{-# LANGUAGE FlexibleInstances #-}
5+{-# LANGUAGE GADTs #-}
6+{-# LANGUAGE JavaScriptFFI #-}
7+{-# LANGUAGE MultiParamTypeClasses #-}
8+{-# LANGUAGE NoMonomorphismRestriction #-}
9+{-# LANGUAGE PolyKinds #-}
10+{-# LANGUAGE RankNTypes #-}
11+{-# LANGUAGE ScopedTypeVariables #-}
12+{-# LANGUAGE TypeFamilies #-}
13+{-# LANGUAGE UndecidableInstances #-}
214
315module Reflex.Dom.WebSocket.Foreign where
416
5−import Prelude hiding (div, span, mapM, mapM_, concat, concatMap, all, sequence)
17+import Prelude hiding (all, concat, concatMap, div, mapM, mapM_, sequence, span)
618
719import Control.Exception
820import Control.Monad.State
921import Data.ByteString (ByteString)
22+import qualified Data.ByteString as BS
23+import Data.Text (Text)
24+import qualified Data.Text as T
1025import Data.Text.Encoding
1126import Foreign.Marshal hiding (void)
1227import Foreign.Ptr
@@ -16,9 +31,6 @@ import Graphics.UI.Gtk.WebKit.JavaScriptCore.JSObjectRef
1631import Graphics.UI.Gtk.WebKit.JavaScriptCore.JSStringRef
1732import Graphics.UI.Gtk.WebKit.JavaScriptCore.JSValueRef
1833import Graphics.UI.Gtk.WebKit.WebView
19−import qualified Data.ByteString as BS
20−import Data.Text (Text)
21−import qualified Data.Text as T
2234
2335import Reflex.Dom.Internal.Foreign
2436
src-ghc/Reflex/Dom/Xhr/Foreign.hs+22−28
@@ -1,23 +1,25 @@
1−{-# LANGUAGE TypeSynonymInstances, FlexibleInstances, QuasiQuotes, ForeignFunctionInterface, OverloadedStrings #-}
1+{-# LANGUAGE FlexibleInstances #-}
2+{-# LANGUAGE OverloadedStrings #-}
3+{-# LANGUAGE QuasiQuotes #-}
4+{-# LANGUAGE TypeSynonymInstances #-}
25module Reflex.Dom.Xhr.Foreign ( module Reflex.Dom.Xhr.Foreign
36 , XhrResponseType
47 ) where
58
9+import Control.Concurrent.MVar
10+import Control.Exception.Base
611import Control.Monad
7−import qualified Data.Text as T
812import Data.Text (Text)
9−import System.Glib.FFI
10−import Graphics.UI.Gtk.WebKit.WebView
13+import qualified Data.Text as T
14+import GHCJS.DOM.File
1115import Graphics.UI.Gtk.WebKit.JavaScriptCore.JSBase
1216import Graphics.UI.Gtk.WebKit.JavaScriptCore.JSObjectRef
1317import Graphics.UI.Gtk.WebKit.JavaScriptCore.JSStringRef
1418import Graphics.UI.Gtk.WebKit.JavaScriptCore.JSValueRef
15−import GHCJS.DOM.File
16−import Reflex.Dom.Xhr.ResponseType
17−import Reflex.Dom.Xhr.Exception
18−import Control.Concurrent.MVar
19−import Control.Exception.Base
2019import Graphics.UI.Gtk.WebKit.Types hiding (Text)
20+import Reflex.Dom.Xhr.Exception
21+import Reflex.Dom.Xhr.ResponseType
22+import System.Glib.FFI
2123
2224import Reflex.Dom.Internal.Foreign
2325
@@ -111,14 +113,12 @@ xmlHttpRequestGetResponse xhr = do
111113 script <- jsstringcreatewithutf8cstring "this.response"
112114 t <- jsevaluatescript c script (xhrValue xhr) nullPtr 1 nullPtr
113115 isNull <- jsvalueisnull c t
114− case isNull of
115− True -> return Nothing
116− False -> case mrt of
117− Just XhrResponseType_ArrayBuffer -> Just . XhrResponseBody_ArrayBuffer <$> bsFromArrayBuffer c t
118− Just XhrResponseType_Blob -> Just . XhrResponseBody_Blob . Blob . castForeignPtr <$> newForeignPtr_ t
119− Just XhrResponseType_Default -> fmap (XhrResponseBody_Default) <$> fromJSStringMaybe c t
120− Just XhrResponseType_Text -> fmap (XhrResponseBody_Text) <$> fromJSStringMaybe c t
121− _ -> return Nothing
116+ if isNull then return Nothing else case mrt of
117+ Just XhrResponseType_ArrayBuffer -> Just . XhrResponseBody_ArrayBuffer <$> bsFromArrayBuffer c t
118+ Just XhrResponseType_Blob -> Just . XhrResponseBody_Blob . Blob . castForeignPtr <$> newForeignPtr_ t
119+ Just XhrResponseType_Default -> fmap XhrResponseBody_Default <$> fromJSStringMaybe c t
120+ Just XhrResponseType_Text -> fmap XhrResponseBody_Text <$> fromJSStringMaybe c t
121+ _ -> return Nothing
122122
123123xmlHttpRequestGetResponseText :: XMLHttpRequest -> IO (Maybe Text)
124124xmlHttpRequestGetResponseText xhr = do
@@ -138,17 +138,11 @@ xmlHttpRequestSendPayload xhr payload = do
138138 onError <- jsobjectmakefunctionwithcallback c nullPtr e
139139 bracket (wrapper' Nothing) freeHaskellFunPtr $ \l -> do
140140 onLoad <- jsobjectmakefunctionwithcallback c nullPtr l
141− (o,s) <- case payload of
142− Nothing -> do
143− d <- jsvaluemakeundefined c
144− o <- toJSObject c [xhrValue xhr, d, onError, onAbort, onLoad]
145− s <- jsstringcreatewithutf8cstring send
146− return (o,s)
147− Just payload' -> do
148− d <- stringToJSValue c payload'
149− o <- toJSObject c [xhrValue xhr, d, onError, onAbort, onLoad]
150− s <- jsstringcreatewithutf8cstring send
151− return (o,s)
141+ d <- case payload of
142+ Nothing -> jsvaluemakeundefined c
143+ Just payload' -> stringToJSValue c payload'
144+ o <- toJSObject c [xhrValue xhr, d, onError, onAbort, onLoad]
145+ s <- jsstringcreatewithutf8cstring send
152146 _ <- jsevaluatescript c s o nullPtr 1 nullPtr
153147 takeMVar result >>= mapM_ throwIO
154148 where
src-ghcjs/Reflex/Dom/Internal/Foreign.hs+8−8
@@ -1,19 +1,19 @@
1−{-# LANGUAGE ForeignFunctionInterface, JavaScriptFFI #-}
1+{-# LANGUAGE ForeignFunctionInterface #-}
2+{-# LANGUAGE JavaScriptFFI #-}
23module Reflex.Dom.Internal.Foreign ( module Reflex.Dom.Internal.Foreign
34 , runWebGUI
45 ) where
56
6−import Control.Monad
77import Data.ByteString (ByteString)
8+import qualified Data.ByteString as BS
89import Foreign
910import Foreign.C
11+import qualified GHCJS.Buffer as JS
1012import GHCJS.DOM
1113import GHCJS.DOM.Types
14+import qualified GHCJS.Marshal.Pure as JS
1215import GHCJS.Types
1316import JavaScript.TypedArray.ArrayBuffer as JS
14−import qualified Data.ByteString as BS
15−import qualified GHCJS.Buffer as JS
16−import qualified GHCJS.Marshal.Pure as JS
1717
1818quitWebView :: WebView -> IO ()
1919quitWebView = error "quitWebView: unimplemented in GHCJS"
@@ -21,12 +21,12 @@ quitWebView = error "quitWebView: unimplemented in GHCJS"
2121foreign import javascript unsafe "location['host']" getLocationHost_ :: IO JSString
2222
2323getLocationHost :: FromJSString r => a -> IO r
24−getLocationHost _ = liftM fromJSString getLocationHost_
24+getLocationHost _ = fmap fromJSString getLocationHost_
2525
2626foreign import javascript unsafe "location['protocol']" getLocationProtocol_ :: IO JSString
2727
2828getLocationProtocol :: FromJSString r => a -> IO r
29−getLocationProtocol _ = liftM fromJSString getLocationProtocol_
29+getLocationProtocol _ = fmap fromJSString getLocationProtocol_
3030
3131withWebViewContext :: a -> (a -> IO b) -> IO b
3232withWebViewContext a f = f a
@@ -40,4 +40,4 @@ bsToArrayBuffer _ bs = BS.useAsCString bs $ \cStr -> do
4040 extractByteArray cStr $ BS.length bs
4141
4242bsFromArrayBuffer :: a -> JSVal -> IO ByteString
43−bsFromArrayBuffer _ ab = liftM (JS.toByteString 0 Nothing . JS.createFromArrayBuffer) $ JS.unsafeFreeze $ JS.pFromJSVal ab
43+bsFromArrayBuffer _ ab = fmap (JS.toByteString 0 Nothing . JS.createFromArrayBuffer) $ JS.unsafeFreeze $ JS.pFromJSVal ab
src-ghcjs/Reflex/Dom/WebSocket/Foreign.hs+14−13
@@ -1,25 +1,26 @@
1−{-# LANGUAGE ForeignFunctionInterface, JavaScriptFFI, CPP #-}
1+{-# LANGUAGE ForeignFunctionInterface #-}
2+{-# LANGUAGE JavaScriptFFI #-}
23
34module Reflex.Dom.WebSocket.Foreign where
45
5−import Prelude hiding (div, span, mapM, mapM_, concat, concatMap, all, sequence)
6+import Prelude hiding (all, concat, concatMap, div, mapM, mapM_, sequence, span)
67
8+import Control.Monad.IO.Class
9+import Control.Monad.Reader
710import Data.ByteString (ByteString)
811import qualified Data.ByteString as BS
9−import GHCJS.Types
10−import GHCJS.DOM.WebSocket (message, open, closeEvent)
11−import qualified GHCJS.DOM.WebSocket as GD
12−import GHCJS.DOM.MessageEvent
12+import Data.Text (Text)
13+import Data.Text.Encoding
14+import GHCJS.Buffer
1315import GHCJS.DOM.EventM (on)
16+import GHCJS.DOM.MessageEvent
1417import GHCJS.DOM.Types hiding (Text)
15−import Control.Monad.IO.Class
16−import Control.Monad.Reader
17−import GHCJS.Buffer
18−import JavaScript.TypedArray.ArrayBuffer as JS
19−import GHCJS.Marshal.Pure
18+import GHCJS.DOM.WebSocket (closeEvent, message, open)
19+import qualified GHCJS.DOM.WebSocket as GD
2020import GHCJS.Foreign.Internal
21−import Data.Text.Encoding
22−import Data.Text (Text)
21+import GHCJS.Marshal.Pure
22+import GHCJS.Types
23+import JavaScript.TypedArray.ArrayBuffer as JS
2324
2425data JSWebSocket = JSWebSocket { unWebSocket :: WebSocket }
2526
src-ghcjs/Reflex/Dom/Xhr/Foreign.hs+16−13
@@ -1,4 +1,7 @@
1−{-# LANGUAGE FlexibleInstances, TypeSynonymInstances, ForeignFunctionInterface, JavaScriptFFI, OverloadedStrings #-}
1+{-# LANGUAGE FlexibleInstances #-}
2+{-# LANGUAGE JavaScriptFFI #-}
3+{-# LANGUAGE OverloadedStrings #-}
4+{-# LANGUAGE TypeSynonymInstances #-}
25
36module Reflex.Dom.Xhr.Foreign (
47 XMLHttpRequest
@@ -6,20 +9,20 @@ module Reflex.Dom.Xhr.Foreign (
69 , module Reflex.Dom.Xhr.Foreign
710) where
811
9−import Prelude hiding (error)
12+import Control.Exception (catch, throwIO)
13+import Data.Maybe (fromMaybe)
1014import Data.Text (Text)
11−import GHCJS.DOM.Types hiding (Text)
1215import GHCJS.DOM
1316import GHCJS.DOM.Enums
14−import GHCJS.DOM.XMLHttpRequest
15−import Data.Maybe (fromMaybe)
16−import GHCJS.DOM.EventTarget (dispatchEvent)
1717import GHCJS.DOM.EventM (EventM, on)
18+import GHCJS.DOM.EventTarget (dispatchEvent)
19+import GHCJS.DOM.Types hiding (Text)
20+import GHCJS.DOM.XMLHttpRequest
21+import GHCJS.Types
22+import Prelude hiding (error)
1823import Reflex.Dom.Internal.Foreign
1924import Reflex.Dom.Xhr.Exception
2025import Reflex.Dom.Xhr.ResponseType
21−import Control.Exception (catch, throwIO)
22−import GHCJS.Types
2326
2427prepareWebView :: WebView -> IO ()
2528prepareWebView _ = return ()
@@ -163,11 +166,11 @@ xmlHttpRequestGetResponse xhr = do
163166 mr <- getResponse xhr
164167 rt <- xmlHttpRequestGetResponseType xhr
165168 case rt of
166− Just XhrResponseType_Blob -> return $ fmap (XhrResponseBody_Blob . castToBlob) mr
167− Just XhrResponseType_Text -> fmap (Just . XhrResponseBody_Text) $ xmlHttpRequestGetStatusText xhr
168− Just XhrResponseType_Default -> fmap (Just . XhrResponseBody_Text) $ xmlHttpRequestGetStatusText xhr
169− Just XhrResponseType_ArrayBuffer -> case (fmap unGObject mr) of
169+ Just XhrResponseType_Blob -> return $ XhrResponseBody_Blob . castToBlob <$> mr
170+ Just XhrResponseType_Text -> Just . XhrResponseBody_Text <$> xmlHttpRequestGetStatusText xhr
171+ Just XhrResponseType_Default -> Just . XhrResponseBody_Text <$> xmlHttpRequestGetStatusText xhr
172+ Just XhrResponseType_ArrayBuffer -> case fmap unGObject mr of
170173 Nothing -> return Nothing
171− Just ptr -> fmap (Just . XhrResponseBody_ArrayBuffer) $ bsFromArrayBuffer ptr ptr
174+ Just ptr -> Just . XhrResponseBody_ArrayBuffer <$> bsFromArrayBuffer ptr ptr
172175 _ -> return Nothing
173176
src/Foreign/JavaScript/TH.hs+46−32
@@ -1,4 +1,18 @@
1−{-# LANGUAGE ForeignFunctionInterface, CPP, TemplateHaskell, TypeFamilies, TypeSynonymInstances, FlexibleInstances, MultiParamTypeClasses, StandaloneDeriving, GeneralizedNewtypeDeriving, ExistentialQuantification, FunctionalDependencies, EmptyDataDecls, FlexibleContexts, RankNTypes, UndecidableInstances #-}
1+{-# LANGUAGE CPP #-}
2+{-# LANGUAGE EmptyDataDecls #-}
3+{-# LANGUAGE ExistentialQuantification #-}
4+{-# LANGUAGE FlexibleContexts #-}
5+{-# LANGUAGE FlexibleInstances #-}
6+{-# LANGUAGE ForeignFunctionInterface #-}
7+{-# LANGUAGE FunctionalDependencies #-}
8+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
9+{-# LANGUAGE MultiParamTypeClasses #-}
10+{-# LANGUAGE RankNTypes #-}
11+{-# LANGUAGE StandaloneDeriving #-}
12+{-# LANGUAGE TemplateHaskell #-}
13+{-# LANGUAGE TypeFamilies #-}
14+{-# LANGUAGE TypeSynonymInstances #-}
15+{-# LANGUAGE UndecidableInstances #-}
216#ifdef __GHCJS__
317{-# LANGUAGE JavaScriptFFI #-}
418#endif
@@ -7,58 +21,58 @@ module Foreign.JavaScript.TH ( module Foreign.JavaScript.TH
721 ) where
822
923import Reflex.Class
10−import Reflex.Host.Class
11−import Reflex.Dom.PerformEvent.Class
1224import Reflex.Dom.Deletable.Class
25+import Reflex.Dom.PerformEvent.Class
26+import Reflex.Host.Class
1327
1428import Language.Haskell.TH
1529
1630#ifdef __GHCJS__
17−import qualified GHCJS.Marshal as JS
18−import qualified GHCJS.Marshal.Pure as JS
19−import qualified GHCJS.Foreign as JS
20−import qualified GHCJS.Foreign.Callback as JS
21−import qualified GHCJS.Types as JS
2231import qualified GHCJS.Buffer as JS
2332import GHCJS.DOM
24−import GHCJS.DOM.Types hiding (fromJSString, Text)
33+import GHCJS.DOM.Types hiding (Text, fromJSString)
2534import qualified GHCJS.DOM.Types as JS
35+import qualified GHCJS.Foreign as JS
36+import qualified GHCJS.Foreign.Callback as JS
37+import qualified GHCJS.Foreign.Callback.Internal (Callback (..))
38+import qualified GHCJS.Marshal as JS
39+import qualified GHCJS.Marshal.Pure as JS
40+import qualified GHCJS.Types as JS
2641import qualified JavaScript.Array as JS
42+import qualified JavaScript.Array.Internal (SomeJSArray (..))
2743import qualified JavaScript.Object as JS
2844import qualified JavaScript.Object.Internal (Object (..))
29−import qualified GHCJS.Foreign.Callback.Internal (Callback (..))
30−import qualified JavaScript.Array.Internal (SomeJSArray (..))
3145import qualified JavaScript.TypedArray.ArrayBuffer as JSArrayBuffer
3246
47+import Data.Hashable
3348import Data.Word
34−import Foreign.Ptr
3549import Foreign.C.Types
36−import Data.Hashable
50+import Foreign.Ptr
3751import Text.Encoding.Z
3852#else
39−import System.Glib.FFI
40−import Graphics.UI.Gtk.WebKit.WebView
53+import Foreign.Marshal
54+import Graphics.UI.Gtk.WebKit.DOM.Node
4155import Graphics.UI.Gtk.WebKit.JavaScriptCore.JSBase
4256import Graphics.UI.Gtk.WebKit.JavaScriptCore.JSObjectRef
4357import Graphics.UI.Gtk.WebKit.JavaScriptCore.JSStringRef
4458import Graphics.UI.Gtk.WebKit.JavaScriptCore.JSValueRef
4559import Graphics.UI.Gtk.WebKit.JavaScriptCore.WebFrame
46−import Graphics.UI.Gtk.WebKit.DOM.Node
47−import Foreign.Marshal
60+import Graphics.UI.Gtk.WebKit.WebView
61+import System.Glib.FFI
4862#endif
4963
64+import Control.Concurrent
5065import Control.Monad
51−import Control.Monad.Ref
66+import Control.Monad.Exception
5267import Control.Monad.Fix
5368import Control.Monad.IO.Class
54−import Control.Monad.Exception
5569import Control.Monad.Reader
70+import Control.Monad.Ref
5671import Control.Monad.State
57−import Control.Monad.Trans.Control
5872import qualified Control.Monad.State.Strict as Strict
73+import Control.Monad.Trans.Control
5974import Data.ByteString (ByteString)
6075import qualified Data.ByteString as BS
61−import Control.Concurrent
6276import Data.Coerce
6377import Data.Monoid
6478import Data.Text (Text)
@@ -213,15 +227,15 @@ instance IsJSContext JSCtx_IO where
213227 newtype JSRef JSCtx_IO = JSRef_IO { unJSRef_IO :: JS.JSVal }
214228
215229instance MonadJS JSCtx_IO IO where
216− runJS (JSFFI f) l = liftM JSRef_IO . f =<< JS.fromListIO (coerce l)
230+ runJS (JSFFI f) l = fmap JSRef_IO . f =<< JS.fromListIO (coerce l)
217231 forkJS = forkIO
218232 mkJSUndefined = return $ JSRef_IO JS.jsUndefined
219233 isJSNull (JSRef_IO r) = return $ JS.isNull r
220234 isJSUndefined (JSRef_IO r) = return $ JS.isUndefined r
221235 fromJSBool (JSRef_IO r) = return $ JS.fromJSBool r
222236 fromJSString (JSRef_IO r) = return $ JS.fromJSString $ JS.pFromJSVal r
223− fromJSArray (JSRef_IO r) = liftM coerce $ JS.toListIO $ coerce r
224− fromJSUint8Array (JSRef_IO r) = liftM (JS.toByteString 0 Nothing . JS.createFromArrayBuffer) $ JSArrayBuffer.unsafeFreeze $ JS.pFromJSVal r --TODO: Assert that this is immutable
237+ fromJSArray (JSRef_IO r) = fmap coerce $ JS.toListIO $ coerce r
238+ fromJSUint8Array (JSRef_IO r) = fmap (JS.toByteString 0 Nothing . JS.createFromArrayBuffer) $ JSArrayBuffer.unsafeFreeze $ JS.pFromJSVal r --TODO: Assert that this is immutable
225239 fromJSNumber (JSRef_IO r) = do
226240 Just n <- JS.fromJSVal r
227241 return n
@@ -241,7 +255,7 @@ instance MonadJS JSCtx_IO IO where
241255 l <- JS.toListIO $ coerce args
242256 JSRef_IO result <- f $ coerce l
243257 return result
244− liftM (JSFun . JSRef_IO) $ funWithArguments $ coerce cb
258+ fmap (JSFun . JSRef_IO) $ funWithArguments $ coerce cb
245259 freeJSFun (JSFun (JSRef_IO r)) = JS.releaseCallback $ coerce r
246260 setJSProp s (JSRef_IO v) (JSRef_IO o) = JS.setProp (JS.toJSString s) v $ coerce o
247261 getJSProp s (JSRef_IO o) = do
@@ -294,7 +308,7 @@ instance MonadJS (JSCtx_JavaScriptCore x) (WithWebView x IO) where
294308 liftIO $ forkIO $ runWithWebView a wv
295309 mkJSUndefined = do
296310 jsContext <- askJSContext
297− liftM JSRef_JavaScriptCore $ liftIO $ jsvaluemakeundefined jsContext
311+ fmap JSRef_JavaScriptCore $ liftIO $ jsvaluemakeundefined jsContext
298312 isJSNull (JSRef_JavaScriptCore r) = do
299313 jsContext <- askJSContext
300314 liftIO $ jsvalueisnull jsContext r
@@ -343,7 +357,7 @@ instance MonadJS (JSCtx_JavaScriptCore x) (WithWebView x IO) where
343357 lenDouble <- fromJSNumberRaw lenRef
344358 let len = round lenDouble
345359 liftIO $ forM [0..len-1] $ \i -> do
346− liftM JSRef_JavaScriptCore $ jsobjectgetpropertyatindex jsContext a i nullPtr --TODO: Exceptions
360+ JSRef_JavaScriptCore <$> jsobjectgetpropertyatindex jsContext a i nullPtr --TODO: Exceptions
347361 fromJSUint8Array a = do
348362 vals <- fromJSArray a
349363 doubles <- mapM fromJSNumber vals
@@ -359,7 +373,7 @@ instance MonadJS (JSCtx_JavaScriptCore x) (WithWebView x IO) where
359373 x <- peekElemOff argv n
360374 jsvalueprotect jsContext x
361375 return $ JSRef_JavaScriptCore x --TODO: Unprotect eventually
362− liftM unJSRef_JavaScriptCore $ runWithWebView (a args) wv
376+ unJSRef_JavaScriptCore <$> runWithWebView (a args) wv
363377 cbRef <- liftIO $ jsobjectmakefunctionwithcallback jsContext nullPtr cb
364378 liftIO $ jsvalueprotect jsContext cbRef
365379 return $ JSFun $ JSRef_JavaScriptCore cbRef
@@ -373,7 +387,7 @@ instance MonadJS (JSCtx_JavaScriptCore x) (WithWebView x IO) where
373387 getJSProp propName (JSRef_JavaScriptCore objRef) = do
374388 withJSStringRaw propName $ \propNameRaw -> do
375389 jsContext <- askJSContext
376− liftIO $ liftM JSRef_JavaScriptCore $ jsobjectgetproperty jsContext objRef propNameRaw nullPtr --TODO: property attribute, exceptions
390+ liftIO $ JSRef_JavaScriptCore <$> jsobjectgetproperty jsContext objRef propNameRaw nullPtr --TODO: property attribute, exceptions
377391 withJSNode = error "withJSNode is only supported in ghcjs"
378392
379393#endif
@@ -399,7 +413,7 @@ instance FromJS x Text where
399413instance FromJS x a => FromJS x (Maybe a) where
400414 fromJS x = do
401415 n <- isJSNull x
402− if n then return Nothing else liftM Just $ fromJS x
416+ if n then return Nothing else Just <$> fromJS x
403417
404418class ToJS x a where
405419 withJS :: MonadJS x m => a -> (JSRef x -> m r) -> m r
@@ -422,7 +436,7 @@ instance ToJS x a => ToJS x (JSArray a) where
422436 withJS = withJSArrayFromList . unJSArray
423437
424438instance FromJS x a => FromJS x (JSArray a) where
425− fromJS = liftM JSArray . mapM fromJS <=< fromJSArray
439+ fromJS = fmap JSArray . mapM fromJS <=< fromJSArray
426440
427441withJSArrayFromList :: (ToJS x a, MonadJS x m) => [a] -> (JSRef x -> m r) -> m r
428442withJSArrayFromList as f = go as []
@@ -444,7 +458,7 @@ instance ToJS x Int where
444458 withJS n = withJSNumber $ fromIntegral n --TODO: Check things; throw exceptions
445459
446460instance FromJS x Int where
447− fromJS = liftM round . fromJSNumber --TODO: Check things; throw exceptions
461+ fromJS = fmap round . fromJSNumber --TODO: Check things; throw exceptions
448462
449463instance ToJS x Double where
450464 withJS = withJSNumber
src/Reflex/Dom.hs+16−31
@@ -1,32 +1,17 @@
1−module Reflex.Dom ( module Reflex
2− , module Reflex.Dom.Builder.Class
3− , module Reflex.Dom.Builder.Immediate
4− , module Reflex.Dom.Builder.Static
5− , module Reflex.Dom.Class
6− , module Reflex.Dom.DynamicWriter
7− , module Reflex.Dom.Internal
8− , module Reflex.Dom.Location
9− , module Reflex.Dom.Old
10− , module Reflex.Dom.PerformEvent.Class
11− , module Reflex.Dom.PostBuild.Class
12− , module Reflex.Dom.Time
13− , module Reflex.Dom.WebSocket
14− , module Reflex.Dom.Widget
15− , module Reflex.Dom.Xhr
16− ) where
1+module Reflex.Dom (module X) where
172
18−import Reflex
19−import Reflex.Dom.Builder.Class
20−import Reflex.Dom.Builder.Immediate
21−import Reflex.Dom.Builder.Static
22−import Reflex.Dom.Class
23−import Reflex.Dom.DynamicWriter
24−import Reflex.Dom.Internal
25−import Reflex.Dom.Location
26−import Reflex.Dom.Old
27−import Reflex.Dom.PerformEvent.Class
28−import Reflex.Dom.PostBuild.Class
29−import Reflex.Dom.Time
30−import Reflex.Dom.WebSocket
31−import Reflex.Dom.Widget
32−import Reflex.Dom.Xhr
3+import Reflex as X
4+import Reflex.Dom.Builder.Class as X
5+import Reflex.Dom.Builder.Immediate as X
6+import Reflex.Dom.Builder.Static as X
7+import Reflex.Dom.Class as X
8+import Reflex.Dom.DynamicWriter as X
9+import Reflex.Dom.Internal as X
10+import Reflex.Dom.Location as X
11+import Reflex.Dom.Old as X
12+import Reflex.Dom.PerformEvent.Class as X
13+import Reflex.Dom.PostBuild.Class as X
14+import Reflex.Dom.Time as X
15+import Reflex.Dom.WebSocket as X
16+import Reflex.Dom.Widget as X
17+import Reflex.Dom.Xhr as X
src/Reflex/Dom/Builder/Class.hs+34−14
@@ -1,4 +1,19 @@
1−{-# LANGUAGE OverloadedStrings, TemplateHaskell, MultiParamTypeClasses, FunctionalDependencies, TypeFamilies, DeriveFunctor, FlexibleInstances, DataKinds, LambdaCase, PolyKinds, RankNTypes, ScopedTypeVariables, PolyKinds, FlexibleContexts, UndecidableInstances, ConstraintKinds, DefaultSignatures #-}
1+{-# LANGUAGE ConstraintKinds #-}
2+{-# LANGUAGE DataKinds #-}
3+{-# LANGUAGE DefaultSignatures #-}
4+{-# LANGUAGE DeriveFunctor #-}
5+{-# LANGUAGE FlexibleContexts #-}
6+{-# LANGUAGE FlexibleInstances #-}
7+{-# LANGUAGE FunctionalDependencies #-}
8+{-# LANGUAGE LambdaCase #-}
9+{-# LANGUAGE MultiParamTypeClasses #-}
10+{-# LANGUAGE OverloadedStrings #-}
11+{-# LANGUAGE PolyKinds #-}
12+{-# LANGUAGE RankNTypes #-}
13+{-# LANGUAGE ScopedTypeVariables #-}
14+{-# LANGUAGE TemplateHaskell #-}
15+{-# LANGUAGE TypeFamilies #-}
16+{-# LANGUAGE UndecidableInstances #-}
217module Reflex.Dom.Builder.Class
318 ( module Reflex.Dom.Builder.Class
419 , module Reflex.Dom.Builder.Class.Events
@@ -9,20 +24,20 @@ import Reflex
924import Reflex.Dom.Builder.Class.Events
1025import Reflex.Dom.Deletable.Class
1126
27+import qualified Control.Category
1228import Control.Lens hiding (element)
1329import Control.Monad.Reader
1430import Control.Monad.Trans.Control
1531import Data.Default
16−import Data.Functor.Misc
17−import Data.Map (Map)
18−import Data.Text (Text)
1932import Data.Dependent.Map (DMap)
2033import qualified Data.Dependent.Map as DMap
21−import Data.Semigroup
34+import Data.Functor.Misc
35+import Data.Map (Map)
2236import Data.Proxy
23−import GHC.Exts (Constraint)
37+import Data.Semigroup
38+import Data.Text (Text)
2439import Data.Type.Coercion
25−import qualified Control.Category
40+import GHC.Exts (Constraint)
2641
2742data Pair1 (f :: k -> *) (g :: k -> *) (a :: k) = Pair1 (f a) (g a)
2843
@@ -49,13 +64,15 @@ class (Monad m, Reflex t, Deletable t m, DomSpace (DomBuilderSpace m)) => DomBui
4964type Namespace = Text
5065
5166data TextNodeConfig t
52− = TextNodeConfig { _textNodeConfig_contents :: Text
67+ = TextNodeConfig { _textNodeConfig_initialContents :: Text
68+ , _textNodeConfig_setContents :: Event t Text
5369 }
5470
55−instance Default (TextNodeConfig t) where
71+instance (Reflex t) => Default (TextNodeConfig t) where
5672 {-# INLINABLE def #-}
5773 def = TextNodeConfig
58− { _textNodeConfig_contents = mempty
74+ { _textNodeConfig_initialContents = mempty
75+ , _textNodeConfig_setContents = never
5976 }
6077
6178data TextNode t = TextNode
@@ -96,6 +113,9 @@ instance Monoid EventFlags where
96113preventDefault :: EventFlags
97114preventDefault = mempty { _eventFlags_preventDefault = True }
98115
116+stopPropagation :: EventFlags
117+stopPropagation = mempty { _eventFlags_propagation = Propagation_Stop }
118+
99119newtype EventFilter d er en = EventFilter (DomHandler d (RawEvent d en) (EventFlags, DomHandler d () (Maybe (er en))))
100120
101121data ElementConfig er t m
@@ -135,7 +155,7 @@ instance Reflex t => Default (PlaceholderConfig above t m) where
135155
136156data Placeholder above t
137157 = Placeholder { _placeholder_insertedAbove :: Event t above
138− , _placeholder_deleted :: Event t ()
158+ , _placeholder_deletedSelf :: Event t ()
139159 }
140160
141161data InputElementConfig er t m
@@ -244,7 +264,7 @@ instance Functor1 (ElementConfig er t) where
244264instance Reflex t => Functor1 (PlaceholderConfig above t) where
245265 {-# INLINABLE fmap1 #-}
246266 fmap1 f cfg = cfg
247− { _placeholderConfig_insertAbove = fmap f $ _placeholderConfig_insertAbove cfg
267+ { _placeholderConfig_insertAbove = f <$> _placeholderConfig_insertAbove cfg
248268 }
249269
250270instance Functor1 (InputElementConfig er t) where
@@ -262,7 +282,7 @@ class HasDomEvent t target eventName where
262282instance Reflex t => HasDomEvent t (Element EventResult d t) en where
263283 type DomEventType (Element EventResult d t) en = EventResultType en
264284 {-# INLINABLE domEvent #-}
265− domEvent en e = fmap unEventResult $ Reflex.select (_element_events e) (WrapArg en)
285+ domEvent en e = unEventResult <$> Reflex.select (_element_events e) (WrapArg en)
266286
267287instance Reflex t => HasDomEvent t (InputElement EventResult d t) en where
268288 type DomEventType (InputElement EventResult d t) en = EventResultType en
@@ -307,7 +327,7 @@ instance MonadTransControlStateless (ReaderT r)
307327type RunStateless t = forall n b. Monad n => t n b -> n b
308328
309329liftWithStateless :: forall m t a. (Monad m, MonadTransControlStateless t) => (RunStateless t -> m a) -> t m a
310−liftWithStateless a = liftWith $ \run -> a $ \x -> liftM (fromStT (Proxy :: Proxy t)) $ run x
330+liftWithStateless a = liftWith $ \run -> a $ \x -> fromStT (Proxy :: Proxy t) <$> run x
311331
312332liftTextNode :: (MonadTrans f, DomBuilder t m) => TextNodeConfig t -> f m (TextNode t)
313333liftTextNode = lift . textNode
src/Reflex/Dom/Builder/Class/Events.hs+6−1
@@ -1,4 +1,9 @@
1−{-# LANGUAGE TemplateHaskell, DataKinds, GADTs, KindSignatures, TypeFamilies, PolyKinds #-}
1+{-# LANGUAGE DataKinds #-}
2+{-# LANGUAGE GADTs #-}
3+{-# LANGUAGE KindSignatures #-}
4+{-# LANGUAGE PolyKinds #-}
5+{-# LANGUAGE TemplateHaskell #-}
6+{-# LANGUAGE TypeFamilies #-}
27module Reflex.Dom.Builder.Class.Events where
38
49import Data.GADT.Compare.TH
src/Reflex/Dom/Builder/Immediate.hs+56−43
@@ -1,42 +1,58 @@
1−{-# LANGUAGE OverloadedStrings, MultiParamTypeClasses, FlexibleInstances, GeneralizedNewtypeDeriving, UndecidableInstances, FunctionalDependencies, DataKinds, TypeFamilies, RankNTypes, ConstraintKinds, TypeOperators, FlexibleContexts, LambdaCase, ScopedTypeVariables, PolyKinds, EmptyDataDecls #-}
1+{-# LANGUAGE ConstraintKinds #-}
2+{-# LANGUAGE DataKinds #-}
3+{-# LANGUAGE EmptyDataDecls #-}
4+{-# LANGUAGE FlexibleContexts #-}
5+{-# LANGUAGE FlexibleInstances #-}
6+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
7+{-# LANGUAGE LambdaCase #-}
8+{-# LANGUAGE MultiParamTypeClasses #-}
9+{-# LANGUAGE OverloadedStrings #-}
10+{-# LANGUAGE PolyKinds #-}
11+{-# LANGUAGE RankNTypes #-}
12+{-# LANGUAGE ScopedTypeVariables #-}
13+{-# LANGUAGE TypeFamilies #-}
14+{-# LANGUAGE TypeOperators #-}
15+{-# LANGUAGE UndecidableInstances #-}
216module Reflex.Dom.Builder.Immediate where
317
18+import Foreign.JavaScript.TH
419import Reflex
5−import Reflex.Host.Class
620import Reflex.Dom.Builder.Class
721import Reflex.Dom.PerformEvent.Class
822import Reflex.Dom.PostBuild.Class
9−import Foreign.JavaScript.TH
23+import Reflex.Host.Class
1024
11−import GHCJS.DOM.Document (Document, createTextNode, createElement, createElementNS, createDocumentFragment)
12−import GHCJS.DOM.Element (setAttribute, setAttributeNS, removeAttribute, removeAttributeNS, getScrollTop)
13−import qualified GHCJS.DOM.HTMLInputElement as Input
14−import qualified GHCJS.DOM.HTMLTextAreaElement as TextArea
15−import qualified GHCJS.DOM.Element as Element
16−import qualified GHCJS.DOM.Window as Window
17−import GHCJS.DOM.EventM (on, event, EventM)
18−import qualified GHCJS.DOM.Event as Event
19−import GHCJS.DOM.MouseEvent
20−import GHCJS.DOM.Node (appendChild, getParentNode, getPreviousSibling, removeChild, toNode, getOwnerDocument, insertBefore)
21−import GHCJS.DOM.Types (Node, IsNode, ToDOMString, FocusEvent, KeyboardEvent, WheelEvent, TouchEvent, IsElement, IsEvent, castToHTMLInputElement, castToHTMLTextAreaElement)
22−import qualified GHCJS.DOM.Types as DOM
23−import qualified GHCJS.DOM.EventM as DOM
24−import GHCJS.DOM.UIEvent
25+import Control.Concurrent.Chan
26+import Control.Lens hiding (element)
27+import Control.Monad.Exception
2528import Control.Monad.Reader
29+import Control.Monad.Ref
2630import Control.Monad.Trans.Control
27−import Control.Lens hiding (element)
28−import Control.Concurrent.Chan
29−import Data.Dependent.Sum
30−import Data.Functor.Misc
3131import Data.Bitraversable
32−import Data.Text (Text)
33−import Data.Maybe
34−import Data.IORef
35−import Control.Monad.Ref
36−import Control.Monad.Exception
32+import Data.Default
3733import Data.Dependent.Map (DMap)
3834import qualified Data.Dependent.Map as DMap
39−import Data.Default
35+import Data.Dependent.Sum
36+import Data.Functor.Misc
37+import Data.IORef
38+import Data.Maybe
39+import Data.Text (Text)
40+import GHCJS.DOM.Document (Document, createDocumentFragment, createElement, createElementNS, createTextNode)
41+import GHCJS.DOM.Element (getScrollTop, removeAttribute, removeAttributeNS, setAttribute, setAttributeNS)
42+import qualified GHCJS.DOM.Element as Element
43+import qualified GHCJS.DOM.Event as Event
44+import GHCJS.DOM.EventM (EventM, event, on)
45+import qualified GHCJS.DOM.EventM as DOM
46+import qualified GHCJS.DOM.HTMLInputElement as Input
47+import qualified GHCJS.DOM.HTMLTextAreaElement as TextArea
48+import GHCJS.DOM.MouseEvent
49+import GHCJS.DOM.Node (appendChild, getOwnerDocument, getParentNode, getPreviousSibling, insertBefore,
50+ removeChild, toNode, setNodeValue)
51+import GHCJS.DOM.Types (FocusEvent, IsElement, IsEvent, IsNode, KeyboardEvent, Node, ToDOMString, TouchEvent,
52+ WheelEvent, castToHTMLInputElement, castToHTMLTextAreaElement)
53+import qualified GHCJS.DOM.Types as DOM
54+import GHCJS.DOM.UIEvent
55+import qualified GHCJS.DOM.Window as Window
4056
4157import Debug.Trace hiding (traceEvent)
4258
@@ -62,7 +78,7 @@ instance MonadTrans (ImmediateDomBuilderT t) where
6278
6379{-# INLINABLE runImmediateDomBuilderT #-}
6480runImmediateDomBuilderT :: ImmediateDomBuilderT t m a -> ImmediateDomBuilderEnv t -> m a
65−runImmediateDomBuilderT (ImmediateDomBuilderT a) env = runReaderT a env
81+runImmediateDomBuilderT (ImmediateDomBuilderT a) = runReaderT a
6682
6783{-# INLINABLE askDocument #-}
6884askDocument :: Monad m => ImmediateDomBuilderT t m Document
@@ -186,8 +202,9 @@ instance DomSpace GhcjsDomSpace where
186202instance SupportsImmediateDomBuilder t m => DomBuilder t (ImmediateDomBuilderT t m) where
187203 type DomBuilderSpace (ImmediateDomBuilderT t m) = GhcjsDomSpace
188204 {-# INLINABLE textNode #-}
189− textNode (TextNodeConfig contents) = do
190− _ <- textNodeInternal contents
205+ textNode (TextNodeConfig initialContents eSetContents) = do
206+ n <- textNodeInternal initialContents
207+ lift $ performEvent_ $ ffor eSetContents $ \t -> setNodeValue n (Just t)
191208 return TextNode
192209 {-# INLINABLE element #-}
193210 element elementTag cfg child = fst <$> makeElement elementTag cfg child
@@ -206,8 +223,7 @@ instance SupportsImmediateDomBuilder t m => DomBuilder t (ImmediateDomBuilderT t
206223 let domInputElement = castToHTMLInputElement domElement
207224 Just v0 <- Input.getValue domInputElement
208225 let getMyValue = fromMaybe "" <$> Input.getValue domInputElement
209− valueChangedByUI <- performEvent $ ffor (Reflex.select (_element_events e) (WrapArg Input)) $ \_ ->
210− getMyValue
226+ valueChangedByUI <- performEvent $ getMyValue <$ Reflex.select (_element_events e) (WrapArg Input)
211227 valueChangedBySetValue <- performEvent $ ffor (cfg ^. inputElementConfig_setValue) $ \v' -> do
212228 Input.setValue domInputElement $ Just v'
213229 getMyValue -- We get the value after setting it in case the browser has mucked with it somehow
@@ -240,8 +256,7 @@ instance SupportsImmediateDomBuilder t m => DomBuilder t (ImmediateDomBuilderT t
240256 let domTextAreaElement = castToHTMLTextAreaElement domElement
241257 Just v0 <- TextArea.getValue domTextAreaElement
242258 let getMyValue = fromMaybe "" <$> TextArea.getValue domTextAreaElement
243− valueChangedByUI <- performEvent $ ffor (Reflex.select (_element_events e) (WrapArg Input)) $ \_ ->
244− getMyValue
259+ valueChangedByUI <- performEvent $ getMyValue <$ Reflex.select (_element_events e) (WrapArg Input)
245260 valueChangedBySetValue <- performEvent $ ffor (cfg ^. textAreaElementConfig_setValue) $ \v' -> do
246261 TextArea.setValue domTextAreaElement $ Just v'
247262 getMyValue -- We get the value after setting it in case the browser has mucked with it somehow
@@ -314,10 +329,9 @@ instance (Monad m, MonadRef m, Ref m ~ Ref IO, MonadReflexCreateTrigger t m) =>
314329 {-# INLINABLE newEventWithLazyTriggerWithOnComplete #-}
315330 newEventWithLazyTriggerWithOnComplete f = do
316331 events <- askEvents
317− eResult <- lift $ newEventWithTrigger $ \t -> f $ \a cb -> do
332+ lift $ newEventWithTrigger $ \t -> f $ \a cb -> do
318333 reResultTrigger <- newIORef $ Just t
319334 writeChan events [TriggerRef reResultTrigger :=> TriggerInvocation a cb]
320− return eResult
321335
322336instance HasWebView m => HasWebView (ImmediateDomBuilderT t m) where
323337 type WebViewPhantom (ImmediateDomBuilderT t m) = WebViewPhantom m
@@ -392,7 +406,7 @@ type family EventType en where
392406
393407{-# INLINABLE defaultDomEventHandler #-}
394408defaultDomEventHandler :: IsElement e => e -> EventName en -> EventM e (EventType en) (Maybe (EventResult en))
395−defaultDomEventHandler e evt = liftM (Just . EventResult) $ case evt of
409+defaultDomEventHandler e evt = fmap (Just . EventResult) $ case evt of
396410 Click -> return ()
397411 Dblclick -> return ()
398412 Keypress -> getKeyEvent
@@ -444,7 +458,7 @@ defaultDomEventHandler e evt = liftM (Just . EventResult) $ case evt of
444458
445459{-# INLINABLE defaultDomWindowEventHandler #-}
446460defaultDomWindowEventHandler :: DOM.Window -> EventName en -> EventM DOM.Window (EventType en) (Maybe (EventResult en))
447−defaultDomWindowEventHandler w evt = liftM (Just . EventResult) $ case evt of
461+defaultDomWindowEventHandler w evt = fmap (Just . EventResult) $ case evt of
448462 Click -> return ()
449463 Dblclick -> return ()
450464 Keypress -> getKeyEvent
@@ -651,8 +665,8 @@ windowOnEventName en e = case en of
651665 Touchcancel -> on e Window.touchCancel
652666
653667{-# INLINABLE wrapDomEvent #-}
654−wrapDomEvent :: (MonadIO m, TriggerEvent t m) => e -> (e -> EventM e event () -> IO (IO ())) -> EventM e event a -> m (Event t a)
655−wrapDomEvent el elementOnevent getValue = wrapDomEventMaybe el elementOnevent $ liftM Just getValue
668+wrapDomEvent :: TriggerEvent t m => e -> (e -> EventM e event () -> IO (IO ())) -> EventM e event a -> m (Event t a)
669+wrapDomEvent el elementOnevent getValue = wrapDomEventMaybe el elementOnevent $ fmap Just getValue
656670
657671{-# INLINABLE subscribeDomEvent #-}
658672subscribeDomEvent :: (EventM e event () -> IO (IO ()))
@@ -668,16 +682,15 @@ subscribeDomEvent elementOnevent getValue eventChan et = elementOnevent $ do
668682 writeChan eventChan [TriggerRef etr :=> TriggerInvocation v (return ())]
669683
670684{-# INLINABLE wrapDomEventMaybe #-}
671−wrapDomEventMaybe :: (MonadIO m, TriggerEvent t m)
685+wrapDomEventMaybe :: TriggerEvent t m
672686 => e
673687 -> (e -> EventM e event () -> IO (IO ()))
674688 -> EventM e event (Maybe a)
675689 -> m (Event t a)
676690wrapDomEventMaybe el elementOnevent getValue = do
677− e <- newEventWithLazyTriggerWithOnComplete $ \trigger -> elementOnevent el $ do
691+ newEventWithLazyTriggerWithOnComplete $ \trigger -> elementOnevent el $ do
678692 mv <- getValue
679693 forM_ mv $ \v -> liftIO $ trigger v $ return ()
680− return e
681694
682695{-# INLINABLE wrapDomEventsMaybe #-}
683696wrapDomEventsMaybe :: (MonadIO m, MonadReflexCreateTrigger t m)
src/Reflex/Dom/Builder/Static.hs+46−23
@@ -1,31 +1,42 @@
1−{-# LANGUAGE OverloadedStrings, MultiParamTypeClasses, FlexibleInstances, GeneralizedNewtypeDeriving, UndecidableInstances, FunctionalDependencies, DataKinds, TypeFamilies, RankNTypes, ConstraintKinds, TypeOperators, FlexibleContexts, LambdaCase, ScopedTypeVariables, PolyKinds, EmptyDataDecls #-}
1+{-# LANGUAGE ConstraintKinds #-}
2+{-# LANGUAGE DataKinds #-}
3+{-# LANGUAGE EmptyDataDecls #-}
4+{-# LANGUAGE FlexibleContexts #-}
5+{-# LANGUAGE FlexibleInstances #-}
6+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
7+{-# LANGUAGE LambdaCase #-}
8+{-# LANGUAGE MultiParamTypeClasses #-}
9+{-# LANGUAGE OverloadedStrings #-}
10+{-# LANGUAGE PolyKinds #-}
11+{-# LANGUAGE RankNTypes #-}
12+{-# LANGUAGE ScopedTypeVariables #-}
13+{-# LANGUAGE TypeFamilies #-}
14+{-# LANGUAGE TypeOperators #-}
15+{-# LANGUAGE UndecidableInstances #-}
216module Reflex.Dom.Builder.Static where
317
18+import Control.Monad.Identity
19+import Control.Monad.Ref
20+import Data.Dependent.Sum (DSum (..))
421import Reflex
5−import Reflex.Host.Class
622import Reflex.Dom.Builder.Class
723import Reflex.Dom.PerformEvent.Base
824import Reflex.Dom.PerformEvent.Class
925import Reflex.Dom.PostBuild.Class
1026import Reflex.Dom.Widget.Basic (applyMap)
11−import Control.Monad.Ref
12−import Control.Monad.Identity
13−import Data.Dependent.Sum (DSum (..))
27+import Reflex.Host.Class
1428
15−import Data.Monoid
16−import Data.Text (Text)
17−import qualified Data.Map as Map
18−import Data.Map (Map)
29+import Blaze.ByteString.Builder.Html.Utf8
1930import Control.Lens hiding (element)
20−import qualified Data.ByteString.Lazy as BL
21−import qualified Data.ByteString.Char8 as B8
22−import Data.ByteString (ByteString)
31+import Control.Monad.Exception
2332import Control.Monad.State.Strict
2433import Control.Monad.Trans.Control
34+import Data.ByteString (ByteString)
2535import Data.ByteString.Builder (toLazyByteString)
26−import Blaze.ByteString.Builder.Html.Utf8
36+import qualified Data.ByteString.Lazy as BL
37+import qualified Data.Map as Map
38+import Data.Monoid
2739import Data.Text.Encoding
28−import Control.Monad.Exception
2940
3041
3142newtype StaticDomBuilderT t m a = StaticDomBuilderT
@@ -91,35 +102,47 @@ instance (Monad m, Ref m ~ Ref IO, Reflex t) => TriggerEvent t (StaticDomBuilder
91102type SupportsStaticDomBuilder t m = (Reflex t, MonadIO m, MonadHold t m, MonadFix m, PerformEvent t m, Performable m ~ m, MonadReflexCreateTrigger t m, Deletable t m, MonadRef m, Ref m ~ Ref IO)
92103
93104data StaticDomSpace
105+
106+-- | Static documents never produce any events, so this type has no inhabitants
107+data StaticDomEvent (a :: k)
108+
109+-- | Static documents don't process events, so all handlers are equivalent
110+data StaticDomHandler (a :: k) (b :: k) = StaticDomHandler
111+
94112instance DomSpace StaticDomSpace where
95− type RawElement StaticDomSpace = ByteString
113+ type RawElement StaticDomSpace = ByteString
114+ type RawEvent StaticDomSpace = StaticDomEvent
115+ type DomHandler StaticDomSpace = StaticDomHandler
116+ type DomHandler1 StaticDomSpace = StaticDomHandler
117+ defaultEventHandler _ = StaticDomHandler
96118
97119instance SupportsStaticDomBuilder t m => DomBuilder t (StaticDomBuilderT t m) where
98120 type DomBuilderSpace (StaticDomBuilderT t m) = StaticDomSpace
99121 {-# INLINABLE textNode #-}
100− textNode (TextNodeConfig contents) = StaticDomBuilderT $ do
101− modify $ (:) $ constant $ BL.toStrict $ toLazyByteString $ fromHtmlEscapedText contents
122+ textNode (TextNodeConfig initialContents setContents) = StaticDomBuilderT $ do
123+ let escape = BL.toStrict . toLazyByteString . fromHtmlEscapedText
124+ modify . (:) <=< hold (escape initialContents) $ fmap escape setContents
102125 return TextNode
103126
104127 {-# INLINABLE element #-}
105128 element elementTag cfg child = do
106− let toAttr (_mns, k) v = encodeUtf8 k <> "=\"" <> (BL.toStrict $ toLazyByteString $ fromHtmlEscapedText v) <> "\""
129+ let toAttr (_mns, k) v = encodeUtf8 k <> "=\"" <> BL.toStrict (toLazyByteString $ fromHtmlEscapedText v) <> "\""
107130 es <- newFanEventWithTrigger $ \_ _ -> return (return ())
108131 StaticDomBuilderT $ do
109132 (result, innerHtml) <- lift $ runStaticDomBuilderT child
110133 attrs0 <- foldDyn applyMap (cfg ^. initialAttributes) (cfg ^. modifyAttributes)
111134 let attrs1 = ffor (current attrs0) $ mconcat . fmap (\(k, v) -> " " <> toAttr k v) . Map.toList
112− let tag = encodeUtf8 elementTag
113− let open = mconcat [constant ("<" <> tag <> " "), attrs1, constant ">"]
114− let close = constant $ "</" <> tag <> ">" -- TODO handle elements without closing tags
115− modify $ (:) $ mconcat $ [open, innerHtml, close]
135+ let tagBS = encodeUtf8 elementTag
136+ let open = mconcat [constant ("<" <> tagBS <> " "), attrs1, constant ">"]
137+ let close = constant $ "</" <> tagBS <> ">" -- TODO handle elements without closing tags
138+ modify $ (:) $ mconcat [open, innerHtml, close]
116139 return (Element es (error "Static.element RawElement was used"), result)
117140
118141 {-# INLINABLE placeholder #-}
119142 placeholder (PlaceholderConfig toInsertAbove _delete) = StaticDomBuilderT $ do
120143 result <- lift $ performEvent (fmap runStaticDomBuilderT toInsertAbove)
121144 acc <- foldDyn (:) [] (fmap snd result)
122− modify $ (:) $ join $ fmap (mconcat . reverse) $ current acc
145+ modify $ (:) $ join $ mconcat . reverse <$> current acc
123146 return $ Placeholder (fmap fst result) never
124147
125148 {-# INLINABLE inputElement #-}
src/Reflex/Dom/Class.hs+11−6
@@ -1,25 +1,30 @@
1+{-# LANGUAGE MultiParamTypeClasses #-}
12module Reflex.Dom.Class ( module Reflex.Dom.Class
23 , module Foreign.JavaScript.TH
4+ , module Web.KeyCode
35 ) where
46
7+import Data.Map (Map)
8+import qualified Data.Map as Map
59import Reflex.Class
6−import Reflex.Dom.PostBuild.Class
7−import Reflex.Dom.PerformEvent.Class
8−
9−import Prelude hiding (mapM, mapM_, sequence, concat)
10+import Web.KeyCode
1011
1112import Foreign.JavaScript.TH
13+import Reflex.Dom.PerformEvent.Class
14+import Reflex.Dom.PostBuild.Class
1215
13−import Data.Map (Map)
14−import qualified Data.Map as Map
16+import Prelude hiding (concat, mapM, mapM_, sequence)
1517
1618-- | Alias for Data.Map.singleton
1719(=:) :: k -> a -> Map k a
1820(=:) = Map.singleton
21+infixr 7 =: -- Ought to bind tighter than <>, which is infixr 6
1922
23+{-# DEPRECATED keycodeEnter "Instead of `x == keycodeEnter`, use `keyCodeLookup x == Enter`" #-}
2024keycodeEnter :: Int
2125keycodeEnter = 13
2226
27+{-# DEPRECATED keycodeEscape "Instead of `x == keycodeEscape`, use `keyCodeLookup x == Escape`" #-}
2328keycodeEscape :: Int
2429keycodeEscape = 27
2530
src/Reflex/Dom/Deletable/Class.hs+4−1
@@ -1,4 +1,7 @@
1−{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies, FlexibleInstances, UndecidableInstances #-}
1+{-# LANGUAGE FlexibleInstances #-}
2+{-# LANGUAGE FunctionalDependencies #-}
3+{-# LANGUAGE MultiParamTypeClasses #-}
4+{-# LANGUAGE UndecidableInstances #-}
25module Reflex.Dom.Deletable.Class where
36
47import Reflex
src/Reflex/Dom/DynamicWriter.hs+22−12
@@ -1,27 +1,37 @@
1−{-# LANGUAGE CPP, FlexibleInstances, MultiParamTypeClasses, TypeFamilies, GeneralizedNewtypeDeriving, UndecidableInstances, StandaloneDeriving, FunctionalDependencies, RecursiveDo, ScopedTypeVariables, LambdaCase, GADTs #-}
1+{-# LANGUAGE CPP #-}
2+{-# LANGUAGE FlexibleInstances #-}
3+{-# LANGUAGE FunctionalDependencies #-}
4+{-# LANGUAGE GADTs #-}
5+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
6+{-# LANGUAGE LambdaCase #-}
7+{-# LANGUAGE MultiParamTypeClasses #-}
8+{-# LANGUAGE RecursiveDo #-}
9+{-# LANGUAGE ScopedTypeVariables #-}
10+{-# LANGUAGE TypeFamilies #-}
11+{-# LANGUAGE UndecidableInstances #-}
212module Reflex.Dom.DynamicWriter where
313
414import Reflex
5−import Reflex.Host.Class
6−import Reflex.Dom.Class
715import Reflex.Dom.Builder.Class
16+import Reflex.Dom.Class
817import Reflex.Dom.PerformEvent.Class
918import Reflex.Dom.PostBuild.Class
19+import Reflex.Host.Class
1020
1121import Control.Lens hiding (element)
22+import Control.Monad.Exception
1223import Control.Monad.IO.Class
13−import Control.Monad.State.Strict
1424import Control.Monad.Reader
1525import Control.Monad.Ref
16−import Control.Monad.Exception
17−import Data.Map (Map)
18−import qualified Data.Map as Map
26+import Control.Monad.State.Strict
1927import Data.Dependent.Map (DMap)
20−import Data.List.NonEmpty (NonEmpty, nonEmpty)
28+import Data.Foldable
2129import Data.Functor.Compose
2230import Data.Functor.Misc
31+import Data.List.NonEmpty (NonEmpty, nonEmpty)
32+import Data.Map (Map)
33+import qualified Data.Map as Map
2334import Data.Semigroup
24−import Data.Foldable
2535import Data.Traversable
2636
2737instance MonadTrans (DynamicWriterT t w) where
@@ -66,7 +76,7 @@ mapIncrementalMapValues :: Reflex t => (v -> v') -> Incremental t PatchMap (Map
6676mapIncrementalMapValues f = mapIncrementalMapValuesWithKey $ const f
6777
6878unsafeMapIncremental :: (Reflex t, Patch p, Patch p') => (a -> a') -> (p a -> p' a') -> Incremental t p a -> Incremental t p' a'
69−unsafeMapIncremental f g a = unsafeBuildIncremental (fmap f $ sample $ currentIncremental a) $ fmap g $ updatedIncremental a
79+unsafeMapIncremental f g a = unsafeBuildIncremental (fmap f $ sample $ currentIncremental a) $ g <$> updatedIncremental a
7080
7181incrementalExtractFunctorDMap :: Reflex t => Incremental t PatchMap (Map k (f v)) -> Incremental t PatchDMap (DMap (Const2 k v) f)
7282incrementalExtractFunctorDMap = unsafeMapIncremental mapWithFunctorToDMap $ \(PatchMap m) -> PatchDMap $ mapWithFunctorToDMap $ fmap Compose m
@@ -174,7 +184,7 @@ instance (DomBuilder t m, Monoid w, MonadHold t m, MonadFix m) => DomBuilder t (
174184 return (el, a)
175185 placeholder cfg = do
176186 let cfg' = cfg
177− { _placeholderConfig_insertAbove = fmap runDynamicWriterTInternal $ _placeholderConfig_insertAbove cfg
187+ { _placeholderConfig_insertAbove = runDynamicWriterTInternal <$> _placeholderConfig_insertAbove cfg
178188 }
179189 let manageChildren :: Event t (NonEmpty (Replaceable t (Dynamic t w))) -- ^ Add nodes on the right; these are in reverse order
180190 -> Event t () -- ^ No more nodes will be added after this event fires
@@ -193,7 +203,7 @@ instance (DomBuilder t m, Monoid w, MonadHold t m, MonadFix m) => DomBuilder t (
193203 p <- DynamicWriterT $ do
194204 modify (children:)
195205 lift $ placeholder cfg'
196− let result = fmap fst $ _placeholder_insertedAbove p
206+ let result = fst <$> _placeholder_insertedAbove p
197207 childOutputs = fmapMaybe (nonEmpty . snd) $ _placeholder_insertedAbove p
198208 return $ p
199209 { _placeholder_insertedAbove = result
src/Reflex/Dom/Internal.hs+33−62
@@ -1,7 +1,19 @@
1−{-# LANGUAGE TypeFamilies, FlexibleContexts, FlexibleInstances, MultiParamTypeClasses, RankNTypes, GADTs, ScopedTypeVariables, FunctionalDependencies, RecursiveDo, UndecidableInstances, GeneralizedNewtypeDeriving, StandaloneDeriving, EmptyDataDecls, NoMonomorphismRestriction, TypeOperators, DeriveDataTypeable, PackageImports, TemplateHaskell, LambdaCase, ConstraintKinds, CPP #-}
1+{-# LANGUAGE ConstraintKinds #-}
2+{-# LANGUAGE FlexibleContexts #-}
3+{-# LANGUAGE FlexibleInstances #-}
4+{-# LANGUAGE GADTs #-}
5+{-# LANGUAGE LambdaCase #-}
6+{-# LANGUAGE MultiParamTypeClasses #-}
7+{-# LANGUAGE NoMonomorphismRestriction #-}
8+{-# LANGUAGE RankNTypes #-}
9+{-# LANGUAGE RecursiveDo #-}
10+{-# LANGUAGE ScopedTypeVariables #-}
11+{-# LANGUAGE TypeFamilies #-}
12+{-# LANGUAGE TypeOperators #-}
13+{-# LANGUAGE UndecidableInstances #-}
214module Reflex.Dom.Internal where
315
4−import Prelude hiding (mapM, mapM_, concat, sequence, sequence_)
16+import Prelude hiding (concat, mapM, mapM_, sequence, sequence_)
517
618import Reflex.Dom.Builder.Immediate
719import Reflex.Dom.Class
@@ -9,32 +21,30 @@ import Reflex.Dom.Internal.Foreign
921import Reflex.Dom.PerformEvent.Base
1022import Reflex.Dom.PostBuild.Class
1123import Reflex.Host.Class
12−import Reflex.Spider (Spider, SpiderHost, runSpiderHost, Global)
24+import Reflex.Spider (Global, Spider, SpiderHost, runSpiderHost)
1325
14−import GHCJS.DOM hiding (runWebGUI)
15−import qualified GHCJS.DOM.Types as DOM
16−import GHCJS.DOM.Node
17−import GHCJS.DOM.Element
18−import GHCJS.DOM.Document
26+import Control.Concurrent
1927import Control.Lens
20−import Control.Monad hiding (mapM, mapM_, forM, forM_, sequence, sequence_)
21−import Control.Monad.Reader hiding (mapM, mapM_, forM, forM_, sequence, sequence_)
28+import Control.Monad
29+import Control.Monad.Reader hiding (forM, forM_, mapM, mapM_, sequence, sequence_)
2230import Control.Monad.Ref
23−import Control.Concurrent
2431import Data.ByteString (ByteString)
2532import Data.Dependent.Sum (DSum (..))
26−import Data.Foldable
27−import qualified Data.Text as T
28−import Data.Text.Encoding
29−import Data.Monoid ((<>))
3033import Data.IORef
31−import Control.Monad
3234import Data.Maybe
35+import Data.Monoid ((<>))
36+import qualified Data.Text as T
37+import Data.Text.Encoding
38+import GHCJS.DOM hiding (runWebGUI)
39+import GHCJS.DOM.Document
40+import GHCJS.DOM.Element
41+import GHCJS.DOM.Node
42+import qualified GHCJS.DOM.Types as DOM
3343
3444{-# INLINABLE mainWidget #-}
3545mainWidget :: (forall x. Widget x ()) -> IO ()
3646mainWidget w = runWebGUI $ \webView -> withWebViewSingleton webView $ \webViewSing -> do
37− Just doc <- liftM (fmap DOM.castToHTMLDocument) $ webViewGetDomDocument webView
47+ Just doc <- fmap DOM.castToHTMLDocument <$> webViewGetDomDocument webView
3848 Just body <- getBody doc
3949 attachWidget body webViewSing w
4050
@@ -42,8 +52,8 @@ mainWidget w = runWebGUI $ \webView -> withWebViewSingleton webView $ \webViewSi
4252{-# INLINABLE mainWidgetWithHead #-}
4353mainWidgetWithHead :: (forall x. Widget x ()) -> (forall x. Widget x ()) -> IO ()
4454mainWidgetWithHead h b = runWebGUI $ \webView -> withWebViewSingleton webView $ \webViewSing -> do
45− Just doc <- liftM (fmap DOM.castToHTMLDocument) $ webViewGetDomDocument webView
46− Just headElement <- liftM (fmap DOM.castToHTMLElement) $ getHead doc
55+ Just doc <- fmap DOM.castToHTMLDocument <$> webViewGetDomDocument webView
56+ Just headElement <- fmap DOM.castToHTMLElement <$> getHead doc
4757 attachWidget headElement webViewSing h
4858 Just body <- getBody doc
4959 attachWidget body webViewSing b
@@ -51,19 +61,12 @@ mainWidgetWithHead h b = runWebGUI $ \webView -> withWebViewSingleton webView $
5161{-# INLINABLE mainWidgetWithCss #-}
5262mainWidgetWithCss :: ByteString -> (forall x. Widget x ()) -> IO ()
5363mainWidgetWithCss css w = runWebGUI $ \webView -> withWebViewSingleton webView $ \webViewSing -> do
54− Just doc <- liftM (fmap DOM.castToHTMLDocument) $ webViewGetDomDocument webView
55− Just headElement <- liftM (fmap DOM.castToHTMLElement) $ getHead doc
64+ Just doc <- fmap DOM.castToHTMLDocument <$> webViewGetDomDocument webView
65+ Just headElement <- fmap DOM.castToHTMLElement <$> getHead doc
5666 setInnerHTML headElement . Just $ "<style>" <> T.unpack (decodeUtf8 css) <> "</style>" --TODO: Fix this
5767 Just body <- getBody doc
5868 attachWidget body webViewSing w
5969
60−{-# INLINABLE mainWidgetFragment #-}
61−mainWidgetFragment :: (forall x. Widget x ()) -> IO ()
62−mainWidgetFragment w = runWebGUI $ \webView -> withWebViewSingleton webView $ \webViewSing -> do
63− Just doc <- liftM (fmap DOM.castToHTMLDocument) $ webViewGetDomDocument webView
64− Just body <- getBody doc
65− attachWidgetFragment body webViewSing w
66−
6770type Widget x = PostBuildT Spider (ImmediateDomBuilderT Spider (WithWebView x (PerformEventT Spider (SpiderHost Global)))) --TODO: Make this more abstract --TODO: Put the WithWebView underneath PerformEventT - I think this would perform better
6871
6972{-# INLINABLE attachWidget #-}
@@ -73,38 +76,6 @@ attachWidget rootElement wv w = fst <$> attachWidget' rootElement wv w
7376{-# INLINABLE attachWidget' #-}
7477attachWidget' :: DOM.IsElement e => e -> WebViewSingleton x -> Widget x a -> IO (a, FireCommand Spider (SpiderHost Global))
7578attachWidget' rootElement wv w = do
76− Just doc <- getOwnerDocument rootElement
77− events <- newChan
78− setInnerHTML rootElement $ Just (""::String)
79− (result, fc@(FireCommand fire)) <- runSpiderHost $ do
80− (postBuild, postBuildTriggerRef) <- newEventWithTriggerRef
81− let builderEnv = ImmediateDomBuilderEnv
82− { _immediateDomBuilderEnv_document = doc
83− , _immediateDomBuilderEnv_parent = toNode rootElement
84− , _immediateDomBuilderEnv_events = events
85− }
86− results@(_, FireCommand fire) <- hostPerformEventT $ runWithWebView (runImmediateDomBuilderT (runPostBuildT w postBuild) builderEnv) wv
87− mPostBuildTrigger <- readRef postBuildTriggerRef
88− forM_ mPostBuildTrigger $ \postBuildTrigger -> fire [postBuildTrigger :=> Identity ()] $ return ()
89− return results
90− void $ forkIO $ forever $ do
91− ers <- readChan events
92− _ <- postGUISync $ runSpiderHost $ do
93− mes <- liftIO $ forM ers $ \(TriggerRef er :=> TriggerInvocation a _) -> do
94− me <- readIORef er
95− return $ fmap (\e -> e :=> Identity a) me
96− _ <- fire (catMaybes mes) $ return ()
97− liftIO $ forM_ ers $ \(_ :=> TriggerInvocation _ cb) -> cb
98− return ()
99− return (result, fc)
100−
101−{-# INLINABLE attachWidgetFragment #-}
102−attachWidgetFragment :: DOM.IsElement e => e -> WebViewSingleton x -> Widget x a -> IO a
103−attachWidgetFragment rootElement wv w = fst <$> attachWidgetFragment' rootElement wv w
104−
105−{-# INLINABLE attachWidgetFragment' #-}
106−attachWidgetFragment' :: DOM.IsElement e => e -> WebViewSingleton x -> Widget x a -> IO (a, FireCommand Spider (SpiderHost Global))
107−attachWidgetFragment' rootElement wv w = do
10879 Just doc <- getOwnerDocument rootElement
10980 Just df <- createDocumentFragment doc
11081 events <- newChan
@@ -129,7 +100,7 @@ attachWidgetFragment' rootElement wv w = do
129100 liftIO $ forM_ ers $ \(_ :=> TriggerInvocation _ cb) -> cb
130101 return ()
131102 setInnerHTML rootElement $ Just (""::String)
132− appendChild rootElement $ Just df
103+ _ <- appendChild rootElement $ Just df
133104 return (result, fc)
134105
135106data AppInput t = AppInput
@@ -142,7 +113,7 @@ data AppOutput t = AppOutput --TODO: Add quit event
142113
143114runApp' :: (t ~ Spider) => (forall x. AppInput t -> Widget x (AppOutput t)) -> IO ()
144115runApp' app = runWebGUI $ \webView -> withWebViewSingleton webView $ \webViewSing -> do
145− Just doc <- liftM (fmap DOM.castToHTMLDocument) $ webViewGetDomDocument webView
116+ Just doc <- fmap DOM.castToHTMLDocument <$> webViewGetDomDocument webView
146117 Just body <- getBody doc
147118 Just win <- getDefaultView doc
148119 rec o <- attachWidget body webViewSing $ do
src/Reflex/Dom/Location.hs+1−1
@@ -1,8 +1,8 @@
11module Reflex.Dom.Location (getLocationHost, getLocationProtocol) where
22
3+import Data.Text (Text)
34import Reflex.Dom.Class
45import qualified Reflex.Dom.Internal.Foreign as F
5−import Data.Text (Text)
66
77import Control.Monad.IO.Class
88
src/Reflex/Dom/Old.hs+3−1
@@ -1,4 +1,6 @@
1−{-# LANGUAGE ConstraintKinds, TypeFamilies, FlexibleContexts #-}
1+{-# LANGUAGE ConstraintKinds #-}
2+{-# LANGUAGE FlexibleContexts #-}
3+{-# LANGUAGE TypeFamilies #-}
24module Reflex.Dom.Old where
35
46import Control.Monad.Exception
src/Reflex/Dom/PerformEvent/Base.hs+28−16
@@ -1,31 +1,41 @@
1−{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies, GeneralizedNewtypeDeriving, FlexibleInstances, TypeFamilies, TypeOperators, RankNTypes, ScopedTypeVariables, StandaloneDeriving, FlexibleContexts, RecursiveDo, UndecidableInstances #-}
1+{-# LANGUAGE FlexibleContexts #-}
2+{-# LANGUAGE FlexibleInstances #-}
3+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
4+{-# LANGUAGE MultiParamTypeClasses #-}
5+{-# LANGUAGE RankNTypes #-}
6+{-# LANGUAGE RecursiveDo #-}
7+{-# LANGUAGE ScopedTypeVariables #-}
8+{-# LANGUAGE StandaloneDeriving #-}
9+{-# LANGUAGE TypeFamilies #-}
10+{-# LANGUAGE TypeOperators #-}
11+{-# LANGUAGE UndecidableInstances #-}
212module Reflex.Dom.PerformEvent.Base where
313
14+import Foreign.JavaScript.TH
415import Reflex
5−import Reflex.Host.Class
6−import Reflex.Dom.PerformEvent.Class
716import Reflex.Dom.Deletable.Class
8−import Foreign.JavaScript.TH
17+import Reflex.Dom.PerformEvent.Class
18+import Reflex.Host.Class
919
20+import Control.Lens
21+import Control.Monad.Exception
1022import Control.Monad.Identity
1123import Control.Monad.Ref
1224import Control.Monad.State.Strict
13−import Control.Monad.Exception
14−import Data.Dependent.Sum
15−import Data.Maybe
16−import Data.Functor.Misc
25+import Data.Align
1726import Data.Dependent.Map (DMap)
1827import qualified Data.Dependent.Map as DMap
19−import Data.Word
28+import Data.Dependent.Sum
2029import Data.Functor.Compose
30+import Data.Functor.Misc
31+import Data.Maybe
2132import Data.Semigroup
2233import Data.These
23−import Data.Align
24−import Control.Lens
34+import Data.Word
2535
2636newtype EventTriggerRef t m a = EventTriggerRef { unEventTriggerRef :: Ref m (Maybe (EventTrigger t a)) }
2737
28−newtype FireCommand t m = FireCommand { runFireCommand :: forall a. [DSum (EventTrigger t) Identity] -> (ReadPhase m a) -> m [a] } --TODO: The handling of this ReadPhase seems wrong, or at least inelegant; how do we actually make the decision about what order frames run in?
38+newtype FireCommand t m = FireCommand { runFireCommand :: forall a. [DSum (EventTrigger t) Identity] -> ReadPhase m a -> m [a] } --TODO: The handling of this ReadPhase seems wrong, or at least inelegant; how do we actually make the decision about what order frames run in?
2939
3040newtype PerformEventT t m a = PerformEventT { unPerformEventT :: StateT [Event t (These (PerformEventT t m [DSum (EventTriggerRef t m) Identity]) ())] (HostFrame t) a }
3141
@@ -55,11 +65,13 @@ instance (ReflexHost t, Ref m ~ Ref IO, MonadRef (HostFrame t), Ref (HostFrame t
5565 return [EventTriggerRef reResultTrigger :=> Identity result]
5666 return eResult
5767
58−instance (ReflexHost t, Monad (HostFrame t), MonadRef (HostFrame t), Ref (HostFrame t) ~ Ref IO, Ref m ~ Ref IO) => Deletable t (PerformEventT t m) where
68+instance (ReflexHost t, Monad (HostFrame t), Ref (HostFrame t) ~ Ref IO, Ref m ~ Ref IO) => Deletable t (PerformEventT t m) where
5969 {-# INLINABLE deletable #-}
6070 deletable d a = PerformEventT $ do
61− (result, eventToPerform) <- lift $ runPerformEventT a
62− modify (align (fmap (PerformEventT . lift) eventToPerform) d :)
71+ (result, reverseEventsToPerform) <- lift $ runStateT (unPerformEventT a) []
72+ let (numberedEvents, _) = numberWith (\n e -> Const2 n :=> e) (reverse reverseEventsToPerform) (1 :: Word64)
73+ eventToPerform <- lift $ mergePerformEventsAndAdd (DMap.fromList numberedEvents) never
74+ modify (align eventToPerform d :)
6375 return result
6476
6577instance ReflexHost t => MonadReflexCreateTrigger t (PerformEventT t m) where
@@ -131,7 +143,7 @@ hostPerformEventT a = do
131143 followupEventTriggerRefs <- runHostFrame toPerform
132144 followupEventTriggers <- forM followupEventTriggerRefs $ \(EventTriggerRef rt :=> x) -> do
133145 mt <- readRef rt
134− return $ fmap (\t -> t :=> x) mt
146+ return $ fmap (:=> x) mt
135147 fmap (result':) $ go $ catMaybes followupEventTriggers
136148 go triggers
137149
src/Reflex/Dom/PerformEvent/Class.hs+9−1
@@ -1,4 +1,12 @@
1−{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies, GeneralizedNewtypeDeriving, FlexibleInstances, TypeFamilies, TypeOperators, RankNTypes, ScopedTypeVariables, StandaloneDeriving, FlexibleContexts, UndecidableInstances #-}
1+{-# LANGUAGE FlexibleContexts #-}
2+{-# LANGUAGE FlexibleInstances #-}
3+{-# LANGUAGE FunctionalDependencies #-}
4+{-# LANGUAGE MultiParamTypeClasses #-}
5+{-# LANGUAGE RankNTypes #-}
6+{-# LANGUAGE ScopedTypeVariables #-}
7+{-# LANGUAGE TypeFamilies #-}
8+{-# LANGUAGE TypeOperators #-}
9+{-# LANGUAGE UndecidableInstances #-}
210module Reflex.Dom.PerformEvent.Class where
311
412import Reflex
src/Reflex/Dom/PostBuild/Class.hs+18−8
@@ -1,17 +1,27 @@
1−{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, GeneralizedNewtypeDeriving, TypeFamilies, UndecidableInstances, RecursiveDo, ScopedTypeVariables, DataKinds, TypeOperators, PolyKinds, FunctionalDependencies #-}
1+{-# LANGUAGE DataKinds #-}
2+{-# LANGUAGE FlexibleInstances #-}
3+{-# LANGUAGE FunctionalDependencies #-}
4+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
5+{-# LANGUAGE MultiParamTypeClasses #-}
6+{-# LANGUAGE PolyKinds #-}
7+{-# LANGUAGE RecursiveDo #-}
8+{-# LANGUAGE ScopedTypeVariables #-}
9+{-# LANGUAGE TypeFamilies #-}
10+{-# LANGUAGE TypeOperators #-}
11+{-# LANGUAGE UndecidableInstances #-}
212module Reflex.Dom.PostBuild.Class where
313
14+import Foreign.JavaScript.TH
415import Reflex
5−import Reflex.Host.Class
616import Reflex.Dom.Builder.Class
717import Reflex.Dom.PerformEvent.Class
8−import Foreign.JavaScript.TH
18+import Reflex.Host.Class
919
1020import Control.Lens hiding (element)
21+import Control.Monad.Exception
1122import Control.Monad.Reader
12−import Control.Monad.Trans.Control
1323import Control.Monad.Ref
14−import Control.Monad.Exception
24+import Control.Monad.Trans.Control
1525
1626class (Reflex t, Monad m) => PostBuild t m | m -> t where
1727 getPostBuild :: m (Event t ())
@@ -48,9 +58,9 @@ instance (DomBuilder t m, PerformEvent t m, MonadFix m, MonadHold t m) => DomBui
4858 element t cfg child = liftWith $ \run -> element t (liftPostBuildTElementConfig cfg) $ run child
4959 {-# INLINABLE placeholder #-}
5060 placeholder cfg = lift $ do
51− rec childPostBuild <- deletable (cfg ^. deleteSelf) $ performEvent $ return () <$ _placeholder_insertedAbove p
61+ rec childPostBuild <- deletable (_placeholder_deletedSelf p) $ performEvent $ return () <$ _placeholder_insertedAbove p
5262 p <- placeholder $ cfg
53− { _placeholderConfig_insertAbove = fmap (\a -> runPostBuildT a =<< headE childPostBuild) $ _placeholderConfig_insertAbove cfg
63+ { _placeholderConfig_insertAbove = ffor (_placeholderConfig_insertAbove cfg) $ \a -> runPostBuildT a =<< headE childPostBuild
5464 }
5565 return p
5666 {-# INLINABLE inputElement #-}
@@ -113,7 +123,7 @@ instance HasWebView m => HasWebView (PostBuildT t m) where
113123
114124{-# INLINABLE runPostBuildT #-}
115125runPostBuildT :: PostBuildT t m a -> Event t () -> m a
116−runPostBuildT (PostBuildT a) postBuild = runReaderT a postBuild
126+runPostBuildT (PostBuildT a) = runReaderT a
117127
118128instance PostBuild t m => PostBuild t (ReaderT r m) where
119129 getPostBuild = lift getPostBuild
src/Reflex/Dom/Time.hs+16−11
@@ -1,18 +1,24 @@
1−{-# LANGUAGE DeriveDataTypeable, TypeFamilies, ScopedTypeVariables, FlexibleContexts, RecursiveDo #-}
1+{-# LANGUAGE DeriveDataTypeable #-}
2+{-# LANGUAGE FlexibleContexts #-}
3+{-# LANGUAGE MultiParamTypeClasses #-}
4+{-# LANGUAGE RecursiveDo #-}
5+{-# LANGUAGE ScopedTypeVariables #-}
6+{-# LANGUAGE TypeFamilies #-}
27module Reflex.Dom.Time where
38
49import Reflex
5−import Reflex.Dom.PostBuild.Class
610import Reflex.Dom.PerformEvent.Class
11+import Reflex.Dom.PostBuild.Class
712
813import Control.Concurrent
14+import qualified Control.Concurrent.Thread.Delay as Concurrent
915import Control.Monad
1016import Control.Monad.Fix
1117import Control.Monad.IO.Class
1218import Data.Fixed
1319import Data.Time.Clock
14−import System.Random
1520import Data.Typeable
21+import System.Random
1622
1723data TickInfo
1824 = TickInfo { _tickInfo_lastUTC :: UTCTime
@@ -42,11 +48,11 @@ tickLossyFrom
4248 -- there could be uses for starting multiple timer threads.
4349 -> m (Event t TickInfo)
4450tickLossyFrom dt t0 e = do
45− rec result <- performEventAsync $ fmap callAtNextInterval $ leftmost [() <$ e, () <$ result]
51+ rec result <- performEventAsync $ callAtNextInterval <$> leftmost [() <$ e, () <$ result]
4652 return result
4753 where callAtNextInterval _ cb = void $ liftIO $ forkIO $ do
4854 tick <- getCurrentTick dt t0
49− threadDelay $ ceiling $ (dt - _tickInfo_alreadyElapsed tick) * 1000000
55+ Concurrent.delay $ ceiling $ (dt - _tickInfo_alreadyElapsed tick) * 1000000
5056 cb tick
5157
5258clockLossy :: (MonadIO m, PerformEvent t m, TriggerEvent t m, MonadIO (Performable m), PostBuild t m, MonadHold t m, MonadFix m) => NominalDiffTime -> UTCTime -> m (Dynamic t TickInfo)
@@ -65,7 +71,7 @@ getCurrentTick dt t0 = do
6571-- | Delay an Event's occurrences by a given amount in seconds.
6672delay :: (PerformEvent t m, TriggerEvent t m, MonadIO (Performable m)) => NominalDiffTime -> Event t a -> m (Event t a)
6773delay dt e = performEventAsync $ ffor e $ \a cb -> liftIO $ void $ forkIO $ do
68− threadDelay $ ceiling $ dt * 1000000
74+ Concurrent.delay $ ceiling $ dt * 1000000
6975 cb a
7076
7177-- | Send events with Poisson timing with the given basis and rate
@@ -84,8 +90,7 @@ poissonLossyFrom
8490 -- there could be uses for starting multiple timer threads.
8591 -- Start sending events in response to the event parameter.
8692 -> m (Event t TickInfo)
87−poissonLossyFrom rnd rate t0 t =
88− inhomogeneousPoissonFrom rnd (current $ constDyn rate) rate t0 t
93+poissonLossyFrom rnd rate = inhomogeneousPoissonFrom rnd (constant rate) rate
8994
9095
9196-- | Send events with Poisson timing with the given basis and rate
@@ -148,13 +153,13 @@ inhomogeneousPoissonFrom rnd rate maxRate t0 e = do
148153
149154 -- Inter-event interval is drawn from exponential
150155 -- distribution accourding to u
151− let dt = realToFrac $ -1 * log(u)/maxRate :: NominalDiffTime
156+ let dt = realToFrac $ (-1) * log u / maxRate :: NominalDiffTime
152157 nEvents = lastN + 1
153158 alreadyElapsed = diffUTCTime t tTargetLast
154159 tTarget = addUTCTime dt tTargetLast
155160 thisDelay = realToFrac $ diffUTCTime tTarget t :: Double
156− threadDelay $ ceiling $ thisDelay * 1000000
157− void $ cb $ (TickInfo t nEvents alreadyElapsed, p)
161+ Concurrent.delay $ ceiling $ thisDelay * 1000000
162+ _ <- cb (TickInfo t nEvents alreadyElapsed, p)
158163 go tTarget nextGen' cb nEvents
159164
160165-- | Send events with inhomogeneous Poisson timing with the given basis
src/Reflex/Dom/WebSocket.hs+26−9
@@ -1,26 +1,45 @@
1−{-# LANGUAGE ForeignFunctionInterface, JavaScriptFFI, CPP, TemplateHaskell, NoMonomorphismRestriction, EmptyDataDecls, RankNTypes, GADTs, RecursiveDo, ScopedTypeVariables, FlexibleInstances, MultiParamTypeClasses, TypeFamilies, FlexibleContexts, DeriveDataTypeable, GeneralizedNewtypeDeriving, StandaloneDeriving, ConstraintKinds, UndecidableInstances, PolyKinds, AllowAmbiguousTypes #-}
1+{-# LANGUAGE AllowAmbiguousTypes #-}
2+{-# LANGUAGE ConstraintKinds #-}
3+{-# LANGUAGE DeriveDataTypeable #-}
4+{-# LANGUAGE EmptyDataDecls #-}
5+{-# LANGUAGE FlexibleContexts #-}
6+{-# LANGUAGE FlexibleInstances #-}
7+{-# LANGUAGE ForeignFunctionInterface #-}
8+{-# LANGUAGE GADTs #-}
9+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
10+{-# LANGUAGE JavaScriptFFI #-}
11+{-# LANGUAGE MultiParamTypeClasses #-}
12+{-# LANGUAGE NoMonomorphismRestriction #-}
13+{-# LANGUAGE PolyKinds #-}
14+{-# LANGUAGE RankNTypes #-}
15+{-# LANGUAGE RecursiveDo #-}
16+{-# LANGUAGE ScopedTypeVariables #-}
17+{-# LANGUAGE StandaloneDeriving #-}
18+{-# LANGUAGE TemplateHaskell #-}
19+{-# LANGUAGE TypeFamilies #-}
20+{-# LANGUAGE UndecidableInstances #-}
221
322module Reflex.Dom.WebSocket where
423
5−import Prelude hiding (div, span, mapM, mapM_, concat, concatMap, all, sequence)
24+import Prelude hiding (all, concat, concatMap, div, mapM, mapM_, sequence, span)
625
726import Reflex
27+import Reflex.Dom.Class
828import Reflex.Dom.PerformEvent.Class
929import Reflex.Dom.PostBuild.Class
10−import Reflex.Dom.Class
1130import Reflex.Dom.WebSocket.Foreign
1231
1332import Control.Concurrent
1433import Control.Concurrent.STM
15−import Control.Exception (catch, SomeException)
34+import Control.Exception (SomeException, catch)
1635import Control.Lens
1736import Control.Monad hiding (forM, forM_, mapM, mapM_, sequence)
1837import Control.Monad.IO.Class
1938import Control.Monad.State
20−import Data.Maybe (isJust)
2139import Data.ByteString (ByteString)
2240import Data.Default
2341import Data.IORef
42+import Data.Maybe (isJust)
2443import Data.Text
2544
2645data WebSocketConfig t
@@ -38,15 +57,13 @@ data WebSocket t
3857webSocket :: (MonadIO m, MonadIO (Performable m), HasWebView m, PerformEvent t m, TriggerEvent t m, PostBuild t m) => Text -> WebSocketConfig t -> m (WebSocket t)
3958webSocket url config = do
4059 wv <- fmap unWebViewSingleton askWebView
41− (eRecv, triggerERecv) <- newTriggerEvent
60+ (eRecv, onMessage) <- newTriggerEvent
4261 currentSocketRef <- liftIO $ newIORef Nothing
4362 --TODO: Disconnect if value no longer needed
4463 (eOpen, triggerEOpen) <- newTriggerEventWithOnComplete
4564 payloadQueue <- liftIO newTQueueIO
4665 isOpen <- liftIO newEmptyTMVarIO
47− let onMessage :: ByteString -> IO ()
48− onMessage m = triggerERecv m
49− onOpen = triggerEOpen () $ do
66+ let onOpen = triggerEOpen () $ do
5067 liftIO $ void $ atomically $ tryPutTMVar isOpen ()
5168 --TODO: Is the fork necessary, or do event handlers run in their own threads automatically?
5269 onClose = void $ forkIO $ do
src/Reflex/Dom/Widget.hs+5−9
@@ -1,10 +1,6 @@
1−module Reflex.Dom.Widget ( module Reflex.Dom.Widget.Basic
2− , module Reflex.Dom.Widget.Input
3− , module Reflex.Dom.Widget.Lazy
4− , module Reflex.Dom.Widget.Resize
5− ) where
1+module Reflex.Dom.Widget (module X) where
62
7−import Reflex.Dom.Widget.Basic
8−import Reflex.Dom.Widget.Input
9−import Reflex.Dom.Widget.Lazy
10−import Reflex.Dom.Widget.Resize
3+import Reflex.Dom.Widget.Basic as X
4+import Reflex.Dom.Widget.Input as X
5+import Reflex.Dom.Widget.Lazy as X
6+import Reflex.Dom.Widget.Resize as X
src/Reflex/Dom/Widget/Basic.hs+95−72
@@ -1,31 +1,42 @@
1−{-# LANGUAGE OverloadedStrings, ScopedTypeVariables, LambdaCase, ConstraintKinds, TypeFamilies, FlexibleContexts, MultiParamTypeClasses, FlexibleInstances, RecursiveDo, GADTs, DataKinds, RankNTypes, TemplateHaskell #-}
2−
1+{-# LANGUAGE ConstraintKinds #-}
2+{-# LANGUAGE DataKinds #-}
3+{-# LANGUAGE FlexibleContexts #-}
4+{-# LANGUAGE FlexibleInstances #-}
5+{-# LANGUAGE GADTs #-}
6+{-# LANGUAGE LambdaCase #-}
7+{-# LANGUAGE MultiParamTypeClasses #-}
8+{-# LANGUAGE OverloadedStrings #-}
9+{-# LANGUAGE RankNTypes #-}
10+{-# LANGUAGE RecursiveDo #-}
11+{-# LANGUAGE ScopedTypeVariables #-}
12+{-# LANGUAGE TypeFamilies #-}
313module Reflex.Dom.Widget.Basic where
414
15+import Reflex.Dom.Builder.Class
516import Reflex.Dom.Class
617import Reflex.Dom.Internal.Foreign ()
718import Reflex.Dom.PostBuild.Class
8−import Reflex.Dom.Builder.Class
919
10−import Prelude hiding (mapM, mapM_, sequence, sequence_)
11−import Reflex
20+import Control.Arrow
21+import Control.Lens hiding (children, element)
22+import Control.Monad.Reader hiding (forM, forM_, mapM, mapM_, sequence, sequence_)
23+import Data.Align
24+import Data.Default
25+import Data.Either
26+import Data.Foldable
1227import Data.Functor.Misc
1328import Data.Map (Map)
1429import qualified Data.Map as Map
15−import Data.Set (Set)
16−import qualified Data.Set as Set
17−import Data.Foldable
18−import Data.Traversable
19−import Control.Monad.Reader hiding (mapM, mapM_, forM, forM_, sequence, sequence_)
20−import Control.Lens hiding (element, children)
21−import Data.These
22−import Data.Align
2330import Data.Maybe
24−import Data.Default
25−import Data.Either
2631import Data.Semigroup
32+import Data.Set (Set)
33+import qualified Data.Set as Set
2734import Data.Text (Text)
2835import qualified Data.Text as T
36+import Data.These
37+import Data.Traversable
38+import Prelude hiding (mapM, mapM_, sequence, sequence_)
39+import Reflex
2940
3041widgetHoldInternal :: DomBuilder t m => m a -> Event t (m b) -> m (a, Event t b)
3142widgetHoldInternal child0 child' = do
@@ -65,28 +76,27 @@ listHoldWithKey initialChildren modifyChildren buildChild = do
6576 & deleteSelf .~ delete
6677 ph <- placeholder myCfg
6778 result <- deletable delete $ buildChild k v
68− return $ ChildResult (result, (fmap (fmap Just) $ _placeholder_insertedAbove ph) <> (Map.singleton k Nothing <$ _placeholder_deleted ph)) --Note: we could also use the "deleted" output on deletable, if it had one; we're using this so that everything changes all at once, instead of deletions being prompt and insertions being delayed
79+ return $ ChildResult (result, (fmap Just <$> _placeholder_insertedAbove ph) <> (Map.singleton k Nothing <$ _placeholder_deletedSelf ph)) --Note: we could also use the "deleted" output on deletable, if it had one; we're using this so that everything changes all at once, instead of deletions being prompt and insertions being delayed
6980 rec initialAugmentedResults <- iforM initialChildren buildAugmentedChild
7081 augmentedResults <- foldDyn applyMap initialAugmentedResults $ newInsertedBelow <> newInsertedAbove
71− let newInsertedAbove = switch $ fmap (mconcat . reverse . fmap (snd . unChildResult) . Map.elems) $ current augmentedResults
82+ let newInsertedAbove = switch $ mconcat . reverse . fmap (snd . unChildResult) . Map.elems <$> current augmentedResults
7283 belowAll <- placeholder $ def & placeholderConfig_insertAbove .~ fmap (imapM buildAugmentedChild) (select placeChildSelector $ Const2 $ Right ())
73− let newInsertedBelow = fmap (fmap Just) $ _placeholder_insertedAbove belowAll
74− mapDyn (fmap (fst . unChildResult)) augmentedResults
84+ let newInsertedBelow = fmap Just <$> _placeholder_insertedAbove belowAll
85+ return $ fmap (fmap (fst . unChildResult)) augmentedResults
7586
7687text :: DomBuilder t m => Text -> m ()
77−text t = void $ textNode $ def & textNodeConfig_contents .~ t
88+text t = void $ textNode $ def & textNodeConfig_initialContents .~ t
7889
79−dynText :: (PostBuild t m, DomBuilder t m) => Dynamic t Text -> m ()
90+dynText :: forall t m. (PostBuild t m, DomBuilder t m) => Dynamic t Text -> m ()
8091dynText t = do
8192 postBuild <- getPostBuild
82− _ <- widgetHoldInternal (return ()) $ text <$> leftmost
93+ void $ textNode $ (def :: TextNodeConfig t) & textNodeConfig_setContents .~ leftmost
8394 [ updated t
8495 , tag (current t) postBuild
8596 ]
86− return ()
8797
8898display :: (PostBuild t m, DomBuilder t m, Show a) => Dynamic t a -> m ()
89−display = dynText <=< mapDyn (T.pack . show)
99+display = dynText . fmap (T.pack . show)
90100
91101button :: DomBuilder t m => Text -> m (Event t ())
92102button t = do
@@ -101,7 +111,7 @@ dyn :: (DomBuilder t m, PostBuild t m) => Dynamic t (m a) -> m (Event t a)
101111dyn child = do
102112 postBuild <- getPostBuild
103113 let newChild = leftmost [updated child, tag (current child) postBuild]
104− liftM snd $ widgetHoldInternal (return ()) newChild
114+ snd <$> widgetHoldInternal (return ()) newChild
105115
106116-- | Given an initial widget and an Event of widget-creating actions, create a widget that is recreated whenever the Event fires.
107117-- The returned Dynamic of widget results occurs when the Event does.
@@ -167,7 +177,7 @@ listWithKey' = listWithKeyShallowDiff
167177listWithKeyShallowDiff :: (Ord k, DomBuilder t m, MonadFix m, MonadHold t m) => Map k v -> Event t (Map k (Maybe v)) -> (k -> v -> Event t v -> m a) -> m (Dynamic t (Map k a))
168178listWithKeyShallowDiff initialVals valsChanged mkChild = do
169179 let childValChangedSelector = fanMap $ fmap (Map.mapMaybe id) valsChanged
170− sentVals <- foldDyn applyMap Map.empty $ fmap (fmap (fmap (\_ -> ()))) valsChanged
180+ sentVals <- foldDyn applyMap Map.empty $ fmap (fmap void) valsChanged
171181 let relevantPatch patch _ = case patch of
172182 Nothing -> Just Nothing -- Even if we let a Nothing through when the element doesn't already exist, this doesn't cause a problem because it is ignored
173183 Just _ -> Nothing -- We don't want to let spurious re-creations of items through
@@ -178,10 +188,10 @@ listWithKeyShallowDiff initialVals valsChanged mkChild = do
178188-- | Create a dynamically-changing set of Event-valued widgets.
179189-- This is like listWithKey, specialized for widgets returning (Event t a). listWithKey would return 'Dynamic t (Map k (Event t a))' in this scenario, but listViewWithKey flattens this to 'Event t (Map k a)' via 'switch'.
180190listViewWithKey :: (Ord k, DomBuilder t m, PostBuild t m, MonadHold t m, MonadFix m) => Dynamic t (Map k v) -> (k -> Dynamic t v -> m (Event t a)) -> m (Event t (Map k a))
181−listViewWithKey vals mkChild = liftM (switch . fmap mergeMap) $ listViewWithKey' vals mkChild
191+listViewWithKey vals mkChild = switch . fmap mergeMap <$> listViewWithKey' vals mkChild
182192
183193listViewWithKey' :: (Ord k, DomBuilder t m, PostBuild t m, MonadHold t m, MonadFix m) => Dynamic t (Map k v) -> (k -> Dynamic t v -> m a) -> m (Behavior t (Map k a))
184−listViewWithKey' vals mkChild = liftM current $ listWithKey vals mkChild
194+listViewWithKey' vals mkChild = current <$> listWithKey vals mkChild
185195
186196-- | Create a dynamically-changing set of widgets, one of which is selected at any time.
187197selectViewListWithKey :: forall t m k v a. (DomBuilder t m, Ord k, PostBuild t m, MonadHold t m, MonadFix m)
@@ -195,14 +205,14 @@ selectViewListWithKey selection vals mkChild = do
195205 selected <- getDemuxed selectionDemux k
196206 selectSelf <- mkChild k v selected
197207 return $ fmap ((,) k) selectSelf
198− liftM switchPromptlyDyn $ mapDyn (leftmost . Map.elems) selectChild
208+ return $ switchPromptlyDyn $ leftmost . Map.elems <$> selectChild
199209
200210selectViewListWithKey_ :: forall t m k v a. (DomBuilder t m, Ord k, PostBuild t m, MonadHold t m, MonadFix m)
201211 => Dynamic t k -- ^ Current selection key
202212 -> Dynamic t (Map k v) -- ^ Dynamic key/value map
203213 -> (k -> Dynamic t v -> Dynamic t Bool -> m (Event t a)) -- ^ Function to create a widget for a given key from Dynamic value and Dynamic Bool indicating if this widget is currently selected
204214 -> m (Event t k) -- ^ Event that fires when any child's return Event fires. Contains key of an arbitrary firing widget.
205−selectViewListWithKey_ selection vals mkChild = liftM (fmap fst) $ selectViewListWithKey selection vals mkChild
215+selectViewListWithKey_ selection vals mkChild = fmap fst <$> selectViewListWithKey selection vals mkChild
206216
207217{-
208218{-# INLINABLE elWith #-}
@@ -230,34 +240,26 @@ emptyElWith' elementTag cfg = do
230240 wrapElement defaultDomEventHandler =<< buildEmptyElementNS (cfg ^. namespace) elementTag (cfg ^. attributes)
231241-}
232242
233−dynamicAttributesToModifyAttributes :: PostBuild t m => Dynamic t (Map Text Text) -> m (Event t (Map AttributeName (Maybe Text)))
234−dynamicAttributesToModifyAttributes d = do
235− postBuild <- getPostBuild
236− let modificationsNeeded = flip pushAlways (align postBuild $ updated d) $ \case
237− This () -> fmap (fmap Just) $ sample $ current d
238− These () new -> return $ fmap Just new
239− That new -> do
240− old <- sample $ current d
241− return $ diffMap old new
242− return $ Map.fromList . fmap (\(k, v) -> ((Nothing, k), v)) . Map.toList <$> modificationsNeeded
243−
244−{-# INLINABLE elDynAttrNS' #-}
245−elDynAttrNS' :: forall t m a. (DomBuilder t m, PostBuild t m) => Maybe Text -> Text -> Dynamic t (Map Text Text) -> m a -> m (Element EventResult (DomBuilderSpace m) t, a)
246−elDynAttrNS' mns elementTag attrs child = do
247− modifyAttrs <- dynamicAttributesToModifyAttributes attrs
248− let cfg = def
249− & elementConfig_namespace .~ mns
250− & modifyAttributes .~ modifyAttrs
251− element elementTag cfg child
252−
253−{-# INLINABLE elDynAttr' #-}
254−elDynAttr' :: forall t m a. (DomBuilder t m, PostBuild t m) => Text -> Dynamic t (Map Text Text) -> m a -> m (Element EventResult (DomBuilderSpace m) t, a)
255−elDynAttr' = elDynAttrNS' Nothing
243+{-# INLINABLE el #-}
244+el :: forall t m a. DomBuilder t m => Text -> m a -> m a
245+el elementTag child = snd <$> el' elementTag child
256246
257247{-# INLINABLE elAttr #-}
258248elAttr :: forall t m a. DomBuilder t m => Text -> Map Text Text -> m a -> m a
259249elAttr elementTag attrs child = snd <$> elAttr' elementTag attrs child
260250
251+{-# INLINABLE elClass #-}
252+elClass :: forall t m a. DomBuilder t m => Text -> Text -> m a -> m a
253+elClass elementTag c child = snd <$> elClass' elementTag c child
254+
255+{-# INLINABLE elDynAttr #-}
256+elDynAttr :: forall t m a. (DomBuilder t m, PostBuild t m) => Text -> Dynamic t (Map Text Text) -> m a -> m a
257+elDynAttr elementTag attrs child = snd <$> elDynAttr' elementTag attrs child
258+
259+{-# INLINABLE elDynClass #-}
260+elDynClass :: forall t m a. (DomBuilder t m, PostBuild t m) => Text -> Dynamic t Text -> m a -> m a
261+elDynClass elementTag c child = snd <$> elDynClass' elementTag c child
262+
261263{-# INLINABLE el' #-}
262264el' :: forall t m a. DomBuilder t m => Text -> m a -> m (Element EventResult (DomBuilderSpace m) t, a)
263265el' elementTag = element elementTag def
@@ -265,18 +267,39 @@ el' elementTag = element elementTag def
265267{-# INLINABLE elAttr' #-}
266268elAttr' :: forall t m a. DomBuilder t m => Text -> Map Text Text -> m a -> m (Element EventResult (DomBuilderSpace m) t, a)
267269elAttr' elementTag attrs = element elementTag $ def
268− & initialAttributes .~ (Map.fromList $ fmap (\(k, v) -> ((Nothing, k), v)) $ Map.toList $ attrs)
270+ & initialAttributes .~ Map.mapKeys (\k -> (Nothing, k)) attrs
269271
270−{-# INLINABLE elDynAttr #-}
271−elDynAttr :: forall t m a. (DomBuilder t m, PostBuild t m) => Text -> Dynamic t (Map Text Text) -> m a -> m a
272−elDynAttr elementTag attrs child = snd <$> elDynAttr' elementTag attrs child
272+{-# INLINABLE elClass' #-}
273+elClass' :: forall t m a. DomBuilder t m => Text -> Text -> m a -> m (Element EventResult (DomBuilderSpace m) t, a)
274+elClass' elementTag c = elAttr' elementTag ("class" =: c)
273275
274−{-# INLINABLE el #-}
275−el :: forall t m a. DomBuilder t m => Text -> m a -> m a
276−el elementTag child = snd <$> el' elementTag child
276+{-# INLINABLE elDynAttr' #-}
277+elDynAttr' :: forall t m a. (DomBuilder t m, PostBuild t m) => Text -> Dynamic t (Map Text Text) -> m a -> m (Element EventResult (DomBuilderSpace m) t, a)
278+elDynAttr' = elDynAttrNS' Nothing
277279
278−elClass :: forall t m a. DomBuilder t m => Text -> Text -> m a -> m a
279−elClass elementTag c child = fmap snd $ element elementTag (def & initialAttributes .~ (Nothing, "class") =: c) child
280+{-# INLINABLE elDynClass' #-}
281+elDynClass' :: forall t m a. (DomBuilder t m, PostBuild t m) => Text -> Dynamic t Text -> m a -> m (Element EventResult (DomBuilderSpace m) t, a)
282+elDynClass' elementTag c = elDynAttr' elementTag (fmap ("class" =:) c)
283+
284+{-# INLINABLE elDynAttrNS' #-}
285+elDynAttrNS' :: forall t m a. (DomBuilder t m, PostBuild t m) => Maybe Text -> Text -> Dynamic t (Map Text Text) -> m a -> m (Element EventResult (DomBuilderSpace m) t, a)
286+elDynAttrNS' mns elementTag attrs child = do
287+ modifyAttrs <- dynamicAttributesToModifyAttributes attrs
288+ let cfg = def
289+ & elementConfig_namespace .~ mns
290+ & modifyAttributes .~ modifyAttrs
291+ element elementTag cfg child
292+
293+dynamicAttributesToModifyAttributes :: PostBuild t m => Dynamic t (Map Text Text) -> m (Event t (Map AttributeName (Maybe Text)))
294+dynamicAttributesToModifyAttributes d = do
295+ postBuild <- getPostBuild
296+ let modificationsNeeded = flip pushAlways (align postBuild $ updated d) $ \case
297+ This () -> fmap (fmap Just) $ sample $ current d
298+ These () new -> return $ fmap Just new
299+ That new -> do
300+ old <- sample $ current d
301+ return $ diffMap old new
302+ return $ Map.fromList . fmap (\(k, v) -> ((Nothing, k), v)) . Map.toList <$> modificationsNeeded
280303
281304--------------------------------------------------------------------------------
282305-- Copied and pasted from Reflex.Widget.Class
@@ -289,7 +312,7 @@ list dm mkChild = listWithKey dm (\_ dv -> mkChild dv)
289312
290313-- | Create a dynamically-changing set of widgets from a Dynamic list.
291314simpleList :: (DomBuilder t m, MonadHold t m, PostBuild t m, MonadFix m) => Dynamic t [v] -> (Dynamic t v -> m a) -> m (Dynamic t [a])
292−simpleList xs mkChild = mapDyn (map snd . Map.toList) =<< flip list mkChild =<< mapDyn (Map.fromList . zip [(1::Int)..]) xs
315+simpleList xs mkChild = fmap (fmap (map snd . Map.toList)) $ flip list mkChild $ fmap (Map.fromList . zip [(1::Int)..]) xs
293316
294317{-
295318schedulePostBuild x = performEvent_ . (x <$) =<< getPostBuild
@@ -325,17 +348,17 @@ newtype Workflow t m a = Workflow { unWorkflow :: m (a, Event t (Workflow t m a)
325348
326349workflow :: forall t m a. (DomBuilder t m, MonadFix m, MonadHold t m) => Workflow t m a -> m (Dynamic t a)
327350workflow w0 = do
328− rec eResult <- widgetHold (unWorkflow w0) $ fmap unWorkflow $ switch $ fmap snd $ current eResult
329− mapDyn fst eResult
351+ rec eResult <- widgetHold (unWorkflow w0) $ fmap unWorkflow $ switch $ snd <$> current eResult
352+ return $ fmap fst eResult
330353
331354workflowView :: forall t m a. (DomBuilder t m, MonadFix m, MonadHold t m, PostBuild t m) => Workflow t m a -> m (Event t a)
332355workflowView w0 = do
333− rec eResult <- dyn =<< mapDyn unWorkflow =<< holdDyn w0 eReplace
334− eReplace <- liftM switch $ hold never $ fmap snd eResult
356+ rec eResult <- dyn . fmap unWorkflow =<< holdDyn w0 eReplace
357+ eReplace <- fmap switch $ hold never $ fmap snd eResult
335358 return $ fmap fst eResult
336359
337360mapWorkflow :: (DomBuilder t m) => (a -> b) -> Workflow t m a -> Workflow t m b
338−mapWorkflow f (Workflow x) = Workflow (fmap (\(v,e) -> (f v, fmap (mapWorkflow f) e)) x)
361+mapWorkflow f (Workflow x) = Workflow (fmap (f *** fmap (mapWorkflow f)) x)
339362
340363divClass :: forall t m a. DomBuilder t m => Text -> m a -> m a
341364divClass = elClass "div"
@@ -343,7 +366,7 @@ divClass = elClass "div"
343366dtdd :: forall t m a. DomBuilder t m => Text -> m a -> m a
344367dtdd h w = do
345368 el "dt" $ text h
346− el "dd" $ w
369+ el "dd" w
347370
348371blank :: forall m. Monad m => m ()
349372blank = return ()
@@ -376,9 +399,9 @@ tabDisplay :: forall t m k. (MonadFix m, DomBuilder t m, MonadHold t m, PostBuil
376399tabDisplay ulClass activeClass tabItems = do
377400 let t0 = listToMaybe $ Map.keys tabItems
378401 rec currentTab :: Demux t (Maybe k) <- elAttr "ul" ("class" =: ulClass) $ do
379− tabClicksList :: [Event t k] <- (liftM Map.elems) $ imapM (\k (s,_) -> headerBarLink s k =<< getDemuxed currentTab (Just k)) tabItems
402+ tabClicksList :: [Event t k] <- Map.elems <$> imapM (\k (s,_) -> headerBarLink s k =<< getDemuxed currentTab (Just k)) tabItems
380403 let eTabClicks :: Event t k = leftmost tabClicksList
381− liftM demux $ holdDyn t0 $ fmap Just eTabClicks
404+ fmap demux $ holdDyn t0 $ fmap Just eTabClicks
382405 el "div" $ do
383406 iforM_ tabItems $ \k (_, w) -> do
384407 isSelected <- getDemuxed currentTab $ Just k
@@ -388,7 +411,7 @@ tabDisplay ulClass activeClass tabItems = do
388411 where
389412 headerBarLink :: Text -> k -> Dynamic t Bool -> m (Event t k)
390413 headerBarLink x k isSelected = do
391− attrs <- mapDyn (\b -> if b then Map.singleton "class" activeClass else Map.empty) isSelected
414+ let attrs = fmap (\b -> if b then Map.singleton "class" activeClass else Map.empty) isSelected
392415 elDynAttr "li" attrs $ do
393416 a <- link x
394417 return $ fmap (const k) (_link_clicked a)
src/Reflex/Dom/Widget/Input.hs+51−93
@@ -1,49 +1,62 @@
1−{-# LANGUAGE OverloadedStrings, ConstraintKinds, TypeFamilies, FlexibleContexts, DataKinds, GADTs, ScopedTypeVariables, FlexibleInstances, RecursiveDo, TemplateHaskell, UndecidableInstances, PolyKinds #-}
1+{-# LANGUAGE ConstraintKinds #-}
2+{-# LANGUAGE DataKinds #-}
3+{-# LANGUAGE FlexibleContexts #-}
4+{-# LANGUAGE FlexibleInstances #-}
5+{-# LANGUAGE GADTs #-}
6+{-# LANGUAGE MultiParamTypeClasses #-}
7+{-# LANGUAGE OverloadedStrings #-}
8+{-# LANGUAGE PolyKinds #-}
9+{-# LANGUAGE RecursiveDo #-}
10+{-# LANGUAGE ScopedTypeVariables #-}
11+{-# LANGUAGE TemplateHaskell #-}
12+{-# LANGUAGE TypeFamilies #-}
13+{-# LANGUAGE UndecidableInstances #-}
214module Reflex.Dom.Widget.Input (module Reflex.Dom.Widget.Input, def, (&), (.~)) where
315
416import Prelude
517
6−import Reflex.Dom.Class
7−import Reflex.Dom.Widget.Basic
8−import Reflex.Dom.PostBuild.Class
918import Reflex.Dom.Builder.Class
1019import Reflex.Dom.Builder.Immediate
20+import Reflex.Dom.Class
21+import Reflex.Dom.PostBuild.Class
22+import Reflex.Dom.Widget.Basic
1123
1224-- For dropdown
13−import Reflex.Dom.PerformEvent.Class
25+import Control.Monad.Fix
26+import Control.Monad.IO.Class
27+import Data.Maybe
28+import Data.Semigroup
1429import GHCJS.DOM.HTMLInputElement (HTMLInputElement, castToHTMLInputElement)
15−import GHCJS.DOM.HTMLTextAreaElement (HTMLTextAreaElement, castToHTMLTextAreaElement)
1630import GHCJS.DOM.HTMLSelectElement (castToHTMLSelectElement)
1731import qualified GHCJS.DOM.HTMLSelectElement as HTMLSelectElement
18−import Data.Maybe
19−import Data.Semigroup
20−import Control.Monad.Fix
21−import Control.Monad.IO.Class
32+import GHCJS.DOM.HTMLTextAreaElement (HTMLTextAreaElement, castToHTMLTextAreaElement)
33+import Reflex.Dom.PerformEvent.Class
34+import qualified Text.Read as T
2235
2336-- For fileInput
37+import qualified GHCJS.DOM.Element as Element
2438import GHCJS.DOM.EventM (on)
2539import GHCJS.DOM.Types (File)
26−import qualified GHCJS.DOM.Element as Element
27−import qualified GHCJS.DOM.File as File
40+-- import qualified GHCJS.DOM.File as File
2841import qualified GHCJS.DOM.FileList as FileList
2942
3043
31−import Reflex
32−import qualified Data.Map as Map
33−import Control.Lens hiding (ix, element)
44+import Control.Lens hiding (element, ix)
3445import Control.Monad hiding (forM_)
46+import qualified Data.Bimap as Bimap
3547import Data.Default
36−import Data.Map (Map)
37−import Data.Text (Text)
38−import qualified Data.Text as T
3948import Data.Dependent.Map (DMap)
4049import qualified Data.Dependent.Map as DMap
41−import qualified Data.Bimap as Bimap
42−import Data.Proxy
4350import Data.Functor.Misc
51+import Data.Map (Map)
52+import qualified Data.Map as Map
53+import Data.Proxy
54+import Data.Text (Text)
55+import qualified Data.Text as T
56+import Reflex
4457
45−import qualified GHCJS.DOM.HTMLInputElement as Input
4658import qualified GHCJS.DOM.Event as Event
59+import qualified GHCJS.DOM.HTMLInputElement as Input
4760
4861data TextInput t
4962 = TextInput { _textInput_value :: Dynamic t Text
@@ -88,30 +101,10 @@ textInput (TextInputConfig inputType initial eSetValue dAttrs) = do
88101 , _textInput_hasFocus = _inputElement_hasFocus i
89102 , _textInput_element = castToHTMLInputElement $ _element_raw $ _inputElement_element i
90103 }
91−{-
92− e <- liftM castToHTMLInputElement $ buildEmptyElement "input" =<< mapDyn (Map.insert "type" inputType) dAttrs
93− Input.setValue e $ Just initial
94− performEvent_ $ fmap (Input.setValue e . Just) eSetValue
95− eChange <- wrapDomEvent e (`on` input) $ fromMaybe "" <$> Input.getValue e
96− postGui <- askPostGui
97− runWithActions <- askRunWithActions
98− eChangeFocus <- newEventWithTrigger $ \eChangeFocusTrigger -> do
99− unsubscribeOnblur <- on e blurEvent $ liftIO $ do
100− postGui $ runWithActions [eChangeFocusTrigger :=> Identity False]
101− unsubscribeOnfocus <- on e focusEvent $ liftIO $ do
102− postGui $ runWithActions [eChangeFocusTrigger :=> Identity True]
103− return $ liftIO $ unsubscribeOnblur >> unsubscribeOnfocus
104− dFocus <- holdDyn False eChangeFocus
105− eKeypress <- wrapDomEvent e (`on` keyPress) getKeyEvent
106− eKeydown <- wrapDomEvent e (`on` keyDown) getKeyEvent
107− eKeyup <- wrapDomEvent e (`on` keyUp) getKeyEvent
108− dValue <- holdDyn initial $ leftmost [eSetValue, eChange]
109− return $ TextInput dValue eChange eKeypress eKeydown eKeyup dFocus e
110−-}
111104
112105{-# INLINABLE textInputGetEnter #-}
113106textInputGetEnter :: Reflex t => TextInput t -> Event t ()
114−textInputGetEnter i = fmapMaybe (\n -> if n == keycodeEnter then Just () else Nothing) $ _textInput_keypress i
107+textInputGetEnter i = fmapMaybe (\n -> if keyCodeLookup n == Enter then Just () else Nothing) $ _textInput_keypress i
115108
116109data TextAreaConfig t
117110 = TextAreaConfig { _textAreaConfig_initialValue :: Text
@@ -149,24 +142,6 @@ textArea (TextAreaConfig initial eSet attrs) = do
149142 , _textArea_hasFocus = _textAreaElement_hasFocus i
150143 , _textArea_element = castToHTMLTextAreaElement $ _element_raw $ _textAreaElement_element i
151144 }
152−{-
153− e <- liftM castToHTMLTextAreaElement $ buildEmptyElement "textarea" attrs
154− TextArea.setValue e $ Just initial
155− postGui <- askPostGui
156− runWithActions <- askRunWithActions
157− eChangeFocus <- newEventWithTrigger $ \eChangeFocusTrigger -> do
158− unsubscribeOnblur <- on e blurEvent $ liftIO $ do
159− postGui $ runWithActions [eChangeFocusTrigger :=> Identity False]
160− unsubscribeOnfocus <- on e focusEvent $ liftIO $ do
161− postGui $ runWithActions [eChangeFocusTrigger :=> Identity True]
162− return $ liftIO $ unsubscribeOnblur >> unsubscribeOnfocus
163− performEvent_ $ fmap (TextArea.setValue e . Just) eSet
164− f <- holdDyn False eChangeFocus
165− ev <- wrapDomEvent e (`on` input) $ fromMaybe "" <$> TextArea.getValue e
166− v <- holdDyn initial $ leftmost [eSet, ev]
167− eKeypress <- wrapDomEvent e (`on` keyPress) getKeyEvent
168− return $ TextArea v ev e f eKeypress
169−-}
170145
171146data CheckboxConfig t
172147 = CheckboxConfig { _checkboxConfig_setValue :: Event t Bool
@@ -190,7 +165,7 @@ data Checkbox t
190165checkbox :: (DomBuilder t m, PostBuild t m) => Bool -> CheckboxConfig t -> m (Checkbox t)
191166checkbox checked config = do
192167 let permanentAttrs = "type" =: "checkbox"
193− dAttrs = fmap (Map.delete "checked" . Map.union permanentAttrs) $ _checkboxConfig_attributes config
168+ dAttrs = Map.delete "checked" . Map.union permanentAttrs <$> _checkboxConfig_attributes config
194169 modifyAttrs <- dynamicAttributesToModifyAttributes dAttrs
195170 i <- inputElement $ def
196171 & inputElementConfig_initialChecked .~ checked
@@ -200,14 +175,6 @@ checkbox checked config = do
200175 return $ Checkbox
201176 { _checkbox_value = _inputElement_checked i
202177 }
203−{-
204− attrs <- mapDyn (\c -> Map.insert "type" "checkbox" $ (if checked then Map.insert "checked" "checked" else Map.delete "checked") c) (_checkboxConfig_attributes config)
205− e <- liftM castToHTMLInputElement $ buildEmptyElement "input" attrs
206− eClick <- wrapDomEvent e (`on` click) $ Input.getChecked e
207− performEvent_ $ fmap (\v -> Input.setChecked e $! v) $ _checkboxConfig_setValue config
208− dValue <- holdDyn checked $ leftmost [_checkboxConfig_setValue config, eClick]
209− return $ Checkbox dValue eClick
210−-}
211178
212179type family CheckboxViewEventResultType (en :: EventTag) :: * where
213180 CheckboxViewEventResultType 'ClickTag = Bool
@@ -296,18 +263,7 @@ checkboxView dAttrs dValue = do
296263 & inputElementConfig_setChecked .~ leftmost [updated dValue, tag (current dValue) postBuild]
297264 & inputElementConfig_elementConfig .~ elementConfig
298265 i <- inputElement inputElementConfig
299− return $ fmap unCheckboxViewEventResult $ select (_element_events $ _inputElement_element i) (WrapArg Click)
300−{-
301− e <- liftM castToHTMLInputElement $ buildEmptyElement "input" =<< mapDyn (Map.insert "type" "checkbox") dAttrs
302− eClicked <- wrapDomEvent e (`on` click) $ do
303− preventDefault
304− Input.getChecked e
305− schedulePostBuild $ do
306− v <- sample $ current dValue
307− when v $ Input.setChecked e True
308− performEvent_ $ fmap (\v -> Input.setChecked e $! v) $ updated dValue
309− return eClicked
310−-}
266+ return $ unCheckboxViewEventResult <$> select (_element_events $ _inputElement_element i) (WrapArg Click)
311267
312268data FileInput t
313269 = FileInput { _fileInput_value :: Dynamic t [File]
@@ -325,11 +281,11 @@ fileInput :: forall t m. (MonadIO m, MonadFix m, MonadHold t m, TriggerEvent t m
325281 => FileInputConfig t -> m (FileInput t)
326282fileInput config = do
327283 let insertType = Map.insert "type" "file"
328− dAttrs = fmap insertType $ _fileInputConfig_attributes config
284+ dAttrs = insertType <$> _fileInputConfig_attributes config
329285 modifyAttrs <- dynamicAttributesToModifyAttributes dAttrs
330286 let cfg = (def :: ElementConfig EventResult t m)
331287 { _elementConfig_modifyAttributes = modifyAttrs
332− , _elementConfig_eventFilters = DMap.singleton Change . EventFilter . GhcjsDomHandler $ \(GhcjsDomEvent evt) -> do
288+ , _elementConfig_eventFilters = DMap.singleton Change . EventFilter . GhcjsDomHandler $ \_ -> do
333289 return . (,) mempty . GhcjsDomHandler $ \_ -> return . Just $ EventResult ()
334290 }
335291 (eRaw, _) <- element "input" cfg blank
@@ -337,7 +293,7 @@ fileInput config = do
337293 eChange <- wrapDomEvent e (`on` Element.change) $ do
338294 Just files <- Input.getFiles e
339295 len <- FileList.getLength files
340− mapM (liftM (fromMaybe (error "fileInput: fileList.item returned null")) . FileList.item files) $ [0 .. len-1]
296+ mapM (fmap (fromMaybe (error "fileInput: fileList.item returned null")) . FileList.item files) [0 .. len-1]
341297 dValue <- holdDyn [] eChange
342298 return $ FileInput
343299 { _fileInput_value = dValue
@@ -418,7 +374,7 @@ regularToDropdownViewEventType en r = case en of
418374--TODO: We should allow the user to specify an ordering instead of relying on the ordering of the Map
419375-- | Create a dropdown box
420376-- 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
421−dropdown :: forall k t m. (DomBuilder t m, MonadFix m, MonadHold t m, PerformEvent t m, MonadIO (Performable m), PostBuild t m, DomBuilderSpace m ~ GhcjsDomSpace, Ord k) => k -> Dynamic t (Map k Text) -> DropdownConfig t k -> m (Dropdown t k)
377+dropdown :: forall k t m. (DomBuilder t m, MonadFix m, MonadHold t m, PerformEvent t m, MonadIO (Performable m), MonadIO m, TriggerEvent t m, PostBuild t m, DomBuilderSpace m ~ GhcjsDomSpace, Ord k) => k -> Dynamic t (Map k Text) -> DropdownConfig t k -> m (Dropdown t k)
422378dropdown k0 options (DropdownConfig setK attrs) = do
423379 optionsWithAddedKeys <- combineDyn Map.union options <=< foldDyn Map.union (k0 =: "") $ fmap (=: "") setK
424380 defaultKey <- holdDyn k0 setK
@@ -443,11 +399,15 @@ dropdown k0 options (DropdownConfig setK attrs) = do
443399 Just1 (EventResult r) -> return $ Just1 $ DropdownViewEventResult $ regularToDropdownViewEventType en r
444400 }
445401 (eRaw, _) <- element "select" cfg $ listWithKey indexedOptions $ \(ix, k) v -> do
446− optionAttrs <- mapDyn (\dk -> "value" =: T.pack (show ix) <> if dk == k then "selected" =: "selected" else mempty) defaultKey
402+ let optionAttrs = fmap (\dk -> "value" =: T.pack (show ix) <> if dk == k then "selected" =: "selected" else mempty) defaultKey
447403 elDynAttr "option" optionAttrs $ dynText v
448404 let e = castToHTMLSelectElement $ _element_raw eRaw
449− performEvent_ $ fmap (HTMLSelectElement.setValue e . Just . show) $ attachDynWithMaybe (flip Bimap.lookupR) ixKeys setK
450− eChange <- return never -- attachDynWith (\ks s -> join $ Bimap.lookup <$> join (readMaybe <$> s) <*> pure ks) ixKeys <$> (wrapDomEvent e (`on` Element.change) $ HTMLSelectElement.getValue e)
405+ performEvent_ $ HTMLSelectElement.setValue e . Just . show <$> attachDynWithMaybe (flip Bimap.lookupR) ixKeys setK
406+ let lookupSelected ks value = do
407+ v <- value
408+ key <- T.readMaybe v
409+ Bimap.lookup key ks
410+ eChange <- attachDynWith lookupSelected ixKeys <$> wrapDomEvent e (`on` Element.change) (HTMLSelectElement.getValue e)
451411 let readKey keys mk = fromMaybe k0 $ do
452412 k <- mk
453413 guard $ Bimap.memberR k keys
@@ -455,13 +415,13 @@ dropdown k0 options (DropdownConfig setK attrs) = do
455415 dValue <- combineDyn readKey ixKeys <=< holdDyn (Just k0) $ leftmost [eChange, fmap Just setK]
456416 return $ Dropdown dValue (attachDynWith readKey ixKeys eChange)
457417
458−liftM concat $ mapM makeLenses
418+concat <$> mapM makeLenses
459419 [ ''TextAreaConfig
460420 , ''TextArea
461421 , ''TextInputConfig
462422 , ''TextInput
463−-- , ''FileInputConfig
464−-- , ''FileInput
423+ , ''FileInputConfig
424+ , ''FileInput
465425 , ''DropdownConfig
466426 , ''Dropdown
467427 , ''CheckboxConfig
@@ -484,11 +444,9 @@ instance HasAttributes (CheckboxConfig t) where
484444 type Attrs (CheckboxConfig t) = Dynamic t (Map Text Text)
485445 attributes = checkboxConfig_attributes
486446
487−{-
488447instance HasAttributes (FileInputConfig t) where
489448 type Attrs (FileInputConfig t) = Dynamic t (Map Text Text)
490449 attributes = fileInputConfig_attributes
491−-}
492450
493451class HasSetValue a where
494452 type SetValue a :: *
src/Reflex/Dom/Widget/Lazy.hs+30−23
@@ -1,23 +1,28 @@
1−{-# LANGUAGE RecursiveDo, ScopedTypeVariables, OverloadedStrings, TypeFamilies, FlexibleContexts #-}
1+{-# LANGUAGE FlexibleContexts #-}
2+{-# LANGUAGE MultiParamTypeClasses #-}
3+{-# LANGUAGE OverloadedStrings #-}
4+{-# LANGUAGE RecursiveDo #-}
5+{-# LANGUAGE ScopedTypeVariables #-}
6+{-# LANGUAGE TypeFamilies #-}
27module Reflex.Dom.Widget.Lazy where
38
49import Reflex
5−import Reflex.Dom.Class
610import Reflex.Dom.Builder.Class
711import Reflex.Dom.Builder.Immediate
8−import Reflex.Dom.PostBuild.Class
12+import Reflex.Dom.Class
913import Reflex.Dom.PerformEvent.Class
14+import Reflex.Dom.PostBuild.Class
1015import Reflex.Dom.Widget.Basic
1116
1217import Control.Monad.Fix
1318import Control.Monad.IO.Class
1419import Data.Fixed
15−import Data.Monoid
16−import qualified Data.Map as Map
1720import Data.Map (Map)
18−import GHCJS.DOM.Element
21+import qualified Data.Map as Map
22+import Data.Monoid
1923import Data.Text (Text)
2024import qualified Data.Text as T
25+import GHCJS.DOM.Element
2126
2227-- |A list view for long lists. Creates a scrollable element and only renders child row elements near the current scroll position.
2328virtualListWithSelection :: forall t m k v. (DomBuilder t m, PostBuild t m, MonadHold t m, PerformEvent t m, MonadIO (Performable m), DomBuilderSpace m ~ GhcjsDomSpace, MonadFix m, Ord k)
@@ -35,11 +40,11 @@ virtualListWithSelection :: forall t m k v. (DomBuilder t m, PostBuild t m, Mona
3540 -> (Int -> k) -- ^ Index to Key function, used to determine position of Map elements
3641 -> m (Dynamic t (Int, Int), Event t k) -- ^ A tuple containing: a 'Dynamic' of the index (based on the current scroll position) and number of items currently being rendered, and an 'Event' of the selected key
3742virtualListWithSelection heightPx rowPx maxIndex i0 setI listTag listAttrs rowTag rowAttrs itemBuilder items indexToKey = do
38− totalHeightStyle <- mapDyn (toHeightStyle . (*) rowPx) maxIndex
39− containerStyle <- mapDyn toContainer heightPx
40− viewportStyle <- mapDyn toViewport heightPx
43+ let totalHeightStyle = fmap (toHeightStyle . (*) rowPx) maxIndex
44+ containerStyle = fmap toContainer heightPx
45+ viewportStyle = fmap toViewport heightPx
4146 rec (container, sel) <- elDynAttr "div" containerStyle $ elDynAttr' "div" viewportStyle $ do
42− currentTop <- mapDyn (listWrapperStyle . fst) window
47+ let currentTop = fmap (listWrapperStyle . fst) window
4348 (_, lis) <- elDynAttr "div" totalHeightStyle $ tagWrapper listTag listAttrs currentTop $ selectViewListWithKey_ selected itemsInWindow $ \k v s -> do
4449 (li,_) <- tagWrapper rowTag rowAttrs (constDyn $ toHeightStyle rowPx) $ itemBuilder k v s
4550 return $ fmap (const k) (domEvent Click li)
@@ -49,14 +54,15 @@ virtualListWithSelection heightPx rowPx maxIndex i0 setI listTag listAttrs rowTa
4954 scrollPosition <- holdDyn 0 $ leftmost [ domEvent Scroll container
5055 , fmap (const (i0 * rowPx)) pb
5156 ]
52− window <- combineDyn (\h -> findWindow h rowPx) heightPx scrollPosition
57+ window <- combineDyn (findWindow rowPx) heightPx scrollPosition
5358 itemsInWindow <- combineDyn (\(_,(idx,num)) is -> Map.fromList $ map (\i -> let ix = indexToKey i in (ix, Map.lookup ix is)) [idx .. idx + num]) window items
5459 postBuild <- getPostBuild
55− performEvent_ $ fmap (\i -> liftIO $ setScrollTop (_element_raw container) (i * rowPx)) $ leftmost [setI, fmap (const i0) postBuild]
56− indexAndLength <- mapDyn snd window
60+ performEvent_ $ ffor (leftmost [setI, i0 <$ postBuild]) $ \i -> do
61+ liftIO $ setScrollTop (_element_raw container) (i * rowPx)
62+ let indexAndLength = fmap snd window
5763 return (indexAndLength, sel)
5864 where
59− toStyleAttr m = "style" =: (Map.foldWithKey (\k v s -> k <> ":" <> v <> ";" <> s) "" m)
65+ toStyleAttr m = "style" =: Map.foldWithKey (\k v s -> k <> ":" <> v <> ";" <> s) "" m
6066 toViewport h = toStyleAttr $ "overflow" =: "auto" <> "position" =: "absolute" <>
6167 "left" =: "0" <> "right" =: "0" <> "height" =: (T.pack (show h) <> "px")
6268 toContainer h = toStyleAttr $ "position" =: "relative" <> "height" =: (T.pack (show h) <> "px")
@@ -66,7 +72,7 @@ virtualListWithSelection heightPx rowPx maxIndex i0 setI listTag listAttrs rowTa
6672 tagWrapper elTag attrs attrsOverride c = do
6773 attrs' <- combineDyn Map.union attrsOverride attrs
6874 elDynAttr' elTag attrs' c
69− findWindow windowSize sizeIncrement startingPosition =
75+ findWindow sizeIncrement windowSize startingPosition =
7076 let (startingIndex, topOffsetPx) = startingPosition `divMod'` sizeIncrement
7177 topPx = startingPosition - topOffsetPx
7278 numItems = windowSize `div` sizeIncrement + 1
@@ -85,20 +91,21 @@ virtualList :: forall t m k v a. (DomBuilder t m, PostBuild t m, MonadHold t m,
8591 -> (k -> v -> Event t v -> m a) -- ^ The row child element builder.
8692 -> m (Dynamic t (Int, Int), Dynamic t (Map k a)) -- ^ A tuple containing: a 'Dynamic' of the index (based on the current scroll position) and number of items currently being rendered, and the 'Dynamic' list result
8793virtualList heightPx rowPx maxIndex i0 setI keyToIndex items0 itemsUpdate itemBuilder = do
88− virtualH <- mapDyn (mkVirtualHeight . (*) rowPx) maxIndex
89− containerStyle <- mapDyn mkContainer heightPx
90− viewportStyle <- mapDyn mkViewport heightPx
94+ let virtualH = fmap (mkVirtualHeight . (*) rowPx) maxIndex
95+ containerStyle = fmap mkContainer heightPx
96+ viewportStyle = fmap mkViewport heightPx
9197 pb <- getPostBuild
9298 rec (viewport, result) <- elDynAttr "div" containerStyle $ elDynAttr' "div" viewportStyle $ elDynAttr "div" virtualH $
9399 listWithKeyShallowDiff items0 itemsUpdate $ \k v e -> elAttr "div" (mkRow k) $ itemBuilder k v e
94100 scrollPosition <- holdDyn 0 $ leftmost [ domEvent Scroll viewport
95101 , fmap (const (i0 * rowPx)) pb
96102 ]
97− window <- combineDyn (\h -> findWindow h rowPx) heightPx scrollPosition
98− performEvent_ $ fmap (\i -> liftIO $ setScrollTop (_element_raw viewport) (i * rowPx)) $ leftmost [setI, fmap (const i0) pb]
103+ window <- combineDyn (findWindow rowPx) heightPx scrollPosition
104+ performEvent_ $ ffor (leftmost [setI, i0 <$ pb]) $ \i -> do
105+ liftIO $ setScrollTop (_element_raw viewport) (i * rowPx)
99106 return (nubDyn window, result)
100107 where
101− toStyleAttr m = "style" =: (Map.foldWithKey (\k v s -> k <> ":" <> v <> ";" <> s) "" m)
108+ toStyleAttr m = "style" =: Map.foldWithKey (\k v s -> k <> ":" <> v <> ";" <> s) "" m
102109 mkViewport h = toStyleAttr $ "overflow" =: "auto" <> "position" =: "absolute" <>
103110 "left" =: "0" <> "right" =: "0" <> "height" =: (T.pack (show h) <> "px")
104111 mkContainer h = toStyleAttr $ "position" =: "relative" <> "height" =: (T.pack (show h) <> "px")
@@ -110,7 +117,7 @@ virtualList heightPx rowPx maxIndex i0 setI keyToIndex items0 itemsUpdate itemBu
110117 "top" =: ((<>"px") $ T.pack $ show $ keyToIndex k * rowPx) <>
111118 "position" =: "absolute" <>
112119 "width" =: "100%"
113− findWindow windowSize sizeIncrement startingPosition =
120+ findWindow sizeIncrement windowSize startingPosition =
114121 let (startingIndex, _) = startingPosition `divMod'` sizeIncrement
115122 numItems = (windowSize + sizeIncrement - 1) `div` sizeIncrement
116123 in (startingIndex, numItems)
@@ -137,6 +144,6 @@ virtualListBuffered buffer heightPx rowPx maxIndex i0 setI keyToIndex items0 ite
137144 then Nothing
138145 else Just (extendWin winOffset winLimit)) (current winBuffered) (updated win)
139146 winBuffered <- holdDyn (0, 0) $ leftmost [ winHitEdge
140− , fmap (uncurry extendWin) $ tagDyn win pb
147+ , attachDynWith (\(x, y) _ -> extendWin x y) win pb
141148 ]
142149 return (updated winBuffered, m)
src/Reflex/Dom/Widget/Resize.hs+18−12
@@ -1,36 +1,42 @@
1−{-# LANGUAGE RecursiveDo, TypeFamilies, FlexibleContexts, OverloadedStrings #-}
1+{-# LANGUAGE FlexibleContexts #-}
2+{-# LANGUAGE MultiParamTypeClasses #-}
3+{-# LANGUAGE OverloadedStrings #-}
4+{-# LANGUAGE RecursiveDo #-}
5+{-# LANGUAGE TypeFamilies #-}
26module Reflex.Dom.Widget.Resize where
37
48import Reflex
5−import Reflex.Dom.PostBuild.Class
6−import Reflex.Dom.PerformEvent.Class
9+import Reflex.Dom.Builder.Class
710import Reflex.Dom.Builder.Immediate
811import Reflex.Dom.Class
912import Reflex.Dom.Old
13+import Reflex.Dom.PerformEvent.Class
14+import Reflex.Dom.PostBuild.Class
1015import Reflex.Dom.Widget.Basic
1116
1217import Control.Monad
18+import Control.Monad.Fix
1319import Control.Monad.IO.Class
1420import Data.Map (Map)
21+import qualified Data.Map as Map
22+import Data.Monoid
1523import Data.Text (Text)
1624import qualified Data.Text as T
17−import Data.Monoid
1825import GHCJS.DOM.Element hiding (reset)
1926import GHCJS.DOM.EventM (on)
20−import qualified Data.Map as Map
2127
2228-- | A widget that wraps the given widget in a div and fires an event when resized.
2329-- Adapted from github.com/marcj/css-element-queries
24−resizeDetector :: MonadWidget t m => m a -> m (Event t (), a)
30+resizeDetector :: (DomBuilder t m, PostBuild t m, TriggerEvent t m, PerformEvent t m, MonadHold t m, DomBuilderSpace m ~ GhcjsDomSpace, MonadIO (Performable m), MonadFix m) => m a -> m (Event t (), a)
2531resizeDetector = resizeDetectorWithStyle ""
2632
27−resizeDetectorWithStyle :: MonadWidget t m
33+resizeDetectorWithStyle :: (DomBuilder t m, PostBuild t m, TriggerEvent t m, PerformEvent t m, MonadHold t m, DomBuilderSpace m ~ GhcjsDomSpace, MonadIO (Performable m), MonadFix m)
2834 => Text -- ^ A css style string. Warning: It should not contain the "position" style attribute.
2935 -> m a -- ^ The embedded widget
3036 -> m (Event t (), a) -- ^ An 'Event' that fires on resize, and the result of the embedded widget
31−resizeDetectorWithStyle styleString w = resizeDetectorWithAttrs ("style" =: styleString) w
37+resizeDetectorWithStyle styleString = resizeDetectorWithAttrs ("style" =: styleString)
3238
33−resizeDetectorWithAttrs :: MonadWidget t m
39+resizeDetectorWithAttrs :: (DomBuilder t m, PostBuild t m, TriggerEvent t m, PerformEvent t m, MonadHold t m, DomBuilderSpace m ~ GhcjsDomSpace, MonadIO (Performable m), MonadFix m)
3440 => Map Text Text -- ^ A map of attributes. Warning: It should not modify the "position" style attribute.
3541 -> m a -- ^ The embedded widget
3642 -> m (Event t (), a) -- ^ An 'Event' that fires on resize, and the result of the embedded widget
@@ -66,12 +72,12 @@ resizeDetectorWithAttrs attrs w = do
6672 pow <- getOffsetWidth (_el_element parent)
6773 poh <- getOffsetHeight (_el_element parent)
6874 if ds == (Just pow, Just poh)
69− then return Nothing
70− else liftM Just reset
75+ then return Nothing
76+ else fmap Just reset
7177 pb <- getPostBuild
7278 expandScroll <- wrapDomEvent (_el_element expand) (`on` scroll) $ return ()
7379 shrinkScroll <- wrapDomEvent (_el_element shrink) (`on` scroll) $ return ()
7480 size0 <- performEvent $ fmap (const $ liftIO reset) pb
7581 rec resize <- performEventAsync $ fmap (\d cb -> liftIO $ cb =<< resetIfChanged d) $ tag (current dimensions) $ leftmost [expandScroll, shrinkScroll]
7682 dimensions <- holdDyn (Nothing, Nothing) $ leftmost [ size0, fmapMaybe id resize ]
77− return (fmap (const ()) $ fmapMaybe id resize, w')
83+ return (fmapMaybe void resize, w')
src/Reflex/Dom/Xhr.hs+35−30
@@ -1,12 +1,19 @@
1−{-# LANGUAGE TemplateHaskell, GADTs, DeriveDataTypeable, FlexibleContexts, OverloadedStrings #-}
1+{-# LANGUAGE DeriveDataTypeable #-}
2+{-# LANGUAGE DeriveFunctor #-}
3+{-# LANGUAGE FlexibleContexts #-}
4+{-# LANGUAGE GADTs #-}
5+{-# LANGUAGE MultiParamTypeClasses #-}
6+{-# LANGUAGE OverloadedStrings #-}
7+{-# LANGUAGE TemplateHaskell #-}
28module Reflex.Dom.Xhr
39 ( XMLHttpRequest
4− , XhrRequest(..)
5− , XhrRequestConfig(..)
6− , XhrResponse(..)
7− , XhrResponseBody(..)
8− , XhrResponseType(..)
9− , XhrException(..)
10+ , XhrRequest (..)
11+ , XhrRequestConfig (..)
12+ , XhrResponse (..)
13+ , XhrResponseBody (..)
14+ , XhrResponseType (..)
15+ , XhrException (..)
16+ , IsXhrPayload (..)
1017 , _xhrResponse_body
1118 , decodeText
1219 , decodeXhrResponse
@@ -42,7 +49,6 @@ module Reflex.Dom.Xhr
4249 , xmlHttpRequestNew
4350 , xmlHttpRequestOnreadystatechange
4451 , xmlHttpRequestOpen
45− , xmlHttpRequestSend
4652 , xmlHttpRequestSetRequestHeader
4753 , xmlHttpRequestSetResponseType
4854 )
@@ -50,20 +56,18 @@ where
5056
5157import Reflex
5258import Reflex.Dom.Class
53−import Reflex.Dom.Xhr.Foreign
5459import Reflex.Dom.PerformEvent.Class
5560import Reflex.Dom.Xhr.Exception
61+import Reflex.Dom.Xhr.Foreign
5662import Reflex.Dom.Xhr.ResponseType
5763
5864import Control.Concurrent
59−import Control.Exception (catch)
65+import Control.Exception (handle)
6066import Control.Lens
6167import Control.Monad hiding (forM)
6268import Control.Monad.IO.Class
6369import Data.Aeson
6470import Data.Aeson.Encode
65−import qualified Data.Text.Lazy as LT
66−import qualified Data.Text.Lazy.Builder as B
6771import qualified Data.ByteString.Lazy as BL
6872import Data.Default
6973import Data.Map (Map)
@@ -71,6 +75,8 @@ import qualified Data.Map as Map
7175import Data.Maybe
7276import Data.Text (Text)
7377import Data.Text.Encoding
78+import qualified Data.Text.Lazy as LT
79+import qualified Data.Text.Lazy.Builder as B
7480import Data.Traversable
7581import Data.Typeable
7682
@@ -79,7 +85,7 @@ data XhrRequest a
7985 , _xhrRequest_url :: Text
8086 , _xhrRequest_config :: XhrRequestConfig a
8187 }
82− deriving (Show, Read, Eq, Ord, Typeable)
88+ deriving (Show, Read, Eq, Ord, Typeable, Functor)
8389
8490data XhrRequestConfig a
8591 = XhrRequestConfig { _xhrRequestConfig_headers :: Map Text Text
@@ -88,7 +94,7 @@ data XhrRequestConfig a
8894 , _xhrRequestConfig_responseType :: Maybe XhrResponseType
8995 , _xhrRequestConfig_sendData :: a
9096 }
91− deriving (Show, Read, Eq, Ord, Typeable)
97+ deriving (Show, Read, Eq, Ord, Typeable, Functor)
9298
9399data XhrResponse
94100 = XhrResponse { _xhrResponse_status :: Word
@@ -134,7 +140,7 @@ newXMLHttpRequestWithError
134140newXMLHttpRequestWithError req cb = do
135141 wv <- askWebView
136142 xhr <- liftIO $ xmlHttpRequestNew $ unWebViewSingleton wv
137− void $ liftIO $ forkIO $ flip catch (cb . Left) $ void $ do
143+ void $ liftIO $ forkIO $ handle (cb . Left) $ void $ do
138144 let c = _xhrRequest_config req
139145 rt = _xhrRequestConfig_responseType c
140146 xmlHttpRequestOpen
@@ -150,20 +156,18 @@ newXMLHttpRequestWithError req cb = do
150156 readyState <- liftIO $ xmlHttpRequestGetReadyState xhr
151157 status <- liftIO $ xmlHttpRequestGetStatus xhr
152158 statusText <- liftIO $ xmlHttpRequestGetStatusText xhr
153− if readyState == 4
154− then do
155− t <- if rt == Just XhrResponseType_Text || rt == Nothing
156− then liftIO $ xmlHttpRequestGetResponseText xhr
157− else return Nothing
158− r <- liftIO $ xmlHttpRequestGetResponse xhr
159− _ <- liftIO $ cb $ Right $
160− XhrResponse { _xhrResponse_status = status
161− , _xhrResponse_statusText = statusText
162− , _xhrResponse_response = r
163− , _xhrResponse_responseText = t
164− }
165− return ()
166− else return ()
159+ when (readyState == 4) $ do
160+ t <- if rt == Just XhrResponseType_Text || isNothing rt
161+ then liftIO $ xmlHttpRequestGetResponseText xhr
162+ else return Nothing
163+ r <- liftIO $ xmlHttpRequestGetResponse xhr
164+ _ <- liftIO $ cb $ Right $ XhrResponse
165+ { _xhrResponse_status = status
166+ , _xhrResponse_statusText = statusText
167+ , _xhrResponse_response = r
168+ , _xhrResponse_responseText = t
169+ }
170+ return ()
167171 _ <- xmlHttpRequestSend xhr (_xhrRequestConfig_sendData c)
168172 return ()
169173 return xhr
@@ -255,8 +259,9 @@ decodeText = decode . BL.fromStrict . encodeUtf8
255259decodeXhrResponse :: FromJSON a => XhrResponse -> Maybe a
256260decodeXhrResponse = join . fmap decodeText . _xhrResponse_responseText
257261
258−liftM concat $ mapM makeLenses
262+concat <$> mapM makeLenses
259263 [ ''XhrRequest
260264 , ''XhrRequestConfig
261265 , ''XhrResponse
262266 ]
267+
src/Reflex/Dom/Xhr/Exception.hs+1−1
@@ -2,8 +2,8 @@
22
33module Reflex.Dom.Xhr.Exception where
44
5+import Control.Exception (Exception (..))
56import Data.Typeable
6−import Control.Exception (Exception(..))
77
88data XhrException = XhrException_Error
99 | XhrException_Aborted
src/Reflex/Dom/Xhr/ResponseType.hs+2−2
@@ -2,10 +2,10 @@
22
33module Reflex.Dom.Xhr.ResponseType where
44
5−import Data.Typeable
5+import Data.ByteString (ByteString)
66import Data.Text (Text)
7+import Data.Typeable
78import GHCJS.DOM.Blob (Blob)
8−import Data.ByteString (ByteString)
99
1010data XhrResponseType = XhrResponseType_Default
1111 | XhrResponseType_ArrayBuffer
test/BrokenHaltSpec.hs+9−10
@@ -2,13 +2,13 @@
22
33module HaltSpec where
44
5−import Control.Monad.IO.Class
6−import Data.Foldable
7−import GHCJS.DOM
5+import Control.Monad.IO.Class
6+import Data.Foldable
7+import GHCJS.DOM
88import qualified Graphics.UI.Gtk as Gtk
9−import Reflex.Dom
10−import Reflex.Spider.Internal (SpiderHostFrame)
11−import Test.Hspec
9+import Reflex.Dom
10+import Reflex.Spider.Internal (SpiderHostFrame)
11+import Test.Hspec
1212
1313spec :: Spec
1414spec = do
@@ -34,7 +34,6 @@ getFirstEventAndHalt action = do
3434 return ()
3535
3636haltGui :: WebView -> IO ()
37−haltGui wv = do
38− Gtk.postGUIAsync $ do
39− w <- Gtk.widgetGetToplevel wv
40− Gtk.widgetDestroy w
37+haltGui wv = Gtk.postGUIAsync $ do
38+ w <- Gtk.widgetGetToplevel wv
39+ Gtk.widgetDestroy w
test/HaltSpec.hs+13−15
@@ -1,29 +1,27 @@
11{-# LANGUAGE FlexibleContexts #-}
22
3−import Control.Monad.IO.Class
4−import Data.Foldable
5−import GHCJS.DOM
3+import Control.Monad.IO.Class
4+import Data.Foldable
5+import GHCJS.DOM
66import qualified Graphics.UI.Gtk as Gtk
7−import Reflex.Dom
8−import Reflex.Spider.Internal (SpiderHostFrame)
7+import Reflex.Dom
8+import Reflex.Spider.Internal (SpiderHostFrame)
99
10+main :: IO ()
1011main = do
1112 getFirstEventAndHalt return
1213 putStrLn "stopped once"
1314
14− forM_ [1 .. 1000] $ \ i -> do
15− getFirstEventAndHalt return
15+ forM_ [1 .. 1000] $ \i -> getFirstEventAndHalt return
1616 putStrLn "stopped many times"
1717
1818type SpiderM = Widget Spider (Gui Spider (WithWebView SpiderHost) SpiderHostFrame)
1919
2020getFirstEventAndHalt :: (Event Spider () -> SpiderM (Event Spider ())) -> IO ()
21−getFirstEventAndHalt action = do
22− _ <- mainWidget $ do
23− tick <- getPostBuild
24− event <- action tick
25− webView <- askWebView
26− quit <- getQuitWidget
27− performEvent_ (quit <$ event)
28− return ()
21+getFirstEventAndHalt action = mainWidget $ do
22+ tick <- getPostBuild
23+ event <- action tick
24+ webView <- askWebView
25+ quit <- getQuitWidget
26+ performEvent_ (quit <$ event)
2927 return ()
test/hlint.hsnew file+12
@@ -0,0 +1,12 @@
1+import Language.Haskell.HLint3 (hlint)
2+import System.Exit (exitFailure, exitSuccess)
3+
4+main :: IO ()
5+main = do
6+ ideas <- hlint
7+ [ "."
8+ , "--ignore=Redundant do"
9+ , "--ignore=Use camelCase"
10+ , "--ignore=Redundant $"
11+ ]
12+ if null ideas then exitSuccess else exitFailure