Skip to content
This repository was archived by the owner on Apr 3, 2019. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<aside id="password-repeat-balloon" class="input-help input-help-balloon password-repeat-balloon">
<ul>
<li class="lock last big-only">{{#unsafeTranslate}}Remember this password &mdash; it encrypts your data! If forgotten you will lose access to Sync data.{{/unsafeTranslate}}</li>
</ul>
</aside>
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<aside id="password-strength-balloon" class="input-help input-help-balloon password-strength-balloon">
<h3 class="big-only">{{#t}}Your Firefox Account password{{/t}}</h3>
<ul>
<li class="lock last big-only">{{#unsafeTranslate}}Stay safe &mdash; don't reuse passwords.{{/unsafeTranslate}}</li>
<li id="password-too-short"
{{^hasUserTakenAction}}class="min-length unmet"{{/hasUserTakenAction}}
{{#isTooShort}}class="min-length fail"{{/isTooShort}}
Expand All @@ -19,7 +19,5 @@
{{#isCommon}}class="not-common fail"{{/isCommon}}
{{^isCommon}}class="not-common met"{{/isCommon}}
>{{#unsafeTranslate}}Must not match this <a %(escapedCommonPasswordLinkAttrs)s>list of common passwords</a>{{/unsafeTranslate}}</li>
<li class="lock big-only">{{#unsafeTranslate}}Be original and be safe &mdash; don't reuse this password anywhere else.{{/unsafeTranslate}}</li>
<li class="lock big-only">{{#unsafeTranslate}}Remember this password &mdash; resetting it erases your data from our servers.{{/unsafeTranslate}}</li>
</ul>
</aside>
1 change: 1 addition & 0 deletions app/scripts/templates/sign_up_password.mustache
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@

<div class="input-row password-row">
<input id="vpassword" type="password" class="password check-password tooltip-below" placeholder="{{#t}}Repeat password{{/t}}" pattern=".{8,}" required data-synchronize-show="true" />
<div class="helper-balloon"></div>
</div>

{{{ coppaHTML }}}
Expand Down
4 changes: 2 additions & 2 deletions app/scripts/views/mixins/password-mixin.js
Original file line number Diff line number Diff line change
Expand Up @@ -199,12 +199,12 @@ module.exports = {
},

showPasswordHelper () {
this.$('.input-help:not(.password-strength-balloon)').css('opacity', '1');
this.$('.input-help:not(.password-strength-balloon,.password-repeat-balloon)').css('opacity', '1');
},

hidePasswordHelper () {
// Hide all input-help classes except input-help-forgot-pw
this.$('.input-help:not(.input-help-forgot-pw,.password-strength-balloon)').css('opacity', '0');
this.$('.input-help:not(.input-help-forgot-pw,.password-strength-balloon,.password-repeat-balloon)').css('opacity', '0');
},

/**
Expand Down
38 changes: 38 additions & 0 deletions app/scripts/views/mixins/password-repeat-mixin.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

import PasswordWithRepeatBalloonView from '../password_repeat/password_with_repeat_balloon';

/**
* Create the mixin to set up the password repeat UI.
*
* @param {Object} config
* @param {String} config.balloonEl selector where the password repeat balloon should attach
* @param {String} config.passwordEl selector for the password element to watch
* @returns {Object} the mixin
*/
export default function (config = {}) {
const { balloonEl, passwordEl } = config;

return {
afterRender () {
return Promise.resolve().then(() => {
if (! this.$(passwordEl).length) {
return;
}
const passwordView = this._createPasswordWithRepeatBalloonView();
this.trackChildView(passwordView);
});
},

_createPasswordWithRepeatBalloonView () {
return new PasswordWithRepeatBalloonView({
balloonEl: this.$(balloonEl),
el: this.$(passwordEl),
lang: this.lang,
translator: this.translator
});
}
};
}
77 changes: 77 additions & 0 deletions app/scripts/views/password_repeat/password_repeat_balloon.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

/**
* Display a password strength balloon. Component automatically
* updates whenever changes are made to the underlying model.
*
* @export
* @class PasswordRepeatBalloonView
* @extends {BaseView}
*/

import BaseView from '../base';
import Cocktail from 'cocktail';
import OneVisibleOfTypeMixin from '../mixins/one-visible-of-type-mixin';
import Template from '../../templates/partial/password-repeat-balloon.mustache';

// Allow the balloon to stay visible for a bit so that
// the user can see all the criteria were met.
const DELAY_BEFORE_HIDE_MS = 750;

const DELAY_BEFORE_HIDE_BALLOON_EL_MS = 500;

const PASSWORD_REPEAT_BALLOON_SELECTOR = '.password-repeat-balloon';

class PasswordRepeatBalloonView extends BaseView {
template = Template;

initialize (config = {}) {
this.delayBeforeHideMS = config.delayBeforeHideMS || DELAY_BEFORE_HIDE_MS;
}

afterRender () {
this.show();
}

update () {
this.clearTimeouts();
return this.render()
.then(() => this.hideAfterDelay());
}

clearTimeouts () {
this.clearTimeout(this._hideTimeout);
this.clearTimeout(this._hideBalloonElTimeout);
}

show () {
this.$(PASSWORD_REPEAT_BALLOON_SELECTOR).show().css('opacity', '1');
}

hide () {
const $balloonEl = this.$(PASSWORD_REPEAT_BALLOON_SELECTOR);
$balloonEl.css('opacity', '0');
this._hideBalloonElTimeout = this.setTimeout(() => {
$balloonEl.hide();
}, DELAY_BEFORE_HIDE_BALLOON_EL_MS);
}

hideAfterDelay () {
this._hideTimeout = this.setTimeout(() => {
this.hide();
}, this.delayBeforeHideMS);
}
}

Cocktail.mixin(
PasswordRepeatBalloonView,
OneVisibleOfTypeMixin({
hideMethod: 'hide',
showMethod: 'show',
viewType: 'tooltip'
})
);

export default PasswordRepeatBalloonView;
51 changes: 51 additions & 0 deletions app/scripts/views/password_repeat/password_with_repeat_balloon.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

/**
* Creates and manages a PasswordRepeatBalloon.
* Updates to the bound password element cause updates to the model
* which are propagated out to the PasswordRepeatBalloon to
* update the UI.
*
* @export
* @class PasswordWithRepeatBalloonView
* @extends {FormView}
*/

import FormView from '../form';
import PasswordRepeatBalloonView from './password_repeat_balloon';

const PasswordWithRepeatBalloonView = FormView.extend({
events: {
blur: 'hideBalloon',
focus: 'showBalloon',
},

initialize (options = {}) {
this.passwordHelperBalloon = options.passwordHelperBalloon;
this.balloonEl = options.balloonEl;
},

showBalloon () {
if (! this.passwordHelperBalloon) {
this.passwordHelperBalloon = new PasswordRepeatBalloonView({
el: this.balloonEl,
lang: this.lang,
model: this.model,
translator: this.translator
});
this.trackChildView(this.passwordHelperBalloon);
}
return this.passwordHelperBalloon.render()
.then(() => this.passwordHelperBalloon.show());
},

hideBalloon () {
if (this.passwordHelperBalloon) {
return this.passwordHelperBalloon.hide();
}
}
});

export default PasswordWithRepeatBalloonView;
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ const DELAY_BEFORE_UPDATE_MODEL_MS = 1000;

const PasswordWithStrengthBalloonView = FormView.extend({
events: {
blur: 'hideBalloon',
change: 'updateModelAfterDelay',
focus: 'createBalloonIfNeeded',
keypress: 'updateModelAfterDelay',
Expand All @@ -44,13 +45,14 @@ const PasswordWithStrengthBalloonView = FormView.extend({
this.updateModelAfterDelay = debounce(() => this.updateModel(), delayBeforeUpdateModelMS);
},

createBalloonIfNeeded () {
createBalloonIfNeeded (ev) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ev looks unused.

// The balloon is created as soon as the user focuses the input element
// and the password is missing or invalid, or as soon as the model
// becomes invalid.
if (this.shouldCreateBalloon()) {
this.createBalloon();
}
this.showBalloon();
},

shouldCreateBalloon () {
Expand Down Expand Up @@ -97,6 +99,18 @@ const PasswordWithStrengthBalloonView = FormView.extend({
});
},

showBalloon () {
if (this.passwordHelperBalloon) {
this.passwordHelperBalloon.show();
}
},

hideBalloon () {
if (this.passwordHelperBalloon) {
this.passwordHelperBalloon.hide();
}
},

/**
* Updates the model after some sort of user action.
*/
Expand Down
7 changes: 6 additions & 1 deletion app/scripts/views/sign_up_password.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import FormPrefillMixin from './mixins/form-prefill-mixin';
import FormView from './form';
import PasswordMixin from './mixins/password-mixin';
import PasswordStrengthMixin from './mixins/password-strength-mixin';
import PasswordRepeatMixin from './mixins/password-repeat-mixin';
import { preventDefaultThen } from './base';
import ServiceMixin from './mixins/service-mixin';
import SignUpMixin from './mixins/signup-mixin';
Expand Down Expand Up @@ -95,8 +96,12 @@ Cocktail.mixin(
FlowEventsMixin,
FormPrefillMixin,
PasswordMixin,
PasswordRepeatMixin({
balloonEl: '#vpassword + .helper-balloon',
passwordEl: '#vpassword'
}),
PasswordStrengthMixin({
balloonEl: '.helper-balloon',
balloonEl: '#password + .helper-balloon',
passwordEl: '#password'
}),
ServiceMixin,
Expand Down
7 changes: 6 additions & 1 deletion app/styles/modules/_password-row.scss
Original file line number Diff line number Diff line change
Expand Up @@ -175,12 +175,13 @@
}


.password-repeat-balloon,
.password-strength-balloon {
font-size: 14px;
font-weight: 400;
line-height: 1.3;
opacity: 1;
padding: 28px 14px;
padding: 21px 14px;
z-index: 5;

// The characters in Arabic look way too small at 14px and are difficult to read. Bump them up by 1
Expand Down Expand Up @@ -256,6 +257,10 @@
background-image: url('/images/icon-lock-grey-50.svg');
text-indent: -9999px;
}

&.lock.last {
padding-bottom: 7px;
}
}

.big-only {
Expand Down
2 changes: 1 addition & 1 deletion app/styles/modules/_settings.scss
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ body.settings #main-content.card {
z-index: 2;

@include respond-to('big') {
margin: 0px;
margin: 0;
position: absolute;
top: 64px;
width: 100%;
Expand Down
1 change: 1 addition & 0 deletions tests/functional.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ module.exports = [
'tests/functional/pages.js',
'tests/functional/back_button_after_start.js',
'tests/functional/cookies_disabled.js',
'tests/functional/password_repeat.js',
'tests/functional/password_strength.js',
'tests/functional/password_visibility.js',
'tests/functional/avatar.js',
Expand Down
5 changes: 5 additions & 0 deletions tests/functional/lib/selectors.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ const PASSWORD_BALLOON = {
NOT_EMAIL_UNMET: '.not-email.unmet',
};

const VPASSWORD_BALLOON = {
BALLOON: '.password-repeat-balloon'
};

/*eslint-disable max-len*/
module.exports = {
'123DONE': {
Expand Down Expand Up @@ -303,6 +307,7 @@ module.exports = {
SHOW_VPASSWORD: '#vpassword ~ .show-password-label',
SUBMIT: 'button[type="submit"]',
VPASSWORD: '#vpassword',
VPASSWORD_BALLOON,
},
SMS_LEARN_MORE: {
HEADER: '#websites-notice'
Expand Down
Loading