summaryrefslogtreecommitdiff
path: root/elm/Lib/Autocomplete.elm
diff options
context:
space:
mode:
Diffstat (limited to 'elm/Lib/Autocomplete.elm')
-rw-r--r--elm/Lib/Autocomplete.elm157
1 files changed, 109 insertions, 48 deletions
diff --git a/elm/Lib/Autocomplete.elm b/elm/Lib/Autocomplete.elm
index 5c5dd33d..4c465d7c 100644
--- a/elm/Lib/Autocomplete.elm
+++ b/elm/Lib/Autocomplete.elm
@@ -12,8 +12,12 @@ module Lib.Autocomplete exposing
, staffSource
, charSource
, animeSource
+ , resolutionSource
+ , engineSource
+ , drmSource
, init
, clear
+ , refocus
, update
, view
)
@@ -40,6 +44,9 @@ import Gen.Producers as GP
import Gen.Staff as GS
import Gen.Chars as GC
import Gen.Anime as GA
+import Gen.Resolutions as GR
+import Gen.Engines as GE
+import Gen.DRM as GDRM
type alias Config m a =
@@ -55,6 +62,8 @@ type alias Config m a =
type SearchSource m a
-- API endpoint to query for completion results + Function to decode results from the API
= Endpoint (String -> (GApi.Response -> m) -> Cmd m) (GApi.Response -> Maybe (List a))
+ -- API endpoint that returns the full list of possible results + Function to decode results from the API + Function to match results against a query
+ | LazyList ((GApi.Response -> m) -> Cmd m) (GApi.Response -> Maybe (List a)) (String -> List a -> List a)
-- Pure function for instant completion results
| Func (String -> List a)
@@ -80,20 +89,20 @@ boardSource =
, view = (\i ->
[ text <| Maybe.withDefault "" (lookup i.btype boardTypes)
] ++ case i.title of
- Just title -> [ b [ class "grayedout" ] [ text " > " ], text title ]
+ Just title -> [ small [] [ text " > " ], text title ]
_ -> []
)
- , key = \i -> i.btype ++ String.fromInt i.iid
+ , key = \i -> Maybe.withDefault i.btype i.iid
}
-tagtraitStatus i =
- case (i.searchable, i.applicable, i.state) of
- (_, _, 0) -> b [ class "grayedout" ] [ text " (awaiting approval)" ]
- (_, _, 1) -> b [ class "grayedout" ] [ text " (deleted)" ] -- (not returned by the API for now)
- (False, False, _) -> b [ class "grayedout" ] [ text " (meta)" ]
- (True, False, _) -> b [ class "grayedout" ] [ text " (not applicable)" ]
- (False, True, _) -> b [ class "grayedout" ] [ text " (not searchable)" ]
+ttStatus i =
+ case ((i.hidden, i.locked), i.searchable, i.applicable) of
+ ((True, False), _, _ ) -> small [] [ text " (awaiting approval)" ]
+ ((True, True ), _, _ ) -> small [] [ text " (deleted)" ] -- (not returned by the API for now)
+ (_, False, False) -> small [] [ text " (meta)" ]
+ (_, True, False) -> small [] [ text " (not applicable)" ]
+ (_, False, True ) -> small [] [ text " (not searchable)" ]
_ -> text ""
@@ -103,8 +112,8 @@ tagSource =
<| \x -> case x of
GApi.TagResult e -> Just e
_ -> Nothing
- , view = \i -> [ text i.name, tagtraitStatus i ]
- , key = \i -> String.fromInt i.id
+ , view = \i -> [ text i.name, ttStatus i ]
+ , key = \i -> i.id
}
@@ -117,11 +126,11 @@ traitSource =
, view = \i ->
[ case i.group_name of
Nothing -> text ""
- Just g -> b [ class "grayedout" ] [ text <| g ++ " / " ]
+ Just g -> small [] [ text <| g ++ " / " ]
, text i.name
- , tagtraitStatus i
+ , ttStatus i
]
- , key = \i -> String.fromInt i.id
+ , key = \i -> i.id
}
@@ -132,34 +141,37 @@ vnSource =
GApi.VNResult e -> Just e
_ -> Nothing
, view = \i ->
- [ b [ class "grayedout" ] [ text <| "v" ++ String.fromInt i.id ++ ": " ]
+ [ small [] [ text <| i.id ++ ": " ]
, text i.title ]
- , key = \i -> String.fromInt i.id
+ , key = \i -> i.id
}
producerSource : SourceConfig m GApi.ApiProducerResult
producerSource =
- { source = Endpoint (\s -> GP.send { search = [s], hidden = False })
+ { source = Endpoint (\s -> GP.send { search = [s] })
<| \x -> case x of
GApi.ProducerResult e -> Just e
_ -> Nothing
, view = \i ->
- [ b [ class "grayedout" ] [ text <| "p" ++ String.fromInt i.id ++ ": " ]
+ [ small [] [ text <| i.id ++ ": " ]
, text i.name ]
- , key = \i -> String.fromInt i.id
+ , key = \i -> i.id
}
staffSource : SourceConfig m GApi.ApiStaffResult
staffSource =
- { source = Endpoint (\s -> GS.send { search = s })
+ { source = Endpoint (\s -> GS.send { search = [s] })
<| \x -> case x of
GApi.StaffResult e -> Just e
_ -> Nothing
, view = \i ->
- [ b [ class "grayedout" ] [ text <| "s" ++ String.fromInt i.id ++ ": " ]
- , text i.name ]
+ [ langIcon i.lang
+ , small [] [ text <| i.id ++ ": " ]
+ , text i.title
+ , if i.alttitle == i.title then text "" else small [] [ text " ", text i.alttitle ]
+ ]
, key = \i -> String.fromInt i.aid
}
@@ -171,33 +183,73 @@ charSource =
GApi.CharResult e -> Just e
_ -> Nothing
, view = \i ->
- [ b [ class "grayedout" ] [ text <| "c" ++ String.fromInt i.id ++ ": " ]
- , text i.name
+ [ small [] [ text <| i.id ++ ": " ]
+ , text i.title
, Maybe.withDefault (text "") <| Maybe.map (\m ->
- b [ class "grayedout" ] [ text <| " (instance of c" ++ String.fromInt m.id ++ ": " ++ m.name ]
+ small [] [ text <| " (instance of " ++ m.id ++ ": " ++ m.title ]
) i.main
]
- , key = \i -> String.fromInt i.id
+ , key = \i -> i.id
}
-animeSource : SourceConfig m GApi.ApiAnimeResult
-animeSource =
- { source = Endpoint (\s -> GA.send { search = s })
+animeSource : Bool -> SourceConfig m GApi.ApiAnimeResult
+animeSource ref =
+ { source = Endpoint (\s -> GA.send { search = s, ref = ref })
<| \x -> case x of
GApi.AnimeResult e -> Just e
_ -> Nothing
, view = \i ->
- [ b [ class "grayedout" ] [ text <| "a" ++ String.fromInt i.id ++ ": " ]
+ [ small [] [ text <| "a" ++ String.fromInt i.id ++ ": " ]
, text i.title ]
, key = \i -> String.fromInt i.id
}
+resolutionSource : SourceConfig m GApi.ApiResolutions
+resolutionSource =
+ { source = LazyList
+ (GR.send {})
+ (\x -> case x of
+ GApi.Resolutions e -> Just e
+ _ -> Nothing)
+ (\s l -> List.filter (\v -> String.contains (String.toLower s) (String.toLower v.resolution)) l |> List.take 10)
+ , view = \i -> [ text i.resolution, small [] [ text <| " (" ++ String.fromInt i.count ++ ")" ] ]
+ , key = \i -> i.resolution
+ }
+
+
+engineSource : SourceConfig m GApi.ApiEngines
+engineSource =
+ { source = LazyList
+ (GE.send {})
+ (\x -> case x of
+ GApi.Engines e -> Just e
+ _ -> Nothing)
+ (\s l -> List.filter (\v -> String.contains (String.toLower s) (String.toLower v.engine)) l |> List.take 10)
+ , view = \i -> [ text i.engine, small [] [ text <| " (" ++ String.fromInt i.count ++ ")" ] ]
+ , key = \i -> i.engine
+ }
+
+
+drmSource : SourceConfig m GApi.ApiDRM
+drmSource =
+ { source = LazyList
+ (GDRM.send {})
+ (\x -> case x of
+ GApi.DRM e -> Just e
+ _ -> Nothing)
+ (\s l -> List.filter (\v -> String.contains (String.toLower s) (String.toLower v.name)) l |> List.take 10)
+ , view = \i -> [ text i.name, small [] [ text <| " (" ++ String.fromInt i.count ++ ")" ] ]
+ , key = \i -> i.name
+ }
+
+
type alias Model a =
{ visible : Bool
, value : String
, results : List a
+ , all : Maybe (List a) -- Used by LazyList
, sel : String
, default : String
, loading : Bool
@@ -210,6 +262,7 @@ init s =
{ visible = False
, value = s
, results = []
+ , all = Nothing
, sel = ""
, default = s
, loading = False
@@ -252,26 +305,26 @@ select cfg offset model =
{ model | sel = Maybe.withDefault "" <| Maybe.map cfg.source.key <| get nextsel }
+-- Blur and focus the input on enter.
+refocus : Config m a -> Cmd m
+refocus cfg = Dom.blur cfg.id
+ |> Task.andThen (always (Dom.focus cfg.id))
+ |> Task.attempt (always (cfg.wrap Noop))
+
+
update : Config m a -> Msg a -> Model a -> (Model a, Cmd m, Maybe a)
update cfg msg model =
let
mod m = (m, Cmd.none, Nothing)
- -- Ugly hack: blur and focus the input on enter. This does two things:
- -- 1. If the user clicked on an entry (resulting in the 'Enter' message),
- -- then this will cause the input to be focussed again. This is
- -- convenient when adding multiple entries.
- refocus = Dom.blur cfg.id
- |> Task.andThen (always (Dom.focus cfg.id))
- |> Task.attempt (always (cfg.wrap Noop))
in
case msg of
Noop -> mod model
Blur -> mod { model | visible = False }
Focus -> mod { model | loading = False, visible = True }
Sel s -> mod { model | sel = s }
- Enter r -> (model, refocus, Just r)
+ Enter r -> (model, refocus cfg, Just r)
- Key "Enter" -> (model, refocus,
+ Key "Enter" -> (model, refocus cfg,
case List.filter (\i -> cfg.source.key i == model.sel) model.results |> List.head of
Just x -> Just x
Nothing -> List.head model.results)
@@ -280,26 +333,34 @@ update cfg msg model =
Key _ -> mod model
Input s ->
+ let m = { model | value = s, default = "" }
+ in
if String.trim s == ""
- then mod { model | value = s, default = "", loading = False, results = [] }
- else case cfg.source.source of
+ then mod { m | loading = False, results = [] }
+ else case (cfg.source.source) of
Endpoint _ _ ->
- ( { model | value = s, default = "", loading = True, wait = model.wait + 1 }
+ ( { m | loading = True, wait = model.wait + 1 }
, Task.perform (always <| cfg.wrap <| Search <| model.wait + 1) (Process.sleep 500)
, Nothing )
- Func f -> mod { model | value = s, default = "", results = f s }
+ LazyList e _ f ->
+ case (model.loading, model.all) of
+ (_, Just l) -> mod { m | results = f s l }
+ (True, _) -> mod m
+ (False, _) -> ({ m | loading = True }, e (cfg.wrap << Results ""), Nothing)
+ Func f -> mod { m | results = f s }
Search i ->
if model.value == "" || model.wait /= i
then mod model
else case cfg.source.source of
Endpoint e _ -> (model, e model.value (cfg.wrap << Results model.value), Nothing)
+ LazyList _ _ _ -> mod model
Func _ -> mod model
Results s r -> mod <|
- if s /= model.value then model -- Discard stale results
- else case cfg.source.source of
- Endpoint _ d -> { model | loading = False, results = d r |> Maybe.withDefault [] }
+ case cfg.source.source of
+ Endpoint _ d -> if s /= model.value then model else { model | loading = False, results = d r |> Maybe.withDefault [] }
+ LazyList _ d f -> let all = d r in { model | loading = False, all = all, results = Maybe.map (\l -> f model.value l) all |> Maybe.withDefault [] }
Func _ -> model
@@ -340,7 +401,7 @@ view cfg model attrs =
)
in div [ class "elm_dd", class "search", style "width" "300px" ]
- [ div [ classList [("hidden", not visible)] ] [ Keyed.node "ul" [] <| msg ++ List.map item model.results ]
- , input
+ [ div [ classList [("hidden", not visible)] ] [ div [] [ Keyed.node "ul" [] <| msg ++ List.map item model.results ] ]
+ , Html.form [] [ input ]
, span [ class "spinner", classList [("hidden", not model.loading)] ] []
]