@@ -0,0 +1,82 @@
1+{-# LANGUAGE ConstraintKinds #-}
2+{-# LANGUAGE EmptyDataDecls #-}
3+{-# LANGUAGE FlexibleContexts #-}
4+{-# LANGUAGE FlexibleInstances #-}
5+{-# LANGUAGE FunctionalDependencies #-}
6+{-# LANGUAGE MultiParamTypeClasses #-}
7+{-# LANGUAGE Rank2Types #-}
8+{-# LANGUAGE ScopedTypeVariables #-}
9+{-# LANGUAGE TypeFamilies #-}
10+{-# LANGUAGE TypeSynonymInstances #-}
11+{-# LANGUAGE UndecidableInstances #-}
12+module Reflex.Dom.Prerender
13+ ( Prerender (..)
14+ , prerender
15+ ) where
16+
17+import Control.Monad.Reader
18+import Data.Constraint
19+import Foreign.JavaScript.TH
20+import GHCJS.DOM.Types (MonadJSM)
21+import Reflex
22+import Reflex.Dom.Builder.InputDisabled
23+import Reflex.Dom.Builder.Immediate
24+import Reflex.Dom.Builder.Static
25+import Reflex.Host.Class
26+
27+type PrerenderClientConstraint js m =
28+ ( HasJS js m
29+ , HasJS js (Performable m)
30+ , MonadJSM m
31+ , MonadJSM (Performable m)
32+ , HasJSContext m
33+ , HasJSContext (Performable m)
34+ , MonadFix m
35+ , MonadFix (Performable m)
36+ )
37+
38+class Prerender js m | m -> js where
39+ prerenderClientDict :: Maybe (Dict (PrerenderClientConstraint js m))
40+
41+-- | Draw one widget when prerendering (e.g. server-side) and another when the
42+-- widget is fully instantiated. In a given execution of this function, there
43+-- will be exactly one invocation of exactly one of the arguments.
44+prerender :: forall js m a. Prerender js m => m a -> (PrerenderClientConstraint js m => m a) -> m a
45+prerender server client = case prerenderClientDict :: Maybe (Dict (PrerenderClientConstraint js m)) of
46+ Nothing -> server
47+ Just Dict -> client
48+
49+instance ( HasJS js m
50+ , HasJS js (Performable m)
51+ , HasJSContext m
52+ , HasJSContext (Performable m)
53+ , MonadJSM m
54+ , MonadJSM (Performable m)
55+ , MonadFix m
56+ , MonadFix (Performable m)
57+ , ReflexHost t
58+ ) => Prerender js (ImmediateDomBuilderT t m) where
59+ prerenderClientDict = Just Dict
60+
61+data NoJavaScript -- This type should never have a HasJS instance
62+
63+instance js ~ NoJavaScript => Prerender js (StaticDomBuilderT t m) where
64+ prerenderClientDict = Nothing
65+
66+instance (Prerender js m, ReflexHost t) => Prerender js (PostBuildT t m) where
67+ prerenderClientDict = fmap (\Dict -> Dict) (prerenderClientDict :: Maybe (Dict (PrerenderClientConstraint js m)))
68+
69+instance Prerender js m => Prerender js (DynamicWriterT t w m) where
70+ prerenderClientDict = fmap (\Dict -> Dict) (prerenderClientDict :: Maybe (Dict (PrerenderClientConstraint js m)))
71+
72+instance Prerender js m => Prerender js (ReaderT w m) where
73+ prerenderClientDict = fmap (\Dict -> Dict) (prerenderClientDict :: Maybe (Dict (PrerenderClientConstraint js m)))
74+
75+instance Prerender js m => Prerender js (RequesterT t request response m) where
76+ prerenderClientDict = fmap (\Dict -> Dict) (prerenderClientDict :: Maybe (Dict (PrerenderClientConstraint js m)))
77+
78+instance Prerender js m => Prerender js (QueryT t q m) where
79+ prerenderClientDict = fmap (\Dict -> Dict) (prerenderClientDict :: Maybe (Dict (PrerenderClientConstraint js m)))
80+
81+instance Prerender js m => Prerender js (InputDisabledT m) where
82+ prerenderClientDict = fmap (\Dict -> Dict) (prerenderClientDict :: Maybe (Dict (PrerenderClientConstraint js m)))