diff --git a/common/test/acceptance/pages/lms/fields.py b/common/test/acceptance/pages/lms/fields.py index ff7fd9b31bf2d3136cc70ae08541ca432ec6fbec..5a925b7f26a531d47889f7b2497d50a2634ba6e8 100644 --- a/common/test/acceptance/pages/lms/fields.py +++ b/common/test/acceptance/pages/lms/fields.py @@ -143,7 +143,11 @@ class FieldsMixin(object): """ self.wait_for_field(field_id) - return self.value_for_text_field(field_id) + query = self.q(css='.u-field-{} .u-field-value'.format(field_id)) + if not query.present: + return None + + return query.text[0] def value_for_text_field(self, field_id, value=None, press_enter=True): """ diff --git a/common/test/acceptance/tests/lms/test_account_settings.py b/common/test/acceptance/tests/lms/test_account_settings.py index 9e8c504509fe6939479c52c4f0ac25f5f5ff3100..4b6b3a30a0d9d1f2fc16c2a194dc6be9d193199a 100644 --- a/common/test/acceptance/tests/lms/test_account_settings.py +++ b/common/test/acceptance/tests/lms/test_account_settings.py @@ -24,6 +24,16 @@ class AccountSettingsTestMixin(EventsTestMixin, WebAppTest): USER_SETTINGS_CHANGED_EVENT_NAME = 'edx.user.settings.changed' ACCOUNT_SETTINGS_REFERER = u"/account/settings" + def visit_account_settings_page(self): + """ + Visit the account settings page for the current user, and store the page instance + as self.account_settings_page. + """ + # pylint: disable=attribute-defined-outside-init + self.account_settings_page = AccountSettingsPage(self.browser) + self.account_settings_page.visit() + self.account_settings_page.wait_for_ajax() + def log_in_as_unique_user(self, email=None): """ Create a unique user and return the account's username and id. @@ -116,14 +126,6 @@ class AccountSettingsPageTest(AccountSettingsTestMixin, WebAppTest): self.username, self.user_id = self.log_in_as_unique_user() self.visit_account_settings_page() - def visit_account_settings_page(self): - """ - Visit the account settings page for the current user. - """ - self.account_settings_page = AccountSettingsPage(self.browser) - self.account_settings_page.visit() - self.account_settings_page.wait_for_ajax() - def test_page_view_event(self): """ Scenario: An event should be recorded when the "Account Settings" @@ -444,3 +446,18 @@ class AccountSettingsPageTest(AccountSettingsTestMixin, WebAppTest): for field_id, title, link_title in providers: self.assertEqual(self.account_settings_page.title_for_field(field_id), title) self.assertEqual(self.account_settings_page.link_title_for_link_field(field_id), link_title) + + +@attr('a11y') +class AccountSettingsA11yTest(AccountSettingsTestMixin, WebAppTest): + """ + Class to test account settings accessibility. + """ + + def test_account_settings_a11y(self): + """ + Test the accessibility of the account settings page. + """ + self.log_in_as_unique_user() + self.visit_account_settings_page() + self.account_settings_page.a11y_audit.check_for_accessibility_errors() diff --git a/common/test/acceptance/tests/lms/test_learner_profile.py b/common/test/acceptance/tests/lms/test_learner_profile.py index de88e9e678585a30185d88dea1453577568d9842..df9c13b3fb282e7025291e87d25f01e70fd731f8 100644 --- a/common/test/acceptance/tests/lms/test_learner_profile.py +++ b/common/test/acceptance/tests/lms/test_learner_profile.py @@ -147,6 +147,26 @@ class LearnerProfileTestMixin(EventsTestMixin): with self.assert_events_match_during(event_filter=event_filter, expected_events=[expected_event]): yield + def initialize_different_user(self, privacy=None, birth_year=None): + """ + Initialize the profile page for a different test user + """ + username, user_id = self.log_in_as_unique_user() + + # Set the privacy for the new user + if privacy is None: + privacy = self.PRIVACY_PUBLIC + self.visit_profile_page(username, privacy=privacy) + + # Set the user's year of birth + if birth_year: + self.set_birth_year(birth_year) + + # Log the user out + LogoutPage(self.browser).visit() + + return username, user_id + @attr('shard_4') class OwnLearnerProfilePageTest(LearnerProfileTestMixin, WebAppTest): @@ -677,7 +697,7 @@ class DifferentUserLearnerProfilePageTest(LearnerProfileTestMixin, WebAppTest): Then I shouldn't see the profile visibility selector dropdown. Then I see some of the profile fields are shown. """ - different_username, different_user_id = self._initialize_different_user(privacy=self.PRIVACY_PRIVATE) + different_username, different_user_id = self.initialize_different_user(privacy=self.PRIVACY_PRIVATE) username, __ = self.log_in_as_unique_user() profile_page = self.visit_profile_page(different_username) self.verify_profile_page_is_private(profile_page, is_editable=False) @@ -693,7 +713,7 @@ class DifferentUserLearnerProfilePageTest(LearnerProfileTestMixin, WebAppTest): Then I see that only the private fields are shown. """ under_age_birth_year = datetime.now().year - 10 - different_username, different_user_id = self._initialize_different_user( + different_username, different_user_id = self.initialize_different_user( privacy=self.PRIVACY_PUBLIC, birth_year=under_age_birth_year ) @@ -713,29 +733,52 @@ class DifferentUserLearnerProfilePageTest(LearnerProfileTestMixin, WebAppTest): Then I shouldn't see the profile visibility selector dropdown. Also `location`, `language` and `about me` fields are not editable. """ - different_username, different_user_id = self._initialize_different_user(privacy=self.PRIVACY_PUBLIC) + different_username, different_user_id = self.initialize_different_user(privacy=self.PRIVACY_PUBLIC) username, __ = self.log_in_as_unique_user() profile_page = self.visit_profile_page(different_username) profile_page.wait_for_public_fields() self.verify_profile_page_is_public(profile_page, is_editable=False) self.verify_profile_page_view_event(username, different_user_id, visibility=self.PRIVACY_PUBLIC) - def _initialize_different_user(self, privacy=None, birth_year=None): + +@attr('a11y') +class LearnerProfileA11yTest(LearnerProfileTestMixin, WebAppTest): + """ + Class to test learner profile accessibility. + """ + + def test_editable_learner_profile_a11y(self): """ - Initialize the profile page for a different test user + Test the accessibility of the editable version of the profile page + (user viewing her own public profile). """ - username, user_id = self.log_in_as_unique_user() + username, _ = self.log_in_as_unique_user() + profile_page = self.visit_profile_page(username) - # Set the privacy for the new user - if privacy is None: - privacy = self.PRIVACY_PUBLIC - self.visit_profile_page(username, privacy=privacy) + # TODO: There are several existing color contrast errors on this page, + # we will ignore this error in the test until we fix them. + profile_page.a11y_audit.config.set_rules({ + "ignore": ['color-contrast'], + }) - # Set the user's year of birth - if birth_year: - self.set_birth_year(birth_year) + profile_page.a11y_audit.check_for_accessibility_errors() - # Log the user out - LogoutPage(self.browser).visit() + profile_page.make_field_editable('language_proficiencies') + profile_page.a11y_audit.check_for_accessibility_errors() - return username, user_id + profile_page.make_field_editable('bio') + profile_page.a11y_audit.check_for_accessibility_errors() + + def test_read_only_learner_profile_a11y(self): + """ + Test the accessibility of the read-only version of a public profile page + (user viewing someone else's profile page). + """ + # initialize_different_user should cause country, language, and bio to be filled out (since + # privacy is public). It doesn't appear that this is happening, although the method + # works in regular bokchoy tests. Perhaps a problem with phantomjs? So this test is currently + # only looking at a read-only profile page with a username. + different_username, _ = self.initialize_different_user(privacy=self.PRIVACY_PUBLIC) + self.log_in_as_unique_user() + profile_page = self.visit_profile_page(different_username) + profile_page.a11y_audit.check_for_accessibility_errors() diff --git a/lms/static/js/spec/views/fields_helpers.js b/lms/static/js/spec/views/fields_helpers.js index 1fe74c2b486fa949946c8e853e0ee07dd76c07b2..6248656d33d3d5f1008ceeb606cc2155f95946b9 100644 --- a/lms/static/js/spec/views/fields_helpers.js +++ b/lms/static/js/spec/views/fields_helpers.js @@ -63,6 +63,10 @@ define(['backbone', 'jquery', 'underscore', 'common/js/spec_helpers/ajax_helpers expect(view.$('.u-field-title').text().trim()).toContain(expectedTitle); }; + var expectDropdownSrTitleToContain = function(view, expectedTitle) { + expect(view.$('.u-field-value .sr').text().trim()).toContain(expectedTitle); + }; + var expectMessageContains = function(view, expectedText) { expect(view.$('.u-field-message').html()).toContain(expectedText); }; @@ -167,7 +171,7 @@ define(['backbone', 'jquery', 'underscore', 'common/js/spec_helpers/ajax_helpers expectMessageContains(view, view.indicators.canEdit); view.$el.click(); } else { - expectTitleAndMessageToContain(view, data.title, data.helpMessage, false); + expectTitleAndMessageToContain(view, data.title, data.helpMessage); } expect(view.el).toHaveClass('mode-edit'); @@ -254,6 +258,7 @@ define(['backbone', 'jquery', 'underscore', 'common/js/spec_helpers/ajax_helpers createFieldData: createFieldData, createErrorMessage: createErrorMessage, expectTitleToContain: expectTitleToContain, + expectDropdownSrTitleToContain: expectDropdownSrTitleToContain, expectTitleAndMessageToContain: expectTitleAndMessageToContain, expectMessageContains: expectMessageContains, expectAjaxRequestWithData: expectAjaxRequestWithData, diff --git a/lms/static/js/spec/views/fields_spec.js b/lms/static/js/spec/views/fields_spec.js index b0cfc860598ea65a4315a656c536ea1d7d9b932c..3dd02806b8ba54e5d19e9b0898514d30bbff975b 100644 --- a/lms/static/js/spec/views/fields_spec.js +++ b/lms/static/js/spec/views/fields_spec.js @@ -10,7 +10,10 @@ define(['backbone', 'jquery', 'underscore', 'common/js/spec_helpers/ajax_helpers describe("edx.FieldViews", function () { var requests, - timerCallback; + timerCallback, + dropdownSelectClass = '.u-field-value > select', + dropdownButtonClass = '.u-field-value > button', + textareaLinkClass = '.u-field-value a'; var fieldViewClasses = [ FieldViews.ReadonlyFieldView, @@ -89,11 +92,11 @@ define(['backbone', 'jquery', 'underscore', 'common/js/spec_helpers/ajax_helpers }); var view = new FieldViews.ReadonlyFieldView(fieldData).render(); - FieldViewsSpecHelpers.expectTitleAndMessageToContain(view, fieldData.title, fieldData.helpMessage, false); - expect(view.$('.u-field-value input').val().trim()).toBe(USERNAME); + FieldViewsSpecHelpers.expectTitleAndMessageToContain(view, fieldData.title, fieldData.helpMessage); + expect(view.fieldValue()).toBe(USERNAME); view.model.set({'username': 'bookworm'}); - expect(view.$('.u-field-value input').val().trim()).toBe('bookworm'); + expect(view.fieldValue()).toBe('bookworm'); }); it("correctly renders, updates and persists changes to TextFieldView when editable == always", function() { @@ -133,13 +136,30 @@ define(['backbone', 'jquery', 'underscore', 'common/js/spec_helpers/ajax_helpers }); var view = new FieldViews.DropdownFieldView(fieldData).render(); - FieldViewsSpecHelpers.expectTitleAndMessageToContain(view, fieldData.title, fieldData.helpMessage, false); + var readOnlyDisplayClass = '.u-field-value-readonly'; + + FieldViewsSpecHelpers.expectDropdownSrTitleToContain(view, fieldData.title); + FieldViewsSpecHelpers.expectMessageContains(view, fieldData.helpMessage); expect(view.el).toHaveClass('mode-hidden'); + // Note that "name" will be retrieved from the model, but the options specified are + // the languages options. Therefore initially the placeholder message will be shown because + // the model value does not match any of the possible options. + expect(view.fieldValue()).toBeNull(); + expect(view.$(readOnlyDisplayClass).text()).toBe(fieldData.placeholderValue); + // Make sure that the select and the button are not in the HTML. + expect(view.$(dropdownSelectClass).length).toBe(0); + expect(view.$(dropdownButtonClass).length).toBe(0); view.model.set({'name': fieldData.options[1][0]}); expect(view.el).toHaveClass('mode-display'); + expect(view.fieldValue()).toBe(fieldData.options[1][0]); + expect(view.$(readOnlyDisplayClass).text()).toBe(fieldData.options[1][1]); + view.$el.click(); expect(view.el).toHaveClass('mode-display'); + // Make sure that the select and the button still are not in the HTML. + expect(view.$(dropdownSelectClass).length).toBe(0); + expect(view.$(dropdownButtonClass).length).toBe(0); }); it("correctly renders, updates and persists changes to DropdownFieldView when editable == always", function() { @@ -210,12 +230,16 @@ define(['backbone', 'jquery', 'underscore', 'common/js/spec_helpers/ajax_helpers expect(view.modelValueIsSet()).toBe(false); expect(view.displayValue()).toBe(''); - if(editable === 'toggle') { view.showEditMode(true); } - view.$('.u-field-value > select').val(FieldViewsSpecHelpers.SELECT_OPTIONS[0]).change(); + if (editable === 'toggle') { + expect(view.$(dropdownButtonClass).length).toBe(1); + view.showEditMode(true); + } + expect(view.$(dropdownSelectClass).length).toBe(1); + view.$(dropdownSelectClass).val(FieldViewsSpecHelpers.SELECT_OPTIONS[0]).change(); expect(view.fieldValue()).toBe(FieldViewsSpecHelpers.SELECT_OPTIONS[0][0]); AjaxHelpers.respondWithNoContent(requests); - if(editable === 'toggle') { view.showEditMode(true); } + if (editable === 'toggle') { view.showEditMode(true); } // When server returns success, there should no longer be an empty option. expect($(view.$('.u-field-value option')[0]).val()).toBe('si'); }); @@ -236,16 +260,18 @@ define(['backbone', 'jquery', 'underscore', 'common/js/spec_helpers/ajax_helpers // set bio to empty to see the placeholder. fieldData.model.set({bio: ''}); var view = new FieldViews.TextareaFieldView(fieldData).render(); - FieldViewsSpecHelpers.expectTitleAndMessageToContain(view, fieldData.title, fieldData.helpMessage, false); + FieldViewsSpecHelpers.expectTitleAndMessageToContain(view, fieldData.title, fieldData.helpMessage); expect(view.el).toHaveClass('mode-hidden'); - expect(view.$('.u-field-value .u-field-value-readonly').text()).toBe(fieldData.placeholderValue); + expect(view.fieldValue()).toBe(fieldData.placeholderValue); + expect(view.$(textareaLinkClass).length).toBe(0); var bio = 'Too much to tell!'; view.model.set({'bio': bio}); expect(view.el).toHaveClass('mode-display'); - expect(view.$('.u-field-value .u-field-value-readonly').text()).toBe(bio); + expect(view.fieldValue()).toBe(bio); view.$el.click(); expect(view.el).toHaveClass('mode-display'); + expect(view.$(textareaLinkClass).length).toBe(0); }); it("correctly renders, updates and persists changes to TextAreaFieldView when editable == toggle", function() { @@ -270,23 +296,26 @@ define(['backbone', 'jquery', 'underscore', 'common/js/spec_helpers/ajax_helpers FieldViewsSpecHelpers.expectTitleToContain(view, fieldData.title); FieldViewsSpecHelpers.expectMessageContains(view, view.indicators.canEdit); expect(view.el).toHaveClass('mode-placeholder'); - expect(view.$('.u-field-value .u-field-value-readonly').text()).toBe(fieldData.placeholderValue); + expect(view.fieldValue()).toBe(fieldData.placeholderValue); + expect(view.$(textareaLinkClass).length).toBe(1); view.$('.wrapper-u-field').click(); expect(view.el).toHaveClass('mode-edit'); view.$(valueInputSelector).val(BIO).focusout(); expect(view.fieldValue()).toBe(BIO); + expect(view.$(textareaLinkClass).length).toBe(0); AjaxHelpers.expectJsonRequest( requests, 'PATCH', view.model.url, {'bio': BIO} ); AjaxHelpers.respondWithNoContent(requests); expect(view.el).toHaveClass('mode-display'); + expect(view.$(textareaLinkClass).length).toBe(1); view.$('.wrapper-u-field').click(); view.$(valueInputSelector).val('').focusout(); AjaxHelpers.respondWithNoContent(requests); expect(view.el).toHaveClass('mode-placeholder'); - expect(view.$('.u-field-value .u-field-value-readonly').text()).toBe(fieldData.placeholderValue); + expect(view.fieldValue()).toBe(fieldData.placeholderValue); }); it("correctly renders LinkFieldView", function() { @@ -298,7 +327,7 @@ define(['backbone', 'jquery', 'underscore', 'common/js/spec_helpers/ajax_helpers }); var view = new FieldViews.LinkFieldView(fieldData).render(); - FieldViewsSpecHelpers.expectTitleAndMessageToContain(view, fieldData.title, fieldData.helpMessage, false); + FieldViewsSpecHelpers.expectTitleAndMessageToContain(view, fieldData.title, fieldData.helpMessage); expect(view.$('.u-field-value > a .u-field-link-title-' + view.options.valueAttribute).text().trim()).toBe(fieldData.linkTitle); }); @@ -311,7 +340,7 @@ define(['backbone', 'jquery', 'underscore', 'common/js/spec_helpers/ajax_helpers }); var view = new FieldViews.LinkFieldView(fieldData).render(); - FieldViewsSpecHelpers.expectTitleAndMessageToContain(view, fieldData.title, fieldData.helpMessage, false); + FieldViewsSpecHelpers.expectTitleAndMessageToContain(view, fieldData.title, fieldData.helpMessage); expect(view.$('.u-field-value > a .u-field-link-title-' + view.options.valueAttribute).text().trim()).toBe(fieldData.linkTitle); }); diff --git a/lms/static/js/views/fields.js b/lms/static/js/views/fields.js index 24aa5efb9b45bf523c7f6ef603b9fff398d5c303..ddc37b431ed0d9ff897dd7ec5ee2e383c0842f24 100644 --- a/lms/static/js/views/fields.js +++ b/lms/static/js/views/fields.js @@ -225,7 +225,7 @@ }, finishEditing: function() { - if (this.persistChanges === false) {return;} + if (this.persistChanges === false || this.mode !== 'edit') {return;} if (this.fieldValue() !== this.modelValue()) { this.saveValue(); } else { @@ -271,11 +271,11 @@ }, fieldValue: function () { - return this.$('.u-field-value input').val(); + return this.$('.u-field-value').text(); }, updateValueInField: function () { - this.$('.u-field-value input').val(_.escape(this.modelValue())); + this.$('.u-field-value ').html(_.escape(this.modelValue())); } }); @@ -345,9 +345,10 @@ this.$el.html(this.template({ id: this.options.valueAttribute, mode: this.mode, + editable: this.editable, title: this.options.title, screenReaderTitle: this.options.screenReaderTitle || this.options.title, - titleVisible: this.options.titleVisible || true, + titleVisible: this.options.titleVisible !== undefined ? this.options.titleVisible : true, iconName: this.options.iconName, showBlankOption: (!this.options.required || !this.modelValueIsSet()), selectOptions: this.options.options, @@ -376,7 +377,13 @@ }, fieldValue: function () { - var value = this.$('.u-field-value select').val(); + var value; + if (this.editable === 'never') { + value = this.modelValueIsSet() ? this.modelValue () : null; + } + else { + value = this.$('.u-field-value select').val(); + } return value === '' ? null : value; }, @@ -390,7 +397,9 @@ }, updateValueInField: function () { - this.$('.u-field-value select').val(this.modelValue() || ''); + if (this.editable !== 'never') { + this.$('.u-field-value select').val(this.modelValue() || ''); + } var value = this.displayValue(this.modelValue() || ''); if (this.modelValueIsSet() === false) { @@ -437,7 +446,9 @@ }, disableField: function(disable) { - this.$('.u-field-value select').prop('disabled', disable); + if (this.editable !== 'never') { + this.$('.u-field-value select').prop('disabled', disable); + } } }); @@ -473,6 +484,7 @@ id: this.options.valueAttribute, screenReaderTitle: this.options.screenReaderTitle || this.options.title, mode: this.mode, + editable: this.editable, value: value, message: this.helpMessage, messagePosition: this.options.messagePosition || 'footer', @@ -504,11 +516,16 @@ modelValue: function() { var value = this._super(); - return value ? $.trim(value) : ''; + return value ? $.trim(value) : ''; }, fieldValue: function () { - return this.$('.u-field-value textarea').val(); + if (this.mode === 'edit') { + return this.$('.u-field-value textarea').val(); + } + else { + return this.$('.u-field-value .u-field-value-readonly').text(); + } }, saveValue: function () { diff --git a/lms/templates/fields/field_dropdown.underscore b/lms/templates/fields/field_dropdown.underscore index 6ec92412a324476404419793404c6f7c6c0d2a13..6d72bafb34ba370bf32619b74ac2f09397b4218c 100644 --- a/lms/templates/fields/field_dropdown.underscore +++ b/lms/templates/fields/field_dropdown.underscore @@ -1,13 +1,13 @@ -<% if (title) { %> - <label class="u-field-title" for="u-field-select-<%- id %>"> - <%- title %> - </label> -<% } %> - -<% if (!titleVisible) { %> - <label class="sr" for="u-field-select-<%- id %>"> - <%- screenReaderTitle %> - </label> +<% if (editable !== 'never') { %> + <% if (title && titleVisible) { %> + <label class="u-field-title" for="u-field-select-<%- id %>"> + <%- title %> + </label> + <% } else { %> + <label class="sr" for="u-field-select-<%- id %>"> + <%- screenReaderTitle %> + </label> + <% } %> <% } %> <% if (iconName) { %> @@ -15,19 +15,24 @@ <% } %> <span class="u-field-value"> - <select name="select" id="u-field-select-<%- id %>" aria-describedby="u-field-message-<%- id %>"> - <% if (showBlankOption) { %> - <option value=""></option> - <% } %> - <% _.each(selectOptions, function(selectOption) { %> - <option value="<%- selectOption[0] %>"><%- selectOption[1] %></option> - <% }); %> - </select> - <button class="u-field-value-display"> + <% if (editable === 'never') { %> <span class="sr"><%- screenReaderTitle %> </span> <span class="u-field-value-readonly"></span> - <span class="sr"> <%- gettext('Click to edit') %></span> - </button> + <% } else { %> + <select name="select" id="u-field-select-<%- id %>" aria-describedby="u-field-message-<%- id %>"> + <% if (showBlankOption) { %> + <option value=""></option> + <% } %> + <% _.each(selectOptions, function(selectOption) { %> + <option value="<%- selectOption[0] %>"><%- selectOption[1] %></option> + <% }); %> + </select> + <button class="u-field-value-display"> + <span class="sr"><%- screenReaderTitle %> </span> + <span class="u-field-value-readonly"></span> + <span class="sr"> <%- gettext('Click to edit') %></span> + </button> + <% } %> </span> <span class="u-field-message" id="u-field-message-<%- id %>"> diff --git a/lms/templates/fields/field_readonly.underscore b/lms/templates/fields/field_readonly.underscore index 2c05a7d4f52f03a60bb744b70fb9e7b66d77fe00..307b014b64653e415edcefedc7e8c668ec7448e0 100644 --- a/lms/templates/fields/field_readonly.underscore +++ b/lms/templates/fields/field_readonly.underscore @@ -1,10 +1,8 @@ -<label class="u-field-title" aria-hidden="true"> - <%- title %> -</label> -<span class="sr" for="u-field-input-<%- id %>"><%- screenReaderTitle %></span> -<span class="u-field-value"> - <input id="u-field-input-<%- id %>" aria-describedby="u-field-message-<%- id %>" type="text" name="input" readonly=true value="<%- value %>"> -</span> +<% if (title) { %> +<span class="u-field-title" aria-hidden="true"><%- title %></span> +<% } %> +<span class="sr" for="u-field-value-<%- id %>"><%- screenReaderTitle %></span> +<span class="u-field-value" id="u-field-value-<%- id %>" aria-describedby="u-field-message-<%- id %>"><%- value %></span> <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-help-message-<%- id %>"> <%- message %></span> diff --git a/lms/templates/fields/field_textarea.underscore b/lms/templates/fields/field_textarea.underscore index aa0d7489f222c285b54dfa4a29b7db7ee8a8c6c4..96cb712a2bda165881f6a786d04441ebd8fe3201 100644 --- a/lms/templates/fields/field_textarea.underscore +++ b/lms/templates/fields/field_textarea.underscore @@ -1,6 +1,10 @@ <div class="wrapper-u-field"> <div class="u-field-header"> - <label class="u-field-title" for="u-field-textarea-<%- id %>" id="u-field-title-<%- id %>" aria-describedby="u-field-message-help-<%- id %>"></label> + <% if (mode === 'edit') { %> + <label class="u-field-title" for="u-field-textarea-<%- id %>" id="u-field-title-<%- id %>"></label> + <% } else { %> + <span class="u-field-title" id="u-field-title-<%- id %>" aria-hidden="true"></span> + <% } %> <% if (messagePosition === 'header') { %> <span class="u-field-message" id="u-field-message-<%- id %>"> <span class="u-field-message-notification" aria-live="polite"></span> @@ -9,14 +13,23 @@ <% }%> </div> - <div class="u-field-value" id="u-field-value-<%- id %>" aria-labelledby="u-field-title-<%- id %>"><% - var textareaDescribedBy = (message ? 'u-field-message-help-' : 'u-field-placeholder-value-') + id; - if (mode === 'edit') {%> - <textarea id="u-field-textarea-<%- id %>" rows="4" aria-describedby="<%- textareaDescribedBy %>"><%- value %></textarea> - <% } else { - %><a href="#"><span class="sr"><%- 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><% - } - %><span class="sr" id="u-field-placeholder-value-<%- id %>"><%- placeholderValue %></span> + <div class="u-field-value" id="u-field-value-<%- id %>" + <% if (mode === 'edit') { %> + aria-labelledby="u-field-title-<%- id %>"><textarea id="u-field-textarea-<%- id %>" rows="4" + <% if (message) { %> + aria-describedby="u-field-message-help-<%- id %>" + <% } %> + ><%- value %></textarea> + <% } else if (editable === 'never') { %> + ><p class="sr"><%- screenReaderTitle %></p><span class="u-field-value-readonly" aria-hidden="false" + <% if (message) { %> + aria-describedby="u-field-message-help-<%- id %>" + <% } %> + ><%- value %></span> + <% } else { %> + ><a href="#"><p class="sr"><%- screenReaderTitle %></p><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> + <span class="sr" id="u-field-placeholder-value-<%- id %>"><%- placeholderValue %></span> + <% } %> </div> <div class="u-field-footer"> diff --git a/lms/templates/student_account/account_settings.html b/lms/templates/student_account/account_settings.html index f799f4dbefcd422b0a0148519b0ec0ff4dc7e98a..69ea9669be07adf9845f4660bff582fbf6eff20f 100644 --- a/lms/templates/student_account/account_settings.html +++ b/lms/templates/student_account/account_settings.html @@ -12,7 +12,7 @@ from microsite_configuration import microsite <%namespace name='static' file='/static_content.html'/> <%block name="pagetitle">${_("Account Settings")}</%block> -<%block name="nav_skip">#u-field-input-username</%block> +<%block name="nav_skip">#content</%block> % if duplicate_provider: <section> diff --git a/lms/templates/student_profile/learner_profile.html b/lms/templates/student_profile/learner_profile.html index 5b2a63579a23d0ccab778cdb8d53fa86d53f08ea..84cb52baf6b15d86136a6ff1b0f0bda2c878ca0c 100644 --- a/lms/templates/student_profile/learner_profile.html +++ b/lms/templates/student_profile/learner_profile.html @@ -8,7 +8,7 @@ from openedx.core.lib.json_utils import EscapedEdxJSONEncoder %> <%block name="pagetitle">${_("Learner Profile")}</%block> -<%block name="nav_skip">#u-field-select-account_privacy</%block> +<%block name="nav_skip">#content</%block> <%block name="bodyclass">view-profile</%block>