Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
E
edx-platform
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
edx
edx-platform
Commits
b78fb8df
Commit
b78fb8df
authored
Nov 01, 2012
by
Victor Shnayder
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Refactored the rest of the input types
parent
3a099970
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
110 additions
and
130 deletions
+110
-130
common/lib/capa/capa/inputtypes.py
+93
-125
common/lib/capa/capa/templates/crystallography.html
+1
-1
common/lib/capa/capa/templates/vsepr_input.html
+1
-1
common/lib/capa/capa/tests/test_inputtypes.py
+15
-3
No files found.
common/lib/capa/capa/inputtypes.py
View file @
b78fb8df
...
@@ -21,12 +21,14 @@ Each input type takes the xml tree as 'element', the previous answer as 'value',
...
@@ -21,12 +21,14 @@ Each input type takes the xml tree as 'element', the previous answer as 'value',
graded status as'status'
graded status as'status'
"""
"""
# TODO: there is a lot of repetitive "grab these elements from xml attributes, with these defaults,
# TODO: make hints do something
# put them in the context" code. Refactor so class just specifies required and optional attrs (with
# defaults for latter), and InputTypeBase does the right thing.
# TODO: make all inputtypes actually render msg
# TODO: remove unused fields (e.g. 'hidden' in a few places)
# TODO: add validators so that content folks get better error messages.
# TODO: Quoting and unquoting is handled in a pretty ad-hoc way. Also something that could be done
# properly once in InputTypeBase.
# Possible todo: make inline the default for textlines and other "one-line" inputs. It probably
# Possible todo: make inline the default for textlines and other "one-line" inputs. It probably
# makes sense, but a bunch of problems have markup that assumes block. Bigger TODO: figure out a
# makes sense, but a bunch of problems have markup that assumes block. Bigger TODO: figure out a
...
@@ -39,7 +41,6 @@ from lxml import etree
...
@@ -39,7 +41,6 @@ from lxml import etree
import
re
import
re
import
shlex
# for splitting quoted strings
import
shlex
# for splitting quoted strings
import
sys
import
sys
import
xml.sax.saxutils
as
saxutils
from
registry
import
TagRegistry
from
registry
import
TagRegistry
...
@@ -535,13 +536,30 @@ class CodeInput(InputTypeBase):
...
@@ -535,13 +536,30 @@ class CodeInput(InputTypeBase):
# non-codemirror editor.
# non-codemirror editor.
]
]
# pulled out for testing
submitted_msg
=
(
"Your file(s) have been submitted; as soon as your submission is"
" graded, this message will be replaced with the grader's feedback."
)
def
setup
(
self
):
@classmethod
self
.
rows
=
self
.
xml
.
get
(
'rows'
)
or
'30'
def
get_attributes
(
cls
):
self
.
cols
=
self
.
xml
.
get
(
'cols'
)
or
'80'
"""
# if specified, then textline is hidden and id is stored in div of name given by hidden
Convert options to a convenient format.
self
.
hidden
=
self
.
xml
.
get
(
'hidden'
,
''
)
"""
return
[
Attribute
(
'rows'
,
'30'
),
Attribute
(
'cols'
,
'80'
),
Attribute
(
'hidden'
,
''
),
# For CodeMirror
Attribute
(
'mode'
,
'python'
),
Attribute
(
'linenumbers'
,
'true'
),
# Template expects tabsize to be an int it can do math with
Attribute
(
'tabsize'
,
4
,
transform
=
int
),
]
def
setup
(
self
):
"""
Implement special logic: handle queueing state, and default input.
"""
# if no student input yet, then use the default input given by the problem
# if no student input yet, then use the default input given by the problem
if
not
self
.
value
:
if
not
self
.
value
:
self
.
value
=
self
.
xml
.
text
self
.
value
=
self
.
xml
.
text
...
@@ -552,28 +570,11 @@ class CodeInput(InputTypeBase):
...
@@ -552,28 +570,11 @@ class CodeInput(InputTypeBase):
if
self
.
status
==
'incomplete'
:
if
self
.
status
==
'incomplete'
:
self
.
status
=
'queued'
self
.
status
=
'queued'
self
.
queue_len
=
self
.
msg
self
.
queue_len
=
self
.
msg
self
.
msg
=
'Submitted to grader.'
self
.
msg
=
self
.
submitted_msg
# For CodeMirror
self
.
mode
=
self
.
xml
.
get
(
'mode'
,
'python'
)
self
.
linenumbers
=
self
.
xml
.
get
(
'linenumbers'
,
'true'
)
self
.
tabsize
=
int
(
self
.
xml
.
get
(
'tabsize'
,
'4'
))
def
_get_render_context
(
self
):
def
_extra_context
(
self
):
"""Defined queue_len, add it """
context
=
{
'id'
:
self
.
id
,
return
{
'queue_len'
:
self
.
queue_len
,}
'value'
:
self
.
value
,
'status'
:
self
.
status
,
'msg'
:
self
.
msg
,
'mode'
:
self
.
mode
,
'linenumbers'
:
self
.
linenumbers
,
'rows'
:
self
.
rows
,
'cols'
:
self
.
cols
,
'hidden'
:
self
.
hidden
,
'tabsize'
:
self
.
tabsize
,
'queue_len'
:
self
.
queue_len
,
}
return
context
registry
.
register
(
CodeInput
)
registry
.
register
(
CodeInput
)
...
@@ -586,26 +587,19 @@ class Schematic(InputTypeBase):
...
@@ -586,26 +587,19 @@ class Schematic(InputTypeBase):
template
=
"schematicinput.html"
template
=
"schematicinput.html"
tags
=
[
'schematic'
]
tags
=
[
'schematic'
]
def
setup
(
self
):
@classmethod
self
.
height
=
self
.
xml
.
get
(
'height'
)
def
get_attributes
(
cls
):
self
.
width
=
self
.
xml
.
get
(
'width'
)
"""
self
.
parts
=
self
.
xml
.
get
(
'parts'
)
Convert options to a convenient format.
self
.
analyses
=
self
.
xml
.
get
(
'analyses'
)
"""
self
.
initial_value
=
self
.
xml
.
get
(
'initial_value'
)
return
[
self
.
submit_analyses
=
self
.
xml
.
get
(
'submit_analyses'
)
Attribute
(
'height'
,
None
),
Attribute
(
'width'
,
None
),
Attribute
(
'parts'
,
None
),
def
_get_render_context
(
self
):
Attribute
(
'analyses'
,
None
),
Attribute
(
'initial_value'
,
None
),
Attribute
(
'submit_analyses'
,
None
),]
context
=
{
'id'
:
self
.
id
,
'value'
:
self
.
value
,
'initial_value'
:
self
.
initial_value
,
'status'
:
self
.
status
,
'width'
:
self
.
width
,
'height'
:
self
.
height
,
'parts'
:
self
.
parts
,
'analyses'
:
self
.
analyses
,
'submit_analyses'
:
self
.
submit_analyses
,}
return
context
return
context
registry
.
register
(
Schematic
)
registry
.
register
(
Schematic
)
...
@@ -626,12 +620,20 @@ class ImageInput(InputTypeBase):
...
@@ -626,12 +620,20 @@ class ImageInput(InputTypeBase):
template
=
"imageinput.html"
template
=
"imageinput.html"
tags
=
[
'imageinput'
]
tags
=
[
'imageinput'
]
def
setup
(
self
):
@classmethod
self
.
src
=
self
.
xml
.
get
(
'src'
)
def
get_attributes
(
cls
):
self
.
height
=
self
.
xml
.
get
(
'height'
)
"""
self
.
width
=
self
.
xml
.
get
(
'width'
)
Note: src, height, and width are all required.
"""
return
[
Attribute
(
'src'
),
Attribute
(
'height'
),
Attribute
(
'width'
),]
# if value is of the form [x,y] then parse it and send along coordinates of previous answer
def
setup
(
self
):
"""
if value is of the form [x,y] then parse it and send along coordinates of previous answer
"""
m
=
re
.
match
(
'
\
[([0-9]+),([0-9]+)]'
,
self
.
value
.
strip
()
.
replace
(
' '
,
''
))
m
=
re
.
match
(
'
\
[([0-9]+),([0-9]+)]'
,
self
.
value
.
strip
()
.
replace
(
' '
,
''
))
if
m
:
if
m
:
# Note: we subtract 15 to compensate for the size of the dot on the screen.
# Note: we subtract 15 to compensate for the size of the dot on the screen.
...
@@ -641,19 +643,10 @@ class ImageInput(InputTypeBase):
...
@@ -641,19 +643,10 @@ class ImageInput(InputTypeBase):
(
self
.
gx
,
self
.
gy
)
=
(
0
,
0
)
(
self
.
gx
,
self
.
gy
)
=
(
0
,
0
)
def
_
get_render
_context
(
self
):
def
_
extra
_context
(
self
):
context
=
{
'id'
:
self
.
id
,
return
{
'gx'
:
self
.
gx
,
'value'
:
self
.
value
,
'gy'
:
self
.
gy
}
'height'
:
self
.
height
,
'width'
:
self
.
width
,
'src'
:
self
.
src
,
'gx'
:
self
.
gx
,
'gy'
:
self
.
gy
,
'status'
:
self
.
status
,
'msg'
:
self
.
msg
,
}
return
context
registry
.
register
(
ImageInput
)
registry
.
register
(
ImageInput
)
...
@@ -669,30 +662,18 @@ class Crystallography(InputTypeBase):
...
@@ -669,30 +662,18 @@ class Crystallography(InputTypeBase):
template
=
"crystallography.html"
template
=
"crystallography.html"
tags
=
[
'crystallography'
]
tags
=
[
'crystallography'
]
@classmethod
def
get_attributes
(
cls
):
"""
Note: height, width are required.
"""
return
[
Attribute
(
'size'
,
None
),
Attribute
(
'height'
),
Attribute
(
'width'
),
def
setup
(
self
):
# can probably be removed (textline should prob be always-hidden)
self
.
height
=
self
.
xml
.
get
(
'height'
)
Attribute
(
'hidden'
,
''
),
self
.
width
=
self
.
xml
.
get
(
'width'
)
]
self
.
size
=
self
.
xml
.
get
(
'size'
)
# if specified, then textline is hidden and id is stored in div of name given by hidden
self
.
hidden
=
self
.
xml
.
get
(
'hidden'
,
''
)
# Escape answers with quotes, so they don't crash the system!
escapedict
=
{
'"'
:
'"'
}
self
.
value
=
saxutils
.
escape
(
self
.
value
,
escapedict
)
def
_get_render_context
(
self
):
context
=
{
'id'
:
self
.
id
,
'value'
:
self
.
value
,
'status'
:
self
.
status
,
'size'
:
self
.
size
,
'msg'
:
self
.
msg
,
'hidden'
:
self
.
hidden
,
'width'
:
self
.
width
,
'height'
:
self
.
height
,
}
return
context
registry
.
register
(
Crystallography
)
registry
.
register
(
Crystallography
)
...
@@ -707,29 +688,16 @@ class VseprInput(InputTypeBase):
...
@@ -707,29 +688,16 @@ class VseprInput(InputTypeBase):
template
=
'vsepr_input.html'
template
=
'vsepr_input.html'
tags
=
[
'vsepr_input'
]
tags
=
[
'vsepr_input'
]
def
setup
(
self
):
@classmethod
self
.
height
=
self
.
xml
.
get
(
'height'
)
def
get_attributes
(
cls
):
self
.
width
=
self
.
xml
.
get
(
'width'
)
"""
Note: height, width are required.
# Escape answers with quotes, so they don't crash the system!
"""
escapedict
=
{
'"'
:
'"'
}
return
[
Attribute
(
'height'
),
self
.
value
=
saxutils
.
escape
(
self
.
value
,
escapedict
)
Attribute
(
'width'
),
Attribute
(
'molecules'
),
self
.
molecules
=
self
.
xml
.
get
(
'molecules'
)
Attribute
(
'geometries'
),
self
.
geometries
=
self
.
xml
.
get
(
'geometries'
)
]
def
_get_render_context
(
self
):
context
=
{
'id'
:
self
.
id
,
'value'
:
self
.
value
,
'status'
:
self
.
status
,
'msg'
:
self
.
msg
,
'width'
:
self
.
width
,
'height'
:
self
.
height
,
'molecules'
:
self
.
molecules
,
'geometries'
:
self
.
geometries
,
}
return
context
registry
.
register
(
VseprInput
)
registry
.
register
(
VseprInput
)
...
@@ -750,17 +718,17 @@ class ChemicalEquationInput(InputTypeBase):
...
@@ -750,17 +718,17 @@ class ChemicalEquationInput(InputTypeBase):
template
=
"chemicalequationinput.html"
template
=
"chemicalequationinput.html"
tags
=
[
'chemicalequationinput'
]
tags
=
[
'chemicalequationinput'
]
def
setup
(
self
):
@classmethod
self
.
size
=
self
.
xml
.
get
(
'size'
,
'20'
)
def
get_attributes
(
cls
):
"""
Can set size of text field.
"""
return
[
Attribute
(
'size'
,
'20'
),]
def
_get_render_context
(
self
):
def
_extra_context
(
self
):
context
=
{
"""
'id'
:
self
.
id
,
TODO (vshnayder): Get rid of this once we have a standard way of requiring js to be loaded.
'value'
:
self
.
value
,
"""
'status'
:
self
.
status
,
return
{
'previewer'
:
'/static/js/capa/chemical_equation_preview.js'
,}
'size'
:
self
.
size
,
'previewer'
:
'/static/js/capa/chemical_equation_preview.js'
,
}
return
context
registry
.
register
(
ChemicalEquationInput
)
registry
.
register
(
ChemicalEquationInput
)
common/lib/capa/capa/templates/crystallography.html
View file @
b78fb8df
...
@@ -19,7 +19,7 @@
...
@@ -19,7 +19,7 @@
<div
style=
"display:none;"
name=
"${hidden}"
inputid=
"input_${id}"
/>
<div
style=
"display:none;"
name=
"${hidden}"
inputid=
"input_${id}"
/>
% endif
% endif
<input
type=
"text"
name=
"input_${id}"
id=
"input_${id}"
value=
"${value}"
<input
type=
"text"
name=
"input_${id}"
id=
"input_${id}"
value=
"${value
|h
}"
%
if
size:
%
if
size:
size=
"${size}"
size=
"${size}"
%
endif
%
endif
...
...
common/lib/capa/capa/templates/vsepr_input.html
View file @
b78fb8df
...
@@ -21,7 +21,7 @@
...
@@ -21,7 +21,7 @@
<div
class=
"incorrect"
id=
"status_${id}"
>
<div
class=
"incorrect"
id=
"status_${id}"
>
% endif
% endif
<input
type=
"text"
name=
"input_${id}"
id=
"input_${id}"
value=
"${value}"
<input
type=
"text"
name=
"input_${id}"
id=
"input_${id}"
value=
"${value
|h
}"
style=
"display:none;"
style=
"display:none;"
/>
/>
...
...
common/lib/capa/capa/tests/test_inputtypes.py
View file @
b78fb8df
...
@@ -2,9 +2,18 @@
...
@@ -2,9 +2,18 @@
Tests of input types.
Tests of input types.
TODO:
TODO:
- refactor: so much repetive code (have factory methods that build xml elements directly, etc)
- test error cases
- check rendering -- e.g. msg should appear in the rendered output. If possible, test that
templates are escaping things properly.
- test unicode in values, parameters, etc.
- test unicode in values, parameters, etc.
- test various html escapes
- test various html escapes
- test funny xml chars -- should never get xml parse error if things are escaped properly.
- test funny xml chars -- should never get xml parse error if things are escaped properly.
"""
"""
from
lxml
import
etree
from
lxml
import
etree
...
@@ -267,14 +276,15 @@ class CodeInputTest(unittest.TestCase):
...
@@ -267,14 +276,15 @@ class CodeInputTest(unittest.TestCase):
'status'
:
'incomplete'
,
'status'
:
'incomplete'
,
'feedback'
:
{
'message'
:
'3'
},
}
'feedback'
:
{
'message'
:
'3'
},
}
the_input
=
lookup_tag
(
'codeinput'
)(
test_system
,
element
,
state
)
input_class
=
lookup_tag
(
'codeinput'
)
the_input
=
input_class
(
test_system
,
element
,
state
)
context
=
the_input
.
_get_render_context
()
context
=
the_input
.
_get_render_context
()
expected
=
{
'id'
:
'prob_1_2'
,
expected
=
{
'id'
:
'prob_1_2'
,
'value'
:
'print "good evening"'
,
'value'
:
'print "good evening"'
,
'status'
:
'queued'
,
'status'
:
'queued'
,
'msg'
:
'Submitted to grader.'
,
'msg'
:
input_class
.
submitted_msg
,
'mode'
:
mode
,
'mode'
:
mode
,
'linenumbers'
:
linenumbers
,
'linenumbers'
:
linenumbers
,
'rows'
:
rows
,
'rows'
:
rows
,
...
@@ -323,8 +333,9 @@ class SchematicTest(unittest.TestCase):
...
@@ -323,8 +333,9 @@ class SchematicTest(unittest.TestCase):
expected
=
{
'id'
:
'prob_1_2'
,
expected
=
{
'id'
:
'prob_1_2'
,
'value'
:
value
,
'value'
:
value
,
'initial_value'
:
initial_value
,
'status'
:
'unsubmitted'
,
'status'
:
'unsubmitted'
,
'msg'
:
''
,
'initial_value'
:
initial_value
,
'width'
:
width
,
'width'
:
width
,
'height'
:
height
,
'height'
:
height
,
'parts'
:
parts
,
'parts'
:
parts
,
...
@@ -488,6 +499,7 @@ class ChemicalEquationTest(unittest.TestCase):
...
@@ -488,6 +499,7 @@ class ChemicalEquationTest(unittest.TestCase):
expected
=
{
'id'
:
'prob_1_2'
,
expected
=
{
'id'
:
'prob_1_2'
,
'value'
:
'H2OYeah'
,
'value'
:
'H2OYeah'
,
'status'
:
'unanswered'
,
'status'
:
'unanswered'
,
'msg'
:
''
,
'size'
:
size
,
'size'
:
size
,
'previewer'
:
'/static/js/capa/chemical_equation_preview.js'
,
'previewer'
:
'/static/js/capa/chemical_equation_preview.js'
,
}
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment