@microsoft/sp-webpart-base
Version:
SharePoint Framework support for building web parts
746 lines • 35.7 kB
JavaScript
"use strict";
// Copyright (c) Microsoft. All rights reserved.
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
var sp_telemetry_1 = require("@msinternal/sp-telemetry");
var sp_diagnostics_1 = require("@microsoft/sp-diagnostics");
var sp_core_library_1 = require("@microsoft/sp-core-library");
var sp_component_base_1 = require("@microsoft/sp-component-base");
var sp_edit_customer_promise_1 = require("@msinternal/sp-edit-customer-promise");
var BaseWebPart_1 = tslib_1.__importDefault(require("./BaseWebPart"));
var ClassicPageUtils_1 = tslib_1.__importDefault(require("./classicPages/ClassicPageUtils"));
var SPWebPartError_1 = require("./error/SPWebPartError");
var WebPartWidthCacheManager_1 = tslib_1.__importDefault(require("./WebPartWidthCacheManager"));
var cswp_base_module_scss_1 = tslib_1.__importDefault(require("./styles/cswp-base.module.scss"));
var KillSwitches_1 = require("../common/KillSwitches");
var Flights_1 = require("../common/Flights");
/**
* This abstract class implements the the base functionality for a client-side web part. Every client-side web part
* needs to inherit from this class.
*
* @remarks
* Along with the base functionality, this class provides some APIs that can be
* used by the web part. These APIs fall in two catagories.
*
* The first category of APIs provide data and functionality. Example, the web part context (i.e. this.context). This
* API should be used to access contextual data relevant to this web part instance.
*
* The second category of APIs provide a base implementation for the web part lifecycle and can be overridden for an
* updated implementation. The render() API is the only API that is mandatory to be implemented/overridden by a web
* part. All other life cycle APIs have a base implementation and can be overridden based on the needs of the web part.
* Please refer to the documentation of the individual APIs to make the right decision.
*
* @public
*/
var BaseClientSideWebPart = /** @class */ (function (_super) {
tslib_1.__extends(BaseClientSideWebPart, _super);
/**
* Constructor for the BaseClientSideWebPart class.
*
* @remarks
* It is highly recommended that the web part use the `onInit()` API to perform any web part specific
* initialization. Most of the web part features like this.context and `this.properties` are not
* available to be used before the the `onInit()` part of the web part loading lifecycle.
*/
function BaseClientSideWebPart() {
var _this = _super.call(this) || this;
_this._logSource = sp_diagnostics_1._LogSource.create('BaseClientSideWebPart');
_this._asyncRenderQosMonitor = new sp_diagnostics_1._QosMonitor("WebPartAsyncRender");
_this._asyncRenderCompleteCalled = false;
/**
* Whether the web part is visible.
*/
_this._isVisible = true;
_this._internalIsDisposing = false;
// Disallow instantiation of the base class by itself
// eslint-disable-next-line @typescript-eslint/no-explicit-any
if (_this.constructor.name === 'BaseClientSideWebPart') {
throw SPWebPartError_1.SPWebPartError.create(SPWebPartError_1.SPWebPartErrorCode.BaseConstructError);
}
_this._firstTimeRenderPromises = [];
return _this;
}
Object.defineProperty(BaseClientSideWebPart.prototype, "domElement", {
// Readonly protected properties. To change these to readonly once TypeScript supports that feature.
/**
* This property is a pointer to the root DOM element of the web part. This is a DIV element and contains the whole
* DOM subtree of the web part.
*
* @readonly
*/
get: function () {
return this.context.domElement;
},
enumerable: false,
configurable: true
});
Object.defineProperty(BaseClientSideWebPart.prototype, "width", {
/**
* This property returns the width of the container for the web part.
* @returns Width (in pixels) of the container for the web part.
*
* @remarks
* Web parts should utilize this property to perform operations such as any conditional styling of components
* based on the initial available width for the web part.
* @readonly
*/
get: function () {
// This function retrieves web part's key to get stored section width from cache.
// If cache key does not exist in cache it will calculate and store the width before returning.
//
// In the case where getWebPartCacheKey is not passed down, it will go through the original
// workflow to calculate web part width.
if (this.displayMode === sp_core_library_1.DisplayMode.Read) {
this._width = WebPartWidthCacheManager_1.default.getOrCalculateWidth(this.domElement, this._getExtendedWidthCacheKey());
}
else {
if (this._width === undefined) {
this._width = WebPartWidthCacheManager_1.default.calculateWebPartWidth(this.domElement);
}
}
return this._width;
},
enumerable: false,
configurable: true
});
Object.defineProperty(BaseClientSideWebPart.prototype, "renderedOnce", {
/**
* This property indicates whether the web part has been rendered once or not. After the first time rendering,
* the value of this property is always true until a full re-render of the web part happens.
*
* @readonly
*/
get: function () {
return !!this._renderedOnce;
},
enumerable: false,
configurable: true
});
Object.defineProperty(BaseClientSideWebPart.prototype, "renderedFromPersistedData", {
/**
* This property indicates whether the web part was rendered from the persisted data (serialized state from the
* last time that the web part was saved) or not.
*
* @remarks
* Example: When web part is added for the first time using toolbox then the value is false.
*
* @readonly
*/
get: function () {
return !!this._renderedFromPersistedData;
},
enumerable: false,
configurable: true
});
Object.defineProperty(BaseClientSideWebPart.prototype, "canOpenPopupOnRender", {
/**
* This property indicates whether a web part can open a popup on initial render.
*
* @remarks
* In some environments the host
* re-renders the web parts frequently, and therefore opening popups during render will cause popups to open
* repeatedly, which is a poor user experience. As an example, the classic SharePoint pages perform postbacks
* causing the page to re-render on all button clicks.
*
* If a web part needs to open a popup on render, it should use this API before opening the popup. If this API
* returns false, the web part should not open popup on initial render. Some web parts that open popups during
* render are the document embed web part that pops up the file picker on initial render, embedded video web part
* that pops up the PropertyPane on initial render.
*
* @readonly
*/
get: function () {
// @todo (SPPPLAT VSO#243602): if the classic page experience is usable, we should remove this API.
return true;
},
enumerable: false,
configurable: true
});
Object.defineProperty(BaseClientSideWebPart.prototype, "isRenderAsync", {
/**
* Indicates whether the web part is rendering in Async mode.
*
* @remarks
* If the web part overrides this field to return true, then it needs to call renderCompleted API
* after the web part rendering is complete.
*
* The default value is false.
*
* @virtual
*/
get: function () {
return false;
},
enumerable: false,
configurable: true
});
Object.defineProperty(BaseClientSideWebPart.prototype, "isVisible", {
/**
* API to hide or show the web part. It tells the host whether the web part is supposed to be hidden.
* The host might decide to remove or recover the side effects that are not rendered by web part implementation.
* @remarks
* This does NOT work in edit mode.
*
* @alpha
*/
get: function () {
return this.displayMode === sp_core_library_1.DisplayMode.Edit || this._isVisible;
},
set: function (value) {
var _a, _b;
if (this.displayMode !== sp_core_library_1.DisplayMode.Edit && value !== this._isVisible) {
this._isVisible = value;
(_b = (_a = this.context.host).onAfterWebPartVisibilityChanged) === null || _b === void 0 ? void 0 : _b.call(_a, this.context.instanceId, value);
}
},
enumerable: false,
configurable: true
});
Object.defineProperty(BaseClientSideWebPart.prototype, "_isDisposing", {
/**
* If the web part is being disposed
* @internal
*/
get: function () {
return this._internalIsDisposing;
},
enumerable: false,
configurable: true
});
/**
* Internal API to update the webpart upon a resize of the DOM window's viewport
*
* See onAfterResize for more details.
*
* @internal
*/
BaseClientSideWebPart.prototype._internalOnAfterResize = function () {
this._width = undefined;
this.onAfterResize(this.width);
};
/**
* Internal API for the first time render of the web part. The purpose of this API is to enforce initialization steps
* before the actual render is called. This API is called only once during the web part loading lifecycle.
*
* @returns The promise indicates the render loop is finished (success or fail).
*
* @internal
*/
BaseClientSideWebPart.prototype._internalFirstTimeRender = function () {
var _this = this;
if (this._renderPromiseResolver) {
throw SPWebPartError_1.SPWebPartError.create(SPWebPartError_1.SPWebPartErrorCode.FirstTimeRenderCalledMoreThanOnce, this.context.webPartTag);
}
return new Promise(function (resolve, reject) {
_this._renderPromiseResolver = resolve;
_this._renderPromiseRejecter = reject;
_this._onInViewport();
});
};
/**
* @internal
*/
BaseClientSideWebPart.prototype._internalSetDisplayMode = function (newDisplayMode) {
if (this.displayMode !== newDisplayMode) {
// Switch display mode will change the canvas width of web part. Clear the cache of width here.
this._width = undefined;
this._renderedFromPersistedData = true;
}
_super.prototype._internalSetDisplayMode.call(this, newDisplayMode);
};
/**
* Internal API for the web part transpile invoke
*
* @returns Transpile result
*
* @internal
*/
BaseClientSideWebPart.prototype._internalTranspile = function (context) {
return this.onTranspile(context);
};
/**
* @internal
* {@inheritDoc BaseWebPart._internalInitialize}
*/
BaseClientSideWebPart.prototype._internalInitialize = function (webPartContext, addedFromPersistedData, mode) {
_super.prototype._internalInitialize.call(this, webPartContext, addedFromPersistedData, mode);
this._renderedOnce = false;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
this['__type'] = 'BaseClientSideWebPart';
// Bind the callbacks
this.render = this.render.bind(this);
this.onDispose = this.onDispose.bind(this);
this.onTranspile = this.onTranspile.bind(this);
this.renderError = this.renderError.bind(this);
this.clearError = this.clearError.bind(this);
this.renderCompleted = this.renderCompleted.bind(this);
this._asyncRenderTimeout = this._asyncRenderTimeout.bind(this);
this._internalHandleThemeChangedEvent = this._internalHandleThemeChangedEvent.bind(this);
// Consume the new ThemeProvider service
this._internalThemeProvider = this.context.serviceScope.consume(sp_component_base_1.ThemeProvider.serviceKey);
// If it exists, get the theme variant
this._internalThemeVariant = this._internalThemeProvider.tryGetTheme();
this.onThemeChanged(this._internalThemeVariant);
// Register a handler to be notified if the theme variant changes
this._internalThemeProvider.themeChangedEvent.add(this, this._internalHandleThemeChangedEvent);
};
/**
* Internal API to dispose the web part.
*
* See onDispose for more details.
*
* @internal
*/
BaseClientSideWebPart.prototype._internalDispose = function () {
var _a;
// this function will eventually call super.dispose();
this._disposeAfterRenderPromises();
(_a = this._internalThemeProvider) === null || _a === void 0 ? void 0 : _a.themeChangedEvent.remove(this, this._internalHandleThemeChangedEvent);
};
/**
* This API should be called to find the render props used to transpile the webpart
* @param context - transpile context
*
* @internal
*/
BaseClientSideWebPart.prototype.onTranspile = function (context) {
// Override in web part to provide transpiled render props.
throw SPWebPartError_1.SPWebPartError.create(SPWebPartError_1.SPWebPartErrorCode.TranspileNotImplemented);
};
/**
* This API should be called by web parts that perform Async rendering. Those web part are required to override
* the isRenderAsync API and return true. One such example is web parts that render content in an IFrame. The
* web part initiates the IFrame rendering in the `render()` API but the actual rendering is complete only after
* the iframe loading completes.
*
* @param error - error object indicating async render has completed with an error
* @param didUpdate - used to override end performance time with sync render time
*/
BaseClientSideWebPart.prototype.renderCompleted = function (error, didUpdate) {
if (error) {
this._handleAsyncRenderFailed(error);
}
else {
this._renderCompleted(didUpdate);
}
};
/**
* This event method is called when the display mode of a web part is changed.
*
* @remarks
* The default implementation of this API calls
* the web part render method to re-render the web part with the new display mode. If a web part developer does not
* want a full re-render to happen on display mode change, they can override this API and perform specific updates
* to the web part DOM to switch its display mode.
*
* If the web part is initialized or re-initialized when switching to a different display mode then this
* lifecycle method is not called. Example: SharePoint Site Page.
*
* @param oldDisplayMode - The old display mode.
*
* @virtual
*/
BaseClientSideWebPart.prototype.onDisplayModeChanged = function (oldDisplayMode) {
var _this = this;
_super.prototype.onDisplayModeChanged.call(this, oldDisplayMode);
if (oldDisplayMode === this.displayMode) {
return;
}
// Note: this quirk has existed for a very long time now. Long enough that it can be considered
// a part of the design :(. Consider the scenario when the page is loaded with "&Mode=Edit" query
// string parameter. As per the original design, the host, say, the ModernPage in this case, should call
// the ClientSideWebPartManager.loadWebPart API with "displayMode == Edit" value. But that is not
// the case. The ModernPage calls loadWebPart with "displayMode == Read" and then calls
// ClientSideWebPartManager.setDisplayMode(displayMode == Edit). This opens the door for race condition
// bugs to occur. Especially as the web part loading lifecycle is becoming more complex. To avoid these
// race conditions from happening we need to to make sure all the first time rendering promises are
// resolved before this._renderWithAccessibleTitle can be called.
Promise.all(this._firstTimeRenderPromises)
.then(function () { return _this._renderWithAccessibleTitle(); })
.catch(function (e) { return sp_diagnostics_1._TraceLogger.logVerboseData({ source: _this._logSource, message: e.message }); });
};
/**
* This API should be used to refresh the contents of the PropertyPane.
*
* @remarks
* This API is called at the end of the web part lifecycle on a page. It should be used to dispose any local
* resources (i.e. DOM elements) that the web part is holding onto. This API is expected to be called in scenarios
* like page navigation i.e. the host is transitioning from one page to another and disposes the page that is being
* transitioned out.
*
* @virtual
*/
BaseClientSideWebPart.prototype.onDispose = function () {
/* EMPTY BLOCK */
};
/**
* This API is invoked when the web part container dom element width is changed, e.g. when the browser
* browser window is resized and when the property pane is toggled open/closed.
*
* @param newWidth - Width (in pixels) of the container for the web part after the resize event.
* @remarks
* Web parts should utilize this method to perform operations such as potentially re-rendering components
* based on the new available width for the web part.
*
* @virtual
*/
BaseClientSideWebPart.prototype.onAfterResize = function (newWidth) {
/* EMPTY BLOCK */
};
/**
* This API is called when a theme is initialized or changed on the page or for the current section.
* @param theme - New theme for the page or section
* @remarks
* Developers sould not call render in overridden method. It can lead to unpredicted re-flow of the web part.
* render will be called from the base class when needed.
*
* @virtual
*/
BaseClientSideWebPart.prototype.onThemeChanged = function (theme) {
/* EMPTY BLOCK */
};
/**
* This API should be used to render an error message in the web part display area. Also logs the error message
* using the trace logger.
*
* @param error - An error object containing the error message to render.
*/
BaseClientSideWebPart.prototype.renderError = function (error) {
this.context.statusRenderer.clearLoadingIndicator(this.domElement);
this.context.statusRenderer.renderError(this.domElement, error);
if (this.displayMode === sp_core_library_1.DisplayMode.Edit &&
!!this.context.manifest.isInternal &&
!!this.context.serviceScope &&
((0, KillSwitches_1.isHandleDisposeRaceConditionKSActive)() || !this.isDisposed)) {
var err = '';
if (!(0, KillSwitches_1.isAddMoreRenderErrorInfoKSActivated)()) {
if (error.name) {
err += 'name:' + error.name + ';';
}
if (error.message) {
err += 'msg:' + error.message + ';';
}
if (this.context && this.context.webPartTag) {
err += 'webPT:' + this.context.webPartTag + ';';
}
if (this.iconImageUrl) {
err += 'iconImageUrl:' + this.iconImageUrl + ';';
}
if (this.title) {
err += 'title:' + this.title + ';';
}
if (this.previewImageUrl) {
err += 'previewImageUrl:' + this.previewImageUrl + ';';
}
if (this.context &&
this.context.pageContext &&
this.context.pageContext.web &&
this.context.pageContext.web.absoluteUrl) {
err += 'absUrl:' + this.context.pageContext.web.absoluteUrl + ';';
}
}
else {
err = error.message;
}
var errorDetails = {
errorCode: "WebPartBase ".concat(this.context.manifest.alias, " Failure"),
errorMessage: err,
errorScenario: 'Render',
errorStack: error === null || error === void 0 ? void 0 : error.stack,
veto: 'WebPart Render Failure'
};
(0, sp_edit_customer_promise_1._logFailuresForEditCustomerPromise)(errorDetails, this.context.serviceScope);
}
sp_diagnostics_1._TraceLogger.logError(this._logSource, error);
};
/**
* This API should be used to clear the error message from the web part display area.
*/
BaseClientSideWebPart.prototype.clearError = function () {
this.context.statusRenderer.clearError(this.domElement);
};
/**
* Internal API to trigger a refresh to the WebPart's visual rendition.
* In this implementation of the BaseWebPart class we call the render API.
*
* @internal
*/
BaseClientSideWebPart.prototype._refresh = function () {
this._renderWithAccessibleTitle();
};
/**
* Internal API triggered by a dynamic property's callback.
* In this implementation of the BaseWebPart class we call the render API, only if rendered once.
*
* @internal
*/
BaseClientSideWebPart.prototype._dynamicPropertyRefresh = function () {
if (this.renderedOnce) {
this.render();
}
};
/**
* Waits for all render promises to resolve before disposing.
*/
BaseClientSideWebPart.prototype._disposeAfterRenderPromises = function () {
var _this = this;
if (!this.isDisposed &&
!(0, KillSwitches_1.isChainDisposeCallsAfterOninitKSActivated)() &&
(0, Flights_1.isWEXWebPartOnDisposePromiseChainEnabled)()) {
this._internalIsDisposing = true;
// VSO: 1268748
// wait for rendering to complete before disposing this component as this would put the application
// in a bad state since (this.context) is deleted in the super.dispose method.
// Note: this logic mirrors what we do in onDisplayModeChanged with more safe guards
Promise.all(this._firstTimeRenderPromises).then(function () {
_this._internalIsDisposing = false;
_super.prototype._internalDispose.call(_this);
}, function (_a) {
var message = _a.message;
sp_diagnostics_1._TraceLogger.logVerboseData({ source: _this._logSource, message: message });
// if the render promises fails then bail and just dispose
_this._internalIsDisposing = false;
_super.prototype._internalDispose.call(_this);
});
}
else {
_super.prototype._internalDispose.call(this);
}
};
/**
* @returns extends base width cache key with additional info to minimize reflows.
* Otherwise if base cache key does not exist return undefined.
* @internal
*/
BaseClientSideWebPart.prototype._getExtendedWidthCacheKey = function () {
var baseKey = this.context.widthCacheKey;
return baseKey ? "".concat(this.displayMode, "-").concat(baseKey) : undefined;
};
/**
* The actual initialization and rendering of the Web part starts when it is close enough
* to the Viewport
*/
BaseClientSideWebPart.prototype._onInViewport = function () {
var _this = this;
// Render promise callback should be defined at this time.
if (!this._renderPromiseResolver || !this._renderPromiseRejecter) {
throw SPWebPartError_1.SPWebPartError.create(SPWebPartError_1.SPWebPartErrorCode.RenderPromiseUndefined, this.context.webPartTag);
}
// Perform web part initialization and then render the web part.
var initPromise = this.onInit();
if (!initPromise) {
var error = SPWebPartError_1.SPWebPartError.create(SPWebPartError_1.SPWebPartErrorCode.OnInitReturnedNullPromise, this.context.webPartTag);
this._renderPromiseRejecter(error);
this._clearRenderPromises();
return;
}
this._firstTimeRenderPromises.push(initPromise);
initPromise
.then(function () {
sp_telemetry_1._PerformanceLogger.markComponent(_this.context.webPartTag, 'init');
var getDataPromise = Promise.resolve();
// Perform web part initialization and then render the web part.
getDataPromise = _this._internalGetData();
if (!getDataPromise) {
throw SPWebPartError_1.SPWebPartError.create(SPWebPartError_1.SPWebPartErrorCode.GetDataReturnedNullPromise, _this.context.webPartTag);
}
_this._firstTimeRenderPromises.push(getDataPromise);
var renderPromise = getDataPromise.then(function () {
sp_telemetry_1._PerformanceLogger.markComponent(_this.context.webPartTag, 'getDataComplete');
// Clear the loading indicator
_this.context.statusRenderer.clearLoadingIndicator(_this.domElement);
if (_this.isRenderAsync) {
_this._startAsyncRenderGuardTimer();
}
_this._renderWithAccessibleTitle();
// Record the time framework has finished calling render(). By this time framework is accountable
// for loading web part module through fasted CDN and loading web part data through appropriate
// techniques like Web part cache and synchronous time to execute web part's render() method.
sp_telemetry_1._PerformanceLogger.markComponent(_this.context.webPartTag, 'syncRender');
if (!(0, KillSwitches_1.isIsolatedACEWPRenderAsyncKSActivated)() && _this.isRenderAsync) {
_this._syncRenderTime = sp_telemetry_1._PerformanceLogger.now();
}
else {
// If rendering happened synchronously, simply complete the rendering cycle.
// Else, create a new promise and wait for it to be resolved. The resolution
// can happen when the web part completes the promise or when the timeout fires.
_this._resolveOrRejectOnRenderPromise();
}
});
return renderPromise;
})
.catch(function (e) {
if (_this._renderPromiseRejecter) {
_this._renderPromiseRejecter(e);
_this._clearRenderPromises();
}
});
};
/**
* Wraps render to ensure any type of rendering has access to the latest context
* to provide the most accurate accessible info to screen readers.
*/
BaseClientSideWebPart.prototype._renderWithAccessibleTitle = function () {
sp_telemetry_1._PerformanceLogger.devMark("webpart(".concat(this.context.webPartTag, ")._renderWithAccessibleTitle"));
var accessibleRoot = (0, KillSwitches_1.isAccessibleRootKSActivated)()
? this.domElement
: this.domElement.parentElement;
this.render();
// The accessible label is only required in edit mode. It is also not required for mobile devices
// which only provide view mode
if (this.displayMode === sp_core_library_1.DisplayMode.Edit) {
// Render the accessible description after and associate by ID to avoid re-rendering the whole zone
// when webpart updates contextual info.
var accessibleContext = this.accessibleTitle || this._getDefaultAccessibleTitle();
if (accessibleContext) {
// Keep ID in sync with ControlZone.render
var contextualLabelId = "cswpAccessibleLabelContextual_".concat(this.context.instanceId);
var accessibleDiv = accessibleRoot.querySelector("#".concat(contextualLabelId));
var isNewLabelElement = !accessibleDiv;
if (isNewLabelElement) {
accessibleDiv = document.createElement('div');
accessibleDiv.id = contextualLabelId;
accessibleDiv.className = cswp_base_module_scss_1.default.screenReaderOnly;
accessibleDiv.setAttribute('aria-hidden', 'true');
}
accessibleDiv.textContent = accessibleContext;
if (isNewLabelElement) {
accessibleRoot.appendChild(accessibleDiv);
}
}
// Perform classic page fixup. It should only be called in edit mode otherwise it will
// make anchor elements not working in view mode.
ClassicPageUtils_1.default.disableAutomaticPostbacks(this.domElement, sp_core_library_1.Environment.type);
}
};
/**
* Start async guard timer. This timer is to help avoid losing performance markers for a web part
* that renders asynchronously but does not call the `renderCompleted` API;
*/
BaseClientSideWebPart.prototype._startAsyncRenderGuardTimer = function () {
var _this = this;
// Note: the timer is 25 seconds because after 30 seconds, the PerformanceLogger will auto expire
// the log timer and we will lose data. This value needs to be smaller than that.
this._clearAsyncRenderGuardTimer();
this._asyncRenderGuardTimer = window.setTimeout(function () {
_this._asyncRenderTimeout();
}, 25000);
if (!(0, KillSwitches_1.isAsyncCompleteKSActivated)() && this._asyncRenderCompleteCalled === true) {
// Now we can process this render complete.
this._renderCompleted(this._asyncRenderCompleteDidUpdate);
this._asyncRenderCompleteCalled = false;
this._asyncRenderCompleteDidUpdate = undefined;
}
};
/**
* Render completed.
*
* @param didUpdate - used to override end performance time with sync render time.
*/
BaseClientSideWebPart.prototype._renderCompleted = function (didUpdate) {
if (this._asyncRenderGuardTimer) {
this._clearAsyncRenderGuardTimer();
this._asyncRenderQosMonitor.writeSuccess({
alias: this.context.manifest.alias,
isInternal: this.context.manifest.isInternal,
webPartId: this.context.manifest.id
});
if (!(0, KillSwitches_1.isIsolatedACEWPRenderAsyncKSActivated)()) {
this._resolveOrRejectOnRenderPromise(undefined, didUpdate);
}
else {
this._resolveOrRejectOnRenderPromise();
}
}
else {
if (!(0, KillSwitches_1.isAsyncCompleteKSActivated)()) {
// We aren't quite ready to handle an async-render-complete, so note that
// it is done, and we will trigger it when we are ready.
this._asyncRenderCompleteCalled = true;
this._asyncRenderCompleteDidUpdate = didUpdate;
}
}
};
BaseClientSideWebPart.prototype._handleAsyncRenderFailed = function (error) {
if (this._asyncRenderGuardTimer) {
this._clearAsyncRenderGuardTimer();
this._logAsyncRenderError(error, 'Failed');
this._resolveOrRejectOnRenderPromise(error);
}
};
/**
* Async render timed out. Log error information and
*/
BaseClientSideWebPart.prototype._asyncRenderTimeout = function () {
// There is a potential race condition when the async guard timer gets queued into the javascript
// task queue right at the time when renderCompleted API gets called. Protect against that.
if (this._asyncRenderGuardTimer) {
this._clearAsyncRenderGuardTimer();
// At this time we only log an error and fail the QOS monitor when the async guard timer fires.
var error = SPWebPartError_1.SPWebPartError.create(SPWebPartError_1.SPWebPartErrorCode.RenderCompletedCallNotCalled, this.context.webPartTag);
this._logAsyncRenderError(error, 'Timeout');
this._resolveOrRejectOnRenderPromise();
}
};
BaseClientSideWebPart.prototype._logAsyncRenderError = function (error, qosFailureTag) {
sp_diagnostics_1._TraceLogger.logErrorData({
source: this._logSource,
error: error,
serviceScope: this.context.serviceScope
});
this._asyncRenderQosMonitor.writeUnexpectedFailure(qosFailureTag, error, {
alias: this.context.manifest.alias,
isInternal: this.context.manifest.isInternal,
webPartId: this.context.manifest.id,
instanceId: this.instanceId
});
};
BaseClientSideWebPart.prototype._clearAsyncRenderGuardTimer = function () {
if (this._asyncRenderGuardTimer) {
window.clearTimeout(this._asyncRenderGuardTimer);
this._asyncRenderGuardTimer = undefined;
}
};
/**
* This is called for every web part whether sync or async once rendering is completed.
*
* @param error - error object indicating asycn render has completed with an error
* @param didUpdate - used to override end performance time with sync render time.
*/
BaseClientSideWebPart.prototype._resolveOrRejectOnRenderPromise = function (error, didUpdate) {
this._renderedOnce = true;
sp_telemetry_1._PerformanceLogger.devMark("webpart(".concat(this.context.webPartTag, ").complete"));
if (error) {
if (this._renderPromiseRejecter) {
this._renderPromiseRejecter(error);
}
}
else {
if (this._renderPromiseResolver) {
this._renderPromiseResolver((0, KillSwitches_1.isIsolatedACEWPRenderAsyncKSActivated)() || didUpdate
? sp_telemetry_1._PerformanceLogger.now()
: this._syncRenderTime);
}
}
this._clearRenderPromises();
};
BaseClientSideWebPart.prototype._clearRenderPromises = function () {
this._renderPromiseResolver = undefined;
this._renderPromiseRejecter = undefined;
// Reset minHeight
this.domElement.style.minHeight = null;
};
BaseClientSideWebPart.prototype._internalHandleThemeChangedEvent = function (args) {
this._internalThemeVariant = args.theme;
this.onThemeChanged(this._internalThemeVariant);
//
// we call render only if the onThemeChanged was overridden in a child class
//
if (this.onThemeChanged !== BaseClientSideWebPart.prototype.onThemeChanged) {
this.render();
}
};
return BaseClientSideWebPart;
}(BaseWebPart_1.default));
exports.default = BaseClientSideWebPart;
//# sourceMappingURL=BaseClientSideWebPart.js.map