Skip to content

Instantly share code, notes, and snippets.

@sparksp
Last active May 21, 2020 09:57
Show Gist options
  • Save sparksp/e1f44f35356269653d054321b76da648 to your computer and use it in GitHub Desktop.
Save sparksp/e1f44f35356269653d054321b76da648 to your computer and use it in GitHub Desktop.
Html.Events.UnlessKeyed
module Html.Events.UnlessKeyed exposing (onClick)
{-|
@docs onClick
-}
import Html
import Html.Events
import Json.Decode as Decode
{-| Triggers on click unless any modifier key is held.
Modifier keys: Alt, Ctrl, Meta or Shift.
Html.a
[ UnlessKeyed.onClick VisitElm
, Html.Attributes.href "https://elm-lang.org"
]
[ Html.text "Visit Elm!" ]
-}
onClick : msg -> Html.Attribute msg
onClick msg =
unlessKeyed ( msg, True )
|> Html.Events.preventDefaultOn "click"
--- DECODERS
unlessKeyed : v -> Decode.Decoder v
unlessKeyed val =
decodeAnyKeyPressed
|> Decode.andThen
(\anyKeyPressed ->
if anyKeyPressed then
Decode.fail "Key pressed"
else
Decode.succeed val
)
decodeAnyKeyPressed : Decode.Decoder Bool
decodeAnyKeyPressed =
Decode.oneOf
[ Decode.field "altKey" decodeTrue
, Decode.field "ctrlKey" decodeTrue
, Decode.field "metaKey" decodeTrue
, Decode.field "shiftKey" decodeTrue
, Decode.succeed False
]
decodeTrue : Decode.Decoder Bool
decodeTrue =
Decode.bool
|> Decode.andThen
(\bool ->
if bool then
Decode.succeed True
else
Decode.fail "Key pressed"
)
@sparksp
Copy link
Author

sparksp commented May 21, 2020

Alternative version from @pd-andy on Slack.

module Html.Events.UnlessKeyed exposing (onClick)

{-|

@docs onClick

-}

import Html
import Html.Events
import Json.Decode as Decode


{-| Triggers on click unless any modifier key is held.

Modifier keys: Alt, Ctrl, Meta or Shift.

    Html.a
        [ UnlessKeyed.onClick VisitElm
        , Html.Attributes.href "https://elm-lang.org/"
        ]
        [ Html.text "Visit Elm!" ]

-}
onClick : msg -> Html.Attribute msg
onClick msg =
    decodeClick ( msg, True )
        |> Html.Events.preventDefaultOn "click"



--- DECODERS


type alias Modifiers =
    { alt : Bool
    , ctrl : Bool
    , meta : Bool
    , shift : Bool
    }


anyPressed : Modifiers -> Bool
anyPressed { alt, ctrl, meta, shift } =
    alt || ctrl || meta || shift


decodeModifiers : Decode.Decoder Modifiers
decodeModifiers =
    Decode.map4 Modifiers
        (Decode.field "altKey" Decode.bool)
        (Decode.field "ctrlKey" Decode.bool)
        (Decode.field "metaKey" Decode.bool)
        (Decode.field "shiftKey" Decode.bool)


decodeClick : v -> Decode.Decoder v
decodeClick val =
    decodeModifiers
        |> Decode.andThen
            (\modifiers ->
                if anyPressed modifiers then
                    Decode.fail "A modifier is key pressed"

                else
                    Decode.succeed val
            )

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment