module Main exposing (..)
import Html exposing (Html, Attribute, div, ul, label, span, li, a, input, text)
import Html.Attributes exposing (..)
import Html.Events exposing (on, onInput, onClick, keyCode)
import Tuple exposing (first, second)
import Json.Decode as Json
main =
Html.beginnerProgram
{ model = model
, view = view
, update = update
}
-- MODEL
type alias Task =
{ id : Int
, description : String
, isComplete : Bool
}
type alias Model =
{ uid : Int
, description : String
, tasks : List Task
, visibilityFilter : String
}
model : Model
model =
Model 3 "" initStartTasks "all"
initStartTasks : List Task
initStartTasks =
List.map mapTask startingTasks
startingTasks : List ( Int, String )
startingTasks =
[ ( 0, "Buy milk" )
, ( 1, "Read paper" )
, ( 2, "Post letter" )
]
mapTask : ( Int, String ) -> Task
mapTask obj =
taskInit (first obj) (second obj)
taskInit : Int -> String -> Task
taskInit id description =
{ id = id
, description = description
, isComplete = False
}
-- UPDATE
type Msg
= DescriptionChange String
| Add
| ApplyFilter String
| ToggleStatus Int Bool
update : Msg -> Model -> Model
update msg model =
case msg of
DescriptionChange newContent ->
{ model | description = newContent }
Add ->
{ model
| uid = model.uid + 1
, description = ""
, tasks =
if String.isEmpty model.description then
model.tasks
else
model.tasks ++ [ taskInit model.uid model.description ]
}
ApplyFilter filter ->
{ model | visibilityFilter = filter }
ToggleStatus id isCompleted ->
let
updateEntry t =
if t.id == id then
{ t | isComplete = isCompleted }
else
t
in
{ model | tasks = List.map updateEntry model.tasks }
-- VIEW
view : Model -> Html Msg
view model =
div [ id "root" ]
[ viewInputBox model
, div [] [ viewTasks model ]
, div [] [ viewFilters model.visibilityFilter ]
]
viewInputBox : Model -> Html Msg
viewInputBox model =
div [ class "has-float-label" ]
[ input [ type_ "text", placeholder " ", value model.description, onInput DescriptionChange, onEnter Add ] []
, label [] [ text "What do you need to do?" ]
]
viewTasks : Model -> Html Msg
viewTasks model =
let
liItems =
List.map viewTaskItem (List.filter (taskFilter model.visibilityFilter) model.tasks)
in
ul [ id "task-list" ]
([] ++ liItems)
taskFilter filter =
filterTasks filter
filterTasks : String -> Task -> Bool
filterTasks filter task =
case filter of
"active" ->
not task.isComplete
"complete" ->
task.isComplete
_ ->
True
viewTaskItem : Task -> Html Msg
viewTaskItem task =
li [ class "list-item", id ("task-" ++ toString task.id) ]
[ label [ class "list-item__checkbox tickbox" ]
[ input [ type_ "checkbox", checked task.isComplete, onClick (ToggleStatus task.id (not task.isComplete)) ] []
, span [] [ text task.description ]
]
]
viewFilters : String -> Html Msg
viewFilters filter =
div [ class "filters" ]
[ visibilityFilter "all" filter
, text " "
, visibilityFilter "active" filter
, text " "
, visibilityFilter "complete" filter
]
visibilityFilter: String -> String -> Html Msg
visibilityFilter filter activeFilter =
a [ href ("#/" ++ filter), classList [("selected", filter == activeFilter)], onClick (ApplyFilter filter) ]
[ text (capitalise filter) ]
capitalise: String -> String
capitalise str =
(String.toUpper (String.left 1 str)) ++ String.slice 1 (String.length str) str
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)