diff --git a/common/lib/capa/capa/responsetypes.py b/common/lib/capa/capa/responsetypes.py
index 273b1a3f8f..d1b58e53a9 100644
--- a/common/lib/capa/capa/responsetypes.py
+++ b/common/lib/capa/capa/responsetypes.py
@@ -8,6 +8,7 @@ Used by capa_problem.py
'''
# standard library imports
+import cgi
import inspect
import json
import logging
@@ -725,7 +726,8 @@ class NumericalResponse(LoncapaResponse):
# I think this is just pyparsing.ParseException, calc.UndefinedVariable:
# But we'd need to confirm
except:
- raise StudentInputError('Invalid input -- please use a number only')
+ raise StudentInputError("Invalid input: could not parse '%s' as a number" %\
+ cgi.escape(student_answer))
if correct:
return CorrectMap(self.answer_id, 'correct')
@@ -1517,11 +1519,12 @@ class FormulaResponse(LoncapaResponse):
cs=self.case_sensitive)
except UndefinedVariable as uv:
log.debug('formularesponse: undefined variable in given=%s' % given)
- raise StudentInputError(uv.message + " not permitted in answer")
+ raise StudentInputError("Invalid input: " + uv.message + " not permitted in answer")
except Exception as err:
#traceback.print_exc()
log.debug('formularesponse: error %s in formula' % err)
- raise StudentInputError("Error in formula")
+ raise StudentInputError("Invalid input: Could not parse '%s' as a formula" %\
+ cgi.escape(given))
if numpy.isnan(student_result) or numpy.isinf(student_result):
return "incorrect"
if not compare_with_tolerance(student_result, instructor_result, self.tolerance):
diff --git a/common/lib/xmodule/xmodule/js/src/capa/display.coffee b/common/lib/xmodule/xmodule/js/src/capa/display.coffee
index ea5d939356..0ea6cffb58 100644
--- a/common/lib/xmodule/xmodule/js/src/capa/display.coffee
+++ b/common/lib/xmodule/xmodule/js/src/capa/display.coffee
@@ -192,8 +192,11 @@ class @Problem
if file_not_selected
errors.push 'You did not select any files to submit'
- if errors.length > 0
- alert errors.join("\n")
+ error_html = '
\n'
+ for error in errors
+ error_html += '- ' + error + '
\n'
+ error_html += '
'
+ @gentle_alert error_html
abort_submission = file_too_large or file_not_selected or unallowed_file_submitted or required_files_not_submitted
@@ -208,7 +211,7 @@ class @Problem
@render(response.contents)
@updateProgress response
else
- alert(response.success)
+ @gentle_alert response.success
if not abort_submission
$.ajaxWithPrefix("#{@url}/problem_check", settings)
@@ -220,8 +223,10 @@ class @Problem
when 'incorrect', 'correct'
@render(response.contents)
@updateProgress response
+ if @el.hasClass 'showed'
+ @el.removeClass 'showed'
else
- alert(response.success)
+ @gentle_alert response.success
reset: =>
Logger.log 'problem_reset', @answers
@@ -253,15 +258,19 @@ class @Problem
@el.removeClass 'showed'
@$('.show').val 'Show Answer'
+ gentle_alert: (msg) =>
+ if @el.find('.capa_alert').length
+ @el.find('.capa_alert').remove()
+ alert_elem = "" + msg + "
"
+ @el.find('.action').after(alert_elem)
+ @el.find('.capa_alert').animate(opacity: 0, 500).animate(opacity: 1, 500)
+
save: =>
Logger.log 'problem_save', @answers
$.postWithPrefix "#{@url}/problem_save", @answers, (response) =>
if response.success
- if @el.find('.save_message').length
- @el.find('.save_message').animate(opacity: 0, 500).animate(opacity: 1, 500)
- else
- saveMessage = "Your answers have been saved but not graded. Hit 'Check' to grade them.
"
- @el.find('.action').after(saveMessage)
+ saveMessage = "Your answers have been saved but not graded. Hit 'Check' to grade them."
+ @gentle_alert saveMessage
@updateProgress response
refreshMath: (event, element) =>
diff --git a/common/lib/xmodule/xmodule/js/src/sequence/display.coffee b/common/lib/xmodule/xmodule/js/src/sequence/display.coffee
index 35a33a9ea1..ab337d9b7e 100644
--- a/common/lib/xmodule/xmodule/js/src/sequence/display.coffee
+++ b/common/lib/xmodule/xmodule/js/src/sequence/display.coffee
@@ -2,6 +2,7 @@ class @Sequence
constructor: (element) ->
@el = $(element).find('.sequence')
@contents = @$('.seq_contents')
+ @num_contents = @contents.length
@id = @el.data('id')
@modx_url = @el.data('course_modx_root')
@initProgress()
@@ -90,18 +91,28 @@ class @Sequence
@toggleArrows()
@hookUpProgressEvent()
+ sequence_links = @$('#seq_content a.seqnav')
+ sequence_links.click @goto
+
goto: (event) =>
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
+ if $(event.target).hasClass 'seqnav' # Links from courseware ...
+ new_position = $(event.target).attr('href')
+ else # Tab links generated by backend template
+ new_position = $(event.target).data('element')
- @render new_position
+ if (1 <= new_position) and (new_position <= @num_contents)
+ 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
+ else
+ alert 'Sequence error! Cannot navigate to tab ' + new_position + 'in the current SequenceModule. Please contact the course staff.'
next: (event) =>
event.preventDefault()