Commit f7e98062 by Waheed Ahmed

Merge pull request #12369 from edx/waheed/ecom-2981-account-settings-nav

Account Settings Navigation
parents 83155840 dc4e4f7d
......@@ -57,3 +57,9 @@ class AccountSettingsPage(FieldsMixin, PageObject):
Wait for loading indicator to become visible.
"""
EmptyPromise(self._is_loading_in_progress, "Loading is in progress.").fulfill()
def switch_account_settings_tabs(self, tab_id):
"""
Switch between the different account settings tabs.
"""
self.q(css='#{}'.format(tab_id)).click()
......@@ -228,13 +228,13 @@ class FieldsMixin(object):
"Link field with link title \"{0}\" is visible.".format(expected_title)
).fulfill()
def click_on_link_in_link_field(self, field_id):
def click_on_link_in_link_field(self, field_id, field_type='a'):
"""
Click the link in a link field.
"""
self.wait_for_field(field_id)
query = self.q(css='.u-field-{} a'.format(field_id))
query = self.q(css='.u-field-{} {}'.format(field_id, field_type))
if query.present:
query.first.click()
......
......@@ -158,7 +158,7 @@ class AccountSettingsPageTest(AccountSettingsTestMixin, WebAppTest):
"""
expected_sections_structure = [
{
'title': 'Basic Account Information (required)',
'title': 'Basic Account Information',
'fields': [
'Username',
'Full Name',
......@@ -169,21 +169,13 @@ class AccountSettingsPageTest(AccountSettingsTestMixin, WebAppTest):
]
},
{
'title': 'Additional Information (optional)',
'title': 'Additional Information',
'fields': [
'Education Completed',
'Gender',
'Year of Birth',
'Preferred Language',
]
},
{
'title': 'Connected Accounts',
'fields': [
'Dummy',
'Facebook',
'Google',
]
}
]
......@@ -240,13 +232,13 @@ class AccountSettingsPageTest(AccountSettingsTestMixin, WebAppTest):
self.account_settings_page.wait_for_page()
self.assertEqual(self.account_settings_page.value_for_dropdown_field(field_id), new_value)
def _test_link_field(self, field_id, title, link_title, success_message):
def _test_link_field(self, field_id, title, link_title, field_type, success_message):
"""
Test behaviour a link field.
"""
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)
self.account_settings_page.click_on_link_in_link_field(field_id)
self.account_settings_page.click_on_link_in_link_field(field_id, field_type=field_type)
self.account_settings_page.wait_for_message(field_id, success_message)
def test_username_field(self):
......@@ -316,7 +308,8 @@ class AccountSettingsPageTest(AccountSettingsTestMixin, WebAppTest):
self._test_link_field(
u'password',
u'Password',
u'Reset Password',
u'Reset Your Password',
u'button',
success_message='Click the link in the message to reset your password.',
)
......@@ -434,7 +427,7 @@ class AccountSettingsPageTest(AccountSettingsTestMixin, WebAppTest):
actual_events
)
def test_connected_accounts(self):
def test_linked_accounts(self):
"""
Test that fields for third party auth providers exist.
......@@ -442,9 +435,11 @@ class AccountSettingsPageTest(AccountSettingsTestMixin, WebAppTest):
because that would require accounts with the providers.
"""
providers = (
['auth-oa2-facebook', 'Facebook', 'Link'],
['auth-oa2-google-oauth2', 'Google', 'Link'],
['auth-oa2-facebook', 'Facebook', 'Link Your Account'],
['auth-oa2-google-oauth2', 'Google', 'Link Your Account'],
)
# switch to "Linked Accounts" tab
self.account_settings_page.switch_account_settings_tabs('accounts-tab')
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)
......
......@@ -222,19 +222,29 @@ class LoginFromCombinedPageTest(UniqueCourseTest):
def _link_dummy_account(self):
""" Go to Account Settings page and link the user's account to the Dummy provider """
account_settings = AccountSettingsPage(self.browser).visit()
# switch to "Linked Accounts" tab
account_settings.switch_account_settings_tabs('accounts-tab')
field_id = "auth-oa2-dummy"
account_settings.wait_for_field(field_id)
self.assertEqual("Link", account_settings.link_title_for_link_field(field_id))
self.assertEqual("Link Your Account", account_settings.link_title_for_link_field(field_id))
account_settings.click_on_link_in_link_field(field_id)
account_settings.wait_for_link_title_for_link_field(field_id, "Unlink")
# make sure we are on "Linked Accounts" tab after the account settings
# page is reloaded
account_settings.switch_account_settings_tabs('accounts-tab')
account_settings.wait_for_link_title_for_link_field(field_id, "Unlink This Account")
def _unlink_dummy_account(self):
""" Verify that the 'Dummy' third party auth provider is linked, then unlink it """
# This must be done after linking the account, or we'll get cross-test side effects
account_settings = AccountSettingsPage(self.browser).visit()
# switch to "Linked Accounts" tab
account_settings.switch_account_settings_tabs('accounts-tab')
field_id = "auth-oa2-dummy"
account_settings.wait_for_field(field_id)
self.assertEqual("Unlink", account_settings.link_title_for_link_field(field_id))
self.assertEqual("Unlink This Account", account_settings.link_title_for_link_field(field_id))
account_settings.click_on_link_in_link_field(field_id)
account_settings.wait_for_message(field_id, "Successfully unlinked")
......@@ -372,9 +382,12 @@ class RegisterFromCombinedPageTest(UniqueCourseTest):
# Now unlink the account (To test the account settings view and also to prevent cross-test side effects)
account_settings = AccountSettingsPage(self.browser).visit()
# switch to "Linked Accounts" tab
account_settings.switch_account_settings_tabs('accounts-tab')
field_id = "auth-oa2-dummy"
account_settings.wait_for_field(field_id)
self.assertEqual("Unlink", account_settings.link_title_for_link_field(field_id))
self.assertEqual("Unlink This Account", account_settings.link_title_for_link_field(field_id))
account_settings.click_on_link_in_link_field(field_id)
account_settings.wait_for_message(field_id, "Successfully unlinked")
......
......@@ -141,7 +141,7 @@ define(['backbone', 'jquery', 'underscore', 'common/js/spec_helpers/ajax_helpers
AjaxHelpers.respondWithJson(requests, Helpers.createUserPreferencesData());
AjaxHelpers.respondWithJson(requests, {}); // Page viewed analytics event
var sectionsData = accountSettingsView.options.sectionsData;
var sectionsData = accountSettingsView.options.tabSections.aboutTabSections;
expect(sectionsData[0].fields.length).toBe(6);
......@@ -180,14 +180,6 @@ define(['backbone', 'jquery', 'underscore', 'common/js/spec_helpers/ajax_helpers
defaultValue: null
}, requests);
});
var section2Fields = sectionsData[2].fields;
expect(section2Fields.length).toBe(2);
for (var i = 0; i < section2Fields.length; i++) {
var view = section2Fields[i].view;
AccountSettingsFieldViewSpecHelpers.verifyAuthField(view, view.options, requests);
}
});
});
});
......@@ -10,13 +10,13 @@ define(['backbone', 'jquery', 'underscore', 'common/js/spec_helpers/ajax_helpers
spyOn(view, 'redirect_to');
FieldViewsSpecHelpers.expectTitleAndMessageToContain(view, data.title, data.helpMessage);
expect(view.$(selector).text().trim()).toBe('Unlink');
expect(view.$(selector).text().trim()).toBe('Unlink This Account');
view.$(selector).click();
FieldViewsSpecHelpers.expectMessageContains(view, 'Unlinking');
AjaxHelpers.expectRequest(requests, 'POST', data.disconnectUrl);
AjaxHelpers.respondWithNoContent(requests);
expect(view.$(selector).text().trim()).toBe('Link');
expect(view.$(selector).text().trim()).toBe('Link Your Account');
FieldViewsSpecHelpers.expectMessageContains(view, 'Successfully unlinked.');
view.$(selector).click();
......
......@@ -32,7 +32,7 @@ define(['backbone', 'jquery', 'underscore', 'common/js/spec_helpers/ajax_helpers
});
var view = new AccountSettingsFieldViews.PasswordFieldView(fieldData).render();
view.$('.u-field-value > a').click();
view.$('.u-field-value > button').click();
AjaxHelpers.expectRequest(requests, 'POST', '/password_reset', "email=legolas%40woodland.middlearth");
AjaxHelpers.respondWithJson(requests, {"success": "true"});
FieldViewsSpecHelpers.expectMessageContains(
......
......@@ -15,7 +15,7 @@ define(['backbone', 'jquery', 'underscore', 'common/js/spec_helpers/ajax_helpers
var model = new UserAccountModel();
model.set(Helpers.createAccountSettingsData());
var sectionsData = [
var aboutSectionsData = [
{
title: "Basic Account Information",
fields: [
......@@ -53,7 +53,9 @@ define(['backbone', 'jquery', 'underscore', 'common/js/spec_helpers/ajax_helpers
var accountSettingsView = new AccountSettingsView({
el: $('.wrapper-account-settings'),
model: model,
sectionsData : sectionsData
tabSections: {
aboutTabSections: aboutSectionsData
}
});
return accountSettingsView;
......
......@@ -75,8 +75,8 @@ define(['underscore'], function(_) {
if ('fieldValue' in view) {
expect(view.fieldValue()).toBe(view.modelValue());
} else if (view.fieldType === 'link') {
expect($(element).find('a').length).toBe(1);
} else if (view.fieldType === 'button') {
expect($(element).find('button').length).toBe(1);
} else {
throw new Error('Unexpected field type: ' + view.fieldType);
}
......@@ -87,7 +87,7 @@ define(['underscore'], function(_) {
};
var expectSettingsSectionsAndFieldsToBeRendered = function (accountSettingsView, fieldsAreRendered) {
var sectionsData = accountSettingsView.options.sectionsData;
var sectionsData = accountSettingsView.options.tabSections.aboutTabSections;
var sectionElements = accountSettingsView.$('.section');
expect(sectionElements.length).toBe(sectionsData.length);
......
;(function (define, undefined) {
'use strict';
define([
'gettext',
'jquery',
'underscore',
'backbone',
'text!templates/student_account/account_settings_section.underscore'
], function (gettext, $, _, Backbone, sectionTemplate) {
var AccountSectionView = Backbone.View.extend({
initialize: function (options) {
this.options = options;
},
render: function () {
this.$el.html(_.template(sectionTemplate)({
sections: this.options.sections,
activeTabName: this.options.activeTabName
}));
}
});
return AccountSectionView;
});
}).call(this, define || RequireJS.define);
......@@ -2,30 +2,35 @@
'use strict';
define([
'gettext', 'jquery', 'underscore', 'backbone', 'logger',
'js/views/fields',
'js/student_account/models/user_account_model',
'js/student_account/models/user_preferences_model',
'js/student_account/views/account_settings_fields',
'js/student_account/views/account_settings_view'
], function (gettext, $, _, Backbone, Logger, FieldViews, UserAccountModel, UserPreferencesModel,
], function (gettext, $, _, Backbone, Logger, UserAccountModel, UserPreferencesModel,
AccountSettingsFieldViews, AccountSettingsView) {
return function (fieldsData, authData, userAccountsApiUrl, userPreferencesApiUrl, accountUserId, platformName) {
var accountSettingsElement, userAccountModel, userPreferencesModel, aboutSectionsData,
accountsSectionData, accountSettingsView, showAccountSettingsPage, showLoadingError;
var accountSettingsElement = $('.wrapper-account-settings');
accountSettingsElement = $('.wrapper-account-settings');
var userAccountModel = new UserAccountModel();
userAccountModel = new UserAccountModel();
userAccountModel.url = userAccountsApiUrl;
var userPreferencesModel = new UserPreferencesModel();
userPreferencesModel = new UserPreferencesModel();
userPreferencesModel.url = userPreferencesApiUrl;
var sectionsData = [
aboutSectionsData = [
{
title: gettext('Basic Account Information (required)'),
title: gettext('Basic Account Information'),
subtitle: gettext(
'These settings include basic information about your account. You can also ' +
'specify additional information and see your linked social accounts on this page.'
),
fields: [
{
view: new FieldViews.ReadonlyFieldView({
view: new AccountSettingsFieldViews.ReadonlyFieldView({
model: userAccountModel,
title: gettext('Username'),
valueAttribute: 'username',
......@@ -35,7 +40,7 @@
})
},
{
view: new FieldViews.TextFieldView({
view: new AccountSettingsFieldViews.TextFieldView({
model: userAccountModel,
title: gettext('Full Name'),
valueAttribute: 'name',
......@@ -60,12 +65,14 @@
view: new AccountSettingsFieldViews.PasswordFieldView({
model: userAccountModel,
title: gettext('Password'),
screenReaderTitle: gettext('Reset your Password'),
screenReaderTitle: gettext('Reset Your Password'),
valueAttribute: 'password',
emailAttribute: 'email',
linkTitle: gettext('Reset Password'),
linkTitle: gettext('Reset Your Password'),
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.')
helpMessage: gettext('When you click "Reset Your Password", edX will send a message ' +
'to the email address for your edX account. Click the link in the message to ' +
'reset your password.')
})
},
{
......@@ -83,7 +90,7 @@
})
},
{
view: new FieldViews.DropdownFieldView({
view: new AccountSettingsFieldViews.DropdownFieldView({
model: userAccountModel,
required: true,
title: gettext('Country or Region'),
......@@ -95,10 +102,10 @@
]
},
{
title: gettext('Additional Information (optional)'),
title: gettext('Additional Information'),
fields: [
{
view: new FieldViews.DropdownFieldView({
view: new AccountSettingsFieldViews.DropdownFieldView({
model: userAccountModel,
title: gettext('Education Completed'),
valueAttribute: 'level_of_education',
......@@ -107,7 +114,7 @@
})
},
{
view: new FieldViews.DropdownFieldView({
view: new AccountSettingsFieldViews.DropdownFieldView({
model: userAccountModel,
title: gettext('Gender'),
valueAttribute: 'gender',
......@@ -116,7 +123,7 @@
})
},
{
view: new FieldViews.DropdownFieldView({
view: new AccountSettingsFieldViews.DropdownFieldView({
model: userAccountModel,
title: gettext('Year of Birth'),
valueAttribute: 'year_of_birth',
......@@ -137,16 +144,17 @@
}
];
if (_.isArray(authData.providers)) {
var accountsSectionData = {
title: gettext('Connected Accounts'),
accountsSectionData = [
{
title: gettext('Linked Accounts'),
subtitle: gettext(
'You can link your social media accounts to your edX account to make signing in to edx.org ' +
'and the edX mobile apps easier.'
),
fields: _.map(authData.providers, function(provider) {
return {
'view': new AccountSettingsFieldViews.AuthFieldView({
title: provider.name,
screenReaderTitle: interpolate_text(
gettext("Connect your {accountName} account"), {accountName: provider['name']}
),
valueAttribute: 'auth-' + provider.id,
helpMessage: '',
connected: provider.connected,
......@@ -156,24 +164,23 @@
})
};
})
};
sectionsData.push(accountsSectionData);
}
}
];
var accountSettingsView = new AccountSettingsView({
accountSettingsView = new AccountSettingsView({
model: userAccountModel,
accountUserId: accountUserId,
el: accountSettingsElement,
sectionsData: sectionsData
tabSections: {
aboutTabSections: aboutSectionsData,
accountsTabSections: accountsSectionData
},
userPreferencesModel: userPreferencesModel
});
accountSettingsView.render();
var showLoadingError = function () {
accountSettingsView.showLoadingError();
};
var showAccountFields = function () {
showAccountSettingsPage = function () {
// Record that the account settings page was viewed.
Logger.log('edx.user.settings.viewed', {
page: "account",
......@@ -185,11 +192,15 @@
accountSettingsView.renderFields();
};
showLoadingError = function () {
accountSettingsView.showLoadingError();
};
userAccountModel.fetch({
success: function () {
// Fetch the user preferences model
userPreferencesModel.fetch({
success: showAccountFields,
success: showAccountSettingsPage,
error: showLoadingError
});
},
......
;(function (define, undefined) {
'use strict';
define([
'gettext', 'jquery', 'underscore', 'backbone', 'text!templates/student_account/account_settings.underscore'
], function (gettext, $, _, Backbone, accountSettingsTemplate) {
'gettext',
'jquery',
'underscore',
'backbone',
'js/student_account/views/account_section_view',
'text!templates/student_account/account_settings.underscore'
], function (gettext, $, _, Backbone, AccountSectionView, accountSettingsTemplate) {
var AccountSettingsView = Backbone.View.extend({
navLink: '.account-nav-link',
activeTab: 'aboutTabSections',
accountSettingsTabs: [
{name: 'aboutTabSections', id: 'about-tab', label: gettext('Account Information'), class: 'active'},
{name: 'accountsTabSections', id: 'accounts-tab', label: gettext('Linked Accounts')}
],
events: {
'click .account-nav-link': 'changeTab'
},
initialize: function (options) {
this.options = _.extend({}, options);
_.bindAll(this, 'render', 'renderFields', 'showLoadingError');
this.options = options;
_.bindAll(this, 'render', 'changeTab', 'renderFields', 'showLoadingError');
},
render: function () {
this.$el.html(_.template(accountSettingsTemplate)({
sections: this.options.sectionsData
accountSettingsTabs: this.accountSettingsTabs
}));
this.renderSection(this.options.tabSections[this.activeTab]);
return this;
},
renderFields: function () {
this.$('.ui-loading-indicator').addClass('is-hidden');
changeTab: function(e) {
var $currentTab;
e.preventDefault();
$currentTab = $(e.target);
this.activeTab = $currentTab.data('name');
this.renderSection(this.options.tabSections[this.activeTab]);
this.renderFields();
$(this.navLink).removeClass('active');
$currentTab.addClass('active');
$(this.navLink).removeAttr('aria-describedby');
$currentTab.attr('aria-describedby', 'header-subtitle-'+this.activeTab);
},
renderSection: function (tabSections) {
var accountSectionView = new AccountSectionView({
activeTabName: this.activeTab,
sections: tabSections,
el: '.account-settings-sections'
});
accountSectionView.render();
},
renderFields: function () {
var view = this;
_.each(this.$('.account-settings-section-body'), function (sectionEl, index) {
_.each(view.options.sectionsData[index].fields, function (field) {
view.$('.ui-loading-indicator').addClass('is-hidden');
_.each(view.$('.account-settings-section-body'), function (sectionEl, index) {
_.each(view.options.tabSections[view.activeTab][index].fields, function (field) {
$(sectionEl).append(field.view.render().el);
});
});
......
......@@ -230,8 +230,15 @@
},
finishEditing: function() {
var modelValue;
if (this.persistChanges === false || this.mode !== 'edit') {return;}
if (this.fieldValue() !== this.modelValue()) {
modelValue = this.modelValue();
if (!(_.isUndefined(modelValue) || _.isNull(modelValue))) {
modelValue = modelValue.toString();
}
if (this.fieldValue() !== modelValue) {
this.saveValue();
} else {
if (this.editable === 'always') {
......
......@@ -518,7 +518,6 @@ $dark-gray: rgb(51, 51, 51) !default;
$border-color: rgb(200, 200, 200) !default;
$sidebar-color: rgb(246, 246, 246) !default;
$outer-border-color: $gray-l3;
$light-gray: rgb(221,221,221) !default;
// used by descriptor css
$lightGrey: rgb(237,241,245) !default;
......
......@@ -3,7 +3,6 @@
.wrapper-footer {
@extend %ui-print-excluded;
margin-top: ($baseline*2) + px;
box-shadow: 0 -1px 5px 0 $shadow-l1;
border-top: 1px solid tint(palette(grayscale, light), 50%);
padding: 25px ($baseline/2 + px) ($baseline*1.5 + px) ($baseline/2 + px);
......
......@@ -5,7 +5,6 @@
.wrapper-footer {
@extend %ui-print-excluded;
margin-top: ($baseline*2);
box-shadow: 0 -1px 5px 0 $shadow-l1;
border-top: 1px solid tint($m-gray, 50%);
padding: 25px ($baseline/2) ($baseline*1.5) ($baseline/2);
......
......@@ -9,11 +9,13 @@
// +Container - Account Settings
.wrapper-account-settings {
@extend .container;
padding-top: ($baseline*2);
background: $white;
width: 100%;
.account-settings-container {
padding: 0;
max-width: grid-width(12);
padding: 10px;
margin: 0 auto;
}
.ui-loading-indicator,
......@@ -36,15 +38,59 @@
.wrapper-account-settings {
.wrapper-header {
max-width: grid-width(12);
height: 139px;
border-bottom: 4px solid $m-gray-l4;
.header-title {
@extend %t-title4;
margin-bottom: ($baseline/2);
padding-top: ($baseline*2);
}
.header-subtitle {
color: $gray-l2;
}
.account-nav {
@include float(left);
margin: ($baseline/2) 0;
padding: 0;
list-style: none;
.account-nav-item {
@include float(left);
display: flex;
margin: 0;
text-transform: none;
justify-content: center;
.account-nav-link {
font-size: em(14);
color: $gray;
padding: 5px 25px 23px;
display: inline-block;
border-radius: 0;
}
button {
@extend %ui-clear-button;
@extend %btn-no-style;
@include appearance(none);
display:block;
padding: ($baseline/4);
&:hover,
&:focus {
text-decoration: none;
border-bottom: 4px solid $courseware-border-bottom-color !important;
}
&.active{
border-bottom: 4px solid $black-t3 !important;
}
}
}
}
}
}
......@@ -54,27 +100,189 @@
.section-header {
@extend %t-title6;
@extend %t-strong;
padding-bottom: ($baseline/2);
border-bottom: 1px solid $gray-l4;
padding-top: ($baseline/2)*3;
color: $dark-gray1;
}
.section {
background-color: $white;
padding: $baseline;
margin-top: $baseline;
border: 1px solid $gray-l4;
box-shadow: 0 0 1px 1px $shadow-l2;
border-radius: 5px;
}
border-bottom: 4px solid $m-gray-l4;
a span {
color: $link-color;
}
.account-settings-header-subtitle {
font-size: em(18);
line-height: normal;
color: $dark-gray;
padding-top: 20px;
padding-bottom: 10px;
}
.account-settings-section-body {
.u-field {
border-bottom: 2px solid $m-gray-l4;
.field {
width: 30%;
vertical-align: top;
display: inline-block;
position: relative;
select {
@include appearance(none);
padding: 14px 30px 14px 15px;
border: 1px solid $light-gray;
background-color: transparent;
border-radius: 2px;
position: relative;
z-index: 10;
&::-ms-expand{
display: none;
}
~ .icon-caret-down{
&:after{
content: "";
border-left: 6px solid transparent;
border-right: 6px solid transparent;
border-top: 7px solid $blue;
position: absolute;
right: 10px;
bottom: 20px;
z-index: 0;
}
}
}
.field-label {
display: block;
width: auto;
margin-bottom: 0.625rem;
font-size: 1rem;
line-height: 1;
color: $dark-gray;
}
.field-input {
@include transition(all 0.125s ease-in-out 0s);
display: inline-block;
padding: 0.625rem;
border: 1px solid $light-gray;
border-radius: 2px;
background: $white;
font-size: $body-font-size;
color: $dark-gray;
width: 100%;
height: 48px;
box-shadow: none;
}
.u-field-link {
@extend %ui-clear-button;
// set styles
@extend %btn-pl-default-base;
@include font-size(18);
width: 100%;
border: 1px solid $blue;
color: $blue;
padding: 11px 14px;
line-height: normal;
}
#u-field-value-username {
padding-top: ($baseline/2);
}
}
.social-field-linked {
background: $m-gray-l4;
box-shadow: 0 1px 2px 1px $shadow-l2;
padding: 1.25rem;
box-sizing: border-box;
margin: 10px;
width: 100%;
.field-label {
@include font-size(24);
}
.u-field-social-help {
display: inline-block;
padding: 20px 0 6px;
}
.u-field-link {
@include font-size(14);
@include text-align(left);
border: none;
margin-top: $baseline;
font-weight: $font-semibold;
padding: 0;
&:focus, &:hover, &:active {
background-color: transparent;
color: $m-blue-d3;
border: none;
}
}
}
.social-field-unlinked {
background: $m-gray-l4;
box-shadow: 0 1px 2px 1px $shadow-l2;
padding: 1.25rem;
box-sizing: border-box;
text-align: center;
margin: 10px;
width: 100%;
.field-label {
@include font-size(24);
text-align: center;
}
.u-field-link {
@include font-size(14);
margin-top: $baseline;
font-weight: $font-semibold;
}
}
.u-field-message {
position: relative;
padding: 24px 0 0 ($baseline*5);
.u-field-message-notification {
position: absolute;
left: 0;
top: 0;
bottom: 0;
margin: auto;
padding: 38px 0 0 ($baseline*5);
}
}
&:last-child {
border-bottom: none;
margin-bottom: ($baseline*2);
}
}
.u-field-social {
border-bottom: none;
margin-right: 20px;
width: 30%;
display: inline-block;
vertical-align: top;
.u-field-social-help {
@include font-size(12);
color: $m-gray-d1;
}
}
}
a span {
&:hover, &:focus {
color: $pink;
text-decoration: none !important;
&:last-child {
border-bottom: none;
}
}
}
<div class="u-field-value field">
<% if (editable !== 'never') { %>
<% if (title && titleVisible) { %>
<label class="u-field-title field-label" for="u-field-select-<%- id %>">
<%- title %>
</label>
<% } else { %>
<label class="sr" for="u-field-select-<%- id %>">
<%- screenReaderTitle %>
</label>
<% } %>
<% } %>
<% if (iconName) { %>
<span class="u-field-icon icon fa <%- iconName %> fa-fw" aria-hidden="true"></span>
<% } %>
<% if (editable === 'never') { %>
<span class="sr"><%- screenReaderTitle %></span>
<span class="u-field-value-readonly"></span>
<% } else { %>
<select name="select" id="u-field-select-<%- id %>" aria-describedby="u-field-help-message-<%- id %>">
<% if (showBlankOption) { %>
<option value=""></option>
<% } %>
<% _.each(selectOptions, function(selectOption) { %>
<option value="<%- selectOption[0] %>"><%- selectOption[1] %></option>
<% }); %>
</select>
<span class="icon-caret-down" aria-hidden="true"></span>
<button class="u-field-value-display">
<span class="sr"><%- screenReaderTitle %> &nbsp;</span>
<span class="u-field-value-readonly"></span>
<span class="sr"><%- gettext('Click to edit') %></span>
</button>
<% } %>
</div>
<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>
</span>
<div class="u-field-value field">
<span class="u-field-title field-label"><%- title %></span>
<button class="u-field-link u-field-link-title-<%- id %> " id="u-field-link-<%- id %>" aria-describedby="u-field-message-help-<%- id %>"><%- linkTitle %></button>
</div>
<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 %>"> <%- message %></span>
</span>
<div class="field">
<span class="u-field-title field-label"><%- title %></span>
<span class="u-field-value" id="u-field-value-<%- id %>" aria-describedby="u-field-message-help-<%- id %>"><b><%- value %></b></span>
</div>
<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 %>"> <%- message %></span>
</span>
<div class="u-field-value field <%- linkClass %>">
<h4 class="u-field-title field-label"><%- title %></h4>
<span class="u-field-social-help"><%- subTitle %></span>
<a class="u-field-link" id="u-field-link-<%- id %>" href="<%- linkHref %>" aria-describedby="u-field-message-help-<%- id %>">
<span class="sr"><%- screenReaderTitle %></span>
<span class="u-field-link-title-<%- id %>" aria-hidden="true"><%- linkTitle %></span>
</a>
</div>
<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 %>"><%- message %></span>
</span>
<div class="u-field-value field">
<label class="u-field-title field-label" for="field-input-<%- id %>"><%- title %></label>
<input class="field-input input-text" type="text" id="field-input-<%- id %>" title="Input field for <%- id %>" aria-describedby="u-field-message-help-<%- id %>" name="input" value="<%- value %>" />
</div>
<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 %>"> <%- message %></span>
</span>
......@@ -2,25 +2,16 @@
<div class="account-settings-container">
<div class="wrapper-header">
<h2 class="header-title"><%- gettext("Account Settings") %></h2>
<small class="account-settings-header-subtitle"><%- gettext("These settings include basic information about your account. You can also specify additional information and see your linked social accounts on this page.") %></small>
<ul class="left list-inline account-nav">
<% _.each(accountSettingsTabs, function(tab) { %>
<li class="account-nav-item">
<button id="<%- tab.id %>" data-name="<%- tab.name %>" <% if (tab.class) { %> aria-describedby="header-subtitle-<%- tab.name %>" <% } %> class="account-nav-link <%- tab.class %>" ><%- tab.label %></button>
</li>
<% }); %>
</ul>
</div>
<div class="account-settings-sections">
<% _.each(sections, function(section) { %>
<div class="section">
<h3 class="section-header"><%- gettext(section.title) %></h3>
<div class="account-settings-section-body">
<div class="ui-loading-indicator">
<span class="spin"><i class="icon fa fa-refresh" aria-hidden=true></i></span>
<span class="copy"><%- gettext("Loading") %></span>
</div>
<div class="ui-loading-error is-hidden">
<i class="fa fa-exclamation-triangle message-error" aria-hidden=true></i>
<span class="copy"><%- gettext("An error occurred. Please reload the page.") %></span>
</div>
</div>
</div>
<% }); %>
</div>
</div>
</main>
<% _.each(sections, function(section) { %>
<div class="section">
<% if (section.subtitle) { %>
<p id="header-subtitle-<%- activeTabName %>" class="account-settings-header-subtitle"><%- gettext(section.subtitle) %></p>
<% } %>
<h3 class="section-header"><%- gettext(section.title) %></h3>
<div class="account-settings-section-body">
<div class="ui-loading-indicator">
<span class="spin"><span class="icon fa fa-refresh" aria-hidden=true></span></span>
<span class="copy"><%- gettext("Loading") %></span>
</div>
<div class="ui-loading-error is-hidden">
<span class="fa fa-exclamation-triangle message-error" aria-hidden=true></span>
<span class="copy"><%- gettext("An error occurred. Please reload the page.") %></span>
</div>
</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