From 257bb49c52c57e5ed6827be00ad2d12a07bb61ef Mon Sep 17 00:00:00 2001 From: Ilya Daynatovich Date: Fri, 21 Oct 2016 17:57:13 +0300 Subject: [PATCH 1/9] Add Require password dialog --- css/_variables.scss | 3 +- css/input-control/_input-control.scss | 11 +++ lang/main.json | 1 + modules/UI/invite/Invite.js | 5 + modules/UI/invite/RequirePasswordDialog.js | 110 +++++++++++++++++++++ modules/UI/invite/RoomLocker.js | 10 +- 6 files changed, 136 insertions(+), 4 deletions(-) create mode 100644 modules/UI/invite/RequirePasswordDialog.js diff --git a/css/_variables.scss b/css/_variables.scss index 117fb2a14..5ffbcfbc7 100644 --- a/css/_variables.scss +++ b/css/_variables.scss @@ -126,4 +126,5 @@ $selectActiveItemBg: $defaultDarkColor; $inputControlEmColor: #f29424; //buttons $linkFontColor: #489afe; -$linkHoverFontColor: #287ade; \ No newline at end of file +$linkHoverFontColor: #287ade; +$errorColor: #c61600; diff --git a/css/input-control/_input-control.scss b/css/input-control/_input-control.scss index 4e1b5c570..05ea6c28f 100644 --- a/css/input-control/_input-control.scss +++ b/css/input-control/_input-control.scss @@ -20,6 +20,8 @@ } &__input { + margin-bottom: 8px; + @include transition(all .2s ease-in); &:last-child { margin-bottom: inherit; @@ -28,6 +30,11 @@ &::selection { background-color: $defaultDarkSelectionColor; } + + &.error { + color: $errorColor; + border-color: $errorColor; + } } &__em { @@ -41,6 +48,10 @@ span { vertical-align: middle; } + + &_error { + color: $errorColor; + } } &__container { diff --git a/lang/main.json b/lang/main.json index acdba53d7..ed791890c 100644 --- a/lang/main.json +++ b/lang/main.json @@ -199,6 +199,7 @@ "passwordError2": "This conversation isn't currently protected by a password. Only the owner of the conference can set a password.", "connectError": "Oops! Something went wrong and we couldn't connect to the conference.", "connectErrorWithMsg": "Oops! Something went wrong and we couldn't connect to the conference: __msg__", + "incorrectPassword": "Password is incorrect", "connecting": "Connecting", "copy": "Copy", "error": "Error", diff --git a/modules/UI/invite/Invite.js b/modules/UI/invite/Invite.js index 289df0251..737ed673b 100644 --- a/modules/UI/invite/Invite.js +++ b/modules/UI/invite/Invite.js @@ -46,6 +46,11 @@ class Invite { } }); + this.conference.on(ConferenceEvents.CONFERENCE_JOINED, () => { + let roomLocker = this.getRoomLocker(); + roomLocker.hideRequirePasswordDialog(); + }); + APP.UI.addListener( UIEvents.INVITE_CLICKED, () => { this.openLinkDialog(); }); diff --git a/modules/UI/invite/RequirePasswordDialog.js b/modules/UI/invite/RequirePasswordDialog.js new file mode 100644 index 000000000..a5e80cd48 --- /dev/null +++ b/modules/UI/invite/RequirePasswordDialog.js @@ -0,0 +1,110 @@ +/* global APP */ + +import UIUtil from '../util/UIUtil'; + +/** + * Show dialog which asks for required conference password. + * @returns {Promise} password or nothing if user canceled + */ +export default class RequirePasswordDialog { + constructor() { + this.titleKey = 'dialog.passwordRequired'; + this.labelKey = 'dialog.passwordLabel'; + this.errorKey = 'dialog.incorrectPassword'; + this.errorId = 'passwordRequiredError'; + this.inputId = 'passwordRequiredInput'; + this.inputErrorClass = 'error'; + this.isOpened = false; + } + + _registerListeners() { + let el = document.getElementById(this.inputId); + el.addEventListener('keypress', this._hideError.bind(this)); + } + + _getBodyMessage() { + let passMsg = APP.translation.translateString("dialog.password"); + let label = APP.translation.translateString(this.labelKey); + let error = APP.translation.translateString(this.errorKey); + return ( + `
+ + +

