diff --git a/courseware/capa_module.py b/courseware/capa_module.py index f841e764e4..c1a19229d1 100644 --- a/courseware/capa_module.py +++ b/courseware/capa_module.py @@ -34,8 +34,16 @@ class LoncapaModule(XModule): html = self.lcp.get_html() content={'name':self.name, 'html':html} + closed = False + if self.lcp.done: + check_button="Reset" + else: + check_button="Check" html=render_to_string('problem.html', - {'problem':content, 'id':self.filename, 'done':self.lcp.done}) + {'problem':content, + 'id':self.filename, + 'check_button':check_button, + }) if encapsulate: html = '
'.format(id=self.item_id)+html+"
" return html diff --git a/courseware/models.py b/courseware/models.py index c3da838f0e..ea40eb42c2 100644 --- a/courseware/models.py +++ b/courseware/models.py @@ -44,7 +44,10 @@ class StudentModule(models.Model): state = models.TextField(null=True, blank=True) grade = models.FloatField(null=True, blank=True) student = models.ForeignKey(User) - MODULE_TYPES = (('problem','problem'),) + MODULE_TYPES = (('problem','problem'), + ('video','video'), + ('html','html'), + ) module_type = models.CharField(max_length=32, choices=MODULE_TYPES, default='problem') module_id = models.CharField(max_length=255) # Filename for homeworks, etc. created = models.DateTimeField(auto_now_add=True) diff --git a/courseware/static/js/video_player.js b/courseware/static/js/video_player.js index 299b18ecd7..7c1da780ce 100644 --- a/courseware/static/js/video_player.js +++ b/courseware/static/js/video_player.js @@ -1,4 +1,4 @@ -var load_id; +var load_id = 0; function caption_at(index) { if (captions==0) @@ -74,15 +74,20 @@ function setytplayerState(newState) { // updateHTML("playerstate", newState); } +// Updates server with location in video so we can resume from the same place +// IMPORTANT TODO: Load test +// POSSIBLE FIX: Move to unload() event and similar +var ajax_video=function(){}; + function onYouTubePlayerReady(playerId) { ytplayer = document.getElementById("myytplayer"); setInterval(updateytplayerInfo, 1000); + setInterval(ajax_video,1000); ytplayer.addEventListener("onStateChange", "onytplayerStateChange"); ytplayer.addEventListener("onError", "onPlayerError"); - if((typeof load_id != "undefined") && (load_id != null)) { + if((typeof load_id != "undefined") && (load_id != 0)) { var id=load_id; - load_id = null; - loadNewVideo(id); + loadNewVideo(id, 0); } } @@ -151,16 +156,20 @@ function updateytplayerInfo() { // functions for the api calls function loadNewVideo(id, startSeconds) { - if (typeof ytplayer != "undefined") { - ytplayer.loadVideoById(id, parseInt(startSeconds)); - } else { - load_id = id; - } - $.getJSON("/static/subs/"+id+".srt.sjson", function(data) { captions=data; }); - + load_id = id; + //if ((typeof ytplayer != "undefined") && (ytplayer.type=="application/x-shockwave-flash")) { + // Try it every time. If we fail, we want the error message for now. + // TODO: Add try/catch + try { + ytplayer.loadVideoById(id, parseInt(startSeconds)); + load_id=0; + } + catch(e) { + window['console'].log(JSON.stringify(e)); + } } function cueNewVideo(id, startSeconds) { diff --git a/courseware/views.py b/courseware/views.py index 7fbab1cedc..f69fe5bcb7 100644 --- a/courseware/views.py +++ b/courseware/views.py @@ -98,6 +98,7 @@ def render_accordion(request,course,chapter,section): def video_mod(request, module): ''' Shows a video, with subtitles. + OBSOLETE. Remove once x_module version confirmed ''' id=module.getAttribute('youtube') return {'js':render_to_string('video_init.js',{'id':id}), @@ -145,14 +146,14 @@ def seq_module(request, module): contents=[(e.getAttribute("name"),j(render_module(request, e))) \ for e in module.childNodes \ if e.nodeType==1] - + js="".join([e[1]['js'] for e in contents if 'js' in e[1]]) return {'js':js+render_to_string('seq_module.js',{'items':contents}), 'content':render_to_string('seq_module.html',{'items':contents})} -modx_modules={'problem':capa_module.LoncapaModule}#, 'video1':video_module.VideoModule} +modx_modules={'problem':capa_module.LoncapaModule, 'video':video_module.VideoModule} def render_x_module(request, xml_module): ''' Generic module for extensions. This renders to HTML. ''' @@ -160,28 +161,36 @@ def render_x_module(request, xml_module): module_type=xml_module.nodeName module_class=modx_modules[module_type] module_id=xml_module.getAttribute(module_class.id_attribute) - s = StudentModule.objects.filter(student=request.user, module_id=module_id) + + # Grab state from database + s = StudentModule.objects.filter(student=request.user, + module_id=module_id, + module_type = module_type) + if len(s) == 0: # If nothing in the database... + state=None + else: + smod = s[0] + state = smod.state + + # Create a new instance + instance=module_class(xml_module.toxml(), + module_id, + state=state) + + # If instance wasn't already in the database, create it if len(s) == 0: - # If not, create one, and save it - instance=module_class(xml_module.toxml(), module_id) smod=StudentModule(student=request.user, + module_type = module_type, module_id=module_id, state=instance.get_state(), xml=instance.xml) - smod.save() - elif len(s) == 1: - # If so, render it - s=s[0] - instance=module_class(xml_module.toxml(), - module_id, - state=s.state) - s.state=instance.get_state() - s.save() - else: - raise Exception("Database is inconsistent (1).") + # Grab content + content = {'content':instance.get_html(), + 'js':instance.get_js()} - return {'content':instance.get_html(), - 'js':instance.get_js()} + smod.save() # This may be optional (at least in the case of no instance in the dB) + + return content def modx_dispatch(request, module=None, dispatch=None, id=None): ''' Generic module for extensions. This handles AJAX. ''' @@ -199,12 +208,13 @@ def modx_dispatch(request, module=None, dispatch=None, id=None): s.save() return HttpResponse(html) -module_types={'video':video_mod, +module_types={'video':render_x_module, 'html':html_module, 'tab':tab_module, 'vertical':vertical_module, 'sequential':seq_module, - 'problem':render_x_module} + 'problem':render_x_module, + } #'lab':lab_module, def render_module(request, module):