diff --git a/lab3_mvc/javascript/simpleview/controller.js b/lab3_mvc/javascript/simpleview/controller.js new file mode 100644 index 0000000..9c5cca4 --- /dev/null +++ b/lab3_mvc/javascript/simpleview/controller.js @@ -0,0 +1,70 @@ + +/** + + A poor man's controller - a very simple module with basic MVC functionaliies + +**/ +(function(exports) { + + var TodoModel = function() { + this.contents = ''; + this.listeners = []; + } + + TodoModel.prototype.setContents = function(contents) { + if (this.contents !== contents) { + this.contents = contents; + this.notifyListeners(); + } + } + + TodoModel.prototype.bindToInput = function(input) { + var _this = this; + + var eventHandler = function(e) { + if (typeof(e.target.value) != 'undefined') { + _this.setContents(e.target.value); + } + }; + + input.addEventListener('keyup', eventHandler); + input.addEventListener('change', eventHandler); + } + + TodoModel.prototype.bindToView = function(view) { + this.addListener(function(model) { + if (view.setValue) { + view.setValue(model.contents); + } else { + view.innerText=model.contents; + } + }); + } + + TodoModel.prototype.addListener = function(listener) { + this.listeners.push(listener); + } + + TodoModel.prototype.notifyListeners = function() { + var this_ = this; + this.listeners.forEach(function(listener) { + listener(this_); + }); + } + + exports.TodoModel = TodoModel; + +})(window); + + +window.addEventListener('DOMContentLoaded', function() { + + var model = new TodoModel(); + var newTodo = document.getElementById('newTodo'); + var todoText = document.getElementById('todoText'); + + model.bindToView(todoText); + model.bindToInput(newTodo); + +}) + diff --git a/lab3_mvc/javascript/simpleview/icon.png b/lab3_mvc/javascript/simpleview/icon.png new file mode 100644 index 0000000..3c5c99a Binary files /dev/null and b/lab3_mvc/javascript/simpleview/icon.png differ diff --git a/lab3_mvc/javascript/simpleview/index.html b/lab3_mvc/javascript/simpleview/index.html new file mode 100644 index 0000000..3270d55 --- /dev/null +++ b/lab3_mvc/javascript/simpleview/index.html @@ -0,0 +1,18 @@ + + + + + + +

Todo

