Navigate items using keyboard

- previous/next item with `.,`
- confirm with `c`
- unconfirm with `u`
This commit is contained in:
Eike Kettner
2020-09-22 00:27:32 +02:00
parent dc0e05bc20
commit 60b8dc2134
10 changed files with 107 additions and 41 deletions

View File

@ -195,7 +195,7 @@ updateItemDetail lmsg model =
Page.ItemDetail.Update.update Page.ItemDetail.Update.update
model.key model.key
model.flags model.flags
inav.next inav
model.uiSettings model.uiSettings
lmsg lmsg
model.itemDetailModel model.itemDetailModel

View File

@ -10,6 +10,7 @@ import Comp.ItemDetail.Model exposing (Msg(..))
import Comp.ItemDetail.Update import Comp.ItemDetail.Update
import Comp.ItemDetail.View exposing (..) import Comp.ItemDetail.View exposing (..)
import Data.Flags exposing (Flags) import Data.Flags exposing (Flags)
import Data.ItemNav exposing (ItemNav)
import Data.UiSettings exposing (UiSettings) import Data.UiSettings exposing (UiSettings)
import Html exposing (..) import Html exposing (..)
import Page exposing (Page(..)) import Page exposing (Page(..))
@ -24,11 +25,11 @@ emptyModel =
Comp.ItemDetail.Model.emptyModel Comp.ItemDetail.Model.emptyModel
update : Nav.Key -> Flags -> Maybe String -> UiSettings -> Msg -> Model -> ( Model, Cmd Msg, Sub Msg ) update : Nav.Key -> Flags -> ItemNav -> UiSettings -> Msg -> Model -> ( Model, Cmd Msg, Sub Msg )
update = update =
Comp.ItemDetail.Update.update Comp.ItemDetail.Update.update
view : { prev : Maybe String, next : Maybe String } -> UiSettings -> Model -> Html Msg view : ItemNav -> UiSettings -> Model -> Html Msg
view = view =
Comp.ItemDetail.View.view Comp.ItemDetail.View.view

View File

@ -40,6 +40,7 @@ import Http
import Page exposing (Page(..)) import Page exposing (Page(..))
import Set exposing (Set) import Set exposing (Set)
import Throttle exposing (Throttle) import Throttle exposing (Throttle)
import Util.Html exposing (KeyCode)
import Util.Tag import Util.Tag
@ -265,6 +266,7 @@ type Msg
| ResetHiddenMsg Field (Result Http.Error BasicResult) | ResetHiddenMsg Field (Result Http.Error BasicResult)
| SaveNameResp (Result Http.Error BasicResult) | SaveNameResp (Result Http.Error BasicResult)
| UpdateThrottle | UpdateThrottle
| KeyPress (Maybe KeyCode)
type SaveNameState type SaveNameState

View File

