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
11080f28
Commit
11080f28
authored
Dec 17, 2013
by
Valera Rozuvan
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #1947 from edx/valera/visual_ui_image_response
Improvement and update for ImageInput
parents
a78400a8
f03f3ebf
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
274 additions
and
37 deletions
+274
-37
common/lib/capa/capa/templates/imageinput.html
+57
-21
common/lib/xmodule/xmodule/js/fixtures/imageinput.html
+31
-0
common/lib/xmodule/xmodule/js/spec/capa/imageinput_spec.js
+145
-0
common/lib/xmodule/xmodule/js/src/capa/imageinput.js
+41
-16
No files found.
common/lib/capa/capa/templates/imageinput.html
View file @
11080f28
<span>
<span>
<input
type=
"hidden"
class=
"imageinput"
src=
"${src}"
name=
"input_${id}"
id=
"input_${id}"
value=
"${value}"
/>
<input
<div
id=
"imageinput_${id}"
onclick=
"image_input_click('${id}',event);"
style =
"background-image:url('${src}');width:${width}px;height:${height}px;position: relative; left: 0; top: 0;"
>
type=
"hidden"
<img
src=
"${STATIC_URL}green-pointer.png"
id=
"cross_${id}"
style=
"position: absolute;top: ${gy}px;left: ${gx}px;"
/>
class=
"imageinput"
</div>
src=
"${src}"
name=
"input_${id}"
id=
"input_${id}"
value=
"${value}"
/>
% if status == 'unsubmitted':
<div
<span
class=
"unanswered"
style=
"display:inline-block;"
id=
"status_${id}"
aria-describedby=
"input_${id}"
>
id=
"imageinput_${id}"
<span
class=
"sr"
>
Status: unanswered
</span>
style=
"background-image: url('${src}'); width: ${width}px; height: ${height}px; position: relative; left: 0; top: 0;"
</span>
>
% elif status == 'correct':
<img
<span
class=
"correct"
id=
"status_${id}"
aria-describedby=
"input_${id}"
>
src=
"${STATIC_URL}green-pointer.png"
<span
class=
"sr"
>
Status: correct
</span>
id=
"cross_${id}"
</span>
style=
"position: absolute; top: ${gy}px; left: ${gx}px;"
% elif status == 'incorrect':
/>
<span
class=
"incorrect"
id=
"status_${id}"
aria-describedby=
"input_${id}"
>
</div>
<span
class=
"sr"
>
Status: incorrect
</span>
</span>
<script
type=
"text/javascript"
charset=
"utf-8"
>
% elif status == 'incomplete':
(
new
ImageInput
(
'${id}'
));
<span
class=
"incorrect"
id=
"status_${id}"
aria-describedby=
"input_${id}"
>
</script>
<span
class=
"sr"
>
Status: incorrect
</span>
</span>
% if status == 'unsubmitted':
% endif
<span
class=
"unanswered"
style=
"display: inline-block;"
id=
"status_${id}"
aria-describedby=
"input_${id}"
>
<span
class=
"sr"
>
Status: unanswered
</span>
</span>
% elif status == 'correct':
<span
class=
"correct"
id=
"status_${id}"
aria-describedby=
"input_${id}"
>
<span
class=
"sr"
>
Status: correct
</span>
</span>
% elif status == 'incorrect':
<span
class=
"incorrect"
id=
"status_${id}"
aria-describedby=
"input_${id}"
>
<span
class=
"sr"
>
Status: incorrect
</span>
</span>
% elif status == 'incomplete':
<span
class=
"incorrect"
id=
"status_${id}"
aria-describedby=
"input_${id}"
>
<span
class=
"sr"
>
Status: incorrect
</span>
</span>
% endif
</span>
</span>
common/lib/xmodule/xmodule/js/fixtures/imageinput.html
0 → 100644
View file @
11080f28
<!-- ${id} = 12345 -->
<!-- ${width} = 300 -->
<!-- ${height} = 400 -->
<span>
<input
type=
"hidden"
class=
"imageinput"
src=
""
name=
"input_12345"
id=
"input_12345"
value=
""
/>
<div
id=
"imageinput_12345"
style=
"width: 300px; height: 400px; position: relative; left: 0; top: 0; visibility: hidden;"
>
<!-- image will go here -->
</div>
<!-- status == 'unsubmitted' -->
<span
class=
"unanswered"
style=
"display: inline-block;"
id=
"status_12345"
aria-describedby=
"input_12345"
>
<span
class=
"sr"
>
Status: unanswered
</span>
</span>
</span>
common/lib/xmodule/xmodule/js/spec/capa/imageinput_spec.js
0 → 100644
View file @
11080f28
/**
* "Beware of bugs in the above code; I have only proved it correct, not tried
* it."
*
* ~ Donald Knuth
*/
(
function
(
$
,
ImageInput
,
undefined
)
{
describe
(
'ImageInput'
,
function
()
{
var
state
;
beforeEach
(
function
()
{
var
el
;
loadFixtures
(
'imageinput.html'
);
el
=
$
(
'#imageinput_12345'
);
el
.
append
(
createTestImage
(
'cross_12345'
,
300
,
400
,
'red'
));
state
=
new
ImageInput
(
'12345'
);
spyOn
(
state
,
'clickHandler'
).
andCallThrough
();
});
it
(
'initialization'
,
function
()
{
expect
(
state
.
elementId
).
toBe
(
'12345'
);
// Check that object's properties are present, and that the DOM
// elements they reference exist.
expect
(
state
.
el
).
toBeDefined
();
expect
(
state
.
el
).
toExist
();
expect
(
state
.
crossEl
).
toBeDefined
();
expect
(
state
.
crossEl
).
toExist
();
expect
(
state
.
inputEl
).
toBeDefined
();
expect
(
state
.
inputEl
).
toExist
();
// Check that the click handler has been attached to the `state.el`
// element. Note that `state.clickHandler()` method is called from
// within the attached handler. That is why we can't use
// Jasmine-jQuery `toHandleWith()` method.
state
.
el
.
click
();
expect
(
state
.
clickHandler
).
toHaveBeenCalled
();
});
it
(
'cross becomes visible after first click'
,
function
()
{
expect
(
state
.
crossEl
.
css
(
'visibility'
)).
toBe
(
'hidden'
);
state
.
el
.
click
();
expect
(
state
.
crossEl
.
css
(
'visibility'
)).
toBe
(
'visible'
);
});
it
(
'coordinates are updated [offsetX is set]'
,
function
()
{
var
event
,
posX
,
posY
,
cssLeft
,
cssTop
;
// Set up of 'click' event.
event
=
jQuery
.
Event
(
'click'
,
{
offsetX
:
35.3
,
offsetY
:
42.7
}
);
// Calculating the expected coordinates.
posX
=
event
.
offsetX
;
posY
=
event
.
offsetY
;
// Triggering 'click' event.
jQuery
(
state
.
el
).
trigger
(
event
);
// Getting actual (new) coordinates, and testing them against the
// expected.
cssLeft
=
stripPx
(
state
.
crossEl
.
css
(
'left'
));
cssTop
=
stripPx
(
state
.
crossEl
.
css
(
'top'
));
expect
(
cssLeft
).
toBeCloseTo
(
posX
-
15
,
1
);
expect
(
cssTop
).
toBeCloseTo
(
posY
-
15
,
1
);
expect
(
state
.
inputEl
.
val
()).
toBe
(
'['
+
Math
.
round
(
posX
)
+
','
+
Math
.
round
(
posY
)
+
']'
);
});
it
(
'coordinates are updated [offsetX is NOT set]'
,
function
()
{
var
event
,
posX
,
posY
,
cssLeft
,
cssTop
;
// Set up of 'click' event.
event
=
jQuery
.
Event
(
'click'
,
{
offsetX
:
undefined
,
offsetY
:
undefined
,
pageX
:
35.3
,
pageY
:
42.7
}
);
state
.
el
[
0
].
offsetLeft
=
12
;
state
.
el
[
0
].
offsetTop
=
3
;
// Calculating the expected coordinates.
posX
=
event
.
pageX
-
state
.
el
[
0
].
offsetLeft
;
posY
=
event
.
pageY
-
state
.
el
[
0
].
offsetTop
;
// Triggering 'click' event.
jQuery
(
state
.
el
).
trigger
(
event
);
// Getting actual (new) coordinates, and testing them against the
// expected.
cssLeft
=
stripPx
(
state
.
crossEl
.
css
(
'left'
));
cssTop
=
stripPx
(
state
.
crossEl
.
css
(
'top'
));
expect
(
cssLeft
).
toBeCloseTo
(
posX
-
15
,
1
);
expect
(
cssTop
).
toBeCloseTo
(
posY
-
15
,
1
);
expect
(
state
.
inputEl
.
val
()).
toBe
(
'['
+
Math
.
round
(
posX
)
+
','
+
Math
.
round
(
posY
)
+
']'
);
});
});
// Instead of storing an image, and then including it in the template via
// the <img /> tag, we will generate one on the fly.
//
// Create a simple image from a canvas. The canvas is filled by a colored
// rectangle.
function
createTestImage
(
id
,
width
,
height
,
fillStyle
)
{
var
canvas
,
ctx
,
img
;
canvas
=
document
.
createElement
(
'canvas'
);
canvas
.
width
=
width
;
canvas
.
height
=
height
;
ctx
=
canvas
.
getContext
(
'2d'
);
ctx
.
fillStyle
=
fillStyle
;
ctx
.
fillRect
(
0
,
0
,
width
,
height
);
img
=
document
.
createElement
(
'img'
);
img
.
src
=
canvas
.
toDataURL
(
'image/png'
);
img
.
id
=
id
;
return
img
;
}
// Strip the trailing 'px' substring from a CSS string containing the
// `left` and `top` properties of an element's style.
function
stripPx
(
str
)
{
return
str
.
substring
(
0
,
str
.
length
-
2
);
}
}).
call
(
this
,
window
.
jQuery
,
window
.
ImageInput
);
common/lib/xmodule/xmodule/js/src/capa/imageinput.js
View file @
11080f28
...
@@ -13,24 +13,49 @@
...
@@ -13,24 +13,49 @@
* ~ Chinese Proverb
* ~ Chinese Proverb
*/
*/
window
.
image_input_click
=
function
(
id
,
event
)
{
window
.
ImageInput
=
(
function
(
$
,
undefined
)
{
var
iiDiv
=
document
.
getElementById
(
'imageinput_'
+
id
),
var
ImageInput
=
ImageInputConstructor
;
posX
=
event
.
offsetX
?
event
.
offsetX
:
event
.
pageX
-
iiDiv
.
offsetLeft
,
ImageInput
.
prototype
=
{
posY
=
event
.
offsetY
?
event
.
offsetY
:
event
.
pageY
-
iiDiv
.
offsetTop
,
constructor
:
ImageInputConstructor
,
clickHandler
:
clickHandler
};
cross
=
document
.
getElementById
(
'cross_'
+
id
),
return
ImageInput
;
// To reduce differences between values returned by different kinds of
function
ImageInputConstructor
(
elementId
)
{
// browsers, we round `posX` and `posY`.
var
_this
=
this
;
//
// IE10: `posX` and `posY` - float.
// Chrome, FF: `posX` and `posY` - integers.
result
=
'['
+
Math
.
round
(
posX
)
+
','
+
Math
.
round
(
posY
)
+
']'
;
cross
.
style
.
left
=
(
posX
-
15
)
+
'px'
;
this
.
elementId
=
elementId
;
cross
.
style
.
top
=
(
posY
-
15
)
+
'px'
;
cross
.
style
.
visibility
=
'visible'
;
document
.
getElementById
(
'input_'
+
id
).
value
=
result
;
this
.
el
=
$
(
'#imageinput_'
+
this
.
elementId
);
};
this
.
crossEl
=
$
(
'#cross_'
+
this
.
elementId
);
this
.
inputEl
=
$
(
'#input_'
+
this
.
elementId
);
this
.
el
.
on
(
'click'
,
function
(
event
)
{
_this
.
clickHandler
(
event
);
});
}
function
clickHandler
(
event
)
{
var
posX
=
event
.
offsetX
?
event
.
offsetX
:
event
.
pageX
-
this
.
el
[
0
].
offsetLeft
,
posY
=
event
.
offsetY
?
event
.
offsetY
:
event
.
pageY
-
this
.
el
[
0
].
offsetTop
,
// To reduce differences between values returned by different kinds
// of browsers, we round `posX` and `posY`.
//
// IE10: `posX` and `posY` - float.
// Chrome, FF: `posX` and `posY` - integers.
result
=
'['
+
Math
.
round
(
posX
)
+
','
+
Math
.
round
(
posY
)
+
']'
;
this
.
crossEl
.
css
({
left
:
posX
-
15
,
top
:
posY
-
15
,
visibility
:
'visible'
});
this
.
inputEl
.
val
(
result
);
}
}).
call
(
this
,
window
.
jQuery
);
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