Commit a24e3cb0 by Andy Armstrong

Implement model refreshing for Teams tab

TNL-2976
parent 04d3cb98
define(['sinon', 'underscore'], function(sinon, _) { define(['sinon', 'underscore', 'URI'], function(sinon, _, URI) {
var fakeServer, fakeRequests, expectRequest, expectJsonRequest, expectPostRequest, 'use strict';
var fakeServer, fakeRequests, expectRequest, expectJsonRequest, expectPostRequest, expectJsonRequestURL,
respondWithJson, respondWithError, respondWithTextError, respondWithNoContent; respondWithJson, respondWithError, respondWithTextError, respondWithNoContent;
/* These utility methods are used by Jasmine tests to create a mock server or /* These utility methods are used by Jasmine tests to create a mock server or
...@@ -69,6 +71,24 @@ define(['sinon', 'underscore'], function(sinon, _) { ...@@ -69,6 +71,24 @@ define(['sinon', 'underscore'], function(sinon, _) {
}; };
/** /**
* Expect that a JSON request be made with the given URL and parameters.
* @param requests The collected requests
* @param expectedUrl The expected URL excluding the parameters
* @param expectedParameters An object representing the URL parameters
* @param requestIndex An optional index for the request (by default, the last request is used)
*/
expectJsonRequestURL = function(requests, expectedUrl, expectedParameters, requestIndex) {
var request, parameters;
if (_.isUndefined(requestIndex)) {
requestIndex = requests.length - 1;
}
request = requests[requestIndex];
parameters = new URI(request.url).query(true);
delete parameters._; // Ignore the cache-busting argument
expect(parameters).toEqual(expectedParameters);
};
/**
* Intended for use with POST requests using application/x-www-form-urlencoded. * Intended for use with POST requests using application/x-www-form-urlencoded.
*/ */
expectPostRequest = function(requests, url, body, requestIndex) { expectPostRequest = function(requests, url, body, requestIndex) {
...@@ -136,6 +156,7 @@ define(['sinon', 'underscore'], function(sinon, _) { ...@@ -136,6 +156,7 @@ define(['sinon', 'underscore'], function(sinon, _) {
'requests': fakeRequests, 'requests': fakeRequests,
'expectRequest': expectRequest, 'expectRequest': expectRequest,
'expectJsonRequest': expectJsonRequest, 'expectJsonRequest': expectJsonRequest,
'expectJsonRequestURL': expectJsonRequestURL,
'expectPostRequest': expectPostRequest, 'expectPostRequest': expectPostRequest,
'respondWithJson': respondWithJson, 'respondWithJson': respondWithJson,
'respondWithError': respondWithError, 'respondWithError': respondWithError,
......
...@@ -248,7 +248,7 @@ class MyTeamsTest(TeamsTabBase): ...@@ -248,7 +248,7 @@ class MyTeamsTest(TeamsTabBase):
self.assertEqual(len(self.my_teams_page.team_cards), 0, msg='Expected to see no team cards') self.assertEqual(len(self.my_teams_page.team_cards), 0, msg='Expected to see no team cards')
self.assertEqual( self.assertEqual(
self.my_teams_page.q(css='.page-content-main').text, self.my_teams_page.q(css='.page-content-main').text,
[u'You are not currently a member of any teams.'] [u'You are not currently a member of any team.']
) )
def test_member_of_a_team(self): def test_member_of_a_team(self):
...@@ -530,7 +530,12 @@ class BrowseTeamsWithinTopicTest(TeamsTabBase): ...@@ -530,7 +530,12 @@ class BrowseTeamsWithinTopicTest(TeamsTabBase):
self.browse_teams_page.go_to_page(1) self.browse_teams_page.go_to_page(1)
self.verify_on_page(1, teams, 'Showing 1-10 out of 20 total', True) self.verify_on_page(1, teams, 'Showing 1-10 out of 20 total', True)
def test_teams_membership(self): @ddt.data(
['Moderator', False]
['Community TA', False],
['Administrator', False]
)
def test_create_team(self, role, should_join_team):
""" """
Scenario: Team cards correctly reflect membership of the team. Scenario: Team cards correctly reflect membership of the team.
Given I am enrolled in a course with a team configuration and a topic Given I am enrolled in a course with a team configuration and a topic
...@@ -540,6 +545,7 @@ class BrowseTeamsWithinTopicTest(TeamsTabBase): ...@@ -540,6 +545,7 @@ class BrowseTeamsWithinTopicTest(TeamsTabBase):
Then I should see the correct page header Then I should see the correct page header
And I should see the team for that topic And I should see the team for that topic
And I should see that the team card shows my membership And I should see that the team card shows my membership
When I visit the My Teams page
""" """
teams = self.create_teams(self.topic, 1) teams = self.create_teams(self.topic, 1)
self.browse_teams_page.visit() self.browse_teams_page.visit()
...@@ -548,11 +554,10 @@ class BrowseTeamsWithinTopicTest(TeamsTabBase): ...@@ -548,11 +554,10 @@ class BrowseTeamsWithinTopicTest(TeamsTabBase):
self.create_membership(self.user_info['username'], teams[0]['id']) self.create_membership(self.user_info['username'], teams[0]['id'])
self.browser.refresh() self.browser.refresh()
self.browse_teams_page.wait_for_ajax() self.browse_teams_page.wait_for_ajax()
## TODO: fix this! self.assertEqual(
# self.assertEqual( self.browse_teams_page.team_cards[0].find_element_by_css_selector('.member-count').text,
# self.browse_teams_page.team_cards[0].find_element_by_css_selector('.member-count').text, '1 / 10 Members'
# '1 / 10 Members' )
# )
def test_navigation_links(self): def test_navigation_links(self):
""" """
......
;(function (define) {
'use strict';
define(['common/js/components/collections/paging_collection'],
function(PagingCollection) {
var BaseCollection = PagingCollection.extend({
initialize: function(options) {
PagingCollection.prototype.initialize.call(this);
this.course_id = options.course_id;
this.perPage = options.per_page;
this.teamEvents = options.teamEvents;
this.teamEvents.bind('teams:update', this.onUpdate, this);
this.isStale = false;
},
onUpdate: function(event) {
this.isStale = true;
},
/**
* Refreshes the collection if it has been marked as stale.
* @param force If true, it will always refresh.
* @returns {promise} Returns a promise representing the refresh
*/
refresh: function(force) {
var self = this,
deferred = $.Deferred();
if (force || this.isStale) {
this.fetch()
.done(function() {
self.isStale = false;
deferred.resolve();
});
} else {
deferred.resolve();
}
return deferred.promise();
}
});
return BaseCollection;
});
}).call(this, define || RequireJS.define);
;(function (define) { ;(function (define) {
'use strict'; 'use strict';
define(['common/js/components/collections/paging_collection', 'teams/js/models/team', 'gettext'], define(['teams/js/collections/base', 'teams/js/models/team', 'gettext'],
function(PagingCollection, TeamModel, gettext) { function(BaseCollection, TeamModel, gettext) {
var TeamCollection = PagingCollection.extend({ var TeamCollection = BaseCollection.extend({
initialize: function(teams, options) { initialize: function(teams, options) {
PagingCollection.prototype.initialize.call(this); var self = this;
BaseCollection.prototype.initialize.call(this, options);
this.course_id = options.course_id; this.server_api = _.extend(
this.server_api['topic_id'] = this.topic_id = options.topic_id; {
this.server_api['expand'] = 'user'; topic_id: this.topic_id = options.topic_id,
this.perPage = options.per_page; expand: 'user',
this.server_api['course_id'] = function () { return encodeURIComponent(this.course_id); }; course_id: function () { return encodeURIComponent(self.course_id); },
this.server_api['order_by'] = function () { return 'name'; }; // TODO surface sort order in UI order_by: function () { return 'name'; } // TODO surface sort order in UI
delete this.server_api['sort_order']; // Sort order is not specified for the Team API },
BaseCollection.prototype.server_api
);
delete this.server_api.sort_order; // Sort order is not specified for the Team API
this.registerSortableField('name', gettext('name')); this.registerSortableField('name', gettext('name'));
this.registerSortableField('open_slots', gettext('open_slots')); this.registerSortableField('open_slots', gettext('open_slots'));
......
;(function (define) { ;(function (define) {
'use strict'; 'use strict';
define(['common/js/components/collections/paging_collection', 'teams/js/models/team_membership'], define(['teams/js/collections/base', 'teams/js/models/team_membership'],
function(PagingCollection, TeamMembershipModel) { function(BaseCollection, TeamMembershipModel) {
var TeamMembershipCollection = PagingCollection.extend({ var TeamMembershipCollection = BaseCollection.extend({
initialize: function(team_memberships, options) { initialize: function(team_memberships, options) {
PagingCollection.prototype.initialize.call(this); var self = this;
BaseCollection.prototype.initialize.call(this, options);
this.course_id = options.course_id; this.perPage = options.per_page || 10;
this.username = options.username; this.username = options.username;
this.privileged = options.privileged; this.privileged = options.privileged;
this.perPage = options.per_page || 10;
this.server_api['expand'] = 'team'; this.server_api = _.extend(
this.server_api['course_id'] = function () { return encodeURIComponent(options.course_id); }; {
this.server_api['username'] = this.username; expand: 'team',
username: this.username,
course_id: function () { return encodeURIComponent(self.course_id); }
},
BaseCollection.prototype.server_api
);
delete this.server_api['sort_order']; // Sort order is not specified for the TeamMembership API delete this.server_api['sort_order']; // Sort order is not specified for the TeamMembership API
delete this.server_api['order_by']; // Order by is not specified for the TeamMembership API delete this.server_api['order_by']; // Order by is not specified for the TeamMembership API
}, },
......
;(function (define) { ;(function (define) {
'use strict'; 'use strict';
define(['common/js/components/collections/paging_collection', 'teams/js/models/topic', 'gettext'], define(['teams/js/collections/base', 'teams/js/models/topic', 'gettext'],
function(PagingCollection, TopicModel, gettext) { function(BaseCollection, TopicModel, gettext) {
var TopicCollection = PagingCollection.extend({ var TopicCollection = BaseCollection.extend({
initialize: function(topics, options) { initialize: function(topics, options) {
PagingCollection.prototype.initialize.call(this); var self = this;
BaseCollection.prototype.initialize.call(this, options);
this.course_id = options.course_id;
this.perPage = topics.results.length; this.perPage = topics.results.length;
this.server_api['course_id'] = function () { return encodeURIComponent(this.course_id); };
this.server_api['order_by'] = function () { return this.sortField; }; this.server_api = _.extend(
{
course_id: function () { return encodeURIComponent(self.course_id); },
order_by: function () { return this.sortField; }
},
BaseCollection.prototype.server_api
);
delete this.server_api['sort_order']; // Sort order is not specified for the Team API delete this.server_api['sort_order']; // Sort order is not specified for the Team API
this.registerSortableField('name', gettext('name')); this.registerSortableField('name', gettext('name'));
...@@ -17,6 +24,10 @@ ...@@ -17,6 +24,10 @@
this.registerSortableField('team_count', gettext('team count')); this.registerSortableField('team_count', gettext('team count'));
}, },
onUpdate: function(event) {
this.isStale = event.action === 'create';
},
model: TopicModel model: TopicModel
}); });
return TopicCollection; return TopicCollection;
......
define(['URI', 'underscore', 'common/js/spec_helpers/ajax_helpers', 'teams/js/collections/topic'], define(['backbone', 'URI', 'underscore', 'common/js/spec_helpers/ajax_helpers', 'teams/js/collections/topic'],
function (URI, _, AjaxHelpers, TopicCollection) { function (Backbone, URI, _, AjaxHelpers, TopicCollection) {
'use strict'; 'use strict';
describe('TopicCollection', function () { describe('TopicCollection', function () {
var topicCollection; var topicCollection;
...@@ -39,7 +39,11 @@ define(['URI', 'underscore', 'common/js/spec_helpers/ajax_helpers', 'teams/js/co ...@@ -39,7 +39,11 @@ define(['URI', 'underscore', 'common/js/spec_helpers/ajax_helpers', 'teams/js/co
], ],
"sort_order": "name" "sort_order": "name"
}, },
{course_id: 'my/course/id', parse: true}); {
teamEvents:_.clone(Backbone.Events),
course_id: 'my/course/id',
parse: true
});
}); });
var testRequestParam = function (self, param, value) { var testRequestParam = function (self, param, value) {
......
...@@ -3,13 +3,13 @@ define([ ...@@ -3,13 +3,13 @@ define([
'underscore', 'underscore',
'backbone', 'backbone',
'common/js/spec_helpers/ajax_helpers', 'common/js/spec_helpers/ajax_helpers',
'teams/js/views/edit_team' 'teams/js/views/edit_team',
], function ($, _, Backbone, AjaxHelpers, TeamEditView) { 'teams/js/spec_helpers/team_spec_helpers'
], function ($, _, Backbone, AjaxHelpers, TeamEditView, TeamSpecHelpers) {
'use strict'; 'use strict';
describe('EditTeam', function () { describe('EditTeam', function () {
var teamEditView, var teamsUrl = '/api/team/v0/teams/',
teamsUrl = '/api/team/v0/teams/',
teamsData = { teamsData = {
id: null, id: null,
name: "TeamName", name: "TeamName",
...@@ -22,7 +22,7 @@ define([ ...@@ -22,7 +22,7 @@ define([
language: "a", language: "a",
membership: [] membership: []
}, },
verifyValidation = function (requests, fieldsData) { verifyValidation = function (requests, teamEditView, fieldsData) {
_.each(fieldsData, function (fieldData) { _.each(fieldsData, function (fieldData) {
teamEditView.$(fieldData[0]).val(fieldData[1]); teamEditView.$(fieldData[0]).val(fieldData[1]);
}); });
...@@ -45,24 +45,11 @@ define([ ...@@ -45,24 +45,11 @@ define([
}); });
expect(requests.length).toBe(0); expect(requests.length).toBe(0);
},
expectContent = function (selector, text) {
expect(teamEditView.$(selector).text().trim()).toBe(text);
},
verifyDropdownData = function (selector, expectedItems) {
var options = teamEditView.$(selector)[0].options;
var renderedItems = $.map(options, function( elem ) {
return [[elem.value, elem.text]];
});
for (var i = 0; i < expectedItems.length; i++) {
expect(renderedItems).toContain(expectedItems[i]);
}
}; };
beforeEach(function () { var createTeamEditView = function() {
setFixtures('<div class="teams-content"></div>'); return new TeamEditView({
spyOn(Backbone.history, 'navigate'); teamEvents: TeamSpecHelpers.teamEvents,
teamEditView = new TeamEditView({
el: $('.teams-content'), el: $('.teams-content'),
teamParams: { teamParams: {
teamsUrl: teamsUrl, teamsUrl: teamsUrl,
...@@ -73,6 +60,11 @@ define([ ...@@ -73,6 +60,11 @@ define([
countries: [['c', 'ccc'], ['d', 'ddd']] countries: [['c', 'ccc'], ['d', 'ddd']]
} }
}).render(); }).render();
};
beforeEach(function () {
setFixtures('<div class="teams-content"></div>');
spyOn(Backbone.history, 'navigate');
}); });
it('can render itself correctly', function () { it('can render itself correctly', function () {
...@@ -82,7 +74,8 @@ define([ ...@@ -82,7 +74,8 @@ define([
'.u-field-optional_description', '.u-field-optional_description',
'.u-field-language', '.u-field-language',
'.u-field-country' '.u-field-country'
]; ],
teamEditView = createTeamEditView();
_.each(fieldClasses, function (fieldClass) { _.each(fieldClasses, function (fieldClass) {
expect(teamEditView.$el.find(fieldClass).length).toBe(1); expect(teamEditView.$el.find(fieldClass).length).toBe(1);
...@@ -93,7 +86,8 @@ define([ ...@@ -93,7 +86,8 @@ define([
}); });
it('can create a team', function () { it('can create a team', function () {
var requests = AjaxHelpers.requests(this); var requests = AjaxHelpers.requests(this),
teamEditView = createTeamEditView();
teamEditView.$('.u-field-name input').val(teamsData.name); teamEditView.$('.u-field-name input').val(teamsData.name);
teamEditView.$('.u-field-textarea textarea').val(teamsData.description); teamEditView.$('.u-field-textarea textarea').val(teamsData.description);
...@@ -109,46 +103,49 @@ define([ ...@@ -109,46 +103,49 @@ define([
}); });
it('shows validation error message when field is empty', function () { it('shows validation error message when field is empty', function () {
var requests = AjaxHelpers.requests(this); var requests = AjaxHelpers.requests(this),
verifyValidation(requests, [ teamEditView = createTeamEditView();
verifyValidation(requests, teamEditView, [
['.u-field-name input', 'Name', 'success'], ['.u-field-name input', 'Name', 'success'],
['.u-field-textarea textarea', '', 'error'] ['.u-field-textarea textarea', '', 'error']
]); ]);
teamEditView.render(); teamEditView.render();
verifyValidation(requests, [ verifyValidation(requests, teamEditView, [
['.u-field-name input', '', 'error'], ['.u-field-name input', '', 'error'],
['.u-field-textarea textarea', 'description', 'success'] ['.u-field-textarea textarea', 'description', 'success']
]); ]);
teamEditView.render(); teamEditView.render();
verifyValidation(requests, [ verifyValidation(requests, teamEditView, [
['.u-field-name input', '', 'error'], ['.u-field-name input', '', 'error'],
['.u-field-textarea textarea', '', 'error'] ['.u-field-textarea textarea', '', 'error']
]); ]);
}); });
it('shows validation error message when field value length exceeded the limit', function () { it('shows validation error message when field value length exceeded the limit', function () {
var requests = AjaxHelpers.requests(this); var requests = AjaxHelpers.requests(this),
var teamName = new Array(500 + 1).join( '$' ); teamEditView = createTeamEditView(),
var teamDescription = new Array(500 + 1).join( '$' ); teamName = new Array(500 + 1).join( '$'),
teamDescription = new Array(500 + 1).join( '$' );
verifyValidation(requests, [ verifyValidation(requests, teamEditView, [
['.u-field-name input', teamName, 'error'], ['.u-field-name input', teamName, 'error'],
['.u-field-textarea textarea', 'description', 'success'] ['.u-field-textarea textarea', 'description', 'success']
]); ]);
teamEditView.render(); teamEditView.render();
verifyValidation(requests, [ verifyValidation(requests, teamEditView, [
['.u-field-name input', 'name', 'success'], ['.u-field-name input', 'name', 'success'],
['.u-field-textarea textarea', teamDescription, 'error'] ['.u-field-textarea textarea', teamDescription, 'error']
]); ]);
teamEditView.render(); teamEditView.render();
verifyValidation(requests, [ verifyValidation(requests, teamEditView, [
['.u-field-name input', teamName, 'error'], ['.u-field-name input', teamName, 'error'],
['.u-field-textarea textarea', teamDescription, 'error'] ['.u-field-textarea textarea', teamDescription, 'error']
]); ]);
}); });
it("shows an error message for HTTP 500", function () { it("shows an error message for HTTP 500", function () {
var requests = AjaxHelpers.requests(this); var teamEditView = createTeamEditView(),
requests = AjaxHelpers.requests(this);
teamEditView.$('.u-field-name input').val(teamsData.name); teamEditView.$('.u-field-name input').val(teamsData.name);
teamEditView.$('.u-field-textarea textarea').val(teamsData.description); teamEditView.$('.u-field-textarea textarea').val(teamsData.description);
...@@ -163,6 +160,7 @@ define([ ...@@ -163,6 +160,7 @@ define([
}); });
it("changes route on cancel click", function () { it("changes route on cancel click", function () {
var teamEditView = createTeamEditView();
teamEditView.$('.create-team.form-actions .action-cancel').click(); teamEditView.$('.create-team.form-actions .action-cancel').click();
expect(Backbone.history.navigate.calls[0].args).toContain('topics/awesomeness'); expect(Backbone.history.navigate.calls[0].args).toContain('topics/awesomeness');
}); });
......
...@@ -3,8 +3,9 @@ define([ ...@@ -3,8 +3,9 @@ define([
'teams/js/collections/team', 'teams/js/collections/team',
'teams/js/collections/team_membership', 'teams/js/collections/team_membership',
'teams/js/views/my_teams', 'teams/js/views/my_teams',
'teams/js/spec_helpers/team_spec_helpers' 'teams/js/spec_helpers/team_spec_helpers',
], function (Backbone, TeamCollection, TeamMembershipCollection, MyTeamsView, TeamSpecHelpers) { 'common/js/spec_helpers/ajax_helpers'
], function (Backbone, TeamCollection, TeamMembershipCollection, MyTeamsView, TeamSpecHelpers, AjaxHelpers) {
'use strict'; 'use strict';
describe('My Teams View', function () { describe('My Teams View', function () {
beforeEach(function () { beforeEach(function () {
...@@ -28,26 +29,51 @@ define([ ...@@ -28,26 +29,51 @@ define([
it('can render itself', function () { it('can render itself', function () {
var teamMembershipsData = TeamSpecHelpers.createMockTeamMembershipsData(1, 5), var teamMembershipsData = TeamSpecHelpers.createMockTeamMembershipsData(1, 5),
teamMemberships = TeamSpecHelpers.createMockTeamMemberships(teamMembershipsData), teamMemberships = TeamSpecHelpers.createMockTeamMemberships(teamMembershipsData),
teamsView = createMyTeamsView({ myTeamsView = createMyTeamsView({
teams: teamMemberships, teams: teamMemberships,
teamMemberships: teamMemberships teamMemberships: teamMemberships
}); });
TeamSpecHelpers.verifyCards(teamsView, teamMembershipsData); TeamSpecHelpers.verifyCards(myTeamsView, teamMembershipsData);
// Verify that there is no header or footer // Verify that there is no header or footer
expect(teamsView.$('.teams-paging-header').text().trim()).toBe(''); expect(myTeamsView.$('.teams-paging-header').text().trim()).toBe('');
expect(teamsView.$('.teams-paging-footer').text().trim()).toBe(''); expect(myTeamsView.$('.teams-paging-footer').text().trim()).toBe('');
}); });
it('shows a message when the user is not a member of any teams', function () { it('shows a message when the user is not a member of any teams', function () {
var teamMemberships = TeamSpecHelpers.createMockTeamMemberships([]), var teamMemberships = TeamSpecHelpers.createMockTeamMemberships([]),
teamsView = createMyTeamsView({ myTeamsView = createMyTeamsView({
teams: teamMemberships, teams: teamMemberships,
teamMemberships: teamMemberships teamMemberships: teamMemberships
}); });
TeamSpecHelpers.verifyCards(teamsView, []); TeamSpecHelpers.verifyCards(myTeamsView, []);
expect(teamsView.$el.text().trim()).toBe('You are not currently a member of any teams.'); expect(myTeamsView.$el.text().trim()).toBe('You are not currently a member of any team.');
});
it('refreshes a stale membership collection when rendering', function() {
var requests = AjaxHelpers.requests(this),
teamMemberships = TeamSpecHelpers.createMockTeamMemberships([]),
myTeamsView = createMyTeamsView({
teams: teamMemberships,
teamMemberships: teamMemberships
});
TeamSpecHelpers.verifyCards(myTeamsView, []);
expect(myTeamsView.$el.text().trim()).toBe('You are not currently a member of any team.');
teamMemberships.teamEvents.trigger('teams:update', { action: 'create' });
myTeamsView.render();
AjaxHelpers.expectJsonRequestURL(
requests,
'foo',
{
expand : 'team',
username : 'testUser',
course_id : 'my/course/id',
page : '1',
page_size : '10'
}
);
AjaxHelpers.respondWithJson(requests, {});
}); });
}); });
}); });
define([ define([
'underscore', 'common/js/spec_helpers/ajax_helpers', 'teams/js/models/team', 'backbone', 'underscore', 'common/js/spec_helpers/ajax_helpers', 'teams/js/models/team',
'teams/js/spec_helpers/team_spec_helpers', 'teams/js/views/team_join', 'teams/js/spec_helpers/team_spec_helpers'
'teams/js/views/team_join' ], function (Backbone, _, AjaxHelpers, TeamModel, TeamJoinView, TeamSpecHelpers) {
], function (_, AjaxHelpers, TeamModel, TeamSpecHelpers, TeamJoinView) {
'use strict'; 'use strict';
describe('TeamJoinView', function () { describe('TeamJoinView', function () {
var createTeamsUrl, var createTeamsUrl,
...@@ -63,6 +62,7 @@ define([ ...@@ -63,6 +62,7 @@ define([
var teamJoinView = new TeamJoinView( var teamJoinView = new TeamJoinView(
{ {
courseID: TeamSpecHelpers.testCourseID, courseID: TeamSpecHelpers.testCourseID,
teamEvents: TeamSpecHelpers.teamEvents,
model: model, model: model,
teamsUrl: createTeamsUrl(teamId), teamsUrl: createTeamsUrl(teamId),
maxTeamSize: maxTeamSize, maxTeamSize: maxTeamSize,
......
...@@ -5,7 +5,9 @@ define([ ...@@ -5,7 +5,9 @@ define([
], function (_, AjaxHelpers, TeamModel, TeamProfileView, TeamSpecHelpers, DiscussionSpecHelper) { ], function (_, AjaxHelpers, TeamModel, TeamProfileView, TeamSpecHelpers, DiscussionSpecHelper) {
'use strict'; 'use strict';
describe('TeamProfileView', function () { describe('TeamProfileView', function () {
var profileView, createTeamProfileView, createTeamModelData, teamModel, var profileView, createTeamProfileView, createTeamModelData, clickLeaveTeam,
teamModel,
leaveTeamLinkSelector = '.leave-team-link',
DEFAULT_MEMBERSHIP = [ DEFAULT_MEMBERSHIP = [
{ {
'user': { 'user': {
...@@ -38,6 +40,7 @@ define([ ...@@ -38,6 +40,7 @@ define([
createTeamProfileView = function(requests, options) { createTeamProfileView = function(requests, options) {
teamModel = new TeamModel(createTeamModelData(options), { parse: true }); teamModel = new TeamModel(createTeamModelData(options), { parse: true });
profileView = new TeamProfileView({ profileView = new TeamProfileView({
teamEvents: TeamSpecHelpers.teamEvents,
courseID: TeamSpecHelpers.testCourseID, courseID: TeamSpecHelpers.testCourseID,
model: teamModel, model: teamModel,
maxTeamSize: options.maxTeamSize || 3, maxTeamSize: options.maxTeamSize || 3,
...@@ -71,6 +74,21 @@ define([ ...@@ -71,6 +74,21 @@ define([
return profileView; return profileView;
}; };
clickLeaveTeam = function(requests, view) {
expect(view.$(leaveTeamLinkSelector).length).toBe(1);
// click on Leave Team link under Team Details
view.$(leaveTeamLinkSelector).click();
// expect a request to DELETE the team membership
AjaxHelpers.expectJsonRequest(requests, 'DELETE', 'api/team/v0/team_membership/test-team,bilbo');
AjaxHelpers.respondWithNoContent(requests);
// expect a request to refetch the user's team memberships
AjaxHelpers.expectJsonRequest(requests, 'GET', '/api/team/v0/teams/test-team');
AjaxHelpers.respondWithJson(requests, createTeamModelData({country: 'US', language: 'en'}));
};
describe('DiscussionsView', function() { describe('DiscussionsView', function() {
it('can render itself', function () { it('can render itself', function () {
var requests = AjaxHelpers.requests(this), var requests = AjaxHelpers.requests(this),
...@@ -84,6 +102,7 @@ define([ ...@@ -84,6 +102,7 @@ define([
expect(view.$('.new-post-btn').length).toEqual(0); expect(view.$('.new-post-btn').length).toEqual(0);
teamModel.set('membership', DEFAULT_MEMBERSHIP); // This should re-render the view. teamModel.set('membership', DEFAULT_MEMBERSHIP); // This should re-render the view.
view.render();
expect(view.$('.new-post-btn').length).toEqual(1); expect(view.$('.new-post-btn').length).toEqual(1);
}); });
...@@ -92,7 +111,7 @@ define([ ...@@ -92,7 +111,7 @@ define([
view = createTeamProfileView(requests, {membership: DEFAULT_MEMBERSHIP}); view = createTeamProfileView(requests, {membership: DEFAULT_MEMBERSHIP});
expect(view.$('.new-post-btn').length).toEqual(1); expect(view.$('.new-post-btn').length).toEqual(1);
teamModel.set('membership', []); clickLeaveTeam(requests, view);
expect(view.$('.new-post-btn').length).toEqual(0); expect(view.$('.new-post-btn').length).toEqual(0);
}); });
}); });
...@@ -119,7 +138,10 @@ define([ ...@@ -119,7 +138,10 @@ define([
assertTeamDetails(view, 0, false); assertTeamDetails(view, 0, false);
expect(view.$('.team-user-membership-status').length).toBe(0); expect(view.$('.team-user-membership-status').length).toBe(0);
// Verify that the leave team link is not present.
expect(view.$(leaveTeamLinkSelector).length).toBe(0);
}); });
it('cannot see the country & language if empty', function() { it('cannot see the country & language if empty', function() {
var requests = AjaxHelpers.requests(this); var requests = AjaxHelpers.requests(this);
var view = createTeamProfileView(requests, {}); var view = createTeamProfileView(requests, {});
...@@ -145,29 +167,21 @@ define([ ...@@ -145,29 +167,21 @@ define([
// assert user profile page url. // assert user profile page url.
expect(view.$('.member-profile').attr('href')).toBe('/u/bilbo'); expect(view.$('.member-profile').attr('href')).toBe('/u/bilbo');
//Verify that the leave team link is present
expect(view.$(leaveTeamLinkSelector).text()).toContain('Leave Team');
}); });
it('can leave team successfully', function() { it('can leave team successfully', function() {
var requests = AjaxHelpers.requests(this); var requests = AjaxHelpers.requests(this);
var leaveTeamLinkSelector = '.leave-team-link';
var view = createTeamProfileView( var view = createTeamProfileView(
requests, { country: 'US', language: 'en', membership: DEFAULT_MEMBERSHIP} requests, {country: 'US', language: 'en', membership: DEFAULT_MEMBERSHIP}
); );
assertTeamDetails(view, 1, true); assertTeamDetails(view, 1, true);
clickLeaveTeam(requests, view);
expect(view.$(leaveTeamLinkSelector).length).toBe(1);
// click on Leave Team link under Team Details
view.$(leaveTeamLinkSelector).click();
// response to DELETE
AjaxHelpers.respondWithNoContent(requests);
// response to model fetch request
AjaxHelpers.respondWithJson(requests, createTeamModelData({country: 'US', language: 'en'}));
assertTeamDetails(view, 0, false); assertTeamDetails(view, 0, false);
}); });
it('shows correct error messages', function () { it('shows correct error messages', function () {
var requests = AjaxHelpers.requests(this); var requests = AjaxHelpers.requests(this);
......
...@@ -5,11 +5,8 @@ define(['jquery', ...@@ -5,11 +5,8 @@ define(['jquery',
function ($, _, TopicCardView, Topic) { function ($, _, TopicCardView, Topic) {
describe('topic card view', function () { describe('topic card view', function () {
var view; var createTopicCardView = function() {
return new TopicCardView({
beforeEach(function () {
spyOn(TopicCardView.prototype, 'action');
view = new TopicCardView({
model: new Topic({ model: new Topic({
'id': 'renewables', 'id': 'renewables',
'name': 'Renewable Energy', 'name': 'Renewable Energy',
...@@ -17,9 +14,14 @@ define(['jquery', ...@@ -17,9 +14,14 @@ define(['jquery',
'team_count': 34 'team_count': 34
}) })
}); });
};
beforeEach(function () {
spyOn(TopicCardView.prototype, 'action');
}); });
it('can render itself', function () { it('can render itself', function () {
var view = createTopicCardView();
expect(view.$el).toHaveClass('square-card'); expect(view.$el).toHaveClass('square-card');
expect(view.$el.find('.card-title').text()).toContain('Renewable Energy'); expect(view.$el.find('.card-title').text()).toContain('Renewable Energy');
expect(view.$el.find('.card-description').text()).toContain('changes in <ⓡⓔⓝⓔⓦⓐⓑⓛⓔ> ʎƃɹǝuǝ'); expect(view.$el.find('.card-description').text()).toContain('changes in <ⓡⓔⓝⓔⓦⓐⓑⓛⓔ> ʎƃɹǝuǝ');
...@@ -28,6 +30,7 @@ define(['jquery', ...@@ -28,6 +30,7 @@ define(['jquery',
}); });
it('navigates when action button is clicked', function () { it('navigates when action button is clicked', function () {
var view = createTopicCardView();
view.$el.find('.action').trigger('click'); view.$el.find('.action').trigger('click');
// TODO test actual navigation once implemented // TODO test actual navigation once implemented
expect(view.action).toHaveBeenCalled(); expect(view.action).toHaveBeenCalled();
......
...@@ -3,8 +3,9 @@ define([ ...@@ -3,8 +3,9 @@ define([
'teams/js/collections/team', 'teams/js/collections/team',
'teams/js/collections/team_membership', 'teams/js/collections/team_membership',
'teams/js/views/topic_teams', 'teams/js/views/topic_teams',
'teams/js/spec_helpers/team_spec_helpers' 'teams/js/spec_helpers/team_spec_helpers',
], function (Backbone, TeamCollection, TeamMembershipCollection, TopicTeamsView, TeamSpecHelpers) { 'common/js/spec_helpers/ajax_helpers'
], function (Backbone, TeamCollection, TeamMembershipCollection, TopicTeamsView, TeamSpecHelpers, AjaxHelpers) {
'use strict'; 'use strict';
describe('Topic Teams View', function () { describe('Topic Teams View', function () {
var createTopicTeamsView = function(options) { var createTopicTeamsView = function(options) {
...@@ -21,6 +22,24 @@ define([ ...@@ -21,6 +22,24 @@ define([
}).render(); }).render();
}; };
var verifyActions = function(teamsView, options) {
if (!options) {
options = {showActions: true};
}
var expectedTitle = 'Are you having trouble finding a team to join?',
expectedMessage = 'Try browsing all teams or searching team descriptions. If you ' +
'still can\'t find a team to join, create a new team in this topic.',
title = teamsView.$('.title').text().trim(),
message = teamsView.$('.copy').text().trim();
if (options.showActions) {
expect(title).toBe(expectedTitle);
expect(message).toBe(expectedMessage);
} else {
expect(title).not.toBe(expectedTitle);
expect(message).not.toBe(expectedMessage);
}
};
beforeEach(function () { beforeEach(function () {
setFixtures('<div class="teams-container"></div>'); setFixtures('<div class="teams-container"></div>');
}); });
...@@ -39,12 +58,7 @@ define([ ...@@ -39,12 +58,7 @@ define([
expect(footerEl).not.toHaveClass('hidden'); expect(footerEl).not.toHaveClass('hidden');
TeamSpecHelpers.verifyCards(teamsView, testTeamData); TeamSpecHelpers.verifyCards(teamsView, testTeamData);
verifyActions(teamsView);
expect(teamsView.$('.title').text()).toBe('Are you having trouble finding a team to join?');
expect(teamsView.$('.copy').text()).toBe(
"Try browsing all teams or searching team descriptions. If you " +
"still can't find a team to join, create a new team in this topic."
);
}); });
it('can browse all teams', function () { it('can browse all teams', function () {
...@@ -74,9 +88,7 @@ define([ ...@@ -74,9 +88,7 @@ define([
it('does not show actions for a user already in a team', function () { it('does not show actions for a user already in a team', function () {
var teamsView = createTopicTeamsView({}); var teamsView = createTopicTeamsView({});
expect(teamsView.$el.text()).not.toContain( verifyActions(teamsView, {showActions: false});
'Are you having trouble finding a team to join?'
);
}); });
it('shows actions for a privileged user already in a team', function () { it('shows actions for a privileged user already in a team', function () {
...@@ -85,9 +97,32 @@ define([ ...@@ -85,9 +97,32 @@ define([
{ privileged: true } { privileged: true }
), ),
teamsView = createTopicTeamsView({ teamMemberships: staffMembership }); teamsView = createTopicTeamsView({ teamMemberships: staffMembership });
expect(teamsView.$el.text()).toContain( verifyActions(teamsView);
'Are you having trouble finding a team to join?' });
/*
// TODO: make this ready for prime time
it('refreshes when the team membership changes', function() {
var requests = AjaxHelpers.requests(this),
teamMemberships = TeamSpecHelpers.createMockTeamMemberships([]),
teamsView = createTopicTeamsView({ teamMemberships: teamMemberships });
verifyActions(teamsView, {showActions: true});
teamMemberships.teamEvents.trigger('teams:update', { action: 'create' });
teamsView.render();
AjaxHelpers.expectJsonRequestURL(
requests,
'foo',
{
expand : 'team',
username : 'testUser',
course_id : 'my/course/id',
page : '1',
page_size : '10'
}
); );
AjaxHelpers.respondWithJson(requests, {});
verifyActions(teamsView, {showActions: false});
}); });
*/
}); });
}); });
define([ define([
'teams/js/collections/topic', 'teams/js/views/topics' 'backbone', 'teams/js/collections/topic', 'teams/js/views/topics',
], function (TopicCollection, TopicsView) { 'teams/js/spec_helpers/team_spec_helpers'
], function (Backbone, TopicCollection, TopicsView, TeamSpecHelpers) {
'use strict'; 'use strict';
describe('TopicsView', function () { describe('TopicsView', function () {
var initialTopics, topicCollection, topicsView, var initialTopics, topicCollection, createTopicsView,
generateTopics = function (startIndex, stopIndex) { generateTopics = function (startIndex, stopIndex) {
return _.map(_.range(startIndex, stopIndex + 1), function (i) { return _.map(_.range(startIndex, stopIndex + 1), function (i) {
return { return {
...@@ -15,6 +16,14 @@ define([ ...@@ -15,6 +16,14 @@ define([
}); });
}; };
createTopicsView = function() {
return new TopicsView({
teamEvents: TeamSpecHelpers.teamEvents,
el: '.topics-container',
collection: topicCollection
}).render();
};
beforeEach(function () { beforeEach(function () {
setFixtures('<div class="topics-container"></div>'); setFixtures('<div class="topics-container"></div>');
initialTopics = generateTopics(1, 5); initialTopics = generateTopics(1, 5);
...@@ -26,13 +35,17 @@ define([ ...@@ -26,13 +35,17 @@ define([
"start": 0, "start": 0,
"results": initialTopics "results": initialTopics
}, },
{course_id: 'my/course/id', parse: true} {
teamEvents: TeamSpecHelpers.teamEvents,
course_id: 'my/course/id',
parse: true
}
); );
topicsView = new TopicsView({el: '.topics-container', collection: topicCollection}).render();
}); });
it('can render the first of many pages', function () { it('can render the first of many pages', function () {
var footerEl = topicsView.$('.topics-paging-footer'), var topicsView = createTopicsView(),
footerEl = topicsView.$('.topics-paging-footer'),
topicCards = topicsView.$('.topic-card'); topicCards = topicsView.$('.topic-card');
expect(topicsView.$('.topics-paging-header').text()).toMatch('Showing 1-5 out of 6 total'); expect(topicsView.$('.topics-paging-header').text()).toMatch('Showing 1-5 out of 6 total');
_.each(initialTopics, function (topic, index) { _.each(initialTopics, function (topic, index) {
......
define([ define([
'backbone',
'underscore', 'underscore',
'teams/js/collections/team', 'teams/js/collections/team',
'teams/js/collections/team_membership', 'teams/js/collections/team_membership',
], function (_, TeamCollection, TeamMembershipCollection) { ], function (Backbone, _, TeamCollection, TeamMembershipCollection) {
'use strict'; 'use strict';
var createMockPostResponse, createMockDiscussionResponse, createAnnotatedContentInfo, createMockThreadResponse, var createMockPostResponse, createMockDiscussionResponse, createAnnotatedContentInfo, createMockThreadResponse,
testCourseID = 'course/1', testCourseID = 'course/1',
testUser = 'testUser', testUser = 'testUser',
testTeamDiscussionID = "12345", testTeamDiscussionID = "12345",
teamEvents = _.clone(Backbone.Events),
testCountries = [ testCountries = [
['', ''], ['', ''],
['US', 'United States'], ['US', 'United States'],
...@@ -47,6 +49,7 @@ define([ ...@@ -47,6 +49,7 @@ define([
results: teamData results: teamData
}, },
{ {
teamEvents: teamEvents,
course_id: 'my/course/id', course_id: 'my/course/id',
parse: true parse: true
} }
...@@ -79,6 +82,7 @@ define([ ...@@ -79,6 +82,7 @@ define([
results: teamMembershipData results: teamMembershipData
}, },
_.extend(_.extend({}, { _.extend(_.extend({}, {
teamEvents: teamEvents,
course_id: 'my/course/id', course_id: 'my/course/id',
parse: true, parse: true,
url: 'api/teams/team_memberships', url: 'api/teams/team_memberships',
...@@ -225,6 +229,7 @@ define([ ...@@ -225,6 +229,7 @@ define([
}; };
return { return {
teamEvents: teamEvents,
testCourseID: testCourseID, testCourseID: testCourseID,
testUser: testUser, testUser: testUser,
testCountries: testCountries, testCountries: testCountries,
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
}, },
initialize: function(options) { initialize: function(options) {
this.teamEvents = options.teamEvents;
this.courseID = options.teamParams.courseID; this.courseID = options.teamParams.courseID;
this.topicID = options.teamParams.topicID; this.topicID = options.teamParams.topicID;
this.collection = options.collection; this.collection = options.collection;
...@@ -113,6 +114,10 @@ ...@@ -113,6 +114,10 @@
this.teamModel.save(data, { wait: true }) this.teamModel.save(data, { wait: true })
.done(function(result) { .done(function(result) {
view.teamEvents.trigger('teams:update', {
action: 'create',
team: result
});
Backbone.history.navigate( Backbone.history.navigate(
'teams/' + view.topicID + '/' + view.teamModel.id, 'teams/' + view.topicID + '/' + view.teamModel.id,
{trigger: true} {trigger: true}
......
...@@ -5,10 +5,17 @@ ...@@ -5,10 +5,17 @@
function (Backbone, gettext, TeamsView) { function (Backbone, gettext, TeamsView) {
var MyTeamsView = TeamsView.extend({ var MyTeamsView = TeamsView.extend({
render: function() { render: function() {
TeamsView.prototype.render.call(this); var view = this;
if (this.collection.length === 0) { if (this.collection.isStale) {
this.$el.append('<p>' + gettext('You are not currently a member of any teams.') + '</p>'); this.$el.html('');
} }
this.collection.refresh()
.done(function() {
TeamsView.prototype.render.call(view);
if (view.collection.length === 0) {
view.$el.append('<p>' + gettext('You are not currently a member of any team.') + '</p>');
}
});
return this; return this;
}, },
......
;(function (define) { ;(function (define) {
'use strict'; 'use strict';
define(['backbone', define(['backbone',
'underscore', 'underscore',
'gettext', 'gettext',
'teams/js/views/team_utils', 'teams/js/views/team_utils',
...@@ -18,6 +18,7 @@ define(['backbone', ...@@ -18,6 +18,7 @@ define(['backbone',
}, },
initialize: function(options) { initialize: function(options) {
this.teamEvents = options.teamEvents;
this.template = _.template(teamJoinTemplate); this.template = _.template(teamJoinTemplate);
this.courseID = options.courseID; this.courseID = options.courseID;
this.maxTeamSize = options.maxTeamSize; this.maxTeamSize = options.maxTeamSize;
...@@ -28,11 +29,10 @@ define(['backbone', ...@@ -28,11 +29,10 @@ define(['backbone',
}, },
render: function() { render: function() {
var message, var view = this,
message,
showButton, showButton,
teamHasSpace; teamHasSpace;
var view = this;
this.getUserTeamInfo(this.currentUsername, view.maxTeamSize).done(function (info) { this.getUserTeamInfo(this.currentUsername, view.maxTeamSize).done(function (info) {
teamHasSpace = info.teamHasSpace; teamHasSpace = info.teamHasSpace;
...@@ -59,7 +59,13 @@ define(['backbone', ...@@ -59,7 +59,13 @@ define(['backbone',
url: view.teamMembershipsUrl, url: view.teamMembershipsUrl,
data: {'username': view.currentUsername, 'team_id': view.model.get('id')} data: {'username': view.currentUsername, 'team_id': view.model.get('id')}
}).done(function (data) { }).done(function (data) {
view.model.fetch({}); view.model.fetch()
.done(function() {
view.teamEvents.trigger('teams:update', {
action: 'join',
team: view.model
});
});
}).fail(function (data) { }).fail(function (data) {
TeamUtils.parseAndShowMessage(data, view.errorMessage); TeamUtils.parseAndShowMessage(data, view.errorMessage);
}); });
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
'click .leave-team-link': 'leaveTeam' 'click .leave-team-link': 'leaveTeam'
}, },
initialize: function (options) { initialize: function (options) {
this.listenTo(this.model, "change", this.render); this.teamEvents = options.teamEvents;
this.courseID = options.courseID; this.courseID = options.courseID;
this.maxTeamSize = options.maxTeamSize; this.maxTeamSize = options.maxTeamSize;
this.requestUsername = options.requestUsername; this.requestUsername = options.requestUsername;
...@@ -26,13 +26,13 @@ ...@@ -26,13 +26,13 @@
this.countries = TeamUtils.selectorOptionsArrayToHashWithBlank(options.countries); this.countries = TeamUtils.selectorOptionsArrayToHashWithBlank(options.countries);
this.languages = TeamUtils.selectorOptionsArrayToHashWithBlank(options.languages); this.languages = TeamUtils.selectorOptionsArrayToHashWithBlank(options.languages);
this.listenTo(this.model, "change", this.render);
}, },
render: function () { render: function () {
var memberships = this.model.get('membership'), var memberships = this.model.get('membership'),
discussionTopicID = this.model.get('discussion_topic_id'), discussionTopicID = this.model.get('discussion_topic_id'),
isMember = TeamUtils.isUserMemberOfTeam(memberships, this.requestUsername); isMember = TeamUtils.isUserMemberOfTeam(memberships, this.requestUsername);
this.$el.html(_.template(teamTemplate, { this.$el.html(_.template(teamTemplate, {
courseID: this.courseID, courseID: this.courseID,
discussionTopicID: discussionTopicID, discussionTopicID: discussionTopicID,
...@@ -76,7 +76,13 @@ ...@@ -76,7 +76,13 @@
type: 'DELETE', type: 'DELETE',
url: view.teamMembershipDetailUrl.replace('team_id', view.model.get('id')) url: view.teamMembershipDetailUrl.replace('team_id', view.model.get('id'))
}).done(function (data) { }).done(function (data) {
view.model.fetch({}); view.model.fetch()
.done(function() {
view.teamEvents.trigger('teams:update', {
action: 'leave',
team: view.model
});
});
}).fail(function (data) { }).fail(function (data) {
TeamUtils.parseAndShowMessage(data, view.errorMessage); TeamUtils.parseAndShowMessage(data, view.errorMessage);
}); });
......
...@@ -81,9 +81,13 @@ ...@@ -81,9 +81,13 @@
router.route.apply(router, route); router.route.apply(router, route);
}); });
// Create an event queue to track team changes
this.teamEvents = _.clone(Backbone.Events);
this.teamMemberships = new TeamMembershipCollection( this.teamMemberships = new TeamMembershipCollection(
this.userInfo.team_memberships_data, this.userInfo.team_memberships_data,
{ {
teamEvents: this.teamEvents,
url: this.teamMembershipsUrl, url: this.teamMembershipsUrl,
course_id: this.courseID, course_id: this.courseID,
username: this.userInfo.username, username: this.userInfo.username,
...@@ -94,6 +98,7 @@ ...@@ -94,6 +98,7 @@
this.myTeamsView = new MyTeamsView({ this.myTeamsView = new MyTeamsView({
router: this.router, router: this.router,
teamEvents: this.teamEvents,
collection: this.teamMemberships, collection: this.teamMemberships,
teamMemberships: this.teamMemberships, teamMemberships: this.teamMemberships,
maxTeamSize: this.maxTeamSize, maxTeamSize: this.maxTeamSize,
...@@ -107,12 +112,18 @@ ...@@ -107,12 +112,18 @@
this.topicsCollection = new TopicCollection( this.topicsCollection = new TopicCollection(
this.topics, this.topics,
{url: options.topicsUrl, course_id: this.courseID, parse: true} {
teamEvents: this.teamEvents,
url: options.topicsUrl,
course_id: this.courseID,
parse: true
}
).bootstrap(); ).bootstrap();
this.topicsView = new TopicsView({ this.topicsView = new TopicsView({
collection: this.topicsCollection, router: this.router,
router: this.router teamEvents: this.teamEvents,
collection: this.topicsCollection
}); });
this.mainView = this.tabbedView = new ViewWithHeader({ this.mainView = this.tabbedView = new ViewWithHeader({
...@@ -196,6 +207,7 @@ ...@@ -196,6 +207,7 @@
}) })
}), }),
main: new TeamEditView({ main: new TeamEditView({
teamEvents: self.teamEvents,
tagName: 'create-new-team', tagName: 'create-new-team',
teamParams: teamsView.main.teamParams, teamParams: teamsView.main.teamParams,
primaryButtonTitle: 'Create' primaryButtonTitle: 'Create'
...@@ -220,6 +232,7 @@ ...@@ -220,6 +232,7 @@
this.getTopic(topicID) this.getTopic(topicID)
.done(function(topic) { .done(function(topic) {
var collection = new TeamCollection([], { var collection = new TeamCollection([], {
teamEvents: self.teamEvents,
course_id: self.courseID, course_id: self.courseID,
topic_id: topicID, topic_id: topicID,
url: self.teamsUrl, url: self.teamsUrl,
...@@ -229,7 +242,7 @@ ...@@ -229,7 +242,7 @@
collection.goTo(1) collection.goTo(1)
.done(function() { .done(function() {
var teamsView = new TopicTeamsView({ var teamsView = new TopicTeamsView({
router: router, router: self.router,
topic: topic, topic: topic,
collection: collection, collection: collection,
teamMemberships: self.teamMemberships, teamMemberships: self.teamMemberships,
...@@ -278,6 +291,8 @@ ...@@ -278,6 +291,8 @@
self.getTopic(topicID).done(function(topic) { self.getTopic(topicID).done(function(topic) {
self.getTeam(teamID, true).done(function(team) { self.getTeam(teamID, true).done(function(team) {
var view = new TeamProfileView({ var view = new TeamProfileView({
teamEvents: self.teamEvents,
router: self.router,
courseID: courseID, courseID: courseID,
model: team, model: team,
maxTeamSize: self.maxTeamSize, maxTeamSize: self.maxTeamSize,
...@@ -287,16 +302,15 @@ ...@@ -287,16 +302,15 @@
languages: self.languages, languages: self.languages,
teamMembershipDetailUrl: self.teamMembershipDetailUrl teamMembershipDetailUrl: self.teamMembershipDetailUrl
}); });
var teamJoinView = new TeamJoinView( var teamJoinView = new TeamJoinView({
{ teamEvents: self.teamEvents,
courseID: courseID, courseID: courseID,
model: team, model: team,
teamsUrl: self.teamsUrl, teamsUrl: self.teamsUrl,
maxTeamSize: self.maxTeamSize, maxTeamSize: self.maxTeamSize,
currentUsername: self.userInfo.username, currentUsername: self.userInfo.username,
teamMembershipsUrl: self.teamMembershipsUrl teamMembershipsUrl: self.teamMembershipsUrl
} });
);
deferred.resolve( deferred.resolve(
self.createViewWithHeader( self.createViewWithHeader(
{ {
......
...@@ -17,9 +17,14 @@ ...@@ -17,9 +17,14 @@
}, },
render: function() { render: function() {
TeamsView.prototype.render.call(this); var self = this;
$.when(
if (this.teamMemberships.canUserCreateTeam()) { this.collection.refresh(),
this.teamMemberships.refresh()
).done(function() {
TeamsView.prototype.render.call(self);
if (self.teamMemberships.canUserCreateTeam()) {
var message = interpolate_text( var message = interpolate_text(
_.escape(gettext("Try {browse_span_start}browsing all teams{span_end} or {search_span_start}searching team descriptions{span_end}. If you still can't find a team to join, {create_span_start}create a new team in this topic{span_end}.")), _.escape(gettext("Try {browse_span_start}browsing all teams{span_end} or {search_span_start}searching team descriptions{span_end}. If you still can't find a team to join, {create_span_start}create a new team in this topic{span_end}.")),
{ {
...@@ -29,8 +34,9 @@ ...@@ -29,8 +34,9 @@
'span_end': '</a>' 'span_end': '</a>'
} }
); );
this.$el.append(_.template(teamActionsTemplate, {message: message})); self.$el.append(_.template(teamActionsTemplate, {message: message}));
} }
});
return this; return this;
}, },
......
;(function (define) { ;(function (define) {
'use strict'; 'use strict';
define([ define([
'gettext',
'teams/js/views/topic_card', 'teams/js/views/topic_card',
'common/js/components/views/paginated_view' 'common/js/components/views/paginated_view'
], function (TopicCardView, PaginatedView) { ], function (gettext, TopicCardView, PaginatedView) {
var TopicsView = PaginatedView.extend({ var TopicsView = PaginatedView.extend({
type: 'topics', type: 'topics',
...@@ -18,6 +19,16 @@ ...@@ -18,6 +19,16 @@
srInfo: this.srInfo srInfo: this.srInfo
}); });
PaginatedView.prototype.initialize.call(this); PaginatedView.prototype.initialize.call(this);
},
render: function() {
var self = this;
this.collection.refresh()
.done(function() {
self.collection.isStale = false;
PaginatedView.prototype.render.call(self);
});
return this;
} }
}); });
return TopicsView; return TopicsView;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment