Add teams-for-topic list view to Teams page.

TNL-1898

Also adds a generic paginated list view and Teams list view. The
common PaginatedView takes a collection and a view class for its items
and creates a header and footer with correct pagination. The topics
list view is refactored to use this generic view.

Authors:
  - Peter Fogg <pfogg@edx.org>
  - Daniel Friedman <dfriedman58@gmail.com>
This commit is contained in:
Daniel Friedman
2015-07-08 17:41:08 -04:00
parent 6d6bfa7f35
commit 21b39ca467
38 changed files with 1449 additions and 314 deletions

View File

@@ -81,7 +81,8 @@
description: description,
action_class: this.callIfFunction(this.actionClass),
action_url: this.callIfFunction(this.actionUrl),
action_content: this.callIfFunction(this.actionContent)
action_content: this.callIfFunction(this.actionContent),
configuration: this.callIfFunction(this.configuration)
}));
var detailsEl = this.$el.find('.card-meta');
_.each(this.callIfFunction(this.details), function (detail) {

View File

@@ -19,35 +19,59 @@
* following properties:
* view (Backbone.View): the view to render for this tab.
* title (string): The title to display for this tab.
* url (string): The URL fragment which will navigate to this tab.
* url (string): The URL fragment which will
* navigate to this tab when a router is
* provided.
* If a router is passed in (via options.router),
* use that router to keep track of history between
* tabs. Backbone.history.start() must be called
* by the router's instatiator after this view is
* initialized.
*/
initialize: function (options) {
this.router = new Backbone.Router();
this.$el.html(this.template({}));
var self = this;
this.router = options.router || null;
this.tabs = options.tabs;
this.urlMap = _.reduce(this.tabs, function (map, value) {
map[value.url] = value;
return map;
}, {});
},
render: function () {
var self = this;
this.$el.html(this.template({}));
_.each(this.tabs, function(tabInfo, index) {
var tabEl = $(_.template(tabTemplate, {
index: index,
title: tabInfo.title
title: tabInfo.title,
url: tabInfo.url
}));
self.$('.page-content-nav').append(tabEl);
self.router.route(tabInfo.url, function () {
self.setActiveTab(index);
});
});
this.setActiveTab(0);
if(Backbone.history.getHash() === "") {
this.setActiveTab(0);
}
return this;
},
setActiveTab: function (index) {
var tab = this.tabs[index],
view = tab.view;
var tab, tabEl, view;
if (typeof index === 'string') {
tab = this.urlMap[index];
tabEl = this.$('a[data-url='+index+']');
}
else {
tab = this.tabs[index];
tabEl = this.$('a[data-index='+index+']');
}
view = tab.view;
this.$('a.is-active').removeClass('is-active').attr('aria-selected', 'false');
this.$('a[data-index='+index+']').addClass('is-active').attr('aria-selected', 'true');
tabEl.addClass('is-active').attr('aria-selected', 'true');
view.setElement(this.$('.page-content-main')).render();
this.$('.sr-is-focusable.sr-tab').focus();
this.router.navigate(tab.url, {replace: true});
if (this.router) {
this.router.navigate(tab.url, {replace: true, trigger: true});
}
},
switchTab: function (event) {

View File

@@ -18,7 +18,7 @@
it('can render itself as a list card', function () {
var view = new CardView({ configuration: 'list_card' });
expect(view.$el).toHaveClass('list-card');
expect(view.$el.find('.wrapper-card-meta .action').length).toBe(1);
expect(view.$el.find('.wrapper-card-core .action').length).toBe(1);
});
it('renders a pennant only if the pennant value is truthy', function () {

View File

@@ -20,23 +20,15 @@
describe('TabbedView component', function () {
beforeEach(function () {
spyOn(Backbone.history, 'navigate').andCallThrough();
Backbone.history.start();
view = new TabbedView({
tabs: [{
url: 'test 1',
title: 'Test 1',
view: new TestSubview({text: 'this is test text'})
}, {
url: 'test 2',
title: 'Test 2',
view: new TestSubview({text: 'other text'})
}]
});
});
afterEach(function () {
Backbone.history.stop();
}).render();
});
it('can render itself', function () {
@@ -59,12 +51,6 @@
expect(view.$el.text()).toContain('other text');
});
it('changes tabs on navigation', function () {
expect(view.$('.nav-item.is-active').data('index')).toEqual(0);
Backbone.history.navigate('test 2', {trigger: true});
expect(view.$('.nav-item.is-active').data('index')).toEqual(1);
});
it('marks the active tab as selected using aria attributes', function () {
expect(view.$('.nav-item[data-index=0]')).toHaveAttr('aria-selected', 'true');
expect(view.$('.nav-item[data-index=1]')).toHaveAttr('aria-selected', 'false');
@@ -73,17 +59,59 @@
expect(view.$('.nav-item[data-index=1]')).toHaveAttr('aria-selected', 'true');
});
it('updates the page URL on tab switches without adding to browser history', function () {
view.$('.nav-item[data-index=1]').click();
expect(Backbone.history.navigate).toHaveBeenCalledWith('test 2', {replace: true});
});
it('sets focus for screen readers', function () {
spyOn($.fn, 'focus');
view.$('.nav-item[data-index=1]').click();
expect(view.$('.sr-is-focusable.sr-tab').focus).toHaveBeenCalled();
});
describe('history', function() {
beforeEach(function () {
spyOn(Backbone.history, 'navigate').andCallThrough();
view = new TabbedView({
tabs: [{
url: 'test 1',
title: 'Test 1',
view: new TestSubview({text: 'this is test text'})
}, {
url: 'test 2',
title: 'Test 2',
view: new TestSubview({text: 'other text'})
}],
router: new Backbone.Router({
routes: {
'test 1': function () {
view.setActiveTab(0);
},
'test 2': function () {
view.setActiveTab(1);
}
}
})
}).render();
Backbone.history.start();
});
afterEach(function () {
view.router.navigate('');
Backbone.history.stop();
});
it('updates the page URL on tab switches without adding to browser history', function () {
view.$('.nav-item[data-index=1]').click();
expect(Backbone.history.navigate).toHaveBeenCalledWith(
'test 2',
{replace: true, trigger: true}
);
});
it('changes tabs on URL navigation', function () {
expect(view.$('.nav-item.is-active').data('index')).toEqual(0);
Backbone.history.navigate('test 2', {trigger: true});
expect(view.$('.nav-item.is-active').data('index')).toEqual(1);
});
});
});
}
);
});
}).call(this, define || RequireJS.define);

View File

@@ -531,6 +531,8 @@
'lms/include/teams/js/spec/topic_card_spec.js',
'lms/include/teams/js/spec/topic_collection_spec.js',
'lms/include/teams/js/spec/topics_spec.js',
'lms/include/teams/js/spec/teams_spec.js',
'lms/include/teams/js/spec/teams_tab_spec.js',
'lms/include/js/spec/components/header/header_spec.js',
'lms/include/js/spec/components/tabbed/tabbed_view_spec.js',
'lms/include/js/spec/components/card/card_spec.js',