123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596 |
- 'use strict';
- /**
- * Licensed Materials - Property of IBM
- * IBM Cognos Products: BI Cloud (C) Copyright IBM Corp. 2014, 2020
- * US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
- *
- * @module dashboard/render/VisView
- * @see VisView
- */
- define(['jquery', 'underscore', 'doT', '../../lib/@waca/core-client/js/core-client/ui/core/View', './filter/FilterIndicator', './info/InfoIndicator', '../../widgets/livewidget/nls/StringResources', '../../lib/@waca/core-client/js/core-client/utils/Utils', './refreshtimer/RefreshTimerIndicator', 'text!./templates/EmptyVisualization.template', './forecastIndicator/ForecastIndicator', './VisTabs', '../../lib/@waca/core-client/js/core-client/utils/BrowserUtils', '../../widgets/livewidget/util/VisUtil', '../../lib/@waca/dashboard-common/dist/utils/MemUtil'], function ($, _, dot, View, FilterIndicator, InfoIndicator, StringResources, Utils, RefreshTimerIndicator, EmptyVisualizationTemplate, ForecastIndicator, VisTabs, BrowserUtils, VisUtil, MemUtil) {
- //Track sub-views created to help with cleanup
- var VisViewSubViews = ['filterIndicator', 'refreshTimerIndicator', 'conditionalViewIndicator', 'infoIndicator'];
- /**
- * VisView is the base class of all Visualization views
- * such as RaveView, GridView etc.
- */
- var VisView = View.extend({
- //The animation speed for all operations if no animation speed is set in properties.
- DEFAULT_ANIMATION_SPEED: 900,
- //The animation type (if none is set, default is currently to fadein).
- ANIMATION_TYPES: {
- NONE: 'none',
- DEFAULT: 'default',
- FADEIN: 'fadein',
- TRANSITION: 'transition',
- GROW: 'grow',
- REVEAL: 'reveal',
- BIGDATA: 'bigdata'
- },
- init: function init(options) {
- VisView.inherited('init', this, arguments);
- _.extend(this, arguments[0]);
- this.noRotate = true;
- this.isMaximizable = true;
- this.logger = options.logger;
- this.ownerWidget = options.ownerWidget;
- this.visualization = this.ownerWidget.getVisualizationApi();
- this.transactionApi = this.dashboardApi.getFeature('Transaction');
- this.internalVisDefinitions = this.dashboardApi.getFeature('VisDefinitions.internal');
- this.content = options.ownerWidget.content;
- this._processTemplateString();
- if (!options.proxiedView && !this._viewManagesOwnQuery()) {
- this._initIndicators();
- }
- this.visEl = this.el.firstChild ? this.el.firstChild : this.el;
- // create the visualization tabs (if supported)
- this.createTabs();
- //When set by an event handler (aka filter), this value controls the animation speed
- //for views that otherwise don't animate (but do support it).
- //If the definition already has animation, it will NOT override its value.
- this.overrideDefaultAnimationSpeed = -1;
- //This setting controls Non-VIPR visualizations allowing them to fade-in/fade-out during rendering.
- //VIPR visualizations use effects which are separate from this setting.
- //By default, Non-VIPR animation is off: (new for Endor) as it causes needless flashing and makes visualizaions appear slower.
- this.animationType = this.ANIMATION_TYPES.NONE;
- this.animationSpeed = this.DEFAULT_ANIMATION_SPEED;
- //The 'renderingNewData' state (maintained by the rendersequnce) is relevant in the context of the view's render() method.
- //It means that, for a particular view.render() call, new data is being rendered.
- this._renderingNewData = false;
- if (!options.proxiedView && !this._viewManagesOwnQuery()) {
- this.createView();
- }
- if (!options.proxiedView) {
- this._addPropertyHandler();
- }
- },
- createTabs: function createTabs() {
- var options = {};
- // reuse the existing DIV if already exists
- if (this.ownerWidget && this.ownerWidget.$el) {
- var $tabs = this.ownerWidget.$el.find('.visTabsView');
- options.el = $tabs.length ? $tabs[0] : null;
- }
- this._tabs = new VisTabs(options);
- // keep it hidden until render
- this._tabs.hide();
- },
- placeAt: function placeAt(element) {
- this.$el.prependTo(element); // insert view as the first element of the content container
- //if tab view exists, insert tabs as the first element
- if (this._tabs) {
- this._tabs.placeAt(element);
- }
- },
- setInExpandedMode: function setInExpandedMode() {
- var conditionalViewIndicator = this.content.getFeature('ConditionalViewIndicator');
- if (conditionalViewIndicator) {
- conditionalViewIndicator.setInExpandedMode();
- }
- },
- onRestore: function onRestore() {
- var conditionalViewIndicator = this.content.getFeature('ConditionalViewIndicator');
- if (conditionalViewIndicator) {
- conditionalViewIndicator.onRestore();
- }
- },
- /**
- * @returns if this specific view supports annotations. Returns false by default, expected to be overriden.
- */
- _doesViewSupportSmartAnnotations: function _doesViewSupportSmartAnnotations() {
- return false;
- },
- // to be implemented by chilren class
- doesVisPropertyMatchExpected: function doesVisPropertyMatchExpected() {
- return false;
- },
- // to be implemented by chilren class
- canApplyAutoBin: function canApplyAutoBin() {
- return false;
- },
- // to be implemented by chilren class
- getBinningConfig: function getBinningConfig() {
- return undefined;
- },
- /*
- * Reads the filter indicator config spec, and instantiates a filter indicator if applicable.
- */
- _initFilterIndicator: function _initFilterIndicator() {
- var filterSpec = this.getFilterIndicatorSpec();
- if (filterSpec && (filterSpec.localFilters || filterSpec.globalFilters || filterSpec.localTopBottoms || filterSpec.drillState)) {
- this.filterIndicator = new FilterIndicator(this.visModel, this.visualization, this.transactionApi, this.getController(), filterSpec, this.logger);
- this.ownerWidget.addIcon(this.filterIndicator.$filter, 'filterIcon');
- }
- },
- _initIndicators: function _initIndicators() {
- var _this = this;
- var visIndicators = this.content.getFeature('VisIndicators');
- if (visIndicators && this.ownerWidget && this.ownerWidget.$el) {
- this._initRefreshIndicator();
- this._initFilterIndicator();
- this._initInfoIndicator();
- this._initForecastingIndicator();
- var indicators = visIndicators.getIndicatorList();
- _.each(indicators, function (indicator) {
- _this.ownerWidget.addIcon(indicator.icon, indicator.name);
- });
- }
- },
- _initForecastingIndicator: function _initForecastingIndicator() {
- this.forecastIndicator = new ForecastIndicator({
- visModel: this.visModel,
- ownerWidget: this.ownerWidget,
- logger: this.logger,
- supportsForecasts: true,
- ownerView: this,
- visAPI: this.ownerWidget.visAPI,
- content: this.content
- });
- this.ownerWidget.addIcon(this.forecastIndicator.getIndicator(), 'forecastIcon');
- },
- _initInfoIndicator: function _initInfoIndicator() {
- this.infoIndicator = new InfoIndicator({
- visModel: this.visModel,
- ownerWidget: this.ownerWidget
- });
- this.ownerWidget.addIcon(this.infoIndicator.$el, 'infoIconDiv');
- },
- _initRefreshIndicator: function _initRefreshIndicator() {
- this.refreshTimerIndicator = new RefreshTimerIndicator(this.ownerWidget);
- this.ownerWidget.addIcon(this.refreshTimerIndicator.$icon, 'timerIcon');
- },
- /*
- * Indicates whether to render filter flyouts
- */
- getFilterIndicatorSpec: function getFilterIndicatorSpec() {
- return {
- localFilters: true,
- globalFilters: true,
- localTopbottoms: true,
- drillState: true
- };
- },
- getController: function getController() {
- return this.content && this.content.getFeature('InteractivityController.deprecated');
- },
- getSelector: function getSelector() {
- return this.content.getFeature('DataPointSelections.deprecated');
- },
- /*
- * Indicates whether to render topbottom flyouts. Unlike filter, topbottom only applys to the current viz there is no global
- */
- /**
- * Render Sequence - override this method when needed by a specific view type.
- * @returns promise - By default, views don't have controls....return a resolved promise with an empty object.
- */
- whenVisControlReady: function whenVisControlReady() {
- return this._noOpRenderStep('base class whenVisControlReady called!');
- },
- /**
- * Render Sequence - override this method when needed by a specific view type.
- * @returns promise - By default, views don't have visSpecs....return a resolved promise with an empty object.
- */
- whenVisSpecReady: function whenVisSpecReady() {
- return this._noOpRenderStep('base class whenVisSpecReady called!');
- },
- /**
- * @returns {boolean} true if this specific view supports annotations. Returns
- * false by default. Expected to be overriden
- */
- supportsAnnotations: function supportsAnnotations() {
- return false;
- },
- /**
- * @returns {boolean} true if this specific view supports annotations. Returns
- * false by default. Expected to be overriden
- */
- supportsForecasts: function supportsForecasts() {
- return false;
- },
- /**
- * Called before data is requested. Use this to clean up infoIndicator, etc.
- */
- preDataReady: function preDataReady() {
- // Reset any warnings/errors in the info indicator as we are starting fresh
- if (this.infoIndicator) {
- this.infoIndicator.clearMessagesWithIds(['visualization_notifications', 'moreDataIndicator', 'autobinSuggestion', 'data_notifications']);
- }
- },
- _hasMappedSlots: function _hasMappedSlots() {
- return this.visualization.getSlots().getMappedSlotList().length !== 0;
- },
- /**
- * Render Sequence - override this method when needed by a specific view type.
- * @returns promise - By default, make a query for the data and do not index the results (ie: RaveView is an exception).
- */
- whenDataReady: function whenDataReady(renderContext) {
- var _this2 = this;
- var result = void 0;
- // A resize event is forced when the layout base view is initialized. This may cause a request
- // to render the visualization before the visControl is created. Guard against this.
- if (this._hasMappedSlots() && this.canExecuteQuery() && !this.hasUnavailableMetadataColumns() && !this.hasMissingFilters()) {
- renderContext.isDevInstall = this.ownerWidget.getDashboardApi().isDevInstall;
- result = this._executeQueries(renderContext).then(function (retData) {
- _this2.dashboardApi.triggerDashboardEvent('synchronize:pageContextFilters', { synchDataFilterEntries: retData.synchDataFilterEntries });
- if (_this2.filterIndicator) {
- _this2.filterIndicator.setSynchronizeDataFilters(retData.synchDataFilterEntries);
- _this2.filterIndicator.update();
- }
- _this2._updateInfoIndicator(retData, renderContext);
- return {
- data: retData,
- sameQueryData: _this2.isSameQueryData(renderContext, retData)
- };
- });
- } else {
- result = Promise.resolve({
- data: {}
- });
- }
- return result;
- },
- _updateInfoIndicator: function _updateInfoIndicator(queryResults, renderContext) {
- var hasMoreData = void 0;
- var queryThreshold = void 0;
- var warnings = void 0;
- if (renderContext.useAPI) {
- var queryId = _.find(queryResults.getQueryResultIdList(), function (id) {
- return queryResults.getResult(id).hasMoreData();
- });
- hasMoreData = queryId !== undefined;
- queryThreshold = hasMoreData && queryResults.getResult(queryId).getRowCount();
- warnings = queryResults.getWarningList();
- } else {
- hasMoreData = queryResults.hasMoreData;
- queryThreshold = queryResults.queryThreshold;
- }
- if (this.infoIndicator) {
- var infoItems = [];
- // @todo: utilize the QueryResultsAPI.getWarningList
- if (hasMoreData) {
- // add data clipping
- if (queryThreshold) {
- infoItems.push({
- id: 'moreDataIndicator',
- label: StringResources.get('moreDataIndicator', { threshold: queryThreshold })
- });
- }
- // check auto-binning: 1) is it supported and 2) not already binned
- if (this.canApplyAutoBin() && !this.hasBinnedDataItems()) {
- infoItems.push({
- id: 'autobinSuggestion',
- label: StringResources.get('autobinSuggestion'),
- isSubMessage: true
- });
- }
- }
- if (warnings && warnings.length) {
- warnings.forEach(function (warning) {
- infoItems.push({
- id: warning.resourceId,
- label: StringResources.get(warning.resourceId, warning.params),
- isSubMessage: !!warning.isSubMessage
- });
- });
- }
- this.infoIndicator.addInfo([{
- id: 'data_notifications',
- label: StringResources.get('dataNotifications'),
- items: infoItems
- }]);
- }
- },
- _executeQueries: function _executeQueries(renderContext) {
- if (renderContext.useAPI) {
- var queryExecution = this.content.getFeature('DataQueryExecution');
- if (renderContext.extraInfo && renderContext.extraInfo.dataQueryParams) {
- queryExecution.addRequestOptions(renderContext.extraInfo.dataQueryParams);
- }
- return queryExecution.executeQueries();
- } else {
- return this.visModel.whenQueryResultsReady(renderContext);
- }
- },
- /**
- * Render Sequence - override this method when needed by a specific view type.
- * @returns {Promise}
- */
- whenSetDataReady: function whenSetDataReady() /* renderContext */{
- return Promise.resolve(true);
- },
- isSameQueryData: function isSameQueryData() {
- var renderContext = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
- var queryResult = arguments[1];
- // TODO clean logic when QueryAPI is live.
- if (renderContext.sameQueryData === undefined) {
- var currTag = queryResult && queryResult.getCacheValidateTag && queryResult.getCacheValidateTag();
- renderContext.sameQueryData = this._previousTag && this._previousTag === currTag;
- this._previousTag = currTag;
- }
- return !!(renderContext.sameQueryData || renderContext.extraInfo && renderContext.extraInfo.annotationRequest);
- },
- /* For Subclass to implement */
- updateInfoIndicator: function updateInfoIndicator(data) {
- if (this.infoIndicator) {
- this.infoIndicator.update(data);
- }
- },
- /**
- * The 'renderingNewData' state (maintained by the renderSequence) is relevant in the context of the view's render() method.
- * It means that, for a particular view.render() call, new data is being rendered.
- * (for example, typically, render following a resize would not be renderingNewData BUT,
- * If a resize occurs quickly after a render, 2 RenderSequence render() calls could result in one view:render() call
- * (effecively the 2 renders are "bundled into 1" from the perspective of the view so we are renderingNewData)
- * @param {boolean} flag - The renderingNewData value is maintained by the render sequence as follows:
- * true: when the data task has executed a query and has new data.
- * false: when the render task has completed a render
- */
- setRenderingNewData: function setRenderingNewData(flag) {
- this._renderingNewData = flag;
- },
- /**
- * @returns the state of the renderingNewData flag. This call makes sense in the context of a particular view.render().
- */
- getRenderingNewData: function getRenderingNewData() {
- return this._renderingNewData;
- },
- /**
- * @returns true if all of the required slots are mapped and this visualization can be rendered.
- */
- isMappingComplete: function isMappingComplete() {
- return this.visualization.getSlots().isMappingComplete();
- },
- /**
- * Determine whether the query can be executed.
- * Generally the query shall execute when all required mapping is complete.
- * However some applications may require to execute the query regardless of the slot mapping state.
- * The config should only affect the behaviour of the query and should have no impact on the actual render
- * of the visualization. The render should continue to render only when isMappingComplete is true.
- */
- canExecuteQuery: function canExecuteQuery() {
- return this.dashboardApi.getConfiguration('forceQuery') === true || this.isMappingComplete();
- },
- isRenderWithoutCompletingMapping: function isRenderWithoutCompletingMapping() {
- var definition = this.visualization.getDefinition();
- return definition.getProperty('renderWithoutCompletingMapping') === true;
- },
- hasUnavailableMetadataColumns: function hasUnavailableMetadataColumns() {
- return this.visualization.hasUnavailableMetadataColumns();
- },
- /**
- * Render Sequence - override this method when needed by a specific view type.
- * @returns promise - By default, views don't have visSpecs....return a resolved promise with an empty object.
- */
- whenHighlighterReady: function whenHighlighterReady() {
- return this._noOpRenderStep('base class whenHighlighterReady called!');
- },
- /**
- * Creates an object consumable by our info indicator
- * @param {object} id id of our info, needs a matching entry in our nls entries
- * @param {Array} items
- * @param {String} item.id
- * @param {String} item.caption
- */
- _getInfoIndicatorEntries: function _getInfoIndicatorEntries(id, items) {
- return [{
- id: id,
- label: StringResources.get(id),
- items: _.map(items, function (item) {
- return {
- id: item.id,
- label: item.caption
- };
- })
- }];
- },
- _setInfoIndicatorWarningsAndErrors: function _setInfoIndicatorWarningsAndErrors(data) {
- if (this.infoIndicator && data) {
- var errorId = 'smart_errors';
- var warningId = 'smart_warnings';
- var warnings = data.getWarnings();
- var errors = data.getErrors();
- this.infoIndicator.addInfo(this._getInfoIndicatorEntries(warningId, warnings));
- this.infoIndicator.addInfo(this._getInfoIndicatorEntries(errorId, errors));
- }
- },
- clearInfoIndicator: function clearInfoIndicator() {
- // Reset any warnings/errors in the info indicator as we are starting fresh
- if (this.infoIndicator) {
- //if our mapping isn't complete, just clear out the info indicator.
- if (!this.isMappingComplete()) {
- this.infoIndicator.reset();
- } else {
- for (var _len = arguments.length, msgId = Array(_len), _key = 0; _key < _len; _key++) {
- msgId[_key] = arguments[_key];
- }
- this.infoIndicator.clearMessagesWithIds(msgId);
- }
- }
- },
- clearAnnotationErrorsAndWarnings: function clearAnnotationErrorsAndWarnings() {
- this.clearInfoIndicator('smart_errors', 'smart_warnings', 'smart_exec_support_warnings', 'annotation_service_error');
- },
- /**
- * Render Sequence - override this method when needed by a specific view type.
- * @returns promise - By default, views don't have visSpecs....return a resolved promise with an empty object.
- */
- whenAnnotatedResultsReady: function whenAnnotatedResultsReady(renderContext) {
- var _this3 = this;
- if (this.isMappingComplete() && !this.hasUnavailableMetadataColumns() && (this._checkAllSupportsAnnotations() || this._checkAllSupportsForecasts())) {
- return this.visModel.whenAnnotatedResultsReady(renderContext).then(function (data) {
- _this3._setInfoIndicatorWarningsAndErrors(data);
- return data;
- });
- } else {
- return Promise.resolve();
- }
- },
- addUnavailableAnnotationServiceErrorMessageToIndicator: function addUnavailableAnnotationServiceErrorMessageToIndicator() {
- if (this.infoIndicator) {
- this.infoIndicator.addInfo([{
- id: 'annotation_service_error',
- label: StringResources.get('smart_errors'),
- items: [{
- id: 'suggestions',
- label: StringResources.get('smart_annotation_insight_unavailable')
- }]
- }]);
- }
- },
- /**
- * Render Sequence - override this method when needed by a specific view type.
- * @returns {object} promise
- */
- whenPredictSuggestionsReady: function whenPredictSuggestionsReady(renderContext) {
- var _this4 = this;
- this.clearInfoIndicator('annotation_service_error', 'suggestions');
- // Clear the messages so that we aren't showing stale info
- this.visModel.clearInsightsIndicatorMessages();
- if (this.content) {
- this.content.getFeature('Forecast').clearForecastIndicatorMessages();
- }
- var supportsAnnotations = this._checkAllSupportsAnnotations();
- if (!supportsAnnotations) {
- this.visModel.resetAnnotations();
- }
- if (this._hasMappedSlots() && this.isMappingComplete()) {
- return this.visModel.whenPredictIsReady(renderContext, supportsAnnotations, this._checkAllSupportsForecasts()).catch(function (error) {
- _this4.addUnavailableAnnotationServiceErrorMessageToIndicator();
- _this4.logger.error('An error occurred while waiting for the annotation suggestions to be ready', error, _this4.visModel);
- });
- }
- return Promise.resolve();
- },
- _checkAllSupportsAnnotations: function _checkAllSupportsAnnotations() {
- return this.supportsAnnotations() && this._viewSupportsAnnotations();
- },
- //We enable annotations for preview launched from Driver analysis Viz key drivers,
- //Except that, for other previews, we disable annotations.
- _viewSupportsAnnotations: function _viewSupportsAnnotations() {
- if (this.ownerWidget.isPreview) {
- return this.ownerWidget.isPredictPreview === true;
- }
- return true;
- },
- _checkAllSupportsForecasts: function _checkAllSupportsForecasts() {
- return this.supportsForecasts() && this._viewSupportsForecasts();
- },
- _viewManagesOwnQuery: function _viewManagesOwnQuery() {
- if (this.ownerWidget.managesOwnQueries) {
- return this.ownerWidget.managesOwnQueries === true;
- }
- return false;
- },
- //We enable forecasts for preview launched from Driver analysis Viz key drivers,
- //Except that, for other previews, we disable annotations.
- _viewSupportsForecasts: function _viewSupportsForecasts() {
- if (this.ownerWidget.isPreview) {
- return this.ownerWidget.isPredictPreview === true;
- }
- return true;
- },
- /**
- * Render Sequence:
- * Each step in the render sequence returns a promise.
- * For any view, or any step, this method can be used to return a resolved promise with an empty object
- */
- _noOpRenderStep: function _noOpRenderStep() {
- //By default, VisViews have no underlying VisControl...return an empty, non-null object.
- return Promise.resolve({});
- },
- _addPropertyHandler: function _addPropertyHandler() {
- this.ownerWidget.model.on('change:properties', this.onChangeProperties, this);
- this.ownerWidget.model.on('change:fillColor', this.onChangeProperties, this);
- },
- /**
- * Set up the View and standard event handlers on the VisModel.
- */
- createView: function createView() {
- if (!this.visModel) {
- throw 'Invalid VisModel reference';
- }
- //Subscribe to model events
- this.visModelEvents = {
- 'change:annotations': this.onChangeAnnotations,
- 'change:pagecontext': this.onChangePageContext, //pageContext changes should be processed as filters.
- 'change:refreshTimer': this.toggleRefreshTimerIndicator
- };
- this.ownerWidget.model.on('change:searchFilters', this.onChangeLocalFilter, this);
- this.ownerWidget.model.on('change:localFilters', this.onChangeLocalFilter, this);
- this.ownerWidget.model.on('change:conditions', this.onChangeConditions, this);
- this.ownerWidget.model.on('change:possibleKeyDrivers', this.onChangePossibleKeyDrivers, this);
- for (var key in this.visModelEvents) {
- if (this.visModelEvents.hasOwnProperty(key)) {
- this.visModel.on(key, this.visModelEvents[key], this);
- }
- }
- if (this.filterIndicator) {
- this.filterIndicator.initEvents();
- }
- if (this.refreshTimerIndicator) {
- this.refreshTimerIndicator.initEvents();
- }
- if (this.forecastIndicator) {
- this.forecastIndicator.initEvents(this.supportsForecasts());
- }
- var content = this.ownerWidget.content;
- content && content.on('all', this.onAllContentChanges, this);
- var visDefinitions = this.dashboardApi.getFeature('VisDefinitions');
- visDefinitions.on('refresh:definition', this.onRefreshVisDefinition, this);
- visDefinitions.on('refresh:all', this.onRefreshAllVisDefinition, this);
- var colorsService = this.dashboardApi.getFeature('Colors');
- colorsService.on('theme:changed', this.onChangeProperties, this);
- },
- /**
- * Event handler when possible key drivers are changed inside vis model
- */
- onChangePossibleKeyDrivers: function onChangePossibleKeyDrivers() {
- var event = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
- if (this._isViewSlotsEmpty()) {
- return this.ownerWidget._rebuildVis(event);
- }
- var reRenderOptions = {
- refresh: {
- predictSuggestions: true,
- keyDrivers: true,
- data: true
- }
- };
- if (this.filterIndicator) {
- this.filterIndicator.update();
- }
- this.appendExtraInfoToRenderOptions(reRenderOptions, event);
- if (this.ownerWidget.isVisible()) {
- this._reRender(reRenderOptions);
- } else {
- this.ownerWidget.setReRenderOnShow(reRenderOptions);
- }
- },
- onRefreshAllVisDefinition: function onRefreshAllVisDefinition() {
- var visDefinition = this.visualization.getDefinition();
- if (visDefinition.getState().getError() || this.content.getFeature('state').getError()) {
- this._reRender({
- refreshAll: true
- });
- }
- },
- onRefreshVisDefinition: function onRefreshVisDefinition(event) {
- var visDefinition = this.visualization.getDefinition();
- if (visDefinition && event && event.info && visDefinition.getId() === event.info.id) {
- this._reRender({
- refreshAll: true
- });
- }
- },
- onAllContentChanges: function onAllContentChanges(e) {
- if (e && e.info && e.info.refresh) {
- var renderOptions = {
- refresh: _.extend({}, e.info.refresh),
- extraInfo: {
- payloadData: {
- transactionToken: e.transactionToken
- }
- }
- };
- if (renderOptions.refresh.all) {
- // TODO: refreshAll should be changed into 'refresh.all' to be consistent with the refresh syntax
- renderOptions.refreshAll = renderOptions.refresh.all;
- }
- // Type change
- // highlighting is included because this event may have
- // been triggered from a failure handler.
- // ensure the remaining rendering sequence is covered
- // var reRenderOptions = {
- // refresh: {
- // visSpec: true,
- // data: true,
- // highlighter: true,
- // predictSuggestions: true
- // }
- // };
- // //If currently rendering icon view, ensure the proper control is loaded.
- // reRenderOptions.refresh.visControl = true;
- // this._reRender(this.appendExtraInfoToRenderOptions(reRenderOptions, event));
- // this.updateConditionalViewIndicator();
- // Todo: once we removed the logic for refresh properties pane upon re-render, this should be removed too
- // UndoRedo action will update the model but the old properties UI doesn't have state management, so we need to do a refresh for this scenario
- var isUndoRedo = e.context && e.context.undoRedo && e.info.featureName !== 'ConditionalFormatting';
- renderOptions.refresh.propertiesPane = this._refreshPropertiesPane(renderOptions, isUndoRedo);
- this._reRender(renderOptions);
- }
- },
- _refreshPropertiesPane: function _refreshPropertiesPane(renderOptions, isUndoRedo) {
- return !this._isLocalViz() || renderOptions.refresh.propertiesPane || !this._isNewConditionalFormattingEnabled() || !!isUndoRedo;
- },
- _isLocalViz: function _isLocalViz() {
- var localVizType = ['KPI', 'Singleton', 'Hierarchy', 'Crosstab', 'List', 'DataPlayer'];
- var visType = this.content.getFeature('Visualization').getType();
- return _.contains(localVizType, visType);
- },
- _isNewConditionalFormattingEnabled: function _isNewConditionalFormattingEnabled() {
- var cf_kpi = !this.dashboardApi.getGlassCoreSvc('.FeatureChecker').checkValue('dashboard', 'condFormat', 'disabled');
- var cf_xtab = !this.dashboardApi.getGlassCoreSvc('.FeatureChecker').checkValue('dashboard', 'xtabcondFormat', 'disabled');
- return cf_kpi || cf_xtab;
- },
- updateSubViews: function updateSubViews() {
- this.updateConditionalViewIndicator();
- },
- /**
- * If this view has a template string, make its content a child of the root "el".
- * If the template includes "data-attach-point" attributes, augment the view class
- * with them.
- * eg:
- * <root>
- * <div class="x" data-attach-point='sliderNode'>
- * <div class="y" data-attach-point='playerButtonNode'>
- * </root>
- *
- * would extend the VisView with members sliderNode=div.x, playerButtonNode=div.y
- */
- _processTemplateString: function _processTemplateString() {
- if (this.templateString) {
- //Populate the view with the template if one has been defined.
- var outTemplate = this.dotTemplate(this.templateString);
- if (!outTemplate) {
- outTemplate = this.templateString;
- }
- this.$el.html(outTemplate);
- var dataAttachPoints = this.el.querySelectorAll('div[data-attach-point]');
- var oAttachPoints = {};
- _.each(dataAttachPoints, function (dataAttachPoint) {
- oAttachPoints[dataAttachPoint.getAttribute('data-attach-point')] = dataAttachPoint;
- });
- _.extend(this, oAttachPoints);
- }
- },
- /**
- * Resize the el for this view to the specified bounds
- * @param bounds in form left, top, width, height.
- */
- resize: function resize(bounds) {
- if (bounds) {
- // capture widget height, if zero or undefined then get parent's height
- var height = bounds.height || this.$el.parent().height();
- // if we have tabs, we must compensate for the space it takes within the widget if the mapping is complete
- if (this._tabs && this._tabs.getTabsCount() > 0 && this.ownerWidget.allowShowTabs && this.ownerWidget.allowShowTabs() && this.isMappingComplete()) {
- height = height - this._tabs.$el.height();
- }
- var fSetBound = function fSetBound(style, styleAttr, val) {
- // Setting style may be expensive, do it only when necessary.
- if (val !== undefined && val !== parseInt(style[styleAttr], 10)) {
- style[styleAttr] = val + 'px';
- }
- };
- var style = this.el.style;
- fSetBound(style, 'left', bounds.left);
- fSetBound(style, 'top', bounds.top);
- fSetBound(style, 'width', bounds.width);
- fSetBound(style, 'height', height);
- }
- },
- /**
- * Remove this view...cleanup any event handlers set up
- * and perform base class cleanup.
- */
- // @override
- remove: function remove() {
- var _this5 = this;
- var finalRemove = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
- this.removeIconView();
- VisView.inherited('remove', this, arguments);
- // todo livewidget_cleanup -- it is weird that we pass a finalRemove
- // It seems to be used to delayed the destruction of a vipr widget
- // but we could handle this in a better way
- VisViewSubViews.forEach(function (view) {
- _this5[view] && _this5[view].remove();
- _this5[view] = null;
- });
- // external events
- for (var key in this.visModelEvents) {
- if (this.visModelEvents.hasOwnProperty(key)) {
- this.visModel.off(key, this.visModelEvents[key], this);
- }
- }
- this.ownerWidget.model.off('change:searchFilters', this.onChangeLocalFilter, this);
- this.ownerWidget.model.off('change:localFilters', this.onChangeLocalFilter, this);
- this.ownerWidget.model.off('change:properties', this.onChangeProperties, this);
- this.ownerWidget.model.off('change:fillColor', this.onChangeProperties, this);
- this.ownerWidget.model.off('change:conditions', this.onChangeConditions, this);
- this.ownerWidget.model.off('change:possibleKeyDrivers', this.onChangePossibleKeyDrivers, this);
- if (this._tabs) {
- this._tabs.remove();
- this._tabs = null;
- }
- var content = this.ownerWidget.content;
- content && content.off('all', this.onAllContentChanges, this);
- var visDefinitions = this.dashboardApi.getFeature('VisDefinitions');
- visDefinitions.off('refresh:definition', this.onRefreshVisDefinition, this);
- visDefinitions.off('refresh:all', this.onRefreshAllVisDefinition, this);
- var colorsService = this.dashboardApi.getFeature('Colors');
- colorsService.off('theme:changed', this.onChangeProperties, this);
- if (finalRemove) {
- MemUtil.destroy(this);
- }
- },
- onChangePageContext: function onChangePageContext(event) {
- var _this6 = this;
- return this.onChangeFilter(event).catch(function (e) {
- var LOG_LEVEL = e && e.message === 'dwErrorStaleRequest' ? 'debug' : 'error';
- _this6.logger[LOG_LEVEL](e);
- });
- },
- _rebuildVis: function _rebuildVis(event, options) {
- this._rebuildPending = true;
- var transactionToken = options && options.extraInfo && options.extraInfo.payloadData && options.extraInfo.payloadData.transactionToken;
- return this.transactionApi.registerTransactionHandler(transactionToken || {}, this.ownerWidget.id + '_rebuildvis', function () {
- var _this7 = this;
- this.ownerWidget._rebuildVis(event).then(function () {
- _this7._rebuildPending = false;
- });
- }.bind(this), options);
- },
- _getRenderTransaction: function _getRenderTransaction(renderOptions) {
- var transaction = renderOptions && renderOptions.extraInfo && renderOptions.extraInfo.payloadData && renderOptions.extraInfo.payloadData.transactionToken;
- return !transaction || transaction.transactionId ? transaction : null;
- },
- _reRender: function _reRender(options) {
- if (!this._rebuildPending) {
- if (this.ownerWidget.isVisible()) {
- var transactionToken = this._getRenderTransaction(options);
- // Only attempt to render requests with:
- // 1. no transaction token
- // 2. valid transaction token
- if (!transactionToken || this.transactionApi.isValidTransaction(transactionToken)) {
- return this.transactionApi.registerTransactionHandler(transactionToken || {}, this.ownerWidget.id, function (opt) {
- if (this.ownerWidget) {
- var visApi = this.ownerWidget.getAPI().getVisApi();
- return visApi.getRenderSequence().reRender(this._mergeOptions(opt));
- }
- return Promise.resolve();
- }.bind(this), options);
- }
- } else {
- this.ownerWidget.setReRenderOnShow(options);
- }
- }
- return Promise.resolve();
- },
- /**
- * @description This function will take the first object in the array and merge the 'refresh' parameters from the other objects into it
- * @param {Array} of render options
- * @returns {Object} the merged options object or the first object if there are no others to merge
- */
- _mergeOptions: function _mergeOptions(options) {
- var mergedOptions = options[0];
- var length = options.length;
- if (length > 1) {
- for (var i = 1; i < length; i++) {
- mergedOptions.refresh = this._mergeRefreshOptions(mergedOptions.refresh, options[i].refresh);
- if (options[i].refreshAll) {
- mergedOptions.refreshAll = options[i].refreshAll;
- }
- }
- }
- if (mergedOptions.refresh && mergedOptions.refresh.data && mergedOptions.refresh.dataIfQueryChanged) {
- // data refresh trumps dataIfQueryChanged
- delete mergedOptions.refresh.dataIfQueryChanged;
- }
- return mergedOptions;
- },
- _mergeRefreshOptions: function _mergeRefreshOptions(refreshOptions, options) {
- Object.keys(options).forEach(function (key) {
- if (!refreshOptions.hasOwnProperty(key)) {
- refreshOptions[key] = options[key];
- } else {
- refreshOptions[key] = refreshOptions[key] || options[key];
- }
- });
- return refreshOptions;
- },
- /**
- * Called when a filter on the VisModel changes.
- * By default....
- *
- * re-render the view when the event sender is not the same as the receiver
- * re-render the selections
- */
- // HANDLER: visModel.on('change:filters')
- onChangeFilter: function onChangeFilter(event) {
- var _this8 = this;
- event = event || {};
- var changeEvent = event.changeEvent;
- var transactionToken = this.transactionApi.startTransaction(changeEvent && changeEvent.data && changeEvent.data.transactionToken);
- var sender = event && event.sender;
- return VisUtil.validateVisDefinition(this.content, this.dashboardApi, { visId: this.ownerWidget.model.visId }).then(function (isValid) {
- if (isValid) {
- return _this8._queryChanged().then(function (result) {
- result = result || {};
- var refreshData = result.isRenderNeeded;
- var extraInfo = void 0;
- var renderOptions = {
- refresh: {
- dataIfQueryChanged: refreshData,
- annotation: true
- }
- };
- if (_this8.filterIndicator) {
- _this8.filterIndicator.setSynchronizeDataFilters(result.synchDataFilterEntries);
- _this8.filterIndicator.update();
- }
- if (!refreshData) {
- // optimization to avoid making unnecessary render requests
- if (!changeEvent || changeEvent.isInScope(_this8.ownerWidget.getScope(), _this8.ownerWidget.getEventGroupId())) {
- if (changeEvent && !changeEvent.brushingChanged() && _.every(changeEvent.getItems(), function (item) {
- return item.getValueCount() === 0;
- })) {
- // If the filter doesn't have any value and it is not a brushing event, do not rerender.
- return;
- }
- // @todo is this necessary?
- if (result.context) {
- result.context.visAPI = _this8.visAPI;
- }
- } else {
- _this8.visModel.renderComplete();
- return;
- }
- // ensure we don't introduce unnecessary animations upon re-render with no data change
- extraInfo = {
- entryDuration: 'zero',
- payloadData: { transactionToken: transactionToken }
- };
- }
- _this8._reRender(_this8.appendExtraInfoToRenderOptions(renderOptions, event, extraInfo)).then(function () {
- if (!refreshData) {
- _this8.dashboardApi.triggerDashboardEvent('dataInVis:selected', { payloadData: _this8.ownerWidget, sender: _this8.ownerWidget.id });
- var isOriginatorOfSelection = event.changeEvent && event.changeEvent.senderMatches(_this8.ownerWidget.id);
- //isOriginator means this widget is the originator of the selection change (not just one that is responding to the selection change).
- _this8.ownerWidget.trigger('visevent:selectionchanged', { sender: _this8.ownerWidget.id, isSelectionOriginator: isOriginatorOfSelection });
- _this8.renderFocused(!sender || sender === _this8.ownerWidget.id);
- }
- });
- });
- }
- }).finally(function () {
- _this8.transactionApi.endTransaction(transactionToken);
- });
- },
- _queryChanged: function _queryChanged() {
- // TODO Wrap to async result when use new query API. Need to be cleaned once switch to query api.
- if (this.ownerWidget.useNewQueryApi()) {
- var internalQueryExecution = this.content.getFeature('DataQueryExecution.internal');
- return internalQueryExecution.queryChanged().then(function (changed) {
- return { isRenderNeeded: changed };
- });
- } else {
- return this.visModel.queryChanged();
- }
- },
- toggleRefreshTimerIndicator: function toggleRefreshTimerIndicator(event) {
- if (this.refreshTimerIndicator.$icon) {
- if (event.autoRefresh) {
- this.refreshTimerIndicator.$icon.removeClass('dataWidgetTimersNone');
- } else {
- this.refreshTimerIndicator.$icon.addClass('dataWidgetTimersNone');
- }
- }
- },
- /**
- * Called when a filter that only affects this widget changes.
- * Such as from the filter dialog.
- *
- * re-render the selections
- */
- onChangeLocalFilter: function onChangeLocalFilter(event) {
- var renderOptions = {
- refresh: {
- data: true,
- annotation: true
- }
- };
- this.ownerWidget.updateMissingFilters();
- /* vis isn't tied to data anymore*/
- if (this._isViewSlotsEmpty()) {
- this._rebuildVis(event, this.appendExtraInfoToRenderOptions(renderOptions, event));
- return;
- }
- this.visModel.setPendingFilters(false); //cancel any pending filters
- var sender = event && event.sender;
- this._reRender(this.appendExtraInfoToRenderOptions(renderOptions, event));
- this.renderFocused(!sender || sender === this.ownerWidget.id);
- if (this.filterIndicator) {
- this.filterIndicator.update();
- }
- },
- onChangePendingFilter: function onChangePendingFilter() {
- this.visModel.setPendingFilters(true);
- },
- /**
- * Slots include vis slots and local filters slots
- */
- _isViewSlotsEmpty: function _isViewSlotsEmpty() {
- return !this.visualization.getSlots().getMappedSlotList().length && this.visModel.getLocalFilters().isEmpty();
- },
- _annotationHasChanged: function _annotationHasChanged(event) {
- var prev = event && event.changeEvent && event.changeEvent.prevValue;
- var curr = event && event.changeEvent && event.changeEvent.value;
- if (prev && prev.selectedAnnotations && prev.selectedAnnotations.length || curr && curr.selectedAnnotations && curr.selectedAnnotations.length) {
- return true;
- } else {
- return false;
- }
- },
- onChangeAnnotations: function onChangeAnnotations(event) {
- if (this._annotationHasChanged(event)) {
- var renderOptions = {
- refresh: {
- dataIfQueryChanged: true,
- annotation: true
- },
- extraInfo: {
- annotationRequest: true
- }
- };
- return this._reRender(this.appendExtraInfoToRenderOptions(renderOptions, event));
- }
- return Promise.resolve();
- },
- onVisible: function onVisible() {},
- isVisible: function isVisible() {
- return this.$el.parent().is(':visible');
- },
- /**
- * Called when a property (like a font or a colour) changes.
- * By default....
- * re-render the view
- * re-render the selections
- * Set queryManager and render options if one of the properties requiring data refresh have changed (currently maintainAxisScales)
- * @param event - an event containing the single property from the property collection that changed (eg: 'showAxisTitles').
- */
- // HANDLER: visModel.on('change:property')
- onChangeProperties: function onChangeProperties(modelEvent) {
- var event = {
- name: 'properties',
- value: modelEvent && modelEvent.value,
- sender: null,
- changeEvent: modelEvent,
- refreshData: modelEvent && modelEvent.origCollectionEvent && modelEvent.origCollectionEvent.dataRefresh
- };
- var renderOptions = {
- refresh: {}
- };
- if (event && event.refreshData || renderOptions.refresh.data) {
- if (_.isEmpty(renderOptions.refresh)) {
- renderOptions.refresh.data = true;
- }
- }
- // re-render the visualization
- var reRenderOptions = this.appendExtraInfoToRenderOptions(renderOptions, event);
- this._reRender(reRenderOptions);
- },
- /**
- * Called when the conditional formatting changes
- */
- onChangeConditions: function onChangeConditions(event) {
- var renderOptions = {
- refresh: {}
- };
- this._reRender(this.appendExtraInfoToRenderOptions(renderOptions, event));
- },
- /**
- * Called when the container is entered.
- */
- onEnterContainer: function onEnterContainer() {
- /* to be overridden */
- },
- /**
- * Called when the container is exited.
- */
- onExitContainer: function onExitContainer() {
- /* to be overridden */
- },
- /**
- * update animation settings for transitions from one state to another according to the following rules:
- * 1) use the default defined in the definition properties unless override is set to exactly 0 (to turn it off)
- * 2) if no animation properties in the definition, use the override value if its > 0
- * 3) if not in the def properties and not overridden by an action, animation should be off.
- * NOTE: by default overrideDefaultAnimationSpeed is -1 which denotes it is not enabled.
- */
- updateAnimationSettings: function updateAnimationSettings(visdefProperties) {
- var visDefAnimationSpeed = visdefProperties && visdefProperties.animationSpeed ? visdefProperties.animationSpeed : 0;
- this.animationSpeed = visDefAnimationSpeed ? visDefAnimationSpeed : this.DEFAULT_ANIMATION_SPEED;
- if (this.overrideDefaultAnimationSpeed === 0 || this.visModel.getSuppressViewAnimations()) {
- //If an action has explicitly turned animation off, respect that option.
- this.animationSpeed = 0;
- } else if (this.overrideDefaultAnimationSpeed > 0 && visDefAnimationSpeed === 0) {
- //If animation is not on, use the override if its not off (-1)
- this.animationSpeed = this.overrideDefaultAnimationSpeed;
- }
- },
- /**
- * VIPR supports animation effects (which are always enabled)
- * It is possible to do a fade-in/fade-out type animation for non-VIPR visualizations.
- * In this case, renderComplete should be called by animate not render.
- * NOTE: This style of animation has been DISABLED for Endor and is likely to be removed/reworked in future
- * as it simply makes non-VIPR visualizations flash needlessly (and appear slower).
- * @returns true if non-VIPR animation has been enabled for a particular visualization type
- */
- isAnimationEnabledForNonVIPRVisualizations: function isAnimationEnabledForNonVIPRVisualizations() {
- return this.animationType && this.animationType !== this.ANIMATION_TYPES.NONE;
- },
- /**
- * For now, for grid/summary/trend etc, there is only one animation effect by default which is to fade out and fade in
- */
- animate: function animate(renderInfo) {
- var _this9 = this;
- this.visModel.renderCompleteBeforeAnimation();
- if (this.isAnimationEnabledForNonVIPRVisualizations()) {
- var renderComplete = function renderComplete() {
- _this9.visModel.renderComplete(renderInfo);
- };
- this.updateAnimationSettings();
- $(this.el).fadeOut(0);
- //If doing fade-in/fade-out animation, we need to call render complete at the end.
- $(this.el).fadeIn(this.animationSpeed, renderComplete);
- }
- },
- /**
- * Override this method to take the selection and highlight it.
- */
- renderSelected: function renderSelected() {},
- /**
- * Override this method to style focused item.
- */
- renderFocused: function renderFocused() {},
- /**
- * The base render method is called at the end of the subtype render() to provide any actions required
- * once render is prepared and submitted to the rendering engine (eg: RAVE).
- *
- * Its important to note that due to the async nature of rendering, this method may be called prior
- * to the actual render being completed.
- * @param {Object} renderInfo - renderInfo passed to all render methods (originates in the render sequence).
- * @param {boolean default=true} callRenderComplete - true if this function is being called at the end of the type-specific view render
- * so that renderComplete will be called. VIPRView is an exception.
- * VIPRView calls VisView:render to do common processing but needs to handle renderComplete itself because of the way it sets/decorates data.
- */
- render: function render(renderInfo) {
- var callRenderComplete = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
- this.animate(renderInfo); //Note: animate is overridden to do nothing for RAVE as it has effects support
- this.updateConditionalViewIndicator({
- data: renderInfo.data
- });
- if (callRenderComplete && !this.isAnimationEnabledForNonVIPRVisualizations()) {
- //If animation is enabled, we need to wait until the end of the animation to call render complete.
- //See (VisView:animate()). NOTE: This style of animation is disabled for Endor.
- this.visModel.renderComplete(renderInfo);
- }
- return Promise.resolve(this);
- },
- /**
- * Removes the icon view element and remove hide class from the rave output area whose role is application
- */
- removeIconView: function removeIconView() {
- if (!(this.hasUnavailableMetadataColumns() || this.hasMissingFilters())) {
- this._removeMissingDataColumnWarning();
- }
- if (this.$iconView) {
- this.$el.find('div[role="application"]').removeClass('hide');
- this.$el.parent().removeClass('showIconView');
- this.$iconView.remove();
- this.$iconView = null;
- }
- this._removeVisualizationDropZones();
- },
- _removeVisualizationDropZones: function _removeVisualizationDropZones() {
- var dropZonesOverlayState = this.content.getFeature('DropZonesOverlayState');
- if (dropZonesOverlayState && dropZonesOverlayState.isEnabled()) {
- dropZonesOverlayState.hide();
- }
- },
- /**
- * Render warning container for this widget visualization
- */
- _renderWarningContainer: function _renderWarningContainer($containerNode) {
- this._removeWarningContainer();
- this.$warningContainer = $('<div></div>', {
- 'class': 'warningContainer'
- });
- $containerNode.append(this.$warningContainer);
- },
- /**
- * Remove warning container
- */
- _removeWarningContainer: function _removeWarningContainer() {
- if (this.$warningContainer) {
- this.$warningContainer.remove();
- this.$warningContainer = null;
- }
- },
- _renderMissingDataColumnWarning: function _renderMissingDataColumnWarning($containerNode) {
- this._removeMissingDataColumnWarning();
- if (this.hasMissingFilters() && this.filterIndicator && this.filterIndicator.$filter) {
- this.filterIndicator.$filter.addClass('dataWidgetFiltersNone');
- }
- this.$dataUnavailable = $('<div></div>', {
- 'class': 'data-unavailable'
- });
- this._renderWarningContainer($containerNode);
- this.$warningContainer.append(this.$dataUnavailable);
- var $warningIcon = $('<div></div>', {
- 'aria-label': StringResources.get('warning'),
- 'class': 'warningIcon'
- });
- this.$dataUnavailable.append($warningIcon);
- Utils.setIcon($warningIcon, 'common-warning', StringResources.get('warning'));
- var $warningText = $('<div></div>', {
- 'class': 'warningText',
- 'text': StringResources.get('datasetItemsUnavailable')
- });
- this.$dataUnavailable.append($warningText);
- },
- _removeMissingDataColumnWarning: function _removeMissingDataColumnWarning() {
- if (this.$dataUnavailable) {
- this.$dataUnavailable.remove();
- this.$dataUnavailable = null;
- }
- this._removeWarningContainer();
- },
- /**
- * Shows icon of the chart type and hide the rave output area whose role is application
- */
- renderIconView: function renderIconView() {
- if (this._tabs) {
- this._tabs.hide();
- }
- var $containerNode = this._prepareRenderIconView();
- this._renderIconView($containerNode);
- this._renderVisualizationDropZones();
- },
- _renderVisualizationDropZones: function _renderVisualizationDropZones() {
- var dropZonesOverlayDOM = this.content.getFeature('DropZonesOverlayDOM');
- var dropZonesOverlayState = this.content.getFeature('DropZonesOverlayState');
- if (dropZonesOverlayState && dropZonesOverlayState.isEnabled() && !this.hasMissingFilters()) {
- if (dropZonesOverlayDOM.isMounted()) {
- dropZonesOverlayState.show();
- } else {
- dropZonesOverlayDOM.render();
- }
- }
- },
- /**
- * Updates the smart annotations indicator if one exists
- */
- updateSmartAnnotationsIndicator: function updateSmartAnnotationsIndicator() {
- var smartAnnotationsIndicator = this.content.getFeature('SmartsIndicator');
- if (smartAnnotationsIndicator) {
- smartAnnotationsIndicator.update();
- }
- },
- updateConditionalViewIndicator: function updateConditionalViewIndicator(options) {
- var conditionalViewIndicator = this.content.getFeature('ConditionalViewIndicator');
- if (conditionalViewIndicator) {
- conditionalViewIndicator.update(options);
- }
- },
- /**
- * Updates the forecast indicator if one exists
- */
- updateForecastIndicator: function updateForecastIndicator() {
- if (this.forecastIndicator) {
- this.forecastIndicator.update();
- }
- },
- /*Subclass can override the function when necessary*/
- _renderIconView: function _renderIconView($containerNode) {
- $containerNode.append(this.$iconView);
- this.$el.find('div[role="application"]').addClass('hide');
- this.$el.parent().addClass('showIconView');
- this.visModel.renderCompleteBeforeAnimation();
- this.visModel.renderComplete();
- },
- /**
- * Returns the content node. Can be overriden by sub classes.
- */
- getContentNode: function getContentNode() {
- return this.contentNode ? $(this.contentNode) : this.$el;
- },
- _prepareRenderIconView: function _prepareRenderIconView() {
- var definition = this.visualization.getDefinition();
- var icon = definition.getPlaceholderIconUri();
- var caption = definition.getLabel();
- var $containerNode = this.getContentNode();
- if (this.hasUnavailableMetadataColumns() || this.hasMissingFilters()) {
- this._renderMissingDataColumnWarning($containerNode);
- } else if (this.$dataUnavailable) {
- this._removeMissingDataColumnWarning();
- }
- var template = dot.template(EmptyVisualizationTemplate);
- if (this.$iconView) {
- this.$iconView.remove();
- }
- this.$iconView = $(template({
- icon: icon,
- caption: caption,
- title: StringResources.get('LIVE_empty_visualization_hint_title'),
- description: StringResources.get('LIVE_empty_visualization_hint_description')
- }));
- return $containerNode;
- },
- hasMissingFilters: function hasMissingFilters() {
- return this.ownerWidget.getUnavailableLocalFilter().length > 0;
- },
- /**
- * Uses the widget size in a given render context
- */
- resizeToWidget: function resizeToWidget(renderInfo) {
- this.resize(renderInfo.widgetSize);
- },
- getLabel: function getLabel() {
- var label;
- var definition = this.visualization.getDefinition();
- if (definition) {
- label = definition.getLabel();
- } else {
- label = StringResources.get('visualizationLabel');
- }
- return label;
- },
- getDescription: function getDescription() {
- var label = this.getLabel();
- var columns = this._getColumnInformationForLabel();
- var description = StringResources.get('dataWidgetDescription', {
- widgetLabel: label,
- columnNames: columns
- });
- return description;
- },
- _getColumnInformationForLabel: function _getColumnInformationForLabel() {
- var columns = '';
- var mappingInfo = this.visualization.getSlots().getMappingInfoList();
- for (var i = 0; i < mappingInfo.length; i++) {
- if (i > 0) {
- columns += ', ';
- }
- columns += mappingInfo[i].dataItem.getLabel();
- }
- return columns;
- },
- getCurrentViewSelector: function getCurrentViewSelector() {
- return null;
- },
- getProperties: function getProperties() {
- if (this.visModel.getDefinition().properties) {
- return Promise.resolve(this.visModel.getDefinition().properties.slice(0));
- }
- return Promise.resolve([]);
- },
- /**
- * @returns true if any any dataItems is binned
- */
- hasBinnedDataItems: function hasBinnedDataItems() {
- return !!this.visualization.getSlots().getMappingInfoList().find(function (mappingInfo) {
- return !!mappingInfo.dataItem.getBinning();
- });
- },
- /**
- * Generate thumbnail
- *
- * @return {Promise}
- */
- generateThumbnail: function generateThumbnail() {
- var _this10 = this;
- var isDisabled = false;
- var isMappingIncomplete = false;
- if (this._isThumbnailDisabled()) {
- isDisabled = true;
- }
- if (!this.isMappingComplete()) {
- isMappingIncomplete = true;
- }
- var promise = void 0;
- if (isDisabled || isMappingIncomplete) {
- promise = Promise.resolve();
- } else {
- promise = this.dashboardApi.getDashboardSvc('.Thumbnail').then(function (thumbnailSvc) {
- return thumbnailSvc.generateMarkup(_this10.$el.get(0));
- });
- }
- return promise.then(function (thumbnail) {
- return {
- isMappingIncomplete: isMappingIncomplete,
- isDisabled: isDisabled,
- thumbnail: thumbnail
- };
- });
- },
- _isThumbnailDisabled: function _isThumbnailDisabled() {
- //TODO: Augment this to disable thumbnail for any declared unsupportedBrowsers
- // disable thumbnails only for IE11 and lower; Edge is supposedly behaving good in most cases
- if (BrowserUtils.isIE() && !BrowserUtils.isIEEdge()) {
- var defn = this.visModel.getDefinition();
- if (defn && defn.thumbnailConfig) {
- //Disable thumbnails for visualizaions that delcares not supporting certain browsers
- var _defn$thumbnailConfig = defn.thumbnailConfig.unsupportedBrowsers,
- unsupportedBrowsers = _defn$thumbnailConfig === undefined ? [] : _defn$thumbnailConfig;
- return unsupportedBrowsers.indexOf('IE') !== -1;
- }
- }
- return false;
- },
- onSummaryDataCellError: function onSummaryDataCellError() {
- var errorMsg = StringResources.get('errorCellWarning');
- this.infoIndicator.addInfo([{
- id: 'error_summary_cell',
- title: errorMsg,
- items: [{
- id: 'error_summary_cell',
- label: errorMsg,
- isSubMessage: true
- }]
- }]);
- },
- appendExtraInfoToRenderOptions: function appendExtraInfoToRenderOptions(renderOptions, event, extraInfo) {
- event = event && event.changeEvent || event;
- if (event && event.data) {
- if (renderOptions.extraInfo) {
- renderOptions.extraInfo.payloadData = event.data;
- } else {
- renderOptions.extraInfo = {
- payloadData: event.data
- };
- }
- }
- if (renderOptions && renderOptions.extraInfo && extraInfo) {
- renderOptions.extraInfo = _.extend(renderOptions.extraInfo, extraInfo);
- }
- return renderOptions;
- }
- });
- return VisView;
- });
- //# sourceMappingURL=VisView.js.map
|