Created
December 2, 2016 17:22
-
-
Save msp/35feb34377a4263ada63d89622a78193 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module AC.AccessibleExample exposing (..) | |
import Autocomplete | |
import Html exposing (..) | |
import Html.Attributes exposing (..) | |
import Html.Events exposing (..) | |
import String | |
import Json.Decode as Decode exposing (field) | |
import Json.Encode as Encode | |
import Dom | |
import Task | |
import Http | |
import Streams.Ports exposing (..) | |
-- | |
-- main = | |
-- Html.program | |
-- { init = init ! [] | |
-- , update = update | |
-- , view = view | |
-- , subscriptions = subscriptions | |
-- } | |
subscriptions : Model -> Sub Msg | |
subscriptions model = | |
Sub.map SetAutoState Autocomplete.subscription | |
type alias Model = | |
{ people : List Person | |
, autoState : Autocomplete.State | |
, howManyToShow : Int | |
, query : String | |
, selectedPerson : Maybe Person | |
, showMenu : Bool | |
} | |
init : Model | |
init = | |
{ people = presidents | |
, autoState = Autocomplete.empty | |
, howManyToShow = 5 | |
, query = "" | |
, selectedPerson = Nothing | |
, showMenu = False | |
} | |
type Msg | |
= SetQuery String | |
| SetAutoState Autocomplete.Msg | |
| Wrap Bool | |
| Reset | |
| HandleEscape | |
| SelectPersonKeyboard String | |
| SelectPersonMouse String | |
| PreviewPerson String | |
| OnFocus | |
| NoOp | |
| OnListResources (Result Http.Error (List Person)) | |
| NewGif (Result Http.Error String) | |
| MorePlease | |
update : Msg -> Model -> ( Model, Cmd Msg ) | |
update msg model = | |
case Debug.log "******* AC update *******" msg of | |
MorePlease -> | |
( model, getRandomGif "foobar" ) | |
SetQuery newQuery -> | |
( { model | query = newQuery, selectedPerson = Nothing }, getRandomGif "foo" ) | |
SetAutoState autoMsg -> | |
let | |
( newState, maybeMsg ) = | |
Autocomplete.update updateConfig autoMsg model.howManyToShow model.autoState (acceptablePeople model.query model.people) | |
newModel = | |
{ model | autoState = newState } | |
in | |
case maybeMsg of | |
Nothing -> | |
newModel ! [] | |
Just updateMsg -> | |
update updateMsg newModel | |
HandleEscape -> | |
let | |
validOptions = | |
not <| List.isEmpty (acceptablePeople model.query model.people) | |
handleEscape = | |
if validOptions then | |
model | |
|> removeSelection | |
|> resetMenu | |
else | |
{ model | query = "" } | |
|> removeSelection | |
|> resetMenu | |
escapedModel = | |
case model.selectedPerson of | |
Just person -> | |
if model.query == person.name then | |
model | |
|> resetInput | |
else | |
handleEscape | |
Nothing -> | |
handleEscape | |
in | |
escapedModel ! [] | |
Wrap toTop -> | |
case model.selectedPerson of | |
Just person -> | |
update Reset model | |
Nothing -> | |
if toTop then | |
{ model | |
| autoState = Autocomplete.resetToLastItem updateConfig (acceptablePeople model.query model.people) model.howManyToShow model.autoState | |
, selectedPerson = List.head <| List.reverse <| List.take model.howManyToShow <| (acceptablePeople model.query model.people) | |
} | |
! [] | |
else | |
{ model | |
| autoState = Autocomplete.resetToFirstItem updateConfig (acceptablePeople model.query model.people) model.howManyToShow model.autoState | |
, selectedPerson = List.head <| List.take model.howManyToShow <| (acceptablePeople model.query model.people) | |
} | |
! [] | |
Reset -> | |
{ model | autoState = Autocomplete.reset updateConfig model.autoState, selectedPerson = Nothing } ! [] | |
SelectPersonKeyboard id -> | |
let | |
newModel = | |
setQuery model id | |
|> resetMenu | |
in | |
newModel ! [] | |
SelectPersonMouse id -> | |
let | |
newModel = | |
setQuery model id | |
|> resetMenu | |
in | |
( newModel, Task.attempt (\_ -> NoOp) (Dom.focus "president-input") ) | |
PreviewPerson id -> | |
{ model | selectedPerson = Just <| getPersonAtId model.people id } ! [] | |
OnFocus -> | |
model ! [] | |
NoOp -> | |
model ! [] | |
OnListResources (Ok newResources) -> | |
let | |
showMenu = | |
not << List.isEmpty <| newResources | |
in | |
-- { model | query = newQuery, selectedPerson = Nothing } cmd | |
( { model | people = newResources, showMenu = showMenu }, Cmd.none ) | |
OnListResources (Err error) -> | |
parseHttpError model error | |
NewGif (Ok newUrl) -> | |
Debug.log "NewGif! OK" | |
( model, Cmd.none ) | |
NewGif (Err _) -> | |
Debug.log "NewGif! ERRRRRRRRRRRR" | |
( model, Cmd.none ) | |
parseHttpError : Model -> Http.Error -> ( Model, Cmd Msg ) | |
parseHttpError model error = | |
case error of | |
Http.NetworkError -> | |
( model, sendAlertToJs "Http.NetworkError" ) | |
Http.Timeout -> | |
( model, sendAlertToJs "Http.Timeout" ) | |
Http.BadUrl error -> | |
( model, sendAlertToJs "Http.BadUrl" ) | |
Http.BadStatus error -> | |
( model, sendAlertToJs ("Http.BadStatus, error: " ++ toString error) ) | |
Http.BadPayload code error -> | |
( model, sendAlertToJs ("Http.BadPayload, code: " ++ code ++ "error: " ++ toString error) ) | |
resetInput model = | |
{ model | query = "" } | |
|> removeSelection | |
|> resetMenu | |
removeSelection model = | |
{ model | selectedPerson = Nothing } | |
getPersonAtId people id = | |
List.filter (\person -> person.name == id) people | |
|> List.head | |
|> Maybe.withDefault (Person "" 0 "" "") | |
setQuery model id = | |
{ model | |
| query = .name <| getPersonAtId model.people id | |
, selectedPerson = Just <| getPersonAtId model.people id | |
} | |
resetMenu model = | |
{ model | |
| autoState = Autocomplete.empty | |
, showMenu = False | |
} | |
view : Model -> Html Msg | |
view model = | |
let | |
options = | |
{ preventDefault = True, stopPropagation = False } | |
dec = | |
(Decode.map | |
(\code -> | |
if code == 38 || code == 40 then | |
Ok NoOp | |
else if code == 27 then | |
Ok HandleEscape | |
else | |
Err "not handling that key" | |
) | |
keyCode | |
) | |
|> Decode.andThen | |
fromResult | |
fromResult : Result String a -> Decode.Decoder a | |
fromResult result = | |
case result of | |
Ok val -> | |
Decode.succeed val | |
Err reason -> | |
Decode.fail reason | |
menu = | |
if model.showMenu then | |
[ viewMenu model ] | |
else | |
[] | |
query = | |
case model.selectedPerson of | |
Just person -> | |
person.name | |
Nothing -> | |
model.query | |
activeDescendant attributes = | |
case model.selectedPerson of | |
Just person -> | |
(attribute "aria-activedescendant" | |
person.name | |
) | |
:: attributes | |
Nothing -> | |
attributes | |
in | |
button [ class "", onClick (MorePlease) ] [ text "TEST ME" ] | |
-- div [] | |
-- (List.append | |
-- [ input | |
-- (activeDescendant | |
-- [ onInput SetQuery | |
-- , onFocus OnFocus | |
-- , onWithOptions "keydown" options dec | |
-- , value query | |
-- , id "president-input" | |
-- , class "autocomplete-input" | |
-- , autocomplete False | |
-- , attribute "aria-owns" "list-of-presidents" | |
-- , attribute "aria-expanded" <| String.toLower <| toString model.showMenu | |
-- , attribute "aria-haspopup" <| String.toLower <| toString model.showMenu | |
-- , attribute "role" "combobox" | |
-- , attribute "aria-autocomplete" "list" | |
-- ] | |
-- ) | |
-- [] | |
-- , button [ class "", onClick (MorePlease) ] [ text "TEST ME" ] | |
-- ] | |
-- menu | |
-- ) | |
viewMenu : Model -> Html Msg | |
viewMenu model = | |
div [ class "autocomplete-menu" ] | |
[ Html.map SetAutoState (Autocomplete.view viewConfig model.howManyToShow model.autoState (acceptablePeople model.query model.people)) ] | |
updateConfig : Autocomplete.UpdateConfig Msg Person | |
updateConfig = | |
Autocomplete.updateConfig | |
{ toId = .name | |
, onKeyDown = | |
\code maybeId -> | |
if code == 38 || code == 40 then | |
Maybe.map PreviewPerson maybeId | |
else if code == 13 then | |
Maybe.map SelectPersonKeyboard maybeId | |
else | |
Just <| Reset | |
, onTooLow = Just <| Wrap False | |
, onTooHigh = Just <| Wrap True | |
, onMouseEnter = \id -> Just <| PreviewPerson id | |
, onMouseLeave = \_ -> Nothing | |
, onMouseClick = \id -> Just <| SelectPersonMouse id | |
, separateSelections = False | |
} | |
viewConfig : Autocomplete.ViewConfig Person | |
viewConfig = | |
let | |
customizedLi keySelected mouseSelected person = | |
{ attributes = | |
[ classList [ ( "autocomplete-item", True ), ( "key-selected", keySelected || mouseSelected ) ] | |
, id person.name | |
] | |
, children = [ Html.text person.name ] | |
} | |
in | |
Autocomplete.viewConfig | |
{ toId = .name | |
, ul = [ class "autocomplete-list" ] | |
, li = customizedLi | |
} | |
-- PEOPLE | |
type alias Person = | |
{ name : String | |
, year : Int | |
, city : String | |
, state : String | |
} | |
acceptablePeople : String -> List Person -> List Person | |
acceptablePeople query people = | |
let | |
lowerQuery = | |
String.toLower query | |
in | |
List.filter (String.contains lowerQuery << String.toLower << .name) people | |
queryDBPediaCommands : String -> List (Cmd Msg) | |
queryDBPediaCommands query = | |
let | |
cmdForDBPedia = | |
queryDBPedia query | |
in | |
[ cmdForDBPedia ] | |
getRandomGif : String -> Cmd Msg | |
getRandomGif topic = | |
let | |
url = | |
"https://api.giphy.com/v1/gifs/random?api_key=dc6zaTOxFJmzC&tag=" ++ topic | |
in | |
Debug.log "SENDING! GIFFY" | |
Http.send | |
NewGif | |
(Http.get url decodeGifUrl) | |
decodeGifUrl : Decode.Decoder String | |
decodeGifUrl = | |
Debug.log "Decoding! GIFFY" | |
Decode.at | |
[ "data", "image_url" ] | |
Decode.string | |
queryDBPedia : String -> Cmd Msg | |
queryDBPedia query = | |
Http.get | |
("http://lookup.dbpedia.org/api/search/PrefixSearch?QueryClass=&MaxHits=5&QueryString=foo") | |
resultsDecoder | |
|> Http.send OnListResources | |
queryDBPediaRequest : String -> Http.Request (List Person) | |
queryDBPediaRequest query = | |
Debug.log "YES ITS DOING IT" | |
Http.get | |
("http://lookup.dbpedia.org/api/search/PrefixSearch?QueryClass=&MaxHits=5&QueryString=" ++ query) | |
resultsDecoder | |
presidents : List Person | |
presidents = | |
[ Person "Barack Obama" 1961 "Honolulu" "Hawaii" | |
] | |
resultsDecoder : Decode.Decoder (List Person) | |
resultsDecoder = | |
let | |
decoder = | |
Decode.list resourceDecoder | |
in | |
Decode.at [ "results" ] decoder | |
resourceDecoder : Decode.Decoder Person | |
resourceDecoder = | |
Decode.map4 | |
Person | |
(field "label" Decode.string) | |
(field "refCount" Decode.int) | |
(field "uri" Decode.string) | |
(field "description" Decode.string) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment