Update a ton of things

This commit is contained in:
Richard Feldman
2016-06-24 17:40:54 -07:00
parent 908ca61c77
commit c8e9a117f5
56 changed files with 1023 additions and 1466 deletions

View File

@@ -1,187 +1,142 @@
module ElmHub (..) where
module ElmHub exposing (..)
import Html exposing (..)
import Html.Attributes exposing (class, target, href, property)
import Html.Attributes exposing (class, target, href, property, defaultValue)
import Html.Events exposing (..)
import Http
import Auth
import Task exposing (Task)
import Effects exposing (Effects)
import Json.Decode exposing (Decoder, (:=))
import Json.Decode exposing (Decoder)
import Json.Decode.Pipeline exposing (..)
import Json.Encode
import Signal exposing (Address)
searchFeed : Address String -> String -> Effects Action
searchFeed address query =
let
getQueryUrl : String -> String
getQueryUrl query =
-- See https://developer.github.com/v3/search/#example for how to customize!
url =
"https://api.github.com/search/repositories?access_token="
"https://api.github.com/search/repositories?access_token="
++ Auth.token
++ "&q="
++ query
++ "+language:elm&sort=stars&order=desc"
-- These only talk to JavaScript ports now. They never result in Actions
-- actually do any actions themselves.
task =
performAction
(\_ -> DoNothing)
(\_ -> DoNothing)
(Signal.send address query)
in
Effects.task task
responseDecoder : Decoder (List SearchResult)
responseDecoder =
"items" := Json.Decode.list searchResultDecoder
Json.Decode.at [ "items" ] (Json.Decode.list searchResultDecoder)
searchResultDecoder : Decoder SearchResult
searchResultDecoder =
decode SearchResult
|> required "id" Json.Decode.int
|> required "full_name" Json.Decode.string
|> required "stargazers_count" Json.Decode.int
{-| Note: this will be a standard function in the next release of Elm.
Example:
type Action =
HandleResponse String | HandleError Http.Error
performAction
(\responseString -> HandleResponse responseString)
(\httpError -> HandleError httpError)
(Http.getString "https://google.com?q=something")
-}
performAction : (a -> b) -> (y -> b) -> Task y a -> Task x b
performAction successToAction errorToAction task =
let
successTask =
Task.map successToAction task
in
Task.onError successTask (\err -> Task.succeed (errorToAction err))
decode SearchResult
|> required "id" Json.Decode.int
|> required "full_name" Json.Decode.string
|> required "stargazers_count" Json.Decode.int
type alias Model =
{ query : String
, results : List SearchResult
, errorMessage : Maybe String
}
{ query : String
, results : List SearchResult
, errorMessage : Maybe String
}
type alias SearchResult =
{ id : ResultId
, name : String
, stars : Int
}
{ id : ResultId
, name : String
, stars : Int
}
type alias ResultId =
Int
Int
initialModel : Model
initialModel =
{ query = "tutorial"
, results = []
, errorMessage = Nothing
}
{ query = "tutorial"
, results = []
, errorMessage = Nothing
}
view : Address Action -> Model -> Html
view address model =
div
[ class "content" ]
[ header
[]
[ h1 [] [ text "ElmHub" ]
, span [ class "tagline" ] [ text "Like GitHub, but for Elm things." ]
view : Model -> Html Msg
view model =
div [ class "content" ]
[ header []
[ h1 [] [ text "ElmHub" ]
, span [ class "tagline" ] [ text "Like GitHub, but for Elm things." ]
]
, input [ class "search-query", onInput SetQuery, defaultValue model.query ] []
, button [ class "search-button", onClick Search ] [ text "Search" ]
, viewErrorMessage model.errorMessage
, ul [ class "results" ] (List.map viewSearchResult model.results)
]
, input [ class "search-query", onInput address SetQuery, defaultValue model.query ] []
, button [ class "search-button", onClick address Search ] [ text "Search" ]
, viewErrorMessage model.errorMessage
, ul
[ class "results" ]
(List.map (viewSearchResult address) model.results)
]
viewErrorMessage : Maybe String -> Html
viewErrorMessage : Maybe String -> Html a
viewErrorMessage errorMessage =
case errorMessage of
Just message ->
div [ class "error" ] [ text message ]
case errorMessage of
Just message ->
div [ class "error" ] [ text message ]
Nothing ->
text ""
Nothing ->
text ""
onInput address wrap =
on "input" targetValue (\val -> Signal.message address (wrap val))
viewSearchResult : SearchResult -> Html Msg
viewSearchResult result =
li []
[ span [ class "star-count" ] [ text (toString result.stars) ]
, a [ href ("https://github.com/" ++ result.name), target "_blank" ]
[ text result.name ]
, button [ class "hide-result", onClick (DeleteById result.id) ]
[ text "X" ]
]
defaultValue str =
property "defaultValue" (Json.Encode.string str)
type Msg
= Search
| SetQuery String
| DeleteById ResultId
| SetResults (List SearchResult)
| SetErrorMessage (Maybe String)
| DoNothing
viewSearchResult : Address Action -> SearchResult -> Html
viewSearchResult address result =
li
[]
[ span [ class "star-count" ] [ text (toString result.stars) ]
, a
[ href ("https://github.com/" ++ result.name), target "_blank" ]
[ text result.name ]
, button
[ class "hide-result", onClick address (DeleteById result.id) ]
[ text "X" ]
]
update : (String -> Cmd Msg) -> Msg -> Model -> ( Model, Cmd Msg )
update searchFeed msg model =
case msg of
Search ->
( model, searchFeed (getQueryUrl model.query) )
SetQuery query ->
( { model | query = query }, Cmd.none )
SetResults results ->
( { model | results = results }, Cmd.none )
SetErrorMessage errorMessage ->
( { model | errorMessage = errorMessage }, Cmd.none )
DeleteById idToHide ->
let
newResults =
model.results
|> List.filter (\{ id } -> id /= idToHide)
newModel =
{ model | results = newResults }
in
( newModel, Cmd.none )
DoNothing ->
( model, Cmd.none )
type Action
= Search
| SetQuery String
| DeleteById ResultId
| SetResults (List SearchResult)
| SetErrorMessage (Maybe String)
| DoNothing
update : Address String -> Action -> Model -> ( Model, Effects Action )
update searchAddress action model =
case action of
Search ->
( model, searchFeed searchAddress model.query )
SetQuery query ->
( { model | query = query }, Effects.none )
SetResults results ->
( { model | results = results }, Effects.none )
SetErrorMessage errorMessage ->
( { model | errorMessage = errorMessage }, Effects.none )
DeleteById idToHide ->
let
newResults =
model.results
|> List.filter (\{ id } -> id /= idToHide)
newModel =
{ model | results = newResults }
in
( newModel, Effects.none )
DoNothing ->
( model, Effects.none )
decodeGithubResponse : Json.Encode.Value -> Msg
decodeGithubResponse value =
-- TODO use Json.Decode.DecodeValue to decode the response into an Action.
--
-- Hint: look at ElmHub.elm, specifically the definition of Action and
-- the deefinition of responseDecoder
SetErrorMessage (Just "TODO decode the response!")