@microsoft/sp-webpart-base
Version:
SharePoint Framework support for building web parts
293 lines • 15.5 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
var sp_component_base_1 = require("@microsoft/sp-component-base");
var sp_telemetry_1 = require("@msinternal/sp-telemetry");
var sp_core_library_1 = require("@microsoft/sp-core-library");
var Strings_resx_1 = tslib_1.__importDefault(require("./loc/Strings.resx"));
var ErrorMessage_1 = tslib_1.__importDefault(require("./ErrorMessage"));
var FriendlyErrorMessage_1 = tslib_1.__importDefault(require("./FriendlyErrorMessage"));
var ClassicPageUtils_1 = tslib_1.__importDefault(require("./classicPages/ClassicPageUtils"));
var SpinnerFactory_1 = tslib_1.__importDefault(require("./SpinnerFactory"));
/**
* This class provides the default implementation for displaying loading indicator and error messages
* for web parts. The web part host can decide to provide custom implementation of how web parts display
* loading indicators and error messages.
*
* @internal
*/
var ClientSideWebPartStatusRenderer = /** @class */ (function () {
function ClientSideWebPartStatusRenderer() {
this._errorId = 'cswp-error';
this._activeIndicatorCache = new Map();
}
/**
* Returns additional time out before showing the spinner
*
* loadingDelayed - Time when asked Viewport loader to check and load web part post module load.
* inViewportLoaded - Time when web part was allowed to load by viewport loader.
*
* 1. If both loadingDelayed and inViewportLoaded are defined return the ViewportWait,
* difference between them would reflect total time in the waiting queue
* (i.e, inViewportLoaded - loadingDelayed).
* 2. If only loadingDelayed is defined (i.e, the rendering of the webpart is still in the queue)
* return a timeout of 500ms.
* 3. If both loadingDelayed and inViewportLoaded are undefined return 0 (i.e, let the things be as they are).
*
* @param webPartTag - event identifier used in written telemetry data for first party web
* parts, e.g., 'WebPart.NewsWebPart.8dd9dec2-c6b3-4d4a-819e-2a5431e901f2'.
*/
ClientSideWebPartStatusRenderer._getAdditionalTimeOut = function (webPartTag) {
var loadingDelayed = sp_telemetry_1._PerformanceLogger.readComponentBreakdown(webPartTag, 'loadingDelayed');
var inViewportLoaded = sp_telemetry_1._PerformanceLogger.readComponentBreakdown(webPartTag, 'inViewPortLoading');
var timeout = 0;
if (loadingDelayed && inViewportLoaded) {
timeout = inViewportLoaded - loadingDelayed;
}
else if (loadingDelayed) {
timeout = 500;
}
else {
timeout = 0;
}
return timeout;
};
/**
* Display a loading spinner.
*
* @param domElement - the web part container div.
* @param loadingMessage - the message to be displayed when the loading spinner id displayed.
* @param timeout - (optional) timeout to render the loading indicator. Default is 1500ms.
*
* @privateRemarks
* First-party web parts should use _displayLoadingIndicator to log perf data.
*/
ClientSideWebPartStatusRenderer.prototype.displayLoadingIndicator = function (domElement, loadingMessage, timeout, clearDomElementCallback) {
this._logEngagement(domElement, 'displayLoadingIndicator');
this._createLoadingIndicator(domElement, loadingMessage, timeout, undefined, undefined, undefined, clearDomElementCallback);
};
/**
* Display a loading indicator.
*
* @param domElement - the web part container div.
* @param loadingMessage - the message to be displayed when the loading indicator id displayed.
* @param performanceLogEventName - event identifier used in written telemetry data for first party web
* parts, e.g., 'WebPart.NewsWebPart.8dd9dec2-c6b3-4d4a-819e-2a5431e901f2'.
* @param reservedHeight - reserved height
* @param isInternal - flag to indicate if web part is internal or external.
* @param timeout - (optional) timeout to render the loading indicator. Default is 1500ms.
* @param clearDomElementCallback - (optional) callback to clear the dom element.
* @param useShimmer - (optional) flag to indicate if shimmer should be used.
*
* @internal
*/
ClientSideWebPartStatusRenderer.prototype._displayLoadingIndicator = function (domElement, loadingMessage, performanceLogEventName, reservedHeight, isInternal, timeout, clearDomElementCallback, useShimmer) {
this._createLoadingIndicator(domElement, loadingMessage, reservedHeight, timeout, performanceLogEventName, isInternal, clearDomElementCallback, useShimmer);
};
/**
* Clear the loading indicator.
*
* @param domElement - the web part container div.
*/
ClientSideWebPartStatusRenderer.prototype.clearLoadingIndicator = function (domElement) {
sp_core_library_1.Validate.isNotNullOrUndefined(domElement, 'domElement');
if (this._activeIndicatorCache.has(domElement)) {
var cacheEntry = this._getCacheEntry(domElement);
if (cacheEntry.loadingTimer) {
window.clearTimeout(cacheEntry.loadingTimer);
}
if (cacheEntry.placeholder) {
// This is needed because some web parts (e.g. Yammer web part) render within the onInit() phase
if (cacheEntry.placeholder.parentElement) {
cacheEntry.placeholder.parentElement.removeChild(cacheEntry.placeholder);
}
}
this._activeIndicatorCache.delete(domElement);
}
};
ClientSideWebPartStatusRenderer.prototype.renderError = function (domElement, error, options) {
if (typeof options === 'function') {
options = { clearDomElementCallback: options };
}
this._renderError(domElement, error, options);
};
/**
* Clear the web part error message.
* @param domElement - the web part container div.
*/
ClientSideWebPartStatusRenderer.prototype.clearError = function (domElement) {
sp_core_library_1.Validate.isNotNullOrUndefined(domElement, 'domElement');
if (!this._activeIndicatorCache.has(domElement)) {
return;
}
var cacheEntry = this._activeIndicatorCache.get(domElement);
if (cacheEntry && cacheEntry.isErrorBeingRendered) {
cacheEntry.isErrorBeingRendered = false;
var divErr = domElement.querySelector("div[data-sp-id='".concat(this._errorId, "']"));
if (divErr) {
divErr.style.display = 'none';
divErr.removeAttribute('data-automation-id');
}
}
};
ClientSideWebPartStatusRenderer.prototype._createLoadingIndicator = function (domElement, loadingMessage, reservedHeight, timeout, performanceLogEventName, isInternal, clearDomElementCallback, useShimmer) {
var _this = this;
sp_core_library_1.Validate.isNotNullOrUndefined(domElement, 'domElement');
if (!timeout || (timeout && isNaN(timeout))) {
timeout = 1500; // milliseconds
}
// In most cases, we do not want to display the loading indicator immediately. We want to delay the
// display of loading indicator to the point when the user will start noticing the slowness in the UI.
var cacheEntry = this._getCacheEntry(domElement);
// Clear if any earlier loading timer
if (cacheEntry.loadingTimer) {
window.clearTimeout(cacheEntry.loadingTimer);
}
cacheEntry.loadingTimer = window.setTimeout(function () {
if (performanceLogEventName && isInternal) {
var additionalTimeOut = ClientSideWebPartStatusRenderer._getAdditionalTimeOut(performanceLogEventName);
cacheEntry.loadingTimer = window.setTimeout(function () {
_this._showLoadingIndicator(domElement, loadingMessage, reservedHeight, performanceLogEventName, isInternal, clearDomElementCallback, useShimmer);
}, additionalTimeOut);
}
else {
_this._showLoadingIndicator(domElement, loadingMessage, reservedHeight, performanceLogEventName, isInternal, clearDomElementCallback, useShimmer);
}
}, timeout);
};
ClientSideWebPartStatusRenderer.prototype._renderError = function (domElement, error, options) {
var _a = options || {}, message = _a.message, clearDomElementCallback = _a.clearDomElementCallback;
sp_core_library_1.Validate.isNotNullOrUndefined(domElement, 'domElement');
sp_core_library_1.Validate.isNotNullOrUndefined(error, 'error');
this._logEngagement(domElement, 'renderError');
var errorText = '';
var newLineSeparator = '\r\n';
var extraMessage = message ? newLineSeparator + newLineSeparator + message : '';
if (error instanceof sp_core_library_1.SPError) {
errorText = error.toStringForUI();
errorText += extraMessage;
}
else {
var vanillaError = error;
var stack = vanillaError.stack;
var callStack = stack
? sp_core_library_1.Text.format(Strings_resx_1.default.WebpartErrorCallStackText, newLineSeparator, stack)
: '';
errorText = sp_core_library_1.Text.format(Strings_resx_1.default.WebpartErrorErrorText, newLineSeparator, "".concat(vanillaError.message || error), callStack, extraMessage);
}
var cacheEntry = this._getCacheEntry(domElement);
cacheEntry.isErrorBeingRendered = true;
var errorComponent;
if (!DEBUG) {
errorComponent = new FriendlyErrorMessage_1.default({ errorMessage: errorText }).render();
}
else {
errorComponent = new ErrorMessage_1.default({ errorMessage: errorText }).render();
}
var divErr = domElement.querySelector("div[data-sp-id='".concat(this._errorId, "']"));
if (divErr) {
divErr.style.display = 'block';
}
else {
divErr = document.createElement('div');
divErr.setAttribute('data-sp-id', this._errorId);
if (clearDomElementCallback) {
clearDomElementCallback(domElement);
}
this._clearChildren(domElement);
domElement.appendChild(divErr);
ClassicPageUtils_1.default.disableAutomaticPostbacks(domElement, sp_core_library_1.Environment.type);
}
// clearError removes the data-automation-id
divErr.setAttribute('data-automation-id', 'webPartError');
divErr.innerHTML = '';
divErr.appendChild(errorComponent);
};
/**
* Show the loading indicator
*
* @param domElement - the web part container div.
* @param loadingMessage - the message to be displayed when the loading Indicator id displayed.
* @param reservedHeight - the height of the loading indicator.
* @param performanceLogEventName - event identifier used in written telemetry data for first party web
* parts, e.g., 'WebPart.NewsWebPart.8dd9dec2-c6b3-4d4a-819e-2a5431e901f2'.
*/
ClientSideWebPartStatusRenderer.prototype._showLoadingIndicator = function (domElement, loadingMessage, reservedHeight, performanceLogEventName, isInternal, clearDomElementCallback, useShimmer) {
if (performanceLogEventName && isInternal) {
sp_telemetry_1._PerformanceLogger.markComponent(performanceLogEventName, 'displaySpinner');
}
// This would set style of the loading Indicator and display it.
this._renderLoadingIndicator(domElement, loadingMessage, reservedHeight, performanceLogEventName, clearDomElementCallback, useShimmer);
};
ClientSideWebPartStatusRenderer.prototype._renderLoadingIndicator = function (domElement, loadingMessage, reservedHeight, performanceLogEventName, clearDomElementCallback, useShimmer) {
if (!this._activeIndicatorCache.has(domElement)) {
return;
}
var cacheEntry = this._getCacheEntry(domElement);
// Error is being rendered, don't render loading indicator
if (cacheEntry.isErrorBeingRendered) {
return;
}
cacheEntry.placeholder = this._createLoadingIndicatorElement(domElement, loadingMessage, reservedHeight, performanceLogEventName, clearDomElementCallback, useShimmer);
};
ClientSideWebPartStatusRenderer.prototype._getCacheEntry = function (domElement) {
if (this._activeIndicatorCache.has(domElement)) {
return this._activeIndicatorCache.get(domElement);
}
var cacheEntry = {
loadingTimer: undefined,
placeholder: undefined,
isErrorBeingRendered: false
};
this._activeIndicatorCache.set(domElement, cacheEntry);
return cacheEntry;
};
ClientSideWebPartStatusRenderer.prototype._createLoadingIndicatorElement = function (domElement, loadingMessage, reservedHeight, performanceLogEventName, clearDomElementCallback, useShimmer) {
if (clearDomElementCallback) {
clearDomElementCallback(domElement);
}
this._clearChildren(domElement);
var titleMessage = sp_core_library_1.Text.format(Strings_resx_1.default.LoadingStatus, loadingMessage);
var loadingIndicatorContainerDiv = performanceLogEventName || useShimmer
? sp_component_base_1._ShimmerFactory.createShimmer(domElement.clientWidth, reservedHeight, performanceLogEventName, titleMessage)
: this._createSpinnerElement(titleMessage, reservedHeight);
loadingIndicatorContainerDiv.style.display = 'block';
return domElement.appendChild(loadingIndicatorContainerDiv);
};
ClientSideWebPartStatusRenderer.prototype._createSpinnerElement = function (titleMessage, reservedHeight) {
var spinnerElement = SpinnerFactory_1.default.createSpinner(titleMessage);
if (reservedHeight !== undefined) {
var parentElement = document.createElement('div');
parentElement.style.maxHeight = "".concat(reservedHeight, "px");
parentElement.appendChild(spinnerElement);
spinnerElement = parentElement;
}
return spinnerElement;
};
ClientSideWebPartStatusRenderer.prototype._clearChildren = function (element) {
// We need to ensure that there are no child nodes. This works for all browsers.
while (element.hasChildNodes()) {
if (element.lastChild) {
element.removeChild(element.lastChild);
}
}
};
ClientSideWebPartStatusRenderer.prototype._logEngagement = function (domElement, logFeature) {
var isWebPartRoot = false;
var spWebPartId = domElement.getAttribute('data-sp-web-part-id') || '';
if (spWebPartId) {
isWebPartRoot = true;
}
sp_telemetry_1._EngagementLogger.log({
name: "ClientSideWebPartStatusRenderer.".concat(logFeature),
isIntentional: true,
extraData: {
spWebPartId: spWebPartId,
isWebPartRoot: isWebPartRoot
}
});
};
return ClientSideWebPartStatusRenderer;
}());
exports.default = ClientSideWebPartStatusRenderer;
//# sourceMappingURL=ClientSideWebPartStatusRenderer.js.map