Merge pull request #1080 from jitsi/dont_show_again

Implement dont show again util
This commit is contained in:
Дамян Минков 2016-10-31 13:36:50 -05:00 committed by GitHub
commit 1036768b2a
6 changed files with 263 additions and 135 deletions

View File

@ -1,5 +1,6 @@
/* global APP, JitsiMeetJS, config */ /* global APP, JitsiMeetJS, config */
import AuthHandler from './modules/UI/authentication/AuthHandler'; import AuthHandler from './modules/UI/authentication/AuthHandler';
import jitsiLocalStorage from './modules/util/JitsiLocalStorage';
const ConnectionEvents = JitsiMeetJS.events.connection; const ConnectionEvents = JitsiMeetJS.events.connection;
const ConnectionErrors = JitsiMeetJS.errors.connection; const ConnectionErrors = JitsiMeetJS.errors.connection;
@ -107,9 +108,9 @@ function connect(id, password, roomName) {
export function openConnection({id, password, retry, roomName}) { export function openConnection({id, password, retry, roomName}) {
let usernameOverride let usernameOverride
= window.localStorage.getItem("xmpp_username_override"); = jitsiLocalStorage.getItem("xmpp_username_override");
let passwordOverride let passwordOverride
= window.localStorage.getItem("xmpp_password_override"); = jitsiLocalStorage.getItem("xmpp_password_override");
if (usernameOverride && usernameOverride.length > 0) { if (usernameOverride && usernameOverride.length > 0) {
id = usernameOverride; id = usernameOverride;

View File

@ -1214,7 +1214,11 @@ UI.showExtensionExternalInstallationDialog = function (url) {
* @param {JitsiTrackError} cameraError * @param {JitsiTrackError} cameraError
*/ */
UI.showDeviceErrorDialog = function (micError, cameraError) { UI.showDeviceErrorDialog = function (micError, cameraError) {
let localStoragePropName = "doNotShowErrorAgain"; let dontShowAgain = {
id: "doNotShowWarningAgain",
localStorageKey: "doNotShowErrorAgain",
textKey: "dialog.doNotShowWarningAgain"
};
let isMicJitsiTrackErrorAndHasName = micError && micError.name && let isMicJitsiTrackErrorAndHasName = micError && micError.name &&
micError instanceof JitsiMeetJS.errorTypes.JitsiTrackError; micError instanceof JitsiMeetJS.errorTypes.JitsiTrackError;
let isCameraJitsiTrackErrorAndHasName = cameraError && cameraError.name && let isCameraJitsiTrackErrorAndHasName = cameraError && cameraError.name &&
@ -1231,17 +1235,11 @@ UI.showDeviceErrorDialog = function (micError, cameraError) {
} }
if (micError) { if (micError) {
localStoragePropName += "-mic-" + micError.name; dontShowAgain.localStorageKey += "-mic-" + micError.name;
} }
if (cameraError) { if (cameraError) {
localStoragePropName += "-camera-" + cameraError.name; dontShowAgain.localStorageKey += "-camera-" + cameraError.name;
}
if (showDoNotShowWarning) {
if (window.localStorage[localStoragePropName] === "true") {
return;
}
} }
let cameraJitsiTrackErrorMsg = cameraError let cameraJitsiTrackErrorMsg = cameraError
@ -1266,12 +1264,6 @@ UI.showDeviceErrorDialog = function (micError, cameraError) {
micError.message micError.message
? `<div>${micError.message}</div>` ? `<div>${micError.message}</div>`
: ``; : ``;
let doNotShowWarningAgainSection = showDoNotShowWarning
? `<label>
<input type='checkbox' id='doNotShowWarningAgain'>
<span data-i18n='dialog.doNotShowWarningAgain'></span>
</label>`
: ``;
let message = ''; let message = '';
if (micError) { if (micError) {
@ -1290,8 +1282,6 @@ UI.showDeviceErrorDialog = function (micError, cameraError) {
${additionalCameraErrorMsg}`; ${additionalCameraErrorMsg}`;
} }
message = `${message}${doNotShowWarningAgainSection}`;
// To make sure we don't have multiple error dialogs open at the same time, // To make sure we don't have multiple error dialogs open at the same time,
// we will just close the previous one if we are going to show a new one. // we will just close the previous one if we are going to show a new one.
deviceErrorDialog && deviceErrorDialog.close(); deviceErrorDialog && deviceErrorDialog.close();
@ -1301,24 +1291,14 @@ UI.showDeviceErrorDialog = function (micError, cameraError) {
message, message,
false, false,
{Ok: true}, {Ok: true},
function () { function () {},
let form = $.prompt.getPrompt();
if (form) {
let input = form.find("#doNotShowWarningAgain");
if (input.length) {
window.localStorage[localStoragePropName] =
input.prop("checked");
}
}
},
null, null,
function () { function () {
// Reset dialog reference to null to avoid memory leaks when // Reset dialog reference to null to avoid memory leaks when
// user closed the dialog manually. // user closed the dialog manually.
deviceErrorDialog = null; deviceErrorDialog = null;
} },
showDoNotShowWarning ? dontShowAgain : undefined
); );
function getTitleKey() { function getTitleKey() {

View File

@ -1,6 +1,7 @@
/* global $, APP, toastr, Impromptu */ /* global $, APP, toastr, Impromptu */
import UIUtil from './UIUtil'; import UIUtil from './UIUtil';
import jitsiLocalStorage from '../../util/JitsiLocalStorage';
/** /**
* Flag for enable/disable of the notifications. * Flag for enable/disable of the notifications.
@ -20,6 +21,91 @@ let popupEnabled = true;
*/ */
let twoButtonDialog = null; let twoButtonDialog = null;
/**
* Generates html for dont show again checkbox.
* @param {object} options options
* @param {string} options.id the id of the checkbox.
* @param {string} options.textKey the key for the text displayed next to
* checkbox
* @param {boolean} options.checked if true the checkbox is foing to be checked
* by default.
* @returns {string}
*/
function generateDontShowCheckbox(options) {
if(!isDontShowAgainEnabled(options)) {
return "";
}
let checked
= (options.checked === true) ? "checked" : "";
return `<br />
<label>
<input type='checkbox' ${checked} id='${options.id}' />
<span data-i18n='${options.textKey}'></span>
</label>`;
}
/**
* Checks whether the dont show again checkbox was checked before.
* @param {object} options - options for dont show again checkbox.
* @param {string} options.id the id of the checkbox.
* @param {string} options.localStorageKey the key for the local storage. if
* not provided options.id will be used.
* @returns {boolean} true if the dialog mustn't be displayed and
* false otherwise.
*/
function dontShowTheDialog(options) {
if(isDontShowAgainEnabled(options)) {
if(jitsiLocalStorage.getItem(options.localStorageKey || options.id)
=== "true") {
return true;
}
}
return false;
}
/**
* Wraps the submit function to process the dont show again status and store
* it.
* @param {object} options - options for dont show again checkbox.
* @param {string} options.id the id of the checkbox.
* @param {Array} options.buttonValues The button values that will trigger
* storing he checkbox value
* @param {string} options.localStorageKey the key for the local storage. if
* not provided options.id will be used.
* @param {Function} submitFunction the submit function to be wrapped
* @returns {Function} wrapped function
*/
function dontShowAgainSubmitFunctionWrapper(options, submitFunction) {
if(isDontShowAgainEnabled(options)) {
return (...args) => {
console.debug(args, options.buttonValues);
//args[1] is the value associated with the pressed button
if(!options.buttonValues || options.buttonValues.length === 0
|| options.buttonValues.indexOf(args[1]) !== -1 ) {
let checkbox = $(`#${options.id}`);
if (checkbox.length) {
jitsiLocalStorage.setItem(
options.localStorageKey || options.id,
checkbox.prop("checked"));
}
}
submitFunction(...args);
};
} else {
return submitFunction;
}
}
/**
* Check whether dont show again checkbox is enabled or not.
* @param {object} options - options for dont show again checkbox.
* @returns {boolean} true if enabled and false if not.
*/
function isDontShowAgainEnabled(options) {
return typeof options === "object";
}
var messageHandler = { var messageHandler = {
OK: "dialog.OK", OK: "dialog.OK",
CANCEL: "dialog.Cancel", CANCEL: "dialog.Cancel",
@ -72,6 +158,16 @@ var messageHandler = {
* the dialog is opened * the dialog is opened
* @param defaultButton index of default button which will be activated when * @param defaultButton index of default button which will be activated when
* the user press 'enter'. Indexed from 0. * the user press 'enter'. Indexed from 0.
* @param {object} dontShowAgain - options for dont show again checkbox.
* @param {string} dontShowAgain.id the id of the checkbox.
* @param {string} dontShowAgain.textKey the key for the text displayed
* next to checkbox
* @param {boolean} dontShowAgain.checked if true the checkbox is foing to
* be checked
* @param {Array} dontShowAgain.buttonValues The button values that will
* trigger storing the checkbox value
* @param {string} dontShowAgain.localStorageKey the key for the local
* storage. if not provided dontShowAgain.id will be used.
* @return the prompt that was created, or null * @return the prompt that was created, or null
*/ */
openTwoButtonDialog: function(options) { openTwoButtonDialog: function(options) {
@ -87,12 +183,20 @@ var messageHandler = {
size, size,
defaultButton, defaultButton,
wrapperClass, wrapperClass,
classes classes,
dontShowAgain
} = options; } = options;
if (!popupEnabled || twoButtonDialog) if (!popupEnabled || twoButtonDialog)
return null; return null;
if(dontShowTheDialog(dontShowAgain)) {
// Maybe we should pass some parameters here? I'm not sure
// and currently we don't need any parameters.
submitFunction();
return null;
}
var buttons = []; var buttons = [];
var leftButton = leftButtonKey ? var leftButton = leftButtonKey ?
@ -108,6 +212,7 @@ var messageHandler = {
if (msgKey) { if (msgKey) {
message = APP.translation.generateTranslationHTML(msgKey); message = APP.translation.generateTranslationHTML(msgKey);
} }
message += generateDontShowCheckbox(dontShowAgain);
classes = classes || this._getDialogClasses(size); classes = classes || this._getDialogClasses(size);
if (wrapperClass) { if (wrapperClass) {
classes.prompt += ` ${wrapperClass}`; classes.prompt += ` ${wrapperClass}`;
@ -122,13 +227,13 @@ var messageHandler = {
loaded: loadedFunction, loaded: loadedFunction,
promptspeed: 0, promptspeed: 0,
classes, classes,
submit: function (e, v, m, f) { submit: dontShowAgainSubmitFunctionWrapper(dontShowAgain,
twoButtonDialog = null; function (e, v, m, f) {
if (v){ twoButtonDialog = null;
if (submitFunction) if (v && submitFunction) {
submitFunction(e, v, m, f); submitFunction(e, v, m, f);
} }
}, }),
close: function (e, v, m, f) { close: function (e, v, m, f) {
twoButtonDialog = null; twoButtonDialog = null;
if (closeFunction) { if (closeFunction) {
@ -155,12 +260,29 @@ var messageHandler = {
* @param loadedFunction function to be called after the prompt is fully * @param loadedFunction function to be called after the prompt is fully
* loaded * loaded
* @param closeFunction function to be called on dialog close * @param closeFunction function to be called on dialog close
* @param {object} dontShowAgain - options for dont show again checkbox.
* @param {string} dontShowAgain.id the id of the checkbox.
* @param {string} dontShowAgain.textKey the key for the text displayed
* next to checkbox
* @param {boolean} dontShowAgain.checked if true the checkbox is foing to
* be checked
* @param {Array} dontShowAgain.buttonValues The button values that will
* trigger storing the checkbox value
* @param {string} dontShowAgain.localStorageKey the key for the local
* storage. if not provided dontShowAgain.id will be used.
*/ */
openDialog: function (titleKey, msgString, persistent, buttons, openDialog: function (titleKey, msgString, persistent, buttons,
submitFunction, loadedFunction, closeFunction) { submitFunction, loadedFunction, closeFunction, dontShowAgain) {
if (!popupEnabled) if (!popupEnabled)
return; return;
if(dontShowTheDialog(dontShowAgain)) {
// Maybe we should pass some parameters here? I'm not sure
// and currently we don't need any parameters.
submitFunction();
return;
}
let args = { let args = {
title: this._getFormattedTitleString(titleKey), title: this._getFormattedTitleString(titleKey),
persistent: persistent, persistent: persistent,
@ -168,7 +290,8 @@ var messageHandler = {
defaultButton: 1, defaultButton: 1,
promptspeed: 0, promptspeed: 0,
loaded: loadedFunction, loaded: loadedFunction,
submit: submitFunction, submit: dontShowAgainSubmitFunctionWrapper(
dontShowAgain, submitFunction),
close: closeFunction, close: closeFunction,
classes: this._getDialogClasses() classes: this._getDialogClasses()
}; };
@ -177,7 +300,8 @@ var messageHandler = {
args.closeText = ''; args.closeText = '';
} }
let dialog = new Impromptu(msgString, args); let dialog = new Impromptu(
msgString + generateDontShowCheckbox(dontShowAgain), args);
APP.translation.translateElement(dialog.getPrompt()); APP.translation.translateElement(dialog.getPrompt());
return dialog; return dialog;
}, },

View File

@ -652,39 +652,18 @@ RemoteVideo.createContainer = function (spanId) {
* participant. * participant.
*/ */
RemoteVideo.showMuteParticipantDialog = function () { RemoteVideo.showMuteParticipantDialog = function () {
//FIXME: don't show again checkbox is implemented very dirty. we should add
// this functionality to MessageHandler class.
if (window.localStorage
&& window.localStorage.getItem(
"dontShowMuteParticipantDialog") === "true") {
return Promise.resolve(MUTED_DIALOG_BUTTON_VALUES.muted);
}
let msgString =
`<div data-i18n="dialog.muteParticipantBody"></div>
<br />
<label>
<input type='checkbox' checked id='doNotShowMessageAgain' />
<span data-i18n='dialog.doNotShowMessageAgain'></span>
</label>`;
return new Promise(resolve => { return new Promise(resolve => {
APP.UI.messageHandler.openTwoButtonDialog({ APP.UI.messageHandler.openTwoButtonDialog({
titleKey : "dialog.muteParticipantTitle", titleKey : "dialog.muteParticipantTitle",
msgString, msgString: "<div data-i18n='dialog.muteParticipantBody'></div>",
leftButtonKey: 'dialog.muteParticipantButton', leftButtonKey: "dialog.muteParticipantButton",
submitFunction: () => { dontShowAgain: {
if(window.localStorage) { id: "dontShowMuteParticipantDialog",
let form = $.prompt.getPrompt(); textKey: "dialog.doNotShowMessageAgain",
if (form) { checked: true,
let input = form.find("#doNotShowMessageAgain"); buttonValues: [true]
if (input.length) {
window.localStorage.setItem(
"dontShowMuteParticipantDialog",
input.prop("checked"));
}
}
}
resolve(MUTED_DIALOG_BUTTON_VALUES.muted);
}, },
submitFunction: () => resolve(MUTED_DIALOG_BUTTON_VALUES.muted),
closeFunction: () => resolve(MUTED_DIALOG_BUTTON_VALUES.cancel) closeFunction: () => resolve(MUTED_DIALOG_BUTTON_VALUES.cancel)
}); });
}); });

View File

@ -1,26 +1,6 @@
/* global JitsiMeetJS */ /* global JitsiMeetJS */
import UIUtil from '../UI/util/UIUtil'; import UIUtil from '../UI/util/UIUtil';
import jitsiLocalStorage from '../util/JitsiLocalStorage';
let email = '';
let avatarId = '';
let displayName = '';
let language = null;
let cameraDeviceId = '';
let micDeviceId = '';
let welcomePageDisabled = false;
let localFlipX = null;
let avatarUrl = '';
function supportsLocalStorage() {
try {
return 'localStorage' in window && window.localStorage !== null;
} catch (e) {
console.log("localstorage is not supported");
return false;
}
}
function generateUniqueId() { function generateUniqueId() {
function _p8() { function _p8() {
@ -29,45 +9,43 @@ function generateUniqueId() {
return _p8() + _p8() + _p8() + _p8(); return _p8() + _p8() + _p8() + _p8();
} }
if (supportsLocalStorage()) { if (!jitsiLocalStorage.getItem("jitsiMeetId")) {
if (!window.localStorage.jitsiMeetId) { jitsiLocalStorage.setItem("jitsiMeetId",generateUniqueId());
window.localStorage.jitsiMeetId = generateUniqueId(); console.log("generated id", jitsiLocalStorage.getItem("jitsiMeetId"));
console.log("generated id", window.localStorage.jitsiMeetId); }
}
email = UIUtil.unescapeHtml(window.localStorage.email || ''); let avatarUrl = '';
avatarId = UIUtil.unescapeHtml(window.localStorage.avatarId || '');
if (!avatarId) {
// if there is no avatar id, we generate a unique one and use it forever
avatarId = generateUniqueId();
window.localStorage.avatarId = avatarId;
}
localFlipX = JSON.parse(window.localStorage.localFlipX || true); let email = UIUtil.unescapeHtml(jitsiLocalStorage.getItem("email") || '');
displayName = UIUtil.unescapeHtml(window.localStorage.displayname || ''); let avatarId = UIUtil.unescapeHtml(jitsiLocalStorage.getItem("avatarId") || '');
language = window.localStorage.language; if (!avatarId) {
cameraDeviceId = window.localStorage.cameraDeviceId || ''; // if there is no avatar id, we generate a unique one and use it forever
micDeviceId = window.localStorage.micDeviceId || ''; avatarId = generateUniqueId();
welcomePageDisabled = JSON.parse( jitsiLocalStorage.setItem("avatarId", avatarId);
window.localStorage.welcomePageDisabled || false }
);
// Currently audio output device change is supported only in Chrome and let localFlipX = JSON.parse(jitsiLocalStorage.getItem("localFlipX") || true);
// default output always has 'default' device ID let displayName = UIUtil.unescapeHtml(
var audioOutputDeviceId = window.localStorage.audioOutputDeviceId jitsiLocalStorage.getItem("displayname") || '');
|| 'default'; let language = jitsiLocalStorage.getItem("language");
let cameraDeviceId = jitsiLocalStorage.getItem("cameraDeviceId") || '';
let micDeviceId = jitsiLocalStorage.getItem("micDeviceId") || '';
let welcomePageDisabled = JSON.parse(
jitsiLocalStorage.getItem("welcomePageDisabled") || false);
if (audioOutputDeviceId !== // Currently audio output device change is supported only in Chrome and
JitsiMeetJS.mediaDevices.getAudioOutputDevice()) { // default output always has 'default' device ID
JitsiMeetJS.mediaDevices.setAudioOutputDevice(audioOutputDeviceId) let audioOutputDeviceId = jitsiLocalStorage.getItem("audioOutputDeviceId")
.catch((ex) => { || 'default';
console.warn('Failed to set audio output device from local ' +
'storage. Default audio output device will be used' + if (audioOutputDeviceId !==
'instead.', ex); JitsiMeetJS.mediaDevices.getAudioOutputDevice()) {
}); JitsiMeetJS.mediaDevices.setAudioOutputDevice(audioOutputDeviceId)
} .catch((ex) => {
} else { console.warn('Failed to set audio output device from local ' +
console.log("local storage is not supported"); 'storage. Default audio output device will be used' +
'instead.', ex);
});
} }
export default { export default {
@ -82,7 +60,8 @@ export default {
displayName = newDisplayName; displayName = newDisplayName;
if (!disableLocalStore) if (!disableLocalStore)
window.localStorage.displayname = UIUtil.escapeHtml(displayName); jitsiLocalStorage.setItem("displayname",
UIUtil.escapeHtml(displayName));
}, },
/** /**
@ -102,7 +81,7 @@ export default {
email = newEmail; email = newEmail;
if (!disableLocalStore) if (!disableLocalStore)
window.localStorage.email = UIUtil.escapeHtml(newEmail); jitsiLocalStorage.setItem("email", UIUtil.escapeHtml(newEmail));
}, },
/** /**
@ -142,7 +121,7 @@ export default {
}, },
setLanguage: function (lang) { setLanguage: function (lang) {
language = lang; language = lang;
window.localStorage.language = lang; jitsiLocalStorage.setItem("language", lang);
}, },
/** /**
@ -151,7 +130,7 @@ export default {
*/ */
setLocalFlipX: function (val) { setLocalFlipX: function (val) {
localFlipX = val; localFlipX = val;
window.localStorage.localFlipX = val; jitsiLocalStorage.setItem("localFlipX", val);
}, },
/** /**
@ -179,7 +158,7 @@ export default {
setCameraDeviceId: function (newId, store) { setCameraDeviceId: function (newId, store) {
cameraDeviceId = newId; cameraDeviceId = newId;
if (store) if (store)
window.localStorage.cameraDeviceId = newId; jitsiLocalStorage.setItem("cameraDeviceId", newId);
}, },
/** /**
@ -199,7 +178,7 @@ export default {
setMicDeviceId: function (newId, store) { setMicDeviceId: function (newId, store) {
micDeviceId = newId; micDeviceId = newId;
if (store) if (store)
window.localStorage.micDeviceId = newId; jitsiLocalStorage.setItem("micDeviceId", newId);
}, },
/** /**
@ -218,7 +197,8 @@ export default {
*/ */
setAudioOutputDeviceId: function (newId = 'default') { setAudioOutputDeviceId: function (newId = 'default') {
return JitsiMeetJS.mediaDevices.setAudioOutputDevice(newId) return JitsiMeetJS.mediaDevices.setAudioOutputDevice(newId)
.then(() => window.localStorage.audioOutputDeviceId = newId); .then(() =>
jitsiLocalStorage.setItem("audioOutputDeviceId", newId));
}, },
/** /**
@ -235,6 +215,6 @@ export default {
*/ */
setWelcomePageEnabled (enabled) { setWelcomePageEnabled (enabled) {
welcomePageDisabled = !enabled; welcomePageDisabled = !enabled;
window.localStorage.welcomePageDisabled = welcomePageDisabled; jitsiLocalStorage.setItem("welcomePageDisabled", welcomePageDisabled);
} }
}; };

View File

@ -0,0 +1,64 @@
/**
* Dummy implementation of Storage interface with empty methods.
*/
class DummyLocalStorage {
/**
* Empty function
*/
getItem() { }
/**
* Empty function
*/
setItem() { }
/**
* Empty function
*/
removeItem() { }
}
/**
* Wrapper class for browser's local storage object.
*/
class JitsiLocalStorage extends DummyLocalStorage {
/**
* @constructor
* @param {Storage} storage browser's local storage object.
*/
constructor(storage) {
super();
this.storage = storage || new DummyLocalStorage();
}
/**
* Returns that passed key's value.
* @param {string} keyName the name of the key you want to retrieve
* the value of.
* @returns {String|null} the value of the key. If the key does not exist,
* null is returned.
*/
getItem(keyName) {
return this.storage.getItem(keyName);
}
/**
* Adds a key to the storage, or update key's value if it already exists.
* @param {string} keyName the name of the key you want to create/update.
* @param {string} keyValue the value you want to give the key you are
* creating/updating.
*/
setItem(keyName, keyValue) {
return this.storage.setItem(keyName, keyValue);
}
/**
* Remove a key from the storage.
* @param {string} keyName the name of the key you want to remove.
*/
removeItem(keyName) {
return this.storage.removeItem(keyName);
}
}
export default new JitsiLocalStorage(window.localStorage);