diff --git a/client/spa/js/learning-resource/learning-resource.view.js b/client/spa/js/learning-resource/learning-resource.view.js
index 44f514e..43b16d8 100644
--- a/client/spa/js/learning-resource/learning-resource.view.js
+++ b/client/spa/js/learning-resource/learning-resource.view.js
@@ -7,7 +7,33 @@ var $ = require('../vendor/index').$;
var fs = require('fs'); //will be replaced by brfs in the browser
// readFileSync will be evaluated statically so errors can't be caught
-var template = fs.readFileSync(__dirname + '/learning-resources.html', 'utf8');
+var template = fs.readFileSync(__dirname + '/learning-resource.html', 'utf8');
+
+var showMessage = function(type, msg) {
+ $('#msg').empty().addClass(type)
+ .html(msg).fadeIn().delay(2000)
+ .fadeOut('slow').queue(function(remove) {
+ $('#msg').removeClass(type);
+ remove();
+ });
+};
+
+var renderAuthors = function(self) {
+ var auth = self.model.get('authors').toString().split(',').join(', ');
+ self.input = self.$('.editing');
+ self.$('select option[value="'+self.model.get('resourceType')+'"]')
+ .attr('selected','selected');
+ self.$('#auth').val(auth);
+ self.$('#author-dsp').text(auth);
+};
+
+var initialValues = function(self) {
+ self.$('#title').val(self.model.get('title'));
+ self.$('#desc').val(self.model.get('description'));
+ self.$('#auth').val(self.model.get('authors'));
+ self.$('select option[value="'+self.model.get('resourceType')+'"]')
+ .attr('selected','selected');
+};
module.exports = Backbone.View.extend({
@@ -34,75 +60,56 @@ module.exports = Backbone.View.extend({
},
cancel: function(){
- this.$('#title').val(this.model.get('title'));
- this.$('#desc').val(this.model.get('description'));
- this.$('#auth').val(this.model.get('authors'));
- this.$('select option[value="'+this.model.get('resourceType')+'"]')
- .attr('selected','selected');
$('#form-area').removeClass('sty-form'); //remove bg color of form
- $('#msg').empty()
- .addClass('alert-warning')
- .html('Changes cancelled')
- .fadeIn().delay(2000).fadeOut('slow')
- .queue(function(remove){
- $('#msg').removeClass('alert-warning');
- remove();
- });
+ showMessage('alert-warning', 'Changes cancelled');
this.$el.removeClass('editing');
},
save: function(){
var view = this;
- var auth = [];
- if (this.$('#auth').val() === '') auth = null;
- else $.each(this.$('#auth').val().split(','), function(){
- auth.push($.trim(this));
- });
- var attributes = {
- title: this.$('#title').val().trim(),
- resourceType: $('#resourceType option:selected').val(),
- description: this.$('#desc').val().trim(),
- authors: auth
+
+ var authorsFormat = function() {
+ var authors = [];
+ // console.log($('#auth').val().split(','));
+ if ($('#auth').val() === '') authors = null;
+ else {
+ $.each($('#auth').val().split(','), function(key,value){
+ authors.push(value.trim());
+ });
+ return authors;
+ }
};
- var options = {
- success: function(){
- $('#form-area').removeClass('sty-form');
- view.$el.removeClass('editing');
- $('#msg').empty()
- .addClass('alert-success')
- .html('Sucessfully updated')
- .fadeIn().delay(2000).fadeOut('slow')
- .queue(function(remove){
- $('#msg').removeClass('alert-success');
- remove();
- });
+
+ var saveArgs = {
+ attributes: {
+ title: this.$('#title').val().trim(),
+ resourceType: $('#resourceType option:selected').val(),
+ description: this.$('#desc').val().trim(),
+ authors: authorsFormat
},
- error: function(model, error){
- //server response errors if no validations specified
+ options: {
+ success: function(){
+ $('#form-area').removeClass('sty-form');
+ view.$el.removeClass('editing');
+ showMessage('alert-success', 'Successfully updated');
+ },
+ error: function(model, error){
+ //server response errors if no validations specified
+ }
}
};
- this.model.save(attributes, options);
+
+ this.model.save(saveArgs.attributes, saveArgs.options);
+
if (this.model.validationError) {
- $('#msg').empty()
- .addClass('alert-danger')
- .html(this.model.validationError)
- .fadeIn().delay(2000).fadeOut('slow')
- .queue(function(remove){
- $('#msg').removeClass('alert-danger');
- remove();
- });
+ showMessage('alert-danger', this.model.validationError);
}
},
render: function(){
var context = this.model.toJSON();
- var auth = this.model.get('authors').toString().split(',').join(', ');
this.$el.html(this.template(context));
- this.input = this.$('.editing');
- this.$('select option[value="'+this.model.get('resourceType')+'"]')
- .attr('selected','selected');
- this.$('#auth').val(auth);
- this.$('#author-dsp').text(auth);
+ renderAuthors(this);
return this;
},
diff --git a/client/spa/js/learning-resource/learning-resources.collection.js b/client/spa/js/learning-resource/learning-resources.collection.js
new file mode 100644
index 0000000..9e70c4e
--- /dev/null
+++ b/client/spa/js/learning-resource/learning-resources.collection.js
@@ -0,0 +1,57 @@
+'use strict';
+
+var Backbone = require('../vendor/index').Backbone;
+
+module.exports = Backbone.Collection.extend({
+
+ url: '/api/learning-resources/',
+
+ initialize: function(){
+ this.on('sortById', this.sortById);
+ this.on('sortByTitle', this.sortByTitle);
+ this.on('sortByResourceType', this.sortByResourceType);
+ this.on('sortByAuthors', this.sortByAuthors);
+ this.on('sortByDescription', this.sortByDescription);
+ this.trigger('sortByTitle');
+ this.trigger('sortByResourceType');
+ this.trigger('sortByAuthors');
+ this.trigger('sortByDescription');
+ },
+
+ sortById: function(){
+ this.comparator = function(model){
+ return model.get('id');
+ };
+ this.sort();
+ },
+
+ sortByTitle: function(){
+ this.comparator = function(model){
+ return model.get('title');
+ };
+ this.sort();
+ },
+
+ sortByResourceType: function(){
+ this.comparator = function(model){
+ return model.get('resourceType');
+ };
+ this.sort();
+ },
+
+ sortByAuthors: function(){
+ this.comparator = function(model){
+ return model.get('authors');
+ };
+ this.sort();
+ },
+
+ sortByDescription: function(){
+ this.comparator = function(model){
+ return model.get('description');
+ };
+ this.sort();
+ }
+
+});
+
diff --git a/client/spa/js/learning-resource/learning-resources.controller.js b/client/spa/js/learning-resource/learning-resources.controller.js
new file mode 100644
index 0000000..262729b
--- /dev/null
+++ b/client/spa/js/learning-resource/learning-resources.controller.js
@@ -0,0 +1,62 @@
+'use strict';
+
+var Backbone = require('../vendor/index').Backbone;
+var $ = require('../vendor/index').$;
+var Model = require('./learning-resource.model');
+var Collection = require('./learning-resources.collection');
+var View = require('./learning-resources.view');
+
+module.exports = Backbone.Controller.extend({
+
+ routes: {
+ 'learning-resources': 'showLearningResources'
+ },
+
+ initialize: function(){
+ this.options.container = this.options.container || 'body';
+ },
+
+ getCollection: function(){
+ if (!this.collection){
+ Collection = Collection.extend({model: Model});
+ this.collection = new Collection();
+ }
+ return this.collection;
+ },
+
+ getView: function(){
+ if (!this.view){
+ var V = View.extend({collection: this.collection});
+ this.view = new V();
+ }
+ return this.view;
+ },
+
+ showLearningResources: function(){
+ var self = this;
+ this.getCollection().fetch({
+ success: function(collection, response, options){
+ self.getView();
+ self.renderView();
+ },
+ error: function(collection, response, options){
+ self.renderError();
+ }
+ });
+ },
+
+ renderToContainer: function(html){
+ return $(this.options.container).html(html);
+ },
+
+ renderView: function(){
+ this.renderToContainer(this.view.render().$el);
+ return this.view;
+ },
+
+ renderError: function(){
+ return this.renderToContainer(
+ '
There was a problem rendering learning resources
');
+ }
+
+});
diff --git a/client/spa/js/learning-resource/learning-resources.html b/client/spa/js/learning-resource/learning-resources.html
index b17cf80..1dbd669 100644
--- a/client/spa/js/learning-resource/learning-resources.html
+++ b/client/spa/js/learning-resource/learning-resources.html
@@ -1,122 +1,23 @@
-
-
+
+
Learning Resources
+
+
+
+ <% _.each( models, function( model ){ %>
+
+
+ | <%- model.attributes.title %> |
+ <%- model.attributes.resourceType %> |
+ <%- model.attributes.authors %> |
+ <%- model.attributes.description %> |
+
+ <% }); %>
+
+
+
diff --git a/client/spa/js/learning-resource/learning-resources.view.js b/client/spa/js/learning-resource/learning-resources.view.js
new file mode 100644
index 0000000..7237300
--- /dev/null
+++ b/client/spa/js/learning-resource/learning-resources.view.js
@@ -0,0 +1,69 @@
+'use strict';
+
+var Backbone = require('../vendor/index').Backbone;
+var _ = require('../vendor/index')._;
+
+var fs = require('fs'); //will be replaced by brfs in the browser
+
+// readFileSync will be evaluated statically so errors can't be caught
+var template = fs.readFileSync(__dirname + '/learning-resources.html', 'utf8');
+
+module.exports = Backbone.View.extend({
+
+ className: 'learning-resources',
+
+ template: _.template(template),
+
+ events:{
+ 'click .sortById': 'sortById',
+ 'click .sortByTitle': 'sortByTitle',
+ 'click .sortByResourceType': 'sortByResourceType',
+ 'click .sortByAuthors': 'sortByAuthors',
+ 'click .sortByDescription': 'sortByDescription'
+ },
+
+ initialize: function() {
+ this.listenTo(this.collection, 'add', function(){
+ this.render();
+ });
+ this.listenTo(this.collection, 'reset', function(){
+ this.render();
+ });
+ this.listenTo(this.collection, 'sort', function(){
+ this.render();
+ });
+ },
+
+ render: function() {
+ var context = this.collection;
+ this.$el.html(this.template(context));
+ return this;
+ },
+
+ sortById: function(){
+ this.collection.trigger('sortById');
+ this.render();
+ },
+
+ sortByTitle: function(){
+ this.collection.trigger('sortByTitle');
+ this.render();
+ },
+
+ sortByResourceType: function(){
+ this.collection.trigger('sortByResourceType');
+ this.render();
+ },
+
+ sortByAuthors: function(){
+ this.collection.trigger('sortByAuthors');
+ this.render();
+ },
+
+ sortByDescription: function(){
+ this.collection.trigger('sortByDescription');
+ this.render();
+ }
+
+});
+
diff --git a/client/spa/js/learning-resource/spec/learning-resource.controller.spec.js b/client/spa/js/learning-resource/spec/learning-resource.controller.spec.js
index 02028dd..f8a78aa 100644
--- a/client/spa/js/learning-resource/spec/learning-resource.controller.spec.js
+++ b/client/spa/js/learning-resource/spec/learning-resource.controller.spec.js
@@ -28,7 +28,7 @@ describe('Learning resource controller', function(){
it('has the expected routes', function(){
expect(controller.routes).toEqual(jasmine.objectContaining({
- 'learning-resource/:id': 'showLearningResource'
+ 'learning-resources/:id': 'showLearningResource'
}));
});
@@ -80,9 +80,9 @@ describe('Learning resource controller', function(){
it('does has a previous view to remove', function(){
var oldView = controller.view;
- spyOn(oldView, 'destroy');
+ spyOn(oldView, 'remove');
controller.showLearningResource(222);
- expect(oldView.destroy).toHaveBeenCalled();
+ expect(oldView.remove).toHaveBeenCalled();
});
});
diff --git a/client/spa/js/learning-resource/spec/learning-resource.view.spec.js b/client/spa/js/learning-resource/spec/learning-resource.view.spec.js
index 4add979..fc4c1aa 100644
--- a/client/spa/js/learning-resource/spec/learning-resource.view.spec.js
+++ b/client/spa/js/learning-resource/spec/learning-resource.view.spec.js
@@ -101,7 +101,7 @@ describe('Learning resource view ', function(){
view.render();
view.$('#title').val('changed title');
view.$('#desc').val('changed description');
- view.$('#authors').val('sis');
+ view.$('#auth').val('sis');
view.$('#resourceType option:selected').val('link');
spyOn(view, 'save').and.callThrough();
view.delegateEvents();
diff --git a/client/spa/js/learning-resource/spec/learning-resources.collection.spec.js b/client/spa/js/learning-resource/spec/learning-resources.collection.spec.js
new file mode 100644
index 0000000..cfa24fd
--- /dev/null
+++ b/client/spa/js/learning-resource/spec/learning-resources.collection.spec.js
@@ -0,0 +1,122 @@
+/*
+global jasmine, describe, it, expect, beforeEach, afterEach, xdescribe, xit,
+spyOn
+*/
+
+// Get the code you want to test
+var Collection = require('../learning-resources.collection');
+
+// Test suite
+console.log('test learning-resources.collection');
+describe('Learning resources collection ', function(){
+
+ var collection;
+ var modelA;
+ var modelB;
+ var modelC;
+
+ beforeEach(function(){
+ // Set up test data
+ modelA = {
+ id: 2,
+ title: 'A',
+ resourceType: 'link',
+ description: 'reading',
+ authors: 'mom'
+ };
+ modelB = {id: 0,
+ title: 'M',
+ resourceType: 'presentation',
+ description: 'mixing',
+ authors: 'bro'
+ };
+ modelC = {id: 1,
+ title: 'X',
+ resourceType: 'document',
+ description: 'listing',
+ authors: 'hass'
+ };
+
+ });
+
+
+ describe('when models are added to the collection ', function(){
+
+ beforeEach(function(){
+ collection = new Collection();
+
+ collection.add([
+ modelC,
+ modelB,
+ modelA
+ ],
+ {silent: false} // Set to true to suppress add event
+ );
+
+ });
+
+
+ it('orders the models by the contact id', function(){
+ expect(collection.at(0).get('id')).toEqual(modelC.id);
+ expect(collection.at(1).get('id')).toEqual(modelB.id);
+ expect(collection.at(2).get('id')).toEqual(modelA.id);
+ });
+
+ });
+
+ describe('when the collection interacts with the server', function(){
+
+ it('fetches from the correct url', function(){
+ collection = new Collection();
+ expect(collection.url).toEqual('/api/learning-resources/');
+ });
+
+ });
+
+ describe('when a sort event is triggered', function(){
+
+ beforeEach(function(){
+ collection = new Collection();
+
+ collection.add([
+ modelC,
+ modelB,
+ modelA
+ ],
+ {silent: false} // Set to true to suppress add event
+ );
+
+ });
+
+ it('sorts by title', function(){
+ collection.trigger('sortByTitle');
+ expect(collection.at(0).get('title')).toEqual(modelA.title);
+ expect(collection.at(1).get('title')).toEqual(modelB.title);
+ expect(collection.at(2).get('title')).toEqual(modelC.title);
+ });
+
+ it('sorts by resource type', function(){
+ collection.trigger('sortByResourceType');
+ expect(collection.at(0).get('resourceType')).toEqual(modelC.resourceType);
+ expect(collection.at(1).get('resourceType')).toEqual(modelA.resourceType);
+ expect(collection.at(2).get('resourceType')).toEqual(modelB.resourceType);
+ });
+
+ it('sorts by authors', function(){
+ collection.trigger('sortByAuthors');
+ expect(collection.at(0).get('authors')).toEqual(modelB.authors);
+ expect(collection.at(1).get('authors')).toEqual(modelC.authors);
+ expect(collection.at(2).get('authors')).toEqual(modelA.authors);
+ });
+
+ it('sorts by description', function(){
+ collection.trigger('sortByDescription');
+ expect(collection.at(0).get('description')).toEqual(modelC.description);
+ expect(collection.at(1).get('description')).toEqual(modelB.description);
+ expect(collection.at(2).get('description')).toEqual(modelA.description);
+ });
+
+ });
+
+});
+
diff --git a/client/spa/js/learning-resource/spec/learning-resources.controller.spec.js b/client/spa/js/learning-resource/spec/learning-resources.controller.spec.js
new file mode 100644
index 0000000..c42282a
--- /dev/null
+++ b/client/spa/js/learning-resource/spec/learning-resources.controller.spec.js
@@ -0,0 +1,124 @@
+/*
+global jasmine, describe, it, expect, beforeEach, afterEach, xdescribe, xit,
+spyOn
+*/
+
+// Get the code you want to test
+var Backbone = require('../../vendor/index').Backbone;
+var Controller = require('../learning-resources.controller');
+var $ = require('jquery');
+var matchers = require('jasmine-jquery-matchers');
+
+// Test suite
+console.log('test learning-resources.controller');
+describe('Learning resources controller', function(){
+
+ var controller;
+
+ beforeEach(function(){
+ controller = new Controller();
+ });
+
+ it('can be created', function(){
+ expect(controller).toBeDefined();
+ });
+
+ describe('when it is created', function(){
+
+ it('has the expected routes', function(){
+ expect(controller.routes).toEqual(jasmine.objectContaining({
+ 'learning-resources': 'showLearningResources'
+ }));
+ });
+
+ it('without a container option, uses body as the container', function(){
+ expect(controller.options.container).toEqual('body');
+ });
+
+ it('with a container option, uses specified container', function(){
+ var ctrl = new Controller({container: '.newcontainer'});
+ expect(ctrl.options.container).toEqual('.newcontainer');
+ });
+ });
+
+ describe('when asked to showLearningResources', function(){
+
+ beforeEach(function(){
+ jasmine.addMatchers(matchers);
+
+ });
+
+ describe('and fetch is successful', function(){
+
+ beforeEach(function(){
+ spyOn(Backbone.Collection.prototype, 'fetch').and.callFake(
+ function(options){
+ options.success();
+ }
+ );
+ });
+
+ it('sets up the collection if it is not already', function(){
+ expect(controller.collection).not.toBeDefined();
+ controller.showLearningResources();
+ expect(controller.collection).toBeDefined();
+ });
+
+ it('uses the existing collection if it is already setup', function(){
+ controller.showLearningResources();
+ controller.collection.add({id: 'xyz'});
+ controller.showLearningResources();
+ expect(controller.collection.at(0).get('id')).toEqual('xyz');
+ });
+
+ it('fetches data for the collection', function(){
+ controller.showLearningResources();
+ expect(controller.collection.fetch).toHaveBeenCalled();
+ });
+
+ it('sets up the view if it is not already', function(){
+ expect(controller.view).not.toBeDefined();
+ controller.showLearningResources();
+ expect(controller.view).toBeDefined();
+ });
+
+ it('uses the existing view if it is already setup', function(){
+ controller.showLearningResources();
+ controller.view.test = true;
+ controller.showLearningResources();
+ expect(controller.view.test).toBeTruthy();
+ });
+
+ it('renders the view to the correct container', function() {
+ spyOn(controller, 'renderView').and.callThrough();
+ controller.showLearningResources();
+ var returnedView = controller.renderView.calls.mostRecent().object.view;
+ expect(returnedView).toEqual(controller.view);
+ expect($('body h3')).toHaveText('Learning Resources');
+ });
+
+ });
+
+ describe('and fetch errors', function(){
+
+ beforeEach(function(){
+ spyOn(Backbone.Collection.prototype, 'fetch').and.callFake(
+ function(options){
+ options.error();
+ }
+ );
+ });
+
+ it('renders error', function(){
+ controller.showLearningResources();
+ expect($('body')).toHaveText(
+ 'There was a problem rendering learning resources'
+ );
+ });
+
+ });
+
+ });
+
+});
+
diff --git a/client/spa/js/learning-resource/spec/learning-resources.view.spec.js b/client/spa/js/learning-resource/spec/learning-resources.view.spec.js
new file mode 100644
index 0000000..6f17424
--- /dev/null
+++ b/client/spa/js/learning-resource/spec/learning-resources.view.spec.js
@@ -0,0 +1,221 @@
+/*
+global jasmine, describe, it, expect, beforeEach, afterEach, xdescribe, xit,
+spyOn
+*/
+
+// Get the code you want to test
+var View = require('../learning-resources.view.js');
+var matchers = require('jasmine-jquery-matchers');
+var _ = require('../../vendor/index')._;
+var Backbone = require('../../vendor/index').Backbone;
+
+// Test suite
+console.log('test learning-resources.view');
+describe('Learning resources view ', function(){
+
+ var model;
+ var collection;
+ var view;
+
+ beforeEach(function(){
+ // Add some convenience tests for working with the DOM
+ jasmine.addMatchers(matchers);
+
+ var Model = Backbone.Model.extend({});
+ var Collection = Backbone.Collection.extend({model: Model});
+ // Needs to have the fields required by the template
+ model = new Model({
+ title: 'Meow',
+ resourceType: 'presentation',
+ description: 'Purrr',
+ authors: 'Mr. Meowmers'
+ });
+
+ collection = new Collection(model);
+
+ view = new View({
+ collection: collection
+ });
+ });
+
+ describe('when the view is instantiated ', function() {
+
+ it('creates the correct element', function () {
+ // Element has to be uppercase
+ expect(view.el.nodeName).toEqual('DIV');
+ });
+
+ it('sets the correct class', function () {
+ view.render();
+ expect(view.$el).toHaveClass('learning-resources');
+ });
+
+ });
+
+ describe('when collection events happen', function(){
+
+ beforeEach(function () {
+ spyOn(view, 'render').and.callThrough();
+ });
+
+ it('renders when something is added to the collection', function(){
+ collection.trigger('add');
+ expect(view.render).toHaveBeenCalled();
+ });
+
+ it('renders when the collection is reset', function(){
+ collection.trigger('reset');
+ expect(view.render).toHaveBeenCalled();
+ });
+
+ it('renders when the collection is sorted', function(){
+ collection.trigger('sort');
+ expect(view.render).toHaveBeenCalled();
+ });
+
+ });
+
+ describe('when the view is rendered', function(){
+
+ it('returns the view object', function(){
+ expect(view.render()).toEqual(view);
+ });
+ it('produces the correct HTML', function(){
+ view.render();
+ expect(view.$el[0]).toHaveText('Meow');
+ });
+
+ });
+
+ // describe('when the user clicks on the Sort By Id button ', function(){
+
+ // beforeEach(function(){
+ // view.render();
+ // });
+
+ // it('triggers the sortById event on the collection', function(){
+ // var spy = jasmine.createSpy('sortById');
+ // collection.on('sortById', spy);
+
+ // view.$('.sortById').trigger('click');
+
+ // expect(spy).toHaveBeenCalled();
+
+ // });
+
+ // it('renders the view', function(){
+ // spyOn(view, 'render');
+
+ // view.$('.sortById').trigger('click');
+
+ // expect(view.render).toHaveBeenCalled();
+ // });
+
+ // });
+
+ describe('when the user clicks on the Title header ', function(){
+
+ beforeEach(function(){
+ view.render();
+ });
+
+ it('triggers the sortByTitle event on the collection', function(){
+ var spy = jasmine.createSpy('sortByTitle');
+ collection.on('sortByTitle', spy);
+
+ view.$('.sortByTitle').trigger('click');
+
+ expect(spy).toHaveBeenCalled();
+
+ });
+
+ it('renders the view', function(){
+ spyOn(view, 'render');
+
+ view.$('.sortByTitle').trigger('click');
+
+ expect(view.render).toHaveBeenCalled();
+ });
+
+ });
+
+ describe('when the user clicks on the Type header ', function(){
+
+ beforeEach(function(){
+ view.render();
+ });
+
+ it('triggers the sortByTitle event on the collection', function(){
+ var spy = jasmine.createSpy('sortByResourceType');
+ collection.on('sortByResourceType', spy);
+
+ view.$('.sortByResourceType').trigger('click');
+
+ expect(spy).toHaveBeenCalled();
+
+ });
+
+ it('renders the view', function(){
+ spyOn(view, 'render');
+
+ view.$('.sortByResourceType').trigger('click');
+
+ expect(view.render).toHaveBeenCalled();
+ });
+
+ });
+
+ describe('when the user clicks on the Authors header ', function(){
+
+ beforeEach(function(){
+ view.render();
+ });
+
+ it('triggers the sortByTitle event on the collection', function(){
+ var spy = jasmine.createSpy('sortByAuthors');
+ collection.on('sortByAuthors', spy);
+
+ view.$('.sortByAuthors').trigger('click');
+
+ expect(spy).toHaveBeenCalled();
+
+ });
+
+ it('renders the view', function(){
+ spyOn(view, 'render');
+
+ view.$('.sortByAuthors').trigger('click');
+
+ expect(view.render).toHaveBeenCalled();
+ });
+
+ });
+
+ describe('when the user clicks on the Description header ', function(){
+
+ beforeEach(function(){
+ view.render();
+ });
+
+ it('triggers the sortByDescription event on the collection', function(){
+ var spy = jasmine.createSpy('sortByDescription');
+ collection.on('sortByDescription', spy);
+
+ view.$('.sortByDescription').trigger('click');
+
+ expect(spy).toHaveBeenCalled();
+
+ });
+
+ it('renders the view', function(){
+ spyOn(view, 'render');
+
+ view.$('.sortByDescription').trigger('click');
+
+ expect(view.render).toHaveBeenCalled();
+ });
+
+ });
+
+});
+
diff --git a/client/spa/js/main.js b/client/spa/js/main.js
index b1b493f..bcebed4 100644
--- a/client/spa/js/main.js
+++ b/client/spa/js/main.js
@@ -5,12 +5,15 @@ window.Backbone = require('./vendor').Backbone;
// Include your code
var Instructor = require('./instructor/instructor.controller');
var Resource = require('./learning-resource/learning-resource.controller');
+var Resources = require('./learning-resource/learning-resources.controller');
+
// Initialize it
window.instructor = new Instructor({router:true, container: 'body'});
window.resource = new Resource({router:true, container: 'body'});
+window.resources = new Resources({router:true, container: 'body'});
// Additional modules go here
-
+/* global window require */
// This should be the last line
window.Backbone.history.start();
diff --git a/common/models/contact.js b/common/models/contact.js
new file mode 100644
index 0000000..d564eba
--- /dev/null
+++ b/common/models/contact.js
@@ -0,0 +1,3 @@
+module.exports = function(Contact) {
+ //Contact.validatesInclusionOf('enumTest', {in: ['contractor', 'employee']});
+};
diff --git a/common/models/contact.json b/common/models/contact.json
new file mode 100644
index 0000000..75ed28b
--- /dev/null
+++ b/common/models/contact.json
@@ -0,0 +1,15 @@
+{
+ "name": "contact",
+ "base": "PersistedModel",
+ "idInjection": true,
+ "properties": {
+ "name": {
+ "type": "string",
+ "required": true
+ }
+ },
+ "validations": [],
+ "relations": {},
+ "acls": [],
+ "methods": []
+}
diff --git a/server/boot/spa.js b/server/boot/spa.js
index c795bbb..1933dba 100644
--- a/server/boot/spa.js
+++ b/server/boot/spa.js
@@ -32,6 +32,3 @@ module.exports = function mountApps(server) {
server.use('/spa', router);
};
-
-
-