mithril-vndb/examples/todomvc/todomvc.js
2016-05-15 11:14:38 -04:00

146 lines
3.9 KiB
JavaScript

var m = require("../../render/hyperscript")
var renderer = require("../../render/render")(window)
var router = require("../../router/router")(window)
//model
var todos = loadData()
var editing = null
var showing = "all"
function loadData() {
return JSON.parse(localStorage["todos-mithril"] || "[]")
}
function saveData() {
localStorage["todos-mithril"] = JSON.stringify(todos)
}
function createTodo(title) {
todos.push({title: title.trim(), completed: false})
}
function setStatuses(completed) {
for (var i = 0; i < todos.length; i++) todos[i].completed = completed
}
function setStatus(todo, completed) {
todo.completed = completed
}
function todosByStatus(todo) {
switch (showing) {
case "all": return true
case "active": return !todo.completed
case "completed": return todo.completed
}
}
function destroy(todo) {
var index = todos.indexOf(todo)
if (index > -1) todos.splice(index, 1)
}
function countRemaining() {
return todos.filter(function(todo) {return !todo.completed}).length
}
function clear() {
for (var i = 0; i < todos.length; i++) {
if (todos[i].completed) destroy(todos[i--])
}
}
function edit(todo) {
editing = todo
}
function update(title) {
editing.title = title.trim()
if (editing.title === "") destroy(editing)
editing = null
}
function reset() {
editing = null
}
function setFilter(filter) {
showing = filter
}
//view
function add(e) {
if (e.keyCode === 13) {
createTodo(this.value)
this.value = ""
}
}
function toggleAll() {
setStatuses(document.getElementById("toggle-all").checked)
}
function toggle(todo) {
setStatus(todo, !todo.completed)
}
function focus(vnode, todo) {
if (todo === editing && vnode.dom !== document.activeElement) {
vnode.dom.value = todo.title
vnode.dom.focus()
vnode.dom.selectionStart = vnode.dom.selectionEnd = todo.title.length
}
}
function save(e) {
if (e.keyCode === 13 || e.type === "blur") update(this.value)
else if (e.keyCode === 27) reset()
}
function view() {
var remaining = countRemaining()
return [
m("header.header", [
m("h1", "todos"),
m("input#new-todo[placeholder='What needs to be done?'][autofocus]", {onkeypress: add}),
]),
m("section#main", {style: {display: todos.length > 0 ? "" : "none"}}, [
m("input#toggle-all[type='checkbox']", {checked: remaining === 0, onclick: toggleAll}),
m("label[for='toggle-all']", {onclick: toggleAll}, "Mark all as complete"),
m("ul#todo-list", [
todos.filter(todosByStatus).map(function(todo) {
return m("li", {class: (todo.completed ? "completed" : "") + " " + (todo === editing ? "editing" : "")}, [
m(".view", [
m("input.toggle[type='checkbox']", {checked: todo.completed, onclick: function() {toggle(todo)}}),
m("label", {ondblclick: function() {edit(todo)}}, todo.title),
m("button.destroy", {onclick: function() {destroy(todo)}}),
]),
m("input.edit", {onupdate: function(vnode) {focus(vnode, todo)}, onkeypress: save, onblur: save})
])
}),
]),
]),
todos.length ? m("footer#footer", [
m("span#todo-count", [
m("strong", remaining),
remaining === 1 ? " item left" : " items left",
]),
m("ul#filters", [
m("li", m("a[href='#/']", {class: showing === "all" ? "selected" : ""}, "All")),
m("li", m("a[href='#/active']", {class: showing === "active" ? "selected" : ""}, "Active")),
m("li", m("a[href='#/completed']", {class: showing === "completed" ? "selected" : ""}, "Completed")),
]),
m("button#clear-completed", {onclick: clear}, "Clear completed"),
]) : null,
]
}
var root = document.getElementById("todoapp")
var raf
renderer.setEventCallback(run)
function run() {
cancelAnimationFrame(raf)
raf = requestAnimationFrame(function() {
saveData()
renderer.render(root, view())
})
}
router.setPrefix("#")
router.defineRoutes({
"/": "all",
"/active": "active",
"/completed": "completed",
}, function(filter) {
setFilter(filter)
run()
}, function() {
router.setPath("/")
})