{-# LANGUAGE FlexibleContexts, TypeFamilies #-} {-# OPTIONS_GHC -F -pgmFtrhsx #-} module Survey.Pages.EditSurvey where import Control.Applicative (Applicative((<*>),pure), Alternative, (*>), (<*), (<$>)) import Control.Monad import Control.Monad.Trans (MonadIO(..)) import Data.Acid import Data.Maybe (fromMaybe) import Data.Text (Text) import qualified Data.Text as Text import Happstack.Server import HSP import qualified HSX.XMLGenerator as HSX import Survey.Types import Survey.State (SurveyState, NewItemToSurvey(..), surveyError) import Survey.Pages.FormPart import qualified Survey.URL as URL import Text.Digestive import Text.Digestive.Common (input) import Text.Digestive.Forms (FormInput(..)) import qualified Text.Digestive.Forms as Forms import Text.Digestive.Forms.Happstack import Text.Digestive.HSP.Html4 hiding (inputTextArea) import Web.Routes editSurveyPage :: (EmbedAsAttr m (Attr String URL.SurveyURL), EmbedAsChild m XML, URL m ~ URL.SurveyURL, XMLGenerator m) => (String -> [XMLGenT m (HSX.XML m)] -> XMLGenT m (HSX.XML m) -> m Response) -> SurveyId -> m Response editSurveyPage pageTemplate sid = do pageTemplate "Edit Survey" [] $
Survey <% show $ unSurveyId $ sid %>
Add a question with an answer that is:
Add True / False
Add Integer Range
Add Long Response
Add Pick One
Survey <% show $ unSurveyId $ sid %>
<% formPart "survey" actionURL addItem Nothing ((,) <$> questionForm <*> choicesForm <* submit "add survey item") %><% surveyError e %>
(Right item) -> pageTemplate "Item Added" []Item successfully added. <% show item %>
inputInt :: (Functor m, Monad m, XMLGenerator x) => Maybe Int -> Form m [Input] String [XMLGenT x (HSX.XML x)] Int inputInt i = (inputString (fmap show i) `transform` (transformEither (\str -> case reads str of [(i,"")] -> Right i _ -> Left $ "Could not parse as Int: " ++ str))) questionForm :: (XMLGenerator x, Functor m, Monad m) => Form m [Input] String [XMLGenT x (HSX.XML x)] Question questionForm = label "Enter the question: " ++> (QuestionText <$> inputText Nothing) trueFalseForm :: (XMLGenerator x, Functor m, Monad m) => Form m [Input] String [XMLGenT x (HSX.XML x)] Choices trueFalseForm = label "true / false" ++> pure ChoiceTrueFalse -- FIXME: add validation rangeIntForm :: (XMLGenerator x, Functor m, Monad m) => Form m [Input] String [XMLGenT x (HSX.XML x)] Choices rangeIntForm = (ChoiceRangeInt <$> (label "min" ++> inputInt Nothing) <*> (label "max" ++> inputInt Nothing)) longResponseForm :: (XMLGenerator x, Functor m, Monad m) => Form m [Input] String [XMLGenT x (HSX.XML x)] Choices longResponseForm = pure $ ChoiceLongResponse Nothing Nothing -- <$> inputTextArea Nothing Nothing Nothing pickOneForm :: (XMLGenerator x, Functor m, Monad m) => Form m [Input] String [XMLGenT x (HSX.XML x)] Choices pickOneForm = ChoicePickOne Text.empty <$> ((inputList inputHiddenInt inputText) Nothing) -- move to digestive-functors-hsp required :: (Monad m) => e -> Transformer m e (Maybe a) a required err = transformEither $ maybe (Left err) Right inputTextArea :: (Monad m, Functor m, EmbedAsAttr x (Attr Text Int), EmbedAsChild x Text, XMLGenerator x, FormInput i f) => Maybe Int -> Maybe Int -> Maybe Text -> Form m i e [XMLGenT x (HSX.XML x)] Text inputTextArea r c = inputText' $ \id' inp -> [] where rows Nothing = [] rows (Just n) = [(Text.pack "rows" := n)] cols Nothing = [] cols (Just n) = [(Text.pack "cols" := n)] inputText' :: (Monad m, Functor m, FormInput i f) => (FormId -> Maybe Text -> v) -- ^ View constructor -> Maybe Text -- ^ Default value -> Form m i e v Text -- ^ Resulting form inputText' = input toView toResult where toView _ inp def = (getInputText =<< inp) `mplus` def toResult = Ok . fromMaybe Text.empty . (getInputText =<<) inputHiddenInt :: (Monad m, Functor m, XMLGenerator x, FormInput i f) => Formlet m i String [XMLGenT x (HSX.XML x)] Int inputHiddenInt i = hiddenString (fmap show i) `transform` (transformRead "inputHiddenInt could not parse form value as an Int") hiddenString :: (Monad m, Functor m, XMLGenerator x, FormInput i f) => Maybe String -> Form m i e [XMLGenT x (HSX.XML x)] String hiddenString str = Forms.inputString (\id' inp -> []) str -- inputList -- | Wraps the more generic 'Text.Digestive.Forms.inputList' function to -- provide a reasonable default for adding add/remove controls to a form. -- The whole thing is wrapped in another div with the class inputList. For -- this function to work, the javascript code in 'inputListJs' or something -- similar must be in scope. -- -- The user needs to specify the hidden formlet because transformRead requires -- an error parameter, and this function can't specify it without loss of -- generality. The idea is that the extra power of being able to customize -- the formlet is worth the small amount of extra code compared to having to -- specify the error. -- inputList :: (XMLGenerator x, Monad m, Functor m, FormInput i f) => Formlet m i e [XMLGenT x (HSX.XML x)] Int -- ^ The formlet holding the number of items in the list -> Formlet m i e [XMLGenT x (HSX.XML x)] a -- ^ The formlet used for each list item. This function surrounds it -- with a div tag with the inputListItem class. -> Formlet m i e [XMLGenT x (HSX.XML x)] [a] -- ^ The dynamic list formlet inputList hidden single d = mapView addControls $ Forms.inputList hidden s d where s def = mapView (\i -> [