Adds move to option for modules
Makes the modules page more accessible for both screenreader and keyboard only users. fixes CNVS-9045 test plan: 1. Using a screenreader go to the modules page (/courses/##/modules) 2. The "keyboard instructions" area should inform you to use the move module options. 3. Navigate to the admin links cog for a module 4. You should see a "Move to..." option. 5. Click it using whatever the screenreader uses for click (VO: Ctrl+Option+Space) 6. A dialog should appear (This dialog should be accessible) 7. You should be able to move a module to whatever location you want. 8. Close the screenreader, repeat steps 3-7 using only the keyboard. 9. When the drag-and-drop handle has focus a warning should appear. Change-Id: Ie64b79ab6fa85d728fd97fba3842717b1a6ed99b Reviewed-on: https://gerrit.instructure.com/39806 Tested-by: Jenkins <jenkins@instructure.com> Reviewed-by: Jeremy Stanley <jeremy@instructure.com> QA-Review: Clare Strong <clare@instructure.com> Product-Review: Hilary Scharton <hilary@instructure.com>
This commit is contained in:
parent
8bfb31f251
commit
c930295ba6
|
@ -145,6 +145,34 @@
|
|||
border: none !important;
|
||||
}
|
||||
|
||||
input.move-module-label-spacer {
|
||||
margin-right: 10px;
|
||||
}
|
||||
.move-module-or {
|
||||
display: inline-block;
|
||||
width: 60px;
|
||||
margin-left: 20px;
|
||||
|
||||
}
|
||||
.move-module-select-spacer {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.drag_and_drop_warning {
|
||||
display: none;
|
||||
color: #fff;
|
||||
background-color: #DC3F3F;
|
||||
border: 1px dashed #fff;
|
||||
font-size: 12px;
|
||||
padding: 1px;
|
||||
z-index: 2;
|
||||
position: absolute;
|
||||
top: -20px;
|
||||
left: -1px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
</style>
|
||||
|
||||
<% if course_home %>
|
||||
|
@ -162,15 +190,9 @@
|
|||
<% end %>
|
||||
</div>
|
||||
|
||||
<div class="hidden-readable" tabindex="0" aria-label="keyboard instructions">
|
||||
<%= t('modules_keyboard_hint',
|
||||
'To change the order of the course modules and module items,
|
||||
first turn the cursor off on your screen reader. Insert-z in JAWS.
|
||||
Press tab to select the first module.
|
||||
Press up and down to choose a module or module item.
|
||||
Press space to select the module or module item to start dragging.
|
||||
Then press up and down to select a destination.
|
||||
Then press space a second time to drop selection after destination.') %>
|
||||
<div class="hidden-readable screenreader-only" tabindex="0" aria-label="keyboard instructions">
|
||||
<%= t('modules_keyboard_hint_updated',
|
||||
'Warning: For improved accessibility, please use the Move To Dialog option found in the menu.') %>
|
||||
</div>
|
||||
|
||||
<% keyboard_navigation([
|
||||
|
@ -215,6 +237,26 @@ TEXT
|
|||
<%= render :partial => 'context_modules/module_item_next', :object => nil, :locals => {:editable => editable} %>
|
||||
|
||||
<% if can_do(@context, @current_user, :manage_content) %>
|
||||
<form id="move_context_module_form" style="display:none" class="form-dialog" title="Move Module">
|
||||
<div class="form-dialog-content">
|
||||
<h2>Place <span id="move_module_name"> </span></h2>
|
||||
<div class="move-module-before-after-container">
|
||||
<input type="radio" name="move_location" value="before" id="move_location_before" class="move-module-label-spacer" /><label class="move-module-label-width" for="move_location_before"><%= t('move_module.before', "Before") %></label>
|
||||
<strong class="move-module-or">OR</strong>
|
||||
<input type="radio" name="move_location" value="after" id="move_location_after" class="move-module-label-spacer" /><label class="move-module-label-width" for="move_location_after"><%= t('move_module.after', "After") %></label>
|
||||
</div>
|
||||
<div class="move-module-select-spacer">
|
||||
<select name="move_context_module_select" id="move_context_module_select"></select>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="form-controls">
|
||||
<button type="button" id="move_module_cancel_btn" class="btn">Cancel</button>
|
||||
<button type="submit" class="btn btn-primary">Move</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
|
||||
<%= form_for :context_module, :url => context_url(@context, :context_context_modules_url), :html => {:id => "add_context_module_form", :style => "display: none;"} do |f| %>
|
||||
<table class="formtable">
|
||||
<tr>
|
||||
|
@ -377,8 +419,8 @@ TEXT
|
|||
<tr>
|
||||
<td class="left">
|
||||
<div style="display: none;">
|
||||
<%= before_label('sort_by', %{Sort By}) %>
|
||||
<a href="#"><%= t('links.sort_by_name', %{Name}) %></a> |
|
||||
<%= before_label('sort_by', %{Sort By}) %>
|
||||
<a href="#"><%= t('links.sort_by_name', %{Name}) %></a> |
|
||||
<a href="#"><%= t('links.sort_by_progress', %{Progress}) %></a>
|
||||
</div>
|
||||
<ul class="side_tabs student_list">
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<%
|
||||
<%
|
||||
context_module = context_module_next
|
||||
editable ||= can_do(@context, @current_user, :manage_content)
|
||||
workflow_state = context_module && context_module.workflow_state
|
||||
|
@ -24,6 +24,10 @@
|
|||
title="<%= t('reorder_modules', %{Drag to reorder modules}) %>"
|
||||
style="<%= hidden unless @modules.length > 1 && editable %>"
|
||||
>
|
||||
<span class="drag_and_drop_warning">
|
||||
<%= t('modules_keyboard_drag_and_drop',
|
||||
'Warning: For improved accessibility, please use the Move To Dialog option found in the menu.') %>
|
||||
</span>
|
||||
<a aria-label="<%= t('reorder_modules', 'Drag to reorder modules') %>" href="#" class="icon-drag-handle"></a>
|
||||
</span>
|
||||
<a
|
||||
|
@ -81,13 +85,19 @@
|
|||
<i class="icon-settings"></i><i class="icon-mini-arrow-down"></i>
|
||||
</button>
|
||||
<ul class="al-options">
|
||||
<li>
|
||||
<li role="presentation">
|
||||
<a
|
||||
href="<%= context_url(@context, :context_url) %>/modules/<%= context_module ? context_module.id : "{{ id }}" %>"
|
||||
class="icon-edit edit_module_link"
|
||||
title="<%= t('links.title.edit_module', %{Edit}) %>"><%= t('links.text.edit_module', %{Edit}) %></a>
|
||||
</li>
|
||||
<li>
|
||||
<li role="presentation">
|
||||
<a
|
||||
href="#<%= context_module ? context_module.id : "{{ id }}" %>"
|
||||
class="move_module_link icon-updown"
|
||||
title="<%= t('links.title.move_module', %{Move this module}) %>"><%= t('links.text.move_module', %{Move To...}) %></a>
|
||||
</li>
|
||||
<li role="presentation">
|
||||
<a
|
||||
href="<%= context_url(@context, :context_url) %>/modules/<%= context_module ? context_module.id : "{{ id }}" %>"
|
||||
class="delete_module_link icon-trash"
|
||||
|
|
|
@ -126,7 +126,7 @@ define([
|
|||
.find(".progression_complete").showIf(data.progression_complete_count > 0).end()
|
||||
.find(".progression_started").showIf(data.progression_started_count > 0);
|
||||
});
|
||||
|
||||
|
||||
$(".context_module .progression_complete").showIf($(".context_module .prerequisites_footer:visible,.context_module_item .criterion img.not_blank").length > 0);
|
||||
if(show_links) {
|
||||
$(".loading_module_progressions_link").remove();
|
||||
|
@ -176,7 +176,7 @@ define([
|
|||
var progression = data.context_module_progression;
|
||||
if(progression.user_id == current_user_id) {
|
||||
var $user_progression = $user_progression_list.find(".progression_" + progression.context_module_id)
|
||||
|
||||
|
||||
if($user_progression.length === 0 && $user_progression_list.length > 0) {
|
||||
$user_progression = $user_progression_list.find(".progression_blank").clone(true);
|
||||
$user_progression.removeClass('progression_blank').addClass('progression_' + progression.context_module_id);
|
||||
|
@ -248,6 +248,61 @@ define([
|
|||
$this.attr('title', content_tag.title);
|
||||
});
|
||||
},
|
||||
showMoveModule: function ($module) {
|
||||
var $form = $('#move_context_module_form');
|
||||
$form.data('current_module', $module);
|
||||
// Set the module name
|
||||
$('#move_module_name').text($module.children('.header').children('.collapse_module_link').children('.name').text());
|
||||
|
||||
// Get current module ordering
|
||||
var currentOrdering = [];
|
||||
var selectOptions = [];
|
||||
|
||||
$("#context_modules .context_module").each(function() {
|
||||
var id = $(this).attr('id').substring('context_module_'.length);
|
||||
var name = $(this).children('.header').children('.collapse_module_link').children('.name').text();
|
||||
currentOrdering.push({
|
||||
'id': id,
|
||||
'name': name
|
||||
});
|
||||
selectOptions.push('<option value="' + id + '">' + name + '</option>');
|
||||
});
|
||||
|
||||
var data = $module.getTemplateData({textValues: ['name', 'unlock_at', 'require_sequential_progress', 'publish_final_grade']});
|
||||
$('#move_context_module_select').append(selectOptions.join(''));
|
||||
//$form.fillFormData(data, {object_name: 'context_module'});
|
||||
$form.dialog({
|
||||
autoOpen: false,
|
||||
modal: true,
|
||||
width: 600,
|
||||
height: 300,
|
||||
close: function () {
|
||||
modules.hideMoveModule(true);
|
||||
}
|
||||
}).dialog('open');
|
||||
$module.removeClass('dont_remove');
|
||||
// $form.find('.ui-dialog-titlebar-close').focus();
|
||||
|
||||
},
|
||||
hideMoveModule: function (remove) {
|
||||
$('#move_context_module_form:visible').dialog('close');
|
||||
},
|
||||
submitMoveModule: function () {
|
||||
var beforeOrAfterVal = $('[name="move_location"]:checked').val();
|
||||
var currentModule = $('#move_context_module_form').data('current_module');
|
||||
var relativeToId = $('#move_context_module_select').val();
|
||||
|
||||
if (beforeOrAfterVal === 'before') {
|
||||
$('#context_module_' + relativeToId).before(currentModule);
|
||||
}
|
||||
if (beforeOrAfterVal === 'after') {
|
||||
$('#context_module_' + relativeToId).after(currentModule);
|
||||
}
|
||||
modules.hideMoveModule();
|
||||
modules.updateModulePositions();
|
||||
|
||||
},
|
||||
|
||||
editModule: function($module) {
|
||||
var $form = $("#add_context_module_form");
|
||||
$form.data('current_module', $module);
|
||||
|
@ -420,7 +475,7 @@ define([
|
|||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
for (var val in result.to_visit) {
|
||||
if (result.to_visit.hasOwnProperty(val)) {
|
||||
var ids = val.split("_");
|
||||
|
@ -480,10 +535,10 @@ define([
|
|||
}
|
||||
};
|
||||
})();
|
||||
|
||||
|
||||
|
||||
modules.initModuleManagement = function() {
|
||||
// Create the context modules backbone view to manage the publish button.
|
||||
// Create the context modules backbone view to manage the publish button.
|
||||
var context_modules_view = new ContextModulesView({
|
||||
el: $("#content"),
|
||||
modules: modules
|
||||
|
@ -731,6 +786,8 @@ define([
|
|||
$(this).remove();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
$(".delete_module_link").live('click', function(event) {
|
||||
event.preventDefault();
|
||||
$(this).parents(".context_module").confirmDelete({
|
||||
|
@ -816,6 +873,27 @@ define([
|
|||
});
|
||||
});
|
||||
|
||||
$('.move_module_link').on('click keyclick', function (event) {
|
||||
event.preventDefault();
|
||||
modules.showMoveModule($(this).parents('.context_module'));
|
||||
});
|
||||
|
||||
$('#move_context_module_form').on('submit', function (event) {
|
||||
event.preventDefault();
|
||||
modules.submitMoveModule();
|
||||
});
|
||||
|
||||
$('#move_module_cancel_btn').on('click keyclick', function (event) {
|
||||
modules.hideMoveModule();
|
||||
});
|
||||
|
||||
$('.icon-drag-handle').on('focus', function (event) {
|
||||
$(event.currentTarget).siblings('.drag_and_drop_warning').show();
|
||||
});
|
||||
$('.icon-drag-handle').on('blur', function (event) {
|
||||
$(event.currentTarget).siblings('.drag_and_drop_warning').hide();
|
||||
});
|
||||
|
||||
$(".edit_module_link").live('click', function(event) {
|
||||
event.preventDefault();
|
||||
modules.editModule($(this).parents(".context_module"));
|
||||
|
@ -1202,11 +1280,11 @@ define([
|
|||
if($("#context_modules").hasClass('editable')) {
|
||||
setTimeout(modules.initModuleManagement, 1000);
|
||||
}
|
||||
|
||||
|
||||
modules.updateProgressions();
|
||||
modules.refreshProgressions();
|
||||
modules.updateAssignmentData();
|
||||
|
||||
|
||||
$(".context_module").find(".expand_module_link,.collapse_module_link").bind('click', function(event, goSlow) {
|
||||
event.preventDefault();
|
||||
var expandCallback = null;
|
||||
|
@ -1304,7 +1382,7 @@ define([
|
|||
var $module = $(this);
|
||||
var moduleData = $module.find(".header").getTemplateData({textValues: ['id', 'name']});
|
||||
var $row = $("#student_progression_dialog .module_" + moduleData.id);
|
||||
|
||||
|
||||
moduleData.progress = $studentWithProgressions.find(".progression_" + moduleData.id + ":first").getTemplateData({textValues: ['workflow_state']}).workflow_state;
|
||||
moduleData.progress = moduleData.progress || "no information";
|
||||
var type = "nothing";
|
||||
|
@ -1387,12 +1465,12 @@ define([
|
|||
var $module = $(this);
|
||||
var moduleData = $module.find(".header").getTemplateData({textValues: ['id', 'name']});
|
||||
var $template = $dialog.find(".module.blank:first").clone(true).removeClass('blank');
|
||||
|
||||
|
||||
$template.addClass('module_' + moduleData.id);
|
||||
$template.fillTemplateData({data: moduleData});
|
||||
$dialog.find(".side_tabs_content tbody").append($template.show());
|
||||
});
|
||||
|
||||
|
||||
$("#student_progression_dialog").dialog({
|
||||
width: 800,
|
||||
open: function() {
|
||||
|
|
Loading…
Reference in New Issue