From 8adcfeaab072dfe0c7369b2ab95c14c69295f1de Mon Sep 17 00:00:00 2001 From: Zachary Vance Date: Tue, 17 Mar 2015 19:03:12 -0700 Subject: [PATCH] Tiniest read-only demo complete --- Gruntfile.js | 6 ++++- dist/flowy.css | 18 +++++++++++++++ dist/flowy.js | 55 +++++++++++++++++++++++++++++++--------------- dist/main.html | 1 + src/css/flowy.css | 18 +++++++++++++++ src/main.html | 1 + src/models/test.js | 55 +++++++++++++++++++++++++++++++--------------- 7 files changed, 117 insertions(+), 37 deletions(-) create mode 100644 dist/flowy.css create mode 100644 src/css/flowy.css diff --git a/Gruntfile.js b/Gruntfile.js index 50071e3..da26c6d 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -11,7 +11,7 @@ module.exports = function(grunt) { } }, watch: { - files: ['<%= jshint.files %>'], + files: ['<%= jshint.files %>', '<%= concat.css.src %>'], tasks: ['default'] }, bower_concat: { @@ -30,6 +30,10 @@ module.exports = function(grunt) { dist: { src: ['src/**/*.js'], dest: 'dist/<%= pkg.name %>.js' + }, + css: { + src: ['src/**/*.css'], + dest: 'dist/<%= pkg.name %>.css' } }, copy: { diff --git a/dist/flowy.css b/dist/flowy.css new file mode 100644 index 0000000..75f80e8 --- /dev/null +++ b/dist/flowy.css @@ -0,0 +1,18 @@ +.text { + font-size: 20pt; + margin-top: 5px; + margin-bottom: 5px; +} + +.bullets > .todo { + margin-left: 30px; +} + +.todo.completed > .text { + text-decoration: line-through; + color: grey; +} + +.todo.collapsed .todo { + display: none; +} diff --git a/dist/flowy.js b/dist/flowy.js index 272d20b..052a922 100644 --- a/dist/flowy.js +++ b/dist/flowy.js @@ -5,9 +5,9 @@ var TodoModel = Backbone.Model.extend({ return { completed: false, collapsed: false, - text: "", + text: "Should never be visible", bullets: [], - parent: 0, + parent: null, }; }, toggleComplete: function() { @@ -21,17 +21,17 @@ var TodoModel = Backbone.Model.extend({ }, getChildren: function(collection) { return _.map(this.get("bullets"), function(id) { - return collection.models[id]; + return collection.get(id); }, this); }, getParent: function(collection) { - return collection.models[this.parent]; + return collection.get(this.get("parent")); }, isTopLevel: function(collection) { - return this.parent === collection.rootId; + return this.get("parent") === collection.rootId; }, - isParentLoaded: function(collection) { - return isTopLevel(collection) ? true : !!this.getParent(collection); + isParentLoaded: function(collection, collectionView) { + return this.isTopLevel(collection) ? true : (this.getParent(collection) && collectionView.getView(this.getParent(collection))); }, }); @@ -41,6 +41,7 @@ var FlowyDocModel = Backbone.Collection.extend({ options = _.defaults({}, options, flowyDocDefaults); this.id = options.id; this.default = options.default; + this.rootId = options.rootId; }, model: TodoModel, localStorage: new Backbone.LocalStorage("todos-backbone"), @@ -52,8 +53,7 @@ var FlowyDocModel = Backbone.Collection.extend({ options.error = function(_, resp, __) { if (resp ==="Record Not Found" && collection.default) { var method = options.reset ? 'reset' : 'set'; - collection[method](resp, options); - collection.set(collection.default); + collection[method](collection.default); } if (error) error(collection, resp, options); }; @@ -115,22 +115,32 @@ var todos = new FlowyDocModel({ var TodoView = Backbone.View.extend({ tagName: 'div', + className: 'todo', events: { - "click": "toggleComplete", + "click > .text": "toggleComplete", }, initialize: function() { this.listenTo(this.model, "change", this.render); this.listenTo(this.model, 'destroy', this.remove); }, - toggleComplete: function() { + toggleComplete: function(e) { this.model.toggleComplete(); + e.stopPropagation(); }, template: "
{{text}}
", + addChild: function(el, position) { + if(typeof position === 'undefined') { + console.log("TodoView:addChild called without a position"); + } + this.$el.find("> .bullets").append(el); + return this; + }, render: function() { - //this.$el.html(this.template(this.model.attributes)); - this.$el.html(Mustache.to_html(this.template, this.model.toJSON())); + var oldChildren = this.$el.find("> .bullets > *"); + this.$el.html(Mustache.to_html(this.template, this.model.toJSON())); // Should hopefully be model.attributes this.$el.toggleClass('completed', this.model.get('completed')); this.$el.toggleClass('collapsed', this.model.get('collapsed')); + this.$el.find("> .bullets").append(oldChildren); return this; }, }); @@ -143,6 +153,7 @@ var AppView = Backbone.View.extend({ this.listenTo(todos, 'add', this.addOne); this.listenTo(todos, 'reset', this.addAll); this.list = options.list; + this.views = {}; // A list of views for each element in the collection this.list.fetch(); }, render: function() { @@ -152,26 +163,34 @@ var AppView = Backbone.View.extend({ this.renderTodo(todo); }, renderTodo: function(todo) { - if (todo.view) { + if (this.getView(todo)) { console.log("View rendered more than once for todo #" + todo.id); return; } var view = new TodoView({model: todo}); - todo.view = view; + this.setView(todo, 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); + } else if (todo.isParentLoaded(this.list, this)) { + var parent = todo.getParent(this.list); + var parentView = this.getView(parent); + parentView.addChild(view.render().el); } // Find unrendered descendents and render them, too. _.each(todo.getChildren(this.list), function(child) { - if (child && !child.view) { + if (child && !this.getView(child)) { this.renderTodo(child); } }, this); return this; }, + setView: function(model, view) { + this.views[model.id] = view; + }, + getView: function(model) { + return this.views[model.id]; + }, addAll: function() { this.list.each(this.addOne, this); }, diff --git a/dist/main.html b/dist/main.html index 1579627..ea60868 100644 --- a/dist/main.html +++ b/dist/main.html @@ -2,6 +2,7 @@ +
diff --git a/src/css/flowy.css b/src/css/flowy.css new file mode 100644 index 0000000..75f80e8 --- /dev/null +++ b/src/css/flowy.css @@ -0,0 +1,18 @@ +.text { + font-size: 20pt; + margin-top: 5px; + margin-bottom: 5px; +} + +.bullets > .todo { + margin-left: 30px; +} + +.todo.completed > .text { + text-decoration: line-through; + color: grey; +} + +.todo.collapsed .todo { + display: none; +} diff --git a/src/main.html b/src/main.html index 1579627..ea60868 100644 --- a/src/main.html +++ b/src/main.html @@ -2,6 +2,7 @@ +
diff --git a/src/models/test.js b/src/models/test.js index 272d20b..052a922 100644 --- a/src/models/test.js +++ b/src/models/test.js @@ -5,9 +5,9 @@ var TodoModel = Backbone.Model.extend({ return { completed: false, collapsed: false, - text: "", + text: "Should never be visible", bullets: [], - parent: 0, + parent: null, }; }, toggleComplete: function() { @@ -21,17 +21,17 @@ var TodoModel = Backbone.Model.extend({ }, getChildren: function(collection) { return _.map(this.get("bullets"), function(id) { - return collection.models[id]; + return collection.get(id); }, this); }, getParent: function(collection) { - return collection.models[this.parent]; + return collection.get(this.get("parent")); }, isTopLevel: function(collection) { - return this.parent === collection.rootId; + return this.get("parent") === collection.rootId; }, - isParentLoaded: function(collection) { - return isTopLevel(collection) ? true : !!this.getParent(collection); + isParentLoaded: function(collection, collectionView) { + return this.isTopLevel(collection) ? true : (this.getParent(collection) && collectionView.getView(this.getParent(collection))); }, }); @@ -41,6 +41,7 @@ var FlowyDocModel = Backbone.Collection.extend({ options = _.defaults({}, options, flowyDocDefaults); this.id = options.id; this.default = options.default; + this.rootId = options.rootId; }, model: TodoModel, localStorage: new Backbone.LocalStorage("todos-backbone"), @@ -52,8 +53,7 @@ var FlowyDocModel = Backbone.Collection.extend({ options.error = function(_, resp, __) { if (resp ==="Record Not Found" && collection.default) { var method = options.reset ? 'reset' : 'set'; - collection[method](resp, options); - collection.set(collection.default); + collection[method](collection.default); } if (error) error(collection, resp, options); }; @@ -115,22 +115,32 @@ var todos = new FlowyDocModel({ var TodoView = Backbone.View.extend({ tagName: 'div', + className: 'todo', events: { - "click": "toggleComplete", + "click > .text": "toggleComplete", }, initialize: function() { this.listenTo(this.model, "change", this.render); this.listenTo(this.model, 'destroy', this.remove); }, - toggleComplete: function() { + toggleComplete: function(e) { this.model.toggleComplete(); + e.stopPropagation(); }, template: "
{{text}}
", + addChild: function(el, position) { + if(typeof position === 'undefined') { + console.log("TodoView:addChild called without a position"); + } + this.$el.find("> .bullets").append(el); + return this; + }, render: function() { - //this.$el.html(this.template(this.model.attributes)); - this.$el.html(Mustache.to_html(this.template, this.model.toJSON())); + var oldChildren = this.$el.find("> .bullets > *"); + this.$el.html(Mustache.to_html(this.template, this.model.toJSON())); // Should hopefully be model.attributes this.$el.toggleClass('completed', this.model.get('completed')); this.$el.toggleClass('collapsed', this.model.get('collapsed')); + this.$el.find("> .bullets").append(oldChildren); return this; }, }); @@ -143,6 +153,7 @@ var AppView = Backbone.View.extend({ this.listenTo(todos, 'add', this.addOne); this.listenTo(todos, 'reset', this.addAll); this.list = options.list; + this.views = {}; // A list of views for each element in the collection this.list.fetch(); }, render: function() { @@ -152,26 +163,34 @@ var AppView = Backbone.View.extend({ this.renderTodo(todo); }, renderTodo: function(todo) { - if (todo.view) { + if (this.getView(todo)) { console.log("View rendered more than once for todo #" + todo.id); return; } var view = new TodoView({model: todo}); - todo.view = view; + this.setView(todo, 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); + } else if (todo.isParentLoaded(this.list, this)) { + var parent = todo.getParent(this.list); + var parentView = this.getView(parent); + parentView.addChild(view.render().el); } // Find unrendered descendents and render them, too. _.each(todo.getChildren(this.list), function(child) { - if (child && !child.view) { + if (child && !this.getView(child)) { this.renderTodo(child); } }, this); return this; }, + setView: function(model, view) { + this.views[model.id] = view; + }, + getView: function(model) { + return this.views[model.id]; + }, addAll: function() { this.list.each(this.addOne, this); }, -- 2.47.3