var UI = {}; var VideoLayout = require("./videolayout/VideoLayout.js"); var AudioLevels = require("./audio_levels/AudioLevels.js"); var Prezi = require("./prezi/Prezi.js"); var Etherpad = require("./etherpad/Etherpad.js"); var Chat = require("./side_pannels/chat/Chat.js"); var Toolbar = require("./toolbars/toolbar"); var ToolbarToggler = require("./toolbars/toolbartoggler"); var BottomToolbar = require("./toolbars/BottomToolbar"); var ContactList = require("./side_pannels/contactlist/ContactList"); var Avatar = require("./avatar/Avatar"); //var EventEmitter = require("events"); var SettingsMenu = require("./side_pannels/settings/SettingsMenu"); var Settings = require("./side_pannels/settings/Settings"); var PanelToggler = require("./side_pannels/SidePanelToggler"); var RoomNameGenerator = require("./welcome_page/RoomnameGenerator"); UI.messageHandler = require("./util/MessageHandler"); var messageHandler = UI.messageHandler; //var eventEmitter = new EventEmitter(); function setupPrezi() { $("#reloadPresentationLink").click(function() { Prezi.reloadPresentation(); }); } function setupChat() { Chat.init(); $("#toggle_smileys").click(function() { Chat.toggleSmileys(); }); } function setupToolbars() { Toolbar.init(); Toolbar.setupButtonsFromConfig(); BottomToolbar.init(); } function registerListeners() { RTC.addStreamListener(function (stream) { switch (stream.type) { case "audio": VideoLayout.changeLocalAudio(stream.getOriginalStream()); break; case "video": VideoLayout.changeLocalVideo(stream.getOriginalStream(), true); break; case "stream": VideoLayout.changeLocalStream(stream.getOriginalStream()); break; case "desktop": VideoLayout.changeLocalVideo(stream, !isUsingScreenStream); break; } }, StreamEventTypes.EVENT_TYPE_LOCAL_CREATED); RTC.addStreamListener(function (stream) { VideoLayout.onRemoteStreamAdded(stream); }, StreamEventTypes.EVENT_TYPE_REMOTE_CREATED); // Listen for large video size updates document.getElementById('largeVideo') .addEventListener('loadedmetadata', function (e) { currentVideoWidth = this.videoWidth; currentVideoHeight = this.videoHeight; VideoLayout.positionLarge(currentVideoWidth, currentVideoHeight); }); statistics.addAudioLevelListener(function(jid, audioLevel) { var resourceJid; if(jid === statistics.LOCAL_JID) { resourceJid = AudioLevels.LOCAL_LEVEL; if(RTC.localAudio.isMuted()) { audioLevel = 0; } } else { resourceJid = Strophe.getResourceFromJid(jid); } AudioLevels.updateAudioLevel(resourceJid, audioLevel, UI.getLargeVideoState().userResourceJid); }); } function bindEvents() { /** * Resizes and repositions videos in full screen mode. */ $(document).on('webkitfullscreenchange mozfullscreenchange fullscreenchange', function () { VideoLayout.resizeLargeVideoContainer(); VideoLayout.positionLarge(); isFullScreen = document.fullScreen || document.mozFullScreen || document.webkitIsFullScreen; } ); $(window).resize(function () { VideoLayout.resizeLargeVideoContainer(); VideoLayout.positionLarge(); }); } UI.start = function () { document.title = interfaceConfig.APP_NAME; if(config.enableWelcomePage && window.location.pathname == "/" && (!window.localStorage.welcomePageDisabled || window.localStorage.welcomePageDisabled == "false")) { $("#videoconference_page").hide(); var setupWelcomePage = require("./welcome_page/WelcomePage"); setupWelcomePage(); return; } if (interfaceConfig.SHOW_JITSI_WATERMARK) { var leftWatermarkDiv = $("#largeVideoContainer div[class='watermark leftwatermark']"); leftWatermarkDiv.css({display: 'block'}); leftWatermarkDiv.parent().get(0).href = interfaceConfig.JITSI_WATERMARK_LINK; } if (interfaceConfig.SHOW_BRAND_WATERMARK) { var rightWatermarkDiv = $("#largeVideoContainer div[class='watermark rightwatermark']"); rightWatermarkDiv.css({display: 'block'}); rightWatermarkDiv.parent().get(0).href = interfaceConfig.BRAND_WATERMARK_LINK; rightWatermarkDiv.get(0).style.backgroundImage = "url(images/rightwatermark.png)"; } if (interfaceConfig.SHOW_POWERED_BY) { $("#largeVideoContainer>a[class='poweredby']").css({display: 'block'}); } $("#welcome_page").hide(); $('body').popover({ selector: '[data-toggle=popover]', trigger: 'click hover', content: function() { return this.getAttribute("content") + KeyboardShortcut.getShortcut(this.getAttribute("shortcut")); } }); VideoLayout.resizeLargeVideoContainer(); $("#videospace").mousemove(function () { return ToolbarToggler.showToolbar(); }); // Set the defaults for prompt dialogs. jQuery.prompt.setDefaults({persistent: false}); // KeyboardShortcut.init(); registerListeners(); bindEvents(); setupPrezi(); setupToolbars(); setupChat(); document.title = interfaceConfig.APP_NAME; $("#downloadlog").click(function (event) { dump(event.target); }); if(config.enableWelcomePage && window.location.pathname == "/" && (!window.localStorage.welcomePageDisabled || window.localStorage.welcomePageDisabled == "false")) { $("#videoconference_page").hide(); var setupWelcomePage = require("./welcome_page/WelcomePage"); setupWelcomePage(); return; } $("#welcome_page").hide(); document.getElementById('largeVideo').volume = 0; if (!$('#settings').is(':visible')) { console.log('init'); init(); } else { loginInfo.onsubmit = function (e) { if (e.preventDefault) e.preventDefault(); $('#settings').hide(); init(); }; } toastr.options = { "closeButton": true, "debug": false, "positionClass": "notification-bottom-right", "onclick": null, "showDuration": "300", "hideDuration": "1000", "timeOut": "2000", "extendedTimeOut": "1000", "showEasing": "swing", "hideEasing": "linear", "showMethod": "fadeIn", "hideMethod": "fadeOut", "reposition": function() { if(PanelToggler.isVisible()) { $("#toast-container").addClass("notification-bottom-right-center"); } else { $("#toast-container").removeClass("notification-bottom-right-center"); } }, "newestOnTop": false }; $('#settingsmenu>input').keyup(function(event){ if(event.keyCode === 13) {//enter SettingsMenu.update(); } }); $("#updateSettings").click(function () { SettingsMenu.update(); }); }; UI.setUserAvatar = function (jid, id) { Avatar.setUserAvatar(jid, id); }; UI.toggleSmileys = function () { Chat.toggleSmileys(); }; UI.chatAddError = function(errorMessage, originalText) { return Chat.chatAddError(errorMessage, originalText); }; UI.chatSetSubject = function(text) { return Chat.chatSetSubject(text); }; UI.updateChatConversation = function (from, displayName, message) { return Chat.updateChatConversation(from, displayName, message); }; UI.onMucJoined = function (jid, info) { Toolbar.updateRoomUrl(window.location.href); document.getElementById('localNick').appendChild( document.createTextNode(Strophe.getResourceFromJid(jid) + ' (me)') ); var settings = Settings.getSettings(); // Add myself to the contact list. ContactList.addContact(jid, settings.email || settings.uid); // Once we've joined the muc show the toolbar ToolbarToggler.showToolbar(); // Show authenticate button if needed Toolbar.showAuthenticateButton( Moderator.isExternalAuthEnabled() && !Moderator.isModerator()); var displayName = !config.displayJids ? info.displayName : Strophe.getResourceFromJid(jid); if (displayName) $(document).trigger('displaynamechanged', ['localVideoContainer', displayName + ' (me)']); }; UI.initEtherpad = function (name) { Etherpad.init(name); }; UI.onMucLeft = function (jid) { console.log('left.muc', jid); var displayName = $('#participant_' + Strophe.getResourceFromJid(jid) + '>.displayname').html(); messageHandler.notify(displayName || 'Somebody', 'disconnected', 'disconnected'); // Need to call this with a slight delay, otherwise the element couldn't be // found for some reason. // XXX(gp) it works fine without the timeout for me (with Chrome 38). window.setTimeout(function () { var container = document.getElementById( 'participant_' + Strophe.getResourceFromJid(jid)); if (container) { ContactList.removeContact(jid); VideoLayout.removeConnectionIndicator(jid); // hide here, wait for video to close before removing $(container).hide(); VideoLayout.resizeThumbnails(); } }, 10); // Unlock large video if (focusedVideoInfo && focusedVideoInfo.jid === jid) { console.info("Focused video owner has left the conference"); focusedVideoInfo = null; } }; UI.getSettings = function () { return Settings.getSettings(); }; UI.toggleFilmStrip = function () { return BottomToolbar.toggleFilmStrip(); }; UI.toggleChat = function () { return BottomToolbar.toggleChat(); }; UI.toggleContactList = function () { return BottomToolbar.toggleContactList(); }; UI.onLocalRoleChange = function (jid, info, pres) { console.info("My role changed, new role: " + info.role); var isModerator = Moderator.isModerator(); VideoLayout.showModeratorIndicator(); Toolbar.showAuthenticateButton( Moderator.isExternalAuthEnabled() && !isModerator); if (isModerator) { Toolbar.closeAuthenticationWindow(); messageHandler.notify( 'Me', 'connected', 'Moderator rights granted !'); } }; UI.onDisposeConference = function (unload) { Toolbar.showAuthenticateButton(false); }; UI.onModeratorStatusChanged = function (isModerator) { Toolbar.showSipCallButton(isModerator); Toolbar.showRecordingButton( isModerator); //&& // FIXME: // Recording visible if // there are at least 2(+ 1 focus) participants //Object.keys(connection.emuc.members).length >= 3); if (isModerator && config.etherpad_base) { Etherpad.init(); } }; UI.onPasswordReqiured = function (callback) { // password is required Toolbar.lockLockButton(); messageHandler.openTwoButtonDialog(null, '

