diff options
Diffstat (limited to 'third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/functional-prog-examples/elm/Todo.elm')
-rw-r--r-- | third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/functional-prog-examples/elm/Todo.elm | 390 |
1 files changed, 390 insertions, 0 deletions
diff --git a/third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/functional-prog-examples/elm/Todo.elm b/third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/functional-prog-examples/elm/Todo.elm new file mode 100644 index 0000000000..bf1d39db31 --- /dev/null +++ b/third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/functional-prog-examples/elm/Todo.elm @@ -0,0 +1,390 @@ +port module Todo exposing (..) + +{-| TodoMVC implemented in Elm, using plain HTML and CSS for rendering. + +This application is broken up into four distinct parts: + + 1. Model - a full description of the application as data + 2. Update - a way to update the model based on user actions + 3. View - a way to visualize our model with HTML + +This program is not particularly large, so definitely see the following +document for notes on structuring more complex GUIs with Elm: +http://guide.elm-lang.org/architecture/ +-} + +import Dom +import Task +import Html exposing (..) +import Html.Attributes exposing (..) +import Html.Events exposing (..) +import Html.Lazy exposing (lazy, lazy2) +import Html.App +import Navigation exposing (Parser) +import String +import String.Extra +import Todo.Task + + +-- MODEL +-- The full application state of our todo app. + + +type alias Model = + { tasks : List Todo.Task.Model + , field : String + , uid : Int + , visibility : String + } + + +type alias Flags = + Maybe Model + + +emptyModel : Model +emptyModel = + { tasks = [] + , visibility = "All" + , field = "" + , uid = 0 + } + + + +-- UPDATE +-- A description of the kinds of actions that can be performed on the model of +-- our application. See the following post for more info on this pattern and +-- some alternatives: http://guide.elm-lang.org/architecture/ + + +type Msg + = NoOp + | UpdateField String + | Add + | UpdateTask ( Int, Todo.Task.Msg ) + | DeleteComplete + | CheckAll Bool + | ChangeVisibility String + + + +-- How we update our Model on any given Message + + +update : Msg -> Model -> ( Model, Cmd Msg ) +update msg model = + case Debug.log "MESSAGE: " msg of + NoOp -> + ( model, Cmd.none ) + + UpdateField str -> + let + newModel = + { model | field = str } + in + ( newModel, save model ) + + Add -> + let + description = + String.trim model.field + + newModel = + if String.isEmpty description then + model + else + { model + | uid = model.uid + 1 + , field = "" + , tasks = model.tasks ++ [ Todo.Task.init description model.uid ] + } + in + ( newModel, save newModel ) + + UpdateTask ( id, taskMsg ) -> + let + updateTask t = + if t.id == id then + Todo.Task.update taskMsg t + else + Just t + + newModel = + { model | tasks = List.filterMap updateTask model.tasks } + in + case taskMsg of + Todo.Task.Focus elementId -> + newModel ! [ save newModel, focusTask elementId ] + + _ -> + ( newModel, save newModel ) + + DeleteComplete -> + let + newModel = + { model + | tasks = List.filter (not << .completed) model.tasks + } + in + ( newModel, save newModel ) + + CheckAll bool -> + let + updateTask t = + { t | completed = bool } + + newModel = + { model | tasks = List.map updateTask model.tasks } + in + ( newModel, save newModel ) + + ChangeVisibility visibility -> + let + newModel = + { model | visibility = visibility } + in + ( newModel, save model ) + + +focusTask : String -> Cmd Msg +focusTask elementId = + Task.perform (\_ -> NoOp) (\_ -> NoOp) (Dom.focus elementId) + + + +-- VIEW + + +view : Model -> Html Msg +view model = + div + [ class "todomvc-wrapper" + , style [ ( "visibility", "hidden" ) ] + ] + [ section + [ class "todoapp" ] + [ lazy taskEntry model.field + , lazy2 taskList model.visibility model.tasks + , lazy2 controls model.visibility model.tasks + ] + , infoFooter + ] + + +taskEntry : String -> Html Msg +taskEntry task = + header + [ class "header" ] + [ h1 [] [ text "todos" ] + , input + [ class "new-todo" + , placeholder "What needs to be done?" + , autofocus True + , value task + , name "newTodo" + , onInput UpdateField + , Todo.Task.onFinish Add NoOp + ] + [] + ] + + +taskList : String -> List Todo.Task.Model -> Html Msg +taskList visibility tasks = + let + isVisible todo = + case visibility of + "Completed" -> + todo.completed + + "Active" -> + not todo.completed + + -- "All" + _ -> + True + + allCompleted = + List.all .completed tasks + + cssVisibility = + if List.isEmpty tasks then + "hidden" + else + "visible" + in + section + [ class "main" + , style [ ( "visibility", cssVisibility ) ] + ] + [ input + [ class "toggle-all" + , type' "checkbox" + , name "toggle" + , checked allCompleted + , onClick (CheckAll (not allCompleted)) + ] + [] + , label + [ for "toggle-all" ] + [ text "Mark all as complete" ] + , ul + [ class "todo-list" ] + (List.map + (\task -> + let + id = + task.id + + taskView = + Todo.Task.view task + in + Html.App.map (\msg -> UpdateTask ( id, msg )) taskView + ) + (List.filter isVisible tasks) + ) + ] + + +controls : String -> List Todo.Task.Model -> Html Msg +controls visibility tasks = + let + tasksCompleted = + List.length (List.filter .completed tasks) + + tasksLeft = + List.length tasks - tasksCompleted + + item_ = + if tasksLeft == 1 then + " item" + else + " items" + in + footer + [ class "footer" + , hidden (List.isEmpty tasks) + ] + [ span + [ class "todo-count" ] + [ strong [] [ text (toString tasksLeft) ] + , text (item_ ++ " left") + ] + , ul + [ class "filters" ] + [ visibilitySwap "#/" "All" visibility + , text " " + , visibilitySwap "#/active" "Active" visibility + , text " " + , visibilitySwap "#/completed" "Completed" visibility + ] + , button + [ class "clear-completed" + , hidden (tasksCompleted == 0) + , onClick DeleteComplete + ] + [ text ("Clear completed (" ++ toString tasksCompleted ++ ")") ] + ] + + +visibilitySwap : String -> String -> String -> Html Msg +visibilitySwap uri visibility actualVisibility = + let + className = + if visibility == actualVisibility then + "selected" + else + "" + in + li + [ onClick (ChangeVisibility visibility) ] + [ a [ class className, href uri ] [ text visibility ] ] + + +infoFooter : Html msg +infoFooter = + footer + [ class "info" ] + [ p [] [ text "Double-click to edit a todo" ] + , p [] + [ text "Written by " + , a [ href "https://github.com/evancz" ] [ text "Evan Czaplicki" ] + ] + , p [] + [ text "Part of " + , a [ href "http://todomvc.com" ] [ text "TodoMVC" ] + ] + ] + + + +-- wire the entire application together + + +main : Program Flags +main = + Navigation.programWithFlags urlParser + { urlUpdate = urlUpdate + , view = view + , init = init + , update = update + , subscriptions = subscriptions + } + + + +-- URL PARSERS - check out evancz/url-parser for fancier URL parsing + + +toUrl : String -> String +toUrl visibility = + "#/" ++ String.toLower visibility + + +fromUrl : String -> Maybe String +fromUrl hash = + let + cleanHash = + String.dropLeft 2 hash + in + if (List.member cleanHash [ "all", "active", "completed" ]) == True then + Just cleanHash + else + Nothing + + +urlParser : Parser (Maybe String) +urlParser = + Navigation.makeParser (fromUrl << .hash) + + +{-| The URL is turned into a Maybe value. If the URL is valid, we just update +our model with the new visibility settings. If it is not a valid URL, +we set the visibility filter to show all tasks. +-} +urlUpdate : Maybe String -> Model -> ( Model, Cmd Msg ) +urlUpdate result model = + case result of + Just visibility -> + update (ChangeVisibility (String.Extra.toSentenceCase visibility)) model + + Nothing -> + update (ChangeVisibility "All") model + + +init : Flags -> Maybe String -> ( Model, Cmd Msg ) +init flags url = + urlUpdate url (Maybe.withDefault emptyModel flags) + + + +-- interactions with localStorage + + +port save : Model -> Cmd msg + + +subscriptions : Model -> Sub Msg +subscriptions model = + Sub.none |