Created
May 17, 2015 17:37
-
-
Save chendrix/3f298c99215ca2096e41 to your computer and use it in GitHub Desktop.
Bug somewhere?
This file contains 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 TodoMe where | |
{-| TodoMVC implemented in Elm, using plain HTML and CSS for rendering. | |
This application is broken up into four distinct parts: | |
1. Model - a full definition of the application's state | |
2. Update - a way to step the application state forward | |
3. View - a way to visualize our application state with HTML | |
4. Inputs - the signals necessary to manage events | |
This clean division of concerns is a core part of Elm. You can read more about | |
this in the Pong tutorial: http://elm-lang.org/blog/Pong.elm | |
This program is not particularly large, so definitely see the following | |
document for notes on structuring more complex GUIs with Elm: | |
http://elm-lang.org/learn/Architecture.elm | |
-} | |
import Html exposing (..) | |
import Html.Attributes exposing (..) | |
import Html.Events exposing (..) | |
import Html.Lazy exposing (lazy, lazy2, lazy3) | |
import Json.Decode as Json | |
import Signal exposing (Signal, Address) | |
import String | |
import Window | |
type alias Model = | |
{ tasks : List Task | |
, field : String | |
, uid : Int | |
, visibility : String | |
} | |
type alias Task = | |
{ description : String | |
, completed : Bool | |
, editing : Bool | |
, id : Int | |
} | |
newTask : String -> Int -> Task | |
newTask desc id = | |
{ description = desc | |
, completed = False | |
, editing = False | |
, id = id | |
} | |
emptyModel : Model | |
emptyModel = | |
{ tasks = [] | |
, field = "" | |
, uid = 0 | |
, visibility = "All" | |
} | |
type Action | |
= NoOp | |
| UpdateField String | |
| EditingTask Int Bool | |
| UpdateTask Int String | |
| Add | |
| Delete Int | |
| DeleteComplete | |
| Check Int Bool | |
| CheckAll Bool | |
| ChangeVisibility String | |
update : Action -> Model -> Model | |
update action model = | |
case action of | |
NoOp -> model | |
UpdateField f -> | |
{ model | field <- f } | |
EditingTask id isEditing -> | |
let updateTask t = if t.id == id then { t | editing <- isEditing } else t | |
in | |
{ model | tasks <- List.map updateTask model.tasks } | |
UpdateTask id task -> | |
let updateTask t = if t.id == id then { t | description <- task } else t | |
in | |
{ model | tasks <- List.map updateTask model.tasks } | |
Add -> | |
{ model | | |
uid <- model.uid + 1, | |
field <- "", | |
tasks <- | |
if String.isEmpty model.field | |
then model.tasks | |
else model.tasks ++ [newTask model.field model.uid] | |
} | |
Delete id -> | |
{ model | tasks <- List.filter (\t -> t.id /= id) model.tasks } | |
DeleteComplete -> | |
{ model | tasks <- List.filter (not << .completed) model.tasks } | |
Check id isChecked -> | |
let updateTask t = if t.id == id then { t | completed <- isChecked } else t | |
in | |
{ model | tasks <- List.map updateTask model.tasks } | |
CheckAll isChecked -> | |
let updateTask t = { t | completed <- isChecked } | |
in | |
{ model | tasks <- List.map updateTask model.tasks } | |
ChangeVisibility visibility -> | |
{ model | visibility <- visibility } | |
view : Address Action -> Model -> Html | |
view address model = | |
div | |
[ class "todomvc-wrapper" | |
, style [ ("visibility", "hidden") ] | |
] | |
[ section | |
[ id "todoapp" ] | |
[ lazy2 taskEntry address model.field | |
--, lazy3 taskList address model.visibility model.tasks | |
--, lazy3 controls address model.visibility model.tasks | |
] | |
--, infoFooter | |
] | |
onEnter : Address a -> a -> Attribute | |
onEnter address value = | |
on "keydown" | |
(Json.customDecoder keyCode is13) | |
(\_ -> Signal.message address value) | |
is13 : Int -> Result String () | |
is13 code = | |
if code == 13 then Ok () else Err "not the right key code" | |
taskEntry : Address Action -> String -> Html | |
taskEntry address task = | |
header | |
[ id "header" ] | |
[ h1 [] [ text "todos" ] | |
, input | |
[ id "new-todo" | |
, placeholder "What needs to be done?" | |
, autofocus True | |
, value task | |
, name "newTodo" | |
, on "input" targetValue (Signal.message address << UpdateField) | |
, onEnter address Add | |
] | |
[] | |
] | |
--taskList : Address Action -> Visibility -> List Task -> Html | |
--taskList address visibility tasks = | |
--controls : Address Action -> Visibility -> List Task -> Html | |
--taskList address visibility tasks = | |
--infoFooter : Html | |
main : Signal Html | |
main = | |
Signal.map (view actions.address) model | |
model : Signal Model | |
model = | |
Signal.foldp update initialModel actions.signal | |
initialModel : Model | |
initialModel = | |
Maybe.withDefault emptyModel getStorage | |
actions : Signal.Mailbox Action | |
actions = | |
Signal.mailbox NoOp | |
port focus : Signal String | |
port focus = | |
let needsFocus act = | |
case act of | |
EditingTask id bool -> bool | |
_ -> False | |
toSelector (EditingTask id _) = ("#todo-" ++ toString id) | |
in | |
actions.signal | |
|> Signal.filter needsFocus (EditingTask 0 True) | |
|> Signal.map toSelector | |
port getStorage : Maybe Model | |
port setStorage : Signal Model | |
port setStorage = model | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment