| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622 | <!DOCTYPE html><html lang="en"><head>    <meta charset="utf-8">    <title>JSDoc: Source: glass/views/ShareView.js</title>    <script src="scripts/prettify/prettify.js"> </script>    <script src="scripts/prettify/lang-css.js"> </script>    <!--[if lt IE 9]>      <script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>    <![endif]-->    <link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">    <link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css"></head><body><div id="main">    <h1 class="page-title">Source: glass/views/ShareView.js</h1>            <section>        <article>            <pre class="prettyprint source linenums"><code>/** * Licensed Materials - Property of IBM * IBM Cognos Products: Collaboration * (C) Copyright IBM Corp. 2017, 2020 * * US Government Users Restricted Rights - Use, duplication or disclosure * restricted by GSA ADP Schedule Contract with IBM Corp. */define([	'underscore',	'jquery',	'react',	'react-dom',	'ca-ui-toolkit',	'../../lib/@waca/core-client/js/core-client/ui/AccessibleView',	'../../lib/@waca/core-client/js/core-client/utils/BrowserUtils',	'../../lib/@waca/core-client/js/core-client/utils/DateTimeUtils',	'../../nls/StringResources',	'../../api/sharing/ShareController',	'../utils/GlassUtil'], function (_, $, React, ReactDOM, Toolkit, AccessibleView, BrowserUtils, DateTimeUtils, StringResources, ShareController, GlassUtil) {	'use strict';	const SHARE_VIEW_CLASS = 'share-view ba-collab-fill-space ba-theme-default';	var ShareView = AccessibleView.extend( /** @lends ShareView */ {		/**		 * @desc Constructor for ShareView.		 * @constructs ShareView		 * @extends AccessibleView		 * @public		 * @param options {Object} Options		 * @param options.glassContext {Object} The glass context		 */		init: function (options) {			_.extend(options, {				enableTabLooping: true,				className: 'ba-collab-fill-space'			});			ShareView.inherited('init', this, arguments);			this.glassContext = options.glassContext;			this.shareController = new ShareController(_.extend({				errorHandler: this.displayError.bind(this),				slideout: this.slideout			}, options));			this._panel = null;			this.link = options.slideout.content.link;			this.embedVisible = this._isEmbedEnabled() && options.slideout.content.embedVisible !== false;			this.imageVisible = !!options.slideout.content.imageVisible;			this._eventHandlers = this.slideout && [				this.slideout.on('show', this.onSlideShow.bind(this)),				this.slideout.on('hide', this.onSlideHide.bind(this))			];			this._logger = options.logger;			try {				this._instrumentationService = this.glassContext.getCoreSvc('.Instrumentation');			} catch (e) {				// just swallow it if the instrumentation service isn't available for some reason.				void (e);			}			this.onSlideShow(); // event is not being called when slide is opened for the first time.			this.reactContainer = null;			this.shareStore = null;			this.imageStore = null;		},		/**		* It will be called after slideout is shown		* @callback		*/		setFocus: function () {			if (this._panel) {				this._panel.setFocus();			}		},		_onIframeFocus: function (e) {			e.stopPropagation();			const activeElement = document.activeElement;			if (activeElement instanceof HTMLIFrameElement				&& !activeElement.classList.contains('cke_panel_frame')				&& !this.$el.get(0).contains(activeElement)				&& this.slideout.isOpen()) {				this.close();			}		},		onSlideShow: function () {			var $iframe = $('iframe');			if ($iframe.length > 0 && this.slideout) {				this._onIframeFocusFunc = this._onIframeFocus.bind(this);				$(window).on('blur', this._onIframeFocusFunc);			}			if (this._panel) {				const assetStrings = this.shareController.getAssetStrings();				this.shareStore.setAssetType(assetStrings.assetType);				this.shareStore.setAssetTitle(assetStrings.assetTitle);				this.shareStore.setIsDirty(this._isDirty());				return Promise.all([ this.refreshLink(), this.refreshIncludeImage() ])					.then(results => {						const link = results[0];						// if cannot send, don't need to get connectors						if (!this.canSend()) {							this.shareStore.setConnectors([]);							this.imageStore.setImageLoaded(false);							return link;						}						// refresh connectors						return this.getConnectors()							.then((connectors) => {								this.shareStore.setConnectors(connectors);								this.imageStore.setImageLoaded(false);								return link;							});					});			}			return Promise.resolve(null);		},		onSlideHide: function () {			var $iframe = $('iframe');			if ($iframe.length > 0 && this.slideout && this._onIframeFocusFunc) {				this._onIframeFocusFunc = null;				$(window).off('blur', this._onIframeFocusFunc);			}			return this.shareController.leaveShareState();		},		/**		 * Sets the current perspective's link URL.		 * @param link		 */		setLink: function (link) {			if (this.shareStore) {				this.shareStore.setLink(link);			}		},		/**		 * Refresh the current perspective's link URL.		 * @instance		 * @returns {Promise} resolved as an object that contains shareUrl and embedUrl		 */		refreshLink: function () {			return new Promise((resolve, reject) => {				if (this.link) {					this.setLink(this.link);					resolve(this.link);				} else {					this.shareController.getLink(this.glassContext)						.then((link) => {							this.setLink(link);							resolve(link);						})						.catch((error) => {							this.setLink(null);							reject(error);						});				}			});		},		/**		 * Fetch user's configured product locale and Product version.		 * @instance		 * @returns {Promise} with the user's browser language.		 */		getConfig: function () {			// The passed in version number is of the form "11.1 RX", but the knowledge center			// uses the form "11.1.X". Until glass provides consistent versioning with the knowlege			// center, we will hard-code the version here.			return this.glassContext.getSvc('.UserProfile')				.then(userProfile => {					const language = userProfile.preferences.productLocale ? userProfile.preferences.productLocale : 'en';					return {						language,						version: '11.1.0'					};				});		},		/**		 * Capture the current perspective's screenshot image.		 * @instance		 * @returns {Promise} with an image string as URL.		 */		refreshImage: function () {			return new Promise((resolve, reject) => {				if (this._panel && this._panel.state.connector) {					if (this._panel.state.connector.isImageSupported()) {						this.shareController							.getScreenshot(this.glassContext)							.then((item) => {								var img = new Image();								img.onload = () => {									this.imageStore.setImage(item.image, item.label, img.width, img.height);									resolve(item);								};								img.src = item.image;							})							.catch((error) => {								this.glassContext.showToast(StringResources.get('error_no_screenshot'), {									type: 'error'								});								this.imageStore.setImage('', '', 0, 0);								reject(error);							});					} else {						var errorTxt = StringResources.get('error_screenshot_unsupported');						this.glassContext.showToast(errorTxt, {							type: 'warning'						});						reject(new Error(errorTxt));					}				} else {					resolve(); // We're not trying to load a screenshot yet.				}			});		},		/**		 * Returns if the content supports export to pdf		 * @returns Promise		 */		canExportToPDF: function () {			return this.shareController.canExportToPDF(this.glassContext).then((result) => {				// when link is set, we were called from My/Team Content navigation.				return result && !this.link && this.features.includes(GlassUtil.feature.EXPORT);			});		},		/**		 * Returns whether "Include image" option should be visible or hidden.		 *		 * @returns {Promise} that resolves to a boolean value.		 */		includeImage: function () {			if (!this.imageVisible) {				return Promise.resolve(false);			}			// Authoring perspective supports image capture but requires an extra check			// of the current report format. Image capture should be enabled for HTML reports;			// disabled for PDF reports.			return this.shareController.canCaptureImage(this.glassContext);		},		/**		 * Update "Include image" flags in the ImageStore.		 * 		 * One use case where it's necessary:		 * 1. Run HTML report.		 * 2. Open Share / Email panel ==> "Include image" should be enabled		 * 3. Hide Share slideout.		 * 4. Run the same report as PDF in the report viewer.		 * 5. Open Share panel ==> "Include image" should be disabled.		 */		refreshIncludeImage: function() {			if (!this.imageStore) {				return Promise.resolve();			}			return this.includeImage().then(result => {				this.imageStore.setShowIncludeImage(result);				return result;			});		},		_checkLinkShareable: function (link) {			var pathQuery = 'pathRef';			if (!!this.type && this.type.assetType === 'folder') {				pathQuery = 'folder';			}			return !!(link && link.shareUrl && link.shareUrl.search(pathQuery + '=.my_folders') === -1);		},		isLinkShareable: function (link) {			return this._isLinkEnabled() && this._checkLinkShareable(link);		},		canSend: function () {			return this._isSendEnabled() && (!this.link ? true : this._checkLinkShareable(this.link));		},		/**		 * Render the view.		 * @instance		 */		render: function () {			// tell html2canvas to ignore our panel when capturing the image.			this.$el.closest('.flyoutPane').attr('data-html2canvas-ignore', 'true');			// 1. render a spinner			ReactDOM.render(React.createElement(Toolkit.ProgressIndicator, {				className: 'initialCollaborationSlideoutSpinner',				id: 'initialCollaborationSlideoutSpinner',				size: 'large',				style: { left: '50%', top: '50%', position: 'absolute', transform: 'translate(-50%, -50%)' }			}), this.$el.get(0));			return new Promise(function (resolve, reject) {				// 2. load modules				require(['collaboration/canvaseditor/CanvasEditor', 'collaboration-ui/collaboration-ui.min', 'ckeditor'], function (CanvasEditor, CollaborationUI) {					// 3. get language and version, connectors and more					Promise.all([this.getConfig(), this.getConnectors(), this.canExportToPDF(), this.refreshLink(), this.includeImage()])						.then(([config, connectors, canExport, link, showIncludeImage]) => {							// 4. remove the spinner							ReactDOM.unmountComponentAtNode(this.$el.get(0));							// 5. create the stores							this.createStores(								CollaborationUI.ShareStore,								CollaborationUI.ImageStore,								CanvasEditor,								connectors,								config,								canExport,								link,								showIncludeImage);							// 6. render react							this.renderReact(CollaborationUI.CollaborationPanel);							// all done!							resolve();						})						.catch(reject);				}.bind(this));			}.bind(this));		},		_isSendEnabled: function () {			return this.features.includes(GlassUtil.feature.SEND);		},		_isLinkEnabled: function () {			return this.features.includes(GlassUtil.feature.LINK);		},		_isEmbedEnabled: function () {			return this.features.includes(GlassUtil.feature.EMBED);		},		_isEmailLinkEnabled: function () {			return this.features.includes(GlassUtil.feature.EMAIL_LINK) && this.glassContext.hasCapability('canIncludeLinkInEmail');		},		_isDirty: function() {			return this.glassContext.currentAppView.isDirty();		},		createStores: function (ShareStore, ImageStore, CanvasEditor, connectors, config, canExport, link, showIncludeImage) {			const assetStrings = this.shareController.getAssetStrings();			const shareStore = ShareStore.create({				isIE11: BrowserUtils.isIE11(),				language: config.language,				version: config.version,				assetTitle: assetStrings.assetTitle,				assetType: assetStrings.assetType,				isDirty: this._isDirty(),				objectType: this.objectType || null,				objectId: this.objectId || null			}, {				CanvasEditor,				glassContext: this.glassContext,				$root: this.$el,				isLinkShareable: this.isLinkShareable.bind(this),				send: this.send.bind(this),				generatePDF: this.generatePDF.bind(this),				displayError: this.displayError.bind(this),				instrument: this.instrument.bind(this),				features: this.features,				glassFeature: GlassUtil.feature,				dateTimeUtils: DateTimeUtils			});			shareStore.enableSend(this._isSendEnabled());			shareStore.enableLink(this._isLinkEnabled());			shareStore.enableEmailLink(this._isEmailLinkEnabled());			shareStore.enableEmbed(this._isEmbedEnabled());			shareStore.enableExport(canExport);			shareStore.setConnectors(connectors);			shareStore.setLink(link);			this.shareStore = shareStore;			const imageStore = ImageStore.create({				showIncludeImage: showIncludeImage,				includeImage: showIncludeImage,				image: '',				imageLoaded: false,				imageLabel: '',				imageWidth: 0,				imageHeight: 0			}, {				refreshImage: this.refreshImage.bind(this)			});			this.imageStore = imageStore;		},		createReactPanel: function (CollaborationPanel, options) {			this._panel = ReactDOM.render(React.createElement(CollaborationPanel, options), this.reactContainer);		},		renderReact: function (CollaborationPanel) {			const $container = $(`<div class="${SHARE_VIEW_CLASS}" tabIndex="-1"></div>`).appendTo(this.$el);			this.enableLooping($container);			const options = {				shareStore: this.shareStore,				imageStore: this.imageStore,				nls: StringResources.get,				panel: 'main',				cancel: this.close.bind(this),				embedVisible: this.embedVisible,				contentMenuShare: !!this.link			};			// render the view with options			this.reactContainer = $container.get(0);			this.createReactPanel(CollaborationPanel, options);			this.$el.on('escapeaction', (event) => {				event.preventDefault();				event.stopPropagation();			});			// The slideout has 'transition' css in its root DOM element, and it relies on these events to calculate animation.			// Stop propagation to avoid issues.			var animEvents = 'transitionend webkitTransitionEnd oTransitionEnd';			$(this.reactContainer).off(animEvents).on(animEvents, function (event) {				event.stopPropagation();			});		},		generatePDF: function (pageSize, includeFilter) {			if (this.shareStore && this.shareStore.canExport) {				this.shareController.exportToPDF(this.glassContext, pageSize, includeFilter);			}		},		instrument: function (action, shareType) {			if (this._instrumentationService && this._instrumentationService.enabled) {				return this.shareController.getInstrumentation(this.glassContext)					.then((event) => {						event.action = action;						event['custom.shareType'] = shareType;						event.type = 'Shared Object';						event.objectType = event.objectType || this.objectType;						// If neither of those worked, try to get the type from glass.						if (!event.objectType && typeof this.glassContext.getCurrentContentView === 'function') {							event.objectType = this.glassContext.getCurrentContentView().getType();						}						event.milestoneName = `${action}_${event.objectType}`;						this._instrumentationService.track(event);					});			}			return Promise.resolve();		},		getConnectors: function () {			// don't need to load connectors if cannot send			if (!this.canSend()) {				return Promise.resolve([]);			}			return this.shareController.getConnectors()				.catch(function (error) {					if (this._logger) {						this._logger.error('Error fetching connectors: ' + error);					}					this.glassContext.showToast(StringResources.get('error_retrieving_platforms'), {						type: 'error'					});					throw error;				}.bind(this));		},		/**		 * Sends the message.		 * @instance		 * @param {object} payload		 * @param {object} payload.connector		 * @param {object} payload.data		 * @returns {Promise}		 */		send: function (payload) {			return this.shareController.send(payload.connector, payload.data)				.then((result) => {					// success					void (result);					const message = (payload.type === 'email') ? StringResources.get('toast_success_email') : StringResources.get('toast_success', {						connector: payload.connector.getLabel()					});					this.glassContext.showToast(message, { type: 'success' });				}).then(() => this.close());		},		/**		 * Close the panel.		 * @instance		 * @returns {Promise}		 */		close: function () {			return this.shareController.close()				.then(function () {					return this.slideout.hide({						force: true,						hideOnly: this.slideout.hideOnly					});				}.bind(this))				.then(function () {					var launchPoint = this.getLaunchPoint();					if (launchPoint) {						$(launchPoint).focus();					}				}.bind(this));		},		/**		 * Display errors as toast message.		 * @instance		 * @param {object} error		 * @throws {error}		 */		displayError: function (error) {			var msg = error.message;			if (error.connector) {				const connectorType = error.connector.getType();				var toastStringId = (connectorType === 'email') ? 'toast_failure_email' : 'toast_failure';				var toastMessageData = {					connector: error.connector.getLabel(),					error: error.message				};				if (error.showContactAdmin) {					toastStringId = (connectorType === 'email') ? 'toast_failure_detailed_email' : 'toast_failure_detailed';					toastMessageData.contactAdmin = StringResources.get('message_contact_administrator');				}				msg = StringResources.get(toastStringId, toastMessageData);			}			this.glassContext.showToast(msg, {				type: 'error'			});			throw error;		},		/**		 * Cleaning up events		 * @override		 */		remove: function () {			if (this._eventHandlers) {				this._eventHandlers.forEach(function (handler) {					if (handler) {						handler.remove();					}				});			}			if (this.reactContainer) {				ReactDOM.unmountComponentAtNode(this.reactContainer);			}		}	});	return ShareView;});</code></pre>        </article>    </section></div><nav>    <h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="ConnectorBase.html">ConnectorBase</a></li><li><a href="Connectors.html">Connectors</a></li><li><a href="EmailClient.html">EmailClient</a></li><li><a href="EmailConnector.html">EmailConnector</a></li><li><a href="MSTeamsAuth.html">MSTeamsAuth</a></li><li><a href="MSTeamsClient.html">MSTeamsClient</a></li><li><a href="MSTeamsConnector.html">MSTeamsConnector</a></li><li><a href="ShareableItems.html">ShareableItems</a></li><li><a href="ShareController.html">ShareController</a></li><li><a href="ShareView.html">ShareView</a></li><li><a href="SlackAuth.html">SlackAuth</a></li><li><a href="SlackClient.html">SlackClient</a></li><li><a href="SlackConnector.html">SlackConnector</a></li></ul><h3>Interfaces</h3><ul><li><a href="ShareInterface.html">ShareInterface</a></li></ul></nav><br class="clear"><footer>    Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a> on Wed May 25 2022 13:54:53 GMT+0000 (UTC)</footer><script> prettyPrint(); </script><script src="scripts/linenumber.js"> </script></body></html>
 |