{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ViewPatterns #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
module Servant.Common.BaseUrl (
BaseUrl (..)
, Scheme (..)
, baseUrlWidget
, showBaseUrl
, SupportsServantReflex
) where
import Control.Monad (join)
import Control.Monad.Fix (MonadFix)
import Data.Monoid ((<>))
import Data.Text (Text)
import qualified Data.Text as T
import GHC.Generics
import Language.Javascript.JSaddle.Monad (MonadJSM)
import Reflex
import Reflex.Dom.Core
import Text.Read
type SupportsServantReflex t m = (Reflex t, TriggerEvent t m, PerformEvent t m, HasWebView (Performable m), MonadJSM (Performable m))
data Scheme =
Http
| Https
deriving (Show, Read, Eq, Ord, Generic)
data BaseUrl = BaseFullUrl Scheme Text Int Text
| BasePath Text
deriving (Ord, Read, Show, Generic)
instance Eq BaseUrl where
BasePath s == BasePath s' = s == s'
BaseFullUrl a b c path == BaseFullUrl a' b' c' path'
= a == a' && b == b' && c == c' && s path == s path'
where s x = if T.isPrefixOf "/" x then T.tail x else x
_ == _ = False
showBaseUrl :: BaseUrl -> Text
showBaseUrl (BasePath s) = s
showBaseUrl (BaseFullUrl urlscheme host port path) =
schemeString <> "//" <> host <> (portString </> path)
where
a </> b = if "/" `T.isPrefixOf` b || T.null b then a <> b else a <> "/" <> b
schemeString = case urlscheme of
Http -> "http:"
Https -> "https:"
portString = case (urlscheme, port) of
(Http, 80) -> ""
(Https, 443) -> ""
_ -> ":" <> T.pack (show port)
baseUrlWidget :: forall t m .(SupportsServantReflex t m,
DomBuilderSpace m ~ GhcjsDomSpace,
MonadFix m,
PostBuild t m,
MonadHold t m,
DomBuilder t m)
=> m (Dynamic t BaseUrl)
baseUrlWidget = elClass "div" "base-url" $ do
urlWidget <- dropdown (0 :: Int) (constDyn $ 0 =: "BasePath" <> 1 =: "BaseUrlFull") def
let bUrlWidget = ffor (value urlWidget) $ \i -> case i of
0 -> pathWidget
1 -> fullUrlWidget
_ -> error "Surprising value"
join <$> widgetHold pathWidget (updated bUrlWidget)
where pathWidget :: m (Dynamic t BaseUrl)
pathWidget = do
text "Url base path"
t <- textInput (def {_textInputConfig_attributes =
constDyn ("placeholder" =: "/a/b")})
return $ BasePath <$> value t
fullUrlWidget :: m (Dynamic t BaseUrl)
fullUrlWidget = do
schm <- dropdown Https (constDyn $ Https =: "https" <> Http =: "http") def
srv <- textInput def {_textInputConfig_attributes = constDyn $ "placeholder" =: "example.com"}
text ":"
prt <- textInput def { _textInputConfig_attributes = constDyn $ "placeholder" =: "80"}
port :: Dynamic t Int <- holdDyn 80 (fmapMaybe (readMaybe . T.unpack) $ updated (value prt))
path <- textInput def { _textInputConfig_attributes = constDyn $ "placeholder" =: "a/b" }
return $ BaseFullUrl <$> value schm <*> value srv <*> port <*> value path