Commit e50a6416 by muhammad-ammar Committed by Andy Armstrong

Accessibility changes for Account Settings and Learner Profile pages

parent f1657d1d
......@@ -182,7 +182,7 @@ class FieldsMixin(object):
"""
self.wait_for_field(field_id)
return self.q(css='.u-field-{} .u-field-value'.format(field_id)).text[0]
return self.q(css='.u-field-{} .u-field-value .u-field-value-readonly'.format(field_id)).text[0]
def value_for_dropdown_field(self, field_id, value=None):
"""
......@@ -210,7 +210,7 @@ class FieldsMixin(object):
"""
self.wait_for_field(field_id)
query = self.q(css='.u-field-{} a'.format(field_id))
query = self.q(css='.u-field-link-title-{}'.format(field_id))
return query.text[0] if query.present else None
def click_on_link_in_link_field(self, field_id):
......
......@@ -32,13 +32,13 @@ define(['backbone', 'jquery', 'underscore', 'js/common_helpers/ajax_helpers', 'j
var AUTH_DATA = {
'providers': [
{
'name': "Network 1",
'name': "Network1",
'connected': true,
'connect_url': 'yetanother1.com/auth/connect',
'disconnect_url': 'yetanother1.com/auth/disconnect'
},
{
'name': "Network 2",
'name': "Network2",
'connected': true,
'connect_url': 'yetanother2.com/auth/connect',
'disconnect_url': 'yetanother2.com/auth/disconnect'
......
......@@ -5,11 +5,11 @@ define(['backbone', 'jquery', 'underscore', 'js/common_helpers/ajax_helpers', 'j
'use strict';
var verifyAuthField = function (view, data, requests) {
var selector = '.u-field-value > a';
var selector = '.u-field-value .u-field-link-title-' + view.options.valueAttribute;
spyOn(view, 'redirect_to');
FieldViewsSpecHelpers.expectTitleAndMessageToBe(view, data.title, data.helpMessage);
FieldViewsSpecHelpers.expectTitleAndMessageToContain(view, data.title, data.helpMessage);
expect(view.$(selector).text().trim()).toBe('Unlink');
view.$(selector).click();
FieldViewsSpecHelpers.expectMessageContains(view, 'Unlinking');
......
......@@ -18,10 +18,10 @@ define(['underscore'], function(_) {
expect(view.fieldValue()).toBe(view.modelValue());
} else if ('optionForValue' in view) {
expect($($element.find('.u-field-value')[0]).text()).toBe(view.displayValue(view.modelValue()));
expect($($element.find('.u-field-value .u-field-value-readonly')[0]).text()).toBe(view.displayValue(view.modelValue()));
}else {
expect($($element.find('.u-field-value')[0]).text()).toBe(view.modelValue());
expect($($element.find('.u-field-value .u-field-value-readonly')[0]).text()).toBe(view.modelValue());
}
} else {
throw new Error('Unexpected field type: ' + view.fieldType);
......
......@@ -59,19 +59,19 @@ define(['backbone', 'jquery', 'underscore', 'js/common_helpers/ajax_helpers', 'j
};
};
var expectTitleToBe = function(view, expectedTitle) {
expect(view.$('.u-field-title').text().trim()).toBe(expectedTitle);
};
var expectTitleAndMessageToBe = function(view, expectedTitle, expectedMessage) {
expectTitleToBe(view, expectedTitle);
expect(view.$('.u-field-message').text().trim()).toBe(expectedMessage);
var expectTitleToContain = function(view, expectedTitle) {
expect(view.$('.u-field-title').text().trim()).toContain(expectedTitle);
};
var expectMessageContains = function(view, expectedText) {
expect(view.$('.u-field-message').html()).toContain(expectedText);
};
var expectTitleAndMessageToContain = function(view, expectedTitle, expectedMessage) {
expectTitleToContain(view, expectedTitle);
expectMessageContains(view, expectedMessage);
};
var expectAjaxRequestWithData = function(requests, data) {
AjaxHelpers.expectJsonRequest(
requests, 'PATCH', API_URL, data
......@@ -82,7 +82,7 @@ define(['backbone', 'jquery', 'underscore', 'js/common_helpers/ajax_helpers', 'j
var message = 'Here to help!';
view.message(message);
view.showHelpMessage(message);
expectMessageContains(view, message);
view.showHelpMessage();
......@@ -121,7 +121,7 @@ define(['backbone', 'jquery', 'underscore', 'js/common_helpers/ajax_helpers', 'j
view.showSuccessMessage();
expectMessageContains(view, view.indicators.success);
// But if we change the message, it should not get reset.
view.message("Do not reset this!");
view.showHelpMessage("Do not reset this!");
jasmine.Clock.tick(5000);
expectMessageContains(view, "Do not reset this!");
};
......@@ -132,15 +132,15 @@ define(['backbone', 'jquery', 'underscore', 'js/common_helpers/ajax_helpers', 'j
if (data.editable === 'toggle') {
expect(view.el).toHaveClass('mode-placeholder');
expectTitleToBe(view, data.title);
expectTitleToContain(view, data.title);
expectMessageContains(view, view.indicators.canEdit);
view.$el.click();
} else {
expectTitleAndMessageToBe(view, data.title, data.helpMessage);
expectTitleAndMessageToContain(view, data.title, data.helpMessage, false);
}
expect(view.el).toHaveClass('mode-edit');
expect(view.fieldValue()).not.toBe(data.validValue);
expect(view.fieldValue()).not.toContain(data.validValue);
view.$(data.valueInputSelector).val(data.validValue).change();
// When the value in the field is changed
......@@ -220,8 +220,8 @@ define(['backbone', 'jquery', 'underscore', 'js/common_helpers/ajax_helpers', 'j
UserAccountModel: UserAccountModel,
createFieldData: createFieldData,
createErrorMessage: createErrorMessage,
expectTitleToBe: expectTitleToBe,
expectTitleAndMessageToBe: expectTitleAndMessageToBe,
expectTitleToContain: expectTitleToContain,
expectTitleAndMessageToContain: expectTitleAndMessageToContain,
expectMessageContains: expectMessageContains,
expectAjaxRequestWithData: expectAjaxRequestWithData,
verifyMessageUpdates: verifyMessageUpdates,
......
......@@ -96,7 +96,7 @@ define(['backbone', 'jquery', 'underscore', 'js/common_helpers/ajax_helpers', 'j
});
var view = new FieldViews.ReadonlyFieldView(fieldData).render();
FieldViewsSpecHelpers.expectTitleAndMessageToBe(view, fieldData.title, fieldData.helpMessage);
FieldViewsSpecHelpers.expectTitleAndMessageToContain(view, fieldData.title, fieldData.helpMessage, false);
expect(view.$('.u-field-value input').val().trim()).toBe(USERNAME);
view.model.set({'username': 'bookworm'});
......@@ -137,7 +137,7 @@ define(['backbone', 'jquery', 'underscore', 'js/common_helpers/ajax_helpers', 'j
});
var view = new FieldViews.DropdownFieldView(fieldData).render();
FieldViewsSpecHelpers.expectTitleAndMessageToBe(view, fieldData.title, fieldData.helpMessage);
FieldViewsSpecHelpers.expectTitleAndMessageToContain(view, fieldData.title, fieldData.helpMessage, false);
expect(view.el).toHaveClass('mode-hidden');
view.model.set({'name': fieldData.options[1][0]});
......@@ -205,14 +205,14 @@ define(['backbone', 'jquery', 'underscore', 'js/common_helpers/ajax_helpers', 'j
// set bio to empty to see the placeholder.
fieldData.model.set({bio: ''});
var view = new FieldViews.TextareaFieldView(fieldData).render();
FieldViewsSpecHelpers.expectTitleAndMessageToBe(view, fieldData.title, fieldData.helpMessage);
FieldViewsSpecHelpers.expectTitleAndMessageToContain(view, fieldData.title, fieldData.helpMessage, false);
expect(view.el).toHaveClass('mode-hidden');
expect(view.$('.u-field-value').text()).toBe(fieldData.placeholderValue);
expect(view.$('.u-field-value .u-field-value-readonly').text()).toBe(fieldData.placeholderValue);
var bio = 'Too much to tell!';
view.model.set({'bio': bio});
expect(view.el).toHaveClass('mode-display');
expect(view.$('.u-field-value').text()).toBe(bio);
expect(view.$('.u-field-value .u-field-value-readonly').text()).toBe(bio);
view.$el.click();
expect(view.el).toHaveClass('mode-display');
});
......@@ -235,10 +235,10 @@ define(['backbone', 'jquery', 'underscore', 'js/common_helpers/ajax_helpers', 'j
var view = new FieldViews.TextareaFieldView(fieldData).render();
FieldViewsSpecHelpers.expectTitleToBe(view, fieldData.title);
FieldViewsSpecHelpers.expectTitleToContain(view, fieldData.title);
FieldViewsSpecHelpers.expectMessageContains(view, view.indicators.canEdit);
expect(view.el).toHaveClass('mode-placeholder');
expect(view.$('.u-field-value').text()).toBe(fieldData.placeholderValue);
expect(view.$('.u-field-value .u-field-value-readonly').text()).toBe(fieldData.placeholderValue);
view.$('.wrapper-u-field').click();
expect(view.el).toHaveClass('mode-edit');
......@@ -254,19 +254,20 @@ define(['backbone', 'jquery', 'underscore', 'js/common_helpers/ajax_helpers', 'j
view.$(valueInputSelector).val('').focusout();
AjaxHelpers.respondWithNoContent(requests);
expect(view.el).toHaveClass('mode-placeholder');
expect(view.$('.u-field-value').text()).toBe(fieldData.placeholderValue);
expect(view.$('.u-field-value .u-field-value-readonly').text()).toBe(fieldData.placeholderValue);
});
it("correctly renders LinkFieldView", function() {
var fieldData = FieldViewsSpecHelpers.createFieldData(FieldViews.LinkFieldView, {
title: 'Title',
linkTitle: 'Link title',
helpMessage: 'Click the link.'
helpMessage: 'Click the link.',
valueAttribute: 'password-reset'
});
var view = new FieldViews.LinkFieldView(fieldData).render();
FieldViewsSpecHelpers.expectTitleAndMessageToBe(view, fieldData.title, fieldData.helpMessage);
expect(view.$('.u-field-value > a').text().trim()).toBe(fieldData.linkTitle);
FieldViewsSpecHelpers.expectTitleAndMessageToContain(view, fieldData.title, fieldData.helpMessage, false);
expect(view.$('.u-field-value > a .u-field-link-title-' + view.options.valueAttribute).text().trim()).toBe(fieldData.linkTitle);
});
});
});
......@@ -58,10 +58,11 @@
view: new AccountSettingsFieldViews.PasswordFieldView({
model: userAccountModel,
title: gettext('Password'),
screenReaderTitle: gettext('Reset your Password'),
valueAttribute: 'password',
emailAttribute: 'email',
linkTitle: gettext('Reset Password'),
linkHref: fieldsData.password.url,
linkHref: fieldsData['password']['url'],
helpMessage: gettext(
'When you click "Reset Password", a message will be sent to your email address. ' +
'Click the link in the message to reset your password.'
......@@ -139,6 +140,9 @@
return {
'view': new AccountSettingsFieldViews.AuthFieldView({
title: provider.name,
screenReaderTitle: interpolate_text(
gettext("Connect your {accountName} account"), {accountName: provider['name']}
),
valueAttribute: 'auth-' + provider.name.toLowerCase(),
helpMessage: '',
connected: provider.connected,
......
......@@ -36,7 +36,7 @@
view.showSuccessMessage();
},
error: function () {
view.message(
view.showNotificationMessage(
view.indicators.error +
gettext(
'You must sign out of edX and sign back in before your language ' +
......@@ -121,6 +121,7 @@
this.$el.html(this.template({
id: this.options.valueAttribute,
title: this.options.title,
screenReaderTitle: this.options.screenReaderTitle,
linkTitle: this.options.connected ? gettext('Unlink') : gettext('Link'),
linkHref: '',
message: this.helpMessage
......
......@@ -65,6 +65,7 @@
var sectionOneFieldViews = [
new FieldsView.DropdownFieldView({
model: accountSettingsModel,
screenReaderTitle: gettext('Location'),
required: true,
editable: editable,
showMessages: false,
......@@ -76,6 +77,7 @@
}),
new AccountSettingsFieldViews.LanguageProficienciesFieldView({
model: accountSettingsModel,
screenReaderTitle: gettext('Preferred Language'),
required: false,
editable: editable,
showMessages: false,
......
......@@ -10,12 +10,12 @@
render: function () {
this._super();
this.message();
this.showNotificationMessage();
this.updateFieldValue();
return this;
},
message: function () {
showNotificationMessage: function () {
var accountSettingsLink = '<a href="' + this.options.accountSettingsPageUrl + '">' + gettext('Account Settings page.') + '</a>';
if (this.profileIsPrivate) {
this._super(interpolate_text(
......
......@@ -20,12 +20,12 @@
tagName: 'div',
indicators: {
'canEdit': '<i class="icon fa fa-pencil message-can-edit" aria-hidden="true"></i>',
'error': '<i class="fa fa-exclamation-triangle message-error" aria-hidden="true"></i>',
'validationError': '<i class="fa fa-exclamation-triangle message-validation-error" aria-hidden="true"></i>',
'inProgress': '<i class="fa fa-spinner fa-pulse message-in-progress" aria-hidden="true"></i>',
'success': '<i class="fa fa-check message-success" aria-hidden="true"></i>',
'plus': '<i class="fa fa-plus placeholder" aria-hidden="true"></i>'
'canEdit': '<i class="icon fa fa-pencil message-can-edit" aria-hidden="true"></i><span class="sr">gettext("Editable")</span>',
'error': '<i class="fa fa-exclamation-triangle message-error" aria-hidden="true"></i><span class="sr">gettext("Error")</span>',
'validationError': '<i class="fa fa-exclamation-triangle message-validation-error" aria-hidden="true"></i><span class="sr">gettext("Validation Error")</span>',
'inProgress': '<i class="fa fa-spinner fa-pulse message-in-progress" aria-hidden="true"></i><span class="sr">gettext("In Progress")</span>',
'success': '<i class="fa fa-check message-success" aria-hidden="true"></i><span class="sr">gettext("Success")</span>',
'plus': '<i class="fa fa-plus placeholder" aria-hidden="true"></i><span class="sr">gettext("Placeholder")</span>'
},
messages: {
......@@ -36,15 +36,17 @@
'success': gettext('Your changes have been saved.')
},
initialize: function (options) {
initialize: function () {
this.template = _.template($(this.templateSelector).text());
this.helpMessage = this.options.helpMessage || '';
this.showMessages = _.isUndefined(this.options.showMessages) ? true : this.options.showMessages;
_.bindAll(this, 'modelValue', 'modelValueIsSet', 'message', 'getMessage', 'title',
'showHelpMessage', 'showInProgressMessage', 'showSuccessMessage', 'showErrorMessage');
_.bindAll(this, 'modelValue', 'modelValueIsSet', 'showNotificationMessage','getNotificationMessage',
'getMessage', 'title', 'showHelpMessage', 'showInProgressMessage', 'showSuccessMessage',
'showErrorMessage'
);
},
modelValue: function () {
......@@ -55,10 +57,6 @@
return (this.modelValue() === true);
},
message: function (message) {
return this.$('.u-field-message').html(message);
},
title: function (text) {
return this.$('.u-field-title').html(text);
},
......@@ -72,25 +70,38 @@
return this.indicators[message_status];
},
showHelpMessage: function (message) {
if (_.isUndefined(message) || _.isNull(message)) {
message = this.helpMessage;
}
this.$('.u-field-message-notification').html('');
this.$('.u-field-message-help').html(message);
},
getNotificationMessage: function() {
return this.$('.u-field-message-notification').html();
},
showNotificationMessage: function(message) {
this.$('.u-field-message-help').html('');
this.$('.u-field-message-notification').html(message);
},
showCanEditMessage: function(show) {
if (!_.isUndefined(show) && show) {
this.message(this.getMessage('canEdit'));
this.showNotificationMessage(this.getMessage('canEdit'));
} else {
this.message('');
this.showNotificationMessage('');
}
},
showHelpMessage: function () {
this.message(this.helpMessage);
},
showInProgressMessage: function () {
this.message(this.getMessage('inProgress'));
this.showNotificationMessage(this.getMessage('inProgress'));
},
showSuccessMessage: function () {
var successMessage = this.getMessage('success');
this.message(successMessage);
this.showNotificationMessage(successMessage);
if (this.options.refreshPageOnSave) {
document.location.reload();
......@@ -102,7 +113,7 @@
this.lastSuccessMessageContext = context;
setTimeout(function () {
if ((context === view.lastSuccessMessageContext) && (view.message().html() === successMessage)) {
if ((context === view.lastSuccessMessageContext) && (view.getNotificationMessage() === successMessage)) {
view.showHelpMessage();
}
}, messageRevertDelay);
......@@ -116,12 +127,12 @@
errors.field_errors[this.options.valueAttribute].user_message
),
message = this.indicators.validationError + validationErrorMessage;
this.message(message);
this.showNotificationMessage(message);
} catch (error) {
this.message(this.getMessage('error'));
this.showNotificationMessage(this.getMessage('error'));
}
} else {
this.message(this.getMessage('error'));
this.showNotificationMessage(this.getMessage('error'));
}
}
});
......@@ -305,6 +316,7 @@
id: this.options.valueAttribute,
mode: this.mode,
title: this.options.title,
screenReaderTitle: this.options.screenReaderTitle || this.options.title,
iconName: this.options.iconName,
required: this.options.required,
selectOptions: this.options.options,
......@@ -351,7 +363,8 @@
if (this.modelValueIsSet() === false) {
value = this.options.placeholderValue || '';
}
this.$('.u-field-value').html(Mustache.escapeHtml(value));
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() || '');
......@@ -413,9 +426,11 @@
}
this.$el.html(this.template({
id: this.options.valueAttribute,
screenReaderTitle: this.options.screenReaderTitle || this.options.title,
mode: this.mode,
value: value,
message: this.helpMessage
message: this.helpMessage,
placeholderValue: this.options.placeholderValue
}));
this.delegateEvents();
this.title((this.modelValue() || this.mode === 'edit') ? this.options.title : this.indicators['plus'] + this.options.title);
......@@ -489,6 +504,7 @@
this.$el.html(this.template({
id: this.options.valueAttribute,
title: this.options.title,
screenReaderTitle: this.options.screenReaderTitle || this.options.title,
linkTitle: this.options.linkTitle,
linkHref: this.options.linkHref,
message: this.helpMessage
......
......@@ -87,8 +87,9 @@
color: $gray;
vertical-align: top;
margin-bottom: 0;
-webkit-font-smoothing: antialiased;
label {
label, span {
@include margin-left($baseline/2);
}
}
......@@ -114,4 +115,9 @@
i {
@include margin-right($baseline/4);
}
.u-field-message-help,
.u-field-message-notification {
color: $gray-l1;
}
}
......@@ -66,4 +66,15 @@
box-shadow: 0 0 1px 1px $shadow-l2;
border-radius: 5px;
}
a span {
color: $link-color;
}
a span {
&:hover, &:focus {
color: $pink;
text-decoration: none !important;
}
}
}
......@@ -5,12 +5,12 @@
<% } %>
<% if (iconName) { %>
<i class="u-field-icon icon fa <%- iconName %> fa-fw" area-hidden="true" ></i>
<i class="u-field-icon icon fa <%- iconName %> fa-fw" aria-hidden="true" ></i>
<% } %>
<span class="u-field-value">
<% if (mode === 'edit') { %>
<select name="select" id="u-field-select-<%- id %>" aria-describedby="u-field-message-<%- id %>">
<select name="select" id="u-field-select-<%- id %>" aria-describedby="u-field-help-message-<%- id %>">
<% if (!required) { %>
<option value=""></option>
<% } %>
......@@ -18,9 +18,16 @@
<option value="<%- selectOption[0] %>"><%- selectOption[1] %></option>
<% }); %>
</select>
<% } %>
<% } else { %>
<a href="#" class="u-field-value-display">
<span class="sr"><%- gettext(screenReaderTitle) %></span>
<span class="u-field-value-readonly"></span>
<span class="sr"><%- gettext('Click to edit') %></span>
</a>
<% }%>
</span>
<span class="u-field-message" id="u-field-message-<%- id %>">
<%- gettext(message) %>
<span class="u-field-message-notification" aria-live="polite"></span>
<span class="u-field-message-help" id="u-field-help-message-<%- id %>"><%- gettext(message) %></span>
</span>
<label class="u-field-title" for="u-field-link-<%- id %>">
<span class="u-field-title" for="u-field-link-<%- id %>">
<%- gettext(title) %>
</label>
</span>
<span class="u-field-value">
<a id="u-field-link-<%- id %>" href="<%- gettext(linkHref) %>" aria-describedby="u-field-message-<%- id %>">
<%- gettext(linkTitle) %>
<a id="u-field-link-<%- id %>" href="<%- linkHref %>" aria-describedby="u-field-message-help-<%- id %>">
<span class="sr"><%- gettext(screenReaderTitle) %></span>
<span class="u-field-link-title-<%- id %>" aria-hidden="true"><%- gettext(linkTitle) %></span>
</a>
</span>
<span class="u-field-message" id="u-field-message-<%- id %>">
<%- gettext(message) %>
<span class="u-field-message-notification" aria-live="polite"></span>
<span class="u-field-message-help" id="u-field-message-help-<%- id %>"><%- gettext(message) %></span>
</span>
......@@ -5,5 +5,6 @@
<input id="u-field-input-<%- id %>" aria-describedby="u-field-message-<%- id %>" type="text" name="input" readonly=true value="<%- gettext(value) %>">
</span>
<span class="u-field-message" id="u-field-message-<%- id %>">
<%- gettext(message) %>
<span class="u-field-message-notification" aria-live="polite"></span>
<span class="u-field-message-help" id="u-field-help-message-<%- id %>"> <%- gettext(message) %></span>
</span>
......@@ -2,8 +2,9 @@
<%- gettext(title) %>
</label>
<span class="u-field-value">
<input id="u-field-input-<%- id %>" aria-describedby="u-field-message-<%- id %>" type="text" name="input" value="<%- gettext(value) %>">
<input id="u-field-input-<%- id %>" aria-describedby="u-field-message-help-<%- id %>" type="text" name="input" value="<%- gettext(value) %>">
</span>
<span class="u-field-message" id="u-field-message-<%- id %>">
<%- gettext(message) %>
<span class="u-field-message-notification" aria-live="polite"></span>
<span class="u-field-message-help" id="u-field-message-help-<%- id %>"> <%- gettext(message) %></span>
</span>
<div class="wrapper-u-field">
<div class="u-field-header">
<label class="u-field-title" for="u-field-textarea-<%- id %>" aria-describedby="u-field-message-<%- id %>"></label>
<span class="u-field-message" id="u-field-message-<%- id %>"><%- message %></span>
<label class="u-field-title" for="u-field-textarea-<%- id %>" id="u-field-title-<%- id %>" aria-describedby="u-field-message-help-<%- id %>"></label>
<span class="u-field-message" id="u-field-message-<%- id %>">
<span class="u-field-message-notification" aria-live="polite"></span>
<span class="u-field-message-help" id="u-field-message-help-<%- id %>"> <%- gettext(message) %></span>
</span>
</div>
<div class="u-field-value"><%
<div class="u-field-value" id="u-field-value-<%- id %>" aria-labelledby="u-field-title-<%- id %>"><%
if (mode === 'edit') {
%><textarea id="u-field-textarea-<%- id %>" rows="4"><%- value %></textarea><%
%><textarea id="u-field-textarea-<%- id %>" rows="4" aria-describedby="u-field-placeholder-value-<%- id %>"><%- value %></textarea><%
} else {
%><%- value %><%
%><a href="#" class="u-field-value-display"><span class="sr"><%- gettext(screenReaderTitle) %></span><span class="u-field-value-readonly" aria-hidden="false" aria-describedby="u-field-placeholder-value-<%- id %>"><%- value %></span><span class="sr"><%- gettext('Click to edit') %></span></a><%
}
%></div>
%><span class="sr" id="u-field-placeholder-value-<%- id %>"><%- gettext(placeholderValue) %></span>
</div>
</div>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment