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.

SettingsMenu.js 9.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. /* global $, APP, AJS, interfaceConfig, JitsiMeetJS */
  2. import { openDialog } from '../../../../react/features/base/dialog';
  3. import { LANGUAGES } from "../../../../react/features/base/i18n";
  4. import { DeviceSelectionDialog }
  5. from '../../../../react/features/device-selection';
  6. import UIUtil from "../../util/UIUtil";
  7. import UIEvents from "../../../../service/UI/UIEvents";
  8. const sidePanelsContainerId = 'sideToolbarContainer';
  9. const deviceSelectionButtonClasses
  10. = 'button-control button-control_primary button-control_full-width';
  11. const htmlStr = `
  12. <div id="settings_container" class="sideToolbarContainer__inner">
  13. <div class="title" data-i18n="settings.title"></div>
  14. <form class="aui">
  15. <div id="languagesSelectWrapper"
  16. class="sideToolbarBlock first hide">
  17. <select id="languagesSelect"></select>
  18. </div>
  19. <div id="deviceOptionsWrapper" class="hide">
  20. <div id="deviceOptionsTitle" class="subTitle hide"
  21. data-i18n="settings.audioVideo"></div>
  22. <div class="sideToolbarBlock first">
  23. <button
  24. class="${deviceSelectionButtonClasses}"
  25. data-i18n="deviceSelection.deviceSettings"
  26. id="deviceSelection"
  27. type="button"></button>
  28. </div>
  29. </div>
  30. <div id="moderatorOptionsWrapper" class="hide">
  31. <div id="moderatorOptionsTitle" class="subTitle hide"
  32. data-i18n="settings.moderator"></div>
  33. <div id="startMutedOptions" class="hide">
  34. <div class="sideToolbarBlock first">
  35. <input type="checkbox" id="startAudioMuted">
  36. <label class="startMutedLabel" for="startAudioMuted"
  37. data-i18n="settings.startAudioMuted"></label>
  38. </div>
  39. <div class="sideToolbarBlock">
  40. <input type="checkbox" id="startVideoMuted">
  41. <label class="startMutedLabel" for="startVideoMuted"
  42. data-i18n="settings.startVideoMuted"></label>
  43. </div>
  44. </div>
  45. <div id="followMeOptions" class="hide">
  46. <div class="sideToolbarBlock">
  47. <input type="checkbox" id="followMeCheckBox">
  48. <label class="followMeLabel" for="followMeCheckBox"
  49. data-i18n="settings.followMe"></label>
  50. </div>
  51. </div>
  52. </div>
  53. </form>
  54. </div>`;
  55. function initHTML() {
  56. $(`#${sidePanelsContainerId}`)
  57. .append(htmlStr);
  58. // make sure we translate the panel, as adding it can be after i18n
  59. // library had initialized and translated already present html
  60. APP.translation.translateElement($(`#${sidePanelsContainerId}`));
  61. }
  62. /**
  63. * Generate html select options for available languages.
  64. *
  65. * @param {string[]} items available languages
  66. * @param {string} [currentLang] current language
  67. * @returns {string}
  68. */
  69. function generateLanguagesOptions(items, currentLang) {
  70. return items.map(function (lang) {
  71. let attrs = {
  72. value: lang,
  73. 'data-i18n': `languages:${lang}`
  74. };
  75. if (lang === currentLang) {
  76. attrs.selected = 'selected';
  77. }
  78. let attrsStr = UIUtil.attrsToString(attrs);
  79. return `<option ${attrsStr}></option>`;
  80. }).join('');
  81. }
  82. /**
  83. * Replace html select element to select2 custom dropdown
  84. *
  85. * @param {jQueryElement} $el native select element
  86. * @param {function} onSelectedCb fired if item is selected
  87. */
  88. function initSelect2($el, onSelectedCb) {
  89. $el.auiSelect2({
  90. minimumResultsForSearch: Infinity
  91. });
  92. if (typeof onSelectedCb === 'function') {
  93. $el.change(onSelectedCb);
  94. }
  95. }
  96. /**
  97. * Open DeviceSelectionDialog with a configuration based on the environment's
  98. * supported abilities.
  99. *
  100. * @param {boolean} isDeviceListAvailable - Whether or not device enumeration
  101. * is possible. This is a value obtained through an async operation whereas all
  102. * other configurations for the modal are obtained synchronously.
  103. * @private
  104. * @returns {void}
  105. */
  106. function _openDeviceSelectionModal(isDeviceListAvailable) {
  107. APP.store.dispatch(openDialog(DeviceSelectionDialog, {
  108. currentAudioOutputId: APP.settings.getAudioOutputDeviceId(),
  109. currentAudioTrack: APP.conference.getLocalAudioTrack(),
  110. currentVideoTrack: APP.conference.getLocalVideoTrack(),
  111. disableAudioInputChange: !JitsiMeetJS.isMultipleAudioInputSupported(),
  112. disableDeviceChange: !isDeviceListAvailable
  113. || !JitsiMeetJS.mediaDevices.isDeviceChangeAvailable(),
  114. hasAudioPermission: JitsiMeetJS.mediaDevices
  115. .isDevicePermissionGranted('audio'),
  116. hasVideoPermission: JitsiMeetJS.mediaDevices
  117. .isDevicePermissionGranted('video'),
  118. hideAudioInputPreview: !JitsiMeetJS.isCollectingLocalStats(),
  119. hideAudioOutputSelect: !JitsiMeetJS.mediaDevices
  120. .isDeviceChangeAvailable('output')
  121. }));
  122. }
  123. export default {
  124. init (emitter) {
  125. initHTML();
  126. //LANGUAGES BOX
  127. if (UIUtil.isSettingEnabled('language')) {
  128. const wrapperId = 'languagesSelectWrapper';
  129. const selectId = 'languagesSelect';
  130. const selectEl = AJS.$(`#${selectId}`);
  131. let selectInput;
  132. selectEl.html(generateLanguagesOptions(
  133. LANGUAGES,
  134. APP.translation.getCurrentLanguage()
  135. ));
  136. initSelect2(selectEl, () => {
  137. const val = selectEl.val();
  138. selectInput[0].dataset.i18n = `languages:${val}`;
  139. APP.translation.translateElement(selectInput);
  140. emitter.emit(UIEvents.LANG_CHANGED, val);
  141. });
  142. //find new selectInput element
  143. selectInput = $(`#s2id_${selectId} .select2-chosen`);
  144. //first select fix for languages options
  145. selectInput[0].dataset.i18n =
  146. `languages:${APP.translation.getCurrentLanguage()}`;
  147. // translate selectInput, which is the currently selected language
  148. // otherwise there will be no selected option
  149. APP.translation.translateElement(selectInput);
  150. APP.translation.translateElement(selectEl);
  151. APP.translation.addLanguageChangedListener(
  152. lng => selectInput[0].dataset.i18n = `languages:${lng}`);
  153. UIUtil.setVisible(wrapperId, true);
  154. }
  155. // DEVICES LIST
  156. if (UIUtil.isSettingEnabled('devices')) {
  157. const wrapperId = 'deviceOptionsWrapper';
  158. JitsiMeetJS.mediaDevices.isDeviceListAvailable()
  159. .then((isDeviceListAvailable) => {
  160. $('#deviceSelection').on('click', () => {
  161. _openDeviceSelectionModal(isDeviceListAvailable);
  162. });
  163. });
  164. // Only show the subtitle if this isn't the only setting section.
  165. if (interfaceConfig.SETTINGS_SECTIONS.length > 1)
  166. UIUtil.setVisible("deviceOptionsTitle", true);
  167. UIUtil.setVisible(wrapperId, true);
  168. }
  169. // MODERATOR
  170. if (UIUtil.isSettingEnabled('moderator')) {
  171. const wrapperId = 'moderatorOptionsWrapper';
  172. // START MUTED
  173. $("#startMutedOptions").change(function () {
  174. let startAudioMuted = $("#startAudioMuted").is(":checked");
  175. let startVideoMuted = $("#startVideoMuted").is(":checked");
  176. emitter.emit(
  177. UIEvents.START_MUTED_CHANGED,
  178. startAudioMuted,
  179. startVideoMuted
  180. );
  181. });
  182. // FOLLOW ME
  183. const followMeToggle = document.getElementById('followMeCheckBox');
  184. followMeToggle.addEventListener('change', () => {
  185. const isFollowMeEnabled = followMeToggle.checked;
  186. emitter.emit(UIEvents.FOLLOW_ME_ENABLED, isFollowMeEnabled);
  187. });
  188. UIUtil.setVisible(wrapperId, true);
  189. }
  190. },
  191. /**
  192. * If start audio muted/start video muted options should be visible or not.
  193. * @param {boolean} show
  194. */
  195. showStartMutedOptions (show) {
  196. if (show && UIUtil.isSettingEnabled('moderator')) {
  197. // Only show the subtitle if this isn't the only setting section.
  198. if (!$("#moderatorOptionsTitle").is(":visible")
  199. && interfaceConfig.SETTINGS_SECTIONS.length > 1)
  200. UIUtil.setVisible("moderatorOptionsTitle", true);
  201. UIUtil.setVisible("startMutedOptions", true);
  202. } else {
  203. // Only show the subtitle if this isn't the only setting section.
  204. if ($("#moderatorOptionsTitle").is(":visible"))
  205. UIUtil.setVisible("moderatorOptionsTitle", false);
  206. UIUtil.setVisible("startMutedOptions", false);
  207. }
  208. },
  209. updateStartMutedBox (startAudioMuted, startVideoMuted) {
  210. $("#startAudioMuted").attr("checked", startAudioMuted);
  211. $("#startVideoMuted").attr("checked", startVideoMuted);
  212. },
  213. /**
  214. * Shows/hides the follow me options in the settings dialog.
  215. *
  216. * @param {boolean} show {true} to show those options, {false} to hide them
  217. */
  218. showFollowMeOptions (show) {
  219. UIUtil.setVisible(
  220. "followMeOptions",
  221. show && UIUtil.isSettingEnabled('moderator'));
  222. },
  223. /**
  224. * Check if settings menu is visible or not.
  225. * @returns {boolean}
  226. */
  227. isVisible () {
  228. return UIUtil.isVisible(document.getElementById("settings_container"));
  229. }
  230. };