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