commit cfe000184696eec5de78b5bbf9390c0e205c0dcb Author: Youwen Wu Date: Sun Feb 16 16:54:16 2025 -0800 initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a72d1b2 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +elm-stuff/ diff --git a/README.md b/README.md new file mode 100644 index 0000000..64ad07f --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# elm experiments + +a collection of various experiments to learn [Elm](https://elm-lang.org/) diff --git a/elm.json b/elm.json new file mode 100644 index 0000000..ce2a08d --- /dev/null +++ b/elm.json @@ -0,0 +1,24 @@ +{ + "type": "application", + "source-directories": [ + "src" + ], + "elm-version": "0.19.1", + "dependencies": { + "direct": { + "elm/browser": "1.0.2", + "elm/core": "1.0.5", + "elm/html": "1.0.0" + }, + "indirect": { + "elm/json": "1.1.3", + "elm/time": "1.0.0", + "elm/url": "1.0.0", + "elm/virtual-dom": "1.0.3" + } + }, + "test-dependencies": { + "direct": {}, + "indirect": {} + } +} diff --git a/src/PasswordValidation.elm b/src/PasswordValidation.elm new file mode 100644 index 0000000..15d4329 --- /dev/null +++ b/src/PasswordValidation.elm @@ -0,0 +1,91 @@ +module PasswordValidation exposing (..) +import Browser +import Html exposing (..) +import Html.Attributes exposing (..) +import Html.Events exposing (onInput) + + + +-- MAIN + + +main = + Browser.sandbox { init = init, update = update, view = view } + + + +-- MODEL + + +type alias Model = + { name : String + , password : String + , passwordAgain : String + } + + +init : Model +init = Model "" "" "" + + + +-- UPDATE + + +type Msg + = Name String + | Password String + | PasswordAgain String + + +update : Msg -> Model -> Model +update msg model = + case msg of + Name name -> + { model | name = name } + + Password password -> + { model | password = password } + + PasswordAgain password -> + { model | passwordAgain = password } + + + +-- VIEW + + +view : Model -> Html Msg +view model = + div [] + [ viewInput "text" "Name" model.name Name + , viewInput "password" "Password" model.password Password + , viewInput "password" "Re-enter Password" model.passwordAgain PasswordAgain + , viewValidation model + ] + +viewInput : String -> String -> String -> (String -> msg) -> Html msg +viewInput t p v toMsg = + input [ type_ t, placeholder p, value v, onInput toMsg ] [] + +viewValidation : Model -> Html msg +viewValidation model = + if List.length (passwordHints model.password) > 0 then + div [ style "color" "red" ] (passwordHints model.password) + else if model.password /= model.passwordAgain then + div [ style "color" "red" ] [ text "Passwords do not match!" ] + else + div [ style "color" "green" ] [ text "OK" ] + +passwordHints : String -> List (Html msg) +passwordHints s = + (optional (String.length s <= 8) (text "Password must be at least 8 characters. ")) + ++ (optional (String.toUpper s == s) (text "Password must contain an uppercase letter. ")) + ++ (optional (String.toLower s == s) (text "Password must contain a lowercase letter. ")) + ++ (optional (not (containsNumeric s)) (text "Password must contain a number. ")) + +optional : Bool -> Html msg -> List (Html msg) +optional b xs = if b then [xs] else [] + +containsNumeric : String -> Bool +containsNumeric s = List.any (\b -> b) (List.map (\x -> String.contains x s) ["1", "2", "3", "4", "5", "6", "7", "8", "9", "0"])