feat(iframe_api): Add more ESLint rules

This commit is contained in:
hristoterezov 2017-04-03 10:48:46 -05:00
parent d416fd8c0f
commit 334eb5d423
3 changed files with 289 additions and 279 deletions

View File

@ -129,7 +129,7 @@ api.executeCommands({displayName: ['nickname'], toggleAudio: []});
``` ```
You can add event listeners to the embedded Jitsi Meet using the `addEventListener` method. You can add event listeners to the embedded Jitsi Meet using the `addEventListener` method.
*NOTE: This method still exists but it is deprecated. JitsiMeetExternalAPI class extends [EventEmitter]. Use [EventEmitter] methods (`addListener` or `on`).* **NOTE: This method still exists but it is deprecated. JitsiMeetExternalAPI class extends [EventEmitter]. Use [EventEmitter] methods (`addListener` or `on`).**
```javascript ```javascript
api.addEventListener(event, listener) api.addEventListener(event, listener)
``` ```
@ -199,7 +199,7 @@ changes. The listener will receive an object with the following structure:
You can also add multiple event listeners by using `addEventListeners`. You can also add multiple event listeners by using `addEventListeners`.
This method requires one argument of type Object. The object argument must This method requires one argument of type Object. The object argument must
have the names of the events as keys and the listeners of the events as values. have the names of the events as keys and the listeners of the events as values.
*NOTE: This method still exists but it is deprecated. JitsiMeetExternalAPI class extends [EventEmitter]. Use [EventEmitter] methods.* **NOTE: This method still exists but it is deprecated. JitsiMeetExternalAPI class extends [EventEmitter]. Use [EventEmitter] methods.**
```javascript ```javascript
function incomingMessageListener(object) function incomingMessageListener(object)
@ -218,13 +218,13 @@ api.addEventListeners({
``` ```
If you want to remove a listener you can use `removeEventListener` method with argument the name of the event. If you want to remove a listener you can use `removeEventListener` method with argument the name of the event.
*NOTE: This method still exists but it is deprecated. JitsiMeetExternalAPI class extends [EventEmitter]. Use [EventEmitter] methods( `removeListener`).* **NOTE: This method still exists but it is deprecated. JitsiMeetExternalAPI class extends [EventEmitter]. Use [EventEmitter] methods( `removeListener`).**
```javascript ```javascript
api.removeEventListener("incomingMessage"); api.removeEventListener("incomingMessage");
``` ```
If you want to remove more than one event you can use `removeEventListeners` method with an Array with the names of the events as an argument. If you want to remove more than one event you can use `removeEventListeners` method with an Array with the names of the events as an argument.
*NOTE: This method still exists but it is deprecated. JitsiMeetExternalAPI class extends [EventEmitter]. Use [EventEmitter] methods.* **NOTE: This method still exists but it is deprecated. JitsiMeetExternalAPI class extends [EventEmitter]. Use [EventEmitter] methods.**
```javascript ```javascript
api.removeEventListeners(["incomingMessage", "outgoingMessageListener"]); api.removeEventListeners(["incomingMessage", "outgoingMessageListener"]);
``` ```

3
modules/API/external/.eslintrc.js vendored Normal file
View File

@ -0,0 +1,3 @@
module.exports = {
'extends': '../../../react/.eslintrc.js'
};

View File

@ -1,18 +1,39 @@
const logger = require("jitsi-meet-logger").getLogger(__filename); import EventEmitter from 'events';
import postisInit from "postis"; import postisInit from 'postis';
import EventEmitter from "events";
const logger = require('jitsi-meet-logger').getLogger(__filename);
/** /**
* The minimum width for the Jitsi Meet frame * Maps the names of the commands expected by the API with the name of the
* @type {number} * commands expected by jitsi-meet
*/ */
const MIN_WIDTH = 790; const commands = {
avatarUrl: 'avatar-url',
displayName: 'display-name',
email: 'email',
hangup: 'video-hangup',
toggleAudio: 'toggle-audio',
toggleChat: 'toggle-chat',
toggleContactList: 'toggle-contact-list',
toggleFilmStrip: 'toggle-film-strip',
toggleShareScreen: 'toggle-share-screen',
toggleVideo: 'toggle-video'
};
/** /**
* The minimum height for the Jitsi Meet frame * Maps the names of the events expected by the API with the name of the
* @type {number} * events expected by jitsi-meet
*/ */
const MIN_HEIGHT = 300; const events = {
displayNameChange: 'display-name-change',
incomingMessage: 'incoming-message',
outgoingMessage: 'outgoing-message',
participantJoined: 'participant-joined',
participantLeft: 'participant-left',
readyToClose: 'video-ready-to-close',
videoConferenceJoined: 'video-conference-joined',
videoConferenceLeft: 'video-conference-left'
};
/** /**
* Last id of api object * Last id of api object
@ -21,56 +42,25 @@ const MIN_HEIGHT = 300;
let id = 0; let id = 0;
/** /**
* Maps the names of the commands expected by the API with the name of the * The minimum height for the Jitsi Meet frame
* commands expected by jitsi-meet * @type {number}
*/ */
const commands = { const MIN_HEIGHT = 300;
"displayName": "display-name",
"toggleAudio": "toggle-audio",
"toggleVideo": "toggle-video",
"toggleFilmStrip": "toggle-film-strip",
"toggleChat": "toggle-chat",
"toggleContactList": "toggle-contact-list",
"toggleShareScreen": "toggle-share-screen",
"hangup": "video-hangup",
"email": "email",
"avatarUrl": "avatar-url"
};
/** /**
* Maps the names of the events expected by the API with the name of the * The minimum width for the Jitsi Meet frame
* events expected by jitsi-meet * @type {number}
*/ */
const events = { const MIN_WIDTH = 790;
"incomingMessage": "incoming-message",
"outgoingMessage": "outgoing-message",
"displayNameChange": "display-name-change",
"participantJoined": "participant-joined",
"participantLeft": "participant-left",
"videoConferenceJoined": "video-conference-joined",
"videoConferenceLeft": "video-conference-left",
"readyToClose": "video-ready-to-close"
};
/**
* Sends the passed object to Jitsi Meet
* @param postis {Postis object} the postis instance that is going to be used
* to send the message
* @param object the object to be sent
* - method {sting}
* - params {object}
*/
function sendMessage(postis, object) {
postis.send(object);
}
/** /**
* Adds given number to the numberOfParticipants property of given APIInstance. * Adds given number to the numberOfParticipants property of given APIInstance.
* @param {JitsiMeetExternalAPI} APIInstance the instance of the *
* JitsiMeetExternalAPI * @param {JitsiMeetExternalAPI} APIInstance - The instance of the API.
* @param {int} number - the number of participants to be added to * @param {int} number - The number of participants to be added to
* numberOfParticipants property (this parameter can be negative number if the * numberOfParticipants property (this parameter can be negative number if the
* numberOfParticipants should be decreased). * numberOfParticipants should be decreased).
* @returns {void}
*/ */
function changeParticipantNumber(APIInstance, number) { function changeParticipantNumber(APIInstance, number) {
APIInstance.numberOfParticipants += number; APIInstance.numberOfParticipants += number;
@ -80,179 +70,206 @@ function changeParticipantNumber(APIInstance, number) {
* Generates array with URL params based on the passed config object that will * Generates array with URL params based on the passed config object that will
* be used for the Jitsi Meet URL generation. * be used for the Jitsi Meet URL generation.
* *
* @param config {object} the config object. * @param {Object} config - The config object.
* @returns {Array<string>} the array with URL param strings. * @returns {Array<string>} The array with URL param strings.
*/ */
function configToURLParamsArray(config) { function configToURLParamsArray(config = {}) {
const params = []; const params = [];
for (const key in config) { for (const key in config) { // eslint-disable-line guard-for-in
try { try {
params.push(key + '=' params.push(`${key}=${
+ encodeURIComponent(JSON.stringify(config[key]))); encodeURIComponent(JSON.stringify(config[key]))}`);
} catch (e) { } catch (e) {
console.warn(`Error encoding ${key}: ${e}`); console.warn(`Error encoding ${key}: ${e}`);
} }
} }
return params; return params;
} }
/**
* Generates the URL for the iframe.
*
* @param {string} domain - The domain name of the server that hosts the
* conference.
* @param {string} [options] - Another optional parameters.
* @param {Object} [options.configOverwrite] - Object containing configuration
* options defined in config.js to be overridden.
* @param {Object} [options.interfaceConfigOverwrite] - Object containing
* configuration options defined in interface_config.js to be overridden.
* @param {string} [options.jwt] - The JWT token if needed by jitsi-meet for
* authentication.
* @param {boolean} [options.noSsl] - If the value is true https won't be used.
* @param {string} [options.roomName] - The name of the room to join.
* @returns {string} The URL.
*/
function generateURL(domain, options = {}) {
const {
configOverwrite,
interfaceConfigOverwrite,
jwt,
noSSL,
roomName
} = options;
let url = `${noSSL ? 'http' : 'https'}://${domain}/${roomName || ''}`;
if (jwt) {
url += `?jwt=${jwt}`;
}
url += `#jitsi_meet_external_api_id=${id}`;
const configURLParams = configToURLParamsArray(configOverwrite);
if (configURLParams.length) {
url += `&config.${configURLParams.join('&config.')}`;
}
const interfaceConfigURLParams
= configToURLParamsArray(interfaceConfigOverwrite);
if (interfaceConfigURLParams.length) {
url += `&interfaceConfig.${
interfaceConfigURLParams.join('&interfaceConfig.')}`;
}
return url;
}
/** /**
* The IFrame API interface class. * The IFrame API interface class.
*/ */
class JitsiMeetExternalAPI extends EventEmitter { class JitsiMeetExternalAPI extends EventEmitter {
/** /**
* Constructs new API instance. Creates iframe element that loads * Constructs new API instance. Creates iframe and loads Jitsi Meet in it.
* Jitsi Meet. *
* @param domain the domain name of the server that hosts the conference * @param {string} domain - The domain name of the server that hosts the
* @param room_name the name of the room to join * conference.
* @param width width of the iframe * @param {string} [roomName] - The name of the room to join.
* @param height height of the iframe * @param {number} [width] - Width of the iframe.
* @param parent_node the node that will contain the iframe * @param {number} [height] - Height of the iframe.
* @param configOverwrite object containing configuration options defined in * @param {DOMElement} [parentNode] - The node that will contain the
* config.js to be overridden. * iframe.
* @param interfaceConfigOverwrite object containing configuration options * @param {Object} [configOverwrite] - Object containing configuration
* defined in interface_config.js to be overridden. * options defined in config.js to be overridden.
* @param noSsl if the value is true https won't be used * @param {Object} [interfaceConfigOverwrite] - Object containing
* @param {string} [jwt] the JWT token if needed by jitsi-meet for * configuration options defined in interface_config.js to be overridden.
* @param {boolean} [noSSL] - If the value is true https won't be used.
* @param {string} [jwt] - The JWT token if needed by jitsi-meet for
* authentication. * authentication.
* @constructor
*/ */
constructor(domain, room_name, width, height, parentNode, constructor(domain, // eslint-disable-line max-params
configOverwrite, interfaceConfigOverwrite, noSsl, jwt) { roomName = '',
width = MIN_WIDTH,
height = MIN_HEIGHT,
parentNode = document.body,
configOverwrite = {},
interfaceConfigOverwrite = {},
noSSL = false,
jwt = undefined) {
super(); super();
this.parentNode = parentNode;
if (!width || width < MIN_WIDTH) { this.url = generateURL(domain, {
width = MIN_WIDTH; configOverwrite,
} interfaceConfigOverwrite,
if (!height || height < MIN_HEIGHT) { jwt,
height = MIN_HEIGHT; noSSL,
} roomName
});
this.parentNode = null; this._createIFrame(Math.max(height, MIN_HEIGHT),
if (parentNode) { Math.max(width, MIN_WIDTH));
this.parentNode = parentNode; this.postis = postisInit({
} else { scope: `jitsi_meet_external_api_${id}`,
var scriptTag = document.scripts[document.scripts.length - 1]; window: this.frame.contentWindow
this.parentNode = scriptTag.parentNode;
}
this.iframeHolder =
this.parentNode.appendChild(document.createElement("div"));
this.iframeHolder.id = "jitsiConference" + id;
if (width) {
this.iframeHolder.style.width = width + "px";
}
if (height) {
this.iframeHolder.style.height = height + "px";
}
this.frameName = "jitsiConferenceFrame" + id;
this.url = (noSsl) ? "http" : "https" +"://" + domain + "/";
if (room_name) {
this.url += room_name;
}
if (jwt) {
this.url += '?jwt=' + jwt;
}
this.url += "#jitsi_meet_external_api_id=" + id;
const configURLParams = configToURLParamsArray(configOverwrite);
if (configURLParams.length) {
this.url += '&config.' + configURLParams.join('&config.');
}
const interfaceConfigURLParams
= configToURLParamsArray(interfaceConfigOverwrite);
if (interfaceConfigURLParams.length) {
this.url += '&interfaceConfig.'
+ interfaceConfigURLParams.join('&interfaceConfig.');
}
this.frame = document.createElement("iframe");
this.frame.src = this.url;
this.frame.name = this.frameName;
this.frame.id = this.frameName;
this.frame.width = "100%";
this.frame.height = "100%";
this.frame.setAttribute("allowFullScreen","true");
this.frame = this.iframeHolder.appendChild(this.frame);
this.postis = postisInit({
window: this.frame.contentWindow,
scope: "jitsi_meet_external_api_" + id
}); });
this.eventHandlers = {};
// Map<{string} event_name, {boolean} postis_listener_added>
this.postisListeners = {};
this.numberOfParticipants = 1; this.numberOfParticipants = 1;
this._setupListeners(); this._setupListeners();
id++; id++;
} }
/** /**
* Executes command. The available commands are: * Creates the iframe element.
* displayName - sets the display name of the local participant to the value *
* passed in the arguments array. * @param {number} height - The height of the iframe.
* toggleAudio - mutes / unmutes audio with no arguments * @param {number} width - The with of the iframe.
* toggleVideo - mutes / unmutes video with no arguments * @returns {void}
* filmStrip - hides / shows the film strip with no arguments *
* If the command doesn't require any arguments the parameter should be set * @private
* to empty array or it may be omitted.
* @param name the name of the command
* @param arguments array of arguments
*/ */
executeCommand(name, ...argumentsList) { _createIFrame(height, width) {
if(!(name in commands)) { this.iframeHolder
logger.error("Not supported command name."); = this.parentNode.appendChild(document.createElement('div'));
return; this.iframeHolder.id = `jitsiConference${id}`;
} this.iframeHolder.style.width = `${width}px`;
sendMessage(this.postis, { this.iframeHolder.style.height = `${height}px`;
method: commands[name],
params: argumentsList this.frameName = `jitsiConferenceFrame${id}`;
});
this.frame = document.createElement('iframe');
this.frame.src = this.url;
this.frame.name = this.frameName;
this.frame.id = this.frameName;
this.frame.width = '100%';
this.frame.height = '100%';
this.frame.setAttribute('allowFullScreen', 'true');
this.frame = this.iframeHolder.appendChild(this.frame);
} }
/** /**
* Executes commands. The available commands are: * Setups listeners that are used internally for JitsiMeetExternalAPI.
* displayName - sets the display name of the local participant to the value *
* passed in the arguments array. * @returns {void}
* toggleAudio - mutes / unmutes audio. no arguments *
* toggleVideo - mutes / unmutes video. no arguments * @private
* filmStrip - hides / shows the film strip. no arguments
* toggleChat - hides / shows chat. no arguments.
* toggleContactList - hides / shows contact list. no arguments.
* toggleShareScreen - starts / stops screen sharing. no arguments.
* @param object the object with commands to be executed. The keys of the
* object are the commands that will be executed and the values are the
* arguments for the command.
*/ */
executeCommands(object) { _setupListeners() {
for (var key in object) { this.postis.listen('participant-joined',
this.executeCommand(key, object[key]); changeParticipantNumber.bind(null, this, 1));
this.postis.listen('participant-left',
changeParticipantNumber.bind(null, this, -1));
for (const eventName in events) { // eslint-disable-line guard-for-in
const postisMethod = events[eventName];
this.postis.listen(postisMethod,
(...args) => this.emit(eventName, ...args));
} }
} }
/** /**
* Adds event listeners to Meet Jitsi. The object key should be the name of * Adds event listener to Meet Jitsi.
*
* @param {string} event - The name of the event.
* @param {Function} listener - The listener.
* @returns {void}
*
* @deprecated
* NOTE: This method is not removed for backward comatability purposes.
*/
addEventListener(event, listener) {
this.on(event, listener);
}
/**
* Adds event listeners to Meet Jitsi.
*
* @param {Object} listeners - The object key should be the name of
* the event and value - the listener. * the event and value - the listener.
* Currently we support the following * Currently we support the following
* events: * events:
* incomingMessage - receives event notifications about incoming * incomingMessage - receives event notifications about incoming
* messages. The listener will receive object with the following structure: * messages. The listener will receive object with the following structure:
* {{ * {{
* "from": from,//JID of the user that sent the message * 'from': from,//JID of the user that sent the message
* "nick": nick,//the nickname of the user that sent the message * 'nick': nick,//the nickname of the user that sent the message
* "message": txt//the text of the message * 'message': txt//the text of the message
* }} * }}
* outgoingMessage - receives event notifications about outgoing * outgoingMessage - receives event notifications about outgoing
* messages. The listener will receive object with the following structure: * messages. The listener will receive object with the following structure:
* {{ * {{
* "message": txt//the text of the message * 'message': txt//the text of the message
* }} * }}
* displayNameChanged - receives event notifications about display name * displayNameChanged - receives event notifications about display name
* change. The listener will receive object with the following structure: * change. The listener will receive object with the following structure:
@ -285,72 +302,99 @@ class JitsiMeetExternalAPI extends EventEmitter {
* }} * }}
* readyToClose - all hangup operations are completed and Jitsi Meet is * readyToClose - all hangup operations are completed and Jitsi Meet is
* ready to be disposed. * ready to be disposed.
* @param object * @returns {void}
* *
* @deprecated
* NOTE: This method is not removed for backward comatability purposes. * NOTE: This method is not removed for backward comatability purposes.
*/ */
addEventListeners(object) { addEventListeners(listeners) {
for (var i in object) { for (const event in listeners) { // eslint-disable-line guard-for-in
this.addEventListener(i, object[i]); this.addEventListener(event, listeners[event]);
} }
} }
/** /**
* Adds event listeners to Meet Jitsi. Currently we support the following * Removes the listeners and removes the Jitsi Meet frame.
* events:
* incomingMessage - receives event notifications about incoming
* messages. The listener will receive object with the following structure:
* {{
* "from": from,//JID of the user that sent the message
* "nick": nick,//the nickname of the user that sent the message
* "message": txt//the text of the message
* }}
* outgoingMessage - receives event notifications about outgoing
* messages. The listener will receive object with the following structure:
* {{
* "message": txt//the text of the message
* }}
* displayNameChanged - receives event notifications about display name
* change. The listener will receive object with the following structure:
* {{
* jid: jid,//the JID of the participant that changed his display name
* displayname: displayName //the new display name
* }}
* participantJoined - receives event notifications about new participant.
* The listener will receive object with the following structure:
* {{
* jid: jid //the jid of the participant
* }}
* participantLeft - receives event notifications about participant the that
* left the room.
* The listener will receive object with the following structure:
* {{
* jid: jid //the jid of the participant
* }}
* video-conference-joined - receives event notifications fired when the
* local user has joined the video conference.
* The listener will receive object with the following structure:
* {{
* roomName: room //the room name of the conference
* }}
* video-conference-left - receives event notifications fired when the local
* user has joined the video conference.
* The listener will receive object with the following structure:
* {{
* roomName: room //the room name of the conference
* }}
* @param event the name of the event
* @param listener the listener
* *
* NOTE: This method is not removed for backward comatability purposes. * @returns {void}
*/ */
addEventListener(event, listener) { dispose() {
this.on(event, listener); const frame = document.getElementById(this.frameName);
this.postis.destroy();
if (frame) {
frame.src = 'about:blank';
}
window.setTimeout(() => {
this.iframeHolder.removeChild(this.frame);
this.iframeHolder.parentNode.removeChild(this.iframeHolder);
}, 10);
}
/**
* Executes command. The available commands are:
* displayName - sets the display name of the local participant to the value
* passed in the arguments array.
* toggleAudio - mutes / unmutes audio with no arguments.
* toggleVideo - mutes / unmutes video with no arguments.
* filmStrip - hides / shows the film strip with no arguments.
* If the command doesn't require any arguments the parameter should be set
* to empty array or it may be omitted.
*
* @param {string} name - The name of the command.
* @returns {void}
*/
executeCommand(name, ...args) {
if (!(name in commands)) {
logger.error('Not supported command name.');
return;
}
this.postis.send({
method: commands[name],
params: args
});
}
/**
* Executes commands. The available commands are:
* displayName - sets the display name of the local participant to the value
* passed in the arguments array.
* toggleAudio - mutes / unmutes audio. no arguments
* toggleVideo - mutes / unmutes video. no arguments
* filmStrip - hides / shows the film strip. no arguments
* toggleChat - hides / shows chat. no arguments.
* toggleContactList - hides / shows contact list. no arguments.
* toggleShareScreen - starts / stops screen sharing. no arguments.
*
* @param {Object} commandList - The object with commands to be executed.
* The keys of the object are the commands that will be executed and the
* values are the arguments for the command.
* @returns {void}
*/
executeCommands(commandList) {
for (const key in commandList) { // eslint-disable-line guard-for-in
this.executeCommand(key, commandList[key]);
}
}
/**
* Returns the number of participants in the conference. The local
* participant is included.
*
* @returns {int} The number of participants in the conference.
*/
getNumberOfParticipants() {
return this.numberOfParticipants;
} }
/** /**
* Removes event listener. * Removes event listener.
* @param event the name of the event. *
* @param {string} event - The name of the event.
* @returns {void}
*
* @deprecated
* NOTE: This method is not removed for backward comatability purposes. * NOTE: This method is not removed for backward comatability purposes.
*/ */
removeEventListener(event) { removeEventListener(event) {
@ -359,52 +403,15 @@ class JitsiMeetExternalAPI extends EventEmitter {
/** /**
* Removes event listeners. * Removes event listeners.
* @param events array with the names of the events. *
* @param {Array<string>} eventList - Array with the names of the events.
* @returns {void}
*
* @deprecated
* NOTE: This method is not removed for backward comatability purposes. * NOTE: This method is not removed for backward comatability purposes.
*/ */
removeEventListeners(events) { removeEventListeners(eventList) {
for(var i = 0; i < events.length; i++) { eventList.forEach(event => this.removeEventListener(event));
this.removeEventListener(events[i]);
}
}
/**
* Returns the number of participants in the conference.
* NOTE: the local participant is included.
* @returns {int} the number of participants in the conference.
*/
getNumberOfParticipants() {
return this.numberOfParticipants;
}
/**
* Setups listeners that are used internally for JitsiMeetExternalAPI.
*/
_setupListeners() {
this.postis.listen("participant-joined",
changeParticipantNumber.bind(null, this, 1));
this.postis.listen("participant-left",
changeParticipantNumber.bind(null, this, -1));
for (const eventName in events) {
const postisMethod = events[eventName];
this.postis.listen(postisMethod,
(...args) => this.emit(eventName, ...args));
}
}
/**
* Removes the listeners and removes the Jitsi Meet frame.
*/
dispose() {
this.postis.destroy();
var frame = document.getElementById(this.frameName);
if(frame)
frame.src = 'about:blank';
window.setTimeout( () => {
this.iframeHolder.removeChild(this.frame);
this.iframeHolder.parentNode.removeChild(this.iframeHolder);
}, 10);
} }
} }