[a11y] Adds context to module level buttons
Makes it so that screenreaders are given specific module context i.e., the module name, whenever they navigation to a module level button fixes CNVS-22866 Test Plan: - Go to the modules page - Using a screenreader go to the publish cloud at the module level. - It should indicate the name of the module, for example: "Published. Click to unpublish My Cool Module." - Similar things should occur for the Add content button and the manage module dropdown. - The publish button and cog buttons for items within modules should similarly give context. Change-Id: I1ba3f5e5c09e8186667af38eb19852295d5f01e2 Reviewed-on: https://gerrit.instructure.com/63049 Product-Review: Aaron Cannon <acannon@instructure.com> Reviewed-by: Sterling Cobb <sterling@instructure.com> Tested-by: Jenkins QA-Review: Clare Strong <clare@instructure.com>
This commit is contained in:
parent
f53907c0dd
commit
60d3834e9d
|
@ -16,6 +16,7 @@ define [
|
||||||
published: true
|
published: true
|
||||||
publishable: true
|
publishable: true
|
||||||
unpublishable: true
|
unpublishable: true
|
||||||
|
module_item_name: null
|
||||||
|
|
||||||
branch: (key) ->
|
branch: (key) ->
|
||||||
(@[key][@get('module_type')] or @[key].generic).call(this)
|
(@[key][@get('module_type')] or @[key].generic).call(this)
|
||||||
|
@ -45,10 +46,24 @@ define [
|
||||||
module: -> module: @attributes
|
module: -> module: @attributes
|
||||||
|
|
||||||
disabledMessages:
|
disabledMessages:
|
||||||
generic: -> I18n.t('disabled', 'Publishing is disabled for this item')
|
generic: -> if @get('module_item_name')
|
||||||
assignment: -> I18n.t('disabled_assignment', "Can't unpublish if there are student submissions")
|
I18n.t('Publishing %{item_name} is disabled', {item_name: @get('module_item_name')})
|
||||||
quiz: -> I18n.t('disabled_quiz', "Can't unpublish if there are student submissions")
|
else
|
||||||
discussion_topic: -> I18n.t('disabled_discussion_topic', "Can't unpublish if there are student submissions")
|
I18n.t('Publishing is disabled for this item')
|
||||||
|
|
||||||
|
assignment: -> if @get('module_item_name')
|
||||||
|
I18n.t("Can't unpublish %{item_name} if there are student submissions", {item_name: @get('module_item_name')})
|
||||||
|
else
|
||||||
|
I18n.t("Can't unpublish if there are student submissions")
|
||||||
|
|
||||||
|
quiz: -> if @get('module_item_name')
|
||||||
|
I18n.t("Can't unpublish %{item_name} if there are student submissions", {item_name: @get('module_item_name')})
|
||||||
|
else
|
||||||
|
I18n.t("Can't unpublish if there are student submissions")
|
||||||
|
discussion_topic: -> if @get('module_item_name')
|
||||||
|
I18n.t("Can't unpublish %{item_name} if there are student submissions", {item_name: @get('module_item_name')})
|
||||||
|
else
|
||||||
|
I18n.t("Can't unpublish if there are student submissions")
|
||||||
|
|
||||||
publish: ->
|
publish: ->
|
||||||
@save 'published', yes
|
@save 'published', yes
|
||||||
|
|
|
@ -16,6 +16,7 @@ define [
|
||||||
togglePublishClassOn: React.PropTypes.object
|
togglePublishClassOn: React.PropTypes.object
|
||||||
model: customPropTypes.filesystemObject
|
model: customPropTypes.filesystemObject
|
||||||
userCanManageFilesForContext: React.PropTypes.bool.isRequired
|
userCanManageFilesForContext: React.PropTypes.bool.isRequired
|
||||||
|
fileName: React.PropTypes.string
|
||||||
|
|
||||||
# == React Functions == #
|
# == React Functions == #
|
||||||
getInitialState: -> @extractStateFromModel( @props.model )
|
getInitialState: -> @extractStateFromModel( @props.model )
|
||||||
|
|
|
@ -13,6 +13,10 @@ define [
|
||||||
publishedClass: 'btn-published'
|
publishedClass: 'btn-published'
|
||||||
unpublishClass: 'btn-unpublish'
|
unpublishClass: 'btn-unpublish'
|
||||||
|
|
||||||
|
# These values allow the default text to be overridden if necessary
|
||||||
|
@optionProperty 'publishText'
|
||||||
|
@optionProperty 'unpublishText'
|
||||||
|
|
||||||
tagName: 'button'
|
tagName: 'button'
|
||||||
className: 'btn'
|
className: 'btn'
|
||||||
|
|
||||||
|
@ -55,7 +59,7 @@ define [
|
||||||
|
|
||||||
addAriaLabel: (label) ->
|
addAriaLabel: (label) ->
|
||||||
$label = @$el.find('span.screenreader-only.accessible_label')
|
$label = @$el.find('span.screenreader-only.accessible_label')
|
||||||
$('<span class="screenreader-only accessible_label"></span>').appendTo(@$el) unless $label.length
|
$label = $('<span class="screenreader-only accessible_label"></span>').appendTo(@$el) unless $label.length
|
||||||
|
|
||||||
$label.text label
|
$label.text label
|
||||||
@$el.attr 'aria-label', label
|
@$el.attr 'aria-label', label
|
||||||
|
@ -134,14 +138,14 @@ define [
|
||||||
renderPublish: ->
|
renderPublish: ->
|
||||||
@renderState
|
@renderState
|
||||||
text: I18n.t 'buttons.publish', 'Publish'
|
text: I18n.t 'buttons.publish', 'Publish'
|
||||||
label: I18n.t 'buttons.publish_desc', 'Unpublished. Click to publish.'
|
label: @publishText || I18n.t 'Unpublished. Click to publish.'
|
||||||
buttonClass: @publishClass
|
buttonClass: @publishClass
|
||||||
iconClass: 'icon-unpublish'
|
iconClass: 'icon-unpublish'
|
||||||
|
|
||||||
renderPublished: ->
|
renderPublished: ->
|
||||||
@renderState
|
@renderState
|
||||||
text: I18n.t 'buttons.published', 'Published'
|
text: I18n.t 'buttons.published', 'Published'
|
||||||
label: I18n.t 'buttons.published_desc', 'Published. Click to unpublish.'
|
label: @unpublishText || I18n.t 'Published. Click to unpublish.'
|
||||||
buttonClass: @publishedClass
|
buttonClass: @publishedClass
|
||||||
iconClass: 'icon-publish'
|
iconClass: 'icon-publish'
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,12 @@ define [
|
||||||
tagName: 'span'
|
tagName: 'span'
|
||||||
className: 'publish-icon'
|
className: 'publish-icon'
|
||||||
|
|
||||||
|
# These values allow the default text to be overridden if necessary
|
||||||
|
@optionProperty 'publishText'
|
||||||
|
@optionProperty 'unpublishText'
|
||||||
|
|
||||||
initialize: ->
|
initialize: ->
|
||||||
|
super
|
||||||
@events = _.extend({}, PublishButtonView.prototype.events, @events)
|
@events = _.extend({}, PublishButtonView.prototype.events, @events)
|
||||||
|
|
||||||
events: {'keyclick' : 'click'}
|
events: {'keyclick' : 'click'}
|
||||||
|
|
|
@ -30,6 +30,7 @@ define([
|
||||||
};
|
};
|
||||||
|
|
||||||
PublishCloud.render = function () {
|
PublishCloud.render = function () {
|
||||||
|
var fileName = this.props.fileName || I18n.t('This file');
|
||||||
if (this.props.userCanManageFilesForContext) {
|
if (this.props.userCanManageFilesForContext) {
|
||||||
if (this.state.published && this.state.restricted) {
|
if (this.state.published && this.state.restricted) {
|
||||||
return (
|
return (
|
||||||
|
@ -40,7 +41,7 @@ define([
|
||||||
ref='publishCloud'
|
ref='publishCloud'
|
||||||
className='btn-link published-status restricted'
|
className='btn-link published-status restricted'
|
||||||
title={this.getRestrictedText()}
|
title={this.getRestrictedText()}
|
||||||
aria-label={this.getRestrictedText() + ' - ' + I18n.t('Click to modify')}
|
aria-label={`${fileName} is ${this.getRestrictedText()} - ${I18n.t('Click to modify')}`}
|
||||||
>
|
>
|
||||||
<i className='icon-cloud-lock' />
|
<i className='icon-cloud-lock' />
|
||||||
</button>
|
</button>
|
||||||
|
@ -54,7 +55,7 @@ define([
|
||||||
ref='publishCloud'
|
ref='publishCloud'
|
||||||
className='btn-link published-status hiddenState'
|
className='btn-link published-status hiddenState'
|
||||||
title={I18n.t('Hidden. Available with a link')}
|
title={I18n.t('Hidden. Available with a link')}
|
||||||
aria-label={I18n.t('Hidden. Available with a link - Click to modify')}
|
aria-label={`${fileName} is ${I18n.t('Hidden. Available with a link - Click to modify')}`}
|
||||||
>
|
>
|
||||||
<i className='icon-cloud-lock' />
|
<i className='icon-cloud-lock' />
|
||||||
</button>
|
</button>
|
||||||
|
@ -68,7 +69,7 @@ define([
|
||||||
ref='publishCloud'
|
ref='publishCloud'
|
||||||
className='btn-link published-status published'
|
className='btn-link published-status published'
|
||||||
title={I18n.t('Published')}
|
title={I18n.t('Published')}
|
||||||
aria-label={I18n.t('Published - Click to modify')}
|
aria-label={`${fileName} is ${I18n.t('Published - Click to modify')}`}
|
||||||
>
|
>
|
||||||
<i className='icon-publish' />
|
<i className='icon-publish' />
|
||||||
</button>
|
</button>
|
||||||
|
@ -82,7 +83,7 @@ define([
|
||||||
ref='publishCloud'
|
ref='publishCloud'
|
||||||
className='btn-link published-status unpublished'
|
className='btn-link published-status unpublished'
|
||||||
title={I18n.t('Unpublished')}
|
title={I18n.t('Unpublished')}
|
||||||
aria-label={I18n.t('Unpublished - Click to modify')}
|
aria-label={`${fileName} is ${I18n.t('Unpublished - Click to modify')}`}
|
||||||
>
|
>
|
||||||
<i className='icon-unpublish' />
|
<i className='icon-unpublish' />
|
||||||
</button>
|
</button>
|
||||||
|
@ -97,7 +98,7 @@ define([
|
||||||
ref='publishCloud'
|
ref='publishCloud'
|
||||||
className='published-status restricted'
|
className='published-status restricted'
|
||||||
title={this.getRestrictedText()}
|
title={this.getRestrictedText()}
|
||||||
aria-label={this.getRestrictedText()}
|
aria-label={`${fileName} is ${this.getRestrictedText()}`}
|
||||||
>
|
>
|
||||||
<i className='icon-calendar-day' />
|
<i className='icon-calendar-day' />
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -115,6 +115,8 @@
|
||||||
data-course-id="<%= context_module && context_module.context_id %>"
|
data-course-id="<%= context_module && context_module.context_id %>"
|
||||||
data-published="<%= published_status == 'published' %>"
|
data-published="<%= published_status == 'published' %>"
|
||||||
data-publishable="<%= true %>"
|
data-publishable="<%= true %>"
|
||||||
|
data-publish-message="<%= t('Unpublished. Click to publish %{module_name}.', {module_name: context_module ? context_module.name : 'module'}) %>"
|
||||||
|
data-unpublish-message="<%= t('Published. Click to unpublish %{module_name}.', {module_name: context_module ? context_module.name : 'module'}) %>"
|
||||||
title=""
|
title=""
|
||||||
data-tooltip
|
data-tooltip
|
||||||
class="publish-icon module <%= published_status %>"
|
class="publish-icon module <%= published_status %>"
|
||||||
|
@ -123,10 +125,10 @@
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<button
|
<button
|
||||||
aria-label="<%= t('aria_labels.add_item', %{Add Content}) %>"
|
aria-label="<%= t('Add Content to %{module_name}', {module_name: context_module ? context_module.name : 'module'}) %>"
|
||||||
rel="<%= context_url(@context, :context_url) %>/modules/<%= context_module ? context_module.id : "{{ id }}" %>/items"
|
rel="<%= context_url(@context, :context_url) %>/modules/<%= context_module ? context_module.id : "{{ id }}" %>/items"
|
||||||
class="add_module_item_link btn"><i class="icon-plus"></i><span class="screenreader-only"><%= t('links.add_item', %{Add Content}) %></span></button>
|
class="add_module_item_link btn"><i class="icon-plus"></i><span class="screenreader-only"><%= t('Add Content to %{module_name}', {module_name: context_module ? context_module.name : 'module'}) %></span></button>
|
||||||
<button class="btn al-trigger" aria-label="<%= t("manager_module", "Manage module") %>">
|
<button class="btn al-trigger" aria-label="<%= t('Manage %{module_name}', {module_name: context_module ? context_module.name : 'module'}) %>">
|
||||||
<i class="icon-settings"></i><i class="icon-mini-arrow-down"></i>
|
<i class="icon-settings"></i><i class="icon-mini-arrow-down"></i>
|
||||||
</button>
|
</button>
|
||||||
<ul class="al-options">
|
<ul class="al-options">
|
||||||
|
|
|
@ -115,6 +115,7 @@
|
||||||
<% if editable || module_item.nil? %>
|
<% if editable || module_item.nil? %>
|
||||||
<div class="ig-admin">
|
<div class="ig-admin">
|
||||||
<span
|
<span
|
||||||
|
data-module-item-name="<%= tag && tag.title %>"
|
||||||
data-module-type="<%= module_item && module_item.content_type_class %>"
|
data-module-type="<%= module_item && module_item.content_type_class %>"
|
||||||
data-content-id="<%= module_item && module_item.content_id %>"
|
data-content-id="<%= module_item && module_item.content_id %>"
|
||||||
data-id="<%= module_item_publishable_id(module_item) %>"
|
data-id="<%= module_item_publishable_id(module_item) %>"
|
||||||
|
@ -124,6 +125,8 @@
|
||||||
data-published="<%= module_item && published_status == 'published' %>"
|
data-published="<%= module_item && published_status == 'published' %>"
|
||||||
data-publishable="<%= module_item_publishable?(module_item) %>"
|
data-publishable="<%= module_item_publishable?(module_item) %>"
|
||||||
data-unpublishable="<%= module_item_unpublishable?(module_item) %>"
|
data-unpublishable="<%= module_item_unpublishable?(module_item) %>"
|
||||||
|
data-publish-message="<%= t('Unpublished. Click to publish %{item_name}.', {item_name: tag && tag.title ? tag.title : ''}) %>"
|
||||||
|
data-unpublish-message="<%= t('Published. Click to unpublish %{item_name}.', {item_name: tag && tag.title ? tag.title : ''}) %>"
|
||||||
title=""
|
title=""
|
||||||
data-tooltip
|
data-tooltip
|
||||||
class="publish-icon <%= published_status %>"
|
class="publish-icon <%= published_status %>"
|
||||||
|
@ -134,7 +137,7 @@
|
||||||
<div class="inline-block cog-menu-container">
|
<div class="inline-block cog-menu-container">
|
||||||
<a class="al-trigger al-trigger-gray" role="button" tabindex="0" href="#">
|
<a class="al-trigger al-trigger-gray" role="button" tabindex="0" href="#">
|
||||||
<i class="icon-settings"></i><i class="icon-mini-arrow-down"></i>
|
<i class="icon-settings"></i><i class="icon-mini-arrow-down"></i>
|
||||||
<span class="screenreader-only"><%= t('settings', 'Settings') %></span>
|
<span class="screenreader-only"><%= t('Manage %{item_name}', {item_name: tag && tag.title ? tag.title : 'item'}) %></span>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<ul class="al-options">
|
<ul class="al-options">
|
||||||
|
|
|
@ -1323,6 +1323,7 @@ define([
|
||||||
var publishData = {
|
var publishData = {
|
||||||
moduleType: data.type,
|
moduleType: data.type,
|
||||||
id: data.publishable_id,
|
id: data.publishable_id,
|
||||||
|
moduleItemName: data.moduleItemName,
|
||||||
moduleId: data.context_module_id,
|
moduleId: data.context_module_id,
|
||||||
courseId: data.context_id,
|
courseId: data.context_id,
|
||||||
published: data.published,
|
published: data.published,
|
||||||
|
@ -1376,7 +1377,8 @@ define([
|
||||||
model: file,
|
model: file,
|
||||||
togglePublishClassOn: $el.parents('.ig-row')[0],
|
togglePublishClassOn: $el.parents('.ig-row')[0],
|
||||||
userCanManageFilesForContext: ENV.MODULE_FILE_PERMISSIONS.manage_files,
|
userCanManageFilesForContext: ENV.MODULE_FILE_PERMISSIONS.manage_files,
|
||||||
usageRightsRequiredForContext: ENV.MODULE_FILE_PERMISSIONS.usage_rights_required
|
usageRightsRequiredForContext: ENV.MODULE_FILE_PERMISSIONS.usage_rights_required,
|
||||||
|
fileName: file.displayName()
|
||||||
}
|
}
|
||||||
|
|
||||||
React.render(PublishCloud(props), $el[0]);
|
React.render(PublishCloud(props), $el[0]);
|
||||||
|
@ -1389,13 +1391,26 @@ define([
|
||||||
id: data.id,
|
id: data.id,
|
||||||
module_id: data.moduleId,
|
module_id: data.moduleId,
|
||||||
module_item_id: data.moduleItemId,
|
module_item_id: data.moduleItemId,
|
||||||
|
module_item_name: data.moduleItemName,
|
||||||
course_id: data.courseId,
|
course_id: data.courseId,
|
||||||
published: data.published,
|
published: data.published,
|
||||||
publishable: data.publishable,
|
publishable: data.publishable,
|
||||||
unpublishable: data.unpublishable
|
unpublishable: data.unpublishable
|
||||||
});
|
});
|
||||||
|
|
||||||
var view = new PublishIconView({model: model, el: $el[0]});
|
var viewOptions = {
|
||||||
|
model: model,
|
||||||
|
el: $el[0]
|
||||||
|
};
|
||||||
|
|
||||||
|
if (data.publishMessage) {
|
||||||
|
viewOptions.publishText = data.publishMessage;
|
||||||
|
}
|
||||||
|
if (data.unpublishMessage) {
|
||||||
|
viewOptions.unpublishText = data.unpublishMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
var view = new PublishIconView(viewOptions);
|
||||||
var row = $el.closest('.ig-row');
|
var row = $el.closest('.ig-row');
|
||||||
|
|
||||||
if (data.published) { row.addClass('ig-published'); }
|
if (data.published) { row.addClass('ig-published'); }
|
||||||
|
|
|
@ -50,6 +50,24 @@ define [
|
||||||
equal btnView.$text.html().match(/Published/).length, 1
|
equal btnView.$text.html().match(/Published/).length, 1
|
||||||
equal btnView.$el.attr('aria-label').match(/can't unpublish/).length, 1
|
equal btnView.$el.attr('aria-label').match(/can't unpublish/).length, 1
|
||||||
|
|
||||||
|
test 'should render the provided publish text when given', ->
|
||||||
|
testText = 'Test Publish Text'
|
||||||
|
btnView = new PublishButtonView({
|
||||||
|
model: @publish,
|
||||||
|
publishText: testText
|
||||||
|
}).render()
|
||||||
|
|
||||||
|
equal btnView.$('.screenreader-only.accessible_label').text(), testText
|
||||||
|
|
||||||
|
test 'should render the provided unpublish text when given', ->
|
||||||
|
testText = 'Test Unpublish Text'
|
||||||
|
btnView = new PublishButtonView({
|
||||||
|
model: @published,
|
||||||
|
unpublishText: testText
|
||||||
|
}).render()
|
||||||
|
|
||||||
|
equal btnView.$('.screenreader-only.accessible_label').text(), testText
|
||||||
|
|
||||||
# state
|
# state
|
||||||
test 'disable should add disabled state', ->
|
test 'disable should add disabled state', ->
|
||||||
btnView = new PublishButtonView(model: @publish).render()
|
btnView = new PublishButtonView(model: @publish).render()
|
||||||
|
|
|
@ -41,7 +41,7 @@ describe 'editing a quiz' do
|
||||||
type_in_tiny('#quiz_description', 'changed description')
|
type_in_tiny('#quiz_description', 'changed description')
|
||||||
click_save_settings_button
|
click_save_settings_button
|
||||||
wait_for_ajax_requests
|
wait_for_ajax_requests
|
||||||
expect(f('#quiz-publish-link').text.strip!).to eq 'Published'
|
expect(f('#quiz-publish-link .publish-text').text.strip!).to eq 'Published'
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'deletes the quiz', priority: "1", test_id: 351921 do
|
it 'deletes the quiz', priority: "1", test_id: 351921 do
|
||||||
|
@ -54,7 +54,7 @@ describe 'editing a quiz' do
|
||||||
end
|
end
|
||||||
f('#quiz-publish-link').click
|
f('#quiz-publish-link').click
|
||||||
wait_for_ajax_requests
|
wait_for_ajax_requests
|
||||||
expect(f('#quiz-publish-link').text.strip!).to eq 'Publish'
|
expect(f('#quiz-publish-link .publish-text').text.strip!).to eq 'Publish'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -90,7 +90,7 @@ describe 'editing a quiz' do
|
||||||
end
|
end
|
||||||
f('#quiz-publish-link').click
|
f('#quiz-publish-link').click
|
||||||
wait_for_ajax_requests
|
wait_for_ajax_requests
|
||||||
expect(f('#quiz-publish-link').text.strip!).to eq 'Unpublish'
|
expect(f('#quiz-publish-link .publish-text').text.strip!).to eq 'Unpublish'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue