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
fd6abc88
Commit
fd6abc88
authored
Jul 08, 2013
by
Julian Arni
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Incorporate review comments
parent
7fbd1a72
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
185 additions
and
207 deletions
+185
-207
common/lib/capa/capa/inputtypes.py
+1
-1
common/static/js/capa/spec/jsinput/jsinput.js
+30
-31
common/static/js/capa/spec/jsinput/mainfixture.html
+113
-98
common/static/js/capa/src/jsinput.js
+41
-77
No files found.
common/lib/capa/capa/inputtypes.py
View file @
fd6abc88
...
@@ -504,7 +504,7 @@ class JSInput(InputTypeBase):
...
@@ -504,7 +504,7 @@ class JSInput(InputTypeBase):
def
_extra_context
(
self
):
def
_extra_context
(
self
):
context
=
{
context
=
{
'applet_loader'
:
'/static/js/capa/jsinput.js'
,
'applet_loader'
:
'/static/js/capa/
src/
jsinput.js'
,
'saved_state'
:
self
.
value
'saved_state'
:
self
.
value
}
}
...
...
common/static/js/capa/spec/jsinput/jsinput.js
View file @
fd6abc88
...
@@ -11,38 +11,15 @@ describe("A jsinput has:", function () {
...
@@ -11,38 +11,15 @@ describe("A jsinput has:", function () {
});
});
});
});
describe
(
"The ctxCall function"
,
function
()
{
it
(
"Evaluatates nested-object functions"
,
function
()
{
var
ctxTest
=
{
ctxFn
:
function
()
{
return
this
.
name
;
}
};
var
fnString
=
"nest.ctxFn"
;
var
holder
=
{};
holder
.
nest
=
ctxTest
;
var
fn
=
_ctxCall
(
holder
,
fnString
);
expect
(
fnString
).
toBe
(
holder
.
nest
.
ctxFn
());
});
it
(
"Throws an exception when the object does not exits"
,
function
()
{
var
notObj
=
_ctxCall
(
"twas"
,
"brilling"
);
expect
(
notObj
).
toThrow
();
});
it
(
"Throws an exception when the function does not exist"
,
function
()
{
var
anobj
=
{};
var
notFn
=
_ctxCall
(
"anobj"
,
"brillig"
);
expect
(
notFn
).
toThrow
();
});
describe
(
"The jsinput constructor"
,
function
(){
})
;
var
iframe1
=
$
(
document
).
find
(
'iframe'
)[
0
]
;
describe
(
"The jsinput constructor"
,
function
(){
var
testJsElem
=
jsinputConstructor
({
var
testJsElem
=
jsinputConstructor
({
id
:
378
1
,
id
:
1
,
elem
:
"<div id='abc'> a div </div>"
,
elem
:
iframe1
,
passive
:
false
passive
:
false
});
});
...
@@ -51,7 +28,7 @@ describe("A jsinput has:", function () {
...
@@ -51,7 +28,7 @@ describe("A jsinput has:", function () {
});
});
it
(
"Adds the object to the jsinput array"
,
function
()
{
it
(
"Adds the object to the jsinput array"
,
function
()
{
expect
(
jsinput
.
jsinputarr
.
exists
(
378
1
)).
toBe
(
true
);
expect
(
jsinput
.
exists
(
1
)).
toBe
(
true
);
});
});
describe
(
"The returned object"
,
function
()
{
describe
(
"The returned object"
,
function
()
{
...
@@ -60,12 +37,34 @@ describe("A jsinput has:", function () {
...
@@ -60,12 +37,34 @@ describe("A jsinput has:", function () {
expect
(
testJsElem
.
update
).
toBeDefined
();
expect
(
testJsElem
.
update
).
toBeDefined
();
});
});
it
(
"Returns an 'update' that is idempotent"
,
function
(){
var
orig
=
testJsElem
.
update
();
for
(
var
i
=
0
;
i
++
;
i
<
5
)
{
expect
(
testJsElem
.
update
()).
toEqual
(
orig
);
}
});
it
(
"Changes the parent's inputfield"
,
function
()
{
it
(
"Changes the parent's inputfield"
,
function
()
{
testJsElem
.
update
();
})
});
});
});
describe
(
"The walkDOM functions"
,
function
()
{
walkDOM
();
it
(
"Creates (at least) one object per iframe"
,
function
()
{
jsinput
.
arr
.
length
>=
2
;
});
});
it
(
"Does not create multiple objects with the same id"
,
function
()
{
while
(
jsinput
.
arr
.
length
>
0
)
{
var
elem
=
jsinput
.
arr
.
pop
();
expect
(
jsinput
.
exists
(
elem
.
id
)).
toBe
(
false
);
}
});
});
});
}
})
)
common/static/js/capa/spec/jsinput/mainfixture.html
View file @
fd6abc88
...
@@ -2,102 +2,117 @@
...
@@ -2,102 +2,117 @@
<head>
<head>
<title>
JSinput jasmine test
</title>
<title>
JSinput jasmine test
</title>
</head>
</head>
<body>
<body>
<section
id=
"inputtype_1"
data=
"gradefn"
class=
"jsinput"
>
<section
id=
"inputtype_1"
data=
"gradefn"
<div
class=
"script_placeholder"
data-src=
"${applet_loader}"
/>
data-setstate=
"setinput"
<iframe
name=
"iframe_1"
class=
"jsinput"
>
sandbox=
"allow-scripts allow-popups allow-same-origin allow-forms allow-pointer-lock"
seamless=
"seamless"
<div
class=
"script_placeholder"
/>
height=
"500"
<iframe
name=
"iframe_1"
width=
"500"
>
<html>
sandbox=
"allow-scripts
<head>
allow-popups
<title>
allow-same-origin
JS input test
allow-forms
</title>
allow-pointer-lock"
<script
type=
"text/javascript"
>
seamless=
"seamless"
function
gradefn
()
{
height=
"500"
var
ans
=
document
.
getElementById
(
"one"
).
value
;
width=
"500"
>
console
.
log
(
"I've been called!"
);
<html>
return
ans
<head>
}
<title>
</script>
JS input test 1
</head>
</title>
<body>
<script
type=
"text/javascript"
>
function
gradefn
()
{
<p>
Simple js input test. Defines a js function that returns the value in the
var
ans
=
document
.
getElementById
(
"one"
).
value
;
input field below when called.
</p>
console
.
log
(
"I've been called!"
);
return
ans
<form>
}
<input
id=
'one'
type=
"TEXT"
/>
</form>
function
setinput
(
val
)
{
document
.
getElementById
(
"one"
).
value
(
val
);
</body>
return
;
</html>
}
</script>
</iframe>
</head>
<input
type=
"hidden"
name=
"input_1"
id=
"input_1"
value=
"${value|h}"
/>
<body>
<br/>
<p>
Simple js input test. Defines a js function that returns the value in
<button
id=
"update_1"
class=
"update"
>
Update
</button>
the input field below when called.
</p>
<p
id=
"answer_1"
class=
"answer"
></p>
<form>
<p
class=
"status"
>
<input
id=
'one'
type=
"TEXT"
/>
</p>
</form>
<br/>
<br/>
</body>
<div
class=
"error_message"
style=
"padding: 5px 5px 5px 5px; background-color:#FA6666; height:60px;width:400px; display: none"
></div>
</html>
</div>
</iframe>
</section>
<input
type=
"hidden"
name=
"input_1"
id=
"input_1"
value=
"${value|h}"
/>
<section
id=
"inputtype_2"
data=
"gradefn"
class=
"jsinput"
>
<br/>
<div
class=
"script_placeholder"
data-src=
"${applet_loader}"
/>
<button
id=
"update_1"
class=
"update"
>
Update
</button>
<iframe
name=
"iframe_2"
<p
id=
"answer_1"
class=
"answer"
></p>
sandbox=
"allow-scripts allow-popups allow-same-origin allow-forms allow-pointer-lock"
seamless=
"seamless"
<p
class=
"status"
>
height=
"500"
</p>
width=
"500"
>
<br/>
<br/>
<html>
<head>
<div
class=
"error_message"
></div>
<title>
JS input test
</section>
</title>
<section
id=
"inputtype_2"
data=
"gradefn"
class=
"jsinput"
>
<script
type=
"text/javascript"
>
function
gradefn
()
{
<div
class=
"script_placeholder"
/>
var
ans
=
document
.
getElementById
(
"one"
).
value
;
<iframe
name=
"iframe_2"
console
.
log
(
"I've been called!"
);
sandbox=
"allow-scripts
return
ans
allow-popups
}
allow-same-origin
</script>
allow-forms
</head>
allow-pointer-lock"
<body>
seamless=
"seamless"
height=
"500"
<p>
Simple js input test. Defines a js function that returns the value in the
width=
"500"
>
input field below when called.
</p>
<html>
<head>
<form>
<title>
<input
id=
'one'
type=
"TEXT"
/>
JS input test
</form>
</title>
<script
type=
"text/javascript"
>
</body>
function
gradefn
()
{
</html>
var
ans
=
document
.
getElementById
(
"one"
).
value
;
console
.
log
(
"I've been called!"
);
</iframe>
return
ans
<input
type=
"hidden"
name=
"input_2"
id=
"input_2"
value=
"${value|h}"
/>
}
</script>
<br/>
</head>
<button
id=
"update_2"
class=
"update"
>
Update
</button>
<body>
<p
id=
"answer_2"
class=
"answer"
></p>
<p>
Simple js input test. Defines a js function that returns the value in
<p
class=
"status"
>
the input field below when called.
</p>
</p>
<br/>
<br/>
<form>
<input
id=
'two'
type=
"TEXT"
/>
<div
class=
"error_message"
style=
"padding: 5px 5px 5px 5px; background-color:#FA6666; height:60px;width:400px; display: none"
></div>
</form>
</div>
</body>
</section>
</html>
</body>
</iframe>
<input
type=
"hidden"
name=
"input_2"
id=
"input_2"
value=
"${value|h}"
/>
<br/>
<button
id=
"update_2"
class=
"update"
>
Update
</button>
<p
id=
"answer_2"
class=
"answer"
></p>
<p
class=
"status"
>
</p>
<br/>
<br/>
<div
class=
"error_message"
></div>
</section>
</body>
</html>
</html>
common/static/js/capa/jsinput.js
→
common/static/js/capa/
src/
jsinput.js
View file @
fd6abc88
...
@@ -12,7 +12,6 @@
...
@@ -12,7 +12,6 @@
// submitted), the constructor is called again.
// submitted), the constructor is called again.
if
(
!
jsinput
)
{
if
(
!
jsinput
)
{
console
.
log
(
"hi"
);
jsinput
=
{
jsinput
=
{
runs
:
1
,
runs
:
1
,
arr
:
[],
arr
:
[],
...
@@ -27,29 +26,9 @@
...
@@ -27,29 +26,9 @@
jsinput
.
runs
++
;
jsinput
.
runs
++
;
if
(
$
(
document
).
find
(
'section[class="jsinput"]'
).
length
>
jsinput
.
runs
)
{
return
;
}
/* Utils */
/* Utils */
jsinput
.
_DEBUG
=
jsinput
.
_DEBUG
||
true
;
var
debuglog
=
function
(
text
)
{
if
(
jsinput
.
_DEBUG
)
{
console
.
log
(
text
);}};
var
eqTimeout
=
function
(
fn
,
pred
,
time
,
max
)
{
var
i
=
0
;
while
(
pred
(
fn
)
&&
i
<
max
)
{
setTimeout
(
fn
,
time
);
}
return
fn
;
};
var
isUndef
=
function
(
e
)
{
return
(
typeof
(
e
)
===
'undefined'
);
};
// Take a string and find the nested object that corresponds to it. E.g.:
// Take a string and find the nested object that corresponds to it. E.g.:
// deepKey(obj, "an.example") -> obj["an"]["example"]
// deepKey(obj, "an.example") -> obj["an"]["example"]
var
_deepKey
=
function
(
obj
,
path
){
var
_deepKey
=
function
(
obj
,
path
){
...
@@ -76,65 +55,51 @@
...
@@ -76,65 +55,51 @@
/* Private methods */
/* Private methods */
var
sect
=
$
(
spec
.
elem
).
parent
().
find
(
'section[class="jsinput"]'
);
var
sect
=
$
(
spec
.
elem
).
parent
().
find
(
'section[class="jsinput"]'
);
var
sect
a
ttr
=
function
(
e
)
{
return
$
(
sect
).
attr
(
e
);
};
var
sect
A
ttr
=
function
(
e
)
{
return
$
(
sect
).
attr
(
e
);
};
var
thisIFrame
=
$
(
spec
.
elem
).
var
thisIFrame
=
$
(
spec
.
elem
).
find
(
'iframe[name^="iframe_"]'
).
find
(
'iframe[name^="iframe_"]'
).
get
(
0
);
get
(
0
);
var
cWindow
=
thisIFrame
.
contentWindow
;
var
cWindow
=
thisIFrame
.
contentWindow
;
// Get the hidden input field to pass to customresponse
// Get the hidden input field to pass to customresponse
function
_input
f
ield
()
{
function
_input
F
ield
()
{
var
parent
=
$
(
spec
.
elem
).
parent
();
var
parent
=
$
(
spec
.
elem
).
parent
();
return
parent
.
find
(
'input[id^="input_"]'
);
return
parent
.
find
(
'input[id^="input_"]'
);
}
}
var
input
field
=
_inputf
ield
();
var
input
Field
=
_inputF
ield
();
// Get the grade function name
// Get the grade function name
var
get
gradefn
=
secta
ttr
(
"data"
);
var
get
GradeFn
=
sectA
ttr
(
"data"
);
// Get state getter
// Get state getter
var
get
getstate
=
secta
ttr
(
"data-getstate"
);
var
get
StateGetter
=
sectA
ttr
(
"data-getstate"
);
// Get state setter
// Get state setter
var
get
setstate
=
secta
ttr
(
"data-setstate"
);
var
get
StateSetter
=
sectA
ttr
(
"data-setstate"
);
// Get stored state
// Get stored state
var
get
storedstate
=
secta
ttr
(
"data-stored"
);
var
get
StoredState
=
sectA
ttr
(
"data-stored"
);
// Put the return value of gradefn in the hidden inputfield.
// Put the return value of gradeFn in the hidden inputField.
// If passed an argument, does not call gradefn, and instead directly
var
update
=
function
()
{
// updates the inputfield with the passed value.
var
update
=
function
(
answer
)
{
var
ans
;
var
ans
;
ans
=
_deepKey
(
cWindow
,
gradefn
);
ans
=
_deepKey
(
cWindow
,
gradeFn
)();
// setstate presumes getstate, so don't getstate unless setstate is
// setstate presumes getstate, so don't getstate unless setstate is
// defined.
// defined.
if
(
get
getstate
&&
getsetstate
)
{
if
(
get
StateGetter
&&
getStateSetter
)
{
var
state
,
store
;
var
state
,
store
;
state
=
_deepKey
(
cWindow
,
getgetstate
);
state
=
unescape
(
_deepKey
(
cWindow
,
getStateGetter
)()
);
store
=
{
store
=
{
answer
:
ans
,
answer
:
ans
,
state
:
state
state
:
state
};
};
inputField
.
val
(
JSON
.
stringify
(
store
));
debuglog
(
"Store: "
+
store
);
inputfield
.
val
(
JSON
.
stringify
(
store
));
}
else
{
}
else
{
inputfield
.
val
(
ans
);
inputField
.
val
(
ans
);
debuglog
(
"Answer: "
+
ans
);
}
}
return
;
return
;
};
};
// Find the update button, and bind the update function to its click
// event.
function
bindUpdate
()
{
var
updatebutton
=
$
(
spec
.
elem
).
find
(
'button[class="update"]'
).
get
(
0
);
$
(
updatebutton
).
click
(
update
);
}
/* Public methods */
/* Public methods */
that
.
update
=
update
;
that
.
update
=
update
;
...
@@ -145,53 +110,53 @@
...
@@ -145,53 +110,53 @@
jsinput
.
arr
.
push
(
that
);
jsinput
.
arr
.
push
(
that
);
// Put the update function as the value of the input
f
ield's "waitfor"
// Put the update function as the value of the input
F
ield's "waitfor"
// attribute so that it is called when the check button is clicked.
// attribute so that it is called when the check button is clicked.
function
bindCheck
()
{
function
bindCheck
()
{
debuglog
(
"Update function: "
+
that
.
update
);
inputField
.
data
(
'waitfor'
,
that
.
update
);
inputfield
.
data
(
'waitfor'
,
that
.
update
);
return
;
return
;
}
}
var
gradefn
=
getgradefn
;
var
gradeFn
=
getGradeFn
;
debuglog
(
"Gradefn: "
+
gradefn
);
if
(
spec
.
passive
===
false
)
{
// If there is a separate "Update" button, bind update to it.
bindUpdate
();
}
else
{
// Otherwise, bind update to the check button.
bindCheck
();
}
bindCheck
();
bindCheck
();
// Check whether application takes in state and there is a saved
// Check whether application takes in state and there is a saved
// state to give it. If get
setstate
is specified but calling it
// state to give it. If get
StateSetter
is specified but calling it
// fails, wait and try again, since the iframe might still be
// fails, wait and try again, since the iframe might still be
// loading.
// loading.
if
(
getsetstate
&&
getstoredstate
)
{
if
(
getStateSetter
&&
getStoredState
)
{
var
sval
;
var
sval
,
jsonVal
;
if
(
typeof
(
getstoredstate
)
===
"object"
)
{
sval
=
getstoredstate
[
"state"
];
try
{
jsonVal
=
JSON
.
parse
(
getStoredState
);
}
catch
(
err
)
{
jsonVal
=
getStoredState
;
}
if
(
typeof
(
jsonVal
)
===
"object"
)
{
sval
=
jsonVal
[
"state"
];
}
else
{
}
else
{
sval
=
getstoredstate
;
sval
=
jsonVal
;
}
}
debuglog
(
"Stored state: "
+
sval
);
debuglog
(
"Set_statefn: "
+
getsetstate
);
// Try calling setstate every 200ms while it throws an exception,
// up to five times; give up after that.
// (Functions in the iframe may not be ready when we first try
// calling it, but might just need more time. Give the functions
// more time.)
function
whileloop
(
n
)
{
function
whileloop
(
n
)
{
if
(
n
<
10
){
if
(
n
<
5
){
try
{
try
{
_deepKey
(
cWindow
,
get
setstate
)(
sval
);
_deepKey
(
cWindow
,
get
StateSetter
)(
sval
);
}
catch
(
err
)
{
}
catch
(
err
)
{
setTimeout
(
whileloop
(
n
+
1
),
200
);
setTimeout
(
whileloop
(
n
+
1
),
200
);
}
}
}
}
else
{
else
{
debuglog
(
"Error: could not set state"
);
console
.
debug
(
"Error: could not set state"
);
_deepKey
(
cWindow
,
getsetstate
)(
sval
);
}
}
}
}
whileloop
(
0
);
whileloop
(
0
);
...
@@ -218,7 +183,6 @@
...
@@ -218,7 +183,6 @@
var
newJsElem
=
jsinputConstructor
({
var
newJsElem
=
jsinputConstructor
({
id
:
newid
,
id
:
newid
,
elem
:
value
,
elem
:
value
,
passive
:
true
});
});
}
}
});
});
...
@@ -227,9 +191,9 @@
...
@@ -227,9 +191,9 @@
// This is ugly, but without a timeout pages with multiple/heavy jsinputs
// This is ugly, but without a timeout pages with multiple/heavy jsinputs
// don't load properly.
// don't load properly.
if
(
$
.
isReady
)
{
if
(
$
.
isReady
)
{
setTimeout
(
walkDOM
,
10
00
);
setTimeout
(
walkDOM
,
3
00
);
}
else
{
}
else
{
$
(
document
).
ready
(
setTimeout
(
walkDOM
,
10
00
));
$
(
document
).
ready
(
setTimeout
(
walkDOM
,
3
00
));
}
}
})(
window
.
jsinput
=
window
.
jsinput
||
false
);
})(
window
.
jsinput
=
window
.
jsinput
||
false
);
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