@@ -33,51 +33,53 @@ module Router
3333 , routeLink
3434 , routePkgIdxTs
3535 , runRouteViewT
36+ , FragRoute (.. ), decodeFrag
3637 ) where
3738
3839import Prelude hiding ((.) , id )
3940import Control.Category (Category (.. ), (.) )
4041import Control.Lens hiding (Bifunctor , bimap , universe , element )
41- import Control.Monad ((<=<) )
4242import Control.Monad.Fix
4343import Control.Monad.Primitive
4444import Control.Monad.Reader
4545import Control.Monad.Ref
46- import Control.Monad.Trans.Control
46+ import qualified Data.Char as C
4747import Data.Coerce
48- import qualified Data.List.NonEmpty as NE
49- import Data.List.NonEmpty (NonEmpty )
5048import qualified Data.Map.Strict as Map
5149import Data.Monoid
5250import Data.Proxy
5351import qualified Data.Set as Set
5452import Data.Set (Set )
5553import Data.Text (Text )
5654import qualified Data.Text as T
57- import Data.Functor.Compose
5855import Reflex.Class
5956import Reflex.Host.Class
6057import Reflex.PostBuild.Class
6158import Reflex.TriggerEvent.Class
6259import Reflex.PerformEvent.Class
6360import Reflex.EventWriter.Class
6461import Reflex.EventWriter.Base
65- import Reflex.Dynamic
6662import Reflex.Dom.Builder.Class
67- import Data.Type.Coercion
6863import Language.Javascript.JSaddle
6964import Reflex.Dom.Core
7065import qualified GHCJS.DOM.Types as DOM
7166import Network.URI
72- import Data.Maybe (Maybe (.. ), fromMaybe , isJust )
73- import qualified Data.List as L
67+ import Data.Maybe (Maybe (.. ), fromMaybe )
7468
7569import PkgId
7670
77- newtype SetRouteT t r m a = SetRouteT { unSetRouteT :: EventWriterT t r m a }
71+ data FragRoute = RouteHome
72+ | RouteQueue
73+ | RoutePackages
74+ | RoutePackage (PkgN , Maybe PkgIdxTs )
75+ | RouteUser UserName
76+ | RouteUnknown T. Text
77+ deriving (Eq , Ord )
78+
79+ newtype SetRouteT t r m a = SetRouteT { unSetRouteT :: EventWriterT t (Endo r ) m a }
7880 deriving (Functor , Applicative , Monad , MonadFix , MonadTrans , MonadIO , NotReady t, MonadHold t, MonadSample t, PostBuild t, TriggerEvent t, MonadReflexCreateTrigger t, HasDocument , DomRenderHook t)
7981
80- instance (Semigroup r , MonadFix m , MonadHold t m , DomBuilder t m ) => DomBuilder t (SetRouteT t r m ) where
82+ instance (MonadFix m , MonadHold t m , DomBuilder t m ) => DomBuilder t (SetRouteT t r m ) where
8183 type DomBuilderSpace (SetRouteT t r m ) = DomBuilderSpace m
8284 element t cfg child = SetRouteT $ element t cfg $ unSetRouteT child
8385 inputElement = lift . inputElement
@@ -91,15 +93,15 @@ instance HasJSContext m => HasJSContext (SetRouteT t r m) where
9193mapSetRouteT :: (forall x . m x -> n x ) -> SetRouteT t r m a -> SetRouteT t r n a
9294mapSetRouteT f (SetRouteT x) = SetRouteT (mapEventWriterT f x)
9395
94- runSetRouteT :: (Semigroup r , Reflex t , Monad m ) => SetRouteT t r m a -> m (a , Event t r )
96+ runSetRouteT :: (Reflex t , Monad m ) => SetRouteT t r m a -> m (a , Event t ( Endo r ) )
9597runSetRouteT = runEventWriterT . unSetRouteT
9698
9799class Reflex t => SetRoute t r m | m -> t r where
98- setRoute :: Event t r -> m ()
100+ setRoute :: Event t ( r -> r ) -> m ()
99101 setRoute = setRoute
100102
101- instance (Semigroup r , Reflex t , Monad m ) => SetRoute t r (SetRouteT t r m ) where
102- setRoute = SetRouteT . tellEvent
103+ instance (Reflex t , Monad m ) => SetRoute t r (SetRouteT t r m ) where
104+ setRoute = SetRouteT . tellEvent . fmap Endo
103105
104106instance (Monad m , SetRoute t r m ) => SetRoute t r (QueryT t q m )
105107
@@ -140,7 +142,7 @@ instance PrimMonad m => PrimMonad (SetRouteT t r m ) where
140142 type PrimState (SetRouteT t r m ) = PrimState m
141143 primitive = lift . primitive
142144
143- instance (Semigroup r , MonadHold t m , Adjustable t m ) => Adjustable t (SetRouteT t r m ) where
145+ instance (MonadHold t m , Adjustable t m ) => Adjustable t (SetRouteT t r m ) where
144146 runWithReplace a0 a' = SetRouteT $ runWithReplace (coerce a0) $ coerceEvent a'
145147 traverseIntMapWithKeyWithAdjust f a0 a' = SetRouteT $ traverseIntMapWithKeyWithAdjust (coerce f) (coerce a0) $ coerce a'
146148 traverseDMapWithKeyWithAdjust f a0 a' = SetRouteT $ traverseDMapWithKeyWithAdjust (\ k v -> coerce $ f k v) (coerce a0) $ coerce a'
@@ -151,23 +153,7 @@ instance (Monad m, MonadQuery t vs m) => MonadQuery t vs (SetRouteT t r m) where
151153 askQueryResult = lift askQueryResult
152154 queryIncremental = lift . queryIncremental
153155
154- switchPkgRoute :: Set PkgIdxTs -> URI -> PkgIdxTs -> Maybe URI
155- switchPkgRoute setPkgIdx oldRoute (PkgIdxTs 0 ) = Nothing
156- switchPkgRoute setPkgIdx oldRoute idxChange =
157- let routeS = (T. pack . uriFragment) oldRoute
158- rootURI = " #/package/"
159- in case T. stripPrefix rootURI routeS of
160- Just sfx | (Just pkgN, Just pkgIdx) <- pkgNFromText sfx
161- , True <- idxChange /= pkgIdx
162- , True <- not (Set. null setPkgIdx)
163- , Just setMax <- Set. lookupMax setPkgIdx
164- -> if setMax == idxChange
165- then Nothing
166- else parseURI . T. unpack $ rootURI <> (pkgNToText pkgN) <> (T. pack " @" ) <> (idxTsToText idxChange)
167- | otherwise -> Nothing
168- Nothing -> Nothing
169-
170- routeLink :: forall t m a route . ( DomBuilder t m , SetRoute t (NonEmpty FragRoute ) m )
156+ routeLink :: forall t m a . ( DomBuilder t m , SetRoute t FragRoute m )
171157 => Bool -- PreventDefault?
172158 -> Text -- Target route
173159 -> m a -- Child widget
@@ -177,16 +163,16 @@ routeLink True r w = do
177163 & elementConfig_eventSpec %~ addEventSpecFlags (Proxy :: Proxy (DomBuilderSpace m )) Click (\ _ -> preventDefault)
178164 & elementConfig_initialAttributes .~ " href" =: r
179165 (e, a) <- element " a" cfg w
180- setRoute $ ((( decodeFrag r) NE. :| [] ) <$ domEvent Click e)
166+ setRoute $ (switchPkgRoute ( Just $ decodeFrag r)) <$ domEvent Click e
181167 return a
182168routeLink False r w = do
183169 let cfg = (def :: ElementConfig EventResult t (DomBuilderSpace m ))
184170 & elementConfig_initialAttributes .~ " href" =: r
185171 (e, a) <- element " a" cfg w
186- setRoute $ ((( decodeFrag r) NE. :| [] ) <$ domEvent Click e)
172+ setRoute $ (switchPkgRoute ( Just $ decodeFrag r)) <$ domEvent Click e
187173 return a
188174
189- routePkgIdxTs :: forall t m . ( PostBuild t m , MonadHold t m , MonadFix m , DomBuilder t m , SetRoute t ( NonEmpty FragRoute ) m )
175+ routePkgIdxTs :: forall t m . (PostBuild t m , MonadHold t m , MonadFix m , DomBuilder t m , SetRoute t FragRoute m )
190176 => PkgN
191177 -> PkgIdxTs
192178 -> Behavior t (Set PkgIdxTs )
@@ -196,50 +182,48 @@ routePkgIdxTs :: forall t m. ( PostBuild t m, MonadHold t m, MonadFix m, DomBuil
196182routePkgIdxTs pn k0 setIdx opt ddConf = do
197183 dd <- dropdown k0 opt ddConf
198184 let evDD = attach setIdx (updated $ dd ^. dropdown_value)
199- setRoute $ (( \ val -> ( createRoutePackage pn val) NE. :| [] ) <$> evDD)
185+ setRoute $ (switchPkgRoute . ( \ tup -> createRoutePackage pn tup) ) <$> evDD
200186 pure dd
201187
202- createRoutePackage :: PkgN -> (Set PkgIdxTs , PkgIdxTs ) -> FragRoute
203- createRoutePackage pn (_, PkgIdxTs 0 ) = RoutePackage (pn, Nothing )
188+ createRoutePackage :: PkgN -> (Set PkgIdxTs , PkgIdxTs ) -> Maybe FragRoute
189+ createRoutePackage pn (_, PkgIdxTs 0 ) = Just $ RoutePackage (pn, Nothing )
204190createRoutePackage pn (setIdx, pkgIdx)
205191 | Just maxIdx <- Set. lookupMax setIdx
206192 , True <- maxIdx /= pkgIdx
207- = RoutePackage (pn, Just pkgIdx)
208- | otherwise = RoutePackage (pn, Nothing )
193+ = Just $ RoutePackage (pn, Just pkgIdx)
194+ | otherwise = Just $ RoutePackage (pn, Nothing )
209195
210196runRouteViewT :: forall t m a . (TriggerEvent t m , PerformEvent t m , MonadHold t m , MonadJSM m , MonadJSM (Performable m ), MonadFix m )
211- => (Dynamic t FragRoute -> SetRouteT t ( NonEmpty FragRoute ) m a )
197+ => (Dynamic t FragRoute -> SetRouteT t FragRoute m a )
212198 -> m a
213199runRouteViewT app = mdo
214200 historyState <- manageHistory $ HistoryCommand_PushState <$> setState
215- dynLoc <- browserHistoryWith getLocationUri
216- (result, changeStateE) <- runSetRouteT $ app route -- changeStateE :: Event t (NonEmpty Fragroute)
201+ -- dynLoc <- browserHistoryWith getLocationUri
202+ (result, changeStateE) <- runSetRouteT $ app route -- changeStateE :: Event t (Endo ( Fragroute -> FragRoute )
217203 let
204+ dynLoc = _historyItem_uri <$> historyState
205+
218206 route :: Dynamic t FragRoute
219207 route = decodeFrag . T. pack . uriFragment <$> dynLoc
220208
221- f (currentHistoryState, oldR) chStateE = -- chState :: NonEmpty Fragroute
222- let newRoute = switchPkgRoute' oldR chStateE
223- oldRoute = case encodeFrag oldR of
224- (Just a) -> a
225- Nothing -> T. empty
226- in
227- HistoryStateUpdate
228- { _historyStateUpdate_state = DOM. SerializedScriptValue jsNull
229- , _historyStateUpdate_title = " "
230- , _historyStateUpdate_uri = applyEncoding oldRoute newRoute (_historyItem_uri currentHistoryState)
231- }
232- setState = attachWith f ( (,) <$> current historyState <*> current route) changeStateE
209+ f (currentHistoryState, oldR) chStateE = -- chState :: Endo (FragRoute -> FragRoute)
210+ let newRoute = encodeFrag $ appEndo chStateE oldR
211+ -- oldRoute = case encodeFrag oldR of
212+ -- (Just a) -> a
213+ -- Nothing -> T.empty
214+ in do
215+ oldRoute <- encodeFrag oldR
216+ newUri <- applyEncoding oldRoute newRoute (_historyItem_uri currentHistoryState)
217+ pure $ HistoryStateUpdate
218+ { _historyStateUpdate_state = DOM. SerializedScriptValue jsNull
219+ , _historyStateUpdate_title = " "
220+ , _historyStateUpdate_uri = Just newUri
221+ }
222+ setState = fmapMaybe id $ attachWith f ( (,) <$> current historyState <*> current route) changeStateE
233223 pure result
234224
235- switchPkgRoute' :: FragRoute -> NonEmpty FragRoute -> Text
236- switchPkgRoute' oldFrag nEFrag
237- | (fragR, _) <- NE. uncons nEFrag
238- , Just fResult <- encodeFrag fragR
239- = fResult
240- | Just oldResult <- encodeFrag oldFrag
241- = oldResult
242- | otherwise = T. empty
225+ switchPkgRoute :: Maybe FragRoute -> FragRoute -> FragRoute
226+ switchPkgRoute newFrag oldFrag = fromMaybe oldFrag newFrag
243227
244228encodeFrag :: FragRoute -> Maybe Text
245229encodeFrag RouteHome = Just " #/"
@@ -252,7 +236,28 @@ encodeFrag (RoutePackage (pkg, maybeIndex))
252236encodeFrag (RouteUser usr) = Just $ " #/user/" <> usr
253237encodeFrag (RouteUnknown _) = Nothing
254238
255- applyEncoding :: Text -> Text -> URI -> Maybe URI
256- applyEncoding oldR newR u
239+ applyEncoding :: Text -> Maybe Text -> URI -> Maybe URI
240+ applyEncoding _ Nothing _ = Nothing
241+ applyEncoding oldR (Just newR) u
257242 | oldR /= newR = Just $ u { uriFragment = T. unpack newR }
258- | otherwise = Nothing
243+ | otherwise = Nothing
244+
245+ decodeFrag :: T. Text -> FragRoute
246+ decodeFrag frag = case frag of
247+ " " -> RouteHome
248+ " #" -> RouteHome
249+ " #/" -> RouteHome
250+ " #/queue" -> RouteQueue
251+ " #/packages" -> RoutePackages
252+
253+ _ | Just sfx <- T. stripPrefix " #/package/" frag
254+ , not (T. null frag)
255+ , (Just pn, idx) <- pkgNFromText sfx
256+ -> RoutePackage (pn , idx)
257+
258+ | Just sfx <- T. stripPrefix " #/user/" frag
259+ , not (T. null frag)
260+ , T. all (\ c -> C. isAsciiLower c || C. isAsciiUpper c || C. isDigit c || c == ' _' ) sfx
261+ -> RouteUser sfx
262+
263+ | otherwise -> RouteUnknown frag
0 commit comments