Merge pull request #433 from isymchych/jitsi-meet-new
Integration of UI module with lib-jitsi-meet
This commit is contained in:
commit
6e007a03af
|
@ -15,5 +15,6 @@
|
|||
"newcap": true, // true: Require capitalization of all constructor functions e.g. `new F()`
|
||||
"maxlen": 80, // {int} Max number of characters per line
|
||||
"latedef": false, //This option prohibits the use of a variable before it was defined
|
||||
"laxbreak": true //Ignore line breaks around "=", "==", "&&", etc.
|
||||
"laxbreak": true, //Ignore line breaks around "=", "==", "&&", etc.
|
||||
"esnext": true //support ES2015
|
||||
}
|
||||
|
|
501
app.js
501
app.js
|
@ -1,49 +1,90 @@
|
|||
/* global $, JitsiMeetJS, config, Promise */
|
||||
/* global $, JitsiMeetJS, config, interfaceConfig */
|
||||
/* application specific logic */
|
||||
|
||||
require("jquery");
|
||||
require("jquery-ui");
|
||||
require("strophe");
|
||||
require("strophe-disco");
|
||||
require("strophe-caps");
|
||||
require("tooltip");
|
||||
require("popover");
|
||||
import "babel-polyfill";
|
||||
import "jquery";
|
||||
import "jquery-ui";
|
||||
import "strophe";
|
||||
import "strophe-disco";
|
||||
import "strophe-caps";
|
||||
import "tooltip";
|
||||
import "popover";
|
||||
import "jQuery-Impromptu";
|
||||
import "autosize";
|
||||
window.toastr = require("toastr");
|
||||
require("jQuery-Impromptu");
|
||||
require("autosize");
|
||||
|
||||
var CQEvents = require('./service/connectionquality/CQEvents');
|
||||
var UIEvents = require('./service/UI/UIEvents');
|
||||
import URLProcessor from "./modules/config/URLProcessor";
|
||||
import RoomnameGenerator from './modules/util/RoomnameGenerator';
|
||||
import CQEvents from './service/connectionquality/CQEvents';
|
||||
import UIEvents from './service/UI/UIEvents';
|
||||
|
||||
var Commands = {
|
||||
import {openConnection} from './modules/connection';
|
||||
import AuthHandler from './modules/AuthHandler';
|
||||
|
||||
import createRoomLocker from './modules/RoomLocker';
|
||||
|
||||
const Commands = {
|
||||
CONNECTION_QUALITY: "connectionQuality",
|
||||
EMAIL: "email"
|
||||
};
|
||||
|
||||
var APP = {
|
||||
init: function () {
|
||||
JitsiMeetJS.init();
|
||||
JitsiMeetJS.setLogLevel(JitsiMeetJS.logLevels.TRACE);
|
||||
function buildRoomName () {
|
||||
let path = window.location.pathname;
|
||||
let roomName;
|
||||
|
||||
// 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
|
||||
roomName = 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) {
|
||||
roomName = path.substr(1).toLowerCase();
|
||||
} else {
|
||||
let word = RoomnameGenerator.generateRoomWithoutSeparator();
|
||||
roomName = word.toLowerCase();
|
||||
window.history.pushState(
|
||||
'VideoChat', `Room: ${word}`, window.location.pathname + word
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return roomName;
|
||||
}
|
||||
|
||||
|
||||
const APP = {
|
||||
init () {
|
||||
let roomName = buildRoomName();
|
||||
this.conference = {
|
||||
roomName,
|
||||
localId: undefined,
|
||||
isModerator: false,
|
||||
membersCount: 0,
|
||||
audioMuted: false,
|
||||
videoMuted: false,
|
||||
isLocalId: function (id) {
|
||||
sipGatewayEnabled: false, //FIXME handle
|
||||
isLocalId (id) {
|
||||
return this.localId === id;
|
||||
},
|
||||
muteAudio: function (mute) {
|
||||
muteAudio (mute) {
|
||||
APP.UI.eventEmitter.emit(UIEvents.AUDIO_MUTED, mute);
|
||||
},
|
||||
toggleAudioMuted: function () {
|
||||
toggleAudioMuted () {
|
||||
this.muteAudio(!this.audioMuted);
|
||||
},
|
||||
muteVideo: function (mute) {
|
||||
muteVideo (mute) {
|
||||
APP.UI.eventEmitter.emit(UIEvents.VIDEO_MUTED, mute);
|
||||
},
|
||||
toggleVideoMuted: function () {
|
||||
toggleVideoMuted () {
|
||||
this.muteVideo(!this.videoMuted);
|
||||
}
|
||||
};
|
||||
|
@ -64,98 +105,116 @@ var APP = {
|
|||
};
|
||||
|
||||
|
||||
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
|
||||
});
|
||||
const ConnectionEvents = JitsiMeetJS.events.connection;
|
||||
const ConnectionErrors = JitsiMeetJS.errors.connection;
|
||||
|
||||
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, {
|
||||
const ConferenceEvents = JitsiMeetJS.events.conference;
|
||||
const ConferenceErrors = JitsiMeetJS.errors.conference;
|
||||
function initConference(localTracks, connection) {
|
||||
let room = connection.initJitsiConference(APP.conference.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?
|
||||
return room.getParticipants().length; // FIXME maybe +1?
|
||||
}
|
||||
});
|
||||
|
||||
room.on(ConferenceEvents.USER_JOINED, function (id) {
|
||||
users[id] = {
|
||||
displayName: undefined,
|
||||
tracks: []
|
||||
};
|
||||
APP.conference.listMembers = function () {
|
||||
return room.getParticipants();
|
||||
};
|
||||
APP.conference.listMembersIds = function () {
|
||||
return room.getParticipants().map(p => p.getId());
|
||||
};
|
||||
|
||||
function getDisplayName(id) {
|
||||
if (APP.conference.isLocalId(id)) {
|
||||
return APP.settings.getDisplayName();
|
||||
}
|
||||
|
||||
var participant = room.getParticipantById(id);
|
||||
if (participant && participant.getDisplayName()) {
|
||||
return participant.getDisplayName();
|
||||
}
|
||||
}
|
||||
|
||||
// add local streams when joined to the conference
|
||||
room.on(ConferenceEvents.CONFERENCE_JOINED, function () {
|
||||
localTracks.forEach(function (track) {
|
||||
room.addTrack(track);
|
||||
APP.UI.addLocalStream(track);
|
||||
});
|
||||
|
||||
APP.UI.updateAuthInfo(room.isAuthEnabled(), room.getAuthLogin());
|
||||
});
|
||||
|
||||
|
||||
room.on(ConferenceEvents.USER_JOINED, function (id, user) {
|
||||
if (APP.conference.isLocalId(id)) {
|
||||
return;
|
||||
}
|
||||
console.error('USER %s connnected', id);
|
||||
// FIXME email???
|
||||
APP.UI.addUser(id);
|
||||
APP.UI.addUser(id, user.getDisplayName());
|
||||
});
|
||||
room.on(ConferenceEvents.USER_LEFT, function (id) {
|
||||
delete users[id];
|
||||
APP.UI.removeUser(id);
|
||||
room.on(ConferenceEvents.USER_LEFT, function (id, user) {
|
||||
console.error('USER LEFT', id);
|
||||
APP.UI.removeUser(id, user.getDisplayName());
|
||||
});
|
||||
|
||||
|
||||
room.on(ConferenceEvents.USER_ROLE_CHANGED, function (id, role) {
|
||||
if (APP.conference.isLocalId(id)) {
|
||||
console.info(`My role changed, new role: ${role}`);
|
||||
APP.conference.isModerator = room.isModerator();
|
||||
APP.UI.updateLocalRole(room.isModerator());
|
||||
} else {
|
||||
var user = room.getParticipantById(id);
|
||||
if (user) {
|
||||
APP.UI.updateUserRole(user);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
let roomLocker = createRoomLocker(room);
|
||||
APP.UI.addListener(UIEvents.ROOM_LOCK_CLICKED, function () {
|
||||
if (room.isModerator()) {
|
||||
let promise = roomLocker.isLocked
|
||||
? roomLocker.askToUnlock()
|
||||
: roomLocker.askToLock();
|
||||
promise.then(function () {
|
||||
APP.UI.markRoomLocked(roomLocker.isLocked);
|
||||
});
|
||||
} else {
|
||||
roomLocker.notifyModeratorRequired();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
room.on(ConferenceEvents.TRACK_ADDED, function (track) {
|
||||
if (track.isLocal()) { // skip local tracks
|
||||
return;
|
||||
}
|
||||
console.error(
|
||||
'REMOTE %s TRACK', track.getType(), track.getParticipantId()
|
||||
);
|
||||
APP.UI.addRemoteStream(track);
|
||||
});
|
||||
room.on(ConferenceEvents.TRACK_REMOVED, function (track) {
|
||||
if (track.isLocal()) { // skip local tracks
|
||||
return;
|
||||
}
|
||||
|
||||
console.error(
|
||||
'REMOTE %s TRACK REMOVED', track.getType(), track.getParticipantId()
|
||||
);
|
||||
|
||||
// FIXME handle
|
||||
});
|
||||
room.on(ConferenceEvents.TRACK_MUTE_CHANGED, function (track) {
|
||||
// FIXME handle mute
|
||||
});
|
||||
|
@ -189,13 +248,21 @@ function initConference(connection, roomName) {
|
|||
});
|
||||
|
||||
|
||||
room.on(ConferenceEvents.CONNECTION_INTERRUPTED, function () {
|
||||
APP.UI.markVideoInterrupted(true);
|
||||
});
|
||||
room.on(ConferenceEvents.CONNECTION_RESTORED, function () {
|
||||
APP.UI.markVideoInterrupted(false);
|
||||
});
|
||||
if (!interfaceConfig.filmStripOnly) {
|
||||
room.on(ConferenceEvents.CONNECTION_INTERRUPTED, function () {
|
||||
APP.UI.markVideoInterrupted(true);
|
||||
});
|
||||
room.on(ConferenceEvents.CONNECTION_RESTORED, function () {
|
||||
APP.UI.markVideoInterrupted(false);
|
||||
});
|
||||
|
||||
APP.UI.addListener(UIEvents.MESSAGE_CREATED, function (message) {
|
||||
room.sendTextMessage(message);
|
||||
});
|
||||
room.on(ConferenceEvents.MESSAGE_RECEIVED, function (id, text, ts) {
|
||||
APP.UI.addMessage(id, getDisplayName(id), text, ts);
|
||||
});
|
||||
}
|
||||
|
||||
APP.connectionquality.addListener(
|
||||
CQEvents.LOCALSTATS_UPDATED,
|
||||
|
@ -248,26 +315,22 @@ function initConference(connection, roomName) {
|
|||
APP.UI.setUserAvatar(data.attributes.id, data.value);
|
||||
});
|
||||
|
||||
let nick = APP.settings.getDisplayName();
|
||||
if (config.useNicks && !nick) {
|
||||
nick = APP.UI.askForNickname();
|
||||
APP.settings.setDisplayName(nick);
|
||||
}
|
||||
|
||||
if (nick) {
|
||||
room.setDisplayName(nick);
|
||||
}
|
||||
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.changeDisplayName(APP.conference.localId, nickname);
|
||||
});
|
||||
|
||||
APP.UI.addListener(
|
||||
|
@ -277,37 +340,192 @@ function initConference(connection, roomName) {
|
|||
}
|
||||
);
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
room.on(
|
||||
ConferenceEvents.CONFERENCE_JOINED,
|
||||
function () {
|
||||
resolve();
|
||||
}
|
||||
APP.UI.addListener(UIEvents.USER_INVITED, function (roomUrl) {
|
||||
APP.UI.inviteParticipants(
|
||||
roomUrl,
|
||||
APP.conference.roomName,
|
||||
roomLocker.password,
|
||||
APP.settings.getDisplayName()
|
||||
);
|
||||
APP.UI.closeAuthenticationDialog();
|
||||
if (config.useNicks) {
|
||||
// FIXME check this
|
||||
var nick = APP.UI.askForNickname();
|
||||
});
|
||||
|
||||
// call hangup
|
||||
APP.UI.addListener(UIEvents.HANGUP, function () {
|
||||
APP.UI.requestFeedback().then(function () {
|
||||
connection.disconnect();
|
||||
|
||||
if (config.enableWelcomePage) {
|
||||
setTimeout(function() {
|
||||
window.localStorage.welcomePageDisabled = false;
|
||||
window.location.pathname = "/";
|
||||
}, 3000);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// logout
|
||||
APP.UI.addListener(UIEvents.LOGOUT, function () {
|
||||
// FIXME handle logout
|
||||
// APP.xmpp.logout(function (url) {
|
||||
// if (url) {
|
||||
// window.location.href = url;
|
||||
// } else {
|
||||
// hangup();
|
||||
// }
|
||||
// });
|
||||
});
|
||||
|
||||
APP.UI.addListener(UIEvents.SIP_DIAL, function (sipNumber) {
|
||||
// FIXME add dial
|
||||
// APP.xmpp.dial(
|
||||
// sipNumber,
|
||||
// 'fromnumber',
|
||||
// APP.conference.roomName,
|
||||
// roomLocker.password
|
||||
// );
|
||||
});
|
||||
|
||||
|
||||
// Starts or stops the recording for the conference.
|
||||
APP.UI.addListener(UIEvents.RECORDING_TOGGLE, function (predefinedToken) {
|
||||
// FIXME recording
|
||||
// APP.xmpp.toggleRecording(function (callback) {
|
||||
// if (predefinedToken) {
|
||||
// callback(predefinedToken);
|
||||
// return;
|
||||
// }
|
||||
|
||||
// APP.UI.requestRecordingToken().then(callback);
|
||||
|
||||
// }, APP.UI.updateRecordingState);
|
||||
});
|
||||
|
||||
APP.UI.addListener(UIEvents.TOPIC_CHANGED, function (topic) {
|
||||
// FIXME handle topic change
|
||||
// APP.xmpp.setSubject(topic);
|
||||
// on SUBJECT_CHANGED UI.setSubject(topic);
|
||||
});
|
||||
|
||||
APP.UI.addListener(UIEvents.USER_KICKED, function (id) {
|
||||
room.kickParticipant(id);
|
||||
});
|
||||
room.on(ConferenceEvents.KICKED, function () {
|
||||
APP.UI.notifyKicked();
|
||||
// FIXME close
|
||||
});
|
||||
|
||||
APP.UI.addListener(UIEvents.AUTH_CLICKED, function () {
|
||||
AuthHandler.authenticate(room);
|
||||
});
|
||||
|
||||
APP.UI.addListener(UIEvents.SELECTED_ENDPOINT, function (id) {
|
||||
room.selectParticipant(id);
|
||||
});
|
||||
|
||||
room.on(ConferenceEvents.DTMF_SUPPORT_CHANGED, function (isDTMFSupported) {
|
||||
APP.UI.updateDTMFSupport(isDTMFSupported);
|
||||
});
|
||||
|
||||
$(window).bind('beforeunload', function () {
|
||||
room.leave();
|
||||
});
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
room.on(ConferenceEvents.CONFERENCE_JOINED, handleConferenceJoined);
|
||||
room.on(ConferenceEvents.CONFERENCE_FAILED, onConferenceFailed);
|
||||
|
||||
let password;
|
||||
let reconnectTimeout;
|
||||
|
||||
function unsubscribe() {
|
||||
room.off(
|
||||
ConferenceEvents.CONFERENCE_JOINED, handleConferenceJoined
|
||||
);
|
||||
room.off(
|
||||
ConferenceEvents.CONFERENCE_FAILED, onConferenceFailed
|
||||
);
|
||||
if (reconnectTimeout) {
|
||||
clearTimeout(reconnectTimeout);
|
||||
}
|
||||
AuthHandler.closeAuth();
|
||||
}
|
||||
room.join();
|
||||
|
||||
function handleConferenceJoined() {
|
||||
unsubscribe();
|
||||
resolve();
|
||||
}
|
||||
|
||||
function handleConferenceFailed(err) {
|
||||
unsubscribe();
|
||||
reject(err);
|
||||
}
|
||||
|
||||
function onConferenceFailed(err, msg = '') {
|
||||
console.error('CONFERENCE FAILED:', err, msg);
|
||||
switch (err) {
|
||||
// room is locked by the password
|
||||
case ConferenceErrors.PASSWORD_REQUIRED:
|
||||
APP.UI.markRoomLocked(true);
|
||||
roomLocker.requirePassword().then(function () {
|
||||
room.join(roomLocker.password);
|
||||
});
|
||||
break;
|
||||
|
||||
case ConferenceErrors.CONNECTION_ERROR:
|
||||
APP.UI.notifyConnectionFailed(msg);
|
||||
break;
|
||||
|
||||
// not enough rights to create conference
|
||||
case ConferenceErrors.AUTHENTICATION_REQUIRED:
|
||||
// schedule reconnect to check if someone else created the room
|
||||
reconnectTimeout = setTimeout(function () {
|
||||
room.join(password);
|
||||
}, 5000);
|
||||
|
||||
// notify user that auth is required
|
||||
AuthHandler.requireAuth(APP.conference.roomName);
|
||||
break;
|
||||
|
||||
default:
|
||||
handleConferenceFailed(err);
|
||||
}
|
||||
}
|
||||
|
||||
room.join(password);
|
||||
});
|
||||
}
|
||||
|
||||
function createLocalTracks () {
|
||||
return JitsiMeetJS.createLocalTracks({
|
||||
devices: ['audio', 'video']
|
||||
}).catch(function (err) {
|
||||
if (err[0] === ConferenceErrors.PASSWORD_REQUIRED) {
|
||||
// FIXME ask for password and try again
|
||||
return initConference(connection, roomName);
|
||||
console.error('failed to create local tracks', err);
|
||||
return [];
|
||||
});
|
||||
}
|
||||
|
||||
function connect() {
|
||||
return openConnection({retry: true}).catch(function (err) {
|
||||
if (err === ConnectionErrors.PASSWORD_REQUIRED) {
|
||||
APP.UI.notifyTokenAuthFailed();
|
||||
} else {
|
||||
APP.UI.notifyConnectionFailed(err);
|
||||
}
|
||||
|
||||
// FIXME else notify that we cannot conenct to the room
|
||||
|
||||
throw new Error(err[0]);
|
||||
throw err;
|
||||
});
|
||||
}
|
||||
|
||||
function init() {
|
||||
connect().then(function (connection) {
|
||||
return initConference(connection, APP.UI.generateRoomName());
|
||||
}).then(function () {
|
||||
APP.UI.start();
|
||||
APP.UI.start();
|
||||
|
||||
JitsiMeetJS.setLogLevel(JitsiMeetJS.logLevels.TRACE);
|
||||
|
||||
JitsiMeetJS.init().then(function () {
|
||||
return Promise.all([createLocalTracks(), connect()]);
|
||||
}).then(function ([tracks, connection]) {
|
||||
console.log('initialized with %s local tracks', tracks.length);
|
||||
return initConference(tracks, connection);
|
||||
}).then(function () {
|
||||
APP.UI.initConference();
|
||||
|
||||
APP.UI.addListener(UIEvents.LANG_CHANGED, function (language) {
|
||||
|
@ -319,6 +537,8 @@ function init() {
|
|||
APP.statistics.start();
|
||||
APP.connectionquality.init();
|
||||
APP.keyboardshortcut.init();
|
||||
}).catch(function (err) {
|
||||
console.error(err);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -331,7 +551,7 @@ function init() {
|
|||
* will be displayed to the user.
|
||||
*/
|
||||
function obtainConfigAndInit() {
|
||||
var roomName = APP.UI.getRoomNode();
|
||||
let roomName = APP.conference.roomName;
|
||||
|
||||
if (config.configLocation) {
|
||||
APP.configFetch.obtainConfig(
|
||||
|
@ -361,7 +581,6 @@ function obtainConfigAndInit() {
|
|||
$(document).ready(function () {
|
||||
console.log("(TIME) document ready:\t", window.performance.now());
|
||||
|
||||
var URLProcessor = require("./modules/config/URLProcessor");
|
||||
URLProcessor.setConfigParametersFromUrl();
|
||||
APP.init();
|
||||
|
||||
|
|
2234
lib-jitsi-meet.js
2234
lib-jitsi-meet.js
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,108 @@
|
|||
/* global JitsiMeetJS */
|
||||
|
||||
import LoginDialog from './UI/authentication/LoginDialog';
|
||||
import UIEvents from '../service/UI/UIEvents';
|
||||
import UIUtil from './UI/util/UIUtil';
|
||||
import {openConnection} from './connection';
|
||||
|
||||
const ConferenceEvents = JitsiMeetJS.events.conference;
|
||||
|
||||
let externalAuthWindow;
|
||||
let authRequiredDialog;
|
||||
|
||||
function doExternalAuth (room, lockPassword) {
|
||||
if (externalAuthWindow) {
|
||||
externalAuthWindow.focus();
|
||||
return;
|
||||
}
|
||||
if (room.isJoined()) {
|
||||
room.getExternalAuthUrl(true).then(function (url) {
|
||||
externalAuthWindow = LoginDialog.showExternalAuthDialog(
|
||||
url,
|
||||
function () {
|
||||
externalAuthWindow = null;
|
||||
room.join(lockPassword);
|
||||
}
|
||||
);
|
||||
});
|
||||
} else {
|
||||
// If conference has not been started yet
|
||||
// then redirect to login page
|
||||
room.getExternalAuthUrl().then(UIUtil.redirect);
|
||||
}
|
||||
}
|
||||
|
||||
function doXmppAuth (room, lockPassword) {
|
||||
let loginDialog = LoginDialog.showAuthDialog(function (id, password) {
|
||||
// auth "on the fly":
|
||||
// 1. open new connection with proper id and password
|
||||
// 2. connect to the room
|
||||
// (this will store sessionId in the localStorage)
|
||||
// 3. close new connection
|
||||
// 4. reallocate focus in current room
|
||||
openConnection({id, password}).then(function (connection) {
|
||||
// open room
|
||||
let newRoom = connection.initJitsiConference(room.getName());
|
||||
|
||||
newRoom.on(ConferenceEvents.CONFERENCE_FAILED, function (err) {
|
||||
connection.disconnect();
|
||||
loginDialog.displayError(err);
|
||||
});
|
||||
|
||||
newRoom.room.moderator.allocateConferenceFocus(function () {
|
||||
connection.disconnect();
|
||||
loginDialog.close();
|
||||
|
||||
if (room.isJoined()) {
|
||||
// just reallocate focus if already joined
|
||||
room.room.moderator.allocateConferenceFocus();
|
||||
} else {
|
||||
// or join
|
||||
room.join(lockPassword);
|
||||
}
|
||||
});
|
||||
|
||||
}, function (err) {
|
||||
loginDialog.displayError(err);
|
||||
});
|
||||
}, function () { // user canceled
|
||||
loginDialog.close();
|
||||
});
|
||||
}
|
||||
|
||||
function authenticate (room, lockPassword) {
|
||||
if (room.isExternalAuthEnabled()) {
|
||||
doExternalAuth(room, lockPassword);
|
||||
} else {
|
||||
doXmppAuth();
|
||||
}
|
||||
}
|
||||
|
||||
function requireAuth(roomName) {
|
||||
if (authRequiredDialog) {
|
||||
return;
|
||||
}
|
||||
|
||||
authRequiredDialog = LoginDialog.showAuthRequiredDialog(
|
||||
roomName, authenticate
|
||||
);
|
||||
}
|
||||
|
||||
function closeAuth() {
|
||||
if (externalAuthWindow) {
|
||||
externalAuthWindow.close();
|
||||
externalAuthWindow = null;
|
||||
}
|
||||
|
||||
if (authRequiredDialog) {
|
||||
authRequiredDialog.close();
|
||||
authRequiredDialog = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export default {
|
||||
authenticate,
|
||||
requireAuth,
|
||||
closeAuth
|
||||
};
|
|
@ -0,0 +1,143 @@
|
|||
/* global APP, JitsiMeetJS */
|
||||
import messageHandler from './UI/util/MessageHandler';
|
||||
import UIUtil from './UI/util/UIUtil';
|
||||
import AnalyticsAdapter from './statistics/AnalyticsAdapter';
|
||||
|
||||
function askForNewPassword () {
|
||||
let passMsg = APP.translation.generateTranslationHTML("dialog.passwordMsg");
|
||||
let yourPassMsg = APP.translation.translateString("dialog.yourPassword");
|
||||
let msg = `
|
||||
<h2>${passMsg}</h2>
|
||||
<input name="lockKey" type="text"
|
||||
data-i18n="[placeholder]dialog.yourPassword"
|
||||
placeholder="${yourPassMsg}" autofocus>
|
||||
`;
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
messageHandler.openTwoButtonDialog(
|
||||
null, null, null,
|
||||
msg, false, "dialog.Save",
|
||||
function (e, v, m, f) {
|
||||
if (v && f.lockKey) {
|
||||
resolve(UIUtil.escapeHtml(f.lockKey));
|
||||
} else {
|
||||
reject();
|
||||
}
|
||||
},
|
||||
null, null, 'input:first'
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
function askForPassword () {
|
||||
let passRequiredMsg = APP.translation.translateString(
|
||||
"dialog.passwordRequired"
|
||||
);
|
||||
let passMsg = APP.translation.translateString("dialog.password");
|
||||
let msg = `
|
||||
<h2 data-i18n="dialog.passwordRequired">${passRequiredMsg}</h2>
|
||||
<input name="lockKey" type="text"
|
||||
data-i18n="[placeholder]dialog.password"
|
||||
placeholder="${passMsg}" autofocus>
|
||||
`;
|
||||
return new Promise(function (resolve, reject) {
|
||||
messageHandler.openTwoButtonDialog(
|
||||
null, null, null, msg,
|
||||
true, "dialog.Ok",
|
||||
function (e, v, m, f) {}, null,
|
||||
function (e, v, m, f) {
|
||||
if (v && f.lockKey) {
|
||||
resolve(UIUtil.escapeHtml(f.lockKey));
|
||||
} else {
|
||||
reject();
|
||||
}
|
||||
},
|
||||
':input:first'
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
function askToUnlock () {
|
||||
return new Promise(function (resolve, reject) {
|
||||
messageHandler.openTwoButtonDialog(
|
||||
null, null, "dialog.passwordCheck",
|
||||
null, false, "dialog.Remove",
|
||||
function (e, v) {
|
||||
if (v) {
|
||||
resolve();
|
||||
} else {
|
||||
reject();
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
function notifyPasswordNotSupported (err) {
|
||||
console.warn('setting password failed', err);
|
||||
messageHandler.showError("dialog.warning", "dialog.passwordNotSupported");
|
||||
}
|
||||
|
||||
function notifyPasswordFailed() {
|
||||
console.warn('room passwords not supported');
|
||||
messageHandler.showError("dialog.lockTitle", "dialog.lockMessage");
|
||||
}
|
||||
|
||||
const ConferenceErrors = JitsiMeetJS.errors.conference;
|
||||
|
||||
export default function createRoomLocker (room) {
|
||||
let password;
|
||||
|
||||
function lock (newPass) {
|
||||
return room.lock(newPass).then(function () {
|
||||
password = newPass;
|
||||
}).catch(function (err) {
|
||||
if (err === ConferenceErrors.PASSWORD_NOT_SUPPORTED) {
|
||||
notifyPasswordNotSupported();
|
||||
} else {
|
||||
notifyPasswordFailed(err);
|
||||
}
|
||||
throw err;
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
get isLocked () {
|
||||
return !!password;
|
||||
},
|
||||
|
||||
get password () {
|
||||
return password;
|
||||
},
|
||||
|
||||
askToUnlock () {
|
||||
askToUnlock().then(function () {
|
||||
return lock();
|
||||
}).then(function () {
|
||||
AnalyticsAdapter.sendEvent('toolbar.lock.disabled');
|
||||
});
|
||||
},
|
||||
|
||||
askToLock () {
|
||||
return askForNewPassword().then(function (newPass) {
|
||||
return lock(newPass);
|
||||
}).then(function () {
|
||||
AnalyticsAdapter.sendEvent('toolbar.lock.enabled');
|
||||
});
|
||||
},
|
||||
|
||||
requirePassword () {
|
||||
return askForPassword().then(function (newPass) {
|
||||
password = newPass;
|
||||
});
|
||||
},
|
||||
|
||||
notifyModeratorRequired () {
|
||||
if (password) {
|
||||
messageHandler.openMessageDialog(null, "dialog.passwordError");
|
||||
} else {
|
||||
messageHandler.openMessageDialog(null, "dialog.passwordError2");
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
494
modules/UI/UI.js
494
modules/UI/UI.js
|
@ -1,62 +1,58 @@
|
|||
/* global Strophe, APP, $, config, interfaceConfig, toastr */
|
||||
/* global APP, $, config, interfaceConfig, toastr */
|
||||
/* jshint -W101 */
|
||||
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");
|
||||
import AudioLevels from './audio_levels/AudioLevels';
|
||||
import Chat from "./side_pannels/chat/Chat";
|
||||
import Toolbar from "./toolbars/Toolbar";
|
||||
import ToolbarToggler from "./toolbars/ToolbarToggler";
|
||||
import BottomToolbar from "./toolbars/BottomToolbar";
|
||||
import ContactList from "./side_pannels/contactlist/ContactList";
|
||||
import Avatar from "./avatar/Avatar";
|
||||
import PanelToggler from "./side_pannels/SidePanelToggler";
|
||||
import UIUtil from "./util/UIUtil";
|
||||
import UIEvents from "../../service/UI/UIEvents";
|
||||
|
||||
import VideoLayout from "./videolayout/VideoLayout";
|
||||
import SettingsMenu from "./side_pannels/settings/SettingsMenu";
|
||||
|
||||
var Prezi = require("./prezi/Prezi");
|
||||
var Etherpad = require("./etherpad/Etherpad");
|
||||
var EventEmitter = require("events");
|
||||
var SettingsMenu = require("./side_pannels/settings/SettingsMenu");
|
||||
var Settings = require("./../settings/Settings");
|
||||
var PanelToggler = require("./side_pannels/SidePanelToggler");
|
||||
var RoomnameGenerator = require("../util/RoomnameGenerator");
|
||||
UI.messageHandler = require("./util/MessageHandler");
|
||||
var messageHandler = UI.messageHandler;
|
||||
var Authentication = require("./authentication/Authentication");
|
||||
var UIUtil = require("./util/UIUtil");
|
||||
var JitsiPopover = require("./util/JitsiPopover");
|
||||
var CQEvents = require("../../service/connectionquality/CQEvents");
|
||||
var DesktopSharingEventTypes
|
||||
= require("../../service/desktopsharing/DesktopSharingEventTypes");
|
||||
var StatisticsEvents = require("../../service/statistics/Events");
|
||||
var UIEvents = require("../../service/UI/UIEvents");
|
||||
var Feedback = require("./Feedback");
|
||||
|
||||
var eventEmitter = new EventEmitter();
|
||||
UI.eventEmitter = eventEmitter;
|
||||
var roomNode = null;
|
||||
var roomName = null;
|
||||
|
||||
|
||||
function promptDisplayName() {
|
||||
var message = '<h2 data-i18n="dialog.displayNameRequired">';
|
||||
message += APP.translation.translateString(
|
||||
"dialog.displayNameRequired");
|
||||
message += '</h2>' +
|
||||
'<input name="displayName" type="text" data-i18n=' +
|
||||
'"[placeholder]defaultNickname" placeholder="' +
|
||||
APP.translation.translateString(
|
||||
"defaultNickname", {name: "Jane Pink"}) +
|
||||
'" autofocus>';
|
||||
let nickRequiredMsg = APP.translation.translateString("dialog.displayNameRequired");
|
||||
let defaultNickMsg = APP.translation.translateString(
|
||||
"defaultNickname", {name: "Jane Pink"}
|
||||
);
|
||||
let message = `
|
||||
<h2 data-i18n="dialog.displayNameRequired">${nickRequiredMsg}</h2>
|
||||
<input name="displayName" type="text"
|
||||
data-i18n="[placeholder]defaultNickname"
|
||||
placeholder="${defaultNickMsg}" autofocus>`;
|
||||
|
||||
var buttonTxt
|
||||
= APP.translation.generateTranslationHTML("dialog.Ok");
|
||||
var buttons = [];
|
||||
buttons.push({title: buttonTxt, value: "ok"});
|
||||
let buttonTxt = APP.translation.generateTranslationHTML("dialog.Ok");
|
||||
let buttons = [{title: buttonTxt, value: "ok"}];
|
||||
|
||||
messageHandler.openDialog(null, message,
|
||||
messageHandler.openDialog(
|
||||
null, message,
|
||||
true,
|
||||
buttons,
|
||||
function (e, v, m, f) {
|
||||
if (v == "ok") {
|
||||
var displayName = f.displayName;
|
||||
let displayName = f.displayName;
|
||||
if (displayName) {
|
||||
UI.inputDisplayNameHandler(displayName);
|
||||
return true;
|
||||
|
@ -65,16 +61,17 @@ function promptDisplayName() {
|
|||
e.preventDefault();
|
||||
},
|
||||
function () {
|
||||
var form = $.prompt.getPrompt();
|
||||
var input = form.find("input[name='displayName']");
|
||||
let form = $.prompt.getPrompt();
|
||||
let input = form.find("input[name='displayName']");
|
||||
input.focus();
|
||||
var button = form.find("button");
|
||||
let button = form.find("button");
|
||||
button.attr("disabled", "disabled");
|
||||
input.keyup(function () {
|
||||
if(!input.val())
|
||||
button.attr("disabled", "disabled");
|
||||
else
|
||||
if (input.val()) {
|
||||
button.removeAttr("disabled");
|
||||
} else {
|
||||
button.attr("disabled", "disabled");
|
||||
}
|
||||
});
|
||||
}
|
||||
);
|
||||
|
@ -99,6 +96,30 @@ function setupToolbars() {
|
|||
BottomToolbar.init(eventEmitter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggles the application in and out of full screen mode
|
||||
* (a.k.a. presentation mode in Chrome).
|
||||
*/
|
||||
function toggleFullScreen () {
|
||||
let fsElement = document.documentElement;
|
||||
|
||||
if (!document.mozFullScreen && !document.webkitIsFullScreen) {
|
||||
//Enter Full Screen
|
||||
if (fsElement.mozRequestFullScreen) {
|
||||
fsElement.mozRequestFullScreen();
|
||||
} else {
|
||||
fsElement.webkitRequestFullScreen(Element.ALLOW_KEYBOARD_INPUT);
|
||||
}
|
||||
} else {
|
||||
//Exit Full Screen
|
||||
if (document.mozCancelFullScreen) {
|
||||
document.mozCancelFullScreen();
|
||||
} else {
|
||||
document.webkitCancelFullScreen();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
UI.notifyGracefulShudown = function () {
|
||||
messageHandler.openMessageDialog(
|
||||
'dialog.serviceUnavailable',
|
||||
|
@ -133,6 +154,10 @@ UI.changeDisplayName = function (id, displayName) {
|
|||
ContactList.onDisplayNameChange(id, displayName);
|
||||
SettingsMenu.onDisplayNameChange(id, displayName);
|
||||
VideoLayout.onDisplayNameChanged(id, displayName);
|
||||
|
||||
if (APP.conference.isLocalId(id)) {
|
||||
Chat.setChatConversationMode(!!displayName);
|
||||
}
|
||||
};
|
||||
|
||||
UI.initConference = function () {
|
||||
|
@ -168,18 +193,34 @@ function registerListeners() {
|
|||
AudioLevels.init();
|
||||
});
|
||||
|
||||
UI.addListener(UIEvents.FILM_STRIP_TOGGLED, function (isToggled) {
|
||||
VideoLayout.onFilmStripToggled(isToggled);
|
||||
});
|
||||
|
||||
UI.addListener(UIEvents.EMAIL_CHANGED, function (email) {
|
||||
UI.setUserAvatar(APP.conference.localId, email);
|
||||
});
|
||||
|
||||
UI.addListener(UIEvents.PREZI_CLICKED, function () {
|
||||
Prezi.openPreziDialog();
|
||||
});
|
||||
|
||||
UI.addListener(UIEvents.ETHERPAD_CLICKED, function () {
|
||||
Etherpad.toggleEtherpad(0);
|
||||
});
|
||||
|
||||
UI.addListener(UIEvents.FULLSCREEN_TOGGLE, toggleFullScreen);
|
||||
|
||||
UI.addListener(UIEvents.TOGGLE_CHAT, UI.toggleChat);
|
||||
|
||||
UI.addListener(UIEvents.TOGGLE_SETTINGS, function () {
|
||||
PanelToggler.toggleSettingsMenu();
|
||||
});
|
||||
|
||||
UI.addListener(UIEvents.TOGGLE_CONTACT_LIST, UI.toggleContactList);
|
||||
|
||||
UI.addListener(UIEvents.TOGGLE_FILM_STRIP, UI.toggleFilmStrip);
|
||||
}
|
||||
|
||||
function bindEvents() {
|
||||
function onResize() {
|
||||
Chat.resizeChat();
|
||||
PanelToggler.resizeChat();
|
||||
VideoLayout.resizeLargeVideoContainer();
|
||||
}
|
||||
|
||||
|
@ -213,6 +254,7 @@ UI.start = function () {
|
|||
registerListeners();
|
||||
|
||||
VideoLayout.init(eventEmitter);
|
||||
ContactList.init(eventEmitter);
|
||||
|
||||
bindEvents();
|
||||
setupPrezi();
|
||||
|
@ -281,16 +323,16 @@ UI.start = function () {
|
|||
};
|
||||
|
||||
|
||||
UI.addLocalStream = function (stream, isMuted) {
|
||||
switch (stream.type) {
|
||||
UI.addLocalStream = function (track) {
|
||||
switch (track.getType()) {
|
||||
case 'audio':
|
||||
VideoLayout.changeLocalAudio(stream, isMuted);
|
||||
VideoLayout.changeLocalAudio(track);
|
||||
break;
|
||||
case 'video':
|
||||
VideoLayout.changeLocalVideo(stream, isMuted);
|
||||
VideoLayout.changeLocalVideo(track);
|
||||
break;
|
||||
default:
|
||||
console.error("Unknown stream type: " + stream.type);
|
||||
console.error("Unknown stream type: " + track.getType());
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
@ -304,83 +346,17 @@ function chatAddError(errorMessage, originalText) {
|
|||
return Chat.chatAddError(errorMessage, originalText);
|
||||
}
|
||||
|
||||
function chatSetSubject(text) {
|
||||
return Chat.chatSetSubject(text);
|
||||
}
|
||||
|
||||
function updateChatConversation(from, displayName, message, stamp) {
|
||||
return Chat.updateChatConversation(from, displayName, message, stamp);
|
||||
}
|
||||
UI.setSubject = function (subject) {
|
||||
Chat.setSubject(subject);
|
||||
};
|
||||
|
||||
function initEtherpad(name) {
|
||||
Etherpad.init(name);
|
||||
}
|
||||
|
||||
function onLocalRoleChanged(jid, info, pres, isModerator) {
|
||||
console.info("My role changed, new role: " + info.role);
|
||||
onModeratorStatusChanged(isModerator);
|
||||
VideoLayout.showModeratorIndicator();
|
||||
SettingsMenu.onRoleChanged();
|
||||
UI.addUser = function (id, displayName) {
|
||||
ContactList.addContact(id);
|
||||
|
||||
if (isModerator) {
|
||||
Authentication.closeAuthenticationWindow();
|
||||
messageHandler.notify(null, "notify.me",
|
||||
'connected', "notify.moderator");
|
||||
|
||||
Toolbar.checkAutoRecord();
|
||||
}
|
||||
}
|
||||
|
||||
function onModeratorStatusChanged(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);
|
||||
}
|
||||
|
||||
UI.notifyPasswordRequired = function (callback) {
|
||||
// password is required
|
||||
Toolbar.lockLockButton();
|
||||
var message = '<h2 data-i18n="dialog.passwordRequired">';
|
||||
message += APP.translation.translateString(
|
||||
"dialog.passwordRequired");
|
||||
message += '</h2>' +
|
||||
'<input name="lockKey" type="text" data-i18n=' +
|
||||
'"[placeholder]dialog.password" placeholder="' +
|
||||
APP.translation.translateString("dialog.password") +
|
||||
'" autofocus>';
|
||||
|
||||
messageHandler.openTwoButtonDialog(null, null, null, message,
|
||||
true,
|
||||
"dialog.Ok",
|
||||
function (e, v, m, f) {},
|
||||
null,
|
||||
function (e, v, m, f) {
|
||||
if (v) {
|
||||
var lockKey = f.lockKey;
|
||||
if (lockKey) {
|
||||
Toolbar.setSharedKey(lockKey);
|
||||
callback(lockKey);
|
||||
}
|
||||
}
|
||||
},
|
||||
':input:first'
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* The dialpad button is shown iff there is at least one member that supports
|
||||
* DTMF (e.g. jigasi).
|
||||
*/
|
||||
function onDtmfSupportChanged(dtmfSupport) {
|
||||
//TODO: enable when the UI is ready
|
||||
//Toolbar.showDialPadButton(dtmfSupport);
|
||||
}
|
||||
|
||||
UI.addUser = function (jid, id, displayName) {
|
||||
messageHandler.notify(
|
||||
displayName,'notify.somebody', 'connected', 'notify.connected'
|
||||
);
|
||||
|
@ -390,27 +366,24 @@ UI.addUser = function (jid, id, displayName) {
|
|||
UIUtil.playSoundNotification('userJoined');
|
||||
|
||||
// Configure avatar
|
||||
UI.setUserAvatar(jid, id);
|
||||
UI.setUserAvatar(id, displayName);
|
||||
|
||||
// Add Peer's container
|
||||
VideoLayout.ensurePeerContainerExists(jid);
|
||||
VideoLayout.addParticipantContainer(id);
|
||||
};
|
||||
|
||||
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) {
|
||||
UI.removeUser = function (id, displayName) {
|
||||
ContactList.removeContact(id);
|
||||
|
||||
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);
|
||||
VideoLayout.removeParticipantContainer(id);
|
||||
};
|
||||
|
||||
function onMucPresenceStatus(jid, info) {
|
||||
|
@ -421,31 +394,41 @@ function onPeerVideoTypeChanged(resourceJid, newVideoType) {
|
|||
VideoLayout.onVideoTypeChanged(resourceJid, newVideoType);
|
||||
}
|
||||
|
||||
function onMucRoleChanged(role, displayName) {
|
||||
UI.updateLocalRole = function (isModerator) {
|
||||
VideoLayout.showModeratorIndicator();
|
||||
|
||||
if (role === 'moderator') {
|
||||
var messageKey, messageOptions = {};
|
||||
if (!displayName) {
|
||||
messageKey = "notify.grantedToUnknown";
|
||||
}
|
||||
else {
|
||||
messageKey = "notify.grantedTo";
|
||||
messageOptions = {to: displayName};
|
||||
}
|
||||
messageHandler.notify(
|
||||
displayName,'notify.somebody',
|
||||
'connected', messageKey,
|
||||
messageOptions);
|
||||
}
|
||||
}
|
||||
Toolbar.showSipCallButton(isModerator);
|
||||
Toolbar.showRecordingButton(isModerator);
|
||||
SettingsMenu.onRoleChanged();
|
||||
|
||||
UI.notifyAuthRequired = function (intervalCallback) {
|
||||
Authentication.openAuthenticationDialog(
|
||||
roomName, intervalCallback, function () {
|
||||
Toolbar.authenticateClicked();
|
||||
}
|
||||
);
|
||||
if (isModerator) {
|
||||
messageHandler.notify(null, "notify.me", 'connected', "notify.moderator");
|
||||
|
||||
Toolbar.checkAutoRecord();
|
||||
}
|
||||
};
|
||||
|
||||
UI.updateUserRole = function (user) {
|
||||
VideoLayout.showModeratorIndicator();
|
||||
|
||||
if (!user.isModerator()) {
|
||||
return;
|
||||
}
|
||||
|
||||
var displayName = user.getDisplayName();
|
||||
if (displayName) {
|
||||
messageHandler.notify(
|
||||
displayName, 'notify.somebody',
|
||||
'connected', 'notify.grantedTo', {
|
||||
to: displayName
|
||||
}
|
||||
);
|
||||
} else {
|
||||
messageHandler.notify(
|
||||
'', 'notify.somebody',
|
||||
'connected', 'notify.grantedToUnknown', {}
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
@ -458,15 +441,16 @@ UI.getSettings = function () {
|
|||
};
|
||||
|
||||
UI.toggleFilmStrip = function () {
|
||||
return BottomToolbar.toggleFilmStrip();
|
||||
BottomToolbar.toggleFilmStrip();
|
||||
VideoLayout.updateLargeVideoSize();
|
||||
};
|
||||
|
||||
UI.toggleChat = function () {
|
||||
return BottomToolbar.toggleChat();
|
||||
PanelToggler.toggleChat();
|
||||
};
|
||||
|
||||
UI.toggleContactList = function () {
|
||||
return BottomToolbar.toggleContactList();
|
||||
PanelToggler.toggleContactList();
|
||||
};
|
||||
|
||||
UI.inputDisplayNameHandler = function (value) {
|
||||
|
@ -482,46 +466,6 @@ UI.getRemoteVideoType = function (jid) {
|
|||
return VideoLayout.getRemoteVideoType(jid);
|
||||
};
|
||||
|
||||
UI.getRoomNode = function () {
|
||||
if (roomNode)
|
||||
return roomNode;
|
||||
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);
|
||||
}
|
||||
}
|
||||
return roomNode;
|
||||
};
|
||||
|
||||
UI.generateRoomName = function () {
|
||||
if (roomName)
|
||||
return roomName;
|
||||
var roomNode = UI.getRoomNode();
|
||||
roomName = roomNode + '@' + config.hosts.muc;
|
||||
return roomName;
|
||||
};
|
||||
|
||||
|
||||
UI.connectionIndicatorShowMore = function(jid) {
|
||||
return VideoLayout.showMore(jid);
|
||||
};
|
||||
|
@ -552,19 +496,10 @@ UI.showLoginPopup = function(callback) {
|
|||
);
|
||||
};
|
||||
|
||||
UI.closeAuthenticationDialog = function () {
|
||||
Authentication.closeAuthenticationDialog();
|
||||
Authentication.stopInterval();
|
||||
};
|
||||
|
||||
UI.askForNickname = function () {
|
||||
return window.prompt('Your nickname (optional)');
|
||||
};
|
||||
|
||||
UI.getRoomName = function () {
|
||||
return roomName;
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets muted audio state for the local participant.
|
||||
*/
|
||||
|
@ -595,7 +530,7 @@ UI.showToolbar = function () {
|
|||
|
||||
//Used by torture
|
||||
UI.dockToolbar = function (isDock) {
|
||||
return ToolbarToggler.dockToolbar(isDock);
|
||||
ToolbarToggler.dockToolbar(isDock);
|
||||
};
|
||||
|
||||
UI.setUserAvatar = function (id, email) {
|
||||
|
@ -655,9 +590,9 @@ UI.handleLastNEndpoints = function (ids) {
|
|||
VideoLayout.onLastNEndpointsChanged(ids, []);
|
||||
};
|
||||
|
||||
UI.setAudioLevel = function (targetJid, lvl) {
|
||||
UI.setAudioLevel = function (id, lvl) {
|
||||
AudioLevels.updateAudioLevel(
|
||||
targetJid, lvl, VideoLayout.getLargeVideoResource()
|
||||
id, lvl, VideoLayout.getLargeVideoId()
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -677,10 +612,6 @@ 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();
|
||||
|
@ -689,4 +620,133 @@ UI.markVideoInterrupted = function (interrupted) {
|
|||
}
|
||||
};
|
||||
|
||||
UI.markRoomLocked = function (locked) {
|
||||
if (locked) {
|
||||
Toolbar.lockLockButton();
|
||||
} else {
|
||||
Toolbar.unlockLockButton();
|
||||
}
|
||||
};
|
||||
|
||||
UI.addMessage = function (from, displayName, message, stamp) {
|
||||
Chat.updateChatConversation(from, displayName, message, stamp);
|
||||
};
|
||||
|
||||
UI.updateDTMFSupport = function (isDTMFSupported) {
|
||||
//TODO: enable when the UI is ready
|
||||
//Toolbar.showDialPadButton(dtmfSupport);
|
||||
};
|
||||
|
||||
/**
|
||||
* Invite participants to conference.
|
||||
*/
|
||||
UI.inviteParticipants = function (roomUrl, conferenceName, key, nick) {
|
||||
let keyText = "";
|
||||
if (key) {
|
||||
keyText = APP.translation.translateString(
|
||||
"email.sharedKey", {sharedKey: key}
|
||||
);
|
||||
}
|
||||
|
||||
let and = APP.translation.translateString("email.and");
|
||||
let supportedBrowsers = `Chromium, Google Chrome ${and} Opera`;
|
||||
|
||||
let subject = APP.translation.translateString(
|
||||
"email.subject", {appName:interfaceConfig.APP_NAME, conferenceName}
|
||||
);
|
||||
|
||||
let body = APP.translation.translateString(
|
||||
"email.body", {
|
||||
appName:interfaceConfig.APP_NAME,
|
||||
sharedKeyText: keyText,
|
||||
roomUrl,
|
||||
supportedBrowsers
|
||||
}
|
||||
);
|
||||
|
||||
body = body.replace(/\n/g, "%0D%0A");
|
||||
|
||||
if (nick) {
|
||||
body += "%0D%0A%0D%0A" + nick;
|
||||
}
|
||||
|
||||
if (interfaceConfig.INVITATION_POWERED_BY) {
|
||||
body += "%0D%0A%0D%0A--%0D%0Apowered by jitsi.org";
|
||||
}
|
||||
|
||||
window.open(`mailto:?subject=${subject}&body=${body}`, '_blank');
|
||||
};
|
||||
|
||||
UI.requestFeedback = function () {
|
||||
return new Promise(function (resolve, reject) {
|
||||
if (Feedback.isEnabled()) {
|
||||
// If the user has already entered feedback, we'll show the window and
|
||||
// immidiately start the conference dispose timeout.
|
||||
if (Feedback.feedbackScore > 0) {
|
||||
Feedback.openFeedbackWindow();
|
||||
resolve();
|
||||
|
||||
} else { // Otherwise we'll wait for user's feedback.
|
||||
Feedback.openFeedbackWindow(resolve);
|
||||
}
|
||||
} else {
|
||||
// If the feedback functionality isn't enabled we show a thank you
|
||||
// dialog.
|
||||
messageHandler.openMessageDialog(
|
||||
null, null, null,
|
||||
APP.translation.translateString(
|
||||
"dialog.thankYou", {appName:interfaceConfig.APP_NAME}
|
||||
)
|
||||
);
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
UI.requestRecordingToken = function () {
|
||||
let msg = APP.translation.generateTranslationHTML("dialog.recordingToken");
|
||||
let token = APP.translation.translateString("dialog.token");
|
||||
return new Promise(function (resolve, reject) {
|
||||
messageHandler.openTwoButtonDialog(
|
||||
null, null, null,
|
||||
`<h2>${msg}</h2>
|
||||
<input name="recordingToken" type="text"
|
||||
data-i18n="[placeholder]dialog.token"
|
||||
placeholder="${token}" autofocus>`,
|
||||
false, "dialog.Save",
|
||||
function (e, v, m, f) {
|
||||
if (v && f.recordingToken) {
|
||||
resolve(UIUtil.escapeHtml(f.recordingToken));
|
||||
} else {
|
||||
reject();
|
||||
}
|
||||
},
|
||||
null,
|
||||
function () { },
|
||||
':input:first'
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
UI.updateRecordingState = function (state) {
|
||||
Toolbar.updateRecordingState(state);
|
||||
};
|
||||
|
||||
UI.notifyTokenAuthFailed = function () {
|
||||
messageHandler.showError("dialog.error", "dialog.tokenAuthFailed");
|
||||
};
|
||||
|
||||
UI.updateAuthInfo = function (isAuthEnabled, login) {
|
||||
let loggedIn = !!login;
|
||||
|
||||
Toolbar.showAuthenticateButton(isAuthEnabled);
|
||||
|
||||
if (isAuthEnabled) {
|
||||
Toolbar.setAuthenticatedIdentity(login);
|
||||
|
||||
Toolbar.showLoginButton(!loggedIn);
|
||||
Toolbar.showLogoutButton(loggedIn);
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = UI;
|
||||
|
|
|
@ -1,12 +1,16 @@
|
|||
/* global APP, interfaceConfig, $, Strophe */
|
||||
/* global APP, interfaceConfig, $ */
|
||||
/* jshint -W101 */
|
||||
var CanvasUtil = require("./CanvasUtils");
|
||||
|
||||
var ASDrawContext = null;
|
||||
import CanvasUtil from './CanvasUtils';
|
||||
|
||||
const LOCAL_LEVEL = 'local';
|
||||
|
||||
let ASDrawContext = null;
|
||||
let audioLevelCanvasCache = {};
|
||||
|
||||
function initActiveSpeakerAudioLevels() {
|
||||
var ASRadius = interfaceConfig.ACTIVE_SPEAKER_AVATAR_SIZE / 2;
|
||||
var ASCenter = (interfaceConfig.ACTIVE_SPEAKER_AVATAR_SIZE + ASRadius) / 2;
|
||||
let ASRadius = interfaceConfig.ACTIVE_SPEAKER_AVATAR_SIZE / 2;
|
||||
let ASCenter = (interfaceConfig.ACTIVE_SPEAKER_AVATAR_SIZE + ASRadius) / 2;
|
||||
|
||||
// Draw a circle.
|
||||
ASDrawContext.arc(ASCenter, ASCenter, ASRadius, 0, 2 * Math.PI);
|
||||
|
@ -18,249 +22,233 @@ function initActiveSpeakerAudioLevels() {
|
|||
}
|
||||
|
||||
/**
|
||||
* The audio Levels plugin.
|
||||
* Resizes the given audio level canvas to match the given thumbnail size.
|
||||
*/
|
||||
var AudioLevels = (function(my) {
|
||||
var audioLevelCanvasCache = {};
|
||||
function resizeAudioLevelCanvas(audioLevelCanvas, thumbnailWidth, thumbnailHeight) {
|
||||
audioLevelCanvas.width = thumbnailWidth + interfaceConfig.CANVAS_EXTRA;
|
||||
audioLevelCanvas.height = thumbnailHeight + interfaceConfig.CANVAS_EXTRA;
|
||||
}
|
||||
|
||||
my.LOCAL_LEVEL = 'local';
|
||||
/**
|
||||
* Draws the audio level canvas into the cached canvas object.
|
||||
*
|
||||
* @param id of the user for whom we draw the audio level
|
||||
* @param audioLevel the newAudio level to render
|
||||
*/
|
||||
function drawAudioLevelCanvas(id, audioLevel) {
|
||||
if (!audioLevelCanvasCache[id]) {
|
||||
|
||||
my.init = function () {
|
||||
ASDrawContext = $('#activeSpeakerAudioLevel')[0].getContext('2d');
|
||||
initActiveSpeakerAudioLevels();
|
||||
};
|
||||
let videoSpanId = getVideoSpanId(id);
|
||||
|
||||
/**
|
||||
* Updates the audio level canvas for the given peerJid. If the canvas
|
||||
* didn't exist we create it.
|
||||
*/
|
||||
my.updateAudioLevelCanvas = function (peerJid, VideoLayout) {
|
||||
var resourceJid = null;
|
||||
var videoSpanId = null;
|
||||
if (!peerJid)
|
||||
videoSpanId = 'localVideoContainer';
|
||||
else {
|
||||
resourceJid = Strophe.getResourceFromJid(peerJid);
|
||||
let audioLevelCanvasOrig = $(`#${videoSpanId}>canvas`).get(0);
|
||||
|
||||
videoSpanId = 'participant_' + resourceJid;
|
||||
/*
|
||||
* FIXME Testing has shown that audioLevelCanvasOrig may not exist.
|
||||
* In such a case, the method CanvasUtil.cloneCanvas may throw an
|
||||
* error. Since audio levels are frequently updated, the errors have
|
||||
* been observed to pile into the console, strain the CPU.
|
||||
*/
|
||||
if (audioLevelCanvasOrig) {
|
||||
audioLevelCanvasCache[id] = CanvasUtil.cloneCanvas(audioLevelCanvasOrig);
|
||||
}
|
||||
}
|
||||
|
||||
let canvas = audioLevelCanvasCache[id];
|
||||
|
||||
if (!canvas) {
|
||||
return;
|
||||
}
|
||||
|
||||
let drawContext = canvas.getContext('2d');
|
||||
|
||||
drawContext.clearRect(0, 0, canvas.width, canvas.height);
|
||||
|
||||
let shadowLevel = getShadowLevel(audioLevel);
|
||||
|
||||
if (shadowLevel > 0) {
|
||||
// drawContext, x, y, w, h, r, shadowColor, shadowLevel
|
||||
CanvasUtil.drawRoundRectGlow(drawContext,
|
||||
interfaceConfig.CANVAS_EXTRA / 2, interfaceConfig.CANVAS_EXTRA / 2,
|
||||
canvas.width - interfaceConfig.CANVAS_EXTRA,
|
||||
canvas.height - interfaceConfig.CANVAS_EXTRA,
|
||||
interfaceConfig.CANVAS_RADIUS,
|
||||
interfaceConfig.SHADOW_COLOR,
|
||||
shadowLevel);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the shadow/glow level for the given audio level.
|
||||
*
|
||||
* @param audioLevel the audio level from which we determine the shadow
|
||||
* level
|
||||
*/
|
||||
function getShadowLevel (audioLevel) {
|
||||
let shadowLevel = 0;
|
||||
|
||||
if (audioLevel <= 0.3) {
|
||||
shadowLevel = Math.round(interfaceConfig.CANVAS_EXTRA/2*(audioLevel/0.3));
|
||||
} else if (audioLevel <= 0.6) {
|
||||
shadowLevel = Math.round(interfaceConfig.CANVAS_EXTRA/2*((audioLevel - 0.3) / 0.3));
|
||||
} else {
|
||||
shadowLevel = Math.round(interfaceConfig.CANVAS_EXTRA/2*((audioLevel - 0.6) / 0.4));
|
||||
}
|
||||
|
||||
return shadowLevel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the video span id corresponding to the given user id
|
||||
*/
|
||||
function getVideoSpanId(id) {
|
||||
let videoSpanId = null;
|
||||
|
||||
if (id === LOCAL_LEVEL || APP.conference.isLocalId(id)) {
|
||||
videoSpanId = 'localVideoContainer';
|
||||
} else {
|
||||
videoSpanId = `participant_${id}`;
|
||||
}
|
||||
|
||||
return videoSpanId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates that the remote video has been resized.
|
||||
*/
|
||||
$(document).bind('remotevideo.resized', function (event, width, height) {
|
||||
let resized = false;
|
||||
|
||||
$('#remoteVideos>span>canvas').each(function() {
|
||||
let canvas = $(this).get(0);
|
||||
if (canvas.width !== width + interfaceConfig.CANVAS_EXTRA) {
|
||||
canvas.width = width + interfaceConfig.CANVAS_EXTRA;
|
||||
resized = true;
|
||||
}
|
||||
|
||||
var videoSpan = document.getElementById(videoSpanId);
|
||||
if (canvas.height !== height + interfaceConfig.CANVAS_EXTRA) {
|
||||
canvas.height = height + interfaceConfig.CANVAS_EXTRA;
|
||||
resized = true;
|
||||
}
|
||||
});
|
||||
|
||||
if (resized) {
|
||||
Object.keys(audioLevelCanvasCache).forEach(function (id) {
|
||||
audioLevelCanvasCache[id].width = width + interfaceConfig.CANVAS_EXTRA;
|
||||
audioLevelCanvasCache[id].height = height + interfaceConfig.CANVAS_EXTRA;
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* The audio Levels plugin.
|
||||
*/
|
||||
const AudioLevels = {
|
||||
|
||||
init () {
|
||||
ASDrawContext = $('#activeSpeakerAudioLevel')[0].getContext('2d');
|
||||
initActiveSpeakerAudioLevels();
|
||||
},
|
||||
|
||||
/**
|
||||
* Updates the audio level canvas for the given id. If the canvas
|
||||
* didn't exist we create it.
|
||||
*/
|
||||
updateAudioLevelCanvas (id, VideoLayout) {
|
||||
let videoSpanId = 'localVideoContainer';
|
||||
if (id) {
|
||||
videoSpanId = `participant_${id}`;
|
||||
}
|
||||
|
||||
let videoSpan = document.getElementById(videoSpanId);
|
||||
|
||||
if (!videoSpan) {
|
||||
if (resourceJid)
|
||||
console.error("No video element for jid", resourceJid);
|
||||
else
|
||||
if (id) {
|
||||
console.error("No video element for id", id);
|
||||
} else {
|
||||
console.error("No video element for local video.");
|
||||
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
var audioLevelCanvas = $('#' + videoSpanId + '>canvas');
|
||||
let audioLevelCanvas = $(`#${videoSpanId}>canvas`);
|
||||
|
||||
var videoSpaceWidth = $('#remoteVideos').width();
|
||||
var thumbnailSize = VideoLayout.calculateThumbnailSize(videoSpaceWidth);
|
||||
var thumbnailWidth = thumbnailSize[0];
|
||||
var thumbnailHeight = thumbnailSize[1];
|
||||
let videoSpaceWidth = $('#remoteVideos').width();
|
||||
let thumbnailSize = VideoLayout.calculateThumbnailSize(videoSpaceWidth);
|
||||
let thumbnailWidth = thumbnailSize[0];
|
||||
let thumbnailHeight = thumbnailSize[1];
|
||||
|
||||
if (!audioLevelCanvas || audioLevelCanvas.length === 0) {
|
||||
|
||||
audioLevelCanvas = document.createElement('canvas');
|
||||
audioLevelCanvas.className = "audiolevel";
|
||||
audioLevelCanvas.style.bottom = "-" + interfaceConfig.CANVAS_EXTRA/2 + "px";
|
||||
audioLevelCanvas.style.left = "-" + interfaceConfig.CANVAS_EXTRA/2 + "px";
|
||||
resizeAudioLevelCanvas( audioLevelCanvas,
|
||||
thumbnailWidth,
|
||||
thumbnailHeight);
|
||||
audioLevelCanvas.style.bottom = `-${interfaceConfig.CANVAS_EXTRA/2}px`;
|
||||
audioLevelCanvas.style.left = `-${interfaceConfig.CANVAS_EXTRA/2}px`;
|
||||
resizeAudioLevelCanvas(audioLevelCanvas, thumbnailWidth, thumbnailHeight);
|
||||
|
||||
videoSpan.appendChild(audioLevelCanvas);
|
||||
} else {
|
||||
audioLevelCanvas = audioLevelCanvas.get(0);
|
||||
|
||||
resizeAudioLevelCanvas( audioLevelCanvas,
|
||||
thumbnailWidth,
|
||||
thumbnailHeight);
|
||||
resizeAudioLevelCanvas(audioLevelCanvas, thumbnailWidth, thumbnailHeight);
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* Updates the audio level UI for the given resourceJid.
|
||||
* Updates the audio level UI for the given id.
|
||||
*
|
||||
* @param resourceJid the resource jid indicating the video element for
|
||||
* which we draw the audio level
|
||||
* @param id id of the user for whom we draw the audio level
|
||||
* @param audioLevel the newAudio level to render
|
||||
*/
|
||||
my.updateAudioLevel = function (resourceJid, audioLevel, largeVideoResourceJid) {
|
||||
drawAudioLevelCanvas(resourceJid, audioLevel);
|
||||
updateAudioLevel (id, audioLevel, largeVideoId) {
|
||||
drawAudioLevelCanvas(id, audioLevel);
|
||||
|
||||
var videoSpanId = getVideoSpanId(resourceJid);
|
||||
let videoSpanId = getVideoSpanId(id);
|
||||
|
||||
var audioLevelCanvas = $('#' + videoSpanId + '>canvas').get(0);
|
||||
let audioLevelCanvas = $(`#${videoSpanId}>canvas`).get(0);
|
||||
|
||||
if (!audioLevelCanvas)
|
||||
if (!audioLevelCanvas) {
|
||||
return;
|
||||
}
|
||||
|
||||
var drawContext = audioLevelCanvas.getContext('2d');
|
||||
let drawContext = audioLevelCanvas.getContext('2d');
|
||||
|
||||
var canvasCache = audioLevelCanvasCache[resourceJid];
|
||||
let canvasCache = audioLevelCanvasCache[id];
|
||||
|
||||
drawContext.clearRect (0, 0,
|
||||
audioLevelCanvas.width, audioLevelCanvas.height);
|
||||
drawContext.clearRect(
|
||||
0, 0, audioLevelCanvas.width, audioLevelCanvas.height
|
||||
);
|
||||
drawContext.drawImage(canvasCache, 0, 0);
|
||||
|
||||
if(resourceJid === AudioLevels.LOCAL_LEVEL) {
|
||||
resourceJid = APP.conference.localId;
|
||||
if (!resourceJid) {
|
||||
if (id === LOCAL_LEVEL) {
|
||||
id = APP.conference.localId;
|
||||
if (!id) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if(resourceJid === largeVideoResourceJid) {
|
||||
if(id === largeVideoId) {
|
||||
window.requestAnimationFrame(function () {
|
||||
AudioLevels.updateActiveSpeakerAudioLevel(audioLevel);
|
||||
});
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
my.updateActiveSpeakerAudioLevel = function(audioLevel) {
|
||||
if($("#activeSpeaker").css("visibility") == "hidden" || ASDrawContext === null)
|
||||
updateActiveSpeakerAudioLevel (audioLevel) {
|
||||
if($("#activeSpeaker").css("visibility") == "hidden" || ASDrawContext === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
ASDrawContext.clearRect(0, 0, 300, 300);
|
||||
if (!audioLevel)
|
||||
if (!audioLevel) {
|
||||
return;
|
||||
}
|
||||
|
||||
ASDrawContext.shadowBlur = getShadowLevel(audioLevel);
|
||||
|
||||
|
||||
// Fill the shape.
|
||||
ASDrawContext.fill();
|
||||
};
|
||||
|
||||
/**
|
||||
* Resizes the given audio level canvas to match the given thumbnail size.
|
||||
*/
|
||||
function resizeAudioLevelCanvas(audioLevelCanvas,
|
||||
thumbnailWidth,
|
||||
thumbnailHeight) {
|
||||
audioLevelCanvas.width = thumbnailWidth + interfaceConfig.CANVAS_EXTRA;
|
||||
audioLevelCanvas.height = thumbnailHeight + interfaceConfig.CANVAS_EXTRA;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Draws the audio level canvas into the cached canvas object.
|
||||
*
|
||||
* @param resourceJid the resource jid indicating the video element for
|
||||
* which we draw the audio level
|
||||
* @param audioLevel the newAudio level to render
|
||||
*/
|
||||
function drawAudioLevelCanvas(resourceJid, audioLevel) {
|
||||
if (!audioLevelCanvasCache[resourceJid]) {
|
||||
|
||||
var videoSpanId = getVideoSpanId(resourceJid);
|
||||
|
||||
var audioLevelCanvasOrig = $('#' + videoSpanId + '>canvas').get(0);
|
||||
|
||||
/*
|
||||
* FIXME Testing has shown that audioLevelCanvasOrig may not exist.
|
||||
* In such a case, the method CanvasUtil.cloneCanvas may throw an
|
||||
* error. Since audio levels are frequently updated, the errors have
|
||||
* been observed to pile into the console, strain the CPU.
|
||||
*/
|
||||
if (audioLevelCanvasOrig) {
|
||||
audioLevelCanvasCache[resourceJid] =
|
||||
CanvasUtil.cloneCanvas(audioLevelCanvasOrig);
|
||||
}
|
||||
}
|
||||
|
||||
var canvas = audioLevelCanvasCache[resourceJid];
|
||||
|
||||
if (!canvas)
|
||||
return;
|
||||
|
||||
var drawContext = canvas.getContext('2d');
|
||||
|
||||
drawContext.clearRect(0, 0, canvas.width, canvas.height);
|
||||
|
||||
var shadowLevel = getShadowLevel(audioLevel);
|
||||
|
||||
if (shadowLevel > 0) {
|
||||
// drawContext, x, y, w, h, r, shadowColor, shadowLevel
|
||||
CanvasUtil.drawRoundRectGlow(drawContext,
|
||||
interfaceConfig.CANVAS_EXTRA / 2, interfaceConfig.CANVAS_EXTRA / 2,
|
||||
canvas.width - interfaceConfig.CANVAS_EXTRA,
|
||||
canvas.height - interfaceConfig.CANVAS_EXTRA,
|
||||
interfaceConfig.CANVAS_RADIUS,
|
||||
interfaceConfig.SHADOW_COLOR,
|
||||
shadowLevel);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the shadow/glow level for the given audio level.
|
||||
*
|
||||
* @param audioLevel the audio level from which we determine the shadow
|
||||
* level
|
||||
*/
|
||||
function getShadowLevel (audioLevel) {
|
||||
var shadowLevel = 0;
|
||||
|
||||
if (audioLevel <= 0.3) {
|
||||
shadowLevel = Math.round(interfaceConfig.CANVAS_EXTRA/2*(audioLevel/0.3));
|
||||
}
|
||||
else if (audioLevel <= 0.6) {
|
||||
shadowLevel = Math.round(interfaceConfig.CANVAS_EXTRA/2*((audioLevel - 0.3) / 0.3));
|
||||
}
|
||||
else {
|
||||
shadowLevel = Math.round(interfaceConfig.CANVAS_EXTRA/2*((audioLevel - 0.6) / 0.4));
|
||||
}
|
||||
return shadowLevel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the video span id corresponding to the given resourceJid or local
|
||||
* user.
|
||||
*/
|
||||
function getVideoSpanId(resourceJid) {
|
||||
var videoSpanId = null;
|
||||
if (resourceJid === AudioLevels.LOCAL_LEVEL || APP.conference.isLocalId(resourceJid)) {
|
||||
videoSpanId = 'localVideoContainer';
|
||||
} else {
|
||||
videoSpanId = 'participant_' + resourceJid;
|
||||
}
|
||||
|
||||
return videoSpanId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates that the remote video has been resized.
|
||||
*/
|
||||
$(document).bind('remotevideo.resized', function (event, width, height) {
|
||||
var resized = false;
|
||||
$('#remoteVideos>span>canvas').each(function() {
|
||||
var canvas = $(this).get(0);
|
||||
if (canvas.width !== width + interfaceConfig.CANVAS_EXTRA) {
|
||||
canvas.width = width + interfaceConfig.CANVAS_EXTRA;
|
||||
resized = true;
|
||||
}
|
||||
|
||||
if (canvas.height !== height + interfaceConfig.CANVAS_EXTRA) {
|
||||
canvas.height = height + interfaceConfig.CANVAS_EXTRA;
|
||||
resized = true;
|
||||
}
|
||||
});
|
||||
|
||||
if (resized)
|
||||
Object.keys(audioLevelCanvasCache).forEach(function (resourceJid) {
|
||||
audioLevelCanvasCache[resourceJid].width =
|
||||
width + interfaceConfig.CANVAS_EXTRA;
|
||||
audioLevelCanvasCache[resourceJid].height =
|
||||
height + interfaceConfig.CANVAS_EXTRA;
|
||||
});
|
||||
});
|
||||
|
||||
return my;
|
||||
|
||||
})(AudioLevels || {});
|
||||
|
||||
module.exports = AudioLevels;
|
||||
export default AudioLevels;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/**
|
||||
* Utility class for drawing canvas shapes.
|
||||
*/
|
||||
var CanvasUtil = (function(my) {
|
||||
const CanvasUtil = {
|
||||
|
||||
/**
|
||||
* Draws a round rectangle with a glow. The glowWidth indicates the depth
|
||||
|
@ -15,8 +15,7 @@ var CanvasUtil = (function(my) {
|
|||
* @param glowColor the color of the glow
|
||||
* @param glowWidth the width of the glow
|
||||
*/
|
||||
my.drawRoundRectGlow
|
||||
= function(drawContext, x, y, w, h, r, glowColor, glowWidth) {
|
||||
drawRoundRectGlow (drawContext, x, y, w, h, r, glowColor, glowWidth) {
|
||||
|
||||
// Save the previous state of the context.
|
||||
drawContext.save();
|
||||
|
@ -73,14 +72,14 @@ var CanvasUtil = (function(my) {
|
|||
|
||||
// Restore the previous context state.
|
||||
drawContext.restore();
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* Clones the given canvas.
|
||||
*
|
||||
* @return the new cloned canvas.
|
||||
*/
|
||||
my.cloneCanvas = function (oldCanvas) {
|
||||
cloneCanvas (oldCanvas) {
|
||||
/*
|
||||
* FIXME Testing has shown that oldCanvas may not exist. In such a case,
|
||||
* the method CanvasUtil.cloneCanvas may throw an error. Since audio
|
||||
|
@ -103,9 +102,7 @@ var CanvasUtil = (function(my) {
|
|||
|
||||
//return the new canvas
|
||||
return newCanvas;
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
return my;
|
||||
})(CanvasUtil || {});
|
||||
|
||||
module.exports = CanvasUtil;
|
||||
export default CanvasUtil;
|
||||
|
|
|
@ -1,124 +0,0 @@
|
|||
/* global $, APP*/
|
||||
|
||||
var LoginDialog = require('./LoginDialog');
|
||||
var Moderator = require('../../xmpp/moderator');
|
||||
|
||||
/* Initial "authentication required" dialog */
|
||||
var authDialog = null;
|
||||
/* Loop retry ID that wits for other user to create the room */
|
||||
var authRetryId = null;
|
||||
var authenticationWindow = null;
|
||||
|
||||
var Authentication = {
|
||||
openAuthenticationDialog: function (roomName, intervalCallback, callback) {
|
||||
// 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(intervalCallback, 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('@'));
|
||||
|
||||
var title
|
||||
= APP.translation.generateTranslationHTML("dialog.WaitingForHost");
|
||||
var msg
|
||||
= APP.translation.generateTranslationHTML(
|
||||
"dialog.WaitForHostMsg", {room: room});
|
||||
|
||||
var buttonTxt
|
||||
= APP.translation.generateTranslationHTML("dialog.IamHost");
|
||||
var buttons = [];
|
||||
buttons.push({title: buttonTxt, value: "authNow"});
|
||||
|
||||
authDialog = APP.UI.messageHandler.openDialog(
|
||||
title,
|
||||
msg,
|
||||
true,
|
||||
buttons,
|
||||
function (onSubmitEvent, submitValue) {
|
||||
|
||||
// Do not close the dialog yet
|
||||
onSubmitEvent.preventDefault();
|
||||
|
||||
// Open login popup
|
||||
if (submitValue === 'authNow') {
|
||||
callback();
|
||||
}
|
||||
}
|
||||
);
|
||||
},
|
||||
closeAuthenticationWindow: function () {
|
||||
if (authenticationWindow) {
|
||||
authenticationWindow.close();
|
||||
authenticationWindow = null;
|
||||
}
|
||||
},
|
||||
xmppAuthenticate: function () {
|
||||
|
||||
var loginDialog = LoginDialog.show(
|
||||
function (connection, state) {
|
||||
if (!state) {
|
||||
// User cancelled
|
||||
loginDialog.close();
|
||||
return;
|
||||
} else if (state == APP.xmpp.Status.CONNECTED) {
|
||||
|
||||
loginDialog.close();
|
||||
|
||||
Authentication.stopInterval();
|
||||
Authentication.closeAuthenticationDialog();
|
||||
|
||||
// Close the connection as anonymous one will be used
|
||||
// to create the conference. Session-id will authorize
|
||||
// the request.
|
||||
connection.disconnect();
|
||||
|
||||
var roomName = APP.UI.generateRoomName();
|
||||
Moderator.allocateConferenceFocus(roomName, function () {
|
||||
// If it's not "on the fly" authentication now join
|
||||
// the conference room
|
||||
if (!APP.xmpp.isMUCJoined()) {
|
||||
APP.UI.checkForNicknameAndJoin();
|
||||
}
|
||||
});
|
||||
}
|
||||
}, true);
|
||||
},
|
||||
focusAuthenticationWindow: function () {
|
||||
// If auth window exists just bring it to the front
|
||||
if (authenticationWindow) {
|
||||
authenticationWindow.focus();
|
||||
return;
|
||||
}
|
||||
},
|
||||
closeAuthenticationDialog: function () {
|
||||
// Close authentication dialog if opened
|
||||
if (authDialog) {
|
||||
authDialog.close();
|
||||
authDialog = null;
|
||||
}
|
||||
},
|
||||
createAuthenticationWindow: function (callback, url) {
|
||||
authenticationWindow = APP.UI.messageHandler.openCenteredPopup(
|
||||
url, 910, 660,
|
||||
// On closed
|
||||
function () {
|
||||
// Close authentication dialog if opened
|
||||
Authentication.closeAuthenticationDialog();
|
||||
callback();
|
||||
authenticationWindow = null;
|
||||
});
|
||||
return authenticationWindow;
|
||||
},
|
||||
stopInterval: function () {
|
||||
// Clear retry interval, so that we don't call 'doJoinAfterFocus' twice
|
||||
if (authRetryId) {
|
||||
window.clearTimeout(authRetryId);
|
||||
authRetryId = null;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = Authentication;
|
|
@ -1,75 +1,78 @@
|
|||
/* global $, APP, config*/
|
||||
|
||||
var XMPP = require('../../xmpp/xmpp');
|
||||
var Moderator = require('../../xmpp/moderator');
|
||||
var messageHandler = require('../util/MessageHandler');
|
||||
|
||||
//FIXME: use LoginDialog to add retries to XMPP.connect method used when
|
||||
// anonymous domain is not enabled
|
||||
function getPasswordInputHtml() {
|
||||
let placeholder = config.hosts.authdomain
|
||||
? "user identity"
|
||||
: "user@domain.net";
|
||||
let passRequiredMsg = APP.translation.translateString(
|
||||
"dialog.passwordRequired"
|
||||
);
|
||||
return `
|
||||
<h2 data-i18n="dialog.passwordRequired">${passRequiredMsg}</h2>
|
||||
<input name="username" type="text" placeholder=${placeholder} autofocus>
|
||||
<input name="password" type="password"
|
||||
data-i18n="[placeholder]dialog.userPassword"
|
||||
placeholder="user password">
|
||||
`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new <tt>Dialog</tt> instance.
|
||||
* @param callback <tt>function(Strophe.Connection, Strophe.Status)</tt> called
|
||||
* when we either fail to connect or succeed(check Strophe.Status).
|
||||
* @param obtainSession <tt>true</tt> if we want to send ConferenceIQ to Jicofo
|
||||
* in order to create session-id after the connection is established.
|
||||
* @constructor
|
||||
*/
|
||||
function Dialog(callback, obtainSession) {
|
||||
|
||||
var self = this;
|
||||
|
||||
var stop = false;
|
||||
|
||||
var connection = APP.xmpp.createConnection();
|
||||
|
||||
var message = '<h2 data-i18n="dialog.passwordRequired">';
|
||||
message += APP.translation.translateString("dialog.passwordRequired");
|
||||
message += '</h2>' +
|
||||
'<input name="username" type="text" ';
|
||||
if (config.hosts.authdomain) {
|
||||
message += 'placeholder="user identity" autofocus>';
|
||||
} else {
|
||||
message += 'placeholder="user@domain.net" autofocus>';
|
||||
function toJid(id) {
|
||||
if (id.indexOf("@") >= 0) {
|
||||
return id;
|
||||
}
|
||||
message += '<input name="password" ' +
|
||||
'type="password" data-i18n="[placeholder]dialog.userPassword"' +
|
||||
' placeholder="user password">';
|
||||
|
||||
var okButton = APP.translation.generateTranslationHTML("dialog.Ok");
|
||||
let jid = id.concat('@');
|
||||
if (config.hosts.authdomain) {
|
||||
jid += config.hosts.authdomain;
|
||||
} else {
|
||||
jid += config.hosts.domain;
|
||||
}
|
||||
|
||||
var cancelButton = APP.translation.generateTranslationHTML("dialog.Cancel");
|
||||
return jid;
|
||||
}
|
||||
|
||||
var states = {
|
||||
function cancelButton() {
|
||||
return {
|
||||
title: APP.translation.generateTranslationHTML("dialog.Cancel"),
|
||||
value: false
|
||||
};
|
||||
}
|
||||
|
||||
function Dialog(successCallback, cancelCallback) {
|
||||
let loginButtons = [{
|
||||
title: APP.translation.generateTranslationHTML("dialog.Ok"),
|
||||
value: true
|
||||
}];
|
||||
let finishedButtons = [{
|
||||
title: APP.translation.translateString('dialog.retry'),
|
||||
value: 'retry'
|
||||
}];
|
||||
|
||||
// show "cancel" button only if cancelCallback provided
|
||||
if (cancelCallback) {
|
||||
loginButtons.push(cancelButton());
|
||||
finishedButtons.push(cancelButton());
|
||||
}
|
||||
|
||||
const states = {
|
||||
login: {
|
||||
html: message,
|
||||
buttons: [
|
||||
{ title: okButton, value: true},
|
||||
{ title: cancelButton, value: false}
|
||||
],
|
||||
html: getPasswordInputHtml(),
|
||||
buttons: loginButtons,
|
||||
focus: ':input:first',
|
||||
submit: function (e, v, m, f) {
|
||||
e.preventDefault();
|
||||
if (v) {
|
||||
var jid = f.username;
|
||||
var password = f.password;
|
||||
let jid = f.username;
|
||||
let password = f.password;
|
||||
if (jid && password) {
|
||||
stop = false;
|
||||
if (jid.indexOf("@") < 0) {
|
||||
jid = jid.concat('@');
|
||||
if (config.hosts.authdomain) {
|
||||
jid += config.hosts.authdomain;
|
||||
} else {
|
||||
jid += config.hosts.domain;
|
||||
}
|
||||
}
|
||||
connection.reset();
|
||||
connDialog.goToState('connecting');
|
||||
connection.connect(jid, password, stateHandler);
|
||||
successCallback(toJid(jid), password);
|
||||
}
|
||||
} else {
|
||||
// User cancelled
|
||||
stop = true;
|
||||
callback();
|
||||
cancelCallback();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -82,115 +85,23 @@ function Dialog(callback, obtainSession) {
|
|||
finished: {
|
||||
title: APP.translation.translateString('dialog.error'),
|
||||
html: '<div id="errorMessage"></div>',
|
||||
buttons: [
|
||||
{
|
||||
title: APP.translation.translateString('dialog.retry'),
|
||||
value: 'retry'
|
||||
},
|
||||
{
|
||||
title: APP.translation.translateString('dialog.Cancel'),
|
||||
value: 'cancel'
|
||||
},
|
||||
],
|
||||
buttons: finishedButtons,
|
||||
defaultButton: 0,
|
||||
submit: function (e, v, m, f) {
|
||||
e.preventDefault();
|
||||
if (v === 'retry')
|
||||
if (v === 'retry') {
|
||||
connDialog.goToState('login');
|
||||
else
|
||||
callback();
|
||||
} else {
|
||||
// User cancelled
|
||||
cancelCallback();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var connDialog
|
||||
= APP.UI.messageHandler.openDialogWithStates(states,
|
||||
{ persistent: true, closeText: '' }, null);
|
||||
|
||||
var stateHandler = function (status, message) {
|
||||
if (stop) {
|
||||
return;
|
||||
}
|
||||
|
||||
var translateKey = "connection." + XMPP.getStatusString(status);
|
||||
var statusStr = APP.translation.translateString(translateKey);
|
||||
|
||||
// Display current state
|
||||
var connectionStatus =
|
||||
connDialog.getState('connecting').find('#connectionStatus');
|
||||
|
||||
connectionStatus.text(statusStr);
|
||||
|
||||
switch (status) {
|
||||
case XMPP.Status.CONNECTED:
|
||||
|
||||
stop = true;
|
||||
if (!obtainSession) {
|
||||
callback(connection, status);
|
||||
return;
|
||||
}
|
||||
// Obtaining session-id status
|
||||
connectionStatus.text(
|
||||
APP.translation.translateString(
|
||||
'connection.FETCH_SESSION_ID'));
|
||||
|
||||
// Authenticate with Jicofo and obtain session-id
|
||||
var roomName = APP.UI.generateRoomName();
|
||||
|
||||
// Jicofo will return new session-id when connected
|
||||
// from authenticated domain
|
||||
connection.sendIQ(
|
||||
Moderator.createConferenceIq(roomName),
|
||||
function (result) {
|
||||
|
||||
connectionStatus.text(
|
||||
APP.translation.translateString(
|
||||
'connection.GOT_SESSION_ID'));
|
||||
|
||||
stop = true;
|
||||
|
||||
// Parse session-id
|
||||
Moderator.parseSessionId(result);
|
||||
|
||||
callback(connection, status);
|
||||
},
|
||||
function (error) {
|
||||
console.error("Auth on the fly failed", error);
|
||||
|
||||
stop = true;
|
||||
|
||||
var errorMsg =
|
||||
APP.translation.translateString(
|
||||
'connection.GET_SESSION_ID_ERROR') +
|
||||
$(error).find('>error').attr('code');
|
||||
|
||||
self.displayError(errorMsg);
|
||||
|
||||
connection.disconnect();
|
||||
});
|
||||
|
||||
break;
|
||||
case XMPP.Status.AUTHFAIL:
|
||||
case XMPP.Status.CONNFAIL:
|
||||
case XMPP.Status.DISCONNECTED:
|
||||
|
||||
stop = true;
|
||||
|
||||
callback(connection, status);
|
||||
|
||||
var errorMessage = statusStr;
|
||||
|
||||
if (message)
|
||||
{
|
||||
errorMessage += ': ' + message;
|
||||
}
|
||||
self.displayError(errorMessage);
|
||||
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
};
|
||||
var connDialog = messageHandler.openDialogWithStates(
|
||||
states, { persistent: true, closeText: '' }, null
|
||||
);
|
||||
|
||||
/**
|
||||
* Displays error message in 'finished' state which allows either to cancel
|
||||
|
@ -211,30 +122,60 @@ function Dialog(callback, obtainSession) {
|
|||
* Closes LoginDialog.
|
||||
*/
|
||||
this.close = function () {
|
||||
stop = true;
|
||||
connDialog.close();
|
||||
};
|
||||
}
|
||||
|
||||
var LoginDialog = {
|
||||
const LoginDialog = {
|
||||
|
||||
/**
|
||||
* Displays login prompt used to establish new XMPP connection. Given
|
||||
* <tt>callback(Strophe.Connection, Strophe.Status)</tt> function will be
|
||||
* called when we connect successfully(status === CONNECTED) or when we fail
|
||||
* to do so. On connection failure program can call Dialog.close() method in
|
||||
* order to cancel or do nothing to let the user retry.
|
||||
* @param callback <tt>function(Strophe.Connection, Strophe.Status)</tt>
|
||||
* called when we either fail to connect or succeed(check
|
||||
* Strophe.Status).
|
||||
* @param obtainSession <tt>true</tt> if we want to send ConferenceIQ to
|
||||
* Jicofo in order to create session-id after the connection is
|
||||
* established.
|
||||
* @returns {Dialog}
|
||||
*/
|
||||
show: function (callback, obtainSession) {
|
||||
return new Dialog(callback, obtainSession);
|
||||
showAuthDialog: function (successCallback, cancelCallback) {
|
||||
return new Dialog(successCallback, cancelCallback);
|
||||
},
|
||||
|
||||
showExternalAuthDialog: function (url, callback) {
|
||||
var dialog = messageHandler.openCenteredPopup(
|
||||
url, 910, 660,
|
||||
// On closed
|
||||
callback
|
||||
);
|
||||
|
||||
if (!dialog) {
|
||||
messageHandler.openMessageDialog(null, "dialog.popupError");
|
||||
}
|
||||
|
||||
return dialog;
|
||||
},
|
||||
|
||||
showAuthRequiredDialog: function (roomName, onAuthNow) {
|
||||
var title = APP.translation.generateTranslationHTML(
|
||||
"dialog.WaitingForHost"
|
||||
);
|
||||
var msg = APP.translation.generateTranslationHTML(
|
||||
"dialog.WaitForHostMsg", {room: roomName}
|
||||
);
|
||||
|
||||
var buttonTxt = APP.translation.generateTranslationHTML(
|
||||
"dialog.IamHost"
|
||||
);
|
||||
var buttons = [{title: buttonTxt, value: "authNow"}];
|
||||
|
||||
return APP.UI.messageHandler.openDialog(
|
||||
title,
|
||||
msg,
|
||||
true,
|
||||
buttons,
|
||||
function (e, submitValue) {
|
||||
|
||||
// Do not close the dialog yet
|
||||
e.preventDefault();
|
||||
|
||||
// Open login popup
|
||||
if (submitValue === 'authNow') {
|
||||
onAuthNow();
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = LoginDialog;
|
||||
export default LoginDialog;
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
var ToolbarToggler = require("../toolbars/ToolbarToggler");
|
||||
var UIUtil = require("../util/UIUtil");
|
||||
var VideoLayout = require("../videolayout/VideoLayout");
|
||||
/* global $, APP */
|
||||
/* jshint -W101 */
|
||||
import UIUtil from "../util/UIUtil";
|
||||
import VideoLayout from "../videolayout/VideoLayout";
|
||||
|
||||
var messageHandler = require("../util/MessageHandler");
|
||||
var PreziPlayer = require("./PreziPlayer");
|
||||
|
||||
|
|
|
@ -1,102 +1,101 @@
|
|||
/* global require, $ */
|
||||
var Chat = require("./chat/Chat");
|
||||
var ContactList = require("./contactlist/ContactList");
|
||||
var Settings = require("./../../settings/Settings");
|
||||
var SettingsMenu = require("./settings/SettingsMenu");
|
||||
var VideoLayout = require("../videolayout/VideoLayout");
|
||||
var ToolbarToggler = require("../toolbars/ToolbarToggler");
|
||||
var UIUtil = require("../util/UIUtil");
|
||||
var LargeVideo = require("../videolayout/LargeVideo");
|
||||
import Chat from "./chat/Chat";
|
||||
import ContactList from "./contactlist/ContactList";
|
||||
import Settings from "./../../settings/Settings";
|
||||
import SettingsMenu from "./settings/SettingsMenu";
|
||||
import VideoLayout from "../videolayout/VideoLayout";
|
||||
import ToolbarToggler from "../toolbars/ToolbarToggler";
|
||||
import UIUtil from "../util/UIUtil";
|
||||
import LargeVideo from "../videolayout/LargeVideo";
|
||||
|
||||
const buttons = {
|
||||
'#chatspace': '#chatBottomButton',
|
||||
'#contactlist': '#contactListButton',
|
||||
'#settingsmenu': '#toolbar_button_settings'
|
||||
};
|
||||
|
||||
var currentlyOpen = null;
|
||||
|
||||
/**
|
||||
* Toggles the windows in the side panel
|
||||
* @param object the window that should be shown
|
||||
* @param selector the selector for the element containing the panel
|
||||
* @param onOpenComplete function to be called when the panel is opened
|
||||
* @param onOpen function to be called if the window is going to be opened
|
||||
* @param onClose function to be called if the window is going to be closed
|
||||
*/
|
||||
function toggle (object, selector, onOpenComplete, onOpen, onClose) {
|
||||
UIUtil.buttonClick(buttons[selector], "active");
|
||||
|
||||
if (object.isVisible()) {
|
||||
$("#toast-container").animate({
|
||||
right: 5
|
||||
}, {
|
||||
queue: false,
|
||||
duration: 500
|
||||
});
|
||||
$(selector).hide("slide", {
|
||||
direction: "right",
|
||||
queue: false,
|
||||
duration: 500
|
||||
});
|
||||
if(typeof onClose === "function") {
|
||||
onClose();
|
||||
}
|
||||
|
||||
currentlyOpen = null;
|
||||
} else {
|
||||
// Undock the toolbar when the chat is shown and if we're in a
|
||||
// video mode.
|
||||
if (LargeVideo.isLargeVideoVisible()) {
|
||||
ToolbarToggler.dockToolbar(false);
|
||||
}
|
||||
|
||||
if (currentlyOpen) {
|
||||
var current = $(currentlyOpen);
|
||||
UIUtil.buttonClick(buttons[currentlyOpen], "active");
|
||||
current.css('z-index', 4);
|
||||
setTimeout(function () {
|
||||
current.css('display', 'none');
|
||||
current.css('z-index', 5);
|
||||
}, 500);
|
||||
}
|
||||
|
||||
$("#toast-container").animate({
|
||||
right: (PanelToggler.getPanelSize()[0] + 5)
|
||||
}, {
|
||||
queue: false,
|
||||
duration: 500
|
||||
});
|
||||
$(selector).show("slide", {
|
||||
direction: "right",
|
||||
queue: false,
|
||||
duration: 500,
|
||||
complete: onOpenComplete
|
||||
});
|
||||
if(typeof onOpen === "function") {
|
||||
onOpen();
|
||||
}
|
||||
|
||||
currentlyOpen = selector;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggler for the chat, contact list, settings menu, etc..
|
||||
*/
|
||||
var PanelToggler = (function(my) {
|
||||
|
||||
var currentlyOpen = null;
|
||||
var buttons = {
|
||||
'#chatspace': '#chatBottomButton',
|
||||
'#contactlist': '#contactListButton',
|
||||
'#settingsmenu': '#toolbar_button_settings'
|
||||
};
|
||||
|
||||
/**
|
||||
* Toggles the windows in the side panel
|
||||
* @param object the window that should be shown
|
||||
* @param selector the selector for the element containing the panel
|
||||
* @param onOpenComplete function to be called when the panel is opened
|
||||
* @param onOpen function to be called if the window is going to be opened
|
||||
* @param onClose function to be called if the window is going to be closed
|
||||
*/
|
||||
var toggle = function(object, selector, onOpenComplete, onOpen, onClose) {
|
||||
UIUtil.buttonClick(buttons[selector], "active");
|
||||
|
||||
if (object.isVisible()) {
|
||||
$("#toast-container").animate({
|
||||
right: '5px'
|
||||
},
|
||||
{
|
||||
queue: false,
|
||||
duration: 500
|
||||
});
|
||||
$(selector).hide("slide", {
|
||||
direction: "right",
|
||||
queue: false,
|
||||
duration: 500
|
||||
});
|
||||
if(typeof onClose === "function") {
|
||||
onClose();
|
||||
}
|
||||
|
||||
currentlyOpen = null;
|
||||
}
|
||||
else {
|
||||
// Undock the toolbar when the chat is shown and if we're in a
|
||||
// video mode.
|
||||
if (LargeVideo.isLargeVideoVisible()) {
|
||||
ToolbarToggler.dockToolbar(false);
|
||||
}
|
||||
|
||||
if(currentlyOpen) {
|
||||
var current = $(currentlyOpen);
|
||||
UIUtil.buttonClick(buttons[currentlyOpen], "active");
|
||||
current.css('z-index', 4);
|
||||
setTimeout(function () {
|
||||
current.css('display', 'none');
|
||||
current.css('z-index', 5);
|
||||
}, 500);
|
||||
}
|
||||
|
||||
$("#toast-container").animate({
|
||||
right: (PanelToggler.getPanelSize()[0] + 5) + 'px'
|
||||
},
|
||||
{
|
||||
queue: false,
|
||||
duration: 500
|
||||
});
|
||||
$(selector).show("slide", {
|
||||
direction: "right",
|
||||
queue: false,
|
||||
duration: 500,
|
||||
complete: onOpenComplete
|
||||
});
|
||||
if(typeof onOpen === "function") {
|
||||
onOpen();
|
||||
}
|
||||
|
||||
currentlyOpen = selector;
|
||||
}
|
||||
};
|
||||
var PanelToggler = {
|
||||
|
||||
/**
|
||||
* Opens / closes the chat area.
|
||||
*/
|
||||
my.toggleChat = function() {
|
||||
var chatCompleteFunction = Chat.isVisible() ?
|
||||
function() {} : function () {
|
||||
Chat.scrollChatToBottom();
|
||||
$('#chatspace').trigger('shown');
|
||||
};
|
||||
toggleChat () {
|
||||
var chatCompleteFunction = Chat.isVisible()
|
||||
? function () {}
|
||||
: function () {
|
||||
Chat.scrollChatToBottom();
|
||||
$('#chatspace').trigger('shown');
|
||||
};
|
||||
|
||||
VideoLayout.resizeVideoArea(!Chat.isVisible(), chatCompleteFunction);
|
||||
|
||||
|
@ -112,16 +111,24 @@ var PanelToggler = (function(my) {
|
|||
}
|
||||
},
|
||||
null,
|
||||
Chat.resizeChat,
|
||||
() => this.resizeChat(),
|
||||
null);
|
||||
};
|
||||
},
|
||||
|
||||
resizeChat () {
|
||||
let [width, height] = this.getPanelSize();
|
||||
Chat.resizeChat(width, height);
|
||||
},
|
||||
|
||||
/**
|
||||
* Opens / closes the contact list area.
|
||||
*/
|
||||
my.toggleContactList = function () {
|
||||
var completeFunction = ContactList.isVisible() ?
|
||||
function() {} : function () { $('#contactlist').trigger('shown');};
|
||||
toggleContactList () {
|
||||
var completeFunction = ContactList.isVisible()
|
||||
? function () {}
|
||||
: function () {
|
||||
$('#contactlist').trigger('shown');
|
||||
};
|
||||
VideoLayout.resizeVideoArea(!ContactList.isVisible(), completeFunction);
|
||||
|
||||
toggle(ContactList,
|
||||
|
@ -131,12 +138,12 @@ var PanelToggler = (function(my) {
|
|||
ContactList.setVisualNotification(false);
|
||||
},
|
||||
null);
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* Opens / closes the settings menu
|
||||
*/
|
||||
my.toggleSettingsMenu = function() {
|
||||
toggleSettingsMenu () {
|
||||
VideoLayout.resizeVideoArea(!SettingsMenu.isVisible(), function (){});
|
||||
toggle(SettingsMenu,
|
||||
'#settingsmenu',
|
||||
|
@ -147,12 +154,12 @@ var PanelToggler = (function(my) {
|
|||
$('#setEmail').get(0).value = settings.email;
|
||||
},
|
||||
null);
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the size of the side panel.
|
||||
*/
|
||||
my.getPanelSize = function () {
|
||||
getPanelSize () {
|
||||
var availableHeight = window.innerHeight;
|
||||
var availableWidth = window.innerWidth;
|
||||
|
||||
|
@ -162,16 +169,13 @@ var PanelToggler = (function(my) {
|
|||
}
|
||||
|
||||
return [panelWidth, availableHeight];
|
||||
};
|
||||
},
|
||||
|
||||
my.isVisible = function() {
|
||||
isVisible () {
|
||||
return (Chat.isVisible() ||
|
||||
ContactList.isVisible() ||
|
||||
SettingsMenu.isVisible());
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
return my;
|
||||
|
||||
}(PanelToggler || {}));
|
||||
|
||||
module.exports = PanelToggler;
|
||||
export default PanelToggler;
|
||||
|
|
|
@ -1,10 +1,13 @@
|
|||
/* global APP, $ */
|
||||
var Replacement = require("./Replacement");
|
||||
var CommandsProcessor = require("./Commands");
|
||||
var ToolbarToggler = require("../../toolbars/ToolbarToggler");
|
||||
|
||||
import {processReplacements, linkify} from './Replacement';
|
||||
import CommandsProcessor from './Commands';
|
||||
import ToolbarToggler from '../../toolbars/ToolbarToggler';
|
||||
|
||||
import UIUtil from '../../util/UIUtil';
|
||||
import UIEvents from '../../../../service/UI/UIEvents';
|
||||
|
||||
var smileys = require("./smileys.json").smileys;
|
||||
var UIUtil = require("../../util/UIUtil");
|
||||
var UIEvents = require("../../../../service/UI/UIEvents");
|
||||
|
||||
var notificationInterval = false;
|
||||
var unreadMessages = 0;
|
||||
|
@ -164,11 +167,11 @@ function resizeChatConversation() {
|
|||
/**
|
||||
* Chat related user interface.
|
||||
*/
|
||||
var Chat = (function (my) {
|
||||
var Chat = {
|
||||
/**
|
||||
* Initializes chat related interface.
|
||||
*/
|
||||
my.init = function (eventEmitter) {
|
||||
init (eventEmitter) {
|
||||
if (APP.settings.getDisplayName()) {
|
||||
Chat.setChatConversationMode(true);
|
||||
}
|
||||
|
@ -178,10 +181,7 @@ var Chat = (function (my) {
|
|||
event.preventDefault();
|
||||
var val = UIUtil.escapeHtml(this.value);
|
||||
this.value = '';
|
||||
if (APP.settings.getDisplayName()) {
|
||||
eventEmitter.emit(UIEvents.NICKNAME_CHANGED, val);
|
||||
return;
|
||||
}
|
||||
eventEmitter.emit(UIEvents.NICKNAME_CHANGED, val);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -192,11 +192,10 @@ var Chat = (function (my) {
|
|||
var value = this.value;
|
||||
usermsg.val('').trigger('autosize.resize');
|
||||
this.focus();
|
||||
var command = new CommandsProcessor(value);
|
||||
if(command.isCommand()) {
|
||||
var command = new CommandsProcessor(value, eventEmitter);
|
||||
if (command.isCommand()) {
|
||||
command.processCommand();
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
var message = UIUtil.escapeHtml(value);
|
||||
eventEmitter.emit(UIEvents.MESSAGE_CREATED, message);
|
||||
}
|
||||
|
@ -216,19 +215,17 @@ var Chat = (function (my) {
|
|||
});
|
||||
|
||||
addSmileys();
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* Appends the given message to the chat conversation.
|
||||
*/
|
||||
my.updateChatConversation =
|
||||
function (from, displayName, message, stamp) {
|
||||
updateChatConversation (id, displayName, message, stamp) {
|
||||
var divClassName = '';
|
||||
|
||||
if (APP.xmpp.myJid() === from) {
|
||||
if (APP.conference.isLocalId(id)) {
|
||||
divClassName = "localuser";
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
divClassName = "remoteuser";
|
||||
|
||||
if (!Chat.isVisible()) {
|
||||
|
@ -244,7 +241,7 @@ var Chat = (function (my) {
|
|||
var escMessage = message.replace(/</g, '<').
|
||||
replace(/>/g, '>').replace(/\n/g, '<br/>');
|
||||
var escDisplayName = UIUtil.escapeHtml(displayName);
|
||||
message = Replacement.processReplacements(escMessage);
|
||||
message = processReplacements(escMessage);
|
||||
|
||||
var messageContainer =
|
||||
'<div class="chatmessage">'+
|
||||
|
@ -257,14 +254,14 @@ var Chat = (function (my) {
|
|||
$('#chatconversation').append(messageContainer);
|
||||
$('#chatconversation').animate(
|
||||
{ scrollTop: $('#chatconversation')[0].scrollHeight}, 1000);
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* Appends error message to the conversation
|
||||
* @param errorMessage the received error message.
|
||||
* @param originalText the original message.
|
||||
*/
|
||||
my.chatAddError = function(errorMessage, originalText) {
|
||||
chatAddError (errorMessage, originalText) {
|
||||
errorMessage = UIUtil.escapeHtml(errorMessage);
|
||||
originalText = UIUtil.escapeHtml(originalText);
|
||||
|
||||
|
@ -275,28 +272,28 @@ var Chat = (function (my) {
|
|||
(errorMessage? (' Reason: ' + errorMessage) : '') + '</div>');
|
||||
$('#chatconversation').animate(
|
||||
{ scrollTop: $('#chatconversation')[0].scrollHeight}, 1000);
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets the subject to the UI
|
||||
* @param subject the subject
|
||||
*/
|
||||
my.chatSetSubject = function(subject) {
|
||||
if (subject)
|
||||
setSubject (subject) {
|
||||
if (subject) {
|
||||
subject = subject.trim();
|
||||
$('#subject').html(Replacement.linkify(UIUtil.escapeHtml(subject)));
|
||||
if(subject === "") {
|
||||
}
|
||||
$('#subject').html(linkify(UIUtil.escapeHtml(subject)));
|
||||
if (subject) {
|
||||
$("#subject").css({display: "block"});
|
||||
} else {
|
||||
$("#subject").css({display: "none"});
|
||||
}
|
||||
else {
|
||||
$("#subject").css({display: "block"});
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets the chat conversation mode.
|
||||
*/
|
||||
my.setChatConversationMode = function (isConversationMode) {
|
||||
setChatConversationMode (isConversationMode) {
|
||||
if (isConversationMode) {
|
||||
$('#nickname').css({visibility: 'hidden'});
|
||||
$('#chatconversation').css({visibility: 'visible'});
|
||||
|
@ -304,42 +301,37 @@ var Chat = (function (my) {
|
|||
$('#smileysarea').css({visibility: 'visible'});
|
||||
$('#usermsg').focus();
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* Resizes the chat area.
|
||||
*/
|
||||
my.resizeChat = function () {
|
||||
var chatSize = require("../SidePanelToggler").getPanelSize();
|
||||
|
||||
$('#chatspace').width(chatSize[0]);
|
||||
$('#chatspace').height(chatSize[1]);
|
||||
resizeChat (width, height) {
|
||||
$('#chatspace').width(width).height(height);
|
||||
|
||||
resizeChatConversation();
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* Indicates if the chat is currently visible.
|
||||
*/
|
||||
my.isVisible = function () {
|
||||
isVisible () {
|
||||
return $('#chatspace').is(":visible");
|
||||
};
|
||||
},
|
||||
/**
|
||||
* Shows and hides the window with the smileys
|
||||
*/
|
||||
my.toggleSmileys = toggleSmileys;
|
||||
toggleSmileys,
|
||||
|
||||
/**
|
||||
* Scrolls chat to the bottom.
|
||||
*/
|
||||
my.scrollChatToBottom = function() {
|
||||
scrollChatToBottom () {
|
||||
setTimeout(function () {
|
||||
$('#chatconversation').scrollTop(
|
||||
$('#chatconversation')[0].scrollHeight);
|
||||
}, 5);
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
return my;
|
||||
}(Chat || {}));
|
||||
module.exports = Chat;
|
||||
export default Chat;
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
/* global APP, require */
|
||||
var UIUtil = require("../../util/UIUtil");
|
||||
/* global APP */
|
||||
import UIUtil from '../../util/UIUtil';
|
||||
import UIEvents from '../../../../service/UI/UIEvents';
|
||||
|
||||
/**
|
||||
* List with supported commands. The keys are the names of the commands and
|
||||
* the value is the function that processes the message.
|
||||
* @type {{String: function}}
|
||||
*/
|
||||
var commands = {
|
||||
const commands = {
|
||||
"topic" : processTopic
|
||||
};
|
||||
|
||||
|
@ -29,9 +30,9 @@ function getCommand(message) {
|
|||
* Processes the data for topic command.
|
||||
* @param commandArguments the arguments of the topic command.
|
||||
*/
|
||||
function processTopic(commandArguments) {
|
||||
function processTopic(commandArguments, emitter) {
|
||||
var topic = UIUtil.escapeHtml(commandArguments);
|
||||
APP.xmpp.setSubject(topic);
|
||||
emitter.emit(UIEvents.TOPIC_CHANGED, topic);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -40,9 +41,11 @@ function processTopic(commandArguments) {
|
|||
* @param message the message
|
||||
* @constructor
|
||||
*/
|
||||
function CommandsProcessor(message) {
|
||||
function CommandsProcessor(message, emitter) {
|
||||
var command = getCommand(message);
|
||||
|
||||
this.emitter = emitter;
|
||||
|
||||
/**
|
||||
* Returns the name of the command.
|
||||
* @returns {String} the command
|
||||
|
@ -80,7 +83,7 @@ CommandsProcessor.prototype.processCommand = function() {
|
|||
if(!this.isCommand())
|
||||
return;
|
||||
|
||||
commands[this.getCommand()](this.getArgument());
|
||||
commands[this.getCommand()](this.getArgument(), this.emitter);
|
||||
};
|
||||
|
||||
module.exports = CommandsProcessor;
|
||||
export default CommandsProcessor;
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
/* jshint -W101 */
|
||||
var Smileys = require("./smileys.json");
|
||||
|
||||
/**
|
||||
* Processes links and smileys in "body"
|
||||
*/
|
||||
function processReplacements(body)
|
||||
{
|
||||
export function processReplacements(body) {
|
||||
//make links clickable
|
||||
body = linkify(body);
|
||||
|
||||
|
@ -18,8 +18,7 @@ function processReplacements(body)
|
|||
* Finds and replaces all links in the links in "body"
|
||||
* with their <a href=""></a>
|
||||
*/
|
||||
function linkify(inputText)
|
||||
{
|
||||
export function linkify(inputText) {
|
||||
var replacedText, replacePattern1, replacePattern2, replacePattern3;
|
||||
|
||||
//URLs starting with http://, https://, or ftp://
|
||||
|
@ -40,8 +39,7 @@ function linkify(inputText)
|
|||
/**
|
||||
* Replaces common smiley strings with images
|
||||
*/
|
||||
function smilify(body)
|
||||
{
|
||||
function smilify(body) {
|
||||
if(!body) {
|
||||
return body;
|
||||
}
|
||||
|
@ -56,8 +54,3 @@ function smilify(body)
|
|||
|
||||
return body;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
processReplacements: processReplacements,
|
||||
linkify: linkify
|
||||
};
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
/* global $, APP, Strophe */
|
||||
var Avatar = require('../../avatar/Avatar');
|
||||
/* global $, APP */
|
||||
import Avatar from '../../avatar/Avatar';
|
||||
import UIEvents from '../../../../service/UI/UIEvents';
|
||||
|
||||
var numberOfContacts = 0;
|
||||
var notificationInterval;
|
||||
let numberOfContacts = 0;
|
||||
let notificationInterval;
|
||||
|
||||
/**
|
||||
* Updates the number of participants in the contact list button and sets
|
||||
|
@ -30,7 +31,7 @@ function updateNumberOfParticipants(delta) {
|
|||
* @return {object} the newly created avatar element
|
||||
*/
|
||||
function createAvatar(jid) {
|
||||
var avatar = document.createElement('img');
|
||||
let avatar = document.createElement('img');
|
||||
avatar.className = "icon-avatar avatar";
|
||||
avatar.src = Avatar.getContactListUrl(jid);
|
||||
|
||||
|
@ -43,10 +44,10 @@ function createAvatar(jid) {
|
|||
* @param displayName the display name to set
|
||||
*/
|
||||
function createDisplayNameParagraph(key, displayName) {
|
||||
var p = document.createElement('p');
|
||||
if(displayName)
|
||||
let p = document.createElement('p');
|
||||
if (displayName) {
|
||||
p.innerText = displayName;
|
||||
else if(key) {
|
||||
} else if(key) {
|
||||
p.setAttribute("data-i18n",key);
|
||||
p.innerText = APP.translation.translateString(key);
|
||||
}
|
||||
|
@ -64,93 +65,79 @@ function stopGlowing(glower) {
|
|||
}
|
||||
}
|
||||
|
||||
function getContactEl (id) {
|
||||
return $(`#contacts>li[id="${id}"]`);
|
||||
}
|
||||
|
||||
function contactElExists (id) {
|
||||
return getContactEl(id).length > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Contact list.
|
||||
*/
|
||||
var ContactList = {
|
||||
init (emitter) {
|
||||
this.emitter = emitter;
|
||||
},
|
||||
/**
|
||||
* Indicates if the chat is currently visible.
|
||||
*
|
||||
* @return <tt>true</tt> if the chat is currently visible, <tt>false</tt> -
|
||||
* otherwise
|
||||
*/
|
||||
isVisible: function () {
|
||||
isVisible () {
|
||||
return $('#contactlist').is(":visible");
|
||||
},
|
||||
|
||||
/**
|
||||
* Adds a contact for the given peerJid if such doesn't yet exist.
|
||||
* Adds a contact for the given id.
|
||||
*
|
||||
* @param peerJid the peerJid corresponding to the contact
|
||||
*/
|
||||
ensureAddContact: function (peerJid) {
|
||||
var resourceJid = Strophe.getResourceFromJid(peerJid);
|
||||
addContact (id) {
|
||||
let contactlist = $('#contacts');
|
||||
|
||||
var contact = $('#contacts>li[id="' + resourceJid + '"]');
|
||||
|
||||
if (!contact || contact.length <= 0)
|
||||
ContactList.addContact(peerJid);
|
||||
},
|
||||
|
||||
/**
|
||||
* Adds a contact for the given peer jid.
|
||||
*
|
||||
* @param peerJid the jid of the contact to add
|
||||
*/
|
||||
addContact: function (peerJid) {
|
||||
var resourceJid = Strophe.getResourceFromJid(peerJid);
|
||||
|
||||
var contactlist = $('#contacts');
|
||||
|
||||
var newContact = document.createElement('li');
|
||||
newContact.id = resourceJid;
|
||||
let newContact = document.createElement('li');
|
||||
newContact.id = id;
|
||||
newContact.className = "clickable";
|
||||
newContact.onclick = function (event) {
|
||||
newContact.onclick = (event) => {
|
||||
if (event.currentTarget.className === "clickable") {
|
||||
$(ContactList).trigger('contactclicked', [peerJid]);
|
||||
this.emitter.emit(UIEvents.CONTACT_CLICKED, id);
|
||||
}
|
||||
};
|
||||
|
||||
newContact.appendChild(createAvatar(peerJid));
|
||||
newContact.appendChild(createAvatar(id));
|
||||
newContact.appendChild(createDisplayNameParagraph("participant"));
|
||||
|
||||
if (resourceJid === APP.xmpp.myResource()) {
|
||||
if (APP.conference.isLocalId(id)) {
|
||||
contactlist.prepend(newContact);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
contactlist.append(newContact);
|
||||
}
|
||||
updateNumberOfParticipants(1);
|
||||
},
|
||||
|
||||
/**
|
||||
* Removes a contact for the given peer jid.
|
||||
* Removes a contact for the given id.
|
||||
*
|
||||
* @param peerJid the peerJid corresponding to the contact to remove
|
||||
*/
|
||||
removeContact: function (peerJid) {
|
||||
var resourceJid = Strophe.getResourceFromJid(peerJid);
|
||||
|
||||
var contact = $('#contacts>li[id="' + resourceJid + '"]');
|
||||
|
||||
if (contact && contact.length > 0) {
|
||||
var contactlist = $('#contactlist>ul');
|
||||
|
||||
contactlist.get(0).removeChild(contact.get(0));
|
||||
removeContact (id) {
|
||||
let contact = getContactEl(id);
|
||||
|
||||
if (contact.length > 0) {
|
||||
contact.remove();
|
||||
updateNumberOfParticipants(-1);
|
||||
}
|
||||
},
|
||||
|
||||
setVisualNotification: function (show, stopGlowingIn) {
|
||||
var glower = $('#contactListButton');
|
||||
setVisualNotification (show, stopGlowingIn) {
|
||||
let glower = $('#contactListButton');
|
||||
|
||||
if (show && !notificationInterval) {
|
||||
notificationInterval = window.setInterval(function () {
|
||||
glower.toggleClass('active glowing');
|
||||
}, 800);
|
||||
}
|
||||
else if (!show && notificationInterval) {
|
||||
} else if (!show && notificationInterval) {
|
||||
stopGlowing(glower);
|
||||
}
|
||||
if (stopGlowingIn) {
|
||||
|
@ -160,34 +147,28 @@ var ContactList = {
|
|||
}
|
||||
},
|
||||
|
||||
setClickable: function (resourceJid, isClickable) {
|
||||
var contact = $('#contacts>li[id="' + resourceJid + '"]');
|
||||
if (isClickable) {
|
||||
contact.addClass('clickable');
|
||||
} else {
|
||||
contact.removeClass('clickable');
|
||||
}
|
||||
setClickable (id, isClickable) {
|
||||
getContactEl(id).toggleClass('clickable', isClickable);
|
||||
},
|
||||
|
||||
onDisplayNameChange: function (id, displayName) {
|
||||
onDisplayNameChange (id, displayName) {
|
||||
if (id === 'localVideoContainer') {
|
||||
id = APP.conference.localId;
|
||||
}
|
||||
var contactName = $('#contacts #' + id + '>p');
|
||||
let contactName = $(`#contacts #${id}>p`);
|
||||
|
||||
if (contactName && displayName && displayName.length > 0) {
|
||||
if (displayName) {
|
||||
contactName.html(displayName);
|
||||
}
|
||||
},
|
||||
|
||||
changeUserAvatar: function (id, contactListUrl) {
|
||||
changeUserAvatar (id, contactListUrl) {
|
||||
// set the avatar in the contact list
|
||||
var contact = $('#' + id + '>img');
|
||||
if (contact && contact.length > 0) {
|
||||
contact.get(0).src = contactListUrl;
|
||||
let contact = $(`#${id}>img`);
|
||||
if (contact.length > 0) {
|
||||
contact.attr('src', contactListUrl);
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = ContactList;
|
||||
export default ContactList;
|
||||
|
|
|
@ -1,12 +1,11 @@
|
|||
/* global APP, $ */
|
||||
var Settings = require("./../../../settings/Settings");
|
||||
var UIUtil = require("../../util/UIUtil");
|
||||
var languages = require("../../../../service/translation/languages");
|
||||
var UIEvents = require("../../../../service/UI/UIEvents");
|
||||
import UIUtil from "../../util/UIUtil";
|
||||
import UIEvents from "../../../../service/UI/UIEvents";
|
||||
import languages from "../../../../service/translation/languages";
|
||||
|
||||
function generateLanguagesSelectBox() {
|
||||
var currentLang = APP.translation.getCurrentLanguage();
|
||||
var html = "<select id=\"languages_selectbox\">";
|
||||
var html = '<select id="languages_selectbox">';
|
||||
var langArray = languages.getLanguages();
|
||||
for(var i = 0; i < langArray.length; i++) {
|
||||
var lang = langArray[i];
|
||||
|
@ -22,7 +21,7 @@ function generateLanguagesSelectBox() {
|
|||
}
|
||||
|
||||
|
||||
var SettingsMenu = {
|
||||
const SettingsMenu = {
|
||||
|
||||
init: function (emitter) {
|
||||
this.emitter = emitter;
|
||||
|
@ -98,5 +97,4 @@ var SettingsMenu = {
|
|||
}
|
||||
};
|
||||
|
||||
|
||||
module.exports = SettingsMenu;
|
||||
export default SettingsMenu;
|
||||
|
|
|
@ -1,66 +1,48 @@
|
|||
/* global $ */
|
||||
var PanelToggler = require("../side_pannels/SidePanelToggler");
|
||||
var UIUtil = require("../util/UIUtil");
|
||||
var AnalyticsAdapter = require("../../statistics/AnalyticsAdapter");
|
||||
var UIEvents = require("../../../service/UI/UIEvents");
|
||||
import UIUtil from '../util/UIUtil';
|
||||
import UIEvents from '../../../service/UI/UIEvents';
|
||||
import AnalyticsAdapter from '../../statistics/AnalyticsAdapter';
|
||||
|
||||
var eventEmitter = null;
|
||||
|
||||
var buttonHandlers = {
|
||||
"bottom_toolbar_contact_list": function () {
|
||||
AnalyticsAdapter.sendEvent('bottomtoolbar.contacts.toggled');
|
||||
BottomToolbar.toggleContactList();
|
||||
},
|
||||
"bottom_toolbar_film_strip": function () {
|
||||
AnalyticsAdapter.sendEvent('bottomtoolbar.filmstrip.toggled');
|
||||
BottomToolbar.toggleFilmStrip();
|
||||
},
|
||||
"bottom_toolbar_chat": function () {
|
||||
AnalyticsAdapter.sendEvent('bottomtoolbar.chat.toggled');
|
||||
BottomToolbar.toggleChat();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
var defaultBottomToolbarButtons = {
|
||||
'chat': '#bottom_toolbar_chat',
|
||||
'contacts': '#bottom_toolbar_contact_list',
|
||||
const defaultBottomToolbarButtons = {
|
||||
'chat': '#bottom_toolbar_chat',
|
||||
'contacts': '#bottom_toolbar_contact_list',
|
||||
'filmstrip': '#bottom_toolbar_film_strip'
|
||||
};
|
||||
|
||||
$(document).bind("remotevideo.resized", function (event, width, height) {
|
||||
let toolbar = $('#bottomToolbar');
|
||||
let bottom = (height - toolbar.outerHeight())/2 + 18;
|
||||
|
||||
var BottomToolbar = (function (my) {
|
||||
my.init = function (emitter) {
|
||||
eventEmitter = emitter;
|
||||
toolbar.css({bottom});
|
||||
});
|
||||
|
||||
const BottomToolbar = {
|
||||
init (emitter) {
|
||||
UIUtil.hideDisabledButtons(defaultBottomToolbarButtons);
|
||||
|
||||
for(var k in buttonHandlers)
|
||||
$("#" + k).click(buttonHandlers[k]);
|
||||
};
|
||||
const buttonHandlers = {
|
||||
"bottom_toolbar_contact_list": function () {
|
||||
AnalyticsAdapter.sendEvent('bottomtoolbar.contacts.toggled');
|
||||
emitter.emit(UIEvents.TOGGLE_CONTACT_LIST);
|
||||
},
|
||||
"bottom_toolbar_film_strip": function () {
|
||||
AnalyticsAdapter.sendEvent('bottomtoolbar.filmstrip.toggled');
|
||||
emitter.emit(UIEvents.TOGGLE_FILM_STRIP);
|
||||
},
|
||||
"bottom_toolbar_chat": function () {
|
||||
AnalyticsAdapter.sendEvent('bottomtoolbar.chat.toggled');
|
||||
emitter.emit(UIEvents.TOGGLE_CHAT);
|
||||
}
|
||||
};
|
||||
|
||||
my.toggleChat = function() {
|
||||
PanelToggler.toggleChat();
|
||||
};
|
||||
Object.keys(buttonHandlers).forEach(
|
||||
buttonId => $(`#${buttonId}`).click(buttonHandlers[buttonId])
|
||||
);
|
||||
},
|
||||
|
||||
my.toggleContactList = function() {
|
||||
PanelToggler.toggleContactList();
|
||||
};
|
||||
toggleFilmStrip () {
|
||||
$("#remoteVideos").toggleClass("hidden");
|
||||
}
|
||||
};
|
||||
|
||||
my.toggleFilmStrip = function() {
|
||||
var filmstrip = $("#remoteVideos");
|
||||
filmstrip.toggleClass("hidden");
|
||||
|
||||
eventEmitter.emit( UIEvents.FILM_STRIP_TOGGLED,
|
||||
filmstrip.hasClass("hidden"));
|
||||
};
|
||||
|
||||
$(document).bind("remotevideo.resized", function (event, width, height) {
|
||||
var bottom = (height - $('#bottomToolbar').outerHeight())/2 + 18;
|
||||
|
||||
$('#bottomToolbar').css({bottom: bottom + 'px'});
|
||||
});
|
||||
|
||||
return my;
|
||||
}(BottomToolbar || {}));
|
||||
|
||||
module.exports = BottomToolbar;
|
||||
export default BottomToolbar;
|
||||
|
|
|
@ -1,26 +1,96 @@
|
|||
/* global APP, $, config, interfaceConfig */
|
||||
/* jshint -W101 */
|
||||
var messageHandler = require("../util/MessageHandler");
|
||||
var BottomToolbar = require("./BottomToolbar");
|
||||
var Prezi = require("../prezi/Prezi");
|
||||
var Etherpad = require("../etherpad/Etherpad");
|
||||
var PanelToggler = require("../side_pannels/SidePanelToggler");
|
||||
var Authentication = require("../authentication/Authentication");
|
||||
var UIUtil = require("../util/UIUtil");
|
||||
var AuthenticationEvents
|
||||
= require("../../../service/authentication/AuthenticationEvents");
|
||||
var AnalyticsAdapter = require("../../statistics/AnalyticsAdapter");
|
||||
var Feedback = require("../Feedback");
|
||||
var UIEvents = require("../../../service/UI/UIEvents");
|
||||
import messageHandler from '../util/MessageHandler';
|
||||
import UIUtil from '../util/UIUtil';
|
||||
import AnalyticsAdapter from '../../statistics/AnalyticsAdapter';
|
||||
import UIEvents from '../../../service/UI/UIEvents';
|
||||
|
||||
var roomUrl = null;
|
||||
var sharedKey = '';
|
||||
var recordingToaster = null;
|
||||
var emitter = null;
|
||||
let roomUrl = null;
|
||||
let recordingToaster = null;
|
||||
let emitter = null;
|
||||
|
||||
var buttonHandlers = {
|
||||
|
||||
/**
|
||||
* Opens the invite link dialog.
|
||||
*/
|
||||
function openLinkDialog () {
|
||||
let inviteAttributes;
|
||||
|
||||
if (roomUrl === null) {
|
||||
inviteAttributes = 'data-i18n="[value]roomUrlDefaultMsg" value="' +
|
||||
APP.translation.translateString("roomUrlDefaultMsg") + '"';
|
||||
} else {
|
||||
inviteAttributes = "value=\"" + encodeURI(roomUrl) + "\"";
|
||||
}
|
||||
messageHandler.openTwoButtonDialog(
|
||||
"dialog.shareLink", null, null,
|
||||
`<input id="inviteLinkRef" type="text" ${inviteAttributes} onclick="this.select();" readonly>`,
|
||||
false, "dialog.Invite",
|
||||
function (e, v) {
|
||||
if (v && roomUrl) {
|
||||
emitter.emit(UIEvents.USER_INVITED, roomUrl);
|
||||
}
|
||||
},
|
||||
function (event) {
|
||||
if (roomUrl) {
|
||||
document.getElementById('inviteLinkRef').select();
|
||||
} else {
|
||||
if (event && event.target) {
|
||||
$(event.target).find('button[value=true]').prop('disabled', true);
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// Sets the state of the recording button
|
||||
function setRecordingButtonState (recordingState) {
|
||||
let selector = $('#toolbar_button_record');
|
||||
|
||||
if (recordingState === 'on') {
|
||||
selector.removeClass("icon-recEnable");
|
||||
selector.addClass("icon-recEnable active");
|
||||
|
||||
$("#largeVideo").toggleClass("videoMessageFilter", true);
|
||||
let recordOnKey = "recording.on";
|
||||
$('#videoConnectionMessage').attr("data-i18n", recordOnKey);
|
||||
$('#videoConnectionMessage').text(APP.translation.translateString(recordOnKey));
|
||||
|
||||
setTimeout(function(){
|
||||
$("#largeVideo").toggleClass("videoMessageFilter", false);
|
||||
$('#videoConnectionMessage').css({display: "none"});
|
||||
}, 1500);
|
||||
|
||||
recordingToaster = messageHandler.notify(
|
||||
null, "recording.toaster", null,
|
||||
null, null,
|
||||
{timeOut: 0, closeButton: null, tapToDismiss: false}
|
||||
);
|
||||
} else if (recordingState === 'off') {
|
||||
selector.removeClass("icon-recEnable active");
|
||||
selector.addClass("icon-recEnable");
|
||||
|
||||
$("#largeVideo").toggleClass("videoMessageFilter", false);
|
||||
$('#videoConnectionMessage').css({display: "none"});
|
||||
|
||||
if (recordingToaster) {
|
||||
messageHandler.remove(recordingToaster);
|
||||
}
|
||||
} else if (recordingState === 'pending') {
|
||||
selector.removeClass("icon-recEnable active");
|
||||
selector.addClass("icon-recEnable");
|
||||
|
||||
$("#largeVideo").toggleClass("videoMessageFilter", true);
|
||||
let recordPendingKey = "recording.pending";
|
||||
$('#videoConnectionMessage').attr("data-i18n", recordPendingKey);
|
||||
$('#videoConnectionMessage').text(APP.translation.translateString(recordPendingKey));
|
||||
$('#videoConnectionMessage').css({display: "block"});
|
||||
}
|
||||
}
|
||||
|
||||
const buttonHandlers = {
|
||||
"toolbar_button_mute": function () {
|
||||
if (APP.RTC.localAudio.isMuted()) {
|
||||
if (APP.conference.audioMuted) {
|
||||
AnalyticsAdapter.sendEvent('toolbar.audio.unmuted');
|
||||
emitter.emit(UIEvents.AUDIO_MUTED, false);
|
||||
} else {
|
||||
|
@ -29,7 +99,7 @@ var buttonHandlers = {
|
|||
}
|
||||
},
|
||||
"toolbar_button_camera": function () {
|
||||
if (APP.RTC.localVideo.isMuted()) {
|
||||
if (APP.conference.videoMuted) {
|
||||
AnalyticsAdapter.sendEvent('toolbar.video.enabled');
|
||||
emitter.emit(UIEvents.VIDEO_MUTED, false);
|
||||
} else {
|
||||
|
@ -37,36 +107,28 @@ var buttonHandlers = {
|
|||
emitter.emit(UIEvents.VIDEO_MUTED, true);
|
||||
}
|
||||
},
|
||||
/*"toolbar_button_authentication": function () {
|
||||
return Toolbar.authenticateClicked();
|
||||
},*/
|
||||
"toolbar_button_record": function () {
|
||||
AnalyticsAdapter.sendEvent('toolbar.recording.toggled');
|
||||
return toggleRecording();
|
||||
emitter.emit(UIEvents.RECORDING_TOGGLE);
|
||||
},
|
||||
"toolbar_button_security": function () {
|
||||
if (sharedKey) {
|
||||
AnalyticsAdapter.sendEvent('toolbar.lock.disabled');
|
||||
} else {
|
||||
AnalyticsAdapter.sendEvent('toolbar.lock.enabled');
|
||||
}
|
||||
return Toolbar.openLockDialog();
|
||||
emitter.emit(UIEvents.ROOM_LOCK_CLICKED);
|
||||
},
|
||||
"toolbar_button_link": function () {
|
||||
AnalyticsAdapter.sendEvent('toolbar.invite.clicked');
|
||||
return Toolbar.openLinkDialog();
|
||||
openLinkDialog();
|
||||
},
|
||||
"toolbar_button_chat": function () {
|
||||
AnalyticsAdapter.sendEvent('toolbar.chat.toggled');
|
||||
return BottomToolbar.toggleChat();
|
||||
emitter.emit(UIEvents.TOGGLE_CHAT);
|
||||
},
|
||||
"toolbar_button_prezi": function () {
|
||||
AnalyticsAdapter.sendEvent('toolbar.prezi.clicked');
|
||||
return Prezi.openPreziDialog();
|
||||
emitter.emit(UIEvents.PREZI_CLICKED);
|
||||
},
|
||||
"toolbar_button_etherpad": function () {
|
||||
AnalyticsAdapter.sendEvent('toolbar.etherpad.clicked');
|
||||
return Etherpad.toggleEtherpad(0);
|
||||
emitter.emit(UIEvents.ETHERPAD_CLICKED);
|
||||
},
|
||||
"toolbar_button_desktopsharing": function () {
|
||||
if (APP.desktopsharing.isUsingScreenStream) {
|
||||
|
@ -74,32 +136,32 @@ var buttonHandlers = {
|
|||
} else {
|
||||
AnalyticsAdapter.sendEvent('toolbar.screen.enabled');
|
||||
}
|
||||
return APP.desktopsharing.toggleScreenSharing();
|
||||
APP.desktopsharing.toggleScreenSharing();
|
||||
},
|
||||
"toolbar_button_fullScreen": function() {
|
||||
AnalyticsAdapter.sendEvent('toolbar.fullscreen.enabled');
|
||||
UIUtil.buttonClick("#toolbar_button_fullScreen", "icon-full-screen icon-exit-full-screen");
|
||||
return Toolbar.toggleFullScreen();
|
||||
emitter.emit(UIEvents.FULLSCREEN_TOGGLE);
|
||||
},
|
||||
"toolbar_button_sip": function () {
|
||||
AnalyticsAdapter.sendEvent('toolbar.sip.clicked');
|
||||
return callSipButtonClicked();
|
||||
showSipNumberInput();
|
||||
},
|
||||
"toolbar_button_dialpad": function () {
|
||||
AnalyticsAdapter.sendEvent('toolbar.sip.dialpad.clicked');
|
||||
return dialpadButtonClicked();
|
||||
dialpadButtonClicked();
|
||||
},
|
||||
"toolbar_button_settings": function () {
|
||||
AnalyticsAdapter.sendEvent('toolbar.settings.toggled');
|
||||
PanelToggler.toggleSettingsMenu();
|
||||
emitter.emit(UIEvents.TOGGLE_SETTINGS);
|
||||
},
|
||||
"toolbar_button_hangup": function () {
|
||||
AnalyticsAdapter.sendEvent('toolbar.hangup');
|
||||
return hangup();
|
||||
emitter.emit(UIEvents.HANGUP);
|
||||
},
|
||||
"toolbar_button_login": function () {
|
||||
AnalyticsAdapter.sendEvent('toolbar.authenticate.login.clicked');
|
||||
Toolbar.authenticateClicked();
|
||||
emitter.emit(UIEvents.AUTH_CLICKED);
|
||||
},
|
||||
"toolbar_button_logout": function () {
|
||||
AnalyticsAdapter.sendEvent('toolbar.authenticate.logout.clicked');
|
||||
|
@ -113,631 +175,213 @@ var buttonHandlers = {
|
|||
"dialog.Yes",
|
||||
function (evt, yes) {
|
||||
if (yes) {
|
||||
APP.xmpp.logout(function (url) {
|
||||
if (url) {
|
||||
window.location.href = url;
|
||||
} else {
|
||||
hangup();
|
||||
}
|
||||
});
|
||||
emitter.emit(UIEvents.LOGOUT);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
var defaultToolbarButtons = {
|
||||
'microphone': '#toolbar_button_mute',
|
||||
'camera': '#toolbar_button_camera',
|
||||
'desktop': '#toolbar_button_desktopsharing',
|
||||
'security': '#toolbar_button_security',
|
||||
'invite': '#toolbar_button_link',
|
||||
'chat': '#toolbar_button_chat',
|
||||
'prezi': '#toolbar_button_prezi',
|
||||
'etherpad': '#toolbar_button_etherpad',
|
||||
'fullscreen': '#toolbar_button_fullScreen',
|
||||
'settings': '#toolbar_button_settings',
|
||||
'hangup': '#toolbar_button_hangup'
|
||||
};
|
||||
|
||||
/**
|
||||
* Hangs up this call.
|
||||
*/
|
||||
function hangup() {
|
||||
var conferenceDispose = function () {
|
||||
APP.xmpp.disposeConference();
|
||||
|
||||
if (config.enableWelcomePage) {
|
||||
setTimeout(function() {
|
||||
window.localStorage.welcomePageDisabled = false;
|
||||
window.location.pathname = "/";
|
||||
}, 3000);
|
||||
}
|
||||
};
|
||||
|
||||
if (Feedback.isEnabled())
|
||||
{
|
||||
// If the user has already entered feedback, we'll show the window and
|
||||
// immidiately start the conference dispose timeout.
|
||||
if (Feedback.feedbackScore > 0) {
|
||||
Feedback.openFeedbackWindow();
|
||||
conferenceDispose();
|
||||
|
||||
}
|
||||
// Otherwise we'll wait for user's feedback.
|
||||
else
|
||||
Feedback.openFeedbackWindow(conferenceDispose);
|
||||
}
|
||||
else {
|
||||
conferenceDispose();
|
||||
|
||||
// If the feedback functionality isn't enabled we show a thank you
|
||||
// dialog.
|
||||
APP.UI.messageHandler.openMessageDialog(null, null, null,
|
||||
APP.translation.translateString("dialog.thankYou",
|
||||
{appName:interfaceConfig.APP_NAME}));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts or stops the recording for the conference.
|
||||
*/
|
||||
function toggleRecording(predefinedToken) {
|
||||
APP.xmpp.toggleRecording(function (callback) {
|
||||
if (predefinedToken) {
|
||||
callback(UIUtil.escapeHtml(predefinedToken));
|
||||
return;
|
||||
}
|
||||
|
||||
var msg = APP.translation.generateTranslationHTML(
|
||||
"dialog.recordingToken");
|
||||
var token = APP.translation.translateString("dialog.token");
|
||||
APP.UI.messageHandler.openTwoButtonDialog(null, null, null,
|
||||
'<h2>' + msg + '</h2>' +
|
||||
'<input name="recordingToken" type="text" ' +
|
||||
' data-i18n="[placeholder]dialog.token" ' +
|
||||
'placeholder="' + token + '" autofocus>',
|
||||
false,
|
||||
"dialog.Save",
|
||||
function (e, v, m, f) {
|
||||
if (v) {
|
||||
var token = f.recordingToken;
|
||||
|
||||
if (token) {
|
||||
callback(UIUtil.escapeHtml(token));
|
||||
}
|
||||
}
|
||||
},
|
||||
null,
|
||||
function () { },
|
||||
':input:first'
|
||||
}
|
||||
);
|
||||
}, Toolbar.setRecordingButtonState);
|
||||
}
|
||||
|
||||
/**
|
||||
* Locks / unlocks the room.
|
||||
*/
|
||||
function lockRoom(lock) {
|
||||
var currentSharedKey = '';
|
||||
if (lock)
|
||||
currentSharedKey = sharedKey;
|
||||
|
||||
APP.xmpp.lockRoom(currentSharedKey, function (res) {
|
||||
// password is required
|
||||
if (sharedKey) {
|
||||
console.log('set room password');
|
||||
Toolbar.lockLockButton();
|
||||
}
|
||||
else {
|
||||
console.log('removed room password');
|
||||
Toolbar.unlockLockButton();
|
||||
}
|
||||
}, function (err) {
|
||||
console.warn('setting password failed', err);
|
||||
messageHandler.showError("dialog.lockTitle",
|
||||
"dialog.lockMessage");
|
||||
Toolbar.setSharedKey('');
|
||||
}, function () {
|
||||
console.warn('room passwords not supported');
|
||||
messageHandler.showError("dialog.warning",
|
||||
"dialog.passwordNotSupported");
|
||||
Toolbar.setSharedKey('');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Invite participants to conference.
|
||||
*/
|
||||
function inviteParticipants() {
|
||||
if (roomUrl === null)
|
||||
return;
|
||||
|
||||
var sharedKeyText = "";
|
||||
if (sharedKey && sharedKey.length > 0) {
|
||||
sharedKeyText =
|
||||
APP.translation.translateString("email.sharedKey",
|
||||
{sharedKey: sharedKey});
|
||||
sharedKeyText = sharedKeyText.replace(/\n/g, "%0D%0A");
|
||||
}
|
||||
|
||||
var supportedBrowsers = "Chromium, Google Chrome " +
|
||||
APP.translation.translateString("email.and") + " Opera";
|
||||
var conferenceName = roomUrl.substring(roomUrl.lastIndexOf('/') + 1);
|
||||
var subject = APP.translation.translateString("email.subject",
|
||||
{appName:interfaceConfig.APP_NAME, conferenceName: conferenceName});
|
||||
var body = APP.translation.translateString("email.body",
|
||||
{appName:interfaceConfig.APP_NAME, sharedKeyText: sharedKeyText,
|
||||
roomUrl: roomUrl, supportedBrowsers: supportedBrowsers});
|
||||
body = body.replace(/\n/g, "%0D%0A");
|
||||
|
||||
if (window.localStorage.displayname) {
|
||||
body += "%0D%0A%0D%0A" + window.localStorage.displayname;
|
||||
}
|
||||
|
||||
if (interfaceConfig.INVITATION_POWERED_BY) {
|
||||
body += "%0D%0A%0D%0A--%0D%0Apowered by jitsi.org";
|
||||
}
|
||||
|
||||
window.open("mailto:?subject=" + subject + "&body=" + body, '_blank');
|
||||
}
|
||||
};
|
||||
const defaultToolbarButtons = {
|
||||
'microphone': '#toolbar_button_mute',
|
||||
'camera': '#toolbar_button_camera',
|
||||
'desktop': '#toolbar_button_desktopsharing',
|
||||
'security': '#toolbar_button_security',
|
||||
'invite': '#toolbar_button_link',
|
||||
'chat': '#toolbar_button_chat',
|
||||
'prezi': '#toolbar_button_prezi',
|
||||
'etherpad': '#toolbar_button_etherpad',
|
||||
'fullscreen': '#toolbar_button_fullScreen',
|
||||
'settings': '#toolbar_button_settings',
|
||||
'hangup': '#toolbar_button_hangup'
|
||||
};
|
||||
|
||||
function dialpadButtonClicked() {
|
||||
//TODO show the dialpad box
|
||||
}
|
||||
|
||||
function callSipButtonClicked() {
|
||||
var defaultNumber
|
||||
= config.defaultSipNumber ? config.defaultSipNumber : '';
|
||||
function showSipNumberInput () {
|
||||
let defaultNumber = config.defaultSipNumber
|
||||
? config.defaultSipNumber
|
||||
: '';
|
||||
|
||||
var sipMsg = APP.translation.generateTranslationHTML(
|
||||
"dialog.sipMsg");
|
||||
messageHandler.openTwoButtonDialog(null, null, null,
|
||||
'<h2>' + sipMsg + '</h2>' +
|
||||
'<input name="sipNumber" type="text"' +
|
||||
' value="' + defaultNumber + '" autofocus>',
|
||||
false,
|
||||
"dialog.Dial",
|
||||
let sipMsg = APP.translation.generateTranslationHTML("dialog.sipMsg");
|
||||
messageHandler.openTwoButtonDialog(
|
||||
null, null, null,
|
||||
`<h2>${sipMsg}</h2>
|
||||
<input name="sipNumber" type="text" value="${defaultNumber}" autofocus>`,
|
||||
false, "dialog.Dial",
|
||||
function (e, v, m, f) {
|
||||
if (v) {
|
||||
var numberInput = f.sipNumber;
|
||||
if (numberInput) {
|
||||
APP.xmpp.dial(
|
||||
numberInput, 'fromnumber', APP.UI.getRoomName(), sharedKey);
|
||||
}
|
||||
if (v && f.sipNumber) {
|
||||
emitter.emit(UIEvents.SIP_DIAL, f.sipNumber);
|
||||
}
|
||||
},
|
||||
null, null, ':input:first'
|
||||
);
|
||||
}
|
||||
|
||||
var Toolbar = (function (my) {
|
||||
|
||||
my.init = function (eventEmitter) {
|
||||
const Toolbar = {
|
||||
init (eventEmitter) {
|
||||
emitter = eventEmitter;
|
||||
|
||||
UIUtil.hideDisabledButtons(defaultToolbarButtons);
|
||||
|
||||
for(var k in buttonHandlers)
|
||||
$("#" + k).click(buttonHandlers[k]);
|
||||
// Update login info
|
||||
APP.xmpp.addListener(
|
||||
AuthenticationEvents.IDENTITY_UPDATED,
|
||||
function (authenticationEnabled, userIdentity) {
|
||||
|
||||
var loggedIn = false;
|
||||
if (userIdentity) {
|
||||
loggedIn = true;
|
||||
}
|
||||
|
||||
Toolbar.showAuthenticateButton(authenticationEnabled);
|
||||
|
||||
if (authenticationEnabled) {
|
||||
Toolbar.setAuthenticatedIdentity(userIdentity);
|
||||
|
||||
Toolbar.showLoginButton(!loggedIn);
|
||||
Toolbar.showLogoutButton(loggedIn);
|
||||
}
|
||||
}
|
||||
Object.keys(buttonHandlers).forEach(
|
||||
buttonId => $(`#${buttonId}`).click(buttonHandlers[buttonId])
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets shared key
|
||||
* @param sKey the shared key
|
||||
*/
|
||||
my.setSharedKey = function (sKey) {
|
||||
sharedKey = sKey;
|
||||
};
|
||||
|
||||
my.authenticateClicked = function () {
|
||||
Authentication.focusAuthenticationWindow();
|
||||
if (!APP.xmpp.isExternalAuthEnabled()) {
|
||||
Authentication.xmppAuthenticate();
|
||||
return;
|
||||
}
|
||||
// Get authentication URL
|
||||
if (!APP.xmpp.isMUCJoined()) {
|
||||
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(APP.UI.getRoomName(), function (url) {
|
||||
// Otherwise - open popup with authentication URL
|
||||
var authenticationWindow = Authentication.createAuthenticationWindow(
|
||||
function () {
|
||||
// On popup closed - retry room allocation
|
||||
APP.xmpp.allocateConferenceFocus(
|
||||
APP.UI.getRoomName(),
|
||||
function () { console.info("AUTH DONE"); }
|
||||
);
|
||||
}, url);
|
||||
if (!authenticationWindow) {
|
||||
messageHandler.openMessageDialog(
|
||||
null, "dialog.popupError");
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* Updates the room invite url.
|
||||
*/
|
||||
my.updateRoomUrl = function (newRoomUrl) {
|
||||
updateRoomUrl (newRoomUrl) {
|
||||
roomUrl = newRoomUrl;
|
||||
|
||||
// If the invite dialog has been already opened we update the information.
|
||||
var inviteLink = document.getElementById('inviteLinkRef');
|
||||
let inviteLink = document.getElementById('inviteLinkRef');
|
||||
if (inviteLink) {
|
||||
inviteLink.value = roomUrl;
|
||||
inviteLink.select();
|
||||
$('#inviteLinkRef').parent()
|
||||
.find('button[value=true]').prop('disabled', false);
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* Disables and enables some of the buttons.
|
||||
*/
|
||||
my.setupButtonsFromConfig = function () {
|
||||
setupButtonsFromConfig () {
|
||||
if (UIUtil.isButtonEnabled('prezi')) {
|
||||
$("#toolbar_button_prezi").css({display: "none"});
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* Opens the lock room dialog.
|
||||
*/
|
||||
my.openLockDialog = function () {
|
||||
// Only the focus is able to set a shared key.
|
||||
if (!APP.xmpp.isModerator()) {
|
||||
if (sharedKey) {
|
||||
messageHandler.openMessageDialog(null,
|
||||
"dialog.passwordError");
|
||||
} else {
|
||||
messageHandler.openMessageDialog(null, "dialog.passwordError2");
|
||||
}
|
||||
} else {
|
||||
if (sharedKey) {
|
||||
messageHandler.openTwoButtonDialog(null, null,
|
||||
"dialog.passwordCheck",
|
||||
null,
|
||||
false,
|
||||
"dialog.Remove",
|
||||
function (e, v) {
|
||||
if (v) {
|
||||
Toolbar.setSharedKey('');
|
||||
lockRoom(false);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
var msg = APP.translation.generateTranslationHTML(
|
||||
"dialog.passwordMsg");
|
||||
var yourPassword = APP.translation.translateString(
|
||||
"dialog.yourPassword");
|
||||
messageHandler.openTwoButtonDialog(null, null, null,
|
||||
'<h2>' + msg + '</h2>' +
|
||||
'<input name="lockKey" type="text"' +
|
||||
' data-i18n="[placeholder]dialog.yourPassword" ' +
|
||||
'placeholder="' + yourPassword + '" autofocus>',
|
||||
false,
|
||||
"dialog.Save",
|
||||
function (e, v, m, f) {
|
||||
if (v) {
|
||||
var lockKey = f.lockKey;
|
||||
|
||||
if (lockKey) {
|
||||
Toolbar.setSharedKey(
|
||||
UIUtil.escapeHtml(lockKey));
|
||||
lockRoom(true);
|
||||
}
|
||||
}
|
||||
},
|
||||
null, null, 'input:first'
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Opens the invite link dialog.
|
||||
*/
|
||||
my.openLinkDialog = function () {
|
||||
var inviteAttributes;
|
||||
|
||||
if (roomUrl === null) {
|
||||
inviteAttributes = 'data-i18n="[value]roomUrlDefaultMsg" value="' +
|
||||
APP.translation.translateString("roomUrlDefaultMsg") + '"';
|
||||
} else {
|
||||
inviteAttributes = "value=\"" + encodeURI(roomUrl) + "\"";
|
||||
}
|
||||
messageHandler.openTwoButtonDialog("dialog.shareLink",
|
||||
null, null,
|
||||
'<input id="inviteLinkRef" type="text" ' +
|
||||
inviteAttributes + ' onclick="this.select();" readonly>',
|
||||
false,
|
||||
"dialog.Invite",
|
||||
function (e, v) {
|
||||
if (v) {
|
||||
if (roomUrl) {
|
||||
inviteParticipants();
|
||||
}
|
||||
}
|
||||
},
|
||||
function (event) {
|
||||
if (roomUrl) {
|
||||
document.getElementById('inviteLinkRef').select();
|
||||
} else {
|
||||
if (event && event.target)
|
||||
$(event.target)
|
||||
.find('button[value=true]').prop('disabled', true);
|
||||
}
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Opens the settings dialog.
|
||||
* FIXME: not used ?
|
||||
*/
|
||||
my.openSettingsDialog = function () {
|
||||
var settings1 = APP.translation.generateTranslationHTML(
|
||||
"dialog.settings1");
|
||||
var settings2 = APP.translation.generateTranslationHTML(
|
||||
"dialog.settings2");
|
||||
var settings3 = APP.translation.generateTranslationHTML(
|
||||
"dialog.settings3");
|
||||
|
||||
var yourPassword = APP.translation.translateString(
|
||||
"dialog.yourPassword");
|
||||
|
||||
messageHandler.openTwoButtonDialog(null,
|
||||
'<h2>' + settings1 + '</h2>' +
|
||||
'<input type="checkbox" id="initMuted">' +
|
||||
settings2 + '<br/>' +
|
||||
'<input type="checkbox" id="requireNicknames">' +
|
||||
settings3 +
|
||||
'<input id="lockKey" type="text" placeholder="' + yourPassword +
|
||||
'" data-i18n="[placeholder]dialog.yourPassword" autofocus>',
|
||||
null,
|
||||
null,
|
||||
false,
|
||||
"dialog.Save",
|
||||
function () {
|
||||
document.getElementById('lockKey').focus();
|
||||
},
|
||||
function (e, v) {
|
||||
if (v) {
|
||||
if ($('#initMuted').is(":checked")) {
|
||||
// it is checked
|
||||
}
|
||||
|
||||
if ($('#requireNicknames').is(":checked")) {
|
||||
// it is checked
|
||||
}
|
||||
/*
|
||||
var lockKey = document.getElementById('lockKey');
|
||||
|
||||
if (lockKey.value) {
|
||||
setSharedKey(lockKey.value);
|
||||
lockRoom(true);
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Toggles the application in and out of full screen mode
|
||||
* (a.k.a. presentation mode in Chrome).
|
||||
*/
|
||||
my.toggleFullScreen = function () {
|
||||
var fsElement = document.documentElement;
|
||||
|
||||
if (!document.mozFullScreen && !document.webkitIsFullScreen) {
|
||||
//Enter Full Screen
|
||||
if (fsElement.mozRequestFullScreen) {
|
||||
fsElement.mozRequestFullScreen();
|
||||
}
|
||||
else {
|
||||
fsElement.webkitRequestFullScreen(Element.ALLOW_KEYBOARD_INPUT);
|
||||
}
|
||||
} else {
|
||||
//Exit Full Screen
|
||||
if (document.mozCancelFullScreen) {
|
||||
document.mozCancelFullScreen();
|
||||
} else {
|
||||
document.webkitCancelFullScreen();
|
||||
}
|
||||
}
|
||||
};
|
||||
/**
|
||||
* Unlocks the lock button state.
|
||||
*/
|
||||
my.unlockLockButton = function () {
|
||||
unlockLockButton () {
|
||||
if ($("#toolbar_button_security").hasClass("icon-security-locked"))
|
||||
UIUtil.buttonClick("#toolbar_button_security", "icon-security icon-security-locked");
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* Updates the lock button state to locked.
|
||||
*/
|
||||
my.lockLockButton = function () {
|
||||
lockLockButton () {
|
||||
if ($("#toolbar_button_security").hasClass("icon-security"))
|
||||
UIUtil.buttonClick("#toolbar_button_security", "icon-security icon-security-locked");
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* Shows or hides authentication button
|
||||
* @param show <tt>true</tt> to show or <tt>false</tt> to hide
|
||||
*/
|
||||
my.showAuthenticateButton = function (show) {
|
||||
showAuthenticateButton (show) {
|
||||
if (UIUtil.isButtonEnabled('authentication') && show) {
|
||||
$('#authentication').css({display: "inline"});
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
$('#authentication').css({display: "none"});
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
// Shows or hides the 'recording' button.
|
||||
my.showRecordingButton = function (show) {
|
||||
showRecordingButton (show) {
|
||||
if (UIUtil.isButtonEnabled('recording') && show) {
|
||||
$('#toolbar_button_record').css({display: "inline-block"});
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
$('#toolbar_button_record').css({display: "none"});
|
||||
}
|
||||
};
|
||||
|
||||
// Sets the state of the recording button
|
||||
my.setRecordingButtonState = function (recordingState) {
|
||||
var selector = $('#toolbar_button_record');
|
||||
|
||||
if (recordingState === 'on') {
|
||||
selector.removeClass("icon-recEnable");
|
||||
selector.addClass("icon-recEnable active");
|
||||
|
||||
$("#largeVideo").toggleClass("videoMessageFilter", true);
|
||||
var recordOnKey = "recording.on";
|
||||
$('#videoConnectionMessage').attr("data-i18n", recordOnKey);
|
||||
$('#videoConnectionMessage').text(APP.translation.translateString(recordOnKey));
|
||||
|
||||
setTimeout(function(){
|
||||
$("#largeVideo").toggleClass("videoMessageFilter", false);
|
||||
$('#videoConnectionMessage').css({display: "none"});
|
||||
}, 1500);
|
||||
|
||||
recordingToaster = messageHandler.notify(null, "recording.toaster", null,
|
||||
null, null, {timeOut: 0, closeButton: null, tapToDismiss: false});
|
||||
} else if (recordingState === 'off') {
|
||||
selector.removeClass("icon-recEnable active");
|
||||
selector.addClass("icon-recEnable");
|
||||
|
||||
$("#largeVideo").toggleClass("videoMessageFilter", false);
|
||||
$('#videoConnectionMessage').css({display: "none"});
|
||||
|
||||
if (recordingToaster)
|
||||
messageHandler.remove(recordingToaster);
|
||||
|
||||
} else if (recordingState === 'pending') {
|
||||
selector.removeClass("icon-recEnable active");
|
||||
selector.addClass("icon-recEnable");
|
||||
|
||||
$("#largeVideo").toggleClass("videoMessageFilter", true);
|
||||
var recordPendingKey = "recording.pending";
|
||||
$('#videoConnectionMessage').attr("data-i18n", recordPendingKey);
|
||||
$('#videoConnectionMessage').text(APP.translation.translateString(recordPendingKey));
|
||||
$('#videoConnectionMessage').css({display: "block"});
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
// checks whether recording is enabled and whether we have params
|
||||
// to start automatically recording
|
||||
my.checkAutoRecord = function () {
|
||||
checkAutoRecord () {
|
||||
if (UIUtil.isButtonEnabled('recording') && config.autoRecord) {
|
||||
toggleRecording(config.autoRecordToken);
|
||||
emitter.emit(UIEvents.RECORDING_TOGGLE, UIUtil.escapeHtml(config.autoRecordToken));
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
// checks whether desktop sharing is enabled and whether
|
||||
// we have params to start automatically sharing
|
||||
my.checkAutoEnableDesktopSharing = function () {
|
||||
checkAutoEnableDesktopSharing () {
|
||||
if (UIUtil.isButtonEnabled('desktop')
|
||||
&& config.autoEnableDesktopSharing) {
|
||||
APP.desktopsharing.toggleScreenSharing();
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
// Shows or hides SIP calls button
|
||||
my.showSipCallButton = function (show) {
|
||||
if (APP.xmpp.isSipGatewayEnabled() && UIUtil.isButtonEnabled('sip') && show) {
|
||||
showSipCallButton (show) {
|
||||
if (APP.conference.sipGatewayEnabled && UIUtil.isButtonEnabled('sip') && show) {
|
||||
$('#toolbar_button_sip').css({display: "inline-block"});
|
||||
} else {
|
||||
$('#toolbar_button_sip').css({display: "none"});
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
// Shows or hides the dialpad button
|
||||
my.showDialPadButton = function (show) {
|
||||
showDialPadButton (show) {
|
||||
if (UIUtil.isButtonEnabled('dialpad') && show) {
|
||||
$('#toolbar_button_dialpad').css({display: "inline-block"});
|
||||
} else {
|
||||
$('#toolbar_button_dialpad').css({display: "none"});
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* Displays user authenticated identity name(login).
|
||||
* @param authIdentity identity name to be displayed.
|
||||
*/
|
||||
my.setAuthenticatedIdentity = function (authIdentity) {
|
||||
setAuthenticatedIdentity (authIdentity) {
|
||||
if (authIdentity) {
|
||||
var selector = $('#toolbar_auth_identity');
|
||||
let selector = $('#toolbar_auth_identity');
|
||||
selector.css({display: "list-item"});
|
||||
selector.text(authIdentity);
|
||||
} else {
|
||||
$('#toolbar_auth_identity').css({display: "none"});
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* Shows/hides login button.
|
||||
* @param show <tt>true</tt> to show
|
||||
*/
|
||||
my.showLoginButton = function (show) {
|
||||
showLoginButton (show) {
|
||||
if (UIUtil.isButtonEnabled('authentication') && show) {
|
||||
$('#toolbar_button_login').css({display: "list-item"});
|
||||
} else {
|
||||
$('#toolbar_button_login').css({display: "none"});
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* Shows/hides logout button.
|
||||
* @param show <tt>true</tt> to show
|
||||
*/
|
||||
my.showLogoutButton = function (show) {
|
||||
showLogoutButton (show) {
|
||||
if (UIUtil.isButtonEnabled('authentication') && show) {
|
||||
$('#toolbar_button_logout').css({display: "list-item"});
|
||||
} else {
|
||||
$('#toolbar_button_logout').css({display: "none"});
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets the state of the button. The button has blue glow if desktop
|
||||
* streaming is active.
|
||||
* @param active the state of the desktop streaming.
|
||||
*/
|
||||
my.changeDesktopSharingButtonState = function (active) {
|
||||
var button = $("#toolbar_button_desktopsharing");
|
||||
changeDesktopSharingButtonState (active) {
|
||||
let button = $("#toolbar_button_desktopsharing");
|
||||
if (active) {
|
||||
button.addClass("glow");
|
||||
} else {
|
||||
button.removeClass("glow");
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
return my;
|
||||
}(Toolbar || {}));
|
||||
updateRecordingState (state) {
|
||||
setRecordingButtonState(state);
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = Toolbar;
|
||||
export default Toolbar;
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
/* global APP, config, $, interfaceConfig */
|
||||
|
||||
var toolbarTimeoutObject,
|
||||
toolbarTimeout = interfaceConfig.INITIAL_TOOLBAR_TIMEOUT,
|
||||
UIUtil = require("../util/UIUtil");
|
||||
import UIUtil from '../util/UIUtil';
|
||||
|
||||
let toolbarTimeoutObject;
|
||||
let toolbarTimeout = interfaceConfig.INITIAL_TOOLBAR_TIMEOUT;
|
||||
|
||||
function showDesktopSharingButton() {
|
||||
if (APP.desktopsharing.isDesktopSharingEnabled() &&
|
||||
|
@ -13,19 +14,24 @@ function showDesktopSharingButton() {
|
|||
}
|
||||
}
|
||||
|
||||
function isToolbarVisible () {
|
||||
return $('#header').is(':visible');
|
||||
}
|
||||
|
||||
/**
|
||||
* Hides the toolbar.
|
||||
*/
|
||||
function hideToolbar() {
|
||||
if(config.alwaysVisibleToolbar)
|
||||
if (config.alwaysVisibleToolbar) {
|
||||
return;
|
||||
}
|
||||
|
||||
var header = $("#header"),
|
||||
bottomToolbar = $("#bottomToolbar");
|
||||
var isToolbarHover = false;
|
||||
let header = $("#header");
|
||||
let bottomToolbar = $("#bottomToolbar");
|
||||
let isToolbarHover = false;
|
||||
header.find('*').each(function () {
|
||||
var id = $(this).attr('id');
|
||||
if ($("#" + id + ":hover").length > 0) {
|
||||
let id = $(this).attr('id');
|
||||
if ($(`#${id}:hover`).length > 0) {
|
||||
isToolbarHover = true;
|
||||
}
|
||||
});
|
||||
|
@ -36,34 +42,36 @@ function hideToolbar() {
|
|||
clearTimeout(toolbarTimeoutObject);
|
||||
toolbarTimeoutObject = null;
|
||||
|
||||
if (!isToolbarHover) {
|
||||
if (isToolbarHover) {
|
||||
toolbarTimeoutObject = setTimeout(hideToolbar, toolbarTimeout);
|
||||
} else {
|
||||
header.hide("slide", { direction: "up", duration: 300});
|
||||
$('#subject').animate({top: "-=40"}, 300);
|
||||
if ($("#remoteVideos").hasClass("hidden")) {
|
||||
bottomToolbar.hide(
|
||||
"slide", {direction: "right", duration: 300});
|
||||
"slide", {direction: "right", duration: 300}
|
||||
);
|
||||
}
|
||||
}
|
||||
else {
|
||||
toolbarTimeoutObject = setTimeout(hideToolbar, toolbarTimeout);
|
||||
}
|
||||
}
|
||||
|
||||
var ToolbarToggler = {
|
||||
const ToolbarToggler = {
|
||||
/**
|
||||
* Shows the main toolbar.
|
||||
*/
|
||||
showToolbar: function () {
|
||||
if (interfaceConfig.filmStripOnly)
|
||||
showToolbar () {
|
||||
if (interfaceConfig.filmStripOnly) {
|
||||
return;
|
||||
var header = $("#header"),
|
||||
bottomToolbar = $("#bottomToolbar");
|
||||
}
|
||||
let header = $("#header");
|
||||
let bottomToolbar = $("#bottomToolbar");
|
||||
if (!header.is(':visible') || !bottomToolbar.is(":visible")) {
|
||||
header.show("slide", { direction: "up", duration: 300});
|
||||
$('#subject').animate({top: "+=40"}, 300);
|
||||
if (!bottomToolbar.is(":visible")) {
|
||||
bottomToolbar.show(
|
||||
"slide", {direction: "right", duration: 300});
|
||||
"slide", {direction: "right", duration: 300}
|
||||
);
|
||||
}
|
||||
|
||||
if (toolbarTimeoutObject) {
|
||||
|
@ -83,33 +91,28 @@ var ToolbarToggler = {
|
|||
*
|
||||
* @param isDock indicates what operation to perform
|
||||
*/
|
||||
dockToolbar: function (isDock) {
|
||||
if (interfaceConfig.filmStripOnly)
|
||||
dockToolbar (isDock) {
|
||||
if (interfaceConfig.filmStripOnly) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isDock) {
|
||||
// First make sure the toolbar is shown.
|
||||
if (!$('#header').is(':visible')) {
|
||||
if (!isToolbarVisible()) {
|
||||
this.showToolbar();
|
||||
}
|
||||
|
||||
// Then clear the time out, to dock the toolbar.
|
||||
if (toolbarTimeoutObject) {
|
||||
clearTimeout(toolbarTimeoutObject);
|
||||
toolbarTimeoutObject = null;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!$('#header').is(':visible')) {
|
||||
clearTimeout(toolbarTimeoutObject);
|
||||
toolbarTimeoutObject = null;
|
||||
} else {
|
||||
if (isToolbarVisible()) {
|
||||
toolbarTimeoutObject = setTimeout(hideToolbar, toolbarTimeout);
|
||||
} else {
|
||||
this.showToolbar();
|
||||
}
|
||||
else {
|
||||
toolbarTimeoutObject = setTimeout(hideToolbar, toolbarTimeout);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
showDesktopSharingButton: showDesktopSharingButton
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = ToolbarToggler;
|
||||
module.exports = ToolbarToggler;
|
||||
|
|
|
@ -1,13 +1,15 @@
|
|||
/* global $, config, interfaceConfig */
|
||||
|
||||
import PanelToggler from "../side_pannels/SidePanelToggler";
|
||||
|
||||
/**
|
||||
* Created by hristo on 12/22/14.
|
||||
*/
|
||||
var UIUtil = module.exports = {
|
||||
var UIUtil = {
|
||||
/**
|
||||
* Returns the available video width.
|
||||
*/
|
||||
getAvailableVideoWidth: function (isVisible) {
|
||||
var PanelToggler = require("../side_pannels/SidePanelToggler");
|
||||
if(typeof isVisible === "undefined" || isVisible === null)
|
||||
isVisible = PanelToggler.isVisible();
|
||||
var rightPanelWidth
|
||||
|
@ -112,5 +114,11 @@ var UIUtil = module.exports = {
|
|||
.filter(function (item) { return item; })
|
||||
.join(',');
|
||||
$(selector).hide();
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
redirect (url) {
|
||||
window.location.href = url;
|
||||
}
|
||||
};
|
||||
|
||||
export default UIUtil;
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
/* global APP, $ */
|
||||
/* jshint -W101 */
|
||||
var JitsiPopover = require("../util/JitsiPopover");
|
||||
import JitsiPopover from "../util/JitsiPopover";
|
||||
|
||||
/**
|
||||
* Constructs new connection indicator.
|
||||
* @param videoContainer the video container associated with the indicator.
|
||||
* @constructor
|
||||
*/
|
||||
function ConnectionIndicator(videoContainer, jid) {
|
||||
function ConnectionIndicator(videoContainer, id) {
|
||||
this.videoContainer = videoContainer;
|
||||
this.bandwidth = null;
|
||||
this.packetLoss = null;
|
||||
|
@ -16,7 +16,7 @@ function ConnectionIndicator(videoContainer, jid) {
|
|||
this.resolution = null;
|
||||
this.transport = [];
|
||||
this.popover = null;
|
||||
this.jid = jid;
|
||||
this.id = id;
|
||||
this.create();
|
||||
}
|
||||
|
||||
|
@ -87,7 +87,7 @@ ConnectionIndicator.prototype.generateText = function () {
|
|||
}
|
||||
|
||||
var resolutionValue = null;
|
||||
if(this.resolution && this.jid) {
|
||||
if(this.resolution && this.id) {
|
||||
var keys = Object.keys(this.resolution);
|
||||
for(var ssrc in this.resolution) {
|
||||
// skip resolutions for ssrc that don't have this info
|
||||
|
@ -99,7 +99,7 @@ ConnectionIndicator.prototype.generateText = function () {
|
|||
}
|
||||
}
|
||||
|
||||
if(this.jid === null) {
|
||||
if(this.id === null) {
|
||||
resolution = "";
|
||||
if(this.resolution === null || !Object.keys(this.resolution) ||
|
||||
Object.keys(this.resolution).length === 0) {
|
||||
|
@ -144,8 +144,8 @@ ConnectionIndicator.prototype.generateText = function () {
|
|||
if(this.videoContainer.videoSpanId == "localVideoContainer") {
|
||||
result += "<div class=\"jitsipopover_showmore\" " +
|
||||
"onclick = \"APP.UI.connectionIndicatorShowMore('" +
|
||||
// FIXME: we do not know local jid when this text is generated
|
||||
//this.jid + "')\" data-i18n='connectionindicator." +
|
||||
// FIXME: we do not know local id when this text is generated
|
||||
//this.id + "')\" data-i18n='connectionindicator." +
|
||||
"local')\" data-i18n='connectionindicator." +
|
||||
(this.showMoreValue ? "less" : "more") + "'>" +
|
||||
translate("connectionindicator." + (this.showMoreValue ? "less" : "more")) +
|
||||
|
@ -365,7 +365,8 @@ ConnectionIndicator.prototype.updateResolution = function (resolution) {
|
|||
*/
|
||||
ConnectionIndicator.prototype.updatePopoverData = function () {
|
||||
this.popover.updateContent(
|
||||
"<div class=\"connection_info\">" + this.generateText() + "</div>");
|
||||
`<div class="connection_info">${this.generateText()}</div>`
|
||||
);
|
||||
APP.translation.translateElement($(".connection_info"));
|
||||
};
|
||||
|
||||
|
@ -385,4 +386,4 @@ ConnectionIndicator.prototype.hideIndicator = function () {
|
|||
this.popover.forceHide();
|
||||
};
|
||||
|
||||
module.exports = ConnectionIndicator;
|
||||
export default ConnectionIndicator;
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
/* global $, APP, Strophe, interfaceConfig */
|
||||
/* global $, APP, interfaceConfig */
|
||||
/* jshint -W101 */
|
||||
var Avatar = require("../avatar/Avatar");
|
||||
import Avatar from "../avatar/Avatar";
|
||||
import ToolbarToggler from "../toolbars/ToolbarToggler";
|
||||
import UIUtil from "../util/UIUtil";
|
||||
import UIEvents from "../../../service/UI/UIEvents";
|
||||
|
||||
var RTCBrowserType = require("../../RTC/RTCBrowserType");
|
||||
var UIUtil = require("../util/UIUtil");
|
||||
var UIEvents = require("../../../service/UI/UIEvents");
|
||||
var xmpp = require("../../xmpp/xmpp");
|
||||
var ToolbarToggler = require("../toolbars/ToolbarToggler");
|
||||
|
||||
// FIXME: With Temasys we have to re-select everytime
|
||||
//var video = $('#largeVideo');
|
||||
|
@ -37,22 +37,22 @@ var state = "video";
|
|||
* @param state the state.
|
||||
* @returns {JQuery|*|jQuery|HTMLElement} the container.
|
||||
*/
|
||||
function getContainerByState(state)
|
||||
{
|
||||
function getContainerByState(state) {
|
||||
var selector = null;
|
||||
switch (state)
|
||||
{
|
||||
case "video":
|
||||
selector = "#largeVideoWrapper";
|
||||
break;
|
||||
case "etherpad":
|
||||
selector = "#etherpad>iframe";
|
||||
break;
|
||||
case "prezi":
|
||||
selector = "#presentation>iframe";
|
||||
break;
|
||||
switch (state) {
|
||||
case "video":
|
||||
selector = "#largeVideoWrapper";
|
||||
break;
|
||||
case "etherpad":
|
||||
selector = "#etherpad>iframe";
|
||||
break;
|
||||
case "prezi":
|
||||
selector = "#presentation>iframe";
|
||||
break;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
return (selector !== null)? $(selector) : null;
|
||||
return $(selector);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -72,24 +72,25 @@ function positionVideo(video,
|
|||
animate) {
|
||||
if (animate) {
|
||||
video.animate({
|
||||
width: width,
|
||||
height: height,
|
||||
top: verticalIndent,
|
||||
bottom: verticalIndent,
|
||||
left: horizontalIndent,
|
||||
right: horizontalIndent
|
||||
},
|
||||
{
|
||||
queue: false,
|
||||
duration: 500
|
||||
});
|
||||
width: width,
|
||||
height: height,
|
||||
top: verticalIndent,
|
||||
bottom: verticalIndent,
|
||||
left: horizontalIndent,
|
||||
right: horizontalIndent
|
||||
}, {
|
||||
queue: false,
|
||||
duration: 500
|
||||
});
|
||||
} else {
|
||||
video.width(width);
|
||||
video.height(height);
|
||||
video.css({ top: verticalIndent + 'px',
|
||||
bottom: verticalIndent + 'px',
|
||||
left: horizontalIndent + 'px',
|
||||
right: horizontalIndent + 'px'});
|
||||
video.css({
|
||||
top: verticalIndent,
|
||||
bottom: verticalIndent,
|
||||
left: horizontalIndent,
|
||||
right: horizontalIndent
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -237,16 +238,13 @@ function getCameraVideoSize(videoWidth,
|
|||
|
||||
/**
|
||||
* Updates the src of the active speaker avatar
|
||||
* @param jid of the current active speaker
|
||||
*/
|
||||
function updateActiveSpeakerAvatarSrc() {
|
||||
var avatar = $("#activeSpeakerAvatar")[0];
|
||||
var jid = currentSmallVideo.peerJid;
|
||||
var url = Avatar.getActiveSpeakerUrl(jid);
|
||||
if (avatar.src === url)
|
||||
return;
|
||||
if (jid) {
|
||||
avatar.src = url;
|
||||
let avatar = $("#activeSpeakerAvatar");
|
||||
let id = currentSmallVideo.id;
|
||||
let url = Avatar.getActiveSpeakerUrl(id);
|
||||
if (id && avatar.attr('src') !== url) {
|
||||
avatar.attr('src', url);
|
||||
currentSmallVideo.showAvatar();
|
||||
}
|
||||
}
|
||||
|
@ -263,13 +261,15 @@ function changeVideo(isVisible) {
|
|||
}
|
||||
|
||||
updateActiveSpeakerAvatarSrc();
|
||||
var largeVideoElement = $('#largeVideo')[0];
|
||||
let largeVideoElement = $('#largeVideo');
|
||||
|
||||
APP.RTC.setVideoSrc(largeVideoElement, currentSmallVideo.getSrc());
|
||||
currentSmallVideo.stream.attach(largeVideoElement);
|
||||
|
||||
var flipX = currentSmallVideo.flipX;
|
||||
let flipX = currentSmallVideo.flipX;
|
||||
|
||||
largeVideoElement.style.transform = flipX ? "scaleX(-1)" : "none";
|
||||
largeVideoElement.css({
|
||||
transform: flipX ? "scaleX(-1)" : "none"
|
||||
});
|
||||
|
||||
LargeVideo.updateVideoSizeAndPosition(currentSmallVideo.getVideoType());
|
||||
|
||||
|
@ -369,40 +369,35 @@ var LargeVideo = {
|
|||
/**
|
||||
* Returns <tt>true</tt> if the user is currently displayed on large video.
|
||||
*/
|
||||
isCurrentlyOnLarge: function (resourceJid) {
|
||||
return currentSmallVideo && resourceJid &&
|
||||
currentSmallVideo.getResourceJid() === resourceJid;
|
||||
isCurrentlyOnLarge: function (id) {
|
||||
return id && id === this.getId();
|
||||
},
|
||||
/**
|
||||
* Updates the large video with the given new video source.
|
||||
*/
|
||||
updateLargeVideo: function (resourceJid, forceUpdate) {
|
||||
if(!isEnabled)
|
||||
updateLargeVideo: function (id, forceUpdate) {
|
||||
if(!isEnabled) {
|
||||
return;
|
||||
var newSmallVideo = this.VideoLayout.getSmallVideo(resourceJid);
|
||||
console.info('hover in ' + resourceJid + ', video: ', newSmallVideo);
|
||||
}
|
||||
let newSmallVideo = this.VideoLayout.getSmallVideo(id);
|
||||
console.info(`hover in ${id} , video: `, newSmallVideo);
|
||||
|
||||
if (!newSmallVideo) {
|
||||
console.error("Small video not found for: " + resourceJid);
|
||||
console.error("Small video not found for: " + id);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!LargeVideo.isCurrentlyOnLarge(resourceJid) || forceUpdate) {
|
||||
if (!LargeVideo.isCurrentlyOnLarge(id) || forceUpdate) {
|
||||
$('#activeSpeaker').css('visibility', 'hidden');
|
||||
|
||||
var oldSmallVideo = null;
|
||||
if (currentSmallVideo) {
|
||||
oldSmallVideo = currentSmallVideo;
|
||||
}
|
||||
let oldId = this.getId();
|
||||
|
||||
currentSmallVideo = newSmallVideo;
|
||||
|
||||
var oldJid = null;
|
||||
if (oldSmallVideo)
|
||||
oldJid = oldSmallVideo.peerJid;
|
||||
if (oldJid !== resourceJid) {
|
||||
// we want the notification to trigger even if userJid is undefined,
|
||||
if (oldId !== id) {
|
||||
// we want the notification to trigger even if id is undefined,
|
||||
// or null.
|
||||
this.eventEmitter.emit(UIEvents.SELECTED_ENDPOINT, resourceJid);
|
||||
this.eventEmitter.emit(UIEvents.SELECTED_ENDPOINT, id);
|
||||
}
|
||||
// We are doing fadeOut/fadeIn animations on parent div which wraps
|
||||
// largeVideo, because when Temasys plugin is in use it replaces
|
||||
|
@ -443,11 +438,10 @@ var LargeVideo = {
|
|||
currentSmallVideo.enableDominantSpeaker(false);
|
||||
}
|
||||
},
|
||||
onVideoTypeChanged: function (resourceJid, newVideoType) {
|
||||
onVideoTypeChanged: function (id, newVideoType) {
|
||||
if (!isEnabled)
|
||||
return;
|
||||
if (LargeVideo.isCurrentlyOnLarge(resourceJid))
|
||||
{
|
||||
if (LargeVideo.isCurrentlyOnLarge(id)) {
|
||||
LargeVideo.updateVideoSizeAndPosition(newVideoType);
|
||||
|
||||
this.position(null, null, null, null, true);
|
||||
|
@ -562,22 +556,23 @@ var LargeVideo = {
|
|||
getVideoPosition = isDesktop ? getDesktopVideoPosition :
|
||||
getCameraVideoPosition;
|
||||
},
|
||||
getResourceJid: function () {
|
||||
return currentSmallVideo ? currentSmallVideo.getResourceJid() : null;
|
||||
getId: function () {
|
||||
return currentSmallVideo ? currentSmallVideo.id : null;
|
||||
},
|
||||
updateAvatar: function (resourceJid) {
|
||||
if(!isEnabled)
|
||||
updateAvatar: function (id) {
|
||||
if (!isEnabled) {
|
||||
return;
|
||||
if (resourceJid === this.getResourceJid()) {
|
||||
}
|
||||
if (id === this.getId()) {
|
||||
updateActiveSpeakerAvatarSrc();
|
||||
}
|
||||
},
|
||||
showAvatar: function (resourceJid, show) {
|
||||
if (!isEnabled)
|
||||
showAvatar: function (id, show) {
|
||||
if (!isEnabled) {
|
||||
return;
|
||||
if (this.getResourceJid() === resourceJid && state === "video") {
|
||||
$("#largeVideoWrapper")
|
||||
.css("visibility", show ? "hidden" : "visible");
|
||||
}
|
||||
if (this.getId() === id && state === "video") {
|
||||
$("#largeVideoWrapper").css("visibility", show ? "hidden" : "visible");
|
||||
$('#activeSpeaker').css("visibility", show ? "visible" : "hidden");
|
||||
return true;
|
||||
}
|
||||
|
@ -721,4 +716,4 @@ var LargeVideo = {
|
|||
}
|
||||
};
|
||||
|
||||
module.exports = LargeVideo;
|
||||
export default LargeVideo;
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
/* global $, interfaceConfig, APP */
|
||||
var SmallVideo = require("./SmallVideo");
|
||||
var ConnectionIndicator = require("./ConnectionIndicator");
|
||||
var UIUtil = require("../util/UIUtil");
|
||||
var UIEvents = require("../../../service/UI/UIEvents");
|
||||
import ConnectionIndicator from "./ConnectionIndicator";
|
||||
import UIUtil from "../util/UIUtil";
|
||||
import UIEvents from "../../../service/UI/UIEvents";
|
||||
import SmallVideo from "./SmallVideo";
|
||||
|
||||
var LargeVideo = require("./LargeVideo");
|
||||
var RTCBrowserType = require("../../RTC/RTCBrowserType");
|
||||
|
||||
|
@ -13,7 +14,6 @@ function LocalVideo(VideoLayout, emitter) {
|
|||
this.VideoLayout = VideoLayout;
|
||||
this.flipX = true;
|
||||
this.isLocal = true;
|
||||
this.peerJid = null;
|
||||
this.emitter = emitter;
|
||||
}
|
||||
|
||||
|
@ -125,7 +125,7 @@ LocalVideo.prototype.setDisplayName = function(displayName, key) {
|
|||
if (e.keyCode === 13) {
|
||||
e.preventDefault();
|
||||
$('#editDisplayName').hide();
|
||||
self.VideoLayout.inputDisplayNameHandler(this.value);
|
||||
// focusout handler will save display name
|
||||
}
|
||||
});
|
||||
});
|
||||
|
@ -143,32 +143,25 @@ LocalVideo.prototype.createConnectionIndicator = function() {
|
|||
this.connectionIndicator = new ConnectionIndicator(this, null);
|
||||
};
|
||||
|
||||
LocalVideo.prototype.changeVideo = function (stream, isMuted) {
|
||||
var self = this;
|
||||
LocalVideo.prototype.changeVideo = function (stream) {
|
||||
this.stream = stream;
|
||||
|
||||
function localVideoClick(event) {
|
||||
let localVideoClick = (event) => {
|
||||
// FIXME: with Temasys plugin event arg is not an event, but
|
||||
// the clicked object itself, so we have to skip this call
|
||||
if (event.stopPropagation) {
|
||||
event.stopPropagation();
|
||||
}
|
||||
self.VideoLayout.handleVideoThumbClicked(
|
||||
true,
|
||||
APP.xmpp.myResource());
|
||||
}
|
||||
this.VideoLayout.handleVideoThumbClicked(true, this.id);
|
||||
};
|
||||
|
||||
var localVideoContainerSelector = $('#localVideoContainer');
|
||||
let localVideoContainerSelector = $('#localVideoContainer');
|
||||
localVideoContainerSelector.off('click');
|
||||
localVideoContainerSelector.on('click', localVideoClick);
|
||||
|
||||
if(isMuted) {
|
||||
APP.UI.setVideoMute(true);
|
||||
return;
|
||||
}
|
||||
this.flipX = stream.videoType != "screen";
|
||||
var localVideo = document.createElement('video');
|
||||
localVideo.id = 'localVideo_' +
|
||||
APP.RTC.getStreamID(stream.getOriginalStream());
|
||||
let localVideo = document.createElement('video');
|
||||
localVideo.id = 'localVideo_' + stream.getId();
|
||||
if (!RTCBrowserType.isIExplorer()) {
|
||||
localVideo.autoplay = true;
|
||||
localVideo.volume = 0; // is it required if audio is separated ?
|
||||
|
@ -192,7 +185,10 @@ LocalVideo.prototype.changeVideo = function (stream, isMuted) {
|
|||
}
|
||||
|
||||
// Attach WebRTC stream
|
||||
APP.RTC.attachMediaStream(localVideoSelector, stream.getOriginalStream());
|
||||
stream.attach(localVideoSelector);
|
||||
|
||||
// FIXME handle
|
||||
return;
|
||||
|
||||
// Add stream ended handler
|
||||
APP.RTC.addMediaStreamInactiveHandler(
|
||||
|
@ -201,20 +197,12 @@ LocalVideo.prototype.changeVideo = function (stream, isMuted) {
|
|||
// because <video> element is replaced with <object>
|
||||
localVideo = $('#' + localVideo.id)[0];
|
||||
localVideoContainer.removeChild(localVideo);
|
||||
self.VideoLayout.updateRemovedVideo(APP.xmpp.myResource());
|
||||
self.VideoLayout.updateRemovedVideo(self.id);
|
||||
});
|
||||
};
|
||||
|
||||
LocalVideo.prototype.joined = function (jid) {
|
||||
this.peerJid = jid;
|
||||
LocalVideo.prototype.joined = function (id) {
|
||||
this.id = id;
|
||||
};
|
||||
|
||||
LocalVideo.prototype.getResourceJid = function () {
|
||||
var myResource = APP.xmpp.myResource();
|
||||
if (!myResource) {
|
||||
console.error("Requested local resource before we're in the MUC");
|
||||
}
|
||||
return myResource;
|
||||
};
|
||||
|
||||
module.exports = LocalVideo;
|
||||
export default LocalVideo;
|
||||
|
|
|
@ -1,24 +1,25 @@
|
|||
/* global $, APP, require, Strophe, interfaceConfig */
|
||||
var ConnectionIndicator = require("./ConnectionIndicator");
|
||||
var SmallVideo = require("./SmallVideo");
|
||||
var AudioLevels = require("../audio_levels/AudioLevels");
|
||||
var MediaStreamType = require("../../../service/RTC/MediaStreamTypes");
|
||||
var RTCBrowserType = require("../../RTC/RTCBrowserType");
|
||||
var UIUtils = require("../util/UIUtil");
|
||||
var XMPPEvents = require("../../../service/xmpp/XMPPEvents");
|
||||
/* global $, APP, interfaceConfig */
|
||||
|
||||
function RemoteVideo(peerJid, VideoLayout) {
|
||||
this.peerJid = peerJid;
|
||||
this.resourceJid = Strophe.getResourceFromJid(peerJid);
|
||||
this.videoSpanId = 'participant_' + this.resourceJid;
|
||||
import ConnectionIndicator from './ConnectionIndicator';
|
||||
|
||||
import SmallVideo from "./SmallVideo";
|
||||
import AudioLevels from "../audio_levels/AudioLevels";
|
||||
import UIUtils from "../util/UIUtil";
|
||||
import UIEvents from '../../../service/UI/UIEvents';
|
||||
|
||||
var RTCBrowserType = require("../../RTC/RTCBrowserType");
|
||||
|
||||
function RemoteVideo(id, VideoLayout, emitter) {
|
||||
this.id = id;
|
||||
this.emitter = emitter;
|
||||
this.videoSpanId = `participant_${id}`;
|
||||
this.VideoLayout = VideoLayout;
|
||||
this.addRemoteVideoContainer();
|
||||
this.connectionIndicator = new ConnectionIndicator(
|
||||
this, this.peerJid);
|
||||
this.connectionIndicator = new ConnectionIndicator(this, id);
|
||||
this.setDisplayName();
|
||||
var nickfield = document.createElement('span');
|
||||
nickfield.className = "nick";
|
||||
nickfield.appendChild(document.createTextNode(this.resourceJid));
|
||||
nickfield.appendChild(document.createTextNode(id));
|
||||
this.container.appendChild(nickfield);
|
||||
this.bindHoverHandler();
|
||||
this.flipX = false;
|
||||
|
@ -30,18 +31,19 @@ RemoteVideo.prototype.constructor = RemoteVideo;
|
|||
|
||||
RemoteVideo.prototype.addRemoteVideoContainer = function() {
|
||||
this.container = RemoteVideo.createContainer(this.videoSpanId);
|
||||
if (APP.xmpp.isModerator())
|
||||
if (APP.conference.isModerator) {
|
||||
this.addRemoteVideoMenu();
|
||||
AudioLevels.updateAudioLevelCanvas(this.peerJid, this.VideoLayout);
|
||||
}
|
||||
AudioLevels.updateAudioLevelCanvas(this.id, this.VideoLayout);
|
||||
|
||||
return this.container;
|
||||
};
|
||||
|
||||
/**
|
||||
* Adds the remote video menu element for the given <tt>jid</tt> in the
|
||||
* Adds the remote video menu element for the given <tt>id</tt> in the
|
||||
* given <tt>parentElement</tt>.
|
||||
*
|
||||
* @param jid the jid indicating the video for which we're adding a menu.
|
||||
* @param id the id indicating the video for which we're adding a menu.
|
||||
* @param parentElement the parent element where this menu will be added
|
||||
*/
|
||||
|
||||
|
@ -60,7 +62,7 @@ if (!interfaceConfig.filmStripOnly) {
|
|||
|
||||
var popupmenuElement = document.createElement('ul');
|
||||
popupmenuElement.className = 'popupmenu';
|
||||
popupmenuElement.id = 'remote_popupmenu_' + this.getResourceJid();
|
||||
popupmenuElement.id = `remote_popupmenu_${this.id}`;
|
||||
spanElement.appendChild(popupmenuElement);
|
||||
|
||||
var muteMenuItem = document.createElement('li');
|
||||
|
@ -88,7 +90,7 @@ if (!interfaceConfig.filmStripOnly) {
|
|||
event.preventDefault();
|
||||
}
|
||||
var isMute = !!self.isMuted;
|
||||
APP.xmpp.setMute(self.peerJid, !isMute);
|
||||
self.emitter.emit(UIEvents.AUDIO_MUTED, !isMute);
|
||||
|
||||
popupmenuElement.setAttribute('style', 'display:none;');
|
||||
|
||||
|
@ -117,7 +119,7 @@ if (!interfaceConfig.filmStripOnly) {
|
|||
"data-i18n='videothumbnail.kick'> </div>";
|
||||
ejectLinkItem.innerHTML = ejectIndicator + ' ' + ejectText;
|
||||
ejectLinkItem.onclick = function(){
|
||||
APP.xmpp.eject(self.peerJid);
|
||||
self.emitter.emit(UIEvents.USER_KICKED, self.id);
|
||||
popupmenuElement.setAttribute('style', 'display:none;');
|
||||
};
|
||||
|
||||
|
@ -157,36 +159,36 @@ RemoteVideo.prototype.removeRemoteStreamElement =
|
|||
select.remove();
|
||||
|
||||
console.info((isVideo ? "Video" : "Audio") +
|
||||
" removed " + this.getResourceJid(), select);
|
||||
" removed " + this.id, select);
|
||||
|
||||
if (isVideo)
|
||||
this.VideoLayout.updateRemovedVideo(this.getResourceJid());
|
||||
this.VideoLayout.updateRemovedVideo(this.id);
|
||||
};
|
||||
|
||||
/**
|
||||
* Removes RemoteVideo from the page.
|
||||
*/
|
||||
RemoteVideo.prototype.remove = function () {
|
||||
console.log("Remove thumbnail", this.peerJid);
|
||||
console.log("Remove thumbnail", this.id);
|
||||
this.removeConnectionIndicator();
|
||||
// Make sure that the large video is updated if are removing its
|
||||
// corresponding small video.
|
||||
this.VideoLayout.updateRemovedVideo(this.getResourceJid());
|
||||
this.VideoLayout.updateRemovedVideo(this.id);
|
||||
// Remove whole container
|
||||
if (this.container.parentNode)
|
||||
if (this.container.parentNode) {
|
||||
this.container.parentNode.removeChild(this.container);
|
||||
}
|
||||
};
|
||||
|
||||
RemoteVideo.prototype.waitForPlayback = function (sel, stream) {
|
||||
|
||||
var webRtcStream = stream.getOriginalStream();
|
||||
var isVideo = stream.isVideoStream();
|
||||
var isVideo = stream.isVideoTrack();
|
||||
if (!isVideo || webRtcStream.id === 'mixedmslabel') {
|
||||
return;
|
||||
}
|
||||
|
||||
var self = this;
|
||||
var resourceJid = this.getResourceJid();
|
||||
|
||||
// Register 'onplaying' listener to trigger 'videoactive' on VideoLayout
|
||||
// when video playback starts
|
||||
|
@ -198,7 +200,7 @@ RemoteVideo.prototype.waitForPlayback = function (sel, stream) {
|
|||
if (RTCBrowserType.isTemasysPluginUsed()) {
|
||||
sel = self.selectVideoElement();
|
||||
}
|
||||
self.VideoLayout.videoactive(sel, resourceJid);
|
||||
self.VideoLayout.videoactive(sel, self.id);
|
||||
sel[0].onplaying = null;
|
||||
if (RTCBrowserType.isTemasysPluginUsed()) {
|
||||
// 'currentTime' is used to check if the video has started
|
||||
|
@ -210,39 +212,33 @@ RemoteVideo.prototype.waitForPlayback = function (sel, stream) {
|
|||
};
|
||||
|
||||
RemoteVideo.prototype.addRemoteStreamElement = function (stream) {
|
||||
if (!this.container)
|
||||
if (!this.container) {
|
||||
return;
|
||||
}
|
||||
|
||||
var self = this;
|
||||
var webRtcStream = stream.getOriginalStream();
|
||||
var isVideo = stream.isVideoStream();
|
||||
var streamElement = SmallVideo.createStreamElement(stream);
|
||||
var newElementId = streamElement.id;
|
||||
this.stream = stream;
|
||||
|
||||
let isVideo = stream.isVideoTrack();
|
||||
let streamElement = SmallVideo.createStreamElement(stream);
|
||||
let newElementId = streamElement.id;
|
||||
|
||||
// Put new stream element always in front
|
||||
UIUtils.prependChild(this.container, streamElement);
|
||||
|
||||
var sel = $('#' + newElementId);
|
||||
let sel = $(`#${newElementId}`);
|
||||
sel.hide();
|
||||
|
||||
// If the container is currently visible we attach the stream.
|
||||
if (!isVideo || (this.container.offsetParent !== null && isVideo)) {
|
||||
this.waitForPlayback(sel, stream);
|
||||
|
||||
APP.RTC.attachMediaStream(sel, webRtcStream);
|
||||
stream.attach(sel);
|
||||
}
|
||||
|
||||
APP.RTC.addMediaStreamInactiveHandler(
|
||||
webRtcStream, function () {
|
||||
console.log('stream ended', this);
|
||||
|
||||
self.removeRemoteStreamElement(webRtcStream, isVideo, newElementId);
|
||||
});
|
||||
|
||||
// Add click handler.
|
||||
var onClickHandler = function (event) {
|
||||
let onClickHandler = (event) => {
|
||||
|
||||
self.VideoLayout.handleVideoThumbClicked(false, self.getResourceJid());
|
||||
this.VideoLayout.handleVideoThumbClicked(false, this.id);
|
||||
|
||||
// On IE we need to populate this handler on video <object>
|
||||
// and it does not give event instance as an argument,
|
||||
|
@ -255,13 +251,14 @@ RemoteVideo.prototype.addRemoteStreamElement = function (stream) {
|
|||
};
|
||||
this.container.onclick = onClickHandler;
|
||||
// reselect
|
||||
if (RTCBrowserType.isTemasysPluginUsed())
|
||||
sel = $('#' + newElementId);
|
||||
sel[0].onclick = onClickHandler;
|
||||
if (RTCBrowserType.isTemasysPluginUsed()) {
|
||||
sel = $(`#${newElementId}`);
|
||||
}
|
||||
sel.click(onClickHandler);
|
||||
},
|
||||
|
||||
/**
|
||||
* Show/hide peer container for the given resourceJid.
|
||||
* Show/hide peer container for the given id.
|
||||
*/
|
||||
RemoteVideo.prototype.showPeerContainer = function (state) {
|
||||
if (!this.container)
|
||||
|
@ -294,7 +291,7 @@ RemoteVideo.prototype.showPeerContainer = function (state) {
|
|||
|
||||
// We want to be able to pin a participant from the contact list, even
|
||||
// if he's not in the lastN set!
|
||||
// ContactList.setClickable(resourceJid, !isHide);
|
||||
// ContactList.setClickable(id, !isHide);
|
||||
|
||||
};
|
||||
|
||||
|
@ -311,12 +308,11 @@ RemoteVideo.prototype.hideConnectionIndicator = function () {
|
|||
/**
|
||||
* Updates the remote video menu.
|
||||
*
|
||||
* @param jid the jid indicating the video for which we're adding a menu.
|
||||
* @param id the id indicating the video for which we're adding a menu.
|
||||
* @param isMuted indicates the current mute state
|
||||
*/
|
||||
RemoteVideo.prototype.updateRemoteVideoMenu = function (isMuted) {
|
||||
var muteMenuItem
|
||||
= $('#remote_popupmenu_' + this.getResourceJid() + '>li>a.mutelink');
|
||||
var muteMenuItem = $(`#remote_popupmenu_${this.id}>li>a.mutelink`);
|
||||
|
||||
var mutedIndicator = "<i class='icon-mic-disabled'></i>";
|
||||
|
||||
|
@ -423,13 +419,6 @@ RemoteVideo.prototype.removeRemoteVideoMenu = function() {
|
|||
}
|
||||
};
|
||||
|
||||
RemoteVideo.prototype.getResourceJid = function () {
|
||||
if (!this.resourceJid) {
|
||||
console.error("Undefined resource jid");
|
||||
}
|
||||
return this.resourceJid;
|
||||
};
|
||||
|
||||
RemoteVideo.createContainer = function (spanId) {
|
||||
var container = document.createElement('span');
|
||||
container.id = spanId;
|
||||
|
@ -439,4 +428,4 @@ RemoteVideo.createContainer = function (spanId) {
|
|||
};
|
||||
|
||||
|
||||
module.exports = RemoteVideo;
|
||||
export default RemoteVideo;
|
||||
|
|
|
@ -1,14 +1,15 @@
|
|||
/* global $, APP, require */
|
||||
/* jshint -W101 */
|
||||
var Avatar = require("../avatar/Avatar");
|
||||
var UIUtil = require("../util/UIUtil");
|
||||
var LargeVideo = require("./LargeVideo");
|
||||
import Avatar from "../avatar/Avatar";
|
||||
import UIUtil from "../util/UIUtil";
|
||||
import LargeVideo from "./LargeVideo";
|
||||
|
||||
var RTCBrowserType = require("../../RTC/RTCBrowserType");
|
||||
var MediaStreamType = require("../../../service/RTC/MediaStreamTypes");
|
||||
|
||||
function SmallVideo() {
|
||||
this.isMuted = false;
|
||||
this.hasAvatar = false;
|
||||
this.stream = null;
|
||||
}
|
||||
|
||||
function setVisibility(selector, show) {
|
||||
|
@ -106,9 +107,10 @@ SmallVideo.prototype.setPresenceStatus = function (statusMsg) {
|
|||
* Creates an audio or video element for a particular MediaStream.
|
||||
*/
|
||||
SmallVideo.createStreamElement = function (stream) {
|
||||
var isVideo = stream.isVideoStream();
|
||||
let isVideo = stream.isVideoTrack();
|
||||
|
||||
var element = isVideo ? document.createElement('video')
|
||||
let element = isVideo
|
||||
? document.createElement('video')
|
||||
: document.createElement('audio');
|
||||
if (isVideo) {
|
||||
element.setAttribute("muted", "true");
|
||||
|
@ -118,8 +120,7 @@ SmallVideo.createStreamElement = function (stream) {
|
|||
element.autoplay = true;
|
||||
}
|
||||
|
||||
element.id = (isVideo ? 'remoteVideo_' : 'remoteAudio_') +
|
||||
APP.RTC.getStreamID(stream.getOriginalStream());
|
||||
element.id = (isVideo ? 'remoteVideo_' : 'remoteAudio_') + stream.getId();
|
||||
|
||||
element.onplay = function () {
|
||||
console.log("(TIME) Render " + (isVideo ? 'video' : 'audio') + ":\t",
|
||||
|
@ -145,7 +146,7 @@ SmallVideo.prototype.bindHoverHandler = function () {
|
|||
// If the video has been "pinned" by the user we want to
|
||||
// keep the display name on place.
|
||||
if (!LargeVideo.isLargeVideoVisible() ||
|
||||
!LargeVideo.isCurrentlyOnLarge(self.getResourceJid()))
|
||||
!LargeVideo.isCurrentlyOnLarge(self.id))
|
||||
self.showDisplayName(false);
|
||||
}
|
||||
);
|
||||
|
@ -237,15 +238,14 @@ SmallVideo.prototype.showVideoIndicator = function(isMuted) {
|
|||
};
|
||||
|
||||
SmallVideo.prototype.enableDominantSpeaker = function (isEnable) {
|
||||
var resourceJid = this.getResourceJid();
|
||||
var displayName = resourceJid;
|
||||
var displayName = this.id;
|
||||
var nameSpan = $('#' + this.videoSpanId + '>span.displayname');
|
||||
if (nameSpan.length > 0)
|
||||
displayName = nameSpan.html();
|
||||
|
||||
console.log("UI enable dominant speaker",
|
||||
displayName,
|
||||
resourceJid,
|
||||
this.id,
|
||||
isEnable);
|
||||
|
||||
|
||||
|
@ -316,6 +316,8 @@ SmallVideo.prototype.createModeratorIndicatorElement = function () {
|
|||
};
|
||||
|
||||
SmallVideo.prototype.selectVideoElement = function () {
|
||||
return $('#' + this.videoSpanId).find(videoElem);
|
||||
// FIXME maybe move this to the library?
|
||||
var videoElem = APP.RTC.getVideoElementName();
|
||||
if (!RTCBrowserType.isTemasysPluginUsed()) {
|
||||
return $('#' + this.videoSpanId).find(videoElem);
|
||||
|
@ -367,32 +369,31 @@ SmallVideo.prototype.hasVideo = function () {
|
|||
*/
|
||||
SmallVideo.prototype.showAvatar = function (show) {
|
||||
if (!this.hasAvatar) {
|
||||
if (this.peerJid) {
|
||||
if (this.id) {
|
||||
// Init avatar
|
||||
this.avatarChanged(Avatar.getThumbUrl(this.peerJid));
|
||||
this.avatarChanged(Avatar.getThumbUrl(this.id));
|
||||
} else {
|
||||
console.error("Unable to init avatar - no peerjid", this);
|
||||
console.error("Unable to init avatar - no id", this);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
var resourceJid = this.getResourceJid();
|
||||
var video = this.selectVideoElement();
|
||||
let video = this.selectVideoElement();
|
||||
|
||||
var avatar = $('#avatar_' + resourceJid);
|
||||
let avatar = $(`#avatar_${this.id}`);
|
||||
|
||||
if (show === undefined || show === null) {
|
||||
if (!this.isLocal &&
|
||||
!this.VideoLayout.isInLastN(resourceJid)) {
|
||||
!this.VideoLayout.isInLastN(this.id)) {
|
||||
show = true;
|
||||
} else {
|
||||
// We want to show the avatar when the video is muted or not exists
|
||||
// that is when 'true' or 'null' is returned
|
||||
show = APP.RTC.isVideoMuted(this.peerJid) !== false;
|
||||
show = !this.stream || this.stream.isMuted();
|
||||
}
|
||||
}
|
||||
|
||||
if (LargeVideo.showAvatar(resourceJid, show)) {
|
||||
if (LargeVideo.showAvatar(this.id, show)) {
|
||||
setVisibility(avatar, false);
|
||||
setVisibility(video, false);
|
||||
} else {
|
||||
|
@ -405,8 +406,7 @@ SmallVideo.prototype.showAvatar = function (show) {
|
|||
|
||||
SmallVideo.prototype.avatarChanged = function (thumbUrl) {
|
||||
var thumbnail = $('#' + this.videoSpanId);
|
||||
var resourceJid = this.getResourceJid();
|
||||
var avatar = $('#avatar_' + resourceJid);
|
||||
var avatar = $('#avatar_' + this.id);
|
||||
this.hasAvatar = true;
|
||||
|
||||
// set the avatar in the thumbnail
|
||||
|
@ -415,7 +415,7 @@ SmallVideo.prototype.avatarChanged = function (thumbUrl) {
|
|||
} else {
|
||||
if (thumbnail && thumbnail.length > 0) {
|
||||
avatar = document.createElement('img');
|
||||
avatar.id = 'avatar_' + resourceJid;
|
||||
avatar.id = 'avatar_' + this.id;
|
||||
avatar.className = 'userAvatar';
|
||||
avatar.src = thumbUrl;
|
||||
thumbnail.append(avatar);
|
||||
|
@ -423,4 +423,4 @@ SmallVideo.prototype.avatarChanged = function (thumbUrl) {
|
|||
}
|
||||
};
|
||||
|
||||
module.exports = SmallVideo;
|
||||
export default SmallVideo;
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,86 @@
|
|||
/* global APP, JitsiMeetJS, config */
|
||||
|
||||
import LoginDialog from './UI/authentication/LoginDialog';
|
||||
|
||||
const ConnectionEvents = JitsiMeetJS.events.connection;
|
||||
const ConnectionErrors = JitsiMeetJS.errors.connection;
|
||||
|
||||
function connect(id, password) {
|
||||
let connection = new JitsiMeetJS.JitsiConnection(null, null, {
|
||||
hosts: config.hosts,
|
||||
bosh: config.bosh,
|
||||
clientNode: config.clientNode
|
||||
});
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
connection.addEventListener(
|
||||
ConnectionEvents.CONNECTION_ESTABLISHED, handleConnectionEstablished
|
||||
);
|
||||
connection.addEventListener(
|
||||
ConnectionEvents.CONNECTION_FAILED, handleConnectionFailed
|
||||
);
|
||||
|
||||
function unsubscribe() {
|
||||
connection.removeEventListener(
|
||||
ConnectionEvents.CONNECTION_ESTABLISHED,
|
||||
handleConnectionEstablished
|
||||
);
|
||||
connection.removeEventListener(
|
||||
ConnectionEvents.CONNECTION_FAILED,
|
||||
handleConnectionFailed
|
||||
);
|
||||
}
|
||||
|
||||
function handleConnectionEstablished() {
|
||||
unsubscribe();
|
||||
resolve(connection);
|
||||
}
|
||||
|
||||
function handleConnectionFailed(err) {
|
||||
unsubscribe();
|
||||
console.error("CONNECTION FAILED:", err);
|
||||
reject(err);
|
||||
}
|
||||
|
||||
connection.connect({id, password});
|
||||
});
|
||||
}
|
||||
|
||||
function requestAuth() {
|
||||
return new Promise(function (resolve, reject) {
|
||||
let authDialog = LoginDialog.showAuthDialog(
|
||||
function (id, password) {
|
||||
connect(id, password).then(function (connection) {
|
||||
authDialog.close();
|
||||
resolve(connection);
|
||||
}, function (err) {
|
||||
if (err === ConnectionErrors.PASSWORD_REQUIRED) {
|
||||
authDialog.displayError(err);
|
||||
} else {
|
||||
authDialog.close();
|
||||
reject(err);
|
||||
}
|
||||
});
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
export function openConnection({id, password, retry}) {
|
||||
return connect(id, password).catch(function (err) {
|
||||
if (!retry) {
|
||||
throw err;
|
||||
}
|
||||
|
||||
if (err === ConnectionErrors.PASSWORD_REQUIRED) {
|
||||
// do not retry if token is not valid
|
||||
if (config.token) {
|
||||
throw err;
|
||||
} else {
|
||||
return requestAuth();
|
||||
}
|
||||
} else {
|
||||
throw err;
|
||||
}
|
||||
});
|
||||
}
|
|
@ -73,6 +73,7 @@ module.exports = {
|
|||
|
||||
init: function () {
|
||||
// Called when RTC finishes initialization
|
||||
return;
|
||||
APP.RTC.addListener(RTCEvents.RTC_READY,
|
||||
function() {
|
||||
screenObtainer.init(eventEmitter);
|
||||
|
|
|
@ -86,6 +86,7 @@ var statistics = {
|
|||
stopRemote();
|
||||
},
|
||||
start: function () {
|
||||
return;
|
||||
APP.RTC.addStreamListener(onStreamCreated,
|
||||
StreamEventTypes.EVENT_TYPE_LOCAL_CREATED);
|
||||
APP.xmpp.addListener(XMPPEvents.DISPOSE_CONFERENCE,
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* jshint -W101 */
|
||||
var RTCBrowserType = require("../RTC/RTCBrowserType");
|
||||
var RTCBrowserType = require('../RTC/RTCBrowserType');
|
||||
|
||||
var SDPUtil = {
|
||||
filter_special_chars: function (text) {
|
||||
|
|
13
package.json
13
package.json
|
@ -42,7 +42,10 @@
|
|||
"jshint": "2.8.0",
|
||||
"precommit-hook": "3.0.0",
|
||||
"uglify-js": "2.4.24",
|
||||
"clean-css": "*"
|
||||
"clean-css": "*",
|
||||
"babelify": "*",
|
||||
"babel-preset-es2015": "*",
|
||||
"babel-polyfill": "*"
|
||||
},
|
||||
"license": "Apache-2.0",
|
||||
"scripts": {
|
||||
|
@ -54,9 +57,15 @@
|
|||
],
|
||||
"browserify": {
|
||||
"transform": [
|
||||
"browserify-shim"
|
||||
"browserify-shim",
|
||||
["babelify", {
|
||||
"ignore": "node_modules"
|
||||
}]
|
||||
]
|
||||
},
|
||||
"babel": {
|
||||
"presets": ["es2015"]
|
||||
},
|
||||
"browser": {
|
||||
"jquery": "./node_modules/jquery/dist/jquery.js",
|
||||
"jquery-ui": "./node_modules/jquery-ui/jquery-ui.js",
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
var UIEvents = {
|
||||
export default {
|
||||
NICKNAME_CHANGED: "UI.nickname_changed",
|
||||
SELECTED_ENDPOINT: "UI.selected_endpoint",
|
||||
PINNED_ENDPOINT: "UI.pinned_endpoint",
|
||||
|
@ -21,10 +21,20 @@ var UIEvents = {
|
|||
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).
|
||||
*/
|
||||
FILM_STRIP_TOGGLED: "UI.filmstrip_toggled"
|
||||
PREZI_CLICKED: "UI.prezi_clicked",
|
||||
ETHERPAD_CLICKED: "UI.etherpad_clicked",
|
||||
ROOM_LOCK_CLICKED: "UI.room_lock_clicked",
|
||||
USER_INVITED: "UI.user_invited",
|
||||
USER_KICKED: "UI.user_kicked",
|
||||
FULLSCREEN_TOGGLE: "UI.fullscreen_toggle",
|
||||
AUTH_CLICKED: "UI.auth_clicked",
|
||||
TOGGLE_CHAT: "UI.toggle_chat",
|
||||
TOGGLE_SETTINGS: "UI.toggle_settings",
|
||||
TOGGLE_CONTACT_LIST: "UI.toggle_contact_list",
|
||||
TOGGLE_FILM_STRIP: "UI.toggle_film_strip",
|
||||
CONTACT_CLICKED: "UI.contact_clicked",
|
||||
HANGUP: "UI.hangup",
|
||||
LOGOUT: "UI.logout",
|
||||
RECORDING_TOGGLE: "UI.recording_toggle",
|
||||
TOPIC_CHANGED: "UI.topic_changed"
|
||||
};
|
||||
module.exports = UIEvents;
|
Loading…
Reference in New Issue