From 4c8e45c75d8273841964bc991452774d37ac1de5 Mon Sep 17 00:00:00 2001 From: Amir Qayyum Khan Date: Thu, 23 Jul 2015 13:00:21 +0500 Subject: [PATCH] Fixed accessibility related issues on schedule tab inside CCX coach dashboard --- lms/static/js/ccx/schedule.js | 112 +++++++++++++----- lms/static/js/spec/ccx/schedule_spec.js | 2 +- .../sass/course/ccx_coach/_dashboard.scss | 19 +++ lms/templates/ccx/coach_dashboard.html | 3 +- lms/templates/ccx/schedule.html | 97 +++++++++------ lms/templates/ccx/schedule.underscore | 92 ++++++++++---- 6 files changed, 239 insertions(+), 86 deletions(-) diff --git a/lms/static/js/ccx/schedule.js b/lms/static/js/ccx/schedule.js index 9a19b996fe96..fa50bf67c49b 100644 --- a/lms/static/js/ccx/schedule.js +++ b/lms/static/js/ccx/schedule.js @@ -86,9 +86,9 @@ var edx = edx || {}; } else { self.vertical_select.html('').prop('disabled', true); - } + } }); - + this.vertical_select.on('change', function() { var vertical_location = self.vertical_select.val(); if (vertical_location !== 'all') { @@ -115,9 +115,9 @@ var edx = edx || {}; due = self.get_datetime('due'); units.map(self.show); var unit = units[units.length - 1]; - self.schedule_apply([unit], self.show); if (unit !== undefined && start) { unit.start = start; } if (unit !== undefined && due) { unit.due = due; } + self.schedule_apply([unit], self.show); self.schedule_collection.set(self.schedule); self.dirty = true; self.render(); @@ -139,22 +139,27 @@ var edx = edx || {}; return !node.hidden;}); this.$el.html(schedule_template({chapters: this.showing})); $('table.ccx-schedule .sequential,.vertical').hide(); - $('table.ccx-schedule .toggle-collapse').on('click', this.toggle_collapse); + $('table.ccx-schedule .unit .toggle-collapse').on('click', this.toggle_collapse); // // Hidden hover fields for empty date fields - $('table.ccx-schedule .date a').each(function() { - if (! $(this).text()) { - $(this).text('Set date').addClass('empty'); + $('table.ccx-schedule .date button').each(function() { + if ($(this).text().trim() === gettext("Click to change")) { + $(this).html('Set date ' + + gettext("Click to change") + ''); } }); - + // Handle date edit clicks - $('table.ccx-schedule .date a').attr('href', '#enter-date-modal') + $('table.ccx-schedule .date button').attr('href', '#enter-date-modal') .leanModal({closeButton: '.close-modal'}); - $('table.ccx-schedule .due-date a').on('click', this.enterNewDate('due')); - $('table.ccx-schedule .start-date a').on('click', this.enterNewDate('start')); + $('table.ccx-schedule .due-date button').on('click', this.enterNewDate('due')); + $('table.ccx-schedule .start-date button').on('click', this.enterNewDate('start')); + // click handler for expand all + $('#ccx_expand_all_btn').on('click', self.expandAll); + // click handler for collapse all + $('#ccx_collapse_all_btn').on('click', self.collapseAll); // Click handler for remove all - $('table.ccx-schedule a#remove-all').on('click', function(event) { + $('table.ccx-schedule button#remove-all').on('click', function(event) { event.preventDefault(); self.schedule_apply(self.schedule, self.hide); self.dirty = true; @@ -162,14 +167,14 @@ var edx = edx || {}; self.render(); }); // Remove unit handler - $('table.ccx-schedule a.remove-unit').on('click', function() { + $('table.ccx-schedule button.remove-unit').on('click', function() { var row = $(this).closest('tr'), path = row.data('location').split(' '), unit = self.find_unit(self.schedule, path[0], path[1], path[2]); self.schedule_apply([unit], self.hide); self.schedule_collection.set(self.schedule); self.dirty = true; - self.render(); + self.render(); }); @@ -191,7 +196,13 @@ var edx = edx || {}; } // Show or hide save button - if (this.dirty) {$('#dirty-schedule').show();} + if (this.dirty) { + $('#dirty-schedule').show(); + $('html, body').animate( + { scrollTop: $('#dirty-schedule').offset().top }, + 'slow', function() {$('#dirty-schedule').focus();} + ); + } else {$('#dirty-schedule').hide();} $('#ajax-error').hide(); @@ -202,8 +213,8 @@ var edx = edx || {}; save: function() { self.schedule_collection.set(self.schedule); var button = $('#dirty-schedule #save-changes'); - button.prop('disabled', true).text(gettext("Saving")+'...'); - + button.prop('disabled', true).text(gettext("Saving")); + $.ajax({ url: save_url, type: 'POST', @@ -213,14 +224,14 @@ var edx = edx || {}; self.dirty = false; self.render(); button.prop('disabled', false).text(gettext("Save changes")); - + // Update textarea with grading policy JSON, since grading policy - // may have changed. + // may have changed. $('#grading-policy').text(data.grading_policy); }, error: function(jqXHR) { console.log(jqXHR.responseText); - $('#ajax-error').show(); + $('#ajax-error').show().focus(); $('#dirty-schedule').hide(); $('form#add-unit select,input,button').prop('disabled', true); button.prop('disabled', false).text(gettext("Save changes")); @@ -290,21 +301,49 @@ var edx = edx || {}; var children = self.get_children(row); if (row.is('.expanded')) { - $(this).removeClass('fa-caret-down').addClass('fa-caret-right'); + $(this).attr('aria-expanded', 'false'); + $(this).find(".fa-caret-down").removeClass('fa-caret-down').addClass('fa-caret-right'); row.removeClass('expanded').addClass('collapsed'); - children.hide(); + children.hide(); } else { - $(this).removeClass('fa-caret-right').addClass('fa-caret-down'); + $(this).attr('aria-expanded', 'true'); + $(this).find(".fa-caret-right").removeClass('fa-caret-right').addClass('fa-caret-down'); row.removeClass('collapsed').addClass('expanded'); children.filter('.collapsed').each(function() { children = children.not(self.get_children(this)); }); - children.show(); + children.show(); } }, + expandAll : function() { + $('table.ccx-schedule > tbody > tr').each(function() { + var row = $(this); + if (!row.is('.expanded')) { + var children = self.get_children(row); + row.find(".ccx_sr_alert").attr("aria-expanded", "true"); + row.find(".fa-caret-right").removeClass('fa-caret-right').addClass('fa-caret-down'); + row.removeClass('collapsed').addClass('expanded'); + children.filter('.collapsed').each(function() { + children = children.not(self.get_children(this)); + }); + children.show(); + } + }); + }, + collapseAll: function() { + $('table.ccx-schedule > tbody > tr').each(function() { + var row = $(this); + if (row.is('.expanded')) { + $(row).find('.ccx_sr_alert').attr('aria-expanded', 'false'); + $(row).find('.fa-caret-down').removeClass('fa-caret-down').addClass('fa-caret-right'); + row.removeClass('expanded').addClass('collapsed'); + $('table.ccx-schedule .sequential,.vertical').hide(); + } + }); + }, enterNewDate: function(what) { return function() { var row = $(this).closest('tr'); @@ -312,10 +351,27 @@ var edx = edx || {}; .data('what', what) .data('location', row.data('location')); modal.find('h2').text( - what === 'due' ? gettext("Enter Due Date") : - gettext("Enter Start Date")); - modal.find('label').text(row.find('td:first').text()); - + what === 'due' ? gettext("Enter Due Date and Time") : + gettext("Enter Start Date and Time")); + + modal.focus(); + + $(document).on('focusin', function(event) { + try { + if (!_.isUndefined(event.target.closest('.modal').id) && + event.target.closest('.modal').id !== 'enter-date-modal' && + event.target.id !== 'enter-date-modal') { + event.preventDefault(); + modal.find('.close-modal').focus(); + } + } catch (err) { + event.preventDefault(); + modal.find('.close-modal').focus(); + } + }); + modal.find('.close-modal').click(function () { + $(document).off('focusin'); + }); var path = row.data('location').split(' '), unit = self.find_unit(self.schedule, path[0], path[1], path[2]), parts = unit[what] ? unit[what].split(' ') : ['', ''], diff --git a/lms/static/js/spec/ccx/schedule_spec.js b/lms/static/js/spec/ccx/schedule_spec.js index 288e5cef7c12..01364a680f1c 100644 --- a/lms/static/js/spec/ccx/schedule_spec.js +++ b/lms/static/js/spec/ccx/schedule_spec.js @@ -164,7 +164,7 @@ define(['common/js/spec_helpers/ajax_helpers', 'js/ccx/schedule'], view.save(); expect(requests.length).toEqual(1) AjaxHelpers.expectJsonRequest(requests, 'POST', 'save_ccx', view.schedule); - expect($('#dirty-schedule #save-changes').text()).toEqual("Saving..."); + expect($('#dirty-schedule #save-changes').text()).toEqual("Saving"); AjaxHelpers.respondWithJson(requests, { data: view.schedule }); diff --git a/lms/static/sass/course/ccx_coach/_dashboard.scss b/lms/static/sass/course/ccx_coach/_dashboard.scss index 0d96f64e33e4..f9a6fba50da2 100644 --- a/lms/static/sass/course/ccx_coach/_dashboard.scss +++ b/lms/static/sass/course/ccx_coach/_dashboard.scss @@ -55,3 +55,22 @@ form.ccx-form { margin: 5px 0 5px 0; } } + +button.ccx-button-link { + background: none; + border: none; + padding: 0; + color: #069; + cursor: pointer; + &:after { + content: "\00a0 "; + } + &:active { + background: none; + border: none; + padding: 0; + } + &:hover { + color: brown; + } +} diff --git a/lms/templates/ccx/coach_dashboard.html b/lms/templates/ccx/coach_dashboard.html index 41c34f3e3dd7..529ccda196b3 100644 --- a/lms/templates/ccx/coach_dashboard.html +++ b/lms/templates/ccx/coach_dashboard.html @@ -38,7 +38,8 @@

${_("CCX Coach Dashboard")}

-
+ +
diff --git a/lms/templates/ccx/schedule.html b/lms/templates/ccx/schedule.html index 10c8e9579438..a8cfe9b5d41c 100644 --- a/lms/templates/ccx/schedule.html +++ b/lms/templates/ccx/schedule.html @@ -29,22 +29,24 @@
-