on develop help sign in
Merge branch 'develop' into dn-add-geoloc-android
commit0abb8abc428d88618779b1a74cbfea335e54a7b5 authorJohn Ericson <John.Ericson@Obsidian.Systems> dateTue 10 Dec 2019, 13:06 (7 years ago) parent8e54d6cc89302c
19 files changed+312−171
default.nix+51−5 dep/reflex-platform/default.nix+7 dep/reflex-platform/github.json+7 reflex-dom-core/ChangeLog.md+10−1 reflex-dom-core/default.nix−63 reflex-dom-core/reflex-dom-core.cabal+17−4 reflex-dom-core/src/Reflex/Dom/Builder/Hydratable.hs+116 reflex-dom-core/src/Reflex/Dom/Builder/Immediate.hs+12−5 reflex-dom-core/src/Reflex/Dom/Builder/InputDisabled.hs+6 reflex-dom-core/src/Reflex/Dom/Core.hs+1 reflex-dom-core/src/Reflex/Dom/Prerender.hs+9−4 reflex-dom-core/src/Reflex/Dom/Widget/Basic.hs+5−4 reflex-dom-core/src/Reflex/Dom/Widget/Resize.hs+4 reflex-dom-core/test/hlint.hs+1 reflex-dom-core/test/hydration.hs+31−22 reflex-dom/default.nix−38 reflex-dom/reflex-dom.cabal+3−8 reflex-platform.nix−8 release.nix+32−9
default.nix+51−5
@@ -1,7 +1,53 @@
1−haskellPackages: nixpkgs: {
2− reflex-dom = haskellPackages.callPackage ./reflex-dom {};
3− reflex-dom-core = haskellPackages.callPackage ./reflex-dom-core {
4− inherit (nixpkgs) iproute chromium;
5− };
1+haskellPackages: let
2+ pkgs = haskellPackages.callPackage ({ pkgs }: pkgs) {};
3+ inherit (pkgs) stdenv;
4+ haskellLib = pkgs.haskell.lib;
5+in {
6+ reflex-dom-core = let
7+ inherit (haskellPackages) ghc;
8+ noGcTest = stdenv.hostPlatform.system != "x86_64-linux"
9+ || stdenv.hostPlatform != stdenv.buildPlatform
10+ || (ghc.isGhcjs or false);
11+ in haskellLib.overrideCabal
12+ (haskellPackages.callCabal2nix "reflex-dom-core" ./reflex-dom-core { })
13+ (drv: {
14+ #TODO: Get hlint working for cross-compilation
15+ doCheck = stdenv.hostPlatform == stdenv.buildPlatform && !(ghc.isGhcjs or false);
16+
17+ # The headless browser run as part of the tests will exit without this
18+ preBuild = ''
19+ export HOME="$PWD"
20+ '';
21+
22+ # Show some output while running tests, so we might notice what's wrong
23+ testTarget = "--show-details=streaming";
24+
25+ testHaskellDepends = with haskellPackages; (drv.testHaskellDepends or []) ++ stdenv.lib.optionals (!noGcTest) [
26+ temporary
27+ jsaddle-warp
28+ process
29+ chrome-test-utils
30+ ];
31+
32+ testSystemDepends = with pkgs; (drv.testSystemDepends or []) ++ [
33+ selenium-server-standalone which
34+ ] ++ stdenv.lib.optionals (!noGcTest) [
35+ chromium
36+ pkgs.iproute
37+ ];
38+ } // stdenv.lib.optionalAttrs (!noGcTest) {
39+ # The headless browser run as part of gc tests would hang/crash without this
40+ preCheck = ''
41+ export FONTCONFIG_PATH=${pkgs.fontconfig.out}/etc/fonts
42+ '';
43+ });
44+ reflex-dom = haskellLib.overrideCabal
45+ (haskellPackages.callCabal2nix "reflex-dom" ./reflex-dom { })
46+ (drv: {
47+ # Hack until https://github.com/NixOS/cabal2nix/pull/432 lands
48+ libraryHaskellDepends = (drv.libraryHaskellDepends or []) ++ stdenv.lib.optionals (with stdenv.hostPlatform; isAndroid && is32bit) [
49+ haskellPackages.android-activity
50+ ];
51+ });
652 chrome-test-utils = haskellPackages.callCabal2nix "chrome-test-utils" ./chrome-test-utils {};
753}
dep/reflex-platform/default.nixnew file+7
@@ -0,0 +1,7 @@
1+# DO NOT HAND-EDIT THIS FILE
2+import ((import <nixpkgs> {}).fetchFromGitHub (
3+ let json = builtins.fromJSON (builtins.readFile ./github.json);
4+ in { inherit (json) owner repo rev sha256;
5+ private = json.private or false;
6+ }
7+))
dep/reflex-platform/github.jsonnew file+7
@@ -0,0 +1,7 @@
1+{
2+ "owner": "reflex-frp",
3+ "repo": "reflex-platform",
4+ "branch": "develop",
5+ "rev": "338fc907e37d70e6469c529456f33221fb05ca1f",
6+ "sha256": "08gfhpp0pkvvi1wnlpcn6wmpzdjvy5z7dy1h66gp2w8b5cx8hx5h"
7+}
reflex-dom-core/ChangeLog.md+10−1
@@ -1,13 +1,22 @@
11# Revision history for reflex-dom-core
22
3+## Unreleased
4+
35## 0.5.2
46
57* Update to use new dependent-sum/map packages and drop dependency on `*Tag` classes (e.g., `ShowTag`).
8+* Update version bounds of base, containers, and stm
9+* Update to use the newly split `these`/`semialign` packages. To use the pre-split `these` package, set the `split-these` flag to false.
10+* Reintroduce "data-ssr": elements without this attribute are skipped during
11+ hydration.
12+* Fix an issue in the hydration tests that prevented the test from finding the chromium executable
13+* Relax constraints on `dyn` and `widgetHold` to match the ones in `networkView` and `networkHold` respectively
14+* Fix prerender for RequesterT so that it doesn't accidentally discard a request that is made at the same moment as getPostBuild's Event fires
615
716## 0.5.1
817
918* Added support for marking elements with a "data-skip-hydration" attribute, which will cause hydration to ignore and skip over them.
10−* Removed "data-ssr" attributes from statically rendered output.:q
19+* Removed "data-ssr" attributes from statically rendered output.
1120
1221## 0.5
1322
reflex-dom-core/default.nixdeleted−63
@@ -1,63 +0,0 @@
1−{ mkDerivation, aeson, base, bifunctors, bimap, blaze-builder
2−, bytestring, chrome-test-utils, constraints, constraints-extras, containers
3−, contravariant, data-default, dependent-map, dependent-sum
4−, dependent-sum-template, directory, exception-transformers
5−, exceptions, filepath, ghcjs-dom, hlint, hspec, hspec-webdriver, http-types, HUnit
6−, jsaddle, jsaddle-warp, keycode, lens, lifted-base
7−, monad-control, mtl, network, network-uri, primitive, process
8−, random, ref-tf, reflex, semigroups, silently, stdenv, stm
9−, template-haskell, temporary, text, these, transformers, unix, wai
10−, wai-websockets, warp, webdriver, websockets, zenc
11−, ghc, iproute, chromium, hashable, selenium-server-standalone, which, fontconfig
12−}:
13−let addGcTestDepends = drv: if (stdenv.system != "x86_64-linux" || stdenv.hostPlatform != stdenv.buildPlatform || (ghc.isGhcjs or false)) then drv else drv // {
14− # The headless browser run as part of gc tests would hang/crash without this
15− preCheck = ''
16− export FONTCONFIG_PATH=${fontconfig.out}/etc/fonts
17− '';
18− testHaskellDepends = (drv.testHaskellDepends or []) ++ [
19− temporary
20− jsaddle-warp
21− process
22− chrome-test-utils
23− ];
24− testSystemDepends = (drv.testSystemDepends or []) ++ [ chromium iproute ];
25− };
26−in mkDerivation (addGcTestDepends {
27− pname = "reflex-dom-core";
28− version = "0.5.2";
29− src = ./.;
30− libraryHaskellDepends = [
31− aeson base bifunctors bimap blaze-builder bytestring constraints
32− containers contravariant data-default dependent-map dependent-sum
33− dependent-sum-template directory exception-transformers ghcjs-dom
34− jsaddle keycode lens monad-control mtl network-uri primitive random
35− ref-tf reflex semigroups stm template-haskell text these
36− transformers unix zenc
37− ] ++ (if ghc.isGhcjs or false then [
38− hashable
39− ] else []);
40−
41− #TODO: Get hlint working for cross-compilation
42− doCheck = stdenv.hostPlatform == stdenv.buildPlatform && !(ghc.isGhcjs or false);
43−
44− # The headless browser run as part of the tests will exit without this
45− preBuild = ''
46− export HOME="$PWD"
47− '';
48−
49− # Show some output while running tests, so we might notice what's wrong
50− testTarget = "--show-details=streaming";
51−
52− testSystemDepends = [ selenium-server-standalone which ];
53− testHaskellDepends = [
54− aeson base bytestring constraints constraints-extras containers
55− dependent-map dependent-sum dependent-sum-template directory
56− exceptions filepath ghcjs-dom hlint hspec hspec-webdriver http-types HUnit jsaddle
57− jsaddle-warp lens lifted-base network process random reflex
58− silently temporary text unix wai wai-websockets warp webdriver
59− websockets
60− ];
61− description = "Functional Reactive Web Apps with Reflex";
62− license = stdenv.lib.licenses.bsd3;
63−})
reflex-dom-core/reflex-dom-core.cabal+17−4
@@ -39,6 +39,11 @@ flag profile-reflex
3939 default: False
4040 manual: True
4141
42+flag split-these
43+ description: Use split these/semialign packages
44+ manual: False
45+ default: True
46+
4247library
4348 hs-source-dirs: src
4449 build-depends:
@@ -48,8 +53,8 @@ library
4853 bimap >= 0.3 && < 0.4,
4954 blaze-builder,
5055 bytestring == 0.10.*,
51− containers >= 0.5 && < 0.7,
52− constraints >= 0.9 && < 0.11,
56+ containers >= 0.6 && < 0.7,
57+ constraints >= 0.9 && < 0.12,
5358 contravariant >= 1.4 && < 1.6,
5459 data-default >= 0.5 && < 0.8,
5560 dependent-map >= 0.3 && < 0.4,
@@ -68,11 +73,9 @@ library
6873 random,
6974 ref-tf == 0.4.*,
7075 reflex >= 0.6.2,
71− semialign == 1.*,
7276 semigroups >= 0.16 && < 0.19,
7377 stm >= 2.4 && < 2.6,
7478 text == 1.2.*,
75− these >= 0.4 && < 1.1,
7679 transformers >= 0.3 && < 0.6,
7780 network-uri >= 2.6.1 && < 2.7,
7881 zenc == 0.1.*
@@ -87,6 +90,14 @@ library
8790 if !os(windows)
8891 build-depends: unix == 2.7.*
8992
93+ if flag(split-these)
94+ build-depends:
95+ semialign >= 1 && < 1.1,
96+ these >= 1 && < 1.1
97+ else
98+ build-depends:
99+ these >= 0.4 && < 0.9
100+
90101 exposed-modules:
91102 Foreign.JavaScript.TH
92103 Foreign.JavaScript.Orphans
@@ -95,6 +106,7 @@ library
95106 Reflex.Dom.Builder.Class.Events
96107 Reflex.Dom.Builder.Immediate
97108 Reflex.Dom.Builder.InputDisabled
109+ Reflex.Dom.Builder.Hydratable
98110 Reflex.Dom.Builder.Static
99111 Reflex.Dom.Class
100112 Reflex.Dom.Core
@@ -189,6 +201,7 @@ test-suite hydration
189201 , warp
190202 , webdriver
191203 , websockets
204+ , which
192205 hs-source-dirs: test
193206 ghc-options: -rtsopts -with-rtsopts=-T -Wall -fwarn-tabs -funbox-strict-fields -O2 -ferror-spans
194207 ghc-prof-options: -fprof-auto -optP-DPROFILING
reflex-dom-core/src/Reflex/Dom/Builder/Hydratable.hsnew file+116
@@ -0,0 +1,116 @@
1+{-# LANGUAGE CPP #-}
2+{-# LANGUAGE FlexibleInstances #-}
3+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
4+{-# LANGUAGE MultiParamTypeClasses #-}
5+{-# LANGUAGE OverloadedStrings #-}
6+{-# LANGUAGE StandaloneDeriving #-}
7+{-# LANGUAGE TypeFamilies #-}
8+{-# LANGUAGE UndecidableInstances #-}
9+module Reflex.Dom.Builder.Hydratable where
10+
11+import Control.Monad.Fix
12+import Control.Monad.Primitive
13+import Control.Monad.Ref
14+import Control.Monad.Trans
15+import Control.Monad.Trans.Control
16+import Data.Coerce
17+import qualified Data.Map as Map
18+import Foreign.JavaScript.TH
19+#ifndef ghcjs_HOST_OS
20+import GHCJS.DOM.Types (MonadJSM (..))
21+#endif
22+import Reflex
23+import Reflex.Dom.Builder.Class
24+import Reflex.Dom.Builder.Immediate (HasDocument (..))
25+import Reflex.Host.Class
26+
27+-- | A DomBuilder transformer that adds "data-ssr" to all elements such that the
28+-- hydration builder knows which bits of DOM were added by us, and which were
29+-- added by external scripts.
30+newtype HydratableT m a = HydratableT { runHydratableT :: m a } deriving (Functor, Applicative, Monad, MonadAtomicRef, MonadFix, MonadIO)
31+
32+#ifndef ghcjs_HOST_OS
33+instance MonadJSM m => MonadJSM (HydratableT m) where
34+ liftJSM' = HydratableT . liftJSM'
35+#endif
36+
37+deriving instance MonadSample t m => MonadSample t (HydratableT m)
38+deriving instance MonadHold t m => MonadHold t (HydratableT m)
39+
40+instance MonadTrans HydratableT where
41+ lift = HydratableT
42+
43+instance MonadTransControl HydratableT where
44+ type StT HydratableT a = a
45+ liftWith f = HydratableT $ f runHydratableT
46+ restoreT = HydratableT
47+
48+instance MonadRef m => MonadRef (HydratableT m) where
49+ type Ref (HydratableT m) = Ref m
50+ newRef = lift . newRef
51+ readRef = lift . readRef
52+ writeRef ref = lift . writeRef ref
53+
54+instance PerformEvent t m => PerformEvent t (HydratableT m) where
55+ type Performable (HydratableT m) = Performable m
56+ performEvent_ = lift . performEvent_
57+ performEvent = lift . performEvent
58+
59+instance PrimMonad m => PrimMonad (HydratableT m) where
60+ type PrimState (HydratableT m) = PrimState m
61+ primitive = lift . primitive
62+
63+makeHydratable :: Reflex t => ElementConfig er t m -> ElementConfig er t m
64+makeHydratable cfg = cfg
65+ { _elementConfig_initialAttributes = Map.insert "data-ssr" "" $ _elementConfig_initialAttributes cfg
66+ , _elementConfig_modifyAttributes = fmap (Map.delete "data-ssr") <$> _elementConfig_modifyAttributes cfg
67+ }
68+
69+instance PostBuild t m => PostBuild t (HydratableT m) where
70+ getPostBuild = lift getPostBuild
71+
72+deriving instance TriggerEvent t m => TriggerEvent t (HydratableT m)
73+
74+instance MonadReflexCreateTrigger t m => MonadReflexCreateTrigger t (HydratableT m) where
75+ newEventWithTrigger = lift . newEventWithTrigger
76+ newFanEventWithTrigger f = lift $ newFanEventWithTrigger f
77+
78+instance Adjustable t m => Adjustable t (HydratableT m) where
79+ runWithReplace a0 a' = HydratableT $ runWithReplace (coerce a0) (coerceEvent a')
80+ traverseDMapWithKeyWithAdjust f dm0 dm' = HydratableT $ traverseDMapWithKeyWithAdjust (\k v -> runHydratableT $ f k v) (coerce dm0) (coerceEvent dm')
81+ traverseDMapWithKeyWithAdjustWithMove f dm0 dm' = HydratableT $ traverseDMapWithKeyWithAdjustWithMove (\k v -> runHydratableT $ f k v) (coerce dm0) (coerceEvent dm')
82+ traverseIntMapWithKeyWithAdjust f m0 m' = HydratableT $ traverseIntMapWithKeyWithAdjust (\k v -> runHydratableT $ f k v) (coerce m0) (coerceEvent m')
83+
84+instance NotReady t m => NotReady t (HydratableT m) where
85+ notReadyUntil = lift . notReadyUntil
86+ notReady = lift notReady
87+
88+instance DomBuilder t m => DomBuilder t (HydratableT m) where
89+ type DomBuilderSpace (HydratableT m) = DomBuilderSpace m
90+ element t cfg = lift . element t (makeHydratable cfg) . runHydratableT
91+ inputElement cfg = lift $ inputElement $ cfg
92+ { _inputElementConfig_elementConfig = makeHydratable $ _inputElementConfig_elementConfig cfg
93+ }
94+ textAreaElement cfg = lift $ textAreaElement $ cfg
95+ { _textAreaElementConfig_elementConfig = makeHydratable $ _textAreaElementConfig_elementConfig cfg
96+ }
97+ selectElement cfg child = do
98+ let cfg' = cfg
99+ { _selectElementConfig_elementConfig = makeHydratable $ _selectElementConfig_elementConfig cfg
100+ }
101+ lift $ selectElement cfg' $ runHydratableT child
102+
103+instance HasDocument m => HasDocument (HydratableT m)
104+
105+instance HasJSContext m => HasJSContext (HydratableT m) where
106+ type JSContextPhantom (HydratableT m) = JSContextPhantom m
107+ askJSContext = lift askJSContext
108+
109+instance HasJS js m => HasJS js (HydratableT m) where
110+ type JSX (HydratableT m) = JSX m
111+ liftJS = lift . liftJS
112+
113+instance DomRenderHook t m => DomRenderHook t (HydratableT m) where
114+ withRenderHook f = HydratableT . withRenderHook f . runHydratableT
115+ requestDomAction = HydratableT . requestDomAction
116+ requestDomAction_ = HydratableT . requestDomAction_
reflex-dom-core/src/Reflex/Dom/Builder/Immediate.hs+12−5
@@ -765,10 +765,17 @@ hydrateElement elementTag cfg child = do
765765 result <- HydrationDomBuilderT $ lift $ runReaderT (unHydrationDomBuilderT child) env'
766766 wrapResult <- liftIO newEmptyMVar
767767 let skipAttr = "data-hydration-skip" :: DOM.JSString
768− hasSkipAttribute :: DOM.Element -> HydrationRunnerT t m Bool
769− hasSkipAttribute e = case cfg ^. namespace of
770− Nothing -> hasAttribute e skipAttr
771− Just ns -> hasAttributeNS e (Just ns) skipAttr
768+ ssrAttr = "data-ssr" :: DOM.JSString
769+ shouldSkip :: DOM.Element -> HydrationRunnerT t m Bool
770+ shouldSkip e = case cfg ^. namespace of
771+ Nothing -> do
772+ skip <- hasAttribute e skipAttr
773+ ssr <- hasAttribute e ssrAttr
774+ pure $ skip || not ssr
775+ Just ns -> do
776+ skip <- hasAttributeNS e (Just ns) skipAttr
777+ ssr <- hasAttributeNS e (Just ns) ssrAttr
778+ pure $ skip || not ssr
772779 childDom <- liftIO $ readIORef childDelayedRef
773780 let rawCfg = extractRawElementConfig cfg
774781 doc <- askDocument
@@ -783,7 +790,7 @@ hydrateElement elementTag cfg child = do
783790 pure e
784791 Just node -> DOM.castTo DOM.Element node >>= \case
785792 Nothing -> go (Just node) -- this node is not an element, skip
786− Just e -> hasSkipAttribute e >>= \case
793+ Just e -> shouldSkip e >>= \case
787794 True -> go (Just node) -- this element is explicitly marked for being skipped by hydration
788795 False -> do
789796 t <- Element.getTagName e
reflex-dom-core/src/Reflex/Dom/Builder/InputDisabled.hs+6
@@ -80,6 +80,7 @@ instance Adjustable t m => Adjustable t (InputDisabledT m) where
8080 runWithReplace a0 a' = InputDisabledT $ runWithReplace (coerce a0) (coerceEvent a')
8181 traverseDMapWithKeyWithAdjust f dm0 dm' = InputDisabledT $ traverseDMapWithKeyWithAdjust (\k v -> runInputDisabledT $ f k v) (coerce dm0) (coerceEvent dm')
8282 traverseDMapWithKeyWithAdjustWithMove f dm0 dm' = InputDisabledT $ traverseDMapWithKeyWithAdjustWithMove (\k v -> runInputDisabledT $ f k v) (coerce dm0) (coerceEvent dm')
83+ traverseIntMapWithKeyWithAdjust f m0 m' = InputDisabledT $ traverseIntMapWithKeyWithAdjust (\k v -> runInputDisabledT $ f k v) (coerce m0) (coerceEvent m')
8384
8485instance NotReady t m => NotReady t (InputDisabledT m) where
8586 notReadyUntil = lift . notReadyUntil
@@ -108,3 +109,8 @@ instance HasJSContext m => HasJSContext (InputDisabledT m) where
108109instance HasJS js m => HasJS js (InputDisabledT m) where
109110 type JSX (InputDisabledT m) = JSX m
110111 liftJS = lift . liftJS
112+
113+instance DomRenderHook t m => DomRenderHook t (InputDisabledT m) where
114+ withRenderHook f = InputDisabledT . withRenderHook f . runInputDisabledT
115+ requestDomAction = InputDisabledT . requestDomAction
116+ requestDomAction_ = InputDisabledT . requestDomAction_
reflex-dom-core/src/Reflex/Dom/Core.hs+1
@@ -6,6 +6,7 @@ module Reflex.Dom.Core (module X) where
66
77import Reflex as X hiding (askEvents)
88import Reflex.Dom.Builder.Class as X
9+import Reflex.Dom.Builder.Hydratable as X
910import Reflex.Dom.Builder.Immediate as X
1011import Reflex.Dom.Builder.InputDisabled as X
1112import Reflex.Dom.Builder.Static as X
reflex-dom-core/src/Reflex/Dom/Prerender.hs+9−4
@@ -33,6 +33,7 @@ import Foreign.JavaScript.TH
3333import GHCJS.DOM.Types (MonadJSM)
3434import Reflex hiding (askEvents)
3535import Reflex.Dom.Builder.Class
36+import Reflex.Dom.Builder.Hydratable
3637import Reflex.Dom.Builder.Immediate
3738import Reflex.Dom.Builder.InputDisabled
3839import Reflex.Dom.Builder.Static
@@ -270,8 +271,8 @@ instance (Prerender js t m, MonadFix m, Reflex t) => Prerender js t (RequesterT
270271 (x, e) <- runRequesterT w (selectInt fannedResponses selector)
271272 pure (x, fmapCheap (IntMap.singleton selector) e)
272273 (result, requestsDyn) <- fmap splitDynPure $ lift $ prerender (withFannedResponses server 0) (withFannedResponses client 1)
273− responses <- fmap (fmapCheap unMultiEntry) $ requesting' $ fmapCheap multiEntry $ switch $ current requestsDyn
274− pure result
274+ responses <- fmap (fmapCheap unMultiEntry) $ requesting' $ fmapCheap multiEntry $ switchPromptlyDyn requestsDyn
275+ return result
275276
276277instance (Prerender js t m, Monad m, Reflex t, MonadFix m, Group q, Additive q, Query q, Eq q) => Prerender js t (QueryT t q m) where
277278 type Client (QueryT t q m) = QueryT t q (Client m)
@@ -283,8 +284,12 @@ instance (Prerender js t m, Monad m, Reflex t, MonadFix m, Group q, Additive q,
283284 pure a
284285
285286instance (Prerender js t m, Monad m) => Prerender js t (InputDisabledT m) where
286− type Client (InputDisabledT m) = Client m
287− prerender (InputDisabledT server) client = InputDisabledT $ prerender server client
287+ type Client (InputDisabledT m) = InputDisabledT (Client m)
288+ prerender (InputDisabledT server) (InputDisabledT client) = InputDisabledT $ prerender server client
289+
290+instance (Prerender js t m, Monad m) => Prerender js t (HydratableT m) where
291+ type Client (HydratableT m) = HydratableT (Client m)
292+ prerender (HydratableT server) (HydratableT client) = HydratableT $ prerender server client
288293
289294instance (Prerender js t m, Monad m, ReflexHost t) => Prerender js t (PostBuildT t m) where
290295 type Client (PostBuildT t m) = PostBuildT t (Client m)
reflex-dom-core/src/Reflex/Dom/Widget/Basic.hs+5−4
@@ -60,6 +60,7 @@ module Reflex.Dom.Widget.Basic
6060 , partitionMapBySetLT
6161 ) where
6262
63+import Reflex.Adjustable.Class
6364import Reflex.Class
6465import Reflex.Collection
6566import Reflex.Dom.Builder.Class
@@ -146,21 +147,21 @@ button t = do
146147-- | Given a Dynamic of widget-creating actions, create a widget that is recreated whenever the Dynamic updates.
147148-- The returned Event of widget results occurs when the Dynamic does.
148149-- Note: Often, the type @a@ is an 'Event', in which case the return value is an Event-of-Events that would typically be flattened (via 'switchHold').
149−dyn :: (DomBuilder t m, PostBuild t m) => Dynamic t (m a) -> m (Event t a)
150+dyn :: (Adjustable t m, NotReady t m, PostBuild t m) => Dynamic t (m a) -> m (Event t a)
150151dyn = networkView
151152
152153-- | Like 'dyn' but discards result.
153−dyn_ :: (DomBuilder t m, PostBuild t m) => Dynamic t (m a) -> m ()
154+dyn_ :: (Adjustable t m, NotReady t m, PostBuild t m) => Dynamic t (m a) -> m ()
154155dyn_ = void . dyn
155156
156157-- | Given an initial widget and an Event of widget-creating actions, create a widget that is recreated whenever the Event fires.
157158-- The returned Dynamic of widget results occurs when the Event does.
158159-- Note: Often, the type 'a' is an Event, in which case the return value is a Dynamic-of-Events that would typically be flattened (via 'switchDyn').
159−widgetHold :: (DomBuilder t m, MonadHold t m) => m a -> Event t (m a) -> m (Dynamic t a)
160+widgetHold :: (Adjustable t m, MonadHold t m) => m a -> Event t (m a) -> m (Dynamic t a)
160161widgetHold = networkHold
161162
162163-- | Like 'widgetHold' but discards result.
163−widgetHold_ :: (DomBuilder t m, MonadHold t m) => m a -> Event t (m a) -> m ()
164+widgetHold_ :: (Adjustable t m, MonadHold t m) => m a -> Event t (m a) -> m ()
164165widgetHold_ z = void . widgetHold z
165166
166167-- | Create a DOM element
reflex-dom-core/src/Reflex/Dom/Widget/Resize.hs+4
@@ -33,6 +33,10 @@ import qualified GHCJS.DOM.Types as DOM
3333
3434-- | A widget that wraps the given widget in a div and fires an event when resized.
3535-- Adapted from @github.com\/marcj\/css-element-queries@
36+--
37+-- This function can cause strange scrollbars to appear in some circumstances.
38+-- These can be hidden with pseudo selectors, for example, in webkit browsers:
39+-- .wrapper *::-webkit-scrollbar { width: 0px; background: transparent; }
3640resizeDetector :: (MonadJSM m, DomBuilder t m, PostBuild t m, TriggerEvent t m, PerformEvent t m, MonadHold t m, DomBuilderSpace m ~ GhcjsDomSpace, MonadJSM (Performable m), MonadFix m) => m a -> m (Event t (), a)
3741resizeDetector = resizeDetectorWithStyle ""
3842
reflex-dom-core/test/hlint.hs+1
@@ -16,6 +16,7 @@ main = do
1616 , "--ignore=Use unless"
1717 , "--ignore=Use if"
1818 , "--ignore=Use fewer imports"
19+ , "--ignore=Use list comprehension"
1920 , "--ignore=Unnecessary hiding" -- Interferes with cross-version compatibility
2021 , "--ignore=Use <$>"
2122 , "--ignore=Reduce duplication" --TODO: Re-enable this test
reflex-dom-core/test/hydration.hs+31−22
@@ -20,9 +20,11 @@
2020{-# LANGUAGE TypeApplications #-}
2121{-# LANGUAGE TypeFamilies #-}
2222
23+import Prelude hiding (fail)
2324import Control.Concurrent
24−import Control.Monad
25+import Control.Monad hiding (fail)
2526import Control.Monad.Catch
27+import Control.Monad.Fail
2628import Control.Monad.Fix
2729import Control.Monad.IO.Class
2830import Control.Monad.Ref
@@ -52,6 +54,7 @@ import System.IO (stderr)
5254import System.IO.Silently
5355import System.IO.Temp
5456import System.Process
57+import System.Which (staticWhich)
5558import qualified Test.HUnit as HUnit (assertEqual, assertFailure)
5659import qualified Test.Hspec as H
5760import qualified Test.Hspec.Core.Spec as H
@@ -59,6 +62,7 @@ import Test.Hspec (xit)
5962import Test.Hspec.WebDriver hiding (runWD, click, uploadFile, WD)
6063import qualified Test.Hspec.WebDriver as WD
6164import Test.WebDriver (WD(..))
65+import Test.WebDriver.Exceptions (ServerError(..))
6266
6367import qualified Data.ByteString.Lazy as LBS
6468import qualified Data.Dependent.Map as DMap
@@ -74,6 +78,9 @@ import qualified Test.WebDriver.Capabilities as WD
7478import Test.Util.ChromeFlags
7579import Test.Util.UnshareNetwork
7680
81+chromium :: FilePath
82+chromium = $(staticWhich "chromium")
83+
7784seleniumPort, jsaddlePort :: PortNumber
7885seleniumPort = 8000
7986jsaddlePort = 8001
@@ -117,13 +124,15 @@ deriveGEq ''DKey
117124deriveGCompare ''DKey
118125deriveGShow ''DKey
119126
127+deriving instance MonadFail WD
128+
120129main :: IO ()
121130main = do
122131 unshareNetork
123132 isHeadless <- (== Nothing) <$> lookupEnv "NO_HEADLESS"
124133 withSandboxedChromeFlags isHeadless $ \chromeFlags -> do
125134 withSeleniumServer $ \selenium -> do
126− browserPath <- liftIO $ T.strip . T.pack <$> readProcess "which" [ "chromium" ] ""
135+ let browserPath = T.strip $ T.pack chromium
127136 when (T.null browserPath) $ fail "No browser found"
128137 withDebugging <- isNothing <$> lookupEnv "NO_DEBUG"
129138 let wdConfig = WD.defaultConfig { WD.wdPort = fromIntegral $ _selenium_portNumber selenium }
@@ -737,9 +746,9 @@ tests withDebugging wdConfig caps _selenium = do
737746 pb <- getPostBuild
738747 performEvent_ $ liftIO (putMVar lock ()) <$ pb
739748 it "result Dynamic is updated *after* switchover" $ runWD $ do
740− let static = checkBodyText "PostBuild"
749+ let preSwitchover = checkBodyText "PostBuild"
741750 check = checkBodyText "Client"
742− testWidget static check $ void $ do
751+ testWidget preSwitchover check $ void $ do
743752 d <- prerender (pure "Initial") (pure "Client")
744753 pb <- getPostBuild
745754 initial <- sample $ current d
@@ -747,16 +756,16 @@ tests withDebugging wdConfig caps _selenium = do
747756 -- This essentially checks that the client IO runs *after* switchover/postBuild,
748757 -- thus can't create conflicting DOM
749758 it "can't exploit IO to break hydration" $ runWD $ do
750− let static = checkBodyText "Initial"
751− testWidgetStatic static $ void $ do
759+ let preSwitchover = checkBodyText "Initial"
760+ testWidgetStatic preSwitchover $ void $ do
752761 ref <- liftIO $ newRef "Initial"
753762 prerender_ (pure ()) (liftIO $ writeRef ref "Client")
754763 text <=< liftIO $ readRef ref
755764 -- As above, so below
756765 it "can't exploit triggerEvent to break hydration" $ runWD $ do
757− let static = checkBodyText "Initial"
766+ let preSwitchover = checkBodyText "Initial"
758767 check = checkBodyText "Client"
759− testWidget static check $ void $ do
768+ testWidget preSwitchover check $ void $ do
760769 (e, trigger) <- newTriggerEvent
761770 prerender_ (pure ()) (liftIO $ trigger "Client")
762771 textNode $ TextNodeConfig "Initial" $ Just e
@@ -945,26 +954,26 @@ tests withDebugging wdConfig caps _selenium = do
945954 postBuildPatch = PatchDMap $ DMap.fromList [Key_Char :=> ComposeMaybe Nothing, Key_Bool :=> ComposeMaybe (Just $ Identity True)]
946955 it "doesn't replace elements at switchover, can delete/update/insert" $ runWD $ do
947956 chan <- liftIO newChan
948− let static :: WD [WD.Element]
949− static = getAndCheckInitialItems keyMap
957+ let preSwitchover :: WD [WD.Element]
958+ preSwitchover = getAndCheckInitialItems keyMap
950959 check :: [WD.Element] -> WD ()
951960 check xs = do
952961 checkInitialItems keyMap xs
953962 checkRemoval chan Key_Int
954963 checkReplace chan Key_Char 'B'
955964 checkInsert chan Key_Bool True
956− testWidget' static check $ do
965+ testWidget' preSwitchover check $ do
957966 (dmap, _evt) <- traverseDMapWithKeyWithAdjust widget keyMap =<< triggerEventWithChan chan
958967 liftIO $ dmap `H.shouldBe` keyMap
959968 it "handles postBuild correctly" $ runWD $ do
960969 chan <- liftIO newChan
961− let static = getAndCheckInitialItems $ applyAlways postBuildPatch keyMap
970+ let preSwitchover = getAndCheckInitialItems $ applyAlways postBuildPatch keyMap
962971 check xs = do
963972 withRetry $ checkInitialItems (applyAlways postBuildPatch keyMap) xs
964973 checkRemoval chan Key_Int
965974 checkInsert chan Key_Char 'B'
966975 checkReplace chan Key_Bool True
967− testWidget' static check $ void $ do
976+ testWidget' preSwitchover check $ void $ do
968977 pb <- getPostBuild
969978 replace <- triggerEventWithChan chan
970979 (dmap, _evt) <- traverseDMapWithKeyWithAdjust widget keyMap $ leftmost [postBuildPatch <$ pb, replace]
@@ -1054,24 +1063,24 @@ tests withDebugging wdConfig caps _selenium = do
10541063 postBuildPatch = PatchIntMap $ IntMap.fromList [(2, Nothing), (3, Just "trois"), (4, Just "four")]
10551064 xit "doesn't replace elements at switchover, can delete/update/insert" $ runWD $ do
10561065 chan <- liftIO newChan
1057− let static = getAndCheckInitialItems intMap
1066+ let preSwitchover = getAndCheckInitialItems intMap
10581067 check xs = do
10591068 checkInitialItems intMap xs
10601069 checkRemoval chan 1
10611070 checkReplace chan 2 "deux"
10621071 checkInsert chan 4 "four"
1063− testWidget' static check $ void $ do
1072+ testWidget' preSwitchover check $ void $ do
10641073 (im, _evt) <- traverseIntMapWithKeyWithAdjust widget intMap =<< triggerEventWithChan chan
10651074 liftIO $ im `H.shouldBe` intMap
10661075 xit "handles postBuild correctly" $ runWD $ do
10671076 chan <- liftIO newChan
1068− let static = getAndCheckInitialItems $ applyAlways postBuildPatch intMap
1077+ let preSwitchover = getAndCheckInitialItems $ applyAlways postBuildPatch intMap
10691078 check xs = do
10701079 withRetry $ checkInitialItems (applyAlways postBuildPatch intMap) xs
10711080 checkRemoval chan 1
10721081 checkInsert chan 2 "deux"
10731082 checkReplace chan 3 "trois"
1074− testWidget' static check $ void $ do
1083+ testWidget' preSwitchover check $ void $ do
10751084 pb <- getPostBuild
10761085 replace <- triggerEventWithChan chan
10771086 (dmap, _evt) <- traverseIntMapWithKeyWithAdjust widget intMap $ leftmost [postBuildPatch <$ pb, replace]
@@ -1166,12 +1175,12 @@ tests withDebugging wdConfig caps _selenium = do
11661175
11671176 describe "hydration" $ moveSpec $ \initMap test -> do
11681177 chan <- liftIO newChan
1169− let static = getAndCheckInitialItems initMap
1178+ let preSwitchover = getAndCheckInitialItems initMap
11701179 check xs = do
11711180 checkInitialItems initMap xs
11721181 body <- getBody
11731182 test body chan
1174− testWidget' static check $ void $ do
1183+ testWidget' preSwitchover check $ void $ do
11751184 (dmap, _evt) <- traverseDMapWithKeyWithAdjustWithMove widget initMap =<< triggerEventWithChan chan
11761185 liftIO $ assertEqual "DMap" initMap dmap
11771186
@@ -1197,7 +1206,7 @@ tests withDebugging wdConfig caps _selenium = do
11971206
11981207 describe "hydrating invalid HTML" $ session' $ do
11991208 it "can hydrate list in paragraph" $ runWD $ do
1200− let static = do
1209+ let preSwitchover = do
12011210 checkBodyText "before\ninner\nafter"
12021211 -- Two <p> tags should be present
12031212 (p1, p2) <- WD.findElems (WD.ByTag "p") >>= \case
@@ -1213,7 +1222,7 @@ tests withDebugging wdConfig caps _selenium = do
12131222 shouldContainText "before\ninner\nafter" p1
12141223 elementShouldBeRemoved ol
12151224 elementShouldBeRemoved p2
1216− testWidget' static check $ do
1225+ testWidget' preSwitchover check $ do
12171226 -- This is deliberately invalid HTML, the browser will interpret it as
12181227 -- <p>before</p><ol>inner</ol>after<p></p>
12191228 el "p" $ do
@@ -1347,7 +1356,7 @@ testWidgetDebug' withDebugging beforeJS afterSwitchover bodyWidget = do
13471356 bodyWidget
13481357 el "script" $ text $ TE.decodeUtf8 $ LBS.toStrict $ jsaddleJs False
13491358 putStrLnDebug "rendering static"
1350− ((), html) <- liftIO $ renderStatic staticApp
1359+ ((), html) <- liftIO $ renderStatic $ runHydratableT staticApp
13511360 putStrLnDebug "rendered static"
13521361 waitBeforeJS <- liftIO newEmptyMVar -- Empty until JS should be run
13531362 waitUntilSwitchover <- liftIO newEmptyMVar -- Empty until switchover
reflex-dom/default.nixdeleted−38
@@ -1,38 +0,0 @@
1−{ mkDerivation, base, bytestring, jsaddle-webkit2gtk, jsaddle-wkwebview, jsaddle-warp, reflex
2−, reflex-dom-core, stdenv, text, ghc, hostPlatform, jsaddle-clib, android-activity ? null
3−, ghcBackend ? if hostPlatform.isDarwin then "wkwebview" else "webkit2gtk"
4−}:
5−assert (builtins.elem ghcBackend [ "warp" "webkit2gtk" "wkwebview" ]);
6−let isAndroid = hostPlatform.libc == "bionic";
7− ghcBackendPackage = {
8− webkit2gtk = jsaddle-webkit2gtk;
9− warp = jsaddle-warp;
10− wkwebview = jsaddle-wkwebview;
11− }.${ghcBackend};
12−in mkDerivation {
13− pname = "reflex-dom";
14− version = "0.5.2";
15− src = builtins.filterSource (path: type: !(builtins.elem (baseNameOf path) [ ".git" "dist" ])) ./.;
16− libraryHaskellDepends = [
17− base bytestring reflex reflex-dom-core text
18− ] ++ (if ghc.isGhcjs or false then [
19− ] else if hostPlatform.isiOS then [
20− jsaddle-wkwebview
21− ] else if isAndroid then [
22− jsaddle-clib
23− android-activity
24− ] else if hostPlatform.isMacOS then [
25− jsaddle-wkwebview
26− ghcBackendPackage
27− ] else [
28− ghcBackendPackage
29− ]);
30− configureFlags = if isAndroid then [
31− "-fandroid"
32− ] else if ghcBackend == "warp" then [
33− "-fuse-warp"
34− ] else [
35− ];
36− description = "Functional Reactive Web Apps with Reflex";
37− license = stdenv.lib.licenses.bsd3;
38−}
reflex-dom/reflex-dom.cabal+3−8
@@ -1,5 +1,5 @@
11Name: reflex-dom
2−Version: 0.5.2
2+Version: 0.5.2.0
33Synopsis: Functional Reactive Web Apps with Reflex
44Description:
55 Reflex-DOM is a Functional Reactive web framework based on the Reflex FRP engine.
@@ -41,14 +41,9 @@ flag build-examples
4141 default: False
4242 manual: True
4343
44−flag android
45− description: Build an Android app
46− default: False
47− manual: True
48−
4944library
5045 hs-source-dirs: src
51− if flag(android)
46+ if os(android)
5247 hs-source-dirs: src-android
5348 other-modules: Reflex.Dom.Android.MainWidget
5449 build-depends:
@@ -83,7 +78,7 @@ library
8378 build-depends:
8479 jsaddle-webkit2gtk
8580 else
86− if !flag(android)
81+ if !os(android)
8782 build-depends:
8883 jsaddle-webkit2gtk
8984
reflex-platform.nixdeleted−8
@@ -1,8 +0,0 @@
1−let
2− reflex-platform-src = (import <nixpkgs> {}).fetchFromGitHub {
3− owner = "reflex-frp";
4− repo = "reflex-platform";
5− rev = "384cd850f3adf1d404bced2424b5f6efb0f415f2";
6− sha256 = "1ws77prqx8khmp8j6br1ij4k2v4dlgv170r9fmg0p1jivfbn8y9d";
7− };
8−in import reflex-platform-src
release.nix+32−9
@@ -1,12 +1,35 @@
1−{ rp ? import ./reflex-platform.nix {}
1+{ reflex-platform-fun ? import ./dep/reflex-platform
22}:
3+
34let
4− inherit (rp.nixpkgs) lib;
5+ native-reflex-platform = reflex-platform-fun {};
6+ inherit (native-reflex-platform.nixpkgs) lib;
57 systems = ["x86_64-linux" "x86_64-darwin"];
6− compilers = ["ghc8_4" "ghc8_0" "ghcjs8_4" "ghcjs8_0"];
7−in lib.genAttrs systems (system:
8− lib.genAttrs compilers (ghc: let
9− reflex-platform = import ./reflex-platform.nix { inherit system; };
10− hsPkgs = reflex-platform.${ghc};
11− in { inherit (import ./. hsPkgs reflex-platform.nixpkgs) reflex-dom reflex-dom-core; })
12−)
8+
9+ perPlatform = lib.genAttrs systems (system: let
10+ reflex-platform = reflex-platform-fun { inherit system; };
11+ compilers = [
12+ "ghc"
13+ "ghcjs"
14+ ] ++ lib.optionals (reflex-platform.androidSupport) [
15+ "ghcAndroidAarch64"
16+ "ghcAndroidAarch32"
17+ ] ++ lib.optionals (reflex-platform.iosSupport) [
18+ "ghcIosAarch64"
19+ ];
20+ hsPkgs = lib.genAttrs compilers (ghc: let
21+ ghc' = reflex-platform.${ghc}.override {
22+ overrides = self: super: import ./. self;
23+ };
24+ in {
25+ inherit (ghc') reflex-dom reflex-dom-core;
26+ });
27+ in hsPkgs // {
28+ cache = reflex-platform.pinBuildInputs "reflex-dom-${system}"
29+ (lib.concatLists (map builtins.attrValues (builtins.attrValues hsPkgs)));
30+ });
31+
32+ metaCache = native-reflex-platform.pinBuildInputs "reflex-dom-everywhere"
33+ (map (a: a.cache) (builtins.attrValues perPlatform));
34+
35+in perPlatform // { inherit metaCache; }