'use strict'; function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } /** * Licensed Materials - Property of IBM * IBM Cognos Products: BI Cloud (C) Copyright IBM Corp. 2013, 2019 * US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp. * * VisRenderState * The VisRenderState represents the current state of rendering for a visualization. * Rendering involves loading all the requirements to render, then calling the view's render method. * */ define(['underscore'], function (_) { return function () { function VisRenderState() { _classCallCheck(this, VisRenderState); /** * _currentContext is a structure representing the current state of the render sequence. * Each member of the currentContext represents a 'step of the renderSequence which points * to various renderContexts that are responsible for those steps. */ this._currentContext = {}; /** * The render context pool holds the set of 'active renderContexts' that store portions * of the data needed to render a visualization. These are cleaned up when no longer * part of the active render context. * * The renderContextPool is keyed by id which is currently a serial number (_renderId) for ease of debuggins * (but could be any unique number). */ this._renderContextPool = {}; //Data Members... this.firstRenderComplete = false; this.lastSizeRendered = null; this._steps = []; } VisRenderState.prototype.remove = function remove() { this.resetRenderState(); }; VisRenderState.prototype.initCurrentContext = function initCurrentContext(stepName) { if (!this._currentContext.hasOwnProperty(this._stepToStepContext(stepName))) { this._steps.push(stepName); this._currentContext[this._stepToStepContext(stepName)] = null; } }; /** * Given a step name (like 'visView', 'visControl', 'data') return the * current rendering context of that step. * @returns a RenderContext object that is responsible for that step in the render sequence. * (or that portion of the renderState's currentContext) */ VisRenderState.prototype.getCurrentContext = function getCurrentContext(stepName) { return this._currentContext[this._stepToStepContext(stepName)]; }; // Main accessor // return elements of the renderStates' current context to callers. VisRenderState.prototype.getCurrentContextData = function getCurrentContextData(stepName) { return this._currentContext[this._stepToStepContext(stepName)] ? this._currentContext[this._stepToStepContext(stepName)][stepName] : null; }; /** * Add a new render context which flows through the renderSequence collecting the parts of the render it is responsible for. * These parts are defined by the options. * If a renderContext completes and all parts are loaded, the visualization can render. * * @param options Information about what should be refreshed when running through the renderSequence. * (also is 'the steps this renderContext is responsible for') * @param {integer} options.renderId - the run id for this context * Examples: * a resize would use pass no options <= which denotes reRender without refreshing any data. * a filter change would use options { refresh: { data: true }}, * a visualization type change where the renderer type stays the same would use { refresh: { visSpec: true } } * Initial render (or changing renderers) would pass { refreshAll: true } meaning all data needs to be loaded. * * @returns a new RenderContext. * @throws Exception when options.renderId is not defined */ VisRenderState.prototype.addRenderContext = function addRenderContext(options) { if (_.isUndefined(options) || _.isUndefined(options.renderId)) { throw new Error('cannot define a render context: missing renderId'); } var renderContext = { id: options.renderId }; _.each(this._steps, function (step) { renderContext[step] = null; }); if (_.keys(options).length > 1) { renderContext.extraInfo = options.extraInfo; if (this._currentContext.dataContext && options.extraInfo && options.extraInfo.sender === 'realtimeRefresh') { // If we are in realtime refresh mode, the data request might return nothing if the data didn't change. // We need to keep the data the same in case renderContext.previousData = this._currentContext.dataContext.data; } } renderContext.resizing = options && options.resizing ? true : false; this._renderContextPool[renderContext.id] = renderContext; if (_.keys(options).length > 1) { if (options.refresh && options.refresh.data && !this.readyToLoadData()) { options.refreshAll = true; } if (options.refresh) { options.refresh.render = true; } else { // For anything else, ensure to do the main render options.refresh = { render: true }; } renderContext.refresh = options.refresh; renderContext.refreshAll = options.refreshAll; if (options.refreshAll) { //Initialize ALL of the _currentContext to point to this renderContext. this.reloadAllRenderSteps(); //Clear the loaded steps in the render sequence. _.each(_.keys(this._currentContext), function (key) { this._currentContext[key] = renderContext; }.bind(this)); } else if (options.refresh) { //Initialize the portions of the _currentContext to be refreshed. _.each(_.keys(options.refresh), function (stepName) { this._currentContext[this._stepToStepContext(stepName)] = renderContext; }.bind(this)); //If calling re-render, at a minumum, we need to ensure the view is loaded. if (!this._currentContext.visViewContext) { this._currentContext.visViewContext = renderContext; } } } return renderContext; }; /** * @returns true when all steps of the renderStates' current context prior to loading data are complete (initialized). */ VisRenderState.prototype.readyToLoadData = function readyToLoadData() { return !!(this.getCurrentContextData('visView') && this.getCurrentContextData('visControl')); }; /** * @returns true when all steps of the renderStates' current context are complete (initialized). */ VisRenderState.prototype.readyToRender = function readyToRender() { return !!(this.getCurrentContextData('visView') && this.getCurrentContextData('visControl') && this.getCurrentContextData('data')); }; /** * Reset the current context and context Renderer pools back to their initial state. */ VisRenderState.prototype.resetRenderState = function resetRenderState() { this.lastSizeRendered = null; this._clearCurrentContext(); this.cleanRenderContextPool( /*removeAll*/true); }; /** * @return true if 'thisRenderContext' is obsolete. * (ie: no longer being used by any step in the _current context.) */ VisRenderState.prototype._renderContextUnused = function _renderContextUnused(thisRenderContext) { var thisRenderContextFound = _.find(_.keys(this._currentContext), function (step) { return this._currentContext[step] === thisRenderContext; }.bind(this)); //Don't delete a render context if any step in the render sequence is still using it. if (thisRenderContextFound) { return false; } //If no steps use this context, still shouldn't delete a render context until it is complete (ie: view render has/has not been called).. return thisRenderContext.renderComplete ? true : false; }; /** * Remove unused (or all) entries from the RenderContextPool. * @param removeAll - when true removes all entries...otherwise, checks if the element is used. */ VisRenderState.prototype.cleanRenderContextPool = function cleanRenderContextPool(removeAll) { _.each(_.keys(this._renderContextPool), function (key) { var renderContext = this._renderContextPool[key]; if (removeAll || this._renderContextUnused(renderContext)) { delete this._renderContextPool[key]; } }.bind(this)); }; /** * Remove all backing data from the currentContext. */ VisRenderState.prototype._clearCurrentContext = function _clearCurrentContext() { if (this.getCurrentContextData('visView')) { this.getCurrentContextData('visView').remove(); } _.each(_.keys(this._currentContext), function (key) { this._currentContext[key] = null; }.bind(this)); }; /** * Force a reload of all rendering steps without removing the RenderInfo assignments. * This is done when the renderer changes...or for any reason a full render is being done. */ VisRenderState.prototype.reloadAllRenderSteps = function reloadAllRenderSteps() { if (this.getCurrentContextData('visView')) { this.getCurrentContextData('visView').remove( /*finalRemove*/false); } _.each(_.keys(this._currentContext), function (stepContext) { //Set the data element within each context step //whose name matches the key without 'Context' //For example visViewContext.visView, visControlContext.visControl, dataContext.data. var step = this._stepContextToStep(stepContext); if (this._currentContext[stepContext] && this._currentContext[stepContext][step]) { this._currentContext[stepContext][step] = null; } }.bind(this)); }; /** * @returns The fully populated renderContext that is active for a particular render. * For example: a particular render might have "refresh: render" defined so other contexts would be null in the render context. * But there is an active data context from a previous render. This would populate that value and all previous render values. */ VisRenderState.prototype.getFullRenderContext = function getFullRenderContext() { var fullRenderContext = {}; for (var stepContext in this._currentContext) { //Set the data element within each context step whose name matches the stepContext name. var step = this._stepContextToStep(stepContext); fullRenderContext[step] = this._currentContext[stepContext] && this._currentContext[stepContext][step] || null; } return fullRenderContext; }; //Helper function to convert a stepName (like 'data' into a stepContextName like 'dataContext') //TODO: Do we really have to make these different? VisRenderState.prototype._stepToStepContext = function _stepToStepContext(stepName) { return stepName + 'Context'; }; //Helper function to convert a contextName (like 'dataContext' into a stepName like 'data') //TODO: Do we really have to make these different? VisRenderState.prototype._stepContextToStep = function _stepContextToStep(contextName) { return contextName.substring(0, contextName.length - 7); }; return VisRenderState; }(); }); //# sourceMappingURL=VisRenderState.js.map