} else {
this.stopEditingText();
this.model.toggleComplete();
- var next = this.model.nextNode(this.model.collection, { childrenAllowed: false}) || this.model.getParent(this.model.collection, { rootAllowed: false});
+ var next = this.model.nextNode({ childrenAllowed: false}) || this.model.getParent({ rootAllowed: false});
if (!next) return false;
next.getView().startEditingText();
}
return false;
},
focusNext: function() {
- var nextNode = this.model.nextNode(this.model.collection, { childrenAllowed: true });
+ var nextNode = this.model.nextNode({ childrenAllowed: true });
if (!nextNode) return false;
this.stopEditingText();
nextNode.getView().startEditingText();
return false;
},
focusPrevious: function() {
- var previousNode = this.model.previousNode(this.model.collection, { childrenAllowed: true });
+ var previousNode = this.model.previousNode({ childrenAllowed: true });
if (!previousNode) return false;
this.stopEditingText();
previousNode.getView().startEditingText();
if (this.model.hasChildren()) {
return;
}
- var previousNode = this.model.previousNode(this.model.collection);
+ var previousNode = this.model.previousNode();
if (!previousNode) {
return;
}
if (this.model.get("text") === "") {
- this.model.remove(this.model.collection);
+ this.model.remove();
previousNode.getView().startEditingText({"atEnd":true});
return false;
} else if (this.isFocusAtBeginning()) {
var text = this.model.get("text");
- this.model.remove(this.model.collection);
+ this.model.remove();
previousNode.setText(previousNode.get("text") + '<span class="focus"></span>' + text);
previousNode.getView().startEditingText({"atMarker": ".focus"});
return false;
if (this.model.hasChildren()) {
return;
}
- var nextNode = this.model.nextNode(this.model.collection);
+ var nextNode = this.model.nextNode();
if (!nextNode) {
return;
}
if (this.model.get("text") === "") {
- this.model.remove(this.model.collection);
+ this.model.remove();
nextNode.getView().startEditingText();
return false;
} else if (this.isFocusAtEnd()) {
var text = nextNode.get("text");
- nextNode.remove(this.model.collection);
+ nextNode.remove();
this.stopEditingText();
this.model.setText(this.model.get("text") + '<span class="focus"></span>' + text);
this.startEditingText({"atMarker": ".focus"});
"delete": function() {
// Delete node and its entire subtree
this.focusPrevious();
- this.model.removeAll(this.model.collection);
+ this.model.removeAll();
return false;
},
indent: function() {
// TODO: maintain focus
- this.model.indent(this.model.collection);
+ this.model.indent();
return false;
},
outdent: function() {
// TODO: maintain focus
- this.model.outdent(this.model.collection);
+ this.model.outdent();
},
expand: function() {
console.log("Expand not implemented"); // TODO
},
moveDown: function() {
// TODO: maintain focus
- this.model.moveDown(this.model.collection);
+ this.model.moveDown();
},
moveUp: function() {
// TODO: maintain focus
- this.model.moveUp(this.model.collection);
+ this.model.moveUp();
},
textChange: function(e) {
- var collection = this.model.collection;
var lines = $(e.target).html().split(/<br\\?>/);
if (lines.length === 0) {
console.log("unexpected number of lines in textChange");
this.outdent();
} else if ((lines.length === 2 && lines[1] === "") || (lines.length === 3 && lines[1] === "" && lines[2] === "")) { // Line break at end
this.model.setText(this.decodeText(lines[0]));
- var emptyAfter = this.model.addTodoAfter({text: this.decodeText(lines[1])}, collection); // Child or not depending on whether this has children
+ var emptyAfter = this.model.addTodoAfter({text: this.decodeText(lines[1])}); // Child or not depending on whether this has children
this.stopEditingText();
emptyAfter.getView().startEditingText();
} else if (lines.length === 2 && lines[0] === "") { // Line break at beginning
- var emptyBefore = this.model.addTodoBefore({text: this.decodeText(lines[0])}, collection);
+ var emptyBefore = this.model.addTodoBefore({text: this.decodeText(lines[0])});
this.model.setText(this.decodeText(lines[1]));
this.stopEditingText();
emptyBefore.getView().startEditingText();
} else if (lines.length === 2) { // Line break in middle
- var newNode = this.model.addTodoAfter({text: this.decodeText(lines[1])}, collection);
+ var newNode = this.model.addTodoAfter({text: this.decodeText(lines[1])});
this.model.setText(this.decodeText(lines[0]));
this.stopEditingText(); // For re-render
newNode.getView().startEditingText(); // Keep focus on current node (second half)
getChildrenCount: function() {
return this.get("bullets").length;
},
- getChildren: function(collection) {
+ getChildren: function() {
return _.map(this.get("bullets"), function(id) {
- return collection.get(id);
+ return this.collection.get(id);
}, this);
},
- getChild: function(collection, index) {
- return collection.get(this.get("bullets")[index]);
+ getChild: function(index) {
+ return this.collection.get(this.get("bullets")[index]);
},
- getParent: function(collection, options) {
+ getParent: function(options) {
options = _.defaults({}, options, { rootAllowed: true });
- var parent = collection.get(this.get("parent"));
- if (parent && parent.id == collection.rootId && !options.rootAllowed) return undefined;
+ var parent = this.collection.get(this.get("parent"));
+ if (parent && parent.isRoot() && !options.rootAllowed) return undefined;
return parent;
},
- getPreviousSibling: function(collection) {
- var parent = this.getParent(collection);
+ getPreviousSibling: function() {
+ var parent = this.getParent();
if (!parent) return undefined;
var index = parent.findChild(this.id);
if (index < 0 || index === 0) return undefined;
- return parent.getChild(collection, index - 1);
+ return parent.getChild(index - 1);
},
- getNextSibling: function(collection) {
- var parent = this.getParent(collection);
+ getNextSibling: function() {
+ var parent = this.getParent();
if (!parent) return undefined;
var index = parent.findChild(this.id);
var numChildren = parent.getChildrenCount();
if (index < 0 || index === numChildren - 1) return undefined;
- return parent.getChild(collection, index + 1);
+ return parent.getChild(index + 1);
},
- nextNode: function(collection, options) {
+ nextNode: function(options) {
options = _.defaults({}, options, {childrenAllowed: true});
if (options.childrenAllowed) {
if (this.hasChildren()) {
- return this.getChild(collection, 0);
+ return this.getChild(0);
}
}
- for (var node = this; node && node.id !== collection.rootId; node = node.getParent(collection)) {
- var next = node.getNextSibling(collection);
+ for (var node = this; node && !node.isRoot(); node = node.getParent()) {
+ var next = node.getNextSibling();
if (next) return next;
}
return undefined;
},
- previousNode: function(collection, options) {
+ previousNode: function(options) {
options = _.defaults({}, options, {childrenAllowed: true});
- var previous = this.getPreviousSibling(collection);
+ var previous = this.getPreviousSibling();
if (previous && options.childrenAllowed) {
while (previous.hasChildren()) {
- previous = previous.getChild(collection, previous.getChildrenCount() - 1);
+ previous = previous.getChild(previous.getChildrenCount() - 1);
}
}
- if (!previous) previous = this.getParent(collection);
+ if (!previous) previous = this.getParent();
if (!previous) return undefined;
- if (previous.id === collection.rootId) {
+ if (previous.isRoot()) {
return undefined;
} else {
return previous;
getView: function() { //TODO: remove
return this.collection.app.getView(this);
},
- isTopLevel: function(collection) {
- return this.get("parent") === collection.rootId;
+ isTopLevel: function() {
+ return this.get("parent") === this.collection.rootId;
},
- isParentLoaded: function(collection, collectionView) {
- return this.isTopLevel(collection) ? true : (this.getParent(collection) && collectionView.getView(this.getParent(collection)));
+ isParentLoaded: function(collectionView) {
+ return this.isTopLevel() ? true : (this.getParent() && collectionView.getView(this.getParent()));
},
findChild: function(childId) {
return this.get("bullets").indexOf(childId);
this.set("bullets", bullets);
return this;
},
- moveTo: function(newLocation, collection) {
- if (collection.rootId == this.id) {
+ moveTo: function(newLocation) {
+ if (this.isRoot()) {
console.log("Cannot move root");
return this;
}
var existingLocation = {
- parent: this.getParent(collection),
- index: this.getParent(collection).findChild(this.id),
+ parent: this.getParent(),
+ index: this.getParent().findChild(this.id),
};
newLocation = _.defaults({}, newLocation, existingLocation);
var newChildren;
newLocation.parent.save();
this.save();
}
- collection.trigger("move", this, existingLocation);
+ this.collection.trigger("move", this, existingLocation);
return this;
},
- moveUp: function(collection) {
+ moveUp: function() {
// Before previous sibling, then as last child of previous node of parent, then before parent, then nothing
},
- moveDown: function(collection) {
+ moveDown: function() {
// After next sibling, then as first child of next node after parent, then up one level, then nothing
},
- indent: function(collection) {
+ indent: function() {
// Last child of previous sibling, then nothing
- var previous = this.getPreviousSibling(collection);
+ var previous = this.getPreviousSibling();
if (!previous) return undefined;
return this.moveTo({
parent: previous,
index: previous.getChildrenCount(),
- }, collection);
+ });
},
- outdent: function(collection) {
+ outdent: function() {
// After parent, then nothing
},
- removeChild: function(childTodoModel, collection) {
+ isRoot: function() {
+ return this.id === this.collection.rootId;
+ },
+ removeChild: function(childTodoModel) {
if (childTodoModel.get("bullets").length > 0) {
console.log("Cannot delete node with children.");
return;
}});
return this;
},
- remove: function(collection) {
- this.getParent(collection).removeChild(this, collection);
+ remove: function() {
+ this.getParent().removeChild(this);
},
- removeAll: function(collection) {
- if (collection.rootId == this.id) {
+ removeAll: function() {
+ if (this.isRoot()) {
console.log("Cannot remove root node of collection");
return;
}
if (this.hasChildren()) {
- var children = _.clone(this.getChildren(collection));
+ var children = _.clone(this.getChildren());
_.each(children, function(child) {
- child.removeAll(collection);
+ child.removeAll();
});
}
- this.remove(collection);
+ this.remove();
},
- addTodoBefore: function(todo, collection) {
+ addTodoBefore: function(todo) {
// Todo always goes as the previous sibling
- var parent = this.getParent(collection);
- var todoModel = collection.create(_.extend(todo, {"parent": parent.id}));
+ var parent = this.getParent();
+ var todoModel = this.collection.create(_.extend(todo, {"parent": parent.id}));
parent.insertChild(todoModel, parent.findChild(this.id));
parent.save();
- collection.trigger("add", todoModel);
+ this.collection.trigger("add", todoModel);
return todoModel;
},
- addTodoAfter: function(todo, collection) {
+ addTodoAfter: function(todo) {
// If there are children, the todo goes as the first child.
// Otherwise, the todo goes as the next sibling
var todoModel;
if (this.get("bullets").length > 0) {
- todoModel = collection.create(_.extend(todo, {"parent": this.id}));
+ todoModel = this.collection.create(_.extend(todo, {"parent": this.id}));
this.insertChild(todoModel, 0);
this.save();
} else {
- parent = this.getParent(collection);
- todoModel = collection.create(_.extend(todo, {"parent": parent.id}));
+ parent = this.getParent();
+ todoModel = this.collection.create(_.extend(todo, {"parent": parent.id}));
parent.insertChild(todoModel, parent.findChild(this.id)+1);
parent.save();
}
- collection.trigger("add", todoModel);
+ this.collection.trigger("add", todoModel);
return todoModel;
}
});
console.log("View rendered more than once for todo #" + todo.id);
return;
}
- var view = new TodoView({model: todo, collection: this.list});
- if (todo.isTopLevel(this.list)) {
+ var view = new TodoView({model: todo});
+ if (todo.isTopLevel()) {
this.setView(todo, view);
this.$("#todo-list").append(view.render().el);
- } else if (todo.isParentLoaded(this.list, this) && todo.getParent(this.list).findChild(todo.id) >= 0 /* because move/insert is nonatomic */) {
+ } else if (todo.isParentLoaded(this) && todo.getParent().findChild(todo.id) >= 0 /* because move/insert is nonatomic */) {
this.setView(todo, view);
- var parent = todo.getParent(this.list);
+ var parent = todo.getParent();
var parentView = this.getView(parent);
parentView.addChild(view.render().el, parent.findChild(todo.id));
}
// Find unrendered descendents and render them, too.
- _.each(todo.getChildren(this.list), function(child) {
+ _.each(todo.getChildren(), function(child) {
if (child && !this.getView(child)) {
this.renderTodo(child);
}
} else {
this.stopEditingText();
this.model.toggleComplete();
- var next = this.model.nextNode(this.model.collection, { childrenAllowed: false}) || this.model.getParent(this.model.collection, { rootAllowed: false});
+ var next = this.model.nextNode({ childrenAllowed: false}) || this.model.getParent({ rootAllowed: false});
if (!next) return false;
next.getView().startEditingText();
}
return false;
},
focusNext: function() {
- var nextNode = this.model.nextNode(this.model.collection, { childrenAllowed: true });
+ var nextNode = this.model.nextNode({ childrenAllowed: true });
if (!nextNode) return false;
this.stopEditingText();
nextNode.getView().startEditingText();
return false;
},
focusPrevious: function() {
- var previousNode = this.model.previousNode(this.model.collection, { childrenAllowed: true });
+ var previousNode = this.model.previousNode({ childrenAllowed: true });
if (!previousNode) return false;
this.stopEditingText();
previousNode.getView().startEditingText();
if (this.model.hasChildren()) {
return;
}
- var previousNode = this.model.previousNode(this.model.collection);
+ var previousNode = this.model.previousNode();
if (!previousNode) {
return;
}
if (this.model.get("text") === "") {
- this.model.remove(this.model.collection);
+ this.model.remove();
previousNode.getView().startEditingText({"atEnd":true});
return false;
} else if (this.isFocusAtBeginning()) {
var text = this.model.get("text");
- this.model.remove(this.model.collection);
+ this.model.remove();
previousNode.setText(previousNode.get("text") + '<span class="focus"></span>' + text);
previousNode.getView().startEditingText({"atMarker": ".focus"});
return false;
if (this.model.hasChildren()) {
return;
}
- var nextNode = this.model.nextNode(this.model.collection);
+ var nextNode = this.model.nextNode();
if (!nextNode) {
return;
}
if (this.model.get("text") === "") {
- this.model.remove(this.model.collection);
+ this.model.remove();
nextNode.getView().startEditingText();
return false;
} else if (this.isFocusAtEnd()) {
var text = nextNode.get("text");
- nextNode.remove(this.model.collection);
+ nextNode.remove();
this.stopEditingText();
this.model.setText(this.model.get("text") + '<span class="focus"></span>' + text);
this.startEditingText({"atMarker": ".focus"});
"delete": function() {
// Delete node and its entire subtree
this.focusPrevious();
- this.model.removeAll(this.model.collection);
+ this.model.removeAll();
return false;
},
indent: function() {
// TODO: maintain focus
- this.model.indent(this.model.collection);
+ this.model.indent();
return false;
},
outdent: function() {
// TODO: maintain focus
- this.model.outdent(this.model.collection);
+ this.model.outdent();
},
expand: function() {
console.log("Expand not implemented"); // TODO
},
moveDown: function() {
// TODO: maintain focus
- this.model.moveDown(this.model.collection);
+ this.model.moveDown();
},
moveUp: function() {
// TODO: maintain focus
- this.model.moveUp(this.model.collection);
+ this.model.moveUp();
},
textChange: function(e) {
- var collection = this.model.collection;
var lines = $(e.target).html().split(/<br\\?>/);
if (lines.length === 0) {
console.log("unexpected number of lines in textChange");
this.outdent();
} else if ((lines.length === 2 && lines[1] === "") || (lines.length === 3 && lines[1] === "" && lines[2] === "")) { // Line break at end
this.model.setText(this.decodeText(lines[0]));
- var emptyAfter = this.model.addTodoAfter({text: this.decodeText(lines[1])}, collection); // Child or not depending on whether this has children
+ var emptyAfter = this.model.addTodoAfter({text: this.decodeText(lines[1])}); // Child or not depending on whether this has children
this.stopEditingText();
emptyAfter.getView().startEditingText();
} else if (lines.length === 2 && lines[0] === "") { // Line break at beginning
- var emptyBefore = this.model.addTodoBefore({text: this.decodeText(lines[0])}, collection);
+ var emptyBefore = this.model.addTodoBefore({text: this.decodeText(lines[0])});
this.model.setText(this.decodeText(lines[1]));
this.stopEditingText();
emptyBefore.getView().startEditingText();
} else if (lines.length === 2) { // Line break in middle
- var newNode = this.model.addTodoAfter({text: this.decodeText(lines[1])}, collection);
+ var newNode = this.model.addTodoAfter({text: this.decodeText(lines[1])});
this.model.setText(this.decodeText(lines[0]));
this.stopEditingText(); // For re-render
newNode.getView().startEditingText(); // Keep focus on current node (second half)
getChildrenCount: function() {
return this.get("bullets").length;
},
- getChildren: function(collection) {
+ getChildren: function() {
return _.map(this.get("bullets"), function(id) {
- return collection.get(id);
+ return this.collection.get(id);
}, this);
},
- getChild: function(collection, index) {
- return collection.get(this.get("bullets")[index]);
+ getChild: function(index) {
+ return this.collection.get(this.get("bullets")[index]);
},
- getParent: function(collection, options) {
+ getParent: function(options) {
options = _.defaults({}, options, { rootAllowed: true });
- var parent = collection.get(this.get("parent"));
- if (parent && parent.id == collection.rootId && !options.rootAllowed) return undefined;
+ var parent = this.collection.get(this.get("parent"));
+ if (parent && parent.isRoot() && !options.rootAllowed) return undefined;
return parent;
},
- getPreviousSibling: function(collection) {
- var parent = this.getParent(collection);
+ getPreviousSibling: function() {
+ var parent = this.getParent();
if (!parent) return undefined;
var index = parent.findChild(this.id);
if (index < 0 || index === 0) return undefined;
- return parent.getChild(collection, index - 1);
+ return parent.getChild(index - 1);
},
- getNextSibling: function(collection) {
- var parent = this.getParent(collection);
+ getNextSibling: function() {
+ var parent = this.getParent();
if (!parent) return undefined;
var index = parent.findChild(this.id);
var numChildren = parent.getChildrenCount();
if (index < 0 || index === numChildren - 1) return undefined;
- return parent.getChild(collection, index + 1);
+ return parent.getChild(index + 1);
},
- nextNode: function(collection, options) {
+ nextNode: function(options) {
options = _.defaults({}, options, {childrenAllowed: true});
if (options.childrenAllowed) {
if (this.hasChildren()) {
- return this.getChild(collection, 0);
+ return this.getChild(0);
}
}
- for (var node = this; node && node.id !== collection.rootId; node = node.getParent(collection)) {
- var next = node.getNextSibling(collection);
+ for (var node = this; node && !node.isRoot(); node = node.getParent()) {
+ var next = node.getNextSibling();
if (next) return next;
}
return undefined;
},
- previousNode: function(collection, options) {
+ previousNode: function(options) {
options = _.defaults({}, options, {childrenAllowed: true});
- var previous = this.getPreviousSibling(collection);
+ var previous = this.getPreviousSibling();
if (previous && options.childrenAllowed) {
while (previous.hasChildren()) {
- previous = previous.getChild(collection, previous.getChildrenCount() - 1);
+ previous = previous.getChild(previous.getChildrenCount() - 1);
}
}
- if (!previous) previous = this.getParent(collection);
+ if (!previous) previous = this.getParent();
if (!previous) return undefined;
- if (previous.id === collection.rootId) {
+ if (previous.isRoot()) {
return undefined;
} else {
return previous;
getView: function() { //TODO: remove
return this.collection.app.getView(this);
},
- isTopLevel: function(collection) {
- return this.get("parent") === collection.rootId;
+ isTopLevel: function() {
+ return this.get("parent") === this.collection.rootId;
},
- isParentLoaded: function(collection, collectionView) {
- return this.isTopLevel(collection) ? true : (this.getParent(collection) && collectionView.getView(this.getParent(collection)));
+ isParentLoaded: function(collectionView) {
+ return this.isTopLevel() ? true : (this.getParent() && collectionView.getView(this.getParent()));
},
findChild: function(childId) {
return this.get("bullets").indexOf(childId);
this.set("bullets", bullets);
return this;
},
- moveTo: function(newLocation, collection) {
- if (collection.rootId == this.id) {
+ moveTo: function(newLocation) {
+ if (this.isRoot()) {
console.log("Cannot move root");
return this;
}
var existingLocation = {
- parent: this.getParent(collection),
- index: this.getParent(collection).findChild(this.id),
+ parent: this.getParent(),
+ index: this.getParent().findChild(this.id),
};
newLocation = _.defaults({}, newLocation, existingLocation);
var newChildren;
newLocation.parent.save();
this.save();
}
- collection.trigger("move", this, existingLocation);
+ this.collection.trigger("move", this, existingLocation);
return this;
},
- moveUp: function(collection) {
+ moveUp: function() {
// Before previous sibling, then as last child of previous node of parent, then before parent, then nothing
},
- moveDown: function(collection) {
+ moveDown: function() {
// After next sibling, then as first child of next node after parent, then up one level, then nothing
},
- indent: function(collection) {
+ indent: function() {
// Last child of previous sibling, then nothing
- var previous = this.getPreviousSibling(collection);
+ var previous = this.getPreviousSibling();
if (!previous) return undefined;
return this.moveTo({
parent: previous,
index: previous.getChildrenCount(),
- }, collection);
+ });
},
- outdent: function(collection) {
+ outdent: function() {
// After parent, then nothing
},
- removeChild: function(childTodoModel, collection) {
+ isRoot: function() {
+ return this.id === this.collection.rootId;
+ },
+ removeChild: function(childTodoModel) {
if (childTodoModel.get("bullets").length > 0) {
console.log("Cannot delete node with children.");
return;
}});
return this;
},
- remove: function(collection) {
- this.getParent(collection).removeChild(this, collection);
+ remove: function() {
+ this.getParent().removeChild(this);
},
- removeAll: function(collection) {
- if (collection.rootId == this.id) {
+ removeAll: function() {
+ if (this.isRoot()) {
console.log("Cannot remove root node of collection");
return;
}
if (this.hasChildren()) {
- var children = _.clone(this.getChildren(collection));
+ var children = _.clone(this.getChildren());
_.each(children, function(child) {
- child.removeAll(collection);
+ child.removeAll();
});
}
- this.remove(collection);
+ this.remove();
},
- addTodoBefore: function(todo, collection) {
+ addTodoBefore: function(todo) {
// Todo always goes as the previous sibling
- var parent = this.getParent(collection);
- var todoModel = collection.create(_.extend(todo, {"parent": parent.id}));
+ var parent = this.getParent();
+ var todoModel = this.collection.create(_.extend(todo, {"parent": parent.id}));
parent.insertChild(todoModel, parent.findChild(this.id));
parent.save();
- collection.trigger("add", todoModel);
+ this.collection.trigger("add", todoModel);
return todoModel;
},
- addTodoAfter: function(todo, collection) {
+ addTodoAfter: function(todo) {
// If there are children, the todo goes as the first child.
// Otherwise, the todo goes as the next sibling
var todoModel;
if (this.get("bullets").length > 0) {
- todoModel = collection.create(_.extend(todo, {"parent": this.id}));
+ todoModel = this.collection.create(_.extend(todo, {"parent": this.id}));
this.insertChild(todoModel, 0);
this.save();
} else {
- parent = this.getParent(collection);
- todoModel = collection.create(_.extend(todo, {"parent": parent.id}));
+ parent = this.getParent();
+ todoModel = this.collection.create(_.extend(todo, {"parent": parent.id}));
parent.insertChild(todoModel, parent.findChild(this.id)+1);
parent.save();
}
- collection.trigger("add", todoModel);
+ this.collection.trigger("add", todoModel);
return todoModel;
}
});
console.log("View rendered more than once for todo #" + todo.id);
return;
}
- var view = new TodoView({model: todo, collection: this.list});
- if (todo.isTopLevel(this.list)) {
+ var view = new TodoView({model: todo});
+ if (todo.isTopLevel()) {
this.setView(todo, view);
this.$("#todo-list").append(view.render().el);
- } else if (todo.isParentLoaded(this.list, this) && todo.getParent(this.list).findChild(todo.id) >= 0 /* because move/insert is nonatomic */) {
+ } else if (todo.isParentLoaded(this) && todo.getParent().findChild(todo.id) >= 0 /* because move/insert is nonatomic */) {
this.setView(todo, view);
- var parent = todo.getParent(this.list);
+ var parent = todo.getParent();
var parentView = this.getView(parent);
parentView.addChild(view.render().el, parent.findChild(todo.id));
}
// Find unrendered descendents and render them, too.
- _.each(todo.getChildren(this.list), function(child) {
+ _.each(todo.getChildren(), function(child) {
if (child && !this.getView(child)) {
this.renderTodo(child);
}
getChildrenCount: function() {
return this.get("bullets").length;
},
- getChildren: function(collection) {
+ getChildren: function() {
return _.map(this.get("bullets"), function(id) {
- return collection.get(id);
+ return this.collection.get(id);
}, this);
},
- getChild: function(collection, index) {
- return collection.get(this.get("bullets")[index]);
+ getChild: function(index) {
+ return this.collection.get(this.get("bullets")[index]);
},
- getParent: function(collection, options) {
+ getParent: function(options) {
options = _.defaults({}, options, { rootAllowed: true });
- var parent = collection.get(this.get("parent"));
- if (parent && parent.id == collection.rootId && !options.rootAllowed) return undefined;
+ var parent = this.collection.get(this.get("parent"));
+ if (parent && parent.isRoot() && !options.rootAllowed) return undefined;
return parent;
},
- getPreviousSibling: function(collection) {
- var parent = this.getParent(collection);
+ getPreviousSibling: function() {
+ var parent = this.getParent();
if (!parent) return undefined;
var index = parent.findChild(this.id);
if (index < 0 || index === 0) return undefined;
- return parent.getChild(collection, index - 1);
+ return parent.getChild(index - 1);
},
- getNextSibling: function(collection) {
- var parent = this.getParent(collection);
+ getNextSibling: function() {
+ var parent = this.getParent();
if (!parent) return undefined;
var index = parent.findChild(this.id);
var numChildren = parent.getChildrenCount();
if (index < 0 || index === numChildren - 1) return undefined;
- return parent.getChild(collection, index + 1);
+ return parent.getChild(index + 1);
},
- nextNode: function(collection, options) {
+ nextNode: function(options) {
options = _.defaults({}, options, {childrenAllowed: true});
if (options.childrenAllowed) {
if (this.hasChildren()) {
- return this.getChild(collection, 0);
+ return this.getChild(0);
}
}
- for (var node = this; node && node.id !== collection.rootId; node = node.getParent(collection)) {
- var next = node.getNextSibling(collection);
+ for (var node = this; node && !node.isRoot(); node = node.getParent()) {
+ var next = node.getNextSibling();
if (next) return next;
}
return undefined;
},
- previousNode: function(collection, options) {
+ previousNode: function(options) {
options = _.defaults({}, options, {childrenAllowed: true});
- var previous = this.getPreviousSibling(collection);
+ var previous = this.getPreviousSibling();
if (previous && options.childrenAllowed) {
while (previous.hasChildren()) {
- previous = previous.getChild(collection, previous.getChildrenCount() - 1);
+ previous = previous.getChild(previous.getChildrenCount() - 1);
}
}
- if (!previous) previous = this.getParent(collection);
+ if (!previous) previous = this.getParent();
if (!previous) return undefined;
- if (previous.id === collection.rootId) {
+ if (previous.isRoot()) {
return undefined;
} else {
return previous;
getView: function() { //TODO: remove
return this.collection.app.getView(this);
},
- isTopLevel: function(collection) {
- return this.get("parent") === collection.rootId;
+ isTopLevel: function() {
+ return this.get("parent") === this.collection.rootId;
},
- isParentLoaded: function(collection, collectionView) {
- return this.isTopLevel(collection) ? true : (this.getParent(collection) && collectionView.getView(this.getParent(collection)));
+ isParentLoaded: function(collectionView) {
+ return this.isTopLevel() ? true : (this.getParent() && collectionView.getView(this.getParent()));
},
findChild: function(childId) {
return this.get("bullets").indexOf(childId);
this.set("bullets", bullets);
return this;
},
- moveTo: function(newLocation, collection) {
- if (collection.rootId == this.id) {
+ moveTo: function(newLocation) {
+ if (this.isRoot()) {
console.log("Cannot move root");
return this;
}
var existingLocation = {
- parent: this.getParent(collection),
- index: this.getParent(collection).findChild(this.id),
+ parent: this.getParent(),
+ index: this.getParent().findChild(this.id),
};
newLocation = _.defaults({}, newLocation, existingLocation);
var newChildren;
newLocation.parent.save();
this.save();
}
- collection.trigger("move", this, existingLocation);
+ this.collection.trigger("move", this, existingLocation);
return this;
},
- moveUp: function(collection) {
+ moveUp: function() {
// Before previous sibling, then as last child of previous node of parent, then before parent, then nothing
},
- moveDown: function(collection) {
+ moveDown: function() {
// After next sibling, then as first child of next node after parent, then up one level, then nothing
},
- indent: function(collection) {
+ indent: function() {
// Last child of previous sibling, then nothing
- var previous = this.getPreviousSibling(collection);
+ var previous = this.getPreviousSibling();
if (!previous) return undefined;
return this.moveTo({
parent: previous,
index: previous.getChildrenCount(),
- }, collection);
+ });
},
- outdent: function(collection) {
+ outdent: function() {
// After parent, then nothing
},
- removeChild: function(childTodoModel, collection) {
+ isRoot: function() {
+ return this.id === this.collection.rootId;
+ },
+ removeChild: function(childTodoModel) {
if (childTodoModel.get("bullets").length > 0) {
console.log("Cannot delete node with children.");
return;
}});
return this;
},
- remove: function(collection) {
- this.getParent(collection).removeChild(this, collection);
+ remove: function() {
+ this.getParent().removeChild(this);
},
- removeAll: function(collection) {
- if (collection.rootId == this.id) {
+ removeAll: function() {
+ if (this.isRoot()) {
console.log("Cannot remove root node of collection");
return;
}
if (this.hasChildren()) {
- var children = _.clone(this.getChildren(collection));
+ var children = _.clone(this.getChildren());
_.each(children, function(child) {
- child.removeAll(collection);
+ child.removeAll();
});
}
- this.remove(collection);
+ this.remove();
},
- addTodoBefore: function(todo, collection) {
+ addTodoBefore: function(todo) {
// Todo always goes as the previous sibling
- var parent = this.getParent(collection);
- var todoModel = collection.create(_.extend(todo, {"parent": parent.id}));
+ var parent = this.getParent();
+ var todoModel = this.collection.create(_.extend(todo, {"parent": parent.id}));
parent.insertChild(todoModel, parent.findChild(this.id));
parent.save();
- collection.trigger("add", todoModel);
+ this.collection.trigger("add", todoModel);
return todoModel;
},
- addTodoAfter: function(todo, collection) {
+ addTodoAfter: function(todo) {
// If there are children, the todo goes as the first child.
// Otherwise, the todo goes as the next sibling
var todoModel;
if (this.get("bullets").length > 0) {
- todoModel = collection.create(_.extend(todo, {"parent": this.id}));
+ todoModel = this.collection.create(_.extend(todo, {"parent": this.id}));
this.insertChild(todoModel, 0);
this.save();
} else {
- parent = this.getParent(collection);
- todoModel = collection.create(_.extend(todo, {"parent": parent.id}));
+ parent = this.getParent();
+ todoModel = this.collection.create(_.extend(todo, {"parent": parent.id}));
parent.insertChild(todoModel, parent.findChild(this.id)+1);
parent.save();
}
- collection.trigger("add", todoModel);
+ this.collection.trigger("add", todoModel);
return todoModel;
}
});
console.log("View rendered more than once for todo #" + todo.id);
return;
}
- var view = new TodoView({model: todo, collection: this.list});
- if (todo.isTopLevel(this.list)) {
+ var view = new TodoView({model: todo});
+ if (todo.isTopLevel()) {
this.setView(todo, view);
this.$("#todo-list").append(view.render().el);
- } else if (todo.isParentLoaded(this.list, this) && todo.getParent(this.list).findChild(todo.id) >= 0 /* because move/insert is nonatomic */) {
+ } else if (todo.isParentLoaded(this) && todo.getParent().findChild(todo.id) >= 0 /* because move/insert is nonatomic */) {
this.setView(todo, view);
- var parent = todo.getParent(this.list);
+ var parent = todo.getParent();
var parentView = this.getView(parent);
parentView.addChild(view.render().el, parent.findChild(todo.id));
}
// Find unrendered descendents and render them, too.
- _.each(todo.getChildren(this.list), function(child) {
+ _.each(todo.getChildren(), function(child) {
if (child && !this.getView(child)) {
this.renderTodo(child);
}
} else {
this.stopEditingText();
this.model.toggleComplete();
- var next = this.model.nextNode(this.model.collection, { childrenAllowed: false}) || this.model.getParent(this.model.collection, { rootAllowed: false});
+ var next = this.model.nextNode({ childrenAllowed: false}) || this.model.getParent({ rootAllowed: false});
if (!next) return false;
next.getView().startEditingText();
}
return false;
},
focusNext: function() {
- var nextNode = this.model.nextNode(this.model.collection, { childrenAllowed: true });
+ var nextNode = this.model.nextNode({ childrenAllowed: true });
if (!nextNode) return false;
this.stopEditingText();
nextNode.getView().startEditingText();
return false;
},
focusPrevious: function() {
- var previousNode = this.model.previousNode(this.model.collection, { childrenAllowed: true });
+ var previousNode = this.model.previousNode({ childrenAllowed: true });
if (!previousNode) return false;
this.stopEditingText();
previousNode.getView().startEditingText();
if (this.model.hasChildren()) {
return;
}
- var previousNode = this.model.previousNode(this.model.collection);
+ var previousNode = this.model.previousNode();
if (!previousNode) {
return;
}
if (this.model.get("text") === "") {
- this.model.remove(this.model.collection);
+ this.model.remove();
previousNode.getView().startEditingText({"atEnd":true});
return false;
} else if (this.isFocusAtBeginning()) {
var text = this.model.get("text");
- this.model.remove(this.model.collection);
+ this.model.remove();
previousNode.setText(previousNode.get("text") + '<span class="focus"></span>' + text);
previousNode.getView().startEditingText({"atMarker": ".focus"});
return false;
if (this.model.hasChildren()) {
return;
}
- var nextNode = this.model.nextNode(this.model.collection);
+ var nextNode = this.model.nextNode();
if (!nextNode) {
return;
}
if (this.model.get("text") === "") {
- this.model.remove(this.model.collection);
+ this.model.remove();
nextNode.getView().startEditingText();
return false;
} else if (this.isFocusAtEnd()) {
var text = nextNode.get("text");
- nextNode.remove(this.model.collection);
+ nextNode.remove();
this.stopEditingText();
this.model.setText(this.model.get("text") + '<span class="focus"></span>' + text);
this.startEditingText({"atMarker": ".focus"});
"delete": function() {
// Delete node and its entire subtree
this.focusPrevious();
- this.model.removeAll(this.model.collection);
+ this.model.removeAll();
return false;
},
indent: function() {
// TODO: maintain focus
- this.model.indent(this.model.collection);
+ this.model.indent();
return false;
},
outdent: function() {
// TODO: maintain focus
- this.model.outdent(this.model.collection);
+ this.model.outdent();
},
expand: function() {
console.log("Expand not implemented"); // TODO
},
moveDown: function() {
// TODO: maintain focus
- this.model.moveDown(this.model.collection);
+ this.model.moveDown();
},
moveUp: function() {
// TODO: maintain focus
- this.model.moveUp(this.model.collection);
+ this.model.moveUp();
},
textChange: function(e) {
- var collection = this.model.collection;
var lines = $(e.target).html().split(/<br\\?>/);
if (lines.length === 0) {
console.log("unexpected number of lines in textChange");
this.outdent();
} else if ((lines.length === 2 && lines[1] === "") || (lines.length === 3 && lines[1] === "" && lines[2] === "")) { // Line break at end
this.model.setText(this.decodeText(lines[0]));
- var emptyAfter = this.model.addTodoAfter({text: this.decodeText(lines[1])}, collection); // Child or not depending on whether this has children
+ var emptyAfter = this.model.addTodoAfter({text: this.decodeText(lines[1])}); // Child or not depending on whether this has children
this.stopEditingText();
emptyAfter.getView().startEditingText();
} else if (lines.length === 2 && lines[0] === "") { // Line break at beginning
- var emptyBefore = this.model.addTodoBefore({text: this.decodeText(lines[0])}, collection);
+ var emptyBefore = this.model.addTodoBefore({text: this.decodeText(lines[0])});
this.model.setText(this.decodeText(lines[1]));
this.stopEditingText();
emptyBefore.getView().startEditingText();
} else if (lines.length === 2) { // Line break in middle
- var newNode = this.model.addTodoAfter({text: this.decodeText(lines[1])}, collection);
+ var newNode = this.model.addTodoAfter({text: this.decodeText(lines[1])});
this.model.setText(this.decodeText(lines[0]));
this.stopEditingText(); // For re-render
newNode.getView().startEditingText(); // Keep focus on current node (second half)