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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690
  1. /* global APP, $, buttonClick, config, lockRoom, interfaceConfig, setSharedKey,
  2. Util */
  3. /* jshint -W101 */
  4. var messageHandler = require("../util/MessageHandler");
  5. var BottomToolbar = require("./BottomToolbar");
  6. var Prezi = require("../prezi/Prezi");
  7. var Etherpad = require("../etherpad/Etherpad");
  8. var PanelToggler = require("../side_pannels/SidePanelToggler");
  9. var Authentication = require("../authentication/Authentication");
  10. var UIUtil = require("../util/UIUtil");
  11. var AuthenticationEvents
  12. = require("../../../service/authentication/AuthenticationEvents");
  13. var roomUrl = null;
  14. var sharedKey = '';
  15. var UI = null;
  16. var recordingToaster = null;
  17. var buttonHandlers = {
  18. "toolbar_button_mute": function () {
  19. return APP.UI.toggleAudio();
  20. },
  21. "toolbar_button_camera": function () {
  22. return APP.UI.toggleVideo();
  23. },
  24. /*"toolbar_button_authentication": function () {
  25. return Toolbar.authenticateClicked();
  26. },*/
  27. "toolbar_button_record": function () {
  28. return toggleRecording();
  29. },
  30. "toolbar_button_security": function () {
  31. return Toolbar.openLockDialog();
  32. },
  33. "toolbar_button_link": function () {
  34. return Toolbar.openLinkDialog();
  35. },
  36. "toolbar_button_chat": function () {
  37. return BottomToolbar.toggleChat();
  38. },
  39. "toolbar_button_prezi": function () {
  40. return Prezi.openPreziDialog();
  41. },
  42. "toolbar_button_etherpad": function () {
  43. return Etherpad.toggleEtherpad(0);
  44. },
  45. "toolbar_button_desktopsharing": function () {
  46. return APP.desktopsharing.toggleScreenSharing();
  47. },
  48. "toolbar_button_fullScreen": function() {
  49. UIUtil.buttonClick("#toolbar_button_fullScreen", "icon-full-screen icon-exit-full-screen");
  50. return Toolbar.toggleFullScreen();
  51. },
  52. "toolbar_button_sip": function () {
  53. return callSipButtonClicked();
  54. },
  55. "toolbar_button_dialpad": function () {
  56. return dialpadButtonClicked();
  57. },
  58. "toolbar_button_settings": function () {
  59. PanelToggler.toggleSettingsMenu();
  60. },
  61. "toolbar_button_hangup": function () {
  62. return hangup();
  63. },
  64. "toolbar_button_login": function () {
  65. Toolbar.authenticateClicked();
  66. },
  67. "toolbar_button_logout": function () {
  68. // Ask for confirmation
  69. messageHandler.openTwoButtonDialog(
  70. "dialog.logoutTitle",
  71. null,
  72. "dialog.logoutQuestion",
  73. null,
  74. false,
  75. "dialog.Yes",
  76. function (evt, yes) {
  77. if (yes) {
  78. APP.xmpp.logout(function (url) {
  79. if (url) {
  80. window.location.href = url;
  81. } else {
  82. hangup();
  83. }
  84. });
  85. }
  86. });
  87. }
  88. };
  89. var defaultToolbarButtons = {
  90. 'microphone': '#toolbar_button_mute',
  91. 'camera': '#toolbar_button_camera',
  92. 'desktop': '#toolbar_button_desktopsharing',
  93. 'security': '#toolbar_button_security',
  94. 'invite': '#toolbar_button_link',
  95. 'chat': '#toolbar_button_chat',
  96. 'prezi': '#toolbar_button_prezi',
  97. 'ethherpad': '#toolbar_button_etherpad',
  98. 'fullscreen': '#toolbar_button_fullScreen',
  99. 'settings': '#toolbar_button_settings',
  100. 'hangup': '#toolbar_button_hangup'
  101. };
  102. function hangup() {
  103. APP.xmpp.disposeConference();
  104. if(config.enableWelcomePage) {
  105. setTimeout(function() {
  106. window.localStorage.welcomePageDisabled = false;
  107. window.location.pathname = "/";
  108. }, 10000);
  109. }
  110. var title = APP.translation.generateTranslationHTML(
  111. "dialog.sessTerminated");
  112. var msg = APP.translation.generateTranslationHTML(
  113. "dialog.hungUp");
  114. var button = APP.translation.generateTranslationHTML(
  115. "dialog.joinAgain");
  116. var buttons = [];
  117. buttons.push({title: button, value: true});
  118. UI.messageHandler.openDialog(
  119. title,
  120. msg,
  121. true,
  122. buttons,
  123. function(event, value, message, formVals) {
  124. window.location.reload();
  125. return false;
  126. }
  127. );
  128. }
  129. /**
  130. * Starts or stops the recording for the conference.
  131. */
  132. function toggleRecording(predefinedToken) {
  133. APP.xmpp.toggleRecording(function (callback) {
  134. if (predefinedToken) {
  135. callback(UIUtil.escapeHtml(predefinedToken));
  136. return;
  137. }
  138. var msg = APP.translation.generateTranslationHTML(
  139. "dialog.recordingToken");
  140. var token = APP.translation.translateString("dialog.token");
  141. APP.UI.messageHandler.openTwoButtonDialog(null, null, null,
  142. '<h2>' + msg + '</h2>' +
  143. '<input name="recordingToken" type="text" ' +
  144. ' data-i18n="[placeholder]dialog.token" ' +
  145. 'placeholder="' + token + '" autofocus>',
  146. false,
  147. "dialog.Save",
  148. function (e, v, m, f) {
  149. if (v) {
  150. var token = f.recordingToken;
  151. if (token) {
  152. callback(UIUtil.escapeHtml(token));
  153. }
  154. }
  155. },
  156. null,
  157. function () { },
  158. ':input:first'
  159. );
  160. }, Toolbar.setRecordingButtonState);
  161. }
  162. /**
  163. * Locks / unlocks the room.
  164. */
  165. function lockRoom(lock) {
  166. var currentSharedKey = '';
  167. if (lock)
  168. currentSharedKey = sharedKey;
  169. APP.xmpp.lockRoom(currentSharedKey, function (res) {
  170. // password is required
  171. if (sharedKey) {
  172. console.log('set room password');
  173. Toolbar.lockLockButton();
  174. }
  175. else {
  176. console.log('removed room password');
  177. Toolbar.unlockLockButton();
  178. }
  179. }, function (err) {
  180. console.warn('setting password failed', err);
  181. messageHandler.showError("dialog.lockTitle",
  182. "dialog.lockMessage");
  183. Toolbar.setSharedKey('');
  184. }, function () {
  185. console.warn('room passwords not supported');
  186. messageHandler.showError("dialog.warning",
  187. "dialog.passwordNotSupported");
  188. Toolbar.setSharedKey('');
  189. });
  190. }
  191. /**
  192. * Invite participants to conference.
  193. */
  194. function inviteParticipants() {
  195. if (roomUrl === null)
  196. return;
  197. var sharedKeyText = "";
  198. if (sharedKey && sharedKey.length > 0) {
  199. sharedKeyText =
  200. APP.translation.translateString("email.sharedKey",
  201. {sharedKey: sharedKey});
  202. sharedKeyText = sharedKeyText.replace(/\n/g, "%0D%0A");
  203. }
  204. var supportedBrowsers = "Chromium, Google Chrome " +
  205. APP.translation.translateString("email.and") + " Opera";
  206. var conferenceName = roomUrl.substring(roomUrl.lastIndexOf('/') + 1);
  207. var subject = APP.translation.translateString("email.subject",
  208. {appName:interfaceConfig.APP_NAME, conferenceName: conferenceName});
  209. var body = APP.translation.translateString("email.body",
  210. {appName:interfaceConfig.APP_NAME, sharedKeyText: sharedKeyText,
  211. roomUrl: roomUrl, supportedBrowsers: supportedBrowsers});
  212. body = body.replace(/\n/g, "%0D%0A");
  213. if (window.localStorage.displayname) {
  214. body += "%0D%0A%0D%0A" + window.localStorage.displayname;
  215. }
  216. if (interfaceConfig.INVITATION_POWERED_BY) {
  217. body += "%0D%0A%0D%0A--%0D%0Apowered by jitsi.org";
  218. }
  219. window.open("mailto:?subject=" + subject + "&body=" + body, '_blank');
  220. }
  221. function dialpadButtonClicked() {
  222. //TODO show the dialpad box
  223. }
  224. function callSipButtonClicked() {
  225. var defaultNumber
  226. = config.defaultSipNumber ? config.defaultSipNumber : '';
  227. var sipMsg = APP.translation.generateTranslationHTML(
  228. "dialog.sipMsg");
  229. messageHandler.openTwoButtonDialog(null, null, null,
  230. '<h2>' + sipMsg + '</h2>' +
  231. '<input name="sipNumber" type="text"' +
  232. ' value="' + defaultNumber + '" autofocus>',
  233. false,
  234. "dialog.Dial",
  235. function (e, v, m, f) {
  236. if (v) {
  237. var numberInput = f.sipNumber;
  238. if (numberInput) {
  239. APP.xmpp.dial(
  240. numberInput, 'fromnumber', UI.getRoomName(), sharedKey);
  241. }
  242. }
  243. },
  244. null, null, ':input:first'
  245. );
  246. }
  247. var Toolbar = (function (my) {
  248. my.init = function (ui) {
  249. UIUtil.hideDisabledButtons(defaultToolbarButtons);
  250. for(var k in buttonHandlers)
  251. $("#" + k).click(buttonHandlers[k]);
  252. UI = ui;
  253. // Update login info
  254. APP.xmpp.addListener(
  255. AuthenticationEvents.IDENTITY_UPDATED,
  256. function (authenticationEnabled, userIdentity) {
  257. var loggedIn = false;
  258. if (userIdentity) {
  259. loggedIn = true;
  260. }
  261. Toolbar.showAuthenticateButton(authenticationEnabled);
  262. if (authenticationEnabled) {
  263. Toolbar.setAuthenticatedIdentity(userIdentity);
  264. Toolbar.showLoginButton(!loggedIn);
  265. Toolbar.showLogoutButton(loggedIn);
  266. }
  267. }
  268. );
  269. };
  270. /**
  271. * Sets shared key
  272. * @param sKey the shared key
  273. */
  274. my.setSharedKey = function (sKey) {
  275. sharedKey = sKey;
  276. };
  277. my.authenticateClicked = function () {
  278. Authentication.focusAuthenticationWindow();
  279. if (!APP.xmpp.isExternalAuthEnabled()) {
  280. Authentication.xmppAuthenticate();
  281. return;
  282. }
  283. // Get authentication URL
  284. if (!APP.xmpp.isMUCJoined()) {
  285. APP.xmpp.getLoginUrl(UI.getRoomName(), function (url) {
  286. // If conference has not been started yet - redirect to login page
  287. window.location.href = url;
  288. });
  289. } else {
  290. APP.xmpp.getPopupLoginUrl(UI.getRoomName(), function (url) {
  291. // Otherwise - open popup with authentication URL
  292. var authenticationWindow = Authentication.createAuthenticationWindow(
  293. function () {
  294. // On popup closed - retry room allocation
  295. APP.xmpp.allocateConferenceFocus(
  296. APP.UI.getRoomName(),
  297. function () { console.info("AUTH DONE"); }
  298. );
  299. }, url);
  300. if (!authenticationWindow) {
  301. messageHandler.openMessageDialog(
  302. null, "dialog.popupError");
  303. }
  304. });
  305. }
  306. };
  307. /**
  308. * Updates the room invite url.
  309. */
  310. my.updateRoomUrl = function (newRoomUrl) {
  311. roomUrl = newRoomUrl;
  312. // If the invite dialog has been already opened we update the information.
  313. var inviteLink = document.getElementById('inviteLinkRef');
  314. if (inviteLink) {
  315. inviteLink.value = roomUrl;
  316. inviteLink.select();
  317. $('#inviteLinkRef').parent()
  318. .find('button[value=true]').prop('disabled', false);
  319. }
  320. };
  321. /**
  322. * Disables and enables some of the buttons.
  323. */
  324. my.setupButtonsFromConfig = function () {
  325. if (UIUtil.isButtonEnabled('prezi')) {
  326. $("#toolbar_button_prezi").css({display: "none"});
  327. }
  328. };
  329. /**
  330. * Opens the lock room dialog.
  331. */
  332. my.openLockDialog = function () {
  333. // Only the focus is able to set a shared key.
  334. if (!APP.xmpp.isModerator()) {
  335. if (sharedKey) {
  336. messageHandler.openMessageDialog(null,
  337. "dialog.passwordError");
  338. } else {
  339. messageHandler.openMessageDialog(null, "dialog.passwordError2");
  340. }
  341. } else {
  342. if (sharedKey) {
  343. messageHandler.openTwoButtonDialog(null, null,
  344. "dialog.passwordCheck",
  345. null,
  346. false,
  347. "dialog.Remove",
  348. function (e, v) {
  349. if (v) {
  350. Toolbar.setSharedKey('');
  351. lockRoom(false);
  352. }
  353. });
  354. } else {
  355. var msg = APP.translation.generateTranslationHTML(
  356. "dialog.passwordMsg");
  357. var yourPassword = APP.translation.translateString(
  358. "dialog.yourPassword");
  359. messageHandler.openTwoButtonDialog(null, null, null,
  360. '<h2>' + msg + '</h2>' +
  361. '<input name="lockKey" type="text"' +
  362. ' data-i18n="[placeholder]dialog.yourPassword" ' +
  363. 'placeholder="' + yourPassword + '" autofocus>',
  364. false,
  365. "dialog.Save",
  366. function (e, v, m, f) {
  367. if (v) {
  368. var lockKey = f.lockKey;
  369. if (lockKey) {
  370. Toolbar.setSharedKey(
  371. UIUtil.escapeHtml(lockKey));
  372. lockRoom(true);
  373. }
  374. }
  375. },
  376. null, null, 'input:first'
  377. );
  378. }
  379. }
  380. };
  381. /**
  382. * Opens the invite link dialog.
  383. */
  384. my.openLinkDialog = function () {
  385. var inviteAttreibutes;
  386. if (roomUrl === null) {
  387. inviteAttreibutes = 'data-i18n="[value]roomUrlDefaultMsg" value="' +
  388. APP.translation.translateString("roomUrlDefaultMsg") + '"';
  389. } else {
  390. inviteAttreibutes = "value=\"" + encodeURI(roomUrl) + "\"";
  391. }
  392. messageHandler.openTwoButtonDialog("dialog.shareLink",
  393. null, null,
  394. '<input id="inviteLinkRef" type="text" ' +
  395. inviteAttreibutes + ' onclick="this.select();" readonly>',
  396. false,
  397. "dialog.Invite",
  398. function (e, v) {
  399. if (v) {
  400. if (roomUrl) {
  401. inviteParticipants();
  402. }
  403. }
  404. },
  405. function (event) {
  406. if (roomUrl) {
  407. document.getElementById('inviteLinkRef').select();
  408. } else {
  409. if (event && event.target)
  410. $(event.target)
  411. .find('button[value=true]').prop('disabled', true);
  412. }
  413. }
  414. );
  415. };
  416. /**
  417. * Opens the settings dialog.
  418. * FIXME: not used ?
  419. */
  420. my.openSettingsDialog = function () {
  421. var settings1 = APP.translation.generateTranslationHTML(
  422. "dialog.settings1");
  423. var settings2 = APP.translation.generateTranslationHTML(
  424. "dialog.settings2");
  425. var settings3 = APP.translation.generateTranslationHTML(
  426. "dialog.settings3");
  427. var yourPassword = APP.translation.translateString(
  428. "dialog.yourPassword");
  429. messageHandler.openTwoButtonDialog(null,
  430. '<h2>' + settings1 + '</h2>' +
  431. '<input type="checkbox" id="initMuted">' +
  432. settings2 + '<br/>' +
  433. '<input type="checkbox" id="requireNicknames">' +
  434. settings3 +
  435. '<input id="lockKey" type="text" placeholder="' + yourPassword +
  436. '" data-i18n="[placeholder]dialog.yourPassword" autofocus>',
  437. null,
  438. null,
  439. false,
  440. "dialog.Save",
  441. function () {
  442. document.getElementById('lockKey').focus();
  443. },
  444. function (e, v) {
  445. if (v) {
  446. if ($('#initMuted').is(":checked")) {
  447. // it is checked
  448. }
  449. if ($('#requireNicknames').is(":checked")) {
  450. // it is checked
  451. }
  452. /*
  453. var lockKey = document.getElementById('lockKey');
  454. if (lockKey.value) {
  455. setSharedKey(lockKey.value);
  456. lockRoom(true);
  457. }
  458. */
  459. }
  460. }
  461. );
  462. };
  463. /**
  464. * Toggles the application in and out of full screen mode
  465. * (a.k.a. presentation mode in Chrome).
  466. */
  467. my.toggleFullScreen = function () {
  468. var fsElement = document.documentElement;
  469. if (!document.mozFullScreen && !document.webkitIsFullScreen) {
  470. //Enter Full Screen
  471. if (fsElement.mozRequestFullScreen) {
  472. fsElement.mozRequestFullScreen();
  473. }
  474. else {
  475. fsElement.webkitRequestFullScreen(Element.ALLOW_KEYBOARD_INPUT);
  476. }
  477. } else {
  478. //Exit Full Screen
  479. if (document.mozCancelFullScreen) {
  480. document.mozCancelFullScreen();
  481. } else {
  482. document.webkitCancelFullScreen();
  483. }
  484. }
  485. };
  486. /**
  487. * Unlocks the lock button state.
  488. */
  489. my.unlockLockButton = function () {
  490. if ($("#toolbar_button_security").hasClass("icon-security-locked"))
  491. UIUtil.buttonClick("#toolbar_button_security", "icon-security icon-security-locked");
  492. };
  493. /**
  494. * Updates the lock button state to locked.
  495. */
  496. my.lockLockButton = function () {
  497. if ($("#toolbar_button_security").hasClass("icon-security"))
  498. UIUtil.buttonClick("#toolbar_button_security", "icon-security icon-security-locked");
  499. };
  500. /**
  501. * Shows or hides authentication button
  502. * @param show <tt>true</tt> to show or <tt>false</tt> to hide
  503. */
  504. my.showAuthenticateButton = function (show) {
  505. if (UIUtil.isButtonEnabled('authentication') && show) {
  506. $('#authentication').css({display: "inline"});
  507. }
  508. else {
  509. $('#authentication').css({display: "none"});
  510. }
  511. };
  512. // Shows or hides the 'recording' button.
  513. my.showRecordingButton = function (show) {
  514. if (UIUtil.isButtonEnabled('recording') && show) {
  515. $('#toolbar_button_record').css({display: "inline-block"});
  516. }
  517. else {
  518. $('#toolbar_button_record').css({display: "none"});
  519. }
  520. };
  521. // Sets the state of the recording button
  522. my.setRecordingButtonState = function (recordingState) {
  523. var selector = $('#toolbar_button_record');
  524. if (recordingState === 'on') {
  525. selector.removeClass("icon-recEnable");
  526. selector.addClass("icon-recEnable active");
  527. $("#largeVideo").toggleClass("videoMessageFilter", true);
  528. var recordOnKey = "recording.on";
  529. $('#videoConnectionMessage').attr("data-i18n", recordOnKey);
  530. $('#videoConnectionMessage').text(APP.translation.translateString(recordOnKey));
  531. setTimeout(function(){
  532. $("#largeVideo").toggleClass("videoMessageFilter", false);
  533. $('#videoConnectionMessage').css({display: "none"});
  534. }, 1500);
  535. recordingToaster = messageHandler.notify(null, "recording.toaster", null,
  536. null, null, {timeOut: 0, closeButton: null, tapToDismiss: false});
  537. } else if (recordingState === 'off') {
  538. selector.removeClass("icon-recEnable active");
  539. selector.addClass("icon-recEnable");
  540. $("#largeVideo").toggleClass("videoMessageFilter", false);
  541. $('#videoConnectionMessage').css({display: "none"});
  542. if (recordingToaster)
  543. messageHandler.remove(recordingToaster);
  544. } else if (recordingState === 'pending') {
  545. selector.removeClass("icon-recEnable active");
  546. selector.addClass("icon-recEnable");
  547. $("#largeVideo").toggleClass("videoMessageFilter", true);
  548. var recordPendingKey = "recording.pending";
  549. $('#videoConnectionMessage').attr("data-i18n", recordPendingKey);
  550. $('#videoConnectionMessage').text(APP.translation.translateString(recordPendingKey));
  551. $('#videoConnectionMessage').css({display: "block"});
  552. }
  553. };
  554. // checks whether recording is enabled and whether we have params to start automatically recording
  555. my.checkAutoRecord = function () {
  556. if (UIUtil.isButtonEnabled('recording') && config.autoRecord) {
  557. toggleRecording(config.autoRecordToken);
  558. }
  559. };
  560. // Shows or hides SIP calls button
  561. my.showSipCallButton = function (show) {
  562. if (APP.xmpp.isSipGatewayEnabled() && UIUtil.isButtonEnabled('sip') && show) {
  563. $('#toolbar_button_sip').css({display: "inline-block"});
  564. } else {
  565. $('#toolbar_button_sip').css({display: "none"});
  566. }
  567. };
  568. // Shows or hides the dialpad button
  569. my.showDialPadButton = function (show) {
  570. if (UIUtil.isButtonEnabled('dialpad') && show) {
  571. $('#toolbar_button_dialpad').css({display: "inline-block"});
  572. } else {
  573. $('#toolbar_button_dialpad').css({display: "none"});
  574. }
  575. };
  576. /**
  577. * Displays user authenticated identity name(login).
  578. * @param authIdentity identity name to be displayed.
  579. */
  580. my.setAuthenticatedIdentity = function (authIdentity) {
  581. if (authIdentity) {
  582. var selector = $('#toolbar_auth_identity');
  583. selector.css({display: "list-item"});
  584. selector.text(authIdentity);
  585. } else {
  586. $('#toolbar_auth_identity').css({display: "none"});
  587. }
  588. };
  589. /**
  590. * Shows/hides login button.
  591. * @param show <tt>true</tt> to show
  592. */
  593. my.showLoginButton = function (show) {
  594. if (UIUtil.isButtonEnabled('authentication') && show) {
  595. $('#toolbar_button_login').css({display: "list-item"});
  596. } else {
  597. $('#toolbar_button_login').css({display: "none"});
  598. }
  599. };
  600. /**
  601. * Shows/hides logout button.
  602. * @param show <tt>true</tt> to show
  603. */
  604. my.showLogoutButton = function (show) {
  605. if (UIUtil.isButtonEnabled('authentication') && show) {
  606. $('#toolbar_button_logout').css({display: "list-item"});
  607. } else {
  608. $('#toolbar_button_logout').css({display: "none"});
  609. }
  610. };
  611. /**
  612. * Sets the state of the button. The button has blue glow if desktop
  613. * streaming is active.
  614. * @param active the state of the desktop streaming.
  615. */
  616. my.changeDesktopSharingButtonState = function (active) {
  617. var button = $("#toolbar_button_desktopsharing");
  618. if (active) {
  619. button.addClass("glow");
  620. } else {
  621. button.removeClass("glow");
  622. }
  623. };
  624. return my;
  625. }(Toolbar || {}));
  626. module.exports = Toolbar;