Commit 5763d113 authored by Sindre Sorhus's avatar Sindre Sorhus

VanillaJS app: convert to tabs + remove some whitespace

parent 86462783
<!DOCTYPE html> <!doctype html>
<html> <html>
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<title>VanillaJS • TodoMVC</title> <title>VanillaJS • TodoMVC</title>
<link rel="stylesheet" href="../../assets/base.css"> <link rel="stylesheet" href="../../assets/base.css">
</head> </head>
<body> <body>
<section id="todoapp">
<section id="todoapp"> <header id="header">
<header id="header"> <h1>Todos</h1>
<h1>Todos</h1> <input id="new-todo" placeholder="What needs to be done?" autofocus>
<input id="new-todo" placeholder="What needs to be done?" autofocus> </header>
</header> <section id="main">
<input id="toggle-all" type="checkbox" >
<section id="main"> <label for="toggle-all">Mark all as complete</label>
<input id="toggle-all" type="checkbox" > <ul id="todo-list"></ul>
<label for="toggle-all">Mark all as complete</label> </section>
<ul id="todo-list"> <footer id="footer">
<span id="todo-count"></span>
</ul> <button id="clear-completed">Clear completed</button>
</section> </footer>
</section>
<footer id="footer"> <footer id="info">
<span id="todo-count"></span> <p>Double-click to edit a todo</p>
<button id="clear-completed">Clear completed</button> <p>Created by <a href="http://twitter.com/ffesseler">Florian Fesseler</a></p>
</footer> <p>Cleanup, edits by <a href="http://github.com/boushley">Aaron Boushley</a></p>
</section> </footer>
<script src="js/app.js"></script>
<footer id="info">
<p>Double-click to edit a todo.</p>
<p>Created by <a href="http://twitter.com/ffesseler">Florian Fesseler</a></p>
<p>Cleanup, edits: <a href="http://github.com/boushley">Aaron Boushley</a>.</p>
</footer>
<!-- scripts here -->
<script src="js/app.js"></script>
</body> </body>
</html> </html>
\ No newline at end of file
var todos = [], var todos = [],
stat = {}, stat = {},
ENTER_KEY = 13; ENTER_KEY = 13;
window.addEventListener( "load", windowLoadHandler, false ); window.addEventListener( "load", windowLoadHandler, false );
function Todo( title, completed ) { function Todo( title, completed ) {
this.id = getUuid(); this.id = getUuid();
this.title = title; this.title = title;
this.completed = completed; this.completed = completed;
} }
function Stat() { function Stat() {
this.todoLeft = 0; this.todoLeft = 0;
this.todoCompleted = 0; this.todoCompleted = 0;
this.totalTodo = 0; this.totalTodo = 0;
} }
function windowLoadHandler() { function windowLoadHandler() {
loadTodos(); loadTodos();
refreshData(); refreshData();
addEventListeners(); addEventListeners();
} }
function addEventListeners() { function addEventListeners() {
document.getElementById( 'new-todo' ).addEventListener( "keypress", newTodoKeyPressHandler, false ); document.getElementById( 'new-todo' ).addEventListener( "keypress", newTodoKeyPressHandler, false );
document.getElementById( 'toggle-all' ).addEventListener( "change", toggleAllChangeHandler, false ); document.getElementById( 'toggle-all' ).addEventListener( "change", toggleAllChangeHandler, false );
} }
function inputEditTodoKeyPressHandler( event ) { function inputEditTodoKeyPressHandler( event ) {
var inputEditTodo, var inputEditTodo,
trimmedText, trimmedText,
todoId; todoId;
inputEditTodo = event.target; inputEditTodo = event.target;
trimmedText = inputEditTodo.value.trim(); trimmedText = inputEditTodo.value.trim();
todoId = event.target.id.slice( 6 ); todoId = event.target.id.slice( 6 );
if ( trimmedText ) { if ( trimmedText ) {
if ( event.keyCode === ENTER_KEY ) { if ( event.keyCode === ENTER_KEY ) {
editTodo( todoId, trimmedText ); editTodo( todoId, trimmedText );
} }
} }
else { else {
removeTodoById( todoId ); removeTodoById( todoId );
refreshData(); refreshData();
} }
} }
function inputEditTodoBlurHandler( event ) { function inputEditTodoBlurHandler( event ) {
var inputEditTodo, var inputEditTodo,
todoId; todoId;
inputEditTodo = event.target; inputEditTodo = event.target;
todoId = event.target.id.slice( 6 ); todoId = event.target.id.slice( 6 );
editTodo( todoId, inputEditTodo.value ); editTodo( todoId, inputEditTodo.value );
} }
function newTodoKeyPressHandler( event ) { function newTodoKeyPressHandler( event ) {
if ( event.keyCode === ENTER_KEY ) { if ( event.keyCode === ENTER_KEY ) {
addTodo( document.getElementById( 'new-todo' ).value ); addTodo( document.getElementById( 'new-todo' ).value );
} }
} }
function toggleAllChangeHandler( event ) { function toggleAllChangeHandler( event ) {
for ( var i in todos ) { for ( var i in todos ) {
todos[i].completed = event.target.checked; todos[i].completed = event.target.checked;
} }
refreshData(); refreshData();
} }
function spanDeleteClickHandler( event ) { function spanDeleteClickHandler( event ) {
removeTodoById( event.target.getAttribute( 'data-todo-id' ) ); removeTodoById( event.target.getAttribute( 'data-todo-id' ) );
refreshData(); refreshData();
} }
function hrefClearClickHandler() { function hrefClearClickHandler() {
removeTodosCompleted(); removeTodosCompleted();
refreshData(); refreshData();
} }
function todoContentHandler( event ) { function todoContentHandler( event ) {
var todoId, var todoId,
div, div,
inputEditTodo; inputEditTodo;
todoId = event.target.getAttribute( 'data-todo-id' ); todoId = event.target.getAttribute( 'data-todo-id' );
div = document.getElementById( 'li_'+todoId ); div = document.getElementById( 'li_'+todoId );
div.className = 'editing'; div.className = 'editing';
inputEditTodo = document.getElementById( 'input_' + todoId ); inputEditTodo = document.getElementById( 'input_' + todoId );
inputEditTodo.focus(); inputEditTodo.focus();
} }
function checkboxChangeHandler( event ) { function checkboxChangeHandler( event ) {
var checkbox, var checkbox,
todo; todo;
checkbox = event.target; checkbox = event.target;
todo = getTodoById( checkbox.getAttribute( 'data-todo-id' ) ); todo = getTodoById( checkbox.getAttribute( 'data-todo-id' ) );
todo.completed = checkbox.checked; todo.completed = checkbox.checked;
refreshData(); refreshData();
} }
function loadTodos() { function loadTodos() {
if ( !localStorage.getItem( 'todos-vanillajs' ) ) { if ( !localStorage.getItem( 'todos-vanillajs' ) ) {
localStorage.setItem( 'todos-vanillajs', JSON.stringify( [] ) ); localStorage.setItem( 'todos-vanillajs', JSON.stringify( [] ) );
} }
todos = JSON.parse( localStorage.getItem( 'todos-vanillajs' ) ); todos = JSON.parse( localStorage.getItem( 'todos-vanillajs' ) );
} }
function addTodo( text ) { function addTodo( text ) {
var trimmedText = text.trim(); var trimmedText = text.trim();
if ( trimmedText ) { if ( trimmedText ) {
var todo = new Todo( trimmedText, false ); var todo = new Todo( trimmedText, false );
todos.push( todo ); todos.push( todo );
refreshData(); refreshData();
} }
} }
function editTodo( todoId, text ) { function editTodo( todoId, text ) {
var i; var i;
for ( i=0; i < todos.length; i++ ) { for ( i=0; i < todos.length; i++ ) {
if ( todos[i].id === todoId ) { if ( todos[i].id === todoId ) {
todos[i].title = text; todos[i].title = text;
} }
} }
refreshData(); refreshData();
} }
function removeTodoById( id ) { function removeTodoById( id ) {
var i; var i;
for ( i=0; i < todos.length; i++ ) { for ( i=0; i < todos.length; i++ ) {
if ( todos[i].id === id ) { if ( todos[i].id === id ) {
todos.splice( i, 1 ); todos.splice( i, 1 );
} }
} }
} }
function removeTodosCompleted() { function removeTodosCompleted() {
var i = todos.length-1; var i = todos.length-1;
while ( i >= 0 ) { while ( i >= 0 ) {
if ( todos[i].completed ) { if ( todos[i].completed ) {
todos.splice( i, 1 ); todos.splice( i, 1 );
} }
--i; --i;
} }
} }
function getTodoById( id ) { function getTodoById( id ) {
var i; var i;
for ( i=0; i < todos.length; i++ ) { for ( i=0; i < todos.length; i++ ) {
if ( todos[i].id === id ) { if ( todos[i].id === id ) {
return todos[i]; return todos[i];
} }
} }
} }
function refreshData() { function refreshData() {
saveTodos(); saveTodos();
computeStats(); computeStats();
redrawTodosUI(); redrawTodosUI();
redrawStatsUI(); redrawStatsUI();
changeToggleAllCheckboxState(); changeToggleAllCheckboxState();
} }
function saveTodos() { function saveTodos() {
localStorage.setItem( 'todos-vanillajs', JSON.stringify( todos ) ); localStorage.setItem( 'todos-vanillajs', JSON.stringify( todos ) );
} }
function computeStats() { function computeStats() {
var i; var i;
stat = new Stat(); stat = new Stat();
stat.totalTodo = todos.length; stat.totalTodo = todos.length;
for ( i=0; i < todos.length; i++ ) { for ( i=0; i < todos.length; i++ ) {
if ( todos[i].completed ) { if ( todos[i].completed ) {
stat.todoCompleted += 1; stat.todoCompleted += 1;
} }
} }
stat.todoLeft = stat.totalTodo - stat.todoCompleted; stat.todoLeft = stat.totalTodo - stat.todoCompleted;
} }
function redrawTodosUI() { function redrawTodosUI() {
var ul, var ul,
todo, todo,
checkbox, checkbox,
label, label,
deleteLink, deleteLink,
divDisplay, divDisplay,
inputEditTodo, inputEditTodo,
li, li,
i; i;
ul = document.getElementById( 'todo-list' ); ul = document.getElementById( 'todo-list' );
document.getElementById( 'main' ).style.display = todos.length ? 'block' : 'none'; document.getElementById( 'main' ).style.display = todos.length ? 'block' : 'none';
ul.innerHTML = ""; ul.innerHTML = "";
document.getElementById( 'new-todo' ).value = ''; document.getElementById( 'new-todo' ).value = '';
for ( i= 0; i < todos.length; i++ ) { for ( i= 0; i < todos.length; i++ ) {
todo = todos[i]; todo = todos[i];
//create checkbox //create checkbox
checkbox = document.createElement( 'input' ); checkbox = document.createElement( 'input' );
checkbox.className = 'toggle'; checkbox.className = 'toggle';
checkbox.setAttribute( 'data-todo-id', todo.id ); checkbox.setAttribute( 'data-todo-id', todo.id );
checkbox.type = 'checkbox'; checkbox.type = 'checkbox';
checkbox.addEventListener( 'change', checkboxChangeHandler ); checkbox.addEventListener( 'change', checkboxChangeHandler );
//create div text //create div text
label = document.createElement( 'label' ); label = document.createElement( 'label' );
label.setAttribute( 'data-todo-id', todo.id ); label.setAttribute( 'data-todo-id', todo.id );
label.appendChild( document.createTextNode( todo.title ) ); label.appendChild( document.createTextNode( todo.title ) );
//create delete button //create delete button
deleteLink = document.createElement( 'button' ); deleteLink = document.createElement( 'button' );
deleteLink.className = 'destroy'; deleteLink.className = 'destroy';
deleteLink.setAttribute( 'data-todo-id', todo.id ); deleteLink.setAttribute( 'data-todo-id', todo.id );
deleteLink.addEventListener( 'click', spanDeleteClickHandler ); deleteLink.addEventListener( 'click', spanDeleteClickHandler );
//create divDisplay //create divDisplay
divDisplay = document.createElement( 'div' ); divDisplay = document.createElement( 'div' );
divDisplay.className = 'view'; divDisplay.className = 'view';
divDisplay.setAttribute( 'data-todo-id', todo.id ); divDisplay.setAttribute( 'data-todo-id', todo.id );
divDisplay.appendChild( checkbox ); divDisplay.appendChild( checkbox );
divDisplay.appendChild( label ); divDisplay.appendChild( label );
divDisplay.appendChild( deleteLink ); divDisplay.appendChild( deleteLink );
divDisplay.addEventListener( 'dblclick', todoContentHandler ); divDisplay.addEventListener( 'dblclick', todoContentHandler );
//create todo input //create todo input
inputEditTodo = document.createElement( 'input' ); inputEditTodo = document.createElement( 'input' );
inputEditTodo.id = 'input_' + todo.id; inputEditTodo.id = 'input_' + todo.id;
inputEditTodo.className = 'edit'; inputEditTodo.className = 'edit';
inputEditTodo.value = todo.title; inputEditTodo.value = todo.title;
inputEditTodo.addEventListener( 'keypress', inputEditTodoKeyPressHandler ); inputEditTodo.addEventListener( 'keypress', inputEditTodoKeyPressHandler );
inputEditTodo.addEventListener( 'blur', inputEditTodoBlurHandler ); inputEditTodo.addEventListener( 'blur', inputEditTodoBlurHandler );
//create li //create li
li = document.createElement( 'li' ); li = document.createElement( 'li' );
li.id = 'li_' + todo.id; li.id = 'li_' + todo.id;
li.appendChild( divDisplay ); li.appendChild( divDisplay );
li.appendChild( inputEditTodo ); li.appendChild( inputEditTodo );
if ( todo.completed ) if ( todo.completed )
{ {
li.className += 'complete'; li.className += 'complete';
checkbox.checked = true; checkbox.checked = true;
} }
ul.appendChild( li ); ul.appendChild( li );
} }
} }
function changeToggleAllCheckboxState() { function changeToggleAllCheckboxState() {
var toggleAll = document.getElementById( 'toggle-all' ); var toggleAll = document.getElementById( 'toggle-all' );
if ( stat.todoCompleted === todos.length ) { if ( stat.todoCompleted === todos.length ) {
toggleAll.checked = true; toggleAll.checked = true;
} else { } else {
toggleAll.checked = false; toggleAll.checked = false;
} }
} }
function redrawStatsUI() { function redrawStatsUI() {
removeChildren( document.getElementsByTagName( 'footer' )[ 0 ] ); removeChildren( document.getElementsByTagName( 'footer' )[ 0 ] );
document.getElementById( 'footer' ).style.display = todos.length ? 'block' : 'none'; document.getElementById( 'footer' ).style.display = todos.length ? 'block' : 'none';
if ( stat.todoCompleted > 0 ) { if ( stat.todoCompleted > 0 ) {
drawTodoClear(); drawTodoClear();
} }
if ( stat.totalTodo > 0 ) { if ( stat.totalTodo > 0 ) {
drawTodoCount(); drawTodoCount();
} }
} }
function drawTodoCount() { function drawTodoCount() {
var number, var number,
theText, theText,
remaining; remaining;
// Create remaining count // Create remaining count
number = document.createElement( 'strong' ); number = document.createElement( 'strong' );
number.innerHTML = stat.todoLeft; number.innerHTML = stat.todoLeft;
theText = ' item'; theText = ' item';
if ( stat.todoLeft !== 1 ) { if ( stat.todoLeft !== 1 ) {
theText += 's'; theText += 's';
} }
theText += ' left'; theText += ' left';
remaining = document.createElement( 'span' ); remaining = document.createElement( 'span' );
remaining.id = 'todo-count'; remaining.id = 'todo-count';
remaining.appendChild( number ); remaining.appendChild( number );
remaining.appendChild( document.createTextNode( theText ) ); remaining.appendChild( document.createTextNode( theText ) );
document.getElementsByTagName( 'footer' )[ 0 ].appendChild( remaining ); document.getElementsByTagName( 'footer' )[ 0 ].appendChild( remaining );
} }
function drawTodoClear() { function drawTodoClear() {
var buttonClear = document.createElement( 'button' ); var buttonClear = document.createElement( 'button' );
buttonClear.id = 'clear-completed'; buttonClear.id = 'clear-completed';
buttonClear.addEventListener( 'click', hrefClearClickHandler ); buttonClear.addEventListener( 'click', hrefClearClickHandler );
buttonClear.innerHTML = 'Clear completed (' + stat.todoCompleted + ')'; buttonClear.innerHTML = 'Clear completed (' + stat.todoCompleted + ')';
document.getElementsByTagName( 'footer' )[ 0 ].appendChild( buttonClear ); document.getElementsByTagName( 'footer' )[ 0 ].appendChild( buttonClear );
} }
function removeChildren( node ) { function removeChildren( node ) {
while ( node.firstChild ) { while ( node.firstChild ) {
node.removeChild( node.firstChild ); node.removeChild( node.firstChild );
} }
} }
function getUuid() { function getUuid() {
var uuid = '', var uuid = '',
i, i,
random; random;
for ( i = 0; i < 32; i++ ) { for ( i = 0; i < 32; i++ ) {
random = Math.random() * 16 | 0; random = Math.random() * 16 | 0;
if ( i === 8 || i === 12 || i === 16 || i === 20 ) { if ( i === 8 || i === 12 || i === 16 || i === 20 ) {
uuid += '-'; uuid += '-';
} }
uuid += ( i === 12 ? 4 : (i === 16 ? (random & 3 | 8) : random) ).toString( 16 ); uuid += ( i === 12 ? 4 : (i === 16 ? (random & 3 | 8) : random) ).toString( 16 );
} }
return uuid; return uuid;
} }
\ No newline at end of file
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