Skip to content

Commit

Permalink
Lurching slightly closer to student sorting
Browse files Browse the repository at this point in the history
Adds handlebars_assets for backbone templates
  • Loading branch information
tjgrathwell committed May 16, 2013
1 parent 00deba2 commit 815af89
Show file tree
Hide file tree
Showing 12 changed files with 169 additions and 41 deletions.
1 change: 1 addition & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ group :production do
end

group :assets do
gem 'handlebars_assets'
gem 'jquery-datatables-rails'
gem 'sass-rails'
gem 'coffee-rails'
Expand Down
5 changes: 5 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,10 @@ GEM
guard-rspec (2.5.0)
guard (>= 1.1)
rspec (~> 2.11)
handlebars_assets (0.12.0)
execjs (>= 1.2.9)
sprockets (>= 2.0.3)
tilt
hashie (1.2.0)
hike (1.2.1)
http_parser.rb (0.5.3)
Expand Down Expand Up @@ -285,6 +289,7 @@ DEPENDENCIES
gmaps4rails
gravatar_image_tag
guard-rspec
handlebars_assets
jasmine
jquery-datatables-rails
jquery-rails
Expand Down
5 changes: 5 additions & 0 deletions app/assets/javascripts/application.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,20 @@
//= require jquery
//= require jquery_ujs
//= require jquery.ui.datepicker
//= require jquery.ui.sortable
//= require twitter/bootstrap/modal
//= require twitter/bootstrap/transition
//= require select2
//= require modernizr
//= require handlebars.runtime
//= require underscore
//= require backbone
//= require backbone-super
//= require bridgetroll
//= require_tree ../templates
//= require_tree ./models
//= require_tree ./collections
//= require ./views/base_view
//= require_tree ./views
//= require_tree .
//= require jquery_nested_form
Expand Down
24 changes: 24 additions & 0 deletions app/assets/javascripts/views/base_view.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
Bridgetroll.Views.Base = Backbone.View.extend({
postRender: $.noop,
context: $.noop,

initialize: function () {
this.subViews = [];
},

render: function () {
this.$el.empty();
if (this.template) {
var template = HandlebarsTemplates[this.template];
this.$el.html(template(this.context()));
}

this.postRender();
this.delegateEvents();

_.each(this.subViews, function (view) {
view.render();
this.$el.append(view.$el);
}, this);
}
});
31 changes: 12 additions & 19 deletions app/assets/javascripts/views/section_organizer_view.js
Original file line number Diff line number Diff line change
@@ -1,30 +1,23 @@
Bridgetroll.Views.SectionOrganizer = Backbone.View.extend({
initialize: function (options) {
this.subViews = [];
this.students = options && options.students;
Bridgetroll.Views.SectionOrganizer = Bridgetroll.Views.Base.extend({
template: 'section_organizer/section_organizer',

this.students.each(function (student) {
this.addStudent(student);
}, this);
events: {
'click .add-section': 'addSection'
},

render: function () {
this.$el.empty();

_.each(this.subViews, function (view) {
view.render();
this.$el.append(view.$el);
}, this);
},
initialize: function (options) {
this._super('initialize', arguments);
this.students = options.students;
this.listenTo(this.students, 'change', this.render);

addStudent: function (student) {
var studentView = new Bridgetroll.Views.Student({model: student});
this.subViews.push(studentView);
var section = new Bridgetroll.Views.Section({title: 'Unsorted Students', students: options.students});
this.subViews.push(section);
this.render();
},

addSection: function () {
var section = new Bridgetroll.Views.Section();
var sectionStudents = new Bridgetroll.Collections.Student();
var section = new Bridgetroll.Views.Section({title: 'New Section', students: sectionStudents});
this.subViews.push(section);
this.render();
}
Expand Down
30 changes: 26 additions & 4 deletions app/assets/javascripts/views/section_view.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,30 @@
Bridgetroll.Views.Section = Backbone.View.extend({
Bridgetroll.Views.Section = Bridgetroll.Views.Base.extend({
className: 'bridgetroll-section',
template: 'section_organizer/section',

render: function () {
this.$el.empty();
this.$el.append('i am a section');
events: {
'sortreceive .students': 'studentAdded',
'sortremove .students': 'studentRemoved'
},

initialize: function (options) {
this._super('initialize', arguments);

this.title = options.title;
this.students = options.students;
},

context: function () {
return {
title: this.title,
students: this.students.toJSON()
}
},

studentAdded: $.noop,
studentRemoved: $.noop,

postRender: function () {
this.$('.students').sortable({connectWith: '.bridgetroll-section .students'});
}
});
8 changes: 0 additions & 8 deletions app/assets/javascripts/views/student_view.js

This file was deleted.

10 changes: 10 additions & 0 deletions app/assets/stylesheets/_section_organizer.css.scss
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,14 @@

.bridgetroll-section {
border: 1px solid green;
padding: 5px;
width: 200px;

.students {
min-height: 50px;
}
}

ul {
list-style-type: none;
}
6 changes: 6 additions & 0 deletions app/assets/templates/section_organizer/section.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<h3>{{title}}</h3>
<ul class='students'>
{{#each students}}
<li>{{this.name}}</li>
{{/each}}
</ul>
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<button class='add-section'>Add Section</button>
31 changes: 21 additions & 10 deletions spec/javascripts/section_organizer/section_organizer_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,23 +10,34 @@ describe("SectionOrganizer", function() {
sectionOrganizer = new Bridgetroll.Views.SectionOrganizer({students: students});
});

it("renders each of the students from the original collection", function () {
sectionOrganizer.render();
expect(sectionOrganizer.$el.text()).toContain('Lana Lang');
expect(sectionOrganizer.$el.text()).toContain('Sue Storm');
expect(sectionOrganizer.$el.text()).toContain('Ted Moesby');
describe("after rendering", function () {
beforeEach(function () {
sectionOrganizer.render();
});

it("contains each of the students from the original collection", function () {
expect(sectionOrganizer.$el.text()).toContain('Lana Lang');
expect(sectionOrganizer.$el.text()).toContain('Sue Storm');
expect(sectionOrganizer.$el.text()).toContain('Ted Moesby');
});

describe("add section button", function () {
it("should invoke #addSection", function () {
spyOn(sectionOrganizer, 'addSection');
sectionOrganizer.$('.add-section').click();
sectionOrganizer.$('.add-section').click(); // TODO: not this
expect(sectionOrganizer.addSection).toHaveBeenCalled();
});
});
});

describe("#addSection", function () {
it("adds a new section as a subview", function () {
sectionOrganizer.render();
expect(sectionOrganizer.$('.bridgetroll-section').length).toEqual(0);

sectionOrganizer.addSection();
expect(sectionOrganizer.$('.bridgetroll-section').length).toEqual(1);

var sectionCount = sectionOrganizer.$('.bridgetroll-section').length;
sectionOrganizer.addSection();
expect(sectionOrganizer.$('.bridgetroll-section').length).toEqual(2);
expect(sectionOrganizer.$('.bridgetroll-section').length).toEqual(sectionCount + 1);
});
});
});
58 changes: 58 additions & 0 deletions vendor/assets/javascripts/backbone-super.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// This method gives you an easier way of calling super
// when you're using Backbone in plain javascript.
// It lets you avoid writing the constructor's name multiple
// times. You still have to specify the name of the method.
//
// So instead of having to write:
//
// User = Backbone.Model.extend({
// save: function(attrs) {
// this.beforeSave(attrs);
// return User.__super__.save.apply(this, arguments);
// }
// });
//
// You get to write:
//
// User = Backbone.Model.extend({
// save: function(attrs) {
// this.beforeSave(attrs);
// return this._super("save", arguments);
// }
// });
//

;(function(Backbone) {

// The super method takes two parameters: a method name
// and an array of arguments to pass to the overridden method.
// This is to optimize for the common case of passing 'arguments'.
function _super(methodName, args) {

// Keep track of how far up the prototype chain we have traversed,
// in order to handle nested calls to _super.
this._superCallObjects || (this._superCallObjects = {});
var currentObject = this._superCallObjects[methodName] || this,
parentObject = findSuper(methodName, currentObject);
this._superCallObjects[methodName] = parentObject;

var result = parentObject[methodName].apply(this, args || []);
delete this._superCallObjects[methodName];
return result;
}

// Find the next object up the prototype chain that has a
// different implementation of the method.
function findSuper(methodName, childObject) {
var object = childObject;
while (object[methodName] === childObject[methodName]) {
object = object.constructor.__super__;
}
return object;
}

_.each(["Model", "Collection", "View", "Router"], function(klass) {
Backbone[klass].prototype._super = _super;
});

})(Backbone);

0 comments on commit 815af89

Please sign in to comment.