packages feed

web-rep-0.11.0.0: src/Web/Rep/Html/Input.hs

{-# LANGUAGE OverloadedStrings #-}

-- | Common web page input elements, often with bootstrap scaffolding.
module Web.Rep.Html.Input
  ( Input (..),
    InputType (..),
    inputToHtml,
  )
where

import Data.Bool
import Data.ByteString (ByteString)
import Data.ByteString.Char8 qualified as C
import Data.Maybe
import GHC.Generics
import MarkupParse

-- | something that might exist on a web page and be a front-end input to computations.
data Input a = Input
  { -- | underlying value
    inputVal :: a,
    -- | label suggestion
    inputLabel :: Maybe ByteString,
    -- | name//key//id of the Input
    inputId :: ByteString,
    -- | type of html input
    inputType :: InputType
  }
  deriving (Eq, Show, Generic)

-- | Various types of web page inputs, encapsulating practical bootstrap class functionality
data InputType
  = Slider [Attr]
  | SliderV [Attr]
  | TextBox
  | TextBox'
  | TextArea Int
  | ColorPicker
  | ChooseFile
  | Dropdown [ByteString]
  | DropdownMultiple [ByteString] Char
  | DropdownSum [ByteString]
  | Datalist [ByteString] ByteString
  | Checkbox Bool
  | Toggle Bool (Maybe ByteString)
  | Button
  deriving (Eq, Show, Generic)

inputToHtml :: (Show a) => Input a -> Markup
inputToHtml (Input v l i (Slider satts)) =
  element
    "div"
    [Attr "class" "form-group-sm"]
    (maybe mempty (elementc "label" [Attr "for" i, Attr "class" "mb-0"]) l)
    <> element_
      "input"
      ( [ Attr "type" "range",
          Attr "class" " form-control-range form-control-sm custom-range jsbClassEventChange",
          Attr "id" i,
          Attr "value" (strToUtf8 $ show v)
        ]
          <> satts
      )
inputToHtml (Input v l i (SliderV satts)) =
  element
    "div"
    [Attr "class" "form-group-sm"]
    ( maybe mempty (elementc "label" [Attr "for" i, Attr "class" "mb-0"]) l
        <> element_
          "input"
          ( [ Attr "type" "range",
              Attr "class" " form-control-range form-control-sm custom-range jsbClassEventChange",
              Attr "id" i,
              Attr "value" (strToUtf8 $ show v),
              Attr "oninput" ("$('#sliderv" <> i <> "').html($(this).val())")
            ]
              <> satts
          )
    )
    <> elementc "span" [Attr "id" ("sliderv" <> i)] (strToUtf8 $ show v)
inputToHtml (Input v l i TextBox) =
  element
    "div"
    [Attr "class" "form-group-sm"]
    ( maybe mempty (elementc "label" [Attr "for" i, Attr "class" "mb-0"]) l
        <> element_
          "input"
          [ Attr "type" "text",
            Attr "class" "form-control form-control-sm jsbClassEventInput",
            Attr "id" i,
            Attr "value" (strToUtf8 $ show v)
          ]
    )
inputToHtml (Input v l i TextBox') =
  element
    "div"
    [Attr "class" "form-group-sm"]
    ( maybe mempty (elementc "label" [Attr "for" i, Attr "class" "mb-0"]) l
        <> element_
          "input"
          [ Attr "type" "text",
            Attr "class" "form-control form-control-sm jsbClassEventFocusout",
            Attr "id" i,
            Attr "value" (strToUtf8 $ show v)
          ]
    )
inputToHtml (Input v l i (TextArea rows)) =
  element
    "div"
    [Attr "class" "form-group-sm"]
    ( maybe mempty (elementc "label" [Attr "for" i, Attr "class" "mb-0"]) l
        <> elementc
          "textarea"
          [ Attr "rows" (strToUtf8 $ show rows),
            Attr "class" "form-control form-control-sm jsbClassEventInput",
            Attr "id" i
          ]
          (strToUtf8 $ show v)
    )
inputToHtml (Input v l i ColorPicker) =
  element
    "div"
    [Attr "class" "form-group-sm"]
    ( maybe mempty (elementc "label" [Attr "for" i, Attr "class" "mb-0"]) l
        <> element_
          "input"
          [ Attr "type" "color",
            Attr "class" "form-control form-control-sm jsbClassEventInput",
            Attr "id" i,
            Attr "value" (strToUtf8 $ show v)
          ]
    )
inputToHtml (Input _ l i ChooseFile) =
  element
    "div"
    [Attr "class" "form-group-sm"]
    ( maybe mempty (elementc "label" [Attr "for" i, Attr "class" "mb-0"]) l
        <> element_
          "input"
          [ Attr "type" "file",
            Attr "class" "form-control-file form-control-sm jsbClassEventChooseFile",
            Attr "id" i
          ]
    )
inputToHtml (Input v l i (Dropdown opts)) =
  element
    "div"
    [Attr "class" "form-group-sm"]
    ( maybe mempty (elementc "label" [Attr "for" i, Attr "class" "mb-0"]) l
        <> element
          "select"
          [ Attr "class" "form-control form-control-sm jsbClassEventInput",
            Attr "id" i
          ]
          (mconcat opts')
    )
  where
    opts' =
      ( \o ->
          elementc
            "option"
            ( bool
                []
                [Attr "selected" "selected"]
                (o == strToUtf8 (show v))
            )
            o
      )
        <$> opts
inputToHtml (Input vs l i (DropdownMultiple opts sep)) =
  element
    "div"
    [Attr "class" "form-group-sm"]
    ( maybe mempty (elementc "label" [Attr "for" i, Attr "class" "mb-0"]) l
        <> element
          "select"
          [ Attr "class" "form-control form-control-sm jsbClassEventChangeMultiple",
            Attr "multiple" "multiple",
            Attr "id" i
          ]
          (mconcat opts')
    )
  where
    opts' =
      ( \o ->
          elementc
            "option"
            ( bool
                []
                [Attr "selected" "selected"]
                (any (\v -> o == strToUtf8 (show v)) (C.split sep (strToUtf8 $ show vs)))
            )
            o
      )
        <$> opts
inputToHtml (Input v l i (DropdownSum opts)) =
  element
    "div"
    [Attr "class" "form-group-sm sumtype-group"]
    ( maybe mempty (elementc "label" [Attr "for" i, Attr "class" "mb-0"]) l
        <> element
          "select"
          [ Attr "class" "form-control form-control-sm jsbClassEventInput jsbClassEventShowSum",
            Attr "id" i
          ]
          (mconcat opts')
    )
  where
    opts' =
      ( \o ->
          elementc
            "option"
            (bool [] [Attr "selected" "selected"] (o == strToUtf8 (show v)))
            o
      )
        <$> opts
inputToHtml (Input v l i (Datalist opts listId)) =
  element
    "div"
    [Attr "class" "form-group-sm"]
    ( maybe mempty (elementc "label" [Attr "for" i, Attr "class" "mb-0"]) l
        <> element_
          "input"
          [ Attr "type" "text",
            Attr "class" "form-control form-control-sm jsbClassEventInput",
            Attr "id" i,
            Attr "list" listId
            -- the datalist concept in html assumes initial state is a null
            -- and doesn't present the list if it has a value alreadyx
            -- , value_ (show $ toHtml v)
          ]
        <> element
          "datalist"
          [Attr "id" listId]
          ( mconcat
              ( ( \o ->
                    elementc
                      "option"
                      ( bool
                          []
                          [Attr "selected" "selected"]
                          (o == strToUtf8 (show v))
                      )
                      o
                )
                  <$> opts
              )
          )
    )
inputToHtml (Input _ l i (Checkbox checked)) =
  element
    "div"
    [Attr "class" "form-check form-check-sm"]
    ( element
        "input"
        ( [ Attr "type" "checkbox",
            Attr "class" "form-check-input jsbClassEventCheckbox",
            Attr "id" i
          ]
            <> bool [] [Attr "checked" ""] checked
        )
        ( maybe mempty (elementc "label" [Attr "for" i, Attr "class" "form-label-check mb-0"]) l
        )
    )
inputToHtml (Input _ l i (Toggle pushed lab)) =
  element
    "div"
    [Attr "class" "form-group-sm"]
    ( maybe mempty (elementc "label" [Attr "for" i, Attr "class" "mb-0"]) l
        <> element_
          "input"
          ( [ Attr "type" "button",
              Attr "class" "btn btn-primary btn-sm jsbClassEventToggle",
              Attr "data-bs-toggle" "button",
              Attr "id" i,
              Attr "aria-pressed" (bool "false" "true" pushed)
            ]
              <> maybe [] (\l' -> [Attr "value" l']) lab
              <> bool [] [Attr "checked" ""] pushed
          )
    )
inputToHtml (Input _ l i Button) =
  element
    "div"
    [Attr "class" "form-group-sm"]
    ( element_
        "input"
        [ Attr "type" "button",
          Attr "id" i,
          Attr "class" "btn btn-primary btn-sm jsbClassEventButton",
          Attr "value" (fromMaybe "button" l)
        ]
    )