Merge pull request #421 from isymchych/use-API

Use JS API in jitsi-meet
This commit is contained in:
hristoterezov 2015-12-03 16:21:03 -06:00
commit 98f0de258b
25 changed files with 23448 additions and 847 deletions

10
.editorconfig Normal file
View File

@ -0,0 +1,10 @@
# http://editorconfig.org
root = true
[*]
charset = utf-8
end_of_line = lf
indent_size = 4
indent_style = space
max_line_length = 80
trim_trailing_whitespace = true

View File

@ -2,6 +2,7 @@ node_modules
libs
debian
analytics.js
lib-jitsi-meet.js
modules/xmpp/strophe.emuc.js
modules/UI/prezi/Prezi.js

View File

@ -8,10 +8,13 @@ DEPLOY_DIR = libs
BROWSERIFY_FLAGS = -d
OUTPUT_DIR = .
all: compile uglify deploy clean
all: update-deps compile uglify deploy clean
update-deps:
$(NPM) update
compile:
$(NPM) update && $(BROWSERIFY) $(BROWSERIFY_FLAGS) -e app.js -s APP | $(EXORCIST) $(OUTPUT_DIR)/app.bundle.js.map > $(OUTPUT_DIR)/app.bundle.js
$(BROWSERIFY) $(BROWSERIFY_FLAGS) -e app.js -s APP | $(EXORCIST) $(OUTPUT_DIR)/app.bundle.js.map > $(OUTPUT_DIR)/app.bundle.js
clean:
rm -f $(OUTPUT_DIR)/app.bundle.*

317
app.js
View File