${error}

+
` + ); + } + + askForPassword() { + if (!this.isOpened) { + return this.open(); + } + + return new Promise((resolve, reject) => { + this.resolve = resolve; + this.reject = reject; + this._showError(); + }); + } + + open() { + let { titleKey } = this; + let msgString = this._getBodyMessage(); + + return new Promise((resolve, reject) => { + this.resolve = resolve; + this.reject = reject; + let submitFunction = this._submitFunction.bind(this); + let closeFunction = this._closeFunction.bind(this); + + APP.UI.messageHandler.openTwoButtonDialog({ + titleKey, + msgString, + leftButtonKey: "dialog.Ok", + submitFunction, + closeFunction, + focus: ':input:first' + }); + + this._registerListeners(); + this.isOpened = true; + }); + } + + _submitFunction(e, v, m, f) { + e.preventDefault(); + + if (v && f.lockKey) { + this.resolve(UIUtil.escapeHtml(f.lockKey)); + } else { + this.reject(APP.UI.messageHandler.CANCEL); + } + } + + _closeFunction() { + this._hideError(); + this.close(); + } + + _showError() { + let className = this.inputErrorClass; + document.getElementById(this.errorId).classList.remove('hide'); + document.getElementById(this.inputId).classList.add(className); + } + + _hideError() { + let className = this.inputErrorClass; + document.getElementById(this.errorId).classList.add('hide'); + document.getElementById(this.inputId).classList.remove(className); + } + + close() { + APP.UI.messageHandler.closeDialog(); + this.isOpened = false; + } +} \ No newline at end of file diff --git a/modules/UI/invite/RoomLocker.js b/modules/UI/invite/RoomLocker.js index 83057e871..91ad721a2 100644 --- a/modules/UI/invite/RoomLocker.js +++ b/modules/UI/invite/RoomLocker.js @@ -1,5 +1,5 @@ /* global APP, JitsiMeetJS */ -import askForPassword from './AskForPassword'; +import RequirePasswordDialog from './RequirePasswordDialog'; /** * Show notification that user cannot set password for the conference @@ -31,7 +31,7 @@ const ConferenceErrors = JitsiMeetJS.errors.conference; */ export default function createRoomLocker (room) { let password; - + let requirePasswordDialog = new RequirePasswordDialog(); /** * If the room was locked from someone other than us, we indicate it with * this property in order to have correct roomLocker state of isLocked. @@ -104,7 +104,7 @@ export default function createRoomLocker (room) { * Asks user for required conference password. */ requirePassword () { - return askForPassword().then( + return requirePasswordDialog.askForPassword().then( newPass => { password = newPass; } ).catch( reason => { @@ -116,6 +116,10 @@ export default function createRoomLocker (room) { console.error(reason); } ); + }, + + hideRequirePasswordDialog() { + requirePasswordDialog.close(); } }; } From d4df6f2ddadc03d63fdcc6d6cb4093b08d4f4f7f Mon Sep 17 00:00:00 2001 From: Ilya Daynatovich Date: Fri, 21 Oct 2016 18:03:25 +0300 Subject: [PATCH 2/9] Got rid of direct usage of room locker --- modules/UI/invite/AskForPassword.js | 31 ---------------------- modules/UI/invite/Invite.js | 24 +++++++++-------- modules/UI/invite/RequirePasswordDialog.js | 9 +++---- 3 files changed, 16 insertions(+), 48 deletions(-) delete mode 100644 modules/UI/invite/AskForPassword.js diff --git a/modules/UI/invite/AskForPassword.js b/modules/UI/invite/AskForPassword.js deleted file mode 100644 index 77a27ddf4..000000000 --- a/modules/UI/invite/AskForPassword.js +++ /dev/null @@ -1,31 +0,0 @@ -/* global APP, $ */ - -import UIUtil from '../util/UIUtil'; - -/** - * Show dialog which asks for required conference password. - * @returns {Promise} password or nothing if user canceled - */ -export default function askForPassword () { - let titleKey = "dialog.passwordRequired"; - let msgString = ` - `; - return new Promise(function (resolve, reject) { - APP.UI.messageHandler.openTwoButtonDialog({ - titleKey, - msgString, - leftButtonKey: "dialog.Ok", - submitFunction: $.noop, - closeFunction: function (e, v, m, f) { - if (v && f.lockKey) { - resolve(UIUtil.escapeHtml(f.lockKey)); - } else { - reject(APP.UI.messageHandler.CANCEL); - } - }, - focus: ':input:first' - }); - }); -} \ No newline at end of file diff --git a/modules/UI/invite/Invite.js b/modules/UI/invite/Invite.js index 737ed673b..7cc821e01 100644 --- a/modules/UI/invite/Invite.js +++ b/modules/UI/invite/Invite.js @@ -32,7 +32,7 @@ class Invite { error); if (!locked) { - this.roomLocker.resetPassword(); + this.getRoomLocker().resetPassword(); } this.setLockedFromElsewhere(locked); @@ -56,9 +56,10 @@ class Invite { APP.UI.addListener( UIEvents.PASSWORD_REQUIRED, () => { + let roomLocker = this.getRoomLocker(); this.setLockedFromElsewhere(true); - this.roomLocker.requirePassword().then(() => { - let pass = this.roomLocker.password; + roomLocker.requirePassword().then(() => { + let pass = roomLocker.password; // we received that password is required, but user is trying // anyway to login without a password, mark room as not // locked in case he succeeds (maybe someone removed the @@ -67,7 +68,7 @@ class Invite { // will be marked as locked. if (!pass) this.setLockedFromElsewhere(false); - this.conference.join(this.roomLocker.password); + this.conference.join(roomLocker.password); }); }); } @@ -129,7 +130,7 @@ class Invite { * @returns {String} password */ getPassword() { - return this.roomLocker.password; + return this.getRoomLocker().password; } /** @@ -149,7 +150,7 @@ class Invite { */ setRoomUnlocked() { if (this.isModerator) { - this.roomLocker.lock().then(() => { + this.getRoomLocker().lock().then(() => { APP.UI.emitEvent(UIEvents.TOGGLE_ROOM_LOCK); this.updateView(); }); @@ -164,8 +165,8 @@ class Invite { */ setRoomLocked(newPass) { let isModerator = this.isModerator; - if (isModerator && (newPass || !this.roomLocker.isLocked)) { - this.roomLocker.lock(newPass).then(() => { + if (isModerator && (newPass || !this.getRoomLocker().isLocked)) { + this.getRoomLocker().lock(newPass).then(() => { APP.UI.emitEvent(UIEvents.TOGGLE_ROOM_LOCK); this.updateView(); }); @@ -187,7 +188,7 @@ class Invite { * @returns {Boolean} isLocked */ isLocked() { - return this.roomLocker.isLocked; + return this.getRoomLocker().isLocked; } /** @@ -195,9 +196,10 @@ class Invite { * @param isLocked */ setLockedFromElsewhere(isLocked) { - let oldLockState = this.roomLocker.isLocked; + let roomLocker = this.getRoomLocker(); + let oldLockState = roomLocker.isLocked; if (oldLockState !== isLocked) { - this.roomLocker.lockedElsewhere = isLocked; + roomLocker.lockedElsewhere = isLocked; APP.UI.emitEvent(UIEvents.TOGGLE_ROOM_LOCK); this.updateView(); } diff --git a/modules/UI/invite/RequirePasswordDialog.js b/modules/UI/invite/RequirePasswordDialog.js index a5e80cd48..d8a71cd34 100644 --- a/modules/UI/invite/RequirePasswordDialog.js +++ b/modules/UI/invite/RequirePasswordDialog.js @@ -23,19 +23,16 @@ export default class RequirePasswordDialog { } _getBodyMessage() { - let passMsg = APP.translation.translateString("dialog.password"); - let label = APP.translation.translateString(this.labelKey); - let error = APP.translation.translateString(this.errorKey); return ( `
+ data-i18n="${this.labelKey}"> + autofocus id="${this.inputId}">

