Commit 41eaaadf authored by Eduard Kyvenko's avatar Eduard Kyvenko Committed by Sam Saccone

Updated elm example to 0.17.1 (#1667)

* Updated elm example to 0.17.1

* Excluded elm compiled assets and packages from jscs

* Removed focus port
parent 07d0b47c
...@@ -38,6 +38,8 @@ ...@@ -38,6 +38,8 @@
"examples/ember-cli/todomvc/dist/**/*.js", "examples/ember-cli/todomvc/dist/**/*.js",
"examples/ember-cli/todomvc/testem.js", "examples/ember-cli/todomvc/testem.js",
"examples/ember-cli/assets/**/*.js", "examples/ember-cli/assets/**/*.js",
"examples/elm/build/elm.js",
"examples/elm/elm-stuff/**",
"examples/humble/js/**", "examples/humble/js/**",
"examples/js_of_ocaml/js/*.js", "examples/js_of_ocaml/js/*.js",
"examples/polymer/elements/elements.build.js", "examples/polymer/elements/elements.build.js",
......
node_modules/todomvc-app-css/* elm-stuff
node_modules/todomvc-app-css
!node_modules/todomvc-app-css/index.css !node_modules/todomvc-app-css/index.css
node_modules/todomvc-common/* node_modules/todomvc-common
!node_modules/todomvc-common/base.css !node_modules/todomvc-common/base.css
!node_modules/todomvc-common/base.js !node_modules/todomvc-common/base.js
module Task where
import Html (..)
import Html.Attributes (..)
import Html.Events (..)
import Json.Decode as Json
import LocalChannel as LC
import Maybe
import Signal
import String
-- MODEL
type alias Model =
{ description : String
, completed : Bool
, edits : Maybe String
, id : Int
}
init : String -> Int -> Model
init desc id =
{ description = desc
, completed = False
, edits = Nothing
, id = id
}
-- UPDATE
type Action
= Focus
| Edit String
| Cancel
| Commit
| Completed Bool
| Delete
update : Action -> Model -> Maybe Model
update update task =
case update of
Focus ->
Just { task | edits <- Just task.description }
Edit description ->
Just { task | edits <- Just description }
Cancel ->
Just { task | edits <- Nothing }
Commit ->
case task.edits of
Nothing ->
Just task
Just rawDescription ->
let description = String.trim rawDescription in
if String.isEmpty description then Nothing else
Just
{ task |
edits <- Nothing,
description <- description
}
Completed bool ->
Just { task | completed <- bool }
Delete ->
Nothing
-- VIEW
view : LC.LocalChannel (Int, Action) -> Model -> Html
view channel task =
let className =
(if task.completed then "completed " else "") ++
case task.edits of
Just _ -> "editing"
Nothing -> ""
description =
Maybe.withDefault task.description task.edits
in
li
[ class className ]
[ div
[ class "view" ]
[ input
[ class "toggle"
, type' "checkbox"
, checked task.completed
, onClick (LC.send channel (task.id, Completed (not task.completed)))
]
[]
, label
[ onDoubleClick (LC.send channel (task.id, Focus)) ]
[ text description ]
, button
[ class "destroy"
, onClick (LC.send channel (task.id, Delete))
]
[]
]
, input
[ class "edit"
, value description
, name "title"
, id ("todo-" ++ toString task.id)
, on "input" targetValue (\desc -> LC.send channel (task.id, Edit desc))
, onBlur (LC.send channel (task.id, Commit))
, onFinish
(LC.send channel (task.id, Commit))
(LC.send channel (task.id, Cancel))
]
[]
]
onFinish : Signal.Message -> Signal.Message -> Attribute
onFinish enterMessage escapeMessage =
let select key =
case key of
13 -> Ok enterMessage
27 -> Ok escapeMessage
_ -> Err "Not a 'finish' key, such as ENTER or ESCAPE"
in
on "keydown" (Json.customDecoder keyCode select) identity
module Todo where port module Todo exposing (..)
{-| TodoMVC implemented in Elm, using plain HTML and CSS for rendering. {-| TodoMVC implemented in Elm, using plain HTML and CSS for rendering.
This application is broken up into four distinct parts: This application is broken up into four distinct parts:
...@@ -6,40 +7,41 @@ This application is broken up into four distinct parts: ...@@ -6,40 +7,41 @@ This application is broken up into four distinct parts:
1. Model - a full description of the application as data 1. Model - a full description of the application as data
2. Update - a way to update the model based on user actions 2. Update - a way to update the model based on user actions
3. View - a way to visualize our model with HTML 3. View - a way to visualize our model 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 This program is not particularly large, so definitely see the following
document for notes on structuring more complex GUIs with Elm: document for notes on structuring more complex GUIs with Elm:
http://elm-lang.org/learn/Architecture.elm http://guide.elm-lang.org/architecture/
-} -}
import Html (..) import Dom
import Html.Attributes (..)
import Html.Events (..)
import Html.Lazy (lazy, lazy2)
import List
import LocalChannel as LC
import Maybe
import Signal
import String
import Task import Task
import Window 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 -- MODEL
-- The full application state of our todo app. -- The full application state of our todo app.
type alias Model = type alias Model =
{ tasks : List Task.Model { tasks : List Todo.Task.Model
, field : String , field : String
, uid : Int , uid : Int
, visibility : String , visibility : String
} }
type alias Flags =
Maybe Model
emptyModel : Model emptyModel : Model
emptyModel = emptyModel =
{ tasks = [] { tasks = []
...@@ -49,221 +51,340 @@ emptyModel = ...@@ -49,221 +51,340 @@ emptyModel =
} }
-- UPDATE
-- UPDATE
-- A description of the kinds of actions that can be performed on the model of -- 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 -- our application. See the following post for more info on this pattern and
-- some alternatives: http://elm-lang.org/learn/Architecture.elm -- some alternatives: http://guide.elm-lang.org/architecture/
type Action
type Msg
= NoOp = NoOp
| UpdateField String | UpdateField String
| Add | Add
| UpdateTask (Int, Task.Action) | UpdateTask ( Int, Todo.Task.Msg )
| DeleteComplete | DeleteComplete
| CheckAll Bool | CheckAll Bool
| ChangeVisibility String | ChangeVisibility String
-- How we update our Model on any given Action
update : Action -> Model -> Model
update action model =
case action of
NoOp -> model
UpdateField str ->
{ model | field <- str }
Add ->
let description = String.trim model.field in
if String.isEmpty description then model else
{ model |
uid <- model.uid + 1,
field <- "",
tasks <- model.tasks ++ [Task.init description model.uid]
}
UpdateTask (id, taskAction) -> -- How we update our Model on any given Message
let updateTask t =
if t.id == id then Task.update taskAction t else Just t
in update : Msg -> Model -> ( Model, Cmd Msg )
{ model | tasks <- List.filterMap updateTask model.tasks } 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)
DeleteComplete ->
{ model | tasks <- List.filter (not << .completed) model.tasks }
CheckAll bool ->
let updateTask t = { t | completed <- bool }
in { model | tasks <- List.map updateTask model.tasks }
ChangeVisibility visibility ->
{ model | visibility <- visibility }
-- VIEW -- VIEW
view : Model -> Html
view : Model -> Html Msg
view model = view model =
div div
[ class "todomvc-wrapper" [ class "todomvc-wrapper"
, style [ ("visibility", "hidden") ] , style [ ( "visibility", "hidden" ) ]
] ]
[ section [ section
[ id "todoapp" ] [ class "todoapp" ]
[ lazy taskEntry model.field [ lazy taskEntry model.field
, lazy2 taskList model.visibility model.tasks , lazy2 taskList model.visibility model.tasks
, lazy2 controls model.visibility model.tasks , lazy2 controls model.visibility model.tasks
] ]
, infoFooter , infoFooter
] ]
taskEntry : String -> Html
taskEntry : String -> Html Msg
taskEntry task = taskEntry task =
header header
[ id "header" ] [ class "header" ]
[ h1 [] [ text "todos" ] [ h1 [] [ text "todos" ]
, input , input
[ id "new-todo" [ class "new-todo"
, placeholder "What needs to be done?" , placeholder "What needs to be done?"
, autofocus True , autofocus True
, value task , value task
, name "newTodo" , name "newTodo"
, on "input" targetValue (Signal.send actions << UpdateField) , onInput UpdateField
, Task.onFinish (Signal.send actions Add) (Signal.send actions NoOp) , Todo.Task.onFinish Add NoOp
] ]
[] []
] ]
taskList : String -> List Task.Model -> Html
taskList : String -> List Todo.Task.Model -> Html Msg
taskList visibility tasks = taskList visibility tasks =
let isVisible todo = let
isVisible todo =
case visibility of case visibility of
"Completed" -> todo.completed "Completed" ->
"Active" -> not todo.completed todo.completed
"All" -> True
"Active" ->
not todo.completed
-- "All"
_ ->
True
allCompleted = List.all .completed tasks allCompleted =
List.all .completed tasks
cssVisibility = if List.isEmpty tasks then "hidden" else "visible" cssVisibility =
if List.isEmpty tasks then
"hidden"
else
"visible"
in in
section section
[ id "main" [ class "main"
, style [ ("visibility", cssVisibility) ] , style [ ( "visibility", cssVisibility ) ]
] ]
[ input [ input
[ id "toggle-all" [ class "toggle-all"
, type' "checkbox" , type' "checkbox"
, name "toggle" , name "toggle"
, checked allCompleted , checked allCompleted
, onClick (Signal.send actions (CheckAll (not allCompleted))) , onClick (CheckAll (not allCompleted))
] ]
[] []
, label , label
[ for "toggle-all" ] [ for "toggle-all" ]
[ text "Mark all as complete" ] [ text "Mark all as complete" ]
, ul , ul
[ id "todo-list" ] [ class "todo-list" ]
(List.map (Task.view taskActions) (List.filter isVisible tasks)) (List.map
] (\task ->
let
controls : String -> List Task.Model -> Html 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 = controls visibility tasks =
let tasksCompleted = List.length (List.filter .completed tasks) let
tasksLeft = List.length tasks - tasksCompleted tasksCompleted =
item_ = if tasksLeft == 1 then " item" else " items" List.length (List.filter .completed tasks)
tasksLeft =
List.length tasks - tasksCompleted
item_ =
if tasksLeft == 1 then
" item"
else
" items"
in in
footer footer
[ id "footer" [ class "footer"
, hidden (List.isEmpty tasks) , hidden (List.isEmpty tasks)
] ]
[ span [ span
[ id "todo-count" ] [ class "todo-count" ]
[ strong [] [ text (toString tasksLeft) ] [ strong [] [ text (toString tasksLeft) ]
, text (item_ ++ " left") , text (item_ ++ " left")
] ]
, ul , ul
[ id "filters" ] [ class "filters" ]
[ visibilitySwap "#/" "All" visibility [ visibilitySwap "#/" "All" visibility
, text " " , text " "
, visibilitySwap "#/active" "Active" visibility , visibilitySwap "#/active" "Active" visibility
, text " " , text " "
, visibilitySwap "#/completed" "Completed" visibility , visibilitySwap "#/completed" "Completed" visibility
] ]
, button , button
[ class "clear-completed" [ class "clear-completed"
, id "clear-completed" , hidden (tasksCompleted == 0)
, hidden (tasksCompleted == 0) , onClick DeleteComplete
, onClick (Signal.send actions DeleteComplete) ]
] [ text ("Clear completed (" ++ toString tasksCompleted ++ ")") ]
[ text ("Clear completed (" ++ toString tasksCompleted ++ ")") ] ]
]
visibilitySwap : String -> String -> String -> Html visibilitySwap : String -> String -> String -> Html Msg
visibilitySwap uri visibility actualVisibility = visibilitySwap uri visibility actualVisibility =
let className = if visibility == actualVisibility then "selected" else "" in let
li className =
[ onClick (Signal.send actions (ChangeVisibility visibility)) ] if visibility == actualVisibility then
[ a [ class className, href uri ] [ text visibility ] ] "selected"
else
""
in
li
[ onClick (ChangeVisibility visibility) ]
[ a [ class className, href uri ] [ text visibility ] ]
infoFooter : Html infoFooter : Html msg
infoFooter = infoFooter =
footer [ id "info" ] footer
[ p [] [ text "Double-click to edit a todo" ] [ class "info" ]
, p [] [ text "Written by " [ p [] [ text "Double-click to edit a todo" ]
, a [ href "https://github.com/evancz" ] [ text "Evan Czaplicki" ] , p []
] [ text "Written by "
, p [] [ text "Part of " , a [ href "https://github.com/evancz" ] [ text "Evan Czaplicki" ]
, a [ href "http://todomvc.com" ] [ text "TodoMVC" ] ]
] , p []
] [ text "Part of "
, a [ href "http://todomvc.com" ] [ text "TodoMVC" ]
]
]
-- SIGNALS
-- wire the entire application together -- wire the entire application together
main : Signal Html
main : Program Flags
main = main =
Signal.map view model Navigation.programWithFlags urlParser
{ urlUpdate = urlUpdate
, view = view
, init = init
, update = update
, subscriptions = subscriptions
}
-- manage the model of our application over time
model : Signal Model
model =
Signal.foldp update initialModel allActions
-- URL PARSERS - check out evancz/url-parser for fancier URL parsing
initialModel : Model
initialModel =
Maybe.withDefault emptyModel savedModel
toUrl : String -> String
toUrl visibility =
"#/" ++ String.toLower visibility
allActions : Signal Action
allActions =
Signal.merge
(Signal.subscribe actions)
(Signal.map ChangeVisibility route)
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
-- interactions with localStorage
port savedModel : Maybe Model
port save : Signal Model urlParser : Parser (Maybe String)
port save = model urlParser =
Navigation.makeParser (fromUrl << .hash)
-- routing
port route : Signal String
-- actions from user input {-| The URL is turned into a Maybe value. If the URL is valid, we just update
actions : Signal.Channel Action 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 ->
taskActions : LC.LocalChannel (Int, Task.Action) update (ChangeVisibility "All") model
port focus : Signal (Maybe Int) init : Flags -> Maybe String -> ( Model, Cmd Msg )
port focus = init flags url =
let toSelector action = urlUpdate url (Maybe.withDefault emptyModel flags)
case action of
UpdateTask (id, Task.Focus) -> Just id
_ -> Nothing
in -- interactions with localStorage
port save : Model -> Cmd msg
subscriptions : Model -> Sub Msg
subscriptions model =
Sub.none
module Todo.Task exposing (..)
import Html exposing (..)
import Html.Attributes exposing (..)
import Html.Events exposing (..)
import Json.Decode
import String
-- MODEL
type alias Model =
{ description : String
, completed : Bool
, edits : Maybe String
, id : Int
}
init : String -> Int -> Model
init desc id =
{ description = desc
, completed = False
, edits = Nothing
, id = id
}
-- UPDATE
type Msg
= Focus String
| Edit String
| Cancel
| Commit
| Completed Bool
| Delete
update : Msg -> Model -> Maybe Model
update msg model =
case msg of
Focus elementId ->
Just { model | edits = Just model.description }
Edit description ->
Just { model | edits = Just description }
Cancel ->
Just { model | edits = Nothing }
Commit ->
case model.edits of
Nothing ->
Just model
Just rawDescription ->
let
description =
String.trim rawDescription
in
if String.isEmpty description then
Nothing
else
Just
{ model
| edits = Nothing
, description = description
}
Completed bool ->
Just { model | completed = bool }
Delete ->
Nothing
-- VIEW
view : Model -> Html Msg
view model =
let
className =
(if model.completed then
"completed "
else
""
)
++ case model.edits of
Just _ ->
"editing"
Nothing ->
""
description =
Maybe.withDefault model.description model.edits
elementId =
"todo-" ++ toString model.id
in
li
[ class className ]
[ div
[ class "view" ]
[ input
[ class "toggle"
, type' "checkbox"
, checked model.completed
, onClick (Completed (not model.completed))
]
[]
, label
[ onDoubleClick (Focus elementId) ]
[ text description ]
, button
[ class "destroy"
, onClick Delete
]
[]
]
, input
[ class "edit"
, value description
, name "title"
, id (elementId)
, onInput Edit
, onBlur Commit
, onFinish Commit Cancel
]
[]
]
onFinish : msg -> msg -> Attribute msg
onFinish enterMessage escapeMessage =
let
select key =
case key of
13 ->
enterMessage
_ ->
-- Not a 'finish' key, such as ENTER or ESCAPE
escapeMessage
in
on "keydown" (Json.Decode.map select keyCode)
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -8,8 +8,11 @@ ...@@ -8,8 +8,11 @@
], ],
"exposed-modules": [], "exposed-modules": [],
"dependencies": { "dependencies": {
"elm-lang/core": "1.0.0 <= v < 2.0.0", "elm-community/string-extra": "1.0.2 <= v < 2.0.0",
"evancz/elm-html": "1.0.0 <= v < 2.0.0", "elm-lang/core": "4.0.5 <= v < 5.0.0",
"evancz/local-channel": "1.0.0 <= v < 2.0.0" "elm-lang/dom": "1.1.0 <= v < 2.0.0",
} "elm-lang/html": "1.1.0 <= v < 2.0.0",
} "elm-lang/navigation": "1.0.0 <= v < 2.0.0"
\ No newline at end of file },
"elm-version": "0.17.1 <= v < 0.18.0"
}
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -16,47 +16,17 @@ ...@@ -16,47 +16,17 @@
</head> </head>
<body> <body>
<script src="elm.js"></script> <script src="build/elm.js"></script>
<script> <script>
(function () { (function () {
var result = localStorage.getItem('elm-todo-model'); var result = localStorage.getItem('elm-todo-model');
var savedModel = result ? JSON.parse(result) : null; var savedModel = result ? JSON.parse(result) : null;
var todomvc = Elm.fullscreen(Elm.Todo, { var todomvc = Elm.Todo.fullscreen(savedModel);
savedModel: savedModel,
route: getRoute()
});
todomvc.ports.save.subscribe(function (model) { todomvc.ports.save.subscribe(function (model) {
localStorage.setItem('elm-todo-model', JSON.stringify(model)); localStorage.setItem('elm-todo-model', JSON.stringify(model));
}); });
// Routing
window.addEventListener('popstate', function () {
todomvc.ports.route.send(getRoute());
}, false);
function getRoute() {
var hash = location.href.split('#')[1] || '';
var route = hash.replace('/', '');
if (['all', 'active', 'completed'].indexOf(route) >= 0) {
return route[0].toUpperCase() + route.substr(1);
}
return 'All';
}
// Setting focus manually
todomvc.ports.focus.subscribe(function (id) {
setTimeout(function () {
if (id === null) {
return;
}
var node = document.getElementById('todo-' + id);
if (document.activeElement !== node) {
node.focus();
}
}, 50);
});
}()); }());
</script> </script>
<script async src="node_modules/todomvc-common/base.js"></script> <script async src="node_modules/todomvc-common/base.js"></script>
......
...@@ -15,12 +15,9 @@ button { ...@@ -15,12 +15,9 @@ button {
font-weight: inherit; font-weight: inherit;
color: inherit; color: inherit;
-webkit-appearance: none; -webkit-appearance: none;
-ms-appearance: none;
appearance: none; appearance: none;
-webkit-font-smoothing: antialiased; -webkit-font-smoothing: antialiased;
-moz-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale;
-ms-font-smoothing: antialiased;
font-smoothing: antialiased;
} }
body { body {
...@@ -32,22 +29,19 @@ body { ...@@ -32,22 +29,19 @@ body {
max-width: 550px; max-width: 550px;
margin: 0 auto; margin: 0 auto;
-webkit-font-smoothing: antialiased; -webkit-font-smoothing: antialiased;
-moz-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale;
-ms-font-smoothing: antialiased;
font-smoothing: antialiased;
font-weight: 300; font-weight: 300;
} }
button, :focus {
input[type="checkbox"] { outline: 0;
outline: none;
} }
.hidden { .hidden {
display: none; display: none;
} }
#todoapp { .todoapp {
background: #fff; background: #fff;
margin: 130px 0 40px 0; margin: 130px 0 40px 0;
position: relative; position: relative;
...@@ -55,25 +49,25 @@ input[type="checkbox"] { ...@@ -55,25 +49,25 @@ input[type="checkbox"] {
0 25px 50px 0 rgba(0, 0, 0, 0.1); 0 25px 50px 0 rgba(0, 0, 0, 0.1);
} }
#todoapp input::-webkit-input-placeholder { .todoapp input::-webkit-input-placeholder {
font-style: italic; font-style: italic;
font-weight: 300; font-weight: 300;
color: #e6e6e6; color: #e6e6e6;
} }
#todoapp input::-moz-placeholder { .todoapp input::-moz-placeholder {
font-style: italic; font-style: italic;
font-weight: 300; font-weight: 300;
color: #e6e6e6; color: #e6e6e6;
} }
#todoapp input::input-placeholder { .todoapp input::input-placeholder {
font-style: italic; font-style: italic;
font-weight: 300; font-weight: 300;
color: #e6e6e6; color: #e6e6e6;
} }
#todoapp h1 { .todoapp h1 {
position: absolute; position: absolute;
top: -155px; top: -155px;
width: 100%; width: 100%;
...@@ -83,11 +77,10 @@ input[type="checkbox"] { ...@@ -83,11 +77,10 @@ input[type="checkbox"] {
color: rgba(175, 47, 47, 0.15); color: rgba(175, 47, 47, 0.15);
-webkit-text-rendering: optimizeLegibility; -webkit-text-rendering: optimizeLegibility;
-moz-text-rendering: optimizeLegibility; -moz-text-rendering: optimizeLegibility;
-ms-text-rendering: optimizeLegibility;
text-rendering: optimizeLegibility; text-rendering: optimizeLegibility;
} }
#new-todo, .new-todo,
.edit { .edit {
position: relative; position: relative;
margin: 0; margin: 0;
...@@ -97,27 +90,23 @@ input[type="checkbox"] { ...@@ -97,27 +90,23 @@ input[type="checkbox"] {
font-weight: inherit; font-weight: inherit;
line-height: 1.4em; line-height: 1.4em;
border: 0; border: 0;
outline: none;
color: inherit; color: inherit;
padding: 6px; padding: 6px;
border: 1px solid #999; border: 1px solid #999;
box-shadow: inset 0 -1px 5px 0 rgba(0, 0, 0, 0.2); box-shadow: inset 0 -1px 5px 0 rgba(0, 0, 0, 0.2);
-ms-box-sizing: border-box;
box-sizing: border-box; box-sizing: border-box;
-webkit-font-smoothing: antialiased; -webkit-font-smoothing: antialiased;
-moz-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale;
-ms-font-smoothing: antialiased;
font-smoothing: antialiased;
} }
#new-todo { .new-todo {
padding: 16px 16px 16px 60px; padding: 16px 16px 16px 60px;
border: none; border: none;
background: rgba(0, 0, 0, 0.003); background: rgba(0, 0, 0, 0.003);
box-shadow: inset 0 -2px 1px rgba(0,0,0,0.03); box-shadow: inset 0 -2px 1px rgba(0,0,0,0.03);
} }
#main { .main {
position: relative; position: relative;
z-index: 2; z-index: 2;
border-top: 1px solid #e6e6e6; border-top: 1px solid #e6e6e6;
...@@ -127,7 +116,7 @@ label[for='toggle-all'] { ...@@ -127,7 +116,7 @@ label[for='toggle-all'] {
display: none; display: none;
} }
#toggle-all { .toggle-all {
position: absolute; position: absolute;
top: -55px; top: -55px;
left: -12px; left: -12px;
...@@ -137,50 +126,50 @@ label[for='toggle-all'] { ...@@ -137,50 +126,50 @@ label[for='toggle-all'] {
border: none; /* Mobile Safari */ border: none; /* Mobile Safari */
} }
#toggle-all:before { .toggle-all:before {
content: '❯'; content: '❯';
font-size: 22px; font-size: 22px;
color: #e6e6e6; color: #e6e6e6;
padding: 10px 27px 10px 27px; padding: 10px 27px 10px 27px;
} }
#toggle-all:checked:before { .toggle-all:checked:before {
color: #737373; color: #737373;
} }
#todo-list { .todo-list {
margin: 0; margin: 0;
padding: 0; padding: 0;
list-style: none; list-style: none;
} }
#todo-list li { .todo-list li {
position: relative; position: relative;
font-size: 24px; font-size: 24px;
border-bottom: 1px solid #ededed; border-bottom: 1px solid #ededed;
} }
#todo-list li:last-child { .todo-list li:last-child {
border-bottom: none; border-bottom: none;
} }
#todo-list li.editing { .todo-list li.editing {
border-bottom: none; border-bottom: none;
padding: 0; padding: 0;
} }
#todo-list li.editing .edit { .todo-list li.editing .edit {
display: block; display: block;
width: 506px; width: 506px;
padding: 13px 17px 12px 17px; padding: 12px 16px;
margin: 0 0 0 43px; margin: 0 0 0 43px;
} }
#todo-list li.editing .view { .todo-list li.editing .view {
display: none; display: none;
} }
#todo-list li .toggle { .todo-list li .toggle {
text-align: center; text-align: center;
width: 40px; width: 40px;
/* auto, since non-WebKit browsers doesn't support input styling */ /* auto, since non-WebKit browsers doesn't support input styling */
...@@ -191,20 +180,18 @@ label[for='toggle-all'] { ...@@ -191,20 +180,18 @@ label[for='toggle-all'] {
margin: auto 0; margin: auto 0;
border: none; /* Mobile Safari */ border: none; /* Mobile Safari */
-webkit-appearance: none; -webkit-appearance: none;
-ms-appearance: none;
appearance: none; appearance: none;
} }
#todo-list li .toggle:after { .todo-list li .toggle:after {
content: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="-10 -18 100 135"><circle cx="50" cy="50" r="50" fill="none" stroke="#ededed" stroke-width="3"/></svg>'); content: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="-10 -18 100 135"><circle cx="50" cy="50" r="50" fill="none" stroke="#ededed" stroke-width="3"/></svg>');
} }
#todo-list li .toggle:checked:after { .todo-list li .toggle:checked:after {
content: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="-10 -18 100 135"><circle cx="50" cy="50" r="50" fill="none" stroke="#bddad5" stroke-width="3"/><path fill="#5dc2af" d="M72 25L42 71 27 56l-4 4 20 20 34-52z"/></svg>'); content: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="-10 -18 100 135"><circle cx="50" cy="50" r="50" fill="none" stroke="#bddad5" stroke-width="3"/><path fill="#5dc2af" d="M72 25L42 71 27 56l-4 4 20 20 34-52z"/></svg>');
} }
#todo-list li label { .todo-list li label {
white-space: pre-line;
word-break: break-all; word-break: break-all;
padding: 15px 60px 15px 15px; padding: 15px 60px 15px 15px;
margin-left: 45px; margin-left: 45px;
...@@ -213,12 +200,12 @@ label[for='toggle-all'] { ...@@ -213,12 +200,12 @@ label[for='toggle-all'] {
transition: color 0.4s; transition: color 0.4s;
} }
#todo-list li.completed label { .todo-list li.completed label {
color: #d9d9d9; color: #d9d9d9;
text-decoration: line-through; text-decoration: line-through;
} }
#todo-list li .destroy { .todo-list li .destroy {
display: none; display: none;
position: absolute; position: absolute;
top: 0; top: 0;
...@@ -233,27 +220,27 @@ label[for='toggle-all'] { ...@@ -233,27 +220,27 @@ label[for='toggle-all'] {
transition: color 0.2s ease-out; transition: color 0.2s ease-out;
} }
#todo-list li .destroy:hover { .todo-list li .destroy:hover {
color: #af5b5e; color: #af5b5e;
} }
#todo-list li .destroy:after { .todo-list li .destroy:after {
content: '×'; content: '×';
} }
#todo-list li:hover .destroy { .todo-list li:hover .destroy {
display: block; display: block;
} }
#todo-list li .edit { .todo-list li .edit {
display: none; display: none;
} }
#todo-list li.editing:last-child { .todo-list li.editing:last-child {
margin-bottom: -1px; margin-bottom: -1px;
} }
#footer { .footer {
color: #777; color: #777;
padding: 10px 15px; padding: 10px 15px;
height: 20px; height: 20px;
...@@ -261,7 +248,7 @@ label[for='toggle-all'] { ...@@ -261,7 +248,7 @@ label[for='toggle-all'] {
border-top: 1px solid #e6e6e6; border-top: 1px solid #e6e6e6;
} }
#footer:before { .footer:before {
content: ''; content: '';
position: absolute; position: absolute;
right: 0; right: 0;
...@@ -276,16 +263,16 @@ label[for='toggle-all'] { ...@@ -276,16 +263,16 @@ label[for='toggle-all'] {
0 17px 2px -6px rgba(0, 0, 0, 0.2); 0 17px 2px -6px rgba(0, 0, 0, 0.2);
} }
#todo-count { .todo-count {
float: left; float: left;
text-align: left; text-align: left;
} }
#todo-count strong { .todo-count strong {
font-weight: 300; font-weight: 300;
} }
#filters { .filters {
margin: 0; margin: 0;
padding: 0; padding: 0;
list-style: none; list-style: none;
...@@ -294,11 +281,11 @@ label[for='toggle-all'] { ...@@ -294,11 +281,11 @@ label[for='toggle-all'] {
left: 0; left: 0;
} }
#filters li { .filters li {
display: inline; display: inline;
} }
#filters li a { .filters li a {
color: inherit; color: inherit;
margin: 3px; margin: 3px;
padding: 3px 7px; padding: 3px 7px;
...@@ -307,39 +294,28 @@ label[for='toggle-all'] { ...@@ -307,39 +294,28 @@ label[for='toggle-all'] {
border-radius: 3px; border-radius: 3px;
} }
#filters li a.selected, .filters li a:hover {
#filters li a:hover {
border-color: rgba(175, 47, 47, 0.1); border-color: rgba(175, 47, 47, 0.1);
} }
#filters li a.selected { .filters li a.selected {
border-color: rgba(175, 47, 47, 0.2); border-color: rgba(175, 47, 47, 0.2);
} }
#clear-completed, .clear-completed,
html #clear-completed:active { html .clear-completed:active {
float: right; float: right;
position: relative; position: relative;
line-height: 20px; line-height: 20px;
text-decoration: none; text-decoration: none;
cursor: pointer; cursor: pointer;
visibility: hidden;
position: relative;
}
#clear-completed::after {
visibility: visible;
content: 'Clear completed';
position: absolute;
right: 0;
white-space: nowrap;
} }
#clear-completed:hover::after { .clear-completed:hover {
text-decoration: underline; text-decoration: underline;
} }
#info { .info {
margin: 65px auto 0; margin: 65px auto 0;
color: #bfbfbf; color: #bfbfbf;
font-size: 10px; font-size: 10px;
...@@ -347,17 +323,17 @@ html #clear-completed:active { ...@@ -347,17 +323,17 @@ html #clear-completed:active {
text-align: center; text-align: center;
} }
#info p { .info p {
line-height: 1; line-height: 1;
} }
#info a { .info a {
color: inherit; color: inherit;
text-decoration: none; text-decoration: none;
font-weight: 400; font-weight: 400;
} }
#info a:hover { .info a:hover {
text-decoration: underline; text-decoration: underline;
} }
...@@ -366,16 +342,16 @@ html #clear-completed:active { ...@@ -366,16 +342,16 @@ html #clear-completed:active {
Can't use it globally since it destroys checkboxes in Firefox Can't use it globally since it destroys checkboxes in Firefox
*/ */
@media screen and (-webkit-min-device-pixel-ratio:0) { @media screen and (-webkit-min-device-pixel-ratio:0) {
#toggle-all, .toggle-all,
#todo-list li .toggle { .todo-list li .toggle {
background: none; background: none;
} }
#todo-list li .toggle { .todo-list li .toggle {
height: 40px; height: 40px;
} }
#toggle-all { .toggle-all {
-webkit-transform: rotate(90deg); -webkit-transform: rotate(90deg);
transform: rotate(90deg); transform: rotate(90deg);
-webkit-appearance: none; -webkit-appearance: none;
...@@ -384,11 +360,11 @@ html #clear-completed:active { ...@@ -384,11 +360,11 @@ html #clear-completed:active {
} }
@media (max-width: 430px) { @media (max-width: 430px) {
#footer { .footer {
height: 50px; height: 50px;
} }
#filters { .filters {
bottom: 10px; bottom: 10px;
} }
} }
...@@ -114,7 +114,12 @@ ...@@ -114,7 +114,12 @@
})({}); })({});
if (location.hostname === 'todomvc.com') { if (location.hostname === 'todomvc.com') {
window._gaq = [['_setAccount','UA-31081062-1'],['_trackPageview']];(function(d,t){var g=d.createElement(t),s=d.getElementsByTagName(t)[0];g.src='//www.google-analytics.com/ga.js';s.parentNode.insertBefore(g,s)}(document,'script')); (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','https://www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-31081062-1', 'auto');
ga('send', 'pageview');
} }
/* jshint ignore:end */ /* jshint ignore:end */
...@@ -228,7 +233,7 @@ ...@@ -228,7 +233,7 @@
xhr.onload = function (e) { xhr.onload = function (e) {
var parsedResponse = JSON.parse(e.target.responseText); var parsedResponse = JSON.parse(e.target.responseText);
if (parsedResponse instanceof Array) { if (parsedResponse instanceof Array) {
var count = parsedResponse.length var count = parsedResponse.length;
if (count !== 0) { if (count !== 0) {
issueLink.innerHTML = 'This app has ' + count + ' open issues'; issueLink.innerHTML = 'This app has ' + count + ' open issues';
document.getElementById('issue-count').style.display = 'inline'; document.getElementById('issue-count').style.display = 'inline';
......
{ {
"private": true, "private": true,
"dependencies": { "dependencies": {
"todomvc-app-css": "^1.0.0", "todomvc-app-css": "^2.0.6",
"todomvc-common": "^1.0.1" "todomvc-common": "^1.0.2"
} }
} }
# Elm TodoMVC Example # Elm TodoMVC Example
> A functional reactive language for interactive applications > A functional language for interactive applications
> _[Elm](http://elm-lang.org/)_ > _[Elm](http://elm-lang.org/)_
...@@ -14,7 +14,7 @@ Here are some links you may find helpful: ...@@ -14,7 +14,7 @@ Here are some links you may find helpful:
* [Try Elm](http://elm-lang.org/try) * [Try Elm](http://elm-lang.org/try)
* [Learn Elm](http://elm-lang.org/Learn.elm) * [Learn Elm](http://elm-lang.org/Learn.elm)
* [Elm Snippets](http://www.share-elm.com/) * [An Introduction to Elm](http://guide.elm-lang.org/)
Get help from other Elm users: Get help from other Elm users:
...@@ -28,25 +28,25 @@ _If you have other helpful links to share, or find any of the links above no lon ...@@ -28,25 +28,25 @@ _If you have other helpful links to share, or find any of the links above no lon
## Project Structure ## Project Structure
All of the Elm code lives in `Todo.elm` and `Task.elm` and relies All of the Elm code lives in `Todo.elm` and `Todo/Task.elm` and relies
on the [elm-html][] library. on the [elm-html][] and [elm-navigation][] packages.
[elm-html]: http://library.elm-lang.org/catalog/evancz-elm-html/latest [elm-html]: http://package.elm-lang.org/packages/elm-lang/html/latest/
[elm-navigation]: http://package.elm-lang.org/packages/elm-lang/navigation/latest/
There also is a port handler set up in `index.html` to set the focus on There also is a port handler set up in `index.html` to set the focus on
particular text fields when necessary. particular text fields when necessary.
## Build Instructions ## Build Instructions
You need to install You need to install [elm](http://elm-lang.org/install)
[elm](https://github.com/elm-lang/elm-platform/blob/master/README.md#elm-platform)
on your machine first. on your machine first.
Run the following commands from the root of this project: Run the following commands from the root of this project:
```bash ```bash
elm-package install elm-package install -y
elm-make Todo.elm --output build/Todo.js elm-make Todo.elm --output build/elm.js
``` ```
Then open `index.html` in your browser! Then open `index.html` in your browser!
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment