export default Controller /** * Takes a model and view and acts as the controller between them * * @constructor * @param {object} model The model instance * @param {object} view The view instance */ function Controller(model, view) { var that = this that.model = model that.view = view that.view.bind('newTodo', function(title) { that.addItem(title) }) that.view.bind('itemEdit', function(item) { that.editItem(item.id) }) that.view.bind('itemEditDone', function(item) { that.editItemSave(item.id, item.title) }) that.view.bind('itemEditCancel', function(item) { that.editItemCancel(item.id) }) that.view.bind('itemRemove', function(item) { that.removeItem(item.id) }) that.view.bind('itemToggle', function(item) { that.toggleComplete(item.id, item.completed) }) that.view.bind('removeCompleted', function() { that.removeCompletedItems() }) that.view.bind('toggleAll', function(status) { that.toggleAll(status.completed) }) } /** * Loads and initialises the view * * @param {string} '' | 'active' | 'completed' */ Controller.prototype.setView = function(locationHash) { var route = locationHash.split('/')[1] var page = route || '' this._updateFilterState(page) } /** * An event to fire on load. Will get all items and display them in the * todo-list */ Controller.prototype.showAll = function() { var that = this that.model.read(function(data) { that.view.render('showEntries', data) }) } /** * Renders all active tasks */ Controller.prototype.showActive = function() { var that = this that.model.read({completed: false}, function(data) { that.view.render('showEntries', data) }) } /** * Renders all completed tasks */ Controller.prototype.showCompleted = function() { var that = this that.model.read({completed: true}, function(data) { that.view.render('showEntries', data) }) } /** * An event to fire whenever you want to add an item. Simply pass in the event * object and it'll handle the DOM insertion and saving of the new item. */ Controller.prototype.addItem = function(title) { var that = this if (title.trim() === '') { return } that.model.create(title, function() { that.view.render('clearNewTodo') that._filter(true) }) } /* * Triggers the item editing mode. */ Controller.prototype.editItem = function(id) { var that = this that.model.read(id, function(data) { that.view.render('editItem', {id, title: data[0].title}) }) } /* * Finishes the item editing mode successfully. */ Controller.prototype.editItemSave = function(id, title) { var that = this if (title.trim()) { that.model.update(id, {title}, function() { that.view.render('editItemDone', {id, title}) }) } else { that.removeItem(id) } } /* * Cancels the item editing mode. */ Controller.prototype.editItemCancel = function(id) { var that = this that.model.read(id, function(data) { that.view.render('editItemDone', {id, title: data[0].title}) }) } /** * By giving it an ID it'll find the DOM element matching that ID, * remove it from the DOM and also remove it from storage. * * @param {number} id The ID of the item to remove from the DOM and * storage */ Controller.prototype.removeItem = function(id) { var that = this that.model.remove(id, function() { that.view.render('removeItem', id) }) that._filter() } /** * Will remove all completed items from the DOM and storage. */ Controller.prototype.removeCompletedItems = function() { var that = this that.model.read({completed: true}, function(data) { data.forEach(function(item) { that.removeItem(item.id) }) }) that._filter() } /** * Give it an ID of a model and a checkbox and it will update the item * in storage based on the checkbox's state. * * @param {number} id The ID of the element to complete or uncomplete * @param {object} checkbox The checkbox to check the state of complete * or not * @param {boolean|undefined} silent Prevent re-filtering the todo items */ Controller.prototype.toggleComplete = function(id, completed, silent) { var that = this that.model.update(id, {completed}, function() { that.view.render('elementComplete', { id, completed, }) }) if (!silent) { that._filter() } } /** * Will toggle ALL checkboxes' on/off state and completeness of models. * Just pass in the event object. */ Controller.prototype.toggleAll = function(completed) { var that = this that.model.read({completed: !completed}, function(data) { data.forEach(function(item) { that.toggleComplete(item.id, completed, true) }) }) that._filter() } /** * Updates the pieces of the page which change depending on the remaining * number of todos. */ Controller.prototype._updateCount = function() { var that = this that.model.getCount(function(todos) { that.view.render('updateElementCount', todos.active) that.view.render('clearCompletedButton', { completed: todos.completed, visible: todos.completed > 0 }) that.view.render('toggleAll', {checked: todos.completed === todos.total}) that.view.render('contentBlockVisibility', {visible: todos.total > 0}) }) } /** * Re-filters the todo items, based on the active route. * @param {boolean|undefined} force forces a re-painting of todo items. */ Controller.prototype._filter = function(force) { var activeRoute = this._activeRoute.charAt(0).toUpperCase() + this._activeRoute.substr(1) // Update the elements on the page, which change with each completed todo this._updateCount() // If the last active route isn't "All", or we're switching routes, we // re-create the todo item elements, calling: // this.show[All|Active|Completed](); if (force || this._lastActiveRoute !== 'All' || this._lastActiveRoute !== activeRoute) { this['show' + activeRoute]() } this._lastActiveRoute = activeRoute } /** * Simply updates the filter nav's selected states */ Controller.prototype._updateFilterState = function(currentPage) { // Store a reference to the active route, allowing us to re-filter todo // items as they are marked complete or incomplete. this._activeRoute = currentPage if (currentPage === '') { this._activeRoute = 'All' } this._filter() this.view.render('setFilter', currentPage) }