{-# LANGUAGE QuasiQuotes #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE CPP #-} {-# LANGUAGE FlexibleContexts #-} module Yesod.Form.Fields ( -- * i18n FormMessage (..) , defaultFormMessage -- * Fields , textField , passwordField , textareaField , hiddenField , intField , dayField , timeField , htmlField , emailField , searchField , selectField , multiSelectField , AutoFocus , urlField , doubleField , parseDate , parseTime , Textarea (..) , radioField , boolField -- * File 'AForm's , fileAFormReq , fileAFormOpt -- * Options , selectField' , radioField' , Option (..) , OptionList (..) , mkOptionList , optionsPersist , optionsPairs , optionsEnum ) where import Yesod.Form.Types import Yesod.Form.I18n.English import Yesod.Widget import Yesod.Message (RenderMessage (renderMessage), SomeMessage (..)) import Text.Hamlet import Text.Blaze (ToHtml (..), preEscapedText, unsafeByteString) import Text.Cassius import Data.Time (Day, TimeOfDay(..)) import qualified Text.Email.Validate as Email import Network.URI (parseURI) import Database.Persist (PersistField) import Text.HTML.SanitizeXSS (sanitizeBalance) import Control.Monad (when, unless) import Data.List (intersect, nub) import Data.Either (rights) import Data.Maybe (catMaybes, listToMaybe) import qualified Blaze.ByteString.Builder.Html.Utf8 as B import Blaze.ByteString.Builder (writeByteString, toLazyByteString) import Blaze.ByteString.Builder.Internal.Write (fromWriteList) import Text.Blaze.Renderer.String (renderHtml) import qualified Data.ByteString as S import qualified Data.ByteString.Lazy as L import Data.Text (Text, unpack, pack) import qualified Data.Text.Read import Control.Monad.Trans.Class (lift) import Control.Applicative ((<$>)) import qualified Data.Map as Map import Yesod.Handler (newIdent, liftIOHandler) import Yesod.Request (FileInfo) import Yesod.Core (toSinglePiece, GGHandler, SinglePiece) import Yesod.Persist (selectList, runDB, Filter, SelectOpt, YesodPersistBackend, Key, YesodPersist, PersistEntity, PersistBackend) import Control.Arrow ((&&&)) #if __GLASGOW_HASKELL__ >= 700 #define WHAMLET whamlet #define HAMLET hamlet #define CASSIUS cassius #define JULIUS julius #define HTML html #else #define WHAMLET $whamlet #define HAMLET $hamlet #define CASSIUS $cassius #define JULIUS $julius #define HTML $html #endif defaultFormMessage :: FormMessage -> Text defaultFormMessage = englishFormMessage blank :: (Monad m, RenderMessage master FormMessage) => (Text -> Either FormMessage a) -> [Text] -> m (Either (SomeMessage master) (Maybe a)) blank _ [] = return $ Right Nothing blank _ ("":_) = return $ Right Nothing blank f (x:_) = return $ either (Left . SomeMessage) (Right . Just) $ f x intField :: (Integral i, RenderMessage master FormMessage) => Field sub master i intField = Field { fieldParse = blank $ \s -> case Data.Text.Read.signed Data.Text.Read.decimal s of Right (a, "") -> Right a _ -> Left $ MsgInvalidInteger s , fieldView = \theId name val isReq -> addHamlet [HAMLET|\ |] } where showVal = either id (pack . showI) showI x = show (fromIntegral x :: Integer) doubleField :: RenderMessage master FormMessage => Field sub master Double doubleField = Field { fieldParse = blank $ \s -> case Data.Text.Read.double s of Right (a, "") -> Right a _ -> Left $ MsgInvalidNumber s , fieldView = \theId name val isReq -> addHamlet [HAMLET|\ |] } where showVal = either id (pack . show) dayField :: RenderMessage master FormMessage => Field sub master Day dayField = Field { fieldParse = blank $ parseDate . unpack , fieldView = \theId name val isReq -> addHamlet [HAMLET|\ |] } where showVal = either id (pack . show) timeField :: RenderMessage master FormMessage => Field sub master TimeOfDay timeField = Field { fieldParse = blank $ parseTime . unpack , fieldView = \theId name val isReq -> addHamlet [HAMLET|\ |] } where showVal = either id (pack . show . roundFullSeconds) roundFullSeconds tod = TimeOfDay (todHour tod) (todMin tod) fullSec where fullSec = fromInteger $ floor $ todSec tod htmlField :: RenderMessage master FormMessage => Field sub master Html htmlField = Field { fieldParse = blank $ Right . preEscapedText . sanitizeBalance , fieldView = \theId name val _isReq -> addHamlet [HAMLET|\