From 78119df2dbee086fe6d3a480dc0b3154fd30c1d9 Mon Sep 17 00:00:00 2001 From: hristoterezov Date: Thu, 30 Mar 2017 16:15:56 -0500 Subject: [PATCH 1/3] ref(iframe_api): Use ES6 --- modules/API/external/external_api.js | 601 ++++++++++++++------------- 1 file changed, 305 insertions(+), 296 deletions(-) diff --git a/modules/API/external/external_api.js b/modules/API/external/external_api.js index 623cc5709..75a51da68 100644 --- a/modules/API/external/external_api.js +++ b/modules/API/external/external_api.js @@ -1,34 +1,29 @@ const logger = require("jitsi-meet-logger").getLogger(__filename); - -/** - * Implements API class that embeds Jitsi Meet in external applications. - */ - -var postisInit = require("postis"); +import postisInit from "postis"; /** * The minimum width for the Jitsi Meet frame * @type {number} */ -var MIN_WIDTH = 790; +const MIN_WIDTH = 790; /** * The minimum height for the Jitsi Meet frame * @type {number} */ -var MIN_HEIGHT = 300; +const MIN_HEIGHT = 300; /** * Last id of api object * @type {number} */ -var id = 0; +let id = 0; /** * Maps the names of the commands expected by the API with the name of the * commands expected by jitsi-meet */ -var commands = { +const commands = { "displayName": "display-name", "toggleAudio": "toggle-audio", "toggleVideo": "toggle-video", @@ -45,7 +40,7 @@ var commands = { * Maps the names of the events expected by the API with the name of the * events expected by jitsi-meet */ -var events = { +const events = { "incomingMessage": "incoming-message", "outgoingMessage": "outgoing-message", "displayNameChange": "display-name-change", @@ -102,305 +97,319 @@ function configToURLParamsArray(config) { } /** - * Constructs new API instance. Creates iframe element that loads - * Jitsi Meet. - * @param domain the domain name of the server that hosts the conference - * @param room_name the name of the room to join - * @param width width of the iframe - * @param height height of the iframe - * @param parent_node the node that will contain the iframe - * @param configOverwrite object containing configuration options defined in - * config.js to be overridden. - * @param interfaceConfigOverwrite object containing configuration options - * defined in interface_config.js to be overridden. - * @param noSsl if the value is true https won't be used - * @param {string} [jwt] the JWT token if needed by jitsi-meet for - * authentication. - * @constructor + * The IFrame API interface class. */ -function JitsiMeetExternalAPI(domain, room_name, width, height, parentNode, - configOverwrite, interfaceConfigOverwrite, noSsl, jwt) { - if (!width || width < MIN_WIDTH) - width = MIN_WIDTH; - if (!height || height < MIN_HEIGHT) - height = MIN_HEIGHT; +class JitsiMeetExternalAPI { + /** + * Constructs new API instance. Creates iframe element that loads + * Jitsi Meet. + * @param domain the domain name of the server that hosts the conference + * @param room_name the name of the room to join + * @param width width of the iframe + * @param height height of the iframe + * @param parent_node the node that will contain the iframe + * @param configOverwrite object containing configuration options defined in + * config.js to be overridden. + * @param interfaceConfigOverwrite object containing configuration options + * defined in interface_config.js to be overridden. + * @param noSsl if the value is true https won't be used + * @param {string} [jwt] the JWT token if needed by jitsi-meet for + * authentication. + * @constructor + */ + constructor(domain, room_name, width, height, parentNode, + configOverwrite, interfaceConfigOverwrite, noSsl, jwt) { + if (!width || width < MIN_WIDTH) { + width = MIN_WIDTH; + } + if (!height || height < MIN_HEIGHT) { + height = MIN_HEIGHT; + } - this.parentNode = null; - if (parentNode) { - this.parentNode = parentNode; - } else { - var scriptTag = document.scripts[document.scripts.length - 1]; - this.parentNode = scriptTag.parentNode; + this.parentNode = null; + if (parentNode) { + this.parentNode = parentNode; + } else { + var scriptTag = document.scripts[document.scripts.length - 1]; + 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._setupListeners(); + + id++; } - 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; + /** + * 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 name the name of the command + * @param arguments array of arguments + */ + executeCommand(name, ...argumentsList) { + if(!(name in commands)) { + logger.error("Not supported command name."); + return; + } + sendMessage(this.postis, { + method: commands[name], + params: argumentsList + }); } - this.url += "#jitsi_meet_external_api_id=" + id; - - const configURLParams = configToURLParamsArray(configOverwrite); - if (configURLParams.length) { - this.url += '&config.' + configURLParams.join('&config.'); + /** + * 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 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) { + for (var key in object) { + this.executeCommand(key, object[key]); + } } - const interfaceConfigURLParams - = configToURLParamsArray(interfaceConfigOverwrite); - if (interfaceConfigURLParams.length) { - this.url += '&interfaceConfig.' - + interfaceConfigURLParams.join('&interfaceConfig.'); + /** + * Adds event listeners to Meet Jitsi. The object key should be the name of + * the event and value - the listener. + * Currently we support the following + * 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 the participant 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 about the local + * user has successfully 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 about the local user + * has left the video conference. + * The listener will receive object with the following structure: + * {{ + * roomName: room //the room name of the conference + * }} + * readyToClose - all hangup operations are completed and Jitsi Meet is + * ready to be disposed. + * @param object + */ + addEventListeners(object) { + for (var i in object) { + this.addEventListener(i, object[i]); + } } - 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 - }); + /** + * Adds event listeners to Meet Jitsi. Currently we support the following + * 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 + */ + addEventListener(event, listener) { + if (!(event in events)) { + logger.error("Not supported event name."); + return; + } + // We cannot remove listeners from postis that's why we are handling the + // callback that way. + if (!this.postisListeners[event]) { + this.postis.listen(events[event], data => { + if((event in this.eventHandlers) && + typeof this.eventHandlers[event] === "function") + this.eventHandlers[event].call(null, data); + }); + this.postisListeners[event] = true; + } + this.eventHandlers[event] = listener; + } - this.eventHandlers = {}; + /** + * Removes event listener. + * @param event the name of the event. + */ + removeEventListener(event) { + if(!(event in this.eventHandlers)) + { + logger.error("The event " + event + " is not registered."); + return; + } + delete this.eventHandlers[event]; + } - // Map<{string} event_name, {boolean} postis_listener_added> - this.postisListeners = {}; + /** + * Removes event listeners. + * @param events array with the names of the events. + */ + removeEventListeners(events) { + for(var i = 0; i < events.length; i++) { + this.removeEventListener(events[i]); + } + } - this.numberOfParticipants = 1; - this._setupListeners(); + /** + * 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; + } - id++; + /** + * 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)); + } + + /** + * 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); + } } -/** - * 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 name the name of the command - * @param arguments array of arguments - */ -JitsiMeetExternalAPI.prototype.executeCommand -= function(name, ...argumentsList) { - if(!(name in commands)) { - logger.error("Not supported command name."); - return; - } - sendMessage(this.postis, {method: commands[name], params: argumentsList}); -}; - -/** - * 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 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. - */ -JitsiMeetExternalAPI.prototype.executeCommands = function(object) { - for(var key in object) - this.executeCommand(key, object[key]); -}; - -/** - * Adds event listeners to Meet Jitsi. The object key should be the name of - * the event and value - the listener. - * Currently we support the following - * 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 the participant 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 about the local user - * has successfully 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 about the local user - * has left the video conference. - * The listener will receive object with the following structure: - * {{ - * roomName: room //the room name of the conference - * }} - * readyToClose - all hangup operations are completed and Jitsi Meet is ready - * to be disposed. - * @param object - */ -JitsiMeetExternalAPI.prototype.addEventListeners = function(object) { - for(var i in object) - this.addEventListener(i, object[i]); -}; - -/** - * Adds event listeners to Meet Jitsi. Currently we support the following - * 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 - */ -JitsiMeetExternalAPI.prototype.addEventListener = function(event, listener) { - if(!(event in events)) { - logger.error("Not supported event name."); - return; - } - // We cannot remove listeners from postis that's why we are handling the - // callback that way. - if(!this.postisListeners[event]) { - this.postis.listen(events[event], function(data) { - if((event in this.eventHandlers) && - typeof this.eventHandlers[event] === "function") - this.eventHandlers[event].call(null, data); - }.bind(this)); - this.postisListeners[event] = true; - } - this.eventHandlers[event] = listener; -}; - -/** - * Removes event listener. - * @param event the name of the event. - */ -JitsiMeetExternalAPI.prototype.removeEventListener = function(event) { - if(!(event in this.eventHandlers)) - { - logger.error("The event " + event + " is not registered."); - return; - } - delete this.eventHandlers[event]; -}; - -/** - * Removes event listeners. - * @param events array with the names of the events. - */ -JitsiMeetExternalAPI.prototype.removeEventListeners = function(events) { - for(var i = 0; i < events.length; i++) - 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. - */ -JitsiMeetExternalAPI.prototype.getNumberOfParticipants = function() { - return this.numberOfParticipants; -}; - -/** - * Setups listeners that are used internally for JitsiMeetExternalAPI. - */ -JitsiMeetExternalAPI.prototype._setupListeners = function() { - this.postis.listen("participant-joined", - changeParticipantNumber.bind(null, this, 1)); - this.postis.listen("participant-left", - changeParticipantNumber.bind(null, this, -1)); -}; - -/** - * Removes the listeners and removes the Jitsi Meet frame. - */ -JitsiMeetExternalAPI.prototype.dispose = function() { - this.postis.destroy(); - var frame = document.getElementById(this.frameName); - if(frame) - frame.src = 'about:blank'; - var self = this; - window.setTimeout(function () { - self.iframeHolder.removeChild(self.frame); - self.iframeHolder.parentNode.removeChild(self.iframeHolder); - }, 10); -}; - module.exports = JitsiMeetExternalAPI; From d416fd8c0fe8a66b5f8a1e8f4e28158d75c0ef62 Mon Sep 17 00:00:00 2001 From: hristoterezov Date: Fri, 31 Mar 2017 11:38:44 -0500 Subject: [PATCH 2/3] ref(iframe_api): Use EventEmitter --- doc/api.md | 8 ++++-- modules/API/external/external_api.js | 40 +++++++++++++--------------- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/doc/api.md b/doc/api.md index fed58c86d..161e51995 100644 --- a/doc/api.md +++ b/doc/api.md @@ -123,12 +123,13 @@ You can also execute multiple commands using the `executeCommands` method: ```javascript api.executeCommands(commands) ``` -The `commands` parameter is an object with the names of the commands as keys and the arguments for the commands asvalues: +The `commands` parameter is an object with the names of the commands as keys and the arguments for the commands as values: ```javascript api.executeCommands({displayName: ['nickname'], toggleAudio: []}); ``` 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`).* ```javascript api.addEventListener(event, listener) ``` @@ -198,6 +199,7 @@ changes. The listener will receive an object with the following structure: You can also add multiple event listeners by using `addEventListeners`. 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. +*NOTE: This method still exists but it is deprecated. JitsiMeetExternalAPI class extends [EventEmitter]. Use [EventEmitter] methods.* ```javascript function incomingMessageListener(object) @@ -216,12 +218,13 @@ api.addEventListeners({ ``` 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`).* ```javascript 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. +*NOTE: This method still exists but it is deprecated. JitsiMeetExternalAPI class extends [EventEmitter]. Use [EventEmitter] methods.* ```javascript api.removeEventListeners(["incomingMessage", "outgoingMessageListener"]); ``` @@ -240,3 +243,4 @@ NOTE: It's a good practice to remove the conference before the page is unloaded. [config.js]: https://github.com/jitsi/jitsi-meet/blob/master/config.js [interface_config.js]: https://github.com/jitsi/jitsi-meet/blob/master/interface_config.js +[EventEmitter]: https://nodejs.org/api/events.html diff --git a/modules/API/external/external_api.js b/modules/API/external/external_api.js index 75a51da68..c61b147c3 100644 --- a/modules/API/external/external_api.js +++ b/modules/API/external/external_api.js @@ -1,5 +1,6 @@ const logger = require("jitsi-meet-logger").getLogger(__filename); import postisInit from "postis"; +import EventEmitter from "events"; /** * The minimum width for the Jitsi Meet frame @@ -99,7 +100,7 @@ function configToURLParamsArray(config) { /** * The IFrame API interface class. */ -class JitsiMeetExternalAPI { +class JitsiMeetExternalAPI extends EventEmitter { /** * Constructs new API instance. Creates iframe element that loads * Jitsi Meet. @@ -119,6 +120,8 @@ class JitsiMeetExternalAPI { */ constructor(domain, room_name, width, height, parentNode, configOverwrite, interfaceConfigOverwrite, noSsl, jwt) { + super(); + if (!width || width < MIN_WIDTH) { width = MIN_WIDTH; } @@ -283,6 +286,8 @@ class JitsiMeetExternalAPI { * readyToClose - all hangup operations are completed and Jitsi Meet is * ready to be disposed. * @param object + * + * NOTE: This method is not removed for backward comatability purposes. */ addEventListeners(object) { for (var i in object) { @@ -336,41 +341,26 @@ class JitsiMeetExternalAPI { * }} * @param event the name of the event * @param listener the listener + * + * NOTE: This method is not removed for backward comatability purposes. */ addEventListener(event, listener) { - if (!(event in events)) { - logger.error("Not supported event name."); - return; - } - // We cannot remove listeners from postis that's why we are handling the - // callback that way. - if (!this.postisListeners[event]) { - this.postis.listen(events[event], data => { - if((event in this.eventHandlers) && - typeof this.eventHandlers[event] === "function") - this.eventHandlers[event].call(null, data); - }); - this.postisListeners[event] = true; - } - this.eventHandlers[event] = listener; + this.on(event, listener); } /** * Removes event listener. * @param event the name of the event. + * NOTE: This method is not removed for backward comatability purposes. */ removeEventListener(event) { - if(!(event in this.eventHandlers)) - { - logger.error("The event " + event + " is not registered."); - return; - } - delete this.eventHandlers[event]; + this.removeListeners(event); } /** * Removes event listeners. * @param events array with the names of the events. + * NOTE: This method is not removed for backward comatability purposes. */ removeEventListeners(events) { for(var i = 0; i < events.length; i++) { @@ -395,6 +385,12 @@ class JitsiMeetExternalAPI { 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)); + } } /** From 334eb5d4230eac1209c084f1d647bd0493e6ee95 Mon Sep 17 00:00:00 2001 From: hristoterezov Date: Mon, 3 Apr 2017 10:48:46 -0500 Subject: [PATCH 3/3] feat(iframe_api): Add more ESLint rules --- doc/api.md | 8 +- modules/API/external/.eslintrc.js | 3 + modules/API/external/external_api.js | 557 ++++++++++++++------------- 3 files changed, 289 insertions(+), 279 deletions(-) create mode 100644 modules/API/external/.eslintrc.js diff --git a/doc/api.md b/doc/api.md index 161e51995..6087e1d95 100644 --- a/doc/api.md +++ b/doc/api.md @@ -129,7 +129,7 @@ api.executeCommands({displayName: ['nickname'], toggleAudio: []}); ``` 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 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`. 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. -*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 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. -*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 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. -*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 api.removeEventListeners(["incomingMessage", "outgoingMessageListener"]); ``` diff --git a/modules/API/external/.eslintrc.js b/modules/API/external/.eslintrc.js new file mode 100644 index 000000000..fa9de82aa --- /dev/null +++ b/modules/API/external/.eslintrc.js @@ -0,0 +1,3 @@ +module.exports = { + 'extends': '../../../react/.eslintrc.js' +}; diff --git a/modules/API/external/external_api.js b/modules/API/external/external_api.js index c61b147c3..fc107fcdf 100644 --- a/modules/API/external/external_api.js +++ b/modules/API/external/external_api.js @@ -1,18 +1,39 @@ -const logger = require("jitsi-meet-logger").getLogger(__filename); -import postisInit from "postis"; -import EventEmitter from "events"; +import EventEmitter from 'events'; +import postisInit from 'postis'; + +const logger = require('jitsi-meet-logger').getLogger(__filename); /** - * The minimum width for the Jitsi Meet frame - * @type {number} + * Maps the names of the commands expected by the API with the name of the + * 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 - * @type {number} + * Maps the names of the events expected by the API with the name of the + * 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 @@ -21,56 +42,25 @@ const MIN_HEIGHT = 300; let id = 0; /** - * Maps the names of the commands expected by the API with the name of the - * commands expected by jitsi-meet + * The minimum height for the Jitsi Meet frame + * @type {number} */ -const commands = { - "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" -}; +const MIN_HEIGHT = 300; /** - * Maps the names of the events expected by the API with the name of the - * events expected by jitsi-meet + * The minimum width for the Jitsi Meet frame + * @type {number} */ -const events = { - "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); -} +const MIN_WIDTH = 790; /** * Adds given number to the numberOfParticipants property of given APIInstance. - * @param {JitsiMeetExternalAPI} APIInstance the instance of the - * JitsiMeetExternalAPI - * @param {int} number - the number of participants to be added to + * + * @param {JitsiMeetExternalAPI} APIInstance - The instance of the API. + * @param {int} number - The number of participants to be added to * numberOfParticipants property (this parameter can be negative number if the * numberOfParticipants should be decreased). + * @returns {void} */ function changeParticipantNumber(APIInstance, 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 * be used for the Jitsi Meet URL generation. * - * @param config {object} the config object. - * @returns {Array} the array with URL param strings. + * @param {Object} config - The config object. + * @returns {Array} The array with URL param strings. */ -function configToURLParamsArray(config) { +function configToURLParamsArray(config = {}) { const params = []; - for (const key in config) { + for (const key in config) { // eslint-disable-line guard-for-in try { - params.push(key + '=' - + encodeURIComponent(JSON.stringify(config[key]))); + params.push(`${key}=${ + encodeURIComponent(JSON.stringify(config[key]))}`); } catch (e) { console.warn(`Error encoding ${key}: ${e}`); } } + 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. */ class JitsiMeetExternalAPI extends EventEmitter { /** - * Constructs new API instance. Creates iframe element that loads - * Jitsi Meet. - * @param domain the domain name of the server that hosts the conference - * @param room_name the name of the room to join - * @param width width of the iframe - * @param height height of the iframe - * @param parent_node the node that will contain the iframe - * @param configOverwrite object containing configuration options defined in - * config.js to be overridden. - * @param interfaceConfigOverwrite object containing configuration options - * defined in interface_config.js to be overridden. - * @param noSsl if the value is true https won't be used - * @param {string} [jwt] the JWT token if needed by jitsi-meet for + * Constructs new API instance. Creates iframe and loads Jitsi Meet in it. + * + * @param {string} domain - The domain name of the server that hosts the + * conference. + * @param {string} [roomName] - The name of the room to join. + * @param {number} [width] - Width of the iframe. + * @param {number} [height] - Height of the iframe. + * @param {DOMElement} [parentNode] - The node that will contain the + * iframe. + * @param {Object} [configOverwrite] - Object containing configuration + * options defined in config.js to be overridden. + * @param {Object} [interfaceConfigOverwrite] - Object containing + * 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. - * @constructor */ - constructor(domain, room_name, width, height, parentNode, - configOverwrite, interfaceConfigOverwrite, noSsl, jwt) { + constructor(domain, // eslint-disable-line max-params + roomName = '', + width = MIN_WIDTH, + height = MIN_HEIGHT, + parentNode = document.body, + configOverwrite = {}, + interfaceConfigOverwrite = {}, + noSSL = false, + jwt = undefined) { super(); - - if (!width || width < MIN_WIDTH) { - width = MIN_WIDTH; - } - if (!height || height < MIN_HEIGHT) { - height = MIN_HEIGHT; - } - - this.parentNode = null; - if (parentNode) { - this.parentNode = parentNode; - } else { - var scriptTag = document.scripts[document.scripts.length - 1]; - 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.parentNode = parentNode; + this.url = generateURL(domain, { + configOverwrite, + interfaceConfigOverwrite, + jwt, + noSSL, + roomName + }); + this._createIFrame(Math.max(height, MIN_HEIGHT), + Math.max(width, MIN_WIDTH)); + this.postis = postisInit({ + scope: `jitsi_meet_external_api_${id}`, + window: this.frame.contentWindow }); - - this.eventHandlers = {}; - - // Map<{string} event_name, {boolean} postis_listener_added> - this.postisListeners = {}; - this.numberOfParticipants = 1; this._setupListeners(); - id++; } /** - * 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 name the name of the command - * @param arguments array of arguments + * Creates the iframe element. + * + * @param {number} height - The height of the iframe. + * @param {number} width - The with of the iframe. + * @returns {void} + * + * @private */ - executeCommand(name, ...argumentsList) { - if(!(name in commands)) { - logger.error("Not supported command name."); - return; - } - sendMessage(this.postis, { - method: commands[name], - params: argumentsList - }); + _createIFrame(height, width) { + this.iframeHolder + = this.parentNode.appendChild(document.createElement('div')); + this.iframeHolder.id = `jitsiConference${id}`; + this.iframeHolder.style.width = `${width}px`; + this.iframeHolder.style.height = `${height}px`; + + 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: - * 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 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. + * Setups listeners that are used internally for JitsiMeetExternalAPI. + * + * @returns {void} + * + * @private */ - executeCommands(object) { - for (var key in object) { - this.executeCommand(key, object[key]); + _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) { // 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. * Currently we support the following * 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 + * '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 + * 'message': txt//the text of the message * }} * displayNameChanged - receives event notifications about display name * 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 * ready to be disposed. - * @param object + * @returns {void} * + * @deprecated * NOTE: This method is not removed for backward comatability purposes. */ - addEventListeners(object) { - for (var i in object) { - this.addEventListener(i, object[i]); + addEventListeners(listeners) { + for (const event in listeners) { // eslint-disable-line guard-for-in + this.addEventListener(event, listeners[event]); } } /** - * Adds event listeners to Meet Jitsi. Currently we support the following - * 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 + * Removes the listeners and removes the Jitsi Meet frame. * - * NOTE: This method is not removed for backward comatability purposes. + * @returns {void} */ - addEventListener(event, listener) { - this.on(event, listener); + dispose() { + 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. - * @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. */ removeEventListener(event) { @@ -359,52 +403,15 @@ class JitsiMeetExternalAPI extends EventEmitter { /** * Removes event listeners. - * @param events array with the names of the events. + * + * @param {Array} eventList - Array with the names of the events. + * @returns {void} + * + * @deprecated * NOTE: This method is not removed for backward comatability purposes. */ - removeEventListeners(events) { - for(var i = 0; i < events.length; i++) { - 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); + removeEventListeners(eventList) { + eventList.forEach(event => this.removeEventListener(event)); } }