Creates UI module.

This commit is contained in:
hristoterezov 2015-01-07 16:54:03 +02:00
parent 4a991f7187
commit 69b0e2ad32
52 changed files with 9898 additions and 3100 deletions

View File

@ -20,3 +20,7 @@ clean:
deploy:
@mkdir -p $(DEPLOY_DIR) && cp $(OUTPUT_DIR)/*.bundle.js $(DEPLOY_DIR)
scp $(DEPLOY_DIR)/*.bundle.js hristo.jitsi.net:/srv/web/hristo.jitsi.net/$(DEPLOY_DIR)
dd: debug deploy

View File

@ -18,12 +18,12 @@ var APIConnector = (function () {
*/
var commands =
{
displayName: VideoLayout.inputDisplayNameHandler,
displayName: UI.inputDisplayNameHandler,
muteAudio: toggleAudio,
muteVideo: toggleVideo,
toggleFilmStrip: BottomToolbar.toggleFilmStrip,
toggleChat: BottomToolbar.toggleChat,
toggleContactList: BottomToolbar.toggleContactList
toggleFilmStrip: UI.toggleFilmStrip,
toggleChat: UI.toggleChat,
toggleContactList: UI.toggleContactList
};

632
app.js
View File

@ -2,12 +2,9 @@
/* application specific logic */
var connection = null;
var authenticatedUser = false;
var authenticationWindow = null;
var activecall = null;
var nickname = null;
var sharedKey = '';
var focusMucJid = null;
var roomUrl = null;
var roomName = null;
var ssrc2jid = {};
var bridgeIsDown = false;
@ -59,10 +56,8 @@ var getVideoPosition;
var sessionTerminated = false;
function init() {
Toolbar.setupButtonsFromConfig();
RTC.addStreamListener(maybeDoJoin, StreamEventTypes.EVENT_TYPE_LOCAL_CREATED);
RTC.addStreamListener(VideoLayout.onLocalStreamCreated, StreamEventTypes.EVENT_TYPE_LOCAL_CREATED)
RTC.start();
var jid = document.getElementById('jid').value || config.hosts.anonymousdomain || config.hosts.domain || window.location.hostname;
@ -77,12 +72,13 @@ function connect(jid, password) {
}
connection = new Strophe.Connection(document.getElementById('boshURL').value || config.bosh || '/http-bind');
var email = SettingsMenu.getEmail();
var displayName = SettingsMenu.getDisplayName();
var settings = UI.getSettings();
var email = settings.email;
var displayName = settings.displayName;
if(email) {
connection.emuc.addEmailToPresence(email);
} else {
connection.emuc.addUserIdToPresence(SettingsMenu.getUID());
connection.emuc.addUserIdToPresence(settings.uid);
}
if(displayName) {
connection.emuc.addDisplayNameToPresence(displayName);
@ -143,41 +139,9 @@ function maybeDoJoin() {
}
}
function generateRoomName() {
var roomnode = null;
var path = window.location.pathname;
// determinde the room node from the url
// TODO: just the roomnode or the whole bare jid?
if (config.getroomnode && typeof config.getroomnode === 'function') {
// custom function might be responsible for doing the pushstate
roomnode = config.getroomnode(path);
} else {
/* fall back to default strategy
* this is making assumptions about how the URL->room mapping happens.
* It currently assumes deployment at root, with a rewrite like the
* following one (for nginx):
location ~ ^/([a-zA-Z0-9]+)$ {
rewrite ^/(.*)$ / break;
}
*/
if (path.length > 1) {
roomnode = path.substr(1).toLowerCase();
} else {
var word = RoomNameGenerator.generateRoomWithoutSeparator();
roomnode = word.toLowerCase();
window.history.pushState('VideoChat',
'Room: ' + word, window.location.pathname + word);
}
}
roomName = roomnode + '@' + config.hosts.muc;
}
function doJoin() {
if (!roomName) {
generateRoomName();
UI.generateRoomName();
}
Moderator.allocateConferenceFocus(
@ -244,7 +208,6 @@ function waitForRemoteVideo(selector, ssrc, stream, jid) {
jid2Ssrc[Strophe.getResourceFromJid(jid)] = ssrc;
} else {
console.warn("No ssrc given for jid", jid);
// messageHandler.showError('Warning', 'No ssrc was given for the video.');
}
$(document).trigger('videoactive.jingle', [selector]);
@ -328,43 +291,7 @@ function waitForPresence(data, sid) {
RTC.createRemoteStream(data, sid, thessrc);
var container;
var remotes = document.getElementById('remoteVideos');
if (data.peerjid) {
VideoLayout.ensurePeerContainerExists(data.peerjid);
container = document.getElementById(
'participant_' + Strophe.getResourceFromJid(data.peerjid));
} else {
if (data.stream.id !== 'mixedmslabel'
// FIXME: default stream is added always with new focus
// (to be investigated)
&& data.stream.id !== 'default') {
console.error('can not associate stream',
data.stream.id,
'with a participant');
// We don't want to add it here since it will cause troubles
return;
}
// FIXME: for the mixed ms we dont need a video -- currently
container = document.createElement('span');
container.id = 'mixedstream';
container.className = 'videocontainer';
remotes.appendChild(container);
Util.playSoundNotification('userJoined');
}
var isVideo = data.stream.getVideoTracks().length > 0;
if (container) {
VideoLayout.addRemoteStreamElement( container,
sid,
data.stream,
data.peerjid,
thessrc);
}
// an attempt to work around https://github.com/jitsi/jitmeet/issues/32
if (isVideo &&
data.peerjid && sess.peerjid === data.peerjid &&
@ -393,19 +320,19 @@ function sendKeyframe(pc) {
},
function (error) {
console.log('triggerKeyframe setLocalDescription failed', error);
messageHandler.showError();
UI.messageHandler.showError();
}
);
},
function (error) {
console.log('triggerKeyframe createAnswer failed', error);
messageHandler.showError();
UI.messageHandler.showError();
}
);
},
function (error) {
console.log('triggerKeyframe setRemoteDescription failed', error);
messageHandler.showError();
UI.messageHandler.showError();
}
);
}
@ -433,7 +360,7 @@ function muteVideo(pc, unmute) {
},
function (error) {
console.log('mute SLD error');
messageHandler.showError('Error',
UI.messageHandler.showError('Error',
'Oops! Something went wrong and we failed to ' +
'mute! (SLD Failure)');
}
@ -441,13 +368,13 @@ function muteVideo(pc, unmute) {
},
function (error) {
console.log(error);
messageHandler.showError();
UI.messageHandler.showError();
}
);
},
function (error) {
console.log('muteVideo SRD error');
messageHandler.showError('Error',
UI.messageHandler.showError('Error',
'Oops! Something went wrong and we failed to stop video!' +
'(SRD Failure)');
@ -455,53 +382,6 @@ function muteVideo(pc, unmute) {
);
}
/**
* Callback for audio levels changed.
* @param jid JID of the user
* @param audioLevel the audio level value
*/
function audioLevelUpdated(jid, audioLevel)
{
var resourceJid;
if(jid === statistics.LOCAL_JID)
{
resourceJid = AudioLevels.LOCAL_LEVEL;
if(isAudioMuted())
{
audioLevel = 0;
}
}
else
{
resourceJid = Strophe.getResourceFromJid(jid);
}
AudioLevels.updateAudioLevel(resourceJid, audioLevel);
}
$(document).bind('callincoming.jingle', function (event, sid) {
var sess = connection.jingle.sessions[sid];
// TODO: do we check activecall == null?
activecall = sess;
statistics.onConferenceCreated(sess);
RTC.onConferenceCreated(sess);
// TODO: check affiliation and/or role
console.log('emuc data for', sess.peerjid, connection.emuc.members[sess.peerjid]);
sess.usedrip = true; // not-so-naive trickle ice
sess.sendAnswer();
sess.accept();
});
$(document).bind('conferenceCreated.jingle', function (event, focus)
{
statistics.onConfereceCreated(getConferenceHandler());
RTC.onConfereceCreated(focus);
});
$(document).bind('setLocalDescription.jingle', function (event, sid) {
// put our ssrcs into presence so other clients can identify our stream
var sess = connection.jingle.sessions[sid];
@ -585,115 +465,7 @@ $(document).bind('iceconnectionstatechange.jingle', function (event, sid, sessio
});
$(document).bind('joined.muc', function (event, jid, info) {
updateRoomUrl(window.location.href);
document.getElementById('localNick').appendChild(
document.createTextNode(Strophe.getResourceFromJid(jid) + ' (me)')
);
// Add myself to the contact list.
ContactList.addContact(jid, SettingsMenu.getEmail() || SettingsMenu.getUID());
// Once we've joined the muc show the toolbar
ToolbarToggler.showToolbar();
// Show authenticate button if needed
Toolbar.showAuthenticateButton(
Moderator.isExternalAuthEnabled() && !Moderator.isModerator());
var displayName = !config.displayJids
? info.displayName : Strophe.getResourceFromJid(jid);
if (displayName)
$(document).trigger('displaynamechanged',
['localVideoContainer', displayName + ' (me)']);
});
$(document).bind('entered.muc', function (event, jid, info, pres) {
console.log('entered', jid, info);
if (info.isFocus)
{
focusMucJid = jid;
console.info("Ignore focus: " + jid +", real JID: " + info.jid);
return;
}
messageHandler.notify(info.displayName || 'Somebody',
'connected',
'connected');
// Add Peer's container
var id = $(pres).find('>userID').text();
var email = $(pres).find('>email');
if(email.length > 0) {
id = email.text();
}
VideoLayout.ensurePeerContainerExists(jid,id);
if(APIConnector.isEnabled() && APIConnector.isEventEnabled("participantJoined"))
{
APIConnector.triggerEvent("participantJoined",{jid: jid});
}
/*if (focus !== null) {
// FIXME: this should prepare the video
if (focus.confid === null) {
console.log('make new conference with', jid);
focus.makeConference(Object.keys(connection.emuc.members),
function(error) {
connection.emuc.addBridgeIsDownToPresence();
connection.emuc.sendPresence();
}
);
Toolbar.showRecordingButton(true);
} else {
console.log('invite', jid, 'into conference');
focus.addNewParticipant(jid);
}
}*/
});
$(document).bind('left.muc', function (event, jid) {
console.log('left.muc', jid);
var displayName = $('#participant_' + Strophe.getResourceFromJid(jid) +
'>.displayname').html();
messageHandler.notify(displayName || 'Somebody',
'disconnected',
'disconnected');
// Need to call this with a slight delay, otherwise the element couldn't be
// found for some reason.
// XXX(gp) it works fine without the timeout for me (with Chrome 38).
window.setTimeout(function () {
var container = document.getElementById(
'participant_' + Strophe.getResourceFromJid(jid));
if (container) {
ContactList.removeContact(jid);
VideoLayout.removeConnectionIndicator(jid);
// hide here, wait for video to close before removing
$(container).hide();
VideoLayout.resizeThumbnails();
}
}, 10);
if(APIConnector.isEnabled() && APIConnector.isEventEnabled("participantLeft"))
{
APIConnector.triggerEvent("participantLeft",{jid: jid});
}
delete jid2Ssrc[jid];
// Unlock large video
if (focusedVideoInfo && focusedVideoInfo.jid === jid)
{
console.info("Focused video owner has left the conference");
focusedVideoInfo = null;
}
connection.jingle.terminateByJid(jid);
if (connection.emuc.getPrezi(jid)) {
$(document).trigger('presentationremoved.muc',
[jid, connection.emuc.getPrezi(jid)]);
}
});
$(document).bind('presence.muc', function (event, jid, info, pres) {
@ -701,7 +473,7 @@ $(document).bind('presence.muc', function (event, jid, info, pres) {
//check if the video bridge is available
if($(pres).find(">bridgeIsDown").length > 0 && !bridgeIsDown) {
bridgeIsDown = true;
messageHandler.showError("Error",
UI.messageHandler.showError("Error",
"Jitsi Videobridge is currently unavailable. Please try again later!");
}
@ -756,7 +528,7 @@ $(document).bind('presence.muc', function (event, jid, info, pres) {
//check if the video bridge is available
if($(pres).find(">bridgeIsDown").length > 0 && !bridgeIsDown) {
bridgeIsDown = true;
messageHandler.showError("Error",
UI.messageHandler.showError("Error",
"Jitsi Videobridge is currently unavailable. Please try again later!");
}
@ -765,14 +537,7 @@ $(document).bind('presence.muc', function (event, jid, info, pres) {
if(email.length > 0) {
id = email.text();
}
Avatar.setUserAvatar(jid, id);
});
$(document).bind('presence.status.muc', function (event, jid, info, pres) {
VideoLayout.setPresenceStatus(
'participant_' + Strophe.getResourceFromJid(jid), info.status);
UI.setUserAvatar(jid, id);
});
@ -782,80 +547,15 @@ $(document).bind('kicked.muc', function (event, jid) {
sessionTerminated = true;
disposeConference(false);
connection.emuc.doLeave();
messageHandler.openMessageDialog("Session Terminated",
UI.messageHandler.openMessageDialog("Session Terminated",
"Ouch! You have been kicked out of the meet!");
}
});
$(document).bind('role.changed.muc', function (event, jid, member, pres) {
console.info("Role changed for " + jid + ", new role: " + member.role);
VideoLayout.showModeratorIndicator();
if (member.role === 'moderator') {
var displayName = member.displayName;
if (!displayName) {
displayName = 'Somebody';
}
messageHandler.notify(
displayName,
'connected',
'Moderator rights granted to ' + displayName + '!');
}
}
);
$(document).bind('local.role.changed.muc', function (event, jid, info, pres) {
console.info("My role changed, new role: " + info.role);
var isModerator = Moderator.isModerator();
VideoLayout.showModeratorIndicator();
Toolbar.showAuthenticateButton(
Moderator.isExternalAuthEnabled() && !isModerator);
if (isModerator) {
if (authenticationWindow) {
authenticationWindow.close();
authenticationWindow = null;
}
messageHandler.notify(
'Me', 'connected', 'Moderator rights granted !');
}
}
);
$(document).bind('passwordrequired.muc', function (event, jid) {
console.log('on password required', jid);
// password is required
Toolbar.lockLockButton();
messageHandler.openTwoButtonDialog(null,
'<h2>Password required</h2>' +
'<input id="lockKey" type="text" placeholder="password" autofocus>',
true,
"Ok",
function (e, v, m, f) {},
function (event) {
document.getElementById('lockKey').focus();
},
function (e, v, m, f) {
if (v) {
var lockKey = document.getElementById('lockKey');
if (lockKey.value !== null) {
setSharedKey(lockKey.value);
connection.emuc.doJoin(jid, lockKey.value);
}
}
}
);
});
$(document).bind('passwordrequired.main', function (event) {
console.log('password is required');
messageHandler.openTwoButtonDialog(null,
UI.messageHandler.openTwoButtonDialog(null,
'<h2>Password required</h2>' +
'<input id="passwordrequired.username" type="text" placeholder="user@domain.net" autofocus>' +
'<input id="passwordrequired.password" type="password" placeholder="user password">',
@ -877,51 +577,6 @@ $(document).bind('passwordrequired.main', function (event) {
);
});
$(document).bind('auth_required.moderator', function () {
// extract room name from 'room@muc.server.net'
var room = roomName.substr(0, roomName.indexOf('@'));
messageHandler.openDialog(
'Stop',
'Authentication is required to create room:<br/>' + room,
true,
{
Authenticate: 'authNow',
Close: 'close'
},
function (onSubmitEvent, submitValue) {
console.info('On submit: ' + submitValue, submitValue);
if (submitValue === 'authNow') {
authenticateClicked();
} else {
Toolbar.showAuthenticateButton(true);
}
}
);
});
function authenticateClicked() {
// Get authentication URL
Moderator.getAuthUrl(function (url) {
// Open popup with authentication URL
authenticationWindow = messageHandler.openCenteredPopup(
url, 500, 400,
function () {
// On popup closed - retry room allocation
Moderator.allocateConferenceFocus(
roomName, doJoinAfterFocus);
authenticationWindow = null;
});
if (!authenticationWindow) {
Toolbar.showAuthenticateButton(true);
messageHandler.openMessageDialog(
null, "Your browser is blocking popup windows from this site." +
" Please enable popups in your browser security settings" +
" and try again.");
}
});
};
/**
* Checks if video identified by given src is desktop stream.
* @param videoSrc eg.
@ -1060,7 +715,7 @@ function setAudioMuted(mute) {
// isMuted is the opposite of audioEnabled
connection.emuc.addAudioInfoToPresence(mute);
connection.emuc.sendPresence();
VideoLayout.showLocalAudioIndicator(mute);
UI.showLocalAudioIndicator(mute);
buttonClick("#mute", "icon-microphone icon-mic-disabled");
}
@ -1079,11 +734,6 @@ function isAudioMuted()
return true;
}
// Starts or stops the recording for the conference.
function toggleRecording() {
Recording.toggleRecording();
}
/**
* Returns an array of the video horizontal and vertical indents,
* so that if fits its parent.
@ -1163,151 +813,17 @@ function getCameraVideoSize(videoWidth,
}
$(document).ready(function () {
document.title = interfaceConfig.APP_NAME;
if(APIConnector.isEnabled())
APIConnector.init();
if(config.enableWelcomePage && window.location.pathname == "/" &&
(!window.localStorage.welcomePageDisabled
|| window.localStorage.welcomePageDisabled == "false"))
{
$("#videoconference_page").hide();
$("#domain_name").text(
window.location.protocol + "//" + window.location.host + "/");
$("span[name='appName']").text(interfaceConfig.APP_NAME);
if (interfaceConfig.SHOW_JITSI_WATERMARK) {
var leftWatermarkDiv
= $("#welcome_page_header div[class='watermark leftwatermark']");
if(leftWatermarkDiv && leftWatermarkDiv.length > 0)
{
leftWatermarkDiv.css({display: 'block'});
leftWatermarkDiv.parent().get(0).href
= interfaceConfig.JITSI_WATERMARK_LINK;
}
}
if (interfaceConfig.SHOW_BRAND_WATERMARK) {
var rightWatermarkDiv
= $("#welcome_page_header div[class='watermark rightwatermark']");
if(rightWatermarkDiv && rightWatermarkDiv.length > 0) {
rightWatermarkDiv.css({display: 'block'});
rightWatermarkDiv.parent().get(0).href
= interfaceConfig.BRAND_WATERMARK_LINK;
rightWatermarkDiv.get(0).style.backgroundImage
= "url(images/rightwatermark.png)";
}
}
if (interfaceConfig.SHOW_POWERED_BY) {
$("#welcome_page_header>a[class='poweredby']")
.css({display: 'block'});
}
function enter_room()
{
var val = $("#enter_room_field").val();
if(!val) {
val = $("#enter_room_field").attr("room_name");
}
if (val) {
window.location.pathname = "/" + val;
}
}
$("#enter_room_button").click(function()
{
enter_room();
});
$("#enter_room_field").keydown(function (event) {
if (event.keyCode === 13 /* enter */) {
enter_room();
}
});
if (!(interfaceConfig.GENERATE_ROOMNAMES_ON_WELCOME_PAGE === false)){
var updateTimeout;
var animateTimeout;
$("#reload_roomname").click(function () {
clearTimeout(updateTimeout);
clearTimeout(animateTimeout);
update_roomname();
});
$("#reload_roomname").show();
function animate(word) {
var currentVal = $("#enter_room_field").attr("placeholder");
$("#enter_room_field").attr("placeholder", currentVal + word.substr(0, 1));
animateTimeout = setTimeout(function() {
animate(word.substring(1, word.length))
}, 70);
}
function update_roomname()
{
var word = RoomNameGenerator.generateRoomWithoutSeparator();
$("#enter_room_field").attr("room_name", word);
$("#enter_room_field").attr("placeholder", "");
clearTimeout(animateTimeout);
animate(word);
updateTimeout = setTimeout(update_roomname, 10000);
}
update_roomname();
}
$("#disable_welcome").click(function () {
window.localStorage.welcomePageDisabled
= $("#disable_welcome").is(":checked");
});
return;
}
if (interfaceConfig.SHOW_JITSI_WATERMARK) {
var leftWatermarkDiv
= $("#largeVideoContainer div[class='watermark leftwatermark']");
leftWatermarkDiv.css({display: 'block'});
leftWatermarkDiv.parent().get(0).href
= interfaceConfig.JITSI_WATERMARK_LINK;
}
if (interfaceConfig.SHOW_BRAND_WATERMARK) {
var rightWatermarkDiv
= $("#largeVideoContainer div[class='watermark rightwatermark']");
rightWatermarkDiv.css({display: 'block'});
rightWatermarkDiv.parent().get(0).href
= interfaceConfig.BRAND_WATERMARK_LINK;
rightWatermarkDiv.get(0).style.backgroundImage
= "url(images/rightwatermark.png)";
}
if (interfaceConfig.SHOW_POWERED_BY) {
$("#largeVideoContainer>a[class='poweredby']").css({display: 'block'});
}
$("#welcome_page").hide();
Chat.init();
$('body').popover({ selector: '[data-toggle=popover]',
trigger: 'click hover',
content: function() {
return this.getAttribute("content") +
KeyboardShortcut.getShortcut(this.getAttribute("shortcut"));
}
});
statistics.addAudioLevelListener(audioLevelUpdated);
UI.start();
statistics.addConnectionStatsListener(ConnectionQuality.updateLocalStats);
statistics.addRemoteStatsStopListener(ConnectionQuality.stopSendingStats);
statistics.start();
Moderator.init();
// Set the defaults for prompt dialogs.
jQuery.prompt.setDefaults({persistent: false});
// Set default desktop sharing method
setDesktopSharing(config.desktopSharing);
// Initialize Chrome extension inline installs
@ -1318,62 +834,6 @@ $(document).ready(function () {
// By default we use camera
getVideoSize = getCameraVideoSize;
getVideoPosition = getCameraVideoPosition;
VideoLayout.resizeLargeVideoContainer();
$(window).resize(function () {
VideoLayout.resizeLargeVideoContainer();
VideoLayout.positionLarge();
});
// Listen for large video size updates
document.getElementById('largeVideo')
.addEventListener('loadedmetadata', function (e) {
currentVideoWidth = this.videoWidth;
currentVideoHeight = this.videoHeight;
VideoLayout.positionLarge(currentVideoWidth, currentVideoHeight);
});
document.getElementById('largeVideo').volume = 0;
if (!$('#settings').is(':visible')) {
console.log('init');
init();
} else {
loginInfo.onsubmit = function (e) {
if (e.preventDefault) e.preventDefault();
$('#settings').hide();
init();
};
}
toastr.options = {
"closeButton": true,
"debug": false,
"positionClass": "notification-bottom-right",
"onclick": null,
"showDuration": "300",
"hideDuration": "1000",
"timeOut": "2000",
"extendedTimeOut": "1000",
"showEasing": "swing",
"hideEasing": "linear",
"showMethod": "fadeIn",
"hideMethod": "fadeOut",
"reposition": function() {
if(PanelToggler.isVisible()) {
$("#toast-container").addClass("notification-bottom-right-center");
} else {
$("#toast-container").removeClass("notification-bottom-right-center");
}
},
"newestOnTop": false
};
$('#settingsmenu>input').keyup(function(event){
if(event.keyCode === 13) {//enter
SettingsMenu.update();
}
})
});
$(window).bind('beforeunload', function () {
@ -1404,9 +864,7 @@ $(window).bind('beforeunload', function () {
});
function disposeConference(onUnload) {
Toolbar.showAuthenticateButton(false);
UI.onDisposeConference(onUnload);
var handler = getConferenceHandler();
if (handler && handler.peerconnection) {
// FIXME: probably removing streams is not required and close() should
@ -1469,37 +927,6 @@ function buttonClick(id, classname) {
$(id).toggleClass(classname); // add the class to the clicked element
}
/**
* Locks / unlocks the room.
*/
function lockRoom(lock) {
if (lock)
connection.emuc.lockRoom(sharedKey);
else
connection.emuc.lockRoom('');
}
/**
* Sets the shared key.
*/
function setSharedKey(sKey) {
sharedKey = sKey;
}
/**
* Updates the room invite url.
*/
function updateRoomUrl(newRoomUrl) {
roomUrl = newRoomUrl;
// If the invite dialog has been already opened we update the information.
var inviteLink = document.getElementById('inviteLinkRef');
if (inviteLink) {
inviteLink.value = roomUrl;
inviteLink.select();
document.getElementById('jqi_state0_buttonInvite').disabled = false;
}
}
/**
* Warning to the user that the conference window is about to be closed.
@ -1514,19 +941,6 @@ function closePageWarning() {
return "You are about to leave this conversation.";
}
/**
* Resizes and repositions videos in full screen mode.
*/
$(document).on('webkitfullscreenchange mozfullscreenchange fullscreenchange',
function () {
VideoLayout.resizeLargeVideoContainer();
VideoLayout.positionLarge();
isFullScreen = document.fullScreen ||
document.mozFullScreen ||
document.webkitIsFullScreen;
}
);
$(document).bind('error.jingle',
function (event, session, error)
@ -1540,7 +954,7 @@ $(document).bind('fatalError.jingle',
{
sessionTerminated = true;
connection.emuc.doLeave();
messageHandler.showError( "Sorry",
UI.messageHandler.showError( "Sorry",
"Internal application error[setRemoteDescription]");
}
);
@ -1550,7 +964,7 @@ function callSipButtonClicked()
var defaultNumber
= config.defaultSipNumber ? config.defaultSipNumber : '';
messageHandler.openTwoButtonDialog(null,
UI.messageHandler.openTwoButtonDialog(null,
'<h2>Enter SIP number</h2>' +
'<input id="sipNumber" type="text"' +
' value="' + defaultNumber + '" autofocus>',

343
chat.js
View File

@ -1,343 +0,0 @@
/* global $, Util, connection, nickname:true, getVideoSize, getVideoPosition, showToolbar, processReplacements */
/**
* Chat related user interface.
*/
var Chat = (function (my) {
var notificationInterval = false;
var unreadMessages = 0;
/**
* Initializes chat related interface.
*/
my.init = function () {
var storedDisplayName = window.localStorage.displayname;
if (storedDisplayName) {
nickname = storedDisplayName;
Chat.setChatConversationMode(true);
}
$('#nickinput').keydown(function (event) {
if (event.keyCode === 13) {
event.preventDefault();
var val = Util.escapeHtml(this.value);
this.value = '';
if (!nickname) {
nickname = val;
window.localStorage.displayname = nickname;
connection.emuc.addDisplayNameToPresence(nickname);
connection.emuc.sendPresence();
Chat.setChatConversationMode(true);
return;
}
}
});
$('#usermsg').keydown(function (event) {
if (event.keyCode === 13) {
event.preventDefault();
var value = this.value;
$('#usermsg').val('').trigger('autosize.resize');
this.focus();
var command = new CommandsProcessor(value);
if(command.isCommand())
{
command.processCommand();
}
else
{
var message = Util.escapeHtml(value);
connection.emuc.sendMessage(message, nickname);
}
}
});
var onTextAreaResize = function () {
resizeChatConversation();
Chat.scrollChatToBottom();
};
$('#usermsg').autosize({callback: onTextAreaResize});
$("#chatspace").bind("shown",
function () {
unreadMessages = 0;
setVisualNotification(false);
});
addSmileys();
};
/**
* Appends the given message to the chat conversation.
*/
my.updateChatConversation = function (from, displayName, message) {
var divClassName = '';
if (connection.emuc.myroomjid === from) {
divClassName = "localuser";
}
else {
divClassName = "remoteuser";
if (!Chat.isVisible()) {
unreadMessages++;
Util.playSoundNotification('chatNotification');
setVisualNotification(true);
}
}
//replace links and smileys
var escMessage = message.replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\n/g, '<br/>'); //Strophe already escapes special symbols on sending, so we escape here only tags to avoid double &amp;
var escDisplayName = Util.escapeHtml(displayName);
message = processReplacements(escMessage);
var messageContainer =
'<div class="chatmessage">'+
'<img src="../images/chatArrow.svg" class="chatArrow">' +
'<div class="username ' + divClassName +'">' + escDisplayName + '</div>' +
'<div class="timestamp">' + getCurrentTime() + '</div>' +
'<div class="usermessage">' + message + '</div>' +
'</div>';
$('#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)
{
errorMessage = Util.escapeHtml(errorMessage);
originalText = Util.escapeHtml(originalText);
$('#chatconversation').append('<div class="errorMessage"><b>Error: </b>'
+ 'Your message' + (originalText? (' \"'+ originalText + '\"') : "")
+ ' was not sent.' + (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)
subject = subject.trim();
$('#subject').html(linkify(Util.escapeHtml(subject)));
if(subject == "")
{
$("#subject").css({display: "none"});
}
else
{
$("#subject").css({display: "block"});
}
};
/**
* Sets the chat conversation mode.
*/
my.setChatConversationMode = function (isConversationMode) {
if (isConversationMode) {
$('#nickname').css({visibility: 'hidden'});
$('#chatconversation').css({visibility: 'visible'});
$('#usermsg').css({visibility: 'visible'});
$('#smileysarea').css({visibility: 'visible'});
$('#usermsg').focus();
}
};
/**
* Resizes the chat area.
*/
my.resizeChat = function () {
var chatSize = PanelToggler.getPanelSize();
$('#chatspace').width(chatSize[0]);
$('#chatspace').height(chatSize[1]);
resizeChatConversation();
};
/**
* Indicates if the chat is currently visible.
*/
my.isVisible = function () {
return $('#chatspace').is(":visible");
};
/**
* Shows and hides the window with the smileys
*/
my.toggleSmileys = function() {
var smileys = $('#smileysContainer');
if(!smileys.is(':visible')) {
smileys.show("slide", { direction: "down", duration: 300});
} else {
smileys.hide("slide", { direction: "down", duration: 300});
}
$('#usermsg').focus();
};
/**
* Scrolls chat to the bottom.
*/
my.scrollChatToBottom = function() {
setTimeout(function () {
$('#chatconversation').scrollTop(
$('#chatconversation')[0].scrollHeight);
}, 5);
};
/**
* Adds the smileys container to the chat
*/
function addSmileys() {
var smileysContainer = document.createElement('div');
smileysContainer.id = 'smileysContainer';
function addClickFunction(smiley, number) {
smiley.onclick = function addSmileyToMessage() {
var usermsg = $('#usermsg');
var message = usermsg.val();
message += smileys['smiley' + number];
usermsg.val(message);
usermsg.get(0).setSelectionRange(message.length, message.length);
Chat.toggleSmileys();
usermsg.focus();
};
}
for(var i = 1; i <= 21; i++) {
var smileyContainer = document.createElement('div');
smileyContainer.id = 'smiley' + i;
smileyContainer.className = 'smileyContainer';
var smiley = document.createElement('img');
smiley.src = 'images/smileys/smiley' + i + '.svg';
smiley.className = 'smiley';
addClickFunction(smiley, i);
smileyContainer.appendChild(smiley);
smileysContainer.appendChild(smileyContainer);
}
$("#chatspace").append(smileysContainer);
}
/**
* Resizes the chat conversation.
*/
function resizeChatConversation() {
var msgareaHeight = $('#usermsg').outerHeight();
var chatspace = $('#chatspace');
var width = chatspace.width();
var chat = $('#chatconversation');
var smileys = $('#smileysarea');
smileys.height(msgareaHeight);
$("#smileys").css('bottom', (msgareaHeight - 26) / 2);
$('#smileysContainer').css('bottom', msgareaHeight);
chat.width(width - 10);
chat.height(window.innerHeight - 15 - msgareaHeight);
}
/**
* Shows/hides a visual notification, indicating that a message has arrived.
*/
function setVisualNotification(show) {
var unreadMsgElement = document.getElementById('unreadMessages');
var unreadMsgBottomElement = document.getElementById('bottomUnreadMessages');
var glower = $('#chatButton');
var bottomGlower = $('#chatBottomButton');
if (unreadMessages) {
unreadMsgElement.innerHTML = unreadMessages.toString();
unreadMsgBottomElement.innerHTML = unreadMessages.toString();
ToolbarToggler.dockToolbar(true);
var chatButtonElement
= document.getElementById('chatButton').parentNode;
var leftIndent = (Util.getTextWidth(chatButtonElement) -
Util.getTextWidth(unreadMsgElement)) / 2;
var topIndent = (Util.getTextHeight(chatButtonElement) -
Util.getTextHeight(unreadMsgElement)) / 2 - 3;
unreadMsgElement.setAttribute(
'style',
'top:' + topIndent +
'; left:' + leftIndent + ';');
var chatBottomButtonElement
= document.getElementById('chatBottomButton').parentNode;
var bottomLeftIndent = (Util.getTextWidth(chatBottomButtonElement) -
Util.getTextWidth(unreadMsgBottomElement)) / 2;
var bottomTopIndent = (Util.getTextHeight(chatBottomButtonElement) -
Util.getTextHeight(unreadMsgBottomElement)) / 2 - 2;
unreadMsgBottomElement.setAttribute(
'style',
'top:' + bottomTopIndent +
'; left:' + bottomLeftIndent + ';');
if (!glower.hasClass('icon-chat-simple')) {
glower.removeClass('icon-chat');
glower.addClass('icon-chat-simple');
}
}
else {
unreadMsgElement.innerHTML = '';
unreadMsgBottomElement.innerHTML = '';
glower.removeClass('icon-chat-simple');
glower.addClass('icon-chat');
}
if (show && !notificationInterval) {
notificationInterval = window.setInterval(function () {
glower.toggleClass('active');
bottomGlower.toggleClass('active glowing');
}, 800);
}
else if (!show && notificationInterval) {
window.clearInterval(notificationInterval);
notificationInterval = false;
glower.removeClass('active');
bottomGlower.removeClass('glowing');
bottomGlower.addClass('active');
}
}
/**
* Returns the current time in the format it is shown to the user
* @returns {string}
*/
function getCurrentTime() {
var now = new Date();
var hour = now.getHours();
var minute = now.getMinutes();
var second = now.getSeconds();
if(hour.toString().length === 1) {
hour = '0'+hour;
}
if(minute.toString().length === 1) {
minute = '0'+minute;
}
if(second.toString().length === 1) {
second = '0'+second;
}
return hour+':'+minute+':'+second;
}
return my;
}(Chat || {}));

View File

@ -1,98 +0,0 @@
/**
* Handles commands received via chat messages.
*/
var CommandsProcessor = (function()
{
/**
* Constructs new CommandProccessor instance from a message.
* @param message the message
* @constructor
*/
function CommandsPrototype(message)
{
/**
* Extracts the command from the message.
* @param message the received message
* @returns {string} the command
*/
function getCommand(message)
{
if(message)
{
for(var command in commands)
{
if(message.indexOf("/" + command) == 0)
return command;
}
}
return "";
};
var command = getCommand(message);
/**
* Returns the name of the command.
* @returns {String} the command
*/
this.getCommand = function()
{
return command;
}
var messageArgument = message.substr(command.length + 2);
/**
* Returns the arguments of the command.
* @returns {string}
*/
this.getArgument = function()
{
return messageArgument;
}
}
/**
* Checks whether this instance is valid command or not.
* @returns {boolean}
*/
CommandsPrototype.prototype.isCommand = function()
{
if(this.getCommand())
return true;
return false;
}
/**
* Processes the command.
*/
CommandsPrototype.prototype.processCommand = function()
{
if(!this.isCommand())
return;
commands[this.getCommand()](this.getArgument());
}
/**
* Processes the data for topic command.
* @param commandArguments the arguments of the topic command.
*/
var processTopic = function(commandArguments)
{
var topic = Util.escapeHtml(commandArguments);
connection.emuc.setSubject(topic);
}
/**
* 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 = {
"topic" : processTopic
};
return CommandsPrototype;
})();

View File

@ -32,7 +32,7 @@ var ConnectionQuality = (function () {
*/
ConnectionQuality.updateLocalStats = function (data) {
stats = data;
VideoLayout.updateLocalConnectionStats(100 - stats.packetLoss.total,stats);
UI.updateLocalConnectionStats(100 - stats.packetLoss.total,stats);
if(sendIntervalId == null)
{
startSendingStats();
@ -97,12 +97,12 @@ var ConnectionQuality = (function () {
ConnectionQuality.updateRemoteStats = function (jid, data) {
if(data == null || data.packetLoss_total == null)
{
VideoLayout.updateConnectionStats(jid, null, null);
UI.updateConnectionStats(jid, null, null);
return;
}
remoteStats[jid] = parseMUCStats(data);
VideoLayout.updateConnectionStats(jid, 100 - data.packetLoss_total,remoteStats[jid]);
UI.updateConnectionStats(jid, 100 - data.packetLoss_total,remoteStats[jid]);
};
@ -113,7 +113,7 @@ var ConnectionQuality = (function () {
clearInterval(sendIntervalId);
sendIntervalId = null;
//notify UI about stopping statistics gathering
VideoLayout.onStatsStop();
UI.onStatsStop();
};
/**

View File

@ -1,4 +1,4 @@
/* global $, alert, changeLocalVideo, chrome, config, connection, getConferenceHandler, getUserMediaWithConstraints, VideoLayout */
/* global $, alert, changeLocalVideo, chrome, config, connection, getConferenceHandler, getUserMediaWithConstraints */
/**
* Indicates that desktop stream is currently in use(for toggle purpose).
* @type {boolean}
@ -86,7 +86,7 @@ function isUpdateRequired(minVersion, extVersion)
catch (e)
{
console.error("Failed to parse extension version", e);
messageHandler.showError('Error',
UI.messageHandler.showError('Error',
'Error when trying to detect desktopsharing extension.');
return true;
}
@ -168,7 +168,7 @@ function obtainScreenFromExtension(streamCallback, failCallback) {
function (arg) {
console.log("Failed to install the extension", arg);
failCallback(arg);
messageHandler.showError('Error',
UI.messageHandler.showError('Error',
'Failed to install desktop sharing extension');
}
);
@ -247,7 +247,7 @@ function streamSwitchDone() {
//window.setTimeout(
// function () {
switchInProgress = false;
Toolbar.changeDesktopSharingButtonState(isUsingScreenStream);
UI.changeDesktopSharingButtonState(isUsingScreenStream);
// }, 100
//);
}
@ -258,7 +258,7 @@ function newStreamCreated(stream) {
connection.jingle.localVideo = stream;
VideoLayout.changeLocalVideo(stream, !isUsingScreenStream);
UI.changeLocalVideo(stream, !isUsingScreenStream);
var conferenceHandler = getConferenceHandler();
if (conferenceHandler) {
@ -267,7 +267,7 @@ function newStreamCreated(stream) {
} else {
// We are done immediately
console.error("No conference handler");
messageHandler.showError('Error',
UI.messageHandler.showError('Error',
'Unable to switch video stream.');
streamSwitchDone();
}

View File

@ -1,206 +0,0 @@
/* global $, config, connection, dockToolbar, Moderator, Prezi,
setLargeVideoVisible, ToolbarToggler, Util, VideoLayout */
var Etherpad = (function (my) {
var etherpadName = null;
var etherpadIFrame = null;
var domain = null;
var options = "?showControls=true&showChat=false&showLineNumbers=true&useMonospaceFont=false";
/**
* Initializes the etherpad.
*/
my.init = function (name) {
if (config.etherpad_base && !etherpadName) {
domain = config.etherpad_base;
if (!name) {
// In case we're the focus we generate the name.
etherpadName = Math.random().toString(36).substring(7) +
'_' + (new Date().getTime()).toString();
shareEtherpad();
}
else
etherpadName = name;
enableEtherpadButton();
}
};
/**
* Opens/hides the Etherpad.
*/
my.toggleEtherpad = function (isPresentation) {
if (!etherpadIFrame)
createIFrame();
var largeVideo = null;
if (Prezi.isPresentationVisible())
largeVideo = $('#presentation>iframe');
else
largeVideo = $('#largeVideo');
if ($('#etherpad>iframe').css('visibility') === 'hidden') {
$('#activeSpeaker').css('visibility', 'hidden');
largeVideo.fadeOut(300, function () {
if (Prezi.isPresentationVisible()) {
largeVideo.css({opacity: '0'});
} else {
VideoLayout.setLargeVideoVisible(false);
}
});
$('#etherpad>iframe').fadeIn(300, function () {
document.body.style.background = '#eeeeee';
$('#etherpad>iframe').css({visibility: 'visible'});
$('#etherpad').css({zIndex: 2});
});
}
else if ($('#etherpad>iframe')) {
$('#etherpad>iframe').fadeOut(300, function () {
$('#etherpad>iframe').css({visibility: 'hidden'});
$('#etherpad').css({zIndex: 0});
document.body.style.background = 'black';
});
if (!isPresentation) {
$('#largeVideo').fadeIn(300, function () {
VideoLayout.setLargeVideoVisible(true);
});
}
}
resize();
};
my.isVisible = function() {
var etherpadIframe = $('#etherpad>iframe');
return etherpadIframe && etherpadIframe.is(':visible');
};
/**
* Resizes the etherpad.
*/
function resize() {
if ($('#etherpad>iframe').length) {
var remoteVideos = $('#remoteVideos');
var availableHeight
= window.innerHeight - remoteVideos.outerHeight();
var availableWidth = Util.getAvailableVideoWidth();
$('#etherpad>iframe').width(availableWidth);
$('#etherpad>iframe').height(availableHeight);
}
}
/**
* Shares the Etherpad name with other participants.
*/
function shareEtherpad() {
connection.emuc.addEtherpadToPresence(etherpadName);
connection.emuc.sendPresence();
}
/**
* Creates the Etherpad button and adds it to the toolbar.
*/
function enableEtherpadButton() {
if (!$('#etherpadButton').is(":visible"))
$('#etherpadButton').css({display: 'inline-block'});
}
/**
* Creates the IFrame for the etherpad.
*/
function createIFrame() {
etherpadIFrame = document.createElement('iframe');
etherpadIFrame.src = domain + etherpadName + options;
etherpadIFrame.frameBorder = 0;
etherpadIFrame.scrolling = "no";
etherpadIFrame.width = $('#largeVideoContainer').width() || 640;
etherpadIFrame.height = $('#largeVideoContainer').height() || 480;
etherpadIFrame.setAttribute('style', 'visibility: hidden;');
document.getElementById('etherpad').appendChild(etherpadIFrame);
etherpadIFrame.onload = function() {
document.domain = document.domain;
bubbleIframeMouseMove(etherpadIFrame);
setTimeout(function() {
//the iframes inside of the etherpad are not yet loaded when the etherpad iframe is loaded
var outer = etherpadIFrame.contentDocument.getElementsByName("ace_outer")[0];
bubbleIframeMouseMove(outer);
var inner = outer.contentDocument.getElementsByName("ace_inner")[0];
bubbleIframeMouseMove(inner);
}, 2000);
};
}
function bubbleIframeMouseMove(iframe){
var existingOnMouseMove = iframe.contentWindow.onmousemove;
iframe.contentWindow.onmousemove = function(e){
if(existingOnMouseMove) existingOnMouseMove(e);
var evt = document.createEvent("MouseEvents");
var boundingClientRect = iframe.getBoundingClientRect();
evt.initMouseEvent(
"mousemove",
true, // bubbles
false, // not cancelable
window,
e.detail,
e.screenX,
e.screenY,
e.clientX + boundingClientRect.left,
e.clientY + boundingClientRect.top,
e.ctrlKey,
e.altKey,
e.shiftKey,
e.metaKey,
e.button,
null // no related element
);
iframe.dispatchEvent(evt);
};
}
/**
* On Etherpad added to muc.
*/
$(document).bind('etherpadadded.muc', function (event, jid, etherpadName) {
console.log("Etherpad added", etherpadName);
if (config.etherpad_base && !Moderator.isModerator()) {
Etherpad.init(etherpadName);
}
});
/**
* On focus changed event.
*/
// FIXME: there is no such event as 'focusechanged.muc'
$(document).bind('focusechanged.muc', function (event, focus) {
console.log("Focus changed");
if (config.etherpad_base)
shareEtherpad();
});
/**
* On video selected event.
*/
$(document).bind('video.selected', function (event, isPresentation) {
if (!config.etherpad_base)
return;
if (etherpadIFrame && etherpadIFrame.style.visibility !== 'hidden')
Etherpad.toggleEtherpad(isPresentation);
});
/**
* Resizes the etherpad, when the window is resized.
*/
$(window).resize(function () {
resize();
});
return my;
}(Etherpad || {}));

View File

@ -31,44 +31,24 @@
<script src="libs/pako.bundle.js?v=1"></script><!-- zlib deflate -->
<script src="libs/toastr.js?v=1"></script><!-- notifications lib -->
<script src="interface_config.js?v=5"></script>
<script src="service/RTC/RTCBrowserType.js?v=1"></script>
<script src="service/RTC/StreamEventTypes.js?v=1"></script>
<script src="service/RTC/MediaStreamTypes.js?v=1"></script>
<script src="libs/modules/UI.bundle.js?v=1"></script>
<script src="libs/modules/statistics.bundle.js?v=1"></script>
<script src="libs/modules/RTC.bundle.js?v=1"></script>
<script src="muc.js?v=17"></script><!-- simple MUC library -->
<script src="estos_log.js?v=2"></script><!-- simple stanza logger -->
<script src="desktopsharing.js?v=3"></script><!-- desktop sharing -->
<script src="app.js?v=22"></script><!-- application logic -->
<script src="commands.js?v=1"></script><!-- application logic -->
<script src="chat.js?v=15"></script><!-- chat logic -->
<script src="contact_list.js?v=8"></script><!-- contact list logic -->
<script src="side_panel_toggler.js?v=1"></script>
<script src="util.js?v=7"></script><!-- utility functions -->
<script src="etherpad.js?v=10"></script><!-- etherpad plugin -->
<script src="prezi.js?v=7"></script><!-- prezi plugin -->
<script src="smileys.js?v=3"></script><!-- smiley images -->
<script src="replacement.js?v=7"></script><!-- link and smiley replacement -->
<script src="moderatemuc.js?v=4"></script><!-- moderator plugin -->
<script src="analytics.js?v=1"></script><!-- google analytics plugin -->
<script src="videolayout.js?v=31"></script><!-- video ui -->
<script src="connectionquality.js?v=1"></script>
<script src="toolbar.js?v=7"></script><!-- toolbar ui -->
<script src="toolbar_toggler.js?v=2"></script>
<script src="canvas_util.js?v=1"></script><!-- canvas drawing utils -->
<script src="audio_levels.js?v=4"></script><!-- audio levels plugin -->
<script src="media_stream.js?v=2"></script><!-- media stream -->
<script src="bottom_toolbar.js?v=6"></script><!-- media stream -->
<script src="moderator.js?v=2"></script><!-- media stream -->
<script src="roomname_generator.js?v=1"></script><!-- generator for random room names -->
<script src="keyboard_shortcut.js?v=3"></script>
<script src="recording.js?v=1"></script>
<script src="tracking.js?v=1"></script><!-- tracking -->
<script src="jitsipopover.js?v=3"></script>
<script src="message_handler.js?v=2"></script>
<script src="api_connector.js?v=2"></script>
<script src="settings_menu.js?v=1"></script>
<script src="service/RTC/RTCBrowserType.js?v=1"></script>
<script src="service/RTC/StreamEventTypes.js?v=1"></script>
<script src="service/RTC/MediaStreamTypes.js?v=1"></script>
<script src="libs/modules/statistics.bundle.js?v=1"></script>
<script src="libs/modules/RTC.bundle.js?v=1"></script>
<script src="avatar.js?v=4"></script><!-- avatars -->
<script src="keyboard_shortcut.js?v=1"></script>
<link rel="stylesheet" href="css/font.css?v=6"/>
<link rel="stylesheet" href="css/toastr.css?v=1">
<link rel="stylesheet" type="text/css" media="screen" href="css/main.css?v=30"/>
@ -89,7 +69,6 @@
<link rel="chrome-webstore-item" href="https://chrome.google.com/webstore/detail/diibjkoicjeejcmhdnailmkgecihlobk">
<script src="libs/jquery-impromptu.js"></script>
<script src="libs/jquery.autosize.js"></script>
<script src="libs/prezi_player.js?v=2"></script>
</head>
<body>
<div id="welcome_page">
@ -179,36 +158,36 @@
<div style="position: relative;" id="header_container">
<div id="header">
<span id="toolbar">
<a class="button" data-container="body" data-toggle="popover" data-placement="bottom" shortcut="mutePopover" content="Mute / Unmute" onclick='toggleAudio();'>
<a class="button" id="toolbar_button_mute" data-container="body" data-toggle="popover" data-placement="bottom" shortcut="mutePopover" content="Mute / Unmute">
<i id="mute" class="icon-microphone"></i>
</a>
<div class="header_button_separator"></div>
<a class="button" data-container="body" data-toggle="popover" data-placement="bottom" shortcut="toggleVideoPopover" content="Start / stop camera" onclick='toggleVideo();'>
<a class="button" id="toolbar_button_camera" data-container="body" data-toggle="popover" data-placement="bottom" shortcut="toggleVideoPopover" content="Start / stop camera" onclick='toggleVideo();'>
<i id="video" class="icon-camera"></i>
</a>
<span id="authentication" style="display: none">
<div class="header_button_separator"></div>
<a class="button" data-container="body" data-toggle="popover" data-placement="bottom" content="Authenticate" onclick='authenticateClicked();'>
<a class="button" id="toolbar_button_authentication" data-container="body" data-toggle="popover" data-placement="bottom" content="Authenticate">
<i id="authButton" class="icon-avatar"></i>
</a>
</span>
<span id="recording" style="display: none">
<div class="header_button_separator"></div>
<a class="button" data-container="body" data-toggle="popover" data-placement="bottom" content="Record" onclick='toggleRecording();'>
<a class="button" id="toolbar_button_record" data-container="body" data-toggle="popover" data-placement="bottom" content="Record">
<i id="recordButton" class="icon-recEnable"></i>
</a>
</span>
<div class="header_button_separator"></div>
<a class="button" data-container="body" data-toggle="popover" data-placement="bottom" content="Lock / unlock room" onclick="Toolbar.openLockDialog();">
<a class="button" id="toolbar_button_security" data-container="body" data-toggle="popover" data-placement="bottom" content="Lock / unlock room">
<i id="lockIcon" class="icon-security"></i>
</a>
<div class="header_button_separator"></div>
<a class="button" data-container="body" data-toggle="popover" data-placement="bottom" content="Invite others" onclick="Toolbar.openLinkDialog();">
<a class="button" id="toolbar_button_link" data-container="body" data-toggle="popover" data-placement="bottom" content="Invite others">
<i class="icon-link"></i>
</a>
<div class="header_button_separator"></div>
<span class="toolbar_span">
<a class="button" data-container="body" data-toggle="popover" shortcut="toggleChatPopover" data-placement="bottom" content="Open / close chat" onclick='BottomToolbar.toggleChat();'>
<a class="button" id="toolbar_button_chat" data-container="body" data-toggle="popover" shortcut="toggleChatPopover" data-placement="bottom" content="Open / close chat">
<i id="chatButton" class="icon-chat">
<span id="unreadMessages"></span>
</i>
@ -216,38 +195,38 @@
</span>
<span id="prezi_button">
<div class="header_button_separator"></div>
<a class="button" data-container="body" data-toggle="popover" data-placement="bottom" content="Share Prezi" onclick='Prezi.openPreziDialog();'>
<a class="button" id="toolbar_button_prezi" data-container="body" data-toggle="popover" data-placement="bottom" content="Share Prezi">
<i class="icon-prezi"></i>
</a>
</span>
<span id="etherpadButton">
<div class="header_button_separator"></div>
<a class="button" data-container="body" data-toggle="popover" data-placement="bottom" content="Shared document" onclick='Etherpad.toggleEtherpad(0);'>
<a class="button" id="toolbar_button_etherpad" data-container="body" data-toggle="popover" data-placement="bottom" content="Shared document">
<i class="icon-share-doc"></i>
</a>
</span>
<div class="header_button_separator"></div>
<span id="desktopsharing" style="display: none">
<a class="button" data-container="body" data-toggle="popover" data-placement="bottom" content="Share screen" onclick="toggleScreenSharing();">
<a class="button" id="toolbar_button_desktopsharing" data-container="body" data-toggle="popover" data-placement="bottom" content="Share screen">
<i class="icon-share-desktop"></i>
</a>
</span>
<div class="header_button_separator"></div>
<a class="button" data-container="body" data-toggle="popover" data-placement="bottom" content="Enter / Exit Full Screen" onclick='buttonClick("#fullScreen", "icon-full-screen icon-exit-full-screen");Toolbar.toggleFullScreen();'>
<a class="button" id="toolbar_button_fullScreen" data-container="body" data-toggle="popover" data-placement="bottom" content="Enter / Exit Full Screen">
<i id="fullScreen" class="icon-full-screen"></i>
</a>
<span id="sipCallButton" style="display: none">
<div class="header_button_separator"></div>
<a class="button" data-container="body" data-toggle="popover" data-placement="bottom" content="Call SIP number" onclick='callSipButtonClicked();'>
<a class="button" id="toolbar_button_sip" data-container="body" data-toggle="popover" data-placement="bottom" content="Call SIP number">
<i class="icon-telephone"></i></a>
</span>
<div class="header_button_separator"></div>
<a class="button" data-container="body" data-toggle="popover" data-placement="bottom" content="Settings" onclick='PanelToggler.toggleSettingsMenu();'>
<a class="button" id="toolbar_button_settings" data-container="body" data-toggle="popover" data-placement="bottom" content="Settings" >
<i id="settingsButton" class="icon-settings"></i>
</a>
<div class="header_button_separator"></div>
<span id="hangup">
<a class="button" data-container="body" data-toggle="popover" data-placement="bottom" content="Hang Up" onclick='hangup();'>
<a class="button" id="toolbar_button_hangup" data-container="body" data-toggle="popover" data-placement="bottom" content="Hang Up">
<i class="icon-hangup" style="color:#ff0000;font-size: 1.4em;"></i>
</a>
</span>
@ -264,8 +243,8 @@
<input id="connect" type="submit" value="Connect" />
</form>
</div>
<div id="reloadPresentation"><a onclick='Prezi.reloadPresentation();'><i title="Reload Prezi" class="fa fa-repeat fa-lg"></i></a></div>
<div id="videospace" onmousemove="ToolbarToggler.showToolbar();">
<div id="reloadPresentation"><a id="reloadPresentationLink"><i title="Reload Prezi" class="fa fa-repeat fa-lg"></i></a></div>
<div id="videospace">
<div id="largeVideoContainer" class="videocontainer">
<div id="presentation"></div>
<div id="etherpad"></div>
@ -297,7 +276,7 @@
</div>
<span id="bottomToolbar">
<span class="bottomToolbar_span">
<a class="bottomToolbarButton" data-container="body" data-toggle="popover" shortcut="toggleChatPopover" data-placement="top" content="Open / close chat" onclick='BottomToolbar.toggleChat();'>
<a class="bottomToolbarButton" id="bottom_toolbar_chat" data-container="body" data-toggle="popover" shortcut="toggleChatPopover" data-placement="top" content="Open / close chat">
<i id="chatBottomButton" class="icon-chat-simple">
<span id="bottomUnreadMessages"></span>
</i>
@ -305,7 +284,7 @@
</span>
<div class="bottom_button_separator"></div>
<span class="bottomToolbar_span">
<a class="bottomToolbarButton" data-container="body" data-toggle="popover" data-placement="top" id="contactlistpopover" content="Open / close contact list" onclick='BottomToolbar.toggleContactList();'>
<a class="bottomToolbarButton" id="bottom_toolbar_contact_list" data-container="body" data-toggle="popover" data-placement="top" id="contactlistpopover" content="Open / close contact list">
<i id="contactListButton" class="icon-contactList">
<span id="numberOfParticipants"></span>
</i>
@ -313,7 +292,7 @@
</span>
<div class="bottom_button_separator"></div>
<span class="bottomToolbar_span">
<a class="bottomToolbarButton" data-container="body" data-toggle="popover" shortcut="filmstripPopover" data-placement="top" content="Show / hide film strip" onclick='BottomToolbar.toggleFilmStrip()'>
<a class="bottomToolbarButton" id="bottom_toolbar_film_strip" data-container="body" data-toggle="popover" shortcut="filmstripPopover" data-placement="top" content="Show / hide film strip">
<i id="filmStripButton" class="icon-filmstrip"></i>
</a>
</span>
@ -332,7 +311,7 @@
<audio id="chatNotification" src="sounds/incomingMessage.wav" preload="auto"></audio>
<textarea id="usermsg" placeholder='Enter text...' autofocus></textarea>
<div id="smileysarea">
<div id="smileys" onclick="Chat.toggleSmileys()">
<div id="smileys" id="toggle_smileys">
<img src="images/smile.svg"/>
</div>
</div>
@ -348,7 +327,7 @@
<div class="arrow-up"></div>
<input type="text" id="setDisplayName" placeholder="Name">
<input type="text" id="setEmail" placeholder="E-Mail">
<button onclick="SettingsMenu.update()" id="updateSettings">Update</button>
<button id="updateSettings">Update</button>
</div>
<a id="downloadlog" onclick='dump(event.target);' data-container="body" data-toggle="popover" data-placement="right" data-content="Download logs" ><i class="fa fa-cloud-download"></i></a>
</div>

View File

@ -4,12 +4,12 @@ var KeyboardShortcut = (function(my) {
67: {
character: "C",
id: "toggleChatPopover",
function: BottomToolbar.toggleChat
function: UI.toggleChat
},
70: {
character: "F",
id: "filmstripPopover",
function: BottomToolbar.toggleFilmStrip
function: UI.toggleFilmStrip
},
77: {
character: "M",
@ -45,7 +45,7 @@ var KeyboardShortcut = (function(my) {
}
//esc while the smileys are visible hides them
} else if (keycode === 27 && $('#smileysContainer').is(':visible')) {
Chat.toggleSmileys();
UI.toggleSmileys();
}
};

View File

@ -92,6 +92,12 @@ function ColibriFocus(connection, bridgejid) {
this.endpointsInfo = null;
}
function conferenceCreated(focus)
{
statistics.onConfereceCreated(getConferenceHandler());
RTC.onConfereceCreated(focus);
}
// creates a conferences with an initial set of peers
ColibriFocus.prototype.makeConference = function (peers, errorCallback) {
var self = this;
@ -411,7 +417,7 @@ ColibriFocus.prototype.createdConference = function (result) {
console.log('remote channels', this.channels);
// Notify that the focus has created the conference on the bridge
$(document).trigger('conferenceCreated.jingle', [self]);
conferenceCreated(self);
var bridgeSDP = new SDP(
'v=0\r\n' +
@ -561,8 +567,7 @@ ColibriFocus.prototype.createdConference = function (result) {
}
// Notify we've created the conference
$(document).trigger(
'conferenceCreated.jingle', self);
conferenceCreated(self);
},
function (error) {
console.warn('setLocalDescription failed.', error);

File diff suppressed because one or more lines are too long

6397
libs/modules/UI.bundle.js Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,4 +1,23 @@
/* jshint -W117 */
function CallIncomingJingle(sid) {
var sess = connection.jingle.sessions[sid];
// TODO: do we check activecall == null?
activecall = sess;
statistics.onConferenceCreated(sess);
RTC.onConferenceCreated(sess);
// TODO: check affiliation and/or role
console.log('emuc data for', sess.peerjid, connection.emuc.members[sess.peerjid]);
sess.usedrip = true; // not-so-naive trickle ice
sess.sendAnswer();
sess.accept();
};
Strophe.addConnectionPlugin('jingle', {
connection: null,
sessions: {},
@ -110,7 +129,7 @@ Strophe.addConnectionPlugin('jingle', {
// the callback should either
// .sendAnswer and .accept
// or .sendTerminate -- not necessarily synchronus
$(document).trigger('callincoming.jingle', [sess.sid]);
CallIncomingJingle(sess.sid);
break;
case 'session-accept':
sess.setRemoteDescription($(iq).find('>jingle'), 'answer');

View File

@ -1,4 +1,4 @@
/* global $, $iq, config, connection, focusMucJid, forceMuted, messageHandler,
/* global $, $iq, config, connection, focusMucJid, forceMuted,
setAudioMuted, Strophe, toggleAudio */
/**
* Moderate connection plugin.
@ -32,10 +32,6 @@ Strophe.addConnectionPlugin('moderate', {
},
function (error) {
console.log('set mute error', error);
// FIXME: this causes an exception
//messageHandler.openReportDialog(null, 'Failed to mute ' +
// $("#participant_" + jid).find(".displayname").text() ||
//"participant" + '.', error);
});
},
onMute: function (iq) {

View File

@ -1,5 +1,5 @@
/* global $, $iq, config, connection, Etherpad, hangUp, messageHandler,
roomName, sessionTerminated, Strophe, Toolbar, Util, VideoLayout */
roomName, sessionTerminated, Strophe, Util */
/**
* Contains logic responsible for enabling/disabling functionality available
* only to moderator users.
@ -13,43 +13,24 @@ var Moderator = (function (my) {
var externalAuthEnabled = false;
my.isModerator = function () {
return connection.emuc.isModerator();
return connection && connection.emuc.isModerator();
};
my.isPeerModerator = function (peerJid) {
return connection.emuc.getMemberRole(peerJid) === 'moderator';
return connection && connection.emuc.getMemberRole(peerJid) === 'moderator';
};
my.isExternalAuthEnabled = function () {
return externalAuthEnabled;
};
my.onModeratorStatusChanged = function (isModerator) {
Toolbar.showSipCallButton(isModerator);
Toolbar.showRecordingButton(
isModerator); //&&
// FIXME:
// Recording visible if
// there are at least 2(+ 1 focus) participants
//Object.keys(connection.emuc.members).length >= 3);
if (isModerator && config.etherpad_base) {
Etherpad.init();
}
my.init = function () {
Moderator.onLocalRoleChange = function (from, member, pres) {
UI.onModeratorStatusChanged(Moderator.isModerator());
};
};
my.init = function () {
$(document).bind(
'local.role.changed.muc',
function (event, jid, info, pres) {
Moderator.onModeratorStatusChanged(Moderator.isModerator());
}
);
$(document).bind(
'left.muc',
function (event, jid) {
my.onMucLeft = function (jid) {
console.info("Someone left is it focus ? " + jid);
var resource = Strophe.getResourceFromJid(jid);
if (resource === 'focus' && !sessionTerminated) {
@ -61,8 +42,6 @@ var Moderator = (function (my) {
location.reload();
}
}
);
};
my.setFocusUserJid = function (focusJid) {
if (!focusUserJid) {
@ -185,13 +164,13 @@ var Moderator = (function (my) {
// Not authorized to create new room
if ($(error).find('>error>not-authorized').length) {
console.warn("Unauthorized to start the conference");
$(document).trigger('auth_required.moderator');
UI.onAuthenticationRequired();
return;
}
var waitMs = getNextErrorTimeout();
console.error("Focus error, retry after " + waitMs, error);
// Show message
messageHandler.notify(
UI.messageHandler.notify(
'Conference focus', 'disconnected',
Moderator.getFocusComponent() +
' not available - retry in ' + (waitMs / 1000) + ' sec');

View File

@ -32,7 +32,7 @@ var DataChannels =
// selections so that it can do adaptive simulcast,
// we want the notification to trigger even if userJid is undefined,
// or null.
var userJid = VideoLayout.getLargeVideoState().userJid;
var userJid = UI.getLargeVideoState().userJid;
// we want the notification to trigger even if userJid is undefined,
// or null.
onSelectedEndpointChanged(userJid);

View File

@ -245,7 +245,7 @@ RTCUtils.prototype.getUserMediaWithConstraints = function(
});
} else {
RTCUtils.getUserMedia(constraints,
this.getUserMedia(constraints,
function (stream) {
console.log('onUserMediaSuccess');
success_callback(stream);
@ -296,7 +296,7 @@ RTCUtils.prototype.obtainAudioAndVideoPermissions = function() {
media: error.media || 'video',
name : error.name
});
messageHandler.showError("Error",
UI.messageHandler.showError("Error",
"Failed to obtain permissions to use the local microphone" +
"and/or camera.");
}

545
modules/UI/UI.js Normal file
View File

@ -0,0 +1,545 @@
var UI = {};
var VideoLayout = require("./videolayout/VideoLayout.js");
var AudioLevels = require("./audio_levels/AudioLevels.js");
var Prezi = require("./prezi/Prezi.js");
var Etherpad = require("./etherpad/Etherpad.js");
var Chat = require("./side_pannels/chat/Chat.js");
var Toolbar = require("./toolbars/toolbar");
var ToolbarToggler = require("./toolbars/toolbartoggler");
var BottomToolbar = require("./toolbars/BottomToolbar");
var ContactList = require("./side_pannels/contactlist/ContactList");
var Avatar = require("./avatar/Avatar");
//var EventEmitter = require("events");
var SettingsMenu = require("./side_pannels/settings/SettingsMenu");
var Settings = require("./side_pannels/settings/Settings");
var PanelToggler = require("./side_pannels/SidePanelToggler");
var RoomNameGenerator = require("./welcome_page/RoomnameGenerator");
UI.messageHandler = require("./util/MessageHandler");
var messageHandler = UI.messageHandler;
//var eventEmitter = new EventEmitter();
function setupPrezi()
{
$("#reloadPresentationLink").click(function()
{
Prezi.reloadPresentation();
});
}
function setupChat()
{
Chat.init();
$("#toggle_smileys").click(function() {
Chat.toggleSmileys();
});
}
function setupToolbars() {
Toolbar.init();
Toolbar.setupButtonsFromConfig();
BottomToolbar.init();
}
function registerListeners() {
RTC.addStreamListener(function (stream) {
switch (stream.type)
{
case "audio":
VideoLayout.changeLocalAudio(stream.getOriginalStream());
break;
case "video":
VideoLayout.changeLocalVideo(stream.getOriginalStream(), true);
break;
case "stream":
VideoLayout.changeLocalStream(stream.getOriginalStream());
break;
case "desktop":
VideoLayout.changeLocalVideo(stream, !isUsingScreenStream);
break;
}
}, StreamEventTypes.EVENT_TYPE_LOCAL_CREATED);
RTC.addStreamListener(function (stream) {
VideoLayout.onRemoteStreamAdded(stream);
}, StreamEventTypes.EVENT_TYPE_REMOTE_CREATED);
// Listen for large video size updates
document.getElementById('largeVideo')
.addEventListener('loadedmetadata', function (e) {
currentVideoWidth = this.videoWidth;
currentVideoHeight = this.videoHeight;
VideoLayout.positionLarge(currentVideoWidth, currentVideoHeight);
});
statistics.addAudioLevelListener(function(jid, audioLevel)
{
var resourceJid;
if(jid === statistics.LOCAL_JID)
{
resourceJid = AudioLevels.LOCAL_LEVEL;
if(isAudioMuted())
{
audioLevel = 0;
}
}
else
{
resourceJid = Strophe.getResourceFromJid(jid);
}
AudioLevels.updateAudioLevel(resourceJid, audioLevel,
UI.getLargeVideoState().userResourceJid);
});
}
function bindEvents()
{
/**
* Resizes and repositions videos in full screen mode.
*/
$(document).on('webkitfullscreenchange mozfullscreenchange fullscreenchange',
function () {
VideoLayout.resizeLargeVideoContainer();
VideoLayout.positionLarge();
isFullScreen = document.fullScreen ||
document.mozFullScreen ||
document.webkitIsFullScreen;
}
);
$(window).resize(function () {
VideoLayout.resizeLargeVideoContainer();
VideoLayout.positionLarge();
});
}
UI.start = function () {
document.title = interfaceConfig.APP_NAME;
if(config.enableWelcomePage && window.location.pathname == "/" &&
(!window.localStorage.welcomePageDisabled || window.localStorage.welcomePageDisabled == "false"))
{
$("#videoconference_page").hide();
var setupWelcomePage = require("./welcome_page/WelcomePage");
setupWelcomePage();
return;
}
if (interfaceConfig.SHOW_JITSI_WATERMARK) {
var leftWatermarkDiv
= $("#largeVideoContainer div[class='watermark leftwatermark']");
leftWatermarkDiv.css({display: 'block'});
leftWatermarkDiv.parent().get(0).href
= interfaceConfig.JITSI_WATERMARK_LINK;
}
if (interfaceConfig.SHOW_BRAND_WATERMARK) {
var rightWatermarkDiv
= $("#largeVideoContainer div[class='watermark rightwatermark']");
rightWatermarkDiv.css({display: 'block'});
rightWatermarkDiv.parent().get(0).href
= interfaceConfig.BRAND_WATERMARK_LINK;
rightWatermarkDiv.get(0).style.backgroundImage
= "url(images/rightwatermark.png)";
}
if (interfaceConfig.SHOW_POWERED_BY) {
$("#largeVideoContainer>a[class='poweredby']").css({display: 'block'});
}
$("#welcome_page").hide();
$('body').popover({ selector: '[data-toggle=popover]',
trigger: 'click hover',
content: function() {
return this.getAttribute("content") +
KeyboardShortcut.getShortcut(this.getAttribute("shortcut"));
}
});
VideoLayout.resizeLargeVideoContainer();
$("#videospace").mousemove(function () {
return ToolbarToggler.showToolbar();
});
// Set the defaults for prompt dialogs.
jQuery.prompt.setDefaults({persistent: false});
// KeyboardShortcut.init();
registerListeners();
bindEvents();
setupPrezi();
setupToolbars();
setupChat();
document.title = interfaceConfig.APP_NAME;
$("#downloadlog").click(function (event) {
dump(event.target);
});
if(config.enableWelcomePage && window.location.pathname == "/" &&
(!window.localStorage.welcomePageDisabled || window.localStorage.welcomePageDisabled == "false"))
{
$("#videoconference_page").hide();
var setupWelcomePage = require("./welcome_page/WelcomePage");
setupWelcomePage();
return;
}
$("#welcome_page").hide();
document.getElementById('largeVideo').volume = 0;
if (!$('#settings').is(':visible')) {
console.log('init');
init();
} else {
loginInfo.onsubmit = function (e) {
if (e.preventDefault) e.preventDefault();
$('#settings').hide();
init();
};
}
toastr.options = {
"closeButton": true,
"debug": false,
"positionClass": "notification-bottom-right",
"onclick": null,
"showDuration": "300",
"hideDuration": "1000",
"timeOut": "2000",
"extendedTimeOut": "1000",
"showEasing": "swing",
"hideEasing": "linear",
"showMethod": "fadeIn",
"hideMethod": "fadeOut",
"reposition": function() {
if(PanelToggler.isVisible()) {
$("#toast-container").addClass("notification-bottom-right-center");
} else {
$("#toast-container").removeClass("notification-bottom-right-center");
}
},
"newestOnTop": false
};
$('#settingsmenu>input').keyup(function(event){
if(event.keyCode === 13) {//enter
SettingsMenu.update();
}
});
$("#updateSettings").click(function () {
SettingsMenu.update();
});
};
UI.setUserAvatar = function (jid, id) {
Avatar.setUserAvatar(jid, id);
};
UI.toggleSmileys = function () {
Chat.toggleSmileys();
};
UI.chatAddError = function(errorMessage, originalText)
{
return Chat.chatAddError(errorMessage, originalText);
};
UI.chatSetSubject = function(text)
{
return Chat.chatSetSubject(text);
};
UI.updateChatConversation = function (from, displayName, message) {
return Chat.updateChatConversation(from, displayName, message);
};
UI.onMucJoined = function (jid, info) {
Toolbar.updateRoomUrl(window.location.href);
document.getElementById('localNick').appendChild(
document.createTextNode(Strophe.getResourceFromJid(jid) + ' (me)')
);
var settings = Settings.getSettings();
// Add myself to the contact list.
ContactList.addContact(jid, settings.email || settings.uid);
// Once we've joined the muc show the toolbar
ToolbarToggler.showToolbar();
// Show authenticate button if needed
Toolbar.showAuthenticateButton(
Moderator.isExternalAuthEnabled() && !Moderator.isModerator());
var displayName = !config.displayJids
? info.displayName : Strophe.getResourceFromJid(jid);
if (displayName)
$(document).trigger('displaynamechanged',
['localVideoContainer', displayName + ' (me)']);
};
UI.initEtherpad = function (name) {
Etherpad.init(name);
};
UI.onMucLeft = function (jid) {
console.log('left.muc', jid);
var displayName = $('#participant_' + Strophe.getResourceFromJid(jid) +
'>.displayname').html();
messageHandler.notify(displayName || 'Somebody',
'disconnected',
'disconnected');
// Need to call this with a slight delay, otherwise the element couldn't be
// found for some reason.
// XXX(gp) it works fine without the timeout for me (with Chrome 38).
window.setTimeout(function () {
var container = document.getElementById(
'participant_' + Strophe.getResourceFromJid(jid));
if (container) {
ContactList.removeContact(jid);
VideoLayout.removeConnectionIndicator(jid);
// hide here, wait for video to close before removing
$(container).hide();
VideoLayout.resizeThumbnails();
}
}, 10);
// Unlock large video
if (focusedVideoInfo && focusedVideoInfo.jid === jid)
{
console.info("Focused video owner has left the conference");
focusedVideoInfo = null;
}
};
UI.getSettings = function () {
return Settings.getSettings();
};
UI.toggleFilmStrip = function () {
return BottomToolbar.toggleFilmStrip();
};
UI.toggleChat = function () {
return BottomToolbar.toggleChat();
};
UI.toggleContactList = function () {
return BottomToolbar.toggleContactList();
};
UI.onLocalRoleChange = function (jid, info, pres) {
console.info("My role changed, new role: " + info.role);
var isModerator = Moderator.isModerator();
VideoLayout.showModeratorIndicator();
Toolbar.showAuthenticateButton(
Moderator.isExternalAuthEnabled() && !isModerator);
if (isModerator) {
Toolbar.closeAuthenticationWindow();
messageHandler.notify(
'Me', 'connected', 'Moderator rights granted !');
}
};
UI.onDisposeConference = function (unload) {
Toolbar.showAuthenticateButton(false);
};
UI.onModeratorStatusChanged = function (isModerator) {
Toolbar.showSipCallButton(isModerator);
Toolbar.showRecordingButton(
isModerator); //&&
// FIXME:
// Recording visible if
// there are at least 2(+ 1 focus) participants
//Object.keys(connection.emuc.members).length >= 3);
if (isModerator && config.etherpad_base) {
Etherpad.init();
}
};
UI.onPasswordReqiured = function (callback) {
// password is required
Toolbar.lockLockButton();
messageHandler.openTwoButtonDialog(null,
'<h2>Password required</h2>' +
'<input id="lockKey" type="text" placeholder="password" autofocus>',
true,
"Ok",
function (e, v, m, f) {},
function (event) {
document.getElementById('lockKey').focus();
},
function (e, v, m, f) {
if (v) {
var lockKey = document.getElementById('lockKey');
if (lockKey.value !== null) {
Toolbar.setSharedKey(lockKey.value);
callback(lockKey.value);
}
}
}
);
};
UI.onAuthenticationRequired = function () {
// extract room name from 'room@muc.server.net'
var room = roomName.substr(0, roomName.indexOf('@'));
messageHandler.openDialog(
'Stop',
'Authentication is required to create room:<br/>' + room,
true,
{
Authenticate: 'authNow',
Close: 'close'
},
function (onSubmitEvent, submitValue) {
console.info('On submit: ' + submitValue, submitValue);
if (submitValue === 'authNow') {
Toolbar.authenticateClicked();
} else {
Toolbar.showAuthenticateButton(true);
}
}
);
};
UI.setRecordingButtonState = function (state) {
Toolbar.setRecordingButtonState(state);
};
UI.changeDesktopSharingButtonState = function (isUsingScreenStream) {
Toolbar.changeDesktopSharingButtonState(isUsingScreenStream);
};
UI.inputDisplayNameHandler = function (value) {
VideoLayout.inputDisplayNameHandler(value);
};
UI.onMucEntered = function (jid, id, displayName) {
messageHandler.notify(displayName || 'Somebody',
'connected',
'connected');
// Add Peer's container
VideoLayout.ensurePeerContainerExists(jid,id);
if(APIConnector.isEnabled() &&
APIConnector.isEventEnabled("participantJoined"))
{
APIConnector.triggerEvent("participantJoined",{jid: jid});
}
};
UI.onMucPresenceStatus = function ( jid, info) {
VideoLayout.setPresenceStatus(
'participant_' + Strophe.getResourceFromJid(jid), info.status);
};
UI.onMucRoleChanged = function (role, displayName) {
VideoLayout.showModeratorIndicator();
if (role === 'moderator') {
var displayName = displayName;
if (!displayName) {
displayName = 'Somebody';
}
messageHandler.notify(
displayName,
'connected',
'Moderator rights granted to ' + displayName + '!');
}
};
UI.updateLocalConnectionStats = function(percent, stats)
{
VideoLayout.updateLocalConnectionStats(percent, stats);
};
UI.updateConnectionStats = function(jid, percent, stats)
{
VideoLayout.updateConnectionStats(jid, percent, stats);
};
UI.onStatsStop = function () {
VideoLayout.onStatsStop();
};
UI.getLargeVideoState = function()
{
return VideoLayout.getLargeVideoState();
};
UI.showLocalAudioIndicator = function (mute) {
VideoLayout.showLocalAudioIndicator(mute);
};
UI.changeLocalVideo = function (stream, flipx) {
VideoLayout.changeLocalVideo(stream, flipx);
};
UI.generateRoomName = function() {
var roomnode = null;
var path = window.location.pathname;
// determinde the room node from the url
// TODO: just the roomnode or the whole bare jid?
if (config.getroomnode && typeof config.getroomnode === 'function') {
// custom function might be responsible for doing the pushstate
roomnode = config.getroomnode(path);
} else {
/* fall back to default strategy
* this is making assumptions about how the URL->room mapping happens.
* It currently assumes deployment at root, with a rewrite like the
* following one (for nginx):
location ~ ^/([a-zA-Z0-9]+)$ {
rewrite ^/(.*)$ / break;
}
*/
if (path.length > 1) {
roomnode = path.substr(1).toLowerCase();
} else {
var word = RoomNameGenerator.generateRoomWithoutSeparator();
roomnode = word.toLowerCase();
window.history.pushState('VideoChat',
'Room: ' + word, window.location.pathname + word);
}
}
roomName = roomnode + '@' + config.hosts.muc;
};
UI.connectionIndicatorShowMore = function(id)
{
return VideoLayout.connectionIndicators[id].showMore();
}
module.exports = UI;

View File

@ -1,3 +1,5 @@
var CanvasUtil = require("./CanvasUtils");
/**
* The audio Levels plugin.
*/
@ -10,7 +12,7 @@ var AudioLevels = (function(my) {
* Updates the audio level canvas for the given peerJid. If the canvas
* didn't exist we create it.
*/
my.updateAudioLevelCanvas = function (peerJid) {
my.updateAudioLevelCanvas = function (peerJid, VideoLayout) {
var resourceJid = null;
var videoSpanId = null;
if (!peerJid)
@ -66,7 +68,7 @@ var AudioLevels = (function(my) {
* which we draw the audio level
* @param audioLevel the newAudio level to render
*/
my.updateAudioLevel = function (resourceJid, audioLevel) {
my.updateAudioLevel = function (resourceJid, audioLevel, largeVideoResourceJid) {
drawAudioLevelCanvas(resourceJid, audioLevel);
var videoSpanId = getVideoSpanId(resourceJid);
@ -91,7 +93,7 @@ var AudioLevels = (function(my) {
resourceJid = Strophe.getResourceFromJid(connection.emuc.myroomjid);
}
if(resourceJid === VideoLayout.getLargeVideoState().userResourceJid) {
if(resourceJid === largeVideoResourceJid) {
AudioLevels.updateActiveSpeakerAudioLevel(audioLevel);
}
};
@ -258,3 +260,5 @@ var AudioLevels = (function(my) {
return my;
})(AudioLevels || {});
module.exports = AudioLevels;

View File

@ -107,3 +107,5 @@ var CanvasUtil = (function(my) {
return my;
})(CanvasUtil || {});
module.exports = CanvasUtil;

View File

@ -1,15 +1,50 @@
var Avatar = (function(my) {
var users = {};
var activeSpeakerJid;
var Settings = require("../side_pannels/settings/Settings");
var users = {};
var activeSpeakerJid;
function setVisibility(selector, show) {
if (selector && selector.length > 0) {
selector.css("visibility", show ? "visible" : "hidden");
}
}
function isUserMuted(jid) {
// XXX(gp) we may want to rename this method to something like
// isUserStreaming, for example.
if (jid && jid != connection.emuc.myroomjid) {
var resource = Strophe.getResourceFromJid(jid);
if (!require("../videolayout/VideoLayout").isInLastN(resource)) {
return true;
}
}
if (!RTC.remoteStreams[jid] || !RTC.remoteStreams[jid][MediaStreamType.VIDEO_TYPE]) {
return null;
}
return RTC.remoteStreams[jid][MediaStreamType.VIDEO_TYPE].muted;
}
function getGravatarUrl(id, size) {
if(id === connection.emuc.myroomjid || !id) {
id = Settings.getSettings().uid;
}
return 'https://www.gravatar.com/avatar/' +
MD5.hexdigest(id.trim().toLowerCase()) +
"?d=wavatar&size=" + (size || "30");
}
var Avatar = {
/**
* Sets the user's avatar in the settings menu(if local user), contact list
* and thumbnail
* @param jid jid of the user
* @param id email or userID to be used as a hash
*/
my.setUserAvatar = function(jid, id) {
if(id) {
if(users[jid] === id) {
setUserAvatar: function (jid, id) {
if (id) {
if (users[jid] === id) {
return;
}
users[jid] = id;
@ -22,19 +57,19 @@ var Avatar = (function(my) {
// set the avatar in the settings menu if it is local user and get the
// local video container
if(jid === connection.emuc.myroomjid) {
if (jid === connection.emuc.myroomjid) {
$('#avatar').get(0).src = thumbUrl;
thumbnail = $('#localVideoContainer');
}
// set the avatar in the contact list
var contact = $('#' + resourceJid + '>img');
if(contact && contact.length > 0) {
if (contact && contact.length > 0) {
contact.get(0).src = contactListUrl;
}
// set the avatar in the thumbnail
if(avatar && avatar.length > 0) {
if (avatar && avatar.length > 0) {
avatar[0].src = thumbUrl;
} else {
if (thumbnail && thumbnail.length > 0) {
@ -48,10 +83,10 @@ var Avatar = (function(my) {
//if the user is the current active speaker - update the active speaker
// avatar
if(jid === activeSpeakerJid) {
Avatar.updateActiveSpeakerAvatarSrc(jid);
if (jid === activeSpeakerJid) {
this.updateActiveSpeakerAvatarSrc(jid);
}
};
},
/**
* Hides or shows the user's avatar
@ -59,23 +94,23 @@ var Avatar = (function(my) {
* @param show whether we should show the avatar or not
* video because there is no dominant speaker and no focused speaker
*/
my.showUserAvatar = function(jid, show) {
if(users[jid]) {
showUserAvatar: function (jid, show) {
if (users[jid]) {
var resourceJid = Strophe.getResourceFromJid(jid);
var video = $('#participant_' + resourceJid + '>video');
var avatar = $('#avatar_' + resourceJid);
if(jid === connection.emuc.myroomjid) {
if (jid === connection.emuc.myroomjid) {
video = $('#localVideoWrapper>video');
}
if(show === undefined || show === null) {
if (show === undefined || show === null) {
show = isUserMuted(jid);
}
//if the user is the currently focused, the dominant speaker or if
//there is no focused and no dominant speaker and the large video is
//currently shown
if (activeSpeakerJid === jid && VideoLayout.isLargeVideoOnTop()) {
if (activeSpeakerJid === jid && require("../videolayout/VideoLayout").isLargeVideoOnTop()) {
setVisibility($("#largeVideo"), !show);
setVisibility($('#activeSpeaker'), show);
setVisibility(avatar, false);
@ -87,62 +122,33 @@ var Avatar = (function(my) {
}
}
}
};
},
/**
* Updates the src of the active speaker avatar
* @param jid of the current active speaker
*/
my.updateActiveSpeakerAvatarSrc = function(jid) {
if(!jid) {
updateActiveSpeakerAvatarSrc: function (jid) {
if (!jid) {
jid = connection.emuc.findJidFromResource(
VideoLayout.getLargeVideoState().userResourceJid);
require("../videolayout/VideoLayout").getLargeVideoState().userResourceJid);
}
var avatar = $("#activeSpeakerAvatar")[0];
var url = getGravatarUrl(users[jid],
interfaceConfig.ACTIVE_SPEAKER_AVATAR_SIZE);
if(jid === activeSpeakerJid && avatar.src === url) {
if (jid === activeSpeakerJid && avatar.src === url) {
return;
}
activeSpeakerJid = jid;
var isMuted = isUserMuted(jid);
if(jid && isMuted !== null) {
if (jid && isMuted !== null) {
avatar.src = url;
setVisibility($("#largeVideo"), !isMuted);
Avatar.showUserAvatar(jid, isMuted);
}
};
function setVisibility(selector, show) {
if (selector && selector.length > 0) {
selector.css("visibility", show ? "visible" : "hidden");
}
}
function isUserMuted(jid) {
// XXX(gp) we may want to rename this method to something like
// isUserStreaming, for example.
if (jid && jid != connection.emuc.myroomjid) {
var resource = Strophe.getResourceFromJid(jid);
if (!VideoLayout.isInLastN(resource)) {
return true;
}
}
};
if (!RTC.remoteStreams[jid] || !RTC.remoteStreams[jid][MediaStreamType.VIDEO_TYPE]) {
return null;
}
return RTC.remoteStreams[jid][MediaStream.VIDEO_TYPE].muted;
}
function getGravatarUrl(id, size) {
if(id === connection.emuc.myroomjid || !id) {
id = SettingsMenu.getUID();
}
return 'https://www.gravatar.com/avatar/' +
MD5.hexdigest(id.trim().toLowerCase()) +
"?d=wavatar&size=" + (size || "30");
}
return my;
}(Avatar || {}));
module.exports = Avatar;

View File

@ -0,0 +1,195 @@
/* global $, config, connection, dockToolbar, Moderator,
setLargeVideoVisible, Util */
var VideoLayout = require("../videolayout/VideoLayout");
var Prezi = require("../prezi/Prezi");
var UIUtil = require("../util/UIUtil");
var etherpadName = null;
var etherpadIFrame = null;
var domain = null;
var options = "?showControls=true&showChat=false&showLineNumbers=true&useMonospaceFont=false";
/**
* Resizes the etherpad.
*/
function resize() {
if ($('#etherpad>iframe').length) {
var remoteVideos = $('#remoteVideos');
var availableHeight
= window.innerHeight - remoteVideos.outerHeight();
var availableWidth = UIUtil.getAvailableVideoWidth();
$('#etherpad>iframe').width(availableWidth);
$('#etherpad>iframe').height(availableHeight);
}
}
/**
* Shares the Etherpad name with other participants.
*/
function shareEtherpad() {
connection.emuc.addEtherpadToPresence(etherpadName);
connection.emuc.sendPresence();
}
/**
* Creates the Etherpad button and adds it to the toolbar.
*/
function enableEtherpadButton() {
if (!$('#etherpadButton').is(":visible"))
$('#etherpadButton').css({display: 'inline-block'});
}
/**
* Creates the IFrame for the etherpad.
*/
function createIFrame() {
etherpadIFrame = document.createElement('iframe');
etherpadIFrame.src = domain + etherpadName + options;
etherpadIFrame.frameBorder = 0;
etherpadIFrame.scrolling = "no";
etherpadIFrame.width = $('#largeVideoContainer').width() || 640;
etherpadIFrame.height = $('#largeVideoContainer').height() || 480;
etherpadIFrame.setAttribute('style', 'visibility: hidden;');
document.getElementById('etherpad').appendChild(etherpadIFrame);
etherpadIFrame.onload = function() {
document.domain = document.domain;
bubbleIframeMouseMove(etherpadIFrame);
setTimeout(function() {
// the iframes inside of the etherpad are
// not yet loaded when the etherpad iframe is loaded
var outer = etherpadIFrame.
contentDocument.getElementsByName("ace_outer")[0];
bubbleIframeMouseMove(outer);
var inner = outer.
contentDocument.getElementsByName("ace_inner")[0];
bubbleIframeMouseMove(inner);
}, 2000);
};
}
function bubbleIframeMouseMove(iframe){
var existingOnMouseMove = iframe.contentWindow.onmousemove;
iframe.contentWindow.onmousemove = function(e){
if(existingOnMouseMove) existingOnMouseMove(e);
var evt = document.createEvent("MouseEvents");
var boundingClientRect = iframe.getBoundingClientRect();
evt.initMouseEvent(
"mousemove",
true, // bubbles
false, // not cancelable
window,
e.detail,
e.screenX,
e.screenY,
e.clientX + boundingClientRect.left,
e.clientY + boundingClientRect.top,
e.ctrlKey,
e.altKey,
e.shiftKey,
e.metaKey,
e.button,
null // no related element
);
iframe.dispatchEvent(evt);
};
}
/**
* On video selected event.
*/
$(document).bind('video.selected', function (event, isPresentation) {
if (config.etherpad_base && etherpadIFrame && etherpadIFrame.style.visibility !== 'hidden')
Etherpad.toggleEtherpad(isPresentation);
});
var Etherpad = {
/**
* Initializes the etherpad.
*/
init: function (name) {
if (config.etherpad_base && !etherpadName) {
domain = config.etherpad_base;
if (!name) {
// In case we're the focus we generate the name.
etherpadName = Math.random().toString(36).substring(7) +
'_' + (new Date().getTime()).toString();
shareEtherpad();
}
else
etherpadName = name;
enableEtherpadButton();
/**
* Resizes the etherpad, when the window is resized.
*/
$(window).resize(function () {
resize();
});
}
},
/**
* Opens/hides the Etherpad.
*/
toggleEtherpad: function (isPresentation) {
if (!etherpadIFrame)
createIFrame();
var largeVideo = null;
if (Prezi.isPresentationVisible())
largeVideo = $('#presentation>iframe');
else
largeVideo = $('#largeVideo');
if ($('#etherpad>iframe').css('visibility') === 'hidden') {
$('#activeSpeaker').css('visibility', 'hidden');
largeVideo.fadeOut(300, function () {
if (Prezi.isPresentationVisible()) {
largeVideo.css({opacity: '0'});
} else {
VideoLayout.setLargeVideoVisible(false);
}
});
$('#etherpad>iframe').fadeIn(300, function () {
document.body.style.background = '#eeeeee';
$('#etherpad>iframe').css({visibility: 'visible'});
$('#etherpad').css({zIndex: 2});
});
}
else if ($('#etherpad>iframe')) {
$('#etherpad>iframe').fadeOut(300, function () {
$('#etherpad>iframe').css({visibility: 'hidden'});
$('#etherpad').css({zIndex: 0});
document.body.style.background = 'black';
});
if (!isPresentation) {
$('#largeVideo').fadeIn(300, function () {
VideoLayout.setLargeVideoVisible(true);
});
}
}
resize();
},
isVisible: function() {
var etherpadIframe = $('#etherpad>iframe');
return etherpadIframe && etherpadIframe.is(':visible');
}
};
module.exports = Etherpad;

354
modules/UI/prezi/Prezi.js Normal file
View File

@ -0,0 +1,354 @@
var ToolbarToggler = require("../toolbars/ToolbarToggler");
var UIUtil = require("../util/UIUtil");
var VideoLayout = require("../videolayout/VideoLayout");
var messageHandler = require("../util/MessageHandler");
var preziPlayer = null;
var Prezi = {
/**
* Reloads the current presentation.
*/
reloadPresentation: function() {
var iframe = document.getElementById(preziPlayer.options.preziId);
iframe.src = iframe.src;
},
/**
* Returns <tt>true</tt> if the presentation is visible, <tt>false</tt> -
* otherwise.
*/
isPresentationVisible: function () {
return ($('#presentation>iframe') != null
&& $('#presentation>iframe').css('opacity') == 1);
},
/**
* Opens the Prezi dialog, from which the user could choose a presentation
* to load.
*/
openPreziDialog: function() {
var myprezi = connection.emuc.getPrezi(connection.emuc.myroomjid);
if (myprezi) {
messageHandler.openTwoButtonDialog("Remove Prezi",
"Are you sure you would like to remove your Prezi?",
false,
"Remove",
function(e,v,m,f) {
if(v) {
connection.emuc.removePreziFromPresence();
connection.emuc.sendPresence();
}
}
);
}
else if (preziPlayer != null) {
messageHandler.openTwoButtonDialog("Share a Prezi",
"Another participant is already sharing a Prezi." +
"This conference allows only one Prezi at a time.",
false,
"Ok",
function(e,v,m,f) {
$.prompt.close();
}
);
}
else {
var openPreziState = {
state0: {
html: '<h2>Share a Prezi</h2>' +
'<input id="preziUrl" type="text" ' +
'placeholder="e.g. ' +
'http://prezi.com/wz7vhjycl7e6/my-prezi" autofocus>',
persistent: false,
buttons: { "Share": true , "Cancel": false},
defaultButton: 1,
submit: function(e,v,m,f){
e.preventDefault();
if(v)
{
var preziUrl = document.getElementById('preziUrl');
if (preziUrl.value)
{
var urlValue
= encodeURI(Util.escapeHtml(preziUrl.value));
if (urlValue.indexOf('http://prezi.com/') != 0
&& urlValue.indexOf('https://prezi.com/') != 0)
{
$.prompt.goToState('state1');
return false;
}
else {
var presIdTmp = urlValue.substring(
urlValue.indexOf("prezi.com/") + 10);
if (!isAlphanumeric(presIdTmp)
|| presIdTmp.indexOf('/') < 2) {
$.prompt.goToState('state1');
return false;
}
else {
connection.emuc
.addPreziToPresence(urlValue, 0);
connection.emuc.sendPresence();
$.prompt.close();
}
}
}
}
else
$.prompt.close();
}
},
state1: {
html: '<h2>Share a Prezi</h2>' +
'Please provide a correct prezi link.',
persistent: false,
buttons: { "Back": true, "Cancel": false },
defaultButton: 1,
submit:function(e,v,m,f) {
e.preventDefault();
if(v==0)
$.prompt.close();
else
$.prompt.goToState('state0');
}
}
};
var focusPreziUrl = function(e) {
document.getElementById('preziUrl').focus();
};
messageHandler.openDialogWithStates(openPreziState, focusPreziUrl, focusPreziUrl);
}
}
};
/**
* A new presentation has been added.
*
* @param event the event indicating the add of a presentation
* @param jid the jid from which the presentation was added
* @param presUrl url of the presentation
* @param currentSlide the current slide to which we should move
*/
function presentationAdded(event, jid, presUrl, currentSlide) {
console.log("presentation added", presUrl);
var presId = getPresentationId(presUrl);
var elementId = 'participant_'
+ Strophe.getResourceFromJid(jid)
+ '_' + presId;
// We explicitly don't specify the peer jid here, because we don't want
// this video to be dealt with as a peer related one (for example we
// don't want to show a mute/kick menu for this one, etc.).
VideoLayout.addRemoteVideoContainer(null, elementId);
VideoLayout.resizeThumbnails();
var controlsEnabled = false;
if (jid === connection.emuc.myroomjid)
controlsEnabled = true;
setPresentationVisible(true);
$('#largeVideoContainer').hover(
function (event) {
if (Prezi.isPresentationVisible()) {
var reloadButtonRight = window.innerWidth
- $('#presentation>iframe').offset().left
- $('#presentation>iframe').width();
$('#reloadPresentation').css({ right: reloadButtonRight,
display:'inline-block'});
}
},
function (event) {
if (!Prezi.isPresentationVisible())
$('#reloadPresentation').css({display:'none'});
else {
var e = event.toElement || event.relatedTarget;
if (e && e.id != 'reloadPresentation' && e.id != 'header')
$('#reloadPresentation').css({display:'none'});
}
});
preziPlayer = new PreziPlayer(
'presentation',
{preziId: presId,
width: getPresentationWidth(),
height: getPresentationHeihgt(),
controls: controlsEnabled,
debug: true
});
$('#presentation>iframe').attr('id', preziPlayer.options.preziId);
preziPlayer.on(PreziPlayer.EVENT_STATUS, function(event) {
console.log("prezi status", event.value);
if (event.value == PreziPlayer.STATUS_CONTENT_READY) {
if (jid != connection.emuc.myroomjid)
preziPlayer.flyToStep(currentSlide);
}
});
preziPlayer.on(PreziPlayer.EVENT_CURRENT_STEP, function(event) {
console.log("event value", event.value);
connection.emuc.addCurrentSlideToPresence(event.value);
connection.emuc.sendPresence();
});
$("#" + elementId).css( 'background-image',
'url(../images/avatarprezi.png)');
$("#" + elementId).click(
function () {
setPresentationVisible(true);
}
);
};
/**
* A presentation has been removed.
*
* @param event the event indicating the remove of a presentation
* @param jid the jid for which the presentation was removed
* @param the url of the presentation
*/
function presentationRemoved(event, jid, presUrl) {
console.log('presentation removed', presUrl);
var presId = getPresentationId(presUrl);
setPresentationVisible(false);
$('#participant_'
+ Strophe.getResourceFromJid(jid)
+ '_' + presId).remove();
$('#presentation>iframe').remove();
if (preziPlayer != null) {
preziPlayer.destroy();
preziPlayer = null;
}
};
/**
* Indicates if the given string is an alphanumeric string.
* Note that some special characters are also allowed (-, _ , /, &, ?, =, ;) for the
* purpose of checking URIs.
*/
function isAlphanumeric(unsafeText) {
var regex = /^[a-z0-9-_\/&\?=;]+$/i;
return regex.test(unsafeText);
}
/**
* Returns the presentation id from the given url.
*/
function getPresentationId (presUrl) {
var presIdTmp = presUrl.substring(presUrl.indexOf("prezi.com/") + 10);
return presIdTmp.substring(0, presIdTmp.indexOf('/'));
}
/**
* Returns the presentation width.
*/
function getPresentationWidth() {
var availableWidth = UIUtil.getAvailableVideoWidth();
var availableHeight = getPresentationHeihgt();
var aspectRatio = 16.0 / 9.0;
if (availableHeight < availableWidth / aspectRatio) {
availableWidth = Math.floor(availableHeight * aspectRatio);
}
return availableWidth;
}
/**
* Returns the presentation height.
*/
function getPresentationHeihgt() {
var remoteVideos = $('#remoteVideos');
return window.innerHeight - remoteVideos.outerHeight();
}
/**
* Resizes the presentation iframe.
*/
function resize() {
if ($('#presentation>iframe')) {
$('#presentation>iframe').width(getPresentationWidth());
$('#presentation>iframe').height(getPresentationHeihgt());
}
}
/**
* Shows/hides a presentation.
*/
function setPresentationVisible(visible) {
var prezi = $('#presentation>iframe');
if (visible) {
// Trigger the video.selected event to indicate a change in the
// large video.
$(document).trigger("video.selected", [true]);
$('#largeVideo').fadeOut(300);
prezi.fadeIn(300, function() {
prezi.css({opacity:'1'});
ToolbarToggler.dockToolbar(true);
VideoLayout.setLargeVideoVisible(false);
});
$('#activeSpeaker').css('visibility', 'hidden');
}
else {
if (prezi.css('opacity') == '1') {
prezi.fadeOut(300, function () {
prezi.css({opacity:'0'});
$('#reloadPresentation').css({display:'none'});
$('#largeVideo').fadeIn(300, function() {
VideoLayout.setLargeVideoVisible(true);
ToolbarToggler.dockToolbar(false);
});
});
}
}
}
/**
* Presentation has been removed.
*/
$(document).bind('presentationremoved.muc', presentationRemoved);
/**
* Presentation has been added.
*/
$(document).bind('presentationadded.muc', presentationAdded);
/*
* Indicates presentation slide change.
*/
$(document).bind('gotoslide.muc', function (event, jid, presUrl, current) {
if (preziPlayer && preziPlayer.getCurrentStep() != current) {
preziPlayer.flyToStep(current);
var animationStepsArray = preziPlayer.getAnimationCountOnSteps();
for (var i = 0; i < parseInt(animationStepsArray[current]); i++) {
preziPlayer.flyToStep(current, i);
}
}
});
/**
* On video selected event.
*/
$(document).bind('video.selected', function (event, isPresentation) {
if (!isPresentation && $('#presentation>iframe')) {
setPresentationVisible(false);
}
});
$(window).resize(function () {
resize();
});
module.exports = Prezi;

View File

@ -1,3 +1,10 @@
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");
/**
* Toggler for the chat, contact list, settings menu, etc..
*/
@ -215,8 +222,9 @@ var PanelToggler = (function(my) {
'#settingsmenu',
null,
function() {
$('#setDisplayName').get(0).value = SettingsMenu.getDisplayName();
$('#setEmail').get(0).value = SettingsMenu.getEmail();
var settings = Settings.getSettings();
$('#setDisplayName').get(0).value = settings.displayName;
$('#setEmail').get(0).value = settings.email;
},
null);
};
@ -243,3 +251,5 @@ var PanelToggler = (function(my) {
return my;
}(PanelToggler || {}));
module.exports = PanelToggler;

View File

@ -0,0 +1,361 @@
/* global $, Util, connection, nickname:true, getVideoSize,
getVideoPosition, showToolbar */
var Replacement = require("./Replacement");
var CommandsProcessor = require("./Commands");
var ToolbarToggler = require("../../toolbars/ToolbarToggler");
var smileys = require("./smileys.json").smileys;
var notificationInterval = false;
var unreadMessages = 0;
/**
* Shows/hides a visual notification, indicating that a message has arrived.
*/
function setVisualNotification(show) {
var unreadMsgElement = document.getElementById('unreadMessages');
var unreadMsgBottomElement
= document.getElementById('bottomUnreadMessages');
var glower = $('#chatButton');
var bottomGlower = $('#chatBottomButton');
if (unreadMessages) {
unreadMsgElement.innerHTML = unreadMessages.toString();
unreadMsgBottomElement.innerHTML = unreadMessages.toString();
ToolbarToggler.dockToolbar(true);
var chatButtonElement
= document.getElementById('chatButton').parentNode;
var leftIndent = (Util.getTextWidth(chatButtonElement) -
Util.getTextWidth(unreadMsgElement)) / 2;
var topIndent = (Util.getTextHeight(chatButtonElement) -
Util.getTextHeight(unreadMsgElement)) / 2 - 3;
unreadMsgElement.setAttribute(
'style',
'top:' + topIndent +
'; left:' + leftIndent + ';');
var chatBottomButtonElement
= document.getElementById('chatBottomButton').parentNode;
var bottomLeftIndent = (Util.getTextWidth(chatBottomButtonElement) -
Util.getTextWidth(unreadMsgBottomElement)) / 2;
var bottomTopIndent = (Util.getTextHeight(chatBottomButtonElement) -
Util.getTextHeight(unreadMsgBottomElement)) / 2 - 2;
unreadMsgBottomElement.setAttribute(
'style',
'top:' + bottomTopIndent +
'; left:' + bottomLeftIndent + ';');
if (!glower.hasClass('icon-chat-simple')) {
glower.removeClass('icon-chat');
glower.addClass('icon-chat-simple');
}
}
else {
unreadMsgElement.innerHTML = '';
unreadMsgBottomElement.innerHTML = '';
glower.removeClass('icon-chat-simple');
glower.addClass('icon-chat');
}
if (show && !notificationInterval) {
notificationInterval = window.setInterval(function () {
glower.toggleClass('active');
bottomGlower.toggleClass('active glowing');
}, 800);
}
else if (!show && notificationInterval) {
window.clearInterval(notificationInterval);
notificationInterval = false;
glower.removeClass('active');
bottomGlower.removeClass('glowing');
bottomGlower.addClass('active');
}
}
/**
* Returns the current time in the format it is shown to the user
* @returns {string}
*/
function getCurrentTime() {
var now = new Date();
var hour = now.getHours();
var minute = now.getMinutes();
var second = now.getSeconds();
if(hour.toString().length === 1) {
hour = '0'+hour;
}
if(minute.toString().length === 1) {
minute = '0'+minute;
}
if(second.toString().length === 1) {
second = '0'+second;
}
return hour+':'+minute+':'+second;
}
function toggleSmileys()
{
var smileys = $('#smileysContainer');
if(!smileys.is(':visible')) {
smileys.show("slide", { direction: "down", duration: 300});
} else {
smileys.hide("slide", { direction: "down", duration: 300});
}
$('#usermsg').focus();
}
function addClickFunction(smiley, number) {
smiley.onclick = function addSmileyToMessage() {
var usermsg = $('#usermsg');
var message = usermsg.val();
message += smileys['smiley' + number];
usermsg.val(message);
usermsg.get(0).setSelectionRange(message.length, message.length);
toggleSmileys();
usermsg.focus();
};
}
/**
* Adds the smileys container to the chat
*/
function addSmileys() {
var smileysContainer = document.createElement('div');
smileysContainer.id = 'smileysContainer';
for(var i = 1; i <= 21; i++) {
var smileyContainer = document.createElement('div');
smileyContainer.id = 'smiley' + i;
smileyContainer.className = 'smileyContainer';
var smiley = document.createElement('img');
smiley.src = 'images/smileys/smiley' + i + '.svg';
smiley.className = 'smiley';
addClickFunction(smiley, i);
smileyContainer.appendChild(smiley);
smileysContainer.appendChild(smileyContainer);
}
$("#chatspace").append(smileysContainer);
}
/**
* Resizes the chat conversation.
*/
function resizeChatConversation() {
var msgareaHeight = $('#usermsg').outerHeight();
var chatspace = $('#chatspace');
var width = chatspace.width();
var chat = $('#chatconversation');
var smileys = $('#smileysarea');
smileys.height(msgareaHeight);
$("#smileys").css('bottom', (msgareaHeight - 26) / 2);
$('#smileysContainer').css('bottom', msgareaHeight);
chat.width(width - 10);
chat.height(window.innerHeight - 15 - msgareaHeight);
}
/**
* Chat related user interface.
*/
var Chat = (function (my) {
/**
* Initializes chat related interface.
*/
my.init = function () {
var storedDisplayName = window.localStorage.displayname;
if (storedDisplayName) {
nickname = storedDisplayName;
Chat.setChatConversationMode(true);
}
$('#nickinput').keydown(function (event) {
if (event.keyCode === 13) {
event.preventDefault();
var val = Util.escapeHtml(this.value);
this.value = '';
if (!nickname) {
nickname = val;
window.localStorage.displayname = nickname;
connection.emuc.addDisplayNameToPresence(nickname);
connection.emuc.sendPresence();
Chat.setChatConversationMode(true);
return;
}
}
});
$('#usermsg').keydown(function (event) {
if (event.keyCode === 13) {
event.preventDefault();
var value = this.value;
$('#usermsg').val('').trigger('autosize.resize');
this.focus();
var command = new CommandsProcessor(value);
if(command.isCommand())
{
command.processCommand();
}
else
{
var message = Util.escapeHtml(value);
connection.emuc.sendMessage(message, nickname);
}
}
});
var onTextAreaResize = function () {
resizeChatConversation();
Chat.scrollChatToBottom();
};
$('#usermsg').autosize({callback: onTextAreaResize});
$("#chatspace").bind("shown",
function () {
unreadMessages = 0;
setVisualNotification(false);
});
addSmileys();
};
/**
* Appends the given message to the chat conversation.
*/
my.updateChatConversation = function (from, displayName, message) {
var divClassName = '';
if (connection.emuc.myroomjid === from) {
divClassName = "localuser";
}
else {
divClassName = "remoteuser";
if (!Chat.isVisible()) {
unreadMessages++;
Util.playSoundNotification('chatNotification');
setVisualNotification(true);
}
}
// replace links and smileys
// Strophe already escapes special symbols on sending,
// so we escape here only tags to avoid double &amp;
var escMessage = message.replace(/</g, '&lt;').
replace(/>/g, '&gt;').replace(/\n/g, '<br/>');
var escDisplayName = Util.escapeHtml(displayName);
message = Replacement.processReplacements(escMessage);
var messageContainer =
'<div class="chatmessage">'+
'<img src="../images/chatArrow.svg" class="chatArrow">' +
'<div class="username ' + divClassName +'">' + escDisplayName +
'</div>' + '<div class="timestamp">' + getCurrentTime() +
'</div>' + '<div class="usermessage">' + message + '</div>' +
'</div>';
$('#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)
{
errorMessage = Util.escapeHtml(errorMessage);
originalText = Util.escapeHtml(originalText);
$('#chatconversation').append(
'<div class="errorMessage"><b>Error: </b>' + 'Your message' +
(originalText? (' \"'+ originalText + '\"') : "") +
' was not sent.' +
(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)
subject = subject.trim();
$('#subject').html(Replacement.linkify(Util.escapeHtml(subject)));
if(subject === "")
{
$("#subject").css({display: "none"});
}
else
{
$("#subject").css({display: "block"});
}
};
/**
* Sets the chat conversation mode.
*/
my.setChatConversationMode = function (isConversationMode) {
if (isConversationMode) {
$('#nickname').css({visibility: 'hidden'});
$('#chatconversation').css({visibility: 'visible'});
$('#usermsg').css({visibility: 'visible'});
$('#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]);
resizeChatConversation();
};
/**
* Indicates if the chat is currently visible.
*/
my.isVisible = function () {
return $('#chatspace').is(":visible");
};
/**
* Shows and hides the window with the smileys
*/
my.toggleSmileys = toggleSmileys;
/**
* Scrolls chat to the bottom.
*/
my.scrollChatToBottom = function() {
setTimeout(function () {
$('#chatconversation').scrollTop(
$('#chatconversation')[0].scrollHeight);
}, 5);
};
return my;
}(Chat || {}));
module.exports = Chat;

View File

@ -0,0 +1,95 @@
/**
* 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 = {
"topic" : processTopic
};
/**
* Extracts the command from the message.
* @param message the received message
* @returns {string} the command
*/
function getCommand(message)
{
if(message)
{
for(var command in commands)
{
if(message.indexOf("/" + command) == 0)
return command;
}
}
return "";
};
/**
* Processes the data for topic command.
* @param commandArguments the arguments of the topic command.
*/
function processTopic(commandArguments)
{
var topic = Util.escapeHtml(commandArguments);
connection.emuc.setSubject(topic);
}
/**
* Constructs new CommandProccessor instance from a message that
* handles commands received via chat messages.
* @param message the message
* @constructor
*/
function CommandsProcessor(message)
{
var command = getCommand(message);
/**
* Returns the name of the command.
* @returns {String} the command
*/
this.getCommand = function()
{
return command;
};
var messageArgument = message.substr(command.length + 2);
/**
* Returns the arguments of the command.
* @returns {string}
*/
this.getArgument = function()
{
return messageArgument;
};
}
/**
* Checks whether this instance is valid command or not.
* @returns {boolean}
*/
CommandsProcessor.prototype.isCommand = function()
{
if(this.getCommand())
return true;
return false;
};
/**
* Processes the command.
*/
CommandsProcessor.prototype.processCommand = function()
{
if(!this.isCommand())
return;
commands[this.getCommand()](this.getArgument());
};
module.exports = CommandsProcessor;

View File

@ -1,3 +1,4 @@
var Smileys = require("./smileys.json");
/**
* Processes links and smileys in "body"
*/
@ -44,6 +45,7 @@ function smilify(body)
return body;
}
var regexs = Smileys["regexs"];
for(var smiley in regexs) {
if(regexs.hasOwnProperty(smiley)) {
body = body.replace(regexs[smiley],
@ -53,3 +55,8 @@ function smilify(body)
return body;
}
module.exports = {
processReplacements: processReplacements,
linkify: linkify
};

View File

@ -0,0 +1,48 @@
{
"smileys": {
"smiley1": ":)",
"smiley2": ":(",
"smiley3": ":D",
"smiley4": "(y)",
"smiley5": " :P",
"smiley6": "(wave)",
"smiley7": "(blush)",
"smiley8": "(chuckle)",
"smiley9": "(shocked)",
"smiley10": ":*",
"smiley11": "(n)",
"smiley12": "(search)",
"smiley13": " <3",
"smiley14": "(oops)",
"smiley15": "(angry)",
"smiley16": "(angel)",
"smiley17": "(sick)",
"smiley18": ";(",
"smiley19": "(bomb)",
"smiley20": "(clap)",
"smiley21": " ;)"
},
"regexs": {
"smiley2": /(:-\(\(|:-\(|:\(\(|:\(|\(sad\))/gi,
"smiley3": /(:-\)\)|:\)\)|\(lol\)|:-D|:D)/gi,
"smiley1": /(:-\)|:\))/gi,
"smiley4": /(\(y\)|\(Y\)|\(ok\))/gi,
"smiley5": /(:-P|:P|:-p|:p)/gi,
"smiley6": /(\(wave\))/gi,
"smiley7": /(\(blush\))/gi,
"smiley8": /(\(chuckle\))/gi,
"smiley9": /(:-0|\(shocked\))/gi,
"smiley10": /(:-\*|:\*|\(kiss\))/gi,
"smiley11": /(\(n\))/gi,
"smiley12": /(\(search\))/g,
"smiley13": /(<3|&lt;3|&amp;lt;3|\(L\)|\(l\)|\(H\)|\(h\))/gi,
"smiley14": /(\(oops\))/gi,
"smiley15": /(\(angry\))/gi,
"smiley16": /(\(angel\))/gi,
"smiley17": /(\(sick\))/gi,
"smiley18": /(;-\(\(|;\(\(|;-\(|;\(|:"\(|:"-\(|:~-\(|:~\(|\(upset\))/gi,
"smiley19": /(\(bomb\))/gi,
"smiley20": /(\(clap\))/gi,
"smiley21": /(;-\)|;\)|;-\)\)|;\)\)|;-D|;D|\(wink\))/gi
}
}

View File

@ -1,125 +1,14 @@
var numberOfContacts = 0;
var notificationInterval;
/**
* Contact list.
*/
var ContactList = (function (my) {
var numberOfContacts = 0;
var notificationInterval;
/**
* Indicates if the chat is currently visible.
*
* @return <tt>true</tt> if the chat is currently visible, <tt>false</tt> -
* otherwise
*/
my.isVisible = function () {
return $('#contactlist').is(":visible");
};
/**
* Adds a contact for the given peerJid if such doesn't yet exist.
*
* @param peerJid the peerJid corresponding to the contact
* @param id the user's email or userId used to get the user's avatar
*/
my.ensureAddContact = function(peerJid, id) {
var resourceJid = Strophe.getResourceFromJid(peerJid);
var contact = $('#contactlist>ul>li[id="' + resourceJid + '"]');
if (!contact || contact.length <= 0)
ContactList.addContact(peerJid,id);
};
/**
* Adds a contact for the given peer jid.
*
* @param peerJid the jid of the contact to add
* @param id the email or userId of the user
*/
my.addContact = function(peerJid, id) {
var resourceJid = Strophe.getResourceFromJid(peerJid);
var contactlist = $('#contactlist>ul');
var newContact = document.createElement('li');
// XXX(gp) contact click event handling is now in videolayout.js. Is the
// following statement (newContact.id = resourceJid) still relevant?
newContact.id = resourceJid;
newContact.className = "clickable";
newContact.onclick = function(event) {
if(event.currentTarget.className === "clickable") {
$(ContactList).trigger('contactclicked', [peerJid]);
}
};
newContact.appendChild(createAvatar(id));
newContact.appendChild(createDisplayNameParagraph("Participant"));
var clElement = contactlist.get(0);
if (resourceJid === Strophe.getResourceFromJid(connection.emuc.myroomjid)
&& $('#contactlist>ul .title')[0].nextSibling.nextSibling)
{
clElement.insertBefore(newContact,
$('#contactlist>ul .title')[0].nextSibling.nextSibling);
}
else {
clElement.appendChild(newContact);
}
updateNumberOfParticipants(1);
};
/**
* Removes a contact for the given peer jid.
*
* @param peerJid the peerJid corresponding to the contact to remove
*/
my.removeContact = function(peerJid) {
var resourceJid = Strophe.getResourceFromJid(peerJid);
var contact = $('#contactlist>ul>li[id="' + resourceJid + '"]');
if (contact && contact.length > 0) {
var contactlist = $('#contactlist>ul');
contactlist.get(0).removeChild(contact.get(0));
updateNumberOfParticipants(-1);
}
};
my.setVisualNotification = function(show, stopGlowingIn) {
var glower = $('#contactListButton');
function stopGlowing() {
window.clearInterval(notificationInterval);
notificationInterval = false;
glower.removeClass('glowing');
if(!ContactList.isVisible()) {
glower.removeClass('active');
}
}
if (show && !notificationInterval) {
notificationInterval = window.setInterval(function () {
glower.toggleClass('active glowing');
}, 800);
}
else if (!show && notificationInterval) {
stopGlowing();
}
if(stopGlowingIn) {
setTimeout(stopGlowing, stopGlowingIn);
}
};
/**
* Updates the number of participants in the contact list button and sets
* the glow
* @param delta indicates whether a new user has joined (1) or someone has
* left(-1)
*/
function updateNumberOfParticipants(delta) {
function updateNumberOfParticipants(delta) {
//when the user is alone we don't show the number of participants
if(numberOfContacts === 0) {
$("#numberOfParticipants").text('');
@ -129,38 +18,38 @@ var ContactList = (function (my) {
numberOfContacts += delta;
$("#numberOfParticipants").text(numberOfContacts);
}
}
}
/**
/**
* Creates the avatar element.
*
* @return the newly created avatar element
*/
function createAvatar(id) {
function createAvatar(id) {
var avatar = document.createElement('img');
avatar.className = "icon-avatar avatar";
avatar.src = "https://www.gravatar.com/avatar/" + id + "?d=wavatar&size=30";
return avatar;
}
}
/**
/**
* Creates the display name paragraph.
*
* @param displayName the display name to set
*/
function createDisplayNameParagraph(displayName) {
function createDisplayNameParagraph(displayName) {
var p = document.createElement('p');
p.innerText = displayName;
return p;
}
}
/**
/**
* Indicates that the display name has changed.
*/
$(document).bind( 'displaynamechanged',
$(document).bind( 'displaynamechanged',
function (event, peerJid, displayName) {
if (peerJid === 'localVideoContainer')
peerJid = connection.emuc.myroomjid;
@ -173,14 +62,127 @@ var ContactList = (function (my) {
contactName.html(displayName);
});
my.setClickable = function(resourceJid, isClickable) {
function stopGlowing(glower) {
window.clearInterval(notificationInterval);
notificationInterval = false;
glower.removeClass('glowing');
if (!ContactList.isVisible()) {
glower.removeClass('active');
}
}
/**
* Contact list.
*/
var ContactList = {
/**
* Indicates if the chat is currently visible.
*
* @return <tt>true</tt> if the chat is currently visible, <tt>false</tt> -
* otherwise
*/
isVisible: function () {
return $('#contactlist').is(":visible");
},
/**
* Adds a contact for the given peerJid if such doesn't yet exist.
*
* @param peerJid the peerJid corresponding to the contact
* @param id the user's email or userId used to get the user's avatar
*/
ensureAddContact: function (peerJid, id) {
var resourceJid = Strophe.getResourceFromJid(peerJid);
var contact = $('#contactlist>ul>li[id="' + resourceJid + '"]');
if(isClickable) {
if (!contact || contact.length <= 0)
ContactList.addContact(peerJid, id);
},
/**
* Adds a contact for the given peer jid.
*
* @param peerJid the jid of the contact to add
* @param id the email or userId of the user
*/
addContact: function (peerJid, id) {
var resourceJid = Strophe.getResourceFromJid(peerJid);
var contactlist = $('#contactlist>ul');
var newContact = document.createElement('li');
newContact.id = resourceJid;
newContact.className = "clickable";
newContact.onclick = function (event) {
if (event.currentTarget.className === "clickable") {
$(ContactList).trigger('contactclicked', [peerJid]);
}
};
newContact.appendChild(createAvatar(id));
newContact.appendChild(createDisplayNameParagraph("Participant"));
var clElement = contactlist.get(0);
if (resourceJid === Strophe.getResourceFromJid(connection.emuc.myroomjid)
&& $('#contactlist>ul .title')[0].nextSibling.nextSibling) {
clElement.insertBefore(newContact,
$('#contactlist>ul .title')[0].nextSibling.nextSibling);
}
else {
clElement.appendChild(newContact);
}
updateNumberOfParticipants(1);
},
/**
* Removes a contact for the given peer jid.
*
* @param peerJid the peerJid corresponding to the contact to remove
*/
removeContact: function (peerJid) {
var resourceJid = Strophe.getResourceFromJid(peerJid);
var contact = $('#contactlist>ul>li[id="' + resourceJid + '"]');
if (contact && contact.length > 0) {
var contactlist = $('#contactlist>ul');
contactlist.get(0).removeChild(contact.get(0));
updateNumberOfParticipants(-1);
}
},
setVisualNotification: function (show, stopGlowingIn) {
var glower = $('#contactListButton');
if (show && !notificationInterval) {
notificationInterval = window.setInterval(function () {
glower.toggleClass('active glowing');
}, 800);
}
else if (!show && notificationInterval) {
stopGlowing(glower);
}
if (stopGlowingIn) {
setTimeout(function () {
stopGlowing(glower);
}, stopGlowingIn);
}
},
setClickable: function (resourceJid, isClickable) {
var contact = $('#contactlist>ul>li[id="' + resourceJid + '"]');
if (isClickable) {
contact.addClass('clickable');
} else {
contact.removeClass('clickable');
}
};
}
};
return my;
}(ContactList || {}));
module.exports = ContactList;

View File

@ -0,0 +1,58 @@
var email = '';
var displayName = '';
var userId;
function supportsLocalStorage() {
try {
return 'localStorage' in window && window.localStorage !== null;
} catch (e) {
console.log("localstorage is not supported");
return false;
}
}
function generateUniqueId() {
function _p8() {
return (Math.random().toString(16)+"000000000").substr(2,8);
}
return _p8() + _p8() + _p8() + _p8();
}
if(supportsLocalStorage()) {
if(!window.localStorage.jitsiMeetId) {
window.localStorage.jitsiMeetId = generateUniqueId();
console.log("generated id", window.localStorage.jitsiMeetId);
}
userId = window.localStorage.jitsiMeetId || '';
email = window.localStorage.email || '';
displayName = window.localStorage.displayname || '';
} else {
console.log("local storage is not supported");
userId = generateUniqueId();
}
var Settings =
{
setDisplayName: function (newDisplayName) {
displayName = newDisplayName;
window.localStorage.displayname = displayName;
return displayName;
},
setEmail: function(newEmail)
{
email = newEmail;
window.localStorage.email = newEmail;
return email;
},
getSettings: function () {
return {
email: email,
displayName: displayName,
uid: userId
};
}
};
module.exports = Settings;

View File

@ -0,0 +1,42 @@
var Avatar = require("../../avatar/Avatar");
var Settings = require("./Settings");
var SettingsMenu = {
update: function() {
var newDisplayName = Util.escapeHtml($('#setDisplayName').get(0).value);
var newEmail = Util.escapeHtml($('#setEmail').get(0).value);
if(newDisplayName) {
var displayName = Settings.setDisplayName(newDisplayName);
connection.emuc.addDisplayNameToPresence(displayName);
}
connection.emuc.addEmailToPresence(newEmail);
var email = Settings.setEmail(newEmail);
connection.emuc.sendPresence();
Avatar.setUserAvatar(connection.emuc.myroomjid, email);
},
isVisible: function() {
return $('#settingsmenu').is(':visible');
},
setDisplayName: function(newDisplayName) {
var displayName = Settings.setDisplayName(newDisplayName);
$('#setDisplayName').get(0).value = displayName;
}
};
$(document).bind('displaynamechanged', function(event, peerJid, newDisplayName) {
if(peerJid === 'localVideoContainer' ||
peerJid === connection.emuc.myroomjid) {
SettingsMenu.setDisplayName(newDisplayName);
}
});
module.exports = SettingsMenu;

View File

@ -1,4 +1,23 @@
var PanelToggler = require("../side_pannels/SidePanelToggler");
var buttonHandlers = {
"bottom_toolbar_contact_list": function () {
BottomToolbar.toggleContactList();
},
"bottom_toolbar_film_strip": function () {
BottomToolbar.toggleFilmStrip();
},
"bottom_toolbar_chat": function () {
BottomToolbar.toggleChat();
}
};
var BottomToolbar = (function (my) {
my.init = function () {
for(var k in buttonHandlers)
$("#" + k).click(buttonHandlers[k]);
};
my.toggleChat = function() {
PanelToggler.toggleChat();
};
@ -20,3 +39,5 @@ var BottomToolbar = (function (my) {
return my;
}(BottomToolbar || {}));
module.exports = BottomToolbar;

View File

@ -1,7 +1,205 @@
/* global $, buttonClick, config, lockRoom, messageHandler, Moderator, roomUrl,
/* global $, buttonClick, config, lockRoom, Moderator,
setSharedKey, sharedKey, Util */
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 roomUrl = null;
var sharedKey = '';
var authenticationWindow = null;
var buttonHandlers =
{
"toolbar_button_mute": function () {
return toggleAudio();
},
"toolbar_button_camera": function () {
return toggleVideo();
},
"toolbar_button_authentication": function () {
return Toolbar.authenticateClicked();
},
"toolbar_button_record": function () {
return toggleRecording();
},
"toolbar_button_security": function () {
return Toolbar.openLockDialog();
},
"toolbar_button_link": function () {
return Toolbar.openLinkDialog();
},
"toolbar_button_chat": function () {
return BottomToolbar.toggleChat();
},
"toolbar_button_prezi": function () {
return Prezi.openPreziDialog();
},
"toolbar_button_etherpad": function () {
return Etherpad.toggleEtherpad(0);
},
"toolbar_button_desktopsharing": function () {
return toggleScreenSharing();
},
"toolbar_button_fullScreen": function()
{
buttonClick("#fullScreen", "icon-full-screen icon-exit-full-screen");
return Toolbar.toggleFullScreen();
},
"toolbar_button_sip": function () {
return callSipButtonClicked();
},
"toolbar_button_settings": function () {
PanelToggler.toggleSettingsMenu();
},
"toolbar_button_hangup": function () {
return hangup();
}
};
/**
* Starts or stops the recording for the conference.
*/
function toggleRecording() {
Recording.toggleRecording();
}
/**
* Locks / unlocks the room.
*/
function lockRoom(lock) {
var currentSharedKey = '';
if (lock)
currentSharedKey = sharedKey;
connection.emuc.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('Lock failed',
'Failed to lock conference.',
err);
Toolbar.setSharedKey('');
}, function () {
console.warn('room passwords not supported');
messageHandler.showError('Warning',
'Room passwords are currently not supported.');
Toolbar.setSharedKey('');
});
};
/**
* Invite participants to conference.
*/
function inviteParticipants() {
if (roomUrl === null)
return;
var sharedKeyText = "";
if (sharedKey && sharedKey.length > 0) {
sharedKeyText =
"This conference is password protected. Please use the " +
"following pin when joining:%0D%0A%0D%0A" +
sharedKey + "%0D%0A%0D%0A";
}
var conferenceName = roomUrl.substring(roomUrl.lastIndexOf('/') + 1);
var subject = "Invitation to a " + interfaceConfig.APP_NAME + " (" + conferenceName + ")";
var body = "Hey there, I%27d like to invite you to a " + interfaceConfig.APP_NAME +
" conference I%27ve just set up.%0D%0A%0D%0A" +
"Please click on the following link in order" +
" to join the conference.%0D%0A%0D%0A" +
roomUrl +
"%0D%0A%0D%0A" +
sharedKeyText +
"Note that " + interfaceConfig.APP_NAME + " is currently" +
" only supported by Chromium," +
" Google Chrome and Opera, so you need" +
" to be using one of these browsers.%0D%0A%0D%0A" +
"Talk to you in a sec!";
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');
}
var Toolbar = (function (my) {
my.init = function () {
for(var k in buttonHandlers)
$("#" + k).click(buttonHandlers[k]);
}
/**
* Sets shared key
* @param sKey the shared key
*/
my.setSharedKey = function (sKey) {
sharedKey = sKey;
};
my.closeAuthenticationWindow = function () {
if (authenticationWindow) {
authenticationWindow.close();
authenticationWindow = null;
}
}
my.authenticateClicked = function () {
// Get authentication URL
Moderator.getAuthUrl(function (url) {
// Open popup with authentication URL
authenticationWindow = messageHandler.openCenteredPopup(
url, 500, 400,
function () {
// On popup closed - retry room allocation
Moderator.allocateConferenceFocus(
roomName, doJoinAfterFocus);
authenticationWindow = null;
});
if (!authenticationWindow) {
Toolbar.showAuthenticateButton(true);
messageHandler.openMessageDialog(
null, "Your browser is blocking popup windows from this site." +
" Please enable popups in your browser security settings" +
" and try again.");
}
});
};
/**
* Updates the room invite url.
*/
my.updateRoomUrl = function (newRoomUrl) {
roomUrl = newRoomUrl;
// If the invite dialog has been already opened we update the information.
var inviteLink = document.getElementById('inviteLinkRef');
if (inviteLink) {
inviteLink.value = roomUrl;
inviteLink.select();
document.getElementById('jqi_state0_buttonInvite').disabled = false;
}
}
/**
* Disables and enables some of the buttons.
*/
@ -41,7 +239,7 @@ var Toolbar = (function (my) {
"Remove",
function (e, v) {
if (v) {
setSharedKey('');
Toolbar.setSharedKey('');
lockRoom(false);
}
});
@ -57,7 +255,7 @@ var Toolbar = (function (my) {
var lockKey = document.getElementById('lockKey');
if (lockKey.value) {
setSharedKey(Util.escapeHtml(lockKey.value));
Toolbar.setSharedKey(Util.escapeHtml(lockKey.value));
lockRoom(true);
}
}
@ -104,47 +302,6 @@ var Toolbar = (function (my) {
);
};
/**
* Invite participants to conference.
*/
function inviteParticipants() {
if (roomUrl === null)
return;
var sharedKeyText = "";
if (sharedKey && sharedKey.length > 0) {
sharedKeyText =
"This conference is password protected. Please use the " +
"following pin when joining:%0D%0A%0D%0A" +
sharedKey + "%0D%0A%0D%0A";
}
var conferenceName = roomUrl.substring(roomUrl.lastIndexOf('/') + 1);
var subject = "Invitation to a " + interfaceConfig.APP_NAME + " (" + conferenceName + ")";
var body = "Hey there, I%27d like to invite you to a " + interfaceConfig.APP_NAME +
" conference I%27ve just set up.%0D%0A%0D%0A" +
"Please click on the following link in order" +
" to join the conference.%0D%0A%0D%0A" +
roomUrl +
"%0D%0A%0D%0A" +
sharedKeyText +
"Note that " + interfaceConfig.APP_NAME + " is currently" +
" only supported by Chromium," +
" Google Chrome and Opera, so you need" +
" to be using one of these browsers.%0D%0A%0D%0A" +
"Talk to you in a sec!";
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');
}
/**
* Opens the settings dialog.
*/
@ -291,3 +448,5 @@ var Toolbar = (function (my) {
return my;
}(Toolbar || {}));
module.exports = Toolbar;

View File

@ -1,45 +1,12 @@
/* global $, interfaceConfig, Moderator, showDesktopSharingButton */
var ToolbarToggler = (function (my) {
var toolbarTimeoutObject,
var toolbarTimeoutObject,
toolbarTimeout = interfaceConfig.INITIAL_TOOLBAR_TIMEOUT;
/**
* Shows the main toolbar.
*/
my.showToolbar = function () {
var header = $("#header"),
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});
}
if (toolbarTimeoutObject) {
clearTimeout(toolbarTimeoutObject);
toolbarTimeoutObject = null;
}
toolbarTimeoutObject = setTimeout(hideToolbar, toolbarTimeout);
toolbarTimeout = interfaceConfig.TOOLBAR_TIMEOUT;
}
if (Moderator.isModerator())
{
// TODO: Enable settings functionality.
// Need to uncomment the settings button in index.html.
// $('#settingsButton').css({visibility:"visible"});
}
// Show/hide desktop sharing button
showDesktopSharingButton();
};
/**
/**
* Hides the toolbar.
*/
var hideToolbar = function () {
function hideToolbar() {
var header = $("#header"),
bottomToolbar = $("#bottomToolbar");
var isToolbarHover = false;
@ -67,7 +34,41 @@ var ToolbarToggler = (function (my) {
else {
toolbarTimeoutObject = setTimeout(hideToolbar, toolbarTimeout);
}
};
}
var ToolbarToggler = {
/**
* Shows the main toolbar.
*/
showToolbar: function () {
var header = $("#header"),
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});
}
if (toolbarTimeoutObject) {
clearTimeout(toolbarTimeoutObject);
toolbarTimeoutObject = null;
}
toolbarTimeoutObject = setTimeout(hideToolbar, toolbarTimeout);
toolbarTimeout = interfaceConfig.TOOLBAR_TIMEOUT;
}
if (Moderator.isModerator())
{
// TODO: Enable settings functionality.
// Need to uncomment the settings button in index.html.
// $('#settingsButton').css({visibility:"visible"});
}
// Show/hide desktop sharing button
showDesktopSharingButton();
},
/**
@ -75,11 +76,11 @@ var ToolbarToggler = (function (my) {
*
* @param isDock indicates what operation to perform
*/
my.dockToolbar = function (isDock) {
dockToolbar: function (isDock) {
if (isDock) {
// First make sure the toolbar is shown.
if (!$('#header').is(':visible')) {
ToolbarToggler.showToolbar();
this.showToolbar();
}
// Then clear the time out, to dock the toolbar.
@ -90,14 +91,14 @@ var ToolbarToggler = (function (my) {
}
else {
if (!$('#header').is(':visible')) {
ToolbarToggler.showToolbar();
this.showToolbar();
}
else {
toolbarTimeoutObject = setTimeout(hideToolbar, toolbarTimeout);
}
}
};
}
};
return my;
}(ToolbarToggler || {}));
module.exports = ToolbarToggler;

View File

@ -119,3 +119,5 @@ var JitsiPopover = (function () {
})();
module.exports = JitsiPopover;

View File

@ -149,4 +149,6 @@ var messageHandler = (function(my) {
return my;
}(messageHandler || {}));
module.exports = messageHandler;

16
modules/UI/util/UIUtil.js Normal file
View File

@ -0,0 +1,16 @@
/**
* Created by hristo on 12/22/14.
*/
module.exports = {
/**
* Returns the available video width.
*/
getAvailableVideoWidth: function () {
var PanelToggler = require("../side_pannels/SidePanelToggler");
var rightPanelWidth
= PanelToggler.isVisible() ? PanelToggler.getPanelSize()[0] : 0;
return window.innerWidth - rightPanelWidth;
}
};

View File

@ -0,0 +1,410 @@
var JitsiPopover = require("../util/JitsiPopover");
/**
* Constructs new connection indicator.
* @param videoContainer the video container associated with the indicator.
* @constructor
*/
function ConnectionIndicator(videoContainer, jid, VideoLayout)
{
this.videoContainer = videoContainer;
this.bandwidth = null;
this.packetLoss = null;
this.bitrate = null;
this.showMoreValue = false;
this.resolution = null;
this.transport = [];
this.popover = null;
this.jid = jid;
this.create();
this.videoLayout = VideoLayout;
}
/**
* Values for the connection quality
* @type {{98: string,
* 81: string,
* 64: string,
* 47: string,
* 30: string,
* 0: string}}
*/
ConnectionIndicator.connectionQualityValues = {
98: "18px", //full
81: "15px",//4 bars
64: "11px",//3 bars
47: "7px",//2 bars
30: "3px",//1 bar
0: "0px"//empty
};
ConnectionIndicator.getIP = function(value)
{
return value.substring(0, value.lastIndexOf(":"));
};
ConnectionIndicator.getPort = function(value)
{
return value.substring(value.lastIndexOf(":") + 1, value.length);
};
ConnectionIndicator.getStringFromArray = function (array) {
var res = "";
for(var i = 0; i < array.length; i++)
{
res += (i === 0? "" : ", ") + array[i];
}
return res;
};
/**
* Generates the html content.
* @returns {string} the html content.
*/
ConnectionIndicator.prototype.generateText = function () {
var downloadBitrate, uploadBitrate, packetLoss, resolution, i;
if(this.bitrate === null)
{
downloadBitrate = "N/A";
uploadBitrate = "N/A";
}
else
{
downloadBitrate =
this.bitrate.download? this.bitrate.download + " Kbps" : "N/A";
uploadBitrate =
this.bitrate.upload? this.bitrate.upload + " Kbps" : "N/A";
}
if(this.packetLoss === null)
{
packetLoss = "N/A";
}
else
{
packetLoss = "<span class='jitsipopover_green'>&darr;</span>" +
(this.packetLoss.download !== null? this.packetLoss.download : "N/A") +
"% <span class='jitsipopover_orange'>&uarr;</span>" +
(this.packetLoss.upload !== null? this.packetLoss.upload : "N/A") + "%";
}
var resolutionValue = null;
if(this.resolution)
{
var keys = Object.keys(this.resolution);
if(keys.length == 1)
{
for(var ssrc in this.resolution)
{
resolutionValue = this.resolution[ssrc];
}
}
else if(keys.length > 1)
{
var displayedSsrc = simulcast.getReceivingSSRC(this.jid);
resolutionValue = this.resolution[displayedSsrc];
}
}
if(this.jid === null)
{
resolution = "";
if(this.resolution === null || !Object.keys(this.resolution) ||
Object.keys(this.resolution).length === 0)
{
resolution = "N/A";
}
else
for(i in this.resolution)
{
resolutionValue = this.resolution[i];
if(resolutionValue)
{
if(resolutionValue.height &&
resolutionValue.width)
{
resolution += (resolution === ""? "" : ", ") +
resolutionValue.width + "x" +
resolutionValue.height;
}
}
}
}
else if(!resolutionValue ||
!resolutionValue.height ||
!resolutionValue.width)
{
resolution = "N/A";
}
else
{
resolution = resolutionValue.width + "x" + resolutionValue.height;
}
var result = "<table style='width:100%'>" +
"<tr>" +
"<td><span class='jitsipopover_blue'>Bitrate:</span></td>" +
"<td><span class='jitsipopover_green'>&darr;</span>" +
downloadBitrate + " <span class='jitsipopover_orange'>&uarr;</span>" +
uploadBitrate + "</td>" +
"</tr><tr>" +
"<td><span class='jitsipopover_blue'>Packet loss: </span></td>" +
"<td>" + packetLoss + "</td>" +
"</tr><tr>" +
"<td><span class='jitsipopover_blue'>Resolution:</span></td>" +
"<td>" + resolution + "</td></tr></table>";
if(this.videoContainer.id == "localVideoContainer")
result += "<div class=\"jitsipopover_showmore\" " +
"onclick = \"UI.connectionIndicatorShowMore('" +
this.videoContainer.id + "')\">" +
(this.showMoreValue? "Show less" : "Show More") + "</div><br />";
if(this.showMoreValue)
{
var downloadBandwidth, uploadBandwidth, transport;
if(this.bandwidth === null)
{
downloadBandwidth = "N/A";
uploadBandwidth = "N/A";
}
else
{
downloadBandwidth = this.bandwidth.download?
this.bandwidth.download + " Kbps" :
"N/A";
uploadBandwidth = this.bandwidth.upload?
this.bandwidth.upload + " Kbps" :
"N/A";
}
if(!this.transport || this.transport.length === 0)
{
transport = "<tr>" +
"<td><span class='jitsipopover_blue'>Address:</span></td>" +
"<td> N/A</td></tr>";
}
else
{
var data = {remoteIP: [], localIP:[], remotePort:[], localPort:[]};
for(i = 0; i < this.transport.length; i++)
{
var ip = ConnectionIndicator.getIP(this.transport[i].ip);
var port = ConnectionIndicator.getPort(this.transport[i].ip);
var localIP =
ConnectionIndicator.getIP(this.transport[i].localip);
var localPort =
ConnectionIndicator.getPort(this.transport[i].localip);
if(data.remoteIP.indexOf(ip) == -1)
{
data.remoteIP.push(ip);
}
if(data.remotePort.indexOf(port) == -1)
{
data.remotePort.push(port);
}
if(data.localIP.indexOf(localIP) == -1)
{
data.localIP.push(localIP);
}
if(data.localPort.indexOf(localPort) == -1)
{
data.localPort.push(localPort);
}
}
var localTransport =
"<tr><td><span class='jitsipopover_blue'>Local address" +
(data.localIP.length > 1? "es" : "") + ": </span></td><td> " +
ConnectionIndicator.getStringFromArray(data.localIP) +
"</td></tr>";
transport =
"<tr><td><span class='jitsipopover_blue'>Remote address"+
(data.remoteIP.length > 1? "es" : "") + ":</span></td><td> " +
ConnectionIndicator.getStringFromArray(data.remoteIP) +
"</td></tr>";
if(this.transport.length > 1)
{
transport += "<tr>" +
"<td>" +
"<span class='jitsipopover_blue'>Remote ports:</span>" +
"</td><td>";
localTransport += "<tr>" +
"<td>" +
"<span class='jitsipopover_blue'>Local ports:</span>" +
"</td><td>";
}
else
{
transport +=
"<tr>" +
"<td>" +
"<span class='jitsipopover_blue'>Remote port:</span>" +
"</td><td>";
localTransport +=
"<tr>" +
"<td>" +
"<span class='jitsipopover_blue'>Local port:</span>" +
"</td><td>";
}
transport +=
ConnectionIndicator.getStringFromArray(data.remotePort);
localTransport +=
ConnectionIndicator.getStringFromArray(data.localPort);
transport += "</td></tr>";
transport += localTransport + "</td></tr>";
transport +="<tr>" +
"<td><span class='jitsipopover_blue'>Transport:</span></td>" +
"<td>" + this.transport[0].type + "</td></tr>";
}
result += "<table style='width:100%'>" +
"<tr>" +
"<td>" +
"<span class='jitsipopover_blue'>Estimated bandwidth:</span>" +
"</td><td>" +
"<span class='jitsipopover_green'>&darr;</span>" +
downloadBandwidth +
" <span class='jitsipopover_orange'>&uarr;</span>" +
uploadBandwidth + "</td></tr>";
result += transport + "</table>";
}
return result;
};
/**
* Shows or hide the additional information.
*/
ConnectionIndicator.prototype.showMore = function () {
this.showMoreValue = !this.showMoreValue;
this.updatePopoverData();
};
function createIcon(classes)
{
var icon = document.createElement("span");
for(var i in classes)
{
icon.classList.add(classes[i]);
}
icon.appendChild(
document.createElement("i")).classList.add("icon-connection");
return icon;
}
/**
* Creates the indicator
*/
ConnectionIndicator.prototype.create = function () {
this.connectionIndicatorContainer = document.createElement("div");
this.connectionIndicatorContainer.className = "connectionindicator";
this.connectionIndicatorContainer.style.display = "none";
this.videoContainer.appendChild(this.connectionIndicatorContainer);
this.popover = new JitsiPopover(
$("#" + this.videoContainer.id + " > .connectionindicator"),
{content: "<div class=\"connection_info\">Come back here for " +
"connection information once the conference starts</div>",
skin: "black"});
this.emptyIcon = this.connectionIndicatorContainer.appendChild(
createIcon(["connection", "connection_empty"]));
this.fullIcon = this.connectionIndicatorContainer.appendChild(
createIcon(["connection", "connection_full"]));
};
/**
* Removes the indicator
*/
ConnectionIndicator.prototype.remove = function()
{
this.connectionIndicatorContainer.remove();
this.popover.forceHide();
};
/**
* Updates the data of the indicator
* @param percent the percent of connection quality
* @param object the statistics data.
*/
ConnectionIndicator.prototype.updateConnectionQuality =
function (percent, object) {
if(percent === null)
{
this.connectionIndicatorContainer.style.display = "none";
this.popover.forceHide();
return;
}
else
{
if(this.connectionIndicatorContainer.style.display == "none") {
this.connectionIndicatorContainer.style.display = "block";
this.videoLayout.updateMutePosition(this.videoContainer.id);
}
}
this.bandwidth = object.bandwidth;
this.bitrate = object.bitrate;
this.packetLoss = object.packetLoss;
this.transport = object.transport;
if(object.resolution)
{
this.resolution = object.resolution;
}
for(var quality in ConnectionIndicator.connectionQualityValues)
{
if(percent >= quality)
{
this.fullIcon.style.width =
ConnectionIndicator.connectionQualityValues[quality];
}
}
this.updatePopoverData();
};
/**
* Updates the resolution
* @param resolution the new resolution
*/
ConnectionIndicator.prototype.updateResolution = function (resolution) {
this.resolution = resolution;
this.updatePopoverData();
};
/**
* Updates the content of the popover
*/
ConnectionIndicator.prototype.updatePopoverData = function () {
this.popover.updateContent(
"<div class=\"connection_info\">" + this.generateText() + "</div>");
};
/**
* Hides the popover
*/
ConnectionIndicator.prototype.hide = function () {
this.popover.forceHide();
};
/**
* Hides the indicator
*/
ConnectionIndicator.prototype.hideIndicator = function () {
this.connectionIndicatorContainer.style.display = "none";
if(this.popover)
this.popover.forceHide();
};
module.exports = ConnectionIndicator;

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,179 @@
//var nouns = [
//];
var pluralNouns = [
"Aliens", "Animals", "Antelopes", "Ants", "Apes", "Apples", "Baboons", "Bacteria", "Badgers", "Bananas", "Bats",
"Bears", "Birds", "Bonobos", "Brides", "Bugs", "Bulls", "Butterflies", "Cheetahs",
"Cherries", "Chicken", "Children", "Chimps", "Clowns", "Cows", "Creatures", "Dinosaurs", "Dogs", "Dolphins",
"Donkeys", "Dragons", "Ducks", "Dwarfs", "Eagles", "Elephants", "Elves", "FAIL", "Fathers",
"Fish", "Flowers", "Frogs", "Fruit", "Fungi", "Galaxies", "Geese", "Goats",
"Gorillas", "Hedgehogs", "Hippos", "Horses", "Hunters", "Insects", "Kids", "Knights",
"Lemons", "Lemurs", "Leopards", "LifeForms", "Lions", "Lizards", "Mice", "Monkeys", "Monsters",
"Mushrooms", "Octopodes", "Oranges", "Orangutans", "Organisms", "Pants", "Parrots", "Penguins",
"People", "Pigeons", "Pigs", "Pineapples", "Plants", "Potatoes", "Priests", "Rats", "Reptiles", "Reptilians",
"Rhinos", "Seagulls", "Sheep", "Siblings", "Snakes", "Spaghetti", "Spiders", "Squid", "Squirrels",
"Stars", "Students", "Teachers", "Tigers", "Tomatoes", "Trees", "Vampires", "Vegetables", "Viruses", "Vulcans",
"Warewolves", "Weasels", "Whales", "Witches", "Wizards", "Wolves", "Workers", "Worms", "Zebras"
];
//var places = [
//"Pub", "University", "Airport", "Library", "Mall", "Theater", "Stadium", "Office", "Show", "Gallows", "Beach",
// "Cemetery", "Hospital", "Reception", "Restaurant", "Bar", "Church", "House", "School", "Square", "Village",
// "Cinema", "Movies", "Party", "Restroom", "End", "Jail", "PostOffice", "Station", "Circus", "Gates", "Entrance",
// "Bridge"
//];
var verbs = [
"Abandon", "Adapt", "Advertise", "Answer", "Anticipate", "Appreciate",
"Approach", "Argue", "Ask", "Bite", "Blossom", "Blush", "Breathe", "Breed", "Bribe", "Burn", "Calculate",
"Clean", "Code", "Communicate", "Compute", "Confess", "Confiscate", "Conjugate", "Conjure", "Consume",
"Contemplate", "Crawl", "Dance", "Delegate", "Devour", "Develop", "Differ", "Discuss",
"Dissolve", "Drink", "Eat", "Elaborate", "Emancipate", "Estimate", "Expire", "Extinguish",
"Extract", "FAIL", "Facilitate", "Fall", "Feed", "Finish", "Floss", "Fly", "Follow", "Fragment", "Freeze",
"Gather", "Glow", "Grow", "Hex", "Hide", "Hug", "Hurry", "Improve", "Intersect", "Investigate", "Jinx",
"Joke", "Jubilate", "Kiss", "Laugh", "Manage", "Meet", "Merge", "Move", "Object", "Observe", "Offer",
"Paint", "Participate", "Party", "Perform", "Plan", "Pursue", "Pierce", "Play", "Postpone", "Pray", "Proclaim",
"Question", "Read", "Reckon", "Rejoice", "Represent", "Resize", "Rhyme", "Scream", "Search", "Select", "Share", "Shoot",
"Shout", "Signal", "Sing", "Skate", "Sleep", "Smile", "Smoke", "Solve", "Spell", "Steer", "Stink",
"Substitute", "Swim", "Taste", "Teach", "Terminate", "Think", "Type", "Unite", "Vanish", "Worship"
];
var adverbs = [
"Absently", "Accurately", "Accusingly", "Adorably", "AllTheTime", "Alone", "Always", "Amazingly", "Angrily",
"Anxiously", "Anywhere", "Appallingly", "Apparently", "Articulately", "Astonishingly", "Badly", "Barely",
"Beautifully", "Blindly", "Bravely", "Brightly", "Briskly", "Brutally", "Calmly", "Carefully", "Casually",
"Cautiously", "Cleverly", "Constantly", "Correctly", "Crazily", "Curiously", "Cynically", "Daily",
"Dangerously", "Deliberately", "Delicately", "Desperately", "Discreetly", "Eagerly", "Easily", "Euphoricly",
"Evenly", "Everywhere", "Exactly", "Expectantly", "Extensively", "FAIL", "Ferociously", "Fiercely", "Finely",
"Flatly", "Frequently", "Frighteningly", "Gently", "Gloriously", "Grimly", "Guiltily", "Happily",
"Hard", "Hastily", "Heroically", "High", "Highly", "Hourly", "Humbly", "Hysterically", "Immensely",
"Impartially", "Impolitely", "Indifferently", "Intensely", "Jealously", "Jovially", "Kindly", "Lazily",
"Lightly", "Loudly", "Lovingly", "Loyally", "Magnificently", "Malevolently", "Merrily", "Mightily", "Miserably",
"Mysteriously", "NOT", "Nervously", "Nicely", "Nowhere", "Objectively", "Obnoxiously", "Obsessively",
"Obviously", "Often", "Painfully", "Patiently", "Playfully", "Politely", "Poorly", "Precisely", "Promptly",
"Quickly", "Quietly", "Randomly", "Rapidly", "Rarely", "Recklessly", "Regularly", "Remorsefully", "Responsibly",
"Rudely", "Ruthlessly", "Sadly", "Scornfully", "Seamlessly", "Seldom", "Selfishly", "Seriously", "Shakily",
"Sharply", "Sideways", "Silently", "Sleepily", "Slightly", "Slowly", "Slyly", "Smoothly", "Softly", "Solemnly", "Steadily", "Sternly", "Strangely", "Strongly", "Stunningly", "Surely", "Tenderly", "Thoughtfully",
"Tightly", "Uneasily", "Vanishingly", "Violently", "Warmly", "Weakly", "Wearily", "Weekly", "Weirdly", "Well",
"Well", "Wickedly", "Wildly", "Wisely", "Wonderfully", "Yearly"
];
var adjectives = [
"Abominable", "Accurate", "Adorable", "All", "Alleged", "Ancient", "Angry", "Angry", "Anxious", "Appalling",
"Apparent", "Astonishing", "Attractive", "Awesome", "Baby", "Bad", "Beautiful", "Benign", "Big", "Bitter",
"Blind", "Blue", "Bold", "Brave", "Bright", "Brisk", "Calm", "Camouflaged", "Casual", "Cautious",
"Choppy", "Chosen", "Clever", "Cold", "Cool", "Crawly", "Crazy", "Creepy", "Cruel", "Curious", "Cynical",
"Dangerous", "Dark", "Delicate", "Desperate", "Difficult", "Discreet", "Disguised", "Dizzy",
"Dumb", "Eager", "Easy", "Edgy", "Electric", "Elegant", "Emancipated", "Enormous", "Euphoric", "Evil",
"FAIL", "Fast", "Ferocious", "Fierce", "Fine", "Flawed", "Flying", "Foolish", "Foxy",
"Freezing", "Funny", "Furious", "Gentle", "Glorious", "Golden", "Good", "Green", "Green", "Guilty",
"Hairy", "Happy", "Hard", "Hasty", "Hazy", "Heroic", "Hostile", "Hot", "Humble", "Humongous",
"Humorous", "Hysterical", "Idealistic", "Ignorant", "Immense", "Impartial", "Impolite", "Indifferent",
"Infuriated", "Insightful", "Intense", "Interesting", "Intimidated", "Intriguing", "Jealous", "Jolly", "Jovial",
"Jumpy", "Kind", "Laughing", "Lazy", "Liquid", "Lonely", "Longing", "Loud", "Loving", "Loyal", "Macabre", "Mad",
"Magical", "Magnificent", "Malevolent", "Medieval", "Memorable", "Mere", "Merry", "Mighty",
"Mischievous", "Miserable", "Modified", "Moody", "Most", "Mysterious", "Mystical", "Needy",
"Nervous", "Nice", "Objective", "Obnoxious", "Obsessive", "Obvious", "Opinionated", "Orange",
"Painful", "Passionate", "Perfect", "Pink", "Playful", "Poisonous", "Polite", "Poor", "Popular", "Powerful",
"Precise", "Preserved", "Pretty", "Purple", "Quick", "Quiet", "Random", "Rapid", "Rare", "Real",
"Reassuring", "Reckless", "Red", "Regular", "Remorseful", "Responsible", "Rich", "Rude", "Ruthless",
"Sad", "Scared", "Scary", "Scornful", "Screaming", "Selfish", "Serious", "Shady", "Shaky", "Sharp",
"Shiny", "Shy", "Simple", "Sleepy", "Slow", "Sly", "Small", "Smart", "Smelly", "Smiling", "Smooth",
"Smug", "Sober", "Soft", "Solemn", "Square", "Square", "Steady", "Strange", "Strong",
"Stunning", "Subjective", "Successful", "Surly", "Sweet", "Tactful", "Tense",
"Thoughtful", "Tight", "Tiny", "Tolerant", "Uneasy", "Unique", "Unseen", "Warm", "Weak",
"Weird", "WellCooked", "Wild", "Wise", "Witty", "Wonderful", "Worried", "Yellow", "Young",
"Zealous"
];
//var pronouns = [
//];
//var conjunctions = [
//"And", "Or", "For", "Above", "Before", "Against", "Between"
//];
/*
* Maps a string (category name) to the array of words from that category.
*/
var CATEGORIES =
{
//"_NOUN_": nouns,
"_PLURALNOUN_": pluralNouns,
//"_PLACE_": places,
"_VERB_": verbs,
"_ADVERB_": adverbs,
"_ADJECTIVE_": adjectives
//"_PRONOUN_": pronouns,
//"_CONJUNCTION_": conjunctions,
};
var PATTERNS = [
"_ADJECTIVE__PLURALNOUN__VERB__ADVERB_"
// BeautifulFungiOrSpaghetti
//"_ADJECTIVE__PLURALNOUN__CONJUNCTION__PLURALNOUN_",
// AmazinglyScaryToy
//"_ADVERB__ADJECTIVE__NOUN_",
// NeitherTrashNorRifle
//"Neither_NOUN_Nor_NOUN_",
//"Either_NOUN_Or_NOUN_",
// EitherCopulateOrInvestigate
//"Either_VERB_Or_VERB_",
//"Neither_VERB_Nor_VERB_",
//"The_ADJECTIVE__ADJECTIVE__NOUN_",
//"The_ADVERB__ADJECTIVE__NOUN_",
//"The_ADVERB__ADJECTIVE__NOUN_s",
//"The_ADVERB__ADJECTIVE__PLURALNOUN__VERB_",
// WolvesComputeBadly
//"_PLURALNOUN__VERB__ADVERB_",
// UniteFacilitateAndMerge
//"_VERB__VERB_And_VERB_",
//NastyWitchesAtThePub
//"_ADJECTIVE__PLURALNOUN_AtThe_PLACE_",
];
/*
* Returns a random element from the array 'arr'
*/
function randomElement(arr)
{
return arr[Math.floor(Math.random() * arr.length)];
}
/*
* Returns true if the string 's' contains one of the
* template strings.
*/
function hasTemplate(s)
{
for (var template in CATEGORIES){
if (s.indexOf(template) >= 0){
return true;
}
}
}
/**
* Generates new room name.
*/
var RoomNameGenerator = {
generateRoomWithoutSeparator: function()
{
// Note that if more than one pattern is available, the choice of 'name' won't be random (names from patterns
// with fewer options will have higher probability of being chosen that names from patterns with more options).
var name = randomElement(PATTERNS);
var word;
while (hasTemplate(name)){
for (var template in CATEGORIES){
word = randomElement(CATEGORIES[template]);
name = name.replace(template, word);
}
}
return name;
}
}
module.exports = RoomNameGenerator;

View File

@ -0,0 +1,103 @@
var animateTimeout, updateTimeout;
var RoomNameGenerator = require("./RoomnameGenerator");
function enter_room()
{
var val = $("#enter_room_field").val();
if(!val) {
val = $("#enter_room_field").attr("room_name");
}
if (val) {
window.location.pathname = "/" + val;
}
}
function animate(word) {
var currentVal = $("#enter_room_field").attr("placeholder");
$("#enter_room_field").attr("placeholder", currentVal + word.substr(0, 1));
animateTimeout = setTimeout(function() {
animate(word.substring(1, word.length))
}, 70);
}
function update_roomname()
{
var word = RoomNameGenerator.generateRoomWithoutSeparator();
$("#enter_room_field").attr("room_name", word);
$("#enter_room_field").attr("placeholder", "");
clearTimeout(animateTimeout);
animate(word);
updateTimeout = setTimeout(update_roomname, 10000);
}
function setupWelcomePage()
{
$("#videoconference_page").hide();
$("#domain_name").text(
window.location.protocol + "//" + window.location.host + "/");
$("span[name='appName']").text(interfaceConfig.APP_NAME);
if (interfaceConfig.SHOW_JITSI_WATERMARK) {
var leftWatermarkDiv
= $("#welcome_page_header div[class='watermark leftwatermark']");
if(leftWatermarkDiv && leftWatermarkDiv.length > 0)
{
leftWatermarkDiv.css({display: 'block'});
leftWatermarkDiv.parent().get(0).href
= interfaceConfig.JITSI_WATERMARK_LINK;
}
}
if (interfaceConfig.SHOW_BRAND_WATERMARK) {
var rightWatermarkDiv
= $("#welcome_page_header div[class='watermark rightwatermark']");
if(rightWatermarkDiv && rightWatermarkDiv.length > 0) {
rightWatermarkDiv.css({display: 'block'});
rightWatermarkDiv.parent().get(0).href
= interfaceConfig.BRAND_WATERMARK_LINK;
rightWatermarkDiv.get(0).style.backgroundImage
= "url(images/rightwatermark.png)";
}
}
if (interfaceConfig.SHOW_POWERED_BY) {
$("#welcome_page_header>a[class='poweredby']")
.css({display: 'block'});
}
$("#enter_room_button").click(function()
{
enter_room();
});
$("#enter_room_field").keydown(function (event) {
if (event.keyCode === 13 /* enter */) {
enter_room();
}
});
if (!(interfaceConfig.GENERATE_ROOMNAMES_ON_WELCOME_PAGE === false)){
var updateTimeout;
var animateTimeout;
$("#reload_roomname").click(function () {
clearTimeout(updateTimeout);
clearTimeout(animateTimeout);
update_roomname();
});
$("#reload_roomname").show();
update_roomname();
}
$("#disable_welcome").click(function () {
window.localStorage.welcomePageDisabled
= $("#disable_welcome").is(":checked");
});
}
module.exports = setupWelcomePage;

View File

@ -51,10 +51,10 @@ function startRemoteStats (peerconnection) {
function onStreamCreated(stream)
{
if(stream.getAudioTracks().length === 0)
if(stream.getOriginalStream().getAudioTracks().length === 0)
return;
localStats = new LocalStats(stream, 100, this,
localStats = new LocalStats(stream.getOriginalStream(), 100, statistics,
eventEmitter);
localStats.start();
}

112
muc.js
View File

@ -49,6 +49,7 @@ Strophe.addConnectionPlugin('emuc', {
onPresence: function (pres) {
var from = pres.getAttribute('from');
var type = pres.getAttribute('type');
console.debug("Presence " + from + " - " + type);
if (type != null) {
return true;
}
@ -56,7 +57,9 @@ Strophe.addConnectionPlugin('emuc', {
// Parse etherpad tag.
var etherpad = $(pres).find('>etherpad');
if (etherpad.length) {
$(document).trigger('etherpadadded.muc', [from, etherpad.text()]);
if (config.etherpad_base && !Moderator.isModerator()) {
UI.initEtherpad(etherpad.text());
}
}
// Parse prezi tag.
@ -138,24 +141,40 @@ Strophe.addConnectionPlugin('emuc', {
if (member.affiliation == 'owner') this.isOwner = true;
if (this.role !== member.role) {
this.role = member.role;
$(document).trigger('local.role.changed.muc', [from, member, pres]);
if(Moderator.onLocalRoleChange)
Moderator.onLocalRoleChange(from, member, pres);
UI.onLocalRoleChange(from, member, pres);
}
if (!this.joined) {
this.joined = true;
$(document).trigger('joined.muc', [from, member]);
UI.onMucJoined(from, member);
this.list_members.push(from);
}
} else if (this.members[from] === undefined) {
// new participant
this.members[from] = member;
this.list_members.push(from);
$(document).trigger('entered.muc', [from, member, pres]);
console.log('entered', from, member);
if (member.isFocus)
{
focusMucJid = from;
console.info("Ignore focus: " + from +", real JID: " + member.jid);
}
else {
var id = $(pres).find('>userID').text();
var email = $(pres).find('>email');
if (email.length > 0) {
id = email.text();
}
UI.onMucEntered(from, id, member.displayName);
}
} else {
// Presence update for existing participant
// Watch role change:
if (this.members[from].role != member.role) {
this.members[from].role = member.role
$(document).trigger('role.changed.muc', [from, member, pres]);
this.members[from].role = member.role;
UI.onMucRoleChanged(member.role, member.displayName);
}
}
// Always trigger presence to update bindings
@ -164,7 +183,7 @@ Strophe.addConnectionPlugin('emuc', {
// Trigger status message update
if (member.status) {
$(document).trigger('presence.status.muc', [from, member, pres]);
UI.onMucPresenceStatus(from, member);
}
return true;
@ -175,7 +194,7 @@ Strophe.addConnectionPlugin('emuc', {
if (!$(pres).find('>x[xmlns="http://jabber.org/protocol/muc#user"]>status[code="110"]').length) {
delete this.members[from];
this.list_members.splice(this.list_members.indexOf(from), 1);
$(document).trigger('left.muc', [from]);
this.onParticipantLeft(from);
}
// If the status code is 110 this means we're leaving and we would like
// to remove everyone else from our view, so we trigger the event.
@ -184,7 +203,7 @@ Strophe.addConnectionPlugin('emuc', {
var member = this.list_members[i];
delete this.members[i];
this.list_members.splice(i, 1);
$(document).trigger('left.muc', member);
this.onParticipantLeft(member);
}
}
if ($(pres).find('>x[xmlns="http://jabber.org/protocol/muc#user"]>status[code="307"]').length) {
@ -195,7 +214,11 @@ Strophe.addConnectionPlugin('emuc', {
onPresenceError: function (pres) {
var from = pres.getAttribute('from');
if ($(pres).find('>error[type="auth"]>not-authorized[xmlns="urn:ietf:params:xml:ns:xmpp-stanzas"]').length) {
$(document).trigger('passwordrequired.muc', [from]);
console.log('on password required', from);
UI.onPasswordReqiured(function (value) {
connection.emuc.doJoin(from, value);
})
} else if ($(pres).find(
'>error[type="cancel"]>not-allowed[xmlns="urn:ietf:params:xml:ns:xmpp-stanzas"]').length) {
var toDomain = Strophe.getDomainFromJid(pres.getAttribute('to'));
@ -205,13 +228,13 @@ Strophe.addConnectionPlugin('emuc', {
$(document).trigger('passwordrequired.main');
} else {
console.warn('onPresError ', pres);
messageHandler.openReportDialog(null,
UI.messageHandler.openReportDialog(null,
'Oops! Something went wrong and we couldn`t connect to the conference.',
pres);
}
} else {
console.warn('onPresError ', pres);
messageHandler.openReportDialog(null,
UI.messageHandler.openReportDialog(null,
'Oops! Something went wrong and we couldn`t connect to the conference.',
pres);
}
@ -244,7 +267,7 @@ Strophe.addConnectionPlugin('emuc', {
var type = msg.getAttribute("type");
if(type == "error")
{
Chat.chatAddError($(msg).find('>text').text(), txt);
UI.chatAddError($(msg).find('>text').text(), txt);
return true;
}
@ -253,7 +276,7 @@ Strophe.addConnectionPlugin('emuc', {
{
var subjectText = subject.text();
if(subjectText || subjectText == "") {
Chat.chatSetSubject(subjectText);
UI.chatSetSubject(subjectText);
console.log("Subject is changed to " + subjectText);
}
}
@ -261,7 +284,7 @@ Strophe.addConnectionPlugin('emuc', {
if (txt) {
console.log('chat', nick, txt);
Chat.updateChatConversation(from, nick, txt);
UI.updateChatConversation(from, nick, txt);
if(APIConnector.isEnabled() && APIConnector.isEventEnabled("incomingMessage"))
{
if(from != this.myroomjid)
@ -271,7 +294,7 @@ Strophe.addConnectionPlugin('emuc', {
}
return true;
},
lockRoom: function (key) {
lockRoom: function (key, onSuccess, onError, onNotSupported) {
//http://xmpp.org/extensions/xep-0045.html#roomconfig
var ob = this;
this.connection.sendIQ($iq({to: this.roomjid, type: 'get'}).c('query', {xmlns: 'http://jabber.org/protocol/muc#owner'}),
@ -285,43 +308,12 @@ Strophe.addConnectionPlugin('emuc', {
formsubmit.c('field', {'var': 'muc#roomconfig_whois'}).c('value').t('anyone').up().up();
// FIXME: is muc#roomconfig_passwordprotectedroom required?
this.connection.sendIQ(formsubmit,
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('Lock failed',
'Failed to lock conference.',
err);
setSharedKey('');
}
);
onSuccess,
onError);
} else {
console.warn('room passwords not supported');
messageHandler.showError('Warning',
'Room passwords are currently not supported.');
setSharedKey('');
onNotSupported();
}
},
function (err) {
console.warn('setting password failed', err);
messageHandler.showError('Lock failed',
'Failed to lock conference.',
err);
setSharedKey('');
}
);
}, onError);
},
kick: function (jid) {
var kickIQ = $iq({to: this.roomjid, type: 'set'})
@ -427,6 +419,7 @@ Strophe.addConnectionPlugin('emuc', {
}
pres.up();
// console.debug(pres.toString());
connection.send(pres);
},
addDisplayNameToPresence: function (displayName) {
@ -509,5 +502,24 @@ Strophe.addConnectionPlugin('emuc', {
return this.members[peerJid].role;
}
return null;
},
onParticipantLeft: function (jid) {
UI.onMucLeft(jid);
if(APIConnector.isEnabled() && APIConnector.isEventEnabled("participantLeft"))
{
APIConnector.triggerEvent("participantLeft",{jid: jid});
}
delete jid2Ssrc[jid];
connection.jingle.terminateByJid(jid);
if (connection.emuc.getPrezi(jid)) {
$(document).trigger('presentationremoved.muc',
[jid, connection.emuc.getPrezi(jid)]);
}
Moderator.onMucLeft(jid);
}
});

346
prezi.js
View File

@ -1,346 +0,0 @@
var Prezi = (function (my) {
var preziPlayer = null;
/**
* Reloads the current presentation.
*/
my.reloadPresentation = function() {
var iframe = document.getElementById(preziPlayer.options.preziId);
iframe.src = iframe.src;
};
/**
* Shows/hides a presentation.
*/
my.setPresentationVisible = function (visible) {
var prezi = $('#presentation>iframe');
if (visible) {
// Trigger the video.selected event to indicate a change in the
// large video.
$(document).trigger("video.selected", [true]);
$('#largeVideo').fadeOut(300);
prezi.fadeIn(300, function() {
prezi.css({opacity:'1'});
ToolbarToggler.dockToolbar(true);
VideoLayout.setLargeVideoVisible(false);
});
$('#activeSpeaker').css('visibility', 'hidden');
}
else {
if (prezi.css('opacity') == '1') {
prezi.fadeOut(300, function () {
prezi.css({opacity:'0'});
$('#reloadPresentation').css({display:'none'});
$('#largeVideo').fadeIn(300, function() {
VideoLayout.setLargeVideoVisible(true);
ToolbarToggler.dockToolbar(false);
});
});
}
}
};
/**
* Returns <tt>true</tt> if the presentation is visible, <tt>false</tt> -
* otherwise.
*/
my.isPresentationVisible = function () {
return ($('#presentation>iframe') != null
&& $('#presentation>iframe').css('opacity') == 1);
};
/**
* Opens the Prezi dialog, from which the user could choose a presentation
* to load.
*/
my.openPreziDialog = function() {
var myprezi = connection.emuc.getPrezi(connection.emuc.myroomjid);
if (myprezi) {
messageHandler.openTwoButtonDialog("Remove Prezi",
"Are you sure you would like to remove your Prezi?",
false,
"Remove",
function(e,v,m,f) {
if(v) {
connection.emuc.removePreziFromPresence();
connection.emuc.sendPresence();
}
}
);
}
else if (preziPlayer != null) {
messageHandler.openTwoButtonDialog("Share a Prezi",
"Another participant is already sharing a Prezi." +
"This conference allows only one Prezi at a time.",
false,
"Ok",
function(e,v,m,f) {
$.prompt.close();
}
);
}
else {
var openPreziState = {
state0: {
html: '<h2>Share a Prezi</h2>' +
'<input id="preziUrl" type="text" ' +
'placeholder="e.g. ' +
'http://prezi.com/wz7vhjycl7e6/my-prezi" autofocus>',
persistent: false,
buttons: { "Share": true , "Cancel": false},
defaultButton: 1,
submit: function(e,v,m,f){
e.preventDefault();
if(v)
{
var preziUrl = document.getElementById('preziUrl');
if (preziUrl.value)
{
var urlValue
= encodeURI(Util.escapeHtml(preziUrl.value));
if (urlValue.indexOf('http://prezi.com/') != 0
&& urlValue.indexOf('https://prezi.com/') != 0)
{
$.prompt.goToState('state1');
return false;
}
else {
var presIdTmp = urlValue.substring(
urlValue.indexOf("prezi.com/") + 10);
if (!isAlphanumeric(presIdTmp)
|| presIdTmp.indexOf('/') < 2) {
$.prompt.goToState('state1');
return false;
}
else {
connection.emuc
.addPreziToPresence(urlValue, 0);
connection.emuc.sendPresence();
$.prompt.close();
}
}
}
}
else
$.prompt.close();
}
},
state1: {
html: '<h2>Share a Prezi</h2>' +
'Please provide a correct prezi link.',
persistent: false,
buttons: { "Back": true, "Cancel": false },
defaultButton: 1,
submit:function(e,v,m,f) {
e.preventDefault();
if(v==0)
$.prompt.close();
else
$.prompt.goToState('state0');
}
}
};
var focusPreziUrl = function(e) {
document.getElementById('preziUrl').focus();
};
messageHandler.openDialogWithStates(openPreziState, focusPreziUrl, focusPreziUrl);
}
};
/**
* A new presentation has been added.
*
* @param event the event indicating the add of a presentation
* @param jid the jid from which the presentation was added
* @param presUrl url of the presentation
* @param currentSlide the current slide to which we should move
*/
var presentationAdded = function(event, jid, presUrl, currentSlide) {
console.log("presentation added", presUrl);
var presId = getPresentationId(presUrl);
var elementId = 'participant_'
+ Strophe.getResourceFromJid(jid)
+ '_' + presId;
// We explicitly don't specify the peer jid here, because we don't want
// this video to be dealt with as a peer related one (for example we
// don't want to show a mute/kick menu for this one, etc.).
VideoLayout.addRemoteVideoContainer(null, elementId);
VideoLayout.resizeThumbnails();
var controlsEnabled = false;
if (jid === connection.emuc.myroomjid)
controlsEnabled = true;
Prezi.setPresentationVisible(true);
$('#largeVideoContainer').hover(
function (event) {
if (Prezi.isPresentationVisible()) {
var reloadButtonRight = window.innerWidth
- $('#presentation>iframe').offset().left
- $('#presentation>iframe').width();
$('#reloadPresentation').css({ right: reloadButtonRight,
display:'inline-block'});
}
},
function (event) {
if (!Prezi.isPresentationVisible())
$('#reloadPresentation').css({display:'none'});
else {
var e = event.toElement || event.relatedTarget;
if (e && e.id != 'reloadPresentation' && e.id != 'header')
$('#reloadPresentation').css({display:'none'});
}
});
preziPlayer = new PreziPlayer(
'presentation',
{preziId: presId,
width: getPresentationWidth(),
height: getPresentationHeihgt(),
controls: controlsEnabled,
debug: true
});
$('#presentation>iframe').attr('id', preziPlayer.options.preziId);
preziPlayer.on(PreziPlayer.EVENT_STATUS, function(event) {
console.log("prezi status", event.value);
if (event.value == PreziPlayer.STATUS_CONTENT_READY) {
if (jid != connection.emuc.myroomjid)
preziPlayer.flyToStep(currentSlide);
}
});
preziPlayer.on(PreziPlayer.EVENT_CURRENT_STEP, function(event) {
console.log("event value", event.value);
connection.emuc.addCurrentSlideToPresence(event.value);
connection.emuc.sendPresence();
});
$("#" + elementId).css( 'background-image',
'url(../images/avatarprezi.png)');
$("#" + elementId).click(
function () {
Prezi.setPresentationVisible(true);
}
);
};
/**
* A presentation has been removed.
*
* @param event the event indicating the remove of a presentation
* @param jid the jid for which the presentation was removed
* @param the url of the presentation
*/
var presentationRemoved = function (event, jid, presUrl) {
console.log('presentation removed', presUrl);
var presId = getPresentationId(presUrl);
Prezi.setPresentationVisible(false);
$('#participant_'
+ Strophe.getResourceFromJid(jid)
+ '_' + presId).remove();
$('#presentation>iframe').remove();
if (preziPlayer != null) {
preziPlayer.destroy();
preziPlayer = null;
}
};
/**
* Indicates if the given string is an alphanumeric string.
* Note that some special characters are also allowed (-, _ , /, &, ?, =, ;) for the
* purpose of checking URIs.
*/
function isAlphanumeric(unsafeText) {
var regex = /^[a-z0-9-_\/&\?=;]+$/i;
return regex.test(unsafeText);
}
/**
* Returns the presentation id from the given url.
*/
function getPresentationId (presUrl) {
var presIdTmp = presUrl.substring(presUrl.indexOf("prezi.com/") + 10);
return presIdTmp.substring(0, presIdTmp.indexOf('/'));
}
/**
* Returns the presentation width.
*/
function getPresentationWidth() {
var availableWidth = Util.getAvailableVideoWidth();
var availableHeight = getPresentationHeihgt();
var aspectRatio = 16.0 / 9.0;
if (availableHeight < availableWidth / aspectRatio) {
availableWidth = Math.floor(availableHeight * aspectRatio);
}
return availableWidth;
}
/**
* Returns the presentation height.
*/
function getPresentationHeihgt() {
var remoteVideos = $('#remoteVideos');
return window.innerHeight - remoteVideos.outerHeight();
}
/**
* Resizes the presentation iframe.
*/
function resize() {
if ($('#presentation>iframe')) {
$('#presentation>iframe').width(getPresentationWidth());
$('#presentation>iframe').height(getPresentationHeihgt());
}
}
/**
* Presentation has been removed.
*/
$(document).bind('presentationremoved.muc', presentationRemoved);
/**
* Presentation has been added.
*/
$(document).bind('presentationadded.muc', presentationAdded);
/*
* Indicates presentation slide change.
*/
$(document).bind('gotoslide.muc', function (event, jid, presUrl, current) {
if (preziPlayer && preziPlayer.getCurrentStep() != current) {
preziPlayer.flyToStep(current);
var animationStepsArray = preziPlayer.getAnimationCountOnSteps();
for (var i = 0; i < parseInt(animationStepsArray[current]); i++) {
preziPlayer.flyToStep(current, i);
}
}
});
/**
* On video selected event.
*/
$(document).bind('video.selected', function (event, isPresentation) {
if (!isPresentation && $('#presentation>iframe')) {
Prezi.setPresentationVisible(false);
}
});
$(window).resize(function () {
resize();
});
return my;
}(Prezi || {}));

View File

@ -45,7 +45,7 @@ var Recording = (function (my) {
if (!recordingToken)
{
messageHandler.openTwoButtonDialog(null,
UI.messageHandler.openTwoButtonDialog(null,
'<h2>Enter recording token</h2>' +
'<input id="recordingToken" type="text" placeholder="token" autofocus>',
false,
@ -70,7 +70,7 @@ var Recording = (function (my) {
}
var oldState = recordingEnabled;
Toolbar.setRecordingButtonState(!oldState);
UI.setRecordingButtonState(!oldState);
my.setRecording(!oldState,
recordingToken,
function (state) {
@ -99,7 +99,7 @@ var Recording = (function (my) {
my.setRecordingToken(null);
}
// Update with returned status
Toolbar.setRecordingButtonState(state);
UI.setRecordingButtonState(state);
}
);
};

View File

@ -1,188 +0,0 @@
var RoomNameGenerator = function(my) {
/**
* Constructs new RoomNameGenerator object.
* @constructor constructs new RoomNameGenerator object.
*/
function RoomNameGeneratorProto()
{
}
//var nouns = [
//];
var pluralNouns = [
"Aliens", "Animals", "Antelopes", "Ants", "Apes", "Apples", "Baboons", "Bacteria", "Badgers", "Bananas", "Bats",
"Bears", "Birds", "Bonobos", "Brides", "Bugs", "Bulls", "Butterflies", "Cheetahs",
"Cherries", "Chicken", "Children", "Chimps", "Clowns", "Cows", "Creatures", "Dinosaurs", "Dogs", "Dolphins",
"Donkeys", "Dragons", "Ducks", "Dwarfs", "Eagles", "Elephants", "Elves", "FAIL", "Fathers",
"Fish", "Flowers", "Frogs", "Fruit", "Fungi", "Galaxies", "Geese", "Goats",
"Gorillas", "Hedgehogs", "Hippos", "Horses", "Hunters", "Insects", "Kids", "Knights",
"Lemons", "Lemurs", "Leopards", "LifeForms", "Lions", "Lizards", "Mice", "Monkeys", "Monsters",
"Mushrooms", "Octopodes", "Oranges", "Orangutans", "Organisms", "Pants", "Parrots", "Penguins",
"People", "Pigeons", "Pigs", "Pineapples", "Plants", "Potatoes", "Priests", "Rats", "Reptiles", "Reptilians",
"Rhinos", "Seagulls", "Sheep", "Siblings", "Snakes", "Spaghetti", "Spiders", "Squid", "Squirrels",
"Stars", "Students", "Teachers", "Tigers", "Tomatoes", "Trees", "Vampires", "Vegetables", "Viruses", "Vulcans",
"Warewolves", "Weasels", "Whales", "Witches", "Wizards", "Wolves", "Workers", "Worms", "Zebras"
];
//var places = [
//"Pub", "University", "Airport", "Library", "Mall", "Theater", "Stadium", "Office", "Show", "Gallows", "Beach",
// "Cemetery", "Hospital", "Reception", "Restaurant", "Bar", "Church", "House", "School", "Square", "Village",
// "Cinema", "Movies", "Party", "Restroom", "End", "Jail", "PostOffice", "Station", "Circus", "Gates", "Entrance",
// "Bridge"
//];
var verbs = [
"Abandon", "Adapt", "Advertise", "Answer", "Anticipate", "Appreciate",
"Approach", "Argue", "Ask", "Bite", "Blossom", "Blush", "Breathe", "Breed", "Bribe", "Burn", "Calculate",
"Clean", "Code", "Communicate", "Compute", "Confess", "Confiscate", "Conjugate", "Conjure", "Consume",
"Contemplate", "Crawl", "Dance", "Delegate", "Devour", "Develop", "Differ", "Discuss",
"Dissolve", "Drink", "Eat", "Elaborate", "Emancipate", "Estimate", "Expire", "Extinguish",
"Extract", "FAIL", "Facilitate", "Fall", "Feed", "Finish", "Floss", "Fly", "Follow", "Fragment", "Freeze",
"Gather", "Glow", "Grow", "Hex", "Hide", "Hug", "Hurry", "Improve", "Intersect", "Investigate", "Jinx",
"Joke", "Jubilate", "Kiss", "Laugh", "Manage", "Meet", "Merge", "Move", "Object", "Observe", "Offer",
"Paint", "Participate", "Party", "Perform", "Plan", "Pursue", "Pierce", "Play", "Postpone", "Pray", "Proclaim",
"Question", "Read", "Reckon", "Rejoice", "Represent", "Resize", "Rhyme", "Scream", "Search", "Select", "Share", "Shoot",
"Shout", "Signal", "Sing", "Skate", "Sleep", "Smile", "Smoke", "Solve", "Spell", "Steer", "Stink",
"Substitute", "Swim", "Taste", "Teach", "Terminate", "Think", "Type", "Unite", "Vanish", "Worship"
];
var adverbs = [
"Absently", "Accurately", "Accusingly", "Adorably", "AllTheTime", "Alone", "Always", "Amazingly", "Angrily",
"Anxiously", "Anywhere", "Appallingly", "Apparently", "Articulately", "Astonishingly", "Badly", "Barely",
"Beautifully", "Blindly", "Bravely", "Brightly", "Briskly", "Brutally", "Calmly", "Carefully", "Casually",
"Cautiously", "Cleverly", "Constantly", "Correctly", "Crazily", "Curiously", "Cynically", "Daily",
"Dangerously", "Deliberately", "Delicately", "Desperately", "Discreetly", "Eagerly", "Easily", "Euphoricly",
"Evenly", "Everywhere", "Exactly", "Expectantly", "Extensively", "FAIL", "Ferociously", "Fiercely", "Finely",
"Flatly", "Frequently", "Frighteningly", "Gently", "Gloriously", "Grimly", "Guiltily", "Happily",
"Hard", "Hastily", "Heroically", "High", "Highly", "Hourly", "Humbly", "Hysterically", "Immensely",
"Impartially", "Impolitely", "Indifferently", "Intensely", "Jealously", "Jovially", "Kindly", "Lazily",
"Lightly", "Loudly", "Lovingly", "Loyally", "Magnificently", "Malevolently", "Merrily", "Mightily", "Miserably",
"Mysteriously", "NOT", "Nervously", "Nicely", "Nowhere", "Objectively", "Obnoxiously", "Obsessively",
"Obviously", "Often", "Painfully", "Patiently", "Playfully", "Politely", "Poorly", "Precisely", "Promptly",
"Quickly", "Quietly", "Randomly", "Rapidly", "Rarely", "Recklessly", "Regularly", "Remorsefully", "Responsibly",
"Rudely", "Ruthlessly", "Sadly", "Scornfully", "Seamlessly", "Seldom", "Selfishly", "Seriously", "Shakily",
"Sharply", "Sideways", "Silently", "Sleepily", "Slightly", "Slowly", "Slyly", "Smoothly", "Softly", "Solemnly", "Steadily", "Sternly", "Strangely", "Strongly", "Stunningly", "Surely", "Tenderly", "Thoughtfully",
"Tightly", "Uneasily", "Vanishingly", "Violently", "Warmly", "Weakly", "Wearily", "Weekly", "Weirdly", "Well",
"Well", "Wickedly", "Wildly", "Wisely", "Wonderfully", "Yearly"
];
var adjectives = [
"Abominable", "Accurate", "Adorable", "All", "Alleged", "Ancient", "Angry", "Angry", "Anxious", "Appalling",
"Apparent", "Astonishing", "Attractive", "Awesome", "Baby", "Bad", "Beautiful", "Benign", "Big", "Bitter",
"Blind", "Blue", "Bold", "Brave", "Bright", "Brisk", "Calm", "Camouflaged", "Casual", "Cautious",
"Choppy", "Chosen", "Clever", "Cold", "Cool", "Crawly", "Crazy", "Creepy", "Cruel", "Curious", "Cynical",
"Dangerous", "Dark", "Delicate", "Desperate", "Difficult", "Discreet", "Disguised", "Dizzy",
"Dumb", "Eager", "Easy", "Edgy", "Electric", "Elegant", "Emancipated", "Enormous", "Euphoric", "Evil",
"FAIL", "Fast", "Ferocious", "Fierce", "Fine", "Flawed", "Flying", "Foolish", "Foxy",
"Freezing", "Funny", "Furious", "Gentle", "Glorious", "Golden", "Good", "Green", "Green", "Guilty",
"Hairy", "Happy", "Hard", "Hasty", "Hazy", "Heroic", "Hostile", "Hot", "Humble", "Humongous",
"Humorous", "Hysterical", "Idealistic", "Ignorant", "Immense", "Impartial", "Impolite", "Indifferent",
"Infuriated", "Insightful", "Intense", "Interesting", "Intimidated", "Intriguing", "Jealous", "Jolly", "Jovial",
"Jumpy", "Kind", "Laughing", "Lazy", "Liquid", "Lonely", "Longing", "Loud", "Loving", "Loyal", "Macabre", "Mad",
"Magical", "Magnificent", "Malevolent", "Medieval", "Memorable", "Mere", "Merry", "Mighty",
"Mischievous", "Miserable", "Modified", "Moody", "Most", "Mysterious", "Mystical", "Needy",
"Nervous", "Nice", "Objective", "Obnoxious", "Obsessive", "Obvious", "Opinionated", "Orange",
"Painful", "Passionate", "Perfect", "Pink", "Playful", "Poisonous", "Polite", "Poor", "Popular", "Powerful",
"Precise", "Preserved", "Pretty", "Purple", "Quick", "Quiet", "Random", "Rapid", "Rare", "Real",
"Reassuring", "Reckless", "Red", "Regular", "Remorseful", "Responsible", "Rich", "Rude", "Ruthless",
"Sad", "Scared", "Scary", "Scornful", "Screaming", "Selfish", "Serious", "Shady", "Shaky", "Sharp",
"Shiny", "Shy", "Simple", "Sleepy", "Slow", "Sly", "Small", "Smart", "Smelly", "Smiling", "Smooth",
"Smug", "Sober", "Soft", "Solemn", "Square", "Square", "Steady", "Strange", "Strong",
"Stunning", "Subjective", "Successful", "Surly", "Sweet", "Tactful", "Tense",
"Thoughtful", "Tight", "Tiny", "Tolerant", "Uneasy", "Unique", "Unseen", "Warm", "Weak",
"Weird", "WellCooked", "Wild", "Wise", "Witty", "Wonderful", "Worried", "Yellow", "Young",
"Zealous"
];
//var pronouns = [
//];
//var conjunctions = [
//"And", "Or", "For", "Above", "Before", "Against", "Between"
//];
/*
* Maps a string (category name) to the array of words from that category.
*/
var CATEGORIES =
{
//"_NOUN_": nouns,
"_PLURALNOUN_": pluralNouns,
//"_PLACE_": places,
"_VERB_": verbs,
"_ADVERB_": adverbs,
"_ADJECTIVE_": adjectives
//"_PRONOUN_": pronouns,
//"_CONJUNCTION_": conjunctions,
};
var PATTERNS = [
"_ADJECTIVE__PLURALNOUN__VERB__ADVERB_"
// BeautifulFungiOrSpaghetti
//"_ADJECTIVE__PLURALNOUN__CONJUNCTION__PLURALNOUN_",
// AmazinglyScaryToy
//"_ADVERB__ADJECTIVE__NOUN_",
// NeitherTrashNorRifle
//"Neither_NOUN_Nor_NOUN_",
//"Either_NOUN_Or_NOUN_",
// EitherCopulateOrInvestigate
//"Either_VERB_Or_VERB_",
//"Neither_VERB_Nor_VERB_",
//"The_ADJECTIVE__ADJECTIVE__NOUN_",
//"The_ADVERB__ADJECTIVE__NOUN_",
//"The_ADVERB__ADJECTIVE__NOUN_s",
//"The_ADVERB__ADJECTIVE__PLURALNOUN__VERB_",
// WolvesComputeBadly
//"_PLURALNOUN__VERB__ADVERB_",
// UniteFacilitateAndMerge
//"_VERB__VERB_And_VERB_",
//NastyWitchesAtThePub
//"_ADJECTIVE__PLURALNOUN_AtThe_PLACE_",
];
/*
* Returns a random element from the array 'arr'
*/
function randomElement(arr)
{
return arr[Math.floor(Math.random() * arr.length)];
}
/*
* Returns true if the string 's' contains one of the
* template strings.
*/
function hasTemplate(s)
{
for (var template in CATEGORIES){
if (s.indexOf(template) >= 0){
return true;
}
}
}
/**
* Generates new room name.
*/
RoomNameGeneratorProto.generateRoomWithoutSeparator = function()
{
// Note that if more than one pattern is available, the choice of 'name' won't be random (names from patterns
// with fewer options will have higher probability of being chosen that names from patterns with more options).
var name = randomElement(PATTERNS);
var word;
while (hasTemplate(name)){
for (var template in CATEGORIES){
word = randomElement(CATEGORIES[template]);
name = name.replace(template, word);
}
}
return name;
};
return RoomNameGeneratorProto;
}();

View File

@ -1,83 +0,0 @@
var SettingsMenu = (function(my) {
var email = '';
var displayName = '';
var userId;
if(supportsLocalStorage()) {
if(!window.localStorage.jitsiMeetId) {
window.localStorage.jitsiMeetId = generateUniqueId();
console.log("generated id", window.localStorage.jitsiMeetId);
}
userId = window.localStorage.jitsiMeetId || '';
email = window.localStorage.email || '';
displayName = window.localStorage.displayname || '';
} else {
console.log("local storage is not supported");
userId = generateUniqueId();
}
my.update = function() {
var newDisplayName = Util.escapeHtml($('#setDisplayName').get(0).value);
if(newDisplayName) {
displayName = newDisplayName;
connection.emuc.addDisplayNameToPresence(displayName);
window.localStorage.displayname = displayName;
}
var newEmail = Util.escapeHtml($('#setEmail').get(0).value);
connection.emuc.addEmailToPresence(newEmail);
email = newEmail;
window.localStorage.email = newEmail;
connection.emuc.sendPresence();
Avatar.setUserAvatar(connection.emuc.myroomjid, email);
};
my.isVisible = function() {
return $('#settingsmenu').is(':visible');
};
my.getUID = function() {
return userId;
};
my.getEmail = function() {
return email;
};
my.getDisplayName = function() {
return displayName;
};
my.setDisplayName = function(newDisplayName) {
displayName = newDisplayName;
window.localStorage.displayname = displayName;
$('#setDisplayName').get(0).value = displayName;
};
function supportsLocalStorage() {
try {
return 'localStorage' in window && window.localStorage !== null;
} catch (e) {
console.log("localstorage is not supported");
return false;
}
}
function generateUniqueId() {
function _p8() {
return (Math.random().toString(16)+"000000000").substr(2,8);
}
return _p8() + _p8() + _p8() + _p8();
}
$(document).bind('displaynamechanged', function(event, peerJid, newDisplayName) {
if(peerJid === 'localVideoContainer' ||
peerJid === connection.emuc.myroomjid) {
SettingsMenu.setDisplayName(newDisplayName);
}
});
return my;
}(SettingsMenu || {}));

View File

@ -1,48 +0,0 @@
var smileys = {
"smiley1": ':)',
"smiley2": ':(',
"smiley3": ':D',
"smiley4": '(y)',
"smiley5": ' :P',
"smiley6": '(wave)',
"smiley7": '(blush)',
"smiley8": '(chuckle)',
"smiley9": '(shocked)',
"smiley10": ':*',
"smiley11": '(n)',
"smiley12": '(search)',
"smiley13": ' <3',
"smiley14": '(oops)',
"smiley15": '(angry)',
"smiley16": '(angel)',
"smiley17": '(sick)',
"smiley18": ';(',
"smiley19": '(bomb)',
"smiley20": '(clap)',
"smiley21": ' ;)'
};
var regexs = {
'smiley2': /(:-\(\(|:-\(|:\(\(|:\(|\(sad\))/gi,
'smiley3': /(:-\)\)|:\)\)|\(lol\)|:-D|:D)/gi,
'smiley1': /(:-\)|:\))/gi,
'smiley4': /(\(y\)|\(Y\)|\(ok\))/gi,
'smiley5': /(:-P|:P|:-p|:p)/gi,
'smiley6': /(\(wave\))/gi,
'smiley7': /(\(blush\))/gi,
'smiley8': /(\(chuckle\))/gi,
'smiley9': /(:-0|\(shocked\))/gi,
'smiley10': /(:-\*|:\*|\(kiss\))/gi,
'smiley11': /(\(n\))/gi,
'smiley12': /(\(search\))/g,
'smiley13': /(<3|&lt;3|&amp;lt;3|\(L\)|\(l\)|\(H\)|\(h\))/gi,
'smiley14': /(\(oops\))/gi,
'smiley15': /(\(angry\))/gi,
'smiley16': /(\(angel\))/gi,
'smiley17': /(\(sick\))/gi,
'smiley18': /(;-\(\(|;\(\(|;-\(|;\(|:'\(|:'-\(|:~-\(|:~\(|\(upset\))/gi,
'smiley19': /(\(bomb\))/gi,
'smiley20': /(\(clap\))/gi,
'smiley21': /(;-\)|;\)|;-\)\)|;\)\)|;-D|;D|\(wink\))/gi
};

10
util.js
View File

@ -47,16 +47,6 @@ var Util = (function (my) {
return $('<div/>').text(unsafeText).html();
};
/**
* Returns the available video width.
*/
my.getAvailableVideoWidth = function () {
var rightPanelWidth
= PanelToggler.isVisible() ? PanelToggler.getPanelSize()[0] : 0;
return window.innerWidth - rightPanelWidth;
};
my.imageToGrayScale = function (canvas) {
var context = canvas.getContext('2d');
var imgData = context.getImageData(0, 0, canvas.width, canvas.height);