Shift everything forward a partg
This commit is contained in:
@@ -1,23 +0,0 @@
|
|||||||
module Main exposing (..)
|
|
||||||
|
|
||||||
import Html exposing (..)
|
|
||||||
import Html.Attributes exposing (..)
|
|
||||||
|
|
||||||
|
|
||||||
elmHubHeader =
|
|
||||||
header []
|
|
||||||
[ -- TODO wrap the following text in an <h1>
|
|
||||||
text "ElmHub"
|
|
||||||
, span [ class "tagline" ]
|
|
||||||
[{- TODO put some text in here that says:
|
|
||||||
"Like GitHub, but for Elm things."
|
|
||||||
-}
|
|
||||||
]
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
main =
|
|
||||||
div [ class "content" ]
|
|
||||||
[ -- TODO put the header here
|
|
||||||
ul [ class "results" ] []
|
|
||||||
]
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
Part 1
|
|
||||||
======
|
|
||||||
|
|
||||||
The instructor will paste notes from the lesson, including code examples from
|
|
||||||
Q&A, in [this document](https://docs.google.com/document/d/1ApuSOk9DP0YsQrxhW7-WE8UOEAV4PPnLDDeqUOL2o5k/edit?usp=sharing).
|
|
||||||
|
|
||||||
## Installation
|
|
||||||
|
|
||||||
```bash
|
|
||||||
elm-package install
|
|
||||||
```
|
|
||||||
|
|
||||||
(Answer `y` when prompted.)
|
|
||||||
|
|
||||||
|
|
||||||
## Building
|
|
||||||
|
|
||||||
```bash
|
|
||||||
elm-live Main.elm --open --output=elm.js
|
|
||||||
```
|
|
||||||
|
|
||||||
## References
|
|
||||||
* [html-to-elm](http://mbylstra.github.io/html-to-elm/) - paste in HTML, get elm-html code
|
|
||||||
* [elm-html documentation](http://package.elm-lang.org/packages/elm-lang/html/latest)
|
|
||||||
* [record syntax](http://elm-lang.org/docs/syntax#records) (e.g. `{ foo = 1, bar = 2 }`)
|
|
||||||
@@ -4,35 +4,20 @@ import Html exposing (..)
|
|||||||
import Html.Attributes exposing (..)
|
import Html.Attributes exposing (..)
|
||||||
|
|
||||||
|
|
||||||
model =
|
|
||||||
{ result =
|
|
||||||
{ id = 1
|
|
||||||
, name = "TheSeamau5/elm-checkerboardgrid-tutorial"
|
|
||||||
, stars = 66
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
elmHubHeader =
|
elmHubHeader =
|
||||||
header []
|
header []
|
||||||
[ h1 [] [ text "ElmHub" ]
|
[ -- TODO wrap the following text in an <h1>
|
||||||
, span [ class "tagline" ] [ text "Like GitHub, but for Elm things." ]
|
text "ElmHub"
|
||||||
]
|
, span [ class "tagline" ]
|
||||||
|
[{- TODO put some text in here that says:
|
||||||
|
"Like GitHub, but for Elm things."
|
||||||
view model =
|
-}
|
||||||
div [ class "content" ]
|
|
||||||
[ elmHubHeader
|
|
||||||
, ul [ class "results" ]
|
|
||||||
[ li []
|
|
||||||
[ span [ class "star-count" ] [{- TODO display the number of stars -}]
|
|
||||||
-- TODO use the model to put a link here that points to
|
|
||||||
-- https://github.com/TheSeamau5/elm-checkerboardgrid-tutorial
|
|
||||||
-- by prepending the "https://github.com/" part.
|
|
||||||
]
|
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
main =
|
main =
|
||||||
view model
|
div [ class "content" ]
|
||||||
|
[ -- TODO put the header here
|
||||||
|
ul [ class "results" ] []
|
||||||
|
]
|
||||||
|
|||||||
@@ -1,20 +0,0 @@
|
|||||||
<!DOCTYPE HTML>
|
|
||||||
<html>
|
|
||||||
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<title>ElmHub</title>
|
|
||||||
<script type="text/javascript" src="elm.js"></script>
|
|
||||||
|
|
||||||
<link rel="stylesheet" href="style.css">
|
|
||||||
<link rel="icon" type="image/png" href="elm-hub.png">
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
</body>
|
|
||||||
|
|
||||||
<script type="text/javascript">
|
|
||||||
var app = Elm.Main.fullscreen();
|
|
||||||
</script>
|
|
||||||
|
|
||||||
</html>
|
|
||||||
|
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2.1 KiB |
@@ -1,35 +1,15 @@
|
|||||||
module Main exposing (..)
|
module Main exposing (..)
|
||||||
|
|
||||||
import Html exposing (..)
|
import Html exposing (..)
|
||||||
import Html.App as Html
|
|
||||||
import Html.Attributes exposing (..)
|
import Html.Attributes exposing (..)
|
||||||
import Html.Events exposing (onClick)
|
|
||||||
|
|
||||||
|
|
||||||
initialModel =
|
model =
|
||||||
{ query = "tutorial"
|
{ result =
|
||||||
, results =
|
{ id = 1
|
||||||
[ { id = 1
|
, name = "TheSeamau5/elm-checkerboardgrid-tutorial"
|
||||||
, name = "TheSeamau5/elm-checkerboardgrid-tutorial"
|
, stars = 66
|
||||||
, stars = 66
|
}
|
||||||
}
|
|
||||||
, { id = 2
|
|
||||||
, name = "grzegorzbalcerek/elm-by-example"
|
|
||||||
, stars = 41
|
|
||||||
}
|
|
||||||
, { id = 3
|
|
||||||
, name = "sporto/elm-tutorial-app"
|
|
||||||
, stars = 35
|
|
||||||
}
|
|
||||||
, { id = 4
|
|
||||||
, name = "jvoigtlaender/Elm-Tutorium"
|
|
||||||
, stars = 10
|
|
||||||
}
|
|
||||||
, { id = 5
|
|
||||||
, name = "sporto/elm-tutorial-assets"
|
|
||||||
, stars = 7
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -43,31 +23,16 @@ elmHubHeader =
|
|||||||
view model =
|
view model =
|
||||||
div [ class "content" ]
|
div [ class "content" ]
|
||||||
[ elmHubHeader
|
[ elmHubHeader
|
||||||
, ul [ class "results" ] (List.map viewSearchResult model.results)
|
, ul [ class "results" ]
|
||||||
|
[ li []
|
||||||
|
[ span [ class "star-count" ] [{- TODO display the number of stars -}]
|
||||||
|
-- TODO use the model to put a link here that points to
|
||||||
|
-- https://github.com/TheSeamau5/elm-checkerboardgrid-tutorial
|
||||||
|
-- by prepending the "https://github.com/" part.
|
||||||
|
]
|
||||||
|
]
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
viewSearchResult result =
|
|
||||||
li []
|
|
||||||
[ span [ class "star-count" ] [ text (toString result.stars) ]
|
|
||||||
, a [ href ("https://github.com/" ++ result.name), target "_blank" ]
|
|
||||||
[ text result.name ]
|
|
||||||
, button
|
|
||||||
-- TODO add an onClick handler that sends a DELETE_BY_ID msg
|
|
||||||
[ class "hide-result" ]
|
|
||||||
[ text "X" ]
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
update msg model =
|
|
||||||
-- TODO if msg.operation == "DELETE_BY_ID",
|
|
||||||
-- then return a new model without the given ID present anymore.
|
|
||||||
model
|
|
||||||
|
|
||||||
|
|
||||||
main =
|
main =
|
||||||
Html.beginnerProgram
|
view model
|
||||||
{ view = view
|
|
||||||
, update = update
|
|
||||||
, model = initialModel
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
Part 2
|
Part 1
|
||||||
======
|
======
|
||||||
|
|
||||||
The instructor will paste notes from the lesson, including code examples from
|
The instructor will paste notes from the lesson, including code examples from
|
||||||
@@ -20,7 +20,6 @@ elm-live Main.elm --open --output=elm.js
|
|||||||
```
|
```
|
||||||
|
|
||||||
## References
|
## References
|
||||||
|
* [html-to-elm](http://mbylstra.github.io/html-to-elm/) - paste in HTML, get elm-html code
|
||||||
* [Type Annotation syntax reference](http://elm-lang.org/docs/syntax#type-annotations)
|
* [elm-html documentation](http://package.elm-lang.org/packages/elm-lang/html/latest)
|
||||||
* [`type alias` syntax reference](http://elm-lang.org/docs/syntax#type-aliases)
|
* [record syntax](http://elm-lang.org/docs/syntax#records) (e.g. `{ foo = 1, bar = 2 }`)
|
||||||
* [`List.map` documentation](http://package.elm-lang.org/packages/elm-lang/core/3.0.0/List#map)
|
|
||||||
|
|||||||
@@ -6,27 +6,6 @@ import Html.Attributes exposing (..)
|
|||||||
import Html.Events exposing (onClick)
|
import Html.Events exposing (onClick)
|
||||||
|
|
||||||
|
|
||||||
type alias Model =
|
|
||||||
{ query : String
|
|
||||||
, results : List SearchResult
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
type alias SearchResult =
|
|
||||||
{ id : Int
|
|
||||||
, name : String
|
|
||||||
, stars : Int
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
type alias Msg =
|
|
||||||
{ operation : String
|
|
||||||
, data : Int
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
{-| TODO add a type annotation to this value
|
|
||||||
-}
|
|
||||||
initialModel =
|
initialModel =
|
||||||
{ query = "tutorial"
|
{ query = "tutorial"
|
||||||
, results =
|
, results =
|
||||||
@@ -54,8 +33,6 @@ initialModel =
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
{-| TODO add a type annotation to this function
|
|
||||||
-}
|
|
||||||
elmHubHeader =
|
elmHubHeader =
|
||||||
header []
|
header []
|
||||||
[ h1 [] [ text "ElmHub" ]
|
[ h1 [] [ text "ElmHub" ]
|
||||||
@@ -63,8 +40,6 @@ elmHubHeader =
|
|||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
{-| TODO add a type annotation to this function
|
|
||||||
-}
|
|
||||||
view model =
|
view model =
|
||||||
div [ class "content" ]
|
div [ class "content" ]
|
||||||
[ elmHubHeader
|
[ elmHubHeader
|
||||||
@@ -72,28 +47,22 @@ view model =
|
|||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
{-| TODO add a type annotation to this function
|
|
||||||
-}
|
|
||||||
viewSearchResult result =
|
viewSearchResult result =
|
||||||
li []
|
li []
|
||||||
[ span [ class "star-count" ] [ text (toString result.stars) ]
|
[ span [ class "star-count" ] [ text (toString result.stars) ]
|
||||||
, a [ href ("https://github.com/" ++ result.name), target "_blank" ]
|
, a [ href ("https://github.com/" ++ result.name), target "_blank" ]
|
||||||
[ text result.name ]
|
[ text result.name ]
|
||||||
, button
|
, button
|
||||||
[ class "hide-result", onClick { operation = "DELETE_BY_ID", data = result.id } ]
|
-- TODO add an onClick handler that sends a DELETE_BY_ID msg
|
||||||
|
[ class "hide-result" ]
|
||||||
[ text "X" ]
|
[ text "X" ]
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
{-| TODO add a type annotation to this function
|
|
||||||
-}
|
|
||||||
update msg model =
|
update msg model =
|
||||||
if msg.operation == "DELETE_BY_ID" then
|
-- TODO if msg.operation == "DELETE_BY_ID",
|
||||||
{ model
|
-- then return a new model without the given ID present anymore.
|
||||||
| results = List.filter (\result -> result.id /= msg.data) model.results
|
model
|
||||||
}
|
|
||||||
else
|
|
||||||
model
|
|
||||||
|
|
||||||
|
|
||||||
main =
|
main =
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
Part 3
|
Part 2
|
||||||
======
|
======
|
||||||
|
|
||||||
The instructor will paste notes from the lesson, including code examples from
|
The instructor will paste notes from the lesson, including code examples from
|
||||||
@@ -21,5 +21,6 @@ elm-live Main.elm --open --output=elm.js
|
|||||||
|
|
||||||
## References
|
## References
|
||||||
|
|
||||||
* [`onClick` documentation](http://package.elm-lang.org/packages/evancz/elm-html/4.0.2/Html-Events#onClick)
|
* [Type Annotation syntax reference](http://elm-lang.org/docs/syntax#type-annotations)
|
||||||
* [record update syntax reference](http://elm-lang.org/docs/syntax#records) (e.g. `{ model | query = "foo" }`)
|
* [`type alias` syntax reference](http://elm-lang.org/docs/syntax#type-aliases)
|
||||||
|
* [`List.map` documentation](http://package.elm-lang.org/packages/elm-lang/core/3.0.0/List#map)
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ module Main exposing (..)
|
|||||||
import Html exposing (..)
|
import Html exposing (..)
|
||||||
import Html.App as Html
|
import Html.App as Html
|
||||||
import Html.Attributes exposing (..)
|
import Html.Attributes exposing (..)
|
||||||
import Html.Events exposing (onClick, onInput)
|
import Html.Events exposing (onClick)
|
||||||
|
|
||||||
|
|
||||||
type alias Model =
|
type alias Model =
|
||||||
@@ -19,12 +19,14 @@ type alias SearchResult =
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
type Msg
|
type alias Msg =
|
||||||
= SetQuery String
|
{ operation : String
|
||||||
| DeleteById Int
|
, data : Int
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
initialModel : Model
|
{-| TODO add a type annotation to this value
|
||||||
|
-}
|
||||||
initialModel =
|
initialModel =
|
||||||
{ query = "tutorial"
|
{ query = "tutorial"
|
||||||
, results =
|
, results =
|
||||||
@@ -52,7 +54,8 @@ initialModel =
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
elmHubHeader : Html Msg
|
{-| TODO add a type annotation to this function
|
||||||
|
-}
|
||||||
elmHubHeader =
|
elmHubHeader =
|
||||||
header []
|
header []
|
||||||
[ h1 [] [ text "ElmHub" ]
|
[ h1 [] [ text "ElmHub" ]
|
||||||
@@ -60,45 +63,39 @@ elmHubHeader =
|
|||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
view : Model -> Html Msg
|
{-| TODO add a type annotation to this function
|
||||||
|
-}
|
||||||
view model =
|
view model =
|
||||||
div [ class "content" ]
|
div [ class "content" ]
|
||||||
[ header []
|
[ elmHubHeader
|
||||||
[ h1 [] [ text "ElmHub" ]
|
|
||||||
, span [ class "tagline" ] [ text "Like GitHub, but for Elm things." ]
|
|
||||||
]
|
|
||||||
, input
|
|
||||||
[ class "search-query"
|
|
||||||
-- TODO onInput, set the query in the model
|
|
||||||
, defaultValue model.query
|
|
||||||
]
|
|
||||||
[]
|
|
||||||
, button [ class "search-button" ] [ text "Search" ]
|
|
||||||
, ul [ class "results" ] (List.map viewSearchResult model.results)
|
, ul [ class "results" ] (List.map viewSearchResult model.results)
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
viewSearchResult : SearchResult -> Html Msg
|
{-| TODO add a type annotation to this function
|
||||||
|
-}
|
||||||
viewSearchResult result =
|
viewSearchResult result =
|
||||||
li []
|
li []
|
||||||
[ span [ class "star-count" ] [ text (toString result.stars) ]
|
[ span [ class "star-count" ] [ text (toString result.stars) ]
|
||||||
, a [ href ("https://github.com/" ++ result.name), target "_blank" ]
|
, a [ href ("https://github.com/" ++ result.name), target "_blank" ]
|
||||||
[ text result.name ]
|
[ text result.name ]
|
||||||
, button
|
, button
|
||||||
-- TODO add an onClick handler that sends a DeleteById action
|
[ class "hide-result", onClick { operation = "DELETE_BY_ID", data = result.id } ]
|
||||||
[ class "hide-result" ]
|
|
||||||
[ text "X" ]
|
[ text "X" ]
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
update : Msg -> Model -> Model
|
{-| TODO add a type annotation to this function
|
||||||
|
-}
|
||||||
update msg model =
|
update msg model =
|
||||||
-- TODO if we get a SetQuery action, use it to set the model's query field,
|
if msg.operation == "DELETE_BY_ID" then
|
||||||
-- and if we get a DeleteById action, delete the appropriate result
|
{ model
|
||||||
model
|
| results = List.filter (\result -> result.id /= msg.data) model.results
|
||||||
|
}
|
||||||
|
else
|
||||||
|
model
|
||||||
|
|
||||||
|
|
||||||
main : Program Never
|
|
||||||
main =
|
main =
|
||||||
Html.beginnerProgram
|
Html.beginnerProgram
|
||||||
{ view = view
|
{ view = view
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
Part 4
|
Part 3
|
||||||
======
|
======
|
||||||
|
|
||||||
The instructor will paste notes from the lesson, including code examples from
|
The instructor will paste notes from the lesson, including code examples from
|
||||||
@@ -21,4 +21,5 @@ elm-live Main.elm --open --output=elm.js
|
|||||||
|
|
||||||
## References
|
## References
|
||||||
|
|
||||||
* [Union Types syntax reference](http://elm-lang.org/docs/syntax#union-types)
|
* [`onClick` documentation](http://package.elm-lang.org/packages/evancz/elm-html/4.0.2/Html-Events#onClick)
|
||||||
|
* [record update syntax reference](http://elm-lang.org/docs/syntax#records) (e.g. `{ model | query = "foo" }`)
|
||||||
|
|||||||
157
part5/Main.elm
157
part5/Main.elm
@@ -2,79 +2,8 @@ module Main exposing (..)
|
|||||||
|
|
||||||
import Html exposing (..)
|
import Html exposing (..)
|
||||||
import Html.App as Html
|
import Html.App as Html
|
||||||
import Html.Attributes exposing (class, target, href, property, defaultValue)
|
import Html.Attributes exposing (..)
|
||||||
import Html.Events exposing (..)
|
import Html.Events exposing (onClick, onInput)
|
||||||
import Json.Decode exposing (Decoder)
|
|
||||||
import Json.Decode.Pipeline exposing (..)
|
|
||||||
|
|
||||||
|
|
||||||
main : Program Never
|
|
||||||
main =
|
|
||||||
Html.beginnerProgram
|
|
||||||
{ view = view
|
|
||||||
, update = update
|
|
||||||
, model = initialModel
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
sampleJson : String
|
|
||||||
sampleJson =
|
|
||||||
"""
|
|
||||||
{
|
|
||||||
"total_count": 40,
|
|
||||||
"incomplete_results": false,
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"id": 3081286,
|
|
||||||
"name": "Tetris",
|
|
||||||
"full_name": "dtrupenn/Tetris",
|
|
||||||
"owner": {
|
|
||||||
"login": "dtrupenn",
|
|
||||||
"id": 872147,
|
|
||||||
"avatar_url": "https://secure.gravatar.com/avatar/e7956084e75f239de85d3a31bc172ace?d=https://a248.e.akamai.net/assets.github.com%2Fimages%2Fgravatars%2Fgravatar-user-420.png",
|
|
||||||
"gravatar_id": "",
|
|
||||||
"url": "https://api.github.com/users/dtrupenn",
|
|
||||||
"received_events_url": "https://api.github.com/users/dtrupenn/received_events",
|
|
||||||
"type": "User"
|
|
||||||
},
|
|
||||||
"private": false,
|
|
||||||
"html_url": "https://github.com/dtrupenn/Tetris",
|
|
||||||
"description": "A C implementation of Tetris using Pennsim through LC4",
|
|
||||||
"fork": false,
|
|
||||||
"url": "https://api.github.com/repos/dtrupenn/Tetris",
|
|
||||||
"created_at": "2012-01-01T00:31:50Z",
|
|
||||||
"updated_at": "2013-01-05T17:58:47Z",
|
|
||||||
"pushed_at": "2012-01-01T00:37:02Z",
|
|
||||||
"homepage": "",
|
|
||||||
"size": 524,
|
|
||||||
"stargazers_count": 1,
|
|
||||||
"watchers_count": 1,
|
|
||||||
"language": "Assembly",
|
|
||||||
"forks_count": 0,
|
|
||||||
"open_issues_count": 0,
|
|
||||||
"master_branch": "master",
|
|
||||||
"default_branch": "master",
|
|
||||||
"score": 10.309712
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
responseDecoder : Decoder (List SearchResult)
|
|
||||||
responseDecoder =
|
|
||||||
Json.Decode.at [ "items" ] (Json.Decode.list searchResultDecoder)
|
|
||||||
|
|
||||||
|
|
||||||
searchResultDecoder : Decoder SearchResult
|
|
||||||
searchResultDecoder =
|
|
||||||
-- See https://developer.github.com/v3/search/#example
|
|
||||||
-- and http://package.elm-lang.org/packages/NoRedInk/elm-decode-pipeline/latest
|
|
||||||
-- TODO replace these calls to `hardcoded` with calls to `require`
|
|
||||||
decode SearchResult
|
|
||||||
|> hardcoded 0
|
|
||||||
|> hardcoded ""
|
|
||||||
|> hardcoded 0
|
|
||||||
|
|
||||||
|
|
||||||
type alias Model =
|
type alias Model =
|
||||||
@@ -90,22 +19,45 @@ type alias SearchResult =
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
type Msg
|
||||||
|
= SetQuery String
|
||||||
|
| DeleteById Int
|
||||||
|
|
||||||
|
|
||||||
initialModel : Model
|
initialModel : Model
|
||||||
initialModel =
|
initialModel =
|
||||||
{ query = "tutorial"
|
{ query = "tutorial"
|
||||||
, results = decodeResults sampleJson
|
, results =
|
||||||
|
[ { id = 1
|
||||||
|
, name = "TheSeamau5/elm-checkerboardgrid-tutorial"
|
||||||
|
, stars = 66
|
||||||
|
}
|
||||||
|
, { id = 2
|
||||||
|
, name = "grzegorzbalcerek/elm-by-example"
|
||||||
|
, stars = 41
|
||||||
|
}
|
||||||
|
, { id = 3
|
||||||
|
, name = "sporto/elm-tutorial-app"
|
||||||
|
, stars = 35
|
||||||
|
}
|
||||||
|
, { id = 4
|
||||||
|
, name = "jvoigtlaender/Elm-Tutorium"
|
||||||
|
, stars = 10
|
||||||
|
}
|
||||||
|
, { id = 5
|
||||||
|
, name = "sporto/elm-tutorial-assets"
|
||||||
|
, stars = 7
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
decodeResults : String -> List SearchResult
|
elmHubHeader : Html Msg
|
||||||
decodeResults json =
|
elmHubHeader =
|
||||||
-- TODO use Json.Decode.decodeString to translate this into either:
|
header []
|
||||||
--
|
[ h1 [] [ text "ElmHub" ]
|
||||||
-- * the search results, if decoding succeeded
|
, span [ class "tagline" ] [ text "Like GitHub, but for Elm things." ]
|
||||||
-- * an empty list if decoding failed
|
]
|
||||||
--
|
|
||||||
-- see http://package.elm-lang.org/packages/elm-lang/core/4.0.0/Json-Decode#decodeString
|
|
||||||
[]
|
|
||||||
|
|
||||||
|
|
||||||
view : Model -> Html Msg
|
view : Model -> Html Msg
|
||||||
@@ -115,10 +67,14 @@ view model =
|
|||||||
[ h1 [] [ text "ElmHub" ]
|
[ h1 [] [ text "ElmHub" ]
|
||||||
, span [ class "tagline" ] [ text "Like GitHub, but for Elm things." ]
|
, span [ class "tagline" ] [ text "Like GitHub, but for Elm things." ]
|
||||||
]
|
]
|
||||||
, input [ class "search-query", onInput SetQuery, defaultValue model.query ] []
|
, input
|
||||||
|
[ class "search-query"
|
||||||
|
-- TODO onInput, set the query in the model
|
||||||
|
, defaultValue model.query
|
||||||
|
]
|
||||||
|
[]
|
||||||
, button [ class "search-button" ] [ text "Search" ]
|
, button [ class "search-button" ] [ text "Search" ]
|
||||||
, ul [ class "results" ]
|
, ul [ class "results" ] (List.map viewSearchResult model.results)
|
||||||
(List.map viewSearchResult model.results)
|
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
@@ -128,25 +84,24 @@ viewSearchResult result =
|
|||||||
[ span [ class "star-count" ] [ text (toString result.stars) ]
|
[ span [ class "star-count" ] [ text (toString result.stars) ]
|
||||||
, a [ href ("https://github.com/" ++ result.name), target "_blank" ]
|
, a [ href ("https://github.com/" ++ result.name), target "_blank" ]
|
||||||
[ text result.name ]
|
[ text result.name ]
|
||||||
, button [ class "hide-result", onClick (DeleteById result.id) ]
|
, button
|
||||||
|
-- TODO add an onClick handler that sends a DeleteById action
|
||||||
|
[ class "hide-result" ]
|
||||||
[ text "X" ]
|
[ text "X" ]
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
type Msg
|
|
||||||
= SetQuery String
|
|
||||||
| DeleteById Int
|
|
||||||
|
|
||||||
|
|
||||||
update : Msg -> Model -> Model
|
update : Msg -> Model -> Model
|
||||||
update msg model =
|
update msg model =
|
||||||
case msg of
|
-- TODO if we get a SetQuery action, use it to set the model's query field,
|
||||||
SetQuery query ->
|
-- and if we get a DeleteById action, delete the appropriate result
|
||||||
{ model | query = query }
|
model
|
||||||
|
|
||||||
DeleteById idToHide ->
|
|
||||||
let
|
main : Program Never
|
||||||
newResults =
|
main =
|
||||||
List.filter (\{ id } -> id /= idToHide) model.results
|
Html.beginnerProgram
|
||||||
in
|
{ view = view
|
||||||
{ model | results = newResults }
|
, update = update
|
||||||
|
, model = initialModel
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
Part 5
|
Part 4
|
||||||
======
|
======
|
||||||
|
|
||||||
The instructor will paste notes from the lesson, including code examples from
|
The instructor will paste notes from the lesson, including code examples from
|
||||||
@@ -18,3 +18,7 @@ elm-package install
|
|||||||
```bash
|
```bash
|
||||||
elm-live Main.elm --open --output=elm.js
|
elm-live Main.elm --open --output=elm.js
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## References
|
||||||
|
|
||||||
|
* [Union Types syntax reference](http://elm-lang.org/docs/syntax#union-types)
|
||||||
|
|||||||
@@ -4,15 +4,12 @@
|
|||||||
"repository": "https://github.com/rtfeldman/elm-workshop.git",
|
"repository": "https://github.com/rtfeldman/elm-workshop.git",
|
||||||
"license": "BSD-3-Clause",
|
"license": "BSD-3-Clause",
|
||||||
"source-directories": [
|
"source-directories": [
|
||||||
".",
|
".", ".."
|
||||||
".."
|
|
||||||
],
|
],
|
||||||
"exposed-modules": [],
|
"exposed-modules": [],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"NoRedInk/elm-decode-pipeline": "1.1.2 <= v < 2.0.0",
|
"elm-lang/core": "4.0.5 <= v < 5.0.0",
|
||||||
"elm-lang/core": "4.0.1 <= v < 5.0.0",
|
"elm-lang/html": "1.1.0 <= v < 2.0.0"
|
||||||
"elm-lang/html": "1.0.0 <= v < 2.0.0",
|
|
||||||
"evancz/elm-http": "3.0.1 <= v < 4.0.0"
|
|
||||||
},
|
},
|
||||||
"elm-version": "0.17.0 <= v < 0.18.0"
|
"elm-version": "0.17.0 <= v < 0.18.0"
|
||||||
}
|
}
|
||||||
|
|||||||
148
part6/Main.elm
148
part6/Main.elm
@@ -1,49 +1,64 @@
|
|||||||
module Main exposing (..)
|
module Main exposing (..)
|
||||||
|
|
||||||
import Auth
|
|
||||||
import Html exposing (..)
|
import Html exposing (..)
|
||||||
|
import Html.App as Html
|
||||||
import Html.Attributes exposing (class, target, href, property, defaultValue)
|
import Html.Attributes exposing (class, target, href, property, defaultValue)
|
||||||
import Html.Events exposing (..)
|
import Html.Events exposing (..)
|
||||||
import Http
|
|
||||||
import Html.App as Html
|
|
||||||
import Task exposing (Task)
|
|
||||||
import Json.Decode exposing (Decoder)
|
import Json.Decode exposing (Decoder)
|
||||||
import Json.Decode.Pipeline exposing (..)
|
import Json.Decode.Pipeline exposing (..)
|
||||||
|
|
||||||
|
|
||||||
main : Program Never
|
main : Program Never
|
||||||
main =
|
main =
|
||||||
Html.program
|
Html.beginnerProgram
|
||||||
{ view = view
|
{ view = view
|
||||||
, update = update
|
, update = update
|
||||||
, init = ( initialModel, searchFeed initialModel.query )
|
, model = initialModel
|
||||||
, subscriptions = \_ -> Sub.none
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
searchFeed : String -> Cmd Msg
|
sampleJson : String
|
||||||
searchFeed query =
|
sampleJson =
|
||||||
let
|
"""
|
||||||
url =
|
{
|
||||||
"https://api.github.com/search/repositories?access_token="
|
"total_count": 40,
|
||||||
++ Auth.token
|
"incomplete_results": false,
|
||||||
++ "&q="
|
"items": [
|
||||||
++ query
|
{
|
||||||
++ "+language:elm&sort=stars&order=desc"
|
"id": 3081286,
|
||||||
|
"name": "Tetris",
|
||||||
-- Hint: responseDecoder may be useful here
|
"full_name": "dtrupenn/Tetris",
|
||||||
task =
|
"owner": {
|
||||||
"TODO replace this String with a Task using http://package.elm-lang.org/packages/evancz/elm-http/latest/Http#get"
|
"login": "dtrupenn",
|
||||||
in
|
"id": 872147,
|
||||||
-- TODO replace this Cmd.none with a call to Task.perform
|
"avatar_url": "https://secure.gravatar.com/avatar/e7956084e75f239de85d3a31bc172ace?d=https://a248.e.akamai.net/assets.github.com%2Fimages%2Fgravatars%2Fgravatar-user-420.png",
|
||||||
-- http://package.elm-lang.org/packages/elm-lang/core/4.0.1/Task#perform
|
"gravatar_id": "",
|
||||||
--
|
"url": "https://api.github.com/users/dtrupenn",
|
||||||
-- Hint: pass these to Task.perform, but in a different order than this!
|
"received_events_url": "https://api.github.com/users/dtrupenn/received_events",
|
||||||
--
|
"type": "User"
|
||||||
-- task
|
},
|
||||||
-- HandleSearchResponse
|
"private": false,
|
||||||
-- HandleSearchError
|
"html_url": "https://github.com/dtrupenn/Tetris",
|
||||||
Cmd.none
|
"description": "A C implementation of Tetris using Pennsim through LC4",
|
||||||
|
"fork": false,
|
||||||
|
"url": "https://api.github.com/repos/dtrupenn/Tetris",
|
||||||
|
"created_at": "2012-01-01T00:31:50Z",
|
||||||
|
"updated_at": "2013-01-05T17:58:47Z",
|
||||||
|
"pushed_at": "2012-01-01T00:37:02Z",
|
||||||
|
"homepage": "",
|
||||||
|
"size": 524,
|
||||||
|
"stargazers_count": 1,
|
||||||
|
"watchers_count": 1,
|
||||||
|
"language": "Assembly",
|
||||||
|
"forks_count": 0,
|
||||||
|
"open_issues_count": 0,
|
||||||
|
"master_branch": "master",
|
||||||
|
"default_branch": "master",
|
||||||
|
"score": 10.309712
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
responseDecoder : Decoder (List SearchResult)
|
responseDecoder : Decoder (List SearchResult)
|
||||||
@@ -53,16 +68,18 @@ responseDecoder =
|
|||||||
|
|
||||||
searchResultDecoder : Decoder SearchResult
|
searchResultDecoder : Decoder SearchResult
|
||||||
searchResultDecoder =
|
searchResultDecoder =
|
||||||
|
-- See https://developer.github.com/v3/search/#example
|
||||||
|
-- and http://package.elm-lang.org/packages/NoRedInk/elm-decode-pipeline/latest
|
||||||
|
-- TODO replace these calls to `hardcoded` with calls to `require`
|
||||||
decode SearchResult
|
decode SearchResult
|
||||||
|> required "id" Json.Decode.int
|
|> hardcoded 0
|
||||||
|> required "full_name" Json.Decode.string
|
|> hardcoded ""
|
||||||
|> required "stargazers_count" Json.Decode.int
|
|> hardcoded 0
|
||||||
|
|
||||||
|
|
||||||
type alias Model =
|
type alias Model =
|
||||||
{ query : String
|
{ query : String
|
||||||
, results : List SearchResult
|
, results : List SearchResult
|
||||||
, errorMessage : Maybe String
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -76,11 +93,21 @@ type alias SearchResult =
|
|||||||
initialModel : Model
|
initialModel : Model
|
||||||
initialModel =
|
initialModel =
|
||||||
{ query = "tutorial"
|
{ query = "tutorial"
|
||||||
, results = []
|
, results = decodeResults sampleJson
|
||||||
, errorMessage = Nothing
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
decodeResults : String -> List SearchResult
|
||||||
|
decodeResults json =
|
||||||
|
-- TODO use Json.Decode.decodeString to translate this into either:
|
||||||
|
--
|
||||||
|
-- * the search results, if decoding succeeded
|
||||||
|
-- * an empty list if decoding failed
|
||||||
|
--
|
||||||
|
-- see http://package.elm-lang.org/packages/elm-lang/core/4.0.0/Json-Decode#decodeString
|
||||||
|
[]
|
||||||
|
|
||||||
|
|
||||||
view : Model -> Html Msg
|
view : Model -> Html Msg
|
||||||
view model =
|
view model =
|
||||||
div [ class "content" ]
|
div [ class "content" ]
|
||||||
@@ -89,22 +116,12 @@ view model =
|
|||||||
, span [ class "tagline" ] [ text "Like GitHub, but for Elm things." ]
|
, span [ class "tagline" ] [ text "Like GitHub, but for Elm things." ]
|
||||||
]
|
]
|
||||||
, input [ class "search-query", onInput SetQuery, defaultValue model.query ] []
|
, input [ class "search-query", onInput SetQuery, defaultValue model.query ] []
|
||||||
, button [ class "search-button", onClick Search ] [ text "Search" ]
|
, button [ class "search-button" ] [ text "Search" ]
|
||||||
, viewErrorMessage model.errorMessage
|
, ul [ class "results" ]
|
||||||
, ul [ class "results" ] (List.map viewSearchResult model.results)
|
(List.map viewSearchResult model.results)
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
viewErrorMessage : Maybe String -> Html a
|
|
||||||
viewErrorMessage errorMessage =
|
|
||||||
case errorMessage of
|
|
||||||
Just message ->
|
|
||||||
div [ class "error" ] [ text message ]
|
|
||||||
|
|
||||||
Nothing ->
|
|
||||||
text ""
|
|
||||||
|
|
||||||
|
|
||||||
viewSearchResult : SearchResult -> Html Msg
|
viewSearchResult : SearchResult -> Html Msg
|
||||||
viewSearchResult result =
|
viewSearchResult result =
|
||||||
li []
|
li []
|
||||||
@@ -117,42 +134,19 @@ viewSearchResult result =
|
|||||||
|
|
||||||
|
|
||||||
type Msg
|
type Msg
|
||||||
= Search
|
= SetQuery String
|
||||||
| SetQuery String
|
|
||||||
| DeleteById Int
|
| DeleteById Int
|
||||||
| HandleSearchResponse (List SearchResult)
|
|
||||||
| HandleSearchError Http.Error
|
|
||||||
|
|
||||||
|
|
||||||
update : Msg -> Model -> ( Model, Cmd Msg )
|
update : Msg -> Model -> Model
|
||||||
update msg model =
|
update msg model =
|
||||||
case msg of
|
case msg of
|
||||||
Search ->
|
|
||||||
( model, searchFeed model.query )
|
|
||||||
|
|
||||||
HandleSearchResponse results ->
|
|
||||||
( { model | results = results }, Cmd.none )
|
|
||||||
|
|
||||||
HandleSearchError error ->
|
|
||||||
-- TODO if decoding failed, store the message in model.errorMessage
|
|
||||||
--
|
|
||||||
-- Hint 1: look for "decode" in the documentation for this union type:
|
|
||||||
-- http://package.elm-lang.org/packages/evancz/elm-http/latest/Http#Error
|
|
||||||
--
|
|
||||||
-- Hint 2: to check if this is working, break responseDecoder
|
|
||||||
-- by changing "stargazers_count" to "description"
|
|
||||||
( model, Cmd.none )
|
|
||||||
|
|
||||||
SetQuery query ->
|
SetQuery query ->
|
||||||
( { model | query = query }, Cmd.none )
|
{ model | query = query }
|
||||||
|
|
||||||
DeleteById idToHide ->
|
DeleteById idToHide ->
|
||||||
let
|
let
|
||||||
newResults =
|
newResults =
|
||||||
model.results
|
List.filter (\{ id } -> id /= idToHide) model.results
|
||||||
|> List.filter (\{ id } -> id /= idToHide)
|
|
||||||
|
|
||||||
newModel =
|
|
||||||
{ model | results = newResults }
|
|
||||||
in
|
in
|
||||||
( newModel, Cmd.none )
|
{ model | results = newResults }
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
Part 6
|
Part 5
|
||||||
======
|
======
|
||||||
|
|
||||||
The instructor will paste notes from the lesson, including code examples from
|
The instructor will paste notes from the lesson, including code examples from
|
||||||
@@ -18,11 +18,3 @@ elm-package install
|
|||||||
```bash
|
```bash
|
||||||
elm-live Main.elm --open --output=elm.js
|
elm-live Main.elm --open --output=elm.js
|
||||||
```
|
```
|
||||||
|
|
||||||
## References
|
|
||||||
|
|
||||||
* [**let-expressions**](http://elm-lang.org/docs/syntax#let-expressions)
|
|
||||||
* [**case-expressions** and **if-expressions**](http://elm-lang.org/docs/syntax#conditionals)
|
|
||||||
* [HTTP Tasks tutorial](http://elm-lang.org/guide/reactivity#http-tasks)
|
|
||||||
* [HTTP Error documentation](http://package.elm-lang.org/packages/evancz/elm-http/3.0.0/Http#Error)
|
|
||||||
* [Modules syntax reference](http://elm-lang.org/docs/syntax#modules)
|
|
||||||
|
|||||||
110
part7/Main.elm
110
part7/Main.elm
@@ -1,11 +1,12 @@
|
|||||||
port module Main exposing (..)
|
module Main exposing (..)
|
||||||
|
|
||||||
import Html.App as Html
|
import Auth
|
||||||
import Json.Decode exposing (..)
|
|
||||||
import Html exposing (..)
|
import Html exposing (..)
|
||||||
import Html.Attributes exposing (class, target, href, property, defaultValue)
|
import Html.Attributes exposing (class, target, href, property, defaultValue)
|
||||||
import Html.Events exposing (..)
|
import Html.Events exposing (..)
|
||||||
import Auth
|
import Http
|
||||||
|
import Html.App as Html
|
||||||
|
import Task exposing (Task)
|
||||||
import Json.Decode exposing (Decoder)
|
import Json.Decode exposing (Decoder)
|
||||||
import Json.Decode.Pipeline exposing (..)
|
import Json.Decode.Pipeline exposing (..)
|
||||||
|
|
||||||
@@ -15,19 +16,34 @@ main =
|
|||||||
Html.program
|
Html.program
|
||||||
{ view = view
|
{ view = view
|
||||||
, update = update
|
, update = update
|
||||||
, init = ( initialModel, githubSearch (getQueryString initialModel.query) )
|
, init = ( initialModel, searchFeed initialModel.query )
|
||||||
, subscriptions = \_ -> githubResponse decodeResponse
|
, subscriptions = \_ -> Sub.none
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
getQueryString : String -> String
|
searchFeed : String -> Cmd Msg
|
||||||
getQueryString query =
|
searchFeed query =
|
||||||
-- See https://developer.github.com/v3/search/#example for how to customize!
|
let
|
||||||
"access_token="
|
url =
|
||||||
++ Auth.token
|
"https://api.github.com/search/repositories?access_token="
|
||||||
++ "&q="
|
++ Auth.token
|
||||||
++ query
|
++ "&q="
|
||||||
++ "+language:elm&sort=stars&order=desc"
|
++ query
|
||||||
|
++ "+language:elm&sort=stars&order=desc"
|
||||||
|
|
||||||
|
-- Hint: responseDecoder may be useful here
|
||||||
|
task =
|
||||||
|
"TODO replace this String with a Task using http://package.elm-lang.org/packages/evancz/elm-http/latest/Http#get"
|
||||||
|
in
|
||||||
|
-- TODO replace this Cmd.none with a call to Task.perform
|
||||||
|
-- http://package.elm-lang.org/packages/elm-lang/core/4.0.1/Task#perform
|
||||||
|
--
|
||||||
|
-- Hint: pass these to Task.perform, but in a different order than this!
|
||||||
|
--
|
||||||
|
-- task
|
||||||
|
-- HandleSearchResponse
|
||||||
|
-- HandleSearchError
|
||||||
|
Cmd.none
|
||||||
|
|
||||||
|
|
||||||
responseDecoder : Decoder (List SearchResult)
|
responseDecoder : Decoder (List SearchResult)
|
||||||
@@ -100,51 +116,43 @@ viewSearchResult result =
|
|||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
update : Msg -> Model -> ( Model, Cmd Msg )
|
|
||||||
update msg model =
|
|
||||||
case msg of
|
|
||||||
Search ->
|
|
||||||
( model, githubSearch (getQueryString model.query) )
|
|
||||||
|
|
||||||
SetQuery query ->
|
|
||||||
( { model | query = query }, Cmd.none )
|
|
||||||
|
|
||||||
HandleSearchResponse results ->
|
|
||||||
( { model | results = results }, Cmd.none )
|
|
||||||
|
|
||||||
HandleSearchError error ->
|
|
||||||
( { model | errorMessage = error }, Cmd.none )
|
|
||||||
|
|
||||||
DeleteById idToDelete ->
|
|
||||||
let
|
|
||||||
newResults =
|
|
||||||
model.results
|
|
||||||
|> List.filter (\{ id } -> id /= idToDelete)
|
|
||||||
|
|
||||||
newModel =
|
|
||||||
{ model | results = newResults }
|
|
||||||
in
|
|
||||||
( newModel, Cmd.none )
|
|
||||||
|
|
||||||
|
|
||||||
type Msg
|
type Msg
|
||||||
= Search
|
= Search
|
||||||
| SetQuery String
|
| SetQuery String
|
||||||
| DeleteById Int
|
| DeleteById Int
|
||||||
| HandleSearchResponse (List SearchResult)
|
| HandleSearchResponse (List SearchResult)
|
||||||
| HandleSearchError (Maybe String)
|
| HandleSearchError Http.Error
|
||||||
|
|
||||||
|
|
||||||
decodeResponse : Value -> Msg
|
update : Msg -> Model -> ( Model, Cmd Msg )
|
||||||
decodeResponse json =
|
update msg model =
|
||||||
-- TODO use decodeValue to decode the response into a Msg.
|
case msg of
|
||||||
--
|
Search ->
|
||||||
-- Hint: look at the definition of Msg and
|
( model, searchFeed model.query )
|
||||||
-- the definition of responseDecoder
|
|
||||||
HandleSearchError (Just "TODO decode the response!")
|
|
||||||
|
|
||||||
|
HandleSearchResponse results ->
|
||||||
|
( { model | results = results }, Cmd.none )
|
||||||
|
|
||||||
port githubSearch : String -> Cmd msg
|
HandleSearchError error ->
|
||||||
|
-- TODO if decoding failed, store the message in model.errorMessage
|
||||||
|
--
|
||||||
|
-- Hint 1: look for "decode" in the documentation for this union type:
|
||||||
|
-- http://package.elm-lang.org/packages/evancz/elm-http/latest/Http#Error
|
||||||
|
--
|
||||||
|
-- Hint 2: to check if this is working, break responseDecoder
|
||||||
|
-- by changing "stargazers_count" to "description"
|
||||||
|
( model, Cmd.none )
|
||||||
|
|
||||||
|
SetQuery query ->
|
||||||
|
( { model | query = query }, Cmd.none )
|
||||||
|
|
||||||
port githubResponse : (Value -> msg) -> Sub msg
|
DeleteById idToHide ->
|
||||||
|
let
|
||||||
|
newResults =
|
||||||
|
model.results
|
||||||
|
|> List.filter (\{ id } -> id /= idToHide)
|
||||||
|
|
||||||
|
newModel =
|
||||||
|
{ model | results = newResults }
|
||||||
|
in
|
||||||
|
( newModel, Cmd.none )
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
Part 7
|
Part 6
|
||||||
======
|
======
|
||||||
|
|
||||||
The instructor will paste notes from the lesson, including code examples from
|
The instructor will paste notes from the lesson, including code examples from
|
||||||
@@ -18,3 +18,11 @@ elm-package install
|
|||||||
```bash
|
```bash
|
||||||
elm-live Main.elm --open --output=elm.js
|
elm-live Main.elm --open --output=elm.js
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## References
|
||||||
|
|
||||||
|
* [**let-expressions**](http://elm-lang.org/docs/syntax#let-expressions)
|
||||||
|
* [**case-expressions** and **if-expressions**](http://elm-lang.org/docs/syntax#conditionals)
|
||||||
|
* [HTTP Tasks tutorial](http://elm-lang.org/guide/reactivity#http-tasks)
|
||||||
|
* [HTTP Error documentation](http://package.elm-lang.org/packages/evancz/elm-http/3.0.0/Http#Error)
|
||||||
|
* [Modules syntax reference](http://elm-lang.org/docs/syntax#modules)
|
||||||
|
|||||||
@@ -4,33 +4,17 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<title>ElmHub</title>
|
<title>ElmHub</title>
|
||||||
<script type="text/javascript" src="github.js"></script>
|
|
||||||
<script type="text/javascript" src="elm.js"></script>
|
<script type="text/javascript" src="elm.js"></script>
|
||||||
|
|
||||||
<link rel="stylesheet" href="style.css">
|
<link rel="stylesheet" href="style.css">
|
||||||
<link rel="icon" type="image/png" href="elm-hub.png">
|
<link rel="icon" type="image/png" href="elm-hub.png">
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<div id="elm-landing-pad"></div>
|
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
// documentation: https://github.com/michael/github
|
var app = Elm.Main.fullscreen();
|
||||||
var github = new Github();
|
|
||||||
|
|
||||||
var app = Elm.Main.embed(document.getElementById("elm-landing-pad"));
|
|
||||||
|
|
||||||
function searchGithub(query) {
|
|
||||||
console.log("Searching for", query);
|
|
||||||
|
|
||||||
github.getSearch(query).repositories({}, function (err, repositories) {
|
|
||||||
console.log("Got response", repositories);
|
|
||||||
|
|
||||||
// TODO: app.ports.portNameGoesHere.send(repositories);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO app.ports.portNameGoesHere.subscribe(searchGithub);
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
141
part8/Main.elm
141
part8/Main.elm
@@ -1,31 +1,150 @@
|
|||||||
port module Main exposing (..)
|
port module Main exposing (..)
|
||||||
|
|
||||||
import ElmHub exposing (..)
|
|
||||||
import Html.App as Html
|
import Html.App as Html
|
||||||
import Json.Decode
|
import Json.Decode exposing (..)
|
||||||
|
import Html exposing (..)
|
||||||
|
import Html.Attributes exposing (class, target, href, property, defaultValue)
|
||||||
|
import Html.Events exposing (..)
|
||||||
|
import Auth
|
||||||
|
import Json.Decode exposing (Decoder)
|
||||||
|
import Json.Decode.Pipeline exposing (..)
|
||||||
|
|
||||||
|
|
||||||
main : Program Never
|
main : Program Never
|
||||||
main =
|
main =
|
||||||
Html.program
|
Html.program
|
||||||
{ view = view
|
{ view = view
|
||||||
, update = update githubSearch
|
, update = update
|
||||||
, init = ( initialModel, githubSearch (getQueryString initialModel.query) )
|
, init = ( initialModel, githubSearch (getQueryString initialModel.query) )
|
||||||
, subscriptions = \_ -> githubResponse decodeResponse
|
, subscriptions = \_ -> githubResponse decodeResponse
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
decodeResponse : Json.Decode.Value -> Msg
|
getQueryString : String -> String
|
||||||
decodeResponse json =
|
getQueryString query =
|
||||||
case Json.Decode.decodeValue responseDecoder json of
|
-- See https://developer.github.com/v3/search/#example for how to customize!
|
||||||
Err err ->
|
"access_token="
|
||||||
HandleSearchError (Just err)
|
++ Auth.token
|
||||||
|
++ "&q="
|
||||||
|
++ query
|
||||||
|
++ "+language:elm&sort=stars&order=desc"
|
||||||
|
|
||||||
Ok results ->
|
|
||||||
HandleSearchResponse results
|
responseDecoder : Decoder (List SearchResult)
|
||||||
|
responseDecoder =
|
||||||
|
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
|
||||||
|
|
||||||
|
|
||||||
|
type alias Model =
|
||||||
|
{ query : String
|
||||||
|
, results : List SearchResult
|
||||||
|
, errorMessage : Maybe String
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
type alias SearchResult =
|
||||||
|
{ id : Int
|
||||||
|
, name : String
|
||||||
|
, stars : Int
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
initialModel : Model
|
||||||
|
initialModel =
|
||||||
|
{ query = "tutorial"
|
||||||
|
, results = []
|
||||||
|
, errorMessage = Nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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)
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
viewErrorMessage : Maybe String -> Html a
|
||||||
|
viewErrorMessage errorMessage =
|
||||||
|
case errorMessage of
|
||||||
|
Just message ->
|
||||||
|
div [ class "error" ] [ text message ]
|
||||||
|
|
||||||
|
Nothing ->
|
||||||
|
text ""
|
||||||
|
|
||||||
|
|
||||||
|
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" ]
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
update : Msg -> Model -> ( Model, Cmd Msg )
|
||||||
|
update msg model =
|
||||||
|
case msg of
|
||||||
|
Search ->
|
||||||
|
( model, githubSearch (getQueryString model.query) )
|
||||||
|
|
||||||
|
SetQuery query ->
|
||||||
|
( { model | query = query }, Cmd.none )
|
||||||
|
|
||||||
|
HandleSearchResponse results ->
|
||||||
|
( { model | results = results }, Cmd.none )
|
||||||
|
|
||||||
|
HandleSearchError error ->
|
||||||
|
( { model | errorMessage = error }, Cmd.none )
|
||||||
|
|
||||||
|
DeleteById idToDelete ->
|
||||||
|
let
|
||||||
|
newResults =
|
||||||
|
model.results
|
||||||
|
|> List.filter (\{ id } -> id /= idToDelete)
|
||||||
|
|
||||||
|
newModel =
|
||||||
|
{ model | results = newResults }
|
||||||
|
in
|
||||||
|
( newModel, Cmd.none )
|
||||||
|
|
||||||
|
|
||||||
|
type Msg
|
||||||
|
= Search
|
||||||
|
| SetQuery String
|
||||||
|
| DeleteById Int
|
||||||
|
| HandleSearchResponse (List SearchResult)
|
||||||
|
| HandleSearchError (Maybe String)
|
||||||
|
|
||||||
|
|
||||||
|
decodeResponse : Value -> Msg
|
||||||
|
decodeResponse json =
|
||||||
|
-- TODO use decodeValue to decode the response into a Msg.
|
||||||
|
--
|
||||||
|
-- Hint: look at the definition of Msg and
|
||||||
|
-- the definition of responseDecoder
|
||||||
|
HandleSearchError (Just "TODO decode the response!")
|
||||||
|
|
||||||
|
|
||||||
port githubSearch : String -> Cmd msg
|
port githubSearch : String -> Cmd msg
|
||||||
|
|
||||||
|
|
||||||
port githubResponse : (Json.Decode.Value -> msg) -> Sub msg
|
port githubResponse : (Value -> msg) -> Sub msg
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
Part 8
|
Part 7
|
||||||
======
|
======
|
||||||
|
|
||||||
The instructor will paste notes from the lesson, including code examples from
|
The instructor will paste notes from the lesson, including code examples from
|
||||||
@@ -18,28 +18,3 @@ elm-package install
|
|||||||
```bash
|
```bash
|
||||||
elm-live Main.elm --open --output=elm.js
|
elm-live Main.elm --open --output=elm.js
|
||||||
```
|
```
|
||||||
|
|
||||||
## Running Tests
|
|
||||||
|
|
||||||
Do either (or both!) of the following:
|
|
||||||
|
|
||||||
#### Running tests on the command line
|
|
||||||
|
|
||||||
```bash
|
|
||||||
elm-test
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Running tests in a browser
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cd tests
|
|
||||||
elm-reactor
|
|
||||||
```
|
|
||||||
|
|
||||||
Then visit [localhost:8000](http://localhost:8000) and choose `HtmlRunner.elm`.
|
|
||||||
|
|
||||||
## References
|
|
||||||
|
|
||||||
* [Using Elm packages](https://github.com/elm-lang/elm-package/blob/master/README.md#basic-usage)
|
|
||||||
* [elm-test documentation](http://package.elm-lang.org/packages/project-fuzzball/test/latest)
|
|
||||||
* [`(<|)` documentation](http://package.elm-lang.org/packages/elm-lang/core/4.0.0/Basics#<|)
|
|
||||||
|
|||||||
@@ -26,11 +26,11 @@
|
|||||||
github.getSearch(query).repositories({}, function (err, repositories) {
|
github.getSearch(query).repositories({}, function (err, repositories) {
|
||||||
console.log("Got response", repositories);
|
console.log("Got response", repositories);
|
||||||
|
|
||||||
app.ports.githubResponse.send(repositories);
|
// TODO: app.ports.portNameGoesHere.send(repositories);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
app.ports.githubSearch.subscribe(searchGithub);
|
// TODO app.ports.portNameGoesHere.subscribe(searchGithub);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
0
part8/.gitignore → part9/.gitignore
vendored
0
part8/.gitignore → part9/.gitignore
vendored
31
part9/Main.elm
Normal file
31
part9/Main.elm
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
port module Main exposing (..)
|
||||||
|
|
||||||
|
import ElmHub exposing (..)
|
||||||
|
import Html.App as Html
|
||||||
|
import Json.Decode
|
||||||
|
|
||||||
|
|
||||||
|
main : Program Never
|
||||||
|
main =
|
||||||
|
Html.program
|
||||||
|
{ view = view
|
||||||
|
, update = update githubSearch
|
||||||
|
, init = ( initialModel, githubSearch (getQueryString initialModel.query) )
|
||||||
|
, subscriptions = \_ -> githubResponse decodeResponse
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
decodeResponse : Json.Decode.Value -> Msg
|
||||||
|
decodeResponse json =
|
||||||
|
case Json.Decode.decodeValue responseDecoder json of
|
||||||
|
Err err ->
|
||||||
|
HandleSearchError (Just err)
|
||||||
|
|
||||||
|
Ok results ->
|
||||||
|
HandleSearchResponse results
|
||||||
|
|
||||||
|
|
||||||
|
port githubSearch : String -> Cmd msg
|
||||||
|
|
||||||
|
|
||||||
|
port githubResponse : (Json.Decode.Value -> msg) -> Sub msg
|
||||||
45
part9/README.md
Normal file
45
part9/README.md
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
Part 8
|
||||||
|
======
|
||||||
|
|
||||||
|
The instructor will paste notes from the lesson, including code examples from
|
||||||
|
Q&A, in [this document](https://docs.google.com/document/d/1ApuSOk9DP0YsQrxhW7-WE8UOEAV4PPnLDDeqUOL2o5k/edit?usp=sharing).
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
```bash
|
||||||
|
elm-package install
|
||||||
|
```
|
||||||
|
|
||||||
|
(Answer `y` when prompted.)
|
||||||
|
|
||||||
|
|
||||||
|
## Building
|
||||||
|
|
||||||
|
```bash
|
||||||
|
elm-live Main.elm --open --output=elm.js
|
||||||
|
```
|
||||||
|
|
||||||
|
## Running Tests
|
||||||
|
|
||||||
|
Do either (or both!) of the following:
|
||||||
|
|
||||||
|
#### Running tests on the command line
|
||||||
|
|
||||||
|
```bash
|
||||||
|
elm-test
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Running tests in a browser
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd tests
|
||||||
|
elm-reactor
|
||||||
|
```
|
||||||
|
|
||||||
|
Then visit [localhost:8000](http://localhost:8000) and choose `HtmlRunner.elm`.
|
||||||
|
|
||||||
|
## References
|
||||||
|
|
||||||
|
* [Using Elm packages](https://github.com/elm-lang/elm-package/blob/master/README.md#basic-usage)
|
||||||
|
* [elm-test documentation](http://package.elm-lang.org/packages/project-fuzzball/test/latest)
|
||||||
|
* [`(<|)` documentation](http://package.elm-lang.org/packages/elm-lang/core/4.0.0/Basics#<|)
|
||||||
|
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2.1 KiB |
@@ -4,12 +4,15 @@
|
|||||||
"repository": "https://github.com/rtfeldman/elm-workshop.git",
|
"repository": "https://github.com/rtfeldman/elm-workshop.git",
|
||||||
"license": "BSD-3-Clause",
|
"license": "BSD-3-Clause",
|
||||||
"source-directories": [
|
"source-directories": [
|
||||||
".", ".."
|
".",
|
||||||
|
".."
|
||||||
],
|
],
|
||||||
"exposed-modules": [],
|
"exposed-modules": [],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"elm-lang/core": "4.0.5 <= v < 5.0.0",
|
"NoRedInk/elm-decode-pipeline": "1.1.2 <= v < 2.0.0",
|
||||||
"elm-lang/html": "1.1.0 <= v < 2.0.0"
|
"elm-lang/core": "4.0.1 <= v < 5.0.0",
|
||||||
|
"elm-lang/html": "1.0.0 <= v < 2.0.0",
|
||||||
|
"evancz/elm-http": "3.0.1 <= v < 4.0.0"
|
||||||
},
|
},
|
||||||
"elm-version": "0.17.0 <= v < 0.18.0"
|
"elm-version": "0.17.0 <= v < 0.18.0"
|
||||||
}
|
}
|
||||||
36
part9/index.html
Normal file
36
part9/index.html
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
<!DOCTYPE HTML>
|
||||||
|
<html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>ElmHub</title>
|
||||||
|
<script type="text/javascript" src="github.js"></script>
|
||||||
|
<script type="text/javascript" src="elm.js"></script>
|
||||||
|
<link rel="stylesheet" href="style.css">
|
||||||
|
<link rel="icon" type="image/png" href="elm-hub.png">
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div id="elm-landing-pad"></div>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
// documentation: https://github.com/michael/github
|
||||||
|
var github = new Github();
|
||||||
|
|
||||||
|
var app = Elm.Main.embed(document.getElementById("elm-landing-pad"));
|
||||||
|
|
||||||
|
function searchGithub(query) {
|
||||||
|
console.log("Searching for", query);
|
||||||
|
|
||||||
|
github.getSearch(query).repositories({}, function (err, repositories) {
|
||||||
|
console.log("Got response", repositories);
|
||||||
|
|
||||||
|
app.ports.githubResponse.send(repositories);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
app.ports.githubSearch.subscribe(searchGithub);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</html>
|
||||||
Reference in New Issue
Block a user