Course navigation menu accessibility issue
Following have been done 1- Change the structure of the course navigation Menu HTML 2- Add some basic styling 3- Add basic JS for html rendering 4- Update tests according to new structure AC-76
This commit is contained in:
committed by
Chris Rodriguez
parent
28fddda407
commit
b32d2205d4
@@ -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 = 'nav>div.chapter:nth-of-type({0})'.format(sec_index + 1)
|
||||
self.q(css=section_css).first.click()
|
||||
|
||||
# Get the subsection by index
|
||||
@@ -94,7 +94,7 @@ 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(
|
||||
subsection_css = "nav>div.chapter-content-container:nth-of-type({0})>div>ol>li:nth-of-type({1})>a".format(
|
||||
sec_index + 1, subsec_index + 1
|
||||
)
|
||||
|
||||
@@ -130,7 +130,7 @@ class CourseNavPage(PageObject):
|
||||
"""
|
||||
Return a list of all section titles on the page.
|
||||
"""
|
||||
chapter_css = 'nav > div.chapter > h3 > a'
|
||||
chapter_css = 'nav > button.chapter > h3'
|
||||
return self.q(css=chapter_css).map(lambda el: el.text.strip()).results
|
||||
|
||||
def _subsection_titles(self, section_index):
|
||||
@@ -140,7 +140,9 @@ 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 = 'nav>.chapter-content-container:nth-of-type({0})>div>ol>li>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 +173,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='nav>button.chapter.is-open>h3').text
|
||||
current_subsection_list = self.q(css='nav div.chapter-content-container ol li.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 ol li'
|
||||
|
||||
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 ol li.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 = 'div#accordion nav button h3'
|
||||
# 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='button.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'
|
||||
}
|
||||
]
|
||||
)
|
||||
|
||||
@@ -642,11 +642,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 +682,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(
|
||||
|
||||
@@ -2,5 +2,11 @@
|
||||
<header id="open_close_accordion">
|
||||
<a href="#">close</a>
|
||||
</header>
|
||||
<div id="accordion"></div>
|
||||
</div>
|
||||
<div id="accordion">
|
||||
<button class="chapter">
|
||||
<h3>
|
||||
Introduction Chapter
|
||||
</h3>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -8,7 +8,7 @@ describe 'Navigation', ->
|
||||
describe 'when there is an active section', ->
|
||||
beforeEach ->
|
||||
spyOn $.fn, 'accordion'
|
||||
$('#accordion').append('<ul><li></li></ul><ul><li class="active"></li></ul>')
|
||||
$('#accordion').append('<div><div><ol><li></li></ol></div></div><div><div><ol><li class="active"></li></ol></div></div>')
|
||||
new Navigation
|
||||
|
||||
it 'activate the accordion with correct active section', ->
|
||||
@@ -21,7 +21,7 @@ describe 'Navigation', ->
|
||||
describe 'when there is no active section', ->
|
||||
beforeEach ->
|
||||
spyOn $.fn, 'accordion'
|
||||
$('#accordion').append('<ul><li></li></ul><ul><li></li></ul>')
|
||||
$('#accordion').append('<div><div><ol><li></li></ol></div></div><div><div><ol><li></li></ol></div></div>')
|
||||
new Navigation
|
||||
|
||||
it 'activate the accordian with no section as active', ->
|
||||
@@ -37,6 +37,9 @@ describe 'Navigation', ->
|
||||
it 'bind the navigation toggle', ->
|
||||
expect($('#open_close_accordion a')).toHandleWith 'click', @navigation.toggle
|
||||
|
||||
it 'bind the setChapter', ->
|
||||
expect($('#accordion .chapter')).toHandleWith 'click', @navigation.setChapter
|
||||
|
||||
describe 'when the #accordion does not exists', ->
|
||||
beforeEach ->
|
||||
$('#accordion').remove()
|
||||
@@ -70,3 +73,25 @@ describe 'Navigation', ->
|
||||
expect(Logger.log).toHaveBeenCalledWith 'accordion',
|
||||
newheader: 'new'
|
||||
oldheader: 'old'
|
||||
|
||||
describe 'setChapter', ->
|
||||
beforeEach ->
|
||||
$('#accordion').append('<div><div><ol><li class="active"><a href="#"></a></li></ol></div></div>')
|
||||
new Navigation
|
||||
it 'Chapter opened', ->
|
||||
e = jQuery.Event('click')
|
||||
$('#accordion .chapter').trigger(e)
|
||||
expect($('.chapter')).toHaveClass('is-open')
|
||||
|
||||
it 'content active on chapter opened', ->
|
||||
e = jQuery.Event('click')
|
||||
$('#accordion .chapter').trigger(e)
|
||||
expect($('.chapter').next('div').children('div')).toHaveClass('ui-accordion-content-active')
|
||||
expect($('.ui-accordion-content-active')).toHaveAttr('aria-hidden', 'false')
|
||||
|
||||
it 'focus move to first child on chapter opened', ->
|
||||
spyOn($.fn, 'focus')
|
||||
e = jQuery.Event('click')
|
||||
$('#accordion .chapter').trigger(e)
|
||||
expect($('.ui-accordion-content-active li:first-child a').focus).toHaveBeenCalled()
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ class @Navigation
|
||||
constructor: ->
|
||||
if $('#accordion').length
|
||||
# First look for an active section
|
||||
active = $('#accordion ul:has(li.active)').index('#accordion ul')
|
||||
active = $('#accordion div div ol:has(li.active)').index('#accordion div div ol')
|
||||
# if we didn't find one, look for an active chapter
|
||||
if active < 0
|
||||
active = $('#accordion h3.active').index('#accordion h3')
|
||||
@@ -15,9 +15,15 @@ class @Navigation
|
||||
autoHeight: false
|
||||
heightStyle: 'content'
|
||||
$('#accordion .ui-state-active').closest('.chapter').addClass('is-open')
|
||||
$('#accordion .ui-state-active').parent().next('div').children('div').addClass('ui-accordion-content-active')
|
||||
$('#accordion .ui-state-active').parent().next('div').show()
|
||||
$('#accordion .ui-state-active').parent().attr('aria-expanded' , 'true').attr('aria-pressed' , 'true')
|
||||
$('#accordion div').filter(':not(.chapter-content-container)').addClass("ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom").filter(":not(.ui-accordion-content-active)").hide()
|
||||
$('.ui-accordion-content div').attr('aria-hidden', 'false')
|
||||
$('.ui-accordion-content-active div').attr('aria-hidden', 'true')
|
||||
$('#open_close_accordion a').click @toggle
|
||||
$('#accordion').show()
|
||||
$('#accordion a').click @setChapter
|
||||
$('#accordion .chapter').click @setChapter
|
||||
|
||||
log: (event, ui) ->
|
||||
Logger.log 'accordion',
|
||||
@@ -28,6 +34,14 @@ class @Navigation
|
||||
$('.course-wrapper').toggleClass('closed')
|
||||
|
||||
setChapter: ->
|
||||
$('#accordion .is-open').removeClass('is-open')
|
||||
$(this).closest('.chapter').addClass('is-open')
|
||||
|
||||
$('#accordion .is-open').removeClass('is-open').attr('aria-expanded' , 'false').attr('aria-pressed' , 'false').find('h3 span').removeClass('ui-icon-triangle-1-s').addClass('ui-icon-triangle-1-e')
|
||||
$(this).closest('.chapter').addClass('is-open').attr('aria-expanded' , 'true').attr('aria-pressed' , 'true').find('h3 span').removeClass('ui-icon-triangle-1-e').addClass('ui-icon-triangle-1-s')
|
||||
$('.ui-accordion-content-active').attr('aria-hidden', 'true')
|
||||
$('.ui-accordion-content-active').parent().hide()
|
||||
$('#accordion .ui-accordion-content-active').removeClass('ui-accordion-content-active')
|
||||
$(this).closest('.chapter').next('div').children('div').addClass('ui-accordion-content-active')
|
||||
$('.ui-accordion-content-active').parent().show()
|
||||
$('.ui-accordion-content-active').show()
|
||||
$('.ui-accordion-content-active li:first-child a').focus()
|
||||
$('.ui-accordion-content-active').attr('aria-hidden', 'false')
|
||||
|
||||
|
||||
@@ -17,43 +17,36 @@
|
||||
}
|
||||
|
||||
div#accordion {
|
||||
@extend %t-copy-sub1;
|
||||
width: auto;
|
||||
font-size: 14px;
|
||||
|
||||
h3 {
|
||||
border-radius: 0;
|
||||
margin: 0;
|
||||
@extend %t-title6;
|
||||
@include padding-left($baseline);
|
||||
overflow: visible;
|
||||
font-size: 16px;
|
||||
margin: 0;
|
||||
border-radius: 0;
|
||||
box-shadow: none;
|
||||
color: $link-color;
|
||||
|
||||
&:first-child {
|
||||
border: none;
|
||||
}
|
||||
|
||||
&:hover, &:focus {
|
||||
color: #666;
|
||||
}
|
||||
|
||||
&.ui-state-hover, &.ui-state-focus {
|
||||
a {
|
||||
color: #666;
|
||||
}
|
||||
}
|
||||
|
||||
&.ui-accordion-header {
|
||||
@extend %t-regular;
|
||||
border-bottom: none;
|
||||
color: $black;
|
||||
|
||||
a {
|
||||
@include padding-left($baseline);
|
||||
border-radius: 0;
|
||||
box-shadow: none;
|
||||
@include padding-left(19px);
|
||||
color: $link-color;
|
||||
}
|
||||
|
||||
&.ui-state-active {
|
||||
@extend .active;
|
||||
border-bottom: none;
|
||||
color: $base-font-color;
|
||||
|
||||
&:hover, &:focus {
|
||||
background: none;
|
||||
@@ -61,9 +54,9 @@
|
||||
}
|
||||
|
||||
span.ui-icon {
|
||||
@include left(0);
|
||||
opacity: 0.3;
|
||||
@include left($baseline);
|
||||
background-image: url("/static/images/ui-icons_222222_256x240.png"); // jQuery UI sprite
|
||||
opacity: 0.3;
|
||||
|
||||
&.ui-icon-triangle-1-e {
|
||||
|
||||
@@ -82,25 +75,24 @@
|
||||
}
|
||||
|
||||
.chapter {
|
||||
width: 100% !important;
|
||||
@include box-sizing(border-box);
|
||||
padding: 11px 14px;
|
||||
@include linear-gradient(top, $sidebar-chapter-bg-top, $sidebar-chapter-bg-bottom);
|
||||
background-color: $sidebar-chapter-bg;
|
||||
box-shadow: 0 1px 0 $white inset, 0 -1px 0 $shadow-l1 inset;
|
||||
@include transition(background-color .1s linear 0s);
|
||||
width: 100% !important;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
border-radius: 0;
|
||||
box-shadow: 0 1px 0 $white inset, 0 -1px 0 $shadow-l1 inset;
|
||||
background-color: $sidebar-chapter-bg;
|
||||
color: $link-color;
|
||||
|
||||
h3 {
|
||||
padding: ($baseline*.75) $baseline ($baseline*.75) ($baseline*2);
|
||||
}
|
||||
|
||||
&.is-open {
|
||||
background: $white;
|
||||
}
|
||||
|
||||
&:first-child {
|
||||
border-radius: 3px 0 0 0;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
border-radius: 0 0 0 3px;
|
||||
box-shadow: 0 1px 0 $white inset;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
&:hover, &:focus {
|
||||
@@ -108,41 +100,47 @@
|
||||
}
|
||||
}
|
||||
|
||||
ul.ui-accordion-content {
|
||||
background: transparent;
|
||||
div.chapter-content-container{
|
||||
display: none;
|
||||
padding: 0 14px ($baseline/2) 14px;
|
||||
border-bottom: 1px solid $shadow-l1;
|
||||
background: $white;
|
||||
}
|
||||
|
||||
div.ui-accordion-content {
|
||||
margin: 0;
|
||||
padding: 0 ($baseline*.75);
|
||||
border: none;
|
||||
border-radius: 0;
|
||||
margin: 0;
|
||||
padding: 9px 0 9px 9px;
|
||||
overflow: auto;
|
||||
width: 100%;
|
||||
background: transparent;
|
||||
|
||||
li {
|
||||
margin: ($baseline/5) 0;
|
||||
// margin-bottom: ($baseline/5);
|
||||
border-bottom: 0;
|
||||
border-radius: 0;
|
||||
margin-bottom: ($baseline/5);
|
||||
|
||||
a {
|
||||
background: transparent;
|
||||
border-radius: 4px;
|
||||
display: block;
|
||||
@include padding( ($baseline/4), ($baseline*1.5), ($baseline/4), ($baseline/2));
|
||||
@extend %t-strong;
|
||||
@include padding(($baseline/4) ($baseline/2));
|
||||
position: relative;
|
||||
display: block;
|
||||
border-radius: ($baseline/5);
|
||||
background: transparent;
|
||||
text-decoration: none;
|
||||
|
||||
p {
|
||||
font-weight: bold;
|
||||
font-family: $sans-serif;
|
||||
@extend %t-action3;
|
||||
@extend %t-strong;
|
||||
margin-bottom: 0;
|
||||
line-height: 1.3;
|
||||
font-family: $sans-serif;
|
||||
|
||||
&.subtitle {
|
||||
@extend %t-copy-sub2;
|
||||
@extend %t-weight2;
|
||||
display: inline-block;
|
||||
width: 90%;
|
||||
color: $gray-d1;
|
||||
@extend %t-action3;
|
||||
@extend %t-regular;
|
||||
display: block;
|
||||
margin: 0;
|
||||
color: $gray-d1;
|
||||
|
||||
&:empty {
|
||||
display: none;
|
||||
@@ -164,7 +162,6 @@
|
||||
}
|
||||
|
||||
&:hover, &:focus {
|
||||
background: $shadow-l1;
|
||||
|
||||
> a p {
|
||||
color: $gray-d3;
|
||||
@@ -182,19 +179,19 @@
|
||||
}
|
||||
|
||||
&.active {
|
||||
@extend %t-weight5;
|
||||
@extend %t-strong;
|
||||
|
||||
&:after {
|
||||
@extend %t-regular;
|
||||
@include transition(none);
|
||||
@include right($baseline);
|
||||
content: '›';
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
right: 20px;
|
||||
margin-top: -13px;
|
||||
font-size: 30px;
|
||||
font-weight: normal;
|
||||
color: #333;
|
||||
color: $gray-d3;
|
||||
opacity: 0;
|
||||
@include transition(none);
|
||||
}
|
||||
|
||||
> a {
|
||||
@@ -208,24 +205,27 @@
|
||||
}
|
||||
|
||||
p {
|
||||
color: #333;
|
||||
color: $gray-d3;
|
||||
}
|
||||
}
|
||||
|
||||
span.subtitle {
|
||||
@extend %t-weight2;
|
||||
@extend %t-regular;
|
||||
}
|
||||
}
|
||||
|
||||
&.graded {
|
||||
> a {
|
||||
.icon {
|
||||
vertical-align: middle;
|
||||
}
|
||||
> a {
|
||||
> img {
|
||||
@include right($baseline/4);
|
||||
position: absolute;
|
||||
bottom: ($baseline/4);
|
||||
margin: auto;
|
||||
}
|
||||
}
|
||||
|
||||
&.active > a {
|
||||
background: linear-gradient(to bottom, #e6e6e6, #d6d6d6);
|
||||
background: linear-gradient(to bottom, $gray-l4, #d6d6d6);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
%>
|
||||
|
||||
<%def name="make_chapter(chapter)">
|
||||
<div class="chapter">
|
||||
<button class="chapter" id="${chapter['display_id']}-parent" aria-controls="${chapter['display_id']}-child" aria-expanded="false" aria-pressed="false">
|
||||
<%
|
||||
if chapter.get('active'):
|
||||
aria_label = _('{chapter}, current chapter').format(chapter=chapter['display_name'])
|
||||
@@ -16,63 +16,36 @@
|
||||
active_class = ''
|
||||
%>
|
||||
<h3 ${active_class} aria-label="${aria_label}">
|
||||
<a href="#">
|
||||
${chapter['display_name']}
|
||||
</a>
|
||||
</h3>
|
||||
</button>
|
||||
<div class="chapter-content-container">
|
||||
<div id="${chapter['display_id']}-child" role="region" aria-labelledby="${chapter['display_id']}-parent" aria-hidden="false">
|
||||
<ol>
|
||||
% 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 ''}">
|
||||
<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>
|
||||
<%
|
||||
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)
|
||||
%>
|
||||
<p class="subtitle">${section['format']} ${due_date}</p>
|
||||
|
||||
<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 ''}">
|
||||
<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>
|
||||
<%
|
||||
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>
|
||||
<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>
|
||||
% 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>
|
||||
% if 'graded' in section and section['graded']:
|
||||
<img src="/static/images/graded.png" alt="Graded Section">
|
||||
% endif
|
||||
</a>
|
||||
</li>
|
||||
% endfor
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
</%def>
|
||||
|
||||
% for chapter in toc:
|
||||
${make_chapter(chapter)}
|
||||
% endfor
|
||||
% endfor
|
||||
Reference in New Issue
Block a user