@ -1,4 +1,4 @@
/* jshint -W117 */
/* global $, JitsiMeetJS, config, Promise */
/* application specific logic */
require("jquery");
@ -12,37 +12,314 @@ window.toastr = require("toastr");
require("jQuery-Impromptu");
require("autosize");
var APP =
{
var CQEvents = require('./service/connectionquality/CQEvents');
var UIEvents = require('./service/UI/UIEvents');
var Commands = {
CONNECTION_QUALITY: "connectionQuality",
EMAIL: "email"
};
var APP = {
init: function () {
JitsiMeetJS.init();
JitsiMeetJS.setLogLevel(JitsiMeetJS.logLevels.TRACE);
this.conference = {
localId: undefined,
isModerator: false,
membersCount: 0,
audioMuted: false,
videoMuted: false,
isLocalId: function (id) {
return this.localId === id;
},
muteAudio: function (mute) {
APP.UI.eventEmitter.emit(UIEvents.AUDIO_MUTED, mute);
},
toggleAudioMuted: function () {
this.muteAudio(!this.audioMuted);
},
muteVideo: function (mute) {
APP.UI.eventEmitter.emit(UIEvents.VIDEO_MUTED, mute);
},
toggleVideoMuted: function () {
this.muteVideo(!this.videoMuted);
}
};
this.UI = require("./modules/UI/UI");
this.API = require("./modules/API/API");
this.connectionquality =
require("./modules/connectionquality/connectionquality");
this.statistics = require("./modules/statistics/statistics");
this.RTC = require("./modules/RTC/RTC");
this.desktopsharing =
require("./modules/desktopsharing/desktopsharing");
this.xmpp = require("./modules/xmpp/xmpp");
this.keyboardshortcut =
require("./modules/keyboardshortcut/keyboardshortcut");
this.translation = require("./modules/translation/translation");
this.settings = require("./modules/settings/Settings");
//this.DTMF = require("./modules/DTMF/DTMF");
this.members = require("./modules/members/MemberList");
this.configFetch = require("./modules/config/HttpConfigFetch");
}
};
function init() {
APP.desktopsharing.init();
APP.RTC.start();
APP.xmpp.start();
APP.statistics.start();
APP.connectionquality.init();
APP.keyboardshortcut.init();
APP.members.start();
var ConnectionEvents = JitsiMeetJS.events.connection;
var ConnectionErrors = JitsiMeetJS.errors.connection;
function connect() {
var connection = new JitsiMeetJS.JitsiConnection(null, null, {
hosts: config.hosts,
bosh: config.bosh,
clientNode: config.clientNode
});
return new Promise(function (resolve, reject) {
var handlers = {};
var unsubscribe = function () {
Object.keys(handlers).forEach(function (event) {
connection.removeEventListener(event, handlers[event]);
});
};
handlers[ConnectionEvents.CONNECTION_ESTABLISHED] = function () {
console.log('CONNECTED');
unsubscribe();
resolve(connection);
};
var listenForFailure = function (event) {
handlers[event] = function () {
// convert arguments to array
var args = Array.prototype.slice.call(arguments);
args.unshift(event);
// [event, ...params]
console.error('CONNECTION FAILED:', args);
unsubscribe();
reject(args);
};
};
listenForFailure(ConnectionEvents.CONNECTION_FAILED);
listenForFailure(ConnectionErrors.PASSWORD_REQUIRED);
listenForFailure(ConnectionErrors.CONNECTION_ERROR);
listenForFailure(ConnectionErrors.OTHER_ERRORS);
// install event listeners
Object.keys(handlers).forEach(function (event) {
connection.addEventListener(event, handlers[event]);
});
connection.connect();
}).catch(function (err) {
if (err[0] === ConnectionErrors.PASSWORD_REQUIRED) {
// FIXME ask for password and try again
return connect();
}
console.error('FAILED TO CONNECT', err);
APP.UI.notifyConnectionFailed(err[1]);
throw new Error(err[0]);
});
}
var ConferenceEvents = JitsiMeetJS.events.conference;
var ConferenceErrors = JitsiMeetJS.errors.conference;
function initConference(connection, roomName) {
var room = connection.initJitsiConference(roomName, {
openSctp: config.openSctp,
disableAudioLevels: config.disableAudioLevels
});
var users = {};
var localTracks = [];
APP.conference.localId = room.myUserId();
Object.defineProperty(APP.conference, "membersCount", {
get: function () {
return Object.keys(users).length; // FIXME maybe +1?
}
});
room.on(ConferenceEvents.USER_JOINED, function (id) {
users[id] = {
displayName: undefined,
tracks: []
};
// FIXME email???
APP.UI.addUser(id);
});
room.on(ConferenceEvents.USER_LEFT, function (id) {
delete users[id];
APP.UI.removeUser(id);
});
room.on(ConferenceEvents.TRACK_MUTE_CHANGED, function (track) {
// FIXME handle mute
});
room.on(ConferenceEvents.TRACK_AUDIO_LEVEL_CHANGED, function (id, lvl) {
APP.UI.setAudioLevel(id, lvl);
});
APP.UI.addListener(UIEvents.AUDIO_MUTED, function (muted) {
// FIXME mute or unmute
APP.UI.setAudioMuted(muted);
APP.conference.audioMuted = muted;
});
APP.UI.addListener(UIEvents.VIDEO_MUTED, function (muted) {
// FIXME mute or unmute
APP.UI.setVideoMuted(muted);
APP.conference.videoMuted = muted;
});
room.on(ConferenceEvents.IN_LAST_N_CHANGED, function (inLastN) {
if (config.muteLocalVideoIfNotInLastN) {
// TODO mute or unmute if required
// mark video on UI
// APP.UI.markVideoMuted(true/false);
}
});
room.on(ConferenceEvents.LAST_N_ENDPOINTS_CHANGED, function (ids) {
APP.UI.handleLastNEndpoints(ids);
});
room.on(ConferenceEvents.ACTIVE_SPEAKER_CHANGED, function (id) {
APP.UI.markDominantSpiker(id);
});
room.on(ConferenceEvents.CONNECTION_INTERRUPTED, function () {
APP.UI.markVideoInterrupted(true);
});
room.on(ConferenceEvents.CONNECTION_RESTORED, function () {
APP.UI.markVideoInterrupted(false);
});
APP.connectionquality.addListener(
CQEvents.LOCALSTATS_UPDATED,
function (percent, stats) {
APP.UI.updateLocalStats(percent, stats);
// send local stats to other users
room.sendCommand(Commands.CONNECTION_QUALITY, {
value: APP.connectionquality.convertToMUCStats(stats),
attributes: {
id: room.myUserId()
}
});
}
);
APP.connectionquality.addListener(CQEvents.STOP, function () {
APP.UI.hideStats();
room.removeCommand(Commands.CONNECTION_QUALITY);
});
// listen to remote stats
room.addCommandListener(Commands.CONNECTION_QUALITY, function (data) {
APP.connectionquality.updateRemoteStats(data.attributes.id, data.value);
});
APP.connectionquality.addListener(
CQEvents.REMOTESTATS_UPDATED,
function (id, percent, stats) {
APP.UI.updateRemoteStats(id, percent, stats);
}
);
// share email with other users
function sendEmail(email) {
room.sendCommand(Commands.EMAIL, {
value: email,
attributes: {
id: room.myUserId()
}
});
}
var email = APP.settings.getEmail();
email && sendEmail(email);
APP.UI.addListener(UIEvents.EMAIL_CHANGED, function (email) {
APP.settings.setEmail(email);
APP.UI.setUserAvatar(room.myUserId(), email);
sendEmail(email);
});
room.addCommandListener(Commands.EMAIL, function (data) {
APP.UI.setUserAvatar(data.attributes.id, data.value);
});
room.on(ConferenceEvents.DISPLAY_NAME_CHANGED, function (id, displayName) {
APP.UI.changeDisplayName(id, displayName);
});
APP.UI.addListener(UIEvents.NICKNAME_CHANGED, function (nickname) {
APP.settings.setDisplayName(nickname);
room.setDisplayName(nickname);
});
APP.UI.addListener(UIEvents.MESSAGE_CREATED, function (message) {
room.sendTextMessage(message);
});
room.on(ConferenceErrors.PASSWORD_REQUIRED, function () {
// FIXME handle
});
room.on(ConferenceErrors.CONNECTION_ERROR, function () {
// FIXME handle
});
APP.UI.addListener(
UIEvents.START_MUTED_CHANGED,
function (startAudioMuted, startVideoMuted) {
// FIXME start muted
}
);
return new Promise(function (resolve, reject) {
room.on(
ConferenceEvents.CONFERENCE_JOINED,
function () {
resolve();
}
);
APP.UI.closeAuthenticationDialog();
if (config.useNicks) {
// FIXME check this
var nick = APP.UI.askForNickname();
}
room.join();
}).catch(function (err) {
if (err[0] === ConferenceErrors.PASSWORD_REQUIRED) {
// FIXME ask for password and try again
return initConference(connection, roomName);
}
// FIXME else notify that we cannot conenct to the room
throw new Error(err[0]);
});
}
function init() {
connect().then(function (connection) {
return initConference(connection, APP.UI.generateRoomName());
}).then(function () {
APP.UI.start();
APP.UI.initConference();
APP.UI.addListener(UIEvents.LANG_CHANGED, function (language) {
APP.translation.setLanguage(language);
APP.settings.setLanguage(language);
});
APP.desktopsharing.init();
APP.statistics.start();
APP.connectionquality.init();
APP.keyboardshortcut.init();
});
}
/**
@ -90,17 +367,17 @@ $(document).ready(function () {
APP.translation.init();
if(APP.API.isEnabled())
if (APP.API.isEnabled()) {
APP.API.init();
}
APP.UI.start(obtainConfigAndInit);
obtainConfigAndInit();
});
$(window).bind('beforeunload', function () {
if(APP.API.isEnabled())
if (APP.API.isEnabled()) {
APP.API.dispose();
}
});
module.exports = APP;

View File

@ -14,6 +14,7 @@
<script src="https://api.callstats.io/static/callstats.min.js"></script>
<script src="config.js?v=15"></script><!-- adapt to your needs, i.e. set hosts and bosh path -->
<script src="interface_config.js?v=6"></script>
<script src="lib-jitsi-meet.js?v=139"></script>
<script src="libs/app.bundle.min.js?v=139"></script>
<script src="analytics.js?v=1"></script><!-- google analytics plugin -->
<!--

22739
lib-jitsi-meet.js Normal file

File diff suppressed because it is too large Load Diff

View File

@ -23,8 +23,8 @@ var commands = {};
function initCommands() {
commands = {
displayName: APP.UI.inputDisplayNameHandler,
toggleAudio: APP.UI.toggleAudio,
toggleVideo: APP.UI.toggleVideo,
toggleAudio: APP.conference.toggleAudioMuted,
toggleVideo: APP.conference.toggleVideoMuted,
toggleFilmStrip: APP.UI.toggleFilmStrip,
toggleChat: APP.UI.toggleChat,
toggleContactList: APP.UI.toggleContactList

View File

@ -21,22 +21,16 @@ UI.messageHandler = require("./util/MessageHandler");
var messageHandler = UI.messageHandler;
var Authentication = require("./authentication/Authentication");
var UIUtil = require("./util/UIUtil");
var NicknameHandler = require("./util/NicknameHandler");
var JitsiPopover = require("./util/JitsiPopover");
var CQEvents = require("../../service/connectionquality/CQEvents");
var DesktopSharingEventTypes
= require("../../service/desktopsharing/DesktopSharingEventTypes");
var MediaStreamType = require("../../service/RTC/MediaStreamTypes");
var RTCEvents = require("../../service/RTC/RTCEvents");
var RTCBrowserType = require("../RTC/RTCBrowserType");
var StreamEventTypes = require("../../service/RTC/StreamEventTypes");
var XMPPEvents = require("../../service/xmpp/XMPPEvents");
var StatisticsEvents = require("../../service/statistics/Events");
var UIEvents = require("../../service/UI/UIEvents");
var MemberEvents = require("../../service/members/Events");
var Feedback = require("./Feedback");
var eventEmitter = new EventEmitter();
UI.eventEmitter = eventEmitter;
var roomNode = null;
var roomName = null;
@ -64,7 +58,7 @@ function promptDisplayName() {
if (v == "ok") {
var displayName = f.displayName;
if (displayName) {
VideoLayout.inputDisplayNameHandler(displayName);
UI.inputDisplayNameHandler(displayName);
return true;
}
}
@ -86,11 +80,6 @@ function promptDisplayName() {
);
}
function notifyForInitialMute() {
messageHandler.notify(null, "notify.mutedTitle", "connected",
"notify.muted", null, {timeOut: 120000});
}
function setupPrezi() {
$("#reloadPresentationLink").click(function() {
Prezi.reloadPresentation();
@ -98,247 +87,83 @@ function setupPrezi() {
}
function setupChat() {
Chat.init();
Chat.init(eventEmitter);
$("#toggle_smileys").click(function() {
Chat.toggleSmileys();
});
}
function setupToolbars() {
Toolbar.init(UI);
Toolbar.init(eventEmitter);
Toolbar.setupButtonsFromConfig();
BottomToolbar.init(eventEmitter);
}
function streamHandler(stream, isMuted) {
switch (stream.type) {
case MediaStreamType.AUDIO_TYPE:
VideoLayout.changeLocalAudio(stream, isMuted);
break;
case MediaStreamType.VIDEO_TYPE:
VideoLayout.changeLocalVideo(stream, isMuted);
break;
default:
console.error("Unknown stream type: " + stream.type);
break;
}
}
function onXmppConnectionFailed(stropheErrorMsg) {
UI.notifyGracefulShudown = function () {
messageHandler.openMessageDialog(
'dialog.serviceUnavailable',
'dialog.gracefulShutdown'
);
};
UI.notifyReservationError = function (code, msg) {
var title = APP.translation.generateTranslationHTML(
"dialog.error");
"dialog.reservationError");
var message = APP.translation.generateTranslationHTML(
"dialog.reservationErrorMsg", {code: code, msg: msg});
messageHandler.openDialog(
title,
message,
true, {},
function (event, value, message, formVals) {
return false;
}
);
};
var message;
if (stropheErrorMsg) {
message = APP.translation.generateTranslationHTML(
"dialog.connectErrorWithMsg", {msg: stropheErrorMsg});
} else {
message = APP.translation.generateTranslationHTML(
"dialog.connectError");
UI.notifyKicked = function () {
messageHandler.openMessageDialog("dialog.sessTerminated", "dialog.kickMessage");
};
UI.notifyBridgeDown = function () {
messageHandler.showError("dialog.error", "dialog.bridgeUnavailable");
};
UI.changeDisplayName = function (id, displayName) {
ContactList.onDisplayNameChange(id, displayName);
SettingsMenu.onDisplayNameChange(id, displayName);
VideoLayout.onDisplayNameChanged(id, displayName);
};
UI.initConference = function () {
var id = APP.conference.localId;
Toolbar.updateRoomUrl(window.location.href);
var meHTML = APP.translation.generateTranslationHTML("me");
var settings = Settings.getSettings();
$("#localNick").html(settings.email || settings.uid + " (" + meHTML + ")");
// Make sure we configure our avatar id, before creating avatar for us
UI.setUserAvatar(id, settings.email || settings.uid);
// Add myself to the contact list.
ContactList.addContact(id);
// Once we've joined the muc show the toolbar
ToolbarToggler.showToolbar();
var displayName = config.displayJids ? id : settings.displayName;
if (displayName) {
UI.changeDisplayName('localVideoContainer', displayName);
}
messageHandler.openDialog(
title, message, true, {}, function (e, v, m, f) { return false; });
}
VideoLayout.mucJoined();
function onDisposeConference(unload) {
Toolbar.showAuthenticateButton(false);
}
function onDisplayNameChanged(jid, displayName) {
ContactList.onDisplayNameChange(jid, displayName);
SettingsMenu.onDisplayNameChange(jid, displayName);
VideoLayout.onDisplayNameChanged(jid, displayName);
}
Toolbar.checkAutoEnableDesktopSharing();
};
function registerListeners() {
APP.RTC.addStreamListener(streamHandler,
StreamEventTypes.EVENT_TYPE_LOCAL_CREATED);
APP.RTC.addStreamListener(streamHandler,
StreamEventTypes.EVENT_TYPE_LOCAL_CHANGED);
APP.RTC.addStreamListener(function (stream) {
VideoLayout.onRemoteStreamAdded(stream);
}, StreamEventTypes.EVENT_TYPE_REMOTE_CREATED);
APP.RTC.addListener(RTCEvents.LASTN_CHANGED, onLastNChanged);
APP.RTC.addListener(RTCEvents.DOMINANTSPEAKER_CHANGED,
function (resourceJid) {
VideoLayout.onDominantSpeakerChanged(resourceJid);
});
APP.RTC.addListener(RTCEvents.LASTN_ENDPOINT_CHANGED,
function (lastNEndpoints, endpointsEnteringLastN, stream) {
VideoLayout.onLastNEndpointsChanged(lastNEndpoints,
endpointsEnteringLastN, stream);
});
APP.RTC.addListener(RTCEvents.AVAILABLE_DEVICES_CHANGED,
function (devices) {
VideoLayout.setDeviceAvailabilityIcons(null, devices);
});
APP.RTC.addListener(RTCEvents.VIDEO_MUTE, UI.setVideoMuteButtonsState);
APP.RTC.addListener(RTCEvents.DATA_CHANNEL_OPEN, function () {
// when the data channel becomes available, tell the bridge about video
// selections so that it can do adaptive simulcast,
// we want the notification to trigger even if userJid is undefined,
// or null.
var userResource = APP.UI.getLargeVideoResource();
eventEmitter.emit(UIEvents.SELECTED_ENDPOINT, userResource);
});
APP.statistics.addListener(StatisticsEvents.AUDIO_LEVEL,
function(jid, audioLevel) {
var resourceJid;
if(jid === APP.statistics.LOCAL_JID) {
resourceJid = AudioLevels.LOCAL_LEVEL;
if(APP.RTC.localAudio.isMuted()) {
audioLevel = 0;
}
} else {
resourceJid = Strophe.getResourceFromJid(jid);
}
AudioLevels.updateAudioLevel(resourceJid, audioLevel,
UI.getLargeVideoResource());
});
APP.desktopsharing.addListener(
DesktopSharingEventTypes.INIT,
ToolbarToggler.showToolbar);
APP.desktopsharing.addListener(
DesktopSharingEventTypes.SWITCHING_DONE,
Toolbar.changeDesktopSharingButtonState);
APP.desktopsharing.addListener(
DesktopSharingEventTypes.FIREFOX_EXTENSION_NEEDED,
function (url) {
APP.UI.messageHandler.openMessageDialog(
"dialog.extensionRequired",
null,
null,
APP.translation.generateTranslationHTML(
"dialog.firefoxExtensionPrompt", {url: url}));
});
APP.connectionquality.addListener(CQEvents.LOCALSTATS_UPDATED,
VideoLayout.updateLocalConnectionStats);
APP.connectionquality.addListener(CQEvents.REMOTESTATS_UPDATED,
VideoLayout.updateConnectionStats);
APP.connectionquality.addListener(CQEvents.STOP,
VideoLayout.onStatsStop);
APP.xmpp.addListener(XMPPEvents.CONNECTION_FAILED, onXmppConnectionFailed);
APP.xmpp.addListener(XMPPEvents.DISPOSE_CONFERENCE, onDisposeConference);
APP.xmpp.addListener(XMPPEvents.GRACEFUL_SHUTDOWN, function () {
messageHandler.openMessageDialog(
'dialog.serviceUnavailable',
'dialog.gracefulShutdown'
);
});
APP.xmpp.addListener(XMPPEvents.RESERVATION_ERROR, function (code, msg) {
var title = APP.translation.generateTranslationHTML(
"dialog.reservationError");
var message = APP.translation.generateTranslationHTML(
"dialog.reservationErrorMsg", {code: code, msg: msg});
messageHandler.openDialog(
title,
message,
true, {},
function (event, value, message, formVals) {
return false;
}
);
});
APP.xmpp.addListener(XMPPEvents.KICKED, function () {
messageHandler.openMessageDialog("dialog.sessTerminated",
"dialog.kickMessage");
});
APP.xmpp.addListener(XMPPEvents.MUC_DESTROYED, function (reason) {
//FIXME: use Session Terminated from translation, but
// 'reason' text comes from XMPP packet and is not translated
var title = APP.translation.generateTranslationHTML("dialog.sessTerminated");
messageHandler.openDialog(
title, reason, true, {},
function (event, value, message, formVals) {
return false;
}
);
});
APP.xmpp.addListener(XMPPEvents.BRIDGE_DOWN, function () {
messageHandler.showError("dialog.error",
"dialog.bridgeUnavailable");
});
APP.xmpp.addListener(XMPPEvents.USER_ID_CHANGED, function (from, id) {
Avatar.setUserAvatar(from, id);
});
APP.xmpp.addListener(XMPPEvents.DISPLAY_NAME_CHANGED, onDisplayNameChanged);
APP.xmpp.addListener(XMPPEvents.MUC_JOINED, onMucJoined);
APP.xmpp.addListener(XMPPEvents.LOCAL_ROLE_CHANGED, onLocalRoleChanged);
APP.xmpp.addListener(XMPPEvents.MUC_MEMBER_JOINED, onMucMemberJoined);
APP.xmpp.addListener(XMPPEvents.MUC_ROLE_CHANGED, onMucRoleChanged);
APP.xmpp.addListener(XMPPEvents.PRESENCE_STATUS, onMucPresenceStatus);
APP.xmpp.addListener(XMPPEvents.SUBJECT_CHANGED, chatSetSubject);
APP.xmpp.addListener(XMPPEvents.MUC_MEMBER_LEFT, onMucMemberLeft);
APP.xmpp.addListener(XMPPEvents.PASSWORD_REQUIRED, onPasswordRequired);
APP.xmpp.addListener(XMPPEvents.ETHERPAD, initEtherpad);
APP.xmpp.addListener(XMPPEvents.AUTHENTICATION_REQUIRED,
onAuthenticationRequired);
APP.xmpp.addListener(XMPPEvents.PARTICIPANT_VIDEO_TYPE_CHANGED,
onPeerVideoTypeChanged);
APP.xmpp.addListener(XMPPEvents.DEVICE_AVAILABLE,
function (resource, devices) {
VideoLayout.setDeviceAvailabilityIcons(resource, devices);
});
APP.xmpp.addListener(XMPPEvents.PARTICIPANT_AUDIO_MUTED,
VideoLayout.onAudioMute);
APP.xmpp.addListener(XMPPEvents.PARTICIPANT_VIDEO_MUTED,
VideoLayout.onVideoMute);
APP.xmpp.addListener(XMPPEvents.AUDIO_MUTED_BY_FOCUS, function (doMuteAudio) {
UI.setAudioMuted(doMuteAudio);
});
APP.members.addListener(MemberEvents.DTMF_SUPPORT_CHANGED,
onDtmfSupportChanged);
APP.xmpp.addListener(XMPPEvents.START_MUTED_SETTING_CHANGED, function (audio, video) {
SettingsMenu.setStartMuted(audio, video);
});
APP.xmpp.addListener(XMPPEvents.START_MUTED_FROM_FOCUS, function (audio, video) {
UI.setInitialMuteFromFocus(audio, video);
});
APP.xmpp.addListener(XMPPEvents.JINGLE_FATAL_ERROR, function (session, error) {
UI.messageHandler.showError("dialog.sorry",
"dialog.internalError");
});
APP.xmpp.addListener(XMPPEvents.PROMPT_FOR_LOGIN, function (callback) {
// FIXME: re-use LoginDialog which supports retries
if (config.token) {
messageHandler.showError("dialog.error", "dialog.tokenAuthFailed");
} else {
UI.showLoginPopup(callback);
}
});
APP.xmpp.addListener(XMPPEvents.FOCUS_DISCONNECTED, function (focusComponent, retrySec) {
UI.messageHandler.notify(
null, "notify.focus",
'disconnected', "notify.focusFail",
{component: focusComponent, ms: retrySec});
});
APP.xmpp.addListener(XMPPEvents.ROOM_JOIN_ERROR, function (pres) {
UI.messageHandler.openReportDialog(null,
"dialog.connectError", pres);
});
APP.xmpp.addListener(XMPPEvents.ROOM_CONNECT_ERROR, function (pres) {
UI.messageHandler.openReportDialog(null,
"dialog.connectError", pres);
});
APP.xmpp.addListener(XMPPEvents.READY_TO_JOIN, function () {
var roomName = UI.generateRoomName();
APP.xmpp.allocateConferenceFocus(roomName, UI.checkForNicknameAndJoin);
});
//NicknameHandler emits this event
UI.addListener(UIEvents.NICKNAME_CHANGED, function (nickname) {
APP.xmpp.addToPresence("displayName", nickname);
});
UI.addListener(UIEvents.LARGEVIDEO_INIT, function () {
AudioLevels.init();
});
@ -347,48 +172,26 @@ function registerListeners() {
VideoLayout.onFilmStripToggled(isToggled);
});
if (!interfaceConfig.filmStripOnly) {
APP.xmpp.addListener(XMPPEvents.MESSAGE_RECEIVED, updateChatConversation);
APP.xmpp.addListener(XMPPEvents.CHAT_ERROR_RECEIVED, chatAddError);
// Listens for video interruption events.
APP.xmpp.addListener(XMPPEvents.CONNECTION_INTERRUPTED, VideoLayout.onVideoInterrupted);
// Listens for video restores events.
APP.xmpp.addListener(XMPPEvents.CONNECTION_RESTORED, VideoLayout.onVideoRestored);
}
}
/**
* Mutes/unmutes the local video.
*
* @param mute <tt>true</tt> to mute the local video; otherwise, <tt>false</tt>
* @param options an object which specifies optional arguments such as the
* <tt>boolean</tt> key <tt>byUser</tt> with default value <tt>true</tt> which
* specifies whether the method was initiated in response to a user command (in
* contrast to an automatic decision taken by the application logic)
*/
function setVideoMute(mute, options) {
APP.RTC.setVideoMute(mute,
UI.setVideoMuteButtonsState,
options);
}
function onResize() {
Chat.resizeChat();
VideoLayout.resizeLargeVideoContainer();
UI.addListener(UIEvents.EMAIL_CHANGED, function (email) {
UI.setUserAvatar(APP.conference.localId, email);
});
}
function bindEvents() {
/**
* Resizes and repositions videos in full screen mode.
*/
$(document).on('webkitfullscreenchange mozfullscreenchange fullscreenchange',
onResize);
function onResize() {
Chat.resizeChat();
VideoLayout.resizeLargeVideoContainer();
}
// Resize and reposition videos in full screen mode.
$(document).on(
'webkitfullscreenchange mozfullscreenchange fullscreenchange', onResize
);
$(window).resize(onResize);
}
UI.start = function (init) {
UI.start = function () {
document.title = interfaceConfig.APP_NAME;
var setupWelcomePage = null;
if(config.enableWelcomePage && window.location.pathname == "/" &&
@ -407,11 +210,9 @@ UI.start = function (init) {
// Set the defaults for prompt dialogs.
$.prompt.setDefaults({persistent: false});
registerListeners();
VideoLayout.init(eventEmitter);
NicknameHandler.init(eventEmitter);
bindEvents();
setupPrezi();
@ -427,12 +228,11 @@ UI.start = function (init) {
$('#notice').css({display: 'block'});
}
$("#downloadlog").click(function (event) {
dump(event.target);
// dump(event.target);
// FIXME integrate logs
});
Feedback.init();
}
else
{
} else {
$("#header").css("display", "none");
$("#bottomToolbar").css("display", "none");
$("#downloadlog").css("display", "none");
@ -440,25 +240,17 @@ UI.start = function (init) {
$("#remoteVideos").css("right", "0px");
messageHandler.disableNotifications();
$('body').popover("disable");
// $("[data-toggle=popover]").popover("disable");
JitsiPopover.enabled = false;
}
document.title = interfaceConfig.APP_NAME;
if(config.requireDisplayName) {
var currentSettings = Settings.getSettings();
if (!currentSettings.displayName) {
if (APP.settings.getDisplayName()) {
promptDisplayName();
}
}
init();
if (!interfaceConfig.filmStripOnly) {
toastr.options = {
"closeButton": true,
@ -483,12 +275,31 @@ UI.start = function (init) {
"newestOnTop": false
};
SettingsMenu.init();
}
};
UI.addLocalStream = function (stream, isMuted) {
switch (stream.type) {
case 'audio':
VideoLayout.changeLocalAudio(stream, isMuted);
break;
case 'video':
VideoLayout.changeLocalVideo(stream, isMuted);
break;
default:
console.error("Unknown stream type: " + stream.type);
break;
}
};
UI.addRemoteStream = function (stream) {
VideoLayout.onRemoteStreamAdded(stream);
};
function chatAddError(errorMessage, originalText) {
return Chat.chatAddError(errorMessage, originalText);
}
@ -497,59 +308,14 @@ function chatSetSubject(text) {
return Chat.chatSetSubject(text);
}
function updateChatConversation(from, displayName, message, myjid, stamp) {
return Chat.updateChatConversation(from, displayName, message, myjid, stamp);
}
function onMucJoined(jid, info) {
Toolbar.updateRoomUrl(window.location.href);
var meHTML = APP.translation.generateTranslationHTML("me");
$("#localNick").html(Strophe.getResourceFromJid(jid) + " (" + meHTML + ")");
var settings = Settings.getSettings();
// Make sure we configure our avatar id, before creating avatar for us
Avatar.setUserAvatar(jid, settings.email || settings.uid);
// Add myself to the contact list.
ContactList.addContact(jid);
// Once we've joined the muc show the toolbar
ToolbarToggler.showToolbar();
var displayName =
config.displayJids ? Strophe.getResourceFromJid(jid) : info.displayName;
if (displayName)
onDisplayNameChanged('localVideoContainer', displayName);
VideoLayout.mucJoined();
Toolbar.checkAutoEnableDesktopSharing();
function updateChatConversation(from, displayName, message, stamp) {
return Chat.updateChatConversation(from, displayName, message, stamp);
}
function initEtherpad(name) {
Etherpad.init(name);
}
function onMucMemberLeft(jid) {
console.log('left.muc', jid);
var displayName = $('#participant_' + Strophe.getResourceFromJid(jid) +
'>.displayname').html();
messageHandler.notify(displayName,'notify.somebody',
'disconnected',
'notify.disconnected');
if (!config.startAudioMuted ||
config.startAudioMuted > APP.members.size()) {
UIUtil.playSoundNotification('userLeft');
}
ContactList.removeContact(jid);
VideoLayout.participantLeft(jid);
}
function onLocalRoleChanged(jid, info, pres, isModerator) {
console.info("My role changed, new role: " + info.role);
onModeratorStatusChanged(isModerator);
@ -575,7 +341,7 @@ function onModeratorStatusChanged(isModerator) {
//Object.keys(connection.emuc.members).length >= 3);
}
function onPasswordRequired(callback) {
UI.notifyPasswordRequired = function (callback) {
// password is required
Toolbar.lockLockButton();
var message = '<h2 data-i18n="dialog.passwordRequired">';
@ -603,7 +369,7 @@ function onPasswordRequired(callback) {
},
':input:first'
);
}
};
/**
* The dialpad button is shown iff there is at least one member that supports
@ -614,21 +380,38 @@ function onDtmfSupportChanged(dtmfSupport) {
//Toolbar.showDialPadButton(dtmfSupport);
}
function onMucMemberJoined(jid, id, displayName) {
messageHandler.notify(displayName,'notify.somebody',
'connected',
'notify.connected');
UI.addUser = function (jid, id, displayName) {
messageHandler.notify(
displayName,'notify.somebody', 'connected', 'notify.connected'
);
if (!config.startAudioMuted ||
config.startAudioMuted > APP.members.size())
config.startAudioMuted > APP.conference.membersCount)
UIUtil.playSoundNotification('userJoined');
// Configure avatar
Avatar.setUserAvatar(jid, id);
UI.setUserAvatar(jid, id);
// Add Peer's container
VideoLayout.ensurePeerContainerExists(jid);
}
};
UI.removeUser = function (jid) {
console.log('left.muc', jid);
var displayName = $('#participant_' + Strophe.getResourceFromJid(jid) +
'>.displayname').html();
messageHandler.notify(displayName,'notify.somebody',
'disconnected',
'notify.disconnected');
if (!config.startAudioMuted ||
config.startAudioMuted > APP.conference.membersCount) {
UIUtil.playSoundNotification('userLeft');
}
ContactList.removeContact(jid);
VideoLayout.participantLeft(jid);
};
function onMucPresenceStatus(jid, info) {
VideoLayout.setPresenceStatus(Strophe.getResourceFromJid(jid), info.status);
@ -657,19 +440,13 @@ function onMucRoleChanged(role, displayName) {
}
}
function onAuthenticationRequired(intervalCallback) {
UI.notifyAuthRequired = function (intervalCallback) {
Authentication.openAuthenticationDialog(
roomName, intervalCallback, function () {
Toolbar.authenticateClicked();
});
}
function onLastNChanged(oldValue, newValue) {
if (config.muteLocalVideoIfNotInLastN) {
setVideoMute(!newValue, { 'byUser': false });
}
}
}
);
};
UI.toggleSmileys = function () {
@ -696,10 +473,6 @@ UI.inputDisplayNameHandler = function (value) {
VideoLayout.inputDisplayNameHandler(value);
};
UI.getLargeVideoResource = function () {
return VideoLayout.getLargeVideoResource();
};
/**
* Return the type of the remote video.
* @param jid the jid for the remote video
@ -779,86 +552,29 @@ UI.showLoginPopup = function(callback) {
);
};
UI.checkForNicknameAndJoin = function () {
UI.closeAuthenticationDialog = function () {
Authentication.closeAuthenticationDialog();
Authentication.stopInterval();
var nick = null;
if (config.useNicks) {
nick = window.prompt('Your nickname (optional)');
}
APP.xmpp.joinRoom(roomName, config.useNicks, nick);
};
function dump(elem, filename) {
elem = elem.parentNode;
elem.download = filename || 'meetlog.json';
elem.href = 'data:application/json;charset=utf-8,\n';
var data = APP.xmpp.getJingleLog();
var metadata = {};
metadata.time = new Date();
metadata.url = window.location.href;
metadata.ua = navigator.userAgent;
var log = APP.xmpp.getXmppLog();
if (log) {
metadata.xmpp = log;
}
data.metadata = metadata;
elem.href += encodeURIComponent(JSON.stringify(data, null, ' '));
return false;
}
UI.askForNickname = function () {
return window.prompt('Your nickname (optional)');
};
UI.getRoomName = function () {
return roomName;
};
UI.setInitialMuteFromFocus = function (muteAudio, muteVideo) {
if (muteAudio || muteVideo)
notifyForInitialMute();
if (muteAudio)
UI.setAudioMuted(true);
if (muteVideo)
UI.setVideoMute(true);
};
/**
* Mutes/unmutes the local video.
*/
UI.toggleVideo = function () {
setVideoMute(!APP.RTC.localVideo.isMuted());
};
/**
* Mutes / unmutes audio for the local participant.
*/
UI.toggleAudio = function() {
UI.setAudioMuted(!APP.RTC.localAudio.isMuted());
};
/**
* Sets muted audio state for the local participant.
*/
UI.setAudioMuted = function (mute, earlyMute) {
var audioMute = null;
if (earlyMute)
audioMute = function (mute, cb) {
return APP.xmpp.sendAudioInfoPresence(mute, cb);
};
else
audioMute = function (mute, cb) {
return APP.xmpp.setAudioMute(mute, cb);
};
if (!audioMute(mute, function () {
VideoLayout.showLocalAudioIndicator(mute);
UI.setAudioMuted = function (mute) {
VideoLayout.showLocalAudioIndicator(mute);
UIUtil.buttonClick("#toolbar_button_mute", "icon-microphone icon-mic-disabled");
};
UIUtil.buttonClick("#toolbar_button_mute", "icon-microphone icon-mic-disabled");
})) {
// We still click the button.
UIUtil.buttonClick("#toolbar_button_mute", "icon-microphone icon-mic-disabled");
return;
}
UI.setVideoMuted = function (muted) {
$('#toolbar_button_camera').toggleClass("icon-camera-disabled", muted);
};
UI.addListener = function (type, listener) {
@ -882,27 +598,95 @@ UI.dockToolbar = function (isDock) {
return ToolbarToggler.dockToolbar(isDock);
};
UI.setVideoMuteButtonsState = function (mute) {
var video = $('#toolbar_button_camera');
var communicativeClass = "icon-camera";
var muteClass = "icon-camera icon-camera-disabled";
UI.setUserAvatar = function (id, email) {
// update avatar
Avatar.setUserAvatar(id, email);
if (mute) {
video.removeClass(communicativeClass);
video.addClass(muteClass);
} else {
video.removeClass(muteClass);
video.addClass(communicativeClass);
var thumbUrl = Avatar.getThumbUrl(id);
var contactListUrl = Avatar.getContactListUrl(id);
VideoLayout.changeUserAvatar(id, thumbUrl);
ContactList.changeUserAvatar(id, contactListUrl);
if (APP.conference.isLocalId(id)) {
SettingsMenu.changeAvatar(thumbUrl);
}
};
UI.userAvatarChanged = function (resourceJid, thumbUrl, contactListUrl) {
VideoLayout.userAvatarChanged(resourceJid, thumbUrl);
ContactList.userAvatarChanged(resourceJid, contactListUrl);
if(resourceJid === APP.xmpp.myResource())
SettingsMenu.changeAvatar(thumbUrl);
UI.notifyConnectionFailed = function (stropheErrorMsg) {
var title = APP.translation.generateTranslationHTML(
"dialog.error");
var message;
if (stropheErrorMsg) {
message = APP.translation.generateTranslationHTML(
"dialog.connectErrorWithMsg", {msg: stropheErrorMsg});
} else {
message = APP.translation.generateTranslationHTML(
"dialog.connectError");
}
messageHandler.openDialog(
title, message, true, {}, function (e, v, m, f) { return false; }
);
};
UI.setVideoMute = setVideoMute;
UI.notifyFirefoxExtensionRequired = function (url) {
messageHandler.openMessageDialog(
"dialog.extensionRequired",
null,
null,
APP.translation.generateTranslationHTML(
"dialog.firefoxExtensionPrompt", {url: url}
)
);
};
UI.notifyInitiallyMuted = function () {
messageHandler.notify(
null, "notify.mutedTitle", "connected", "notify.muted", null, {timeOut: 120000}
);
};
UI.markDominantSpiker = function (id) {
VideoLayout.onDominantSpeakerChanged(id);
};
UI.handleLastNEndpoints = function (ids) {
VideoLayout.onLastNEndpointsChanged(ids, []);
};
UI.setAudioLevel = function (targetJid, lvl) {
AudioLevels.updateAudioLevel(
targetJid, lvl, VideoLayout.getLargeVideoResource()
);
};
UI.updateDesktopSharingButtons = function () {
Toolbar.changeDesktopSharingButtonState();
};
UI.hideStats = function () {
VideoLayout.hideStats();
};
UI.updateLocalStats = function (percent, stats) {
VideoLayout.updateLocalConnectionStats(percent, stats);
};
UI.updateRemoteStats = function (jid, percent, stats) {
VideoLayout.updateConnectionStats(jid, percent, stats);
};
UI.showAuthenticateButton = function (show) {
Toolbar.showAuthenticateButton(show);
};
UI.markVideoInterrupted = function (interrupted) {
if (interrupted) {
VideoLayout.onVideoInterrupted();
} else {
VideoLayout.onVideoRestored();
}
};
module.exports = UI;

View File

@ -109,10 +109,10 @@ var AudioLevels = (function(my) {
drawContext.drawImage(canvasCache, 0, 0);
if(resourceJid === AudioLevels.LOCAL_LEVEL) {
if(!APP.xmpp.myJid()) {
resourceJid = APP.conference.localId;
if (!resourceJid) {
return;
}
resourceJid = APP.xmpp.myResource();
}
if(resourceJid === largeVideoResourceJid) {
@ -223,11 +223,11 @@ var AudioLevels = (function(my) {
*/
function getVideoSpanId(resourceJid) {
var videoSpanId = null;
if (resourceJid === AudioLevels.LOCAL_LEVEL ||
(APP.xmpp.myResource() && resourceJid === APP.xmpp.myResource()))
if (resourceJid === AudioLevels.LOCAL_LEVEL || APP.conference.isLocalId(resourceJid)) {
videoSpanId = 'localVideoContainer';
else
} else {
videoSpanId = 'participant_' + resourceJid;
}
return videoSpanId;
}

View File

@ -1,6 +1,4 @@
/* global Strophe, APP, MD5 */
var Settings = require("../../settings/Settings");
/* global MD5 */
var users = {};
var Avatar = {
@ -8,57 +6,55 @@ var Avatar = {
/**
* Sets the user's avatar in the settings menu(if local user), contact list
* and thumbnail
* @param jid jid of the user
* @param id email or userID to be used as a hash
* @param id id of the user
* @param email email or nickname to be used as a hash
*/
setUserAvatar: function (jid, id) {
if (id) {
if (users[jid] === id) {
setUserAvatar: function (id, email) {
if (email) {
if (users[id] === email) {
return;
}
users[jid] = id;
users[id] = email;
}
var thumbUrl = this.getThumbUrl(jid);
var contactListUrl = this.getContactListUrl(jid);
var resourceJid = Strophe.getResourceFromJid(jid);
APP.UI.userAvatarChanged(resourceJid, thumbUrl, contactListUrl);
var thumbUrl = this.getThumbUrl(id);
var contactListUrl = this.getContactListUrl(id);
},
/**
* Returns image URL for the avatar to be displayed on large video area
* where current active speaker is presented.
* @param jid full MUC jid of the user for whom we want to obtain avatar URL
* @param id id of the user for whom we want to obtain avatar URL
*/
getActiveSpeakerUrl: function (jid) {
return this.getGravatarUrl(jid, 100);
getActiveSpeakerUrl: function (id) {
return this.getGravatarUrl(id, 100);
},
/**
* Returns image URL for the avatar to be displayed on small video thumbnail
* @param jid full MUC jid of the user for whom we want to obtain avatar URL
* @param id id of the user for whom we want to obtain avatar URL
*/
getThumbUrl: function (jid) {
return this.getGravatarUrl(jid, 100);
getThumbUrl: function (id) {
return this.getGravatarUrl(id, 100);
},
/**
* Returns the URL for the avatar to be displayed as contactlist item
* @param jid full MUC jid of the user for whom we want to obtain avatar URL
* @param id id of the user for whom we want to obtain avatar URL
*/
getContactListUrl: function (jid) {
return this.getGravatarUrl(jid, 30);
getContactListUrl: function (id) {
return this.getGravatarUrl(id, 30);
},
getGravatarUrl: function (jid, size) {
if (!jid) {
console.error("Get gravatar - jid is undefined");
getGravatarUrl: function (id, size) {
if (!id) {
console.error("Get gravatar - id is undefined");
return null;
}
var id = users[jid];
if (!id) {
var email = users[id];
if (!email) {
console.warn(
"No avatar stored yet for " + jid + " - using JID as ID");
id = jid;
"No avatar stored yet for " + id + " - using user id as ID"
);
email = id;
}
return 'https://www.gravatar.com/avatar/' +
MD5.hexdigest(id.trim().toLowerCase()) +
MD5.hexdigest(email.trim().toLowerCase()) +
"?d=wavatar&size=" + (size || "30");
}

View File

@ -1,9 +1,8 @@
/* global APP, $, Util, nickname:true */
/* global APP, $ */
var Replacement = require("./Replacement");
var CommandsProcessor = require("./Commands");
var ToolbarToggler = require("../../toolbars/ToolbarToggler");
var smileys = require("./smileys.json").smileys;
var NicknameHandler = require("../../util/NicknameHandler");
var UIUtil = require("../../util/UIUtil");
var UIEvents = require("../../../../service/UI/UIEvents");
@ -169,22 +168,18 @@ var Chat = (function (my) {
/**
* Initializes chat related interface.
*/
my.init = function () {
if(NicknameHandler.getNickname())
my.init = function (eventEmitter) {
if (APP.settings.getDisplayName()) {
Chat.setChatConversationMode(true);
NicknameHandler.addListener(UIEvents.NICKNAME_CHANGED,
function (nickname) {
Chat.setChatConversationMode(true);
});
}
$('#nickinput').keydown(function (event) {
if (event.keyCode === 13) {
event.preventDefault();
var val = UIUtil.escapeHtml(this.value);
this.value = '';
if (!NicknameHandler.getNickname()) {
NicknameHandler.setNickname(val);
if (APP.settings.getDisplayName()) {
eventEmitter.emit(UIEvents.NICKNAME_CHANGED, val);
return;
}
}
@ -203,8 +198,7 @@ var Chat = (function (my) {
}
else {
var message = UIUtil.escapeHtml(value);
APP.xmpp.sendChatMessage(message,
NicknameHandler.getNickname());
eventEmitter.emit(UIEvents.MESSAGE_CREATED, message);
}
}
});
@ -228,7 +222,7 @@ var Chat = (function (my) {
* Appends the given message to the chat conversation.
*/
my.updateChatConversation =
function (from, displayName, message, myjid, stamp) {
function (from, displayName, message, stamp) {
var divClassName = '';
if (APP.xmpp.myJid() === from) {

View File

@ -169,21 +169,20 @@ var ContactList = {
}
},
onDisplayNameChange: function (peerJid, displayName) {
if (peerJid === 'localVideoContainer')
peerJid = APP.xmpp.myJid();
onDisplayNameChange: function (id, displayName) {
if (id === 'localVideoContainer') {
id = APP.conference.localId;
}
var contactName = $('#contacts #' + id + '>p');
var resourceJid = Strophe.getResourceFromJid(peerJid);
var contactName = $('#contacts #' + resourceJid + '>p');
if (contactName && displayName && displayName.length > 0)
if (contactName && displayName && displayName.length > 0) {
contactName.html(displayName);
}
},
userAvatarChanged: function (resourceJid, contactListUrl) {
changeUserAvatar: function (id, contactListUrl) {
// set the avatar in the contact list
var contact = $('#' + resourceJid + '>img');
var contact = $('#' + id + '>img');
if (contact && contact.length > 0) {
contact.get(0).src = contactListUrl;
}

View File

@ -1,8 +1,8 @@
/* global APP, $ */
var Avatar = require("../../avatar/Avatar");
var Settings = require("./../../../settings/Settings");
var UIUtil = require("../../util/UIUtil");
var languages = require("../../../../service/translation/languages");
var UIEvents = require("../../../../service/UI/UIEvents");
function generateLanguagesSelectBox() {
var currentLang = APP.translation.getCurrentLanguage();
@ -24,7 +24,9 @@ function generateLanguagesSelectBox() {
var SettingsMenu = {
init: function () {
init: function (emitter) {
this.emitter = emitter;
var startMutedSelector = $("#startMutedOptions");
startMutedSelector.before(generateLanguagesSelectBox());
APP.translation.translateElement($("#languages_selectbox"));
@ -34,10 +36,9 @@ var SettingsMenu = {
}
});
if (APP.xmpp.isModerator()) {
if (APP.conference.isModerator) {
startMutedSelector.css("display", "block");
}
else {
} else {
startMutedSelector.css("display", "none");
}
@ -47,7 +48,7 @@ var SettingsMenu = {
},
onRoleChanged: function () {
if(APP.xmpp.isModerator()) {
if(APP.conference.isModerator) {
$("#startMutedOptions").css("display", "block");
}
else {
@ -61,43 +62,35 @@ var SettingsMenu = {
},
update: function() {
// FIXME check if this values really changed:
// compare them with Settings etc.
var newDisplayName =
UIUtil.escapeHtml($('#setDisplayName').get(0).value);
var newEmail = UIUtil.escapeHtml($('#setEmail').get(0).value);
UIUtil.escapeHtml($('#setDisplayName').get(0).value);
if(newDisplayName) {
var displayName = Settings.setDisplayName(newDisplayName);
APP.xmpp.addToPresence("displayName", displayName, true);
if (newDisplayName) {
this.emitter.emit(UIEvents.NICKNAME_CHANGED, newDisplayName);
}
var language = $("#languages_selectbox").val();
APP.translation.setLanguage(language);
Settings.setLanguage(language);
this.emitter.emit(UIEvents.LANG_CHANGED, language);
APP.xmpp.addToPresence("email", newEmail);
var email = Settings.setEmail(newEmail);
var newEmail = UIUtil.escapeHtml($('#setEmail').get(0).value);
this.emitter.emit(UIEvents.EMAIL_CHANGED, newEmail);
var startAudioMuted = ($("#startAudioMuted").is(":checked"));
var startVideoMuted = ($("#startVideoMuted").is(":checked"));
APP.xmpp.addToPresence("startMuted",
[startAudioMuted, startVideoMuted]);
Avatar.setUserAvatar(APP.xmpp.myJid(), email);
this.emitter.emit(
UIEvents.START_MUTED_CHANGED, startAudioMuted, startVideoMuted
);
},
isVisible: function() {
return $('#settingsmenu').is(':visible');
},
setDisplayName: function(newDisplayName) {
var displayName = Settings.setDisplayName(newDisplayName);
$('#setDisplayName').get(0).value = displayName;
},
onDisplayNameChange: function(peerJid, newDisplayName) {
if(peerJid === 'localVideoContainer' ||
peerJid === APP.xmpp.myJid()) {
this.setDisplayName(newDisplayName);
onDisplayNameChange: function(id, newDisplayName) {
if(id === 'localVideoContainer' || APP.conference.isLocalId(id)) {
$('#setDisplayName').get(0).value = newDisplayName;
}
},
changeAvatar: function (thumbUrl) {

View File

@ -1,5 +1,4 @@
/* global APP, $, buttonClick, config, lockRoom, interfaceConfig, setSharedKey,
Util */
/* global APP, $, config, interfaceConfig */
/* jshint -W101 */
var messageHandler = require("../util/MessageHandler");
var BottomToolbar = require("./BottomToolbar");
@ -12,28 +11,31 @@ var AuthenticationEvents
= require("../../../service/authentication/AuthenticationEvents");
var AnalyticsAdapter = require("../../statistics/AnalyticsAdapter");
var Feedback = require("../Feedback");
var UIEvents = require("../../../service/UI/UIEvents");
var roomUrl = null;
var sharedKey = '';
var UI = null;
var recordingToaster = null;
var emitter = null;
var buttonHandlers = {
"toolbar_button_mute": function () {
if (APP.RTC.localAudio.isMuted()) {
AnalyticsAdapter.sendEvent('toolbar.audio.unmuted');
emitter.emit(UIEvents.AUDIO_MUTED, false);
} else {
AnalyticsAdapter.sendEvent('toolbar.audio.muted');
emitter.emit(UIEvents.AUDIO_MUTED, true);
}
return APP.UI.toggleAudio();
},
"toolbar_button_camera": function () {
if (APP.RTC.localVideo.isMuted()) {
AnalyticsAdapter.sendEvent('toolbar.video.enabled');
emitter.emit(UIEvents.VIDEO_MUTED, false);
} else {
AnalyticsAdapter.sendEvent('toolbar.video.disabled');
emitter.emit(UIEvents.VIDEO_MUTED, true);
}
return APP.UI.toggleVideo();
},
/*"toolbar_button_authentication": function () {
return Toolbar.authenticateClicked();
@ -299,7 +301,7 @@ function callSipButtonClicked() {
var numberInput = f.sipNumber;
if (numberInput) {
APP.xmpp.dial(
numberInput, 'fromnumber', UI.getRoomName(), sharedKey);
numberInput, 'fromnumber', APP.UI.getRoomName(), sharedKey);
}
}
},
@ -309,12 +311,12 @@ function callSipButtonClicked() {
var Toolbar = (function (my) {
my.init = function (ui) {
my.init = function (eventEmitter) {
emitter = eventEmitter;
UIUtil.hideDisabledButtons(defaultToolbarButtons);
for(var k in buttonHandlers)
$("#" + k).click(buttonHandlers[k]);
UI = ui;
// Update login info
APP.xmpp.addListener(
AuthenticationEvents.IDENTITY_UPDATED,
@ -353,12 +355,12 @@ var Toolbar = (function (my) {
}
// Get authentication URL
if (!APP.xmpp.isMUCJoined()) {
APP.xmpp.getLoginUrl(UI.getRoomName(), function (url) {
APP.xmpp.getLoginUrl(APP.UI.getRoomName(), function (url) {
// If conference has not been started yet - redirect to login page
window.location.href = url;
});
} else {
APP.xmpp.getPopupLoginUrl(UI.getRoomName(), function (url) {
APP.xmpp.getPopupLoginUrl(APP.UI.getRoomName(), function (url) {
// Otherwise - open popup with authentication URL
var authenticationWindow = Authentication.createAuthenticationWindow(
function () {

View File

@ -1,5 +1,4 @@
/* global APP, config, $, interfaceConfig, Moderator,
DesktopStreaming.showDesktopSharingButton */
/* global APP, config, $, interfaceConfig */
var toolbarTimeoutObject,
toolbarTimeout = interfaceConfig.INITIAL_TOOLBAR_TIMEOUT,
@ -75,13 +74,6 @@ var ToolbarToggler = {
toolbarTimeout = interfaceConfig.TOOLBAR_TIMEOUT;
}
if (APP.xmpp.isModerator())
{
// TODO: Enable settings functionality.
// Need to uncomment the settings button in index.html.
// $('#settingsButton').css({visibility:"visible"});
}
// Show/hide desktop sharing button
showDesktopSharingButton();
},

View File

@ -1,30 +0,0 @@
var UIEvents = require("../../../service/UI/UIEvents");
var nickname = null;
var eventEmitter = null;
var NicknameHandler = {
init: function (emitter) {
eventEmitter = emitter;
var storedDisplayName = window.localStorage.displayname;
if (storedDisplayName) {
nickname = storedDisplayName;
}
},
setNickname: function (newNickname) {
if (!newNickname || nickname === newNickname)
return;
nickname = newNickname;
window.localStorage.displayname = nickname;
eventEmitter.emit(UIEvents.NICKNAME_CHANGED, newNickname);
},
getNickname: function () {
return nickname;
},
addListener: function (type, listener) {
eventEmitter.on(type, listener);
}
};
module.exports = NicknameHandler;

View File

@ -1,12 +1,12 @@
/* global $, interfaceConfig, APP */
var SmallVideo = require("./SmallVideo");
var ConnectionIndicator = require("./ConnectionIndicator");
var NicknameHandler = require("../util/NicknameHandler");
var UIUtil = require("../util/UIUtil");
var UIEvents = require("../../../service/UI/UIEvents");
var LargeVideo = require("./LargeVideo");
var RTCBrowserType = require("../../RTC/RTCBrowserType");
function LocalVideo(VideoLayout) {
function LocalVideo(VideoLayout, emitter) {
this.videoSpanId = "localVideoContainer";
this.container = $("#localVideoContainer").get(0);
this.bindHoverHandler();
@ -14,6 +14,7 @@ function LocalVideo(VideoLayout) {
this.flipX = true;
this.isLocal = true;
this.peerJid = null;
this.emitter = emitter;
}
LocalVideo.prototype = Object.create(SmallVideo.prototype);
@ -117,11 +118,13 @@ LocalVideo.prototype.setDisplayName = function(displayName, key) {
editDisplayName.one("focusout", function (e) {
self.VideoLayout.inputDisplayNameHandler(this.value);
$('#editDisplayName').hide();
});
editDisplayName.on('keydown', function (e) {
if (e.keyCode === 13) {
e.preventDefault();
$('#editDisplayName').hide();
self.VideoLayout.inputDisplayNameHandler(this.value);
}
});
@ -130,25 +133,7 @@ LocalVideo.prototype.setDisplayName = function(displayName, key) {
};
LocalVideo.prototype.inputDisplayNameHandler = function (name) {
name = UIUtil.escapeHtml(name);
NicknameHandler.setNickname(name);
var localDisplayName = $('#localDisplayName');
if (!localDisplayName.is(":visible")) {
if (NicknameHandler.getNickname()) {
var meHTML = APP.translation.generateTranslationHTML("me");
localDisplayName.html(NicknameHandler.getNickname() + " (" +
meHTML + ")");
} else {
var defaultHTML = APP.translation.generateTranslationHTML(
interfaceConfig.DEFAULT_LOCAL_DISPLAY_NAME);
localDisplayName .html(defaultHTML);
}
localDisplayName.show();
}
$('#editDisplayName').hide();
this.emitter.emit(UIEvents.NICKNAME_CHANGED, UIUtil.escapeHtml(name));
};
LocalVideo.prototype.createConnectionIndicator = function() {

View File

@ -36,7 +36,7 @@ var focusedVideoResourceJid = null;
var VideoLayout = (function (my) {
my.init = function (emitter) {
eventEmitter = emitter;
localVideoThumbnail = new LocalVideo(VideoLayout);
localVideoThumbnail = new LocalVideo(VideoLayout, emitter);
if (interfaceConfig.filmStripOnly) {
LargeVideo.disable();
} else {
@ -56,8 +56,6 @@ var VideoLayout = (function (my) {
};
my.changeLocalAudio = function(stream, isMuted) {
if (isMuted)
APP.UI.setAudioMuted(true, true);
APP.RTC.attachMediaStream($('#localAudio'), stream.getOriginalStream());
var localAudio = document.getElementById('localAudio');
// Writing volume not allowed in IE
@ -177,7 +175,7 @@ var VideoLayout = (function (my) {
console.info("electLastVisibleVideo: " + jid);
return jid;
};
my.onRemoteStreamAdded = function (stream) {
if (stream.peerjid) {
VideoLayout.ensurePeerContainerExists(stream.peerjid);
@ -277,9 +275,9 @@ var VideoLayout = (function (my) {
/**
* Checks if container for participant identified by given peerJid exists
* in the document and creates it eventually.
*
*
* @param peerJid peer Jid to check.
*
*
* @return Returns <tt>true</tt> if the peer container exists,
* <tt>false</tt> - otherwise
*/
@ -589,16 +587,13 @@ var VideoLayout = (function (my) {
/**
* Display name changed.
*/
my.onDisplayNameChanged =
function (jid, displayName, status) {
if (jid === 'localVideoContainer' ||
jid === APP.xmpp.myJid()) {
my.onDisplayNameChanged = function (id, displayName, status) {
if (id === 'localVideoContainer' ||
APP.conference.isLocalId(id)) {
localVideoThumbnail.setDisplayName(displayName);
} else {
VideoLayout.ensurePeerContainerExists(jid);
remoteVideos[Strophe.getResourceFromJid(jid)].setDisplayName(
displayName,
status);
VideoLayout.ensurePeerContainerExists(id);
remoteVideos[id].setDisplayName(displayName, status);
}
};
@ -652,9 +647,7 @@ var VideoLayout = (function (my) {
* @param endpointsEnteringLastN the list currently entering last N
* endpoints
*/
my.onLastNEndpointsChanged = function (lastNEndpoints,
endpointsEnteringLastN,
stream) {
my.onLastNEndpointsChanged = function (lastNEndpoints, endpointsEnteringLastN) {
if (lastNCount !== lastNEndpoints.length)
lastNCount = lastNEndpoints.length;
@ -847,7 +840,7 @@ var VideoLayout = (function (my) {
/**
* Hides all the indicators
*/
my.onStatsStop = function () {
my.hideStats = function () {
for(var video in remoteVideos) {
remoteVideos[video].hideIndicator();
}
@ -879,7 +872,7 @@ var VideoLayout = (function (my) {
VideoLayout.resizeThumbnails();
};
my.onVideoTypeChanged = function (resourceJid, newVideoType) {
if (remoteVideoTypes[resourceJid] === newVideoType) {
return;
@ -1005,14 +998,16 @@ var VideoLayout = (function (my) {
}
};
my.userAvatarChanged = function(resourceJid, thumbUrl) {
var smallVideo = VideoLayout.getSmallVideo(resourceJid);
if(smallVideo)
my.changeUserAvatar = function(id, thumbUrl) {
var smallVideo = VideoLayout.getSmallVideo(id);
if (smallVideo) {
smallVideo.avatarChanged(thumbUrl);
else
} else {
console.warn(
"Missed avatar update - no small video yet for " + resourceJid);
LargeVideo.updateAvatar(resourceJid, thumbUrl);
"Missed avatar update - no small video yet for " + id
);
}
LargeVideo.updateAvatar(id, thumbUrl);
};
my.createEtherpadIframe = function(src, onloadHandler)

View File

@ -3,7 +3,6 @@
var EventEmitter = require("events");
var eventEmitter = new EventEmitter();
var CQEvents = require("../../service/connectionquality/CQEvents");
var XMPPEvents = require("../../service/xmpp/XMPPEvents");
var StatisticsEvents = require("../../service/statistics/Events");
/**
@ -18,43 +17,6 @@ var stats = {};
*/
var remoteStats = {};
/**
* Interval for sending statistics to other participants
* @type {null}
*/
var sendIntervalId = null;
/**
* Start statistics sending.
*/
function startSendingStats() {
sendStats();
sendIntervalId = setInterval(sendStats, 10000);
}
/**
* Sends statistics to other participants
*/
function sendStats() {
APP.xmpp.addToPresence("connectionQuality", convertToMUCStats(stats));
}
/**
* Converts statistics to format for sending through XMPP
* @param stats the statistics
* @returns {{bitrate_donwload: *, bitrate_uplpoad: *, packetLoss_total: *, packetLoss_download: *, packetLoss_upload: *}}
*/
function convertToMUCStats(stats) {
return {
"bitrate_download": stats.bitrate.download,
"bitrate_upload": stats.bitrate.upload,
"packetLoss_total": stats.packetLoss.total,
"packetLoss_download": stats.packetLoss.download,
"packetLoss_upload": stats.packetLoss.upload
};
}
/**
* Converts statistics to format used by VideoLayout
* @param stats
@ -76,11 +38,12 @@ function parseMUCStats(stats) {
var ConnectionQuality = {
init: function () {
APP.xmpp.addListener(XMPPEvents.REMOTE_STATS, this.updateRemoteStats);
APP.statistics.addListener(StatisticsEvents.CONNECTION_STATS,
this.updateLocalStats);
APP.statistics.addListener(StatisticsEvents.STOP,
this.stopSendingStats);
APP.statistics.addListener(
StatisticsEvents.CONNECTION_STATS, this.updateLocalStats
);
APP.statistics.addListener(
StatisticsEvents.STOP, this.stopSendingStats
);
},
/**
@ -90,33 +53,29 @@ var ConnectionQuality = {
updateLocalStats: function (data) {
stats = data;
eventEmitter.emit(CQEvents.LOCALSTATS_UPDATED, 100 - stats.packetLoss.total, stats);
if (!sendIntervalId) {
startSendingStats();
}
},
/**
* Updates remote statistics
* @param jid the jid associated with the statistics
* @param id the id associated with the statistics
* @param data the statistics
*/
updateRemoteStats: function (jid, data) {
updateRemoteStats: function (id, data) {
if (!data || !data.packetLoss_total) {
eventEmitter.emit(CQEvents.REMOTESTATS_UPDATED, jid, null, null);
eventEmitter.emit(CQEvents.REMOTESTATS_UPDATED, id, null, null);
return;
}
remoteStats[jid] = parseMUCStats(data);
remoteStats[id] = parseMUCStats(data);
eventEmitter.emit(CQEvents.REMOTESTATS_UPDATED,
jid, 100 - data.packetLoss_total, remoteStats[jid]);
eventEmitter.emit(
CQEvents.REMOTESTATS_UPDATED, id, 100 - data.packetLoss_total, remoteStats[id]
);
},
/**
* Stops statistics sending.
*/
stopSendingStats: function () {
clearInterval(sendIntervalId);
sendIntervalId = null;
//notify UI about stopping statistics gathering
eventEmitter.emit(CQEvents.STOP);
},
@ -127,11 +86,25 @@ var ConnectionQuality = {
getStats: function () {
return stats;
},
addListener: function (type, listener) {
eventEmitter.on(type, listener);
}
},
/**
* Converts statistics to format for sending through XMPP
* @param stats the statistics
* @returns {{bitrate_donwload: *, bitrate_uplpoad: *, packetLoss_total: *, packetLoss_download: *, packetLoss_upload: *}}
*/
convertToMUCStats: function (stats) {
return {
"bitrate_download": stats.bitrate.download,
"bitrate_upload": stats.bitrate.upload,
"packetLoss_total": stats.packetLoss.total,
"packetLoss_download": stats.packetLoss.download,
"packetLoss_upload": stats.packetLoss.upload
};
}
};
module.exports = ConnectionQuality;

View File

@ -21,20 +21,18 @@ function initShortcutHandlers() {
77: {
character: "M",
id: "mutePopover",
function: APP.UI.toggleAudio
function: APP.conference.toggleAudioMuted
},
84: {
character: "T",
function: function() {
if(!APP.RTC.localAudio.isMuted()) {
APP.UI.toggleAudio();
}
APP.conference.muteAudio(true);
}
},
86: {
character: "V",
id: "toggleVideoPopover",
function: APP.UI.toggleVideo
function: APP.conference.toggleVideoMuted
}
};
}
@ -67,9 +65,7 @@ var KeyboardShortcut = {
$(":focus").is("input[type=password]") ||
$(":focus").is("textarea"))) {
if(e.which === "T".charCodeAt(0)) {
if(APP.RTC.localAudio.isMuted()) {
APP.UI.toggleAudio();
}
APP.conference.muteAudio(true);
}
}
};

View File

@ -1,128 +0,0 @@
/* global APP, require, $ */
/**
* This module is meant to (eventually) contain and manage all information
* about members/participants of the conference, so that other modules don't
* have to do it on their own, and so that other modules can access members'
* information from a single place.
*
* Currently this module only manages information about the support of jingle
* DTMF of the members. Other fields, as well as accessor methods are meant to
* be added as needed.
*/
var XMPPEvents = require("../../service/xmpp/XMPPEvents");
var Events = require("../../service/members/Events");
var EventEmitter = require("events");
var eventEmitter = new EventEmitter();
/**
* The actual container.
*/
var members = {};
/**
* There is at least one member that supports DTMF (i.e. is jigasi).
*/
var atLeastOneDtmf = false;
function registerListeners() {
APP.xmpp.addListener(XMPPEvents.MUC_MEMBER_JOINED, onMucMemberJoined);
APP.xmpp.addListener(XMPPEvents.MUC_MEMBER_LEFT, onMucMemberLeft);
}
/**
* Handles a new member joining the MUC.
*/
function onMucMemberJoined(jid, id, displayName) {
var member = {
displayName: displayName
};
APP.xmpp.getConnection().disco.info(
jid, "" /* node */, function(iq) { onDiscoInfoReceived(jid, iq); });
members[jid] = member;
}
/**
* Handles a member leaving the MUC.
*/
function onMucMemberLeft(jid) {
delete members[jid];
updateAtLeastOneDtmf();
}
/**
* Handles the reception of a disco#info packet from a particular JID.
* @param jid the JID sending the packet.
* @param iq the packet.
*/
function onDiscoInfoReceived(jid, iq) {
if (!members[jid])
return;
var supportsDtmf
= $(iq).find('>query>feature[var="urn:xmpp:jingle:dtmf:0"]').length > 0;
updateDtmf(jid, supportsDtmf);
}
/**
* Updates the 'supportsDtmf' field for a member.
* @param jid the jid of the member.
* @param newValue the new value for the 'supportsDtmf' field.
*/
function updateDtmf(jid, newValue) {
var oldValue = members[jid].supportsDtmf;
members[jid].supportsDtmf = newValue;
if (newValue != oldValue) {
updateAtLeastOneDtmf();
}
}
/**
* Checks each member's 'supportsDtmf' field and updates
* 'atLastOneSupportsDtmf'.
*/
function updateAtLeastOneDtmf() {
var newAtLeastOneDtmf = false;
for (var key in members) {
if (typeof members[key].supportsDtmf !== 'undefined'
&& members[key].supportsDtmf) {
newAtLeastOneDtmf= true;
break;
}
}
if (atLeastOneDtmf != newAtLeastOneDtmf) {
atLeastOneDtmf = newAtLeastOneDtmf;
eventEmitter.emit(Events.DTMF_SUPPORT_CHANGED, atLeastOneDtmf);
}
}
/**
* Exported interface.
*/
var Members = {
start: function() {
registerListeners();
},
addListener: function(type, listener) {
eventEmitter.on(type, listener);
},
removeListener: function (type, listener) {
eventEmitter.removeListener(type, listener);
},
size: function () {
return Object.keys(members).length;
},
getMembers: function () {
return members;
}
};
module.exports = Members;

View File

@ -57,6 +57,9 @@ var Settings = {
* @returns {string} the display name we just set
*/
setDisplayName: function (newDisplayName) {
if (displayName === newDisplayName) {
return displayName;
}
displayName = newDisplayName;
window.localStorage.displayname = displayName;
return displayName;
@ -84,6 +87,10 @@ var Settings = {
return email;
},
getEmail: function () {
return email;
},
getSettings: function () {
return {
email: email,

View File

@ -1,5 +1,4 @@
/* global $, $iq, config, connection, focusMucJid, forceMuted,
setAudioMuted, Strophe */
/* global $, $iq, config, connection, focusMucJid, forceMuted, Strophe */
/**
* Moderate connection plugin.
*/
@ -58,4 +57,4 @@ module.exports = function (XMPP, eventEmitter) {
this.connection.emuc.kick(jid);
}
});
};
};

View File

@ -3,6 +3,24 @@ var UIEvents = {
SELECTED_ENDPOINT: "UI.selected_endpoint",
PINNED_ENDPOINT: "UI.pinned_endpoint",
LARGEVIDEO_INIT: "UI.largevideo_init",
/**
* Notifies that local user created text message.
*/
MESSAGE_CREATED: "UI.message_created",
/**
* Notifies that local user changed language.
*/
LANG_CHANGED: "UI.lang_changed",
/**
* Notifies that local user changed email.
*/
EMAIL_CHANGED: "UI.email_changed",
/**
* Notifies that "start muted" settings changed.
*/
START_MUTED_CHANGED: "UI.start_muted_changed",
AUDIO_MUTED: "UI.audio_muted",
VIDEO_MUTED: "UI.video_muted",
/**
* Notifies interested parties when the film strip (remote video's panel)
* is hidden (toggled) or shown (un-toggled).

View File

@ -1,5 +0,0 @@
var Events = {
DTMF_SUPPORT_CHANGED: "members.dtmf_support_changed"
};
module.exports = Events;