Merge pull request #8397 from edx/peter-fogg/category-subnavigation
TNL-1891 Browse Teams: Category Subnavigation
This commit is contained in:
@@ -18,4 +18,4 @@ class TeamsPage(CoursePage):
|
||||
|
||||
def get_body_text(self):
|
||||
""" Returns the current dummy text. This will be changed once there is more content on the page. """
|
||||
return self.q(css='.teams-text').text[0]
|
||||
return self.q(css='.page-content-main').text[0]
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
define(["jquery", "teams/js/teams_tab_factory"],
|
||||
function($, TeamsTabFactory) {
|
||||
define(["jquery", "backbone", "teams/js/teams_tab_factory"],
|
||||
function($, Backbone, TeamsTabFactory) {
|
||||
'use strict';
|
||||
|
||||
describe("teams django app", function() {
|
||||
@@ -10,6 +10,10 @@ define(["jquery", "teams/js/teams_tab_factory"],
|
||||
teamsTab = new TeamsTabFactory();
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
Backbone.history.stop();
|
||||
});
|
||||
|
||||
it("can load templates", function() {
|
||||
expect($("body").text()).toContain("This is the new Teams tab");
|
||||
});
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
'gettext',
|
||||
'js/components/header/views/header',
|
||||
'js/components/header/models/header',
|
||||
'text!teams/templates/teams-tab.underscore'],
|
||||
function (Backbone, _, gettext, HeaderView, HeaderModel, teamsTabTemplate) {
|
||||
'js/components/tabbed/views/tabbed_view'],
|
||||
function (Backbone, _, gettext, HeaderView, HeaderModel, TabbedView) {
|
||||
var TeamTabView = Backbone.View.extend({
|
||||
initialize: function() {
|
||||
this.headerModel = new HeaderModel({
|
||||
@@ -17,12 +17,35 @@
|
||||
this.headerView = new HeaderView({
|
||||
model: this.headerModel
|
||||
});
|
||||
// TODO replace this with actual views!
|
||||
var TempTabView = Backbone.View.extend({
|
||||
initialize: function (options) {
|
||||
this.text = options.text;
|
||||
},
|
||||
|
||||
render: function () {
|
||||
this.$el.text(this.text)
|
||||
}
|
||||
});
|
||||
this.tabbedView = new TabbedView({
|
||||
tabs: [{
|
||||
title: gettext('My Teams'),
|
||||
url: 'teams',
|
||||
view: new TempTabView({text: 'This is the new Teams tab.'})
|
||||
}, {
|
||||
title: gettext('Browse'),
|
||||
url: 'browse',
|
||||
view: new TempTabView({text: 'Browse team topics here.'})
|
||||
}]
|
||||
});
|
||||
Backbone.history.start();
|
||||
},
|
||||
|
||||
render: function() {
|
||||
this.$el.html(_.template(teamsTabTemplate, {}));
|
||||
this.$el.prepend(this.headerView.$el);
|
||||
this.$el.append(this.headerView.$el);
|
||||
this.headerView.render();
|
||||
this.$el.append(this.tabbedView.$el);
|
||||
this.tabbedView.render();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
<p class="teams-text">This is the new Teams tab.</p>
|
||||
59
lms/static/js/components/tabbed/views/tabbed_view.js
Normal file
59
lms/static/js/components/tabbed/views/tabbed_view.js
Normal file
@@ -0,0 +1,59 @@
|
||||
;(function (define) {
|
||||
'use strict';
|
||||
define(['backbone',
|
||||
'underscore',
|
||||
'jquery',
|
||||
'text!templates/components/tabbed/tabbed_view.underscore',
|
||||
'text!templates/components/tabbed/tab.underscore'],
|
||||
function (Backbone, _, $, tabbedViewTemplate, tabTemplate) {
|
||||
var TabbedView = Backbone.View.extend({
|
||||
events: {
|
||||
'click .nav-item': 'switchTab'
|
||||
},
|
||||
|
||||
template: _.template(tabbedViewTemplate),
|
||||
|
||||
/**
|
||||
* View for a tabbed interface. Expects a list of tabs
|
||||
* in its options object, each of which should contain the
|
||||
* 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.
|
||||
*/
|
||||
initialize: function (options) {
|
||||
this.router = new Backbone.Router();
|
||||
this.$el.html(this.template({}));
|
||||
var self = this;
|
||||
this.tabs = options.tabs;
|
||||
_.each(this.tabs, function(tabInfo, index) {
|
||||
var tabEl = $(_.template(tabTemplate, {
|
||||
index: index,
|
||||
title: tabInfo.title
|
||||
}));
|
||||
self.$('.page-content-nav').append(tabEl);
|
||||
|
||||
self.router.route(tabInfo.url, function () {
|
||||
self.setActiveTab(index);
|
||||
});
|
||||
});
|
||||
this.setActiveTab(0);
|
||||
},
|
||||
|
||||
setActiveTab: function (index) {
|
||||
this.$('a.is-active').removeClass('is-active').attr('aria-selected', 'false');
|
||||
this.$('a[data-index='+index+']').addClass('is-active').attr('aria-selected', 'true');
|
||||
var view = this.tabs[index].view;
|
||||
view.render();
|
||||
this.$('.page-content-main').html(view.$el.html());
|
||||
this.$('.sr-is-focusable').focus();
|
||||
},
|
||||
|
||||
switchTab: function (event) {
|
||||
event.preventDefault();
|
||||
this.setActiveTab($(event.currentTarget).data('index'));
|
||||
}
|
||||
});
|
||||
return TabbedView;
|
||||
});
|
||||
}).call(this, define || RequireJS.define);
|
||||
78
lms/static/js/spec/components/tabbed/tabbed_view_spec.js
Normal file
78
lms/static/js/spec/components/tabbed/tabbed_view_spec.js
Normal file
@@ -0,0 +1,78 @@
|
||||
(function (define) {
|
||||
'use strict';
|
||||
|
||||
define(['jquery',
|
||||
'underscore',
|
||||
'backbone',
|
||||
'js/components/tabbed/views/tabbed_view'
|
||||
],
|
||||
function($, _, Backbone, TabbedView) {
|
||||
var view,
|
||||
TestSubview = Backbone.View.extend({
|
||||
initialize: function (options) {
|
||||
this.text = options.text;
|
||||
},
|
||||
|
||||
render: function () {
|
||||
this.$el.text(this.text);
|
||||
}
|
||||
});
|
||||
|
||||
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();
|
||||
});
|
||||
|
||||
it('can render itself', function () {
|
||||
expect(view.$el.html()).toContain('<nav class="page-content-nav" role="tablist">')
|
||||
});
|
||||
|
||||
it('shows its first tab by default', function () {
|
||||
expect(view.$el.text()).toContain('this is test text');
|
||||
expect(view.$el.text()).not.toContain('other text');
|
||||
});
|
||||
|
||||
it('displays titles for each tab', function () {
|
||||
expect(view.$el.text()).toContain('Test 1');
|
||||
expect(view.$el.text()).toContain('Test 2');
|
||||
});
|
||||
|
||||
it('can switch tabs', function () {
|
||||
view.$('.nav-item[data-index=1]').click();
|
||||
expect(view.$el.text()).not.toContain('this is test text');
|
||||
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');
|
||||
view.$('.nav-item[data-index=1]').click();
|
||||
expect(view.$('.nav-item[data-index=0]')).toHaveAttr('aria-selected', 'false');
|
||||
expect(view.$('.nav-item[data-index=1]')).toHaveAttr('aria-selected', 'true');
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
||||
}).call(this, define || RequireJS.define);
|
||||
@@ -579,6 +579,7 @@
|
||||
// Run the LMS tests
|
||||
'lms/include/teams/js/spec/teams_factory_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/photocapture_spec.js',
|
||||
'lms/include/js/spec/staff_debug_actions_spec.js',
|
||||
'lms/include/js/spec/views/notification_spec.js',
|
||||
|
||||
@@ -92,10 +92,10 @@ fixture_paths:
|
||||
- templates/verify_student
|
||||
- templates/file-upload.underscore
|
||||
- templates/components/header
|
||||
- templates/components/tabbed
|
||||
- js/fixtures/edxnotes
|
||||
- js/fixtures/search
|
||||
- templates/search
|
||||
- teams/templates
|
||||
- templates/discovery
|
||||
|
||||
requirejs:
|
||||
|
||||
1
lms/templates/components/tabbed/tab.underscore
Normal file
1
lms/templates/components/tabbed/tab.underscore
Normal file
@@ -0,0 +1 @@
|
||||
<a class="nav-item" href="" data-index="<%= index %>" role="tab" aria-selected="false"><%- title %></a>
|
||||
5
lms/templates/components/tabbed/tabbed_view.underscore
Normal file
5
lms/templates/components/tabbed/tabbed_view.underscore
Normal file
@@ -0,0 +1,5 @@
|
||||
<div class="page-content">
|
||||
<nav class="page-content-nav" role="tablist"></nav>
|
||||
<div class="sr-is-focusable" tabindex="-1"></div>
|
||||
<div class="page-content-main"></div>
|
||||
</div>
|
||||
Reference in New Issue
Block a user