 Fix UI when leaving current call
When the chat view is shown in the main view the call UI (videos and
screens) is hidden using a CSS trick. However, when there is no chat
view in the main view the elements for videos and screens were always
visible. Those elements are initially "empty", but once the user joins a
call they are filled with contents (like the icon to mute the own audio,
or the avatar of the speaking user). As the elements were always visible
the call UI was shown in the main view after a room was left (either
explicitly or implicitly, for example, if the moderator deleted the
room), as in those cases there is no chat view hidding them.
Besides that, the empty content element was hidden when joining a call
but never shown back again. Due to that when a room was left after
joining a call the empty content element was also missing.
Now the videos, screens and empty content are explicitly shown or hidden
as needed when the user joins a call, leaves a call, or leaves a room,
just like it is done with the chat view.
Signed-off-by: Daniel Calviño Sánchez <danxuliu@gmail.com>
8 years ago  Fix UI when leaving current call
When the chat view is shown in the main view the call UI (videos and
screens) is hidden using a CSS trick. However, when there is no chat
view in the main view the elements for videos and screens were always
visible. Those elements are initially "empty", but once the user joins a
call they are filled with contents (like the icon to mute the own audio,
or the avatar of the speaking user). As the elements were always visible
the call UI was shown in the main view after a room was left (either
explicitly or implicitly, for example, if the moderator deleted the
room), as in those cases there is no chat view hidding them.
Besides that, the empty content element was hidden when joining a call
but never shown back again. Due to that when a room was left after
joining a call the empty content element was also missing.
Now the videos, screens and empty content are explicitly shown or hidden
as needed when the user joins a call, leaves a call, or leaves a room,
just like it is done with the chat view.
Signed-off-by: Daniel Calviño Sánchez <danxuliu@gmail.com>
8 years ago  Fix UI when leaving current call
When the chat view is shown in the main view the call UI (videos and
screens) is hidden using a CSS trick. However, when there is no chat
view in the main view the elements for videos and screens were always
visible. Those elements are initially "empty", but once the user joins a
call they are filled with contents (like the icon to mute the own audio,
or the avatar of the speaking user). As the elements were always visible
the call UI was shown in the main view after a room was left (either
explicitly or implicitly, for example, if the moderator deleted the
room), as in those cases there is no chat view hidding them.
Besides that, the empty content element was hidden when joining a call
but never shown back again. Due to that when a room was left after
joining a call the empty content element was also missing.
Now the videos, screens and empty content are explicitly shown or hidden
as needed when the user joins a call, leaves a call, or leaves a room,
just like it is done with the chat view.
Signed-off-by: Daniel Calviño Sánchez <danxuliu@gmail.com>
8 years ago  Fix UI when leaving current call
When the chat view is shown in the main view the call UI (videos and
screens) is hidden using a CSS trick. However, when there is no chat
view in the main view the elements for videos and screens were always
visible. Those elements are initially "empty", but once the user joins a
call they are filled with contents (like the icon to mute the own audio,
or the avatar of the speaking user). As the elements were always visible
the call UI was shown in the main view after a room was left (either
explicitly or implicitly, for example, if the moderator deleted the
room), as in those cases there is no chat view hidding them.
Besides that, the empty content element was hidden when joining a call
but never shown back again. Due to that when a room was left after
joining a call the empty content element was also missing.
Now the videos, screens and empty content are explicitly shown or hidden
as needed when the user joins a call, leaves a call, or leaves a room,
just like it is done with the chat view.
Signed-off-by: Daniel Calviño Sánchez <danxuliu@gmail.com>
8 years ago  Fix UI when leaving current call
When the chat view is shown in the main view the call UI (videos and
screens) is hidden using a CSS trick. However, when there is no chat
view in the main view the elements for videos and screens were always
visible. Those elements are initially "empty", but once the user joins a
call they are filled with contents (like the icon to mute the own audio,
or the avatar of the speaking user). As the elements were always visible
the call UI was shown in the main view after a room was left (either
explicitly or implicitly, for example, if the moderator deleted the
room), as in those cases there is no chat view hidding them.
Besides that, the empty content element was hidden when joining a call
but never shown back again. Due to that when a room was left after
joining a call the empty content element was also missing.
Now the videos, screens and empty content are explicitly shown or hidden
as needed when the user joins a call, leaves a call, or leaves a room,
just like it is done with the chat view.
Signed-off-by: Daniel Calviño Sánchez <danxuliu@gmail.com>
8 years ago |
|
/* global Marionette, Backbone, OCA */
/** * @author Christoph Wurst <christoph@winzerhof-wurst.at> * * @license GNU AGPL version 3 or any later version * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>.
* */
(function(OC, OCA, Marionette, Backbone, _, $) { 'use strict';
OCA.Talk = OCA.Talk || {};
var roomChannel = Backbone.Radio.channel('rooms');
OCA.Talk.Application = Marionette.Application.extend({ OWNER: 1, MODERATOR: 2, USER: 3, GUEST: 4, USERSELFJOINED: 5,
/* Must stay in sync with values in "lib/Room.php". */ FLAG_DISCONNECTED: 0, FLAG_IN_CALL: 1, FLAG_WITH_AUDIO: 2, FLAG_WITH_VIDEO: 4,
/** @property {OCA.SpreedMe.Models.Room} activeRoom */ activeRoom: null,
/** @property {String} token */ token: null,
/** @property {OCA.Talk.Connection} connection */ connection: null,
/** @property {OCA.Talk.Signaling.base} signaling */ signaling: null,
/** @property {OCA.SpreedMe.Models.RoomCollection} _rooms */ _rooms: null, /** @property {OCA.SpreedMe.Views.RoomListView} _roomsView */ _roomsView: null, /** @property {OCA.SpreedMe.Models.ParticipantCollection} _participants */ _participants: null, /** @property {OCA.SpreedMe.Views.ParticipantView} _participantsView */ _participantsView: null, /** @property {boolean} videoWasEnabledAtLeastOnce */ videoWasEnabledAtLeastOnce: false, displayedGuestNameHint: false, audioDisabled: localStorage.getItem("audioDisabled"), audioNotFound: false, videoDisabled: localStorage.getItem("videoDisabled"), videoNotFound: false, fullscreenDisabled: true, _searchTerm: '', guestNick: null, _currentEmptyContent: null, _lastEmptyContent: null, _registerPageEvents: function() { $('#select-participants').select2({ ajax: { url: OC.linkToOCS('core/autocomplete', 2) + 'get', dataType: 'json', quietMillis: 100, data: function (term) { this._searchTerm = term; return { format: 'json', search: term, itemType: 'call', itemId: 'new', shareTypes: [OC.Share.SHARE_TYPE_USER, OC.Share.SHARE_TYPE_GROUP] }; }.bind(this), results: function (response) { // TODO improve error case
if (response.ocs.data === undefined) { console.error('Failure happened', response); return; }
var results = []; response.ocs.data.forEach(function(suggestion) { results.push({ id: suggestion.id, displayName: suggestion.label, type: suggestion.source === 'users' ? 'user' : 'group' }); });
//Add custom entry to create a new empty group or public room
if (OCA.SpreedMe.app._searchTerm === '') { results.unshift({ id: "create-public-room", displayName: t('spreed', 'New public conversation'), type: "createPublicRoom" }); results.unshift({ id: "create-group-room", displayName: t('spreed', 'New group conversation'), type: "createGroupRoom" }); } else { var shortenedName = OCA.SpreedMe.app._searchTerm; if (OCA.SpreedMe.app._searchTerm.length > 25) { shortenedName = shortenedName.substring(0, 25) + '…'; }
results.push({ id: "create-group-room", displayName: shortenedName, type: "createGroupRoom" }); results.push({ id: "create-public-room", displayName: t('spreed', '{name} (public)', { name: shortenedName }), type: "createPublicRoom" }); }
return { results: results, more: false }; } }, initSelection: function (element, callback) { callback({id: element.val()}); }, formatResult: function (element) { if (element.type === "createPublicRoom") { return '<span><div class="avatar icon-public-white"></div>' + escapeHTML(element.displayName) + '</span>'; }
if (element.type === "createGroupRoom" || element.type === 'group') { return '<span><div class="avatar icon-contacts"></div>' + escapeHTML(element.displayName) + '</span>'; }
return '<span><div class="avatar" data-user="' + escapeHTML(element.id) + '" data-user-display-name="' + escapeHTML(element.displayName) + '"></div>' + escapeHTML(element.displayName) + '</span>'; }, formatSelection: function () { return '<span class="select2-default" style="padding-left: 0;">' + t('spreed', 'New conversation …') + '</span>'; } });
$('#select-participants').on("click", function() { $('.select2-drop').find('.avatar[data-user]').each(function () { var element = $(this); if (element.data('user-display-name')) { element.avatar(element.data('user'), 32, undefined, false, undefined, element.data('user-display-name')); } else { element.avatar(element.data('user'), 32); } }); });
$('#select-participants').on("select2-selecting", function(e) { switch (e.object.type) { case "user": this.connection.createOneToOneVideoCall(e.val); break; case "group": this.connection.createGroupVideoCall(e.val, ""); break; case "createPublicRoom": this.connection.createPublicVideoCall(OCA.SpreedMe.app._searchTerm); break; case "createGroupRoom": this.connection.createGroupVideoCall("", OCA.SpreedMe.app._searchTerm); break; default: console.log("Unknown type", e.object.type); break; } }.bind(this));
$('#select-participants').on("select2-loaded", function() { $('.select2-drop').find('.avatar[data-user]').each(function () { var element = $(this); if (element.data('user-display-name')) { element.avatar(element.data('user'), 32, undefined, false, undefined, element.data('user-display-name')); } else { element.avatar(element.data('user'), 32); } }); });
// Initialize button tooltips
$('[data-toggle="tooltip"]').tooltip({trigger: 'hover'}).click(function() { $(this).tooltip('hide'); });
this.registerLocalVideoButtonHandlers();
$(document).keyup(this._onKeyUp.bind(this)); },
registerLocalVideoButtonHandlers: function() { $('#hideVideo').click(function() { if(!OCA.SpreedMe.app.videoWasEnabledAtLeastOnce) { // don't allow clicking the video toggle
// when no video ever was streamed (that
// means that permission wasn't granted
// yet or there is no video available at
// all)
console.log('video can not be enabled - there was no stream available before'); return; } if ($(this).hasClass('video-disabled')) { OCA.SpreedMe.app.enableVideo(); localStorage.removeItem("videoDisabled"); } else { OCA.SpreedMe.app.disableVideo(); localStorage.setItem("videoDisabled", true); } });
$('#mute').click(function() { if (OCA.SpreedMe.webrtc.webrtc.isAudioEnabled()) { OCA.SpreedMe.app.disableAudio(); localStorage.setItem("audioDisabled", true); } else { OCA.SpreedMe.app.enableAudio(); localStorage.removeItem("audioDisabled"); } });
$('#video-fullscreen').click(function() { if (this.fullscreenDisabled) { this.enableFullscreen(); } else { this.disableFullscreen(); } }.bind(this));
$('#screensharing-button').click(function() { var webrtc = OCA.SpreedMe.webrtc; if (!webrtc.capabilities.supportScreenSharing) { if (window.location.protocol === 'https:') { OC.Notification.showTemporary(t('spreed', 'Screensharing is not supported by your browser.')); } else { OC.Notification.showTemporary(t('spreed', 'Screensharing requires the page to be loaded through HTTPS.')); } return; }
if (webrtc.getLocalScreen()) { $('#screensharing-menu').toggleClass('open'); } else { var screensharingButton = $(this); screensharingButton.prop('disabled', true); webrtc.shareScreen(function(err) { screensharingButton.prop('disabled', false); if (!err) { $('#screensharing-button').attr('data-original-title', t('spreed', 'Screensharing options')) .removeClass('screensharing-disabled icon-screen-off') .addClass('icon-screen'); return; }
switch (err.name) { case "HTTPS_REQUIRED": OC.Notification.showTemporary(t('spreed', 'Screensharing requires the page to be loaded through HTTPS.')); break; case "PERMISSION_DENIED": case "NotAllowedError": case "CEF_GETSCREENMEDIA_CANCELED": // Experimental, may go away in the future.
break; case "FF52_REQUIRED": OC.Notification.showTemporary(t('spreed', 'Sharing your screen only works with Firefox version 52 or newer.')); break; case "EXTENSION_UNAVAILABLE": var extensionURL = null; if (!!window.chrome && !!window.chrome.webstore) {// Chrome
extensionURL = 'https://chrome.google.com/webstore/detail/screensharing-for-nextclo/kepnpjhambipllfmgmbapncekcmabkol'; }
if (extensionURL) { var text = t('spreed', 'Screensharing extension is required to share your screen.'); var element = $('<a>').attr('href', extensionURL).attr('target','_blank').text(text);
OC.Notification.showTemporary(element, {isHTML: true}); } else { OC.Notification.showTemporary(t('spreed', 'Please use a different browser like Firefox or Chrome to share your screen.')); } break; default: OC.Notification.showTemporary(t('spreed', 'An error occurred while starting screensharing.')); console.log("Could not start screensharing", err); break; } }); } });
$("#show-screen-button").on('click', function() { var currentUser = OCA.SpreedMe.webrtc.connection.getSessionid(); OCA.SpreedMe.sharedScreens.switchScreenToId(currentUser);
$('#screensharing-menu').toggleClass('open', false); });
$("#stop-screen-button").on('click', function() { OCA.SpreedMe.webrtc.stopScreenShare(); }); },
_onKeyUp: function(event) { // Define which objects to check for the event properties.
var key = event.which;
// Trigger the event only if no input or textarea is focused
// and the CTRL key is not pressed
if ($('input:focus').length === 0 && $('textarea:focus').length === 0 && $('div[contenteditable=true]:focus').length === 0 && !event.ctrlKey) {
// Actual shortcut handling
switch (key) { case 86: // 'v'
event.preventDefault(); if (this.videoDisabled) { this.enableVideo(); } else { this.disableVideo(); } break; case 77: // 'm'
event.preventDefault(); if (this.audioDisabled) { this.enableAudio(); } else { this.disableAudio(); } break; case 70: // 'f'
event.preventDefault(); if (this.fullscreenDisabled) { this.enableFullscreen(); } else { this.disableFullscreen(); } break; case 67: // 'c'
event.preventDefault(); this._sidebarView.selectTab('chat'); break; case 80: // 'p'
event.preventDefault(); this._sidebarView.selectTab('participants'); break; } } },
_showRoomList: function() { this._roomsView = new OCA.SpreedMe.Views.RoomListView({ el: '#app-navigation ul', collection: this._rooms }); }, _showParticipantList: function() { this._participants = new OCA.SpreedMe.Models.ParticipantCollection(); this._participantsView = new OCA.SpreedMe.Views.ParticipantView({ room: this.activeRoom, collection: this._participants, id: 'participantsTabView' });
this.signaling.on('participantListChanged', function() { // The "participantListChanged" event can be triggered by the
// signaling before the room is set in the collection.
if (this._participants.url) { this._participants.fetch(); } }.bind(this));
this._participantsView.listenTo(this._rooms, 'change:active', function(model, active) { if (active) { this.setRoom(model); } });
this._sidebarView.addTab('participants', { label: t('spreed', 'Participants'), icon: 'icon-contacts-dark' }, this._participantsView); }, /** * @param {string} token */ _setRoomActive: function(token) { if (OC.getCurrentUser().uid) { this._rooms.forEach(function(room) { room.set('active', room.get('token') === token); }); } }, addParticipantToRoom: function(token, participant) { $.post( OC.linkToOCS('apps/spreed/api/v1/room', 2) + token + '/participants', { newParticipant: participant } ).done(function() { this.signaling.syncRooms(); }.bind(this)); }, syncAndSetActiveRoom: function(token) { var self = this; this.signaling.syncRooms() .then(function() { self.stopListening(self.activeRoom, 'change:participantFlags');
var participants; if (OC.getCurrentUser().uid) { roomChannel.trigger('active', token);
self._rooms.forEach(function(room) { if (room.get('token') === token) { self.activeRoom = room; } }); participants = self.activeRoom.get('participants'); } else { // The public page supports only a single room, so the
// active room is already the room for the given token.
participants = self.activeRoom.get('participants'); self.setRoomMessageForGuest(participants); } // Disable video when entering a room with more than 5 participants.
if (participants && Object.keys(participants).length > 5) { self.disableVideo(); }
self.setPageTitle(self.activeRoom.get('displayName'));
self.updateContentsLayout(); self.listenTo(self.activeRoom, 'change:participantFlags', self.updateContentsLayout);
self.updateSidebarWithActiveRoom(); }); }, updateContentsLayout: function() { if (!this.activeRoom) { // This should never happen, but just in case
return; }
var flags = this.activeRoom.get('participantFlags') || 0; var inCall = flags & OCA.SpreedMe.app.FLAG_IN_CALL !== 0; if (inCall && this._chatViewInMainView === true) { this._chatView.saveScrollPosition(); this._chatView.$el.detach(); this._sidebarView.addTab('chat', { label: t('spreed', 'Chat'), icon: 'icon-comment', priority: 100 }, this._chatView); this._sidebarView.selectTab('chat'); this._chatView.restoreScrollPosition(); this._chatView.setTooltipContainer(this._chatView.$el); this._chatViewInMainView = false; } else if (!inCall && !this._chatViewInMainView) { this._chatView.saveScrollPosition(); this._sidebarView.removeTab('chat'); this._chatView.$el.prependTo('#app-content-wrapper'); this._chatView.restoreScrollPosition(); this._chatView.setTooltipContainer($('#app')); this._chatView.focusChatInput(); this._chatViewInMainView = true; }
if (inCall) { $('#video-speaking').show(); $('#videos').show(); $('#screens').show(); $('#emptycontent').hide(); } else { $('#video-speaking').hide(); $('#videos').hide(); $('#screens').hide(); $('#emptycontent').show(); } }, updateSidebarWithActiveRoom: function() { this._sidebarView.enable();
// The sidebar has a width of 27% of the window width and a minimum
// width of 300px. Therefore, when the window is 1111px wide or
// narrower the sidebar will always be 300px wide, and when that
// happens it will overlap with the content area (the narrower the
// window the larger the overlap). Due to this the sidebar is opened
// automatically only if it will not overlap with the content area.
if ($(window).width() > 1111) { this._sidebarView.open(); }
var callInfoView = new OCA.SpreedMe.Views.CallInfoView({ model: this.activeRoom, guestNameModel: this._localStorageModel }); this._sidebarView.setCallInfoView(callInfoView);
this._messageCollection.setRoomToken(this.activeRoom.get('token')); this._messageCollection.receiveMessages(); }, setPageTitle: function(title){ if (title) { title += ' - '; } else { title = ''; } title += t('spreed', 'Talk'); title += ' - ' + oc_defaults.title; window.document.title = title; }, /** * * @param {string|Object} icon * @param {string} icon.userId * @param {string} icon.displayName * @param {string} message * @param {string} [messageAdditional] * @param {string} [url] */ setEmptyContentMessage: function(icon, message, messageAdditional, url) { var $icon = $('#emptycontent-icon'), $emptyContent = $('#emptycontent');
//Remove previous icon and avatar from emptycontent
$icon.removeAttr('class').attr('class', ''); $icon.html('');
if (url) { $('#shareRoomInput').removeClass('hidden').val(url); $('#shareRoomClipboardButton').removeClass('hidden'); } else { $('#shareRoomInput').addClass('hidden'); $('#shareRoomClipboardButton').addClass('hidden'); }
if (typeof icon === 'string') { $icon.addClass(icon); } else { var $avatar = $('<div>'); $avatar.addClass('avatar room-avatar'); if (icon.userId !== icon.displayName) { $avatar.avatar(icon.userId, 128, undefined, false, undefined, icon.displayName); } else { $avatar.avatar(icon.userId, 128); } $icon.append($avatar); }
$emptyContent.find('h2').html(message); $emptyContent.find('p').text(messageAdditional ? messageAdditional : ''); this._lastEmptyContent = this._currentEmptyContent; this._currentEmptyContent = arguments; }, restoreEmptyContent: function() { this.setEmptyContentMessage.apply(this, this._lastEmptyContent); }, setRoomMessageForGuest: function(participants) { if (Object.keys(participants).length === 1) { var participantId = '', participantName = '';
_.each(participants, function(data, userId) { if (OC.getCurrentUser().uid !== userId) { participantId = userId; participantName = data.name; } });
OCA.SpreedMe.app.setEmptyContentMessage( { userId: participantId, displayName: participantName}, t('spreed', 'Waiting for {participantName} to join the call …', {participantName: participantName}) );
} else { OCA.SpreedMe.app.setEmptyContentMessage('icon-contacts-dark', t('spreed', 'Waiting for others to join the call …')); } }, initialize: function() { this._sidebarView = new OCA.SpreedMe.Views.SidebarView(); $('#content').append(this._sidebarView.$el);
if (OC.getCurrentUser().uid) { this._rooms = new OCA.SpreedMe.Models.RoomCollection(); this.listenTo(roomChannel, 'active', this._setRoomActive); } else { this.initGuestName(); }
this._sidebarView.listenTo(roomChannel, 'leaveCurrentRoom', function() { this.disable(); });
this._messageCollection = new OCA.SpreedMe.Models.ChatMessageCollection(null, {token: null}); this._chatView = new OCA.SpreedMe.Views.ChatView({ collection: this._messageCollection, id: 'commentsTabView', guestNameModel: this._localStorageModel });
this._messageCollection.listenTo(roomChannel, 'leaveCurrentRoom', function() { this.stopReceivingMessages(); });
this.listenTo(roomChannel, 'leaveCurrentRoom', function() { this._chatView.$el.detach(); this._chatViewInMainView = false;
$('#video-speaking').hide(); $('#videos').hide(); $('#screens').hide(); $('#emptycontent').show(); });
$(document).on('click', this.onDocumentClick); OC.Util.History.addOnPopStateHandler(_.bind(this._onPopState, this)); }, onStart: function() { this.signaling = OCA.Talk.Signaling.createConnection(); this.connection = new OCA.Talk.Connection(this); this.token = $('#app').attr('data-token');
this.signaling.on('joinRoom', function(/* token */) { this.inRoom = true; if (this.pendingNickChange) { this.setGuestName(this.pendingNickChange); delete this.pendingNickChange; } }.bind(this));
$(window).unload(function () { this.connection.leaveCurrentRoom(false); this.signaling.disconnect(); }.bind(this));
if (OC.getCurrentUser().uid) { this._showRoomList(); this.signaling.setRoomCollection(this._rooms) .then(function(data) { $('#app-navigation').removeClass('icon-loading'); this._roomsView.render();
if (data.length === 0) { $('#select-participants').select2('open'); } }.bind(this));
this._showParticipantList(); } else if (this.token) { // The token is always defined in the public page (although not
// in the public share auth page).
this.activeRoom = new OCA.SpreedMe.Models.Room({ token: this.token }); this.signaling.setRoom(this.activeRoom); }
this._registerPageEvents(); this.initShareRoomClipboard();
if (this.token) { this.connection.joinRoom(this.token); } }, setupWebRTC: function() { if (!OCA.SpreedMe.webrtc) { OCA.SpreedMe.initWebRTC(this); } OCA.SpreedMe.webrtc.startMedia(this.token); }, startLocalMedia: function(configuration) { if (this.callbackAfterMedia) { this.callbackAfterMedia(configuration); this.callbackAfterMedia = null; }
$('.videoView').removeClass('hidden'); this.initAudioVideoSettings(configuration); this.restoreEmptyContent(); }, startWithoutLocalMedia: function(isAudioEnabled, isVideoEnabled) { if (this.callbackAfterMedia) { this.callbackAfterMedia(null); this.callbackAfterMedia = null; }
$('.videoView').removeClass('hidden');
this.disableAudio(); if (!isAudioEnabled) { this.hasNoAudio(); }
this.disableVideo(); if (!isVideoEnabled) { this.hasNoVideo(); } }, _onPopState: function(params) { if (!_.isUndefined(params.token)) { this.connection.joinRoom(params.token); } }, onDocumentClick: function(event) { var uiChannel = Backbone.Radio.channel('ui');
uiChannel.trigger('document:click', event); }, initAudioVideoSettings: function(configuration) { if (this.audioDisabled) { this.disableAudio(); }
if (configuration.video !== false) { if (this.videoDisabled) { this.disableVideo(); } } else { this.videoWasEnabledAtLeastOnce = false; this.disableVideo(); } }, enableFullscreen: function() { var fullscreenElem = document.getElementById('content');
if (fullscreenElem.requestFullscreen) { fullscreenElem.requestFullscreen(); } else if (fullscreenElem.webkitRequestFullscreen) { fullscreenElem.webkitRequestFullscreen(Element.ALLOW_KEYBOARD_INPUT); } else if (fullscreenElem.mozRequestFullScreen) { fullscreenElem.mozRequestFullScreen(); } else if (fullscreenElem.msRequestFullscreen) { fullscreenElem.msRequestFullscreen(); } $('#video-fullscreen').attr('data-original-title', t('spreed', 'Exit fullscreen (f)'));
this.fullscreenDisabled = false; }, disableFullscreen: function() {
if (document.exitFullscreen) { document.exitFullscreen(); } else if (document.webkitExitFullscreen) { document.webkitExitFullscreen(); } else if (document.mozCancelFullScreen) { document.mozCancelFullScreen(); } else if (document.msExitFullscreen) { document.msExitFullscreen(); } $('#video-fullscreen').attr('data-original-title', t('spreed', 'Fullscreen (f)'));
this.fullscreenDisabled = true; }, enableAudioButton: function() { $('#mute').attr('data-original-title', t('spreed', 'Mute audio (m)')) .removeClass('audio-disabled icon-audio-off') .addClass('icon-audio'); }, enableAudio: function() { if (this.audioNotFound || !OCA.SpreedMe.webrtc) { return; } OCA.SpreedMe.webrtc.unmute(); this.enableAudioButton(); this.audioDisabled = false; }, disableAudioButton: function() { $('#mute').attr('data-original-title', t('spreed', 'Unmute audio (m)')) .addClass('audio-disabled icon-audio-off') .removeClass('icon-audio'); }, disableAudio: function() { if (this.audioNotFound || !OCA.SpreedMe.webrtc) { return; } OCA.SpreedMe.webrtc.mute(); this.disableAudioButton(); this.audioDisabled = true; }, hasAudio: function() { $('#mute').removeClass('no-audio-available'); this.enableAudioButton(); this.audioNotFound = false; }, hasNoAudio: function() { $('#mute').removeClass('audio-disabled icon-audio') .addClass('no-audio-available icon-audio-off') .attr('data-original-title', t('spreed', 'No audio')); this.audioDisabled = true; this.audioNotFound = true; }, enableVideoUI: function() { var $hideVideoButton = $('#hideVideo'); var $audioMuteButton = $('#mute'); var $screensharingButton = $('#screensharing-button'); var avatarContainer = $hideVideoButton.closest('.videoView').find('.avatar-container'); var localVideo = $hideVideoButton.closest('.videoView').find('#localVideo');
$hideVideoButton.attr('data-original-title', t('spreed', 'Disable video (v)')) .removeClass('local-video-disabled video-disabled icon-video-off') .addClass('icon-video'); $audioMuteButton.removeClass('local-video-disabled'); $screensharingButton.removeClass('local-video-disabled');
avatarContainer.hide(); localVideo.show(); }, enableVideo: function() { if (this.videoNotFound || !OCA.SpreedMe.webrtc) { return; }
OCA.SpreedMe.webrtc.resumeVideo(); this.enableVideoUI(); this.videoDisabled = false; }, hideVideo: function() { var $hideVideoButton = $('#hideVideo'); var $audioMuteButton = $('#mute'); var $screensharingButton = $('#screensharing-button'); var avatarContainer = $hideVideoButton.closest('.videoView').find('.avatar-container'); var localVideo = $hideVideoButton.closest('.videoView').find('#localVideo');
if (!$hideVideoButton.hasClass('no-video-available')) { $hideVideoButton.attr('data-original-title', t('spreed', 'Enable video (v)')) .addClass('local-video-disabled video-disabled icon-video-off') .removeClass('icon-video'); $audioMuteButton.addClass('local-video-disabled'); $screensharingButton.addClass('local-video-disabled'); }
var avatar = avatarContainer.find('.avatar'); var guestName = localStorage.getItem("nick"); if (OC.getCurrentUser().uid) { avatar.avatar(OC.getCurrentUser().uid, 128); } else { avatar.imageplaceholder('?', guestName, 128); avatar.css('background-color', '#b9b9b9'); if (this.displayedGuestNameHint === false) { OC.Notification.showTemporary(t('spreed', 'Set your name in the chat window so other participants can identify you better.')); this.displayedGuestNameHint = true; } }
avatarContainer.removeClass('hidden'); avatarContainer.show(); localVideo.hide(); }, disableVideo: function() { if (this.videoNotFound || !OCA.SpreedMe.webrtc) { return; }
OCA.SpreedMe.webrtc.pauseVideo(); this.hideVideo(); this.videoDisabled = true; }, hasVideo: function() { $('#hideVideo').removeClass('no-video-available'); this.enableVideoUI(); this.videoNotFound = false; }, hasNoVideo: function() { $('#hideVideo').removeClass('icon-video') .addClass('no-video-available icon-video-off') .attr('data-original-title', t('spreed', 'No Camera')); this.videoDisabled = true; this.videoNotFound = true; }, disableScreensharingButton: function() { $('#screensharing-button').attr('data-original-title', t('spreed', 'Enable screensharing')) .addClass('screensharing-disabled icon-screen-off') .removeClass('icon-screen'); $('#screensharing-menu').toggleClass('open', false); }, setGuestName: function(name) { $.ajax({ url: OC.linkToOCS('apps/spreed/api/v1/guest', 2) + this.token + '/name', type: 'POST', data: { displayName: name }, beforeSend: function (request) { request.setRequestHeader('Accept', 'application/json'); }, success: function() { this._onChangeGuestName(name); }.bind(this) }); }, initGuestName: function() { this._localStorageModel = new OCA.SpreedMe.Models.LocalStorageModel({ nick: '' }); this._localStorageModel.on('change:nick', function(model, newDisplayName) { if (!this.token || !this.inRoom) { this.pendingNickChange = newDisplayName; return; }
this.setGuestName(newDisplayName); }.bind(this));
this._localStorageModel.fetch(); }, _onChangeGuestName: function(newDisplayName) { var avatar = $('#localVideoContainer').find('.avatar');
avatar.imageplaceholder('?', newDisplayName, 128); avatar.css('background-color', '#b9b9b9');
if (OCA.SpreedMe.webrtc) { console.log('_onChangeGuestName.webrtc'); OCA.SpreedMe.webrtc.sendDirectlyToAll('status', 'nickChanged', newDisplayName); } }, initShareRoomClipboard: function () { $('body').find('.shareRoomClipboard').tooltip({ placement: 'bottom', trigger: 'hover', title: t('core', 'Copy') });
var clipboard = new Clipboard('.shareRoomClipboard'); clipboard.on('success', function(e) { var $input = $(e.trigger); $input.tooltip('hide') .attr('data-original-title', t('core', 'Copied!')) .tooltip('fixTitle') .tooltip({placement: 'bottom', trigger: 'manual'}) .tooltip('show'); _.delay(function() { $input.tooltip('hide') .attr('data-original-title', t('core', 'Copy')) .tooltip('fixTitle'); }, 3000); }); clipboard.on('error', function (e) { var $input = $(e.trigger); var actionMsg = ''; if (/iPhone|iPad/i.test(navigator.userAgent)) { actionMsg = t('core', 'Not supported!'); } else if (/Mac/i.test(navigator.userAgent)) { actionMsg = t('core', 'Press ⌘-C to copy.'); } else { actionMsg = t('core', 'Press Ctrl-C to copy.'); }
$input.tooltip('hide') .attr('data-original-title', actionMsg) .tooltip('fixTitle') .tooltip({placement: 'bottom', trigger: 'manual'}) .tooltip('show'); _.delay(function () { $input.tooltip('hide') .attr('data-original-title', t('spreed', 'Copy')) .tooltip('fixTitle'); }, 3000); }); } });
})(OC, OCA, Marionette, Backbone, _, $);
|