Implement model refreshing for Teams tab
TNL-2976
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
define(['sinon', 'underscore'], function(sinon, _) {
|
||||
var fakeServer, fakeRequests, expectRequest, expectJsonRequest, expectPostRequest,
|
||||
define(['sinon', 'underscore', 'URI'], function(sinon, _, URI) {
|
||||
'use strict';
|
||||
|
||||
var fakeServer, fakeRequests, expectRequest, expectJsonRequest, expectPostRequest, expectJsonRequestURL,
|
||||
respondWithJson, respondWithError, respondWithTextError, respondWithNoContent;
|
||||
|
||||
/* These utility methods are used by Jasmine tests to create a mock server or
|
||||
@@ -68,6 +70,24 @@ define(['sinon', 'underscore'], function(sinon, _) {
|
||||
expect(JSON.parse(request.requestBody)).toEqual(jsonRequest);
|
||||
};
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
@@ -136,6 +156,7 @@ define(['sinon', 'underscore'], function(sinon, _) {
|
||||
'requests': fakeRequests,
|
||||
'expectRequest': expectRequest,
|
||||
'expectJsonRequest': expectJsonRequest,
|
||||
'expectJsonRequestURL': expectJsonRequestURL,
|
||||
'expectPostRequest': expectPostRequest,
|
||||
'respondWithJson': respondWithJson,
|
||||
'respondWithError': respondWithError,
|
||||
|
||||
@@ -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(
|
||||
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):
|
||||
@@ -530,7 +530,12 @@ class BrowseTeamsWithinTopicTest(TeamsTabBase):
|
||||
self.browse_teams_page.go_to_page(1)
|
||||
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.
|
||||
Given I am enrolled in a course with a team configuration and a topic
|
||||
@@ -540,6 +545,7 @@ class BrowseTeamsWithinTopicTest(TeamsTabBase):
|
||||
Then I should see the correct page header
|
||||
And I should see the team for that topic
|
||||
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)
|
||||
self.browse_teams_page.visit()
|
||||
@@ -548,11 +554,10 @@ class BrowseTeamsWithinTopicTest(TeamsTabBase):
|
||||
self.create_membership(self.user_info['username'], teams[0]['id'])
|
||||
self.browser.refresh()
|
||||
self.browse_teams_page.wait_for_ajax()
|
||||
## TODO: fix this!
|
||||
# self.assertEqual(
|
||||
# self.browse_teams_page.team_cards[0].find_element_by_css_selector('.member-count').text,
|
||||
# '1 / 10 Members'
|
||||
# )
|
||||
self.assertEqual(
|
||||
self.browse_teams_page.team_cards[0].find_element_by_css_selector('.member-count').text,
|
||||
'1 / 10 Members'
|
||||
)
|
||||
|
||||
def test_navigation_links(self):
|
||||
"""
|
||||
|
||||
43
lms/djangoapps/teams/static/teams/js/collections/base.js
Normal file
43
lms/djangoapps/teams/static/teams/js/collections/base.js
Normal file
@@ -0,0 +1,43 @@
|
||||
;(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);
|
||||
@@ -1,18 +1,22 @@
|
||||
;(function (define) {
|
||||
'use strict';
|
||||
define(['common/js/components/collections/paging_collection', 'teams/js/models/team', 'gettext'],
|
||||
function(PagingCollection, TeamModel, gettext) {
|
||||
var TeamCollection = PagingCollection.extend({
|
||||
define(['teams/js/collections/base', 'teams/js/models/team', 'gettext'],
|
||||
function(BaseCollection, TeamModel, gettext) {
|
||||
var TeamCollection = BaseCollection.extend({
|
||||
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['topic_id'] = this.topic_id = options.topic_id;
|
||||
this.server_api['expand'] = 'user';
|
||||
this.perPage = options.per_page;
|
||||
this.server_api['course_id'] = function () { return encodeURIComponent(this.course_id); };
|
||||
this.server_api['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
|
||||
this.server_api = _.extend(
|
||||
{
|
||||
topic_id: this.topic_id = options.topic_id,
|
||||
expand: 'user',
|
||||
course_id: function () { return encodeURIComponent(self.course_id); },
|
||||
order_by: function () { return 'name'; } // TODO surface sort order in UI
|
||||
},
|
||||
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('open_slots', gettext('open_slots'));
|
||||
@@ -21,5 +25,5 @@
|
||||
model: TeamModel
|
||||
});
|
||||
return TeamCollection;
|
||||
});
|
||||
});
|
||||
}).call(this, define || RequireJS.define);
|
||||
|
||||
@@ -1,18 +1,24 @@
|
||||
;(function (define) {
|
||||
'use strict';
|
||||
define(['common/js/components/collections/paging_collection', 'teams/js/models/team_membership'],
|
||||
function(PagingCollection, TeamMembershipModel) {
|
||||
var TeamMembershipCollection = PagingCollection.extend({
|
||||
define(['teams/js/collections/base', 'teams/js/models/team_membership'],
|
||||
function(BaseCollection, TeamMembershipModel) {
|
||||
var TeamMembershipCollection = BaseCollection.extend({
|
||||
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.privileged = options.privileged;
|
||||
this.perPage = options.per_page || 10;
|
||||
this.server_api['expand'] = 'team';
|
||||
this.server_api['course_id'] = function () { return encodeURIComponent(options.course_id); };
|
||||
this.server_api['username'] = this.username;
|
||||
|
||||
this.server_api = _.extend(
|
||||
{
|
||||
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['order_by']; // Order by is not specified for the TeamMembership API
|
||||
},
|
||||
@@ -28,5 +34,5 @@
|
||||
}
|
||||
});
|
||||
return TeamMembershipCollection;
|
||||
});
|
||||
});
|
||||
}).call(this, define || RequireJS.define);
|
||||
|
||||
@@ -1,15 +1,22 @@
|
||||
;(function (define) {
|
||||
'use strict';
|
||||
define(['common/js/components/collections/paging_collection', 'teams/js/models/topic', 'gettext'],
|
||||
function(PagingCollection, TopicModel, gettext) {
|
||||
var TopicCollection = PagingCollection.extend({
|
||||
define(['teams/js/collections/base', 'teams/js/models/topic', 'gettext'],
|
||||
function(BaseCollection, TopicModel, gettext) {
|
||||
var TopicCollection = BaseCollection.extend({
|
||||
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.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
|
||||
|
||||
this.registerSortableField('name', gettext('name'));
|
||||
@@ -17,8 +24,12 @@
|
||||
this.registerSortableField('team_count', gettext('team count'));
|
||||
},
|
||||
|
||||
onUpdate: function(event) {
|
||||
this.isStale = event.action === 'create';
|
||||
},
|
||||
|
||||
model: TopicModel
|
||||
});
|
||||
return TopicCollection;
|
||||
});
|
||||
});
|
||||
}).call(this, define || RequireJS.define);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
define(['URI', 'underscore', 'common/js/spec_helpers/ajax_helpers', 'teams/js/collections/topic'],
|
||||
function (URI, _, AjaxHelpers, TopicCollection) {
|
||||
define(['backbone', 'URI', 'underscore', 'common/js/spec_helpers/ajax_helpers', 'teams/js/collections/topic'],
|
||||
function (Backbone, URI, _, AjaxHelpers, TopicCollection) {
|
||||
'use strict';
|
||||
describe('TopicCollection', function () {
|
||||
var topicCollection;
|
||||
@@ -39,7 +39,11 @@ define(['URI', 'underscore', 'common/js/spec_helpers/ajax_helpers', 'teams/js/co
|
||||
],
|
||||
"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) {
|
||||
|
||||
@@ -3,13 +3,13 @@ define([
|
||||
'underscore',
|
||||
'backbone',
|
||||
'common/js/spec_helpers/ajax_helpers',
|
||||
'teams/js/views/edit_team'
|
||||
], function ($, _, Backbone, AjaxHelpers, TeamEditView) {
|
||||
'teams/js/views/edit_team',
|
||||
'teams/js/spec_helpers/team_spec_helpers'
|
||||
], function ($, _, Backbone, AjaxHelpers, TeamEditView, TeamSpecHelpers) {
|
||||
'use strict';
|
||||
|
||||
describe('EditTeam', function () {
|
||||
var teamEditView,
|
||||
teamsUrl = '/api/team/v0/teams/',
|
||||
var teamsUrl = '/api/team/v0/teams/',
|
||||
teamsData = {
|
||||
id: null,
|
||||
name: "TeamName",
|
||||
@@ -22,7 +22,7 @@ define([
|
||||
language: "a",
|
||||
membership: []
|
||||
},
|
||||
verifyValidation = function (requests, fieldsData) {
|
||||
verifyValidation = function (requests, teamEditView, fieldsData) {
|
||||
_.each(fieldsData, function (fieldData) {
|
||||
teamEditView.$(fieldData[0]).val(fieldData[1]);
|
||||
});
|
||||
@@ -45,24 +45,11 @@ define([
|
||||
});
|
||||
|
||||
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 () {
|
||||
setFixtures('<div class="teams-content"></div>');
|
||||
spyOn(Backbone.history, 'navigate');
|
||||
teamEditView = new TeamEditView({
|
||||
var createTeamEditView = function() {
|
||||
return new TeamEditView({
|
||||
teamEvents: TeamSpecHelpers.teamEvents,
|
||||
el: $('.teams-content'),
|
||||
teamParams: {
|
||||
teamsUrl: teamsUrl,
|
||||
@@ -73,6 +60,11 @@ define([
|
||||
countries: [['c', 'ccc'], ['d', 'ddd']]
|
||||
}
|
||||
}).render();
|
||||
};
|
||||
|
||||
beforeEach(function () {
|
||||
setFixtures('<div class="teams-content"></div>');
|
||||
spyOn(Backbone.history, 'navigate');
|
||||
});
|
||||
|
||||
it('can render itself correctly', function () {
|
||||
@@ -82,7 +74,8 @@ define([
|
||||
'.u-field-optional_description',
|
||||
'.u-field-language',
|
||||
'.u-field-country'
|
||||
];
|
||||
],
|
||||
teamEditView = createTeamEditView();
|
||||
|
||||
_.each(fieldClasses, function (fieldClass) {
|
||||
expect(teamEditView.$el.find(fieldClass).length).toBe(1);
|
||||
@@ -93,7 +86,8 @@ define([
|
||||
});
|
||||
|
||||
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-textarea textarea').val(teamsData.description);
|
||||
@@ -109,46 +103,49 @@ define([
|
||||
});
|
||||
|
||||
it('shows validation error message when field is empty', function () {
|
||||
var requests = AjaxHelpers.requests(this);
|
||||
verifyValidation(requests, [
|
||||
var requests = AjaxHelpers.requests(this),
|
||||
teamEditView = createTeamEditView();
|
||||
verifyValidation(requests, teamEditView, [
|
||||
['.u-field-name input', 'Name', 'success'],
|
||||
['.u-field-textarea textarea', '', 'error']
|
||||
]);
|
||||
teamEditView.render();
|
||||
verifyValidation(requests, [
|
||||
verifyValidation(requests, teamEditView, [
|
||||
['.u-field-name input', '', 'error'],
|
||||
['.u-field-textarea textarea', 'description', 'success']
|
||||
]);
|
||||
teamEditView.render();
|
||||
verifyValidation(requests, [
|
||||
verifyValidation(requests, teamEditView, [
|
||||
['.u-field-name input', '', 'error'],
|
||||
['.u-field-textarea textarea', '', 'error']
|
||||
]);
|
||||
});
|
||||
|
||||
it('shows validation error message when field value length exceeded the limit', function () {
|
||||
var requests = AjaxHelpers.requests(this);
|
||||
var teamName = new Array(500 + 1).join( '$' );
|
||||
var teamDescription = new Array(500 + 1).join( '$' );
|
||||
var requests = AjaxHelpers.requests(this),
|
||||
teamEditView = createTeamEditView(),
|
||||
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-textarea textarea', 'description', 'success']
|
||||
]);
|
||||
teamEditView.render();
|
||||
verifyValidation(requests, [
|
||||
verifyValidation(requests, teamEditView, [
|
||||
['.u-field-name input', 'name', 'success'],
|
||||
['.u-field-textarea textarea', teamDescription, 'error']
|
||||
]);
|
||||
teamEditView.render();
|
||||
verifyValidation(requests, [
|
||||
verifyValidation(requests, teamEditView, [
|
||||
['.u-field-name input', teamName, 'error'],
|
||||
['.u-field-textarea textarea', teamDescription, 'error']
|
||||
]);
|
||||
});
|
||||
|
||||
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-textarea textarea').val(teamsData.description);
|
||||
@@ -163,6 +160,7 @@ define([
|
||||
});
|
||||
|
||||
it("changes route on cancel click", function () {
|
||||
var teamEditView = createTeamEditView();
|
||||
teamEditView.$('.create-team.form-actions .action-cancel').click();
|
||||
expect(Backbone.history.navigate.calls[0].args).toContain('topics/awesomeness');
|
||||
});
|
||||
|
||||
@@ -3,8 +3,9 @@ define([
|
||||
'teams/js/collections/team',
|
||||
'teams/js/collections/team_membership',
|
||||
'teams/js/views/my_teams',
|
||||
'teams/js/spec_helpers/team_spec_helpers'
|
||||
], function (Backbone, TeamCollection, TeamMembershipCollection, MyTeamsView, TeamSpecHelpers) {
|
||||
'teams/js/spec_helpers/team_spec_helpers',
|
||||
'common/js/spec_helpers/ajax_helpers'
|
||||
], function (Backbone, TeamCollection, TeamMembershipCollection, MyTeamsView, TeamSpecHelpers, AjaxHelpers) {
|
||||
'use strict';
|
||||
describe('My Teams View', function () {
|
||||
beforeEach(function () {
|
||||
@@ -28,26 +29,51 @@ define([
|
||||
it('can render itself', function () {
|
||||
var teamMembershipsData = TeamSpecHelpers.createMockTeamMembershipsData(1, 5),
|
||||
teamMemberships = TeamSpecHelpers.createMockTeamMemberships(teamMembershipsData),
|
||||
teamsView = createMyTeamsView({
|
||||
myTeamsView = createMyTeamsView({
|
||||
teams: teamMemberships,
|
||||
teamMemberships: teamMemberships
|
||||
});
|
||||
|
||||
TeamSpecHelpers.verifyCards(teamsView, teamMembershipsData);
|
||||
TeamSpecHelpers.verifyCards(myTeamsView, teamMembershipsData);
|
||||
|
||||
// Verify that there is no header or footer
|
||||
expect(teamsView.$('.teams-paging-header').text().trim()).toBe('');
|
||||
expect(teamsView.$('.teams-paging-footer').text().trim()).toBe('');
|
||||
expect(myTeamsView.$('.teams-paging-header').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 () {
|
||||
var teamMemberships = TeamSpecHelpers.createMockTeamMemberships([]),
|
||||
teamsView = createMyTeamsView({
|
||||
myTeamsView = createMyTeamsView({
|
||||
teams: teamMemberships,
|
||||
teamMemberships: teamMemberships
|
||||
});
|
||||
TeamSpecHelpers.verifyCards(teamsView, []);
|
||||
expect(teamsView.$el.text().trim()).toBe('You are not currently a member of any teams.');
|
||||
TeamSpecHelpers.verifyCards(myTeamsView, []);
|
||||
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, {});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
define([
|
||||
'underscore', 'common/js/spec_helpers/ajax_helpers', 'teams/js/models/team',
|
||||
'teams/js/spec_helpers/team_spec_helpers',
|
||||
'teams/js/views/team_join'
|
||||
], function (_, AjaxHelpers, TeamModel, TeamSpecHelpers, TeamJoinView) {
|
||||
'backbone', 'underscore', 'common/js/spec_helpers/ajax_helpers', 'teams/js/models/team',
|
||||
'teams/js/views/team_join', 'teams/js/spec_helpers/team_spec_helpers'
|
||||
], function (Backbone, _, AjaxHelpers, TeamModel, TeamJoinView, TeamSpecHelpers) {
|
||||
'use strict';
|
||||
describe('TeamJoinView', function () {
|
||||
var createTeamsUrl,
|
||||
@@ -63,6 +62,7 @@ define([
|
||||
var teamJoinView = new TeamJoinView(
|
||||
{
|
||||
courseID: TeamSpecHelpers.testCourseID,
|
||||
teamEvents: TeamSpecHelpers.teamEvents,
|
||||
model: model,
|
||||
teamsUrl: createTeamsUrl(teamId),
|
||||
maxTeamSize: maxTeamSize,
|
||||
|
||||
@@ -5,16 +5,18 @@ define([
|
||||
], function (_, AjaxHelpers, TeamModel, TeamProfileView, TeamSpecHelpers, DiscussionSpecHelper) {
|
||||
'use strict';
|
||||
describe('TeamProfileView', function () {
|
||||
var profileView, createTeamProfileView, createTeamModelData, teamModel,
|
||||
var profileView, createTeamProfileView, createTeamModelData, clickLeaveTeam,
|
||||
teamModel,
|
||||
leaveTeamLinkSelector = '.leave-team-link',
|
||||
DEFAULT_MEMBERSHIP = [
|
||||
{
|
||||
'user': {
|
||||
'username': 'bilbo',
|
||||
'profile_image': {
|
||||
'has_image': true,
|
||||
'image_url_medium': '/image-url'
|
||||
}
|
||||
'image_url_medium': '/image-url'
|
||||
}
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
@@ -38,6 +40,7 @@ define([
|
||||
createTeamProfileView = function(requests, options) {
|
||||
teamModel = new TeamModel(createTeamModelData(options), { parse: true });
|
||||
profileView = new TeamProfileView({
|
||||
teamEvents: TeamSpecHelpers.teamEvents,
|
||||
courseID: TeamSpecHelpers.testCourseID,
|
||||
model: teamModel,
|
||||
maxTeamSize: options.maxTeamSize || 3,
|
||||
@@ -71,6 +74,21 @@ define([
|
||||
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() {
|
||||
it('can render itself', function () {
|
||||
var requests = AjaxHelpers.requests(this),
|
||||
@@ -84,6 +102,7 @@ define([
|
||||
|
||||
expect(view.$('.new-post-btn').length).toEqual(0);
|
||||
teamModel.set('membership', DEFAULT_MEMBERSHIP); // This should re-render the view.
|
||||
view.render();
|
||||
expect(view.$('.new-post-btn').length).toEqual(1);
|
||||
});
|
||||
|
||||
@@ -92,7 +111,7 @@ define([
|
||||
view = createTeamProfileView(requests, {membership: DEFAULT_MEMBERSHIP});
|
||||
|
||||
expect(view.$('.new-post-btn').length).toEqual(1);
|
||||
teamModel.set('membership', []);
|
||||
clickLeaveTeam(requests, view);
|
||||
expect(view.$('.new-post-btn').length).toEqual(0);
|
||||
});
|
||||
});
|
||||
@@ -119,7 +138,10 @@ define([
|
||||
assertTeamDetails(view, 0, false);
|
||||
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() {
|
||||
var requests = AjaxHelpers.requests(this);
|
||||
var view = createTeamProfileView(requests, {});
|
||||
@@ -145,29 +167,21 @@ define([
|
||||
// assert user profile page url.
|
||||
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() {
|
||||
var requests = AjaxHelpers.requests(this);
|
||||
var leaveTeamLinkSelector = '.leave-team-link';
|
||||
|
||||
var view = createTeamProfileView(
|
||||
requests, { country: 'US', language: 'en', membership: DEFAULT_MEMBERSHIP}
|
||||
requests, {country: 'US', language: 'en', membership: DEFAULT_MEMBERSHIP}
|
||||
);
|
||||
assertTeamDetails(view, 1, true);
|
||||
|
||||
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'}));
|
||||
|
||||
clickLeaveTeam(requests, view);
|
||||
assertTeamDetails(view, 0, false);
|
||||
});
|
||||
|
||||
it('shows correct error messages', function () {
|
||||
var requests = AjaxHelpers.requests(this);
|
||||
|
||||
|
||||
@@ -5,11 +5,8 @@ define(['jquery',
|
||||
function ($, _, TopicCardView, Topic) {
|
||||
|
||||
describe('topic card view', function () {
|
||||
var view;
|
||||
|
||||
beforeEach(function () {
|
||||
spyOn(TopicCardView.prototype, 'action');
|
||||
view = new TopicCardView({
|
||||
var createTopicCardView = function() {
|
||||
return new TopicCardView({
|
||||
model: new Topic({
|
||||
'id': 'renewables',
|
||||
'name': 'Renewable Energy',
|
||||
@@ -17,9 +14,14 @@ define(['jquery',
|
||||
'team_count': 34
|
||||
})
|
||||
});
|
||||
};
|
||||
|
||||
beforeEach(function () {
|
||||
spyOn(TopicCardView.prototype, 'action');
|
||||
});
|
||||
|
||||
it('can render itself', function () {
|
||||
var view = createTopicCardView();
|
||||
expect(view.$el).toHaveClass('square-card');
|
||||
expect(view.$el.find('.card-title').text()).toContain('Renewable Energy');
|
||||
expect(view.$el.find('.card-description').text()).toContain('changes in <ⓡⓔⓝⓔⓦⓐⓑⓛⓔ> ʎƃɹǝuǝ');
|
||||
@@ -28,6 +30,7 @@ define(['jquery',
|
||||
});
|
||||
|
||||
it('navigates when action button is clicked', function () {
|
||||
var view = createTopicCardView();
|
||||
view.$el.find('.action').trigger('click');
|
||||
// TODO test actual navigation once implemented
|
||||
expect(view.action).toHaveBeenCalled();
|
||||
|
||||
@@ -3,8 +3,9 @@ define([
|
||||
'teams/js/collections/team',
|
||||
'teams/js/collections/team_membership',
|
||||
'teams/js/views/topic_teams',
|
||||
'teams/js/spec_helpers/team_spec_helpers'
|
||||
], function (Backbone, TeamCollection, TeamMembershipCollection, TopicTeamsView, TeamSpecHelpers) {
|
||||
'teams/js/spec_helpers/team_spec_helpers',
|
||||
'common/js/spec_helpers/ajax_helpers'
|
||||
], function (Backbone, TeamCollection, TeamMembershipCollection, TopicTeamsView, TeamSpecHelpers, AjaxHelpers) {
|
||||
'use strict';
|
||||
describe('Topic Teams View', function () {
|
||||
var createTopicTeamsView = function(options) {
|
||||
@@ -21,6 +22,24 @@ define([
|
||||
}).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 () {
|
||||
setFixtures('<div class="teams-container"></div>');
|
||||
});
|
||||
@@ -39,12 +58,7 @@ define([
|
||||
expect(footerEl).not.toHaveClass('hidden');
|
||||
|
||||
TeamSpecHelpers.verifyCards(teamsView, testTeamData);
|
||||
|
||||
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."
|
||||
);
|
||||
verifyActions(teamsView);
|
||||
});
|
||||
|
||||
it('can browse all teams', function () {
|
||||
@@ -74,9 +88,7 @@ define([
|
||||
|
||||
it('does not show actions for a user already in a team', function () {
|
||||
var teamsView = createTopicTeamsView({});
|
||||
expect(teamsView.$el.text()).not.toContain(
|
||||
'Are you having trouble finding a team to join?'
|
||||
);
|
||||
verifyActions(teamsView, {showActions: false});
|
||||
});
|
||||
|
||||
it('shows actions for a privileged user already in a team', function () {
|
||||
@@ -85,9 +97,32 @@ define([
|
||||
{ privileged: true }
|
||||
),
|
||||
teamsView = createTopicTeamsView({ teamMemberships: staffMembership });
|
||||
expect(teamsView.$el.text()).toContain(
|
||||
'Are you having trouble finding a team to join?'
|
||||
);
|
||||
verifyActions(teamsView);
|
||||
});
|
||||
|
||||
/*
|
||||
// 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});
|
||||
});
|
||||
*/
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
define([
|
||||
'teams/js/collections/topic', 'teams/js/views/topics'
|
||||
], function (TopicCollection, TopicsView) {
|
||||
'backbone', 'teams/js/collections/topic', 'teams/js/views/topics',
|
||||
'teams/js/spec_helpers/team_spec_helpers'
|
||||
], function (Backbone, TopicCollection, TopicsView, TeamSpecHelpers) {
|
||||
'use strict';
|
||||
describe('TopicsView', function () {
|
||||
var initialTopics, topicCollection, topicsView,
|
||||
var initialTopics, topicCollection, createTopicsView,
|
||||
generateTopics = function (startIndex, stopIndex) {
|
||||
return _.map(_.range(startIndex, stopIndex + 1), function (i) {
|
||||
return {
|
||||
@@ -15,6 +16,14 @@ define([
|
||||
});
|
||||
};
|
||||
|
||||
createTopicsView = function() {
|
||||
return new TopicsView({
|
||||
teamEvents: TeamSpecHelpers.teamEvents,
|
||||
el: '.topics-container',
|
||||
collection: topicCollection
|
||||
}).render();
|
||||
};
|
||||
|
||||
beforeEach(function () {
|
||||
setFixtures('<div class="topics-container"></div>');
|
||||
initialTopics = generateTopics(1, 5);
|
||||
@@ -26,13 +35,17 @@ define([
|
||||
"start": 0,
|
||||
"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 () {
|
||||
var footerEl = topicsView.$('.topics-paging-footer'),
|
||||
var topicsView = createTopicsView(),
|
||||
footerEl = topicsView.$('.topics-paging-footer'),
|
||||
topicCards = topicsView.$('.topic-card');
|
||||
expect(topicsView.$('.topics-paging-header').text()).toMatch('Showing 1-5 out of 6 total');
|
||||
_.each(initialTopics, function (topic, index) {
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
define([
|
||||
'backbone',
|
||||
'underscore',
|
||||
'teams/js/collections/team',
|
||||
'teams/js/collections/team_membership',
|
||||
], function (_, TeamCollection, TeamMembershipCollection) {
|
||||
], function (Backbone, _, TeamCollection, TeamMembershipCollection) {
|
||||
'use strict';
|
||||
var createMockPostResponse, createMockDiscussionResponse, createAnnotatedContentInfo, createMockThreadResponse,
|
||||
testCourseID = 'course/1',
|
||||
testUser = 'testUser',
|
||||
testTeamDiscussionID = "12345",
|
||||
teamEvents = _.clone(Backbone.Events),
|
||||
testCountries = [
|
||||
['', ''],
|
||||
['US', 'United States'],
|
||||
@@ -47,6 +49,7 @@ define([
|
||||
results: teamData
|
||||
},
|
||||
{
|
||||
teamEvents: teamEvents,
|
||||
course_id: 'my/course/id',
|
||||
parse: true
|
||||
}
|
||||
@@ -79,6 +82,7 @@ define([
|
||||
results: teamMembershipData
|
||||
},
|
||||
_.extend(_.extend({}, {
|
||||
teamEvents: teamEvents,
|
||||
course_id: 'my/course/id',
|
||||
parse: true,
|
||||
url: 'api/teams/team_memberships',
|
||||
@@ -225,6 +229,7 @@ define([
|
||||
};
|
||||
|
||||
return {
|
||||
teamEvents: teamEvents,
|
||||
testCourseID: testCourseID,
|
||||
testUser: testUser,
|
||||
testCountries: testCountries,
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
},
|
||||
|
||||
initialize: function(options) {
|
||||
this.teamEvents = options.teamEvents;
|
||||
this.courseID = options.teamParams.courseID;
|
||||
this.topicID = options.teamParams.topicID;
|
||||
this.collection = options.collection;
|
||||
@@ -28,7 +29,7 @@
|
||||
this.countries = options.teamParams.countries;
|
||||
this.primaryButtonTitle = options.primaryButtonTitle || 'Submit';
|
||||
|
||||
_.bindAll(this, 'goBackToTopic', 'createTeam');
|
||||
_.bindAll(this, 'goBackToTopic', 'createTeam');
|
||||
|
||||
this.teamModel = new TeamModel({});
|
||||
this.teamModel.url = this.teamsUrl;
|
||||
@@ -113,6 +114,10 @@
|
||||
|
||||
this.teamModel.save(data, { wait: true })
|
||||
.done(function(result) {
|
||||
view.teamEvents.trigger('teams:update', {
|
||||
action: 'create',
|
||||
team: result
|
||||
});
|
||||
Backbone.history.navigate(
|
||||
'teams/' + view.topicID + '/' + view.teamModel.id,
|
||||
{trigger: true}
|
||||
@@ -175,10 +180,10 @@
|
||||
if (screenReaderMessage) {
|
||||
this.$('.screen-reader-message').text(screenReaderMessage);
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
goBackToTopic: function () {
|
||||
Backbone.history.navigate('topics/' + this.topicID, {trigger: true});
|
||||
goBackToTopic: function () {
|
||||
Backbone.history.navigate('topics/' + this.topicID, {trigger: true});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -5,10 +5,17 @@
|
||||
function (Backbone, gettext, TeamsView) {
|
||||
var MyTeamsView = TeamsView.extend({
|
||||
render: function() {
|
||||
TeamsView.prototype.render.call(this);
|
||||
if (this.collection.length === 0) {
|
||||
this.$el.append('<p>' + gettext('You are not currently a member of any teams.') + '</p>');
|
||||
var view = this;
|
||||
if (this.collection.isStale) {
|
||||
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;
|
||||
},
|
||||
|
||||
|
||||
@@ -1,108 +1,114 @@
|
||||
;(function (define) {
|
||||
'use strict';
|
||||
'use strict';
|
||||
|
||||
define(['backbone',
|
||||
'underscore',
|
||||
'gettext',
|
||||
'teams/js/views/team_utils',
|
||||
'text!teams/templates/team-join.underscore'],
|
||||
function (Backbone, _, gettext, TeamUtils, teamJoinTemplate) {
|
||||
return Backbone.View.extend({
|
||||
define(['backbone',
|
||||
'underscore',
|
||||
'gettext',
|
||||
'teams/js/views/team_utils',
|
||||
'text!teams/templates/team-join.underscore'],
|
||||
function (Backbone, _, gettext, TeamUtils, teamJoinTemplate) {
|
||||
return Backbone.View.extend({
|
||||
|
||||
errorMessage: gettext("An error occurred. Try again."),
|
||||
alreadyMemberMessage: gettext("You already belong to another team."),
|
||||
teamFullMessage: gettext("This team is full."),
|
||||
errorMessage: gettext("An error occurred. Try again."),
|
||||
alreadyMemberMessage: gettext("You already belong to another team."),
|
||||
teamFullMessage: gettext("This team is full."),
|
||||
|
||||
events: {
|
||||
"click .action-primary": "joinTeam"
|
||||
},
|
||||
events: {
|
||||
"click .action-primary": "joinTeam"
|
||||
},
|
||||
|
||||
initialize: function(options) {
|
||||
this.template = _.template(teamJoinTemplate);
|
||||
this.courseID = options.courseID;
|
||||
this.maxTeamSize = options.maxTeamSize;
|
||||
this.currentUsername = options.currentUsername;
|
||||
this.teamMembershipsUrl = options.teamMembershipsUrl;
|
||||
_.bindAll(this, 'render', 'joinTeam', 'getUserTeamInfo');
|
||||
this.listenTo(this.model, "change", this.render);
|
||||
},
|
||||
initialize: function(options) {
|
||||
this.teamEvents = options.teamEvents;
|
||||
this.template = _.template(teamJoinTemplate);
|
||||
this.courseID = options.courseID;
|
||||
this.maxTeamSize = options.maxTeamSize;
|
||||
this.currentUsername = options.currentUsername;
|
||||
this.teamMembershipsUrl = options.teamMembershipsUrl;
|
||||
_.bindAll(this, 'render', 'joinTeam', 'getUserTeamInfo');
|
||||
this.listenTo(this.model, "change", this.render);
|
||||
},
|
||||
|
||||
render: function() {
|
||||
var message,
|
||||
showButton,
|
||||
teamHasSpace;
|
||||
render: function() {
|
||||
var view = this,
|
||||
message,
|
||||
showButton,
|
||||
teamHasSpace;
|
||||
this.getUserTeamInfo(this.currentUsername, view.maxTeamSize).done(function (info) {
|
||||
teamHasSpace = info.teamHasSpace;
|
||||
|
||||
var view = this;
|
||||
this.getUserTeamInfo(this.currentUsername, view.maxTeamSize).done(function (info) {
|
||||
teamHasSpace = info.teamHasSpace;
|
||||
// if user is the member of current team then we wouldn't show anything
|
||||
if (!info.memberOfCurrentTeam) {
|
||||
showButton = !info.alreadyMember && teamHasSpace;
|
||||
|
||||
// if user is the member of current team then we wouldn't show anything
|
||||
if (!info.memberOfCurrentTeam) {
|
||||
showButton = !info.alreadyMember && teamHasSpace;
|
||||
if (info.alreadyMember) {
|
||||
message = info.memberOfCurrentTeam ? '' : view.alreadyMemberMessage;
|
||||
} else if (!teamHasSpace) {
|
||||
message = view.teamFullMessage;
|
||||
}
|
||||
}
|
||||
|
||||
if (info.alreadyMember) {
|
||||
message = info.memberOfCurrentTeam ? '' : view.alreadyMemberMessage;
|
||||
} else if (!teamHasSpace) {
|
||||
message = view.teamFullMessage;
|
||||
}
|
||||
}
|
||||
view.$el.html(view.template({showButton: showButton, message: message}));
|
||||
});
|
||||
return view;
|
||||
},
|
||||
|
||||
view.$el.html(view.template({showButton: showButton, message: message}));
|
||||
});
|
||||
return view;
|
||||
},
|
||||
joinTeam: function () {
|
||||
var view = this;
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: view.teamMembershipsUrl,
|
||||
data: {'username': view.currentUsername, 'team_id': view.model.get('id')}
|
||||
}).done(function (data) {
|
||||
view.model.fetch()
|
||||
.done(function() {
|
||||
view.teamEvents.trigger('teams:update', {
|
||||
action: 'join',
|
||||
team: view.model
|
||||
});
|
||||
});
|
||||
}).fail(function (data) {
|
||||
TeamUtils.parseAndShowMessage(data, view.errorMessage);
|
||||
});
|
||||
},
|
||||
|
||||
joinTeam: function () {
|
||||
var view = this;
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: view.teamMembershipsUrl,
|
||||
data: {'username': view.currentUsername, 'team_id': view.model.get('id')}
|
||||
}).done(function (data) {
|
||||
view.model.fetch({});
|
||||
}).fail(function (data) {
|
||||
TeamUtils.parseAndShowMessage(data, view.errorMessage);
|
||||
});
|
||||
},
|
||||
getUserTeamInfo: function (username, maxTeamSize) {
|
||||
var deferred = $.Deferred();
|
||||
var info = {
|
||||
alreadyMember: false,
|
||||
memberOfCurrentTeam: false,
|
||||
teamHasSpace: false
|
||||
};
|
||||
|
||||
getUserTeamInfo: function (username, maxTeamSize) {
|
||||
var deferred = $.Deferred();
|
||||
var info = {
|
||||
alreadyMember: false,
|
||||
memberOfCurrentTeam: false,
|
||||
teamHasSpace: false
|
||||
};
|
||||
info.memberOfCurrentTeam = TeamUtils.isUserMemberOfTeam(this.model.get('membership'), username);
|
||||
var teamHasSpace = this.model.get('membership').length < maxTeamSize;
|
||||
|
||||
info.memberOfCurrentTeam = TeamUtils.isUserMemberOfTeam(this.model.get('membership'), username);
|
||||
var teamHasSpace = this.model.get('membership').length < maxTeamSize;
|
||||
if (info.memberOfCurrentTeam) {
|
||||
info.alreadyMember = true;
|
||||
info.memberOfCurrentTeam = true;
|
||||
deferred.resolve(info);
|
||||
} else {
|
||||
if (teamHasSpace) {
|
||||
var view = this;
|
||||
$.ajax({
|
||||
type: 'GET',
|
||||
url: view.teamMembershipsUrl,
|
||||
data: {'username': username, 'course_id': view.courseID}
|
||||
}).done(function (data) {
|
||||
info.alreadyMember = (data.count > 0);
|
||||
info.memberOfCurrentTeam = false;
|
||||
info.teamHasSpace = teamHasSpace;
|
||||
deferred.resolve(info);
|
||||
}).fail(function (data) {
|
||||
TeamUtils.parseAndShowMessage(data, view.errorMessage);
|
||||
deferred.reject();
|
||||
});
|
||||
} else {
|
||||
deferred.resolve(info);
|
||||
}
|
||||
}
|
||||
|
||||
if (info.memberOfCurrentTeam) {
|
||||
info.alreadyMember = true;
|
||||
info.memberOfCurrentTeam = true;
|
||||
deferred.resolve(info);
|
||||
} else {
|
||||
if (teamHasSpace) {
|
||||
var view = this;
|
||||
$.ajax({
|
||||
type: 'GET',
|
||||
url: view.teamMembershipsUrl,
|
||||
data: {'username': username, 'course_id': view.courseID}
|
||||
}).done(function (data) {
|
||||
info.alreadyMember = (data.count > 0);
|
||||
info.memberOfCurrentTeam = false;
|
||||
info.teamHasSpace = teamHasSpace;
|
||||
deferred.resolve(info);
|
||||
}).fail(function (data) {
|
||||
TeamUtils.parseAndShowMessage(data, view.errorMessage);
|
||||
deferred.reject();
|
||||
});
|
||||
} else {
|
||||
deferred.resolve(info);
|
||||
}
|
||||
}
|
||||
|
||||
return deferred.promise();
|
||||
}
|
||||
});
|
||||
});
|
||||
return deferred.promise();
|
||||
}
|
||||
});
|
||||
});
|
||||
}).call(this, define || RequireJS.define);
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
'click .leave-team-link': 'leaveTeam'
|
||||
},
|
||||
initialize: function (options) {
|
||||
this.listenTo(this.model, "change", this.render);
|
||||
this.teamEvents = options.teamEvents;
|
||||
this.courseID = options.courseID;
|
||||
this.maxTeamSize = options.maxTeamSize;
|
||||
this.requestUsername = options.requestUsername;
|
||||
@@ -26,13 +26,13 @@
|
||||
this.countries = TeamUtils.selectorOptionsArrayToHashWithBlank(options.countries);
|
||||
this.languages = TeamUtils.selectorOptionsArrayToHashWithBlank(options.languages);
|
||||
|
||||
this.listenTo(this.model, "change", this.render);
|
||||
},
|
||||
|
||||
render: function () {
|
||||
var memberships = this.model.get('membership'),
|
||||
discussionTopicID = this.model.get('discussion_topic_id'),
|
||||
isMember = TeamUtils.isUserMemberOfTeam(memberships, this.requestUsername);
|
||||
|
||||
this.$el.html(_.template(teamTemplate, {
|
||||
courseID: this.courseID,
|
||||
discussionTopicID: discussionTopicID,
|
||||
@@ -73,10 +73,16 @@
|
||||
event.preventDefault();
|
||||
var view = this;
|
||||
$.ajax({
|
||||
type: 'DELETE',
|
||||
url: view.teamMembershipDetailUrl.replace('team_id', view.model.get('id'))
|
||||
type: 'DELETE',
|
||||
url: view.teamMembershipDetailUrl.replace('team_id', view.model.get('id'))
|
||||
}).done(function (data) {
|
||||
view.model.fetch({});
|
||||
view.model.fetch()
|
||||
.done(function() {
|
||||
view.teamEvents.trigger('teams:update', {
|
||||
action: 'leave',
|
||||
team: view.model
|
||||
});
|
||||
});
|
||||
}).fail(function (data) {
|
||||
TeamUtils.parseAndShowMessage(data, view.errorMessage);
|
||||
});
|
||||
|
||||
@@ -81,9 +81,13 @@
|
||||
router.route.apply(router, route);
|
||||
});
|
||||
|
||||
// Create an event queue to track team changes
|
||||
this.teamEvents = _.clone(Backbone.Events);
|
||||
|
||||
this.teamMemberships = new TeamMembershipCollection(
|
||||
this.userInfo.team_memberships_data,
|
||||
{
|
||||
teamEvents: this.teamEvents,
|
||||
url: this.teamMembershipsUrl,
|
||||
course_id: this.courseID,
|
||||
username: this.userInfo.username,
|
||||
@@ -94,6 +98,7 @@
|
||||
|
||||
this.myTeamsView = new MyTeamsView({
|
||||
router: this.router,
|
||||
teamEvents: this.teamEvents,
|
||||
collection: this.teamMemberships,
|
||||
teamMemberships: this.teamMemberships,
|
||||
maxTeamSize: this.maxTeamSize,
|
||||
@@ -107,12 +112,18 @@
|
||||
|
||||
this.topicsCollection = new TopicCollection(
|
||||
this.topics,
|
||||
{url: options.topicsUrl, course_id: this.courseID, parse: true}
|
||||
{
|
||||
teamEvents: this.teamEvents,
|
||||
url: options.topicsUrl,
|
||||
course_id: this.courseID,
|
||||
parse: true
|
||||
}
|
||||
).bootstrap();
|
||||
|
||||
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({
|
||||
@@ -196,6 +207,7 @@
|
||||
})
|
||||
}),
|
||||
main: new TeamEditView({
|
||||
teamEvents: self.teamEvents,
|
||||
tagName: 'create-new-team',
|
||||
teamParams: teamsView.main.teamParams,
|
||||
primaryButtonTitle: 'Create'
|
||||
@@ -220,6 +232,7 @@
|
||||
this.getTopic(topicID)
|
||||
.done(function(topic) {
|
||||
var collection = new TeamCollection([], {
|
||||
teamEvents: self.teamEvents,
|
||||
course_id: self.courseID,
|
||||
topic_id: topicID,
|
||||
url: self.teamsUrl,
|
||||
@@ -229,7 +242,7 @@
|
||||
collection.goTo(1)
|
||||
.done(function() {
|
||||
var teamsView = new TopicTeamsView({
|
||||
router: router,
|
||||
router: self.router,
|
||||
topic: topic,
|
||||
collection: collection,
|
||||
teamMemberships: self.teamMemberships,
|
||||
@@ -278,25 +291,26 @@
|
||||
self.getTopic(topicID).done(function(topic) {
|
||||
self.getTeam(teamID, true).done(function(team) {
|
||||
var view = new TeamProfileView({
|
||||
teamEvents: self.teamEvents,
|
||||
router: self.router,
|
||||
courseID: courseID,
|
||||
model: team,
|
||||
maxTeamSize: self.maxTeamSize,
|
||||
isPrivileged: self.userInfo.privileged,
|
||||
requestUsername: self.userInfo.username,
|
||||
countries: self.countries,
|
||||
languages: self.languages,
|
||||
teamMembershipDetailUrl: self.teamMembershipDetailUrl
|
||||
});
|
||||
var teamJoinView = new TeamJoinView({
|
||||
teamEvents: self.teamEvents,
|
||||
courseID: courseID,
|
||||
model: team,
|
||||
maxTeamSize: self.maxTeamSize,
|
||||
isPrivileged: self.userInfo.privileged,
|
||||
requestUsername: self.userInfo.username,
|
||||
countries: self.countries,
|
||||
languages: self.languages,
|
||||
teamMembershipDetailUrl: self.teamMembershipDetailUrl
|
||||
});
|
||||
var teamJoinView = new TeamJoinView(
|
||||
{
|
||||
courseID: courseID,
|
||||
model: team,
|
||||
teamsUrl: self.teamsUrl,
|
||||
maxTeamSize: self.maxTeamSize,
|
||||
currentUsername: self.userInfo.username,
|
||||
teamMembershipsUrl: self.teamMembershipsUrl
|
||||
}
|
||||
);
|
||||
model: team,
|
||||
teamsUrl: self.teamsUrl,
|
||||
maxTeamSize: self.maxTeamSize,
|
||||
currentUsername: self.userInfo.username,
|
||||
teamMembershipsUrl: self.teamMembershipsUrl
|
||||
});
|
||||
deferred.resolve(
|
||||
self.createViewWithHeader(
|
||||
{
|
||||
|
||||
@@ -17,20 +17,26 @@
|
||||
},
|
||||
|
||||
render: function() {
|
||||
TeamsView.prototype.render.call(this);
|
||||
var self = this;
|
||||
$.when(
|
||||
this.collection.refresh(),
|
||||
this.teamMemberships.refresh()
|
||||
).done(function() {
|
||||
TeamsView.prototype.render.call(self);
|
||||
|
||||
if (this.teamMemberships.canUserCreateTeam()) {
|
||||
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}.")),
|
||||
{
|
||||
'browse_span_start': '<a class="browse-teams" href="">',
|
||||
'search_span_start': '<a class="search-teams" href="">',
|
||||
'create_span_start': '<a class="create-team" href="">',
|
||||
'span_end': '</a>'
|
||||
}
|
||||
);
|
||||
this.$el.append(_.template(teamActionsTemplate, {message: message}));
|
||||
}
|
||||
if (self.teamMemberships.canUserCreateTeam()) {
|
||||
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}.")),
|
||||
{
|
||||
'browse_span_start': '<a class="browse-teams" href="">',
|
||||
'search_span_start': '<a class="search-teams" href="">',
|
||||
'create_span_start': '<a class="create-team" href="">',
|
||||
'span_end': '</a>'
|
||||
}
|
||||
);
|
||||
self.$el.append(_.template(teamActionsTemplate, {message: message}));
|
||||
}
|
||||
});
|
||||
return this;
|
||||
},
|
||||
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
;(function (define) {
|
||||
'use strict';
|
||||
define([
|
||||
'gettext',
|
||||
'teams/js/views/topic_card',
|
||||
'common/js/components/views/paginated_view'
|
||||
], function (TopicCardView, PaginatedView) {
|
||||
], function (gettext, TopicCardView, PaginatedView) {
|
||||
var TopicsView = PaginatedView.extend({
|
||||
type: 'topics',
|
||||
|
||||
@@ -18,6 +19,16 @@
|
||||
srInfo: this.srInfo
|
||||
});
|
||||
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;
|
||||
|
||||
Reference in New Issue
Block a user