diff --git a/public/js/vroom.js b/public/js/vroom.js index 223de7c..38e40c0 100644 --- a/public/js/vroom.js +++ b/public/js/vroom.js @@ -1,12 +1,14 @@ /* This file is part of the VROOM project released under the MIT licence -Copyright 2014 Firewall Services -Daniel Berteaud +Copyright 2014-2015 Daniel Berteaud */ // Default notifications -$.notify.defaults( { globalPosition: 'bottom left' } ); +$.notify.defaults({ + globalPosition: 'bottom left' +}); + // Enable tooltip on required elements $('.help').tooltip({ container: 'body', @@ -19,6 +21,7 @@ $('.popup').popover({ $('.modal').on('show.bs.modal', function(){ $('.help').tooltip('hide'); }); + // Enable bootstrap-swicth $('.bs-switch').bootstrapSwitch(); @@ -29,9 +32,12 @@ var locale = {}, // When pagination is done, how many item per page var itemPerPage = 20; -// Will store the global webrtc object +// Some global vars, like +// the SimpleWebRTC object var webrtc = undefined; +// The current room configuration var roomInfo = {}; +// The current peers (we init the list with only ourself) var peers = { local: { screenShared: false, @@ -44,7 +50,6 @@ var peers = { } }; - // Mark current page link as active $('#lnk_' + page).addClass('active'); @@ -70,6 +75,11 @@ $.ajaxSetup({ } }); + +// +// Define a few functions +// + // Localize a string, or just print it if localization doesn't exist function localize(string){ if (locale[string]){ @@ -92,7 +102,7 @@ function showApiError(data){ } } -// Handle lang switch +// Handle lang switch drop down menu $('#switch_lang').change(function(){ $.ajax({ data: { @@ -112,9 +122,6 @@ $('#switch_lang').change(function(){ }); }); -// -// Define a few functions -// // Escape a string to be used as a jQuerry selector // Taken from http://totaldev.com/content/escaping-characters-get-valid-jquery-id @@ -130,7 +137,7 @@ function stringEscape(string){ return string; } -// Select a color (randomly) from this list, used for text chat +// Select a color (randomly) from this list, used for text chat, and the name under the preview function chooseColor(){ // Shamelessly taken from http://martin.ankerl.com/2009/12/09/how-to-create-random-colors-programmatically/ var colors = [ @@ -191,19 +198,19 @@ function getTime(){ var hours = d.getHours().toString(), minutes = d.getMinutes().toString(), seconds = d.getSeconds().toString(); - hours = (hours.length < 2) ? '0' + hours:hours; - minutes = (minutes.length < 2) ? '0' + minutes:minutes; - seconds = (seconds.length < 2) ? '0' + seconds:seconds; + hours = (hours.length < 2) ? '0' + hours : hours; + minutes = (minutes.length < 2) ? '0' + minutes : minutes; + seconds = (seconds.length < 2) ? '0' + seconds : seconds; return hours + ':' + minutes + ':' + seconds; } // Convert dates from UTC to local TZ function utc2Local(date) { - var newDate = new Date(date.getTime()+date.getTimezoneOffset()*60*1000); + var newDate = new Date(date.getTime() + date.getTimezoneOffset() * 60 * 1000); var offset = date.getTimezoneOffset() / 60; var hours = date.getHours(); newDate.setHours(hours - offset); - return newDate; + return newDate; } // Temporarily suspend a button, prevent abuse @@ -220,7 +227,7 @@ function maxHeight(){ return $(window).height()-$('#toolbar').height()-25; } -// Create a new input field +// Create a new email input field function addEmailInputField(form, val){ var parentEl = $('#' + form), currentEntry = parentEl.find('.email-entry:last'), @@ -229,6 +236,7 @@ function addEmailInputField(form, val){ newEntry.removeClass('has-error'); adjustAddRemoveEmailButtons(form); } + // Adjust add and remove buttons foir email notifications function adjustAddRemoveEmailButtons(form){ $('#' + form).find('.email-entry:not(:last) .btn-add-email') @@ -240,11 +248,12 @@ function adjustAddRemoveEmailButtons(form){ .addClass('btn-primary').addClass('btn-add-email') .html(''); } -// Add emails input fields +// Add emails input field $(document).on('click','button.btn-add-email',function(e){ e.preventDefault(); addEmailInputField($(this).parents('.email-list:first').attr('id'), ''); }); +// Remove email input field $(document).on('click','button.btn-remove-email',function(e){ e.preventDefault(); el = $(this).parents('.email-entry:first'); @@ -324,7 +333,7 @@ $('#configureRoomForm').submit(function(e){ $(input).parent().addClass('has-error'); //$(input).parent().notify(localize('ERROR_MAIL_INVALID'), 'error'); validEmail = false; - // Break the each loop + // Break the each loop and return an error now, we can't submit as is return false; } else{ @@ -368,6 +377,8 @@ $('#configureRoomForm').submit(function(e){ showApiError(data); }, success: function(data){ + // On success, reset the input fields, collapse the password inputs + // and close the configuration modal $('#ownerPass,#ownerPassConfirm,#joinPass,#joinPassConfirm').val(''); $('#configureModal').modal('hide'); $('#joinPassFields,#ownerPassFields').hide(); @@ -393,9 +404,10 @@ function getRoomInfo(cb){ }, success: function(data){ roomInfo = data; - // Reset the list of email displayed, so first remove evry input field but the last one + // Reset the list of email displayed, so first remove every input field but the last one // We keep it so we can clone it again $('.email-list').find('.email-entry:not(:last)').remove(); + // Now add one input per email $.each(data.notif, function(index, obj){ addEmailInputField('email-list-notification', obj.email); }); @@ -412,6 +424,7 @@ function getRoomInfo(cb){ $('#askForNameSet').bootstrapSwitch('state', data.ask_for_name); $('#joinPassSet').bootstrapSwitch('state', data.join_auth); $('#ownerPassSet').bootstrapSwitch('state', data.owner_auth); + // exec the callback if defined if (typeof cb === 'function'){ cb(); } @@ -475,7 +488,7 @@ function initIndex(){ $('#roomName').val(''); $('#conflictModal').modal('hide'); }); - + // Check for invalid room name as user is typing $('#roomName').on('input', function(){ if (!$('#roomName').val().match(/^[\w\-]{0,49}$/)){ $('#roomName').parent().addClass('has-error'); @@ -509,6 +522,7 @@ function initDoc(){ offset: $('#headerNav').outerHeight(true) + 40 }); + // Small delay so the affix can start when everything is loaded setTimeout(function() { var $sideBar = $('#toc'); $sideBar.affix({ @@ -713,6 +727,7 @@ function initAdminRooms(){ }); } +// Started when entering a room function initJoin(room){ // Auth input if access is protected $('#authBeforeJoinPass').on('input', function() { @@ -794,6 +809,8 @@ function initJoin(room){ $('.connecting-err-reason').text(data.msg); $('#auth-before-join').slideDown(); } + // 403 is when the room is locked, and there's no owner pass + // So there's nothing to do, the access will be denied else if (data.status === 403){ data = data.responseJSON; $('.connecting-err-reason').text(data.msg); @@ -806,6 +823,7 @@ function initJoin(room){ }, success: function(data){ $('.connecting-err-reason').hide(); + // Once auth is passed, we get the room configuration $.ajax({ data: { req: JSON.stringify({ @@ -820,6 +838,8 @@ function initJoin(room){ }, success: function(data){ roomInfo = data; + // If our name is asked before joining the room, display the corresponding modal + // Else, just continue (with webrtc initialization if (roomInfo.ask_for_name){ $('#display-name-pre').slideDown(); } @@ -831,10 +851,14 @@ function initJoin(room){ } }); } + // Always start by trying with an empty password. + // Only if one is required the modal will appear try_auth('', false); } +// This just create the webrtc object, and then continue function init_webrtc(room){ + // First get SimpleWebRTC config from the server $.ajax({ data: { req: JSON.stringify({ @@ -854,7 +878,6 @@ function init_webrtc(room){ data.config.localVideoEl = 'webRTCVideoLocal'; webrtc = new SimpleWebRTC(data.config); // Handle the readyToCall event: join the room - // Or prompt for a name first webrtc.once('readyToCall', function () { peers.local.id = webrtc.connection.connection.socket.sessionid; webrtc.joinRoom(roomName); @@ -866,7 +889,7 @@ function init_webrtc(room){ $('#no-webrtc-msg').slideDown(); } else{ - // Hide screen sharing btn if not supported, disable it on mobile + // Hide screen sharing btn if not supported, or when connecting from a mobile if (!webrtc.capabilities.supportScreenSharing || !$.browser.desktop){ $('.btn-share-screen').remove(); } @@ -876,7 +899,7 @@ function init_webrtc(room){ }); } -// This is the main function called when you join a room +// This is the main function called when you join a room (after auth and all the basic stuff ready) function initVroom(room) { var mainVid = false, @@ -915,8 +938,11 @@ function initVroom(room) { showApiError(data); }, success: function(data){ + // If its our own role, check if it chagned if (id === peers.local.id){ if (data.role != peers.local.role){ + // In which case, we refresh room config + // and tell all other peers we've changed getRoomInfo(); webrtc.sendToAll('role_change', {}); } @@ -935,8 +961,8 @@ function initVroom(room) { else if (peers[id]){ peers[id].role = data.role; if (data.role == 'owner'){ - // If this peer is a owner, we add the mark on its preview - $('#overlay_' + id).append($('
').attr('id', 'owner_' + id).addClass('owner hidden-xs')); + // If this peer is an owner, we add the mark on its preview + $('#overlay_' + id).append($('
').attr('id', 'owner_' + id).addClass('owner hidden-xs')); // And we disable owner's action for him $('#ownerActions_' + id).remove(); } @@ -976,7 +1002,7 @@ function initVroom(room) { el.removeClass('selected'); } else{ - // Clone this new preview into the main div + // Clone the clicked preview and put it in the main div $('#mainVideo').html(el.clone().dblclick(function() { fullScreen(this); }) @@ -990,7 +1016,7 @@ function initVroom(room) { $('.selected').removeClass('selected'); el.addClass('selected'); mainVid = el.attr('id'); - // Cut the volume the corresponding preview + // Cut the volume of the corresponding preview $('#webRTCVideo video').each(function(){ if ($(this).get(0).paused){ $(this).get(0).play(); @@ -1015,17 +1041,17 @@ function initVroom(room) { } // Handle a new video (either another peer, or a screen - // including our own local screen - function addVideo(video,peer){ + // including our own local screen) + function addVideo(video, peer){ playSound('join.mp3'); - // The div continer of this new video + // The div container of this new video // will contain the video preview plus all other info like displayName, overlay and volume bar - var div = $('
').addClass('col-xs-3 col-sm-12 col-lg-6 previewContainer').append(video).appendTo('#webRTCVideo'); + var div = $('
').addClass('col-xs-3 col-sm-12 col-lg-6 previewContainer').append(video).appendTo('#webRTCVideo'); var id; // Peer isn't defined ? it's our own local screen if (!peer){ id = 'local'; - $('
').addClass('displayName').attr('id', 'name_local_screen').appendTo(div); + $('
').addClass('displayName').attr('id', 'name_local_screen').appendTo(div); updateDisplayName(id); $(video).addClass('latencyUnknown'); } @@ -1033,7 +1059,7 @@ function initVroom(room) { else if (video.id.match(/screen/)){ id = peer.id + '_screen'; var peer_id = video.id.replace('_screen_incoming', ''); - $('
').addClass('displayName').attr('id', 'name_' + peer_id + '_screen').appendTo(div); + $('
').addClass('displayName').attr('id', 'name_' + peer_id + '_screen').appendTo(div); updateDisplayName(peer_id); } // It's the webcam of a peer @@ -1042,31 +1068,31 @@ function initVroom(room) { id = peer.id; // Create 4 divs which will contains the volume bar, the displayName, the muted/paused and // the owner actions (overlay) - $('
').addClass('volumeBar').attr('id', 'volume_' + id).appendTo(div); - $('
').addClass('displayName').attr('id', 'name_' + id).appendTo(div); - $('
').attr('id', 'overlay_' + id).addClass('hidden-xs').appendTo(div); - // Will contains per peer action menu (mute/pause/kick), but will only be displayed - // on owners screen - $('
').addClass('ownerActions hidden-xs').attr('id', 'ownerActions_' + id).appendTo(div) - .append($('
',{ + $('
').addClass('volumeBar').attr('id', 'volume_' + id).appendTo(div); + $('
').addClass('displayName').attr('id', 'name_' + id).appendTo(div); + $('
').attr('id', 'overlay_' + id).addClass('hidden-xs').appendTo(div); + // Will contain per peer action menu (mute/pause/kick), but will only be displayed + // on owner's screen + $('
').addClass('ownerActions hidden-xs').attr('id', 'ownerActions_' + id).appendTo(div) + .append($('
',{ class: 'btn-group' }) - .append($('', { + .append($('', { + }).prop('title', localize('MUTE_PEER'))) + .append($('', { + .append($('', { + .append($('