Merge pull request #385 from MITx/kimth/lms-coderesponse
Kimth/lms coderesponse
This commit is contained in:
@@ -307,7 +307,18 @@ def filesubmission(element, value, status, render_template, msg=''):
|
||||
Upload a single file (e.g. for programming assignments)
|
||||
'''
|
||||
eid = element.get('id')
|
||||
context = { 'id': eid, 'state': status, 'msg': msg, 'value': value, }
|
||||
|
||||
# Check if problem has been queued
|
||||
queued = ''
|
||||
queue_len = 0
|
||||
if status == 'incomplete': # Flag indicating that the problem has been queued, 'msg' is length of queue
|
||||
queued = 'true'
|
||||
queue_len = msg
|
||||
msg = 'Submitted to grader. (Queue length: %s)' % queue_len
|
||||
|
||||
context = { 'id': eid, 'state': status, 'msg': msg, 'value': value,
|
||||
'queued': queued, 'queue_len': queue_len
|
||||
}
|
||||
html = render_template("filesubmission.html", context)
|
||||
return etree.XML(html)
|
||||
|
||||
@@ -329,10 +340,18 @@ def textbox(element, value, status, render_template, msg=''):
|
||||
hidden = element.get('hidden', '') # if specified, then textline is hidden and id is stored in div of name given by hidden
|
||||
|
||||
if not value: value = element.text # if no student input yet, then use the default input given by the problem
|
||||
|
||||
# Check if problem has been queued
|
||||
queued = ''
|
||||
queue_len = 0
|
||||
if status == 'incomplete': # Flag indicating that the problem has been queued, 'msg' is length of queue
|
||||
queued = 'true'
|
||||
queue_len = msg
|
||||
msg = 'Submitted to grader. (Queue length: %s)' % queue_len
|
||||
|
||||
# For CodeMirror
|
||||
mode = element.get('mode') or 'python' # mode, eg "python" or "xml"
|
||||
linenumbers = element.get('linenumbers','true') # for CodeMirror
|
||||
mode = element.get('mode','python')
|
||||
linenumbers = element.get('linenumbers','true')
|
||||
tabsize = element.get('tabsize','4')
|
||||
tabsize = int(tabsize)
|
||||
|
||||
@@ -340,6 +359,7 @@ def textbox(element, value, status, render_template, msg=''):
|
||||
'mode': mode, 'linenumbers': linenumbers,
|
||||
'rows': rows, 'cols': cols,
|
||||
'hidden': hidden, 'tabsize': tabsize,
|
||||
'queued': queued, 'queue_len': queue_len,
|
||||
}
|
||||
html = render_template("textbox.html", context)
|
||||
try:
|
||||
|
||||
@@ -898,7 +898,7 @@ class CodeResponse(LoncapaResponse):
|
||||
'processor': self.code,
|
||||
}
|
||||
|
||||
# Submit request
|
||||
# Submit request. When successful, 'msg' is the prior length of the queue
|
||||
if is_file(submission):
|
||||
contents.update({'edX_student_response': submission.name})
|
||||
(error, msg) = qinterface.send_to_queue(header=xheader,
|
||||
@@ -914,8 +914,11 @@ class CodeResponse(LoncapaResponse):
|
||||
cmap.set(self.answer_id, queuekey=None,
|
||||
msg='Unable to deliver your submission to grader. (Reason: %s.) Please try again later.' % msg)
|
||||
else:
|
||||
# Non-null CorrectMap['queuekey'] indicates that the problem has been queued
|
||||
cmap.set(self.answer_id, queuekey=queuekey, msg='Submitted to grader. (Queue length: %s)' % msg)
|
||||
# Queueing mechanism flags:
|
||||
# 1) Backend: Non-null CorrectMap['queuekey'] indicates that the problem has been queued
|
||||
# 2) Frontend: correctness='incomplete' eventually trickles down through inputtypes.textbox
|
||||
# and .filesubmission to inform the browser to poll the LMS
|
||||
cmap.set(self.answer_id, queuekey=queuekey, correctness='incomplete', msg=msg)
|
||||
|
||||
return cmap
|
||||
|
||||
|
||||
@@ -9,6 +9,9 @@
|
||||
% elif state == 'incomplete':
|
||||
<span class="incorrect" id="status_${id}"></span>
|
||||
% endif
|
||||
% if queued:
|
||||
<span class="xqueue" id="${id}" >${queue_len}</span>
|
||||
% endif
|
||||
<span class="debug">(${state})</span>
|
||||
<br/>
|
||||
<span class="message">${msg|n}</span>
|
||||
|
||||
@@ -19,6 +19,9 @@
|
||||
% if hidden:
|
||||
<div style="display:none;" name="${hidden}" inputid="input_${id}" />
|
||||
% endif
|
||||
% if queued:
|
||||
<span class="xqueue" id="${id}" >${queue_len}</span>
|
||||
% endif
|
||||
<br/>
|
||||
<span class="debug">(${state})</span>
|
||||
<br/>
|
||||
|
||||
@@ -49,6 +49,8 @@ padding-left: flex-gutter(9);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
div {
|
||||
p.status {
|
||||
text-indent: -9999px;
|
||||
@@ -64,6 +66,16 @@ div {
|
||||
}
|
||||
}
|
||||
|
||||
&.processing {
|
||||
p.status {
|
||||
@include inline-block();
|
||||
background: url('../images/spinner.gif') center center no-repeat;
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
text-indent: -9999px;
|
||||
}
|
||||
}
|
||||
|
||||
&.correct, &.ui-icon-check {
|
||||
p.status {
|
||||
@include inline-block();
|
||||
@@ -134,6 +146,15 @@ div {
|
||||
width: 14px;
|
||||
}
|
||||
|
||||
&.processing, &.ui-icon-check {
|
||||
@include inline-block();
|
||||
background: url('../images/spinner.gif') center center no-repeat;
|
||||
height: 20px;
|
||||
position: relative;
|
||||
top: 6px;
|
||||
width: 25px;
|
||||
}
|
||||
|
||||
&.correct, &.ui-icon-check {
|
||||
@include inline-block();
|
||||
background: url('../images/correct-icon.png') center center no-repeat;
|
||||
|
||||
@@ -12,7 +12,10 @@ class @Problem
|
||||
bind: =>
|
||||
MathJax.Hub.Queue ["Typeset", MathJax.Hub]
|
||||
window.update_schematics()
|
||||
@inputs = @$("[id^=input_#{@element_id.replace(/problem_/, '')}_]")
|
||||
|
||||
problem_prefix = @element_id.replace(/problem_/,'')
|
||||
@inputs = @$("[id^=input_#{problem_prefix}_]")
|
||||
|
||||
@$('section.action input:button').click @refreshAnswers
|
||||
@$('section.action input.check').click @check_fd
|
||||
#@$('section.action input.check').click @check
|
||||
@@ -26,15 +29,37 @@ class @Problem
|
||||
@el.attr progress: response.progress_status
|
||||
@el.trigger('progressChanged')
|
||||
|
||||
queueing: =>
|
||||
@queued_items = @$(".xqueue")
|
||||
if @queued_items.length > 0
|
||||
if window.queuePollerID # Only one poller 'thread' per Problem
|
||||
window.clearTimeout(window.queuePollerID)
|
||||
window.queuePollerID = window.setTimeout(@poll, 100)
|
||||
|
||||
poll: =>
|
||||
$.postWithPrefix "#{@url}/problem_get", (response) =>
|
||||
@el.html(response.html)
|
||||
@executeProblemScripts()
|
||||
@bind()
|
||||
|
||||
@queued_items = @$(".xqueue")
|
||||
if @queued_items.length == 0
|
||||
delete window.queuePollerID
|
||||
else
|
||||
# TODO: Dynamically adjust timeout interval based on @queued_items.value
|
||||
window.queuePollerID = window.setTimeout(@poll, 1000)
|
||||
|
||||
render: (content) ->
|
||||
if content
|
||||
@el.html(content)
|
||||
@bind()
|
||||
@queueing()
|
||||
else
|
||||
$.postWithPrefix "#{@url}/problem_get", (response) =>
|
||||
@el.html(response.html)
|
||||
@executeProblemScripts()
|
||||
@bind()
|
||||
@queueing()
|
||||
|
||||
executeProblemScripts: ->
|
||||
@el.find(".script_placeholder").each (index, placeholder) ->
|
||||
|
||||
@@ -91,6 +91,13 @@ class @Sequence
|
||||
event.preventDefault()
|
||||
new_position = $(event.target).data('element')
|
||||
Logger.log "seq_goto", old: @position, new: new_position, id: @id
|
||||
|
||||
# On Sequence chage, destroy any existing polling thread
|
||||
# for queued submissions, see ../capa/display.coffee
|
||||
if window.queuePollerID
|
||||
window.clearTimeout(window.queuePollerID)
|
||||
delete window.queuePollerID
|
||||
|
||||
@render new_position
|
||||
|
||||
next: (event) =>
|
||||
|
||||
BIN
common/static/images/spinner.gif
Normal file
BIN
common/static/images/spinner.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.8 KiB |
Reference in New Issue
Block a user