Created
July 27, 2012 01:09
-
-
Save OscarGodson/3185561 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// We'll wrap our app in the "app" namespace | |
app = { | |
model: {} | |
, view: {} | |
, controller: {} | |
}; | |
// Setup our data if this is the first time opening our app | |
app.data = { | |
init: function(){ | |
var data, dbName; | |
this._dbName = 'todos-vanillajs'; | |
dbName = this._dbName; | |
if(!localStorage[dbName]){ | |
data = { | |
tasks: {} | |
, id: 0 | |
} | |
localStorage[dbName] = JSON.stringify(data); | |
} | |
this._data = localStorage[dbName]; | |
} | |
// NOTE: In a real app this would be like an AJAX GET request | |
, payload: function(){ | |
return JSON.parse(localStorage[this._dbName]); | |
} | |
// NOTE: In a real app this would be like an AJAX POST request | |
, sync: function(data){ | |
localStorage[this._dbName] = JSON.stringify(data); | |
} | |
} | |
// OK, init the data... in a real app this would be a | |
// DB connection or something | |
app.data.init(); | |
// Defined our model | |
app.model.Tasks = { | |
create: function(task){ | |
if(task == undefined){ | |
throw new Error('No task was given'); | |
} | |
var data = app.data.payload(); | |
data.tasks[data.id] = { "task": task, status: 0 }; | |
data.id = data.id + 1; | |
app.data.sync(data); | |
return this; | |
} | |
, read: function(id){ | |
var data = app.data.payload(); | |
if(id == undefined){ | |
return data.tasks; | |
} | |
else if(!data.tasks[id]){ | |
throw new Error('No task found with that ID'); | |
} | |
else{ | |
return data.tasks[id]; | |
} | |
} | |
, update: function(id, newData){ | |
var data = app.data.payload(); | |
if(id == undefined || data.tasks[id] == undefined){ | |
throw new Error('No task found with that ID'); | |
} | |
else{ | |
for(x in newData){ | |
data.tasks[id][x] = newData[x]; | |
} | |
app.data.sync(data); | |
} | |
return this; | |
} | |
, destroy: function(id){ | |
var data = app.data.payload(); | |
if(id == undefined){ | |
data.tasks = {}; | |
} | |
else if(data.tasks[id] == undefined){ | |
throw new Error('No task found with that ID'); | |
} | |
else{ | |
delete data.tasks[id]; | |
} | |
app.data.sync(data); | |
return this; | |
} | |
} | |
// Define our view | |
app.view.Tasks = { | |
task: function(data){ | |
var template, output, html, task, done; | |
template = '' + | |
'<li id="task-{{id}}" data-task-id="{{id}}">' + | |
'<div class="todo {{done}}">' + | |
'<div class="display">' + | |
'<input {{checked}} class="check" type="checkbox" data-task-id="{{id}}">' + | |
'<div class="todo-content">{{task}}</div>' + | |
'<span class="todo-destroy" data-task-id="{{id}}"></span>' + | |
'</div>' + | |
'</div>' + | |
'</li>'; | |
for(x in data){ | |
// Clone our template or... | |
if(output == undefined){ | |
output = template; | |
} | |
// Add to our already created clone | |
else{ | |
output = output+template; | |
} | |
task = data[x]; | |
// Add the "checked" attribute if it's been done | |
if(task.status == '1'){ | |
checked = 'checked'; | |
done = 'done'; | |
} | |
else{ | |
checked = ''; | |
done = ''; | |
} | |
// Replace our tags with data | |
// NOTE: This _should_ use something like Mustache.js in the real world | |
output = output.replace(/{{id}}/g,x); | |
output = output.replace(/{{task}}/g,task.task); | |
output = output.replace(/{{checked}}/g,checked); | |
output = output.replace(/{{done}}/g,done); | |
} | |
//If there is no output return a blank string | |
return output ? output : ''; | |
} | |
, stats: function(data){ | |
var template | |
, todo = [] | |
, done = [] | |
, todoPlural = '' | |
, donePlural = ''; | |
todoTemplate = '' + | |
'<div class="todo-count">' + | |
'<span class="number">{{todo-count}}</span> ' + | |
'<span class="word">item{{todo-plural}}</span>' + | |
'</div>'; | |
doneTemplate = '' + | |
'<div class="todo-clear">' + | |
'<a href="#">' + | |
'Clear ' + | |
'<span class="number-done">{{done-count}}</span>' + | |
' completed ' + | |
'<span>item{{done-plural}}</span>' + | |
'</a>' + | |
'</div>'; | |
for(x in data){ | |
if(data[x].status == 1){ | |
done.push(x); | |
} | |
else{ | |
todo.push(x); | |
} | |
} | |
if(done.length !== 1){ | |
donePlural = 's'; | |
} | |
if(todo.length !== 1){ | |
todoPlural = 's'; | |
} | |
todoTemplate = todoTemplate.replace(/{{todo-count}}/, todo.length); | |
todoTemplate = todoTemplate.replace(/{{todo-plural}}/, todoPlural); | |
if(done.length > 0){ | |
doneTemplate = doneTemplate.replace(/{{done-count}}/, done.length); | |
doneTemplate = doneTemplate.replace(/{{done-plural}}/, donePlural); | |
} | |
else{ | |
doneTemplate = ''; | |
} | |
return todoTemplate+doneTemplate; | |
} | |
} | |
// Define our controller | |
app.controller.Tasks = { | |
create: function(e){ | |
if(e.keyCode == 13){ | |
app.model.Tasks.create(this.value); | |
app.controller.Tasks.render(); | |
this.value = ''; | |
} | |
} | |
, update: function(e){ | |
var done = 0 | |
, data = app.data.payload().tasks; | |
if(e.target.className == 'check'){ | |
if(e.target.checked){ | |
done = 1; | |
} | |
app.model.Tasks.update(e.target.dataset.taskId, { status: done }); | |
} | |
if(e.target.className == 'todo-destroy'){ | |
app.model.Tasks.destroy(e.target.dataset.taskId); | |
} | |
console.log(e.target.nodeName); | |
//while(e.target.nodeName !== 'DIV'){ | |
if(e.target.className == 'todo-clear'){ | |
for(x in data){ | |
if(data[x].status == 1){ | |
app.model.Tasks.destroy(x); | |
} | |
} | |
} | |
//} | |
//Refresh the view | |
app.controller.Tasks.render(); | |
} | |
, render: function(){ | |
var data = app.data.payload().tasks; | |
document.getElementById('todo-list').innerHTML = app.view.Tasks.task(data); | |
document.getElementById('todo-stats').innerHTML = app.view.Tasks.stats(data); | |
} | |
} | |
// When a user hits enter on the input | |
document.getElementById('new-todo').addEventListener('keyup', app.controller.Tasks.create); | |
// Delegated event that contains events for everything in the <li>s like delete and update | |
document.getElementById('todoapp').addEventListener('click', app.controller.Tasks.update, true); | |
// Initial view load | |
document.addEventListener("DOMContentLoaded", app.controller.Tasks.render, false); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment