Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixed accessibility issues in Schedule Tab in CCX #9114

Merged
merged 1 commit into from
Aug 14, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
112 changes: 84 additions & 28 deletions lms/static/js/ccx/schedule.js
Original file line number Diff line number Diff line change
Expand Up @@ -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') {
Expand 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();
Expand All @@ -139,37 +139,42 @@ 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 <span class="sr"> ' +
gettext("Click to change") + '</span>');
}
});

// 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;
self.schedule_collection.set(self.schedule);
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();
});


Expand All @@ -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();
Expand All @@ -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',
Expand All @@ -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"));
Expand Down Expand Up @@ -290,32 +301,77 @@ 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');
var modal = $('#enter-date-modal')
.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(' ') : ['', ''],
Expand Down
2 changes: 1 addition & 1 deletion lms/static/js/spec/ccx/schedule_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
});
Expand Down
19 changes: 19 additions & 0 deletions lms/static/sass/course/ccx_coach/_dashboard.scss
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}
3 changes: 2 additions & 1 deletion lms/templates/ccx/coach_dashboard.html
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ <h1>${_("CCX Coach Dashboard")}</h1>
<section>
<form action="${create_ccx_url}" method="POST">
<input type="hidden" name="csrfmiddlewaretoken" value="${csrf_token}"/>
<input name="name" placeholder="Name your CCX"/><br/>
<label class="sr" for="ccx_name">${_('Name your CCX')}</label>
<input name="name" id="ccx_name" placeholder="${_('Name your CCX')}"/><br/>
<button id="create-ccx">Coach a new Custom Course for EdX</button>
</form>
</section>
Expand Down
97 changes: 63 additions & 34 deletions lms/templates/ccx/schedule.html
Original file line number Diff line number Diff line change
Expand Up @@ -29,22 +29,24 @@
<div id="new-ccx-schedule"></div>
</div>

<section id="enter-date-modal" class="modal" aria-hidden="true">
<div class="inner-wrapper" role="dialog">
<section id="enter-date-modal" class="modal"
tabindex="-1" role="dialog" aria-labelledby="ccx_schedule_set_date_heading">
<div class="inner-wrapper">
<button class="close-modal">
<i class="icon fa fa-remove"></i>
<span class="sr">
${_("Close")}
</span>
<i class="icon fa fa-remove" aria-hidden="true"></i>
<span class="sr">${_("Close")}</span>
</button>
<header>
<h2></h2>
<h2 id="ccx_schedule_set_date_heading"></h2>
</header>
<form role="form">
<form>
<div class="field datepair">
<label></label>
<input placeholder="Date" class="date" type="text" name="date"/ size="11">
<input placeholder="Time" class="time" type="text" name="time"/ size="6">
## Translators: This explains to people using a screen reader how to interpret the format of YYYY-MM-DD
<label class="sr" for="ccx_dialog_date">${_('Date format four digit year dash two digit month dash two digit day')}</label>
<input placeholder="Date" class="date" type="text" name="date" id="ccx_dialog_date" size="11" />
## Translators: This explains to people using a screen reader how to interpret the format of HH:MM
<label class="sr" for="ccx_dialog_time">${_('Time format two digit hours colon two digit minutes')}</label>
<input placeholder="Time" class="time" type="text" name="time" id="ccx_dialog_time" size="6" />
</div>
<div class="field">
<button type="submit" class="btn btn-primary">${_('Set date')}</button>
Expand All @@ -54,44 +56,62 @@ <h2></h2>
</section>

<div class="ccx-schedule-sidebar">
<div class="ccx-sidebar-panel" id="dirty-schedule">
<h2>${_('Save changes')}</h2>
<form role="form">
<p>${_("You have unsaved changes.")}</p>
<div class="ccx-sidebar-panel" id="dirty-schedule" tabindex="-1" role="region"
aria-labelledby="ccx_schedule_save_changes_heading">
<h2 id="ccx_schedule_save_changes_heading">${_('Save changes')}</h2>
<form>
<p id="message_save">${_("You have unsaved changes.")}</p>
<div class="field">
<br/>
<button id="save-changes">${_("Save changes")}</button>
<button id="save-changes" aria-describedby="message_save">${_("Save changes")}</button>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this aria-describedby that alerts the user that there are unsaved changes is a nice touch 👍

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks

