mirror of https://github.com/jitsi/jitsi-meet
parent
c7e2331284
commit
9eb2873cfa
@ -1,30 +1,50 @@ |
||||
/* jshint -W117 */ |
||||
/* application specific logic */ |
||||
|
||||
var APP = |
||||
{ |
||||
init: function () { |
||||
this.UI = require("./modules/UI/UI"); |
||||
this.API = require("./modules/API/API"); |
||||
this.connectionquality = require("./modules/connectionquality/connectionquality"); |
||||
this.statistics = require("./modules/statistics/statistics"); |
||||
this.RTC = require("./modules/RTC/RTC"); |
||||
this.simulcast = require("./modules/simulcast/simulcast"); |
||||
this.desktopsharing = require("./modules/desktopsharing/desktopsharing"); |
||||
this.xmpp = require("./modules/xmpp/xmpp"); |
||||
this.keyboardshortcut = require("./modules/keyboardshortcut/keyboardshortcut"); |
||||
} |
||||
}; |
||||
|
||||
function init() { |
||||
|
||||
RTC.start(); |
||||
xmpp.start(UI.getCreadentials); |
||||
APP.RTC.start(); |
||||
APP.xmpp.start(APP.UI.getCreadentials); |
||||
APP.statistics.start(); |
||||
APP.connectionquality.init(); |
||||
|
||||
// Set default desktop sharing method
|
||||
APP.desktopsharing.init(); |
||||
|
||||
APP.keyboardshortcut.init(); |
||||
} |
||||
|
||||
|
||||
$(document).ready(function () { |
||||
|
||||
if(API.isEnabled()) |
||||
API.init(); |
||||
APP.init(); |
||||
|
||||
UI.start(); |
||||
statistics.start(); |
||||
connectionquality.init(); |
||||
|
||||
// Set default desktop sharing method
|
||||
desktopsharing.init(); |
||||
if(APP.API.isEnabled()) |
||||
APP.API.init(); |
||||
|
||||
APP.UI.start(init); |
||||
|
||||
keyboardshortcut.init(); |
||||
}); |
||||
|
||||
$(window).bind('beforeunload', function () { |
||||
if(API.isEnabled()) |
||||
API.dispose(); |
||||
if(APP.API.isEnabled()) |
||||
APP.API.dispose(); |
||||
}); |
||||
|
||||
module.exports = APP; |
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,234 +0,0 @@ |
||||
!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.API=e()}}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){ |
||||
/** |
||||
* Implements API class that communicates with external api class |
||||
* and provides interface to access Jitsi Meet features by external |
||||
* applications that embed Jitsi Meet |
||||
*/ |
||||
|
||||
|
||||
|
||||
/** |
||||
* List of the available commands. |
||||
* @type {{ |
||||
* displayName: inputDisplayNameHandler, |
||||
* muteAudio: toggleAudio, |
||||
* muteVideo: toggleVideo, |
||||
* filmStrip: toggleFilmStrip |
||||
* }} |
||||
*/ |
||||
var commands = |
||||
{ |
||||
displayName: UI.inputDisplayNameHandler, |
||||
muteAudio: UI.toggleAudio, |
||||
muteVideo: UI.toggleVideo, |
||||
toggleFilmStrip: UI.toggleFilmStrip, |
||||
toggleChat: UI.toggleChat, |
||||
toggleContactList: UI.toggleContactList |
||||
}; |
||||
|
||||
|
||||
/** |
||||
* Maps the supported events and their status |
||||
* (true it the event is enabled and false if it is disabled) |
||||
* @type {{ |
||||
* incomingMessage: boolean, |
||||
* outgoingMessage: boolean, |
||||
* displayNameChange: boolean, |
||||
* participantJoined: boolean, |
||||
* participantLeft: boolean |
||||
* }} |
||||
*/ |
||||
var events = |
||||
{ |
||||
incomingMessage: false, |
||||
outgoingMessage:false, |
||||
displayNameChange: false, |
||||
participantJoined: false, |
||||
participantLeft: false |
||||
}; |
||||
|
||||
var displayName = {}; |
||||
|
||||
/** |
||||
* Processes commands from external applicaiton. |
||||
* @param message the object with the command |
||||
*/ |
||||
function processCommand(message) |
||||
{ |
||||
if(message.action != "execute") |
||||
{ |
||||
console.error("Unknown action of the message"); |
||||
return; |
||||
} |
||||
for(var key in message) |
||||
{ |
||||
if(commands[key]) |
||||
commands[key].apply(null, message[key]); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Processes events objects from external applications |
||||
* @param event the event |
||||
*/ |
||||
function processEvent(event) { |
||||
if(!event.action) |
||||
{ |
||||
console.error("Event with no action is received."); |
||||
return; |
||||
} |
||||
|
||||
var i = 0; |
||||
switch(event.action) |
||||
{ |
||||
case "add": |
||||
for(; i < event.events.length; i++) |
||||
{ |
||||
events[event.events[i]] = true; |
||||
} |
||||
break; |
||||
case "remove": |
||||
for(; i < event.events.length; i++) |
||||
{ |
||||
events[event.events[i]] = false; |
||||
} |
||||
break; |
||||
default: |
||||
console.error("Unknown action for event."); |
||||
} |
||||
|
||||
} |
||||
|
||||
/** |
||||
* Sends message to the external application. |
||||
* @param object |
||||
*/ |
||||
function sendMessage(object) { |
||||
window.parent.postMessage(JSON.stringify(object), "*"); |
||||
} |
||||
|
||||
/** |
||||
* Processes a message event from the external application |
||||
* @param event the message event |
||||
*/ |
||||
function processMessage(event) |
||||
{ |
||||
var message; |
||||
try { |
||||
message = JSON.parse(event.data); |
||||
} catch (e) {} |
||||
|
||||
if(!message.type) |
||||
return; |
||||
switch (message.type) |
||||
{ |
||||
case "command": |
||||
processCommand(message); |
||||
break; |
||||
case "event": |
||||
processEvent(message); |
||||
break; |
||||
default: |
||||
console.error("Unknown type of the message"); |
||||
return; |
||||
} |
||||
|
||||
} |
||||
|
||||
function setupListeners() { |
||||
xmpp.addListener(XMPPEvents.MUC_ENTER, function (from) { |
||||
API.triggerEvent("participantJoined", {jid: from}); |
||||
}); |
||||
xmpp.addListener(XMPPEvents.MESSAGE_RECEIVED, function (from, nick, txt, myjid) { |
||||
if (from != myjid) |
||||
API.triggerEvent("incomingMessage", |
||||
{"from": from, "nick": nick, "message": txt}); |
||||
}); |
||||
xmpp.addListener(XMPPEvents.MUC_LEFT, function (jid) { |
||||
API.triggerEvent("participantLeft", {jid: jid}); |
||||
}); |
||||
xmpp.addListener(XMPPEvents.DISPLAY_NAME_CHANGED, function (jid, newDisplayName) { |
||||
name = displayName[jid]; |
||||
if(!name || name != newDisplayName) { |
||||
API.triggerEvent("displayNameChange", {jid: jid, displayname: newDisplayName}); |
||||
displayName[jid] = newDisplayName; |
||||
} |
||||
}); |
||||
xmpp.addListener(XMPPEvents.SENDING_CHAT_MESSAGE, function (body) { |
||||
API.triggerEvent("outgoingMessage", {"message": body}); |
||||
}); |
||||
} |
||||
|
||||
var API = { |
||||
/** |
||||
* Check whether the API should be enabled or not. |
||||
* @returns {boolean} |
||||
*/ |
||||
isEnabled: function () { |
||||
var hash = location.hash; |
||||
if(hash && hash.indexOf("external") > -1 && window.postMessage) |
||||
return true; |
||||
return false; |
||||
}, |
||||
/** |
||||
* Initializes the APIConnector. Setups message event listeners that will |
||||
* receive information from external applications that embed Jitsi Meet. |
||||
* It also sends a message to the external application that APIConnector |
||||
* is initialized. |
||||
*/ |
||||
init: function () { |
||||
if (window.addEventListener) |
||||
{ |
||||
window.addEventListener('message', |
||||
processMessage, false); |
||||
} |
||||
else |
||||
{ |
||||
window.attachEvent('onmessage', processMessage); |
||||
} |
||||
sendMessage({type: "system", loaded: true}); |
||||
setupListeners(); |
||||
}, |
||||
/** |
||||
* Checks whether the event is enabled ot not. |
||||
* @param name the name of the event. |
||||
* @returns {*} |
||||
*/ |
||||
isEventEnabled: function (name) { |
||||
return events[name]; |
||||
}, |
||||
|
||||
/** |
||||
* Sends event object to the external application that has been subscribed |
||||
* for that event. |
||||
* @param name the name event |
||||
* @param object data associated with the event |
||||
*/ |
||||
triggerEvent: function (name, object) { |
||||
if(this.isEnabled() && this.isEventEnabled(name)) |
||||
sendMessage({ |
||||
type: "event", action: "result", event: name, result: object}); |
||||
}, |
||||
|
||||
/** |
||||
* Removes the listeners. |
||||
*/ |
||||
dispose: function () { |
||||
if(window.removeEventListener) |
||||
{ |
||||
window.removeEventListener("message", |
||||
processMessage, false); |
||||
} |
||||
else |
||||
{ |
||||
window.detachEvent('onmessage', processMessage); |
||||
} |
||||
|
||||
} |
||||
|
||||
|
||||
}; |
||||
|
||||
module.exports = API; |
||||
},{}]},{},[1])(1) |
||||
}); |
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,438 +0,0 @@ |
||||
!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var n;"undefined"!=typeof window?n=window:"undefined"!=typeof global?n=global:"undefined"!=typeof self&&(n=self),n.connectionquality=e()}}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){ |
||||
var EventEmitter = require("events"); |
||||
var eventEmitter = new EventEmitter(); |
||||
|
||||
/** |
||||
* local stats |
||||
* @type {{}} |
||||
*/ |
||||
var stats = {}; |
||||
|
||||
/** |
||||
* remote stats |
||||
* @type {{}} |
||||
*/ |
||||
var remoteStats = {}; |
||||
|
||||
/** |
||||
* Interval for sending statistics to other participants |
||||
* @type {null} |
||||
*/ |
||||
var sendIntervalId = null; |
||||
|
||||
|
||||
/** |
||||
* Start statistics sending. |
||||
*/ |
||||
function startSendingStats() { |
||||
sendStats(); |
||||
sendIntervalId = setInterval(sendStats, 10000); |
||||
} |
||||
|
||||
/** |
||||
* Sends statistics to other participants |
||||
*/ |
||||
function sendStats() { |
||||
xmpp.addToPresence("connectionQuality", convertToMUCStats(stats)); |
||||
} |
||||
|
||||
/** |
||||
* Converts statistics to format for sending through XMPP |
||||
* @param stats the statistics |
||||
* @returns {{bitrate_donwload: *, bitrate_uplpoad: *, packetLoss_total: *, packetLoss_download: *, packetLoss_upload: *}} |
||||
*/ |
||||
function convertToMUCStats(stats) { |
||||
return { |
||||
"bitrate_download": stats.bitrate.download, |
||||
"bitrate_upload": stats.bitrate.upload, |
||||
"packetLoss_total": stats.packetLoss.total, |
||||
"packetLoss_download": stats.packetLoss.download, |
||||
"packetLoss_upload": stats.packetLoss.upload |
||||
}; |
||||
} |
||||
|
||||
/** |
||||
* Converts statitistics to format used by VideoLayout |
||||
* @param stats |
||||
* @returns {{bitrate: {download: *, upload: *}, packetLoss: {total: *, download: *, upload: *}}} |
||||
*/ |
||||
function parseMUCStats(stats) { |
||||
return { |
||||
bitrate: { |
||||
download: stats.bitrate_download, |
||||
upload: stats.bitrate_upload |
||||
}, |
||||
packetLoss: { |
||||
total: stats.packetLoss_total, |
||||
download: stats.packetLoss_download, |
||||
upload: stats.packetLoss_upload |
||||
} |
||||
}; |
||||
} |
||||
|
||||
|
||||
var ConnectionQuality = { |
||||
init: function () { |
||||
xmpp.addListener(XMPPEvents.REMOTE_STATS, this.updateRemoteStats); |
||||
statistics.addConnectionStatsListener(this.updateLocalStats); |
||||
statistics.addRemoteStatsStopListener(this.stopSendingStats); |
||||
|
||||
}, |
||||
|
||||
/** |
||||
* Updates the local statistics |
||||
* @param data new statistics |
||||
*/ |
||||
updateLocalStats: function (data) { |
||||
stats = data; |
||||
eventEmitter.emit(CQEvents.LOCALSTATS_UPDATED, 100 - stats.packetLoss.total, stats); |
||||
if (sendIntervalId == null) { |
||||
startSendingStats(); |
||||
} |
||||
}, |
||||
|
||||
/** |
||||
* Updates remote statistics |
||||
* @param jid the jid associated with the statistics |
||||
* @param data the statistics |
||||
*/ |
||||
updateRemoteStats: function (jid, data) { |
||||
if (data == null || data.packetLoss_total == null) { |
||||
eventEmitter.emit(CQEvents.REMOTESTATS_UPDATED, jid, null, null); |
||||
return; |
||||
} |
||||
remoteStats[jid] = parseMUCStats(data); |
||||
|
||||
eventEmitter.emit(CQEvents.REMOTESTATS_UPDATED, |
||||
jid, 100 - data.packetLoss_total, remoteStats[jid]); |
||||
}, |
||||
|
||||
/** |
||||
* Stops statistics sending. |
||||
*/ |
||||
stopSendingStats: function () { |
||||
clearInterval(sendIntervalId); |
||||
sendIntervalId = null; |
||||
//notify UI about stopping statistics gathering
|
||||
eventEmitter.emit(CQEvents.STOP); |
||||
}, |
||||
|
||||
/** |
||||
* Returns the local statistics. |
||||
*/ |
||||
getStats: function () { |
||||
return stats; |
||||
}, |
||||
|
||||
addListener: function (type, listener) { |
||||
eventEmitter.on(type, listener); |
||||
} |
||||
|
||||
}; |
||||
|
||||
module.exports = ConnectionQuality; |
||||
},{"events":2}],2:[function(require,module,exports){ |
||||
// Copyright Joyent, Inc. and other Node contributors.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to permit
|
||||
// persons to whom the Software is furnished to do so, subject to the
|
||||
// following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included
|
||||
// in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
|
||||
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||
// USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
function EventEmitter() { |
||||
this._events = this._events || {}; |
||||
this._maxListeners = this._maxListeners || undefined; |
||||
} |
||||
module.exports = EventEmitter; |
||||
|
||||
// Backwards-compat with node 0.10.x
|
||||
EventEmitter.EventEmitter = EventEmitter; |
||||
|
||||
EventEmitter.prototype._events = undefined; |
||||
EventEmitter.prototype._maxListeners = undefined; |
||||
|
||||
// By default EventEmitters will print a warning if more than 10 listeners are
|
||||
// added to it. This is a useful default which helps finding memory leaks.
|
||||
EventEmitter.defaultMaxListeners = 10; |
||||
|
||||
// Obviously not all Emitters should be limited to 10. This function allows
|
||||
// that to be increased. Set to zero for unlimited.
|
||||
EventEmitter.prototype.setMaxListeners = function(n) { |
||||
if (!isNumber(n) || n < 0 || isNaN(n)) |
||||
throw TypeError('n must be a positive number'); |
||||
this._maxListeners = n; |
||||
return this; |
||||
}; |
||||
|
||||
EventEmitter.prototype.emit = function(type) { |
||||
var er, handler, len, args, i, listeners; |
||||
|
||||
if (!this._events) |
||||
this._events = {}; |
||||
|
||||
// If there is no 'error' event listener then throw.
|
||||
if (type === 'error') { |
||||
if (!this._events.error || |
||||
(isObject(this._events.error) && !this._events.error.length)) { |
||||
er = arguments[1]; |
||||
if (er instanceof Error) { |
||||
throw er; // Unhandled 'error' event
|
||||
} |
||||
throw TypeError('Uncaught, unspecified "error" event.'); |
||||
} |
||||
} |
||||
|
||||
handler = this._events[type]; |
||||
|
||||
if (isUndefined(handler)) |
||||
return false; |
||||
|
||||
if (isFunction(handler)) { |
||||
switch (arguments.length) { |
||||
// fast cases
|
||||
case 1: |
||||
handler.call(this); |
||||
break; |
||||
case 2: |
||||
handler.call(this, arguments[1]); |
||||
break; |
||||
case 3: |
||||
handler.call(this, arguments[1], arguments[2]); |
||||
break; |
||||
// slower
|
||||
default: |
||||
len = arguments.length; |
||||
args = new Array(len - 1); |
||||
for (i = 1; i < len; i++) |
||||
args[i - 1] = arguments[i]; |
||||
handler.apply(this, args); |
||||
} |
||||
} else if (isObject(handler)) { |
||||
len = arguments.length; |
||||
args = new Array(len - 1); |
||||
for (i = 1; i < len; i++) |
||||
args[i - 1] = arguments[i]; |
||||
|
||||
listeners = handler.slice(); |
||||
len = listeners.length; |
||||
for (i = 0; i < len; i++) |
||||
listeners[i].apply(this, args); |
||||
} |
||||
|
||||
return true; |
||||
}; |
||||
|
||||
EventEmitter.prototype.addListener = function(type, listener) { |
||||
var m; |
||||
|
||||
if (!isFunction(listener)) |
||||
throw TypeError('listener must be a function'); |
||||
|
||||
if (!this._events) |
||||
this._events = {}; |
||||
|
||||
// To avoid recursion in the case that type === "newListener"! Before
|
||||
// adding it to the listeners, first emit "newListener".
|
||||
if (this._events.newListener) |
||||
this.emit('newListener', type, |
||||
isFunction(listener.listener) ? |
||||
listener.listener : listener); |
||||
|
||||
if (!this._events[type]) |
||||
// Optimize the case of one listener. Don't need the extra array object.
|
||||
this._events[type] = listener; |
||||
else if (isObject(this._events[type])) |
||||
// If we've already got an array, just append.
|
||||
this._events[type].push(listener); |
||||
else |
||||
// Adding the second element, need to change to array.
|
||||
this._events[type] = [this._events[type], listener]; |
||||
|
||||
// Check for listener leak
|
||||
if (isObject(this._events[type]) && !this._events[type].warned) { |
||||
var m; |
||||
if (!isUndefined(this._maxListeners)) { |
||||
m = this._maxListeners; |
||||
} else { |
||||
m = EventEmitter.defaultMaxListeners; |
||||
} |
||||
|
||||
if (m && m > 0 && this._events[type].length > m) { |
||||
this._events[type].warned = true; |
||||
console.error('(node) warning: possible EventEmitter memory ' + |
||||
'leak detected. %d listeners added. ' + |
||||
'Use emitter.setMaxListeners() to increase limit.', |
||||
this._events[type].length); |
||||
if (typeof console.trace === 'function') { |
||||
// not supported in IE 10
|
||||
console.trace(); |
||||
} |
||||
} |
||||
} |
||||
|
||||
return this; |
||||
}; |
||||
|
||||
EventEmitter.prototype.on = EventEmitter.prototype.addListener; |
||||
|
||||
EventEmitter.prototype.once = function(type, listener) { |
||||
if (!isFunction(listener)) |
||||
throw TypeError('listener must be a function'); |
||||
|
||||
var fired = false; |
||||
|
||||
function g() { |
||||
this.removeListener(type, g); |
||||
|
||||
if (!fired) { |
||||
fired = true; |
||||
listener.apply(this, arguments); |
||||
} |
||||
} |
||||
|
||||
g.listener = listener; |
||||
this.on(type, g); |
||||
|
||||
return this; |
||||
}; |
||||
|
||||
// emits a 'removeListener' event iff the listener was removed
|
||||
EventEmitter.prototype.removeListener = function(type, listener) { |
||||
var list, position, length, i; |
||||
|
||||
if (!isFunction(listener)) |
||||
throw TypeError('listener must be a function'); |
||||
|
||||
if (!this._events || !this._events[type]) |
||||
return this; |
||||
|
||||
list = this._events[type]; |
||||
length = list.length; |
||||
position = -1; |
||||
|
||||
if (list === listener || |
||||
(isFunction(list.listener) && list.listener === listener)) { |
||||
delete this._events[type]; |
||||
if (this._events.removeListener) |
||||
this.emit('removeListener', type, listener); |
||||
|
||||
} else if (isObject(list)) { |
||||
for (i = length; i-- > 0;) { |
||||
if (list[i] === listener || |
||||
(list[i].listener && list[i].listener === listener)) { |
||||
position = i; |
||||
break; |
||||
} |
||||
} |
||||
|
||||
if (position < 0) |
||||
return this; |
||||
|
||||
if (list.length === 1) { |
||||
list.length = 0; |
||||
delete this._events[type]; |
||||
} else { |
||||
list.splice(position, 1); |
||||
} |
||||
|
||||
if (this._events.removeListener) |
||||
this.emit('removeListener', type, listener); |
||||
} |
||||
|
||||
return this; |
||||
}; |
||||
|
||||
EventEmitter.prototype.removeAllListeners = function(type) { |
||||
var key, listeners; |
||||
|
||||
if (!this._events) |
||||
return this; |
||||
|
||||
// not listening for removeListener, no need to emit
|
||||
if (!this._events.removeListener) { |
||||
if (arguments.length === 0) |
||||
this._events = {}; |
||||
else if (this._events[type]) |
||||
delete this._events[type]; |
||||
return this; |
||||
} |
||||
|
||||
// emit removeListener for all listeners on all events
|
||||
if (arguments.length === 0) { |
||||
for (key in this._events) { |
||||
if (key === 'removeListener') continue; |
||||
this.removeAllListeners(key); |
||||
} |
||||
this.removeAllListeners('removeListener'); |
||||
this._events = {}; |
||||
return this; |
||||
} |
||||
|
||||
listeners = this._events[type]; |
||||
|
||||
if (isFunction(listeners)) { |
||||
this.removeListener(type, listeners); |
||||
} else { |
||||
// LIFO order
|
||||
while (listeners.length) |
||||
this.removeListener(type, listeners[listeners.length - 1]); |
||||
} |
||||
delete this._events[type]; |
||||
|
||||
return this; |
||||
}; |
||||
|
||||
EventEmitter.prototype.listeners = function(type) { |
||||
var ret; |
||||
if (!this._events || !this._events[type]) |
||||
ret = []; |
||||
else if (isFunction(this._events[type])) |
||||
ret = [this._events[type]]; |
||||
else |
||||
ret = this._events[type].slice(); |
||||
return ret; |
||||
}; |
||||
|
||||
EventEmitter.listenerCount = function(emitter, type) { |
||||
var ret; |
||||
if (!emitter._events || !emitter._events[type]) |
||||
ret = 0; |
||||
else if (isFunction(emitter._events[type])) |
||||
ret = 1; |
||||
else |
||||
ret = emitter._events[type].length; |
||||
return ret; |
||||
}; |
||||
|
||||
function isFunction(arg) { |
||||
return typeof arg === 'function'; |
||||
} |
||||
|
||||
function isNumber(arg) { |
||||
return typeof arg === 'number'; |
||||
} |
||||
|
||||
function isObject(arg) { |
||||
return typeof arg === 'object' && arg !== null; |
||||
} |
||||
|
||||
function isUndefined(arg) { |
||||
return arg === void 0; |
||||
} |
||||
|
||||
},{}]},{},[1])(1) |
||||
}); |
@ -1,628 +0,0 @@ |
||||
!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.desktopsharing=e()}}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){ |
||||
/* global $, alert, changeLocalVideo, chrome, config, getConferenceHandler, getUserMediaWithConstraints */ |
||||
/** |
||||
* Indicates that desktop stream is currently in use(for toggle purpose). |
||||
* @type {boolean} |
||||
*/ |
||||
var isUsingScreenStream = false; |
||||
/** |
||||
* Indicates that switch stream operation is in progress and prevent from triggering new events. |
||||
* @type {boolean} |
||||
*/ |
||||
var switchInProgress = false; |
||||
|
||||
/** |
||||
* Method used to get screen sharing stream. |
||||
* |
||||
* @type {function (stream_callback, failure_callback} |
||||
*/ |
||||
var obtainDesktopStream = null; |
||||
|
||||
/** |
||||
* Flag used to cache desktop sharing enabled state. Do not use directly as it can be <tt>null</tt>. |
||||
* @type {null|boolean} |
||||
*/ |
||||
var _desktopSharingEnabled = null; |
||||
|
||||
var EventEmitter = require("events"); |
||||
|
||||
var eventEmitter = new EventEmitter(); |
||||
|
||||
/** |
||||
* Method obtains desktop stream from WebRTC 'screen' source. |
||||
* Flag 'chrome://flags/#enable-usermedia-screen-capture' must be enabled. |
||||
*/ |
||||
function obtainWebRTCScreen(streamCallback, failCallback) { |
||||
RTC.getUserMediaWithConstraints( |
||||
['screen'], |
||||
streamCallback, |
||||
failCallback |
||||
); |
||||
} |
||||
|
||||
/** |
||||
* Constructs inline install URL for Chrome desktop streaming extension. |
||||
* The 'chromeExtensionId' must be defined in config.js. |
||||
* @returns {string} |
||||
*/ |
||||
function getWebStoreInstallUrl() |
||||
{ |
||||
return "https://chrome.google.com/webstore/detail/" + config.chromeExtensionId; |
||||
} |
||||
|
||||
/** |
||||
* Checks whether extension update is required. |
||||
* @param minVersion minimal required version |
||||
* @param extVersion current extension version |
||||
* @returns {boolean} |
||||
*/ |
||||
function isUpdateRequired(minVersion, extVersion) |
||||
{ |
||||
try |
||||
{ |
||||
var s1 = minVersion.split('.'); |
||||
var s2 = extVersion.split('.'); |
||||
|
||||
var len = Math.max(s1.length, s2.length); |
||||
for (var i = 0; i < len; i++) |
||||
{ |
||||
var n1 = 0, |
||||
n2 = 0; |
||||
|
||||
if (i < s1.length) |
||||
n1 = parseInt(s1[i]); |
||||
if (i < s2.length) |
||||
n2 = parseInt(s2[i]); |
||||
|
||||
if (isNaN(n1) || isNaN(n2)) |
||||
{ |
||||
return true; |
||||
} |
||||
else if (n1 !== n2) |
||||
{ |
||||
return n1 > n2; |
||||
} |
||||
} |
||||
|
||||
// will happen if boths version has identical numbers in
|
||||
// their components (even if one of them is longer, has more components)
|
||||
return false; |
||||
} |
||||
catch (e) |
||||
{ |
||||
console.error("Failed to parse extension version", e); |
||||
UI.messageHandler.showError('Error', |
||||
'Error when trying to detect desktopsharing extension.'); |
||||
return true; |
||||
} |
||||
} |
||||
|
||||
|
||||
function checkExtInstalled(isInstalledCallback) { |
||||
if (!chrome.runtime) { |
||||
// No API, so no extension for sure
|
||||
isInstalledCallback(false); |
||||
return; |
||||
} |
||||
chrome.runtime.sendMessage( |
||||
config.chromeExtensionId, |
||||
{ getVersion: true }, |
||||
function (response) { |
||||
if (!response || !response.version) { |
||||
// Communication failure - assume that no endpoint exists
|
||||
console.warn("Extension not installed?: " + chrome.runtime.lastError); |
||||
isInstalledCallback(false); |
||||
} else { |
||||
// Check installed extension version
|
||||
var extVersion = response.version; |
||||
console.log('Extension version is: ' + extVersion); |
||||
var updateRequired = isUpdateRequired(config.minChromeExtVersion, extVersion); |
||||
if (updateRequired) { |
||||
alert( |
||||
'Jitsi Desktop Streamer requires update. ' + |
||||
'Changes will take effect after next Chrome restart.'); |
||||
} |
||||
isInstalledCallback(!updateRequired); |
||||
} |
||||
} |
||||
); |
||||
} |
||||
|
||||
function doGetStreamFromExtension(streamCallback, failCallback) { |
||||
// Sends 'getStream' msg to the extension. Extension id must be defined in the config.
|
||||
chrome.runtime.sendMessage( |
||||
config.chromeExtensionId, |
||||
{ getStream: true, sources: config.desktopSharingSources }, |
||||
function (response) { |
||||
if (!response) { |
||||
failCallback(chrome.runtime.lastError); |
||||
return; |
||||
} |
||||
console.log("Response from extension: " + response); |
||||
if (response.streamId) { |
||||
RTC.getUserMediaWithConstraints( |
||||
['desktop'], |
||||
function (stream) { |
||||
streamCallback(stream); |
||||
}, |
||||
failCallback, |
||||
null, null, null, |
||||
response.streamId); |
||||
} else { |
||||
failCallback("Extension failed to get the stream"); |
||||
} |
||||
} |
||||
); |
||||
} |
||||
/** |
||||
* Asks Chrome extension to call chooseDesktopMedia and gets chrome 'desktop' stream for returned stream token. |
||||
*/ |
||||
function obtainScreenFromExtension(streamCallback, failCallback) { |
||||
checkExtInstalled( |
||||
function (isInstalled) { |
||||
if (isInstalled) { |
||||
doGetStreamFromExtension(streamCallback, failCallback); |
||||
} else { |
||||
chrome.webstore.install( |
||||
getWebStoreInstallUrl(), |
||||
function (arg) { |
||||
console.log("Extension installed successfully", arg); |
||||
// We need to reload the page in order to get the access to chrome.runtime
|
||||
window.location.reload(false); |
||||
}, |
||||
function (arg) { |
||||
console.log("Failed to install the extension", arg); |
||||
failCallback(arg); |
||||
UI.messageHandler.showError('Error', |
||||
'Failed to install desktop sharing extension'); |
||||
} |
||||
); |
||||
} |
||||
} |
||||
); |
||||
} |
||||
|
||||
/** |
||||
* Call this method to toggle desktop sharing feature. |
||||
* @param method pass "ext" to use chrome extension for desktop capture(chrome extension required), |
||||
* pass "webrtc" to use WebRTC "screen" desktop source('chrome://flags/#enable-usermedia-screen-capture' |
||||
* must be enabled), pass any other string or nothing in order to disable this feature completely. |
||||
*/ |
||||
function setDesktopSharing(method) { |
||||
// Check if we are running chrome
|
||||
if (!navigator.webkitGetUserMedia) { |
||||
obtainDesktopStream = null; |
||||
console.info("Desktop sharing disabled"); |
||||
} else if (method == "ext") { |
||||
obtainDesktopStream = obtainScreenFromExtension; |
||||
console.info("Using Chrome extension for desktop sharing"); |
||||
} else if (method == "webrtc") { |
||||
obtainDesktopStream = obtainWebRTCScreen; |
||||
console.info("Using Chrome WebRTC for desktop sharing"); |
||||
} |
||||
|
||||
// Reset enabled cache
|
||||
_desktopSharingEnabled = null; |
||||
} |
||||
|
||||
/** |
||||
* Initializes <link rel=chrome-webstore-item /> with extension id set in config.js to support inline installs. |
||||
* Host site must be selected as main website of published extension. |
||||
*/ |
||||
function initInlineInstalls() |
||||
{ |
||||
$("link[rel=chrome-webstore-item]").attr("href", getWebStoreInstallUrl()); |
||||
} |
||||
|
||||
function getSwitchStreamFailed(error) { |
||||
console.error("Failed to obtain the stream to switch to", error); |
||||
switchInProgress = false; |
||||
} |
||||
|
||||
function streamSwitchDone() { |
||||
switchInProgress = false; |
||||
eventEmitter.emit( |
||||
DesktopSharingEventTypes.SWITCHING_DONE, |
||||
isUsingScreenStream); |
||||
} |
||||
|
||||
function newStreamCreated(stream) |
||||
{ |
||||
eventEmitter.emit(DesktopSharingEventTypes.NEW_STREAM_CREATED, |
||||
stream, isUsingScreenStream, streamSwitchDone); |
||||
} |
||||
|
||||
|
||||
module.exports = { |
||||
isUsingScreenStream: function () { |
||||
return isUsingScreenStream; |
||||
}, |
||||
|
||||
/** |
||||
* @returns {boolean} <tt>true</tt> if desktop sharing feature is available and enabled. |
||||
*/ |
||||
isDesktopSharingEnabled: function () { |
||||
if (_desktopSharingEnabled === null) { |
||||
if (obtainDesktopStream === obtainScreenFromExtension) { |
||||
// Parse chrome version
|
||||
var userAgent = navigator.userAgent.toLowerCase(); |
||||
// We can assume that user agent is chrome, because it's enforced when 'ext' streaming method is set
|
||||
var ver = parseInt(userAgent.match(/chrome\/(\d+)\./)[1], 10); |
||||
console.log("Chrome version" + userAgent, ver); |
||||
_desktopSharingEnabled = ver >= 34; |
||||
} else { |
||||
_desktopSharingEnabled = obtainDesktopStream === obtainWebRTCScreen; |
||||
} |
||||
} |
||||
return _desktopSharingEnabled; |
||||
}, |
||||
|
||||
init: function () { |
||||
setDesktopSharing(config.desktopSharing); |
||||
|
||||
// Initialize Chrome extension inline installs
|
||||
if (config.chromeExtensionId) { |
||||
initInlineInstalls(); |
||||
} |
||||
|
||||
eventEmitter.emit(DesktopSharingEventTypes.INIT); |
||||
}, |
||||
|
||||
addListener: function(listener, type) |
||||
{ |
||||
eventEmitter.on(type, listener); |
||||
}, |
||||
|
||||
removeListener: function (listener,type) { |
||||
eventEmitter.removeListener(type, listener); |
||||
}, |
||||
|
||||
/* |
||||
* Toggles screen sharing. |
||||
*/ |
||||
toggleScreenSharing: function () { |
||||
if (switchInProgress || !obtainDesktopStream) { |
||||
console.warn("Switch in progress or no method defined"); |
||||
return; |
||||
} |
||||
switchInProgress = true; |
||||
|
||||
if (!isUsingScreenStream) |
||||
{ |
||||
// Switch to desktop stream
|
||||
obtainDesktopStream( |
||||
function (stream) { |
||||
// We now use screen stream
|
||||
isUsingScreenStream = true; |
||||
// Hook 'ended' event to restore camera when screen stream stops
|
||||
stream.addEventListener('ended', |
||||
function (e) { |
||||
if (!switchInProgress && isUsingScreenStream) { |
||||
toggleScreenSharing(); |
||||
} |
||||
} |
||||
); |
||||
newStreamCreated(stream); |
||||
}, |
||||
getSwitchStreamFailed); |
||||
} else { |
||||
// Disable screen stream
|
||||
RTC.getUserMediaWithConstraints( |
||||
['video'], |
||||
function (stream) { |
||||
// We are now using camera stream
|
||||
isUsingScreenStream = false; |
||||
newStreamCreated(stream); |
||||
}, |
||||
getSwitchStreamFailed, config.resolution || '360' |
||||
); |
||||
} |
||||
} |
||||
}; |
||||
|
||||
|
||||
},{"events":2}],2:[function(require,module,exports){ |
||||
// Copyright Joyent, Inc. and other Node contributors.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to permit
|
||||
// persons to whom the Software is furnished to do so, subject to the
|
||||
// following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included
|
||||
// in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
|
||||
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||
// USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
function EventEmitter() { |
||||
this._events = this._events || {}; |
||||
this._maxListeners = this._maxListeners || undefined; |
||||
} |
||||
module.exports = EventEmitter; |
||||
|
||||
// Backwards-compat with node 0.10.x
|
||||
EventEmitter.EventEmitter = EventEmitter; |
||||
|
||||
EventEmitter.prototype._events = undefined; |
||||
EventEmitter.prototype._maxListeners = undefined; |
||||
|
||||
// By default EventEmitters will print a warning if more than 10 listeners are
|
||||
// added to it. This is a useful default which helps finding memory leaks.
|
||||
EventEmitter.defaultMaxListeners = 10; |
||||
|
||||
// Obviously not all Emitters should be limited to 10. This function allows
|
||||
// that to be increased. Set to zero for unlimited.
|
||||
EventEmitter.prototype.setMaxListeners = function(n) { |
||||
if (!isNumber(n) || n < 0 || isNaN(n)) |
||||
throw TypeError('n must be a positive number'); |
||||
this._maxListeners = n; |
||||
return this; |
||||
}; |
||||
|
||||
EventEmitter.prototype.emit = function(type) { |
||||
var er, handler, len, args, i, listeners; |
||||
|
||||
if (!this._events) |
||||
this._events = {}; |
||||
|
||||
// If there is no 'error' event listener then throw.
|
||||
if (type === 'error') { |
||||
if (!this._events.error || |
||||
(isObject(this._events.error) && !this._events.error.length)) { |
||||
er = arguments[1]; |
||||
if (er instanceof Error) { |
||||
throw er; // Unhandled 'error' event
|
||||
} |
||||
throw TypeError('Uncaught, unspecified "error" event.'); |
||||
} |
||||
} |
||||
|
||||
handler = this._events[type]; |
||||
|
||||
if (isUndefined(handler)) |
||||
return false; |
||||
|
||||
if (isFunction(handler)) { |
||||
switch (arguments.length) { |
||||
// fast cases
|
||||
case 1: |
||||
handler.call(this); |
||||
break; |
||||
case 2: |
||||
handler.call(this, arguments[1]); |
||||
break; |
||||
case 3: |
||||
handler.call(this, arguments[1], arguments[2]); |
||||
break; |
||||
// slower
|
||||
default: |
||||
len = arguments.length; |
||||
args = new Array(len - 1); |
||||
for (i = 1; i < len; i++) |
||||
args[i - 1] = arguments[i]; |
||||
handler.apply(this, args); |
||||
} |
||||
} else if (isObject(handler)) { |
||||
len = arguments.length; |
||||
args = new Array(len - 1); |
||||
for (i = 1; i < len; i++) |
||||
args[i - 1] = arguments[i]; |
||||
|
||||
listeners = handler.slice(); |
||||
len = listeners.length; |
||||
for (i = 0; i < len; i++) |
||||
listeners[i].apply(this, args); |
||||
} |
||||
|
||||
return true; |
||||
}; |
||||
|
||||
EventEmitter.prototype.addListener = function(type, listener) { |
||||
var m; |
||||
|
||||
if (!isFunction(listener)) |
||||
throw TypeError('listener must be a function'); |
||||
|
||||
if (!this._events) |
||||
this._events = {}; |
||||
|
||||
// To avoid recursion in the case that type === "newListener"! Before
|
||||
// adding it to the listeners, first emit "newListener".
|
||||
if (this._events.newListener) |
||||
this.emit('newListener', type, |
||||
isFunction(listener.listener) ? |
||||
listener.listener : listener); |
||||
|
||||
if (!this._events[type]) |
||||
// Optimize the case of one listener. Don't need the extra array object.
|
||||
this._events[type] = listener; |
||||
else if (isObject(this._events[type])) |
||||
// If we've already got an array, just append.
|
||||
this._events[type].push(listener); |
||||
else |
||||
// Adding the second element, need to change to array.
|
||||
this._events[type] = [this._events[type], listener]; |
||||
|
||||
// Check for listener leak
|
||||
if (isObject(this._events[type]) && !this._events[type].warned) { |
||||
var m; |
||||
if (!isUndefined(this._maxListeners)) { |
||||
m = this._maxListeners; |
||||
} else { |
||||
m = EventEmitter.defaultMaxListeners; |
||||
} |
||||
|
||||
if (m && m > 0 && this._events[type].length > m) { |
||||
this._events[type].warned = true; |
||||
console.error('(node) warning: possible EventEmitter memory ' + |
||||
'leak detected. %d listeners added. ' + |
||||
'Use emitter.setMaxListeners() to increase limit.', |
||||
this._events[type].length); |
||||
if (typeof console.trace === 'function') { |
||||
// not supported in IE 10
|
||||
console.trace(); |
||||
} |
||||
} |
||||
} |
||||
|
||||
return this; |
||||
}; |
||||
|
||||
EventEmitter.prototype.on = EventEmitter.prototype.addListener; |
||||
|
||||
EventEmitter.prototype.once = function(type, listener) { |
||||
if (!isFunction(listener)) |
||||
throw TypeError('listener must be a function'); |
||||
|
||||
var fired = false; |
||||
|
||||
function g() { |
||||
this.removeListener(type, g); |
||||
|
||||
if (!fired) { |
||||
fired = true; |
||||
listener.apply(this, arguments); |
||||
} |
||||
} |
||||
|
||||
g.listener = listener; |
||||
this.on(type, g); |
||||
|
||||
return this; |
||||
}; |
||||
|
||||
// emits a 'removeListener' event iff the listener was removed
|
||||
EventEmitter.prototype.removeListener = function(type, listener) { |
||||
var list, position, length, i; |
||||
|
||||
if (!isFunction(listener)) |
||||
throw TypeError('listener must be a function'); |
||||
|
||||
if (!this._events || !this._events[type]) |
||||
return this; |
||||
|
||||
list = this._events[type]; |
||||
length = list.length; |
||||
position = -1; |
||||
|
||||
if (list === listener || |
||||
(isFunction(list.listener) && list.listener === listener)) { |
||||
delete this._events[type]; |
||||
if (this._events.removeListener) |
||||
this.emit('removeListener', type, listener); |
||||
|
||||
} else if (isObject(list)) { |
||||
for (i = length; i-- > 0;) { |
||||
if (list[i] === listener || |
||||
(list[i].listener && list[i].listener === listener)) { |
||||
position = i; |
||||
break; |
||||
} |
||||
} |
||||
|
||||
if (position < 0) |
||||
return this; |
||||
|
||||
if (list.length === 1) { |
||||
list.length = 0; |
||||
delete this._events[type]; |
||||
} else { |
||||
list.splice(position, 1); |
||||
} |
||||
|
||||
if (this._events.removeListener) |
||||
this.emit('removeListener', type, listener); |
||||
} |
||||
|
||||
return this; |
||||
}; |
||||
|
||||
EventEmitter.prototype.removeAllListeners = function(type) { |
||||
var key, listeners; |
||||
|
||||
if (!this._events) |
||||
return this; |
||||
|
||||
// not listening for removeListener, no need to emit
|
||||
if (!this._events.removeListener) { |
||||
if (arguments.length === 0) |
||||
this._events = {}; |
||||
else if (this._events[type]) |
||||
delete this._events[type]; |
||||
return this; |
||||
} |
||||
|
||||
// emit removeListener for all listeners on all events
|
||||
if (arguments.length === 0) { |
||||
for (key in this._events) { |
||||
if (key === 'removeListener') continue; |
||||
this.removeAllListeners(key); |
||||
} |
||||
this.removeAllListeners('removeListener'); |
||||
this._events = {}; |
||||
return this; |
||||
} |
||||
|
||||
listeners = this._events[type]; |
||||
|
||||
if (isFunction(listeners)) { |
||||
this.removeListener(type, listeners); |
||||
} else { |
||||
// LIFO order
|
||||
while (listeners.length) |
||||
this.removeListener(type, listeners[listeners.length - 1]); |
||||
} |
||||
delete this._events[type]; |
||||
|
||||
return this; |
||||
}; |
||||
|
||||
EventEmitter.prototype.listeners = function(type) { |
||||
var ret; |
||||
if (!this._events || !this._events[type]) |
||||
ret = []; |
||||
else if (isFunction(this._events[type])) |
||||
ret = [this._events[type]]; |
||||
else |
||||
ret = this._events[type].slice(); |
||||
return ret; |
||||
}; |
||||
|
||||
EventEmitter.listenerCount = function(emitter, type) { |
||||
var ret; |
||||
if (!emitter._events || !emitter._events[type]) |
||||
ret = 0; |
||||
else if (isFunction(emitter._events[type])) |
||||
ret = 1; |
||||
else |
||||
ret = emitter._events[type].length; |
||||
return ret; |
||||
}; |
||||
|
||||
function isFunction(arg) { |
||||
return typeof arg === 'function'; |
||||
} |
||||
|
||||
function isNumber(arg) { |
||||
return typeof arg === 'number'; |
||||
} |
||||
|
||||
function isObject(arg) { |
||||
return typeof arg === 'object' && arg !== null; |
||||
} |
||||
|
||||
function isUndefined(arg) { |
||||
return arg === void 0; |
||||
} |
||||
|
||||
},{}]},{},[1])(1) |
||||
}); |
@ -1,95 +0,0 @@ |
||||
!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var o;"undefined"!=typeof window?o=window:"undefined"!=typeof global?o=global:"undefined"!=typeof self&&(o=self),o.keyboardshortcut=e()}}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){ |
||||
//maps keycode to character, id of popover for given function and function
|
||||
var shortcuts = { |
||||
67: { |
||||
character: "C", |
||||
id: "toggleChatPopover", |
||||
function: UI.toggleChat |
||||
}, |
||||
70: { |
||||
character: "F", |
||||
id: "filmstripPopover", |
||||
function: UI.toggleFilmStrip |
||||
}, |
||||
77: { |
||||
character: "M", |
||||
id: "mutePopover", |
||||
function: UI.toggleAudio |
||||
}, |
||||
84: { |
||||
character: "T", |
||||
function: function() { |
||||
if(!RTC.localAudio.isMuted()) { |
||||
UI.toggleAudio(); |
||||
} |
||||
} |
||||
}, |
||||
86: { |
||||
character: "V", |
||||
id: "toggleVideoPopover", |
||||
function: UI.toggleVideo |
||||
} |
||||
}; |
||||
|
||||
|
||||
var KeyboardShortcut = { |
||||
init: function () { |
||||
window.onkeyup = function(e) { |
||||
var keycode = e.which; |
||||
if(!($(":focus").is("input[type=text]") || |
||||
$(":focus").is("input[type=password]") || |
||||
$(":focus").is("textarea"))) { |
||||
if (typeof shortcuts[keycode] === "object") { |
||||
shortcuts[keycode].function(); |
||||
} |
||||
else if (keycode >= "0".charCodeAt(0) && |
||||
keycode <= "9".charCodeAt(0)) { |
||||
UI.clickOnVideo(keycode - "0".charCodeAt(0) + 1); |
||||
} |
||||
//esc while the smileys are visible hides them
|
||||
} else if (keycode === 27 && $('#smileysContainer').is(':visible')) { |
||||
UI.toggleSmileys(); |
||||
} |
||||
}; |
||||
|
||||
window.onkeydown = function(e) { |
||||
if(!($(":focus").is("input[type=text]") || |
||||
$(":focus").is("input[type=password]") || |
||||
$(":focus").is("textarea"))) { |
||||
if(e.which === "T".charCodeAt(0)) { |
||||
if(RTC.localAudio.isMuted()) { |
||||
UI.toggleAudio(); |
||||
} |
||||
} |
||||
} |
||||
}; |
||||
var self = this; |
||||
$('body').popover({ selector: '[data-toggle=popover]', |
||||
trigger: 'click hover', |
||||
content: function() { |
||||
return this.getAttribute("content") + |
||||
self.getShortcut(this.getAttribute("shortcut")); |
||||
} |
||||
}); |
||||
}, |
||||
/** |
||||
* |
||||
* @param id indicates the popover associated with the shortcut |
||||
* @returns {string} the keyboard shortcut used for the id given |
||||
*/ |
||||
getShortcut: function (id) { |
||||
for (var keycode in shortcuts) { |
||||
if (shortcuts.hasOwnProperty(keycode)) { |
||||
if (shortcuts[keycode].id === id) { |
||||
return " (" + shortcuts[keycode].character + ")"; |
||||
} |
||||
} |
||||
} |
||||
return ""; |
||||
} |
||||
}; |
||||
|
||||
module.exports = KeyboardShortcut; |
||||
|
||||
},{}]},{},[1])(1) |
||||
}); |
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Loading…
Reference in new issue