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.

middleware.web.ts 6.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. import { batch } from 'react-redux';
  2. import { AnyAction } from 'redux';
  3. import { IReduxState } from '../app/types';
  4. import { OVERWRITE_CONFIG, SET_CONFIG, UPDATE_CONFIG } from '../base/config/actionTypes';
  5. import { NotifyClickButton } from '../base/config/configType';
  6. import MiddlewareRegistry from '../base/redux/MiddlewareRegistry';
  7. import { I_AM_VISITOR_MODE } from '../visitors/actionTypes';
  8. import { iAmVisitor } from '../visitors/functions';
  9. import {
  10. CLEAR_TOOLBOX_TIMEOUT,
  11. SET_BUTTONS_WITH_NOTIFY_CLICK,
  12. SET_FULL_SCREEN,
  13. SET_PARTICIPANT_MENU_BUTTONS_WITH_NOTIFY_CLICK,
  14. SET_TOOLBAR_BUTTONS,
  15. SET_TOOLBOX_TIMEOUT
  16. } from './actionTypes';
  17. import { setMainToolbarThresholds } from './actions.web';
  18. import { TOOLBAR_BUTTONS, VISITORS_MODE_BUTTONS } from './constants';
  19. import { NOTIFY_CLICK_MODE } from './types';
  20. import './subscriber.web';
  21. /**
  22. * Middleware which intercepts Toolbox actions to handle changes to the
  23. * visibility timeout of the Toolbox.
  24. *
  25. * @param {Store} store - The redux store.
  26. * @returns {Function}
  27. */
  28. MiddlewareRegistry.register(store => next => action => {
  29. switch (action.type) {
  30. case CLEAR_TOOLBOX_TIMEOUT: {
  31. const { timeoutID } = store.getState()['features/toolbox'];
  32. clearTimeout(timeoutID ?? undefined);
  33. break;
  34. }
  35. case UPDATE_CONFIG:
  36. case OVERWRITE_CONFIG:
  37. case I_AM_VISITOR_MODE:
  38. case SET_CONFIG: {
  39. const result = next(action);
  40. const { dispatch, getState } = store;
  41. const state = getState();
  42. if (action.type !== I_AM_VISITOR_MODE) {
  43. const {
  44. customToolbarButtons,
  45. buttonsWithNotifyClick,
  46. participantMenuButtonsWithNotifyClick,
  47. customParticipantMenuButtons
  48. } = state['features/base/config'];
  49. batch(() => {
  50. if (action.type !== I_AM_VISITOR_MODE) {
  51. dispatch(setMainToolbarThresholds());
  52. }
  53. dispatch({
  54. type: SET_BUTTONS_WITH_NOTIFY_CLICK,
  55. buttonsWithNotifyClick: _buildButtonsArray(buttonsWithNotifyClick, customToolbarButtons)
  56. });
  57. dispatch({
  58. type: SET_PARTICIPANT_MENU_BUTTONS_WITH_NOTIFY_CLICK,
  59. participantMenuButtonsWithNotifyClick:
  60. _buildButtonsArray(participantMenuButtonsWithNotifyClick, customParticipantMenuButtons)
  61. });
  62. });
  63. }
  64. const toolbarButtons = _getToolbarButtons(state);
  65. dispatch({
  66. type: SET_TOOLBAR_BUTTONS,
  67. toolbarButtons
  68. });
  69. return result;
  70. }
  71. case SET_FULL_SCREEN:
  72. return _setFullScreen(next, action);
  73. case SET_TOOLBOX_TIMEOUT: {
  74. const { timeoutID } = store.getState()['features/toolbox'];
  75. const { handler, timeoutMS }: { handler: Function; timeoutMS: number; } = action;
  76. clearTimeout(timeoutID ?? undefined);
  77. action.timeoutID = setTimeout(handler, timeoutMS);
  78. break;
  79. }
  80. }
  81. return next(action);
  82. });
  83. type DocumentElement = {
  84. requestFullscreen?: Function;
  85. webkitRequestFullscreen?: Function;
  86. };
  87. /**
  88. * Makes an external request to enter or exit full screen mode.
  89. *
  90. * @param {Dispatch} next - The redux dispatch function to dispatch the
  91. * specified action to the specified store.
  92. * @param {Action} action - The redux action SET_FULL_SCREEN which is being
  93. * dispatched in the specified store.
  94. * @private
  95. * @returns {Object} The value returned by {@code next(action)}.
  96. */
  97. function _setFullScreen(next: Function, action: AnyAction) {
  98. const result = next(action);
  99. const { fullScreen } = action;
  100. if (fullScreen) {
  101. const documentElement: DocumentElement
  102. = document.documentElement || {};
  103. if (typeof documentElement.requestFullscreen === 'function') {
  104. documentElement.requestFullscreen();
  105. } else if (
  106. typeof documentElement.webkitRequestFullscreen === 'function') {
  107. documentElement.webkitRequestFullscreen();
  108. }
  109. return result;
  110. }
  111. if (typeof document.exitFullscreen === 'function') {
  112. document.exitFullscreen();
  113. } else if (typeof document.webkitExitFullscreen === 'function') {
  114. document.webkitExitFullscreen();
  115. }
  116. return result;
  117. }
  118. /**
  119. * Common logic to gather buttons that have to notify the api when clicked.
  120. *
  121. * @param {Array} buttonsWithNotifyClick - The array of systme buttons that need to notify the api.
  122. * @param {Array} customButtons - The custom buttons.
  123. * @returns {Array}
  124. */
  125. function _buildButtonsArray(
  126. buttonsWithNotifyClick?: NotifyClickButton[],
  127. customButtons?: {
  128. icon: string;
  129. id: string;
  130. text: string;
  131. }[]
  132. ): Map<string, NOTIFY_CLICK_MODE> {
  133. const customButtonsWithNotifyClick = customButtons?.map(
  134. ({ id }) => ([ id, NOTIFY_CLICK_MODE.ONLY_NOTIFY ]) as [string, NOTIFY_CLICK_MODE]) ?? [];
  135. const buttons = (Array.isArray(buttonsWithNotifyClick) ? buttonsWithNotifyClick : [])
  136. .filter(button => typeof button === 'string' || (typeof button === 'object' && typeof button.key === 'string'))
  137. .map(button => {
  138. if (typeof button === 'string') {
  139. return [ button, NOTIFY_CLICK_MODE.PREVENT_AND_NOTIFY ] as [string, NOTIFY_CLICK_MODE];
  140. }
  141. return [
  142. button.key,
  143. button.preventExecution ? NOTIFY_CLICK_MODE.PREVENT_AND_NOTIFY : NOTIFY_CLICK_MODE.ONLY_NOTIFY
  144. ] as [string, NOTIFY_CLICK_MODE];
  145. });
  146. return new Map([ ...customButtonsWithNotifyClick, ...buttons ]);
  147. }
  148. /**
  149. * Returns the list of enabled toolbar buttons.
  150. *
  151. * @param {Object} state - The redux state.
  152. * @returns {Array<string>} - The list of enabled toolbar buttons.
  153. */
  154. function _getToolbarButtons(state: IReduxState): Array<string> {
  155. const { toolbarButtons, customToolbarButtons } = state['features/base/config'];
  156. const customButtons = customToolbarButtons?.map(({ id }) => id);
  157. let buttons = Array.isArray(toolbarButtons) ? toolbarButtons : TOOLBAR_BUTTONS;
  158. if (iAmVisitor(state)) {
  159. buttons = VISITORS_MODE_BUTTONS.filter(button => buttons.indexOf(button) > -1);
  160. }
  161. if (customButtons) {
  162. return [ ...buttons, ...customButtons ];
  163. }
  164. return buttons;
  165. }