mercury
Version:
A truly modular frontend framework
194 lines (169 loc) • 5.33 kB
JavaScript
;
var hg = require('../../index.js');
var h = require('../../index.js').h;
var Router = require('../lib/router/');
var document = require('global/document');
var TodoItem = require('./todo-item.js');
var ROOT_URI = String(document.location.pathname);
var COMPLETED_URI = ROOT_URI + '/completed';
var ACTIVE_URI = ROOT_URI + '/active';
module.exports = TodoApp;
function TodoApp(opts) {
opts = opts || {};
var state = hg.state({
todos: hg.varhash(opts.todos || {}, TodoItem),
route: Router(),
field: hg.struct({
text: hg.value(opts.field && opts.field.text || '')
}),
channels: {
setTodoField: setTodoField,
add: add,
clearCompleted: clearCompleted,
toggleAll: toggleAll,
destroy: destroy
}
});
TodoItem.onDestroy.asHash(state.todos, function onDestroy(ev) {
destroy(state, ev);
});
return state;
}
function setTodoField(state, data) {
state.field.text.set(data.newTodo);
}
function add(state, data) {
if (data.newTodo.trim() === '') {
return;
}
var todo = TodoItem({
title: data.newTodo.trim()
});
state.todos.put(todo.id(), todo);
state.field.text.set('');
}
function clearCompleted(state) {
Object.keys(state.todos).forEach(function clear(key) {
if (TodoItem.isCompleted(state.todos[key])) {
destroy(state, state.todos[key]());
}
});
}
function toggleAll(state, value) {
Object.keys(state.todos).forEach(function toggle(key) {
TodoItem.setCompleted(state.todos[key], value.toggle);
});
}
function destroy(state, opts) {
state.todos.delete(opts.id);
}
TodoApp.render = function render(state) {
return h('.todomvc-wrapper', {
style: { visibility: 'hidden' }
}, [
h('link', {
rel: 'stylesheet',
href: '/mercury/examples/todomvc/style.css'
}),
h('section#todoapp.todoapp', [
hg.partial(header, state.field, state.channels),
hg.partial(mainSection,
state.todos, state.route, state.channels),
hg.partial(statsSection,
state.todos, state.route, state.channels)
]),
hg.partial(infoFooter)
]);
};
function header(field, channels) {
return h('header#header.header', {
'ev-event': [
hg.sendChange(channels.setTodoField),
hg.sendSubmit(channels.add)
]
}, [
h('h1', 'Todos'),
h('input#new-todo.new-todo', {
placeholder: 'What needs to be done?',
autofocus: true,
value: field.text,
name: 'newTodo'
})
]);
}
function mainSection(todos, route, channels) {
var todosList = objectToArray(todos);
var allCompleted = todosList.every(function isComplete(todo) {
return todo.completed;
});
var visibleTodos = todosList.filter(function isVisible(todo) {
return route === COMPLETED_URI && todo.completed ||
route === ACTIVE_URI && !todo.completed ||
route === ROOT_URI;
});
return h('section#main.main', { hidden: !todosList.length }, [
h('input#toggle-all.toggle-all', {
type: 'checkbox',
name: 'toggle',
checked: allCompleted,
'ev-change': hg.sendValue(channels.toggleAll)
}),
h('label', { htmlFor: 'toggle-all' }, 'Mark all as complete'),
h('ul#todo-list.todolist', visibleTodos
.map(function renderItem(todo) {
return TodoItem.render(todo, channels);
}))
]);
}
function statsSection(todos, route, channels) {
var todosList = objectToArray(todos);
var todosLeft = todosList.filter(function notComplete(todo) {
return !todo.completed;
}).length;
var todosCompleted = todosList.length - todosLeft;
return h('footer#footer.footer', {
hidden: !todosList.length
}, [
h('span#todo-count.todo-count', [
h('strong', String(todosLeft)),
todosLeft === 1 ? ' item' : ' items',
' left'
]),
h('ul#filters.filters', [
link(ROOT_URI, 'All', route === ROOT_URI),
link(ACTIVE_URI, 'Active', route === ACTIVE_URI),
link(COMPLETED_URI, 'Completed',
route === COMPLETED_URI)
]),
h('button.clear-completed#clear-completed', {
hidden: todosCompleted === 0,
'ev-click': hg.send(channels.clearCompleted)
}, 'Clear completed (' + String(todosCompleted) + ')')
]);
}
function link(uri, text, isSelected) {
return h('li', [
Router.anchor({
className: isSelected ? 'selected' : '',
href: uri
}, text)
]);
}
function infoFooter() {
return h('footer#info.info', [
h('p', 'Double-click to edit a todo'),
h('p', [
'Written by ',
h('a', { href: 'https://github.com/Raynos' }, 'Raynos')
]),
h('p', [
'Part of ',
h('a', { href: 'http://todomvc.com' }, 'TodoMVC')
])
]);
}
function objectToArray(obj) {
return Object.keys(obj).map(function toItem(k) {
return obj[k];
});
}