1
0
mirror of https://github.com/jhillyerd/inbucket.git synced 2025-12-18 10:07:02 +00:00

ui: Allow keyboard navigation of message list

This commit is contained in:
James Hillyerd
2019-02-17 12:59:05 -08:00
parent 34799b9a04
commit b2255fefab

View File

@@ -22,11 +22,11 @@ import Html.Attributes
, type_ , type_
, value , value
) )
import Html.Events exposing (..) import Html.Events as Events
import Http exposing (Error) import Http exposing (Error)
import HttpUtil import HttpUtil
import Json.Decode as Decode exposing (Decoder) import Json.Decode as D
import Json.Encode as Encode import Json.Encode as E
import Ports import Ports
import Route import Route
import Task import Task
@@ -136,6 +136,7 @@ subscriptions model =
type Msg type Msg
= ListLoaded (Result HttpUtil.Error (List MessageHeader)) = ListLoaded (Result HttpUtil.Error (List MessageHeader))
| ClickMessage MessageID | ClickMessage MessageID
| ListKeyPress String Int
| OpenMessage MessageID | OpenMessage MessageID
| CloseMessage | CloseMessage
| MessageLoaded (Result HttpUtil.Error Message) | MessageLoaded (Result HttpUtil.Error Message)
@@ -166,7 +167,7 @@ update msg model =
) )
OpenMessage id -> OpenMessage id ->
updateOpenMessage model.session model id updateOpenMessage model id
CloseMessage -> CloseMessage ->
case model.state of case model.state of
@@ -187,6 +188,14 @@ update msg model =
, Cmd.none , Cmd.none
) )
ListKeyPress id keyCode ->
case keyCode of
13 ->
updateOpenMessage model id
_ ->
( model, Cmd.none )
ListLoaded (Ok headers) -> ListLoaded (Ok headers) ->
case model.state of case model.state of
LoadingList selection -> LoadingList selection ->
@@ -198,7 +207,7 @@ update msg model =
in in
case selection of case selection of
Just id -> Just id ->
updateOpenMessage model.session newModel id updateOpenMessage newModel id
Nothing -> Nothing ->
( { newModel ( { newModel
@@ -459,8 +468,8 @@ updateMarkMessageSeen model message =
( model, Cmd.none ) ( model, Cmd.none )
updateOpenMessage : Session -> Model -> String -> ( Model, Cmd Msg ) updateOpenMessage : Model -> String -> ( Model, Cmd Msg )
updateOpenMessage session model id = updateOpenMessage model id =
let let
newModel = newModel =
{ model | session = Session.addRecent model.mailboxName model.session } { model | session = Session.addRecent model.mailboxName model.session }
@@ -493,12 +502,12 @@ view model =
[ input [ input
[ type_ "search" [ type_ "search"
, placeholder "search" , placeholder "search"
, onInput OnSearchInput , Events.onInput OnSearchInput
, value model.searchInput , value model.searchInput
] ]
[] []
, button , button
[ onClick PurgeMailboxPrompt [ Events.onClick PurgeMailboxPrompt
, alt "Purge Mailbox" , alt "Purge Mailbox"
] ]
[ i [ class "fas fa-trash" ] [] ] [ i [ class "fas fa-trash" ] [] ]
@@ -534,8 +543,8 @@ viewModal promptPurge =
div [] div []
[ p [] [ text "Are you sure you want to delete all messages in this mailbox?" ] [ p [] [ text "Are you sure you want to delete all messages in this mailbox?" ]
, div [ class "button-bar" ] , div [ class "button-bar" ]
[ button [ onClick PurgeMailboxConfirmed, class "danger" ] [ text "Yes" ] [ button [ Events.onClick PurgeMailboxConfirmed, class "danger" ] [ text "Yes" ]
, button [ onClick PurgeMailboxCanceled ] [ text "Cancel" ] , button [ Events.onClick PurgeMailboxCanceled ] [ text "Cancel" ]
] ]
] ]
@@ -560,12 +569,14 @@ viewMessageList session model =
messageChip : Model -> Maybe MessageID -> MessageHeader -> Html Msg messageChip : Model -> Maybe MessageID -> MessageHeader -> Html Msg
messageChip model selected message = messageChip model selected message =
div div
[ classList [ class "message-list-entry"
[ ( "message-list-entry", True ) , classList
, ( "selected", selected == Just message.id ) [ ( "selected", selected == Just message.id )
, ( "unseen", not message.seen ) , ( "unseen", not message.seen )
] ]
, onClick (ClickMessage message.id) , Events.onClick (ClickMessage message.id)
, onKeyUp (ListKeyPress message.id)
, tabindex 0
] ]
[ div [ class "subject" ] [ text message.subject ] [ div [ class "subject" ] [ text message.subject ]
, div [ class "from" ] [ text message.from ] , div [ class "from" ] [ text message.from ]
@@ -592,9 +603,9 @@ viewMessage zone message bodyMode =
in in
div [] div []
[ div [ class "button-bar" ] [ div [ class "button-bar" ]
[ button [ class "message-close light", onClick CloseMessage ] [ button [ class "message-close light", Events.onClick CloseMessage ]
[ i [ class "fas fa-arrow-left" ] [] ] [ i [ class "fas fa-arrow-left" ] [] ]
, button [ class "danger", onClick (DeleteMessage message) ] [ text "Delete" ] , button [ class "danger", Events.onClick (DeleteMessage message) ] [ text "Delete" ]
, a [ href sourceUrl, target "_blank" ] , a [ href sourceUrl, target "_blank" ]
[ button [ tabindex -1 ] [ text "Source" ] ] [ button [ tabindex -1 ] [ text "Source" ] ]
, htmlButton , htmlButton
@@ -643,7 +654,7 @@ messageBody message bodyMode =
bodyModeTab mode label = bodyModeTab mode label =
a a
[ classList [ ( "active", bodyMode == mode ) ] [ classList [ ( "active", bodyMode == mode ) ]
, onClick (MessageBody mode) , Events.onClick (MessageBody mode)
, href "#" , href "#"
] ]
[ text label ] [ text label ]
@@ -666,10 +677,10 @@ messageBody message bodyMode =
, article [ class "message-body" ] , article [ class "message-body" ]
[ case bodyMode of [ case bodyMode of
SafeHtmlBody -> SafeHtmlBody ->
Html.node "rendered-html" [ property "content" (Encode.string message.html) ] [] Html.node "rendered-html" [ property "content" (E.string message.html) ] []
TextBody -> TextBody ->
Html.node "rendered-html" [ property "content" (Encode.string message.text) ] [] Html.node "rendered-html" [ property "content" (E.string message.text) ] []
] ]
] ]
@@ -749,3 +760,8 @@ filterMessageList list =
|| String.contains list.searchFilter (String.toLower header.from) || String.contains list.searchFilter (String.toLower header.from)
in in
List.filter matches list.headers List.filter matches list.headers
onKeyUp : (Int -> msg) -> Attribute msg
onKeyUp tagger =
Events.on "keyup" (D.map tagger Events.keyCode)