setText: function(text) {
this.save({text: text});
},
+ getChildren: function(collection) {
+ return _.map(this.get("bullets"), function(id) {
+ return collection.models[id];
+ }, this);
+ },
+ getParent: function(collection) {
+ return collection.models[this.parent];
+ },
+ isTopLevel: function(collection) {
+ return this.parent === collection.rootId;
+ },
+ isParentLoaded: function(collection) {
+ return isTopLevel(collection) ? true : !!this.getParent(collection);
+ },
});
+
+flowyDocDefaults = { rootId: null };
var FlowyDocModel = Backbone.Collection.extend({
initialize: function(options) {
+ options = _.defaults({}, options, flowyDocDefaults);
this.id = options.id;
this.default = options.default;
},
model: TodoModel,
localStorage: new Backbone.LocalStorage("todos-backbone"),
fetch: function(options) { // TODO: Move to base class as default behavior for localStorage
- // If during the initial fetch, the collection is empty, instead populate it using this.default
+ // If during the initial fetch, the collection is not present, instead populate it using this.default
options = options ? _.clone(options) : {};
var error = options.error;
var collection = this;
id: "master",
default: [
new TodoModel({
+ parent: null,
+ id: 1,
text: "Daily todos",
- bullets: [
- new TodoModel({
- text: "Shave",
- completed: true
- }),
- new TodoModel({
- text: "Check t-mail",
- completed: true
- }),
- new TodoModel({
- text: "Eat green eggs and ham",
- }),
- ],
+ bullets: [2,3,4],
+ }),
+ new TodoModel({
+ parent: 1,
+ id: 2,
+ text: "Shave",
+ completed: true
+ }),
+ new TodoModel({
+ parent: 1,
+ id: 3,
+ text: "Check t-mail",
+ completed: true
+ }),
+ new TodoModel({
+ parent: 1,
+ id: 4,
+ text: "Eat green eggs and ham",
}),
new TodoModel({
+ parent: null,
+ id: 5,
text: "To do this year",
collapsed: true,
- bullets: [
- new TodoModel({
- text: "Save the world",
- bullets: [
- new TodoModel({
- text: "Save California",
- }),
- ],
- }),
- ],
+ bullets: [6],
+ }),
+ new TodoModel({
+ parent: 5,
+ id: 6,
+ text: "Save the world",
+ bullets: [7],
+ }),
+ new TodoModel({
+ parent: 6,
+ id: 7,
+ text: "Save California",
}),
],
});
this.$el.toggleClass('completed', this.model.get('completed'));
this.$el.toggleClass('collapsed', this.model.get('collapsed'));
return this;
- }
+ },
});
+var appDefaults = { list: todos };
var AppView = Backbone.View.extend({
el: $("#todo-app"),
- initialize: function() {
+ initialize: function(options) {
+ options = _.defaults({}, options, appDefaults);
this.listenTo(todos, 'add', this.addOne);
this.listenTo(todos, 'reset', this.addAll);
- todos.fetch(); // If there's nothing on the server can you load defaults instead? check out conditions for calling success/failure for one
- //this.addAll(); //No, make it co-operate with the server
+ this.list = options.list;
+ this.list.fetch();
},
render: function() {
return this;
},
addOne: function(todo) {
+ this.renderTodo(todo);
+ },
+ renderTodo: function(todo) {
+ if (todo.view) {
+ console.log("View rendered more than once for todo #" + todo.id);
+ return;
+ }
var view = new TodoView({model: todo});
- this.$("#todo-list").append(view.render().el);
+ todo.view = view;
+ if (todo.isTopLevel(this.list)) {
+ this.$("#todo-list").append(view.render().el);
+ } else if (todo.isParentLoaded(this.list)) {
+ todo.getParent(this.list).view.el.append(view.render().el);
+ }
+
+ // Find unrendered descendents and render them, too.
+ _.each(todo.getChildren(this.list), function(child) {
+ if (child && !child.view) {
+ this.renderTodo(child);
+ }
+ }, this);
+ return this;
},
addAll: function() {
- todos.each(this.addOne, this);
+ this.list.each(this.addOne, this);
},
});
setText: function(text) {
this.save({text: text});
},
+ getChildren: function(collection) {
+ return _.map(this.get("bullets"), function(id) {
+ return collection.models[id];
+ }, this);
+ },
+ getParent: function(collection) {
+ return collection.models[this.parent];
+ },
+ isTopLevel: function(collection) {
+ return this.parent === collection.rootId;
+ },
+ isParentLoaded: function(collection) {
+ return isTopLevel(collection) ? true : !!this.getParent(collection);
+ },
});
+
+flowyDocDefaults = { rootId: null };
var FlowyDocModel = Backbone.Collection.extend({
initialize: function(options) {
+ options = _.defaults({}, options, flowyDocDefaults);
this.id = options.id;
this.default = options.default;
},
model: TodoModel,
localStorage: new Backbone.LocalStorage("todos-backbone"),
fetch: function(options) { // TODO: Move to base class as default behavior for localStorage
- // If during the initial fetch, the collection is empty, instead populate it using this.default
+ // If during the initial fetch, the collection is not present, instead populate it using this.default
options = options ? _.clone(options) : {};
var error = options.error;
var collection = this;
id: "master",
default: [
new TodoModel({
+ parent: null,
+ id: 1,
text: "Daily todos",
- bullets: [
- new TodoModel({
- text: "Shave",
- completed: true
- }),
- new TodoModel({
- text: "Check t-mail",
- completed: true
- }),
- new TodoModel({
- text: "Eat green eggs and ham",
- }),
- ],
+ bullets: [2,3,4],
+ }),
+ new TodoModel({
+ parent: 1,
+ id: 2,
+ text: "Shave",
+ completed: true
+ }),
+ new TodoModel({
+ parent: 1,
+ id: 3,
+ text: "Check t-mail",
+ completed: true
+ }),
+ new TodoModel({
+ parent: 1,
+ id: 4,
+ text: "Eat green eggs and ham",
}),
new TodoModel({
+ parent: null,
+ id: 5,
text: "To do this year",
collapsed: true,
- bullets: [
- new TodoModel({
- text: "Save the world",
- bullets: [
- new TodoModel({
- text: "Save California",
- }),
- ],
- }),
- ],
+ bullets: [6],
+ }),
+ new TodoModel({
+ parent: 5,
+ id: 6,
+ text: "Save the world",
+ bullets: [7],
+ }),
+ new TodoModel({
+ parent: 6,
+ id: 7,
+ text: "Save California",
}),
],
});
this.$el.toggleClass('completed', this.model.get('completed'));
this.$el.toggleClass('collapsed', this.model.get('collapsed'));
return this;
- }
+ },
});
+var appDefaults = { list: todos };
var AppView = Backbone.View.extend({
el: $("#todo-app"),
- initialize: function() {
+ initialize: function(options) {
+ options = _.defaults({}, options, appDefaults);
this.listenTo(todos, 'add', this.addOne);
this.listenTo(todos, 'reset', this.addAll);
- todos.fetch(); // If there's nothing on the server can you load defaults instead? check out conditions for calling success/failure for one
- //this.addAll(); //No, make it co-operate with the server
+ this.list = options.list;
+ this.list.fetch();
},
render: function() {
return this;
},
addOne: function(todo) {
+ this.renderTodo(todo);
+ },
+ renderTodo: function(todo) {
+ if (todo.view) {
+ console.log("View rendered more than once for todo #" + todo.id);
+ return;
+ }
var view = new TodoView({model: todo});
- this.$("#todo-list").append(view.render().el);
+ todo.view = view;
+ if (todo.isTopLevel(this.list)) {
+ this.$("#todo-list").append(view.render().el);
+ } else if (todo.isParentLoaded(this.list)) {
+ todo.getParent(this.list).view.el.append(view.render().el);
+ }
+
+ // Find unrendered descendents and render them, too.
+ _.each(todo.getChildren(this.list), function(child) {
+ if (child && !child.view) {
+ this.renderTodo(child);
+ }
+ }, this);
+ return this;
},
addAll: function() {
- todos.each(this.addOne, this);
+ this.list.each(this.addOne, this);
},
});