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.

Toolbar.js 28KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872
  1. /* global APP, $, config, interfaceConfig, JitsiMeetJS */
  2. import UIUtil from '../util/UIUtil';
  3. import UIEvents from '../../../service/UI/UIEvents';
  4. import SideContainerToggler from "../side_pannels/SideContainerToggler";
  5. let emitter = null;
  6. let Toolbar;
  7. /**
  8. * Handlers for toolbar buttons.
  9. *
  10. * buttonId {string}: handler {function}
  11. */
  12. const buttonHandlers = {
  13. "toolbar_button_profile": function () {
  14. JitsiMeetJS.analytics.sendEvent('toolbar.profile.toggled');
  15. emitter.emit(UIEvents.TOGGLE_PROFILE);
  16. },
  17. "toolbar_button_mute": function () {
  18. let sharedVideoManager = APP.UI.getSharedVideoManager();
  19. if (APP.conference.audioMuted) {
  20. // If there's a shared video with the volume "on" and we aren't
  21. // the video owner, we warn the user
  22. // that currently it's not possible to unmute.
  23. if (sharedVideoManager
  24. && sharedVideoManager.isSharedVideoVolumeOn()
  25. && !sharedVideoManager.isSharedVideoOwner()) {
  26. UIUtil.animateShowElement(
  27. $("#unableToUnmutePopup"), true, 5000);
  28. }
  29. else {
  30. JitsiMeetJS.analytics.sendEvent('toolbar.audio.unmuted');
  31. emitter.emit(UIEvents.AUDIO_MUTED, false, true);
  32. }
  33. } else {
  34. JitsiMeetJS.analytics.sendEvent('toolbar.audio.muted');
  35. emitter.emit(UIEvents.AUDIO_MUTED, true, true);
  36. }
  37. },
  38. "toolbar_button_camera": function () {
  39. if (APP.conference.videoMuted) {
  40. JitsiMeetJS.analytics.sendEvent('toolbar.video.enabled');
  41. emitter.emit(UIEvents.VIDEO_MUTED, false);
  42. } else {
  43. JitsiMeetJS.analytics.sendEvent('toolbar.video.disabled');
  44. emitter.emit(UIEvents.VIDEO_MUTED, true);
  45. }
  46. },
  47. "toolbar_button_link": function () {
  48. JitsiMeetJS.analytics.sendEvent('toolbar.invite.clicked');
  49. emitter.emit(UIEvents.INVITE_CLICKED);
  50. },
  51. "toolbar_button_chat": function () {
  52. JitsiMeetJS.analytics.sendEvent('toolbar.chat.toggled');
  53. emitter.emit(UIEvents.TOGGLE_CHAT);
  54. },
  55. "toolbar_contact_list": function () {
  56. JitsiMeetJS.analytics.sendEvent(
  57. 'toolbar.contacts.toggled');
  58. emitter.emit(UIEvents.TOGGLE_CONTACT_LIST);
  59. },
  60. "toolbar_button_etherpad": function () {
  61. JitsiMeetJS.analytics.sendEvent('toolbar.etherpad.clicked');
  62. emitter.emit(UIEvents.ETHERPAD_CLICKED);
  63. },
  64. "toolbar_button_sharedvideo": function () {
  65. JitsiMeetJS.analytics.sendEvent('toolbar.sharedvideo.clicked');
  66. emitter.emit(UIEvents.SHARED_VIDEO_CLICKED);
  67. },
  68. "toolbar_button_desktopsharing": function () {
  69. if (APP.conference.isSharingScreen) {
  70. JitsiMeetJS.analytics.sendEvent('toolbar.screen.disabled');
  71. } else {
  72. JitsiMeetJS.analytics.sendEvent('toolbar.screen.enabled');
  73. }
  74. emitter.emit(UIEvents.TOGGLE_SCREENSHARING);
  75. },
  76. "toolbar_button_fullScreen": function() {
  77. JitsiMeetJS.analytics.sendEvent('toolbar.fullscreen.enabled');
  78. emitter.emit(UIEvents.TOGGLE_FULLSCREEN);
  79. },
  80. "toolbar_button_sip": function () {
  81. JitsiMeetJS.analytics.sendEvent('toolbar.sip.clicked');
  82. showSipNumberInput();
  83. },
  84. "toolbar_button_dialpad": function () {
  85. JitsiMeetJS.analytics.sendEvent('toolbar.sip.dialpad.clicked');
  86. dialpadButtonClicked();
  87. },
  88. "toolbar_button_settings": function () {
  89. JitsiMeetJS.analytics.sendEvent('toolbar.settings.toggled');
  90. emitter.emit(UIEvents.TOGGLE_SETTINGS);
  91. },
  92. "toolbar_button_hangup": function () {
  93. JitsiMeetJS.analytics.sendEvent('toolbar.hangup');
  94. emitter.emit(UIEvents.HANGUP);
  95. },
  96. "toolbar_button_login": function () {
  97. JitsiMeetJS.analytics.sendEvent('toolbar.authenticate.login.clicked');
  98. emitter.emit(UIEvents.AUTH_CLICKED);
  99. },
  100. "toolbar_button_logout": function () {
  101. let titleKey = "dialog.logoutTitle";
  102. let msgKey = "dialog.logoutQuestion";
  103. JitsiMeetJS.analytics.sendEvent('toolbar.authenticate.logout.clicked');
  104. // Ask for confirmation
  105. APP.UI.messageHandler.openTwoButtonDialog({
  106. titleKey,
  107. msgKey,
  108. leftButtonKey: "dialog.Yes",
  109. submitFunction: function (evt, yes) {
  110. if (yes) {
  111. emitter.emit(UIEvents.LOGOUT);
  112. }
  113. }
  114. });
  115. },
  116. "toolbar_film_strip": function () {
  117. JitsiMeetJS.analytics.sendEvent(
  118. 'toolbar.filmstrip.toggled');
  119. emitter.emit(UIEvents.TOGGLE_FILM_STRIP);
  120. },
  121. "toolbar_button_raisehand": function () {
  122. JitsiMeetJS.analytics.sendEvent(
  123. 'toolbar.raiseHand.clicked');
  124. APP.conference.maybeToggleRaisedHand();
  125. }
  126. };
  127. /**
  128. * All toolbars buttons description
  129. */
  130. const defaultToolbarButtons = {
  131. 'microphone': {
  132. id: 'toolbar_button_mute',
  133. tooltipKey: 'toolbar.mute',
  134. className: "button icon-microphone",
  135. shortcut: 'M',
  136. shortcutAttr: 'mutePopover',
  137. shortcutFunc: function() {
  138. JitsiMeetJS.analytics.sendEvent('shortcut.audiomute.toggled');
  139. APP.conference.toggleAudioMuted();
  140. },
  141. shortcutDescription: "keyboardShortcuts.mute",
  142. popups: [
  143. {
  144. id: "micMutedPopup",
  145. className: "loginmenu",
  146. dataAttr: "[html]toolbar.micMutedPopup"
  147. },
  148. {
  149. id: "unableToUnmutePopup",
  150. className: "loginmenu",
  151. dataAttr: "[html]toolbar.unableToUnmutePopup"
  152. },
  153. {
  154. id: "talkWhileMutedPopup",
  155. className: "loginmenu",
  156. dataAttr: "[html]toolbar.talkWhileMutedPopup"
  157. }
  158. ],
  159. content: "Mute / Unmute",
  160. i18n: "[content]toolbar.mute"
  161. },
  162. 'camera': {
  163. id: 'toolbar_button_camera',
  164. tooltipKey: 'toolbar.videomute',
  165. className: "button icon-camera",
  166. shortcut: 'V',
  167. shortcutAttr: 'toggleVideoPopover',
  168. shortcutFunc: function() {
  169. JitsiMeetJS.analytics.sendEvent('shortcut.videomute.toggled');
  170. APP.conference.toggleVideoMuted();
  171. },
  172. shortcutDescription: "keyboardShortcuts.videoMute",
  173. content: "Start / stop camera",
  174. i18n: "[content]toolbar.videomute"
  175. },
  176. 'desktop': {
  177. id: 'toolbar_button_desktopsharing',
  178. tooltipKey: 'toolbar.sharescreen',
  179. className: 'button icon-share-desktop',
  180. shortcut: 'D',
  181. shortcutAttr: 'toggleDesktopSharingPopover',
  182. shortcutFunc: function() {
  183. JitsiMeetJS.analytics.sendEvent('shortcut.screen.toggled');
  184. APP.conference.toggleScreenSharing();
  185. },
  186. shortcutDescription: 'keyboardShortcuts.toggleScreensharing',
  187. content: 'Share screen',
  188. i18n: '[content]toolbar.sharescreen'
  189. },
  190. 'invite': {
  191. id: 'toolbar_button_link',
  192. tooltipKey: 'toolbar.invite',
  193. className: 'button icon-link',
  194. content: 'Invite others',
  195. i18n: '[content]toolbar.invite'
  196. },
  197. 'chat': {
  198. id: 'toolbar_button_chat',
  199. tooltipKey: 'toolbar.chat',
  200. className: 'button icon-chat',
  201. shortcut: 'C',
  202. shortcutAttr: 'toggleChatPopover',
  203. shortcutFunc: function() {
  204. JitsiMeetJS.analytics.sendEvent('shortcut.chat.toggled');
  205. APP.UI.toggleChat();
  206. },
  207. shortcutDescription: 'keyboardShortcuts.toggleChat',
  208. sideContainerId: 'chat_container',
  209. html: `<span class="badge-round">
  210. <span id="unreadMessages"></span>
  211. </span>`
  212. },
  213. 'contacts': {
  214. id: 'toolbar_contact_list',
  215. tooltipKey: 'bottomtoolbar.contactlist',
  216. className: 'button icon-contactList',
  217. sideContainerId: 'contacts_container',
  218. html: `<span class="badge-round">
  219. <span id="numberOfParticipants"></span>
  220. </span>`
  221. },
  222. 'profile': {
  223. id: 'toolbar_button_profile',
  224. tooltipKey: 'profile.setDisplayNameLabel',
  225. className: 'button',
  226. sideContainerId: 'profile_container',
  227. html: `<img id="avatar" src="images/avatar2.png"/>`
  228. },
  229. 'etherpad': {
  230. id: 'toolbar_button_etherpad',
  231. tooltipKey: 'toolbar.etherpad',
  232. className: 'button icon-share-doc'
  233. },
  234. 'fullscreen': {
  235. id: 'toolbar_button_fullScreen',
  236. tooltipKey: 'toolbar.fullscreen',
  237. className: "button icon-full-screen",
  238. shortcut: 'S',
  239. shortcutAttr: 'toggleFullscreenPopover',
  240. shortcutFunc: function() {
  241. JitsiMeetJS.analytics.sendEvent('shortcut.fullscreen.toggled');
  242. APP.UI.toggleFullScreen();
  243. },
  244. shortcutDescription: "keyboardShortcuts.fullScreen",
  245. content: "Enter / Exit Full Screen",
  246. i18n: "[content]toolbar.fullscreen"
  247. },
  248. 'settings': {
  249. id: 'toolbar_button_settings',
  250. tooltipKey: 'toolbar.Settings',
  251. className: 'button icon-settings',
  252. sideContainerId: "settings_container"
  253. },
  254. 'hangup': {
  255. id: 'toolbar_button_hangup',
  256. tooltipKey: 'toolbar.hangup',
  257. className: "button icon-hangup",
  258. content: "Hang Up",
  259. i18n: "[content]toolbar.hangup"
  260. },
  261. 'filmstrip': {
  262. id: 'toolbar_film_strip',
  263. tooltipKey: 'toolbar.filmstrip',
  264. className: "button icon-toggle-filmstrip",
  265. shortcut: "F",
  266. shortcutAttr: "filmstripPopover",
  267. shortcutFunc: function() {
  268. JitsiMeetJS.analytics.sendEvent("shortcut.film.toggled");
  269. APP.UI.toggleFilmStrip();
  270. },
  271. shortcutDescription: "keyboardShortcuts.toggleFilmstrip"
  272. },
  273. 'raisehand': {
  274. id: "toolbar_button_raisehand",
  275. tooltipKey: 'toolbar.raiseHand',
  276. className: "button icon-raised-hand",
  277. shortcut: "R",
  278. shortcutAttr: "raiseHandPopover",
  279. shortcutFunc: function() {
  280. JitsiMeetJS.analytics.sendEvent("shortcut.raisehand.clicked");
  281. APP.conference.maybeToggleRaisedHand();
  282. },
  283. shortcutDescription: "keyboardShortcuts.raiseHand",
  284. content: "Raise Hand",
  285. i18n: "[content]toolbar.raiseHand"
  286. },
  287. //init and btn handler: Recording.initRecordingButton (Recording.js)
  288. 'recording': {
  289. id: 'toolbar_button_record',
  290. tooltipKey: 'liveStreaming.buttonTooltip',
  291. className: 'button'
  292. },
  293. 'sharedvideo': {
  294. id: 'toolbar_button_sharedvideo',
  295. tooltipKey: 'toolbar.sharedvideo',
  296. className: 'button icon-shared-video',
  297. html: `<ul id="sharedVideoMutedPopup"
  298. class="loginmenu extendedToolbarPopup">
  299. <li data-i18n="[html]toolbar.sharedVideoMutedPopup"></li>
  300. </ul>
  301. `
  302. },
  303. 'sip': {
  304. id: 'toolbar_button_sip',
  305. tooltipKey: 'toolbar.sip',
  306. className: 'button icon-telephone'
  307. },
  308. 'dialpad': {
  309. id: 'toolbar_button_dialpad',
  310. tooltipKey: 'toolbar.dialpad',
  311. className: 'button icon-dialpad',
  312. //TODO: remove it after UI.updateDTMFSupport fix
  313. hidden: true
  314. }
  315. };
  316. function dialpadButtonClicked() {
  317. //TODO show the dialpad box
  318. }
  319. function showSipNumberInput () {
  320. let defaultNumber = config.defaultSipNumber
  321. ? config.defaultSipNumber
  322. : '';
  323. let titleKey = "dialog.sipMsg";
  324. let msgString = (`
  325. <input name="sipNumber" type="text"
  326. value="${defaultNumber}" autofocus>`);
  327. APP.UI.messageHandler.openTwoButtonDialog({
  328. titleKey,
  329. msgString,
  330. leftButtonKey: "dialog.Dial",
  331. submitFunction: function (e, v, m, f) {
  332. if (v && f.sipNumber) {
  333. emitter.emit(UIEvents.SIP_DIAL, f.sipNumber);
  334. }
  335. },
  336. focus: ':input:first'
  337. });
  338. }
  339. /**
  340. * Get place for toolbar button.
  341. * Now it can be in main toolbar or in extended (left) toolbar
  342. *
  343. * @param btn {string}
  344. * @returns {string}
  345. */
  346. function getToolbarButtonPlace (btn) {
  347. return interfaceConfig.MAIN_TOOLBAR_BUTTONS.includes(btn) ?
  348. 'main' :
  349. 'extended';
  350. }
  351. Toolbar = {
  352. init (eventEmitter) {
  353. emitter = eventEmitter;
  354. // The toolbar is enabled by default.
  355. this.enabled = true;
  356. this.toolbarSelector = $("#mainToolbarContainer");
  357. this.extendedToolbarSelector = $("#extendedToolbar");
  358. // Initialise the toolbar buttons.
  359. // The main toolbar will only take into account
  360. // it's own configuration from interface_config.
  361. this._initToolbarButtons();
  362. this._setShortcutsAndTooltips();
  363. this._setButtonHandlers();
  364. APP.UI.addListener(UIEvents.SIDE_TOOLBAR_CONTAINER_TOGGLED,
  365. (containerId, isVisible) => {
  366. Toolbar._handleSideToolbarContainerToggled( containerId,
  367. isVisible);
  368. });
  369. APP.UI.addListener(UIEvents.LOCAL_RAISE_HAND_CHANGED,
  370. (isRaisedHand) => {
  371. this._setToggledState("toolbar_button_raisehand", isRaisedHand);
  372. });
  373. APP.UI.addListener(UIEvents.FULLSCREEN_TOGGLED,
  374. (isFullScreen) => {
  375. Toolbar._handleFullScreenToggled(isFullScreen);
  376. });
  377. if(!APP.tokenData.isGuest) {
  378. $("#toolbar_button_profile").addClass("unclickable");
  379. UIUtil.removeTooltip(
  380. document.getElementById('toolbar_button_profile'));
  381. }
  382. },
  383. /**
  384. * Enables / disables the toolbar.
  385. * @param {e} set to {true} to enable the toolbar or {false}
  386. * to disable it
  387. */
  388. enable (e) {
  389. this.enabled = e;
  390. if (!e && this.isVisible())
  391. this.hide(false);
  392. },
  393. /**
  394. * Indicates if the bottom toolbar is currently enabled.
  395. * @return {this.enabled}
  396. */
  397. isEnabled() {
  398. return this.enabled;
  399. },
  400. /**
  401. * Shows or hides authentication button
  402. * @param show <tt>true</tt> to show or <tt>false</tt> to hide
  403. */
  404. showAuthenticateButton (show) {
  405. let display = show ? 'block' : 'none';
  406. $('#authenticationContainer').css({display});
  407. },
  408. showEtherpadButton () {
  409. if (!$('#toolbar_button_etherpad').is(":visible")) {
  410. $('#toolbar_button_etherpad').css({display: 'inline-block'});
  411. }
  412. },
  413. // Shows or hides the 'shared video' button.
  414. showSharedVideoButton () {
  415. let $element = $('#toolbar_button_sharedvideo');
  416. if (UIUtil.isButtonEnabled('sharedvideo')
  417. && config.disableThirdPartyRequests !== true) {
  418. $element.css({display: "inline-block"});
  419. UIUtil.setTooltip($element.get(0), 'toolbar.sharedvideo', 'right');
  420. } else {
  421. $('#toolbar_button_sharedvideo').css({display: "none"});
  422. }
  423. },
  424. // checks whether desktop sharing is enabled and whether
  425. // we have params to start automatically sharing
  426. checkAutoEnableDesktopSharing () {
  427. if (UIUtil.isButtonEnabled('desktop')
  428. && config.autoEnableDesktopSharing) {
  429. emitter.emit(UIEvents.TOGGLE_SCREENSHARING);
  430. }
  431. },
  432. // Shows or hides SIP calls button
  433. showSipCallButton (show) {
  434. if (APP.conference.sipGatewayEnabled()
  435. && UIUtil.isButtonEnabled('sip') && show) {
  436. $('#toolbar_button_sip').css({display: "inline-block"});
  437. } else {
  438. $('#toolbar_button_sip').css({display: "none"});
  439. }
  440. },
  441. // Shows or hides the dialpad button
  442. showDialPadButton (show) {
  443. if (UIUtil.isButtonEnabled('dialpad') && show) {
  444. $('#toolbar_button_dialpad').css({display: "inline-block"});
  445. } else {
  446. $('#toolbar_button_dialpad').css({display: "none"});
  447. }
  448. },
  449. /**
  450. * Displays user authenticated identity name(login).
  451. * @param authIdentity identity name to be displayed.
  452. */
  453. setAuthenticatedIdentity (authIdentity) {
  454. let selector = $('#toolbar_auth_identity');
  455. if (authIdentity) {
  456. selector.css({display: "list-item"});
  457. selector.text(authIdentity);
  458. } else {
  459. selector.css({display: "none"});
  460. selector.text('');
  461. }
  462. },
  463. /**
  464. * Shows/hides login button.
  465. * @param show <tt>true</tt> to show
  466. */
  467. showLoginButton (show) {
  468. if (show) {
  469. $('#toolbar_button_login').css({display: "list-item"});
  470. } else {
  471. $('#toolbar_button_login').css({display: "none"});
  472. }
  473. },
  474. /**
  475. * Shows/hides logout button.
  476. * @param show <tt>true</tt> to show
  477. */
  478. showLogoutButton (show) {
  479. if (show) {
  480. $('#toolbar_button_logout').css({display: "list-item"});
  481. } else {
  482. $('#toolbar_button_logout').css({display: "none"});
  483. }
  484. },
  485. /**
  486. * Update the state of the button. The button has blue glow if desktop
  487. * streaming is active.
  488. */
  489. updateDesktopSharingButtonState () {
  490. this._setToggledState( "toolbar_button_desktopsharing",
  491. APP.conference.isSharingScreen);
  492. },
  493. /**
  494. * Marks video icon as muted or not.
  495. *
  496. * @param {boolean} muted if icon should look like muted or not
  497. */
  498. toggleVideoIcon (muted) {
  499. $('#toolbar_button_camera').toggleClass("icon-camera-disabled", muted);
  500. this._setToggledState("toolbar_button_camera", muted);
  501. },
  502. /**
  503. * Enables / disables audio toolbar button.
  504. *
  505. * @param {boolean} enabled indicates if the button should be enabled
  506. * or disabled
  507. */
  508. setVideoIconEnabled (enabled) {
  509. this._setMediaIconEnabled(
  510. '#toolbar_button_camera',
  511. enabled,
  512. /* data-i18n attribute value */
  513. `[content]toolbar.${enabled ? 'videomute' : 'cameraDisabled'}`,
  514. /* shortcut attribute value */
  515. 'toggleVideoPopover');
  516. enabled || this.toggleVideoIcon(!enabled);
  517. },
  518. /**
  519. * Enables/disables the toolbar button associated with a specific media such
  520. * as audio or video.
  521. *
  522. * @param {string} btn - The jQuery selector <tt>string</tt> which
  523. * identifies the toolbar button to be enabled/disabled.
  524. * @param {boolean} enabled - <tt>true</tt> to enable the specified
  525. * <tt>btn</tt> or <tt>false</tt> to disable it.
  526. * @param {string} dataI18n - The value to assign to the <tt>data-i18n</tt>
  527. * attribute of the specified <tt>btn</tt>.
  528. * @param {string} shortcut - The value, if any, to assign to the
  529. * <tt>shortcut</tt> attribute of the specified <tt>btn</tt> if the toolbar
  530. * button is enabled.
  531. */
  532. _setMediaIconEnabled(btn, enabled, dataI18n, shortcut) {
  533. const $btn = $(btn);
  534. $btn
  535. .prop('disabled', !enabled)
  536. .attr('data-i18n', dataI18n)
  537. .attr('shortcut', enabled && shortcut ? shortcut : '');
  538. enabled
  539. ? $btn.removeAttr('disabled')
  540. : $btn.attr('disabled', 'disabled');
  541. APP.translation.translateElement($btn);
  542. },
  543. /**
  544. * Marks audio icon as muted or not.
  545. *
  546. * @param {boolean} muted if icon should look like muted or not
  547. */
  548. toggleAudioIcon(muted) {
  549. $('#toolbar_button_mute')
  550. .toggleClass("icon-microphone", !muted)
  551. .toggleClass("icon-mic-disabled", muted);
  552. this._setToggledState("toolbar_button_mute", muted);
  553. },
  554. /**
  555. * Enables / disables audio toolbar button.
  556. *
  557. * @param {boolean} enabled indicates if the button should be enabled
  558. * or disabled
  559. */
  560. setAudioIconEnabled (enabled) {
  561. this._setMediaIconEnabled(
  562. '#toolbar_button_mute',
  563. enabled,
  564. /* data-i18n attribute value */
  565. `[content]toolbar.${enabled ? 'mute' : 'micDisabled'}`,
  566. /* shortcut attribute value */
  567. 'mutePopover');
  568. enabled || this.toggleAudioIcon(!enabled);
  569. },
  570. /**
  571. * Indicates if the toolbar is currently hovered.
  572. * @return {boolean} true if the toolbar is currently hovered,
  573. * false otherwise
  574. */
  575. isHovered() {
  576. var hovered = false;
  577. this.toolbarSelector.find('*').each(function () {
  578. let id = $(this).attr('id');
  579. if ($(`#${id}:hover`).length > 0) {
  580. hovered = true;
  581. // break each
  582. return false;
  583. }
  584. });
  585. if (hovered)
  586. return true;
  587. if ($("#bottomToolbar:hover").length > 0
  588. || $("#extendedToolbar:hover").length > 0
  589. || SideContainerToggler.isHovered()) {
  590. return true;
  591. }
  592. return false;
  593. },
  594. /**
  595. * Returns true if this toolbar is currently visible, or false otherwise.
  596. * @return <tt>true</tt> if currently visible, <tt>false</tt> - otherwise
  597. */
  598. isVisible() {
  599. return this.toolbarSelector.hasClass("fadeIn");
  600. },
  601. /**
  602. * Hides the toolbar with animation or not depending on the animate
  603. * parameter.
  604. */
  605. hide() {
  606. this.toolbarSelector
  607. .removeClass("fadeIn")
  608. .addClass("fadeOut");
  609. let slideInAnimation = (SideContainerToggler.isVisible)
  610. ? "slideInExtX"
  611. : "slideInX";
  612. let slideOutAnimation = (SideContainerToggler.isVisible)
  613. ? "slideOutExtX"
  614. : "slideOutX";
  615. this.extendedToolbarSelector.toggleClass(slideInAnimation)
  616. .toggleClass(slideOutAnimation);
  617. },
  618. /**
  619. * Shows the toolbar with animation or not depending on the animate
  620. * parameter.
  621. */
  622. show() {
  623. if (this.toolbarSelector.hasClass("fadeOut")) {
  624. this.toolbarSelector.removeClass("fadeOut");
  625. }
  626. let slideInAnimation = (SideContainerToggler.isVisible)
  627. ? "slideInExtX"
  628. : "slideInX";
  629. let slideOutAnimation = (SideContainerToggler.isVisible)
  630. ? "slideOutExtX"
  631. : "slideOutX";
  632. if (this.extendedToolbarSelector.hasClass(slideOutAnimation)) {
  633. this.extendedToolbarSelector.toggleClass(slideOutAnimation);
  634. }
  635. this.toolbarSelector.addClass("fadeIn");
  636. this.extendedToolbarSelector.toggleClass(slideInAnimation);
  637. },
  638. registerClickListeners(listener) {
  639. $('#mainToolbarContainer').click(listener);
  640. $("#extendedToolbar").click(listener);
  641. },
  642. /**
  643. * Handles the side toolbar toggle.
  644. *
  645. * @param {string} containerId the identifier of the container element
  646. */
  647. _handleSideToolbarContainerToggled(containerId) {
  648. Object.keys(defaultToolbarButtons).forEach(
  649. id => {
  650. if (!UIUtil.isButtonEnabled(id))
  651. return;
  652. var button = defaultToolbarButtons[id];
  653. if (button.sideContainerId
  654. && button.sideContainerId === containerId) {
  655. UIUtil.buttonClick(button.id, "selected");
  656. return;
  657. }
  658. }
  659. );
  660. },
  661. /**
  662. * Handles full screen toggled.
  663. *
  664. * @param {boolean} isFullScreen indicates if we're currently in full
  665. * screen mode
  666. */
  667. _handleFullScreenToggled(isFullScreen) {
  668. let element
  669. = document.getElementById("toolbar_button_fullScreen");
  670. element.className = isFullScreen
  671. ? element.className
  672. .replace("icon-full-screen", "icon-exit-full-screen")
  673. : element.className
  674. .replace("icon-exit-full-screen", "icon-full-screen");
  675. Toolbar._setToggledState("toolbar_button_fullScreen", isFullScreen);
  676. },
  677. /**
  678. * Initialise toolbar buttons.
  679. */
  680. _initToolbarButtons() {
  681. interfaceConfig.TOOLBAR_BUTTONS.forEach((value, index) => {
  682. let place = getToolbarButtonPlace(value);
  683. if (value && value in defaultToolbarButtons) {
  684. let button = defaultToolbarButtons[value];
  685. this._addToolbarButton(
  686. button,
  687. place,
  688. (interfaceConfig.MAIN_TOOLBAR_SPLITTER_INDEX !== undefined
  689. && index
  690. === interfaceConfig.MAIN_TOOLBAR_SPLITTER_INDEX));
  691. }
  692. });
  693. },
  694. /**
  695. * Adds the given button to the main (top) or extended (left) toolbar.
  696. *
  697. * @param {Object} the button to add.
  698. * @param {boolean} isFirst indicates if this is the first button in the
  699. * toolbar
  700. * @param {boolean} isLast indicates if this is the last button in the
  701. * toolbar
  702. * @param {boolean} isSplitter if this button is a splitter button for
  703. * the dialog, which means that a special splitter style will be applied
  704. */
  705. _addToolbarButton(button, place, isSplitter) {
  706. const places = {
  707. main: 'mainToolbar',
  708. extended: 'extendedToolbarButtons'
  709. };
  710. let id = places[place];
  711. let buttonElement = document.createElement("a");
  712. if (button.className)
  713. buttonElement.className = button.className
  714. + ((isSplitter) ? " splitter": "");
  715. buttonElement.id = button.id;
  716. if (button.html)
  717. buttonElement.innerHTML = button.html;
  718. //TODO: remove it after UI.updateDTMFSupport fix
  719. if (button.hidden)
  720. buttonElement.style.display = 'none';
  721. if (button.shortcutAttr)
  722. buttonElement.setAttribute("shortcut", button.shortcutAttr);
  723. if (button.content)
  724. buttonElement.setAttribute("content", button.content);
  725. if (button.i18n)
  726. buttonElement.setAttribute("data-i18n", button.i18n);
  727. buttonElement.setAttribute("data-container", "body");
  728. buttonElement.setAttribute("data-placement", "bottom");
  729. this._addPopups(buttonElement, button.popups);
  730. document.getElementById(id)
  731. .appendChild(buttonElement);
  732. },
  733. _addPopups(buttonElement, popups = []) {
  734. popups.forEach((popup) => {
  735. let popupElement = document.createElement("ul");
  736. popupElement.id = popup.id;
  737. popupElement.className = popup.className;
  738. let liElement = document.createElement("li");
  739. liElement.setAttribute("data-i18n", popup.dataAttr);
  740. popupElement.appendChild(liElement);
  741. buttonElement.appendChild(popupElement);
  742. });
  743. },
  744. /**
  745. * Sets the toggled state of the given element depending on the isToggled
  746. * parameter.
  747. *
  748. * @param elementId the element identifier
  749. * @param isToggled indicates if the element should be toggled or untoggled
  750. */
  751. _setToggledState(elementId, isToggled) {
  752. $("#" + elementId).toggleClass("toggled", isToggled);
  753. },
  754. /**
  755. * Sets Shortcuts and Tooltips for all toolbar buttons
  756. *
  757. * @private
  758. */
  759. _setShortcutsAndTooltips() {
  760. Object.keys(defaultToolbarButtons).forEach(
  761. id => {
  762. if (UIUtil.isButtonEnabled(id)) {
  763. let button = defaultToolbarButtons[id];
  764. let buttonElement = document.getElementById(button.id);
  765. if (!buttonElement) return false;
  766. let tooltipPosition
  767. = (interfaceConfig.MAIN_TOOLBAR_BUTTONS
  768. .indexOf(id) > -1)
  769. ? "bottom" : "right";
  770. UIUtil.setTooltip( buttonElement,
  771. button.tooltipKey,
  772. tooltipPosition);
  773. if (button.shortcut)
  774. APP.keyboardshortcut.registerShortcut(
  775. button.shortcut,
  776. button.shortcutAttr,
  777. button.shortcutFunc,
  778. button.shortcutDescription
  779. );
  780. }
  781. }
  782. );
  783. },
  784. /**
  785. * Sets Handlers for all toolbar buttons
  786. *
  787. * @private
  788. */
  789. _setButtonHandlers() {
  790. Object.keys(buttonHandlers).forEach(
  791. buttonId => $(`#${buttonId}`).click(function(event) {
  792. !$(this).prop('disabled') && buttonHandlers[buttonId](event);
  793. })
  794. );
  795. }
  796. };
  797. export default Toolbar;