Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
X
xblock-poll
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
xblock-poll
Commits
cd8ec661
Commit
cd8ec661
authored
Sep 14, 2016
by
Matjaz Gregoric
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Accessibilityy improvements.
This commit addresses a11y issues listed in SOL-2059.
parent
84580b6f
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
146 additions
and
133 deletions
+146
-133
poll/poll.py
+26
-20
poll/public/handlebars/poll_results.handlebars
+38
-35
poll/public/handlebars/poll_studio.handlebars
+1
-1
poll/public/handlebars/survey_results.handlebars
+40
-37
poll/public/html/poll.html
+24
-22
poll/public/html/survey.html
+4
-4
poll/public/js/poll.js
+3
-2
poll/public/js/poll_edit.js
+1
-1
tests/integration/test_functions.py
+9
-11
No files found.
poll/poll.py
View file @
cd8ec661
...
...
@@ -123,6 +123,19 @@ class PollBase(XBlock, ResourceMixin, PublishEventMixin):
return
[(
key
,
{
'label'
:
markdown
(
value
[
'label'
]),
'img'
:
value
[
'img'
],
'img_alt'
:
value
.
get
(
'img_alt'
)})
for
key
,
value
in
items
]
def
_get_block_id
(
self
):
"""
Return unique ID of this block. Useful for HTML ID attributes.
Works both in LMS/Studio and workbench runtimes:
- In LMS/Studio, use the location.html_id method.
- In the workbench, use the usage_id.
"""
if
hasattr
(
self
,
'location'
):
return
self
.
location
.
html_id
()
# pylint: disable=no-member
else
:
return
unicode
(
self
.
scope_ids
.
usage_id
)
def
img_alt_mandatory
(
self
):
"""
Determine whether alt attributes for images are configured to be mandatory. Defaults to True.
...
...
@@ -404,13 +417,13 @@ class PollBlock(PollBase):
'feedback'
:
markdown
(
self
.
feedback
)
or
False
,
'js_template'
:
js_template
,
'any_img'
:
self
.
any_image
(
self
.
answers
),
# The SDK doesn't set url_name.
'url_name'
:
getattr
(
self
,
'url_name'
,
''
),
'display_name'
:
self
.
display_name
,
'can_vote'
:
self
.
can_vote
(),
'max_submissions'
:
self
.
max_submissions
,
'submissions_count'
:
self
.
submissions_count
,
'can_view_private_results'
:
self
.
can_view_private_results
(),
# a11y: Transfer block ID to enable creating unique ids for questions and answers in the template
'block_id'
:
self
.
_get_block_id
(),
})
if
self
.
choice
:
...
...
@@ -465,6 +478,8 @@ class PollBlock(PollBase):
'plural'
:
total
>
1
,
'display_name'
:
self
.
display_name
,
'any_img'
:
self
.
any_image
(
self
.
answers
),
# a11y: Transfer block ID to enable creating unique ids for questions and answers in the template
'block_id'
:
self
.
_get_block_id
(),
}
@XBlock.json_handler
...
...
@@ -613,19 +628,6 @@ class SurveyBlock(PollBase):
choices
=
Dict
(
help
=
_
(
"The user's answers"
),
scope
=
Scope
.
user_state
)
event_namespace
=
'xblock.survey'
def
_get_block_id
(
self
):
"""
Return ID of this Survey block.
Take into account the needs of both LMS/Studio and workbench runtimes:
- In LMS/Studio, usage_id is a UsageKey object.
- In the workbench, usage_id is a string.
"""
usage_id
=
self
.
scope_ids
.
usage_id
# Try accessing block ID. If usage_id does not have it, return usage_id itself:
return
unicode
(
getattr
(
usage_id
,
'block_id'
,
usage_id
))
def
student_view
(
self
,
context
=
None
):
"""
The primary view of the SurveyBlock, shown to students
...
...
@@ -649,8 +651,6 @@ class SurveyBlock(PollBase):
'any_img'
:
self
.
any_image
(
self
.
questions
),
# Mustache is treating an empty string as true.
'feedback'
:
markdown
(
self
.
feedback
)
or
False
,
# The SDK doesn't set url_name.
'url_name'
:
getattr
(
self
,
'url_name'
,
''
),
'block_name'
:
self
.
block_name
,
'can_vote'
:
self
.
can_vote
(),
'submissions_count'
:
self
.
submissions_count
,
...
...
@@ -820,9 +820,15 @@ class SurveyBlock(PollBase):
detail
,
total
=
self
.
tally_detail
()
return
{
'answers'
:
[
value
for
value
in
OrderedDict
(
self
.
answers
)
.
values
()],
'tally'
:
detail
,
'total'
:
total
,
'feedback'
:
markdown
(
self
.
feedback
),
'plural'
:
total
>
1
,
'block_name'
:
self
.
block_name
,
{
'key'
:
key
,
'label'
:
label
}
for
key
,
label
in
self
.
answers
],
'tally'
:
detail
,
'total'
:
total
,
'feedback'
:
markdown
(
self
.
feedback
),
'plural'
:
total
>
1
,
'block_name'
:
self
.
block_name
,
# a11y: Transfer block ID to enable creating unique ids for questions and answers in the template
'block_id'
:
self
.
_get_block_id
()
}
@XBlock.json_handler
...
...
poll/public/handlebars/poll_results.handlebars
View file @
cd8ec661
<script
id
=
"poll-results-template"
type=
"text/html"
>
<script
class
=
"poll-results-template"
type=
"text/html"
>
<
h3
class
=
"poll-header"
>
{{
display_name
}}
<
/h3
>
<
div
class
=
"poll-question-container"
>
{{{
question
}}}
<
/div
>
<
ul
class
=
"poll-answers-results poll-results
{{
~#
if
any_img
}}
has-images
{{/if}}
"
>
{{#
each
tally
}}
<
li
class
=
"poll-result"
>
<
div
class
=
"poll-result-input-container"
>
<
input
id
=
"answer-
{{
key
}}
"
type
=
"radio"
disabled
{{#if
choice
}}
checked
{{/if}}
/>
<
/div
>
{{
~#
if
..
/
any_img
~
}}
<
div
class
=
"poll-image result-image"
>
<
label
for
=
"answer-
{{
key
}}
"
class
=
"poll-image-label"
>
{{#if
img
}}
<
img
src
=
"
{{
img
}}
"
alt
=
"
{{
img_alt
}}
"
/>
{{/if}}
<
/label
>
<
/div><div class="percentage-gauge-background"></
div
>
{{
~
/
if
~
}}
<
div
class
=
"percentage-gauge-container"
>
<
div
class
=
"percentage-gauge"
style
=
"width:
{{
percent
}}
%;"
><
/div
>
<
label
class
=
"poll-answer-label"
for
=
"answer-
{{
key
}}
"
>
{{{
answer
}}}
<
/label
>
<
/div
>
<
div
class
=
"poll-percent-container"
>
<
span
class
=
"poll-percent-display
{{#if
first
}}
poll-top-choice
{{/if}}
"
>
{{
percent
}}
%<
/span
>
<
div
class
=
"poll-results-wrapper"
role
=
"radiogroup"
tabindex
=
"0"
>
<
h4
class
=
"poll-header"
>
{{
i18n
"Results"
}}
<
/h4
>
<
ul
class
=
"poll-answers-results poll-results
{{
~#
if
any_img
}}
has-images
{{/if}}
"
>
{{#
each
tally
}}
<
li
class
=
"poll-result"
>
<
div
class
=
"poll-result-input-container"
>
<
input
id
=
"answer-
{{
key
}}
-
{{
..
/
block_id
}}
"
type
=
"radio"
disabled
{{#if
choice
}}
checked
{{/if}}
/>
<
/div
>
{{
~#
if
..
/
any_img
~
}}
<
div
class
=
"poll-image result-image"
>
<
label
for
=
"answer-
{{
key
}}
-
{{
..
/
block_id
}}
"
class
=
"poll-image-label"
>
{{#if
img
}}
<
img
src
=
"
{{
img
}}
"
alt
=
"
{{
img_alt
}}
"
/>
{{/if}}
<
/label
>
<
/div><div class="percentage-gauge-background"></
div
>
{{
~
/
if
~
}}
<
div
class
=
"percentage-gauge-container"
>
<
div
class
=
"percentage-gauge"
style
=
"width:
{{
percent
}}
%;"
><
/div
>
<
label
class
=
"poll-answer-label"
for
=
"answer-
{{
key
}}
-
{{
..
/
block_id
}}
"
>
{{{
answer
}}}
<
/label
>
<
/div
>
<
div
class
=
"poll-percent-container"
>
<
span
class
=
"poll-percent-display
{{#if
first
}}
poll-top-choice
{{/if}}
"
>
{{
percent
}}
%<
/span
>
<
/div
>
<
/li
>
{{/
each
}}
<
/ul
>
<
input
class
=
"input-main"
type
=
"button"
name
=
"poll-submit"
value
=
"Submit"
disabled
>
<
div
class
=
"poll-footnote"
>
{{
interpolate
(
i18n_ngettext
"Results gathered from {total} respondent."
"Results gathered from {total} respondents."
total
)
total
=
total
}}
<
/div
>
{{#if
feedback
}}
<
hr
/>
<
h3
class
=
"poll-header"
>
{{
i18n
"Feedback"
}}
<
/h3
>
<
div
class
=
"poll-feedback"
>
{{{
feedback
}}}
<
/div
>
<
/li
>
{{/
each
}}
<
/ul
>
<
input
class
=
"input-main"
type
=
"button"
name
=
"poll-submit"
value
=
"Submit"
disabled
>
<
div
class
=
"poll-footnote"
>
{{
interpolate
(
i18n_ngettext
"Results gathered from {total} respondent."
"Results gathered from {total} respondents."
total
)
total
=
total
}}
{{/if}}
<
/div
>
{{#if
feedback
}}
<
hr
/>
<
h3
class
=
"poll-header"
>
{{
i18n
"Feedback"
}}
<
/h3
>
<
div
class
=
"poll-feedback"
>
{{{
feedback
}}}
<
/div
>
{{/if}}
</script>
poll/public/handlebars/poll_studio.handlebars
View file @
cd8ec661
<script
id
=
"poll-form-component"
type=
"text/html"
>
<script
class
=
"poll-form-component"
type=
"text/html"
>
{{#
each
items
}}
<
li
class
=
"field comp-setting-entry is-set poll-
{{
noun
}}
-studio-item"
>
<
div
class
=
"wrapper-comp-setting"
>
...
...
poll/public/handlebars/survey_results.handlebars
View file @
cd8ec661
<script
id
=
"survey-results-template"
type=
"text/html"
>
<script
class
=
"survey-results-template"
type=
"text/html"
>
<
h3
class
=
"poll-header"
>
{{
block_name
}}
<
/h3
>
<
table
class
=
"survey-table poll-results"
>
<
thead
>
<
tr
>
<
td
><
/td
>
{{#
each
answers
}}
<
th
class
=
"survey-answer"
>
{{{
this
}}}
<
/th
>
{{/
each
}}
<
/tr
>
<
/thead
>
{{#
each
tally
}}
<
tr
class
=
"survey-row"
>
<
th
class
=
"survey-question"
>
{{#if
img
}}
<
div
class
=
"poll-image-td"
>
<
img
src
=
"
{{
img
}}
"
alt
=
"img_alt"
/>
<
/div
>
{{/if}}
{{{
label
}}}
<
/th
>
{{#
each
answers
}}
<
td
class
=
"survey-percentage survey-option
{{#if
choice
}}
survey-choice
{{/if}}{{#if
top
}}
poll-top-choice
{{/if}}
"
>
{{
percent
}}
%<
/td
>
{{/
each
}}
<
/tr
>
{{/
each
}}
<
/table
>
<
input
class
=
"input-main"
type
=
"button"
name
=
"poll-submit"
value
=
"Submit"
disabled
>
<
div
class
=
"poll-footnote"
>
{{
interpolate
(
i18n_ngettext
"Results gathered from {total} respondent."
"Results gathered from {total} respondents."
total
)
total
=
total
}}
<
/div
>
{{#if
feedback
}}
<
hr
/>
<
h3
class
=
"poll-header"
>
{{
i18n
"Feedback"
}}
<
/h3
>
<
div
class
=
"poll-feedback"
>
{{{
feedback
}}}
<
div
class
=
"poll-results-wrapper"
tabindex
=
"0"
>
<
h4
class
=
"poll-header"
>
{{
i18n
"Results"
}}
<
/h4
>
<
table
class
=
"survey-table poll-results"
>
<
thead
>
<
tr
>
<
td
><
/td
>
{{#
each
answers
}}
<
th
id
=
"answer-
{{
key
}}
-
{{
..
/
block_id
}}
"
class
=
"survey-answer"
>
{{{
label
}}}
<
/th
>
{{/
each
}}
<
/tr
>
<
/thead
>
{{#
each
tally
}}
<
tr
class
=
"survey-row"
>
<
th
class
=
"survey-question"
>
{{#if
img
}}
<
div
class
=
"poll-image-td"
>
<
img
src
=
"
{{
img
}}
"
alt
=
"img_alt"
/>
<
/div
>
{{/if}}
{{{
label
}}}
<
/th
>
{{#
each
answers
}}
<
td
class
=
"survey-percentage survey-option
{{#if
choice
}}
survey-choice
{{/if}}{{#if
top
}}
poll-top-choice
{{/if}}
"
aria
-
labelledby
=
"answer-
{{
key
}}
-
{{
..
/
..
/
block_id
}}
"
>
{{
percent
}}
%<
/td
>
{{/
each
}}
<
/tr
>
{{/
each
}}
<
/table
>
<
input
class
=
"input-main"
type
=
"button"
name
=
"poll-submit"
value
=
"Submit"
disabled
>
<
div
class
=
"poll-footnote"
>
{{
interpolate
(
i18n_ngettext
"Results gathered from {total} respondent."
"Results gathered from {total} respondents."
total
)
total
=
total
}}
<
/div
>
{{/if}}
{{#if
feedback
}}
<
hr
/>
<
h3
class
=
"poll-header"
>
{{
i18n
"Feedback"
}}
<
/h3
>
<
div
class
=
"poll-feedback"
>
{{{
feedback
}}}
<
/div
>
{{/if}}
<
/div
>
</script>
poll/public/html/poll.html
View file @
cd8ec661
...
...
@@ -5,29 +5,31 @@
<h3
class=
"poll-header"
>
{{ display_name }}
</h3>
<form>
<div
class=
"poll-question-container"
>
{{ question|safe }}
</div>
<ul
class=
"poll-answers"
>
{% for key, value in answers %}
<li
class=
"poll-answer"
>
<div
class=
"poll-input-container"
>
<input
type=
"radio"
name=
"choice"
id=
"{{ url_name }}-answer-{{ key }}"
value=
"{{ key }}"
{%
if
choice =
=
key
%}
checked
{%
endif
%}
/>
</div>
{% if any_img %}
<div
class=
"poll-image"
>
<label
for=
"{{ url_name }}-answer-{{ key }}"
class=
"poll-image-label"
>
{% if value.img %}
<img
src=
"{{ value.img }}"
/>
{% endif %}
</label>
<div
role=
"group"
aria-labelledby=
"{{ block_id }}-question"
>
<div
id=
"{{ block_id }}-question"
class=
"poll-question-container"
>
{{ question|safe }}
</div>
<ul
class=
"poll-answers"
>
{% for key, value in answers %}
<li
class=
"poll-answer"
>
<div
class=
"poll-input-container"
>
<input
type=
"radio"
name=
"choice"
id=
"{{ block_id }}-answer-{{ key }}"
value=
"{{ key }}"
{%
if
choice =
=
key
%}
checked
{%
endif
%}
/>
</div>
{% endif %}
<label
class=
"poll-answer-text"
for=
"{{ url_name }}-answer-{{ key }}"
>
{{ value.label|safe }}
</label>
</li>
{% endfor %}
</ul>
{% if any_img %}
<div
class=
"poll-image"
>
<label
for=
"{{ block_id }}-answer-{{ key }}"
class=
"poll-image-label"
>
{% if value.img %}
<img
src=
"{{ value.img }}"
/>
{% endif %}
</label>
</div>
{% endif %}
<label
class=
"poll-answer-text"
for=
"{{ block_id }}-answer-{{ key }}"
>
{{ value.label|safe }}
</label>
</li>
{% endfor %}
</ul>
</div>
<input
class=
"input-main"
type=
"button"
name=
"poll-submit"
value=
"{% if choice %}Resubmit{% else %}Submit{% endif %}"
disabled
/>
</form>
...
...
poll/public/html/survey.html
View file @
cd8ec661
{{ js_template|safe }}
<div
class=
"poll-block themed-xblock"
data-private=
"{% if private_results %}1{% endif %}"
data-can-vote=
"{% if can_vote %}1{% endif %}"
>
<div
class=
"poll-block themed-xblock"
data-private=
"{% if private_results %}1{% endif %}"
data-can-vote=
"{% if can_vote %}1{% endif %}"
>
<div
class=
"poll-block-form-wrapper"
>
<h3
class=
"poll-header"
>
{{block_name}}
</h3>
<form>
...
...
@@ -13,7 +14,7 @@
</tr>
</thead>
{% for key, question in questions %}
<tr
class=
"survey-row"
>
<tr
class=
"survey-row"
role=
"group"
aria-labelledby=
"{{block_id}}-{{key}}"
>
<th
id=
"{{block_id}}-{{key}}"
class=
"survey-question"
>
{% if question.img %}
<div
class=
"poll-image-td"
>
...
...
@@ -28,9 +29,8 @@
<input
type=
"radio"
name=
"{{key}}"
value=
"{{answer}}"
{%
if
question
.
choice =
=
answer
%}
checked
{%
endif
%}
aria-labelledby=
"{{block_id}}-{{
key}} {{block_id}}-{{
answer}}"
aria-labelledby=
"{{block_id}}-{{answer}}"
/>
<span
class=
"sr"
>
{{label}}
</span>
</label>
</td>
{% endfor %}
...
...
poll/public/js/poll.js
View file @
cd8ec661
...
...
@@ -37,7 +37,7 @@ function PollUtil (runtime, element, pollType) {
});
});
this
.
resultsTemplate
=
Handlebars
.
compile
(
$
(
"
#
"
+
pollType
+
"-results-template"
,
element
).
html
());
this
.
resultsTemplate
=
Handlebars
.
compile
(
$
(
"
.
"
+
pollType
+
"-results-template"
,
element
).
html
());
this
.
viewResultsButton
=
$
(
'.view-results-button'
,
element
);
this
.
viewResultsButton
.
click
(
this
.
getResults
);
...
...
@@ -204,12 +204,13 @@ function PollUtil (runtime, element, pollType) {
data
:
JSON
.
stringify
({}),
success
:
function
(
data
)
{
$
(
'div.poll-block'
,
element
).
html
(
self
.
resultsTemplate
(
data
));
$
(
'.poll-results-wrapper'
).
focus
();
whenImagesLoaded
(
adjustGaugeBackground
);
}
});
};
this
.
enableSubmit
=
function
()
{
this
.
enableSubmit
=
function
()
{
// Enable the submit button.
self
.
submit
.
removeAttr
(
"disabled"
);
self
.
answers
.
unbind
(
"change.enableSubmit"
);
...
...
poll/public/js/poll_edit.js
View file @
cd8ec661
...
...
@@ -12,7 +12,7 @@ function PollEditUtil(runtime, element, pollType) {
this
.
init
=
function
()
{
// Set up the editing form for a Poll or Survey.
var
temp
=
$
(
'
#
poll-form-component'
,
element
).
html
();
var
temp
=
$
(
'
.
poll-form-component'
,
element
).
html
();
// Set up gettext in case it isn't available in the client runtime:
if
(
typeof
gettext
==
"undefined"
)
{
...
...
tests/integration/test_functions.py
View file @
cd8ec661
...
...
@@ -25,8 +25,6 @@ Tests a realistic, configured Poll to make sure that everything works as it
should.
"""
import
itertools
from
.base_test
import
PollBaseTest
...
...
@@ -165,15 +163,15 @@ class TestSurveyFunctions(PollBaseTest):
answers
=
self
.
browser
.
find_elements_by_css_selector
(
'.survey-answer'
)
question_ids
=
[
question
.
get_attribute
(
'id'
)
for
question
in
questions
]
answer_ids
=
[
answer
.
get_attribute
(
'id'
)
for
answer
in
answers
]
id_pairs
=
[
"{question_id} {answer_id}"
.
format
(
question_id
=
question_id
,
answer_id
=
answer_id
)
for
question_id
,
answer_id
in
itertools
.
product
(
question_ids
,
answer_ids
)
]
options
=
self
.
browser
.
find_elements_by_css_selector
(
'.survey-option input'
)
self
.
assertEqual
(
len
(
options
),
len
(
id_pairs
)
)
for
option
in
options
:
labelledby
=
option
.
get_attribute
(
'aria-labelledby'
)
self
.
assertIn
(
labelledby
,
id_pairs
)
rows
=
self
.
browser
.
find_elements_by_css_selector
(
'.survey-row'
)
self
.
assertEqual
(
len
(
rows
),
len
(
questions
)
)
for
i
,
row
in
enumerate
(
rows
):
self
.
assertEqual
(
row
.
get_attribute
(
'role'
),
'group'
)
self
.
assertEqual
(
row
.
get_attribute
(
'aria-labelledby'
),
question_ids
[
i
]
)
options
=
row
.
find_elements_by_css_selector
(
'.survey-option input'
)
self
.
assertEqual
(
len
(
options
),
len
(
answers
))
for
j
,
option
in
enumerate
(
options
):
self
.
assertEqual
(
option
.
get_attribute
(
'aria-labelledby'
),
answer_ids
[
j
]
)
def
fill_survey
(
self
,
assert_submit
=
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