From 15e377170a3c557fa3f3ba2a35e648a593a0a51d Mon Sep 17 00:00:00 2001 From: Zachary Vance Date: Tue, 17 Mar 2015 17:41:23 -0700 Subject: [PATCH] render all children --- dist/flowy.js | 110 ++++++++++++++++++++++++++++++++------------- src/models/test.js | 110 ++++++++++++++++++++++++++++++++------------- 2 files changed, 160 insertions(+), 60 deletions(-) diff --git a/dist/flowy.js b/dist/flowy.js index 199f116..272d20b 100644 --- a/dist/flowy.js +++ b/dist/flowy.js @@ -19,16 +19,33 @@ var TodoModel = Backbone.Model.extend({ 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; @@ -53,34 +70,45 @@ var todos = new FlowyDocModel({ 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", }), ], }); @@ -104,26 +132,48 @@ var TodoView = Backbone.View.extend({ 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); }, }); diff --git a/src/models/test.js b/src/models/test.js index 199f116..272d20b 100644 --- a/src/models/test.js +++ b/src/models/test.js @@ -19,16 +19,33 @@ var TodoModel = Backbone.Model.extend({ 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; @@ -53,34 +70,45 @@ var todos = new FlowyDocModel({ 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", }), ], }); @@ -104,26 +132,48 @@ var TodoView = Backbone.View.extend({ 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); }, }); -- 2.47.3