From a14e6f0a7eef75e55d8e430fccbc120b4fd249ed Mon Sep 17 00:00:00 2001
From: Usman Khalid <2200617@gmail.com>
Date: Mon, 20 Apr 2015 15:29:38 +0500
Subject: [PATCH] Accessibility tweaks for account settings and profile pages.
TNL-1660
---
.../account_settings_factory_spec.js | 6 +-
lms/static/js/spec/student_account/helpers.js | 8 +--
lms/static/js/spec/views/fields_helpers.js | 14 ++--
lms/static/js/spec/views/fields_spec.js | 9 ++-
.../views/account_settings_fields.js | 2 +-
.../views/learner_profile_factory.js | 5 +-
.../views/learner_profile_fields.js | 4 +-
lms/static/js/views/fields.js | 67 +++++++++++++------
lms/static/sass/shared/_fields.scss | 10 +++
.../fields/field_dropdown.underscore | 31 ++++-----
.../fields/field_readonly.underscore | 5 +-
.../fields/field_textarea.underscore | 2 +-
.../student_account/account_settings.html | 1 +
.../student_profile/learner_profile.html | 1 +
14 files changed, 105 insertions(+), 60 deletions(-)
diff --git a/lms/static/js/spec/student_account/account_settings_factory_spec.js b/lms/static/js/spec/student_account/account_settings_factory_spec.js
index 6442e400f6..7685e8bed9 100644
--- a/lms/static/js/spec/student_account/account_settings_factory_spec.js
+++ b/lms/static/js/spec/student_account/account_settings_factory_spec.js
@@ -161,7 +161,8 @@ define(['backbone', 'jquery', 'underscore', 'js/common_helpers/ajax_helpers', 'j
validValue: 'My Name',
invalidValue1: '',
invalidValue2: '@',
- validationError: "Think again!"
+ validationError: "Think again!",
+ defaultValue: ''
}, requests);
}
@@ -180,7 +181,8 @@ define(['backbone', 'jquery', 'underscore', 'js/common_helpers/ajax_helpers', 'j
validValue: Helpers.FIELD_OPTIONS[1][0],
invalidValue1: Helpers.FIELD_OPTIONS[2][0],
invalidValue2: Helpers.FIELD_OPTIONS[3][0],
- validationError: "Nope, this will not do!"
+ validationError: "Nope, this will not do!",
+ defaultValue: null
}, requests);
});
diff --git a/lms/static/js/spec/student_account/helpers.js b/lms/static/js/spec/student_account/helpers.js
index 8d0266e515..97001265b3 100644
--- a/lms/static/js/spec/student_account/helpers.js
+++ b/lms/static/js/spec/student_account/helpers.js
@@ -15,12 +15,12 @@ define(['underscore'], function(_) {
username: 'student',
name: 'Student',
email: 'student@edx.org',
- level_of_education: '',
- gender: '',
+ level_of_education: null,
+ gender: null,
year_of_birth: '3', // Note: test birth year range is a string from 0-3
requires_parental_consent: false,
- country: '',
- language: '',
+ country: '1',
+ language: null,
bio: "About the student",
language_proficiencies: [{code: '1'}],
profile_image: PROFILE_IMAGE
diff --git a/lms/static/js/spec/views/fields_helpers.js b/lms/static/js/spec/views/fields_helpers.js
index 6898ffa067..6a69383d3a 100644
--- a/lms/static/js/spec/views/fields_helpers.js
+++ b/lms/static/js/spec/views/fields_helpers.js
@@ -114,7 +114,7 @@ define(['backbone', 'jquery', 'underscore', 'js/common_helpers/ajax_helpers', 'j
expectMessageContains(view, view.helpMessage);
view.showSuccessMessage();
expectMessageContains(view, view.indicators.success);
- jasmine.Clock.tick(5000);
+ jasmine.Clock.tick(7000);
// Message gets reset
expectMessageContains(view, view.helpMessage);
@@ -122,7 +122,7 @@ define(['backbone', 'jquery', 'underscore', 'js/common_helpers/ajax_helpers', 'j
expectMessageContains(view, view.indicators.success);
// But if we change the message, it should not get reset.
view.showHelpMessage("Do not reset this!");
- jasmine.Clock.tick(5000);
+ jasmine.Clock.tick(7000);
expectMessageContains(view, "Do not reset this!");
};
@@ -138,9 +138,11 @@ define(['backbone', 'jquery', 'underscore', 'js/common_helpers/ajax_helpers', 'j
} else {
expectTitleAndMessageToContain(view, data.title, data.helpMessage, false);
}
-
expect(view.el).toHaveClass('mode-edit');
- expect(view.fieldValue()).not.toContain(data.validValue);
+
+ if (view.fieldValue() !== null) {
+ expect(view.fieldValue()).not.toContain(data.validValue);
+ }
view.$(data.valueInputSelector).val(data.validValue).change();
// When the value in the field is changed
@@ -185,8 +187,8 @@ define(['backbone', 'jquery', 'underscore', 'js/common_helpers/ajax_helpers', 'j
view.$(data.valueInputSelector).val('').change();
// When the value in the field is changed
- expect(view.fieldValue()).toBe('');
- request_data[data.valueAttribute] = '';
+ expect(view.fieldValue()).toBe(data.defaultValue);
+ request_data[data.valueAttribute] = data.defaultValue;
AjaxHelpers.expectJsonRequest(
requests, 'PATCH', url, request_data
);
diff --git a/lms/static/js/spec/views/fields_spec.js b/lms/static/js/spec/views/fields_spec.js
index 06a3e6bb74..6514c9c61b 100644
--- a/lms/static/js/spec/views/fields_spec.js
+++ b/lms/static/js/spec/views/fields_spec.js
@@ -121,7 +121,8 @@ define(['backbone', 'jquery', 'underscore', 'js/common_helpers/ajax_helpers', 'j
validValue: 'My Name',
invalidValue1: 'Your Name',
invalidValue2: 'Her Name',
- validationError: "Think again!"
+ validationError: "Think again!",
+ defaultValue: ''
}, requests);
});
@@ -164,7 +165,8 @@ define(['backbone', 'jquery', 'underscore', 'js/common_helpers/ajax_helpers', 'j
validValue: FieldViewsSpecHelpers.SELECT_OPTIONS[0][0],
invalidValue1: FieldViewsSpecHelpers.SELECT_OPTIONS[1][0],
invalidValue2: FieldViewsSpecHelpers.SELECT_OPTIONS[2][0],
- validationError: "Nope, this will not do!"
+ validationError: "Nope, this will not do!",
+ defaultValue: null
}, requests);
});
@@ -188,7 +190,8 @@ define(['backbone', 'jquery', 'underscore', 'js/common_helpers/ajax_helpers', 'j
validValue: FieldViewsSpecHelpers.SELECT_OPTIONS[0][0],
invalidValue1: FieldViewsSpecHelpers.SELECT_OPTIONS[1][0],
invalidValue2: FieldViewsSpecHelpers.SELECT_OPTIONS[2][0],
- validationError: "Nope, this will not do!"
+ validationError: "Nope, this will not do!",
+ defaultValue: null
}, requests);
});
diff --git a/lms/static/js/student_account/views/account_settings_fields.js b/lms/static/js/student_account/views/account_settings_fields.js
index 159ad4059b..ca3fe3f492 100644
--- a/lms/static/js/student_account/views/account_settings_fields.js
+++ b/lms/static/js/student_account/views/account_settings_fields.js
@@ -97,7 +97,7 @@
if (_.isArray(modelValue) && modelValue.length > 0) {
return modelValue[0].code;
} else {
- return '';
+ return null;
}
},
diff --git a/lms/static/js/student_profile/views/learner_profile_factory.js b/lms/static/js/student_profile/views/learner_profile_factory.js
index 4b88bc7672..dfe65a1dd7 100644
--- a/lms/static/js/student_profile/views/learner_profile_factory.js
+++ b/lms/static/js/student_profile/views/learner_profile_factory.js
@@ -63,6 +63,7 @@
var usernameFieldView = new FieldsView.ReadonlyFieldView({
model: accountSettingsModel,
+ screenReaderTitle: gettext('Username'),
valueAttribute: "username",
helpMessage: ""
});
@@ -70,12 +71,12 @@
var sectionOneFieldViews = [
new FieldsView.DropdownFieldView({
model: accountSettingsModel,
- screenReaderTitle: gettext('Location'),
+ screenReaderTitle: gettext('Country'),
required: true,
editable: editable,
showMessages: false,
iconName: 'fa-map-marker',
- placeholderValue: '',
+ placeholderValue: gettext('Add Country'),
valueAttribute: "country",
options: options.country_options,
helpMessage: ''
diff --git a/lms/static/js/student_profile/views/learner_profile_fields.js b/lms/static/js/student_profile/views/learner_profile_fields.js
index 243585fc36..29f75edf5c 100644
--- a/lms/static/js/student_profile/views/learner_profile_fields.js
+++ b/lms/static/js/student_profile/views/learner_profile_fields.js
@@ -59,7 +59,10 @@
// Update model to get the latest urls of profile image.
this.model.fetch().done(function () {
view.setCurrentStatus('');
+ view.render();
+ view.$('.u-field-upload-button').focus();
}).fail(function () {
+ view.setCurrentStatus('');
view.showErrorMessage(view.errorMessage);
});
},
@@ -67,7 +70,6 @@
imageChangeFailed: function (e, data) {
this.setCurrentStatus('');
this.showImageChangeFailedMessage(data.jqXHR.status, data.jqXHR.responseText);
- this.render();
},
showImageChangeFailedMessage: function (status, responseText) {
diff --git a/lms/static/js/views/fields.js b/lms/static/js/views/fields.js
index 1303b9bfc5..b42736e53c 100644
--- a/lms/static/js/views/fields.js
+++ b/lms/static/js/views/fields.js
@@ -6,7 +6,7 @@
var Mustache = window.Mustache || RequireMustache;
- var messageRevertDelay = 4000;
+ var messageRevertDelay = 6000;
var FieldViews = {};
FieldViews.FieldView = Backbone.View.extend({
@@ -176,10 +176,7 @@
this.showSuccessMessage();
},
- showDisplayMode: function(render) {
- this.mode = 'display';
- if (render) { this.render(); }
-
+ updateDisplayModeClass: function() {
this.$el.removeClass('mode-edit');
this.$el.toggleClass('mode-hidden', (this.editable === 'never' && !this.modelValueIsSet()));
@@ -187,6 +184,12 @@
this.$el.toggleClass('mode-display', (this.modelValueIsSet()));
},
+ showDisplayMode: function(render) {
+ this.mode = 'display';
+ if (render) { this.render(); }
+ this.updateDisplayModeClass();
+ },
+
showEditMode: function(render) {
this.mode = 'edit';
if (render) { this.render(); }
@@ -233,6 +236,7 @@
this.$el.html(this.template({
id: this.options.valueAttribute,
title: this.options.title,
+ screenReaderTitle: this.options.screenReaderTitle || this.options.title,
value: this.modelValue(),
message: this.helpMessage
}));
@@ -345,7 +349,8 @@
},
fieldValue: function () {
- return this.$('.u-field-value select').val();
+ var value = this.$('.u-field-value select').val();
+ return value === '' ? null : value;
},
displayValue: function (value) {
@@ -358,16 +363,17 @@
},
updateValueInField: function () {
+ this.$('.u-field-value select').val(this.modelValue() || '');
+
+ var value = this.displayValue(this.modelValue() || '');
+ if (this.modelValueIsSet() === false) {
+ value = this.options.placeholderValue || '';
+ }
+ this.$('.u-field-value').attr('aria-label', this.options.title);
+ this.$('.u-field-value-readonly').html(Mustache.escapeHtml(value));
+
if (this.mode === 'display') {
- var value = this.displayValue(this.modelValue() || '');
- if (this.modelValueIsSet() === false) {
- value = this.options.placeholderValue || '';
- }
- this.$('.u-field-value').attr('aria-label', this.options.title);
- this.$('.u-field-value-readonly').html(Mustache.escapeHtml(value));
- this.showDisplayMode(false);
- } else {
- this.$('.u-field-value select').val(this.modelValue() || '');
+ this.updateDisplayModeClass();
}
},
@@ -377,6 +383,13 @@
this.saveAttributes(attributes);
},
+ showDisplayMode: function(render) {
+ this._super(render);
+ if (this.editable === 'toggle') {
+ this.$('.u-field-value a').focus();
+ }
+ },
+
showEditMode: function(render) {
this._super(render);
if (this.editable === 'toggle') {
@@ -386,10 +399,13 @@
saveSucceeded: function() {
if (this.editable === 'toggle') {
- this.showDisplayMode(true);
- } else {
- this.showEditMode(true);
+ this.showDisplayMode();
}
+
+ if (this.options.required && this.modelValueIsSet()) {
+ this.$('option[value=""]').remove();
+ }
+
this._super();
},
@@ -410,13 +426,13 @@
'focusout textarea': 'finishEditing',
'change textarea': 'adjustTextareaHeight',
'keyup textarea': 'adjustTextareaHeight',
- 'keydown textarea': 'adjustTextareaHeight',
+ 'keydown textarea': 'onKeyDown',
'paste textarea': 'adjustTextareaHeight',
'cut textarea': 'adjustTextareaHeight'
},
initialize: function (options) {
- _.bindAll(this, 'render', 'adjustTextareaHeight', 'fieldValue', 'saveValue', 'updateView');
+ _.bindAll(this, 'render', 'onKeyDown', 'adjustTextareaHeight', 'fieldValue', 'saveValue', 'updateView');
this._super(options);
this.listenTo(this.model, "change:" + this.options.valueAttribute, this.updateView);
},
@@ -443,6 +459,15 @@
return this;
},
+ onKeyDown: function (event) {
+ if (event.keyCode === 13) {
+ event.preventDefault();
+ this.finishEditing(event);
+ } else {
+ this.adjustTextareaHeight();
+ }
+ },
+
adjustTextareaHeight: function() {
var textarea = this.$('textarea');
textarea.css('height', 'auto').css('height', textarea.prop('scrollHeight') + 10);
@@ -483,6 +508,7 @@
this._super();
if (this.editable === 'toggle') {
this.showDisplayMode(true);
+ this.$('a').focus();
}
}
});
@@ -552,7 +578,6 @@
this._super(options);
_.bindAll(this, 'render', 'imageChangeSucceeded', 'imageChangeFailed', 'fileSelected',
'watchForPageUnload', 'onBeforeUnload');
- this.listenTo(this.model, "change:" + this.options.valueAttribute, this.render);
},
render: function () {
diff --git a/lms/static/sass/shared/_fields.scss b/lms/static/sass/shared/_fields.scss
index f277e96114..277278beee 100644
--- a/lms/static/sass/shared/_fields.scss
+++ b/lms/static/sass/shared/_fields.scss
@@ -121,3 +121,13 @@
color: $gray-l1;
}
}
+
+.u-field-dropdown {
+ &.mode-display select, &.mode-placeholder select {
+ display: none;
+ }
+
+ &.mode-edit a.u-field-value-display {
+ display: none;
+ }
+}
diff --git a/lms/templates/fields/field_dropdown.underscore b/lms/templates/fields/field_dropdown.underscore
index 28d7d676f4..b42ab0cc36 100644
--- a/lms/templates/fields/field_dropdown.underscore
+++ b/lms/templates/fields/field_dropdown.underscore
@@ -5,26 +5,23 @@
<% } %>
<% if (iconName) { %>
-
+
<% } %>
- <% if (mode === 'edit') { %>
-
- <% } else { %>
-
- <%- screenReaderTitle %>
-
- <%- gettext('Click to edit') %>
-
- <% }%>
+
+
+ <%- screenReaderTitle %>
+
+ <%- gettext('Click to edit') %>
+
diff --git a/lms/templates/fields/field_readonly.underscore b/lms/templates/fields/field_readonly.underscore
index 02a9bb11f1..2c05a7d4f5 100644
--- a/lms/templates/fields/field_readonly.underscore
+++ b/lms/templates/fields/field_readonly.underscore
@@ -1,6 +1,7 @@
-