'use strict'; // import {qs, qsa, $on, $parent, $delegate} from './helpers'; let _itemId = element => parseInt($parent(element, 'li').dataset.id, 10); let _setFilter = currentPage => { qs('.filters .selected').className = ''; qs(`.filters [href="#/${currentPage}"]`).className = 'selected'; }; let _elementComplete = (id, completed) => { let listItem = qs(`[data-id="${id}"]`); if (!listItem) { return; } listItem.className = completed ? 'completed' : ''; // In case it was toggled from an event and not by clicking the checkbox qs('input', listItem).checked = completed; }; let _editItem = (id, title) => { let listItem = qs(`[data-id="${id}"]`); if (!listItem) { return; } listItem.className += ' editing'; let input = document.createElement('input'); input.className = 'edit'; listItem.appendChild(input); input.focus(); input.value = title; }; /** * View that abstracts away the browser's DOM completely. * It has two simple entry points: * * - bind(eventName, handler) * Takes a todo application event and registers the handler * - render(command, parameterObject) * Renders the given command with the options */ class View { constructor(template) { this.template = template; this.ENTER_KEY = 13; this.ESCAPE_KEY = 27; this.$todoList = qs('.todo-list'); this.$todoItemCounter = qs('.todo-count'); this.$clearCompleted = qs('.clear-completed'); this.$main = qs('.main'); this.$footer = qs('.footer'); this.$toggleAll = qs('.toggle-all'); this.$newTodo = qs('.new-todo'); this.viewCommands = { showEntries: parameter => this.$todoList.innerHTML = this.template.show(parameter), removeItem: parameter => this._removeItem(parameter), updateElementCount: parameter => this.$todoItemCounter.innerHTML = this.template.itemCounter(parameter), clearCompletedButton: parameter => this._clearCompletedButton(parameter.completed, parameter.visible), contentBlockVisibility: parameter => this.$main.style.display = this.$footer.style.display = parameter.visible ? 'block' : 'none', toggleAll: parameter => this.$toggleAll.checked = parameter.checked, setFilter: parameter => _setFilter(parameter), clearNewTodo: parameter => this.$newTodo.value = '', elementComplete: parameter => _elementComplete(parameter.id, parameter.completed), editItem: parameter => _editItem(parameter.id, parameter.title), editItemDone: parameter => this._editItemDone(parameter.id, parameter.title), }; } _removeItem(id) { let elem = qs(`[data-id="${id}"]`); if (elem) { this.$todoList.removeChild(elem); } } _clearCompletedButton(completedCount, visible) { this.$clearCompleted.innerHTML = this.template.clearCompletedButton(completedCount); this.$clearCompleted.style.display = visible ? 'block' : 'none'; } _editItemDone(id, title) { let listItem = qs(`[data-id="${id}"]`); if (!listItem) { return; } let input = qs('input.edit', listItem); listItem.removeChild(input); listItem.className = listItem.className.replace(' editing', ''); qsa('label', listItem).forEach(label => label.textContent = title); } render(viewCmd, parameter) { this.viewCommands[viewCmd](parameter); } _bindItemEditDone(handler) { let self = this; $delegate(self.$todoList, 'li .edit', 'blur', function () { if (!this.dataset.iscanceled) { handler({ id: _itemId(this), title: this.value }); } }); // Remove the cursor from the input when you hit enter just like if it were a real form $delegate(self.$todoList, 'li .edit', 'keypress', function (event) { if (event.keyCode === self.ENTER_KEY) { this.blur(); } }); } _bindItemEditCancel(handler) { let self = this; $delegate(self.$todoList, 'li .edit', 'keyup', function (event) { if (event.keyCode === self.ESCAPE_KEY) { let id = _itemId(this); this.dataset.iscanceled = true; this.blur(); handler({ id }); } }); } bind(event, handler) { if (event === 'newTodo') { $on(this.$newTodo, 'change', () => handler(this.$newTodo.value)); } else if (event === 'removeCompleted') { $on(this.$clearCompleted, 'click', handler); } else if (event === 'toggleAll') { $on(this.$toggleAll, 'click', function(){ handler({completed: this.checked}); }); } else if (event === 'itemEdit') { $delegate(this.$todoList, 'li label', 'dblclick', function(){ handler({id: _itemId(this)}); }); } else if (event === 'itemRemove') { $delegate(this.$todoList, '.destroy', 'click', function(){ handler({id: _itemId(this)}); }); } else if (event === 'itemToggle') { $delegate(this.$todoList, '.toggle', 'click', function(){ handler({ id: _itemId(this), completed: this.checked }); }); } else if (event === 'itemEditDone') { this._bindItemEditDone(handler); } else if (event === 'itemEditCancel') { this._bindItemEditCancel(handler); } } }