Commit 1f1a87d9 by Calen Pennington

Merge pull request #379 from MITx/feature/victor/keep-accordion-state

Make accordion remember state
parents b9459ace 1c3038ff
...@@ -46,11 +46,12 @@ def toc_for_course(user, request, course, active_chapter, active_section): ...@@ -46,11 +46,12 @@ def toc_for_course(user, request, course, active_chapter, active_section):
'format': format, 'due': due, 'active' : bool}, ...] 'format': format, 'due': due, 'active' : bool}, ...]
active is set for the section and chapter corresponding to the passed active is set for the section and chapter corresponding to the passed
parameters. Everything else comes from the xml, or defaults to "". parameters, which are expected to be url_names of the chapter+section.
Everything else comes from the xml, or defaults to "".
chapters with name 'hidden' are skipped. chapters with name 'hidden' are skipped.
''' '''
student_module_cache = StudentModuleCache.cache_for_descriptor_descendents(user, course, depth=2) student_module_cache = StudentModuleCache.cache_for_descriptor_descendents(user, course, depth=2)
course = get_module(user, request, course.location, student_module_cache) course = get_module(user, request, course.location, student_module_cache)
...@@ -59,8 +60,8 @@ def toc_for_course(user, request, course, active_chapter, active_section): ...@@ -59,8 +60,8 @@ def toc_for_course(user, request, course, active_chapter, active_section):
sections = list() sections = list()
for section in chapter.get_display_items(): for section in chapter.get_display_items():
active = (chapter.display_name == active_chapter and active = (chapter.url_name == active_chapter and
section.display_name == active_section) section.url_name == active_section)
hide_from_toc = section.metadata.get('hide_from_toc', 'false').lower() == 'true' hide_from_toc = section.metadata.get('hide_from_toc', 'false').lower() == 'true'
if not hide_from_toc: if not hide_from_toc:
...@@ -73,7 +74,7 @@ def toc_for_course(user, request, course, active_chapter, active_section): ...@@ -73,7 +74,7 @@ def toc_for_course(user, request, course, active_chapter, active_section):
chapters.append({'display_name': chapter.display_name, chapters.append({'display_name': chapter.display_name,
'url_name': chapter.url_name, 'url_name': chapter.url_name,
'sections': sections, 'sections': sections,
'active': chapter.display_name == active_chapter}) 'active': chapter.url_name == active_chapter})
return chapters return chapters
...@@ -122,10 +123,10 @@ def get_module(user, request, location, student_module_cache, position=None): ...@@ -122,10 +123,10 @@ def get_module(user, request, location, student_module_cache, position=None):
position within module position within module
Returns: xmodule instance Returns: xmodule instance
''' '''
descriptor = modulestore().get_item(location) descriptor = modulestore().get_item(location)
#TODO Only check the cache if this module can possibly have state #TODO Only check the cache if this module can possibly have state
instance_module = None instance_module = None
shared_module = None shared_module = None
...@@ -133,13 +134,13 @@ def get_module(user, request, location, student_module_cache, position=None): ...@@ -133,13 +134,13 @@ def get_module(user, request, location, student_module_cache, position=None):
if descriptor.stores_state: if descriptor.stores_state:
instance_module = student_module_cache.lookup(descriptor.category, instance_module = student_module_cache.lookup(descriptor.category,
descriptor.location.url()) descriptor.location.url())
shared_state_key = getattr(descriptor, 'shared_state_key', None) shared_state_key = getattr(descriptor, 'shared_state_key', None)
if shared_state_key is not None: if shared_state_key is not None:
shared_module = student_module_cache.lookup(descriptor.category, shared_module = student_module_cache.lookup(descriptor.category,
shared_state_key) shared_state_key)
instance_state = instance_module.state if instance_module is not None else None instance_state = instance_module.state if instance_module is not None else None
shared_state = shared_module.state if shared_module is not None else None shared_state = shared_module.state if shared_module is not None else None
...@@ -206,13 +207,13 @@ def get_instance_module(user, module, student_module_cache): ...@@ -206,13 +207,13 @@ def get_instance_module(user, module, student_module_cache):
""" """
if user.is_authenticated(): if user.is_authenticated():
if not module.descriptor.stores_state: if not module.descriptor.stores_state:
log.exception("Attempted to get the instance_module for a module " log.exception("Attempted to get the instance_module for a module "
+ str(module.id) + " which does not store state.") + str(module.id) + " which does not store state.")
return None return None
instance_module = student_module_cache.lookup(module.category, instance_module = student_module_cache.lookup(module.category,
module.location.url()) module.location.url())
if not instance_module: if not instance_module:
instance_module = StudentModule( instance_module = StudentModule(
student=user, student=user,
...@@ -222,11 +223,11 @@ def get_instance_module(user, module, student_module_cache): ...@@ -222,11 +223,11 @@ def get_instance_module(user, module, student_module_cache):
max_grade=module.max_score()) max_grade=module.max_score())
instance_module.save() instance_module.save()
student_module_cache.append(instance_module) student_module_cache.append(instance_module)
return instance_module return instance_module
else: else:
return None return None
def get_shared_instance_module(user, module, student_module_cache): def get_shared_instance_module(user, module, student_module_cache):
""" """
Return shared_module is a StudentModule specific to all modules with the same Return shared_module is a StudentModule specific to all modules with the same
...@@ -236,7 +237,7 @@ def get_shared_instance_module(user, module, student_module_cache): ...@@ -236,7 +237,7 @@ def get_shared_instance_module(user, module, student_module_cache):
if user.is_authenticated(): if user.is_authenticated():
# To get the shared_state_key, we need to descriptor # To get the shared_state_key, we need to descriptor
descriptor = modulestore().get_item(module.location) descriptor = modulestore().get_item(module.location)
shared_state_key = getattr(module, 'shared_state_key', None) shared_state_key = getattr(module, 'shared_state_key', None)
if shared_state_key is not None: if shared_state_key is not None:
shared_module = student_module_cache.lookup(module.category, shared_module = student_module_cache.lookup(module.category,
...@@ -251,7 +252,7 @@ def get_shared_instance_module(user, module, student_module_cache): ...@@ -251,7 +252,7 @@ def get_shared_instance_module(user, module, student_module_cache):
student_module_cache.append(shared_module) student_module_cache.append(shared_module)
else: else:
shared_module = None shared_module = None
return shared_module return shared_module
else: else:
return None return None
...@@ -259,7 +260,7 @@ def get_shared_instance_module(user, module, student_module_cache): ...@@ -259,7 +260,7 @@ def get_shared_instance_module(user, module, student_module_cache):
@csrf_exempt @csrf_exempt
def xqueue_callback(request, userid, id, dispatch): def xqueue_callback(request, userid, id, dispatch):
''' '''
Entry point for graded results from the queueing system. Entry point for graded results from the queueing system.
''' '''
# Test xqueue package, which we expect to be: # Test xqueue package, which we expect to be:
# xpackage = {'xqueue_header': json.dumps({'lms_key':'secretkey',...}), # xpackage = {'xqueue_header': json.dumps({'lms_key':'secretkey',...}),
...@@ -331,7 +332,7 @@ def modx_dispatch(request, dispatch=None, id=None): ...@@ -331,7 +332,7 @@ def modx_dispatch(request, dispatch=None, id=None):
instance_module = get_instance_module(request.user, instance, student_module_cache) instance_module = get_instance_module(request.user, instance, student_module_cache)
shared_module = get_shared_instance_module(request.user, instance, student_module_cache) shared_module = get_shared_instance_module(request.user, instance, student_module_cache)
# Don't track state for anonymous users (who don't have student modules) # Don't track state for anonymous users (who don't have student modules)
if instance_module is not None: if instance_module is not None:
oldgrade = instance_module.grade oldgrade = instance_module.grade
......
...@@ -69,12 +69,12 @@ def gradebook(request, course_id): ...@@ -69,12 +69,12 @@ def gradebook(request, course_id):
if 'course_admin' not in user_groups(request.user): if 'course_admin' not in user_groups(request.user):
raise Http404 raise Http404
course = check_course(course_id) course = check_course(course_id)
student_objects = User.objects.all()[:100] student_objects = User.objects.all()[:100]
student_info = [] student_info = []
#TODO: Only select students who are in the course #TODO: Only select students who are in the course
for student in student_objects: for student in student_objects:
student_info.append({ student_info.append({
'username': student.username, 'username': student.username,
'id': student.id, 'id': student.id,
...@@ -104,10 +104,10 @@ def profile(request, course_id, student_id=None): ...@@ -104,10 +104,10 @@ def profile(request, course_id, student_id=None):
student_module_cache = StudentModuleCache.cache_for_descriptor_descendents(request.user, course) student_module_cache = StudentModuleCache.cache_for_descriptor_descendents(request.user, course)
course_module = get_module(request.user, request, course.location, student_module_cache) course_module = get_module(request.user, request, course.location, student_module_cache)
courseware_summary = grades.progress_summary(student, course_module, course.grader, student_module_cache) courseware_summary = grades.progress_summary(student, course_module, course.grader, student_module_cache)
grade_summary = grades.grade(request.user, request, course, student_module_cache) grade_summary = grades.grade(request.user, request, course, student_module_cache)
context = {'name': user_info.name, context = {'name': user_info.name,
'username': student.username, 'username': student.username,
'location': user_info.location, 'location': user_info.location,
...@@ -129,19 +129,14 @@ def render_accordion(request, course, chapter, section): ...@@ -129,19 +129,14 @@ def render_accordion(request, course, chapter, section):
If chapter and section are '' or None, renders a default accordion. If chapter and section are '' or None, renders a default accordion.
course, chapter, and section are the url_names.
Returns the html string''' Returns the html string'''
# grab the table of contents # grab the table of contents
toc = toc_for_course(request.user, request, course, chapter, section) toc = toc_for_course(request.user, request, course, chapter, section)
active_chapter = 1 context = dict([('toc', toc),
for i in range(len(toc)):
if toc[i]['active']:
active_chapter = i
context = dict([('active_chapter', active_chapter),
('toc', toc),
('course_name', course.title),
('course_id', course.id), ('course_id', course.id),
('csrf', csrf(request)['csrf_token'])] + template_imports.items()) ('csrf', csrf(request)['csrf_token'])] + template_imports.items())
return render_to_string('accordion.html', context) return render_to_string('accordion.html', context)
......
class @Navigation class @Navigation
constructor: -> constructor: ->
if $('#accordion').length if $('#accordion').length
# First look for an active section
active = $('#accordion ul:has(li.active)').index('#accordion ul') 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 $('#accordion').bind('accordionchange', @log).accordion
active: if active >= 0 then active else 1 active: active
header: 'h3' header: 'h3'
autoHeight: false autoHeight: false
$('#open_close_accordion a').click @toggle $('#open_close_accordion a').click @toggle
......
<%! from django.core.urlresolvers import reverse %> <%! from django.core.urlresolvers import reverse %>
<%def name="make_chapter(chapter)"> <%def name="make_chapter(chapter)">
<h3><a href="#">${chapter['display_name']}</a></h3> <h3 ${' class="active"' if 'active' in chapter and chapter['active'] else ''}><a href="#">${chapter['display_name']}</a>
</h3>
<ul> <ul>
% for section in chapter['sections']: % for section in chapter['sections']:
......
...@@ -15,7 +15,7 @@ urlpatterns = ('', ...@@ -15,7 +15,7 @@ urlpatterns = ('',
url(r'^dashboard$', 'student.views.dashboard', name="dashboard"), url(r'^dashboard$', 'student.views.dashboard', name="dashboard"),
url(r'^admin_dashboard$', 'dashboard.views.dashboard'), url(r'^admin_dashboard$', 'dashboard.views.dashboard'),
url(r'^change_email$', 'student.views.change_email_request'), url(r'^change_email$', 'student.views.change_email_request'),
url(r'^email_confirm/(?P<key>[^/]*)$', 'student.views.confirm_email_change'), url(r'^email_confirm/(?P<key>[^/]*)$', 'student.views.confirm_email_change'),
url(r'^change_name$', 'student.views.change_name_request'), url(r'^change_name$', 'student.views.change_name_request'),
...@@ -118,7 +118,7 @@ if settings.COURSEWARE_ENABLED: ...@@ -118,7 +118,7 @@ if settings.COURSEWARE_ENABLED:
#About the course #About the course
url(r'^courses/(?P<course_id>[^/]+/[^/]+/[^/]+)/about$', url(r'^courses/(?P<course_id>[^/]+/[^/]+/[^/]+)/about$',
'courseware.views.course_about', name="about_course"), 'courseware.views.course_about', name="about_course"),
#Inside the course #Inside the course
url(r'^courses/(?P<course_id>[^/]+/[^/]+/[^/]+)/info$', url(r'^courses/(?P<course_id>[^/]+/[^/]+/[^/]+)/info$',
'courseware.views.course_info', name="info"), 'courseware.views.course_info', name="info"),
...@@ -130,16 +130,18 @@ if settings.COURSEWARE_ENABLED: ...@@ -130,16 +130,18 @@ if settings.COURSEWARE_ENABLED:
'staticbook.views.index_shifted'), 'staticbook.views.index_shifted'),
url(r'^courses/(?P<course_id>[^/]+/[^/]+/[^/]+)/courseware/?$', url(r'^courses/(?P<course_id>[^/]+/[^/]+/[^/]+)/courseware/?$',
'courseware.views.index', name="courseware"), 'courseware.views.index', name="courseware"),
url(r'^courses/(?P<course_id>[^/]+/[^/]+/[^/]+)/courseware/(?P<chapter>[^/]*)/$',
'courseware.views.index', name="courseware_chapter"),
url(r'^courses/(?P<course_id>[^/]+/[^/]+/[^/]+)/courseware/(?P<chapter>[^/]*)/(?P<section>[^/]*)/$', url(r'^courses/(?P<course_id>[^/]+/[^/]+/[^/]+)/courseware/(?P<chapter>[^/]*)/(?P<section>[^/]*)/$',
'courseware.views.index', name="courseware_section"), 'courseware.views.index', name="courseware_section"),
url(r'^courses/(?P<course_id>[^/]+/[^/]+/[^/]+)/profile$', url(r'^courses/(?P<course_id>[^/]+/[^/]+/[^/]+)/profile$',
'courseware.views.profile', name="profile"), 'courseware.views.profile', name="profile"),
url(r'^courses/(?P<course_id>[^/]+/[^/]+/[^/]+)/profile/(?P<student_id>[^/]*)/$', url(r'^courses/(?P<course_id>[^/]+/[^/]+/[^/]+)/profile/(?P<student_id>[^/]*)/$',
'courseware.views.profile'), 'courseware.views.profile'),
# For the instructor # For the instructor
url(r'^courses/(?P<course_id>[^/]+/[^/]+/[^/]+)/gradebook$', url(r'^courses/(?P<course_id>[^/]+/[^/]+/[^/]+)/gradebook$',
'courseware.views.gradebook'), 'courseware.views.gradebook'),
) )
# Multicourse wiki # Multicourse wiki
......
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