Commit 0b64f2d6 by clrux

Merge pull request #9525 from edx/clrux/ac-76

LMS: Course navigation revamp
parents b7a432c2 508ded26
......@@ -82,7 +82,7 @@ class CourseNavPage(PageObject):
# Click the section to ensure it's open (no harm in clicking twice if it's already open)
# Add one to convert from list index to CSS index
section_css = 'nav>div.chapter:nth-of-type({0})>h3>a'.format(sec_index + 1)
section_css = '.course-navigation .chapter:nth-of-type({0})'.format(sec_index + 1)
self.q(css=section_css).first.click()
# Get the subsection by index
......@@ -94,9 +94,10 @@ class CourseNavPage(PageObject):
return
# Convert list indices (start at zero) to CSS indices (start at 1)
subsection_css = "nav>div.chapter:nth-of-type({0})>ul>li:nth-of-type({1})>a".format(
sec_index + 1, subsec_index + 1
)
subsection_css = (
".course-navigation .chapter-content-container:nth-of-type({0}) "
".menu-item:nth-of-type({1})"
).format(sec_index + 1, subsec_index + 1)
# Click the subsection and ensure that the page finishes reloading
self.q(css=subsection_css).first.click()
......@@ -130,7 +131,7 @@ class CourseNavPage(PageObject):
"""
Return a list of all section titles on the page.
"""
chapter_css = 'nav > div.chapter > h3 > a'
chapter_css = '.course-navigation .chapter .group-heading'
return self.q(css=chapter_css).map(lambda el: el.text.strip()).results
def _subsection_titles(self, section_index):
......@@ -140,7 +141,10 @@ class CourseNavPage(PageObject):
"""
# Retrieve the subsection title for the section
# Add one to the list index to get the CSS index, which starts at one
subsection_css = 'nav>div.chapter:nth-of-type({0})>ul>li>a>p:nth-of-type(1)'.format(section_index)
subsection_css = (
".course-navigation .chapter-content-container:nth-of-type({0}) "
".menu-item a p:nth-of-type(1)"
).format(section_index)
# If the element is visible, we can get its text directly
# Otherwise, we need to get the HTML
......@@ -171,8 +175,8 @@ class CourseNavPage(PageObject):
That's true right after we click the section/subsection, but not true in general
(the user could go to a section, then expand another tab).
"""
current_section_list = self.q(css='nav>div.chapter.is-open>h3>a').text
current_subsection_list = self.q(css='nav>div.chapter.is-open li.active>a>p').text
current_section_list = self.q(css='.course-navigation .chapter.is-open .group-heading').text
current_subsection_list = self.q(css='.course-navigation .chapter-content-container .menu-item.active a p').text
if len(current_section_list) == 0:
self.warning("Could not find the current section")
......
......@@ -14,7 +14,7 @@ class CoursewarePage(CoursePage):
url_path = "courseware/"
xblock_component_selector = '.vert .xblock'
section_selector = '.chapter'
subsection_selector = '.chapter ul li'
subsection_selector = '.chapter-content-container a'
def is_browser_on_page(self):
return self.q(css='body.courseware').present
......@@ -102,7 +102,7 @@ class CoursewarePage(CoursePage):
"""
return the url of the active subsection in the left nav
"""
return self.q(css='.chapter ul li.active a').attrs('href')[0]
return self.q(css='.chapter-content-container .menu-item.active a').attrs('href')[0]
@property
def can_start_proctored_exam(self):
......
......@@ -1121,7 +1121,7 @@ class EntranceExamTest(UniqueCourseTest):
When I view the courseware that has an entrance exam
Then there should be an "Entrance Exam" chapter.'
"""
entrance_exam_link_selector = 'div#accordion nav div h3 a'
entrance_exam_link_selector = '.accordion .course-navigation .chapter .group-heading'
# visit courseware page and make sure there is not entrance exam chapter.
self.courseware_page.visit()
self.courseware_page.wait_for_page()
......
......@@ -92,7 +92,7 @@ def when_i_navigate_to_a_section(step):
world.disable_jquery_animations()
# Open the 2nd section
world.css_click(css_selector='div.chapter', index=1)
world.css_click(css_selector='.chapter', index=1)
subsection_css = 'a[href*="Test_Subsection_2/"]'
# Click on the subsection to see the content
......
......@@ -74,6 +74,7 @@ from xmodule.modulestore.exceptions import ItemNotFoundError
from xmodule.x_module import XModuleDescriptor
from xmodule.mixin import wrap_with_license
from util.json_request import JsonResponse
from util.model_utils import slugify
from util.sandboxing import can_execute_unsafe_code, get_python_lib_zip
from util import milestones_helpers
from verify_student.services import ReverificationService
......@@ -165,6 +166,7 @@ def toc_for_course(user, request, course, active_chapter, active_section, field_
for chapter in chapters:
# Only show required content, if there is required content
# chapter.hide_from_toc is read-only (boo)
display_id = slugify(chapter.display_name_with_default)
local_hide_from_toc = False
if required_content:
if unicode(chapter.location) not in required_content:
......@@ -246,6 +248,7 @@ def toc_for_course(user, request, course, active_chapter, active_section, field_
sections.append(section_context)
toc_chapters.append({
'display_name': chapter.display_name_with_default,
'display_id': display_id,
'url_name': chapter.url_name,
'sections': sections,
'active': chapter.url_name == active_chapter
......
......@@ -155,7 +155,8 @@ class EntranceExamTestCases(LoginEnrollmentTestCase, ModuleStoreTestCase):
}
],
'url_name': u'Entrance_Exam_Section_-_Chapter_1',
'display_name': u'Entrance Exam Section - Chapter 1'
'display_name': u'Entrance Exam Section - Chapter 1',
'display_id': u'entrance-exam-section-chapter-1',
}
]
)
......@@ -182,19 +183,22 @@ class EntranceExamTestCases(LoginEnrollmentTestCase, ModuleStoreTestCase):
}
],
'url_name': u'Overview',
'display_name': u'Overview'
'display_name': u'Overview',
'display_id': u'overview'
},
{
'active': False,
'sections': [],
'url_name': u'Week_1',
'display_name': u'Week 1'
'display_name': u'Week 1',
'display_id': u'week-1'
},
{
'active': False,
'sections': [],
'url_name': u'Instructor',
'display_name': u'Instructor'
'display_name': u'Instructor',
'display_id': u'instructor'
},
{
'active': True,
......@@ -209,7 +213,8 @@ class EntranceExamTestCases(LoginEnrollmentTestCase, ModuleStoreTestCase):
}
],
'url_name': u'Entrance_Exam_Section_-_Chapter_1',
'display_name': u'Entrance Exam Section - Chapter 1'
'display_name': u'Entrance Exam Section - Chapter 1',
'display_id': u'entrance-exam-section-chapter-1'
}
]
)
......
......@@ -633,6 +633,7 @@ class TestTOC(ModuleStoreTestCase):
def test_toc_toy_from_chapter(self, default_ms, setup_finds, setup_sends, toc_finds):
with self.store.default_store(default_ms):
self.setup_modulestore(default_ms, setup_finds, setup_sends)
expected = ([{'active': True, 'sections':
[{'url_name': 'Toy_Videos', 'display_name': u'Toy Videos', 'graded': True,
'format': u'Lecture Sequence', 'due': None, 'active': False},
......@@ -642,11 +643,11 @@ class TestTOC(ModuleStoreTestCase):
'format': '', 'due': None, 'active': False},
{'url_name': 'video_4f66f493ac8f', 'display_name': 'Video', 'graded': True,
'format': '', 'due': None, 'active': False}],
'url_name': 'Overview', 'display_name': u'Overview'},
'url_name': 'Overview', 'display_name': u'Overview', 'display_id': u'overview'},
{'active': False, 'sections':
[{'url_name': 'toyvideo', 'display_name': 'toyvideo', 'graded': True,
'format': '', 'due': None, 'active': False}],
'url_name': 'secret:magic', 'display_name': 'secret:magic'}])
'url_name': 'secret:magic', 'display_name': 'secret:magic', 'display_id': 'secretmagic'}])
course = self.store.get_course(self.toy_course.id, depth=2)
with check_mongo_calls(toc_finds):
......@@ -682,11 +683,11 @@ class TestTOC(ModuleStoreTestCase):
'format': '', 'due': None, 'active': False},
{'url_name': 'video_4f66f493ac8f', 'display_name': 'Video', 'graded': True,
'format': '', 'due': None, 'active': False}],
'url_name': 'Overview', 'display_name': u'Overview'},
'url_name': 'Overview', 'display_name': u'Overview', 'display_id': u'overview'},
{'active': False, 'sections':
[{'url_name': 'toyvideo', 'display_name': 'toyvideo', 'graded': True,
'format': '', 'due': None, 'active': False}],
'url_name': 'secret:magic', 'display_name': 'secret:magic'}])
'url_name': 'secret:magic', 'display_name': 'secret:magic', 'display_id': 'secretmagic'}])
with check_mongo_calls(toc_finds):
actual = render.toc_for_course(
......
......@@ -107,7 +107,6 @@ class TestNavigation(ModuleStoreTestCase, LoginEnrollmentTestCase):
'chapter': 'Chrome',
'section': displayname,
}))
self.assertEquals('open_close_accordion' in response.content, accordion)
self.assertEquals('course-tabs' in response.content, tabs)
self.assertTabInactive('progress', response)
......
......@@ -26,7 +26,6 @@ class RenderXBlockTestMixin(object):
# DOM elements that appear in the LMS Courseware,
# but are excluded from the xBlock-only rendering.
COURSEWARE_CHROME_HTML_ELEMENTS = [
'<header id="open_close_accordion"',
'<ol class="course-tabs"',
'<footer id="footer-openedx"',
'<div class="window-wrap"',
......
<div class="course-wrapper">
<header id="open_close_accordion">
<a href="#">close</a>
</header>
<div id="accordion"></div>
</div>
describe 'Courseware', ->
describe 'start', ->
it 'create the navigation', ->
spyOn(window, 'Navigation')
Courseware.start()
expect(window.Navigation).toHaveBeenCalled()
it 'binds the Logger', ->
spyOn(Logger, 'bind')
Courseware.start()
......
describe 'Navigation', ->
beforeEach ->
loadFixtures 'coffee/fixtures/accordion.html'
@navigation = new Navigation
describe 'constructor', ->
describe 'when the #accordion exists', ->
describe 'when there is an active section', ->
beforeEach ->
spyOn $.fn, 'accordion'
$('#accordion').append('<ul><li></li></ul><ul><li class="active"></li></ul>')
new Navigation
it 'activate the accordion with correct active section', ->
expect($('#accordion').accordion).toHaveBeenCalledWith
active: 1
header: 'h3'
autoHeight: false
heightStyle: 'content'
describe 'when there is no active section', ->
beforeEach ->
spyOn $.fn, 'accordion'
$('#accordion').append('<ul><li></li></ul><ul><li></li></ul>')
new Navigation
it 'activate the accordian with no section as active', ->
expect($('#accordion').accordion).toHaveBeenCalledWith
active: 0
header: 'h3'
autoHeight: false
heightStyle: 'content'
it 'binds the accordionchange event', ->
expect($('#accordion')).toHandleWith 'accordionchange', @navigation.log
it 'bind the navigation toggle', ->
expect($('#open_close_accordion a')).toHandleWith 'click', @navigation.toggle
describe 'when the #accordion does not exists', ->
beforeEach ->
$('#accordion').remove()
it 'does not activate the accordion', ->
spyOn $.fn, 'accordion'
expect($('#accordion').accordion).wasNotCalled()
describe 'toggle', ->
it 'toggle closed class on the wrapper', ->
$('.course-wrapper').removeClass('closed')
@navigation.toggle()
expect($('.course-wrapper')).toHaveClass('closed')
@navigation.toggle()
expect($('.course-wrapper')).not.toHaveClass('closed')
describe 'log', ->
beforeEach ->
spyOn Logger, 'log'
it 'submit event log', ->
@navigation.log {}, {
newHeader:
text: -> "new"
oldHeader:
text: -> "old"
}
expect(Logger.log).toHaveBeenCalledWith 'accordion',
newheader: 'new'
oldheader: 'old'
......@@ -2,7 +2,6 @@ class @Courseware
@prefix: ''
constructor: ->
new Navigation
Logger.bind()
@render()
......
class @Navigation
constructor: ->
if $('#accordion').length
# First look for an active section
active = $('#accordion ul:has(li.active)').index('#accordion ul')
# if we didn't find one, look for an active chapter
if active < 0
active = $('#accordion h3.active').index('#accordion h3')
# if that didn't work either, default to 0
if active < 0
active = 0
$('#accordion').bind('accordionchange', @log).accordion
active: active
header: 'h3'
autoHeight: false
heightStyle: 'content'
$('#accordion .ui-state-active').closest('.chapter').addClass('is-open')
$('#open_close_accordion a').click @toggle
$('#accordion').show()
$('#accordion a').click @setChapter
log: (event, ui) ->
Logger.log 'accordion',
newheader: ui.newHeader.text()
oldheader: ui.oldHeader.text()
toggle: ->
$('.course-wrapper').toggleClass('closed')
setChapter: ->
$('#accordion .is-open').removeClass('is-open')
$(this).closest('.chapter').addClass('is-open')
\ No newline at end of file
// This file is intentionally blank as it was removed because it was not
// longer necessary, but the pipeline requires it for whatever reason.
// Until the pipeline issue is resolved this file is here. It shouldn't
// conflict with anything.
var nothingtoseehere;
\ No newline at end of file
<div class="course-wrapper">
<div class="accordion">
<a href="accordion-menu-1" role="button" class="button-chapter chapter" aria-controls="accordion-menu-1">
<span class="group-heading">
1 Introduction Chapter
</span>
</a>
<div class="chapter-content-container" id="accordion-menu-1" tabindex="-1" aria-expanded="true">
<div class="chapter-menu">
<div class="menu-item">
<a href="#">
<p>1 edX Homepage</p>
<p class="subtitle">Ungraded</p>
</a>
</div>
<div class="menu-item active">
<a href="#">
<p>1 The edX Blog</p>
</a>
</div>
<div class="menu-item graded">
<a href="#">
<p>1 Courses Dashboard</p>
<p class="subtitle">Graded</p>
</a>
</div>
</div>
<a href="accordion-menu-2" role="button" class="button-chapter chapter" aria-controls="accordion-menu-2">
<span class="group-heading">
2 Another Chapter
</span>
</a>
<div class="chapter-content-container" id="accordion-menu-2" tabindex="-1" aria-expanded="false">
<div class="chapter-menu">
<div class="menu-item">
<a href="#">
<p>2 edX Homepage</p>
<p class="subtitle">Ungraded</p>
</a>
</div>
<div class="menu-item">
<a href="#">
<p>2 The edX Blog</p>
</a>
</div>
<div class="menu-item">
<a class="graded" href="#">
<p>2 Courses Dashboard</p>
<p class="subtitle">Graded</p>
</a>
</div>
</div>
</div>
</div>
</div>
</div>]
\ No newline at end of file
......@@ -70,6 +70,7 @@
'history': 'js/vendor/history',
'js/staff_debug_actions': 'js/staff_debug_actions',
'js/vendor/jquery.qubit': 'js/vendor/jquery.qubit',
'js/utils/navigation': 'js/utils/navigation',
// Backbone classes loaded explicitly until they are converted to use RequireJS
'js/models/notification': 'js/models/notification',
......@@ -686,6 +687,7 @@
'lms/include/js/spec/edxnotes/plugins/caret_navigation_spec.js',
'lms/include/js/spec/edxnotes/collections/notes_spec.js',
'lms/include/js/spec/search/search_spec.js',
'lms/include/js/spec/navigation_spec.js',
'lms/include/js/spec/discovery/collections/filters_spec.js',
'lms/include/js/spec/discovery/models/course_card_spec.js',
'lms/include/js/spec/discovery/models/course_directory_spec.js',
......
define(['jquery', 'js/utils/navigation'], function($) {
'use strict';
describe('Course Navigation Accordion', function() {
var accordion, button, heading, chapterContent, chapterMenu;
beforeEach(function() {
loadFixtures('js/fixtures/accordion.html');
accordion = $('.accordion');
button = accordion.children('.button-chapter');
heading = button.children('.group-heading');
chapterContent = accordion.children('.chapter-content-container');
chapterMenu = chapterContent.children('.chapter-menu');
spyOn($.fn, 'focus').andCallThrough();
edx.util.navigation.init();
});
describe('constructor', function() {
describe('always', function() {
it('ensures accordion is present', function() {
expect(accordion.length).toBe(1);
});
it('ensures aria attributes are present', function() {
expect(chapterContent).toHaveAttr({
'aria-expanded': 'true'
});
});
it('ensures only one active item', function() {
expect(chapterMenu.find('.active').length).toBe(1);
});
});
describe('open section with mouse click', function() {
it('ensures new section is opened and previous section is closed', function() {
button:eq(1).click();
expect(chapterContent:eq(0)).not.toHaveClass('is-open');
expect(chapterContent:eq(1)).toHaveClass('is-open');
expect(button:eq(0)).not.toHaveClass('is-open');
expect(button:eq(1)).toHaveClass('is-open');
expect(chapterContent:eq(1).focus).toHaveBeenCalled();
});
it('ensure proper aria and attrs', function() {
expect(chapterContent:eq(1)).toHaveAttr({
'aria-expanded': 'false'
});
expect(chapterContent:eq(0)).toHaveAttr({
'aria-expanded': 'true'
});
});
});
describe('open section with spacebar', function() {
function keyPressEvent(key) {
return $.Event('keydown', { keyCode: key });
}
it('ensures new section is opened and previous section is closed', function() {
button:eq(1).focus();
button.trigger(keyPressEvent(32)); // Spacebar
expect(chapterContent:eq(0)).not.toHaveClass('is-open');
expect(chapterContent:eq(1)).toHaveClass('is-open');
expect(button:eq(0)).not.toHaveClass('is-open');
expect(button:eq(1)).toHaveClass('is-open');
expect(chapterContent:eq(1).focus).toHaveBeenCalled();
});
it('ensure proper aria and attrs', function() {
expect(chapterContent:eq(1)).toHaveAttr({
'aria-expanded': 'false'
});
expect(chapterContent:eq(0)).toHaveAttr({
'aria-expanded': 'true'
});
});
});
});
});
});
\ No newline at end of file
var edx = edx || {},
Navigation = (function() {
var navigation = {
init: function() {
if ($('.accordion').length) {
navigation.loadAccordion();
}
},
loadAccordion: function() {
navigation.checkForCurrent();
navigation.listenForClick();
navigation.listenForKeypress();
},
getActiveIndex: function() {
var index = $('.accordion .button-chapter:has(.active)').index('.accordion .button-chapter'),
button = null;
if (index > -1) {
button = $('.accordion .button-chapter:eq(' + index + ')');
}
return button;
},
checkForCurrent: function() {
var button = navigation.getActiveIndex();
navigation.closeAccordions();
if (button !== null) {
navigation.setupCurrentAccordionSection(button);
}
},
listenForClick: function() {
$('.accordion').on('click', '.button-chapter', function(event) {
event.preventDefault();
var button = $(event.currentTarget),
section = button.next('.chapter-content-container');
navigation.closeAccordions(button, section);
navigation.openAccordion(button, section);
});
},
listenForKeypress: function() {
$('.accordion').on('keydown', '.button-chapter', function(event) {
// because we're changing the role of the toggle from an 'a' to a 'button'
// we need to ensure it has the same keyboard use cases as a real button.
// this is useful for screenreader users primarily.
if (event.which == 32) { // spacebar
event.preventDefault();
$(event.currentTarget).trigger('click');
} else {
return true;
}
});
},
closeAccordions: function(button, section) {
var menu = $(section).find('.chapter-menu'), toggle;
$('.accordion .button-chapter').each(function(index, element) {
toggle = $(element);
toggle
.removeClass('is-open')
.attr('aria-expanded', 'false');
toggle
.children('.group-heading')
.removeClass('active')
.find('.icon')
.addClass('fa-caret-right')
.removeClass('fa-caret-down');
toggle
.next('.chapter-content-container')
.removeClass('is-open')
.find('.chapter-menu').not(menu)
.removeClass('is-open')
.slideUp();
});
},
setupCurrentAccordionSection: function(button) {
var section = $(button).next('.chapter-content-container');
navigation.openAccordion(button, section);
},
openAccordion: function(button, section) {
var sectionEl = $(section),
firstLink = sectionEl.find('.menu-item').first(),
buttonEl = $(button);
buttonEl
.addClass('is-open')
.attr('aria-expanded', 'true');
buttonEl
.children('.group-heading')
.addClass('active')
.find('.icon')
.removeClass('fa-caret-right')
.addClass('fa-caret-down');
sectionEl
.addClass('is-open')
.find('.chapter-menu')
.addClass('is-open')
.slideDown();
}
};
return {
init: navigation.init
};
})();
edx.util = edx.util || {};
edx.util.navigation = Navigation;
edx.util.navigation.init();
......@@ -671,7 +671,7 @@ div.course-wrapper {
}
}
div#accordion {
.accordion {
visibility: hidden;
width: 10px;
padding: 0;
......@@ -679,11 +679,6 @@ div.course-wrapper {
nav {
white-space: pre;
overflow: hidden;
ul {
overflow: hidden;
white-space: nowrap;
}
}
}
}
......
......@@ -6,73 +6,45 @@
%>
<%def name="make_chapter(chapter)">
<div class="chapter">
<%
if chapter.get('active'):
aria_label = _('{chapter}, current chapter').format(chapter=chapter['display_name'])
active_class = ' class="active"'
else:
aria_label = chapter['display_name']
active_class = ''
%>
<h3 ${active_class} aria-label="${aria_label}">
<a href="#">
${chapter['display_name']}
</a>
</h3>
<ul>
% for section in chapter['sections']:
<li class="${'active' if 'active' in section and section['active'] else ''} ${'graded' if 'graded' in section and section['graded'] else ''}">
<%
if chapter.get('active'):
aria_label = _('{chapter} current chapter').format(chapter=chapter['display_name'])
active_class = 'active'
else:
aria_label = chapter['display_name']
active_class = ''
%>
<a href="#${chapter['display_id']}-child" role="button" class="button-chapter chapter ${active_class}" id="${chapter['display_id']}-parent" aria-controls="${chapter['display_id']}-child" aria-expanded="false">
<span class="group-heading ${active_class}" aria-label="${aria_label}">
<span class="icon fa fa-caret-right" aria-hidden="true"></span>
${chapter['display_name']}
</span>
</a>
<div class="chapter-content-container" id="${chapter['display_id']}-child" tabindex="-1" role="group" aria-label="${chapter['display_name']} submenu">
<div class="chapter-menu">
% for section in chapter['sections']:
<div class="menu-item ${'active' if 'active' in section and section['active'] else ''} ${'graded' if 'graded' in section and section['graded'] else ''}">
<a href="${reverse('courseware_section', args=[course_id, chapter['url_name'], section['url_name']])}">
<p>${section['display_name']} ${'<span class="sr">, current section</span>' if 'active' in section and section['active'] else ''}</p>
<%
<p>${section['display_name']} ${'<span class="sr"> current section</span>' if 'active' in section and section['active'] else ''}</p>
<%
if section.get('due') is None:
due_date = ''
else:
formatted_string = get_time_display(section['due'], due_date_display_format, coerce_tz=settings.TIME_ZONE_DISPLAYED_FOR_DEADLINES)
due_date = '' if len(formatted_string)==0 else _('due {date}').format(date=formatted_string)
%>
## There is behavior differences between
## rending of sections which have proctoring/timed examinations
## and those that do not.
##
## Proctoring exposes a exam status message field as well as
## a status icon
% if section['format'] or due_date or 'proctoring' in section:
<p class="subtitle">
% if 'proctoring' in section:
## Display the proctored exam status icon and status message
<i class="fa ${section['proctoring'].get('suggested_icon', 'fa-lock')} ${section['proctoring'].get('status', 'eligible')}"></i>&nbsp;
<span class="subtitle-name">${section['proctoring'].get('short_description', '')}
</span>
## completed proctored exam statuses should not show the due date
## since the exam has already been submitted by the user
% if not section['proctoring'].get('in_completed_state', False):
<span class="subtitle-name">${due_date}</span>
% endif
% else:
## non-proctored section, we just show the exam format and the due date
## this is the standard case in edx-platform
<span class="subtitle-name">${section['format']} ${due_date}
</span>
%>
<p class="subtitle">${section['format']} ${due_date}</p>
% if 'graded' in section and section['graded']:
<span class="menu-icon icon fa fa-pencil-square-o" aria-hidden="true"></span>
<span class="sr">This content is graded</span>
% endif
</p>
% endif
% if 'graded' in section and section['graded']:
## sections that are graded should indicate this through an icon
<i class="icon fa fa-pencil-square-o" aria-hidden="true" data-tooltip="${_("This section is graded.")}"></i>
% endif
</a>
</li>
% endfor
</ul>
</div>
</div>
% endfor
</div>
</div>
</%def>
% for chapter in toc:
${make_chapter(chapter)}
% endfor
% endfor
\ No newline at end of file
......@@ -165,10 +165,6 @@ ${fragment.foot_html()}
% if disable_accordion is UNDEFINED or not disable_accordion:
<div class="course-index">
<header id="open_close_accordion">
<a href="#">${_("close")}</a>
</header>
% if settings.FEATURES.get('ENABLE_COURSEWARE_SEARCH'):
<div id="courseware-search-bar" class="search-bar courseware-search-bar" role="search" aria-label="Course">
<form>
......@@ -186,8 +182,8 @@ ${fragment.foot_html()}
</div>
% endif
<div id="accordion" style="display: none">
<nav aria-label="${_('Course Navigation')}">
<div class="accordion">
<nav class="course-navigation" aria-label="${_('Course')}">
% if accordion.strip():
${accordion}
% else:
......
......@@ -204,11 +204,11 @@ import pytz
activeHeader: "ui-icon-carat-1-s"
};
var act = 0;
$("#accordion").accordion(
$(".accordion").accordion(
{
heightStyle: 'content',
activate: function(event, ui) {
var active = jQuery("#accordion").accordion('option', 'active');
var active = jQuery(".accordion").accordion('option', 'active');
$.cookie('saved_index', null);
$.cookie('saved_index', active);
$('#error-msg').val('');
......
......@@ -130,6 +130,7 @@ from branding import api as branding_api
<%block name="js_extra"/>
<script type="text/javascript" src="${static.url('js/vendor/noreferrer.js')}" charset="utf-8"></script>
<script type="text/javascript" src="${static.url('js/utils/navigation.js')}" charset="utf-8"></script>
</body>
</html>
......
......@@ -71,9 +71,6 @@ $("#open_close_accordion a").click(function(){
<div class="book-wrapper">
<section aria-label="${_('Textbook Navigation')}" class="book-sidebar">
<header id="open_close_accordion">
<a href="#">close</a>
</header>
<ul id="booknav" class="treeview-booknav">
<%def name="print_entry(entry)">
......
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