Last active
May 26, 2017 19:11
-
-
Save stewart/ce374b8f2511a7db1548b686f0feac68 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 Main exposing (..) | |
import Dom | |
import Html exposing (..) | |
import Html.Attributes exposing (..) | |
import Html.Events exposing (..) | |
import Html.Keyed as Keyed | |
import Json.Decode as Json | |
import Task | |
-- model | |
type alias Model = | |
{ uid : Id | |
, title : String | |
, items : List Item | |
} | |
type alias Item = | |
{ id : Id | |
, title : String | |
, completed : Bool | |
, editing : Bool | |
} | |
type alias Id = | |
Int | |
-- msg | |
type Msg | |
= None | |
| UpdateTitle String | |
| CreateItem | |
| ToggleItem Id Bool | |
| EditingItem Id Bool | |
| UpdateItem Id String | |
-- init | |
init : Model | |
init = | |
{ uid = 0 | |
, title = "" | |
, items = [] | |
} | |
-- update | |
update : Msg -> Model -> ( Model, Cmd Msg ) | |
update msg model = | |
case msg of | |
None -> | |
model ! [] | |
UpdateTitle str -> | |
{ model | title = str } ! [] | |
CreateItem -> | |
let | |
item = | |
{ id = model.uid | |
, title = model.title | |
, completed = False | |
, editing = False | |
} | |
in | |
if String.isEmpty model.title then | |
model ! [] | |
else | |
{ model | |
| uid = model.uid + 1 | |
, title = "" | |
, items = item :: model.items | |
} | |
! [] | |
ToggleItem id completed -> | |
let | |
update = | |
updateItem id (\item -> { item | completed = completed }) | |
in | |
{ model | items = List.map update model.items } ! [] | |
EditingItem id editing -> | |
let | |
update = | |
updateItem id (\item -> { item | editing = editing }) | |
action = | |
if editing then | |
Task.attempt (always None) | |
(Dom.focus ("item-editing-" ++ (toString id))) | |
else | |
Cmd.none | |
in | |
{ model | items = List.map update model.items } ! [ action ] | |
UpdateItem id str -> | |
let | |
update = | |
updateItem id (\item -> { item | title = str }) | |
in | |
{ model | items = List.map update model.items } ! [] | |
updateItem : Id -> (Item -> Item) -> Item -> Item | |
updateItem id fn item = | |
if item.id == id then | |
fn item | |
else | |
item | |
-- view | |
view : Model -> Html Msg | |
view model = | |
main_ [] | |
[ viewInput model | |
, viewItems model | |
] | |
viewInput : Model -> Html Msg | |
viewInput { title } = | |
div [ class "item-input" ] | |
[ input | |
[ onInput UpdateTitle | |
, onEnter CreateItem | |
, value title | |
] | |
[] | |
] | |
viewItems : Model -> Html Msg | |
viewItems model = | |
let | |
items = | |
model.items | |
|> List.partition (not << .completed) | |
|> (\( x, y ) -> [ x, y ]) | |
|> List.concat | |
in | |
Keyed.ul [ class "item-list" ] (List.map viewKeyedItem items) | |
viewKeyedItem : Item -> ( String, Html Msg ) | |
viewKeyedItem item = | |
let | |
partial = | |
if item.editing then | |
viewItemForm item | |
else | |
viewItem item | |
in | |
( (toString item.id), partial ) | |
viewItemForm : Item -> Html Msg | |
viewItemForm item = | |
li | |
[ class "item item-form" ] | |
[ input | |
[ type_ "text" | |
, id ("item-editing-" ++ (toString item.id)) | |
, value item.title | |
, onBlur (EditingItem item.id False) | |
, onInput (UpdateItem item.id) | |
, onEnter (EditingItem item.id False) | |
] | |
[] | |
] | |
viewItem : Item -> Html Msg | |
viewItem item = | |
li | |
[ classList | |
[ ( "item", True ) | |
, ( "is-completed", item.completed ) | |
] | |
] | |
[ viewItemCheckbox item | |
, div | |
[ class "item-title" | |
, onDoubleClick (EditingItem item.id True) | |
] | |
[ text item.title ] | |
] | |
viewItemCheckbox : Item -> Html Msg | |
viewItemCheckbox item = | |
let | |
identifier = | |
"item-completed-" ++ (toString item.id) | |
toggle bool = | |
ToggleItem item.id bool | |
in | |
label [ for identifier, class "item-checkbox" ] | |
[ input | |
[ type_ "checkbox" | |
, id identifier | |
, checked item.completed | |
, onCheck toggle | |
] | |
[] | |
] | |
-- misc | |
onEnter : Msg -> Attribute Msg | |
onEnter msg = | |
let | |
isEnter code = | |
if code == 13 then | |
Json.succeed msg | |
else | |
Json.fail "Not enter" | |
in | |
on "keydown" (Json.andThen isEnter keyCode) | |
-- main | |
main : Program Never Model Msg | |
main = | |
Html.program | |
{ init = ( init, Cmd.none ) | |
, update = update | |
, view = view | |
, subscriptions = always Sub.none | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment