UNPKG

@microsoft/sp-webpart-base

Version:

SharePoint Framework support for building web parts

705 lines 40.3 kB
import { Validate, _BROKER_IN_USE_KEY, _BrowserUtilities, Text } from '@microsoft/sp-core-library'; import { _LogSource, _TraceLogger } from '@microsoft/sp-diagnostics'; import { _AadConstants, _AadTokenProviders } from '@microsoft/sp-http-base'; import { _IframeLoadRedirector, _SPLoaderFlights } from '@microsoft/sp-loader'; import * as lodash from '@microsoft/sp-lodash-subset'; import { ThemeProvider } from '@microsoft/sp-component-base'; import { isIsolatedAceEnabled } from '../../common/Flights'; import { isIsolatedWebPartTabStopKSActivated, isIsolatedAdaptiveCardExtensionIframedPropertyPaneKSActivated, isDynamicIframedPropertyPaneHandlingKSActivated, isPreventLateIframeRedirectKSActivated } from '../../common/KillSwitches'; import { IframedWebPartAction } from '../../core/IIframedWebPartMessage'; import iframedPropertyPaneStyles from './IframedPropertyPane.module.scss'; import { ReservedIframeQueryParamKeys } from './ReservedIframeQueryParamKeys'; import { isEqual } from '@microsoft/sp-lodash-subset'; import { IframedWebPart } from '../../core/iframedInterfaces/IframedWebPart'; import { IFRAMED_WEB_PART } from '../../core/iframedInterfaces/IBaseIframedWebPart'; import { IframedAdaptiveCardExtensionWebPart } from '../../core/iframedInterfaces/IframedAdaptiveCardExtensionWebPart'; import strings from '../../core/loc/Strings.resx'; var LOG_SOURCE = _LogSource.create('IframedWebPartController'); var WEBPART_IFRAME_ID_PREFIX = 'dom-isolated-webpart'; var PROPERTYPANE_IFRAME_ID = 'dom-isolated-property-pane'; var IFRAMED_PROPERTYPANE_CONTAINER_ID = 'spIFramePropertyPaneContainer'; var IframedWebPartController = /** @class */ (function () { function IframedWebPartController(host) { this._iframeSrcUrl = undefined; this._iframedWebparts = new Map(); this._host = host; this._ppIframeElement = undefined; this._iframeContextMap = new Map(); this._updateWebPartData = this._updateWebPartData.bind(this); this._updateWebPartDisplayMode = this._updateWebPartDisplayMode.bind(this); this._iframeEventListener = this._iframeEventListener.bind(this); window.addEventListener('message', this._iframeEventListener); } /** * Delete references an iframed web part. */ IframedWebPartController.prototype.deleteWebPart = function (instanceId) { this._iframeContextMap.delete(instanceId); Validate.isNonemptyString(instanceId, 'instanceId'); var webPart = this._iframedWebparts.get(instanceId); // Send message to the iframed property pane if it exists. var iframePropertyPaneElement = document.getElementById(PROPERTYPANE_IFRAME_ID); if (iframePropertyPaneElement && iframePropertyPaneElement.contentWindow) { var messageToPropertyPane = { instanceId: instanceId, action: IframedWebPartAction.DeleteWebPart }; iframePropertyPaneElement.contentWindow.postMessage(messageToPropertyPane, webPart.url); } this.requestPropertyPaneAction('Close'); webPart.dispose(); this._iframedWebparts.delete(instanceId); }; /** * Get the instanceId's of all the iframed webparts. */ IframedWebPartController.prototype.getAllInstanceIds = function () { var instanceIds = []; this._iframedWebparts.forEach(function (value, key) { instanceIds.push(key); }); return instanceIds; }; /** * Send a message to the iframed webpart to notify that their container * has been resized. */ IframedWebPartController.prototype.notifyContainerResize = function (instanceId) { // @todo #VS0:617678 Add support for "notifyContrainerResize" }; IframedWebPartController.prototype.startDirtyBitTimer = function (instanceId) { // This lifecycle event is manually handled when a web part property is changed. }; /** * @param domainUrl - the domain from which the web part should be loaded. * Returns an iframe that points to a SpWebApplication that loads the webpart. * @param pageContext - Page context reference. * @param webPartManagerContext - web part manager context. */ IframedWebPartController.prototype.loadWebPart = function (domainUrl, pageContext, webPartManagerContext, isIsolatedACEWP) { this._iframeContextMap.set(webPartManagerContext.instanceId, webPartManagerContext); this._iframeSrcUrl = this._generateIframeSrcUrl(domainUrl, pageContext, webPartManagerContext); Validate.isNotNullOrUndefined(webPartManagerContext.webPartData, 'webPartData'); var metadata = { origin: domainUrl, url: this._iframeSrcUrl, webPartData: webPartManagerContext.webPartData, webPartElementId: "".concat(WEBPART_IFRAME_ID_PREFIX, "-").concat(webPartManagerContext.instanceId), displayMode: webPartManagerContext.displayMode, addedFromPersistedData: !!webPartManagerContext.addedFromPersistedData, theme: undefined }; // This instanceId appears twice if we are loading the property pane of an already rendered // webpart, in that case we do not need to write twice. if (!this._iframedWebparts.has(webPartManagerContext.instanceId)) { // Fill in the initial values on the web part data if we are creating the web part's instance. if (!webPartManagerContext.addedFromPersistedData) { metadata.webPartData.dataVersion = '1.0'; // Note: Same instance id should be passed as 'newWebPartInstanceId' to the iframe. metadata.webPartData.instanceId = webPartManagerContext.instanceId; } if (!isIsolatedAdaptiveCardExtensionIframedPropertyPaneKSActivated() && isIsolatedACEWP) { this._iframedWebparts.set(webPartManagerContext.instanceId, new IframedAdaptiveCardExtensionWebPart(this, webPartManagerContext.serviceScope || this._host.serviceScope, metadata)); } else { this._iframedWebparts.set(webPartManagerContext.instanceId, new IframedWebPart(this, webPartManagerContext.serviceScope || this._host.serviceScope, metadata)); if (_SPLoaderFlights._isSafariIsolationEnabled()) { var iframe_1 = document.createElement('iframe'); iframe_1.id = metadata.webPartElementId; iframe_1.src = this._addFilteredQueryParamsFromHostPage(metadata.url); iframe_1.classList.add(iframedPropertyPaneStyles.iframeWebPart); iframe_1.scrolling = 'no'; iframe_1.title = metadata.webPartData.title; if (!_BrowserUtilities.isUsingSecureBroker()) { if (!isPreventLateIframeRedirectKSActivated()) { void _IframeLoadRedirector.instance; } iframe_1.onload = function () { return _IframeLoadRedirector.instance.confirmLoadOrRedirect(iframe_1.src); }; } if (!isIsolatedWebPartTabStopKSActivated()) { iframe_1.tabIndex = 0; } var div = document.createElement('div'); div.appendChild(iframe_1); webPartManagerContext.domElement.appendChild(div); } else { webPartManagerContext.domElement.innerHTML = "<div>\n <iframe\n id=".concat(metadata.webPartElementId, "\n src=").concat(this._addFilteredQueryParamsFromHostPage(metadata.url), "\n class=").concat(iframedPropertyPaneStyles.iframeWebPart, "\n scrolling=\"no\"\n ").concat(!isIsolatedWebPartTabStopKSActivated() ? 'tabindex="0"' : '', "\n title=\"").concat(metadata.webPartData.title, "\"\n ></iframe>\n </div>"); } } } }; IframedWebPartController.prototype.assignIsolatedACEWP = function (instanceId, isolatedACEWP) { if (this._iframedWebparts.has(instanceId)) { var webPart = this._iframedWebparts.get(instanceId); if (webPart.type === IFRAMED_WEB_PART.isolatedACEWebPart) { webPart.webPart = isolatedACEWP; } } }; /** * To open a property pane for a web part that has been loaded into an iframe, we create a sibling dom element on the * page and render the property pane into it. We use the same method of loading an iframe with the addition of a * query parameter, 'openPropertyPane=true'. By default 'openPropertyPane' is undefined and thus false. * @param propertyPaneState - the desired state of the property pane. * @param instanceId - the instanceId of the corresponding web part. */ IframedWebPartController.prototype.requestPropertyPaneAction = function (propertyPaneState, instanceId) { Validate.isNotNullOrUndefined(propertyPaneState, 'propertyPaneState'); switch (propertyPaneState) { case 'Open': case 'OpenDetails': Validate.isNonemptyString(instanceId, 'instanceId'); if ((!isDynamicIframedPropertyPaneHandlingKSActivated() && this._iframedPropertyPaneWebPartInstanceId !== instanceId) || !this._ppIframeElement) { // No-Iframe element is present on the page this._createPropertyPaneElement(instanceId, propertyPaneState === 'OpenDetails'); } this._showPropertyPane(instanceId, propertyPaneState); break; case 'Close': if (this._ppIframeElement) { this._hidePropertyPane(instanceId); } break; case 'Toggle': Validate.isNonemptyString(instanceId, 'instanceId'); if (this._iframedPropertyPaneContainer && this._iframedPropertyPaneContainer.classList.contains(iframedPropertyPaneStyles.showPane)) { this._hidePropertyPane(instanceId); } else { // Create the iframed property pane element if none exists. if ((!isDynamicIframedPropertyPaneHandlingKSActivated() && this._iframedPropertyPaneWebPartInstanceId !== instanceId) || !this._iframedPropertyPaneContainer) { this._createPropertyPaneElement(instanceId); } this._showPropertyPane(instanceId, 'Open'); } break; case 'Refresh': Validate.isNonemptyString(instanceId, 'instanceId'); this._refreshPropertyPane(instanceId); break; case 'Default': break; } }; /** * Returns the most recently saved WebPartData for the web part associated * with the 'instanceId'. */ IframedWebPartController.prototype.serialize = function (instanceId) { Validate.isNonemptyString(instanceId, 'instanceId'); var metadata = this._iframedWebparts.get(instanceId); return metadata.webPartData; }; /** * Handles the ClientSideWebPartManager's request to set the displayMode for a web part * in an iframe. (Saves the displayMode and sends a message to the iframe window). */ IframedWebPartController.prototype.setDisplayMode = function (displayMode, instanceId) { Validate.isNotNullOrUndefined(displayMode, 'displayMode'); Validate.isNonemptyString(instanceId, 'instanceId'); var messageToRenderedWebPart = { instanceId: instanceId, action: IframedWebPartAction.SetDisplayMode, displayMode: displayMode }; // Save the display mode in case the web part has not yet rendered, after rendering has completed // a message will be sent to the IframedWebPartController requesting the 'displayMode'. var metadata = this._iframedWebparts.get(instanceId); metadata.displayMode = displayMode; // Send a message to the iframed window containing the rendered web part // No need to validate the iframe exists because it may not have been rendered yet if // this is the first time the page is loaded. var targetWindow = this._getCurrentIframeWebPartContentWindow(metadata.webPartElementId); if (targetWindow) { targetWindow.postMessage(messageToRenderedWebPart, metadata.url); } }; /** * Handles requests to set the theme for a web part in an iframe. */ IframedWebPartController.prototype.setTheme = function (theme, instanceId) { var metadata = this._iframedWebparts.get(instanceId); if (metadata.theme && isEqual(metadata.theme, theme)) { // we don't want to send unnecessary messages return; } var messageToRenderedWebPart = { instanceId: instanceId, action: IframedWebPartAction.SetTheme, theme: theme }; // Save the theme in case the web part has not yet rendered, after rendering has completed // a message will be sent to the IframedWebPartController requesting the 'theme'. metadata.theme = theme; // Send a message to the iframed window containing the rendered web part // No need to validate the iframe exists because it may not have been rendered yet if // this is the first time the page is loaded. var targetWindow = this._getCurrentIframeWebPartContentWindow(metadata.webPartElementId); if (targetWindow) { targetWindow.postMessage(messageToRenderedWebPart, metadata.url); } }; /** * Returns the url that loads the webpart with instanceId and componentId on the 'webPartManagerContext'. * @param domainUrl - the domain from which the web part should be loaded. * @param pageContext - Page context reference. * @param webPartManagerContext - web part manager context. */ IframedWebPartController.prototype._generateIframeSrcUrl = function (domainUrl, pageContext, webPartManagerContext) { var _a, _b; var isTeamsApp = _BrowserUtilities.isTeamsHosted(); var isUsingSecureBroker = isTeamsApp && _BrowserUtilities.isUsingSecureBroker(); var iframeSrcUrl; if (!isUsingSecureBroker) { iframeSrcUrl = "".concat(domainUrl, "/_layouts/15/webpart.aspx?"); } else { var domainAndPath = new URL(domainUrl); iframeSrcUrl = domainAndPath.pathname; if (!domainAndPath.pathname.endsWith('/')) { iframeSrcUrl += '/'; } iframeSrcUrl += "/_layouts/15/webpart.aspx?"; } // If the web part is being added from the persisted data it means that the web part instance // already exists on the page otherwise we are creating a new instance for the web part. if (webPartManagerContext.addedFromPersistedData) { iframeSrcUrl += "".concat(ReservedIframeQueryParamKeys.List, "=%7B"); iframeSrcUrl += ((_a = webPartManagerContext.isolatedItemContext) === null || _a === void 0 ? void 0 : _a.list) || pageContext.list.id; iframeSrcUrl += "%7D&".concat(ReservedIframeQueryParamKeys.Id, "="); iframeSrcUrl += ((_b = webPartManagerContext.isolatedItemContext) === null || _b === void 0 ? void 0 : _b.id) || pageContext.listItem.id; iframeSrcUrl += "&".concat(ReservedIframeQueryParamKeys.WebPartInstanceId, "="); iframeSrcUrl += webPartManagerContext.instanceId; } else { iframeSrcUrl += "".concat(ReservedIframeQueryParamKeys.NewWebPartInstanceId, "="); iframeSrcUrl += webPartManagerContext.instanceId; } iframeSrcUrl += "&".concat(ReservedIframeQueryParamKeys.ParentWindowOrigin, "="); iframeSrcUrl += window.location.origin; iframeSrcUrl += "&".concat(ReservedIframeQueryParamKeys.ComponentId, "="); iframeSrcUrl += webPartManagerContext.manifest.id; iframeSrcUrl += "&".concat(ReservedIframeQueryParamKeys.HostedInCanvas); if (isTeamsApp) { iframeSrcUrl += "&".concat(ReservedIframeQueryParamKeys.HostedInTeams); if (isUsingSecureBroker) { iframeSrcUrl += "&".concat(_BROKER_IN_USE_KEY, "=true"); iframeSrcUrl = "".concat(domainUrl, "/_layouts/15/brokerlogon.aspx?").concat(_BROKER_IN_USE_KEY, "=true&") + // TODO: If we want to support testing in a simple way we need to pass the debug query string parameters to the iframe 'dest=' + encodeURIComponent(iframeSrcUrl); } } return iframeSrcUrl; }; /** * Creates an iframe HTML element, sets the source url to load an application that will * display the property pane associated with the given parameters, and add the iframed * element as a child to the page chrome. This method will not show the property pane by * default, 'showPropertyPane' should be called after. */ IframedWebPartController.prototype._createPropertyPaneElement = function (instanceId, openDetails) { if (!this._pageContentElement) { this._pageContentElement = document.getElementById('spPageChromeAppDiv'); } if (!this._iframedPropertyPaneContainer) { this._iframedPropertyPaneContainer = document.createElement('div'); this._iframedPropertyPaneContainer.id = IFRAMED_PROPERTYPANE_CONTAINER_ID; this._iframedPropertyPaneContainer.className = iframedPropertyPaneStyles.spIFramePropertyPaneContainer; } var metadata = this._iframedWebparts.get(instanceId); if (!isDynamicIframedPropertyPaneHandlingKSActivated()) { this._iframedPropertyPaneWebPartInstanceId = instanceId; } this._iframeSrcUrl = metadata.url; this._iframeSrcUrl += "&".concat(openDetails ? ReservedIframeQueryParamKeys.OpenDetailsPropertyPane : ReservedIframeQueryParamKeys.OpenPropertyPane, "=true"); this._iframedPropertyPaneContainer.innerHTML = "\n <iframe\n id=".concat(PROPERTYPANE_IFRAME_ID, "\n src=").concat(this._addFilteredQueryParamsFromHostPage(this._iframeSrcUrl), "\n class=").concat(iframedPropertyPaneStyles.iframePropertyPane, "\n title=").concat(Text.format(strings.IsolatedWebPartPropertiesIframeTitle, metadata.webPartData.title), "\n ></iframe>"); var parent = this._pageContentElement.parentElement; parent.appendChild(this._iframedPropertyPaneContainer); this._ppIframeElement = document.getElementById(PROPERTYPANE_IFRAME_ID); }; /** * Event listener that takes actions on behalf of iframed webparts. */ IframedWebPartController.prototype._iframeEventListener = function (event) { var _this = this; var _a, _b; if (this._iframedWebparts.has(event.data.instanceId)) { var metadata = this._iframedWebparts.get(event.data.instanceId); var currentOrigin = new URL(event.origin).origin; if (currentOrigin.toLowerCase() === event.origin.toLowerCase()) { var eventData_1 = event.data; Validate.isNotNullOrUndefined(eventData_1.action, 'action'); switch (eventData_1.action) { case IframedWebPartAction.RequestDisplayMode: this._updateWebPartDisplayMode(eventData_1.instanceId); break; case IframedWebPartAction.GetOboToken: var _c = eventData_1.oboRequest, application = _c.application, claims = _c.claims; var tokenProvider = _AadTokenProviders.configurable; var tokenPromise = void 0; if (application === _AadConstants.PRE_AUTHORIZED_APP_PRINCIPAL_ID) { tokenPromise = tokenProvider._oboFirstPartyTokenCallback(claims); } else { tokenPromise = tokenProvider._oboThirdPartyTokenCallback(application, claims); } tokenPromise .then(function (token) { _this._setOboToken(eventData_1.instanceId, token); }) .catch(function () { // Notify the web part of a failed token fetch _this._setOboToken(eventData_1.instanceId, undefined); }); break; case IframedWebPartAction.SetDimensions: var iframeWebPartElement = document.getElementById(metadata.webPartElementId); Validate.isNotNullOrUndefined(iframeWebPartElement, 'iframedWebPartElement'); if (isIsolatedAceEnabled()) { var height = eventData_1.height, instanceId = eventData_1.instanceId, isFullScreen = eventData_1.isFullScreen, width = eventData_1.width; if (isFullScreen) { var clientRect = iframeWebPartElement.getBoundingClientRect(); // Remove height/width, raise z priority, and stretch fullscreen iframeWebPartElement.style.cssText = 'bottom: 0; left: 0; position: fixed; top: 0; z-index: 99999'; if (iframeWebPartElement.parentElement) { if (this._isHostDashboardWebPart(instanceId)) { // The Dashboard Web Part needs the additional padding added for isolation added to the client height to avoid jank iframeWebPartElement.parentElement.style.height = "".concat(clientRect.height + 3, "px"); } else { // The Canvas does not hold the width so we set the parent element to the current width as a "placeholder" iframeWebPartElement.parentElement.style.width = "".concat(clientRect.width, "px"); } } // Notify the iframe of the old client size // In the case of ACEs, we use this info to place the ACE into its original position var targetWindow = this._getCurrentIframeWebPartContentWindow(metadata.webPartElementId); if (targetWindow) { targetWindow.postMessage({ instanceId: eventData_1.instanceId, clientRect: clientRect }, metadata.url); } } else { // Reset all potential modifications from previously being "fullscreen" (_a = iframeWebPartElement.parentElement) === null || _a === void 0 ? void 0 : _a.style.removeProperty('width'); (_b = iframeWebPartElement.parentElement) === null || _b === void 0 ? void 0 : _b.style.removeProperty('height'); iframeWebPartElement.style.removeProperty('position'); iframeWebPartElement.style.removeProperty('top'); iframeWebPartElement.style.removeProperty('left'); iframeWebPartElement.style.removeProperty('bottom'); if (height) { iframeWebPartElement.style.height = "".concat(height, "px"); } if (width && !this._isHostDashboardWebPart(instanceId)) { iframeWebPartElement.style.width = "".concat(width, "px"); } } } else { Validate.isNotNullOrUndefined(eventData_1.height, 'height'); iframeWebPartElement.style.height = "".concat(eventData_1.height, "px"); } break; case IframedWebPartAction.UpdateWebPartData: Validate.isNotNullOrUndefined(eventData_1.webPartData, 'webPartData'); this._updateWebPartData(eventData_1.instanceId, eventData_1.webPartData, IframedWebPartAction.UpdateWebPartData); break; case IframedWebPartAction.UpdatePropertyPaneData: Validate.isNotNullOrUndefined(eventData_1.webPartData, 'webPartData'); this._updateWebPartData(eventData_1.instanceId, eventData_1.webPartData, IframedWebPartAction.UpdatePropertyPaneData); break; case IframedWebPartAction.UpdatePropertyPaneLifeCycle: switch (eventData_1.propertyPaneLifeCycleEvent) { case 'Closed': this._hidePropertyPane(event.data.instanceId); } break; case IframedWebPartAction.WebPartRenderedInPropertyPaneIframe: var data = { instanceId: event.data.instanceId, action: IframedWebPartAction.RequestPropertyPaneAction, propertyPaneAction: 'Refresh', webPartData: metadata.webPartData }; this._ppIframeElement.contentWindow.postMessage(data, metadata.url); break; case IframedWebPartAction.UpdateWebpartLifeCycle: this._updateParentHost(eventData_1); break; case IframedWebPartAction.RequestTheme: this._updateThemeInfo(eventData_1.instanceId); break; case IframedWebPartAction.RequestPropertyPaneAction: this.requestPropertyPaneAction(eventData_1.propertyPaneAction, eventData_1.instanceId); break; case IframedWebPartAction.UpdateAudiences: this._updateAudiences(eventData_1.instanceId, eventData_1.audiences || []); break; default: break; } } } }; IframedWebPartController.prototype._updateThemeInfo = function (instanceId) { var theme = this._tryGetTheme(instanceId); if (theme) { this.setTheme(theme, instanceId); } }; IframedWebPartController.prototype._tryGetTheme = function (instanceId) { var _a, _b; return (_b = (_a = this._iframeContextMap .get(instanceId)) === null || _a === void 0 ? void 0 : _a.serviceScope) === null || _b === void 0 ? void 0 : _b.consume(ThemeProvider.serviceKey).tryGetTheme(); }; IframedWebPartController.prototype._updateParentHost = function (_a) { var instanceId = _a.instanceId, parentHostLifeCycle = _a.parentHostLifeCycle; var context = this._iframeContextMap.get(instanceId); var _b = parentHostLifeCycle, lifeCycleMethod = _b.lifeCycleMethod, error = _b.error; switch (lifeCycleMethod) { case 'onBeforeWebPartLoad': this._host.onBeforeWebPartLoad(context); break; case 'onAfterWebPartLoad': this._host.onAfterWebPartLoad(context); break; case 'onBeforeWebPartInitialize': this._host.onBeforeWebPartInitializeOld(context); break; case 'onAfterWebPartInitialize': this._host.onAfterWebPartInitialize(context); break; case 'onBeforeWebPartRender': this._host.onBeforeWebPartRender(context); break; case 'onAfterWebPartRender': this._host.onAfterWebPartRender(context); break; case 'onAfterWebPartLoadFailed': if (error) { this._host.onAfterWebPartLoadFailed(context, error); } break; case 'onAfterWebPartInitializeFailed': if (error) { this._host.onAfterWebPartInitializeFailed(context, error); } break; case 'onAfterWebPartRenderFailed': if (error) { this._host.onAfterWebPartRenderFailed(context, error); } break; } }; /** * Sends a message to an iframed webpart requesting the 'displayMode' set by the ClientSideWebPartManager. * * When an iframe loads a webpart in an iframe it has the context of the webpart's 'displayMode', but the * iframe does not. Thus, after a webpart loads in an iframed, we send a message to the IframedWebPartController * asking for the display mode, which is then sent to the iframe via a window message. * */ IframedWebPartController.prototype._updateWebPartDisplayMode = function (instanceId) { var metadata = this._iframedWebparts.get(instanceId); var messageToIframe = { instanceId: instanceId, displayMode: metadata.displayMode, action: IframedWebPartAction.SetDisplayMode }; var targetWindow = this._getCurrentIframeWebPartContentWindow(metadata.webPartElementId); if (targetWindow) { targetWindow.postMessage(messageToIframe, metadata.url); } }; /** * Sends a message to the iframed web part to update it's web part data if the incoming * webPartData differs from the currently saved reference. * There are two scenarios: * 1. the property pane has been updated and is sending a message to the rendered web part * 2. the rendered web part has been updated and is sending a message to the property pane * - we use the param 'action' to differentiate the difference and use the correct element id * of the property pane or the web part. * * @param instanceId - web part instance id * @param webPartData - the incoming web part data. */ IframedWebPartController.prototype._updateWebPartData = function (instanceId, webPartData, action) { var _a; var webPart = this._iframedWebparts.get(instanceId); // Only send a message if the webPartData differs from the last webPartData we sent if (!lodash.isEqual(webPartData, webPart.webPartData)) { webPart.webPartData = webPartData; this._iframedWebparts.set(instanceId, webPart); this._host.setDirty(instanceId); if (!isIsolatedAdaptiveCardExtensionIframedPropertyPaneKSActivated() && webPart.type === IFRAMED_WEB_PART.isolatedACEWebPart) { (_a = webPart.webPart) === null || _a === void 0 ? void 0 : _a.updateACEData(instanceId, webPartData); // IframedWebPart content window does not exist with Isolated ACEs. return; } var message = { instanceId: instanceId, webPartData: webPartData, action: IframedWebPartAction.SetWebPartData }; switch (action) { case IframedWebPartAction.UpdatePropertyPaneData: // The propertyPane iframe may not be open var iframePropertyPaneElement = document.getElementById(PROPERTYPANE_IFRAME_ID); if (iframePropertyPaneElement && iframePropertyPaneElement.contentWindow) { iframePropertyPaneElement.contentWindow.postMessage(message, webPart.url); } break; case IframedWebPartAction.UpdateWebPartData: var targetWindow = this._getCurrentIframeWebPartContentWindow(webPart.webPartElementId); if (targetWindow) { targetWindow.postMessage(message, webPart.url); } break; default: _TraceLogger.logError(LOG_SOURCE, new Error('Invalid parameter "action"')); break; } } }; IframedWebPartController.prototype._updateAudiences = function (instanceId, audiences) { var _a, _b; (_b = (_a = this._host).onAudiencesChanged) === null || _b === void 0 ? void 0 : _b.call(_a, instanceId, audiences); }; IframedWebPartController.prototype._refreshPropertyPane = function (webPartInstanceId) { if (this._iframedPropertyPaneContainer && webPartInstanceId) { var eventData = { instanceId: webPartInstanceId, action: IframedWebPartAction.RequestPropertyPaneAction, propertyPaneAction: 'Refresh' }; var metadata = this._iframedWebparts.get(webPartInstanceId); if (this._ppIframeElement && this._ppIframeElement.contentWindow) { this._ppIframeElement.contentWindow.postMessage(eventData, metadata.url); } } }; IframedWebPartController.prototype._hidePropertyPane = function (webPartInstanceId) { if (this._iframedPropertyPaneContainer) { if (webPartInstanceId) { var eventData = { // Pass the instanceId so we know which web part to // configure when we the property pane is opened. instanceId: webPartInstanceId, action: IframedWebPartAction.RequestPropertyPaneAction, propertyPaneAction: 'Close' }; var metadata = this._iframedWebparts.get(webPartInstanceId); // This message is being listened for in SpWebPartApplication._openPropertyPaneListener if (this._ppIframeElement && this._ppIframeElement.contentWindow) { this._ppIframeElement.contentWindow.postMessage(eventData, metadata.url); } } this._iframedPropertyPaneContainer.classList.remove(iframedPropertyPaneStyles.showPane); this._iframedPropertyPaneContainer.classList.add(iframedPropertyPaneStyles.hidePane); this._pageContentElement.classList.remove(iframedPropertyPaneStyles.shrinkContent); } }; /** * Adds and removes the neccessary styles to show the iframed property pane container. * Also posts a message to the window element so that the PropertyPaneController * can show the property pane content. * @param webPartInstanceId - instanceId so we know which property pane to open */ IframedWebPartController.prototype._showPropertyPane = function (webPartInstanceId, action) { var _this = this; var propertyPaneAction = action || 'Open'; if (propertyPaneAction !== 'Open' && propertyPaneAction !== 'OpenDetails') { return; } if (webPartInstanceId && this._iframedWebparts.has(webPartInstanceId)) { var metadata_1 = this._iframedWebparts.get(webPartInstanceId); // Update the src property in the iframe // (This is important if there are two iframed web parts on the page) var openDetailsPropertyPane = propertyPaneAction === 'OpenDetails'; var iframeSrc = new URL(this._ppIframeElement.src); if (openDetailsPropertyPane) { iframeSrc.searchParams.delete('openPropertyPane'); iframeSrc.searchParams.set('openDetailsPropertyPane', 'true'); } else { iframeSrc.searchParams.delete('openDetailsPropertyPane'); iframeSrc.searchParams.set('openPropertyPane', 'true'); } this._ppIframeElement.src = iframeSrc.toString(); var eventData_2 = { // Pass the instanceId so we know which web part to // configure when we the property pane is opened. instanceId: webPartInstanceId, action: IframedWebPartAction.RequestPropertyPaneAction, propertyPaneAction: propertyPaneAction }; // This message is being listened for in SpWebPartApplication._openPropertyPaneListener if (this._ppIframeElement && this._ppIframeElement.contentWindow && this._ppIframeElement.contentDocument) { this._ppIframeElement.contentDocument.onload = (function () { _this._ppIframeElement.contentWindow.postMessage(eventData_2, metadata_1.url); }).bind(this); } } this._iframedPropertyPaneContainer.classList.add(iframedPropertyPaneStyles.showPane); this._iframedPropertyPaneContainer.classList.remove(iframedPropertyPaneStyles.hidePane); this._pageContentElement.classList.add(iframedPropertyPaneStyles.shrinkContent); }; IframedWebPartController.prototype._setOboToken = function (instanceId, oboToken) { var message = { instanceId: instanceId, oboToken: oboToken, action: IframedWebPartAction.SetOboToken }; var metadata = this._iframedWebparts.get(instanceId); var targetWindow = this._getCurrentIframeWebPartContentWindow(metadata.webPartElementId); if (targetWindow) { targetWindow.postMessage(message, metadata.url); } }; /** * Adds the non-reserved query params from the host page to the iframe url. * * @param url - current iframe url. */ IframedWebPartController.prototype._addFilteredQueryParamsFromHostPage = function (url) { var reservedKeys = Object.keys(ReservedIframeQueryParamKeys).map(function (key) { return ReservedIframeQueryParamKeys[key]; }); var searchParams = new URL(window.location.href).searchParams; for (var _i = 0, reservedKeys_1 = reservedKeys; _i < reservedKeys_1.length; _i++) { var param = reservedKeys_1[_i]; if (searchParams.has(param)) { searchParams.delete(param); } } return "".concat(url, "&").concat(searchParams.toString()); }; IframedWebPartController.prototype._getCurrentIframeWebPartContentWindow = function (elementId) { var iframeWebPartElement = document.getElementById(elementId); return iframeWebPartElement === null || iframeWebPartElement === void 0 ? void 0 : iframeWebPartElement.contentWindow; }; /** * @param instanceId - Web part to check * @returns - A boolean indicating whether the web part is being rendered in the Dashboard Web Part */ IframedWebPartController.prototype._isHostDashboardWebPart = function (instanceId) { var _a; var element = this._iframeContextMap.get(instanceId).domElement; return ((_a = element.parentElement) === null || _a === void 0 ? void 0 : _a.dataset.spFeatureTag) === 'DashboardWebPart'; }; return IframedWebPartController; }()); export default IframedWebPartController; //# sourceMappingURL=IframedWebPartController.js.map