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 27KB

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