Commit 3560728d authored by Aaron Boushley's avatar Aaron Boushley

Merging Pull Request 34. Vanilla JS implementation.

parents 73817d73 282c89f2
......@@ -80,19 +80,20 @@
<h5>Live demos</h5>
<ul>
<li><a href="todo-example/emberjs/index.html">Ember.js</a></li>
<li><a href="todo-example/javascriptmvc/todo/todo/index.html">JavaScriptMVC</a></li>
<li><a href="todo-example/spine/index.html">Spine.js</a></li>
<li><a href="todo-example/backbone/index.html">Backbone.js</a></li>
<li><a href="todo-example/backbone_require/index.html">Backbone.js + RequireJS</a></li>
<li><a href="todo-example/sammyjs/index.html">Sammy.js</a></li>
<li><a href="todo-example/knockback/todos-classic/index.html">Knockback.js</a></li>
<li><a href="todo-example/knockoutjs/index.html">KnockoutJS (MVVM)</a></li>
<li><a href="todo-example/yuilibrary/index.html">YUILibrary</a></li>
<li><a href="todo-example/angularjs/main/index.html">AngularJS</a></li>
<li><a href="todo-example/angularjs/persistencejs/index.html">Angular + PersistenceJS</a></li>
<li><a href="todo-example/broke/index.html">Broke.js</a></li>
<li><a href="todo-example/fidel/index.html">Fidel.js</a></li>
<li><a href="todo-example/emberjs/index.html">Ember.js</a></li>
<li><a href="todo-example/javascriptmvc/todo/todo/index.html">JavaScriptMVC</a></li>
<li><a href="todo-example/spine/index.html">Spine.js</a></li>
<li><a href="todo-example/backbone/index.html">Backbone.js</a></li>
<li><a href="todo-example/backbone_require/index.html">Backbone.js + RequireJS</a></li>
<li><a href="todo-example/sammyjs/index.html">Sammy.js</a></li>
<li><a href="todo-example/knockback/todos-classic/index.html">Knockback.js</a></li>
<li><a href="todo-example/knockoutjs/index.html">KnockoutJS (MVVM)</a></li>
<li><a href="todo-example/yuilibrary/index.html">YUILibrary</a></li>
<li><a href="todo-example/angularjs/main/index.html">AngularJS</a></li>
<li><a href="todo-example/angularjs/persistencejs/index.html">Angular + PersistenceJS</a></li>
<li><a href="todo-example/broke/index.html">Broke.js</a></li>
<li><a href="todo-example/fidel/index.html">Fidel.js</a></li>
<li><a href="todo-example/vanillajs/index.html">Vanilla JS</a></li>
</ul>
<h5>Contributors</h5>
......@@ -109,6 +110,7 @@
<li><a href="https://github.com/jacobmumm">Jacob Mumm</a></li>
<li><a href="https://github.com/brokenseal">Davide Callegari</a></li>
<li><a href="https://github.com/kmalakoff">Kevin Malakoff</a></li>
<li><a href="https://twitter.com/ffesseler">Florian Fesseler</a></li>
</ul>
<h5>Coming Soon</h5>
......@@ -117,6 +119,7 @@
<li>Dojo Todo app (with MVC patterns)</li>
<li>Batman.js Todo app</li>
<li>Todo app boilerplate</li>
<li>Todo app pure JS : no framework, no MVC</li>
</ul>
</div>
......
This diff is collapsed.
<!DOCTYPE html>
<html>
<head>
<link href="css/todos.css" rel="stylesheet" type="text/css">
<script src="js/todo.js"></script>
<script src="js/json2.js"></script>
</head>
<body onload="bodyLoadHandler()">
<div id="todoapp">
<div class="title">
<h1>Todos</h1>
</div>
<div class="content">
<div id="create-todo">
<input id="new-todo" placeholder="What needs to be done?" onkeypress="newTodoKeyPressHandler(event)">
<span class="ui-tooltip-top" style="display:none;">Press Enter to save this task</span>
</div>
<div id="todos">
<ul id="todo-list">
</ul>
</div>
<div id="todo-stats">
</div>
</div>
</div>
</body>
</html>
\ No newline at end of file
/* json2.js
* 2008-01-17
* Public Domain
* No warranty expressed or implied. Use at your own risk.
* See http://www.JSON.org/js.html
*/
if(!this.JSON){JSON=function(){function f(n){return n<10?'0'+n:n;}
Date.prototype.toJSON=function(){return this.getUTCFullYear()+'-'+
f(this.getUTCMonth()+1)+'-'+
f(this.getUTCDate())+'T'+
f(this.getUTCHours())+':'+
f(this.getUTCMinutes())+':'+
f(this.getUTCSeconds())+'Z';};var m={'\b':'\\b','\t':'\\t','\n':'\\n','\f':'\\f','\r':'\\r','"':'\\"','\\':'\\\\'};function stringify(value,whitelist){var a,i,k,l,r=/["\\\x00-\x1f\x7f-\x9f]/g,v;switch(typeof value){case'string':return r.test(value)?'"'+value.replace(r,function(a){var c=m[a];if(c){return c;}
c=a.charCodeAt();return'\\u00'+Math.floor(c/16).toString(16)+
(c%16).toString(16);})+'"':'"'+value+'"';case'number':return isFinite(value)?String(value):'null';case'boolean':case'null':return String(value);case'object':if(!value){return'null';}
if(typeof value.toJSON==='function'){return stringify(value.toJSON());}
a=[];if(typeof value.length==='number'&&!(value.propertyIsEnumerable('length'))){l=value.length;for(i=0;i<l;i+=1){a.push(stringify(value[i],whitelist)||'null');}
return'['+a.join(',')+']';}
if(whitelist){l=whitelist.length;for(i=0;i<l;i+=1){k=whitelist[i];if(typeof k==='string'){v=stringify(value[k],whitelist);if(v){a.push(stringify(k)+':'+v);}}}}else{for(k in value){if(typeof k==='string'){v=stringify(value[k],whitelist);if(v){a.push(stringify(k)+':'+v);}}}}
return'{'+a.join(',')+'}';}}
return{stringify:stringify,parse:function(text,filter){var j;function walk(k,v){var i,n;if(v&&typeof v==='object'){for(i in v){if(Object.prototype.hasOwnProperty.apply(v,[i])){n=walk(i,v[i]);if(n!==undefined){v[i]=n;}}}}
return filter(k,v);}
if(/^[\],:{}\s]*$/.test(text.replace(/\\./g,'@').replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,']').replace(/(?:^|:|,)(?:\s*\[)+/g,''))){j=eval('('+text+')');return typeof filter==='function'?walk('',j):j;}
throw new SyntaxError('parseJSON');}};}();}
\ No newline at end of file
var tasks = [];
var stat;
/**************************/
/* MODEL /
/**************************/
function Todo(name, done) {
this.id = uuid();
this.name = name;
this.done = done;
}
function Stat() {
this.todoLeft = 0;
this.todoCompleted = 0;
this.totalTodo = 0;
}
/**************************/
/* EVENT HANDLERS /
/**************************/
function bodyLoadHandler() {
loadTasks();
refreshData();
}
function inputEditTodoKeyPressHandler(event) {
var inputEditTodo = event.target;
var taskId = event.target.id.slice(6);
if (event.keyCode === 13) {
editTask(taskId, inputEditTodo.value);
}
}
function newTodoKeyPressHandler(event) {
if (event.keyCode === 13) {
addTask(document.getElementById("new-todo").value);
}
}
function spanDeleteClickHandler(event) {
removeTaskById(event.target.id);
refreshData();
}
function hrefClearClickHandler() {
removeTasksDone();
refreshData();
}
function todoContentHandler(event) {
var taskId = event.target.id;
var div = document.getElementById("li_"+taskId);
div.className = "editing";
var inputEditTodo = document.getElementById("input_"+taskId);
inputEditTodo.focus();
}
function checkboxChangeHandler(event) {
var checkbox = event.target;
var todo = getTodoById(checkbox.id);
todo.done = checkbox.checked;
refreshData();
}
/**************************/
/* ACTIONS /
/**************************/
function loadTasks() {
if (!localStorage.todo) {
localStorage.todo = JSON.stringify([]);
}
tasks = JSON.parse(localStorage['todo']);
}
function addTask(text) {
var todo = new Todo(text, false);
tasks.push(todo);
refreshData();
}
function editTask(taskId, text) {
for (var i=0; i < tasks.length; i++) {
if (tasks[i].id === taskId) {
tasks[i].name = text;
}
}
refreshData();
}
function removeTaskById(id) {
for (var i=0; i < tasks.length; i++) {
if (tasks[i].id === id) {
tasks.splice(i, 1);
}
}
}
function removeTasksDone() {
for (var i=tasks.length-1; i >= 0; --i) {
if (tasks[i].done) {
tasks.splice(i, 1);
}
}
}
function getTodoById(id) {
for (var i=0; i < tasks.length; i++) {
if (tasks[i].id === id) {
return tasks[i];
}
}
}
function refreshData() {
saveTasks();
computeStats();
redrawTasksUI();
redrawStatsUI();
}
function saveTasks() {
localStorage['todo'] = JSON.stringify(tasks);
}
function computeStats() {
stat = new Stat();
stat.totalTodo = tasks.length;
for (var i=0; i < tasks.length; i++) {
if (tasks[i].done) {
stat.todoCompleted += 1;
}
}
stat.todoLeft = stat.totalTodo - stat.todoCompleted;
}
/**************************/
/* DRAWING /
/**************************/
function redrawTasksUI() {
var ul = document.getElementById("todo-list");
var todo;
removeChildren(ul);
document.getElementById("new-todo").value = "";
for (var i= 0; i < tasks.length; i++) {
todo = tasks[i];
//create checkbox
var checkbox = document.createElement("input");
checkbox.className = "check";
checkbox.id = todo.id;
checkbox.type = "checkbox";
checkbox.addEventListener("change", checkboxChangeHandler);
//create div text
var divText = document.createElement("div");
divText.className = "todo-content";
divText.id = todo.id;
divText.appendChild(document.createTextNode(todo.name));
divText.addEventListener("dblclick", todoContentHandler);
//create delete button
var spanDelete = document.createElement("span");
spanDelete.className = "todo-destroy";
spanDelete.id = todo.id;
spanDelete.addEventListener("click", spanDeleteClickHandler);
//create divDisplay
var divDisplay = document.createElement("div");
divDisplay.className = "display";
divDisplay.appendChild(checkbox);
divDisplay.appendChild(divText);
divDisplay.appendChild(spanDelete);
//create div todo
var divTodo = document.createElement("div");
divTodo.className = "todo ";
divTodo.appendChild(divDisplay);
//create todo input
var inputEditTodo = document.createElement("input");
inputEditTodo.id = "input_" + todo.id;
inputEditTodo.type = "text";
inputEditTodo.className = "todo-input";
inputEditTodo.value = todo.name;
inputEditTodo.addEventListener("keypress", inputEditTodoKeyPressHandler);
//create div edit
var divEdit = document.createElement("div");
divEdit.className = "edit";
divEdit.appendChild(inputEditTodo);
//create li
var li = document.createElement("li");
li.id = "li_" + todo.id;
li.appendChild(divTodo);
li.appendChild(divEdit);
if (todo.done)
{
divTodo.className += "done";
checkbox.checked = true;
}
ul.appendChild(li);
}
}
function redrawStatsUI() {
removeChildren(document.getElementById("todo-stats"))
if (stat.totalTodo > 0) {
drawTodoCount();
}
if (stat.todoCompleted > 0) {
drawTodoClear();
}
}
function drawTodoCount() {
//create span number
var spanNumber = document.createElement("span");
spanNumber.className = "number";
spanNumber.innerHTML = stat.todoLeft;
//create span word
var spanWord = document.createElement("span");
spanWord.className = "word";
spanWord.innerHTML = " item";
if (stat.todoLeft > 1) {
spanWord.innerHTML += "s";
}
var spanTodoCount = document.createElement("span");
spanTodoCount.className = "todo-count";
spanTodoCount.appendChild(spanNumber);
spanTodoCount.appendChild(spanWord);
spanTodoCount.innerHTML += " left.";
document.getElementById("todo-stats").appendChild(spanTodoCount);
}
function drawTodoClear() {
//create a href
var hrefClear = document.createElement("a");
hrefClear.href = "#";
hrefClear.addEventListener("click", hrefClearClickHandler);
hrefClear.innerHTML = "Clear ";
//create span number done
var spanNumberDone = document.createElement("span");
spanNumberDone.className = "number-done";
spanNumberDone.innerHTML = stat.todoCompleted;
hrefClear.appendChild(spanNumberDone);
hrefClear.innerHTML += " completed ";
//create span word
var spanWordDone = document.createElement("span");
spanWordDone.className = "word-done";
spanWordDone.innerHTML = " item";
if (stat.todoCompleted > 1) {
spanWordDone.innerHTML += "s";
}
hrefClear.appendChild(spanWordDone);
var spanTodoClear = document.createElement("span");
spanTodoClear.className = "todo-clear";
spanTodoClear.appendChild(hrefClear);
document.getElementById("todo-stats").appendChild(spanTodoClear);
}
function removeChildren(node) {
while (node.hasChildNodes()) {
node.removeChild(node.firstChild);
}
}
/**************************/
/* UTILS /
/**************************/
function uuid() {
var uuid = "", i, random;
for (i = 0; i < 32; i++) {
random = Math.random() * 16 | 0;
if (i == 8 || i == 12 || i == 16 || i == 20) {
uuid += "-"
}
uuid += (i == 12 ? 4 : (i == 16 ? (random & 3 | 8) : random)).toString(16);
}
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