JSinput input type

This commit is contained in:
Julian Arni
2013-05-15 14:05:31 -04:00
parent 343d9019e0
commit e08215e62a
9 changed files with 453 additions and 1 deletions

View File

@@ -451,6 +451,68 @@ class JavascriptInput(InputTypeBase):
registry.register(JavascriptInput)
#-----------------------------------------------------------------------------
class JSInput(InputTypeBase):
"""
DO NOT USE! HAS NOT BEEN TESTED BEYOND 700X PROBLEMS, AND MAY CHANGE IN
BACKWARDS-INCOMPATIBLE WAYS.
Inputtype for general javascript inputs. Intended to be used with
customresponse.
Loads in a sandboxed iframe to help prevent css and js conflicts between
frame and top-level window.
iframe sandbox whitelist:
- allow-scripts
- allow-popups
- allow-forms
- allow-pointer-lock
This in turn means that the iframe cannot directly access the top-level
window elements.
Example:
<jsinput html_file="/static/test.html"
gradefn="grade"
height="500"
width="400"/>
See the documentation in the /doc/public folder for more information.
"""
template = "jsinput.html"
tags = ['jsinput']
@classmethod
def get_attributes(cls):
"""
Register the attributes.
"""
return [Attribute('params', None), # extra iframe params
Attribute('html_file', None),
Attribute('gradefn', "gradefn"),
Attribute('get_statefn', None), # Function to call in iframe
# to get current state.
Attribute('set_statefn', None), # Function to call iframe to
# set state
Attribute('width', "400"), # iframe width
Attribute('height', "300")] # iframe height
def _extra_context(self):
context = {
'applet_loader': '/static/js/capa/jsinput.js',
'saved_state': self.value
}
return context
registry.register(JSInput)
#-----------------------------------------------------------------------------
class TextLine(InputTypeBase):

View File

@@ -929,7 +929,7 @@ class CustomResponse(LoncapaResponse):
'chemicalequationinput', 'vsepr_input',
'drag_and_drop_input', 'editamoleculeinput',
'designprotein2dinput', 'editageneinput',
'annotationinput']
'annotationinput', 'jsinput']
def setup_response(self):
xml = self.xml

View File

@@ -0,0 +1,64 @@
<section id="inputtype_${id}" class="jsinput"
data="${gradefn}"
% if saved_state:
data-stored="${saved_state|x}"
% endif
% if get_statefn:
data-getstate="${get_statefn}"
% endif
% if set_statefn:
data-setstate="${set_statefn}"
% endif
>
<div class="script_placeholder" data-src="${applet_loader}"/>
% if status == 'unsubmitted':
<div class="unanswered" id="status_${id}">
% elif status == 'correct':
<div class="correct" id="status_${id}">
% elif status == 'incorrect':
<div class="incorrect" id="status_${id}">
% elif status == 'incomplete':
<div class="incorrect" id="status_${id}">
% endif
<iframe name="iframe_${id}"
id="iframe_${id}"
sandbox="allow-scripts allow-popups allow-same-origin allow-forms allow-pointer-lock"
seamless="seamless"
frameborder="0"
src="${html_file}"
height="${height}"
width="${width}"
/>
<input type="hidden" name="input_${id}" id="input_${id}"
waitfor=""
value="${value|h}"/>
<br/>
<p id="answer_${id}" class="answer"></p>
<p class="status">
% if status == 'unsubmitted':
unanswered
% elif status == 'correct':
correct
% elif status == 'incorrect':
incorrect
% elif status == 'incomplete':
incomplete
% endif
</p>
<br/> <br/>
<div class="error_message" style="padding: 5px 5px 5px 5px; background-color:#FA6666; height:60px;width:400px; display: none"></div>
% if status in ['unsubmitted', 'correct', 'incorrect', 'incomplete']:
</div>
% endif
% if msg:
<span class="message">${msg|n}</span>
% endif
</section>

View File

@@ -140,6 +140,11 @@ class @Problem
check_fd: =>
Logger.log 'problem_check', @answers
# If some function wants to be called before sending the answer to the
# server, give it a chance to do so.
if $('input[waitfor]').length != 0
($(lcall).data("waitfor").call() for lcall in $('input[waitfor]'))
@refreshAnswers()
# If there are no file inputs in the problem, we can fall back on @check
if $('input:file').length == 0
@check()