</div>
</form>
</div>
<div class="ccx-sidebar-panel" id="ajax-error">
<div class="ccx-sidebar-panel" id="ajax-error" tabindex="-1" role="region" aria-labelledby="ccx_schedule_error_message">
<h2>${_('Error')}</h2>
<p>${_("There was an error saving changes.")}</p>
<p id="ccx_schedule_error_message">${_("There was an error saving changes.")}</p>
</div>
<div class="ccx-sidebar-panel">
<h2>${_('Schedule a Unit')}</h2>
<div class="ccx-sidebar-panel" aria-labelledby="ccx_schedule_unit"
id="ccx_schedule_unit_panel" role="region">
<h2 id="ccx_schedule_unit">${_('Schedule a Unit')}</h2>
<form role="form" id="add-unit" name="add-unit" class="ccx-form">
<div class="field">
<b>${_('Section')}</b><br/>
<select name="chapter"></select>
<label for="ccx_chapter"><b>${_('Section')}</b></label>
<select name="chapter" id="ccx_chapter" ></select>
</div>
<div class="field">
<b>${_('Subsection')}</b><br/>
<select name="sequential"></select>
<label for="ccx_sequential"><b>${_('Subsection')}</b></label>
<select name="sequential" id="ccx_sequential"></select>
</div>
<div class="field">
<b>${_('Unit')}</b><br/>
<select name="vertical"></select>
<label for="ccx_vertical"><b>${_('Unit')}</b></label>
<select name="vertical" id="ccx_vertical"></select>
</div>
<div class="field datepair">
<b>${_('Start Date')}</b><br/>
<input placeholder="Date" type="date" class="date" name="start_date"/>
<input placeholder="time" type="time" class="time" name="start_time"/>
<label for="ccx_start_date">
<b>${_('Start Date')}</b>
<span class="sr">
## Translators: This explains to people using a screen reader how to interpret the format of YYYY-MM-DD
&nbsp;${_('format four digit year dash two digit month dash two digit day')}
</span>
</label>
<input placeholder="yyyy-mm-dd" type="text" class="date" name="start_date" id="ccx_start_date" />
## Translators: This explains to people using a screen reader how to interpret the format of HH:MM
<label for="ccx_start_time" class="sr">${_('Start time format two digit hours colon two digit minutes')}</label>
<input placeholder="time" type="text" class="time" name="start_time" id="ccx_start_time"/>
</div>
<div class="field datepair">
<b>${_('Due Date')}</b> ${_('(Optional)')}<br/>
<input placeholder="Date" type="date" class="date" name="due_date"/>
<input placeholder="time" type="time" class="time" name="due_time"/>
<label for="ccx_due_date">
<b>${_('Due Date')}</b> ${_('(Optional)')}
<span class="sr">
## Translators: This explains to people using a screen reader how to interpret the format of YYYY-MM-DD
&nbsp;${_('format four digit year dash two digit month dash two digit day')}
</span>
</label>
<input placeholder="yyyy-mm-dd" type="text" class="date" name="due_date" id="ccx_due_date"/>
## Translators: This explains to people using a screen reader how to interpret the format of HH:MM
<label for="ccx_due_time" class="sr">${_('Due Time format two digit hours colon two digit minutes')}</label>
<input placeholder="time" type="text" class="time" name="due_time" id="ccx_due_time"/>
</div>
<div class="field">
<br/>
Expand All @@ -102,7 +122,7 @@ <h2>${_('Schedule a Unit')}</h2>
<button id="add-all">${_('Add All Units')}</button>
</div>
</form>
<div id="all-units-added">
<div id="all-units-added" tabindex="-1" role="region">
${_("All units have been added.")}
</div>
</div>
Expand All @@ -118,11 +138,20 @@ <h2>${_('Schedule a Unit')}</h2>
//ccx_schedule.render();
$('.datepair .time').timepicker({
'showDuration': true,
'timeFormat': 'G:i'
'timeFormat': 'G:i',
'autoclose': true
});
$('.datepair .date').datepicker({
'dateFormat': 'yy-mm-dd',
'autoclose': true
});
$('.datepair .date').change(function() {
var date = $(this).datepicker( "getDate" );
if (date) {
$(this).val(date.getFullYear() + "-" +
('0' + (date.getMonth() + 1)).slice(-2) + "-" +
('0' + date.getDate()).slice(-2));
}
});
});
</script>
Loading