XBlocks can disable navigation chrome.
There is an option to: * Enable/disable accordion navigation * Enable/disable/repoint tab navigation This allows for full-screen XBlocks (e.g. a code IDE, or large video player). It is also the first pass at allowing top-level XBlocks. It's also now possible to make a chromeless XBlock, point a tab to it, and make it point back to that tab. Next steps down that path would be: * Fix up how tabs are handled. The current version is a hack. * Create appropriate XBlocks for courseware, tabbed navigation, etc. to reach feature parity * Invert/rejigger the XML format.
This commit is contained in:
@@ -147,7 +147,15 @@ class MongoContentStore(ContentStore):
|
||||
|
||||
for asset in assets:
|
||||
asset_location = AssetLocation._from_deprecated_son(asset['_id'], course_key.run) # pylint: disable=protected-access
|
||||
self.export(asset_location, output_directory)
|
||||
# TODO: On 6/19/14, I had to put a try/except around this
|
||||
# to export a course. The course failed on JSON files in
|
||||
# the /static/ directory placed in it with an import.
|
||||
#
|
||||
# If this hasn't been looked at in a while, remove this comment.
|
||||
#
|
||||
# When debugging course exports, this might be a good place
|
||||
# to look. -- pmitros
|
||||
self.export(asset_location, output_directory)
|
||||
for attr, value in asset.iteritems():
|
||||
if attr not in ['_id', 'md5', 'uploadDate', 'length', 'chunkSize']:
|
||||
policy.setdefault(asset_location.name, {})[attr] = value
|
||||
|
||||
@@ -28,17 +28,38 @@ class TestNavigation(ModuleStoreTestCase, LoginEnrollmentTestCase):
|
||||
|
||||
self.test_course = CourseFactory.create(display_name='Robot_Sub_Course')
|
||||
self.course = CourseFactory.create(display_name='Robot_Super_Course')
|
||||
self.chapter0 = ItemFactory.create(parent_location=self.course.location,
|
||||
self.chapter0 = ItemFactory.create(parent=self.course,
|
||||
display_name='Overview')
|
||||
self.chapter9 = ItemFactory.create(parent_location=self.course.location,
|
||||
self.chapter9 = ItemFactory.create(parent=self.course,
|
||||
display_name='factory_chapter')
|
||||
self.section0 = ItemFactory.create(parent_location=self.chapter0.location,
|
||||
self.section0 = ItemFactory.create(parent=self.chapter0,
|
||||
display_name='Welcome')
|
||||
self.section9 = ItemFactory.create(parent_location=self.chapter9.location,
|
||||
self.section9 = ItemFactory.create(parent=self.chapter9,
|
||||
display_name='factory_section')
|
||||
self.unit0 = ItemFactory.create(parent_location=self.section0.location,
|
||||
self.unit0 = ItemFactory.create(parent=self.section0,
|
||||
display_name='New Unit')
|
||||
|
||||
self.chapterchrome = ItemFactory.create(parent=self.course,
|
||||
display_name='Chrome')
|
||||
self.chromelesssection = ItemFactory.create(parent=self.chapterchrome,
|
||||
display_name='chromeless',
|
||||
chrome='none')
|
||||
self.accordionsection = ItemFactory.create(parent=self.chapterchrome,
|
||||
display_name='accordion',
|
||||
chrome='accordion')
|
||||
self.tabssection = ItemFactory.create(parent=self.chapterchrome,
|
||||
display_name='tabs',
|
||||
chrome='tabs')
|
||||
self.defaultchromesection = ItemFactory.create(parent=self.chapterchrome,
|
||||
display_name='defaultchrome')
|
||||
self.fullchromesection = ItemFactory.create(parent=self.chapterchrome,
|
||||
display_name='fullchrome',
|
||||
chrome='accordion,tabs')
|
||||
self.tabtest = ItemFactory.create(parent=self.chapterchrome,
|
||||
display_name='progress_tab',
|
||||
default_tab = 'progress')
|
||||
|
||||
|
||||
# Create student accounts and activate them.
|
||||
for i in range(len(self.STUDENT_INFO)):
|
||||
email, password = self.STUDENT_INFO[i]
|
||||
@@ -48,6 +69,50 @@ class TestNavigation(ModuleStoreTestCase, LoginEnrollmentTestCase):
|
||||
|
||||
self.staff_user = GlobalStaffFactory()
|
||||
|
||||
def test_chrome_settings(self):
|
||||
'''
|
||||
Test settings for disabling and modifying navigation chrome in the courseware:
|
||||
- Accordion enabled, or disabled
|
||||
- Navigation tabs enabled, disabled, or redirected
|
||||
'''
|
||||
email, password = self.STUDENT_INFO[0]
|
||||
self.login(email, password)
|
||||
self.enroll(self.course, True)
|
||||
|
||||
test_data = (
|
||||
('tabs', False, True),
|
||||
('none', False, False),
|
||||
('fullchrome', True, True),
|
||||
('accordion', True, False),
|
||||
('fullchrome', True, True))
|
||||
for (displayname, accordion, tabs) in test_data:
|
||||
response = self.client.get(reverse('courseware_section', kwargs={
|
||||
'course_id': self.course.id.to_deprecated_string(),
|
||||
'chapter': 'Chrome',
|
||||
'section': displayname,
|
||||
}))
|
||||
self.assertEquals('open_close_accordion' in response.content, accordion)
|
||||
self.assertEquals('course-tabs' in response.content, tabs)
|
||||
|
||||
def tab_active(tabname, response):
|
||||
''' Check if the progress tab is active in the tab set '''
|
||||
for line in response.content.split('\n'):
|
||||
if tabname in line and 'active' in line:
|
||||
return True
|
||||
return False
|
||||
|
||||
self.assertFalse(tab_active('progress', response))
|
||||
self.assertTrue(tab_active('courseware', response))
|
||||
|
||||
response = self.client.get(reverse('courseware_section', kwargs={
|
||||
'course_id': self.course.id.to_deprecated_string(),
|
||||
'chapter': 'Chrome',
|
||||
'section': 'progress_tab',
|
||||
}))
|
||||
|
||||
self.assertTrue(tab_active('progress', response))
|
||||
self.assertFalse(tab_active('courseware', response))
|
||||
|
||||
@override_settings(SESSION_INACTIVITY_TIMEOUT_IN_SECONDS=1)
|
||||
def test_inactive_session_timeout(self):
|
||||
"""
|
||||
|
||||
@@ -338,6 +338,7 @@ def index(request, course_id, chapter=None, section=None,
|
||||
|
||||
if section is not None:
|
||||
section_descriptor = chapter_descriptor.get_child_by(lambda m: m.location.name == section)
|
||||
|
||||
if section_descriptor is None:
|
||||
# Specifically asked-for section doesn't exist
|
||||
if masq == 'student': # if staff is masquerading as student be kinder, don't 404
|
||||
@@ -345,6 +346,17 @@ def index(request, course_id, chapter=None, section=None,
|
||||
return redirect(reverse('courseware', args=[course.id.to_deprecated_string()]))
|
||||
raise Http404
|
||||
|
||||
## Allow chromeless operation
|
||||
if section_descriptor.chrome:
|
||||
chrome = [s.strip() for s in section_descriptor.chrome.lower().split(",")]
|
||||
if 'accordion' not in chrome:
|
||||
del context['accordion']
|
||||
if 'tabs' not in chrome:
|
||||
context['disable_tabs'] = True
|
||||
|
||||
if section_descriptor.default_tab:
|
||||
context['default_tab'] = section_descriptor.default_tab
|
||||
|
||||
# cdodge: this looks silly, but let's refetch the section_descriptor with depth=None
|
||||
# which will prefetch the children more efficiently than doing a recursive load
|
||||
section_descriptor = modulestore().get_item(section_descriptor.location, depth=None)
|
||||
|
||||
@@ -18,5 +18,20 @@ class LmsBlockMixin(XBlockMixin):
|
||||
"grader to apply, and what to show in the TOC)",
|
||||
scope=Scope.settings,
|
||||
)
|
||||
chrome = String(
|
||||
help="Which chrome to show. Options: "
|
||||
"chromeless -- No chrome"
|
||||
"tabs -- just tabs"
|
||||
"accordion -- just accordion"
|
||||
"tabs,accordion -- Full Chrome",
|
||||
scope=Scope.settings,
|
||||
default = None,
|
||||
)
|
||||
default_tab = String(
|
||||
help="Override which tab is selected."
|
||||
"If not set, courseware tab is shown.",
|
||||
scope=Scope.settings,
|
||||
default = None,
|
||||
)
|
||||
source_file = String(help="source file name (eg for latex)", scope=Scope.settings)
|
||||
ispublic = Boolean(help="Whether this course is open to the public, or only to admins", scope=Scope.settings)
|
||||
|
||||
@@ -20,12 +20,13 @@ def url_class(is_active):
|
||||
<%! from courseware.views import notification_image_for_tab %>
|
||||
<% import waffle %>
|
||||
|
||||
% if disable_tabs is UNDEFINED:
|
||||
<nav class="${active_page} course-material">
|
||||
<div class="inner-wrapper">
|
||||
<ol class="course-tabs">
|
||||
% for tab in CourseTabList.iterate_displayable(course, settings, user.is_authenticated(), has_access(user, 'staff', course, course.id)):
|
||||
<%
|
||||
tab_is_active = (tab.tab_id == active_page)
|
||||
tab_is_active = (tab.tab_id == active_page) or (tab.tab_id == default_tab)
|
||||
tab_image = notification_image_for_tab(tab, user, course)
|
||||
%>
|
||||
% if waffle.flag_is_active(request, 'visual_treatment'):
|
||||
@@ -55,6 +56,7 @@ def url_class(is_active):
|
||||
</ol>
|
||||
</div>
|
||||
</nav>
|
||||
%endif
|
||||
|
||||
% if masquerade is not UNDEFINED:
|
||||
% if staff_access and masquerade is not None:
|
||||
|
||||
@@ -179,8 +179,10 @@ ${fragment.foot_html()}
|
||||
</div>
|
||||
% endif
|
||||
|
||||
% if accordion:
|
||||
<%include file="/dashboard/_dashboard_prompt_midcourse_reverify.html" />
|
||||
% if default_tab:
|
||||
<%include file="/courseware/course_navigation.html" />
|
||||
% else:
|
||||
<%include file="/courseware/course_navigation.html" args="active_page='courseware'" />
|
||||
% endif
|
||||
|
||||
|
||||
Reference in New Issue
Block a user