diff --git a/connection.js b/connection.js
index 94f73e5e4..81ecec3de 100644
--- a/connection.js
+++ b/connection.js
@@ -1,5 +1,6 @@
/* global APP, JitsiMeetJS, config */
import AuthHandler from './modules/UI/authentication/AuthHandler';
+import jitsiLocalStorage from './modules/util/JitsiLocalStorage';
const ConnectionEvents = JitsiMeetJS.events.connection;
const ConnectionErrors = JitsiMeetJS.errors.connection;
@@ -107,9 +108,9 @@ function connect(id, password, roomName) {
export function openConnection({id, password, retry, roomName}) {
let usernameOverride
- = window.localStorage.getItem("xmpp_username_override");
+ = jitsiLocalStorage.getItem("xmpp_username_override");
let passwordOverride
- = window.localStorage.getItem("xmpp_password_override");
+ = jitsiLocalStorage.getItem("xmpp_password_override");
if (usernameOverride && usernameOverride.length > 0) {
id = usernameOverride;
diff --git a/modules/UI/UI.js b/modules/UI/UI.js
index 76a919988..99b437e8b 100644
--- a/modules/UI/UI.js
+++ b/modules/UI/UI.js
@@ -1214,7 +1214,11 @@ UI.showExtensionExternalInstallationDialog = function (url) {
* @param {JitsiTrackError} cameraError
*/
UI.showDeviceErrorDialog = function (micError, cameraError) {
- let localStoragePropName = "doNotShowErrorAgain";
+ let dontShowAgain = {
+ id: "doNotShowWarningAgain",
+ localStorageKey: "doNotShowErrorAgain",
+ textKey: "dialog.doNotShowWarningAgain"
+ };
let isMicJitsiTrackErrorAndHasName = micError && micError.name &&
micError instanceof JitsiMeetJS.errorTypes.JitsiTrackError;
let isCameraJitsiTrackErrorAndHasName = cameraError && cameraError.name &&
@@ -1231,17 +1235,11 @@ UI.showDeviceErrorDialog = function (micError, cameraError) {
}
if (micError) {
- localStoragePropName += "-mic-" + micError.name;
+ dontShowAgain.localStorageKey += "-mic-" + micError.name;
}
if (cameraError) {
- localStoragePropName += "-camera-" + cameraError.name;
- }
-
- if (showDoNotShowWarning) {
- if (window.localStorage[localStoragePropName] === "true") {
- return;
- }
+ dontShowAgain.localStorageKey += "-camera-" + cameraError.name;
}
let cameraJitsiTrackErrorMsg = cameraError
@@ -1266,12 +1264,6 @@ UI.showDeviceErrorDialog = function (micError, cameraError) {
micError.message
? `
${micError.message}
`
: ``;
- let doNotShowWarningAgainSection = showDoNotShowWarning
- ? ``
- : ``;
let message = '';
if (micError) {
@@ -1290,8 +1282,6 @@ UI.showDeviceErrorDialog = function (micError, cameraError) {
${additionalCameraErrorMsg}`;
}
- message = `${message}${doNotShowWarningAgainSection}`;
-
// 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.
deviceErrorDialog && deviceErrorDialog.close();
@@ -1301,24 +1291,14 @@ UI.showDeviceErrorDialog = function (micError, cameraError) {
message,
false,
{Ok: true},
- function () {
- let form = $.prompt.getPrompt();
-
- if (form) {
- let input = form.find("#doNotShowWarningAgain");
-
- if (input.length) {
- window.localStorage[localStoragePropName] =
- input.prop("checked");
- }
- }
- },
+ function () {},
null,
function () {
// Reset dialog reference to null to avoid memory leaks when
// user closed the dialog manually.
deviceErrorDialog = null;
- }
+ },
+ showDoNotShowWarning ? dontShowAgain : undefined
);
function getTitleKey() {
diff --git a/modules/UI/util/MessageHandler.js b/modules/UI/util/MessageHandler.js
index 54c996cea..2f63abbf4 100644
--- a/modules/UI/util/MessageHandler.js
+++ b/modules/UI/util/MessageHandler.js
@@ -1,6 +1,7 @@
/* global $, APP, toastr, Impromptu */
import UIUtil from './UIUtil';
+import jitsiLocalStorage from '../../util/JitsiLocalStorage';
/**
* Flag for enable/disable of the notifications.
@@ -20,6 +21,91 @@ let popupEnabled = true;
*/
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 `
+ `;
+}
+
+/**
+ * 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 = {
OK: "dialog.OK",
CANCEL: "dialog.Cancel",
@@ -72,6 +158,16 @@ var messageHandler = {
* the dialog is opened
* @param defaultButton index of default button which will be activated when
* 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
*/
openTwoButtonDialog: function(options) {
@@ -87,12 +183,20 @@ var messageHandler = {
size,
defaultButton,
wrapperClass,
- classes
+ classes,
+ dontShowAgain
} = options;
if (!popupEnabled || twoButtonDialog)
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 leftButton = leftButtonKey ?
@@ -108,6 +212,7 @@ var messageHandler = {
if (msgKey) {
message = APP.translation.generateTranslationHTML(msgKey);
}
+ message += generateDontShowCheckbox(dontShowAgain);
classes = classes || this._getDialogClasses(size);
if (wrapperClass) {
classes.prompt += ` ${wrapperClass}`;
@@ -122,13 +227,13 @@ var messageHandler = {
loaded: loadedFunction,
promptspeed: 0,
classes,
- submit: function (e, v, m, f) {
- twoButtonDialog = null;
- if (v){
- if (submitFunction)
+ submit: dontShowAgainSubmitFunctionWrapper(dontShowAgain,
+ function (e, v, m, f) {
+ twoButtonDialog = null;
+ if (v && submitFunction) {
submitFunction(e, v, m, f);
- }
- },
+ }
+ }),
close: function (e, v, m, f) {
twoButtonDialog = null;
if (closeFunction) {
@@ -155,12 +260,29 @@ var messageHandler = {
* @param loadedFunction function to be called after the prompt is fully
* loaded
* @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,
- submitFunction, loadedFunction, closeFunction) {
+ submitFunction, loadedFunction, closeFunction, dontShowAgain) {
if (!popupEnabled)
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 = {
title: this._getFormattedTitleString(titleKey),
persistent: persistent,
@@ -168,7 +290,8 @@ var messageHandler = {
defaultButton: 1,
promptspeed: 0,
loaded: loadedFunction,
- submit: submitFunction,
+ submit: dontShowAgainSubmitFunctionWrapper(
+ dontShowAgain, submitFunction),
close: closeFunction,
classes: this._getDialogClasses()
};
@@ -177,7 +300,8 @@ var messageHandler = {
args.closeText = '';
}
- let dialog = new Impromptu(msgString, args);
+ let dialog = new Impromptu(
+ msgString + generateDontShowCheckbox(dontShowAgain), args);
APP.translation.translateElement(dialog.getPrompt());
return dialog;
},
diff --git a/modules/UI/videolayout/RemoteVideo.js b/modules/UI/videolayout/RemoteVideo.js
index 1a918b1a3..43ea0bbc3 100644
--- a/modules/UI/videolayout/RemoteVideo.js
+++ b/modules/UI/videolayout/RemoteVideo.js
@@ -652,39 +652,18 @@ RemoteVideo.createContainer = function (spanId) {
* participant.
*/
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 =
- `
-
- `;
return new Promise(resolve => {
APP.UI.messageHandler.openTwoButtonDialog({
titleKey : "dialog.muteParticipantTitle",
- msgString,
- leftButtonKey: 'dialog.muteParticipantButton',
- submitFunction: () => {
- if(window.localStorage) {
- let form = $.prompt.getPrompt();
- if (form) {
- let input = form.find("#doNotShowMessageAgain");
- if (input.length) {
- window.localStorage.setItem(
- "dontShowMuteParticipantDialog",
- input.prop("checked"));
- }
- }
- }
- resolve(MUTED_DIALOG_BUTTON_VALUES.muted);
+ msgString: "",
+ leftButtonKey: "dialog.muteParticipantButton",
+ dontShowAgain: {
+ id: "dontShowMuteParticipantDialog",
+ textKey: "dialog.doNotShowMessageAgain",
+ checked: true,
+ buttonValues: [true]
},
+ submitFunction: () => resolve(MUTED_DIALOG_BUTTON_VALUES.muted),
closeFunction: () => resolve(MUTED_DIALOG_BUTTON_VALUES.cancel)
});
});
diff --git a/modules/settings/Settings.js b/modules/settings/Settings.js
index ac1b7293d..66368b34f 100644
--- a/modules/settings/Settings.js
+++ b/modules/settings/Settings.js
@@ -1,26 +1,6 @@
/* global JitsiMeetJS */
-
import UIUtil from '../UI/util/UIUtil';
-
-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;
- }
-}
-
+import jitsiLocalStorage from '../util/JitsiLocalStorage';
function generateUniqueId() {
function _p8() {
@@ -29,45 +9,43 @@ function generateUniqueId() {
return _p8() + _p8() + _p8() + _p8();
}
-if (supportsLocalStorage()) {
- if (!window.localStorage.jitsiMeetId) {
- window.localStorage.jitsiMeetId = generateUniqueId();
- console.log("generated id", window.localStorage.jitsiMeetId);
- }
+if (!jitsiLocalStorage.getItem("jitsiMeetId")) {
+ jitsiLocalStorage.setItem("jitsiMeetId",generateUniqueId());
+ console.log("generated id", jitsiLocalStorage.getItem("jitsiMeetId"));
+}
- email = UIUtil.unescapeHtml(window.localStorage.email || '');
- 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;
- }
+let avatarUrl = '';
- localFlipX = JSON.parse(window.localStorage.localFlipX || true);
- displayName = UIUtil.unescapeHtml(window.localStorage.displayname || '');
- language = window.localStorage.language;
- cameraDeviceId = window.localStorage.cameraDeviceId || '';
- micDeviceId = window.localStorage.micDeviceId || '';
- welcomePageDisabled = JSON.parse(
- window.localStorage.welcomePageDisabled || false
- );
+let email = UIUtil.unescapeHtml(jitsiLocalStorage.getItem("email") || '');
+let avatarId = UIUtil.unescapeHtml(jitsiLocalStorage.getItem("avatarId") || '');
+if (!avatarId) {
+ // if there is no avatar id, we generate a unique one and use it forever
+ avatarId = generateUniqueId();
+ jitsiLocalStorage.setItem("avatarId", avatarId);
+}
- // Currently audio output device change is supported only in Chrome and
- // default output always has 'default' device ID
- var audioOutputDeviceId = window.localStorage.audioOutputDeviceId
- || 'default';
+let localFlipX = JSON.parse(jitsiLocalStorage.getItem("localFlipX") || true);
+let displayName = UIUtil.unescapeHtml(
+ jitsiLocalStorage.getItem("displayname") || '');
+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 !==
- JitsiMeetJS.mediaDevices.getAudioOutputDevice()) {
- JitsiMeetJS.mediaDevices.setAudioOutputDevice(audioOutputDeviceId)
- .catch((ex) => {
- console.warn('Failed to set audio output device from local ' +
- 'storage. Default audio output device will be used' +
- 'instead.', ex);
- });
- }
-} else {
- console.log("local storage is not supported");
+// Currently audio output device change is supported only in Chrome and
+// default output always has 'default' device ID
+let audioOutputDeviceId = jitsiLocalStorage.getItem("audioOutputDeviceId")
+ || 'default';
+
+if (audioOutputDeviceId !==
+ JitsiMeetJS.mediaDevices.getAudioOutputDevice()) {
+ JitsiMeetJS.mediaDevices.setAudioOutputDevice(audioOutputDeviceId)
+ .catch((ex) => {
+ console.warn('Failed to set audio output device from local ' +
+ 'storage. Default audio output device will be used' +
+ 'instead.', ex);
+ });
}
export default {
@@ -82,7 +60,8 @@ export default {
displayName = newDisplayName;
if (!disableLocalStore)
- window.localStorage.displayname = UIUtil.escapeHtml(displayName);
+ jitsiLocalStorage.setItem("displayname",
+ UIUtil.escapeHtml(displayName));
},
/**
@@ -102,7 +81,7 @@ export default {
email = newEmail;
if (!disableLocalStore)
- window.localStorage.email = UIUtil.escapeHtml(newEmail);
+ jitsiLocalStorage.setItem("email", UIUtil.escapeHtml(newEmail));
},
/**
@@ -142,7 +121,7 @@ export default {
},
setLanguage: function (lang) {
language = lang;
- window.localStorage.language = lang;
+ jitsiLocalStorage.setItem("language", lang);
},
/**
@@ -151,7 +130,7 @@ export default {
*/
setLocalFlipX: function (val) {
localFlipX = val;
- window.localStorage.localFlipX = val;
+ jitsiLocalStorage.setItem("localFlipX", val);
},
/**
@@ -179,7 +158,7 @@ export default {
setCameraDeviceId: function (newId, store) {
cameraDeviceId = newId;
if (store)
- window.localStorage.cameraDeviceId = newId;
+ jitsiLocalStorage.setItem("cameraDeviceId", newId);
},
/**
@@ -199,7 +178,7 @@ export default {
setMicDeviceId: function (newId, store) {
micDeviceId = newId;
if (store)
- window.localStorage.micDeviceId = newId;
+ jitsiLocalStorage.setItem("micDeviceId", newId);
},
/**
@@ -218,7 +197,8 @@ export default {
*/
setAudioOutputDeviceId: function (newId = 'default') {
return JitsiMeetJS.mediaDevices.setAudioOutputDevice(newId)
- .then(() => window.localStorage.audioOutputDeviceId = newId);
+ .then(() =>
+ jitsiLocalStorage.setItem("audioOutputDeviceId", newId));
},
/**
@@ -235,6 +215,6 @@ export default {
*/
setWelcomePageEnabled (enabled) {
welcomePageDisabled = !enabled;
- window.localStorage.welcomePageDisabled = welcomePageDisabled;
+ jitsiLocalStorage.setItem("welcomePageDisabled", welcomePageDisabled);
}
};
diff --git a/modules/util/JitsiLocalStorage.js b/modules/util/JitsiLocalStorage.js
new file mode 100644
index 000000000..4aa60ec5e
--- /dev/null
+++ b/modules/util/JitsiLocalStorage.js
@@ -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);