+
+ + +
+ + + diff --git a/lab3_mvc/javascript/simpleview/main.js b/lab3_mvc/javascript/simpleview/main.js new file mode 100644 index 0000000..48f4770 --- /dev/null +++ b/lab3_mvc/javascript/simpleview/main.js @@ -0,0 +1,5 @@ +chrome.app.runtime.onLaunched.addListener(function() { + chrome.app.window.create('index.html', + {width: 500, height: 309}); +}); + diff --git a/lab3_mvc/javascript/simpleview/manifest.json b/lab3_mvc/javascript/simpleview/manifest.json new file mode 100644 index 0000000..63b3df2 --- /dev/null +++ b/lab3_mvc/javascript/simpleview/manifest.json @@ -0,0 +1,12 @@ +{ + "manifest_version": 2, + "name": "Lab3a Simple MVC", + "version": "1", + "app": { + "background": { + "scripts": ["main.js"] + } + }, + "icons": { "128": "icon.png" } +} + diff --git a/lab3_mvc/javascript/simpleview/todo.css b/lab3_mvc/javascript/simpleview/todo.css new file mode 100644 index 0000000..b35d3dd --- /dev/null +++ b/lab3_mvc/javascript/simpleview/todo.css @@ -0,0 +1,21 @@ +body { + font-family: "Helvetica Neue",Helvetica,Arial,sans-serif; +} + +ul { + list-style: none; +} + +button, input[type=submit] { + background-color: #0074CC; + background-image: linear-gradient(top, #08C, #05C); + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + color: white; +} + +.done-true { + text-decoration: line-through; + color: grey; +} + diff --git a/lab3_mvc/javascript/withcontroller/controller.js b/lab3_mvc/javascript/withcontroller/controller.js new file mode 100644 index 0000000..1821445 --- /dev/null +++ b/lab3_mvc/javascript/withcontroller/controller.js @@ -0,0 +1,164 @@ +/** + + A poor man's controller - a very simple module with basic MVC functionaliies + +**/ +(function(exports) { + + var nextId = 1; + + var TodoModel = function() { + this.todos = {}; + this.listeners = []; + } + + TodoModel.prototype.clearTodos = function() { + this.todos = {}; + this.notifyListeners('removed'); + } + + TodoModel.prototype.archiveDone = function() { + var oldTodos = this.todos; + this.todos={}; + for (var id in oldTodos) { + if ( ! oldTodos[id].isDone ) { + this.todos[id] = oldTodos[id]; + } + } + this.notifyListeners('archived'); + } + + TodoModel.prototype.setTodoState = function(id, isDone) { + if ( this.todos[id].isDone != isDone ) { + this.todos[id].isDone = isDone; + this.notifyListeners('stateChanged', id); + } + } + + TodoModel.prototype.addTodo = function(text, isDone) { + var id = nextId++; + this.todos[id]={'id': id, 'text': text, 'isDone': isDone}; + this.notifyListeners('added', id); + } + + TodoModel.prototype.addListener = function(listener) { + this.listeners.push(listener); + } + + TodoModel.prototype.notifyListeners = function(change, param) { + var this_ = this; + this.listeners.forEach(function(listener) { + listener(this_, change, param); + }); + } + + exports.TodoModel = TodoModel; + +})(window); + + +window.addEventListener('DOMContentLoaded', function() { + + var model = new TodoModel(); + var form = document.querySelector('form'); + var archive = document.getElementById('archive'); + var list = document.getElementById('list'); + var todoTemplate = document.querySelector('#templates > [data-name="list"]'); + + /** + * When the form is submitted, we need to add a new todo and clear the input + **/ + form.addEventListener('submit', function(e) { + var textEl = e.target.querySelector('input[type="text"]'); + model.addTodo(textEl.value, false); + textEl.value=null; + e.preventDefault(); + }); + + + /** + * A simple handler for the archive link + **/ + archive.addEventListener('click', function(e) { + model.archiveDone(); + e.preventDefault(); + }); + + + /** + * Listen to changes in the model and trigger the appropriate changes in the view + **/ + model.addListener(function(model, changeType, param) { + if ( changeType === 'removed' || changeType === 'archived') { + redrawUI(model); + } else if ( changeType === 'added' ) { + drawTodo(model.todos[param], list); + } else if ( changeType === 'stateChanged') { + updateTodo(model.todos[param]); + } + updateCounters(model); + }); + + /** + * Clean the current ToDo list and add elements again + **/ + var redrawUI = function(model) { + list.innerHTML=''; + for (var id in model.todos) { + drawTodo(model.todos[id], list); + } + }; + + /** + * Deep clone a template node, set its ID and add it to the DOM container. + * Add a listener to the newly added checkbox, so it can trigger the state flip + * when the checkbox is clicked. + **/ + var drawTodo = function(todoObj, container) { + var el = todoTemplate.cloneNode(true); + el.setAttribute('data-id', todoObj.id); + container.appendChild(el); + updateTodo(todoObj); + var checkbox = el.querySelector('input[type="checkbox"]'); + checkbox.addEventListener('change', function(e) { + model.setTodoState(todoObj.id, e.target.checked); + }); + } + + + /** + * Find the element corresponding to the given ToDo model object and update its + * state and description from the model. + */ + var updateTodo = function(model) { + var todoElement = list.querySelector('li[data-id="'+model.id+'"]'); + if (todoElement) { + var checkbox = todoElement.querySelector('input[type="checkbox"]'); + var desc = todoElement.querySelector('span'); + checkbox.checked = model.isDone; + desc.innerText = model.text; + desc.className = "done-"+model.isDone; + } + } + + /** + * Recalculate total number of ToDos and remaining ToDos and update + * appropriate elements in the DOM. + **/ + var updateCounters = function(model) { + var count = 0; + var notDone = 0; + for (var id in model.todos) { + count++; + if ( ! model.todos[id].isDone ) { + notDone ++; + } + } + document.getElementById('remaining').innerText = notDone; + document.getElementById('length').innerText = count; + } + + updateCounters(model); + +}); + diff --git a/lab3_mvc/javascript/withcontroller/icon.png b/lab3_mvc/javascript/withcontroller/icon.png new file mode 100644 index 0000000..3c5c99a Binary files /dev/null and b/lab3_mvc/javascript/withcontroller/icon.png differ diff --git a/lab3_mvc/javascript/withcontroller/index.html b/lab3_mvc/javascript/withcontroller/index.html new file mode 100644 index 0000000..c0810b8 --- /dev/null +++ b/lab3_mvc/javascript/withcontroller/index.html @@ -0,0 +1,30 @@ + + + + + + +

Todo

+
+ of remaining + [ archive ] + +
+ + +
+
+ + + + + + + diff --git a/lab3_mvc/javascript/withcontroller/main.js b/lab3_mvc/javascript/withcontroller/main.js new file mode 100644 index 0000000..48f4770 --- /dev/null +++ b/lab3_mvc/javascript/withcontroller/main.js @@ -0,0 +1,5 @@ +chrome.app.runtime.onLaunched.addListener(function() { + chrome.app.window.create('index.html', + {width: 500, height: 309}); +}); + diff --git a/lab3_mvc/javascript/withcontroller/manifest.json b/lab3_mvc/javascript/withcontroller/manifest.json new file mode 100644 index 0000000..c3c11ce --- /dev/null +++ b/lab3_mvc/javascript/withcontroller/manifest.json @@ -0,0 +1,12 @@ +{ + "manifest_version": 2, + "name": "Lab3b MVC with controller", + "version": "1", + "app": { + "background": { + "scripts": ["main.js"] + } + }, + "icons": { "128": "icon.png" } +} + diff --git a/lab3_mvc/javascript/withcontroller/todo.css b/lab3_mvc/javascript/withcontroller/todo.css new file mode 100644 index 0000000..b35d3dd --- /dev/null +++ b/lab3_mvc/javascript/withcontroller/todo.css @@ -0,0 +1,21 @@ +body { + font-family: "Helvetica Neue",Helvetica,Arial,sans-serif; +} + +ul { + list-style: none; +} + +button, input[type=submit] { + background-color: #0074CC; + background-image: linear-gradient(top, #08C, #05C); + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + color: white; +} + +.done-true { + text-decoration: line-through; + color: grey; +} + diff --git a/lab5_data/javascript/1_storage_sync/controller.js b/lab5_data/javascript/1_storage_sync/controller.js new file mode 100644 index 0000000..11e8f6a --- /dev/null +++ b/lab5_data/javascript/1_storage_sync/controller.js @@ -0,0 +1,193 @@ +/** + + A poor man's controller - a very simple module with basic MVC functionaliies + +**/ +(function(exports) { + + var nextId = 1; + + var TodoModel = function() { + this.todos = {}; + this.listeners = []; + } + + TodoModel.prototype.setTodos = function(todos) { + this.todos = todos; + var maxId = 0; + for (var id in todos) { + var idInt = parseInt(id); + maxId = idInt > maxId ? idInt : maxId; + } + nextId = maxId + 1; + this.notifyListeners('reset'); + } + + TodoModel.prototype.clearTodos = function() { + this.todos = {}; + this.notifyListeners('removed'); + } + + TodoModel.prototype.archiveDone = function() { + var oldTodos = this.todos; + this.todos={}; + for (var id in oldTodos) { + if ( ! oldTodos[id].isDone ) { + this.todos[id] = oldTodos[id]; + } + } + this.notifyListeners('archived'); + } + + TodoModel.prototype.setTodoState = function(id, isDone) { + if ( this.todos[id].isDone != isDone ) { + this.todos[id].isDone = isDone; + this.notifyListeners('stateChanged', id); + } + } + + TodoModel.prototype.addTodo = function(text, isDone) { + var id = nextId++; + this.todos[id]={'id': id, 'text': text, 'isDone': isDone}; + this.notifyListeners('added', id); + } + + TodoModel.prototype.addListener = function(listener) { + this.listeners.push(listener); + } + + TodoModel.prototype.notifyListeners = function(change, param) { + var this_ = this; + this.listeners.forEach(function(listener) { + listener(this_, change, param); + }); + } + + exports.TodoModel = TodoModel; + +})(window); + + +window.addEventListener('DOMContentLoaded', function() { + + var model = new TodoModel(); + var form = document.querySelector('form'); + var archive = document.getElementById('archive'); + var list = document.getElementById('list'); + var todoTemplate = document.querySelector('#templates > [data-name="list"]'); + + /** + * When the form is submitted, we need to add a new todo and clear the input + **/ + form.addEventListener('submit', function(e) { + var textEl = e.target.querySelector('input[type="text"]'); + model.addTodo(textEl.value, false); + textEl.value=null; + e.preventDefault(); + }); + + + /** + * A simple handler for the archive link + **/ + archive.addEventListener('click', function(e) { + model.archiveDone(); + e.preventDefault(); + }); + + + /** + * Listen to changes in the model and trigger the appropriate changes in the view + **/ + model.addListener(function(model, changeType, param) { + if ( changeType === 'removed' || changeType === 'archived' || changeType === 'reset') { + redrawUI(model); + } else if ( changeType === 'added' ) { + drawTodo(model.todos[param], list); + } else if ( changeType === 'stateChanged') { + updateTodo(model.todos[param]); + } + storageSave(); + updateCounters(model); + }); + + + // If there is saved data in storage, use it. Otherwise, bootstrap with sample todos + var storageLoad = function() { + chrome.storage.sync.get('todolist', function(value) { + if (value && value.todolist) { + model.setTodos(value.todolist); + } else { + model.addTodo('learn Chrome Apps', true); + model.addTodo('build a Chrome App', false); + } + }); + } + + var storageSave = function() { + chrome.storage.sync.set({'todolist': model.todos}); + }; + + /** + * Clean the current ToDo list and add elements again + **/ + var redrawUI = function(model) { + list.innerHTML=''; + for (var id in model.todos) { + drawTodo(model.todos[id], list); + } + }; + + /** + * Deep clone a template node, set its ID and add it to the DOM container. + * Add a listener to the newly added checkbox, so it can trigger the state flip + * when the checkbox is clicked. + **/ + var drawTodo = function(todoObj, container) { + var el = todoTemplate.cloneNode(true); + el.setAttribute('data-id', todoObj.id); + container.appendChild(el); + updateTodo(todoObj); + var checkbox = el.querySelector('input[type="checkbox"]'); + checkbox.addEventListener('change', function(e) { + model.setTodoState(todoObj.id, e.target.checked); + }); + } + + + /** + * Find the element corresponding to the given ToDo model object and update its + * state and description from the model. + */ + var updateTodo = function(model) { + var todoElement = list.querySelector('li[data-id="'+model.id+'"]'); + if (todoElement) { + var checkbox = todoElement.querySelector('input[type="checkbox"]'); + var desc = todoElement.querySelector('span'); + checkbox.checked = model.isDone; + desc.innerText = model.text; + desc.className = "done-"+model.isDone; + } + } + + /** + * Recalculate total number of ToDos and remaining ToDos and update + * appropriate elements in the DOM. + **/ + var updateCounters = function(model) { + var count = 0; + var notDone = 0; + for (var id in model.todos) { + count++; + if ( ! model.todos[id].isDone ) { + notDone ++; + } + } + document.getElementById('remaining').innerText = notDone; + document.getElementById('length').innerText = count; + } + + storageLoad(); + +}); + diff --git a/lab5_data/javascript/1_storage_sync/icon.png b/lab5_data/javascript/1_storage_sync/icon.png new file mode 100644 index 0000000..ffd3426 Binary files /dev/null and b/lab5_data/javascript/1_storage_sync/icon.png differ diff --git a/lab5_data/javascript/1_storage_sync/index.html b/lab5_data/javascript/1_storage_sync/index.html new file mode 100644 index 0000000..c0810b8 --- /dev/null +++ b/lab5_data/javascript/1_storage_sync/index.html @@ -0,0 +1,30 @@ + + + + + + +

Todo

+
+ of remaining + [ archive ] + +
+ + +
+
+ + + + + + + diff --git a/lab5_data/javascript/1_storage_sync/main.js b/lab5_data/javascript/1_storage_sync/main.js new file mode 100644 index 0000000..48f4770 --- /dev/null +++ b/lab5_data/javascript/1_storage_sync/main.js @@ -0,0 +1,5 @@ +chrome.app.runtime.onLaunched.addListener(function() { + chrome.app.window.create('index.html', + {width: 500, height: 309}); +}); + diff --git a/lab5_data/javascript/1_storage_sync/manifest.json b/lab5_data/javascript/1_storage_sync/manifest.json new file mode 100644 index 0000000..d183837 --- /dev/null +++ b/lab5_data/javascript/1_storage_sync/manifest.json @@ -0,0 +1,13 @@ +{ + "manifest_version": 2, + "name": "Lab5a Storage sync", + "version": "1", + "app": { + "background": { + "scripts": ["main.js"] + } + }, + "permissions": ["storage"], + "icons": { "128": "icon.png" } +} + diff --git a/lab5_data/javascript/1_storage_sync/todo.css b/lab5_data/javascript/1_storage_sync/todo.css new file mode 100644 index 0000000..43f107e --- /dev/null +++ b/lab5_data/javascript/1_storage_sync/todo.css @@ -0,0 +1,23 @@ +body { + font-family: "Helvetica Neue",Helvetica,Arial,sans-serif; +} + +ul { + list-style: none; + max-height: 120px; + overflow-y: auto; +} + +button, input[type=submit] { + background-color: #0074CC; + background-image: linear-gradient(top, #08C, #05C); + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + color: white; +} + +.done-true { + text-decoration: line-through; + color: grey; +} + diff --git a/lab5_data/javascript/2_drop_files/controller.js b/lab5_data/javascript/2_drop_files/controller.js new file mode 100644 index 0000000..7f524c7 --- /dev/null +++ b/lab5_data/javascript/2_drop_files/controller.js @@ -0,0 +1,261 @@ +/** + + A poor man's controller - a very simple module with basic MVC functionaliies + +**/ +(function(exports) { + + var nextId = 1; + + var TodoModel = function() { + this.todos = {}; + this.listeners = []; + } + + TodoModel.prototype.setTodos = function(todos) { + this.todos = todos; + var maxId = 0; + for (var id in todos) { + var idInt = parseInt(id); + maxId = idInt > maxId ? idInt : maxId; + } + nextId = maxId + 1; + this.notifyListeners('reset'); + } + + TodoModel.prototype.clearTodos = function() { + this.todos = {}; + this.notifyListeners('removed'); + } + + TodoModel.prototype.archiveDone = function() { + var oldTodos = this.todos; + this.todos={}; + for (var id in oldTodos) { + if ( ! oldTodos[id].isDone ) { + this.todos[id] = oldTodos[id]; + } + } + this.notifyListeners('archived'); + } + + TodoModel.prototype.setTodoState = function(id, isDone) { + if ( this.todos[id].isDone != isDone ) { + this.todos[id].isDone = isDone; + this.notifyListeners('stateChanged', id); + } + } + + TodoModel.prototype.addTodo = function(text, isDone, extras) { + var id = nextId++; + this.todos[id]={'id': id, 'text': text, 'isDone': isDone, 'extras': extras}; + this.notifyListeners('added', id); + } + + TodoModel.prototype.addListener = function(listener) { + this.listeners.push(listener); + } + + TodoModel.prototype.notifyListeners = function(change, param) { + var this_ = this; + this.listeners.forEach(function(listener) { + listener(this_, change, param); + }); + } + + exports.TodoModel = TodoModel; + +})(window); + + + +(function(exports) { + + var defaultDropText = "Or drop files here..."; + + var dropText = document.getElementById('dropText'); + dropText.innerText = defaultDropText; + + // on dragOver, we will change the style and text accordingly, depending on + // the data being transfered + var dragOver = function(e) { + e.stopPropagation(); + e.preventDefault(); + var valid = isValid(e.dataTransfer); + if (valid) { + dropText.innerText="Drop files and remote images and they will become Todos"; + document.body.classList.add("dragging"); + } else { + dropText.innerText="Can only drop files and remote images here"; + document.body.classList.add("invalid-dragging"); + } + } + + var isValid = function(dataTransfer) { + return dataTransfer && dataTransfer.types + && ( dataTransfer.types.indexOf('Files') >= 0 + || dataTransfer.types.indexOf('text/uri-list') >=0 ) + } + + // reset style and text to the default + var dragLeave = function(e) { + dropText.innerText=defaultDropText; + document.body.classList.remove('dragging'); + document.body.classList.remove('invalid-dragging'); + } + + // on drop, we create the appropriate TODOs using dropped data + var drop = function(e, model) { + e.preventDefault(); + e.stopPropagation(); + if (isValid(e.dataTransfer)) { + if (e.dataTransfer.types.indexOf('Files') >= 0) { + var files = e.dataTransfer.files; + for (var i = 0; i < files.length; i++) { + var text = files[i].name+', '+files[i].size+' bytes'; + model.addTodo(text, false, {file: files[i]}); + } + } else { // uris + var uri=e.dataTransfer.getData("text/uri-list"); + model.addTodo(uri, false, {uri: uri}); + } + } + + dragLeave(); + } + + exports.setDragHandlers = function(model) { + document.body.addEventListener("dragover", dragOver, false); + document.body.addEventListener("dragleave", dragLeave, false); + document.body.addEventListener("drop", function(e) { + drop(e, model); + }, false); + } + +})(window); + + +window.addEventListener('DOMContentLoaded', function() { + + var model = new TodoModel(); + var form = document.querySelector('form'); + var archive = document.getElementById('archive'); + var list = document.getElementById('list'); + var todoTemplate = document.querySelector('#templates > [data-name="list"]'); + + /** + * When the form is submitted, we need to add a new todo and clear the input + **/ + form.addEventListener('submit', function(e) { + var textEl = e.target.querySelector('input[type="text"]'); + model.addTodo(textEl.value, false); + textEl.value=null; + e.preventDefault(); + }); + + + /** + * A simple handler for the archive link + **/ + archive.addEventListener('click', function(e) { + model.archiveDone(); + e.preventDefault(); + }); + + + /** + * Listen to changes in the model and trigger the appropriate changes in the view + **/ + model.addListener(function(model, changeType, param) { + if ( changeType === 'removed' || changeType === 'archived' || changeType === 'reset') { + redrawUI(model); + } else if ( changeType === 'added' ) { + drawTodo(model.todos[param], list); + } else if ( changeType === 'stateChanged') { + updateTodo(model.todos[param]); + } + storageSave(); + updateCounters(model); + }); + + + // If there is saved data in storage, use it. Otherwise, bootstrap with sample todos + var storageLoad = function() { + chrome.storage.sync.get('todolist', function(value) { + if (value && value.todolist) { + model.setTodos(value.todolist); + } else { + model.addTodo('learn Chrome Apps', true); + model.addTodo('build a Chrome App', false); + } + }); + } + + var storageSave = function() { + chrome.storage.sync.set({'todolist': model.todos}); + }; + + /** + * Clean the current ToDo list and add elements again + **/ + var redrawUI = function(model) { + list.innerHTML=''; + for (var id in model.todos) { + drawTodo(model.todos[id], list); + } + }; + + /** + * Deep clone a template node, set its ID and add it to the DOM container. + * Add a listener to the newly added checkbox, so it can trigger the state flip + * when the checkbox is clicked. + **/ + var drawTodo = function(todoObj, container) { + var el = todoTemplate.cloneNode(true); + el.setAttribute('data-id', todoObj.id); + container.appendChild(el); + updateTodo(todoObj); + var checkbox = el.querySelector('input[type="checkbox"]'); + checkbox.addEventListener('change', function(e) { + model.setTodoState(todoObj.id, e.target.checked); + }); + } + + + /** + * Find the element corresponding to the given ToDo model object and update its + * state and description from the model. + */ + var updateTodo = function(model) { + var todoElement = list.querySelector('li[data-id="'+model.id+'"]'); + if (todoElement) { + var checkbox = todoElement.querySelector('input[type="checkbox"]'); + var desc = todoElement.querySelector('span'); + checkbox.checked = model.isDone; + desc.innerText = model.text; + desc.className = "done-"+model.isDone; + } + } + + /** + * Recalculate total number of ToDos and remaining ToDos and update + * appropriate elements in the DOM. + **/ + var updateCounters = function(model) { + var count = 0; + var notDone = 0; + for (var id in model.todos) { + count++; + if ( ! model.todos[id].isDone ) { + notDone ++; + } + } + document.getElementById('remaining').innerText = notDone; + document.getElementById('length').innerText = count; + } + + storageLoad(); + setDragHandlers(model); + +}); + diff --git a/lab5_data/javascript/2_drop_files/icon.png b/lab5_data/javascript/2_drop_files/icon.png new file mode 100644 index 0000000..ffd3426 Binary files /dev/null and b/lab5_data/javascript/2_drop_files/icon.png differ diff --git a/lab5_data/javascript/2_drop_files/index.html b/lab5_data/javascript/2_drop_files/index.html new file mode 100644 index 0000000..a09944d --- /dev/null +++ b/lab5_data/javascript/2_drop_files/index.html @@ -0,0 +1,32 @@ + + + + + + +

Todo

+
+ of remaining + [ archive ] + +
+ + +
+
+
+
+ + + + + + + diff --git a/lab5_data/javascript/2_drop_files/main.js b/lab5_data/javascript/2_drop_files/main.js new file mode 100644 index 0000000..48f4770 --- /dev/null +++ b/lab5_data/javascript/2_drop_files/main.js @@ -0,0 +1,5 @@ +chrome.app.runtime.onLaunched.addListener(function() { + chrome.app.window.create('index.html', + {width: 500, height: 309}); +}); + diff --git a/lab5_data/javascript/2_drop_files/manifest.json b/lab5_data/javascript/2_drop_files/manifest.json new file mode 100644 index 0000000..fdaabf2 --- /dev/null +++ b/lab5_data/javascript/2_drop_files/manifest.json @@ -0,0 +1,13 @@ +{ + "manifest_version": 2, + "name": "Lab5b Drop files", + "version": "1", + "app": { + "background": { + "scripts": ["main.js"] + } + }, + "permissions": ["storage"], + "icons": { "128": "icon.png" } +} + diff --git a/lab5_data/javascript/2_drop_files/todo.css b/lab5_data/javascript/2_drop_files/todo.css new file mode 100644 index 0000000..5254e90 --- /dev/null +++ b/lab5_data/javascript/2_drop_files/todo.css @@ -0,0 +1,43 @@ +html { + height: 100%; + overflow: hidden; +} + +body { + font-family: "Helvetica Neue",Helvetica,Arial,sans-serif; + height: 100%; +} + +@-webkit-keyframes switch-green { + from { background-color: white;} to {background-color: rgb(163, 255, 163);} +} +@-webkit-keyframes switch-red { + from { background-color: white;} to {background-color: rgb(255, 203, 203);} +} +.dragging { + -webkit-animation: switch-green 0.5s ease-in-out 0 infinite alternate; +} + +.invalid-dragging { + -webkit-animation: switch-red 0.5s ease-in-out 0 infinite alternate; +} + +ul { + list-style: none; + max-height: 120px; + overflow-y: auto; +} + +button, input[type=submit] { + background-color: #0074CC; + background-image: linear-gradient(top, #08C, #05C); + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + color: white; +} + +.done-true { + text-decoration: line-through; + color: grey; +} +