{-# language OverloadedStrings #-}
{-# language TypeOperators #-}
module FlexTask.FormUtil
(
($$>)
, addCss
, addJs
, addCssAndJs
, applyToWidget
, addAttribute
, addAttributes
, addCssClass
, addNameAndCssClass
, readOnly
, universalLabel
, showToUniversalLabel
, newFlexId
, newFlexName
, repeatFlexName
, printWidget
) where
import Data.Containers.ListUtils (nubOrd)
import Data.List.Extra (isInfixOf, isPrefixOf, trimEnd, splitOn)
import Data.String (fromString)
import Data.Text (Text, pack)
import Data.Tuple.Extra (second)
import Text.Cassius (Css)
import Text.Julius (Javascript)
import Yesod
import Yesod.Core.Types (RY)
import qualified Control.Monad.Trans.RWS as RWS (get)
import qualified Data.Map as M (lookup)
import qualified Data.Text as T (replace)
import FlexTask.ConvertForm (getFormData)
import FlexTask.YesodConfig (
FlexForm(..),
Handler,
Rendered,
Rendered',
Widget,
)
infixr 0 $$>
($$>)
:: (Monad w, Monad m)
=> Rendered' m (w a)
-> Rendered' m (w b)
-> Rendered' m (w b)
Rendered' m (w a)
f1 $$> :: forall (w :: * -> *) (m :: * -> *) a b.
(Monad w, Monad m) =>
Rendered' m (w a) -> Rendered' m (w b) -> Rendered' m (w b)
$$> Rendered' m (w b)
f2 = do
res1 <- Rendered' m (w a)
m (RWST
(Maybe (Env, FileEnv), FlexForm, [Lang])
Enctype
Ints
Handler
([[Lang]], w a))
f1
res2 <- f2
pure $ do
(names1,wid1) <- res1
(names2,wid2) <- res2
pure (nubOrd $ names1 ++ names2, wid1 >> wid2)
applyToWidget :: Functor m => (w -> w') -> Rendered' m w -> Rendered' m w'
applyToWidget :: forall (m :: * -> *) w w'.
Functor m =>
(w -> w') -> Rendered' m w -> Rendered' m w'
applyToWidget w -> w'
f Rendered' m w
form = (([[Lang]], w) -> ([[Lang]], w'))
-> RWST
(Maybe (Env, FileEnv), FlexForm, [Lang])
Enctype
Ints
Handler
([[Lang]], w)
-> RWST
(Maybe (Env, FileEnv), FlexForm, [Lang])
Enctype
Ints
Handler
([[Lang]], w')
forall a b.
(a -> b)
-> RWST
(Maybe (Env, FileEnv), FlexForm, [Lang]) Enctype Ints Handler a
-> RWST
(Maybe (Env, FileEnv), FlexForm, [Lang]) Enctype Ints Handler b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ((w -> w') -> ([[Lang]], w) -> ([[Lang]], w')
forall b b' a. (b -> b') -> (a, b) -> (a, b')
second w -> w'
f) (RWST
(Maybe (Env, FileEnv), FlexForm, [Lang])
Enctype
Ints
Handler
([[Lang]], w)
-> RWST
(Maybe (Env, FileEnv), FlexForm, [Lang])
Enctype
Ints
Handler
([[Lang]], w'))
-> m (RWST
(Maybe (Env, FileEnv), FlexForm, [Lang])
Enctype
Ints
Handler
([[Lang]], w))
-> m (RWST
(Maybe (Env, FileEnv), FlexForm, [Lang])
Enctype
Ints
Handler
([[Lang]], w'))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Rendered' m w
m (RWST
(Maybe (Env, FileEnv), FlexForm, [Lang])
Enctype
Ints
Handler
([[Lang]], w))
form
addContent
:: (ToWidget FlexForm (render -> a), Functor m)
=> (render -> a)
-> Rendered' m Widget
-> Rendered' m Widget
addContent :: forall render a (m :: * -> *).
(ToWidget FlexForm (render -> a), Functor m) =>
(render -> a) -> Rendered' m Widget -> Rendered' m Widget
addContent render -> a
content = (Widget -> Widget) -> Rendered' m Widget -> Rendered' m Widget
forall (m :: * -> *) w w'.
Functor m =>
(w -> w') -> Rendered' m w -> Rendered' m w'
applyToWidget (Widget -> Widget -> Widget
forall a b.
WidgetFor FlexForm a
-> WidgetFor FlexForm b -> WidgetFor FlexForm a
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
<* (render -> a) -> Widget
forall site a (m :: * -> *).
(ToWidget site a, MonadWidget m, HandlerSite m ~ site) =>
a -> m ()
forall (m :: * -> *).
(MonadWidget m, HandlerSite m ~ FlexForm) =>
(render -> a) -> m ()
toWidget render -> a
content)
addCss
:: (render ~ RY FlexForm, Functor m)
=> (render -> Css)
-> Rendered' m Widget
-> Rendered' m Widget
addCss :: forall render (m :: * -> *).
(render ~ RY FlexForm, Functor m) =>
(render -> Css) -> Rendered' m Widget -> Rendered' m Widget
addCss = (render -> Css) -> Rendered' m Widget -> Rendered' m Widget
forall render a (m :: * -> *).
(ToWidget FlexForm (render -> a), Functor m) =>
(render -> a) -> Rendered' m Widget -> Rendered' m Widget
addContent
addJs
:: (render ~ RY FlexForm, Functor m)
=> (render -> Javascript)
-> Rendered' m Widget
-> Rendered' m Widget
addJs :: forall render (m :: * -> *).
(render ~ RY FlexForm, Functor m) =>
(render -> Javascript) -> Rendered' m Widget -> Rendered' m Widget
addJs = (render -> Javascript) -> Rendered' m Widget -> Rendered' m Widget
forall render a (m :: * -> *).
(ToWidget FlexForm (render -> a), Functor m) =>
(render -> a) -> Rendered' m Widget -> Rendered' m Widget
addContent
addCssAndJs
:: (render ~ RY FlexForm, Functor m)
=> (render -> Css)
-> (render -> Javascript)
-> Rendered' m Widget
-> Rendered' m Widget
addCssAndJs :: forall render (m :: * -> *).
(render ~ RY FlexForm, Functor m) =>
(render -> Css)
-> (render -> Javascript)
-> Rendered' m Widget
-> Rendered' m Widget
addCssAndJs render -> Css
css render -> Javascript
js = (Widget -> Widget) -> Rendered' m Widget -> Rendered' m Widget
forall (m :: * -> *) w w'.
Functor m =>
(w -> w') -> Rendered' m w -> Rendered' m w'
applyToWidget ((Widget -> Widget -> Widget
forall a b.
WidgetFor FlexForm a
-> WidgetFor FlexForm b -> WidgetFor FlexForm a
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
<* (render -> Css) -> Widget
forall site a (m :: * -> *).
(ToWidget site a, MonadWidget m, HandlerSite m ~ site) =>
a -> m ()
forall (m :: * -> *).
(MonadWidget m, HandlerSite m ~ FlexForm) =>
(render -> Css) -> m ()
toWidget render -> Css
css) (Widget -> Widget) -> (Widget -> Widget) -> Widget -> Widget
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Widget -> Widget -> Widget
forall a b.
WidgetFor FlexForm a
-> WidgetFor FlexForm b -> WidgetFor FlexForm a
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
<* (render -> Javascript) -> Widget
forall site a (m :: * -> *).
(ToWidget site a, MonadWidget m, HandlerSite m ~ site) =>
a -> m ()
forall (m :: * -> *).
(MonadWidget m, HandlerSite m ~ FlexForm) =>
(render -> Javascript) -> m ()
toWidget render -> Javascript
js))
addNameAndCssClass :: Text -> Text -> FieldSettings app
addNameAndCssClass :: forall app. Lang -> Lang -> FieldSettings app
addNameAndCssClass Lang
name Lang
cssClass = FieldSettings app
forall {master}. FieldSettings master
addFieldAttrs
where
fSettings :: FieldSettings site
fSettings = Lang -> FieldSettings site
forall site msg.
RenderMessage site msg =>
msg -> FieldSettings site
fieldSettingsLabel Lang
name
addFieldAttrs :: FieldSettings master
addFieldAttrs = FieldSettings master
forall {master}. FieldSettings master
fSettings {
fsName = Just name,
fsAttrs = addClass cssClass $ fsAttrs fSettings
}
addAttribute :: (Text,Text) -> FieldSettings app -> FieldSettings app
addAttribute :: forall app. (Lang, Lang) -> FieldSettings app -> FieldSettings app
addAttribute (Lang, Lang)
attribute FieldSettings app
fs = FieldSettings app
fs { fsAttrs = attribute : fsAttrs fs}
addAttributes :: [(Text,Text)] -> FieldSettings app -> FieldSettings app
addAttributes :: forall app.
[(Lang, Lang)] -> FieldSettings app -> FieldSettings app
addAttributes [(Lang, Lang)]
as FieldSettings app
fs = FieldSettings app
fs { fsAttrs = as ++ fsAttrs fs}
addCssClass :: Text -> FieldSettings app -> FieldSettings app
addCssClass :: forall app. Lang -> FieldSettings app -> FieldSettings app
addCssClass Lang
c FieldSettings app
fs = FieldSettings app
fs { fsAttrs = addClass c $ fsAttrs fs}
readOnly :: FieldSettings app -> FieldSettings app
readOnly :: forall app. FieldSettings app -> FieldSettings app
readOnly = [(Lang, Lang)] -> FieldSettings app -> FieldSettings app
forall app.
[(Lang, Lang)] -> FieldSettings app -> FieldSettings app
addAttributes [(Lang
"readonly",Lang
""),(Lang
"style",Lang
"background-color: #EEEEEE")]
universalLabel :: String -> SomeMessage FlexForm
universalLabel :: String -> SomeMessage FlexForm
universalLabel = String -> SomeMessage FlexForm
forall a. IsString a => String -> a
fromString
showToUniversalLabel :: Show a => a -> SomeMessage FlexForm
showToUniversalLabel :: forall a. Show a => a -> SomeMessage FlexForm
showToUniversalLabel = String -> SomeMessage FlexForm
universalLabel (String -> SomeMessage FlexForm)
-> (a -> String) -> a -> SomeMessage FlexForm
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> String
forall a. Show a => a -> String
show
newFlexId :: MForm Handler Text
newFlexId :: MForm Handler Lang
newFlexId = HasCallStack => Lang -> Lang -> Lang -> Lang
Lang -> Lang -> Lang -> Lang
T.replace Lang
"h" Lang
"flex" (Lang -> Lang)
-> RWST
(Maybe (Env, FileEnv), FlexForm, [Lang]) Enctype Ints Handler Lang
-> RWST
(Maybe (Env, FileEnv), FlexForm, [Lang]) Enctype Ints Handler Lang
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> RWST
(Maybe (Env, FileEnv), FlexForm, [Lang]) Enctype Ints Handler Lang
forall (m :: * -> *). MonadHandler m => m Lang
newIdent
repeatFlexName :: MForm Handler Text
repeatFlexName :: MForm Handler Lang
repeatFlexName = do
i <- RWST
(Maybe (Env, FileEnv), FlexForm, [Lang]) Enctype Ints Handler Ints
forall w (m :: * -> *) r s. (Monoid w, Monad m) => RWST r w s m s
RWS.get
pure $ pack $ "flex" ++ show i
newFlexName :: MForm Handler Text
newFlexName :: MForm Handler Lang
newFlexName = HasCallStack => Lang -> Lang -> Lang -> Lang
Lang -> Lang -> Lang -> Lang
T.replace Lang
"f" Lang
"flex" (Lang -> Lang)
-> RWST
(Maybe (Env, FileEnv), FlexForm, [Lang]) Enctype Ints Handler Lang
-> RWST
(Maybe (Env, FileEnv), FlexForm, [Lang]) Enctype Ints Handler Lang
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> MForm Handler Lang
RWST
(Maybe (Env, FileEnv), FlexForm, [Lang]) Enctype Ints Handler Lang
forall (m :: * -> *). Monad m => MForm m Lang
newFormIdent
printWidget :: Lang -> Rendered Widget -> IO ()
printWidget :: Lang -> Rendered Widget -> IO ()
printWidget Lang
lang Rendered Widget
render = do
(_, dict) <- Rendered Widget -> IO ([[Lang]], HtmlDict)
getFormData Rendered Widget
render
putStrLn $ maybe "Form not available in this language."
(trimEnd . unlines . addIndent 0 . intoLines)
$ M.lookup lang dict
where
intoLines :: String -> [String]
intoLines String
s =
let opening :: [String]
opening = (String -> String) -> [String] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map (String
"<" String -> String -> String
forall a. [a] -> [a] -> [a]
++) ([String] -> [String]) -> [String] -> [String]
forall a b. (a -> b) -> a -> b
$ Int -> [String] -> [String]
forall a. Int -> [a] -> [a]
drop Int
1 (String -> String -> [String]
forall a. (HasCallStack, Eq a) => [a] -> [a] -> [[a]]
splitOn String
"<" String
s)
closing :: [String]
closing = (String -> [String]) -> [String] -> [String]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap ((String -> Bool) -> [String] -> [String]
forall a. (a -> Bool) -> [a] -> [a]
filter (String -> String -> Bool
forall a. Eq a => a -> a -> Bool
/=String
"") ([String] -> [String])
-> (String -> [String]) -> String -> [String]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> String -> [String]
forall a. (HasCallStack, Eq a) => [a] -> [a] -> [[a]]
splitOn String
">") [String]
opening
in (String -> String) -> [String] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map (\String
x -> if String
"<" String -> String -> Bool
forall a. Eq a => [a] -> [a] -> Bool
`isPrefixOf` String
x then String
x String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
">" else String
x) [String]
closing
addIndent :: Int -> [String] -> [String]
addIndent Int
_ [] = []
addIndent Int
i (String
s:[String]
ss)
| String
"</" String -> String -> Bool
forall a. Eq a => [a] -> [a] -> Bool
`isInfixOf` String
s
= (Int -> Char -> String
forall a. Int -> a -> [a]
replicate (Int
iInt -> Int -> Int
forall a. Num a => a -> a -> a
-Int
2) Char
' ' String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
s) String -> [String] -> [String]
forall a. a -> [a] -> [a]
: Int -> [String] -> [String]
addIndent (Int
iInt -> Int -> Int
forall a. Num a => a -> a -> a
-Int
2) [String]
ss
| String
">" String -> String -> Bool
forall a. Eq a => [a] -> [a] -> Bool
`isInfixOf` String
s Bool -> Bool -> Bool
&& Bool -> Bool
not ((String -> Bool) -> [String] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any (String -> String -> Bool
forall a. Eq a => [a] -> [a] -> Bool
`isInfixOf` String
s) [String]
noClose)
= (Int -> Char -> String
forall a. Int -> a -> [a]
replicate Int
i Char
' ' String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
s) String -> [String] -> [String]
forall a. a -> [a] -> [a]
: Int -> [String] -> [String]
addIndent (Int
iInt -> Int -> Int
forall a. Num a => a -> a -> a
+Int
2) [String]
ss
| Bool
otherwise
= (Int -> Char -> String
forall a. Int -> a -> [a]
replicate Int
i Char
' ' String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
s) String -> [String] -> [String]
forall a. a -> [a] -> [a]
: Int -> [String] -> [String]
addIndent Int
i [String]
ss
noClose :: [String]
noClose =
[ String
"area"
, String
"base"
, String
"br"
, String
"col"
, String
"embed"
, String
"hr"
, String
"img"
, String
"input"
, String
"link"
, String
"meta"
, String
"param"
, String
"source"
, String
"track"
, String
"wbr"
]