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 @@ -