You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

MessageHandler.js 17KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506
  1. /* global $, APP */
  2. const logger = require("jitsi-meet-logger").getLogger(__filename);
  3. import jitsiLocalStorage from '../../util/JitsiLocalStorage';
  4. import {
  5. Notification,
  6. showNotification
  7. } from '../../../react/features/notifications';
  8. /**
  9. * Flag for enabling/disabling popups.
  10. * @type {boolean}
  11. */
  12. let popupEnabled = true;
  13. /**
  14. * Currently displayed two button dialog.
  15. * @type {null}
  16. */
  17. let twoButtonDialog = null;
  18. /**
  19. * Generates html for dont show again checkbox.
  20. * @param {object} options options
  21. * @param {string} options.id the id of the checkbox.
  22. * @param {string} options.textKey the key for the text displayed next to
  23. * checkbox
  24. * @param {boolean} options.checked if true the checkbox is foing to be checked
  25. * by default.
  26. * @returns {string}
  27. */
  28. function generateDontShowCheckbox(options) {
  29. if(!isDontShowAgainEnabled(options)) {
  30. return "";
  31. }
  32. let checked
  33. = (options.checked === true) ? "checked" : "";
  34. return `<br />
  35. <label>
  36. <input type='checkbox' ${checked} id='${options.id}' />
  37. <span data-i18n='${options.textKey}'></span>
  38. </label>`;
  39. }
  40. /**
  41. * Checks whether the dont show again checkbox was checked before.
  42. * @param {object} options - options for dont show again checkbox.
  43. * @param {string} options.id the id of the checkbox.
  44. * @param {string} options.localStorageKey the key for the local storage. if
  45. * not provided options.id will be used.
  46. * @returns {boolean} true if the dialog mustn't be displayed and
  47. * false otherwise.
  48. */
  49. function dontShowTheDialog(options) {
  50. if(isDontShowAgainEnabled(options)) {
  51. if(jitsiLocalStorage.getItem(options.localStorageKey || options.id)
  52. === "true") {
  53. return true;
  54. }
  55. }
  56. return false;
  57. }
  58. /**
  59. * Wraps the submit function to process the dont show again status and store
  60. * it.
  61. * @param {object} options - options for dont show again checkbox.
  62. * @param {string} options.id the id of the checkbox.
  63. * @param {Array} options.buttonValues The button values that will trigger
  64. * storing he checkbox value
  65. * @param {string} options.localStorageKey the key for the local storage. if
  66. * not provided options.id will be used.
  67. * @param {Function} submitFunction the submit function to be wrapped
  68. * @returns {Function} wrapped function
  69. */
  70. function dontShowAgainSubmitFunctionWrapper(options, submitFunction) {
  71. if(isDontShowAgainEnabled(options)) {
  72. return (...args) => {
  73. logger.debug(args, options.buttonValues);
  74. //args[1] is the value associated with the pressed button
  75. if(!options.buttonValues || options.buttonValues.length === 0
  76. || options.buttonValues.indexOf(args[1]) !== -1 ) {
  77. let checkbox = $(`#${options.id}`);
  78. if (checkbox.length) {
  79. jitsiLocalStorage.setItem(
  80. options.localStorageKey || options.id,
  81. checkbox.prop("checked"));
  82. }
  83. }
  84. submitFunction(...args);
  85. };
  86. } else {
  87. return submitFunction;
  88. }
  89. }
  90. /**
  91. * Check whether dont show again checkbox is enabled or not.
  92. * @param {object} options - options for dont show again checkbox.
  93. * @returns {boolean} true if enabled and false if not.
  94. */
  95. function isDontShowAgainEnabled(options) {
  96. return typeof options === "object";
  97. }
  98. var messageHandler = {
  99. OK: "dialog.OK",
  100. CANCEL: "dialog.Cancel",
  101. /**
  102. * Shows a message to the user.
  103. *
  104. * @param titleKey the key used to find the translation of the title of the
  105. * message, if a message title is not provided.
  106. * @param messageKey the key used to find the translation of the message
  107. * @param i18nOptions the i18n options (optional)
  108. * @param closeFunction function to be called after
  109. * the prompt is closed (optional)
  110. * @return the prompt that was created, or null
  111. */
  112. openMessageDialog(titleKey, messageKey, i18nOptions, closeFunction) {
  113. if (!popupEnabled)
  114. return null;
  115. let dialog = $.prompt(
  116. APP.translation.generateTranslationHTML(messageKey, i18nOptions),
  117. {
  118. title: this._getFormattedTitleString(titleKey),
  119. persistent: false,
  120. promptspeed: 0,
  121. classes: this._getDialogClasses(),
  122. close(e, v, m, f) {
  123. if(closeFunction)
  124. closeFunction(e, v, m, f);
  125. }
  126. });
  127. APP.translation.translateElement(dialog, i18nOptions);
  128. return $.prompt.getApi();
  129. },
  130. /**
  131. * Shows a message to the user with two buttons: first is given as a
  132. * parameter and the second is Cancel.
  133. *
  134. * @param titleKey the key for the title of the message
  135. * @param msgKey the key for the message
  136. * @param msgString the text of the message
  137. * @param persistent boolean value which determines whether the message is
  138. * persistent or not
  139. * @param leftButton the fist button's text
  140. * @param submitFunction function to be called on submit
  141. * @param loadedFunction function to be called after the prompt is fully
  142. * loaded
  143. * @param closeFunction function to be called after the prompt is closed
  144. * @param focus optional focus selector or button index to be focused after
  145. * the dialog is opened
  146. * @param defaultButton index of default button which will be activated when
  147. * the user press 'enter'. Indexed from 0.
  148. * @param {object} dontShowAgain - options for dont show again checkbox.
  149. * @param {string} dontShowAgain.id the id of the checkbox.
  150. * @param {string} dontShowAgain.textKey the key for the text displayed
  151. * next to checkbox
  152. * @param {boolean} dontShowAgain.checked if true the checkbox is foing to
  153. * be checked
  154. * @param {Array} dontShowAgain.buttonValues The button values that will
  155. * trigger storing the checkbox value
  156. * @param {string} dontShowAgain.localStorageKey the key for the local
  157. * storage. if not provided dontShowAgain.id will be used.
  158. * @return the prompt that was created, or null
  159. */
  160. openTwoButtonDialog: function(options) {
  161. let {
  162. titleKey,
  163. msgKey,
  164. msgString,
  165. leftButtonKey,
  166. submitFunction,
  167. loadedFunction,
  168. closeFunction,
  169. focus,
  170. size,
  171. defaultButton,
  172. wrapperClass,
  173. classes,
  174. dontShowAgain
  175. } = options;
  176. if (!popupEnabled || twoButtonDialog)
  177. return null;
  178. if(dontShowTheDialog(dontShowAgain)) {
  179. // Maybe we should pass some parameters here? I'm not sure
  180. // and currently we don't need any parameters.
  181. submitFunction();
  182. return null;
  183. }
  184. var buttons = [];
  185. var leftButton = leftButtonKey ?
  186. APP.translation.generateTranslationHTML(leftButtonKey) :
  187. APP.translation.generateTranslationHTML('dialog.Submit');
  188. buttons.push({ title: leftButton, value: true});
  189. var cancelButton
  190. = APP.translation.generateTranslationHTML("dialog.Cancel");
  191. buttons.push({title: cancelButton, value: false});
  192. var message = msgString;
  193. if (msgKey) {
  194. message = APP.translation.generateTranslationHTML(msgKey);
  195. }
  196. message += generateDontShowCheckbox(dontShowAgain);
  197. classes = classes || this._getDialogClasses(size);
  198. if (wrapperClass) {
  199. classes.prompt += ` ${wrapperClass}`;
  200. }
  201. twoButtonDialog = $.prompt(message, {
  202. title: this._getFormattedTitleString(titleKey),
  203. persistent: false,
  204. buttons: buttons,
  205. defaultButton: defaultButton,
  206. focus: focus,
  207. loaded: loadedFunction,
  208. promptspeed: 0,
  209. classes,
  210. submit: dontShowAgainSubmitFunctionWrapper(dontShowAgain,
  211. function (e, v, m, f) {
  212. twoButtonDialog = null;
  213. if (v && submitFunction) {
  214. submitFunction(e, v, m, f);
  215. }
  216. }),
  217. close: function (e, v, m, f) {
  218. twoButtonDialog = null;
  219. if (closeFunction) {
  220. closeFunction(e, v, m, f);
  221. }
  222. }
  223. });
  224. APP.translation.translateElement(twoButtonDialog);
  225. return $.prompt.getApi();
  226. },
  227. /**
  228. * Shows a message to the user with two buttons: first is given as a
  229. * parameter and the second is Cancel.
  230. *
  231. * @param titleKey the key for the title of the message
  232. * @param msgString the text of the message
  233. * @param persistent boolean value which determines whether the message is
  234. * persistent or not
  235. * @param buttons object with the buttons. The keys must be the name of the
  236. * button and value is the value that will be passed to
  237. * submitFunction
  238. * @param submitFunction function to be called on submit
  239. * @param loadedFunction function to be called after the prompt is fully
  240. * loaded
  241. * @param closeFunction function to be called on dialog close
  242. * @param {object} dontShowAgain - options for dont show again checkbox.
  243. * @param {string} dontShowAgain.id the id of the checkbox.
  244. * @param {string} dontShowAgain.textKey the key for the text displayed
  245. * next to checkbox
  246. * @param {boolean} dontShowAgain.checked if true the checkbox is foing to
  247. * be checked
  248. * @param {Array} dontShowAgain.buttonValues The button values that will
  249. * trigger storing the checkbox value
  250. * @param {string} dontShowAgain.localStorageKey the key for the local
  251. * storage. if not provided dontShowAgain.id will be used.
  252. */
  253. openDialog(
  254. titleKey,
  255. msgString,
  256. persistent,
  257. buttons,
  258. submitFunction,
  259. loadedFunction,
  260. closeFunction,
  261. dontShowAgain) {
  262. if (!popupEnabled)
  263. return;
  264. if(dontShowTheDialog(dontShowAgain)) {
  265. // Maybe we should pass some parameters here? I'm not sure
  266. // and currently we don't need any parameters.
  267. submitFunction();
  268. return;
  269. }
  270. let args = {
  271. title: this._getFormattedTitleString(titleKey),
  272. persistent: persistent,
  273. buttons: buttons,
  274. defaultButton: 1,
  275. promptspeed: 0,
  276. loaded: function() {
  277. if (loadedFunction) {
  278. loadedFunction.apply(this, arguments);
  279. }
  280. // Hide the close button
  281. if (persistent) {
  282. $(".jqiclose", this).hide();
  283. }
  284. },
  285. submit: dontShowAgainSubmitFunctionWrapper(
  286. dontShowAgain, submitFunction),
  287. close: closeFunction,
  288. classes: this._getDialogClasses()
  289. };
  290. if (persistent) {
  291. args.closeText = '';
  292. }
  293. let dialog = $.prompt(
  294. msgString + generateDontShowCheckbox(dontShowAgain), args);
  295. APP.translation.translateElement(dialog);
  296. return $.prompt.getApi();
  297. },
  298. /**
  299. * Returns the formatted title string.
  300. *
  301. * @return the title string formatted as a div.
  302. */
  303. _getFormattedTitleString(titleKey) {
  304. let $titleString = $('<h2>');
  305. $titleString.addClass('aui-dialog2-header-main');
  306. $titleString.attr('data-i18n',titleKey);
  307. return $('<div>').append($titleString).html();
  308. },
  309. /**
  310. * Returns the dialog css classes.
  311. *
  312. * @return the dialog css classes
  313. */
  314. _getDialogClasses(size = 'small') {
  315. return {
  316. box: '',
  317. form: '',
  318. prompt: `dialog aui-layer aui-dialog2 aui-dialog2-${size}`,
  319. close: 'aui-icon aui-icon-small aui-iconfont-close-dialog',
  320. fade: 'aui-blanket',
  321. button: 'button-control',
  322. message: 'aui-dialog2-content',
  323. buttons: 'aui-dialog2-footer',
  324. defaultButton: 'button-control_primary',
  325. title: 'aui-dialog2-header'
  326. };
  327. },
  328. /**
  329. * Shows a dialog with different states to the user.
  330. *
  331. * @param statesObject object containing all the states of the dialog.
  332. * @param options impromptu options
  333. * @param translateOptions options passed to translation
  334. */
  335. openDialogWithStates: function (statesObject, options, translateOptions) {
  336. if (!popupEnabled)
  337. return;
  338. let { classes, size } = options;
  339. let defaultClasses = this._getDialogClasses(size);
  340. options.classes = Object.assign({}, defaultClasses, classes);
  341. options.promptspeed = options.promptspeed || 0;
  342. for (let state in statesObject) {
  343. let currentState = statesObject[state];
  344. if(currentState.titleKey) {
  345. currentState.title
  346. = this._getFormattedTitleString(currentState.titleKey);
  347. }
  348. }
  349. let dialog = $.prompt(statesObject, options);
  350. APP.translation.translateElement(dialog, translateOptions);
  351. return $.prompt.getApi();
  352. },
  353. /**
  354. * Opens new popup window for given <tt>url</tt> centered over current
  355. * window.
  356. *
  357. * @param url the URL to be displayed in the popup window
  358. * @param w the width of the popup window
  359. * @param h the height of the popup window
  360. * @param onPopupClosed optional callback function called when popup window
  361. * has been closed.
  362. *
  363. * @returns {object} popup window object if opened successfully or undefined
  364. * in case we failed to open it(popup blocked)
  365. */
  366. openCenteredPopup: function (url, w, h, onPopupClosed) {
  367. if (!popupEnabled)
  368. return;
  369. var l = window.screenX + (window.innerWidth / 2) - (w / 2);
  370. var t = window.screenY + (window.innerHeight / 2) - (h / 2);
  371. var popup = window.open(
  372. url, '_blank',
  373. 'top=' + t + ', left=' + l + ', width=' + w + ', height=' + h + '');
  374. if (popup && onPopupClosed) {
  375. var pollTimer = window.setInterval(function () {
  376. if (popup.closed !== false) {
  377. window.clearInterval(pollTimer);
  378. onPopupClosed();
  379. }
  380. }, 200);
  381. }
  382. return popup;
  383. },
  384. /**
  385. * Shows a dialog prompting the user to send an error report.
  386. *
  387. * @param titleKey the title of the message
  388. * @param msgKey the text of the message
  389. * @param error the error that is being reported
  390. */
  391. openReportDialog: function(titleKey, msgKey, error) {
  392. this.openMessageDialog(titleKey, msgKey);
  393. logger.log(error);
  394. //FIXME send the error to the server
  395. },
  396. /**
  397. * Shows an error dialog to the user.
  398. * @param titleKey the title of the message.
  399. * @param msgKey the text of the message.
  400. */
  401. showError: function(titleKey, msgKey) {
  402. if (!titleKey) {
  403. titleKey = "dialog.oops";
  404. }
  405. if (!msgKey) {
  406. msgKey = "dialog.defaultError";
  407. }
  408. messageHandler.openMessageDialog(titleKey, msgKey);
  409. },
  410. /**
  411. * Displays a notification about participant action.
  412. * @param displayName the display name of the participant that is
  413. * associated with the notification.
  414. * @param displayNameKey the key from the language file for the display
  415. * name. Only used if displayName i not provided.
  416. * @param cls css class for the notification
  417. * @param messageKey the key from the language file for the text of the
  418. * message.
  419. * @param messageArguments object with the arguments for the message.
  420. * @param optional configurations for the notification (e.g. timeout)
  421. */
  422. participantNotification(
  423. displayName,
  424. displayNameKey,
  425. cls,
  426. messageKey,
  427. messageArguments,
  428. timeout = 2500) {
  429. APP.store.dispatch(
  430. showNotification(
  431. Notification,
  432. {
  433. defaultTitleKey: displayNameKey,
  434. descriptionArguments: messageArguments,
  435. descriptionKey: messageKey,
  436. title: displayName
  437. },
  438. timeout));
  439. },
  440. /**
  441. * Displays a notification.
  442. *
  443. * @param {string} titleKey - The key from the language file for the title
  444. * of the notification.
  445. * @param {string} messageKey - The key from the language file for the text
  446. * of the message.
  447. * @param {Object} messageArguments - The arguments for the message
  448. * translation.
  449. * @returns {void}
  450. */
  451. notify: function(titleKey, messageKey, messageArguments) {
  452. this.participantNotification(
  453. null, titleKey, null, messageKey, messageArguments);
  454. },
  455. enablePopups: function (enable) {
  456. popupEnabled = enable;
  457. },
  458. /**
  459. * Returns true if dialog is opened
  460. * false otherwise
  461. * @returns {boolean} isOpened
  462. */
  463. isDialogOpened: function () {
  464. return !!$.prompt.getCurrentStateName();
  465. }
  466. };
  467. export default messageHandler;