@ -36,6 +36,7 @@ import Comp.YesNoDimmer
import Data.Direction exposing (Direction) import Data.Direction exposing (Direction)
import Data.Fields exposing (Field) import Data.Fields exposing (Field)
import Data.Flags exposing (Flags) import Data.Flags exposing (Flags)
import Data.ItemNav exposing (ItemNav)
import Data.UiSettings exposing (UiSettings) import Data.UiSettings exposing (UiSettings)
import DatePicker import DatePicker
import Dict import Dict
@ -50,14 +51,15 @@ import Throttle
import Time import Time
import Util.File exposing (makeFileId) import Util.File exposing (makeFileId)
import Util.Folder exposing (mkFolderOption) import Util.Folder exposing (mkFolderOption)
import Util.Html exposing (KeyCode(..))
import Util.Http import Util.Http
import Util.List import Util.List
import Util.Maybe import Util.Maybe
import Util.String import Util.String
update : Nav.Key -> Flags -> Maybe String -> UiSettings -> Msg -> Model -> ( Model, Cmd Msg, Sub Msg ) update : Nav.Key -> Flags -> ItemNav -> UiSettings -> Msg -> Model -> ( Model, Cmd Msg, Sub Msg )
update key flags next settings msg model = update key flags inav settings msg model =
case msg of case msg of
Init -> Init ->
let let
@ -83,7 +85,7 @@ update key flags next settings msg model =
( m1, c1, s1 ) = ( m1, c1, s1 ) =
update key update key
flags flags
next inav
settings settings
(TagDropdownMsg (Comp.Dropdown.SetSelection item.tags)) (TagDropdownMsg (Comp.Dropdown.SetSelection item.tags))
model model
@ -91,7 +93,7 @@ update key flags next settings msg model =
( m2, c2, s2 ) = ( m2, c2, s2 ) =
update key update key
flags flags
next inav
settings settings
(DirDropdownMsg (DirDropdownMsg
(Comp.Dropdown.SetSelection (Comp.Dropdown.SetSelection
@ -106,7 +108,7 @@ update key flags next settings msg model =
( m3, c3, s3 ) = ( m3, c3, s3 ) =
update key update key
flags flags
next inav
settings settings
(OrgDropdownMsg (OrgDropdownMsg
(Comp.Dropdown.SetSelection (Comp.Dropdown.SetSelection
@ -121,7 +123,7 @@ update key flags next settings msg model =
( m4, c4, s4 ) = ( m4, c4, s4 ) =
update key update key
flags flags
next inav
settings settings
(CorrPersonMsg (CorrPersonMsg
(Comp.Dropdown.SetSelection (Comp.Dropdown.SetSelection
@ -136,7 +138,7 @@ update key flags next settings msg model =
( m5, c5, s5 ) = ( m5, c5, s5 ) =
update key update key
flags flags
next inav
settings settings
(ConcPersonMsg (ConcPersonMsg
(Comp.Dropdown.SetSelection (Comp.Dropdown.SetSelection
@ -151,7 +153,7 @@ update key flags next settings msg model =
( m6, c6, s6 ) = ( m6, c6, s6 ) =
update key update key
flags flags
next inav
settings settings
(ConcEquipMsg (ConcEquipMsg
(Comp.Dropdown.SetSelection (Comp.Dropdown.SetSelection
@ -164,12 +166,12 @@ update key flags next settings msg model =
m5 m5
( m7, c7, s7 ) = ( m7, c7, s7 ) =
update key flags next settings AddFilesReset m6 update key flags inav settings AddFilesReset m6
( m8, c8, s8 ) = ( m8, c8, s8 ) =
update key update key
flags flags
next inav
settings settings
(FolderDropdownMsg (FolderDropdownMsg
(Comp.Dropdown.SetSelection (Comp.Dropdown.SetSelection
@ -498,7 +500,7 @@ update key flags next settings msg model =
noSub ( { model | deleteItemConfirm = cm }, cmd ) noSub ( { model | deleteItemConfirm = cm }, cmd )
RequestDelete -> RequestDelete ->
update key flags next settings (DeleteItemConfirm Comp.YesNoDimmer.activate) model update key flags inav settings (DeleteItemConfirm Comp.YesNoDimmer.activate) model
SetCorrOrgSuggestion idname -> SetCorrOrgSuggestion idname ->
noSub ( model, setCorrOrg flags model (Just idname) ) noSub ( model, setCorrOrg flags model (Just idname) )
@ -537,7 +539,7 @@ update key flags next settings msg model =
|> List.map mkIdName |> List.map mkIdName
|> Comp.Dropdown.SetOptions |> Comp.Dropdown.SetOptions
in in
update key flags next settings (FolderDropdownMsg opts) model_ update key flags inav settings (FolderDropdownMsg opts) model_
GetFolderResp (Err _) -> GetFolderResp (Err _) ->
noSub ( model, Cmd.none ) noSub ( model, Cmd.none )
@ -548,7 +550,7 @@ update key flags next settings msg model =
Comp.Dropdown.SetOptions tags.items Comp.Dropdown.SetOptions tags.items
( m1, c1, s1 ) = ( m1, c1, s1 ) =
update key flags next settings (TagDropdownMsg tagList) model update key flags inav settings (TagDropdownMsg tagList) model
in in
( m1, c1, s1 ) ( m1, c1, s1 )
@ -560,7 +562,7 @@ update key flags next settings msg model =
opts = opts =
Comp.Dropdown.SetOptions orgs.items Comp.Dropdown.SetOptions orgs.items
in in
update key flags next settings (OrgDropdownMsg opts) model update key flags inav settings (OrgDropdownMsg opts) model
GetOrgResp (Err _) -> GetOrgResp (Err _) ->
noSub ( model, Cmd.none ) noSub ( model, Cmd.none )
@ -571,10 +573,10 @@ update key flags next settings msg model =
Comp.Dropdown.SetOptions ps.items Comp.Dropdown.SetOptions ps.items
( m1, c1, s1 ) = ( m1, c1, s1 ) =
update key flags next settings (CorrPersonMsg opts) model update key flags inav settings (CorrPersonMsg opts) model
( m2, c2, s2 ) = ( m2, c2, s2 ) =
update key flags next settings (ConcPersonMsg opts) m1 update key flags inav settings (ConcPersonMsg opts) m1
in in
( m2, Cmd.batch [ c1, c2 ], Sub.batch [ s1, s2 ] ) ( m2, Cmd.batch [ c1, c2 ], Sub.batch [ s1, s2 ] )
@ -589,7 +591,7 @@ update key flags next settings msg model =
equips.items equips.items
) )
in in
update key flags next settings (ConcEquipMsg opts) model update key flags inav settings (ConcEquipMsg opts) model
GetEquipResp (Err _) -> GetEquipResp (Err _) ->
noSub ( model, Cmd.none ) noSub ( model, Cmd.none )
@ -625,7 +627,7 @@ update key flags next settings msg model =
DeleteResp (Ok res) -> DeleteResp (Ok res) ->
if res.success then if res.success then
case next of case inav.next of
Just id -> Just id ->
noSub ( model, Page.set key (ItemDetailPage id) ) noSub ( model, Page.set key (ItemDetailPage id) )
@ -639,7 +641,7 @@ update key flags next settings msg model =
noSub ( model, Cmd.none ) noSub ( model, Cmd.none )
GetItemResp (Ok item) -> GetItemResp (Ok item) ->
update key flags next settings (SetItem item) model update key flags inav settings (SetItem item) model
GetItemResp (Err _) -> GetItemResp (Err _) ->
noSub ( model, Cmd.none ) noSub ( model, Cmd.none )
@ -834,7 +836,7 @@ update key flags next settings msg model =
DeleteAttachResp (Ok res) -> DeleteAttachResp (Ok res) ->
if res.success then if res.success then
update key flags next settings ReloadItem model update key flags inav settings ReloadItem model
else else
noSub ( model, Cmd.none ) noSub ( model, Cmd.none )
@ -845,7 +847,7 @@ update key flags next settings msg model =
RequestDeleteAttachment id -> RequestDeleteAttachment id ->
update key update key
flags flags
next inav
settings settings
(DeleteAttachConfirm id Comp.YesNoDimmer.activate) (DeleteAttachConfirm id Comp.YesNoDimmer.activate)
model model
@ -1228,6 +1230,41 @@ update key flags next settings msg model =
in in
withSub ( { model | nameSaveThrottle = newThrottle }, cmd ) withSub ( { model | nameSaveThrottle = newThrottle }, cmd )
KeyPress n ->
case n of
Just Letter_C ->
if model.item.state == "created" then
update key flags inav settings ConfirmItem model
else
noSub ( model, Cmd.none )
Just Letter_U ->
if model.item.state /= "created" then
update key flags inav settings UnconfirmItem model
else
noSub ( model, Cmd.none )
Just Point ->
case inav.next of
Just id ->
noSub ( model, Page.set key (ItemDetailPage id) )
Nothing ->
noSub ( model, Cmd.none )
Just Comma ->
case inav.prev of
Just id ->
noSub ( model, Page.set key (ItemDetailPage id) )
Nothing ->
noSub ( model, Cmd.none )
_ ->
noSub ( model, Cmd.none )
--- Helper --- Helper

View File

@ -14,6 +14,7 @@ import Comp.YesNoDimmer
import Data.Direction import Data.Direction
import Data.Fields import Data.Fields
import Data.Icons as Icons import Data.Icons as Icons
import Data.ItemNav exposing (ItemNav)
import Data.UiSettings exposing (UiSettings) import Data.UiSettings exposing (UiSettings)
import DatePicker import DatePicker
import Dict import Dict
@ -27,6 +28,7 @@ import Page exposing (Page(..))
import Set import Set
import Util.File exposing (makeFileId) import Util.File exposing (makeFileId)
import Util.Folder import Util.Folder
import Util.Html exposing (onKeyUpCode)
import Util.List import Util.List
import Util.Maybe import Util.Maybe
import Util.Size import Util.Size
@ -34,9 +36,11 @@ import Util.String
import Util.Time import Util.Time
view : { prev : Maybe String, next : Maybe String } -> UiSettings -> Model -> Html Msg view : ItemNav -> UiSettings -> Model -> Html Msg
view inav settings model = view inav settings model =
div [] div
[ onKeyUpCode KeyPress
]
[ renderItemInfo settings model [ renderItemInfo settings model
, renderDetailMenu inav model , renderDetailMenu inav model
, renderMailForm settings model , renderMailForm settings model
@ -87,7 +91,7 @@ view inav settings model =
--- Helper --- Helper
renderDetailMenu : { prev : Maybe String, next : Maybe String } -> Model -> Html Msg renderDetailMenu : ItemNav -> Model -> Html Msg
renderDetailMenu inav model = renderDetailMenu inav model =
div div
[ classList [ classList
@ -109,6 +113,7 @@ renderDetailMenu inav model =
, Maybe.map ItemDetailPage inav.prev , Maybe.map ItemDetailPage inav.prev
|> Maybe.map Page.href |> Maybe.map Page.href
|> Maybe.withDefault (href "#") |> Maybe.withDefault (href "#")
, title "Previous item. Key ','"
] ]
[ i [ class "caret square left outline icon" ] [] [ i [ class "caret square left outline icon" ] []
] ]
@ -120,6 +125,7 @@ renderDetailMenu inav model =
, Maybe.map ItemDetailPage inav.next , Maybe.map ItemDetailPage inav.next
|> Maybe.map Page.href |> Maybe.map Page.href
|> Maybe.withDefault (href "#") |> Maybe.withDefault (href "#")
, title "Next item. Key '.'"
] ]
[ i [ class "caret square right outline icon" ] [] [ i [ class "caret square right outline icon" ] []
] ]
@ -718,7 +724,7 @@ renderEditButtons model =
[ ( "borderless item", True ) [ ( "borderless item", True )
, ( "invisible", model.item.state /= "created" ) , ( "invisible", model.item.state /= "created" )
] ]
, title "Confirm metadata" , title "Confirm metadata. Key 'c'."
, href "#" , href "#"
, onClick ConfirmItem , onClick ConfirmItem
] ]
@ -730,7 +736,7 @@ renderEditButtons model =
, ( "invisible", model.item.state /= "confirmed" ) , ( "invisible", model.item.state /= "confirmed" )
] ]
, href "#" , href "#"
, title "Unconfirm metadata" , title "Unconfirm metadata. Key 'u'."
, onClick UnconfirmItem , onClick UnconfirmItem
] ]
[ i [ class "eye slash outline icon" ] [] [ i [ class "eye slash outline icon" ] []

View File

@ -0,0 +1,7 @@
module Data.ItemNav exposing (ItemNav)
type alias ItemNav =
{ prev : Maybe String
, next : Maybe String
}

View File

@ -18,6 +18,7 @@ import Comp.FixedDropdown
import Comp.ItemCardList import Comp.ItemCardList
import Comp.SearchMenu import Comp.SearchMenu
import Data.Flags exposing (Flags) import Data.Flags exposing (Flags)
import Data.ItemNav exposing (ItemNav)
import Data.Items import Data.Items
import Data.UiSettings exposing (UiSettings) import Data.UiSettings exposing (UiSettings)
import Http import Http
@ -119,7 +120,7 @@ searchTypeString st =
"Contents Only" "Contents Only"
itemNav : String -> Model -> { prev : Maybe String, next : Maybe String } itemNav : String -> Model -> ItemNav
itemNav id model = itemNav id model =
let let
prev = prev =

View File

@ -5,21 +5,22 @@ import Browser.Navigation as Nav
import Comp.ItemDetail import Comp.ItemDetail
import Comp.ItemDetail.Model import Comp.ItemDetail.Model
import Data.Flags exposing (Flags) import Data.Flags exposing (Flags)
import Data.ItemNav exposing (ItemNav)
import Data.UiSettings exposing (UiSettings) import Data.UiSettings exposing (UiSettings)
import Page.ItemDetail.Data exposing (Model, Msg(..)) import Page.ItemDetail.Data exposing (Model, Msg(..))
import Scroll import Scroll
import Task import Task
update : Nav.Key -> Flags -> Maybe String -> UiSettings -> Msg -> Model -> ( Model, Cmd Msg, Sub Msg ) update : Nav.Key -> Flags -> ItemNav -> UiSettings -> Msg -> Model -> ( Model, Cmd Msg, Sub Msg )
update key flags next settings msg model = update key flags inav settings msg model =
case msg of case msg of
Init id -> Init id ->
let let
( lm, lc, ls ) = ( lm, lc, ls ) =
Comp.ItemDetail.update key Comp.ItemDetail.update key
flags flags
next inav
settings settings
Comp.ItemDetail.Model.Init Comp.ItemDetail.Model.Init
model.detail model.detail
@ -39,7 +40,7 @@ update key flags next settings msg model =
ItemDetailMsg lmsg -> ItemDetailMsg lmsg ->
let let
( lm, lc, ls ) = ( lm, lc, ls ) =
Comp.ItemDetail.update key flags next settings lmsg model.detail Comp.ItemDetail.update key flags inav settings lmsg model.detail
in in
( { model | detail = lm } ( { model | detail = lm }
, Cmd.map ItemDetailMsg lc , Cmd.map ItemDetailMsg lc
@ -51,7 +52,7 @@ update key flags next settings msg model =
lmsg = lmsg =
Comp.ItemDetail.Model.SetItem item Comp.ItemDetail.Model.SetItem item
in in
update key flags next settings (ItemDetailMsg lmsg) model update key flags inav settings (ItemDetailMsg lmsg) model
ItemResp (Err _) -> ItemResp (Err _) ->
( model, Cmd.none, Sub.none ) ( model, Cmd.none, Sub.none )

View File

@ -1,18 +1,13 @@
module Page.ItemDetail.View exposing (view) module Page.ItemDetail.View exposing (view)
import Comp.ItemDetail import Comp.ItemDetail
import Data.ItemNav exposing (ItemNav)
import Data.UiSettings exposing (UiSettings) import Data.UiSettings exposing (UiSettings)
import Html exposing (..) import Html exposing (..)
import Html.Attributes exposing (..) import Html.Attributes exposing (..)
import Page.ItemDetail.Data exposing (Model, Msg(..)) import Page.ItemDetail.Data exposing (Model, Msg(..))
type alias ItemNav =
{ prev : Maybe String
, next : Maybe String
}
view : ItemNav -> UiSettings -> Model -> Html Msg view : ItemNav -> UiSettings -> Model -> Html Msg
view inav settings model = view inav settings model =
div [ class "ui fluid container item-detail-page" ] div [ class "ui fluid container item-detail-page" ]

View File

@ -46,12 +46,16 @@ type KeyCode
| Enter | Enter
| Space | Space
| ESC | ESC
| Letter_C
| Letter_N | Letter_N
| Letter_P | Letter_P
| Letter_H | Letter_H
| Letter_J | Letter_J
| Letter_K | Letter_K
| Letter_L | Letter_L
| Letter_U
| Point
| Comma
| Code Int | Code Int
@ -79,6 +83,9 @@ intToKeyCode code =
27 -> 27 ->
Just ESC Just ESC
67 ->
Just Letter_C
72 -> 72 ->
Just Letter_H Just Letter_H
@ -97,6 +104,15 @@ intToKeyCode code =
80 -> 80 ->
Just Letter_P Just Letter_P
85 ->
Just Letter_U
188 ->
Just Comma
190 ->
Just Point
n -> n ->
Just (Code n) Just (Code n)