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.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792
  1. var UI = {};
  2. var VideoLayout = require("./videolayout/VideoLayout.js");
  3. var AudioLevels = require("./audio_levels/AudioLevels.js");
  4. var Prezi = require("./prezi/Prezi.js");
  5. var Etherpad = require("./etherpad/Etherpad.js");
  6. var Chat = require("./side_pannels/chat/Chat.js");
  7. var Toolbar = require("./toolbars/Toolbar");
  8. var ToolbarToggler = require("./toolbars/ToolbarToggler");
  9. var BottomToolbar = require("./toolbars/BottomToolbar");
  10. var ContactList = require("./side_pannels/contactlist/ContactList");
  11. var Avatar = require("./avatar/Avatar");
  12. var EventEmitter = require("events");
  13. var SettingsMenu = require("./side_pannels/settings/SettingsMenu");
  14. var Settings = require("./../settings/Settings");
  15. var PanelToggler = require("./side_pannels/SidePanelToggler");
  16. var RoomNameGenerator = require("./welcome_page/RoomnameGenerator");
  17. UI.messageHandler = require("./util/MessageHandler");
  18. var messageHandler = UI.messageHandler;
  19. var Authentication = require("./authentication/Authentication");
  20. var UIUtil = require("./util/UIUtil");
  21. var NicknameHandler = require("./util/NicknameHandler");
  22. var CQEvents = require("../../service/connectionquality/CQEvents");
  23. var DesktopSharingEventTypes
  24. = require("../../service/desktopsharing/DesktopSharingEventTypes");
  25. var RTCEvents = require("../../service/RTC/RTCEvents");
  26. var StreamEventTypes = require("../../service/RTC/StreamEventTypes");
  27. var XMPPEvents = require("../../service/xmpp/XMPPEvents");
  28. var MemberEvents = require("../../service/members/Events");
  29. var eventEmitter = new EventEmitter();
  30. var roomName = null;
  31. function notifyForInitialMute()
  32. {
  33. if(config.startAudioMuted || config.startVideoMuted)
  34. {
  35. messageHandler.notify(null, "notify.mutedTitle", "connected", "notify.muted", null, {timeOut: 120000});
  36. }
  37. }
  38. function setupPrezi()
  39. {
  40. $("#reloadPresentationLink").click(function()
  41. {
  42. Prezi.reloadPresentation();
  43. });
  44. }
  45. function setupChat()
  46. {
  47. Chat.init();
  48. $("#toggle_smileys").click(function() {
  49. Chat.toggleSmileys();
  50. });
  51. }
  52. function setupToolbars() {
  53. Toolbar.init(UI);
  54. Toolbar.setupButtonsFromConfig();
  55. BottomToolbar.init();
  56. }
  57. function streamHandler(stream, isMuted) {
  58. switch (stream.type)
  59. {
  60. case "audio":
  61. VideoLayout.changeLocalAudio(stream, isMuted);
  62. break;
  63. case "video":
  64. VideoLayout.changeLocalVideo(stream, isMuted);
  65. break;
  66. case "stream":
  67. VideoLayout.changeLocalStream(stream, isMuted);
  68. break;
  69. }
  70. }
  71. function onDisposeConference(unload) {
  72. Toolbar.showAuthenticateButton(false);
  73. };
  74. function onDisplayNameChanged(jid, displayName) {
  75. ContactList.onDisplayNameChange(jid, displayName);
  76. SettingsMenu.onDisplayNameChange(jid, displayName);
  77. VideoLayout.onDisplayNameChanged(jid, displayName);
  78. }
  79. function registerListeners() {
  80. APP.RTC.addStreamListener(streamHandler, StreamEventTypes.EVENT_TYPE_LOCAL_CREATED);
  81. APP.RTC.addStreamListener(streamHandler, StreamEventTypes.EVENT_TYPE_LOCAL_CHANGED);
  82. APP.RTC.addStreamListener(function (stream) {
  83. VideoLayout.onRemoteStreamAdded(stream);
  84. }, StreamEventTypes.EVENT_TYPE_REMOTE_CREATED);
  85. APP.RTC.addStreamListener(function (jid) {
  86. VideoLayout.onVideoTypeChanged(jid);
  87. }, StreamEventTypes.EVENT_TYPE_REMOTE_CHANGED);
  88. APP.RTC.addListener(RTCEvents.LASTN_CHANGED, onLastNChanged);
  89. APP.RTC.addListener(RTCEvents.DOMINANTSPEAKER_CHANGED, function (resourceJid) {
  90. VideoLayout.onDominantSpeakerChanged(resourceJid);
  91. });
  92. APP.RTC.addListener(RTCEvents.LASTN_ENDPOINT_CHANGED,
  93. function (lastNEndpoints, endpointsEnteringLastN, stream) {
  94. VideoLayout.onLastNEndpointsChanged(lastNEndpoints,
  95. endpointsEnteringLastN, stream);
  96. });
  97. APP.RTC.addListener(RTCEvents.SIMULCAST_LAYER_CHANGED,
  98. function (endpointSimulcastLayers) {
  99. VideoLayout.onSimulcastLayersChanged(endpointSimulcastLayers);
  100. });
  101. APP.RTC.addListener(RTCEvents.SIMULCAST_LAYER_CHANGING,
  102. function (endpointSimulcastLayers) {
  103. VideoLayout.onSimulcastLayersChanging(endpointSimulcastLayers);
  104. });
  105. APP.RTC.addListener(RTCEvents.AVAILABLE_DEVICES_CHANGED,
  106. function (devices) {
  107. VideoLayout.setDeviceAvailabilityIcons(null, devices);
  108. })
  109. APP.statistics.addAudioLevelListener(function(jid, audioLevel)
  110. {
  111. var resourceJid;
  112. if(jid === APP.statistics.LOCAL_JID)
  113. {
  114. resourceJid = AudioLevels.LOCAL_LEVEL;
  115. if(APP.RTC.localAudio.isMuted())
  116. {
  117. audioLevel = 0;
  118. }
  119. }
  120. else
  121. {
  122. resourceJid = Strophe.getResourceFromJid(jid);
  123. }
  124. AudioLevels.updateAudioLevel(resourceJid, audioLevel,
  125. UI.getLargeVideoState().userResourceJid);
  126. });
  127. APP.desktopsharing.addListener(function () {
  128. ToolbarToggler.showDesktopSharingButton();
  129. }, DesktopSharingEventTypes.INIT);
  130. APP.desktopsharing.addListener(
  131. Toolbar.changeDesktopSharingButtonState,
  132. DesktopSharingEventTypes.SWITCHING_DONE);
  133. APP.connectionquality.addListener(CQEvents.LOCALSTATS_UPDATED,
  134. VideoLayout.updateLocalConnectionStats);
  135. APP.connectionquality.addListener(CQEvents.REMOTESTATS_UPDATED,
  136. VideoLayout.updateConnectionStats);
  137. APP.connectionquality.addListener(CQEvents.STOP,
  138. VideoLayout.onStatsStop);
  139. APP.xmpp.addListener(XMPPEvents.DISPOSE_CONFERENCE, onDisposeConference);
  140. APP.xmpp.addListener(XMPPEvents.GRACEFUL_SHUTDOWN, function () {
  141. messageHandler.openMessageDialog(
  142. 'dialog.serviceUnavailable',
  143. 'dialog.gracefulShutdown'
  144. );
  145. });
  146. APP.xmpp.addListener(XMPPEvents.RESERVATION_ERROR, function (code, msg) {
  147. var title = APP.translation.generateTranslatonHTML(
  148. "dialog.reservationError");
  149. var message = APP.translation.generateTranslatonHTML(
  150. "dialog.reservationErrorMsg", {code: code, msg: msg});
  151. messageHandler.openDialog(
  152. title,
  153. message,
  154. true, {},
  155. function (event, value, message, formVals)
  156. {
  157. return false;
  158. }
  159. );
  160. });
  161. APP.xmpp.addListener(XMPPEvents.KICKED, function () {
  162. messageHandler.openMessageDialog("dialog.sessTerminated",
  163. "dialog.kickMessage");
  164. });
  165. APP.xmpp.addListener(XMPPEvents.MUC_DESTROYED, function (reason) {
  166. //FIXME: use Session Terminated from translation, but
  167. // 'reason' text comes from XMPP packet and is not translated
  168. var title = APP.translation.generateTranslatonHTML("dialog.sessTerminated");
  169. messageHandler.openDialog(
  170. title, reason, true, {},
  171. function (event, value, message, formVals)
  172. {
  173. return false;
  174. }
  175. );
  176. });
  177. APP.xmpp.addListener(XMPPEvents.BRIDGE_DOWN, function () {
  178. messageHandler.showError("dialog.error",
  179. "dialog.bridgeUnavailable");
  180. });
  181. APP.xmpp.addListener(XMPPEvents.USER_ID_CHANGED, function (from, id) {
  182. Avatar.setUserAvatar(from, id);
  183. });
  184. APP.xmpp.addListener(XMPPEvents.STREAMS_CHANGED, function (jid, changedStreams) {
  185. for(stream in changedStreams)
  186. {
  187. // might need to update the direction if participant just went from sendrecv to recvonly
  188. if (stream.type === 'video' || stream.type === 'screen') {
  189. var el = $('#participant_' + Strophe.getResourceFromJid(jid) + '>video');
  190. switch (stream.direction) {
  191. case 'sendrecv':
  192. el.show();
  193. break;
  194. case 'recvonly':
  195. el.hide();
  196. // FIXME: Check if we have to change large video
  197. //VideoLayout.updateLargeVideo(el);
  198. break;
  199. }
  200. }
  201. }
  202. });
  203. APP.xmpp.addListener(XMPPEvents.DISPLAY_NAME_CHANGED, onDisplayNameChanged);
  204. APP.xmpp.addListener(XMPPEvents.MUC_JOINED, onMucJoined);
  205. APP.xmpp.addListener(XMPPEvents.LOCAL_ROLE_CHANGED, onLocalRoleChanged);
  206. APP.xmpp.addListener(XMPPEvents.MUC_MEMBER_JOINED, onMucMemberJoined);
  207. APP.xmpp.addListener(XMPPEvents.MUC_ROLE_CHANGED, onMucRoleChanged);
  208. APP.xmpp.addListener(XMPPEvents.PRESENCE_STATUS, onMucPresenceStatus);
  209. APP.xmpp.addListener(XMPPEvents.SUBJECT_CHANGED, chatSetSubject);
  210. APP.xmpp.addListener(XMPPEvents.MESSAGE_RECEIVED, updateChatConversation);
  211. APP.xmpp.addListener(XMPPEvents.MUC_MEMBER_LEFT, onMucMemberLeft);
  212. APP.xmpp.addListener(XMPPEvents.PASSWORD_REQUIRED, onPasswordRequired);
  213. APP.xmpp.addListener(XMPPEvents.CHAT_ERROR_RECEIVED, chatAddError);
  214. APP.xmpp.addListener(XMPPEvents.ETHERPAD, initEtherpad);
  215. APP.xmpp.addListener(XMPPEvents.AUTHENTICATION_REQUIRED,
  216. onAuthenticationRequired);
  217. APP.xmpp.addListener(XMPPEvents.DEVICE_AVAILABLE,
  218. function (resource, devices) {
  219. VideoLayout.setDeviceAvailabilityIcons(resource, devices);
  220. });
  221. APP.members.addListener(MemberEvents.DTMF_SUPPORT_CHANGED,
  222. onDtmfSupportChanged);
  223. }
  224. /**
  225. * Mutes/unmutes the local video.
  226. *
  227. * @param mute <tt>true</tt> to mute the local video; otherwise, <tt>false</tt>
  228. * @param options an object which specifies optional arguments such as the
  229. * <tt>boolean</tt> key <tt>byUser</tt> with default value <tt>true</tt> which
  230. * specifies whether the method was initiated in response to a user command (in
  231. * contrast to an automatic decision taken by the application logic)
  232. */
  233. function setVideoMute(mute, options) {
  234. APP.RTC.setVideoMute(mute,
  235. UI.setVideoMuteButtonsState,
  236. options);
  237. }
  238. function bindEvents()
  239. {
  240. /**
  241. * Resizes and repositions videos in full screen mode.
  242. */
  243. $(document).on('webkitfullscreenchange mozfullscreenchange fullscreenchange',
  244. function () {
  245. VideoLayout.resizeLargeVideoContainer();
  246. VideoLayout.positionLarge();
  247. }
  248. );
  249. $(window).resize(function () {
  250. VideoLayout.resizeLargeVideoContainer();
  251. VideoLayout.positionLarge();
  252. });
  253. }
  254. UI.start = function (init) {
  255. document.title = interfaceConfig.APP_NAME;
  256. if(config.enableWelcomePage && window.location.pathname == "/" &&
  257. (!window.localStorage.welcomePageDisabled || window.localStorage.welcomePageDisabled == "false"))
  258. {
  259. $("#videoconference_page").hide();
  260. var setupWelcomePage = require("./welcome_page/WelcomePage");
  261. setupWelcomePage();
  262. return;
  263. }
  264. if (interfaceConfig.SHOW_JITSI_WATERMARK) {
  265. var leftWatermarkDiv
  266. = $("#largeVideoContainer div[class='watermark leftwatermark']");
  267. leftWatermarkDiv.css({display: 'block'});
  268. leftWatermarkDiv.parent().get(0).href
  269. = interfaceConfig.JITSI_WATERMARK_LINK;
  270. }
  271. if (interfaceConfig.SHOW_BRAND_WATERMARK) {
  272. var rightWatermarkDiv
  273. = $("#largeVideoContainer div[class='watermark rightwatermark']");
  274. rightWatermarkDiv.css({display: 'block'});
  275. rightWatermarkDiv.parent().get(0).href
  276. = interfaceConfig.BRAND_WATERMARK_LINK;
  277. rightWatermarkDiv.get(0).style.backgroundImage
  278. = "url(images/rightwatermark.png)";
  279. }
  280. if (interfaceConfig.SHOW_POWERED_BY) {
  281. $("#largeVideoContainer>a[class='poweredby']").css({display: 'block'});
  282. }
  283. $("#welcome_page").hide();
  284. VideoLayout.resizeLargeVideoContainer();
  285. $("#videospace").mousemove(function () {
  286. return ToolbarToggler.showToolbar();
  287. });
  288. // Set the defaults for prompt dialogs.
  289. jQuery.prompt.setDefaults({persistent: false});
  290. VideoLayout.init(eventEmitter);
  291. AudioLevels.init();
  292. NicknameHandler.init(eventEmitter);
  293. registerListeners();
  294. bindEvents();
  295. setupPrezi();
  296. setupToolbars();
  297. setupChat();
  298. document.title = interfaceConfig.APP_NAME;
  299. $("#downloadlog").click(function (event) {
  300. dump(event.target);
  301. });
  302. if(config.enableWelcomePage && window.location.pathname == "/" &&
  303. (!window.localStorage.welcomePageDisabled || window.localStorage.welcomePageDisabled == "false"))
  304. {
  305. $("#videoconference_page").hide();
  306. var setupWelcomePage = require("./welcome_page/WelcomePage");
  307. setupWelcomePage();
  308. return;
  309. }
  310. $("#welcome_page").hide();
  311. // Display notice message at the top of the toolbar
  312. if (config.noticeMessage) {
  313. $('#noticeText').text(config.noticeMessage);
  314. $('#notice').css({display: 'block'});
  315. }
  316. document.getElementById('largeVideo').volume = 0;
  317. if (!$('#settings').is(':visible')) {
  318. console.log('init');
  319. init();
  320. } else {
  321. loginInfo.onsubmit = function (e) {
  322. if (e.preventDefault) e.preventDefault();
  323. $('#settings').hide();
  324. init();
  325. };
  326. }
  327. toastr.options = {
  328. "closeButton": true,
  329. "debug": false,
  330. "positionClass": "notification-bottom-right",
  331. "onclick": null,
  332. "showDuration": "300",
  333. "hideDuration": "1000",
  334. "timeOut": "2000",
  335. "extendedTimeOut": "1000",
  336. "showEasing": "swing",
  337. "hideEasing": "linear",
  338. "showMethod": "fadeIn",
  339. "hideMethod": "fadeOut",
  340. "reposition": function() {
  341. if(PanelToggler.isVisible()) {
  342. $("#toast-container").addClass("notification-bottom-right-center");
  343. } else {
  344. $("#toast-container").removeClass("notification-bottom-right-center");
  345. }
  346. },
  347. "newestOnTop": false
  348. };
  349. SettingsMenu.init();
  350. notifyForInitialMute();
  351. };
  352. function chatAddError(errorMessage, originalText)
  353. {
  354. return Chat.chatAddError(errorMessage, originalText);
  355. };
  356. function chatSetSubject(text)
  357. {
  358. return Chat.chatSetSubject(text);
  359. };
  360. function updateChatConversation(from, displayName, message) {
  361. return Chat.updateChatConversation(from, displayName, message);
  362. };
  363. function onMucJoined(jid, info) {
  364. Toolbar.updateRoomUrl(window.location.href);
  365. var meHTML = APP.translation.generateTranslatonHTML("me");
  366. $("#localNick").html(Strophe.getResourceFromJid(jid) + " (" + meHTML + ")");
  367. var settings = Settings.getSettings();
  368. // Add myself to the contact list.
  369. ContactList.addContact(jid, settings.email || settings.uid);
  370. // Once we've joined the muc show the toolbar
  371. ToolbarToggler.showToolbar();
  372. var displayName = !config.displayJids
  373. ? info.displayName : Strophe.getResourceFromJid(jid);
  374. if (displayName)
  375. onDisplayNameChanged('localVideoContainer', displayName);
  376. VideoLayout.mucJoined();
  377. }
  378. function initEtherpad(name) {
  379. Etherpad.init(name);
  380. };
  381. function onMucMemberLeft(jid) {
  382. console.log('left.muc', jid);
  383. var displayName = $('#participant_' + Strophe.getResourceFromJid(jid) +
  384. '>.displayname').html();
  385. messageHandler.notify(displayName,'notify.somebody',
  386. 'disconnected',
  387. 'notify.disconnected');
  388. // Need to call this with a slight delay, otherwise the element couldn't be
  389. // found for some reason.
  390. // XXX(gp) it works fine without the timeout for me (with Chrome 38).
  391. window.setTimeout(function () {
  392. var container = document.getElementById(
  393. 'participant_' + Strophe.getResourceFromJid(jid));
  394. if (container) {
  395. ContactList.removeContact(jid);
  396. VideoLayout.removeConnectionIndicator(jid);
  397. // hide here, wait for video to close before removing
  398. $(container).hide();
  399. VideoLayout.resizeThumbnails();
  400. }
  401. }, 10);
  402. VideoLayout.participantLeft(jid);
  403. };
  404. function onLocalRoleChanged(jid, info, pres, isModerator)
  405. {
  406. console.info("My role changed, new role: " + info.role);
  407. onModeratorStatusChanged(isModerator);
  408. VideoLayout.showModeratorIndicator();
  409. if (isModerator) {
  410. Authentication.closeAuthenticationWindow();
  411. messageHandler.notify(null, "notify.me",
  412. 'connected', "notify.moderator");
  413. }
  414. }
  415. function onModeratorStatusChanged(isModerator) {
  416. Toolbar.showSipCallButton(isModerator);
  417. Toolbar.showRecordingButton(
  418. isModerator); //&&
  419. // FIXME:
  420. // Recording visible if
  421. // there are at least 2(+ 1 focus) participants
  422. //Object.keys(connection.emuc.members).length >= 3);
  423. if (isModerator && config.etherpad_base) {
  424. Etherpad.init();
  425. }
  426. };
  427. function onPasswordRequired(callback) {
  428. // password is required
  429. Toolbar.lockLockButton();
  430. var message = '<h2 data-i18n="dialog.passwordRequired">';
  431. message += APP.translation.translateString(
  432. "dialog.passwordRequired");
  433. message += '</h2>' +
  434. '<input name="lockKey" type="text" data-i18n=' +
  435. '"[placeholder]dialog.password" placeholder="' +
  436. APP.translation.translateString("dialog.password") +
  437. '" autofocus>';
  438. messageHandler.openTwoButtonDialog(null, null, null, message,
  439. true,
  440. "dialog.Ok",
  441. function (e, v, m, f) {},
  442. null,
  443. function (e, v, m, f) {
  444. if (v) {
  445. var lockKey = f.lockKey;
  446. if (lockKey) {
  447. Toolbar.setSharedKey(lockKey);
  448. callback(lockKey);
  449. }
  450. }
  451. },
  452. ':input:first'
  453. );
  454. }
  455. /**
  456. * The dialpad button is shown iff there is at least one member that supports
  457. * DTMF (e.g. jigasi).
  458. */
  459. function onDtmfSupportChanged(dtmfSupport) {
  460. //TODO: enable when the UI is ready
  461. //Toolbar.showDialPadButton(dtmfSupport);
  462. }
  463. function onMucMemberJoined(jid, id, displayName) {
  464. messageHandler.notify(displayName,'notify.somebody',
  465. 'connected',
  466. 'notify.connected');
  467. // Add Peer's container
  468. VideoLayout.ensurePeerContainerExists(jid,id);
  469. }
  470. function onMucPresenceStatus( jid, info) {
  471. VideoLayout.setPresenceStatus(
  472. 'participant_' + Strophe.getResourceFromJid(jid), info.status);
  473. }
  474. function onMucRoleChanged(role, displayName) {
  475. VideoLayout.showModeratorIndicator();
  476. if (role === 'moderator') {
  477. var messageKey, messageOptions = {};
  478. if (!displayName) {
  479. messageKey = "notify.grantedToUnknown";
  480. }
  481. else
  482. {
  483. messageKey = "notify.grantedTo";
  484. messageOptions = {to: displayName};
  485. }
  486. messageHandler.notify(
  487. displayName,'notify.somebody',
  488. 'connected', messageKey,
  489. messageOptions);
  490. }
  491. }
  492. function onAuthenticationRequired(intervalCallback) {
  493. Authentication.openAuthenticationDialog(
  494. roomName, intervalCallback, function () {
  495. Toolbar.authenticateClicked();
  496. });
  497. };
  498. function onLastNChanged(oldValue, newValue) {
  499. if (config.muteLocalVideoIfNotInLastN) {
  500. setVideoMute(!newValue, { 'byUser': false });
  501. }
  502. }
  503. UI.toggleSmileys = function () {
  504. Chat.toggleSmileys();
  505. };
  506. UI.getSettings = function () {
  507. return Settings.getSettings();
  508. };
  509. UI.toggleFilmStrip = function () {
  510. return BottomToolbar.toggleFilmStrip();
  511. };
  512. UI.toggleChat = function () {
  513. return BottomToolbar.toggleChat();
  514. };
  515. UI.toggleContactList = function () {
  516. return BottomToolbar.toggleContactList();
  517. };
  518. UI.inputDisplayNameHandler = function (value) {
  519. VideoLayout.inputDisplayNameHandler(value);
  520. };
  521. UI.getLargeVideoState = function()
  522. {
  523. return VideoLayout.getLargeVideoState();
  524. };
  525. UI.generateRoomName = function() {
  526. if(roomName)
  527. return roomName;
  528. var roomnode = null;
  529. var path = window.location.pathname;
  530. // determinde the room node from the url
  531. // TODO: just the roomnode or the whole bare jid?
  532. if (config.getroomnode && typeof config.getroomnode === 'function') {
  533. // custom function might be responsible for doing the pushstate
  534. roomnode = config.getroomnode(path);
  535. } else {
  536. /* fall back to default strategy
  537. * this is making assumptions about how the URL->room mapping happens.
  538. * It currently assumes deployment at root, with a rewrite like the
  539. * following one (for nginx):
  540. location ~ ^/([a-zA-Z0-9]+)$ {
  541. rewrite ^/(.*)$ / break;
  542. }
  543. */
  544. if (path.length > 1) {
  545. roomnode = path.substr(1).toLowerCase();
  546. } else {
  547. var word = RoomNameGenerator.generateRoomWithoutSeparator();
  548. roomnode = word.toLowerCase();
  549. window.history.pushState('VideoChat',
  550. 'Room: ' + word, window.location.pathname + word);
  551. }
  552. }
  553. roomName = roomnode + '@' + config.hosts.muc;
  554. return roomName;
  555. };
  556. UI.connectionIndicatorShowMore = function(id)
  557. {
  558. return VideoLayout.connectionIndicators[id].showMore();
  559. };
  560. UI.showLoginPopup = function(callback)
  561. {
  562. console.log('password is required');
  563. var message = '<h2 data-i18n="dialog.passwordRequired">';
  564. message += APP.translation.translateString(
  565. "dialog.passwordRequired");
  566. message += '</h2>' +
  567. '<input name="username" type="text" ' +
  568. 'placeholder="user@domain.net" autofocus>' +
  569. '<input name="password" ' +
  570. 'type="password" data-i18n="[placeholder]dialog.userPassword"' +
  571. ' placeholder="user password">';
  572. UI.messageHandler.openTwoButtonDialog(null, null, null, message,
  573. true,
  574. "dialog.Ok",
  575. function (e, v, m, f) {
  576. if (v) {
  577. if (f.username !== null && f.password != null) {
  578. callback(f.username, f.password);
  579. }
  580. }
  581. },
  582. null, null, ':input:first'
  583. );
  584. }
  585. UI.checkForNicknameAndJoin = function () {
  586. Authentication.closeAuthenticationDialog();
  587. Authentication.stopInterval();
  588. var nick = null;
  589. if (config.useNicks) {
  590. nick = window.prompt('Your nickname (optional)');
  591. }
  592. APP.xmpp.joinRoom(roomName, config.useNicks, nick);
  593. };
  594. function dump(elem, filename) {
  595. elem = elem.parentNode;
  596. elem.download = filename || 'meetlog.json';
  597. elem.href = 'data:application/json;charset=utf-8,\n';
  598. var data = APP.xmpp.populateData();
  599. var metadata = {};
  600. metadata.time = new Date();
  601. metadata.url = window.location.href;
  602. metadata.ua = navigator.userAgent;
  603. var log = APP.xmpp.getLogger();
  604. if (log) {
  605. metadata.xmpp = log;
  606. }
  607. data.metadata = metadata;
  608. elem.href += encodeURIComponent(JSON.stringify(data, null, ' '));
  609. return false;
  610. }
  611. UI.getRoomName = function () {
  612. return roomName;
  613. };
  614. /**
  615. * Mutes/unmutes the local video.
  616. */
  617. UI.toggleVideo = function () {
  618. setVideoMute(!APP.RTC.localVideo.isMuted());
  619. };
  620. /**
  621. * Mutes / unmutes audio for the local participant.
  622. */
  623. UI.toggleAudio = function() {
  624. UI.setAudioMuted(!APP.RTC.localAudio.isMuted());
  625. };
  626. /**
  627. * Sets muted audio state for the local participant.
  628. */
  629. UI.setAudioMuted = function (mute, earlyMute) {
  630. var audioMute = null;
  631. if(earlyMute)
  632. audioMute = function (mute, cb) {
  633. return APP.xmpp.sendAudioInfoPresence(mute, cb);
  634. };
  635. else
  636. audioMute = function (mute, cb) {
  637. return APP.xmpp.setAudioMute(mute, cb);
  638. }
  639. if(!audioMute(mute, function () {
  640. VideoLayout.showLocalAudioIndicator(mute);
  641. UIUtil.buttonClick("#mute", "icon-microphone icon-mic-disabled");
  642. }))
  643. {
  644. // We still click the button.
  645. UIUtil.buttonClick("#mute", "icon-microphone icon-mic-disabled");
  646. return;
  647. }
  648. }
  649. UI.addListener = function (type, listener) {
  650. eventEmitter.on(type, listener);
  651. }
  652. UI.clickOnVideo = function (videoNumber) {
  653. var remoteVideos = $(".videocontainer:not(#mixedstream)");
  654. if (remoteVideos.length > videoNumber) {
  655. remoteVideos[videoNumber].click();
  656. }
  657. }
  658. //Used by torture
  659. UI.showToolbar = function () {
  660. return ToolbarToggler.showToolbar();
  661. }
  662. //Used by torture
  663. UI.dockToolbar = function (isDock) {
  664. return ToolbarToggler.dockToolbar(isDock);
  665. }
  666. UI.setVideoMuteButtonsState = function (mute) {
  667. var video = $('#video');
  668. var communicativeClass = "icon-camera";
  669. var muteClass = "icon-camera icon-camera-disabled";
  670. if (mute) {
  671. video.removeClass(communicativeClass);
  672. video.addClass(muteClass);
  673. } else {
  674. video.removeClass(muteClass);
  675. video.addClass(communicativeClass);
  676. }
  677. }
  678. UI.setVideoMute = setVideoMute;
  679. module.exports = UI;