UNPKG

opentok-screen-sharing

Version:
502 lines (408 loc) 15.3 kB
/* global chrome OT ScreenSharingAccPack OTKAnalytics define */ (function () { /** Include external dependencies */ var _; var $; var OTKAnalytics; if (typeof module === 'object' && typeof module.exports === 'object') { /* eslint-disable import/no-unresolved */ _ = require('underscore'); $ = require('jquery'); OTKAnalytics = require('opentok-solutions-logging'); /* eslint-enable import/no-unresolved */ } else { _ = this._; $ = this.$; OTKAnalytics = this.OTKAnalytics; } /** Private Variables*/ var _this; // Reference to instance of ScreenSharingAccPack var _active; // Currently sharing screen? var _accPack; // Common layer API var _session; // OpenTok session var _screenSharingControl = [ '<div class="ots-video-control circle share-screen" id="startScreenSharing"></div>' ].join('\n'); var _screenSharingView = [ '<div class="hidden" id="screenShareView">', '<div class="ots-feed-main-video">', '<div class="ots-feed-holder" id="videoHolderScreenShare"></div>', '<div class="ots-feed-mask"></div>', '<img src="https://assets.tokbox.com/solutions/images/widget-video-mask.png"/>', '</div>', '<div class="ots-feed-call-controls" id="feedControlsFromScreen">', '<button class="ots-icon-screen active hidden" id="endScreenShareBtn"></button>', '</div>', '</div>' ].join('\n'); var _screenDialogsExtensions = [ /* eslint-disable max-len */ '<div id="dialog-form-chrome" class="ots-ss-modal" style="display: none;">', '<div class="ots-modal-body">', '<div class="ots-modal-title with-icon">', '<i class="ots-icon-share-large"></i>', '<span>Screen Share<br/>Extension Installation</span>', '</div>', '<p>You need a Chrome extension to share your screen. Install Screensharing Extension. Once you have installed, please, click the share screen button again.</p>', '<button id="btn-install-plugin-chrome" class="ots-btn-install">Accept</button>', '<button id="btn-cancel-plugin-chrome" class="ots-cancel-btn-install"></button>', '</div>', '</div>', '<div id="dialog-form-ff" class="ots-ss-modal" style="display: none;">', '<div class="ots-modal-body">', '<div class="ots-modal-title with-icon">', '<i class="ots-icon-share-large"></i>', '<span>Screen Share<br/>Extension Installation</span>', '</div>', '<p>You need a Firefox extension to share your screen. Install Screensharing Extension. Once you have installed, refresh your browser and click the share screen button again.</p>', '<a href="#" id="btn-install-plugin-ff" class="ots-btn-install">Install extension</a>', '<a href="#" id="btn-cancel-plugin-ff" class="ots-cancel-btn-install"></a>', '</div>', '</div>' /* eslint-enable max-len */ ].join('\n'); /** Private Methods */ /** Analytics */ var _otkanalytics; // vars for the analytics logs. Internal use var _logEventData = { clientVersion: 'js-vsol-x.y.z', // x.y.z filled by npm build script componentId: 'screenSharingAccPack', name: 'guidScreensharingAccPack', actionInitialize: 'Init', actionStart: 'Start', actionEnd: 'End', enableAnnotations: 'EnableAnnotations', disableAnnotations: 'DisableAnnotations', enableAudioScreenSharing: 'EnableAudioScreenSharing', disableAudioScreenSharing: 'DisableAudioScreenSharing', variationAttempt: 'Attempt', variationError: 'Failure', variationSuccess: 'Success', }; var _logAnalytics = function () { // init the analytics logs var _source = window.location.href; var otkanalyticsData = { clientVersion: _logEventData.clientVersion, source: _source, componentId: _logEventData.componentId, name: _logEventData.name }; _otkanalytics = new OTKAnalytics(otkanalyticsData); var sessionInfo = { sessionId: _session.id, connectionId: _session.connection.connectionId, partnerId: _session.apiKey }; _otkanalytics.addSessionInfo(sessionInfo); }; var _log = function (action, variation) { var data = { action: action, variation: variation }; _otkanalytics.logEvent(data); }; var _defaultScreenProperties = { insertMode: 'append', width: '100%', height: '100%', showControls: false, style: { buttonDisplayMode: 'off', }, videoSource: 'window', }; var _setupUI = function (parent) { $('body').append(_this.screenDialogsExtensions); _this.appendControl && $(_this.controlsContainer).append(_screenSharingControl); $(parent).append(_screenSharingView); }; var _toggleScreenSharingButton = function (show) { $('#startScreenSharing')[show ? 'show' : 'hide'](); }; // Trigger event via common layer API var _triggerEvent = function (event, data) { if (_accPack) { _accPack.triggerEvent(event, data); } }; /** * Create a publisher for the screen. If we're using annotation, we first need * to create the annotion window and get a reference to its annotation container * element so that we can pass it to the initPublisher function. * @returns {promise} < Resolve: [Object] Container element for annotation in external window > */ var _initPublisher = function (publisherOptions) { var createPublisher = function (publisherDiv) { var innerDeferred = $.Deferred(); var getContainer = function () { if (publisherDiv) { return publisherDiv; } if (typeof _this.screenSharingContainer === 'function') { return document.querySelector(_this.screenSharingContainer('publisher', 'screen')); } else { return _this.screenSharingContainer; } } var container = getContainer(); var properties = Object.assign({}, _this.localScreenProperties || _defaultScreenProperties, publisherOptions); _this.publisher = OT.initPublisher(container, properties, function (error) { if (error) { _triggerEvent('screenSharingError', error); innerDeferred.reject(_.extend(_.omit(error, 'messsage'), { message: 'Error starting the screen sharing', })); } else { _this.publisher.on('mediaStopped', function () { end(); }); innerDeferred.resolve(); } }); return innerDeferred.promise(); }; var outerDeferred = $.Deferred(); if (_this.annotation && _this.externalWindow) { _log(_logEventData.enableAnnotations, _logEventData.variationSuccess); _accPack.setupExternalAnnotation() .then(function (annotationWindow) { _this.annotationWindow = annotationWindow || null; var annotationElements = annotationWindow.createContainerElements(); createPublisher(annotationElements.publisher) .then(function () { outerDeferred.resolve(annotationElements.annotation); }); }); } else { createPublisher() .then(function () { outerDeferred.resolve(); }); } return outerDeferred.promise(); }; /** * Start publishing the screen * @param annotationContainer */ var _publish = function (annotationContainer) { _session.publish(_this.publisher, function (error) { if (error) { // Let's write our own error message var customError = _.omit(error, 'message'); if (error.code === 1500 && navigator.userAgent.indexOf('Firefox') !== -1) { $('#dialog-form-ff').toggle(); } else { var errorMessage; if (error.code === 1010) { errorMessage = 'Check your network connection'; } else { errorMessage = 'Error sharing the screen'; } customError.message = errorMessage; _triggerEvent('screenSharingError', customError); _log(_logEventData.actionStart, _logEventData.variationError); } } else { if (_this.annotation && _this.externalWindow) { _accPack.linkAnnotation(_this.publisher, annotationContainer, _this.annotationWindow); _log(_logEventData.actionInitialize, _logEventData.variationSuccess); } _active = true; _triggerEvent('startScreenSharing', _this.publisher); _log(_logEventData.actionStart, _logEventData.variationSuccess); } }); }; /** * Stop publishing the screen */ var _stopPublishing = function () { _session.unpublish(_this.publisher); }; /** Public Methods */ var extensionAvailable = function () { var deferred = $.Deferred(); if (window.location.protocol === 'http:' && !_this.dev) { alert("Screensharing only works under 'https', please add 'https://' in front of your debugger url."); deferred.reject('https required'); } OT.checkScreenSharingCapability(function (response) { if (!response.supported || response.extensionRegistered === false) { alert('This browser does not support screen sharing! Please use Chrome, Firefox or IE!'); deferred.reject('browser support not available'); } else if (response.extensionInstalled === false) { if (detectBrowser() === 'Firefox') { if (!firefoxExtensionRequired()) { deferred.resolve(); } else { $('#dialog-form-ff').toggle(); deferred.reject('screensharing extension not installed'); } } else { $('#dialog-form-chrome').toggle(); deferred.reject('screensharing extension not installed'); } } else { deferred.resolve(); } }); return deferred.promise(); }; /** * @param {Object} [publisherOptions] - Properties for the screen sharing publisher. */ var start = function (publisherOptions) { _log(_logEventData.actionStart, _logEventData.variationAttempt); extensionAvailable(_this.extensionID, _this.extensionPathFF) .then(_initPublisher(publisherOptions)) .then(_publish) .fail(function (error) { console.log('Error starting screensharing: ', error); _log(_logEventData.actionStart, _logEventData.variationError); }); }; var end = function (callEnded) { _stopPublishing(); _active = false; if (callEnded) { _toggleScreenSharingButton(false); } _triggerEvent('endScreenSharing', _this.publisher); _log(_logEventData.actionEnd, _logEventData.variationSuccess); }; /** Events */ var _registerEvents = function () { if (!_accPack) { return; } var events = ['startScreenSharing', 'endScreenSharing', 'screenSharingError']; _accPack.registerEvents(events); }; var _addScreenSharingListeners = function () { var startOrEnd = _.throttle(function () { !!_active ? end() : start(); }, 750); $('#startScreenSharing').on('click', startOrEnd); /** Handlers for screensharing extension modal */ $('#btn-install-plugin-chrome').on('click', function () { window.open(['https://chrome.google.com/webstore/detail/', _this.extensionID].join(''), '_blank'); $('#dialog-form-chrome').toggle(); }); $('#btn-cancel-plugin-chrome').on('click', function () { $('#dialog-form-chrome').toggle(); }); $('#btn-install-plugin-ff').prop('href', _this.extensionPathFF); $('#btn-install-plugin-ff').on('click', function () { $('#dialog-form-ff').toggle(); }); $('#btn-cancel-plugin-ff').on('click', function () { $('#dialog-form-ff').toggle(); }); if (!!_accPack) { _accPack.registerEventListener('startCall', function () { _toggleScreenSharingButton(true); }); _accPack.registerEventListener('endCall', function () { if (_active) { end(true); } else { _toggleScreenSharingButton(false); } }); _accPack.registerEventListener('annotationWindowClosed', function () { end(); }); } }; var _validateExtension = function (extensionID, extensionPathFF, appendWebStoreLink) { if (detectBrowser() === 'Chrome') { if (!extensionID || !extensionID.length) { throw new Error('Error starting the screensharing. Chrome extensionID required'); } else { if (appendWebStoreLink) { $('<link/>', { rel: 'chrome-webstore-item', href: ['https://chrome.google.com/webstore/detail/', extensionID].join('') }).appendTo('head'); } OT.registerScreenSharingExtension('chrome', extensionID, 2); } } }; var _validateOptions = function (options) { if (!_.property('session', options)) { throw new Error('Screen Share Acc Pack requires an OpenTok session'); } _session = _.property('session')(options); _accPack = _.property('accPack')(options); var appendLink = options.appendWebStoreLink === undefined ? true : options.appendWebStoreLink; _validateExtension(_.property('extensionID')(options), _.property('extensionPathFF')(options), appendLink); }; /** * @constructor * Represents a screensharing component * @param {Object} options * @param {String} options.session * @param {Object} [options.accPack] * @param {String} [options.extensionID] * @param {String} [options.appendWebStoreLink] * @param {String} [options.extentionPathFF] * @param {String} [options.screensharingParent] * @param {String} [options.screenDialogsExtensions] * @param {String | Function} [options.screensharingContainer] */ var ScreenSharingAccPack = function (options) { _this = this; // Check for required options _validateOptions(options); // Extend our instance var optionsProps = [ 'annotation', 'externalWindow', 'extensionURL', 'extensionID', 'appendWebStoreLink', 'extensionPathFF', 'screenSharingContainer', 'screenSharingParent', 'controlsContainer', 'screenProperties', 'localScreenProperties', 'appendControl', 'dev', 'screenDialogsExtensions', ]; _.extend(_this, _.defaults(_.pick(options, optionsProps), { screenSharingParent: '#videoContainer', screenSharingContainer: document.getElementById('videoHolderSharedScreen'), controlsContainer: '#feedControls', appendWebStoreLink: true, appendControl: true, screenDialogsExtensions: _screenDialogsExtensions, })); // Do UIy things _setupUI(_this.screensharingParent); _registerEvents(); _addScreenSharingListeners(); // init analytics logs _logAnalytics(); _log(_logEventData.actionInitialize, _logEventData.variationSuccess); }; ScreenSharingAccPack.prototype = { constructor: ScreenSharingAccPack, extensionAvailable: extensionAvailable, start: start, end: end }; if (typeof exports === 'object') { module.exports = ScreenSharingAccPack; } else if (typeof define === 'function' && define.amd) { define(function () { return ScreenSharingAccPack; }); } else { this.ScreenSharingAccPack = ScreenSharingAccPack; } }.call(this));