From: Zachary Vance Date: Tue, 26 May 2015 01:09:41 +0000 (-0700) Subject: Indent works in model, but not in UI X-Git-Url: https://git.za3k.com/?a=commitdiff_plain;h=4087469b15721b90b360d6a7ceeaf0d7d16b044c;p=flowy.git Indent works in model, but not in UI --- diff --git a/dist/flowy.js b/dist/flowy.js index 0be641a..dac4809 100644 --- a/dist/flowy.js +++ b/dist/flowy.js @@ -301,7 +301,8 @@ var Shortcut = (function(document, _) { }, _displayKeybinding: function(shortcut, options) { options = _.defaults({}, options, { displayMultiple: true, allowRebind: false }); - var keybindings = shortcut.keybinding.split(","); + var keybindings = shortcut.keybinding; + if (typeof(keybindings) === 'string') keybindings = [keybindings]; if (!options.displayMultiple && keybindings.length > 1) { keybindings = [keybindings[0]]; } @@ -334,6 +335,7 @@ var Shortcut = (function(document, _) { var undelegateEvents = View.undelegateEvents; var ShortcutRegex = /^Shortcut\("([^")]*)", ?"([^")]*)", ?"([^")]*)"\) (.*)$/; function delegate(id, description, defaultKeybinding, objectType, callback){ + if (typeof(defaultKeybinding) !== 'string' && defaultKeybinding.split) defaultKeybinding = defaultKeybinding.split(','); var shortcut = Shortcut.registerShortcut({ id: id, description: description, @@ -408,7 +410,8 @@ var TodoView = Backbone.View.extend({ 'Shortcut("zoomIn", "Not Done - Zoom in", "alt+right") > .text': 'zoomIn', 'Shortcut("zoomOut", "Not Done - Zoom out", "alt+left") > .text': 'zoomOut', 'Shortcut("expand", "Not Done - Expand / collapse", "ctrl+space") > .text': 'expand', - 'Shortcut("indent", "Not Done - Indent", "tab,alt+shift+right") > .text': 'indent', + //'Shortcut("indent", "Not Done - Indent", "tab,alt+shift+right") > .text': 'indent', + 'Shortcut("indent", "Not Done - Indent", "tab") > .text': 'indent', 'Shortcut("outdent", "Not Done - Outdent", "shift+tab,alt+shift+left") > .text': 'outdent', 'Shortcut("moveDown", "Not Done - Move", "alt+shift+down") > .text': 'moveDown', 'Shortcut("moveUp", "Not Done - Move", "alt+shift+up") > .text': 'moveUp', @@ -525,14 +528,13 @@ var TodoView = Backbone.View.extend({ return false; }, indent: function() { - // Last child of previous sibling, then nothing - console.log("Indent not implemented"); // TODO - this.moveTo({keyboard:true}); + // TODO: maintain focus + this.model.indent(this.model.collection); + return false; }, outdent: function() { - // After parent, then nothing - console.log("Outdent not implemented"); // TODO - this.moveTo({keyboard:true}); + // TODO: maintain focus + this.model.outdent(this.model.collection); }, expand: function() { console.log("Expand not implemented"); // TODO @@ -546,22 +548,12 @@ var TodoView = Backbone.View.extend({ console.log("Zoom not implemented"); // TODO }, moveDown: function() { - // After next sibling, then as first child of next node after parent, then up one level, then nothing - console.log("Move not implemented"); // TODO - this.moveTo({keyboard:true}); + // TODO: maintain focus + this.model.moveDown(this.model.collection); }, moveUp: function() { - // Before previous sibling, then as last child of previous node of parent, then before parent, then nothing - console.log("Move not implemented"); // TODO - this.moveTo({keyboard:true}); - }, - moveTo: function(loc, options) { - loc = _.defaults({}, loc, { parent: this.model.getParent(this.model.collection), index: this.model.getParent(this.model.collection).findChild(this.model.id) }); - options = _.defaults({}, options, { - keyboard: false, // Whether the action was done with keyboard vs mouse (affects UI focus) - }); - console.log("Move not implemented"); - return false; + // TODO: maintain focus + this.model.moveUp(this.model.collection); }, textChange: function(e) { var collection = this.model.collection; @@ -743,6 +735,59 @@ var TodoModel = Backbone.Model.extend({ this.set("bullets", bullets); return this; }, + moveTo: function(newLocation, collection) { + if (collection.rootId == this.id) { + console.log("Cannot move root"); + return this; + } + var existingLocation = { + parent: this.getParent(collection), + index: this.getParent(collection).findChild(this.id), + }; + newLocation = _.defaults({}, newLocation, existingLocation); + var newChildren; + if (newLocation.parent === existingLocation.parent && newLocation.index === existingLocation.index) { + // No-op + } else if (newLocation.parent === this.parent) { + // We moved to a new location under the same parent. + newChildren = _.clone(newLocation.parent.get("bullets")); + newChildren.splice(existingLocation.index, 1); + newLocation.index = (newLocation.index < existingLocation.index) ? newLocation.index : newLocation.index - 1; // Adjust indices for insertion + newChildren.splice(existingLocation.index, 0, this.id); + + newLocation.parent.save("bullets", newChildren); + this.save(); + } else { + // We moved to a new parent + newChildren = _.clone(existingLocation.parent.get("bullets")); + newChildren.splice(existingLocation.index, 1); + existingLocation.parent.save("bullets", newChildren); + + newLocation.parent.insertChild(this, newLocation.index); + newLocation.parent.save(); + this.save(); + } + collection.trigger("move", this, existingLocation); + return this; + }, + moveUp: function(collection) { + // Before previous sibling, then as last child of previous node of parent, then before parent, then nothing + }, + moveDown: function(collection) { + // After next sibling, then as first child of next node after parent, then up one level, then nothing + }, + indent: function(collection) { + // Last child of previous sibling, then nothing + var previous = this.getPreviousSibling(collection); + if (!previous) return undefined; + return this.moveTo({ + parent: previous, + index: previous.getChildrenCount(), + }, collection); + }, + outdent: function(collection) { + // After parent, then nothing + }, removeChild: function(childTodoModel, collection) { if (childTodoModel.get("bullets").length > 0) { console.log("Cannot delete node with children."); @@ -896,6 +941,7 @@ var AppView = Backbone.View.extend({ this.list = options.list || new FlowyDocModel(); this.list.app = this; this.listenTo(this.list, 'add', this.addOne); + this.listenTo(this.list, 'move', this.moveOne); this.listenTo(this.list, 'reset', this.addAll); var self = this; this.$("#reset-button").on("click", function() { @@ -919,6 +965,18 @@ var AppView = Backbone.View.extend({ addOne: function(todo) { this.renderTodo(todo); }, + moveOne: function(todo, oldLocation) { + var view = this.getView(todo); + + var oldParent = oldLocation.parent; + var oldParentView; + if (oldParent) oldParentView = this.getView(oldParent); + if (oldParentView) { + // Remove from old parent + } + + this.renderTodo(todo, { rerender: true }); // Don't remove existing view since it's still valid. + }, toggleShortcuts: function() { this.$(".shortcuts").toggle(); }, @@ -928,8 +986,11 @@ var AppView = Backbone.View.extend({ search: function() { console.log("Search not yet implemented"); // TODO }, - renderTodo: function(todo) { - if (this.getView(todo)) { + renderTodo: function(todo, options) { + options = _.defaults({}, options, { + rerender: false, + }); + if (this.getView(todo) && !options.rerender) { console.log("View rendered more than once for todo #" + todo.id); return; } @@ -958,6 +1019,9 @@ var AppView = Backbone.View.extend({ getView: function(model) { return this.views[model.id]; }, + removeView: function(model) { + delete this.views[model.id]; + }, addAll: function() { this.views = {}; this.$("#todo-list").html(null); diff --git a/dist/flowy.unwrapped.js b/dist/flowy.unwrapped.js index 3dc2344..64385a6 100644 --- a/dist/flowy.unwrapped.js +++ b/dist/flowy.unwrapped.js @@ -300,7 +300,8 @@ var Shortcut = (function(document, _) { }, _displayKeybinding: function(shortcut, options) { options = _.defaults({}, options, { displayMultiple: true, allowRebind: false }); - var keybindings = shortcut.keybinding.split(","); + var keybindings = shortcut.keybinding; + if (typeof(keybindings) === 'string') keybindings = [keybindings]; if (!options.displayMultiple && keybindings.length > 1) { keybindings = [keybindings[0]]; } @@ -333,6 +334,7 @@ var Shortcut = (function(document, _) { var undelegateEvents = View.undelegateEvents; var ShortcutRegex = /^Shortcut\("([^")]*)", ?"([^")]*)", ?"([^")]*)"\) (.*)$/; function delegate(id, description, defaultKeybinding, objectType, callback){ + if (typeof(defaultKeybinding) !== 'string' && defaultKeybinding.split) defaultKeybinding = defaultKeybinding.split(','); var shortcut = Shortcut.registerShortcut({ id: id, description: description, @@ -407,7 +409,8 @@ var TodoView = Backbone.View.extend({ 'Shortcut("zoomIn", "Not Done - Zoom in", "alt+right") > .text': 'zoomIn', 'Shortcut("zoomOut", "Not Done - Zoom out", "alt+left") > .text': 'zoomOut', 'Shortcut("expand", "Not Done - Expand / collapse", "ctrl+space") > .text': 'expand', - 'Shortcut("indent", "Not Done - Indent", "tab,alt+shift+right") > .text': 'indent', + //'Shortcut("indent", "Not Done - Indent", "tab,alt+shift+right") > .text': 'indent', + 'Shortcut("indent", "Not Done - Indent", "tab") > .text': 'indent', 'Shortcut("outdent", "Not Done - Outdent", "shift+tab,alt+shift+left") > .text': 'outdent', 'Shortcut("moveDown", "Not Done - Move", "alt+shift+down") > .text': 'moveDown', 'Shortcut("moveUp", "Not Done - Move", "alt+shift+up") > .text': 'moveUp', @@ -524,14 +527,13 @@ var TodoView = Backbone.View.extend({ return false; }, indent: function() { - // Last child of previous sibling, then nothing - console.log("Indent not implemented"); // TODO - this.moveTo({keyboard:true}); + // TODO: maintain focus + this.model.indent(this.model.collection); + return false; }, outdent: function() { - // After parent, then nothing - console.log("Outdent not implemented"); // TODO - this.moveTo({keyboard:true}); + // TODO: maintain focus + this.model.outdent(this.model.collection); }, expand: function() { console.log("Expand not implemented"); // TODO @@ -545,22 +547,12 @@ var TodoView = Backbone.View.extend({ console.log("Zoom not implemented"); // TODO }, moveDown: function() { - // After next sibling, then as first child of next node after parent, then up one level, then nothing - console.log("Move not implemented"); // TODO - this.moveTo({keyboard:true}); + // TODO: maintain focus + this.model.moveDown(this.model.collection); }, moveUp: function() { - // Before previous sibling, then as last child of previous node of parent, then before parent, then nothing - console.log("Move not implemented"); // TODO - this.moveTo({keyboard:true}); - }, - moveTo: function(loc, options) { - loc = _.defaults({}, loc, { parent: this.model.getParent(this.model.collection), index: this.model.getParent(this.model.collection).findChild(this.model.id) }); - options = _.defaults({}, options, { - keyboard: false, // Whether the action was done with keyboard vs mouse (affects UI focus) - }); - console.log("Move not implemented"); - return false; + // TODO: maintain focus + this.model.moveUp(this.model.collection); }, textChange: function(e) { var collection = this.model.collection; @@ -742,6 +734,59 @@ var TodoModel = Backbone.Model.extend({ this.set("bullets", bullets); return this; }, + moveTo: function(newLocation, collection) { + if (collection.rootId == this.id) { + console.log("Cannot move root"); + return this; + } + var existingLocation = { + parent: this.getParent(collection), + index: this.getParent(collection).findChild(this.id), + }; + newLocation = _.defaults({}, newLocation, existingLocation); + var newChildren; + if (newLocation.parent === existingLocation.parent && newLocation.index === existingLocation.index) { + // No-op + } else if (newLocation.parent === this.parent) { + // We moved to a new location under the same parent. + newChildren = _.clone(newLocation.parent.get("bullets")); + newChildren.splice(existingLocation.index, 1); + newLocation.index = (newLocation.index < existingLocation.index) ? newLocation.index : newLocation.index - 1; // Adjust indices for insertion + newChildren.splice(existingLocation.index, 0, this.id); + + newLocation.parent.save("bullets", newChildren); + this.save(); + } else { + // We moved to a new parent + newChildren = _.clone(existingLocation.parent.get("bullets")); + newChildren.splice(existingLocation.index, 1); + existingLocation.parent.save("bullets", newChildren); + + newLocation.parent.insertChild(this, newLocation.index); + newLocation.parent.save(); + this.save(); + } + collection.trigger("move", this, existingLocation); + return this; + }, + moveUp: function(collection) { + // Before previous sibling, then as last child of previous node of parent, then before parent, then nothing + }, + moveDown: function(collection) { + // After next sibling, then as first child of next node after parent, then up one level, then nothing + }, + indent: function(collection) { + // Last child of previous sibling, then nothing + var previous = this.getPreviousSibling(collection); + if (!previous) return undefined; + return this.moveTo({ + parent: previous, + index: previous.getChildrenCount(), + }, collection); + }, + outdent: function(collection) { + // After parent, then nothing + }, removeChild: function(childTodoModel, collection) { if (childTodoModel.get("bullets").length > 0) { console.log("Cannot delete node with children."); @@ -895,6 +940,7 @@ var AppView = Backbone.View.extend({ this.list = options.list || new FlowyDocModel(); this.list.app = this; this.listenTo(this.list, 'add', this.addOne); + this.listenTo(this.list, 'move', this.moveOne); this.listenTo(this.list, 'reset', this.addAll); var self = this; this.$("#reset-button").on("click", function() { @@ -918,6 +964,18 @@ var AppView = Backbone.View.extend({ addOne: function(todo) { this.renderTodo(todo); }, + moveOne: function(todo, oldLocation) { + var view = this.getView(todo); + + var oldParent = oldLocation.parent; + var oldParentView; + if (oldParent) oldParentView = this.getView(oldParent); + if (oldParentView) { + // Remove from old parent + } + + this.renderTodo(todo, { rerender: true }); // Don't remove existing view since it's still valid. + }, toggleShortcuts: function() { this.$(".shortcuts").toggle(); }, @@ -927,8 +985,11 @@ var AppView = Backbone.View.extend({ search: function() { console.log("Search not yet implemented"); // TODO }, - renderTodo: function(todo) { - if (this.getView(todo)) { + renderTodo: function(todo, options) { + options = _.defaults({}, options, { + rerender: false, + }); + if (this.getView(todo) && !options.rerender) { console.log("View rendered more than once for todo #" + todo.id); return; } @@ -957,6 +1018,9 @@ var AppView = Backbone.View.extend({ getView: function(model) { return this.views[model.id]; }, + removeView: function(model) { + delete this.views[model.id]; + }, addAll: function() { this.views = {}; this.$("#todo-list").html(null); diff --git a/src/library/shortcut.js b/src/library/shortcut.js index cf2e92e..7ab8fba 100644 --- a/src/library/shortcut.js +++ b/src/library/shortcut.js @@ -239,7 +239,8 @@ var Shortcut = (function(document, _) { }, _displayKeybinding: function(shortcut, options) { options = _.defaults({}, options, { displayMultiple: true, allowRebind: false }); - var keybindings = shortcut.keybinding.split(","); + var keybindings = shortcut.keybinding; + if (typeof(keybindings) === 'string') keybindings = [keybindings]; if (!options.displayMultiple && keybindings.length > 1) { keybindings = [keybindings[0]]; } diff --git a/src/library/viewShortcuts.js b/src/library/viewShortcuts.js index 659c59f..d004864 100644 --- a/src/library/viewShortcuts.js +++ b/src/library/viewShortcuts.js @@ -9,6 +9,7 @@ var undelegateEvents = View.undelegateEvents; var ShortcutRegex = /^Shortcut\("([^")]*)", ?"([^")]*)", ?"([^")]*)"\) (.*)$/; function delegate(id, description, defaultKeybinding, objectType, callback){ + if (typeof(defaultKeybinding) !== 'string' && defaultKeybinding.split) defaultKeybinding = defaultKeybinding.split(','); var shortcut = Shortcut.registerShortcut({ id: id, description: description, diff --git a/src/models/todo.js b/src/models/todo.js index d5d366a..58aaf63 100644 --- a/src/models/todo.js +++ b/src/models/todo.js @@ -100,6 +100,59 @@ var TodoModel = Backbone.Model.extend({ this.set("bullets", bullets); return this; }, + moveTo: function(newLocation, collection) { + if (collection.rootId == this.id) { + console.log("Cannot move root"); + return this; + } + var existingLocation = { + parent: this.getParent(collection), + index: this.getParent(collection).findChild(this.id), + }; + newLocation = _.defaults({}, newLocation, existingLocation); + var newChildren; + if (newLocation.parent === existingLocation.parent && newLocation.index === existingLocation.index) { + // No-op + } else if (newLocation.parent === this.parent) { + // We moved to a new location under the same parent. + newChildren = _.clone(newLocation.parent.get("bullets")); + newChildren.splice(existingLocation.index, 1); + newLocation.index = (newLocation.index < existingLocation.index) ? newLocation.index : newLocation.index - 1; // Adjust indices for insertion + newChildren.splice(existingLocation.index, 0, this.id); + + newLocation.parent.save("bullets", newChildren); + this.save(); + } else { + // We moved to a new parent + newChildren = _.clone(existingLocation.parent.get("bullets")); + newChildren.splice(existingLocation.index, 1); + existingLocation.parent.save("bullets", newChildren); + + newLocation.parent.insertChild(this, newLocation.index); + newLocation.parent.save(); + this.save(); + } + collection.trigger("move", this, existingLocation); + return this; + }, + moveUp: function(collection) { + // Before previous sibling, then as last child of previous node of parent, then before parent, then nothing + }, + moveDown: function(collection) { + // After next sibling, then as first child of next node after parent, then up one level, then nothing + }, + indent: function(collection) { + // Last child of previous sibling, then nothing + var previous = this.getPreviousSibling(collection); + if (!previous) return undefined; + return this.moveTo({ + parent: previous, + index: previous.getChildrenCount(), + }, collection); + }, + outdent: function(collection) { + // After parent, then nothing + }, removeChild: function(childTodoModel, collection) { if (childTodoModel.get("bullets").length > 0) { console.log("Cannot delete node with children."); diff --git a/src/views/app.js b/src/views/app.js index fa573e8..f515ae9 100644 --- a/src/views/app.js +++ b/src/views/app.js @@ -72,6 +72,7 @@ var AppView = Backbone.View.extend({ this.list = options.list || new FlowyDocModel(); this.list.app = this; this.listenTo(this.list, 'add', this.addOne); + this.listenTo(this.list, 'move', this.moveOne); this.listenTo(this.list, 'reset', this.addAll); var self = this; this.$("#reset-button").on("click", function() { @@ -95,6 +96,18 @@ var AppView = Backbone.View.extend({ addOne: function(todo) { this.renderTodo(todo); }, + moveOne: function(todo, oldLocation) { + var view = this.getView(todo); + + var oldParent = oldLocation.parent; + var oldParentView; + if (oldParent) oldParentView = this.getView(oldParent); + if (oldParentView) { + // Remove from old parent + } + + this.renderTodo(todo, { rerender: true }); // Don't remove existing view since it's still valid. + }, toggleShortcuts: function() { this.$(".shortcuts").toggle(); }, @@ -104,8 +117,11 @@ var AppView = Backbone.View.extend({ search: function() { console.log("Search not yet implemented"); // TODO }, - renderTodo: function(todo) { - if (this.getView(todo)) { + renderTodo: function(todo, options) { + options = _.defaults({}, options, { + rerender: false, + }); + if (this.getView(todo) && !options.rerender) { console.log("View rendered more than once for todo #" + todo.id); return; } @@ -134,6 +150,9 @@ var AppView = Backbone.View.extend({ getView: function(model) { return this.views[model.id]; }, + removeView: function(model) { + delete this.views[model.id]; + }, addAll: function() { this.views = {}; this.$("#todo-list").html(null); diff --git a/src/views/todo.js b/src/views/todo.js index 67a850a..405464f 100644 --- a/src/views/todo.js +++ b/src/views/todo.js @@ -18,7 +18,8 @@ var TodoView = Backbone.View.extend({ 'Shortcut("zoomIn", "Not Done - Zoom in", "alt+right") > .text': 'zoomIn', 'Shortcut("zoomOut", "Not Done - Zoom out", "alt+left") > .text': 'zoomOut', 'Shortcut("expand", "Not Done - Expand / collapse", "ctrl+space") > .text': 'expand', - 'Shortcut("indent", "Not Done - Indent", "tab,alt+shift+right") > .text': 'indent', + //'Shortcut("indent", "Not Done - Indent", "tab,alt+shift+right") > .text': 'indent', + 'Shortcut("indent", "Not Done - Indent", "tab") > .text': 'indent', 'Shortcut("outdent", "Not Done - Outdent", "shift+tab,alt+shift+left") > .text': 'outdent', 'Shortcut("moveDown", "Not Done - Move", "alt+shift+down") > .text': 'moveDown', 'Shortcut("moveUp", "Not Done - Move", "alt+shift+up") > .text': 'moveUp', @@ -135,14 +136,13 @@ var TodoView = Backbone.View.extend({ return false; }, indent: function() { - // Last child of previous sibling, then nothing - console.log("Indent not implemented"); // TODO - this.moveTo({keyboard:true}); + // TODO: maintain focus + this.model.indent(this.model.collection); + return false; }, outdent: function() { - // After parent, then nothing - console.log("Outdent not implemented"); // TODO - this.moveTo({keyboard:true}); + // TODO: maintain focus + this.model.outdent(this.model.collection); }, expand: function() { console.log("Expand not implemented"); // TODO @@ -156,22 +156,12 @@ var TodoView = Backbone.View.extend({ console.log("Zoom not implemented"); // TODO }, moveDown: function() { - // After next sibling, then as first child of next node after parent, then up one level, then nothing - console.log("Move not implemented"); // TODO - this.moveTo({keyboard:true}); + // TODO: maintain focus + this.model.moveDown(this.model.collection); }, moveUp: function() { - // Before previous sibling, then as last child of previous node of parent, then before parent, then nothing - console.log("Move not implemented"); // TODO - this.moveTo({keyboard:true}); - }, - moveTo: function(loc, options) { - loc = _.defaults({}, loc, { parent: this.model.getParent(this.model.collection), index: this.model.getParent(this.model.collection).findChild(this.model.id) }); - options = _.defaults({}, options, { - keyboard: false, // Whether the action was done with keyboard vs mouse (affects UI focus) - }); - console.log("Move not implemented"); - return false; + // TODO: maintain focus + this.model.moveUp(this.model.collection); }, textChange: function(e) { var collection = this.model.collection;