on develop help sign in
Merge branch 'refactor' of github.com:reflex-frp/reflex-dom into refactor
cc768a7Ryan Trinkle
.gitignore+1
@@ -1,4 +1,5 @@
1dist
1dist
2+dist-*
2cabal-dev
3cabal-dev
3*.o
4*.o
4*.hi
5*.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 @@
3, transformers, data-default, semigroups, blaze-builder, aeson
3, transformers, data-default, semigroups, blaze-builder, aeson
4, ghc, webkitgtk3-javascriptcore, exception-transformers
4, ghc, webkitgtk3-javascriptcore, exception-transformers
5, webkitgtk24x, dependent-sum-template, bifunctors, bimap
5, 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
7}:
8}:
8
9
9mkDerivation {
10mkDerivation {
@@ -11,27 +12,39 @@ mkDerivation {
11 version = "0.3";
12 version = "0.3";
12 src = builtins.filterSource (path: type: baseNameOf path != ".git") ./.;
13 src = builtins.filterSource (path: type: baseNameOf path != ".git") ./.;
13 buildDepends = [
14 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
26 aeson
15 aeson
27− exception-transformers
28− dependent-sum-template
29 bifunctors
16 bifunctors
30− zenc
31− random
32 bimap
17 bimap
18+ blaze-builder
19+ data-default
20+ dependent-map
21+ dependent-sum-template
22+ exception-transformers
23+ ghcjs-dom
24+ keycode
25+ lens
33 monad-control
26 monad-control
34− ] ++ (if (ghc.pname or null) == "ghcjs" then [ ] else [ 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+ ];
35− pkgconfigDepends = if (ghc.pname or null) == "ghcjs" then [ ] else [ webkitgtk24x webkitgtk3-javascriptcore raw-strings-qq ];
44+ pkgconfigDepends = if ghc.isGhcjs or false then [] else [
45+ raw-strings-qq
46+ webkitgtk24x
47+ webkitgtk3-javascriptcore
48+ ];
36 license = null;
49 license = null;
37}
50}
reflex-dom.cabal+9−1
@@ -50,7 +50,9 @@ library
50 zenc == 0.1.*,
50 zenc == 0.1.*,
51 bifunctors >= 4.2 && < 6,
51 bifunctors >= 4.2 && < 6,
52 bimap >= 0.3 && < 0.4,
52 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
54
56
55 if impl(ghcjs)
57 if impl(ghcjs)
56 hs-source-dirs: src-ghcjs
58 hs-source-dirs: src-ghcjs
@@ -104,6 +106,12 @@ library
104 other-extensions: TemplateHaskell
106 other-extensions: TemplateHaskell
105 ghc-options: -Wall -fwarn-tabs -funbox-strict-fields -O2 -ferror-spans
107 ghc-options: -Wall -fwarn-tabs -funbox-strict-fields -O2 -ferror-spans
106
108
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+
107source-repository head
115source-repository head
108 type: git
116 type: git
109 location: https://github.com/reflex-frp/reflex-dom
117 location: https://github.com/reflex-frp/reflex-dom
src-ghc/Reflex/Dom/Internal/Foreign.hs+22−19
@@ -1,12 +1,21 @@
1+{-# LANGUAGE CPP #-}
1−{-# LANGUAGE CPP, ForeignFunctionInterface, ScopedTypeVariables, LambdaCase, OverloadedStrings #-}
2+{-# LANGUAGE ForeignFunctionInterface #-}
3+{-# LANGUAGE LambdaCase #-}
4+{-# LANGUAGE OverloadedStrings #-}
5+{-# LANGUAGE ScopedTypeVariables #-}
2module Reflex.Dom.Internal.Foreign where
6module Reflex.Dom.Internal.Foreign where
3
7
4import Control.Concurrent
8import Control.Concurrent
5import Control.Exception (bracket)
9import Control.Exception (bracket)
6import Control.Lens hiding (set)
10import Control.Lens hiding (set)
7import Control.Monad
11import 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_)
9import Data.ByteString (ByteString)
13import 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
10import Foreign.Marshal hiding (void)
19import Foreign.Marshal hiding (void)
11import Foreign.Ptr
20import Foreign.Ptr
12import GHCJS.DOM hiding (runWebGUI)
21import GHCJS.DOM hiding (runWebGUI)
@@ -18,17 +27,13 @@ import Graphics.UI.Gtk.WebKit.JavaScriptCore.JSObjectRef
18import Graphics.UI.Gtk.WebKit.JavaScriptCore.JSStringRef
27import Graphics.UI.Gtk.WebKit.JavaScriptCore.JSStringRef
19import Graphics.UI.Gtk.WebKit.JavaScriptCore.JSValueRef
28import Graphics.UI.Gtk.WebKit.JavaScriptCore.JSValueRef
20import Graphics.UI.Gtk.WebKit.JavaScriptCore.WebFrame
29import 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)
22import Graphics.UI.Gtk.WebKit.WebFrame
31import Graphics.UI.Gtk.WebKit.WebFrame
23import Graphics.UI.Gtk.WebKit.WebInspector
32import Graphics.UI.Gtk.WebKit.WebInspector
24import Graphics.UI.Gtk.WebKit.WebSettings
33import Graphics.UI.Gtk.WebKit.WebSettings
25import Graphics.UI.Gtk.WebKit.WebView
34import Graphics.UI.Gtk.WebKit.WebView
26import System.Directory
35import System.Directory
27import System.Glib.FFI hiding (void)
36import 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
32
37
33#ifndef mingw32_HOST_OS
38#ifndef mingw32_HOST_OS
34import System.Posix.Signals
39import System.Posix.Signals
@@ -113,29 +118,27 @@ toJSObject ctx args = do
113fromJSStringMaybe :: JSContextRef -> JSValueRef -> IO (Maybe Text)
118fromJSStringMaybe :: JSContextRef -> JSValueRef -> IO (Maybe Text)
114fromJSStringMaybe c t = do
119fromJSStringMaybe c t = do
115 isNull <- jsvalueisnull c t
120 isNull <- jsvalueisnull c t
116− case isNull of
117− True -> return Nothing
121+ if isNull then return Nothing else do
118− False -> do
119− j <- jsvaluetostringcopy c t nullPtr
122+ j <- jsvaluetostringcopy c t nullPtr
120− l <- jsstringgetmaximumutf8cstringsize j
123+ l <- jsstringgetmaximumutf8cstringsize j
121− s <- allocaBytes (fromIntegral l) $ \ps -> do
124+ s <- allocaBytes (fromIntegral l) $ \ps -> do
122− _ <- jsstringgetutf8cstring'_ j ps (fromIntegral l)
125+ _ <- jsstringgetutf8cstring'_ j ps (fromIntegral l)
123− peekCString ps
126+ peekCString ps
124− return $ Just $ T.pack s
127+ return $ Just $ T.pack s
125
128
126getLocationHost :: WebView -> IO Text
129getLocationHost :: WebView -> IO Text
127getLocationHost wv = withWebViewContext wv $ \c -> do
130getLocationHost wv = withWebViewContext wv $ \c -> do
128 script <- jsstringcreatewithutf8cstring "location.host"
131 script <- jsstringcreatewithutf8cstring "location.host"
129 lh <- jsevaluatescript c script nullPtr nullPtr 1 nullPtr
132 lh <- jsevaluatescript c script nullPtr nullPtr 1 nullPtr
130 lh' <- fromJSStringMaybe c lh
133 lh' <- fromJSStringMaybe c lh
131− return $ maybe "" id lh'
134+ return $ fromMaybe "" lh'
132
135
133getLocationProtocol :: WebView -> IO Text
136getLocationProtocol :: WebView -> IO Text
134getLocationProtocol wv = withWebViewContext wv $ \c -> do
137getLocationProtocol wv = withWebViewContext wv $ \c -> do
135 script <- jsstringcreatewithutf8cstring "location.protocol"
138 script <- jsstringcreatewithutf8cstring "location.protocol"
136 lp <- jsevaluatescript c script nullPtr nullPtr 1 nullPtr
139 lp <- jsevaluatescript c script nullPtr nullPtr 1 nullPtr
137 lp' <- fromJSStringMaybe c lp
140 lp' <- fromJSStringMaybe c lp
138− return $ maybe "" id lp'
141+ return $ fromMaybe "" lp'
139
142
140bsToArrayBuffer :: JSContextRef -> ByteString -> IO JSValueRef
143bsToArrayBuffer :: JSContextRef -> ByteString -> IO JSValueRef
141bsToArrayBuffer c bs = do
144bsToArrayBuffer c bs = do
@@ -159,7 +162,7 @@ bsFromArrayBuffer c a = do
159 i' <- jsvaluemakenumber c (fromIntegral i)
162 i' <- jsvaluemakenumber c (fromIntegral i)
160 args <- toJSObject c [uint8Array, i']
163 args <- toJSObject c [uint8Array, i']
161 getIntegral =<< jsevaluatescript c getIx args nullPtr 1 nullPtr
164 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
163
166
164withWebViewContext :: WebView -> (JSContextRef -> IO a) -> IO a
167withWebViewContext :: WebView -> (JSContextRef -> IO a) -> IO a
165withWebViewContext wv f = f =<< webFrameGetGlobalContext =<< webViewGetMainFrame wv
168withWebViewContext 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 #-}
2
14
3module Reflex.Dom.WebSocket.Foreign where
15module Reflex.Dom.WebSocket.Foreign where
4
16
5−import Prelude hiding (div, span, mapM, mapM_, concat, concatMap, all, sequence)
17+import Prelude hiding (all, concat, concatMap, div, mapM, mapM_, sequence, span)
6
18
7import Control.Exception
19import Control.Exception
8import Control.Monad.State
20import Control.Monad.State
9import Data.ByteString (ByteString)
21import Data.ByteString (ByteString)
22+import qualified Data.ByteString as BS
23+import Data.Text (Text)
24+import qualified Data.Text as T
10import Data.Text.Encoding
25import Data.Text.Encoding
11import Foreign.Marshal hiding (void)
26import Foreign.Marshal hiding (void)
12import Foreign.Ptr
27import Foreign.Ptr
@@ -16,9 +31,6 @@ import Graphics.UI.Gtk.WebKit.JavaScriptCore.JSObjectRef
16import Graphics.UI.Gtk.WebKit.JavaScriptCore.JSStringRef
31import Graphics.UI.Gtk.WebKit.JavaScriptCore.JSStringRef
17import Graphics.UI.Gtk.WebKit.JavaScriptCore.JSValueRef
32import Graphics.UI.Gtk.WebKit.JavaScriptCore.JSValueRef
18import Graphics.UI.Gtk.WebKit.WebView
33import Graphics.UI.Gtk.WebKit.WebView
19−import qualified Data.ByteString as BS
20−import Data.Text (Text)
21−import qualified Data.Text as T
22
34
23import Reflex.Dom.Internal.Foreign
35import Reflex.Dom.Internal.Foreign
24
36
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 #-}
2module Reflex.Dom.Xhr.Foreign ( module Reflex.Dom.Xhr.Foreign
5module Reflex.Dom.Xhr.Foreign ( module Reflex.Dom.Xhr.Foreign
3 , XhrResponseType
6 , XhrResponseType
4 ) where
7 ) where
5
8
9+import Control.Concurrent.MVar
10+import Control.Exception.Base
6import Control.Monad
11import Control.Monad
7−import qualified Data.Text as T
8import Data.Text (Text)
12import Data.Text (Text)
9−import System.Glib.FFI
13+import qualified Data.Text as T
10−import Graphics.UI.Gtk.WebKit.WebView
14+import GHCJS.DOM.File
11import Graphics.UI.Gtk.WebKit.JavaScriptCore.JSBase
15import Graphics.UI.Gtk.WebKit.JavaScriptCore.JSBase
12import Graphics.UI.Gtk.WebKit.JavaScriptCore.JSObjectRef
16import Graphics.UI.Gtk.WebKit.JavaScriptCore.JSObjectRef
13import Graphics.UI.Gtk.WebKit.JavaScriptCore.JSStringRef
17import Graphics.UI.Gtk.WebKit.JavaScriptCore.JSStringRef
14import Graphics.UI.Gtk.WebKit.JavaScriptCore.JSValueRef
18import 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
20import Graphics.UI.Gtk.WebKit.Types hiding (Text)
19import Graphics.UI.Gtk.WebKit.Types hiding (Text)
20+import Reflex.Dom.Xhr.Exception
21+import Reflex.Dom.Xhr.ResponseType
22+import System.Glib.FFI
21
23
22import Reflex.Dom.Internal.Foreign
24import Reflex.Dom.Internal.Foreign
23
25
@@ -111,14 +113,12 @@ xmlHttpRequestGetResponse xhr = do
111 script <- jsstringcreatewithutf8cstring "this.response"
113 script <- jsstringcreatewithutf8cstring "this.response"
112 t <- jsevaluatescript c script (xhrValue xhr) nullPtr 1 nullPtr
114 t <- jsevaluatescript c script (xhrValue xhr) nullPtr 1 nullPtr
113 isNull <- jsvalueisnull c t
115 isNull <- jsvalueisnull c t
114− case isNull of
115− True -> return Nothing
116+ if isNull then return Nothing else case mrt of
116− False -> case mrt of
117− Just XhrResponseType_ArrayBuffer -> Just . XhrResponseBody_ArrayBuffer <$> bsFromArrayBuffer c t
117+ Just XhrResponseType_ArrayBuffer -> Just . XhrResponseBody_ArrayBuffer <$> bsFromArrayBuffer c t
118− Just XhrResponseType_Blob -> Just . XhrResponseBody_Blob . Blob . castForeignPtr <$> newForeignPtr_ t
118+ Just XhrResponseType_Blob -> Just . XhrResponseBody_Blob . Blob . castForeignPtr <$> newForeignPtr_ t
119− Just XhrResponseType_Default -> fmap (XhrResponseBody_Default) <$> fromJSStringMaybe c t
119+ Just XhrResponseType_Default -> fmap XhrResponseBody_Default <$> fromJSStringMaybe c t
120− Just XhrResponseType_Text -> fmap (XhrResponseBody_Text) <$> fromJSStringMaybe c t
120+ Just XhrResponseType_Text -> fmap XhrResponseBody_Text <$> fromJSStringMaybe c t
121− _ -> return Nothing
121+ _ -> return Nothing
122
122
123xmlHttpRequestGetResponseText :: XMLHttpRequest -> IO (Maybe Text)
123xmlHttpRequestGetResponseText :: XMLHttpRequest -> IO (Maybe Text)
124xmlHttpRequestGetResponseText xhr = do
124xmlHttpRequestGetResponseText xhr = do
@@ -138,17 +138,11 @@ xmlHttpRequestSendPayload xhr payload = do
138 onError <- jsobjectmakefunctionwithcallback c nullPtr e
138 onError <- jsobjectmakefunctionwithcallback c nullPtr e
139 bracket (wrapper' Nothing) freeHaskellFunPtr $ \l -> do
139 bracket (wrapper' Nothing) freeHaskellFunPtr $ \l -> do
140 onLoad <- jsobjectmakefunctionwithcallback c nullPtr l
140 onLoad <- jsobjectmakefunctionwithcallback c nullPtr l
141− (o,s) <- case payload of
141+ d <- case payload of
142− Nothing -> do
143− d <- jsvaluemakeundefined c
142+ Nothing -> 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'
143+ Just payload' -> stringToJSValue c payload'
149− o <- toJSObject c [xhrValue xhr, d, onError, onAbort, onLoad]
144+ o <- toJSObject c [xhrValue xhr, d, onError, onAbort, onLoad]
150− s <- jsstringcreatewithutf8cstring send
145+ s <- jsstringcreatewithutf8cstring send
151− return (o,s)
152 _ <- jsevaluatescript c s o nullPtr 1 nullPtr
146 _ <- jsevaluatescript c s o nullPtr 1 nullPtr
153 takeMVar result >>= mapM_ throwIO
147 takeMVar result >>= mapM_ throwIO
154 where
148 where
src-ghcjs/Reflex/Dom/Internal/Foreign.hs+8−8
@@ -1,19 +1,19 @@
1−{-# LANGUAGE ForeignFunctionInterface, JavaScriptFFI #-}
1+{-# LANGUAGE ForeignFunctionInterface #-}
2+{-# LANGUAGE JavaScriptFFI #-}
2module Reflex.Dom.Internal.Foreign ( module Reflex.Dom.Internal.Foreign
3module Reflex.Dom.Internal.Foreign ( module Reflex.Dom.Internal.Foreign
3 , runWebGUI
4 , runWebGUI
4 ) where
5 ) where
5
6
6−import Control.Monad
7import Data.ByteString (ByteString)
7import Data.ByteString (ByteString)
8+import qualified Data.ByteString as BS
8import Foreign
9import Foreign
9import Foreign.C
10import Foreign.C
11+import qualified GHCJS.Buffer as JS
10import GHCJS.DOM
12import GHCJS.DOM
11import GHCJS.DOM.Types
13import GHCJS.DOM.Types
14+import qualified GHCJS.Marshal.Pure as JS
12import GHCJS.Types
15import GHCJS.Types
13import JavaScript.TypedArray.ArrayBuffer as JS
16import 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
17
17
18quitWebView :: WebView -> IO ()
18quitWebView :: WebView -> IO ()
19quitWebView = error "quitWebView: unimplemented in GHCJS"
19quitWebView = error "quitWebView: unimplemented in GHCJS"
@@ -21,12 +21,12 @@ quitWebView = error "quitWebView: unimplemented in GHCJS"
21foreign import javascript unsafe "location['host']" getLocationHost_ :: IO JSString
21foreign import javascript unsafe "location['host']" getLocationHost_ :: IO JSString
22
22
23getLocationHost :: FromJSString r => a -> IO r
23getLocationHost :: FromJSString r => a -> IO r
24−getLocationHost _ = liftM fromJSString getLocationHost_
24+getLocationHost _ = fmap fromJSString getLocationHost_
25
25
26foreign import javascript unsafe "location['protocol']" getLocationProtocol_ :: IO JSString
26foreign import javascript unsafe "location['protocol']" getLocationProtocol_ :: IO JSString
27
27
28getLocationProtocol :: FromJSString r => a -> IO r
28getLocationProtocol :: FromJSString r => a -> IO r
29−getLocationProtocol _ = liftM fromJSString getLocationProtocol_
29+getLocationProtocol _ = fmap fromJSString getLocationProtocol_
30
30
31withWebViewContext :: a -> (a -> IO b) -> IO b
31withWebViewContext :: a -> (a -> IO b) -> IO b
32withWebViewContext a f = f a
32withWebViewContext a f = f a
@@ -40,4 +40,4 @@ bsToArrayBuffer _ bs = BS.useAsCString bs $ \cStr -> do
40 extractByteArray cStr $ BS.length bs
40 extractByteArray cStr $ BS.length bs
41
41
42bsFromArrayBuffer :: a -> JSVal -> IO ByteString
42bsFromArrayBuffer :: 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 #-}
2
3
3module Reflex.Dom.WebSocket.Foreign where
4module Reflex.Dom.WebSocket.Foreign where
4
5
5−import Prelude hiding (div, span, mapM, mapM_, concat, concatMap, all, sequence)
6+import Prelude hiding (all, concat, concatMap, div, mapM, mapM_, sequence, span)
6
7
8+import Control.Monad.IO.Class
9+import Control.Monad.Reader
7import Data.ByteString (ByteString)
10import Data.ByteString (ByteString)
8import qualified Data.ByteString as BS
11import qualified Data.ByteString as BS
9−import GHCJS.Types
12+import Data.Text (Text)
10−import GHCJS.DOM.WebSocket (message, open, closeEvent)
13+import Data.Text.Encoding
11−import qualified GHCJS.DOM.WebSocket as GD
12−import GHCJS.DOM.MessageEvent
14+import GHCJS.Buffer
13import GHCJS.DOM.EventM (on)
15import GHCJS.DOM.EventM (on)
16+import GHCJS.DOM.MessageEvent
14import GHCJS.DOM.Types hiding (Text)
17import GHCJS.DOM.Types hiding (Text)
15−import Control.Monad.IO.Class
18+import GHCJS.DOM.WebSocket (closeEvent, message, open)
16−import Control.Monad.Reader
19+import qualified GHCJS.DOM.WebSocket as GD
17−import GHCJS.Buffer
18−import JavaScript.TypedArray.ArrayBuffer as JS
19−import GHCJS.Marshal.Pure
20import GHCJS.Foreign.Internal
20import GHCJS.Foreign.Internal
21−import Data.Text.Encoding
21+import GHCJS.Marshal.Pure
22−import Data.Text (Text)
22+import GHCJS.Types
23+import JavaScript.TypedArray.ArrayBuffer as JS
23
24
24data JSWebSocket = JSWebSocket { unWebSocket :: WebSocket }
25data JSWebSocket = JSWebSocket { unWebSocket :: WebSocket }
25
26
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 #-}
2
5
3module Reflex.Dom.Xhr.Foreign (
6module Reflex.Dom.Xhr.Foreign (
4 XMLHttpRequest
7 XMLHttpRequest
@@ -6,20 +9,20 @@ module Reflex.Dom.Xhr.Foreign (
6 , module Reflex.Dom.Xhr.Foreign
9 , module Reflex.Dom.Xhr.Foreign
7) where
10) where
8
11
9−import Prelude hiding (error)
12+import Control.Exception (catch, throwIO)
13+import Data.Maybe (fromMaybe)
10import Data.Text (Text)
14import Data.Text (Text)
11−import GHCJS.DOM.Types hiding (Text)
12import GHCJS.DOM
15import GHCJS.DOM
13import GHCJS.DOM.Enums
16import GHCJS.DOM.Enums
14−import GHCJS.DOM.XMLHttpRequest
15−import Data.Maybe (fromMaybe)
16−import GHCJS.DOM.EventTarget (dispatchEvent)
17import GHCJS.DOM.EventM (EventM, on)
17import 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)
18import Reflex.Dom.Internal.Foreign
23import Reflex.Dom.Internal.Foreign
19import Reflex.Dom.Xhr.Exception
24import Reflex.Dom.Xhr.Exception
20import Reflex.Dom.Xhr.ResponseType
25import Reflex.Dom.Xhr.ResponseType
21−import Control.Exception (catch, throwIO)
22−import GHCJS.Types
23
26
24prepareWebView :: WebView -> IO ()
27prepareWebView :: WebView -> IO ()
25prepareWebView _ = return ()
28prepareWebView _ = return ()
@@ -163,11 +166,11 @@ xmlHttpRequestGetResponse xhr = do
163 mr <- getResponse xhr
166 mr <- getResponse xhr
164 rt <- xmlHttpRequestGetResponseType xhr
167 rt <- xmlHttpRequestGetResponseType xhr
165 case rt of
168 case rt of
166− Just XhrResponseType_Blob -> return $ fmap (XhrResponseBody_Blob . castToBlob) mr
169+ Just XhrResponseType_Blob -> return $ XhrResponseBody_Blob . castToBlob <$> mr
167− Just XhrResponseType_Text -> fmap (Just . XhrResponseBody_Text) $ xmlHttpRequestGetStatusText xhr
170+ Just XhrResponseType_Text -> Just . XhrResponseBody_Text <$> xmlHttpRequestGetStatusText xhr
168− Just XhrResponseType_Default -> fmap (Just . XhrResponseBody_Text) $ xmlHttpRequestGetStatusText xhr
171+ Just XhrResponseType_Default -> Just . XhrResponseBody_Text <$> xmlHttpRequestGetStatusText xhr
169− Just XhrResponseType_ArrayBuffer -> case (fmap unGObject mr) of
172+ Just XhrResponseType_ArrayBuffer -> case fmap unGObject mr of
170 Nothing -> return Nothing
173 Nothing -> return Nothing
171− Just ptr -> fmap (Just . XhrResponseBody_ArrayBuffer) $ bsFromArrayBuffer ptr ptr
174+ Just ptr -> Just . XhrResponseBody_ArrayBuffer <$> bsFromArrayBuffer ptr ptr
172 _ -> return Nothing
175 _ -> return Nothing
173
176
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 #-}
2#ifdef __GHCJS__
16#ifdef __GHCJS__
3{-# LANGUAGE JavaScriptFFI #-}
17{-# LANGUAGE JavaScriptFFI #-}
4#endif
18#endif
@@ -7,58 +21,58 @@ module Foreign.JavaScript.TH ( module Foreign.JavaScript.TH
7 ) where
21 ) where
8
22
9import Reflex.Class
23import Reflex.Class
10−import Reflex.Host.Class
11−import Reflex.Dom.PerformEvent.Class
12import Reflex.Dom.Deletable.Class
24import Reflex.Dom.Deletable.Class
25+import Reflex.Dom.PerformEvent.Class
26+import Reflex.Host.Class
13
27
14import Language.Haskell.TH
28import Language.Haskell.TH
15
29
16#ifdef __GHCJS__
30#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
22import qualified GHCJS.Buffer as JS
31import qualified GHCJS.Buffer as JS
23import GHCJS.DOM
32import GHCJS.DOM
24−import GHCJS.DOM.Types hiding (fromJSString, Text)
33+import GHCJS.DOM.Types hiding (Text, fromJSString)
25import qualified GHCJS.DOM.Types as JS
34import 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
26import qualified JavaScript.Array as JS
41import qualified JavaScript.Array as JS
42+import qualified JavaScript.Array.Internal (SomeJSArray (..))
27import qualified JavaScript.Object as JS
43import qualified JavaScript.Object as JS
28import qualified JavaScript.Object.Internal (Object (..))
44import qualified JavaScript.Object.Internal (Object (..))
29−import qualified GHCJS.Foreign.Callback.Internal (Callback (..))
30−import qualified JavaScript.Array.Internal (SomeJSArray (..))
31import qualified JavaScript.TypedArray.ArrayBuffer as JSArrayBuffer
45import qualified JavaScript.TypedArray.ArrayBuffer as JSArrayBuffer
32
46
47+import Data.Hashable
33import Data.Word
48import Data.Word
34−import Foreign.Ptr
35import Foreign.C.Types
49import Foreign.C.Types
36−import Data.Hashable
50+import Foreign.Ptr
37import Text.Encoding.Z
51import Text.Encoding.Z
38#else
52#else
39−import System.Glib.FFI
53+import Foreign.Marshal
40−import Graphics.UI.Gtk.WebKit.WebView
54+import Graphics.UI.Gtk.WebKit.DOM.Node
41import Graphics.UI.Gtk.WebKit.JavaScriptCore.JSBase
55import Graphics.UI.Gtk.WebKit.JavaScriptCore.JSBase
42import Graphics.UI.Gtk.WebKit.JavaScriptCore.JSObjectRef
56import Graphics.UI.Gtk.WebKit.JavaScriptCore.JSObjectRef
43import Graphics.UI.Gtk.WebKit.JavaScriptCore.JSStringRef
57import Graphics.UI.Gtk.WebKit.JavaScriptCore.JSStringRef
44import Graphics.UI.Gtk.WebKit.JavaScriptCore.JSValueRef
58import Graphics.UI.Gtk.WebKit.JavaScriptCore.JSValueRef
45import Graphics.UI.Gtk.WebKit.JavaScriptCore.WebFrame
59import Graphics.UI.Gtk.WebKit.JavaScriptCore.WebFrame
46−import Graphics.UI.Gtk.WebKit.DOM.Node
60+import Graphics.UI.Gtk.WebKit.WebView
47−import Foreign.Marshal
61+import System.Glib.FFI
48#endif
62#endif
49
63
64+import Control.Concurrent
50import Control.Monad
65import Control.Monad
51−import Control.Monad.Ref
66+import Control.Monad.Exception
52import Control.Monad.Fix
67import Control.Monad.Fix
53import Control.Monad.IO.Class
68import Control.Monad.IO.Class
54−import Control.Monad.Exception
55import Control.Monad.Reader
69import Control.Monad.Reader
70+import Control.Monad.Ref
56import Control.Monad.State
71import Control.Monad.State
57−import Control.Monad.Trans.Control
58import qualified Control.Monad.State.Strict as Strict
72import qualified Control.Monad.State.Strict as Strict
73+import Control.Monad.Trans.Control
59import Data.ByteString (ByteString)
74import Data.ByteString (ByteString)
60import qualified Data.ByteString as BS
75import qualified Data.ByteString as BS
61−import Control.Concurrent
62import Data.Coerce
76import Data.Coerce
63import Data.Monoid
77import Data.Monoid
64import Data.Text (Text)
78import Data.Text (Text)
@@ -213,15 +227,15 @@ instance IsJSContext JSCtx_IO where
213 newtype JSRef JSCtx_IO = JSRef_IO { unJSRef_IO :: JS.JSVal }
227 newtype JSRef JSCtx_IO = JSRef_IO { unJSRef_IO :: JS.JSVal }
214
228
215instance MonadJS JSCtx_IO IO where
229instance 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)
217 forkJS = forkIO
231 forkJS = forkIO
218 mkJSUndefined = return $ JSRef_IO JS.jsUndefined
232 mkJSUndefined = return $ JSRef_IO JS.jsUndefined
219 isJSNull (JSRef_IO r) = return $ JS.isNull r
233 isJSNull (JSRef_IO r) = return $ JS.isNull r
220 isJSUndefined (JSRef_IO r) = return $ JS.isUndefined r
234 isJSUndefined (JSRef_IO r) = return $ JS.isUndefined r
221 fromJSBool (JSRef_IO r) = return $ JS.fromJSBool r
235 fromJSBool (JSRef_IO r) = return $ JS.fromJSBool r
222 fromJSString (JSRef_IO r) = return $ JS.fromJSString $ JS.pFromJSVal r
236 fromJSString (JSRef_IO r) = return $ JS.fromJSString $ JS.pFromJSVal r
223− fromJSArray (JSRef_IO r) = liftM coerce $ JS.toListIO $ coerce r
237+ fromJSArray (JSRef_IO r) = fmap 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
238+ fromJSUint8Array (JSRef_IO r) = fmap (JS.toByteString 0 Nothing . JS.createFromArrayBuffer) $ JSArrayBuffer.unsafeFreeze $ JS.pFromJSVal r --TODO: Assert that this is immutable
225 fromJSNumber (JSRef_IO r) = do
239 fromJSNumber (JSRef_IO r) = do
226 Just n <- JS.fromJSVal r
240 Just n <- JS.fromJSVal r
227 return n
241 return n
@@ -241,7 +255,7 @@ instance MonadJS JSCtx_IO IO where
241 l <- JS.toListIO $ coerce args
255 l <- JS.toListIO $ coerce args
242 JSRef_IO result <- f $ coerce l
256 JSRef_IO result <- f $ coerce l
243 return result
257 return result
244− liftM (JSFun . JSRef_IO) $ funWithArguments $ coerce cb
258+ fmap (JSFun . JSRef_IO) $ funWithArguments $ coerce cb
245 freeJSFun (JSFun (JSRef_IO r)) = JS.releaseCallback $ coerce r
259 freeJSFun (JSFun (JSRef_IO r)) = JS.releaseCallback $ coerce r
246 setJSProp s (JSRef_IO v) (JSRef_IO o) = JS.setProp (JS.toJSString s) v $ coerce o
260 setJSProp s (JSRef_IO v) (JSRef_IO o) = JS.setProp (JS.toJSString s) v $ coerce o
247 getJSProp s (JSRef_IO o) = do
261 getJSProp s (JSRef_IO o) = do
@@ -294,7 +308,7 @@ instance MonadJS (JSCtx_JavaScriptCore x) (WithWebView x IO) where
294 liftIO $ forkIO $ runWithWebView a wv
308 liftIO $ forkIO $ runWithWebView a wv
295 mkJSUndefined = do
309 mkJSUndefined = do
296 jsContext <- askJSContext
310 jsContext <- askJSContext
297− liftM JSRef_JavaScriptCore $ liftIO $ jsvaluemakeundefined jsContext
311+ fmap JSRef_JavaScriptCore $ liftIO $ jsvaluemakeundefined jsContext
298 isJSNull (JSRef_JavaScriptCore r) = do
312 isJSNull (JSRef_JavaScriptCore r) = do
299 jsContext <- askJSContext
313 jsContext <- askJSContext
300 liftIO $ jsvalueisnull jsContext r
314 liftIO $ jsvalueisnull jsContext r
@@ -343,7 +357,7 @@ instance MonadJS (JSCtx_JavaScriptCore x) (WithWebView x IO) where
343 lenDouble <- fromJSNumberRaw lenRef
357 lenDouble <- fromJSNumberRaw lenRef
344 let len = round lenDouble
358 let len = round lenDouble
345 liftIO $ forM [0..len-1] $ \i -> do
359 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
347 fromJSUint8Array a = do
361 fromJSUint8Array a = do
348 vals <- fromJSArray a
362 vals <- fromJSArray a
349 doubles <- mapM fromJSNumber vals
363 doubles <- mapM fromJSNumber vals
@@ -359,7 +373,7 @@ instance MonadJS (JSCtx_JavaScriptCore x) (WithWebView x IO) where
359 x <- peekElemOff argv n
373 x <- peekElemOff argv n
360 jsvalueprotect jsContext x
374 jsvalueprotect jsContext x
361 return $ JSRef_JavaScriptCore x --TODO: Unprotect eventually
375 return $ JSRef_JavaScriptCore x --TODO: Unprotect eventually
362− liftM unJSRef_JavaScriptCore $ runWithWebView (a args) wv
376+ unJSRef_JavaScriptCore <$> runWithWebView (a args) wv
363 cbRef <- liftIO $ jsobjectmakefunctionwithcallback jsContext nullPtr cb
377 cbRef <- liftIO $ jsobjectmakefunctionwithcallback jsContext nullPtr cb
364 liftIO $ jsvalueprotect jsContext cbRef
378 liftIO $ jsvalueprotect jsContext cbRef
365 return $ JSFun $ JSRef_JavaScriptCore cbRef
379 return $ JSFun $ JSRef_JavaScriptCore cbRef
@@ -373,7 +387,7 @@ instance MonadJS (JSCtx_JavaScriptCore x) (WithWebView x IO) where
373 getJSProp propName (JSRef_JavaScriptCore objRef) = do
387 getJSProp propName (JSRef_JavaScriptCore objRef) = do
374 withJSStringRaw propName $ \propNameRaw -> do
388 withJSStringRaw propName $ \propNameRaw -> do
375 jsContext <- askJSContext
389 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
377 withJSNode = error "withJSNode is only supported in ghcjs"
391 withJSNode = error "withJSNode is only supported in ghcjs"
378
392
379#endif
393#endif
@@ -399,7 +413,7 @@ instance FromJS x Text where
399instance FromJS x a => FromJS x (Maybe a) where
413instance FromJS x a => FromJS x (Maybe a) where
400 fromJS x = do
414 fromJS x = do
401 n <- isJSNull x
415 n <- isJSNull x
402− if n then return Nothing else liftM Just $ fromJS x
416+ if n then return Nothing else Just <$> fromJS x
403
417
404class ToJS x a where
418class ToJS x a where
405 withJS :: MonadJS x m => a -> (JSRef x -> m r) -> m r
419 withJS :: MonadJS x m => a -> (JSRef x -> m r) -> m r
@@ -422,7 +436,7 @@ instance ToJS x a => ToJS x (JSArray a) where
422 withJS = withJSArrayFromList . unJSArray
436 withJS = withJSArrayFromList . unJSArray
423
437
424instance FromJS x a => FromJS x (JSArray a) where
438instance FromJS x a => FromJS x (JSArray a) where
425− fromJS = liftM JSArray . mapM fromJS <=< fromJSArray
439+ fromJS = fmap JSArray . mapM fromJS <=< fromJSArray
426
440
427withJSArrayFromList :: (ToJS x a, MonadJS x m) => [a] -> (JSRef x -> m r) -> m r
441withJSArrayFromList :: (ToJS x a, MonadJS x m) => [a] -> (JSRef x -> m r) -> m r
428withJSArrayFromList as f = go as []
442withJSArrayFromList as f = go as []
@@ -444,7 +458,7 @@ instance ToJS x Int where
444 withJS n = withJSNumber $ fromIntegral n --TODO: Check things; throw exceptions
458 withJS n = withJSNumber $ fromIntegral n --TODO: Check things; throw exceptions
445
459
446instance FromJS x Int where
460instance FromJS x Int where
447− fromJS = liftM round . fromJSNumber --TODO: Check things; throw exceptions
461+ fromJS = fmap round . fromJSNumber --TODO: Check things; throw exceptions
448
462
449instance ToJS x Double where
463instance ToJS x Double where
450 withJS = withJSNumber
464 withJS = withJSNumber
src/Reflex/Dom.hs+16−31
@@ -1,32 +1,17 @@
1−module Reflex.Dom ( module Reflex
1+module Reflex.Dom (module X) where
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
17
2
18−import Reflex
3+import Reflex as X
19−import Reflex.Dom.Builder.Class
4+import Reflex.Dom.Builder.Class as X
20−import Reflex.Dom.Builder.Immediate
5+import Reflex.Dom.Builder.Immediate as X
21−import Reflex.Dom.Builder.Static
6+import Reflex.Dom.Builder.Static as X
22−import Reflex.Dom.Class
7+import Reflex.Dom.Class as X
23−import Reflex.Dom.DynamicWriter
8+import Reflex.Dom.DynamicWriter as X
24−import Reflex.Dom.Internal
9+import Reflex.Dom.Internal as X
25−import Reflex.Dom.Location
10+import Reflex.Dom.Location as X
26−import Reflex.Dom.Old
11+import Reflex.Dom.Old as X
27−import Reflex.Dom.PerformEvent.Class
12+import Reflex.Dom.PerformEvent.Class as X
28−import Reflex.Dom.PostBuild.Class
13+import Reflex.Dom.PostBuild.Class as X
29−import Reflex.Dom.Time
14+import Reflex.Dom.Time as X
30−import Reflex.Dom.WebSocket
15+import Reflex.Dom.WebSocket as X
31−import Reflex.Dom.Widget
16+import Reflex.Dom.Widget as X
32−import Reflex.Dom.Xhr
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 #-}
2module Reflex.Dom.Builder.Class
17module Reflex.Dom.Builder.Class
3 ( module Reflex.Dom.Builder.Class
18 ( module Reflex.Dom.Builder.Class
4 , module Reflex.Dom.Builder.Class.Events
19 , module Reflex.Dom.Builder.Class.Events
@@ -9,20 +24,20 @@ import Reflex
9import Reflex.Dom.Builder.Class.Events
24import Reflex.Dom.Builder.Class.Events
10import Reflex.Dom.Deletable.Class
25import Reflex.Dom.Deletable.Class
11
26
27+import qualified Control.Category
12import Control.Lens hiding (element)
28import Control.Lens hiding (element)
13import Control.Monad.Reader
29import Control.Monad.Reader
14import Control.Monad.Trans.Control
30import Control.Monad.Trans.Control
15import Data.Default
31import Data.Default
16−import Data.Functor.Misc
17−import Data.Map (Map)
18−import Data.Text (Text)
19import Data.Dependent.Map (DMap)
32import Data.Dependent.Map (DMap)
20import qualified Data.Dependent.Map as DMap
33import qualified Data.Dependent.Map as DMap
21−import Data.Semigroup
34+import Data.Functor.Misc
35+import Data.Map (Map)
22import Data.Proxy
36import Data.Proxy
23−import GHC.Exts (Constraint)
37+import Data.Semigroup
38+import Data.Text (Text)
24import Data.Type.Coercion
39import Data.Type.Coercion
25−import qualified Control.Category
40+import GHC.Exts (Constraint)
26
41
27data Pair1 (f :: k -> *) (g :: k -> *) (a :: k) = Pair1 (f a) (g a)
42data Pair1 (f :: k -> *) (g :: k -> *) (a :: k) = Pair1 (f a) (g a)
28
43
@@ -49,13 +64,15 @@ class (Monad m, Reflex t, Deletable t m, DomSpace (DomBuilderSpace m)) => DomBui
49type Namespace = Text
64type Namespace = Text
50
65
51data TextNodeConfig t
66data TextNodeConfig t
52− = TextNodeConfig { _textNodeConfig_contents :: Text
67+ = TextNodeConfig { _textNodeConfig_initialContents :: Text
68+ , _textNodeConfig_setContents :: Event t Text
53 }
69 }
54
70
55−instance Default (TextNodeConfig t) where
71+instance (Reflex t) => Default (TextNodeConfig t) where
56 {-# INLINABLE def #-}
72 {-# INLINABLE def #-}
57 def = TextNodeConfig
73 def = TextNodeConfig
58− { _textNodeConfig_contents = mempty
74+ { _textNodeConfig_initialContents = mempty
75+ , _textNodeConfig_setContents = never
59 }
76 }
60
77
61data TextNode t = TextNode
78data TextNode t = TextNode
@@ -96,6 +113,9 @@ instance Monoid EventFlags where
96preventDefault :: EventFlags
113preventDefault :: EventFlags
97preventDefault = mempty { _eventFlags_preventDefault = True }
114preventDefault = mempty { _eventFlags_preventDefault = True }
98
115
116+stopPropagation :: EventFlags
117+stopPropagation = mempty { _eventFlags_propagation = Propagation_Stop }
118+
99newtype EventFilter d er en = EventFilter (DomHandler d (RawEvent d en) (EventFlags, DomHandler d () (Maybe (er en))))
119newtype EventFilter d er en = EventFilter (DomHandler d (RawEvent d en) (EventFlags, DomHandler d () (Maybe (er en))))
100
120
101data ElementConfig er t m
121data ElementConfig er t m
@@ -135,7 +155,7 @@ instance Reflex t => Default (PlaceholderConfig above t m) where
135
155
136data Placeholder above t
156data Placeholder above t
137 = Placeholder { _placeholder_insertedAbove :: Event t above
157 = Placeholder { _placeholder_insertedAbove :: Event t above
138− , _placeholder_deleted :: Event t ()
158+ , _placeholder_deletedSelf :: Event t ()
139 }
159 }
140
160
141data InputElementConfig er t m
161data InputElementConfig er t m
@@ -244,7 +264,7 @@ instance Functor1 (ElementConfig er t) where
244instance Reflex t => Functor1 (PlaceholderConfig above t) where
264instance Reflex t => Functor1 (PlaceholderConfig above t) where
245 {-# INLINABLE fmap1 #-}
265 {-# INLINABLE fmap1 #-}
246 fmap1 f cfg = cfg
266 fmap1 f cfg = cfg
247− { _placeholderConfig_insertAbove = fmap f $ _placeholderConfig_insertAbove cfg
267+ { _placeholderConfig_insertAbove = f <$> _placeholderConfig_insertAbove cfg
248 }
268 }
249
269
250instance Functor1 (InputElementConfig er t) where
270instance Functor1 (InputElementConfig er t) where
@@ -262,7 +282,7 @@ class HasDomEvent t target eventName where
262instance Reflex t => HasDomEvent t (Element EventResult d t) en where
282instance Reflex t => HasDomEvent t (Element EventResult d t) en where
263 type DomEventType (Element EventResult d t) en = EventResultType en
283 type DomEventType (Element EventResult d t) en = EventResultType en
264 {-# INLINABLE domEvent #-}
284 {-# 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)
266
286
267instance Reflex t => HasDomEvent t (InputElement EventResult d t) en where
287instance Reflex t => HasDomEvent t (InputElement EventResult d t) en where
268 type DomEventType (InputElement EventResult d t) en = EventResultType en
288 type DomEventType (InputElement EventResult d t) en = EventResultType en
@@ -307,7 +327,7 @@ instance MonadTransControlStateless (ReaderT r)
307type RunStateless t = forall n b. Monad n => t n b -> n b
327type RunStateless t = forall n b. Monad n => t n b -> n b
308
328
309liftWithStateless :: forall m t a. (Monad m, MonadTransControlStateless t) => (RunStateless t -> m a) -> t m a
329liftWithStateless :: 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
311
331
312liftTextNode :: (MonadTrans f, DomBuilder t m) => TextNodeConfig t -> f m (TextNode t)
332liftTextNode :: (MonadTrans f, DomBuilder t m) => TextNodeConfig t -> f m (TextNode t)
313liftTextNode = lift . textNode
333liftTextNode = 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 #-}
2module Reflex.Dom.Builder.Class.Events where
7module Reflex.Dom.Builder.Class.Events where
3
8
4import Data.GADT.Compare.TH
9import 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 #-}
2module Reflex.Dom.Builder.Immediate where
16module Reflex.Dom.Builder.Immediate where
3
17
18+import Foreign.JavaScript.TH
4import Reflex
19import Reflex
5−import Reflex.Host.Class
6import Reflex.Dom.Builder.Class
20import Reflex.Dom.Builder.Class
7import Reflex.Dom.PerformEvent.Class
21import Reflex.Dom.PerformEvent.Class
8import Reflex.Dom.PostBuild.Class
22import Reflex.Dom.PostBuild.Class
9−import Foreign.JavaScript.TH
23+import Reflex.Host.Class
10
24
11−import GHCJS.DOM.Document (Document, createTextNode, createElement, createElementNS, createDocumentFragment)
25+import Control.Concurrent.Chan
12−import GHCJS.DOM.Element (setAttribute, setAttributeNS, removeAttribute, removeAttributeNS, getScrollTop)
26+import Control.Lens hiding (element)
13−import qualified GHCJS.DOM.HTMLInputElement as Input
27+import Control.Monad.Exception
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
25import Control.Monad.Reader
28import Control.Monad.Reader
29+import Control.Monad.Ref
26import Control.Monad.Trans.Control
30import 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
31import Data.Bitraversable
31import Data.Bitraversable
32−import Data.Text (Text)
32+import Data.Default
33−import Data.Maybe
34−import Data.IORef
35−import Control.Monad.Ref
36−import Control.Monad.Exception
37import Data.Dependent.Map (DMap)
33import Data.Dependent.Map (DMap)
38import qualified Data.Dependent.Map as DMap
34import 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
40
56
41import Debug.Trace hiding (traceEvent)
57import Debug.Trace hiding (traceEvent)
42
58
@@ -62,7 +78,7 @@ instance MonadTrans (ImmediateDomBuilderT t) where
62
78
63{-# INLINABLE runImmediateDomBuilderT #-}
79{-# INLINABLE runImmediateDomBuilderT #-}
64runImmediateDomBuilderT :: ImmediateDomBuilderT t m a -> ImmediateDomBuilderEnv t -> m a
80runImmediateDomBuilderT :: ImmediateDomBuilderT t m a -> ImmediateDomBuilderEnv t -> m a
65−runImmediateDomBuilderT (ImmediateDomBuilderT a) env = runReaderT a env
81+runImmediateDomBuilderT (ImmediateDomBuilderT a) = runReaderT a
66
82
67{-# INLINABLE askDocument #-}
83{-# INLINABLE askDocument #-}
68askDocument :: Monad m => ImmediateDomBuilderT t m Document
84askDocument :: Monad m => ImmediateDomBuilderT t m Document
@@ -186,8 +202,9 @@ instance DomSpace GhcjsDomSpace where
186instance SupportsImmediateDomBuilder t m => DomBuilder t (ImmediateDomBuilderT t m) where
202instance SupportsImmediateDomBuilder t m => DomBuilder t (ImmediateDomBuilderT t m) where
187 type DomBuilderSpace (ImmediateDomBuilderT t m) = GhcjsDomSpace
203 type DomBuilderSpace (ImmediateDomBuilderT t m) = GhcjsDomSpace
188 {-# INLINABLE textNode #-}
204 {-# INLINABLE textNode #-}
189− textNode (TextNodeConfig contents) = do
205+ textNode (TextNodeConfig initialContents eSetContents) = do
190− _ <- textNodeInternal contents
206+ n <- textNodeInternal initialContents
207+ lift $ performEvent_ $ ffor eSetContents $ \t -> setNodeValue n (Just t)
191 return TextNode
208 return TextNode
192 {-# INLINABLE element #-}
209 {-# INLINABLE element #-}
193 element elementTag cfg child = fst <$> makeElement elementTag cfg child
210 element elementTag cfg child = fst <$> makeElement elementTag cfg child
@@ -206,8 +223,7 @@ instance SupportsImmediateDomBuilder t m => DomBuilder t (ImmediateDomBuilderT t
206 let domInputElement = castToHTMLInputElement domElement
223 let domInputElement = castToHTMLInputElement domElement
207 Just v0 <- Input.getValue domInputElement
224 Just v0 <- Input.getValue domInputElement
208 let getMyValue = fromMaybe "" <$> Input.getValue domInputElement
225 let getMyValue = fromMaybe "" <$> Input.getValue domInputElement
209− valueChangedByUI <- performEvent $ ffor (Reflex.select (_element_events e) (WrapArg Input)) $ \_ ->
226+ valueChangedByUI <- performEvent $ getMyValue <$ Reflex.select (_element_events e) (WrapArg Input)
210− getMyValue
211 valueChangedBySetValue <- performEvent $ ffor (cfg ^. inputElementConfig_setValue) $ \v' -> do
227 valueChangedBySetValue <- performEvent $ ffor (cfg ^. inputElementConfig_setValue) $ \v' -> do
212 Input.setValue domInputElement $ Just v'
228 Input.setValue domInputElement $ Just v'
213 getMyValue -- We get the value after setting it in case the browser has mucked with it somehow
229 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
240 let domTextAreaElement = castToHTMLTextAreaElement domElement
256 let domTextAreaElement = castToHTMLTextAreaElement domElement
241 Just v0 <- TextArea.getValue domTextAreaElement
257 Just v0 <- TextArea.getValue domTextAreaElement
242 let getMyValue = fromMaybe "" <$> TextArea.getValue domTextAreaElement
258 let getMyValue = fromMaybe "" <$> TextArea.getValue domTextAreaElement
243− valueChangedByUI <- performEvent $ ffor (Reflex.select (_element_events e) (WrapArg Input)) $ \_ ->
259+ valueChangedByUI <- performEvent $ getMyValue <$ Reflex.select (_element_events e) (WrapArg Input)
244− getMyValue
245 valueChangedBySetValue <- performEvent $ ffor (cfg ^. textAreaElementConfig_setValue) $ \v' -> do
260 valueChangedBySetValue <- performEvent $ ffor (cfg ^. textAreaElementConfig_setValue) $ \v' -> do
246 TextArea.setValue domTextAreaElement $ Just v'
261 TextArea.setValue domTextAreaElement $ Just v'
247 getMyValue -- We get the value after setting it in case the browser has mucked with it somehow
262 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) =>
314 {-# INLINABLE newEventWithLazyTriggerWithOnComplete #-}
329 {-# INLINABLE newEventWithLazyTriggerWithOnComplete #-}
315 newEventWithLazyTriggerWithOnComplete f = do
330 newEventWithLazyTriggerWithOnComplete f = do
316 events <- askEvents
331 events <- askEvents
317− eResult <- lift $ newEventWithTrigger $ \t -> f $ \a cb -> do
332+ lift $ newEventWithTrigger $ \t -> f $ \a cb -> do
318 reResultTrigger <- newIORef $ Just t
333 reResultTrigger <- newIORef $ Just t
319 writeChan events [TriggerRef reResultTrigger :=> TriggerInvocation a cb]
334 writeChan events [TriggerRef reResultTrigger :=> TriggerInvocation a cb]
320− return eResult
321
335
322instance HasWebView m => HasWebView (ImmediateDomBuilderT t m) where
336instance HasWebView m => HasWebView (ImmediateDomBuilderT t m) where
323 type WebViewPhantom (ImmediateDomBuilderT t m) = WebViewPhantom m
337 type WebViewPhantom (ImmediateDomBuilderT t m) = WebViewPhantom m
@@ -392,7 +406,7 @@ type family EventType en where
392
406
393{-# INLINABLE defaultDomEventHandler #-}
407{-# INLINABLE defaultDomEventHandler #-}
394defaultDomEventHandler :: IsElement e => e -> EventName en -> EventM e (EventType en) (Maybe (EventResult en))
408defaultDomEventHandler :: 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
396 Click -> return ()
410 Click -> return ()
397 Dblclick -> return ()
411 Dblclick -> return ()
398 Keypress -> getKeyEvent
412 Keypress -> getKeyEvent
@@ -444,7 +458,7 @@ defaultDomEventHandler e evt = liftM (Just . EventResult) $ case evt of
444
458
445{-# INLINABLE defaultDomWindowEventHandler #-}
459{-# INLINABLE defaultDomWindowEventHandler #-}
446defaultDomWindowEventHandler :: DOM.Window -> EventName en -> EventM DOM.Window (EventType en) (Maybe (EventResult en))
460defaultDomWindowEventHandler :: 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
448 Click -> return ()
462 Click -> return ()
449 Dblclick -> return ()
463 Dblclick -> return ()
450 Keypress -> getKeyEvent
464 Keypress -> getKeyEvent
@@ -651,8 +665,8 @@ windowOnEventName en e = case en of
651 Touchcancel -> on e Window.touchCancel
665 Touchcancel -> on e Window.touchCancel
652
666
653{-# INLINABLE wrapDomEvent #-}
667{-# INLINABLE wrapDomEvent #-}
654−wrapDomEvent :: (MonadIO m, TriggerEvent t m) => e -> (e -> EventM e event () -> IO (IO ())) -> EventM e event a -> m (Event t a)
668+wrapDomEvent :: 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
669+wrapDomEvent el elementOnevent getValue = wrapDomEventMaybe el elementOnevent $ fmap Just getValue
656
670
657{-# INLINABLE subscribeDomEvent #-}
671{-# INLINABLE subscribeDomEvent #-}
658subscribeDomEvent :: (EventM e event () -> IO (IO ()))
672subscribeDomEvent :: (EventM e event () -> IO (IO ()))
@@ -668,16 +682,15 @@ subscribeDomEvent elementOnevent getValue eventChan et = elementOnevent $ do
668 writeChan eventChan [TriggerRef etr :=> TriggerInvocation v (return ())]
682 writeChan eventChan [TriggerRef etr :=> TriggerInvocation v (return ())]
669
683
670{-# INLINABLE wrapDomEventMaybe #-}
684{-# INLINABLE wrapDomEventMaybe #-}
671−wrapDomEventMaybe :: (MonadIO m, TriggerEvent t m)
685+wrapDomEventMaybe :: TriggerEvent t m
672 => e
686 => e
673 -> (e -> EventM e event () -> IO (IO ()))
687 -> (e -> EventM e event () -> IO (IO ()))
674 -> EventM e event (Maybe a)
688 -> EventM e event (Maybe a)
675 -> m (Event t a)
689 -> m (Event t a)
676wrapDomEventMaybe el elementOnevent getValue = do
690wrapDomEventMaybe el elementOnevent getValue = do
677− e <- newEventWithLazyTriggerWithOnComplete $ \trigger -> elementOnevent el $ do
691+ newEventWithLazyTriggerWithOnComplete $ \trigger -> elementOnevent el $ do
678 mv <- getValue
692 mv <- getValue
679 forM_ mv $ \v -> liftIO $ trigger v $ return ()
693 forM_ mv $ \v -> liftIO $ trigger v $ return ()
680− return e
681
694
682{-# INLINABLE wrapDomEventsMaybe #-}
695{-# INLINABLE wrapDomEventsMaybe #-}
683wrapDomEventsMaybe :: (MonadIO m, MonadReflexCreateTrigger t m)
696wrapDomEventsMaybe :: (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 #-}
2module Reflex.Dom.Builder.Static where
16module Reflex.Dom.Builder.Static where
3
17
18+import Control.Monad.Identity
19+import Control.Monad.Ref
20+import Data.Dependent.Sum (DSum (..))
4import Reflex
21import Reflex
5−import Reflex.Host.Class
6import Reflex.Dom.Builder.Class
22import Reflex.Dom.Builder.Class
7import Reflex.Dom.PerformEvent.Base
23import Reflex.Dom.PerformEvent.Base
8import Reflex.Dom.PerformEvent.Class
24import Reflex.Dom.PerformEvent.Class
9import Reflex.Dom.PostBuild.Class
25import Reflex.Dom.PostBuild.Class
10import Reflex.Dom.Widget.Basic (applyMap)
26import Reflex.Dom.Widget.Basic (applyMap)
11−import Control.Monad.Ref
27+import Reflex.Host.Class
12−import Control.Monad.Identity
13−import Data.Dependent.Sum (DSum (..))
14
28
15−import Data.Monoid
29+import Blaze.ByteString.Builder.Html.Utf8
16−import Data.Text (Text)
17−import qualified Data.Map as Map
18−import Data.Map (Map)
19import Control.Lens hiding (element)
30import Control.Lens hiding (element)
20−import qualified Data.ByteString.Lazy as BL
31+import Control.Monad.Exception
21−import qualified Data.ByteString.Char8 as B8
22−import Data.ByteString (ByteString)
23import Control.Monad.State.Strict
32import Control.Monad.State.Strict
24import Control.Monad.Trans.Control
33import Control.Monad.Trans.Control
34+import Data.ByteString (ByteString)
25import Data.ByteString.Builder (toLazyByteString)
35import 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
27import Data.Text.Encoding
39import Data.Text.Encoding
28−import Control.Monad.Exception
29
40
30
41
31newtype StaticDomBuilderT t m a = StaticDomBuilderT
42newtype StaticDomBuilderT t m a = StaticDomBuilderT
@@ -91,35 +102,47 @@ instance (Monad m, Ref m ~ Ref IO, Reflex t) => TriggerEvent t (StaticDomBuilder
91type 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)
102type 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)
92
103
93data StaticDomSpace
104data 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+
94instance DomSpace StaticDomSpace where
112instance 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
96
118
97instance SupportsStaticDomBuilder t m => DomBuilder t (StaticDomBuilderT t m) where
119instance SupportsStaticDomBuilder t m => DomBuilder t (StaticDomBuilderT t m) where
98 type DomBuilderSpace (StaticDomBuilderT t m) = StaticDomSpace
120 type DomBuilderSpace (StaticDomBuilderT t m) = StaticDomSpace
99 {-# INLINABLE textNode #-}
121 {-# INLINABLE textNode #-}
100− textNode (TextNodeConfig contents) = StaticDomBuilderT $ do
122+ textNode (TextNodeConfig initialContents setContents) = StaticDomBuilderT $ do
101− modify $ (:) $ constant $ BL.toStrict $ toLazyByteString $ fromHtmlEscapedText contents
123+ let escape = BL.toStrict . toLazyByteString . fromHtmlEscapedText
124+ modify . (:) <=< hold (escape initialContents) $ fmap escape setContents
102 return TextNode
125 return TextNode
103
126
104 {-# INLINABLE element #-}
127 {-# INLINABLE element #-}
105 element elementTag cfg child = do
128 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) <> "\""
107 es <- newFanEventWithTrigger $ \_ _ -> return (return ())
130 es <- newFanEventWithTrigger $ \_ _ -> return (return ())
108 StaticDomBuilderT $ do
131 StaticDomBuilderT $ do
109 (result, innerHtml) <- lift $ runStaticDomBuilderT child
132 (result, innerHtml) <- lift $ runStaticDomBuilderT child
110 attrs0 <- foldDyn applyMap (cfg ^. initialAttributes) (cfg ^. modifyAttributes)
133 attrs0 <- foldDyn applyMap (cfg ^. initialAttributes) (cfg ^. modifyAttributes)
111 let attrs1 = ffor (current attrs0) $ mconcat . fmap (\(k, v) -> " " <> toAttr k v) . Map.toList
134 let attrs1 = ffor (current attrs0) $ mconcat . fmap (\(k, v) -> " " <> toAttr k v) . Map.toList
112− let tag = encodeUtf8 elementTag
135+ let tagBS = encodeUtf8 elementTag
113− let open = mconcat [constant ("<" <> tag <> " "), attrs1, constant ">"]
136+ let open = mconcat [constant ("<" <> tagBS <> " "), attrs1, constant ">"]
114− let close = constant $ "</" <> tag <> ">" -- TODO handle elements without closing tags
137+ let close = constant $ "</" <> tagBS <> ">" -- TODO handle elements without closing tags
115− modify $ (:) $ mconcat $ [open, innerHtml, close]
138+ modify $ (:) $ mconcat [open, innerHtml, close]
116 return (Element es (error "Static.element RawElement was used"), result)
139 return (Element es (error "Static.element RawElement was used"), result)
117
140
118 {-# INLINABLE placeholder #-}
141 {-# INLINABLE placeholder #-}
119 placeholder (PlaceholderConfig toInsertAbove _delete) = StaticDomBuilderT $ do
142 placeholder (PlaceholderConfig toInsertAbove _delete) = StaticDomBuilderT $ do
120 result <- lift $ performEvent (fmap runStaticDomBuilderT toInsertAbove)
143 result <- lift $ performEvent (fmap runStaticDomBuilderT toInsertAbove)
121 acc <- foldDyn (:) [] (fmap snd result)
144 acc <- foldDyn (:) [] (fmap snd result)
122− modify $ (:) $ join $ fmap (mconcat . reverse) $ current acc
145+ modify $ (:) $ join $ mconcat . reverse <$> current acc
123 return $ Placeholder (fmap fst result) never
146 return $ Placeholder (fmap fst result) never
124
147
125 {-# INLINABLE inputElement #-}
148 {-# INLINABLE inputElement #-}
src/Reflex/Dom/Class.hs+11−6
@@ -1,25 +1,30 @@
1+{-# LANGUAGE MultiParamTypeClasses #-}
1module Reflex.Dom.Class ( module Reflex.Dom.Class
2module Reflex.Dom.Class ( module Reflex.Dom.Class
2 , module Foreign.JavaScript.TH
3 , module Foreign.JavaScript.TH
4+ , module Web.KeyCode
3 ) where
5 ) where
4
6
7+import Data.Map (Map)
8+import qualified Data.Map as Map
5import Reflex.Class
9import Reflex.Class
6−import Reflex.Dom.PostBuild.Class
10+import Web.KeyCode
7−import Reflex.Dom.PerformEvent.Class
8−
9−import Prelude hiding (mapM, mapM_, sequence, concat)
10
11
11import Foreign.JavaScript.TH
12import Foreign.JavaScript.TH
13+import Reflex.Dom.PerformEvent.Class
14+import Reflex.Dom.PostBuild.Class
12
15
13−import Data.Map (Map)
16+import Prelude hiding (concat, mapM, mapM_, sequence)
14−import qualified Data.Map as Map
15
17
16-- | Alias for Data.Map.singleton
18-- | Alias for Data.Map.singleton
17(=:) :: k -> a -> Map k a
19(=:) :: k -> a -> Map k a
18(=:) = Map.singleton
20(=:) = Map.singleton
21+infixr 7 =: -- Ought to bind tighter than <>, which is infixr 6
19
22
23+{-# DEPRECATED keycodeEnter "Instead of `x == keycodeEnter`, use `keyCodeLookup x == Enter`" #-}
20keycodeEnter :: Int
24keycodeEnter :: Int
21keycodeEnter = 13
25keycodeEnter = 13
22
26
27+{-# DEPRECATED keycodeEscape "Instead of `x == keycodeEscape`, use `keyCodeLookup x == Escape`" #-}
23keycodeEscape :: Int
28keycodeEscape :: Int
24keycodeEscape = 27
29keycodeEscape = 27
25
30
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 #-}
2module Reflex.Dom.Deletable.Class where
5module Reflex.Dom.Deletable.Class where
3
6
4import Reflex
7import 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 #-}
2module Reflex.Dom.DynamicWriter where
12module Reflex.Dom.DynamicWriter where
3
13
4import Reflex
14import Reflex
5−import Reflex.Host.Class
6−import Reflex.Dom.Class
7import Reflex.Dom.Builder.Class
15import Reflex.Dom.Builder.Class
16+import Reflex.Dom.Class
8import Reflex.Dom.PerformEvent.Class
17import Reflex.Dom.PerformEvent.Class
9import Reflex.Dom.PostBuild.Class
18import Reflex.Dom.PostBuild.Class
19+import Reflex.Host.Class
10
20
11import Control.Lens hiding (element)
21import Control.Lens hiding (element)
22+import Control.Monad.Exception
12import Control.Monad.IO.Class
23import Control.Monad.IO.Class
13−import Control.Monad.State.Strict
14import Control.Monad.Reader
24import Control.Monad.Reader
15import Control.Monad.Ref
25import Control.Monad.Ref
16−import Control.Monad.Exception
26+import Control.Monad.State.Strict
17−import Data.Map (Map)
18−import qualified Data.Map as Map
19import Data.Dependent.Map (DMap)
27import Data.Dependent.Map (DMap)
20−import Data.List.NonEmpty (NonEmpty, nonEmpty)
28+import Data.Foldable
21import Data.Functor.Compose
29import Data.Functor.Compose
22import Data.Functor.Misc
30import Data.Functor.Misc
31+import Data.List.NonEmpty (NonEmpty, nonEmpty)
32+import Data.Map (Map)
33+import qualified Data.Map as Map
23import Data.Semigroup
34import Data.Semigroup
24−import Data.Foldable
25import Data.Traversable
35import Data.Traversable
26
36
27instance MonadTrans (DynamicWriterT t w) where
37instance MonadTrans (DynamicWriterT t w) where
@@ -66,7 +76,7 @@ mapIncrementalMapValues :: Reflex t => (v -> v') -> Incremental t PatchMap (Map
66mapIncrementalMapValues f = mapIncrementalMapValuesWithKey $ const f
76mapIncrementalMapValues f = mapIncrementalMapValuesWithKey $ const f
67
77
68unsafeMapIncremental :: (Reflex t, Patch p, Patch p') => (a -> a') -> (p a -> p' a') -> Incremental t p a -> Incremental t p' a'
78unsafeMapIncremental :: (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
70
80
71incrementalExtractFunctorDMap :: Reflex t => Incremental t PatchMap (Map k (f v)) -> Incremental t PatchDMap (DMap (Const2 k v) f)
81incrementalExtractFunctorDMap :: Reflex t => Incremental t PatchMap (Map k (f v)) -> Incremental t PatchDMap (DMap (Const2 k v) f)
72incrementalExtractFunctorDMap = unsafeMapIncremental mapWithFunctorToDMap $ \(PatchMap m) -> PatchDMap $ mapWithFunctorToDMap $ fmap Compose m
82incrementalExtractFunctorDMap = 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 (
174 return (el, a)
184 return (el, a)
175 placeholder cfg = do
185 placeholder cfg = do
176 let cfg' = cfg
186 let cfg' = cfg
177− { _placeholderConfig_insertAbove = fmap runDynamicWriterTInternal $ _placeholderConfig_insertAbove cfg
187+ { _placeholderConfig_insertAbove = runDynamicWriterTInternal <$> _placeholderConfig_insertAbove cfg
178 }
188 }
179 let manageChildren :: Event t (NonEmpty (Replaceable t (Dynamic t w))) -- ^ Add nodes on the right; these are in reverse order
189 let manageChildren :: Event t (NonEmpty (Replaceable t (Dynamic t w))) -- ^ Add nodes on the right; these are in reverse order
180 -> Event t () -- ^ No more nodes will be added after this event fires
190 -> 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 (
193 p <- DynamicWriterT $ do
203 p <- DynamicWriterT $ do
194 modify (children:)
204 modify (children:)
195 lift $ placeholder cfg'
205 lift $ placeholder cfg'
196− let result = fmap fst $ _placeholder_insertedAbove p
206+ let result = fst <$> _placeholder_insertedAbove p
197 childOutputs = fmapMaybe (nonEmpty . snd) $ _placeholder_insertedAbove p
207 childOutputs = fmapMaybe (nonEmpty . snd) $ _placeholder_insertedAbove p
198 return $ p
208 return $ p
199 { _placeholder_insertedAbove = result
209 { _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 #-}
2module Reflex.Dom.Internal where
14module Reflex.Dom.Internal where
3
15
4−import Prelude hiding (mapM, mapM_, concat, sequence, sequence_)
16+import Prelude hiding (concat, mapM, mapM_, sequence, sequence_)
5
17
6import Reflex.Dom.Builder.Immediate
18import Reflex.Dom.Builder.Immediate
7import Reflex.Dom.Class
19import Reflex.Dom.Class
@@ -9,32 +21,30 @@ import Reflex.Dom.Internal.Foreign
9import Reflex.Dom.PerformEvent.Base
21import Reflex.Dom.PerformEvent.Base
10import Reflex.Dom.PostBuild.Class
22import Reflex.Dom.PostBuild.Class
11import Reflex.Host.Class
23import Reflex.Host.Class
12−import Reflex.Spider (Spider, SpiderHost, runSpiderHost, Global)
24+import Reflex.Spider (Global, Spider, SpiderHost, runSpiderHost)
13
25
14−import GHCJS.DOM hiding (runWebGUI)
26+import Control.Concurrent
15−import qualified GHCJS.DOM.Types as DOM
16−import GHCJS.DOM.Node
17−import GHCJS.DOM.Element
18−import GHCJS.DOM.Document
19import Control.Lens
27import Control.Lens
20−import Control.Monad hiding (mapM, mapM_, forM, forM_, sequence, sequence_)
28+import Control.Monad
21−import Control.Monad.Reader hiding (mapM, mapM_, forM, forM_, sequence, sequence_)
29+import Control.Monad.Reader hiding (forM, forM_, mapM, mapM_, sequence, sequence_)
22import Control.Monad.Ref
30import Control.Monad.Ref
23−import Control.Concurrent
24import Data.ByteString (ByteString)
31import Data.ByteString (ByteString)
25import Data.Dependent.Sum (DSum (..))
32import Data.Dependent.Sum (DSum (..))
26−import Data.Foldable
27−import qualified Data.Text as T
28−import Data.Text.Encoding
29−import Data.Monoid ((<>))
30import Data.IORef
33import Data.IORef
31−import Control.Monad
32import Data.Maybe
34import 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
33
43
34{-# INLINABLE mainWidget #-}
44{-# INLINABLE mainWidget #-}
35mainWidget :: (forall x. Widget x ()) -> IO ()
45mainWidget :: (forall x. Widget x ()) -> IO ()
36mainWidget w = runWebGUI $ \webView -> withWebViewSingleton webView $ \webViewSing -> do
46mainWidget w = runWebGUI $ \webView -> withWebViewSingleton webView $ \webViewSing -> do
37− Just doc <- liftM (fmap DOM.castToHTMLDocument) $ webViewGetDomDocument webView
47+ Just doc <- fmap DOM.castToHTMLDocument <$> webViewGetDomDocument webView
38 Just body <- getBody doc
48 Just body <- getBody doc
39 attachWidget body webViewSing w
49 attachWidget body webViewSing w
40
50
@@ -42,8 +52,8 @@ mainWidget w = runWebGUI $ \webView -> withWebViewSingleton webView $ \webViewSi
42{-# INLINABLE mainWidgetWithHead #-}
52{-# INLINABLE mainWidgetWithHead #-}
43mainWidgetWithHead :: (forall x. Widget x ()) -> (forall x. Widget x ()) -> IO ()
53mainWidgetWithHead :: (forall x. Widget x ()) -> (forall x. Widget x ()) -> IO ()
44mainWidgetWithHead h b = runWebGUI $ \webView -> withWebViewSingleton webView $ \webViewSing -> do
54mainWidgetWithHead h b = runWebGUI $ \webView -> withWebViewSingleton webView $ \webViewSing -> do
45− Just doc <- liftM (fmap DOM.castToHTMLDocument) $ webViewGetDomDocument webView
55+ Just doc <- fmap DOM.castToHTMLDocument <$> webViewGetDomDocument webView
46− Just headElement <- liftM (fmap DOM.castToHTMLElement) $ getHead doc
56+ Just headElement <- fmap DOM.castToHTMLElement <$> getHead doc
47 attachWidget headElement webViewSing h
57 attachWidget headElement webViewSing h
48 Just body <- getBody doc
58 Just body <- getBody doc
49 attachWidget body webViewSing b
59 attachWidget body webViewSing b
@@ -51,19 +61,12 @@ mainWidgetWithHead h b = runWebGUI $ \webView -> withWebViewSingleton webView $
51{-# INLINABLE mainWidgetWithCss #-}
61{-# INLINABLE mainWidgetWithCss #-}
52mainWidgetWithCss :: ByteString -> (forall x. Widget x ()) -> IO ()
62mainWidgetWithCss :: ByteString -> (forall x. Widget x ()) -> IO ()
53mainWidgetWithCss css w = runWebGUI $ \webView -> withWebViewSingleton webView $ \webViewSing -> do
63mainWidgetWithCss css w = runWebGUI $ \webView -> withWebViewSingleton webView $ \webViewSing -> do
54− Just doc <- liftM (fmap DOM.castToHTMLDocument) $ webViewGetDomDocument webView
64+ Just doc <- fmap DOM.castToHTMLDocument <$> webViewGetDomDocument webView
55− Just headElement <- liftM (fmap DOM.castToHTMLElement) $ getHead doc
65+ Just headElement <- fmap DOM.castToHTMLElement <$> getHead doc
56 setInnerHTML headElement . Just $ "<style>" <> T.unpack (decodeUtf8 css) <> "</style>" --TODO: Fix this
66 setInnerHTML headElement . Just $ "<style>" <> T.unpack (decodeUtf8 css) <> "</style>" --TODO: Fix this
57 Just body <- getBody doc
67 Just body <- getBody doc
58 attachWidget body webViewSing w
68 attachWidget body webViewSing w
59
69
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−
67type 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
70type 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
68
71
69{-# INLINABLE attachWidget #-}
72{-# INLINABLE attachWidget #-}
@@ -73,38 +76,6 @@ attachWidget rootElement wv w = fst <$> attachWidget' rootElement wv w
73{-# INLINABLE attachWidget' #-}
76{-# INLINABLE attachWidget' #-}
74attachWidget' :: DOM.IsElement e => e -> WebViewSingleton x -> Widget x a -> IO (a, FireCommand Spider (SpiderHost Global))
77attachWidget' :: DOM.IsElement e => e -> WebViewSingleton x -> Widget x a -> IO (a, FireCommand Spider (SpiderHost Global))
75attachWidget' rootElement wv w = do
78attachWidget' 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
108 Just doc <- getOwnerDocument rootElement
79 Just doc <- getOwnerDocument rootElement
109 Just df <- createDocumentFragment doc
80 Just df <- createDocumentFragment doc
110 events <- newChan
81 events <- newChan
@@ -129,7 +100,7 @@ attachWidgetFragment' rootElement wv w = do
129 liftIO $ forM_ ers $ \(_ :=> TriggerInvocation _ cb) -> cb
100 liftIO $ forM_ ers $ \(_ :=> TriggerInvocation _ cb) -> cb
130 return ()
101 return ()
131 setInnerHTML rootElement $ Just (""::String)
102 setInnerHTML rootElement $ Just (""::String)
132− appendChild rootElement $ Just df
103+ _ <- appendChild rootElement $ Just df
133 return (result, fc)
104 return (result, fc)
134
105
135data AppInput t = AppInput
106data AppInput t = AppInput
@@ -142,7 +113,7 @@ data AppOutput t = AppOutput --TODO: Add quit event
142
113
143runApp' :: (t ~ Spider) => (forall x. AppInput t -> Widget x (AppOutput t)) -> IO ()
114runApp' :: (t ~ Spider) => (forall x. AppInput t -> Widget x (AppOutput t)) -> IO ()
144runApp' app = runWebGUI $ \webView -> withWebViewSingleton webView $ \webViewSing -> do
115runApp' app = runWebGUI $ \webView -> withWebViewSingleton webView $ \webViewSing -> do
145− Just doc <- liftM (fmap DOM.castToHTMLDocument) $ webViewGetDomDocument webView
116+ Just doc <- fmap DOM.castToHTMLDocument <$> webViewGetDomDocument webView
146 Just body <- getBody doc
117 Just body <- getBody doc
147 Just win <- getDefaultView doc
118 Just win <- getDefaultView doc
148 rec o <- attachWidget body webViewSing $ do
119 rec o <- attachWidget body webViewSing $ do
src/Reflex/Dom/Location.hs+1−1
@@ -1,8 +1,8 @@
1module Reflex.Dom.Location (getLocationHost, getLocationProtocol) where
1module Reflex.Dom.Location (getLocationHost, getLocationProtocol) where
2
2
3+import Data.Text (Text)
3import Reflex.Dom.Class
4import Reflex.Dom.Class
4import qualified Reflex.Dom.Internal.Foreign as F
5import qualified Reflex.Dom.Internal.Foreign as F
5−import Data.Text (Text)
6
6
7import Control.Monad.IO.Class
7import Control.Monad.IO.Class
8
8
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 #-}
2module Reflex.Dom.Old where
4module Reflex.Dom.Old where
3
5
4import Control.Monad.Exception
6import 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 #-}
2module Reflex.Dom.PerformEvent.Base where
12module Reflex.Dom.PerformEvent.Base where
3
13
14+import Foreign.JavaScript.TH
4import Reflex
15import Reflex
5−import Reflex.Host.Class
6−import Reflex.Dom.PerformEvent.Class
7import Reflex.Dom.Deletable.Class
16import Reflex.Dom.Deletable.Class
8−import Foreign.JavaScript.TH
17+import Reflex.Dom.PerformEvent.Class
18+import Reflex.Host.Class
9
19
20+import Control.Lens
21+import Control.Monad.Exception
10import Control.Monad.Identity
22import Control.Monad.Identity
11import Control.Monad.Ref
23import Control.Monad.Ref
12import Control.Monad.State.Strict
24import Control.Monad.State.Strict
13−import Control.Monad.Exception
25+import Data.Align
14−import Data.Dependent.Sum
15−import Data.Maybe
16−import Data.Functor.Misc
17import Data.Dependent.Map (DMap)
26import Data.Dependent.Map (DMap)
18import qualified Data.Dependent.Map as DMap
27import qualified Data.Dependent.Map as DMap
19−import Data.Word
28+import Data.Dependent.Sum
20import Data.Functor.Compose
29import Data.Functor.Compose
30+import Data.Functor.Misc
31+import Data.Maybe
21import Data.Semigroup
32import Data.Semigroup
22import Data.These
33import Data.These
23−import Data.Align
34+import Data.Word
24−import Control.Lens
25
35
26newtype EventTriggerRef t m a = EventTriggerRef { unEventTriggerRef :: Ref m (Maybe (EventTrigger t a)) }
36newtype EventTriggerRef t m a = EventTriggerRef { unEventTriggerRef :: Ref m (Maybe (EventTrigger t a)) }
27
37
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?
29
39
30newtype PerformEventT t m a = PerformEventT { unPerformEventT :: StateT [Event t (These (PerformEventT t m [DSum (EventTriggerRef t m) Identity]) ())] (HostFrame t) a }
40newtype PerformEventT t m a = PerformEventT { unPerformEventT :: StateT [Event t (These (PerformEventT t m [DSum (EventTriggerRef t m) Identity]) ())] (HostFrame t) a }
31
41
@@ -55,11 +65,13 @@ instance (ReflexHost t, Ref m ~ Ref IO, MonadRef (HostFrame t), Ref (HostFrame t
55 return [EventTriggerRef reResultTrigger :=> Identity result]
65 return [EventTriggerRef reResultTrigger :=> Identity result]
56 return eResult
66 return eResult
57
67
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
59 {-# INLINABLE deletable #-}
69 {-# INLINABLE deletable #-}
60 deletable d a = PerformEventT $ do
70 deletable d a = PerformEventT $ do
61− (result, eventToPerform) <- lift $ runPerformEventT a
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
62− modify (align (fmap (PerformEventT . lift) eventToPerform) d :)
74+ modify (align eventToPerform d :)
63 return result
75 return result
64
76
65instance ReflexHost t => MonadReflexCreateTrigger t (PerformEventT t m) where
77instance ReflexHost t => MonadReflexCreateTrigger t (PerformEventT t m) where
@@ -131,7 +143,7 @@ hostPerformEventT a = do
131 followupEventTriggerRefs <- runHostFrame toPerform
143 followupEventTriggerRefs <- runHostFrame toPerform
132 followupEventTriggers <- forM followupEventTriggerRefs $ \(EventTriggerRef rt :=> x) -> do
144 followupEventTriggers <- forM followupEventTriggerRefs $ \(EventTriggerRef rt :=> x) -> do
133 mt <- readRef rt
145 mt <- readRef rt
134− return $ fmap (\t -> t :=> x) mt
146+ return $ fmap (:=> x) mt
135 fmap (result':) $ go $ catMaybes followupEventTriggers
147 fmap (result':) $ go $ catMaybes followupEventTriggers
136 go triggers
148 go triggers
137
149
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 #-}
2module Reflex.Dom.PerformEvent.Class where
10module Reflex.Dom.PerformEvent.Class where
3
11
4import Reflex
12import 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 #-}
2module Reflex.Dom.PostBuild.Class where
12module Reflex.Dom.PostBuild.Class where
3
13
14+import Foreign.JavaScript.TH
4import Reflex
15import Reflex
5−import Reflex.Host.Class
6import Reflex.Dom.Builder.Class
16import Reflex.Dom.Builder.Class
7import Reflex.Dom.PerformEvent.Class
17import Reflex.Dom.PerformEvent.Class
8−import Foreign.JavaScript.TH
18+import Reflex.Host.Class
9
19
10import Control.Lens hiding (element)
20import Control.Lens hiding (element)
21+import Control.Monad.Exception
11import Control.Monad.Reader
22import Control.Monad.Reader
12−import Control.Monad.Trans.Control
13import Control.Monad.Ref
23import Control.Monad.Ref
14−import Control.Monad.Exception
24+import Control.Monad.Trans.Control
15
25
16class (Reflex t, Monad m) => PostBuild t m | m -> t where
26class (Reflex t, Monad m) => PostBuild t m | m -> t where
17 getPostBuild :: m (Event t ())
27 getPostBuild :: m (Event t ())
@@ -48,9 +58,9 @@ instance (DomBuilder t m, PerformEvent t m, MonadFix m, MonadHold t m) => DomBui
48 element t cfg child = liftWith $ \run -> element t (liftPostBuildTElementConfig cfg) $ run child
58 element t cfg child = liftWith $ \run -> element t (liftPostBuildTElementConfig cfg) $ run child
49 {-# INLINABLE placeholder #-}
59 {-# INLINABLE placeholder #-}
50 placeholder cfg = lift $ do
60 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
52 p <- placeholder $ cfg
62 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
54 }
64 }
55 return p
65 return p
56 {-# INLINABLE inputElement #-}
66 {-# INLINABLE inputElement #-}
@@ -113,7 +123,7 @@ instance HasWebView m => HasWebView (PostBuildT t m) where
113
123
114{-# INLINABLE runPostBuildT #-}
124{-# INLINABLE runPostBuildT #-}
115runPostBuildT :: PostBuildT t m a -> Event t () -> m a
125runPostBuildT :: PostBuildT t m a -> Event t () -> m a
116−runPostBuildT (PostBuildT a) postBuild = runReaderT a postBuild
126+runPostBuildT (PostBuildT a) = runReaderT a
117
127
118instance PostBuild t m => PostBuild t (ReaderT r m) where
128instance PostBuild t m => PostBuild t (ReaderT r m) where
119 getPostBuild = lift getPostBuild
129 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 #-}
2module Reflex.Dom.Time where
7module Reflex.Dom.Time where
3
8
4import Reflex
9import Reflex
5−import Reflex.Dom.PostBuild.Class
6import Reflex.Dom.PerformEvent.Class
10import Reflex.Dom.PerformEvent.Class
11+import Reflex.Dom.PostBuild.Class
7
12
8import Control.Concurrent
13import Control.Concurrent
14+import qualified Control.Concurrent.Thread.Delay as Concurrent
9import Control.Monad
15import Control.Monad
10import Control.Monad.Fix
16import Control.Monad.Fix
11import Control.Monad.IO.Class
17import Control.Monad.IO.Class
12import Data.Fixed
18import Data.Fixed
13import Data.Time.Clock
19import Data.Time.Clock
14−import System.Random
15import Data.Typeable
20import Data.Typeable
21+import System.Random
16
22
17data TickInfo
23data TickInfo
18 = TickInfo { _tickInfo_lastUTC :: UTCTime
24 = TickInfo { _tickInfo_lastUTC :: UTCTime
@@ -42,11 +48,11 @@ tickLossyFrom
42 -- there could be uses for starting multiple timer threads.
48 -- there could be uses for starting multiple timer threads.
43 -> m (Event t TickInfo)
49 -> m (Event t TickInfo)
44tickLossyFrom dt t0 e = do
50tickLossyFrom dt t0 e = do
45− rec result <- performEventAsync $ fmap callAtNextInterval $ leftmost [() <$ e, () <$ result]
51+ rec result <- performEventAsync $ callAtNextInterval <$> leftmost [() <$ e, () <$ result]
46 return result
52 return result
47 where callAtNextInterval _ cb = void $ liftIO $ forkIO $ do
53 where callAtNextInterval _ cb = void $ liftIO $ forkIO $ do
48 tick <- getCurrentTick dt t0
54 tick <- getCurrentTick dt t0
49− threadDelay $ ceiling $ (dt - _tickInfo_alreadyElapsed tick) * 1000000
55+ Concurrent.delay $ ceiling $ (dt - _tickInfo_alreadyElapsed tick) * 1000000
50 cb tick
56 cb tick
51
57
52clockLossy :: (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)
58clockLossy :: (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
65-- | Delay an Event's occurrences by a given amount in seconds.
71-- | Delay an Event's occurrences by a given amount in seconds.
66delay :: (PerformEvent t m, TriggerEvent t m, MonadIO (Performable m)) => NominalDiffTime -> Event t a -> m (Event t a)
72delay :: (PerformEvent t m, TriggerEvent t m, MonadIO (Performable m)) => NominalDiffTime -> Event t a -> m (Event t a)
67delay dt e = performEventAsync $ ffor e $ \a cb -> liftIO $ void $ forkIO $ do
73delay dt e = performEventAsync $ ffor e $ \a cb -> liftIO $ void $ forkIO $ do
68− threadDelay $ ceiling $ dt * 1000000
74+ Concurrent.delay $ ceiling $ dt * 1000000
69 cb a
75 cb a
70
76
71-- | Send events with Poisson timing with the given basis and rate
77-- | Send events with Poisson timing with the given basis and rate
@@ -84,8 +90,7 @@ poissonLossyFrom
84 -- there could be uses for starting multiple timer threads.
90 -- there could be uses for starting multiple timer threads.
85 -- Start sending events in response to the event parameter.
91 -- Start sending events in response to the event parameter.
86 -> m (Event t TickInfo)
92 -> 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
89
94
90
95
91-- | Send events with Poisson timing with the given basis and rate
96-- | Send events with Poisson timing with the given basis and rate
@@ -148,13 +153,13 @@ inhomogeneousPoissonFrom rnd rate maxRate t0 e = do
148
153
149 -- Inter-event interval is drawn from exponential
154 -- Inter-event interval is drawn from exponential
150 -- distribution accourding to u
155 -- distribution accourding to u
151− let dt = realToFrac $ -1 * log(u)/maxRate :: NominalDiffTime
156+ let dt = realToFrac $ (-1) * log u / maxRate :: NominalDiffTime
152 nEvents = lastN + 1
157 nEvents = lastN + 1
153 alreadyElapsed = diffUTCTime t tTargetLast
158 alreadyElapsed = diffUTCTime t tTargetLast
154 tTarget = addUTCTime dt tTargetLast
159 tTarget = addUTCTime dt tTargetLast
155 thisDelay = realToFrac $ diffUTCTime tTarget t :: Double
160 thisDelay = realToFrac $ diffUTCTime tTarget t :: Double
156− threadDelay $ ceiling $ thisDelay * 1000000
161+ Concurrent.delay $ ceiling $ thisDelay * 1000000
157− void $ cb $ (TickInfo t nEvents alreadyElapsed, p)
162+ _ <- cb (TickInfo t nEvents alreadyElapsed, p)
158 go tTarget nextGen' cb nEvents
163 go tTarget nextGen' cb nEvents
159
164
160-- | Send events with inhomogeneous Poisson timing with the given basis
165-- | 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 #-}
2
21
3module Reflex.Dom.WebSocket where
22module Reflex.Dom.WebSocket where
4
23
5−import Prelude hiding (div, span, mapM, mapM_, concat, concatMap, all, sequence)
24+import Prelude hiding (all, concat, concatMap, div, mapM, mapM_, sequence, span)
6
25
7import Reflex
26import Reflex
27+import Reflex.Dom.Class
8import Reflex.Dom.PerformEvent.Class
28import Reflex.Dom.PerformEvent.Class
9import Reflex.Dom.PostBuild.Class
29import Reflex.Dom.PostBuild.Class
10−import Reflex.Dom.Class
11import Reflex.Dom.WebSocket.Foreign
30import Reflex.Dom.WebSocket.Foreign
12
31
13import Control.Concurrent
32import Control.Concurrent
14import Control.Concurrent.STM
33import Control.Concurrent.STM
15−import Control.Exception (catch, SomeException)
34+import Control.Exception (SomeException, catch)
16import Control.Lens
35import Control.Lens
17import Control.Monad hiding (forM, forM_, mapM, mapM_, sequence)
36import Control.Monad hiding (forM, forM_, mapM, mapM_, sequence)
18import Control.Monad.IO.Class
37import Control.Monad.IO.Class
19import Control.Monad.State
38import Control.Monad.State
20−import Data.Maybe (isJust)
21import Data.ByteString (ByteString)
39import Data.ByteString (ByteString)
22import Data.Default
40import Data.Default
23import Data.IORef
41import Data.IORef
42+import Data.Maybe (isJust)
24import Data.Text
43import Data.Text
25
44
26data WebSocketConfig t
45data WebSocketConfig t
@@ -38,15 +57,13 @@ data WebSocket t
38webSocket :: (MonadIO m, MonadIO (Performable m), HasWebView m, PerformEvent t m, TriggerEvent t m, PostBuild t m) => Text -> WebSocketConfig t -> m (WebSocket t)
57webSocket :: (MonadIO m, MonadIO (Performable m), HasWebView m, PerformEvent t m, TriggerEvent t m, PostBuild t m) => Text -> WebSocketConfig t -> m (WebSocket t)
39webSocket url config = do
58webSocket url config = do
40 wv <- fmap unWebViewSingleton askWebView
59 wv <- fmap unWebViewSingleton askWebView
41− (eRecv, triggerERecv) <- newTriggerEvent
60+ (eRecv, onMessage) <- newTriggerEvent
42 currentSocketRef <- liftIO $ newIORef Nothing
61 currentSocketRef <- liftIO $ newIORef Nothing
43 --TODO: Disconnect if value no longer needed
62 --TODO: Disconnect if value no longer needed
44 (eOpen, triggerEOpen) <- newTriggerEventWithOnComplete
63 (eOpen, triggerEOpen) <- newTriggerEventWithOnComplete
45 payloadQueue <- liftIO newTQueueIO
64 payloadQueue <- liftIO newTQueueIO
46 isOpen <- liftIO newEmptyTMVarIO
65 isOpen <- liftIO newEmptyTMVarIO
47− let onMessage :: ByteString -> IO ()
48− onMessage m = triggerERecv m
49− onOpen = triggerEOpen () $ do
66+ let onOpen = triggerEOpen () $ do
50 liftIO $ void $ atomically $ tryPutTMVar isOpen ()
67 liftIO $ void $ atomically $ tryPutTMVar isOpen ()
51 --TODO: Is the fork necessary, or do event handlers run in their own threads automatically?
68 --TODO: Is the fork necessary, or do event handlers run in their own threads automatically?
52 onClose = void $ forkIO $ do
69 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
1+module Reflex.Dom.Widget (module X) where
2− , module Reflex.Dom.Widget.Input
3− , module Reflex.Dom.Widget.Lazy
4− , module Reflex.Dom.Widget.Resize
5− ) where
6
2
7−import Reflex.Dom.Widget.Basic
3+import Reflex.Dom.Widget.Basic as X
8−import Reflex.Dom.Widget.Input
4+import Reflex.Dom.Widget.Input as X
9−import Reflex.Dom.Widget.Lazy
5+import Reflex.Dom.Widget.Lazy as X
10−import Reflex.Dom.Widget.Resize
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 #-}
1+{-# LANGUAGE ConstraintKinds #-}
2−
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 #-}
3module Reflex.Dom.Widget.Basic where
13module Reflex.Dom.Widget.Basic where
4
14
15+import Reflex.Dom.Builder.Class
5import Reflex.Dom.Class
16import Reflex.Dom.Class
6import Reflex.Dom.Internal.Foreign ()
17import Reflex.Dom.Internal.Foreign ()
7import Reflex.Dom.PostBuild.Class
18import Reflex.Dom.PostBuild.Class
8−import Reflex.Dom.Builder.Class
9
19
20+import Control.Arrow
21+import Control.Lens hiding (children, element)
10−import Prelude hiding (mapM, mapM_, sequence, sequence_)
22+import Control.Monad.Reader hiding (forM, forM_, mapM, mapM_, sequence, sequence_)
11−import Reflex
23+import Data.Align
24+import Data.Default
25+import Data.Either
26+import Data.Foldable
12import Data.Functor.Misc
27import Data.Functor.Misc
13import Data.Map (Map)
28import Data.Map (Map)
14import qualified Data.Map as Map
29import 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
23import Data.Maybe
30import Data.Maybe
24−import Data.Default
25−import Data.Either
26import Data.Semigroup
31import Data.Semigroup
32+import Data.Set (Set)
33+import qualified Data.Set as Set
27import Data.Text (Text)
34import Data.Text (Text)
28import qualified Data.Text as T
35import qualified Data.Text as T
36+import Data.These
37+import Data.Traversable
38+import Prelude hiding (mapM, mapM_, sequence, sequence_)
39+import Reflex
29
40
30widgetHoldInternal :: DomBuilder t m => m a -> Event t (m b) -> m (a, Event t b)
41widgetHoldInternal :: DomBuilder t m => m a -> Event t (m b) -> m (a, Event t b)
31widgetHoldInternal child0 child' = do
42widgetHoldInternal child0 child' = do
@@ -65,28 +76,27 @@ listHoldWithKey initialChildren modifyChildren buildChild = do
65 & deleteSelf .~ delete
76 & deleteSelf .~ delete
66 ph <- placeholder myCfg
77 ph <- placeholder myCfg
67 result <- deletable delete $ buildChild k v
78 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
69 rec initialAugmentedResults <- iforM initialChildren buildAugmentedChild
80 rec initialAugmentedResults <- iforM initialChildren buildAugmentedChild
70 augmentedResults <- foldDyn applyMap initialAugmentedResults $ newInsertedBelow <> newInsertedAbove
81 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
72 belowAll <- placeholder $ def & placeholderConfig_insertAbove .~ fmap (imapM buildAugmentedChild) (select placeChildSelector $ Const2 $ Right ())
83 belowAll <- placeholder $ def & placeholderConfig_insertAbove .~ fmap (imapM buildAugmentedChild) (select placeChildSelector $ Const2 $ Right ())
73− let newInsertedBelow = fmap (fmap Just) $ _placeholder_insertedAbove belowAll
84+ let newInsertedBelow = fmap Just <$> _placeholder_insertedAbove belowAll
74− mapDyn (fmap (fst . unChildResult)) augmentedResults
85+ return $ fmap (fmap (fst . unChildResult)) augmentedResults
75
86
76text :: DomBuilder t m => Text -> m ()
87text :: DomBuilder t m => Text -> m ()
77−text t = void $ textNode $ def & textNodeConfig_contents .~ t
88+text t = void $ textNode $ def & textNodeConfig_initialContents .~ t
78
89
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 ()
80dynText t = do
91dynText t = do
81 postBuild <- getPostBuild
92 postBuild <- getPostBuild
82− _ <- widgetHoldInternal (return ()) $ text <$> leftmost
93+ void $ textNode $ (def :: TextNodeConfig t) & textNodeConfig_setContents .~ leftmost
83 [ updated t
94 [ updated t
84 , tag (current t) postBuild
95 , tag (current t) postBuild
85 ]
96 ]
86− return ()
87
97
88display :: (PostBuild t m, DomBuilder t m, Show a) => Dynamic t a -> m ()
98display :: (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)
90
100
91button :: DomBuilder t m => Text -> m (Event t ())
101button :: DomBuilder t m => Text -> m (Event t ())
92button t = do
102button t = do
@@ -101,7 +111,7 @@ dyn :: (DomBuilder t m, PostBuild t m) => Dynamic t (m a) -> m (Event t a)
101dyn child = do
111dyn child = do
102 postBuild <- getPostBuild
112 postBuild <- getPostBuild
103 let newChild = leftmost [updated child, tag (current child) postBuild]
113 let newChild = leftmost [updated child, tag (current child) postBuild]
104− liftM snd $ widgetHoldInternal (return ()) newChild
114+ snd <$> widgetHoldInternal (return ()) newChild
105
115
106-- | Given an initial widget and an Event of widget-creating actions, create a widget that is recreated whenever the Event fires.
116-- | Given an initial widget and an Event of widget-creating actions, create a widget that is recreated whenever the Event fires.
107-- The returned Dynamic of widget results occurs when the Event does.
117-- The returned Dynamic of widget results occurs when the Event does.
@@ -167,7 +177,7 @@ listWithKey' = listWithKeyShallowDiff
167listWithKeyShallowDiff :: (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))
177listWithKeyShallowDiff :: (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))
168listWithKeyShallowDiff initialVals valsChanged mkChild = do
178listWithKeyShallowDiff initialVals valsChanged mkChild = do
169 let childValChangedSelector = fanMap $ fmap (Map.mapMaybe id) valsChanged
179 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
171 let relevantPatch patch _ = case patch of
181 let relevantPatch patch _ = case patch of
172 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
182 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
173 Just _ -> Nothing -- We don't want to let spurious re-creations of items through
183 Just _ -> Nothing -- We don't want to let spurious re-creations of items through
@@ -178,10 +188,10 @@ listWithKeyShallowDiff initialVals valsChanged mkChild = do
178-- | Create a dynamically-changing set of Event-valued widgets.
188-- | Create a dynamically-changing set of Event-valued widgets.
179-- 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'.
189-- 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'.
180listViewWithKey :: (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))
190listViewWithKey :: (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
182
192
183listViewWithKey' :: (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))
193listViewWithKey' :: (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
185
195
186-- | Create a dynamically-changing set of widgets, one of which is selected at any time.
196-- | Create a dynamically-changing set of widgets, one of which is selected at any time.
187selectViewListWithKey :: forall t m k v a. (DomBuilder t m, Ord k, PostBuild t m, MonadHold t m, MonadFix m)
197selectViewListWithKey :: 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
195 selected <- getDemuxed selectionDemux k
205 selected <- getDemuxed selectionDemux k
196 selectSelf <- mkChild k v selected
206 selectSelf <- mkChild k v selected
197 return $ fmap ((,) k) selectSelf
207 return $ fmap ((,) k) selectSelf
198− liftM switchPromptlyDyn $ mapDyn (leftmost . Map.elems) selectChild
208+ return $ switchPromptlyDyn $ leftmost . Map.elems <$> selectChild
199
209
200selectViewListWithKey_ :: forall t m k v a. (DomBuilder t m, Ord k, PostBuild t m, MonadHold t m, MonadFix m)
210selectViewListWithKey_ :: forall t m k v a. (DomBuilder t m, Ord k, PostBuild t m, MonadHold t m, MonadFix m)
201 => Dynamic t k -- ^ Current selection key
211 => Dynamic t k -- ^ Current selection key
202 -> Dynamic t (Map k v) -- ^ Dynamic key/value map
212 -> Dynamic t (Map k v) -- ^ Dynamic key/value map
203 -> (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
213 -> (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
204 -> m (Event t k) -- ^ Event that fires when any child's return Event fires. Contains key of an arbitrary firing widget.
214 -> 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
206
216
207{-
217{-
208{-# INLINABLE elWith #-}
218{-# INLINABLE elWith #-}
@@ -230,34 +240,26 @@ emptyElWith' elementTag cfg = do
230 wrapElement defaultDomEventHandler =<< buildEmptyElementNS (cfg ^. namespace) elementTag (cfg ^. attributes)
240 wrapElement defaultDomEventHandler =<< buildEmptyElementNS (cfg ^. namespace) elementTag (cfg ^. attributes)
231-}
241-}
232
242
233−dynamicAttributesToModifyAttributes :: PostBuild t m => Dynamic t (Map Text Text) -> m (Event t (Map AttributeName (Maybe Text)))
243+{-# INLINABLE el #-}
234−dynamicAttributesToModifyAttributes d = do
244+el :: forall t m a. DomBuilder t m => Text -> m a -> m a
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
245+el elementTag child = snd <$> el' elementTag child
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
256
246
257{-# INLINABLE elAttr #-}
247{-# INLINABLE elAttr #-}
258elAttr :: forall t m a. DomBuilder t m => Text -> Map Text Text -> m a -> m a
248elAttr :: forall t m a. DomBuilder t m => Text -> Map Text Text -> m a -> m a
259elAttr elementTag attrs child = snd <$> elAttr' elementTag attrs child
249elAttr elementTag attrs child = snd <$> elAttr' elementTag attrs child
260
250
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+
261{-# INLINABLE el' #-}
263{-# INLINABLE el' #-}
262el' :: forall t m a. DomBuilder t m => Text -> m a -> m (Element EventResult (DomBuilderSpace m) t, a)
264el' :: forall t m a. DomBuilder t m => Text -> m a -> m (Element EventResult (DomBuilderSpace m) t, a)
263el' elementTag = element elementTag def
265el' elementTag = element elementTag def
@@ -265,18 +267,39 @@ el' elementTag = element elementTag def
265{-# INLINABLE elAttr' #-}
267{-# INLINABLE elAttr' #-}
266elAttr' :: forall t m a. DomBuilder t m => Text -> Map Text Text -> m a -> m (Element EventResult (DomBuilderSpace m) t, a)
268elAttr' :: forall t m a. DomBuilder t m => Text -> Map Text Text -> m a -> m (Element EventResult (DomBuilderSpace m) t, a)
267elAttr' elementTag attrs = element elementTag $ def
269elAttr' 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
269
271
270−{-# INLINABLE elDynAttr #-}
272+{-# INLINABLE elClass' #-}
271−elDynAttr :: forall t m a. (DomBuilder t m, PostBuild t m) => Text -> Dynamic t (Map Text Text) -> m a -> m a
273+elClass' :: forall t m a. DomBuilder t m => Text -> Text -> m a -> m (Element EventResult (DomBuilderSpace m) t, a)
272−elDynAttr elementTag attrs child = snd <$> elDynAttr' elementTag attrs child
274+elClass' elementTag c = elAttr' elementTag ("class" =: c)
273
275
274−{-# INLINABLE el #-}
276+{-# INLINABLE elDynAttr' #-}
275−el :: forall t m a. DomBuilder t m => Text -> m a -> m a
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)
276−el elementTag child = snd <$> el' elementTag child
278+elDynAttr' = elDynAttrNS' Nothing
277
279
280+{-# INLINABLE elDynClass' #-}
278−elClass :: forall t m a. DomBuilder t m => Text -> Text -> m a -> m a
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)
279−elClass elementTag c child = fmap snd $ element elementTag (def & initialAttributes .~ (Nothing, "class") =: c) child
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
280
303
281--------------------------------------------------------------------------------
304--------------------------------------------------------------------------------
282-- Copied and pasted from Reflex.Widget.Class
305-- Copied and pasted from Reflex.Widget.Class
@@ -289,7 +312,7 @@ list dm mkChild = listWithKey dm (\_ dv -> mkChild dv)
289
312
290-- | Create a dynamically-changing set of widgets from a Dynamic list.
313-- | Create a dynamically-changing set of widgets from a Dynamic list.
291simpleList :: (DomBuilder t m, MonadHold t m, PostBuild t m, MonadFix m) => Dynamic t [v] -> (Dynamic t v -> m a) -> m (Dynamic t [a])
314simpleList :: (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
293
316
294{-
317{-
295schedulePostBuild x = performEvent_ . (x <$) =<< getPostBuild
318schedulePostBuild x = performEvent_ . (x <$) =<< getPostBuild
@@ -325,17 +348,17 @@ newtype Workflow t m a = Workflow { unWorkflow :: m (a, Event t (Workflow t m a)
325
348
326workflow :: forall t m a. (DomBuilder t m, MonadFix m, MonadHold t m) => Workflow t m a -> m (Dynamic t a)
349workflow :: forall t m a. (DomBuilder t m, MonadFix m, MonadHold t m) => Workflow t m a -> m (Dynamic t a)
327workflow w0 = do
350workflow w0 = do
328− rec eResult <- widgetHold (unWorkflow w0) $ fmap unWorkflow $ switch $ fmap snd $ current eResult
351+ rec eResult <- widgetHold (unWorkflow w0) $ fmap unWorkflow $ switch $ snd <$> current eResult
329− mapDyn fst eResult
352+ return $ fmap fst eResult
330
353
331workflowView :: forall t m a. (DomBuilder t m, MonadFix m, MonadHold t m, PostBuild t m) => Workflow t m a -> m (Event t a)
354workflowView :: forall t m a. (DomBuilder t m, MonadFix m, MonadHold t m, PostBuild t m) => Workflow t m a -> m (Event t a)
332workflowView w0 = do
355workflowView w0 = do
333− rec eResult <- dyn =<< mapDyn unWorkflow =<< holdDyn w0 eReplace
356+ rec eResult <- dyn . fmap unWorkflow =<< holdDyn w0 eReplace
334− eReplace <- liftM switch $ hold never $ fmap snd eResult
357+ eReplace <- fmap switch $ hold never $ fmap snd eResult
335 return $ fmap fst eResult
358 return $ fmap fst eResult
336
359
337mapWorkflow :: (DomBuilder t m) => (a -> b) -> Workflow t m a -> Workflow t m b
360mapWorkflow :: (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)
339
362
340divClass :: forall t m a. DomBuilder t m => Text -> m a -> m a
363divClass :: forall t m a. DomBuilder t m => Text -> m a -> m a
341divClass = elClass "div"
364divClass = elClass "div"
@@ -343,7 +366,7 @@ divClass = elClass "div"
343dtdd :: forall t m a. DomBuilder t m => Text -> m a -> m a
366dtdd :: forall t m a. DomBuilder t m => Text -> m a -> m a
344dtdd h w = do
367dtdd h w = do
345 el "dt" $ text h
368 el "dt" $ text h
346− el "dd" $ w
369+ el "dd" w
347
370
348blank :: forall m. Monad m => m ()
371blank :: forall m. Monad m => m ()
349blank = return ()
372blank = return ()
@@ -376,9 +399,9 @@ tabDisplay :: forall t m k. (MonadFix m, DomBuilder t m, MonadHold t m, PostBuil
376tabDisplay ulClass activeClass tabItems = do
399tabDisplay ulClass activeClass tabItems = do
377 let t0 = listToMaybe $ Map.keys tabItems
400 let t0 = listToMaybe $ Map.keys tabItems
378 rec currentTab :: Demux t (Maybe k) <- elAttr "ul" ("class" =: ulClass) $ do
401 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
380 let eTabClicks :: Event t k = leftmost tabClicksList
403 let eTabClicks :: Event t k = leftmost tabClicksList
381− liftM demux $ holdDyn t0 $ fmap Just eTabClicks
404+ fmap demux $ holdDyn t0 $ fmap Just eTabClicks
382 el "div" $ do
405 el "div" $ do
383 iforM_ tabItems $ \k (_, w) -> do
406 iforM_ tabItems $ \k (_, w) -> do
384 isSelected <- getDemuxed currentTab $ Just k
407 isSelected <- getDemuxed currentTab $ Just k
@@ -388,7 +411,7 @@ tabDisplay ulClass activeClass tabItems = do
388 where
411 where
389 headerBarLink :: Text -> k -> Dynamic t Bool -> m (Event t k)
412 headerBarLink :: Text -> k -> Dynamic t Bool -> m (Event t k)
390 headerBarLink x k isSelected = do
413 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
392 elDynAttr "li" attrs $ do
415 elDynAttr "li" attrs $ do
393 a <- link x
416 a <- link x
394 return $ fmap (const k) (_link_clicked a)
417 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 #-}
2module Reflex.Dom.Widget.Input (module Reflex.Dom.Widget.Input, def, (&), (.~)) where
14module Reflex.Dom.Widget.Input (module Reflex.Dom.Widget.Input, def, (&), (.~)) where
3
15
4import Prelude
16import Prelude
5
17
6−import Reflex.Dom.Class
7−import Reflex.Dom.Widget.Basic
8−import Reflex.Dom.PostBuild.Class
9import Reflex.Dom.Builder.Class
18import Reflex.Dom.Builder.Class
10import Reflex.Dom.Builder.Immediate
19import Reflex.Dom.Builder.Immediate
20+import Reflex.Dom.Class
21+import Reflex.Dom.PostBuild.Class
22+import Reflex.Dom.Widget.Basic
11
23
12-- For dropdown
24-- 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
14import GHCJS.DOM.HTMLInputElement (HTMLInputElement, castToHTMLInputElement)
29import GHCJS.DOM.HTMLInputElement (HTMLInputElement, castToHTMLInputElement)
15−import GHCJS.DOM.HTMLTextAreaElement (HTMLTextAreaElement, castToHTMLTextAreaElement)
16import GHCJS.DOM.HTMLSelectElement (castToHTMLSelectElement)
30import GHCJS.DOM.HTMLSelectElement (castToHTMLSelectElement)
17import qualified GHCJS.DOM.HTMLSelectElement as HTMLSelectElement
31import qualified GHCJS.DOM.HTMLSelectElement as HTMLSelectElement
18−import Data.Maybe
32+import GHCJS.DOM.HTMLTextAreaElement (HTMLTextAreaElement, castToHTMLTextAreaElement)
19−import Data.Semigroup
33+import Reflex.Dom.PerformEvent.Class
20−import Control.Monad.Fix
34+import qualified Text.Read as T
21−import Control.Monad.IO.Class
22
35
23-- For fileInput
36-- For fileInput
37+import qualified GHCJS.DOM.Element as Element
24import GHCJS.DOM.EventM (on)
38import GHCJS.DOM.EventM (on)
25import GHCJS.DOM.Types (File)
39import 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
28import qualified GHCJS.DOM.FileList as FileList
41import qualified GHCJS.DOM.FileList as FileList
29
42
30
43
31−import Reflex
32−import qualified Data.Map as Map
33−import Control.Lens hiding (ix, element)
44+import Control.Lens hiding (element, ix)
34import Control.Monad hiding (forM_)
45import Control.Monad hiding (forM_)
46+import qualified Data.Bimap as Bimap
35import Data.Default
47import Data.Default
36−import Data.Map (Map)
37−import Data.Text (Text)
38−import qualified Data.Text as T
39import Data.Dependent.Map (DMap)
48import Data.Dependent.Map (DMap)
40import qualified Data.Dependent.Map as DMap
49import qualified Data.Dependent.Map as DMap
41−import qualified Data.Bimap as Bimap
42−import Data.Proxy
43import Data.Functor.Misc
50import 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
44
57
45−import qualified GHCJS.DOM.HTMLInputElement as Input
46import qualified GHCJS.DOM.Event as Event
58import qualified GHCJS.DOM.Event as Event
59+import qualified GHCJS.DOM.HTMLInputElement as Input
47
60
48data TextInput t
61data TextInput t
49 = TextInput { _textInput_value :: Dynamic t Text
62 = TextInput { _textInput_value :: Dynamic t Text
@@ -88,30 +101,10 @@ textInput (TextInputConfig inputType initial eSetValue dAttrs) = do
88 , _textInput_hasFocus = _inputElement_hasFocus i
101 , _textInput_hasFocus = _inputElement_hasFocus i
89 , _textInput_element = castToHTMLInputElement $ _element_raw $ _inputElement_element i
102 , _textInput_element = castToHTMLInputElement $ _element_raw $ _inputElement_element i
90 }
103 }
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−-}
111
104
112{-# INLINABLE textInputGetEnter #-}
105{-# INLINABLE textInputGetEnter #-}
113textInputGetEnter :: Reflex t => TextInput t -> Event t ()
106textInputGetEnter :: 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
115
108
116data TextAreaConfig t
109data TextAreaConfig t
117 = TextAreaConfig { _textAreaConfig_initialValue :: Text
110 = TextAreaConfig { _textAreaConfig_initialValue :: Text
@@ -149,24 +142,6 @@ textArea (TextAreaConfig initial eSet attrs) = do
149 , _textArea_hasFocus = _textAreaElement_hasFocus i
142 , _textArea_hasFocus = _textAreaElement_hasFocus i
150 , _textArea_element = castToHTMLTextAreaElement $ _element_raw $ _textAreaElement_element i
143 , _textArea_element = castToHTMLTextAreaElement $ _element_raw $ _textAreaElement_element i
151 }
144 }
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−-}
170
145
171data CheckboxConfig t
146data CheckboxConfig t
172 = CheckboxConfig { _checkboxConfig_setValue :: Event t Bool
147 = CheckboxConfig { _checkboxConfig_setValue :: Event t Bool
@@ -190,7 +165,7 @@ data Checkbox t
190checkbox :: (DomBuilder t m, PostBuild t m) => Bool -> CheckboxConfig t -> m (Checkbox t)
165checkbox :: (DomBuilder t m, PostBuild t m) => Bool -> CheckboxConfig t -> m (Checkbox t)
191checkbox checked config = do
166checkbox checked config = do
192 let permanentAttrs = "type" =: "checkbox"
167 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
194 modifyAttrs <- dynamicAttributesToModifyAttributes dAttrs
169 modifyAttrs <- dynamicAttributesToModifyAttributes dAttrs
195 i <- inputElement $ def
170 i <- inputElement $ def
196 & inputElementConfig_initialChecked .~ checked
171 & inputElementConfig_initialChecked .~ checked
@@ -200,14 +175,6 @@ checkbox checked config = do
200 return $ Checkbox
175 return $ Checkbox
201 { _checkbox_value = _inputElement_checked i
176 { _checkbox_value = _inputElement_checked i
202 }
177 }
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−-}
211
178
212type family CheckboxViewEventResultType (en :: EventTag) :: * where
179type family CheckboxViewEventResultType (en :: EventTag) :: * where
213 CheckboxViewEventResultType 'ClickTag = Bool
180 CheckboxViewEventResultType 'ClickTag = Bool
@@ -296,18 +263,7 @@ checkboxView dAttrs dValue = do
296 & inputElementConfig_setChecked .~ leftmost [updated dValue, tag (current dValue) postBuild]
263 & inputElementConfig_setChecked .~ leftmost [updated dValue, tag (current dValue) postBuild]
297 & inputElementConfig_elementConfig .~ elementConfig
264 & inputElementConfig_elementConfig .~ elementConfig
298 i <- inputElement inputElementConfig
265 i <- inputElement inputElementConfig
299− return $ fmap unCheckboxViewEventResult $ select (_element_events $ _inputElement_element i) (WrapArg Click)
266+ return $ 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−-}
311
267
312data FileInput t
268data FileInput t
313 = FileInput { _fileInput_value :: Dynamic t [File]
269 = FileInput { _fileInput_value :: Dynamic t [File]
@@ -325,11 +281,11 @@ fileInput :: forall t m. (MonadIO m, MonadFix m, MonadHold t m, TriggerEvent t m
325 => FileInputConfig t -> m (FileInput t)
281 => FileInputConfig t -> m (FileInput t)
326fileInput config = do
282fileInput config = do
327 let insertType = Map.insert "type" "file"
283 let insertType = Map.insert "type" "file"
328− dAttrs = fmap insertType $ _fileInputConfig_attributes config
284+ dAttrs = insertType <$> _fileInputConfig_attributes config
329 modifyAttrs <- dynamicAttributesToModifyAttributes dAttrs
285 modifyAttrs <- dynamicAttributesToModifyAttributes dAttrs
330 let cfg = (def :: ElementConfig EventResult t m)
286 let cfg = (def :: ElementConfig EventResult t m)
331 { _elementConfig_modifyAttributes = modifyAttrs
287 { _elementConfig_modifyAttributes = modifyAttrs
332− , _elementConfig_eventFilters = DMap.singleton Change . EventFilter . GhcjsDomHandler $ \(GhcjsDomEvent evt) -> do
288+ , _elementConfig_eventFilters = DMap.singleton Change . EventFilter . GhcjsDomHandler $ \_ -> do
333 return . (,) mempty . GhcjsDomHandler $ \_ -> return . Just $ EventResult ()
289 return . (,) mempty . GhcjsDomHandler $ \_ -> return . Just $ EventResult ()
334 }
290 }
335 (eRaw, _) <- element "input" cfg blank
291 (eRaw, _) <- element "input" cfg blank
@@ -337,7 +293,7 @@ fileInput config = do
337 eChange <- wrapDomEvent e (`on` Element.change) $ do
293 eChange <- wrapDomEvent e (`on` Element.change) $ do
338 Just files <- Input.getFiles e
294 Just files <- Input.getFiles e
339 len <- FileList.getLength files
295 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]
341 dValue <- holdDyn [] eChange
297 dValue <- holdDyn [] eChange
342 return $ FileInput
298 return $ FileInput
343 { _fileInput_value = dValue
299 { _fileInput_value = dValue
@@ -418,7 +374,7 @@ regularToDropdownViewEventType en r = case en of
418--TODO: We should allow the user to specify an ordering instead of relying on the ordering of the Map
374--TODO: We should allow the user to specify an ordering instead of relying on the ordering of the Map
419-- | Create a dropdown box
375-- | Create a dropdown box
420-- 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
376-- 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)
422dropdown k0 options (DropdownConfig setK attrs) = do
378dropdown k0 options (DropdownConfig setK attrs) = do
423 optionsWithAddedKeys <- combineDyn Map.union options <=< foldDyn Map.union (k0 =: "") $ fmap (=: "") setK
379 optionsWithAddedKeys <- combineDyn Map.union options <=< foldDyn Map.union (k0 =: "") $ fmap (=: "") setK
424 defaultKey <- holdDyn k0 setK
380 defaultKey <- holdDyn k0 setK
@@ -443,11 +399,15 @@ dropdown k0 options (DropdownConfig setK attrs) = do
443 Just1 (EventResult r) -> return $ Just1 $ DropdownViewEventResult $ regularToDropdownViewEventType en r
399 Just1 (EventResult r) -> return $ Just1 $ DropdownViewEventResult $ regularToDropdownViewEventType en r
444 }
400 }
445 (eRaw, _) <- element "select" cfg $ listWithKey indexedOptions $ \(ix, k) v -> do
401 (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
447 elDynAttr "option" optionAttrs $ dynText v
403 elDynAttr "option" optionAttrs $ dynText v
448 let e = castToHTMLSelectElement $ _element_raw eRaw
404 let e = castToHTMLSelectElement $ _element_raw eRaw
449− performEvent_ $ fmap (HTMLSelectElement.setValue e . Just . show) $ attachDynWithMaybe (flip Bimap.lookupR) ixKeys setK
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
450− eChange <- return never -- attachDynWith (\ks s -> join $ Bimap.lookup <$> join (readMaybe <$> s) <*> pure ks) ixKeys <$> (wrapDomEvent e (`on` Element.change) $ HTMLSelectElement.getValue e)
410+ eChange <- attachDynWith lookupSelected ixKeys <$> wrapDomEvent e (`on` Element.change) (HTMLSelectElement.getValue e)
451 let readKey keys mk = fromMaybe k0 $ do
411 let readKey keys mk = fromMaybe k0 $ do
452 k <- mk
412 k <- mk
453 guard $ Bimap.memberR k keys
413 guard $ Bimap.memberR k keys
@@ -455,13 +415,13 @@ dropdown k0 options (DropdownConfig setK attrs) = do
455 dValue <- combineDyn readKey ixKeys <=< holdDyn (Just k0) $ leftmost [eChange, fmap Just setK]
415 dValue <- combineDyn readKey ixKeys <=< holdDyn (Just k0) $ leftmost [eChange, fmap Just setK]
456 return $ Dropdown dValue (attachDynWith readKey ixKeys eChange)
416 return $ Dropdown dValue (attachDynWith readKey ixKeys eChange)
457
417
458−liftM concat $ mapM makeLenses
418+concat <$> mapM makeLenses
459 [ ''TextAreaConfig
419 [ ''TextAreaConfig
460 , ''TextArea
420 , ''TextArea
461 , ''TextInputConfig
421 , ''TextInputConfig
462 , ''TextInput
422 , ''TextInput
463−-- , ''FileInputConfig
423+ , ''FileInputConfig
464−-- , ''FileInput
424+ , ''FileInput
465 , ''DropdownConfig
425 , ''DropdownConfig
466 , ''Dropdown
426 , ''Dropdown
467 , ''CheckboxConfig
427 , ''CheckboxConfig
@@ -484,11 +444,9 @@ instance HasAttributes (CheckboxConfig t) where
484 type Attrs (CheckboxConfig t) = Dynamic t (Map Text Text)
444 type Attrs (CheckboxConfig t) = Dynamic t (Map Text Text)
485 attributes = checkboxConfig_attributes
445 attributes = checkboxConfig_attributes
486
446
487−{-
488instance HasAttributes (FileInputConfig t) where
447instance HasAttributes (FileInputConfig t) where
489 type Attrs (FileInputConfig t) = Dynamic t (Map Text Text)
448 type Attrs (FileInputConfig t) = Dynamic t (Map Text Text)
490 attributes = fileInputConfig_attributes
449 attributes = fileInputConfig_attributes
491−-}
492
450
493class HasSetValue a where
451class HasSetValue a where
494 type SetValue a :: *
452 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 #-}
2module Reflex.Dom.Widget.Lazy where
7module Reflex.Dom.Widget.Lazy where
3
8
4import Reflex
9import Reflex
5−import Reflex.Dom.Class
6import Reflex.Dom.Builder.Class
10import Reflex.Dom.Builder.Class
7import Reflex.Dom.Builder.Immediate
11import Reflex.Dom.Builder.Immediate
8−import Reflex.Dom.PostBuild.Class
12+import Reflex.Dom.Class
9import Reflex.Dom.PerformEvent.Class
13import Reflex.Dom.PerformEvent.Class
14+import Reflex.Dom.PostBuild.Class
10import Reflex.Dom.Widget.Basic
15import Reflex.Dom.Widget.Basic
11
16
12import Control.Monad.Fix
17import Control.Monad.Fix
13import Control.Monad.IO.Class
18import Control.Monad.IO.Class
14import Data.Fixed
19import Data.Fixed
15−import Data.Monoid
16−import qualified Data.Map as Map
17import Data.Map (Map)
20import Data.Map (Map)
18−import GHCJS.DOM.Element
21+import qualified Data.Map as Map
22+import Data.Monoid
19import Data.Text (Text)
23import Data.Text (Text)
20import qualified Data.Text as T
24import qualified Data.Text as T
25+import GHCJS.DOM.Element
21
26
22-- |A list view for long lists. Creates a scrollable element and only renders child row elements near the current scroll position.
27-- |A list view for long lists. Creates a scrollable element and only renders child row elements near the current scroll position.
23virtualListWithSelection :: 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)
28virtualListWithSelection :: 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
35 -> (Int -> k) -- ^ Index to Key function, used to determine position of Map elements
40 -> (Int -> k) -- ^ Index to Key function, used to determine position of Map elements
36 -> 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
41 -> 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
37virtualListWithSelection heightPx rowPx maxIndex i0 setI listTag listAttrs rowTag rowAttrs itemBuilder items indexToKey = do
42virtualListWithSelection heightPx rowPx maxIndex i0 setI listTag listAttrs rowTag rowAttrs itemBuilder items indexToKey = do
38− totalHeightStyle <- mapDyn (toHeightStyle . (*) rowPx) maxIndex
43+ let totalHeightStyle = fmap (toHeightStyle . (*) rowPx) maxIndex
39− containerStyle <- mapDyn toContainer heightPx
44+ containerStyle = fmap toContainer heightPx
40− viewportStyle <- mapDyn toViewport heightPx
45+ viewportStyle = fmap toViewport heightPx
41 rec (container, sel) <- elDynAttr "div" containerStyle $ elDynAttr' "div" viewportStyle $ do
46 rec (container, sel) <- elDynAttr "div" containerStyle $ elDynAttr' "div" viewportStyle $ do
42− currentTop <- mapDyn (listWrapperStyle . fst) window
47+ let currentTop = fmap (listWrapperStyle . fst) window
43 (_, lis) <- elDynAttr "div" totalHeightStyle $ tagWrapper listTag listAttrs currentTop $ selectViewListWithKey_ selected itemsInWindow $ \k v s -> do
48 (_, lis) <- elDynAttr "div" totalHeightStyle $ tagWrapper listTag listAttrs currentTop $ selectViewListWithKey_ selected itemsInWindow $ \k v s -> do
44 (li,_) <- tagWrapper rowTag rowAttrs (constDyn $ toHeightStyle rowPx) $ itemBuilder k v s
49 (li,_) <- tagWrapper rowTag rowAttrs (constDyn $ toHeightStyle rowPx) $ itemBuilder k v s
45 return $ fmap (const k) (domEvent Click li)
50 return $ fmap (const k) (domEvent Click li)
@@ -49,14 +54,15 @@ virtualListWithSelection heightPx rowPx maxIndex i0 setI listTag listAttrs rowTa
49 scrollPosition <- holdDyn 0 $ leftmost [ domEvent Scroll container
54 scrollPosition <- holdDyn 0 $ leftmost [ domEvent Scroll container
50 , fmap (const (i0 * rowPx)) pb
55 , fmap (const (i0 * rowPx)) pb
51 ]
56 ]
52− window <- combineDyn (\h -> findWindow h rowPx) heightPx scrollPosition
57+ window <- combineDyn (findWindow rowPx) heightPx scrollPosition
53 itemsInWindow <- combineDyn (\(_,(idx,num)) is -> Map.fromList $ map (\i -> let ix = indexToKey i in (ix, Map.lookup ix is)) [idx .. idx + num]) window items
58 itemsInWindow <- combineDyn (\(_,(idx,num)) is -> Map.fromList $ map (\i -> let ix = indexToKey i in (ix, Map.lookup ix is)) [idx .. idx + num]) window items
54 postBuild <- getPostBuild
59 postBuild <- getPostBuild
60+ performEvent_ $ ffor (leftmost [setI, i0 <$ postBuild]) $ \i -> do
55− performEvent_ $ fmap (\i -> liftIO $ setScrollTop (_element_raw container) (i * rowPx)) $ leftmost [setI, fmap (const i0) postBuild]
61+ liftIO $ setScrollTop (_element_raw container) (i * rowPx)
56− indexAndLength <- mapDyn snd window
62+ let indexAndLength = fmap snd window
57 return (indexAndLength, sel)
63 return (indexAndLength, sel)
58 where
64 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
60 toViewport h = toStyleAttr $ "overflow" =: "auto" <> "position" =: "absolute" <>
66 toViewport h = toStyleAttr $ "overflow" =: "auto" <> "position" =: "absolute" <>
61 "left" =: "0" <> "right" =: "0" <> "height" =: (T.pack (show h) <> "px")
67 "left" =: "0" <> "right" =: "0" <> "height" =: (T.pack (show h) <> "px")
62 toContainer h = toStyleAttr $ "position" =: "relative" <> "height" =: (T.pack (show h) <> "px")
68 toContainer h = toStyleAttr $ "position" =: "relative" <> "height" =: (T.pack (show h) <> "px")
@@ -66,7 +72,7 @@ virtualListWithSelection heightPx rowPx maxIndex i0 setI listTag listAttrs rowTa
66 tagWrapper elTag attrs attrsOverride c = do
72 tagWrapper elTag attrs attrsOverride c = do
67 attrs' <- combineDyn Map.union attrsOverride attrs
73 attrs' <- combineDyn Map.union attrsOverride attrs
68 elDynAttr' elTag attrs' c
74 elDynAttr' elTag attrs' c
69− findWindow windowSize sizeIncrement startingPosition =
75+ findWindow sizeIncrement windowSize startingPosition =
70 let (startingIndex, topOffsetPx) = startingPosition `divMod'` sizeIncrement
76 let (startingIndex, topOffsetPx) = startingPosition `divMod'` sizeIncrement
71 topPx = startingPosition - topOffsetPx
77 topPx = startingPosition - topOffsetPx
72 numItems = windowSize `div` sizeIncrement + 1
78 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,
85 -> (k -> v -> Event t v -> m a) -- ^ The row child element builder.
91 -> (k -> v -> Event t v -> m a) -- ^ The row child element builder.
86 -> 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
92 -> 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
87virtualList heightPx rowPx maxIndex i0 setI keyToIndex items0 itemsUpdate itemBuilder = do
93virtualList heightPx rowPx maxIndex i0 setI keyToIndex items0 itemsUpdate itemBuilder = do
88− virtualH <- mapDyn (mkVirtualHeight . (*) rowPx) maxIndex
94+ let virtualH = fmap (mkVirtualHeight . (*) rowPx) maxIndex
89− containerStyle <- mapDyn mkContainer heightPx
95+ containerStyle = fmap mkContainer heightPx
90− viewportStyle <- mapDyn mkViewport heightPx
96+ viewportStyle = fmap mkViewport heightPx
91 pb <- getPostBuild
97 pb <- getPostBuild
92 rec (viewport, result) <- elDynAttr "div" containerStyle $ elDynAttr' "div" viewportStyle $ elDynAttr "div" virtualH $
98 rec (viewport, result) <- elDynAttr "div" containerStyle $ elDynAttr' "div" viewportStyle $ elDynAttr "div" virtualH $
93 listWithKeyShallowDiff items0 itemsUpdate $ \k v e -> elAttr "div" (mkRow k) $ itemBuilder k v e
99 listWithKeyShallowDiff items0 itemsUpdate $ \k v e -> elAttr "div" (mkRow k) $ itemBuilder k v e
94 scrollPosition <- holdDyn 0 $ leftmost [ domEvent Scroll viewport
100 scrollPosition <- holdDyn 0 $ leftmost [ domEvent Scroll viewport
95 , fmap (const (i0 * rowPx)) pb
101 , fmap (const (i0 * rowPx)) pb
96 ]
102 ]
97− window <- combineDyn (\h -> findWindow h rowPx) heightPx scrollPosition
103+ window <- combineDyn (findWindow rowPx) heightPx scrollPosition
98− performEvent_ $ fmap (\i -> liftIO $ setScrollTop (_element_raw viewport) (i * rowPx)) $ leftmost [setI, fmap (const i0) pb]
104+ performEvent_ $ ffor (leftmost [setI, i0 <$ pb]) $ \i -> do
105+ liftIO $ setScrollTop (_element_raw viewport) (i * rowPx)
99 return (nubDyn window, result)
106 return (nubDyn window, result)
100 where
107 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
102 mkViewport h = toStyleAttr $ "overflow" =: "auto" <> "position" =: "absolute" <>
109 mkViewport h = toStyleAttr $ "overflow" =: "auto" <> "position" =: "absolute" <>
103 "left" =: "0" <> "right" =: "0" <> "height" =: (T.pack (show h) <> "px")
110 "left" =: "0" <> "right" =: "0" <> "height" =: (T.pack (show h) <> "px")
104 mkContainer h = toStyleAttr $ "position" =: "relative" <> "height" =: (T.pack (show h) <> "px")
111 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
110 "top" =: ((<>"px") $ T.pack $ show $ keyToIndex k * rowPx) <>
117 "top" =: ((<>"px") $ T.pack $ show $ keyToIndex k * rowPx) <>
111 "position" =: "absolute" <>
118 "position" =: "absolute" <>
112 "width" =: "100%"
119 "width" =: "100%"
113− findWindow windowSize sizeIncrement startingPosition =
120+ findWindow sizeIncrement windowSize startingPosition =
114 let (startingIndex, _) = startingPosition `divMod'` sizeIncrement
121 let (startingIndex, _) = startingPosition `divMod'` sizeIncrement
115 numItems = (windowSize + sizeIncrement - 1) `div` sizeIncrement
122 numItems = (windowSize + sizeIncrement - 1) `div` sizeIncrement
116 in (startingIndex, numItems)
123 in (startingIndex, numItems)
@@ -137,6 +144,6 @@ virtualListBuffered buffer heightPx rowPx maxIndex i0 setI keyToIndex items0 ite
137 then Nothing
144 then Nothing
138 else Just (extendWin winOffset winLimit)) (current winBuffered) (updated win)
145 else Just (extendWin winOffset winLimit)) (current winBuffered) (updated win)
139 winBuffered <- holdDyn (0, 0) $ leftmost [ winHitEdge
146 winBuffered <- holdDyn (0, 0) $ leftmost [ winHitEdge
140− , fmap (uncurry extendWin) $ tagDyn win pb
147+ , attachDynWith (\(x, y) _ -> extendWin x y) win pb
141 ]
148 ]
142 return (updated winBuffered, m)
149 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 #-}
2module Reflex.Dom.Widget.Resize where
6module Reflex.Dom.Widget.Resize where
3
7
4import Reflex
8import Reflex
5−import Reflex.Dom.PostBuild.Class
9+import Reflex.Dom.Builder.Class
6−import Reflex.Dom.PerformEvent.Class
7import Reflex.Dom.Builder.Immediate
10import Reflex.Dom.Builder.Immediate
8import Reflex.Dom.Class
11import Reflex.Dom.Class
9import Reflex.Dom.Old
12import Reflex.Dom.Old
13+import Reflex.Dom.PerformEvent.Class
14+import Reflex.Dom.PostBuild.Class
10import Reflex.Dom.Widget.Basic
15import Reflex.Dom.Widget.Basic
11
16
12import Control.Monad
17import Control.Monad
18+import Control.Monad.Fix
13import Control.Monad.IO.Class
19import Control.Monad.IO.Class
14import Data.Map (Map)
20import Data.Map (Map)
21+import qualified Data.Map as Map
22+import Data.Monoid
15import Data.Text (Text)
23import Data.Text (Text)
16import qualified Data.Text as T
24import qualified Data.Text as T
17−import Data.Monoid
18import GHCJS.DOM.Element hiding (reset)
25import GHCJS.DOM.Element hiding (reset)
19import GHCJS.DOM.EventM (on)
26import GHCJS.DOM.EventM (on)
20−import qualified Data.Map as Map
21
27
22-- | A widget that wraps the given widget in a div and fires an event when resized.
28-- | A widget that wraps the given widget in a div and fires an event when resized.
23-- Adapted from github.com/marcj/css-element-queries
29-- 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)
25resizeDetector = resizeDetectorWithStyle ""
31resizeDetector = resizeDetectorWithStyle ""
26
32
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)
28 => Text -- ^ A css style string. Warning: It should not contain the "position" style attribute.
34 => Text -- ^ A css style string. Warning: It should not contain the "position" style attribute.
29 -> m a -- ^ The embedded widget
35 -> m a -- ^ The embedded widget
30 -> m (Event t (), a) -- ^ An 'Event' that fires on resize, and the result of the embedded widget
36 -> 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)
32
38
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)
34 => Map Text Text -- ^ A map of attributes. Warning: It should not modify the "position" style attribute.
40 => Map Text Text -- ^ A map of attributes. Warning: It should not modify the "position" style attribute.
35 -> m a -- ^ The embedded widget
41 -> m a -- ^ The embedded widget
36 -> m (Event t (), a) -- ^ An 'Event' that fires on resize, and the result of the embedded widget
42 -> 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
66 pow <- getOffsetWidth (_el_element parent)
72 pow <- getOffsetWidth (_el_element parent)
67 poh <- getOffsetHeight (_el_element parent)
73 poh <- getOffsetHeight (_el_element parent)
68 if ds == (Just pow, Just poh)
74 if ds == (Just pow, Just poh)
69− then return Nothing
75+ then return Nothing
70− else liftM Just reset
76+ else fmap Just reset
71 pb <- getPostBuild
77 pb <- getPostBuild
72 expandScroll <- wrapDomEvent (_el_element expand) (`on` scroll) $ return ()
78 expandScroll <- wrapDomEvent (_el_element expand) (`on` scroll) $ return ()
73 shrinkScroll <- wrapDomEvent (_el_element shrink) (`on` scroll) $ return ()
79 shrinkScroll <- wrapDomEvent (_el_element shrink) (`on` scroll) $ return ()
74 size0 <- performEvent $ fmap (const $ liftIO reset) pb
80 size0 <- performEvent $ fmap (const $ liftIO reset) pb
75 rec resize <- performEventAsync $ fmap (\d cb -> liftIO $ cb =<< resetIfChanged d) $ tag (current dimensions) $ leftmost [expandScroll, shrinkScroll]
81 rec resize <- performEventAsync $ fmap (\d cb -> liftIO $ cb =<< resetIfChanged d) $ tag (current dimensions) $ leftmost [expandScroll, shrinkScroll]
76 dimensions <- holdDyn (Nothing, Nothing) $ leftmost [ size0, fmapMaybe id resize ]
82 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 #-}
2module Reflex.Dom.Xhr
8module Reflex.Dom.Xhr
3 ( XMLHttpRequest
9 ( XMLHttpRequest
4− , XhrRequest(..)
10+ , XhrRequest (..)
5− , XhrRequestConfig(..)
11+ , XhrRequestConfig (..)
6− , XhrResponse(..)
12+ , XhrResponse (..)
7− , XhrResponseBody(..)
13+ , XhrResponseBody (..)
8− , XhrResponseType(..)
14+ , XhrResponseType (..)
9− , XhrException(..)
15+ , XhrException (..)
16+ , IsXhrPayload (..)
10 , _xhrResponse_body
17 , _xhrResponse_body
11 , decodeText
18 , decodeText
12 , decodeXhrResponse
19 , decodeXhrResponse
@@ -42,7 +49,6 @@ module Reflex.Dom.Xhr
42 , xmlHttpRequestNew
49 , xmlHttpRequestNew
43 , xmlHttpRequestOnreadystatechange
50 , xmlHttpRequestOnreadystatechange
44 , xmlHttpRequestOpen
51 , xmlHttpRequestOpen
45− , xmlHttpRequestSend
46 , xmlHttpRequestSetRequestHeader
52 , xmlHttpRequestSetRequestHeader
47 , xmlHttpRequestSetResponseType
53 , xmlHttpRequestSetResponseType
48 )
54 )
@@ -50,20 +56,18 @@ where
50
56
51import Reflex
57import Reflex
52import Reflex.Dom.Class
58import Reflex.Dom.Class
53−import Reflex.Dom.Xhr.Foreign
54import Reflex.Dom.PerformEvent.Class
59import Reflex.Dom.PerformEvent.Class
55import Reflex.Dom.Xhr.Exception
60import Reflex.Dom.Xhr.Exception
61+import Reflex.Dom.Xhr.Foreign
56import Reflex.Dom.Xhr.ResponseType
62import Reflex.Dom.Xhr.ResponseType
57
63
58import Control.Concurrent
64import Control.Concurrent
59−import Control.Exception (catch)
65+import Control.Exception (handle)
60import Control.Lens
66import Control.Lens
61import Control.Monad hiding (forM)
67import Control.Monad hiding (forM)
62import Control.Monad.IO.Class
68import Control.Monad.IO.Class
63import Data.Aeson
69import Data.Aeson
64import Data.Aeson.Encode
70import Data.Aeson.Encode
65−import qualified Data.Text.Lazy as LT
66−import qualified Data.Text.Lazy.Builder as B
67import qualified Data.ByteString.Lazy as BL
71import qualified Data.ByteString.Lazy as BL
68import Data.Default
72import Data.Default
69import Data.Map (Map)
73import Data.Map (Map)
@@ -71,6 +75,8 @@ import qualified Data.Map as Map
71import Data.Maybe
75import Data.Maybe
72import Data.Text (Text)
76import Data.Text (Text)
73import Data.Text.Encoding
77import Data.Text.Encoding
78+import qualified Data.Text.Lazy as LT
79+import qualified Data.Text.Lazy.Builder as B
74import Data.Traversable
80import Data.Traversable
75import Data.Typeable
81import Data.Typeable
76
82
@@ -79,7 +85,7 @@ data XhrRequest a
79 , _xhrRequest_url :: Text
85 , _xhrRequest_url :: Text
80 , _xhrRequest_config :: XhrRequestConfig a
86 , _xhrRequest_config :: XhrRequestConfig a
81 }
87 }
82− deriving (Show, Read, Eq, Ord, Typeable)
88+ deriving (Show, Read, Eq, Ord, Typeable, Functor)
83
89
84data XhrRequestConfig a
90data XhrRequestConfig a
85 = XhrRequestConfig { _xhrRequestConfig_headers :: Map Text Text
91 = XhrRequestConfig { _xhrRequestConfig_headers :: Map Text Text
@@ -88,7 +94,7 @@ data XhrRequestConfig a
88 , _xhrRequestConfig_responseType :: Maybe XhrResponseType
94 , _xhrRequestConfig_responseType :: Maybe XhrResponseType
89 , _xhrRequestConfig_sendData :: a
95 , _xhrRequestConfig_sendData :: a
90 }
96 }
91− deriving (Show, Read, Eq, Ord, Typeable)
97+ deriving (Show, Read, Eq, Ord, Typeable, Functor)
92
98
93data XhrResponse
99data XhrResponse
94 = XhrResponse { _xhrResponse_status :: Word
100 = XhrResponse { _xhrResponse_status :: Word
@@ -134,7 +140,7 @@ newXMLHttpRequestWithError
134newXMLHttpRequestWithError req cb = do
140newXMLHttpRequestWithError req cb = do
135 wv <- askWebView
141 wv <- askWebView
136 xhr <- liftIO $ xmlHttpRequestNew $ unWebViewSingleton wv
142 xhr <- liftIO $ xmlHttpRequestNew $ unWebViewSingleton wv
137− void $ liftIO $ forkIO $ flip catch (cb . Left) $ void $ do
143+ void $ liftIO $ forkIO $ handle (cb . Left) $ void $ do
138 let c = _xhrRequest_config req
144 let c = _xhrRequest_config req
139 rt = _xhrRequestConfig_responseType c
145 rt = _xhrRequestConfig_responseType c
140 xmlHttpRequestOpen
146 xmlHttpRequestOpen
@@ -150,20 +156,18 @@ newXMLHttpRequestWithError req cb = do
150 readyState <- liftIO $ xmlHttpRequestGetReadyState xhr
156 readyState <- liftIO $ xmlHttpRequestGetReadyState xhr
151 status <- liftIO $ xmlHttpRequestGetStatus xhr
157 status <- liftIO $ xmlHttpRequestGetStatus xhr
152 statusText <- liftIO $ xmlHttpRequestGetStatusText xhr
158 statusText <- liftIO $ xmlHttpRequestGetStatusText xhr
153− if readyState == 4
159+ when (readyState == 4) $ do
154− then do
155− t <- if rt == Just XhrResponseType_Text || rt == Nothing
160+ t <- if rt == Just XhrResponseType_Text || isNothing rt
156− then liftIO $ xmlHttpRequestGetResponseText xhr
161+ then liftIO $ xmlHttpRequestGetResponseText xhr
157− else return Nothing
162+ else return Nothing
158− r <- liftIO $ xmlHttpRequestGetResponse xhr
163+ r <- liftIO $ xmlHttpRequestGetResponse xhr
159− _ <- liftIO $ cb $ Right $
164+ _ <- liftIO $ cb $ Right $ XhrResponse
160− XhrResponse { _xhrResponse_status = status
165+ { _xhrResponse_status = status
161− , _xhrResponse_statusText = statusText
166+ , _xhrResponse_statusText = statusText
162− , _xhrResponse_response = r
167+ , _xhrResponse_response = r
163− , _xhrResponse_responseText = t
168+ , _xhrResponse_responseText = t
164− }
169+ }
165− return ()
166− else return ()
170+ return ()
167 _ <- xmlHttpRequestSend xhr (_xhrRequestConfig_sendData c)
171 _ <- xmlHttpRequestSend xhr (_xhrRequestConfig_sendData c)
168 return ()
172 return ()
169 return xhr
173 return xhr
@@ -255,8 +259,9 @@ decodeText = decode . BL.fromStrict . encodeUtf8
255decodeXhrResponse :: FromJSON a => XhrResponse -> Maybe a
259decodeXhrResponse :: FromJSON a => XhrResponse -> Maybe a
256decodeXhrResponse = join . fmap decodeText . _xhrResponse_responseText
260decodeXhrResponse = join . fmap decodeText . _xhrResponse_responseText
257
261
258−liftM concat $ mapM makeLenses
262+concat <$> mapM makeLenses
259 [ ''XhrRequest
263 [ ''XhrRequest
260 , ''XhrRequestConfig
264 , ''XhrRequestConfig
261 , ''XhrResponse
265 , ''XhrResponse
262 ]
266 ]
267+
src/Reflex/Dom/Xhr/Exception.hs+1−1
@@ -2,8 +2,8 @@
2
2
3module Reflex.Dom.Xhr.Exception where
3module Reflex.Dom.Xhr.Exception where
4
4
5+import Control.Exception (Exception (..))
5import Data.Typeable
6import Data.Typeable
6−import Control.Exception (Exception(..))
7
7
8data XhrException = XhrException_Error
8data XhrException = XhrException_Error
9 | XhrException_Aborted
9 | XhrException_Aborted
src/Reflex/Dom/Xhr/ResponseType.hs+2−2
@@ -2,10 +2,10 @@
2
2
3module Reflex.Dom.Xhr.ResponseType where
3module Reflex.Dom.Xhr.ResponseType where
4
4
5−import Data.Typeable
5+import Data.ByteString (ByteString)
6import Data.Text (Text)
6import Data.Text (Text)
7+import Data.Typeable
7import GHCJS.DOM.Blob (Blob)
8import GHCJS.DOM.Blob (Blob)
8−import Data.ByteString (ByteString)
9
9
10data XhrResponseType = XhrResponseType_Default
10data XhrResponseType = XhrResponseType_Default
11 | XhrResponseType_ArrayBuffer
11 | XhrResponseType_ArrayBuffer
test/BrokenHaltSpec.hs+9−10
@@ -2,13 +2,13 @@
2
2
3module HaltSpec where
3module HaltSpec where
4
4
5−import Control.Monad.IO.Class
5+import Control.Monad.IO.Class
6−import Data.Foldable
6+import Data.Foldable
7−import GHCJS.DOM
7+import GHCJS.DOM
8import qualified Graphics.UI.Gtk as Gtk
8import qualified Graphics.UI.Gtk as Gtk
9−import Reflex.Dom
9+import Reflex.Dom
10−import Reflex.Spider.Internal (SpiderHostFrame)
10+import Reflex.Spider.Internal (SpiderHostFrame)
11−import Test.Hspec
11+import Test.Hspec
12
12
13spec :: Spec
13spec :: Spec
14spec = do
14spec = do
@@ -34,7 +34,6 @@ getFirstEventAndHalt action = do
34 return ()
34 return ()
35
35
36haltGui :: WebView -> IO ()
36haltGui :: WebView -> IO ()
37−haltGui wv = do
38− Gtk.postGUIAsync $ do
37+haltGui wv = Gtk.postGUIAsync $ do
39− w <- Gtk.widgetGetToplevel wv
38+ w <- Gtk.widgetGetToplevel wv
40− Gtk.widgetDestroy w
39+ Gtk.widgetDestroy w
test/HaltSpec.hs+13−15
@@ -1,29 +1,27 @@
1{-# LANGUAGE FlexibleContexts #-}
1{-# LANGUAGE FlexibleContexts #-}
2
2
3−import Control.Monad.IO.Class
3+import Control.Monad.IO.Class
4−import Data.Foldable
4+import Data.Foldable
5−import GHCJS.DOM
5+import GHCJS.DOM
6import qualified Graphics.UI.Gtk as Gtk
6import qualified Graphics.UI.Gtk as Gtk
7−import Reflex.Dom
7+import Reflex.Dom
8−import Reflex.Spider.Internal (SpiderHostFrame)
8+import Reflex.Spider.Internal (SpiderHostFrame)
9
9
10+main :: IO ()
10main = do
11main = do
11 getFirstEventAndHalt return
12 getFirstEventAndHalt return
12 putStrLn "stopped once"
13 putStrLn "stopped once"
13
14
14− forM_ [1 .. 1000] $ \ i -> do
15− getFirstEventAndHalt return
15+ forM_ [1 .. 1000] $ \i -> getFirstEventAndHalt return
16 putStrLn "stopped many times"
16 putStrLn "stopped many times"
17
17
18type SpiderM = Widget Spider (Gui Spider (WithWebView SpiderHost) SpiderHostFrame)
18type SpiderM = Widget Spider (Gui Spider (WithWebView SpiderHost) SpiderHostFrame)
19
19
20getFirstEventAndHalt :: (Event Spider () -> SpiderM (Event Spider ())) -> IO ()
20getFirstEventAndHalt :: (Event Spider () -> SpiderM (Event Spider ())) -> IO ()
21−getFirstEventAndHalt action = do
21+getFirstEventAndHalt action = mainWidget $ do
22− _ <- mainWidget $ do
23− tick <- getPostBuild
22+ tick <- getPostBuild
24− event <- action tick
23+ event <- action tick
25− webView <- askWebView
24+ webView <- askWebView
26− quit <- getQuitWidget
25+ quit <- getQuitWidget
27− performEvent_ (quit <$ event)
26+ performEvent_ (quit <$ event)
28− return ()
29 return ()
27 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