From b77ee3947051b9a42496c8cd6bf40bdb5b55b135 Mon Sep 17 00:00:00 2001 From: Adrian Cochrane Date: Tue, 12 Sep 2023 14:52:24 +1200 Subject: [PATCH] Render ", - label = fromMaybe (attr "name" el "") $ fmap text label', + label = fromMaybe (attr "name" el "") $ fmap Txt.concat $ + fmap filterSelect label', description = fromMaybe (mkEl $ attr "title" el "") $ fmap node $ elByID $ attr "aria-describedby" el "", @@ -295,7 +296,7 @@ parseInput el | _:_ <- laxElement "input" el = Just Input { dirname = "", value = "", -- Sourced from list... - checked = True, + checked = False, readonly = False, formAction = Nothing, formEnctype = Nothing, @@ -311,19 +312,21 @@ parseInput el | _:_ <- laxElement "input" el = Just Input { fileData = defaultFileData, imageData = defaultImageData, textArea = defaultTextArea - } + } | otherwise = Nothing where elByAttr k v = listToMaybe $ (root >=> descendant >=> attributeIs k v) el elByID = elByAttr "id" label' = elByAttr "for" (attr "id" el "") `orElse` listToMaybe $ (ancestor >=> laxElement "label") el + filterSelect = descendant >=> + checkNot (orSelf ancestor >=> laxElement "select") >=> + content parseOptions :: Cursor -> [OptionGroup] parseOptions el = [parseGroup opt | opt <- (descendant >=> laxElements ["option", "optgroup"] >=> checkNot (parent >=> laxElement "optgroup")) el] where - checkNot test = check (not . bool . test) parseGroup opt | _:_ <- laxElement "option" opt = OptGroup "" False [parseOption opt False] @@ -350,6 +353,8 @@ parseDocument doc n forms = orSelf descendant >=> laxElement "form" doc' = fromDocument doc +checkNot :: Boolean b => (Cursor -> b) -> Axis +checkNot test = check (not . bool . test) rightToMaybe :: Either a b -> Maybe b rightToMaybe (Left _) = Nothing rightToMaybe (Right x) = Just x diff --git a/src/Text/HTML/Form/Query.hs b/src/Text/HTML/Form/Query.hs index 11d1e55..3bfcb62 100644 --- a/src/Text/HTML/Form/Query.hs +++ b/src/Text/HTML/Form/Query.hs @@ -1,19 +1,34 @@ +{-# LANGUAGE OverloadedStrings #-} module Text.HTML.Form.Query( renderQueryString, renderQueryString', renderQuery') where -import Text.HTML.Form (Form(..), Input(..)) +import Text.HTML.Form (Form(..), Input(..), OptionGroup(..), Option(..)) import Network.URI (escapeURIString, isUnescapedInURIComponent) import Data.List (intercalate) import Data.Text (unpack) renderQueryString :: Form -> String renderQueryString = renderQueryString' . renderQuery' +renderQueryString' :: [(String, String)] -> String renderQueryString' query = intercalate "&" [ - escape key ++ '=':escape value | (key, value) <- query + escape key ++ '=':escape val | (key, val) <- query ] renderQuery' :: Form -> [(String, String)] -renderQuery' form = [(unpack $ inputName input, unpack $ value input) - | input <- inputs form, checked input] +renderQuery' form = concatMap renderInput' $ inputs form +renderInput' :: Input -> [(String, String)] +renderInput' Input { checked = False, inputType = inputType' } + | inputType' `elem` ["radio", "checkbox"] = [] +renderInput' Input { inputType = "", + inputName = k, list = opts, multiple = True + } = [(unpack k, unpack $ optValue opt) | + grp <- opts, opt <- subopts grp, optSelected opt] +renderInput' Input { inputName = k, value = v } = [(unpack k, unpack v)] +escape :: String -> String escape = escapeURIString isUnescapedInURIComponent diff --git a/src/Text/HTML/Form/WebApp.hs b/src/Text/HTML/Form/WebApp.hs index 986bca7..687facd 100644 --- a/src/Text/HTML/Form/WebApp.hs +++ b/src/Text/HTML/Form/WebApp.hs @@ -5,6 +5,7 @@ import Data.ByteString as BS import Data.Text as Txt import Data.Text.Encoding as Txt import Text.Read (readMaybe) +import Network.URI (unEscapeString) import Text.HTML.Form (Form(..), Input(..)) import Text.HTML.Form.WebApp.Ginger (template) @@ -15,24 +16,44 @@ renderPage form (n:path) query | Just ix <- readMaybe $ Txt.unpack n, ix < Prelude.length (inputs form) = renderInput form ix (inputs form !! ix) path query renderPage form [] _ = return $ Just $ Txt.concat [ - "Start!"] + "Start!"] renderPage _ _ _ = return Nothing renderInput :: Form -> Int -> Input -> [Text] -> [(ByteString, Maybe ByteString)] -> IO (Maybe Text) +renderInput form ix input [""] qs = renderInput form ix input [] qs +renderInput form ix input@Input { multiple = True } [p] qs + | '=':v' <- Txt.unpack p, + (utf8 $ inputName input, Just $ utf8' v') `Prelude.elem` qs = + renderInput form ix input [] $ + unset (inputName input) (Txt.pack $ unEscapeString v') qs + | '=':v' <- Txt.unpack p = renderInput form ix input [] $ + (utf8 $ inputName input, Just $ utf8' $ unEscapeString v'):qs +renderInput form ix input [p] qs + | '=':v' <- Txt.unpack p = renderInput form ix input [] $ + set (inputName input) (Txt.pack $ unEscapeString v') qs renderInput form ix input@Input {inputType="checkbox", inputName=k', value=v'} [] qs | (utf8 k', Just $ utf8 v') `Prelude.elem` qs = - template "checkbox.html" form ix input [ - q | q@(k, v) <- qs, k /= utf8 k', v /= Just (utf8 v')] + template "checkbox.html" form ix input $ unset k' v' qs | v' == "", (utf8 k', Nothing) `Prelude.elem` qs = template "checkbox.html" form ix input [ - q | q@(k, v) <- qs, k /= utf8 k', v /= Nothing] + q | q@(k, v) <- qs, not (k == utf8 k' && v == Nothing)] | otherwise = template "checkbox.html" form ix input $ (utf8 k', Just $ utf8 v'):qs renderInput form ix input@Input {inputType="radio", inputName=k', value=v'} [] qs = - template "checkbox.html" form ix input $ - (utf8 k', Just $ utf8 v'):[q | q@(k, _) <- qs, k /= utf8 k'] -renderInput _ _ _ _ _ = return Nothing + template "checkbox.html" form ix input $ set k' v' qs +renderInput form ix input@Input { inputType="