Skip to content

Commit

Permalink
Upstream helper functions to Yesod.Form.Option. (#1828)
Browse files Browse the repository at this point in the history
The 2 new functions are:

- `optionsFromList'`: Creates an `OptionList` from a list using the `PathPiece` instance for the external value
and a custom function for the user-facing value.
- `optionsEnum'`: creates an `OptionList` from an enumeration.
  • Loading branch information
LukeTemp authored Feb 27, 2024
1 parent d3618b0 commit 5cfe884
Show file tree
Hide file tree
Showing 3 changed files with 105 additions and 1 deletion.
7 changes: 7 additions & 0 deletions yesod-form/ChangeLog.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# ChangeLog for yesod-form


## 1.7.7

* Added `optionsFromList'` to create an OptionList from a List, using the PathPiece instance for the external value and
a custom function for the user-facing value. Also added `optionsEnum'` to create an OptionList from an enumeration
[#1828](https://github.com/yesodweb/yesod/pull/1828)

## 1.7.6

* Added `datetimeLocalField` for creating a html `<input type="datetime-local">` [#1817](https://github.com/yesodweb/yesod/pull/1817)
Expand Down
96 changes: 96 additions & 0 deletions yesod-form/Yesod/Form/Option.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
{-# LANGUAGE FlexibleContexts #-}

module Yesod.Form.Option where

import Yesod.Core
import Yesod.Form.Fields

-- | Creates an `OptionList` from a `List`, using the `PathPiece` instance for
-- the external value and a custom function for the user-facing value.
--
-- @since 1.7.7
--
-- PathPiece instances should provide suitable external values, since path
-- pieces serve to be exposed through URLs or HTML anyway. Show/Read instances
-- are avoided here since they could leak internal representations to forms,
-- query params, javascript etc.
--
-- === __Example usage__
--
-- > data UserRole = URSalesTeam | URSalesHead | URTechTeam | URTechHead
-- >
-- > instance PathPiece UserDepartment where
-- > toPathPiece = \case
-- > URSalesTeam -> "sales-team"
-- > URSalesHead -> "sales-head"
-- > URTechTeam -> "tech-team"
-- > URTechHead -> "tech-head"
-- > fromPathPiece = \case
-- > "sales-team" -> Just URSalesTeam
-- > "sales-head" -> Just URSalesHead
-- > "tech-team" -> Just URTechTeam
-- > "tech-head" -> Just URTechHead
-- > _ -> Nothing
-- >
-- > userRoleOptions ::
-- > (MonadHandler m, RenderMessage (HandlerSite m) msg) => m (OptionList UserRole)
-- > userRoleOptions = optionsFromList' userRoles toMsg
-- > where
-- > userRoles = [URSalesTeam, URSalesHead, URTechTeam, URTechHead]
-- > toMsg :: UserRole -> Text
-- > toMsg = \case
-- > URSalesTeam -> "Sales Team"
-- > URSalesHead -> "Head of Sales Team"
-- > URTechTeam -> "Tech Team"
-- > URTechHead -> "Head of Tech Team"
--
-- userRoleOptions, will produce an OptionList with the following attributes:
--
-- > +----------------+----------------+--------------------+
-- > | Internal Value | External Value | User-facing Value |
-- > +----------------+----------------+--------------------+
-- > | URSalesTeam | sales-team | Sales Team |
-- > +----------------+----------------+--------------------+
-- > | URSalesHead | sales-head | Head of Sales Team |
-- > +----------------+----------------+--------------------+
-- > | URTechTeam | tech-team | Tech Team |
-- > +----------------+----------------+--------------------+
-- > | URTechHead | tech-head | Head of Tech Team |
-- > +----------------+----------------+--------------------+
--
-- Note that the type constraint allows localizable messages in place of toMsg (see
-- https://en.wikipedia.org/wiki/Yesod_(web_framework)#Localizable_messages).

optionsFromList' ::
MonadHandler m
=> RenderMessage (HandlerSite m) msg
=> PathPiece a
=> [a]
-> (a -> msg)
-> m (OptionList a)
optionsFromList' lst toDisplay = do
mr <- getMessageRender
pure $ mkOptionList $ flip map lst $ \v -> Option
{ optionDisplay = mr $ toDisplay v
, optionInternalValue = v
, optionExternalValue = toPathPiece v
}

-- | Creates an `OptionList` from an `Enum`.
--
-- @since 1.7.7
--
-- optionsEnum' == optionsFromList' [minBound..maxBound]
--
-- Creates an `OptionList` containing every constructor of `a`, so that these
-- constructors do not need to be typed out. Bounded and Enum instances must
-- exist for `a` to use this.
optionsEnum' ::
MonadHandler m
=> RenderMessage (HandlerSite m) msg
=> PathPiece a
=> Enum a
=> Bounded a
=> (a -> msg)
-> m (OptionList a)
optionsEnum' = optionsFromList' [minBound..maxBound]
3 changes: 2 additions & 1 deletion yesod-form/yesod-form.cabal
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
cabal-version: >= 1.10
name: yesod-form
version: 1.7.6
version: 1.7.7
license: MIT
license-file: LICENSE
author: Michael Snoyman <[email protected]>
Expand Down Expand Up @@ -46,6 +46,7 @@ library
build-depends: network-uri >= 2.6

exposed-modules: Yesod.Form
Yesod.Form.Option
Yesod.Form.Types
Yesod.Form.Functions
Yesod.Form.Bootstrap3
Expand Down

0 comments on commit 5cfe884

Please sign in to comment.