${error}

+ data-i18n="${this.errorKey}">

` ); } From 5e8c5b3ce431468bfa18f8e8e7f940a205f3b4a7 Mon Sep 17 00:00:00 2001 From: Ilya Daynatovich Date: Fri, 21 Oct 2016 18:14:12 +0300 Subject: [PATCH 3/9] Add JSDoc --- modules/UI/invite/RequirePasswordDialog.js | 40 ++++++++++++++++++++++ modules/UI/invite/RoomLocker.js | 7 +++- 2 files changed, 46 insertions(+), 1 deletion(-) diff --git a/modules/UI/invite/RequirePasswordDialog.js b/modules/UI/invite/RequirePasswordDialog.js index d8a71cd34..6f25ca7b3 100644 --- a/modules/UI/invite/RequirePasswordDialog.js +++ b/modules/UI/invite/RequirePasswordDialog.js @@ -17,11 +17,20 @@ export default class RequirePasswordDialog { this.isOpened = false; } + /** + * Registering dialog listeners + * @private + */ _registerListeners() { let el = document.getElementById(this.inputId); el.addEventListener('keypress', this._hideError.bind(this)); } + /** + * Helper method returning dialog body + * @returns {string} + * @private + */ _getBodyMessage() { return ( `
@@ -37,6 +46,10 @@ export default class RequirePasswordDialog { ); } + /** + * Asking for a password + * @returns {Promise} + */ askForPassword() { if (!this.isOpened) { return this.open(); @@ -49,6 +62,10 @@ export default class RequirePasswordDialog { }); } + /** + * Opens the dialog + * @returns {Promise} + */ open() { let { titleKey } = this; let msgString = this._getBodyMessage(); @@ -73,6 +90,14 @@ export default class RequirePasswordDialog { }); } + /** + * Submit dialog callback + * @param e - event + * @param v - value + * @param m - message + * @param f - form + * @private + */ _submitFunction(e, v, m, f) { e.preventDefault(); @@ -83,23 +108,38 @@ export default class RequirePasswordDialog { } } + /** + * Close dialog callback + * @private + */ _closeFunction() { this._hideError(); this.close(); } + /** + * Method showing error hint + * @private + */ _showError() { let className = this.inputErrorClass; document.getElementById(this.errorId).classList.remove('hide'); document.getElementById(this.inputId).classList.add(className); } + /** + * Method hiding error hint + * @private + */ _hideError() { let className = this.inputErrorClass; document.getElementById(this.errorId).classList.add('hide'); document.getElementById(this.inputId).classList.remove(className); } + /** + * Close the dialog + */ close() { APP.UI.messageHandler.closeDialog(); this.isOpened = false; diff --git a/modules/UI/invite/RoomLocker.js b/modules/UI/invite/RoomLocker.js index 91ad721a2..22dc39a27 100644 --- a/modules/UI/invite/RoomLocker.js +++ b/modules/UI/invite/RoomLocker.js @@ -118,8 +118,13 @@ export default function createRoomLocker (room) { ); }, + /** + * Hides require password dialog + */ hideRequirePasswordDialog() { - requirePasswordDialog.close(); + if (requirePasswordDialog.isOpened) { + requirePasswordDialog.close(); + } } }; } From cba5528478c0fa58560174bd822b04a7ed17f97f Mon Sep 17 00:00:00 2001 From: Ilya Daynatovich Date: Fri, 21 Oct 2016 18:18:17 +0300 Subject: [PATCH 4/9] Move error color to theme --- css/_variables.scss | 2 +- css/themes/_light.scss | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/css/_variables.scss b/css/_variables.scss index 5ffbcfbc7..a09e0ec1f 100644 --- a/css/_variables.scss +++ b/css/_variables.scss @@ -127,4 +127,4 @@ $inputControlEmColor: #f29424; //buttons $linkFontColor: #489afe; $linkHoverFontColor: #287ade; -$errorColor: #c61600; + diff --git a/css/themes/_light.scss b/css/themes/_light.scss index ae8224eff..6062e8bb5 100644 --- a/css/themes/_light.scss +++ b/css/themes/_light.scss @@ -55,6 +55,7 @@ $hintFontSize: em(13, 14); $linkFontColor: #3572b0; $linkHoverFontColor: darken(#3572b0, 10%); $dropdownColor: #333; +$errorColor: #c61600; // Popover colors $popoverBg: #000; From 22b7142159c61405012728d59d8c430f3fee2ad6 Mon Sep 17 00:00:00 2001 From: Ilya Daynatovich Date: Mon, 24 Oct 2016 12:12:44 +0300 Subject: [PATCH 5/9] Add select input after incorrect input --- modules/UI/invite/RequirePasswordDialog.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/modules/UI/invite/RequirePasswordDialog.js b/modules/UI/invite/RequirePasswordDialog.js index 6f25ca7b3..bc3fba7d0 100644 --- a/modules/UI/invite/RequirePasswordDialog.js +++ b/modules/UI/invite/RequirePasswordDialog.js @@ -123,8 +123,10 @@ export default class RequirePasswordDialog { */ _showError() { let className = this.inputErrorClass; + let input = document.getElementById(this.inputId); document.getElementById(this.errorId).classList.remove('hide'); - document.getElementById(this.inputId).classList.add(className); + input.classList.add(className); + input.select(); } /** From 7a2eca37062e6aeb848b6ed2e05f8717f14c203e Mon Sep 17 00:00:00 2001 From: Ilya Daynatovich Date: Mon, 24 Oct 2016 16:45:19 +0300 Subject: [PATCH 6/9] fix reopening require pass dialog --- modules/UI/invite/RequirePasswordDialog.js | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/modules/UI/invite/RequirePasswordDialog.js b/modules/UI/invite/RequirePasswordDialog.js index bc3fba7d0..0dcdf8240 100644 --- a/modules/UI/invite/RequirePasswordDialog.js +++ b/modules/UI/invite/RequirePasswordDialog.js @@ -100,7 +100,16 @@ export default class RequirePasswordDialog { */ _submitFunction(e, v, m, f) { e.preventDefault(); + this._processInput(v, f); + } + /** + * Processing input in dialog + * @param v - value + * @param f - form + * @private + */ + _processInput(v, f) { if (v && f.lockKey) { this.resolve(UIUtil.escapeHtml(f.lockKey)); } else { @@ -112,7 +121,8 @@ export default class RequirePasswordDialog { * Close dialog callback * @private */ - _closeFunction() { + _closeFunction(e, v, m, f) { + this._processInput(v, f); this._hideError(); this.close(); } From 62713bf87caccba3969602e97d521488df7aba5e Mon Sep 17 00:00:00 2001 From: Ilya Daynatovich Date: Sat, 5 Nov 2016 17:13:47 +0200 Subject: [PATCH 7/9] Editions in PR --- modules/UI/invite/Invite.js | 2 +- modules/UI/invite/RequirePasswordDialog.js | 6 ++++-- modules/UI/util/MessageHandler.js | 7 ------- 3 files changed, 5 insertions(+), 10 deletions(-) diff --git a/modules/UI/invite/Invite.js b/modules/UI/invite/Invite.js index 7cc821e01..7a786b9fa 100644 --- a/modules/UI/invite/Invite.js +++ b/modules/UI/invite/Invite.js @@ -68,7 +68,7 @@ class Invite { // will be marked as locked. if (!pass) this.setLockedFromElsewhere(false); - this.conference.join(roomLocker.password); + this.conference.join(pass); }); }); } diff --git a/modules/UI/invite/RequirePasswordDialog.js b/modules/UI/invite/RequirePasswordDialog.js index 0dcdf8240..be612d3e0 100644 --- a/modules/UI/invite/RequirePasswordDialog.js +++ b/modules/UI/invite/RequirePasswordDialog.js @@ -76,7 +76,7 @@ export default class RequirePasswordDialog { let submitFunction = this._submitFunction.bind(this); let closeFunction = this._closeFunction.bind(this); - APP.UI.messageHandler.openTwoButtonDialog({ + this._dialog = APP.UI.messageHandler.openTwoButtonDialog({ titleKey, msgString, leftButtonKey: "dialog.Ok", @@ -153,7 +153,9 @@ export default class RequirePasswordDialog { * Close the dialog */ close() { - APP.UI.messageHandler.closeDialog(); + if (this._dialog) { + this._dialog.close(); + } this.isOpened = false; } } \ No newline at end of file diff --git a/modules/UI/util/MessageHandler.js b/modules/UI/util/MessageHandler.js index 2f63abbf4..e52c5fa60 100644 --- a/modules/UI/util/MessageHandler.js +++ b/modules/UI/util/MessageHandler.js @@ -338,13 +338,6 @@ var messageHandler = { }; }, - /** - * Closes currently opened dialog. - */ - closeDialog: function () { - $.prompt.close(); - }, - /** * Shows a dialog with different states to the user. * From 2b089502944ae3529e9090198f2d544fc1d829a0 Mon Sep 17 00:00:00 2001 From: Ilya Daynatovich Date: Mon, 7 Nov 2016 13:28:34 +0200 Subject: [PATCH 8/9] Fix the tests --- modules/UI/util/MessageHandler.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/UI/util/MessageHandler.js b/modules/UI/util/MessageHandler.js index e52c5fa60..5aa67cc90 100644 --- a/modules/UI/util/MessageHandler.js +++ b/modules/UI/util/MessageHandler.js @@ -126,7 +126,7 @@ var messageHandler = { if (!popupEnabled) return null; - let dialog = $.prompt( + let dialog = new Impromptu( APP.translation.generateTranslationHTML(messageKey, i18nOptions), { title: this._getFormattedTitleString(titleKey), persistent: false, @@ -218,7 +218,7 @@ var messageHandler = { classes.prompt += ` ${wrapperClass}`; } - twoButtonDialog = $.prompt(message, { + twoButtonDialog = new Impromptu(message, { title: this._getFormattedTitleString(titleKey), persistent: false, buttons: buttons, From f4e6dceaa42885873004ba2b8698703e0aff9fa7 Mon Sep 17 00:00:00 2001 From: Ilya Daynatovich Date: Tue, 8 Nov 2016 17:16:00 +0200 Subject: [PATCH 9/9] Return Impormptu api when create dialog --- modules/UI/util/MessageHandler.js | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/modules/UI/util/MessageHandler.js b/modules/UI/util/MessageHandler.js index 5aa67cc90..8509c6c48 100644 --- a/modules/UI/util/MessageHandler.js +++ b/modules/UI/util/MessageHandler.js @@ -1,4 +1,4 @@ -/* global $, APP, toastr, Impromptu */ +/* global $, APP, toastr */ import UIUtil from './UIUtil'; import jitsiLocalStorage from '../../util/JitsiLocalStorage'; @@ -126,7 +126,7 @@ var messageHandler = { if (!popupEnabled) return null; - let dialog = new Impromptu( + let dialog = $.prompt( APP.translation.generateTranslationHTML(messageKey, i18nOptions), { title: this._getFormattedTitleString(titleKey), persistent: false, @@ -138,7 +138,7 @@ var messageHandler = { } }); APP.translation.translateElement(dialog, i18nOptions); - return dialog; + return $.prompt.getApi(); }, /** * Shows a message to the user with two buttons: first is given as a @@ -218,7 +218,7 @@ var messageHandler = { classes.prompt += ` ${wrapperClass}`; } - twoButtonDialog = new Impromptu(message, { + twoButtonDialog = $.prompt(message, { title: this._getFormattedTitleString(titleKey), persistent: false, buttons: buttons, @@ -242,7 +242,7 @@ var messageHandler = { } }); APP.translation.translateElement(twoButtonDialog); - return twoButtonDialog; + return $.prompt.getApi(); }, /** @@ -300,10 +300,10 @@ var messageHandler = { args.closeText = ''; } - let dialog = new Impromptu( + let dialog = $.prompt( msgString + generateDontShowCheckbox(dontShowAgain), args); - APP.translation.translateElement(dialog.getPrompt()); - return dialog; + APP.translation.translateElement(dialog); + return $.prompt.getApi(); }, /** @@ -360,9 +360,9 @@ var messageHandler = { = this._getFormattedTitleString(currentState.titleKey); } } - let dialog = new Impromptu(statesObject, options); - APP.translation.translateElement(dialog.getPrompt(), translateOptions); - return dialog; + let dialog = $.prompt(statesObject, options); + APP.translation.translateElement(dialog, translateOptions); + return $.prompt.getApi(); }, /**