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
3cef87b9
Commit
3cef87b9
authored
Sep 20, 2016
by
Matjaz Gregoric
Committed by
GitHub
Sep 20, 2016
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #16 from open-craft/mtyaka/a11y-fixes
A11y fixes
parents
84580b6f
7ef8e5d1
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
147 additions
and
134 deletions
+147
-134
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
setup.py
+1
-1
tests/integration/test_functions.py
+9
-11
No files found.
poll/poll.py
View file @
3cef87b9
...
...
@@ -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 @
3cef87b9
<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 @
3cef87b9
<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 @
3cef87b9
<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 @
3cef87b9
...
...
@@ -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 @
3cef87b9
{{ 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 @
3cef87b9
...
...
@@ -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 @
3cef87b9
...
...
@@ -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"
)
{
...
...
setup.py
View file @
3cef87b9
...
...
@@ -44,7 +44,7 @@ def package_data(pkg, roots):
setup
(
name
=
'xblock-poll'
,
version
=
'1.2'
,
version
=
'1.2
.1
'
,
description
=
'An XBlock for polling users.'
,
packages
=
[
'poll'
,
...
...
tests/integration/test_functions.py
View file @
3cef87b9
...
...
@@ -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