Password required

' + '', true, "Ok", function (e, v, m, f) {}, function (event) { document.getElementById('lockKey').focus(); }, function (e, v, m, f) { if (v) { var lockKey = document.getElementById('lockKey'); if (lockKey.value !== null) { Toolbar.setSharedKey(lockKey.value); callback(lockKey.value); } } } ); }; UI.onAuthenticationRequired = function () { // This is the loop that will wait for the room to be created by // someone else. 'auth_required.moderator' will bring us back here. authRetryId = window.setTimeout( function () { Moderator.allocateConferenceFocus(roomName, doJoinAfterFocus); }, 5000); // Show prompt only if it's not open if (authDialog !== null) { return; } // extract room name from 'room@muc.server.net' var room = roomName.substr(0, roomName.indexOf('@')); authDialog = messageHandler.openDialog( 'Stop', 'Authentication is required to create room:
' + room + '
You can either authenticate to create the room or ' + 'just wait for someone else to do so.', true, { Authenticate: 'authNow' }, function (onSubmitEvent, submitValue) { // Do not close the dialog yet onSubmitEvent.preventDefault(); // Open login popup if (submitValue === 'authNow') { Toolbar.authenticateClicked(); } } ); }; UI.setRecordingButtonState = function (state) { Toolbar.setRecordingButtonState(state); }; UI.changeDesktopSharingButtonState = function (isUsingScreenStream) { Toolbar.changeDesktopSharingButtonState(isUsingScreenStream); }; UI.inputDisplayNameHandler = function (value) { VideoLayout.inputDisplayNameHandler(value); }; UI.onMucEntered = function (jid, id, displayName) { messageHandler.notify(displayName || 'Somebody', 'connected', 'connected'); // Add Peer's container VideoLayout.ensurePeerContainerExists(jid,id); }; UI.onMucPresenceStatus = function ( jid, info) { VideoLayout.setPresenceStatus( 'participant_' + Strophe.getResourceFromJid(jid), info.status); }; UI.onMucRoleChanged = function (role, displayName) { VideoLayout.showModeratorIndicator(); if (role === 'moderator') { var displayName = displayName; if (!displayName) { displayName = 'Somebody'; } messageHandler.notify( displayName, 'connected', 'Moderator rights granted to ' + displayName + '!'); } }; UI.updateLocalConnectionStats = function(percent, stats) { VideoLayout.updateLocalConnectionStats(percent, stats); }; UI.updateConnectionStats = function(jid, percent, stats) { VideoLayout.updateConnectionStats(jid, percent, stats); }; UI.onStatsStop = function () { VideoLayout.onStatsStop(); }; UI.getLargeVideoState = function() { return VideoLayout.getLargeVideoState(); }; UI.showLocalAudioIndicator = function (mute) { VideoLayout.showLocalAudioIndicator(mute); }; UI.changeLocalVideo = function (stream, flipx) { VideoLayout.changeLocalVideo(stream, flipx); }; UI.generateRoomName = function() { var roomnode = null; var path = window.location.pathname; // determinde the room node from the url // TODO: just the roomnode or the whole bare jid? if (config.getroomnode && typeof config.getroomnode === 'function') { // custom function might be responsible for doing the pushstate roomnode = config.getroomnode(path); } else { /* fall back to default strategy * this is making assumptions about how the URL->room mapping happens. * It currently assumes deployment at root, with a rewrite like the * following one (for nginx): location ~ ^/([a-zA-Z0-9]+)$ { rewrite ^/(.*)$ / break; } */ if (path.length > 1) { roomnode = path.substr(1).toLowerCase(); } else { var word = RoomNameGenerator.generateRoomWithoutSeparator(); roomnode = word.toLowerCase(); window.history.pushState('VideoChat', 'Room: ' + word, window.location.pathname + word); } } roomName = roomnode + '@' + config.hosts.muc; }; UI.connectionIndicatorShowMore = function(id) { return VideoLayout.connectionIndicators[id].showMore(); }; UI.showToolbar = function () { return ToolbarToggler.showToolbar(); }; UI.dockToolbar = function (isDock) { return ToolbarToggler.dockToolbar(isDock); }; function dump(elem, filename) { elem = elem.parentNode; elem.download = filename || 'meetlog.json'; elem.href = 'data:application/json;charset=utf-8,\n'; var data = {}; if (connection.jingle) { data = connection.jingle.populateData(); } var metadata = {}; metadata.time = new Date(); metadata.url = window.location.href; metadata.ua = navigator.userAgent; if (connection.logger) { metadata.xmpp = connection.logger.log; } data.metadata = metadata; elem.href += encodeURIComponent(JSON.stringify(data, null, ' ')); return false; } module.exports = UI;