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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873
  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 class="input-control"
  308. name="sipNumber" type="text"
  309. value="${defaultNumber}" autofocus>`);
  310. APP.UI.messageHandler.openTwoButtonDialog({
  311. titleKey,
  312. msgString,
  313. leftButtonKey: "dialog.Dial",
  314. submitFunction: function (e, v, m, f) {
  315. if (v && f.sipNumber) {
  316. emitter.emit(UIEvents.SIP_DIAL, f.sipNumber);
  317. }
  318. },
  319. focus: ':input:first'
  320. });
  321. }
  322. /**
  323. * Get place for toolbar button.
  324. * Now it can be in main toolbar or in extended (left) toolbar
  325. *
  326. * @param btn {string}
  327. * @returns {string}
  328. */
  329. function getToolbarButtonPlace (btn) {
  330. return interfaceConfig.MAIN_TOOLBAR_BUTTONS.includes(btn) ?
  331. 'main' :
  332. 'extended';
  333. }
  334. Toolbar = {
  335. init (eventEmitter) {
  336. emitter = eventEmitter;
  337. // The toolbar is enabled by default.
  338. this.enabled = true;
  339. this.toolbarSelector = $("#mainToolbarContainer");
  340. this.extendedToolbarSelector = $("#extendedToolbar");
  341. // Initialise the toolbar buttons.
  342. // The main toolbar will only take into account
  343. // it's own configuration from interface_config.
  344. this._initToolbarButtons();
  345. this._setShortcutsAndTooltips();
  346. this._setButtonHandlers();
  347. APP.UI.addListener(UIEvents.SIDE_TOOLBAR_CONTAINER_TOGGLED,
  348. (containerId, isVisible) => {
  349. Toolbar._handleSideToolbarContainerToggled( containerId,
  350. isVisible);
  351. });
  352. APP.UI.addListener(UIEvents.LOCAL_RAISE_HAND_CHANGED,
  353. (isRaisedHand) => {
  354. this._setToggledState("toolbar_button_raisehand", isRaisedHand);
  355. });
  356. APP.UI.addListener(UIEvents.FULLSCREEN_TOGGLED,
  357. (isFullScreen) => {
  358. Toolbar._handleFullScreenToggled(isFullScreen);
  359. });
  360. if(!APP.tokenData.isGuest) {
  361. $("#toolbar_button_profile").addClass("unclickable");
  362. UIUtil.removeTooltip(
  363. document.getElementById('toolbar_button_profile'));
  364. }
  365. },
  366. /**
  367. * Enables / disables the toolbar.
  368. * @param {e} set to {true} to enable the toolbar or {false}
  369. * to disable it
  370. */
  371. enable (e) {
  372. this.enabled = e;
  373. if (!e && this.isVisible())
  374. this.hide(false);
  375. },
  376. /**
  377. * Indicates if the bottom toolbar is currently enabled.
  378. * @return {this.enabled}
  379. */
  380. isEnabled() {
  381. return this.enabled;
  382. },
  383. /**
  384. * Shows or hides authentication button
  385. * @param show <tt>true</tt> to show or <tt>false</tt> to hide
  386. */
  387. showAuthenticateButton (show) {
  388. let id = 'authenticationContainer';
  389. if (show) {
  390. UIUtil.showElement(id);
  391. } else {
  392. UIUtil.hideElement(id);
  393. }
  394. },
  395. showEtherpadButton () {
  396. if (!$('#toolbar_button_etherpad').is(":visible")) {
  397. $('#toolbar_button_etherpad').css({display: 'inline-block'});
  398. }
  399. },
  400. // Shows or hides the 'shared video' button.
  401. showSharedVideoButton () {
  402. let id = 'toolbar_button_sharedvideo';
  403. let shouldShow = UIUtil.isButtonEnabled('sharedvideo')
  404. && !config.disableThirdPartyRequests;
  405. if (shouldShow) {
  406. let el = document.getElementById(id);
  407. UIUtil.setTooltip(el, 'toolbar.sharedvideo', 'right');
  408. UIUtil.showElement(id);
  409. } else {
  410. UIUtil.hideElement(id);
  411. }
  412. },
  413. // checks whether desktop sharing is enabled and whether
  414. // we have params to start automatically sharing
  415. checkAutoEnableDesktopSharing () {
  416. if (UIUtil.isButtonEnabled('desktop')
  417. && config.autoEnableDesktopSharing) {
  418. emitter.emit(UIEvents.TOGGLE_SCREENSHARING);
  419. }
  420. },
  421. // Shows or hides SIP calls button
  422. showSipCallButton (show) {
  423. let shouldShow = APP.conference.sipGatewayEnabled()
  424. && UIUtil.isButtonEnabled('sip') && show;
  425. let id = 'toolbar_button_sip';
  426. if (shouldShow) {
  427. UIUtil.showElement(id);
  428. } else {
  429. UIUtil.hideElement(id);
  430. }
  431. },
  432. // Shows or hides the dialpad button
  433. showDialPadButton (show) {
  434. let shouldShow = UIUtil.isButtonEnabled('dialpad') && show;
  435. let id = 'toolbar_button_dialpad';
  436. if (shouldShow) {
  437. UIUtil.showElement(id);
  438. } else {
  439. UIUtil.hideElement(id);
  440. }
  441. },
  442. /**
  443. * Displays user authenticated identity name(login).
  444. * @param authIdentity identity name to be displayed.
  445. */
  446. setAuthenticatedIdentity (authIdentity) {
  447. let id = 'toolbar_auth_identity';
  448. if(authIdentity) {
  449. UIUtil.showElement(id);
  450. $(`#${id}`).text(authIdentity);
  451. } else {
  452. UIUtil.hideElement(id);
  453. $(`#${id}`).text('');
  454. }
  455. },
  456. /**
  457. * Shows/hides login button.
  458. * @param show <tt>true</tt> to show
  459. */
  460. showLoginButton (show) {
  461. let id = 'toolbar_button_login';
  462. if (show) {
  463. UIUtil.showElement(id);
  464. } else {
  465. UIUtil.hideElement(id);
  466. }
  467. },
  468. /**
  469. * Shows/hides logout button.
  470. * @param show <tt>true</tt> to show
  471. */
  472. showLogoutButton (show) {
  473. let id = 'toolbar_button_logout';
  474. if (show) {
  475. UIUtil.showElement(id);
  476. } else {
  477. UIUtil.hideElement(id);
  478. }
  479. },
  480. /**
  481. * Update the state of the button. The button has blue glow if desktop
  482. * streaming is active.
  483. */
  484. updateDesktopSharingButtonState () {
  485. this._setToggledState( "toolbar_button_desktopsharing",
  486. APP.conference.isSharingScreen);
  487. },
  488. /**
  489. * Marks video icon as muted or not.
  490. *
  491. * @param {boolean} muted if icon should look like muted or not
  492. */
  493. toggleVideoIcon (muted) {
  494. $('#toolbar_button_camera').toggleClass("icon-camera-disabled", muted);
  495. this._setToggledState("toolbar_button_camera", muted);
  496. },
  497. /**
  498. * Enables / disables audio toolbar button.
  499. *
  500. * @param {boolean} enabled indicates if the button should be enabled
  501. * or disabled
  502. */
  503. setVideoIconEnabled (enabled) {
  504. this._setMediaIconEnabled(
  505. '#toolbar_button_camera',
  506. enabled,
  507. /* data-i18n attribute value */
  508. `[content]toolbar.${enabled ? 'videomute' : 'cameraDisabled'}`,
  509. /* shortcut attribute value */
  510. 'toggleVideoPopover');
  511. enabled || this.toggleVideoIcon(!enabled);
  512. },
  513. /**
  514. * Enables/disables the toolbar button associated with a specific media such
  515. * as audio or video.
  516. *
  517. * @param {string} btn - The jQuery selector <tt>string</tt> which
  518. * identifies the toolbar button to be enabled/disabled.
  519. * @param {boolean} enabled - <tt>true</tt> to enable the specified
  520. * <tt>btn</tt> or <tt>false</tt> to disable it.
  521. * @param {string} dataI18n - The value to assign to the <tt>data-i18n</tt>
  522. * attribute of the specified <tt>btn</tt>.
  523. * @param {string} shortcut - The value, if any, to assign to the
  524. * <tt>shortcut</tt> attribute of the specified <tt>btn</tt> if the toolbar
  525. * button is enabled.
  526. */
  527. _setMediaIconEnabled(btn, enabled, dataI18n, shortcut) {
  528. const $btn = $(btn);
  529. $btn
  530. .prop('disabled', !enabled)
  531. .attr('data-i18n', dataI18n)
  532. .attr('shortcut', enabled && shortcut ? shortcut : '');
  533. enabled
  534. ? $btn.removeAttr('disabled')
  535. : $btn.attr('disabled', 'disabled');
  536. APP.translation.translateElement($btn);
  537. },
  538. /**
  539. * Marks audio icon as muted or not.
  540. *
  541. * @param {boolean} muted if icon should look like muted or not
  542. */
  543. toggleAudioIcon(muted) {
  544. $('#toolbar_button_mute')
  545. .toggleClass("icon-microphone", !muted)
  546. .toggleClass("icon-mic-disabled", muted);
  547. this._setToggledState("toolbar_button_mute", muted);
  548. },
  549. /**
  550. * Enables / disables audio toolbar button.
  551. *
  552. * @param {boolean} enabled indicates if the button should be enabled
  553. * or disabled
  554. */
  555. setAudioIconEnabled (enabled) {
  556. this._setMediaIconEnabled(
  557. '#toolbar_button_mute',
  558. enabled,
  559. /* data-i18n attribute value */
  560. `[content]toolbar.${enabled ? 'mute' : 'micDisabled'}`,
  561. /* shortcut attribute value */
  562. 'mutePopover');
  563. enabled || this.toggleAudioIcon(!enabled);
  564. },
  565. /**
  566. * Indicates if the toolbar is currently hovered.
  567. * @return {boolean} true if the toolbar is currently hovered,
  568. * false otherwise
  569. */
  570. isHovered() {
  571. var hovered = false;
  572. this.toolbarSelector.find('*').each(function () {
  573. let id = $(this).attr('id');
  574. if ($(`#${id}:hover`).length > 0) {
  575. hovered = true;
  576. // break each
  577. return false;
  578. }
  579. });
  580. if (hovered)
  581. return true;
  582. if ($("#bottomToolbar:hover").length > 0
  583. || $("#extendedToolbar:hover").length > 0
  584. || SideContainerToggler.isHovered()) {
  585. return true;
  586. }
  587. return false;
  588. },
  589. /**
  590. * Returns true if this toolbar is currently visible, or false otherwise.
  591. * @return <tt>true</tt> if currently visible, <tt>false</tt> - otherwise
  592. */
  593. isVisible() {
  594. return this.toolbarSelector.hasClass("fadeIn");
  595. },
  596. /**
  597. * Hides the toolbar with animation or not depending on the animate
  598. * parameter.
  599. */
  600. hide() {
  601. this.toolbarSelector
  602. .removeClass("fadeIn")
  603. .addClass("fadeOut");
  604. let slideInAnimation = (SideContainerToggler.isVisible)
  605. ? "slideInExtX"
  606. : "slideInX";
  607. let slideOutAnimation = (SideContainerToggler.isVisible)
  608. ? "slideOutExtX"
  609. : "slideOutX";
  610. this.extendedToolbarSelector.toggleClass(slideInAnimation)
  611. .toggleClass(slideOutAnimation);
  612. },
  613. /**
  614. * Shows the toolbar with animation or not depending on the animate
  615. * parameter.
  616. */
  617. show() {
  618. if (this.toolbarSelector.hasClass("fadeOut")) {
  619. this.toolbarSelector.removeClass("fadeOut");
  620. }
  621. let slideInAnimation = (SideContainerToggler.isVisible)
  622. ? "slideInExtX"
  623. : "slideInX";
  624. let slideOutAnimation = (SideContainerToggler.isVisible)
  625. ? "slideOutExtX"
  626. : "slideOutX";
  627. if (this.extendedToolbarSelector.hasClass(slideOutAnimation)) {
  628. this.extendedToolbarSelector.toggleClass(slideOutAnimation);
  629. }
  630. this.toolbarSelector.addClass("fadeIn");
  631. this.extendedToolbarSelector.toggleClass(slideInAnimation);
  632. },
  633. registerClickListeners(listener) {
  634. $('#mainToolbarContainer').click(listener);
  635. $("#extendedToolbar").click(listener);
  636. },
  637. /**
  638. * Handles the side toolbar toggle.
  639. *
  640. * @param {string} containerId the identifier of the container element
  641. */
  642. _handleSideToolbarContainerToggled(containerId) {
  643. Object.keys(defaultToolbarButtons).forEach(
  644. id => {
  645. if (!UIUtil.isButtonEnabled(id))
  646. return;
  647. var button = defaultToolbarButtons[id];
  648. if (button.sideContainerId
  649. && button.sideContainerId === containerId) {
  650. UIUtil.buttonClick(button.id, "selected");
  651. return;
  652. }
  653. }
  654. );
  655. },
  656. /**
  657. * Handles full screen toggled.
  658. *
  659. * @param {boolean} isFullScreen indicates if we're currently in full
  660. * screen mode
  661. */
  662. _handleFullScreenToggled(isFullScreen) {
  663. let element
  664. = document.getElementById("toolbar_button_fullScreen");
  665. element.className = isFullScreen
  666. ? element.className
  667. .replace("icon-full-screen", "icon-exit-full-screen")
  668. : element.className
  669. .replace("icon-exit-full-screen", "icon-full-screen");
  670. Toolbar._setToggledState("toolbar_button_fullScreen", isFullScreen);
  671. },
  672. /**
  673. * Initialise toolbar buttons.
  674. */
  675. _initToolbarButtons() {
  676. interfaceConfig.TOOLBAR_BUTTONS.forEach((value, index) => {
  677. let place = getToolbarButtonPlace(value);
  678. if (value && value in defaultToolbarButtons) {
  679. let button = defaultToolbarButtons[value];
  680. this._addToolbarButton(
  681. button,
  682. place,
  683. (interfaceConfig.MAIN_TOOLBAR_SPLITTER_INDEX !== undefined
  684. && index
  685. === interfaceConfig.MAIN_TOOLBAR_SPLITTER_INDEX));
  686. }
  687. });
  688. },
  689. /**
  690. * Adds the given button to the main (top) or extended (left) toolbar.
  691. *
  692. * @param {Object} the button to add.
  693. * @param {boolean} isFirst indicates if this is the first button in the
  694. * toolbar
  695. * @param {boolean} isLast indicates if this is the last button in the
  696. * toolbar
  697. * @param {boolean} isSplitter if this button is a splitter button for
  698. * the dialog, which means that a special splitter style will be applied
  699. */
  700. _addToolbarButton(button, place, isSplitter) {
  701. const places = {
  702. main: 'mainToolbar',
  703. extended: 'extendedToolbarButtons'
  704. };
  705. let id = places[place];
  706. let buttonElement = document.createElement("a");
  707. if (button.className) {
  708. buttonElement.className = button.className;
  709. }
  710. if (isSplitter) {
  711. let splitter = document.createElement('span');
  712. splitter.className = 'toolbar__splitter';
  713. document.getElementById(id).appendChild(splitter);
  714. }
  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;