156 lines
5.6 KiB
Haskell
156 lines
5.6 KiB
Haskell
{-# LANGUAGE QuasiQuotes #-}
|
|
module Yesod.Form.Jquery
|
|
( YesodJquery (..)
|
|
, jqueryDayField
|
|
, maybeJqueryDayField
|
|
, jqueryDayTimeField
|
|
, jqueryDayTimeFieldProfile
|
|
, jqueryAutocompleteField
|
|
, maybeJqueryAutocompleteField
|
|
, jqueryDayFieldProfile
|
|
) where
|
|
|
|
import Yesod.Handler
|
|
import Yesod.Form.Core
|
|
import Yesod.Form.Profiles
|
|
import Yesod.Widget
|
|
import Data.Time (UTCTime (..), Day, TimeOfDay (..), timeOfDayToTime,
|
|
timeToTimeOfDay)
|
|
import Yesod.Hamlet
|
|
import Data.Char (isSpace)
|
|
|
|
class YesodJquery a where
|
|
-- | The jQuery Javascript file.
|
|
urlJqueryJs :: a -> Either (Route a) String
|
|
urlJqueryJs _ = Right "http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"
|
|
|
|
-- | The jQuery UI 1.8.1 Javascript file.
|
|
urlJqueryUiJs :: a -> Either (Route a) String
|
|
urlJqueryUiJs _ = Right "http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.1/jquery-ui.min.js"
|
|
|
|
-- | The jQuery UI 1.8.1 CSS file; defaults to cupertino theme.
|
|
urlJqueryUiCss :: a -> Either (Route a) String
|
|
urlJqueryUiCss _ = Right "http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.1/themes/cupertino/jquery-ui.css"
|
|
|
|
-- | jQuery UI time picker add-on.
|
|
urlJqueryUiDateTimePicker :: a -> Either (Route a) String
|
|
urlJqueryUiDateTimePicker _ = Right "http://github.com/gregwebs/jquery.ui.datetimepicker/raw/master/jquery.ui.datetimepicker.js"
|
|
|
|
jqueryDayField :: YesodJquery y => FormFieldSettings -> FormletField sub y Day
|
|
jqueryDayField = requiredFieldHelper jqueryDayFieldProfile
|
|
|
|
maybeJqueryDayField :: YesodJquery y => FormFieldSettings -> FormletField sub y (Maybe Day)
|
|
maybeJqueryDayField = optionalFieldHelper jqueryDayFieldProfile
|
|
|
|
jqueryDayFieldProfile :: YesodJquery y => FieldProfile sub y Day
|
|
jqueryDayFieldProfile = FieldProfile
|
|
{ fpParse = maybe
|
|
(Left "Invalid day, must be in YYYY-MM-DD format")
|
|
Right
|
|
. readMay
|
|
, fpRender = show
|
|
, fpWidget = \theId name val isReq -> do
|
|
addBody [$hamlet|
|
|
%input#$theId$!name=$name$!type=date!:isReq:required!value=$val$
|
|
|]
|
|
addScript' urlJqueryJs
|
|
addScript' urlJqueryUiJs
|
|
addStylesheet' urlJqueryUiCss
|
|
addJavascript [$julius|
|
|
$(function(){$("#%theId%").datepicker({dateFormat:'yy-mm-dd'})});
|
|
|]
|
|
}
|
|
|
|
ifRight :: Either a b -> (b -> c) -> Either a c
|
|
ifRight e f = case e of
|
|
Left l -> Left l
|
|
Right r -> Right $ f r
|
|
|
|
showLeadingZero :: (Show a) => a -> String
|
|
showLeadingZero time = let t = show time in if length t == 1 then "0" ++ t else t
|
|
|
|
jqueryDayTimeField :: YesodJquery y => FormFieldSettings -> FormletField sub y UTCTime
|
|
jqueryDayTimeField = requiredFieldHelper jqueryDayTimeFieldProfile
|
|
|
|
-- use A.M/P.M and drop seconds and "UTC" (as opposed to normal UTCTime show)
|
|
jqueryDayTimeUTCTime :: UTCTime -> String
|
|
jqueryDayTimeUTCTime (UTCTime day utcTime) =
|
|
let timeOfDay = timeToTimeOfDay utcTime
|
|
in (replace '-' '/' (show day)) ++ " " ++ showTimeOfDay timeOfDay
|
|
where
|
|
showTimeOfDay (TimeOfDay hour minute _) =
|
|
let (h, apm) = if hour < 12 then (hour, "AM") else (hour - 12, "PM")
|
|
in (show h) ++ ":" ++ (showLeadingZero minute) ++ " " ++ apm
|
|
|
|
jqueryDayTimeFieldProfile :: YesodJquery y => FieldProfile sub y UTCTime
|
|
jqueryDayTimeFieldProfile = FieldProfile
|
|
{ fpParse = parseUTCTime
|
|
, fpRender = jqueryDayTimeUTCTime
|
|
, fpWidget = \theId name val isReq -> do
|
|
addBody [$hamlet|
|
|
%input#$theId$!name=$name$!:isReq:required!value=$val$
|
|
|]
|
|
addScript' urlJqueryJs
|
|
addScript' urlJqueryUiJs
|
|
addScript' urlJqueryUiDateTimePicker
|
|
addStylesheet' urlJqueryUiCss
|
|
addJavascript [$julius|
|
|
$(function(){$("#%theId%").datetimepicker({dateFormat : "yyyy/mm/dd h:MM TT"})});
|
|
|]
|
|
}
|
|
|
|
parseUTCTime :: String -> Either String UTCTime
|
|
parseUTCTime s =
|
|
let (dateS, timeS) = break isSpace (dropWhile isSpace s)
|
|
dateE = parseDate dateS
|
|
in case dateE of
|
|
Left l -> Left l
|
|
Right date ->
|
|
ifRight (parseTime timeS)
|
|
(UTCTime date . timeOfDayToTime)
|
|
|
|
jqueryAutocompleteField :: YesodJquery y =>
|
|
Route y -> FormFieldSettings -> FormletField sub y String
|
|
jqueryAutocompleteField = requiredFieldHelper . jqueryAutocompleteFieldProfile
|
|
|
|
maybeJqueryAutocompleteField :: YesodJquery y =>
|
|
Route y -> FormFieldSettings -> FormletField sub y (Maybe String)
|
|
maybeJqueryAutocompleteField src =
|
|
optionalFieldHelper $ jqueryAutocompleteFieldProfile src
|
|
|
|
jqueryAutocompleteFieldProfile :: YesodJquery y => Route y -> FieldProfile sub y String
|
|
jqueryAutocompleteFieldProfile src = FieldProfile
|
|
{ fpParse = Right
|
|
, fpRender = id
|
|
, fpWidget = \theId name val isReq -> do
|
|
addBody [$hamlet|
|
|
%input.autocomplete#$theId$!name=$name$!type=text!:isReq:required!value=$val$
|
|
|]
|
|
addScript' urlJqueryJs
|
|
addScript' urlJqueryUiJs
|
|
addStylesheet' urlJqueryUiCss
|
|
addJavascript [$julius|
|
|
$(function(){$("#%theId%").autocomplete({source:"@src@",minLength:2})});
|
|
|]
|
|
}
|
|
|
|
addScript' :: (y -> Either (Route y) String) -> GWidget sub y ()
|
|
addScript' f = do
|
|
y <- liftHandler getYesod
|
|
addScriptEither $ f y
|
|
|
|
addStylesheet' :: (y -> Either (Route y) String) -> GWidget sub y ()
|
|
addStylesheet' f = do
|
|
y <- liftHandler getYesod
|
|
addStylesheetEither $ f y
|
|
|
|
readMay :: Read a => String -> Maybe a
|
|
readMay s = case reads s of
|
|
(x, _):_ -> Just x
|
|
[] -> Nothing
|
|
|
|
-- | Replaces all instances of a value in a list by another value.
|
|
-- from http://hackage.haskell.org/packages/archive/cgi/3001.1.7.1/doc/html/src/Network-CGI-Protocol.html#replace
|
|
replace :: Eq a => a -> a -> [a] -> [a]
|
|
replace x y = map (\z -> if z == x then y else z)
|