DeprecateWidgetBase.js 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827
  1. 'use strict';
  2. /*
  3. * Licensed Materials - Property of IBM
  4. * IBM Cognos Products: Dashboard (C) Copyright IBM Corp. 2014, 2021
  5. * US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
  6. */
  7. define(['../AnalyticsBaseWidget', 'underscore', 'jquery', '../../prompts/PromptManager', '../../DynamicFileLoader', '../../lib/@waca/core-client/js/core-client/utils/Deferred'], function (WidgetBase, _, $, PromptManager, DynamicFileLoader, Deferred) {
  8. 'use strict';
  9. /**
  10. * INTENT: DeprecateWidgetBase currently includes implementation for the DataWidget class....
  11. * TODO: Its role should be formalized or this class should be deprecated and divided among more focused objects.
  12. */
  13. var DeprecateWidgetBase = WidgetBase.extend({
  14. isMaximizeSupported: true,
  15. customPalettePrefix: '__CM__',
  16. // constructor
  17. init: function init(params) {
  18. DeprecateWidgetBase.inherited('init', this, arguments);
  19. //Deferred object used indicate that all the VisDefinition specs are fetched and Widget is ready for rendering
  20. this.readyDfd = new Deferred();
  21. this.visualizationDfd = new Deferred();
  22. //dashboard is active on init
  23. this._isDashboardActive = true;
  24. this.logger = this.dashboardApi.getGlassCoreSvc('.Logger');
  25. this._useNewQueryApi = params.useNewQueryApi;
  26. this.visModelManager = null; // The model for this visualization
  27. this.dataSet = null; // The dataSet (datasource object) for this visualization mappings (columns)
  28. this.transactionApi = this.dashboardApi.getFeature('Transaction');
  29. this.visualizationFeature = this.content.getFeature('Visualization');
  30. this.colorsService.on('palette:deleted', this.onPaletteDeleted, this);
  31. this.colorsService.on('palette:updated', this.onPaletteUpdated, this);
  32. },
  33. destroy: function destroy() {
  34. DeprecateWidgetBase.inherited('destroy', this, arguments);
  35. this.clearRefreshTimer();
  36. this.dataSet = null;
  37. if (this.model) {
  38. this.model.off('change:queryRefresh', this.registerRefreshTimer, this);
  39. this.model = null;
  40. }
  41. this._removeShapingModelEvents();
  42. this.readyDfd = null;
  43. this.visualizationDfd = null;
  44. this.logger = null;
  45. this.boardModel = null;
  46. },
  47. reRender: function reRender(extraInfo) {
  48. return this.visAPI.reRender(extraInfo);
  49. },
  50. registerEvents: function registerEvents() {
  51. DeprecateWidgetBase.inherited('registerEvents', this, arguments);
  52. this.dashboardApi.on('widget:toolbar:show:before', this.onToolbarShowBefore, this);
  53. this.dashboardApi.on('widget:toolbar:hide:after', this.onToolbarHideAfter, this);
  54. this.dashboardApi.on('dashboard:show', this.onDashboardShow, this);
  55. this.dashboardApi.on('dashboard:deactivate', this.onDashboardDeactivate, this);
  56. },
  57. unregisterEvents: function unregisterEvents() {
  58. DeprecateWidgetBase.inherited('unregisterEvents', this, arguments);
  59. this.dashboardApi.off('widget:toolbar:show:before', this.onToolbarShowBefore, this);
  60. this.dashboardApi.off('widget:toolbar:show:after', this.onToolbarShowAfter, this);
  61. this.dashboardApi.off('widget:toolbar:show:after', this.onToolbarShowAfter, this);
  62. this.dashboardApi.off('widget:toolbar:hide:after', this.onToolbarHideAfter, this);
  63. this.dashboardApi.off('dashboard:show', this.onDashboardShow, this);
  64. this.dashboardApi.off('dashboard:deactivate', this.onDashboardDeactivate, this);
  65. this.colorsService.off('palette:deleted', this.onPaletteDeleted, this);
  66. this.colorsService.off('palette:updated', this.onPaletteUpdated, this);
  67. },
  68. getCurrentVis: function getCurrentVis() {
  69. return this._currVis;
  70. },
  71. onStartMove: function onStartMove() /*payload*/{
  72. if (this._currVis && this._currVis.onStartMove) {
  73. this._currVis.onStartMove();
  74. }
  75. },
  76. onStopMove: function onStopMove() /*payload*/{
  77. if (this._currVis && this._currVis.onStopMove) {
  78. this._currVis.onStopMove();
  79. }
  80. },
  81. onToolbarHideAfter: function onToolbarHideAfter(payload) {
  82. if (this._currVis) {
  83. var selector = this._currVis.getCurrentViewSelector();
  84. if (selector && selector.setPopoverClosed) {
  85. selector.setPopoverClosed(payload);
  86. }
  87. }
  88. },
  89. onToolbarShowBefore: function onToolbarShowBefore(payload) {
  90. if (this._currVis) {
  91. var selector = this._currVis.getCurrentViewSelector();
  92. if (selector && selector.setPopoverOpened) {
  93. selector.setPopoverOpened(payload);
  94. }
  95. }
  96. },
  97. /**
  98. * Called when the parent dashboard fires the dashboard:show event.
  99. */
  100. onDashboardShow: function onDashboardShow() {
  101. //start our refresh timer if needed.
  102. this._isTimerActive = true;
  103. this._isDashboardActive = true;
  104. },
  105. /**
  106. * Called when the parent dashboard fires the dashboard:deactivate event.
  107. */
  108. onDashboardDeactivate: function onDashboardDeactivate() {
  109. //clear the refresh timer so it doesn't fire when the dashboard is not activated (aka shown)
  110. this._isTimerActive = false;
  111. this._isDashboardActive = false;
  112. },
  113. /**
  114. * When a theme mapping is updated (a new vis type definition is provided) we need to update
  115. * the theme mapping.
  116. * @param themeMapping - json description of which properties map to which super property
  117. * For example:
  118. * {
  119. * "id": "axisLineColor",
  120. * "mapping": [
  121. * "valAxisLineColor",
  122. * "catAxisLineColor"
  123. * ]
  124. * }
  125. */
  126. updateThemeMapping: function updateThemeMapping(themeMapping) {
  127. this.colorsService.updateThemeMapping(themeMapping);
  128. },
  129. /**
  130. * Widget Life cycle handler - gets called when container is ready and the widget model is initialized.
  131. * This override is used to initialize the white list since the whitelist is attached to the widget model.
  132. */
  133. onContainerReady: function onContainerReady(containerContext) {
  134. var _this = this;
  135. console.debug('onContainerReady');
  136. DeprecateWidgetBase.inherited('onContainerReady', this, arguments);
  137. this.model = containerContext.model;
  138. if (this.model) {
  139. this.model.on('change:queryRefresh', this.registerRefreshTimer, this);
  140. }
  141. // TODO: we should build this automatically from the viz definition
  142. // TODO: livewidget_cleanup -- most of these properties are not part of the live widget root , so they are not needed here
  143. this.addWhiteListAttrs('titleHtml', 'name', 'type', 'localFilters', 'visId', 'showTitle', 'properties', 'maintainAxisScales', 'colorPalette', 'showItemLabel', 'titleType', 'titleMode', 'truncateTitle', 'hideLegend', 'hideAxisTitleLabels', 'legendPosition', 'lineColor', 'interpolation', 'elementColor', 'symbolShape', 'symbolFill', 'heatScalePalette', 'heatScaleColorOrder', 'hideRadialTitle', 'hideRadialValue', 'archetype', 'expandOnRender', 'hideLabel', 'hideValue', 'hideTreeMapLeafLabels', 'pieAsDonut', 'hideGridLines', 'hideSymbols', 'hideDataLines', 'conditions', 'queryRefresh', 'transpose', 'labelLocation', 'interpolate', 'condColorPalette', 'condColorOrder', 'hideSummaries', 'legend.position', 'donutRadius', 'labelLocation', 'lineWithPoints.symbol', 'itemLabel.display', 'tiledmap.style', 'fillDirection', 'savedPrompts', 'labels.visible', 'label.format', 'defaultPaletteIndex', 'actions', 'showInsights', 'lineWithPoints.symbol');
  144. var getContentRef = function getContentRef(propName) {
  145. var value = _this.visAPI.getPropertyValue(propName);
  146. // We only want palettes that start with __CM__ to be added to the content references
  147. if (value && value.indexOf(_this.customPalettePrefix) === 0) {
  148. return value.split(_this.customPalettePrefix)[1];
  149. }
  150. return null;
  151. };
  152. var contentReferences = [];
  153. ['colorPalette', 'contColorPalette', 'condColorPalette'].forEach(function (propName) {
  154. contentReferences.push({
  155. type: 'palette',
  156. get: function get() {
  157. return getContentRef(propName);
  158. }
  159. });
  160. });
  161. this.addContentReferences(contentReferences);
  162. this.registerRefreshTimer();
  163. },
  164. /**
  165. * Reset the widget size to the visualization preferred size.
  166. *
  167. */
  168. resizeToPreferredSize: function resizeToPreferredSize() {
  169. this.setPreferredSize(this.visAPI.getPreferredSize());
  170. },
  171. /**
  172. * place the visualization into the dom at the specified point (replace the previous dataview if any)
  173. * By default, the visualization will be placed at this.el.
  174. * @param visualization the visualization (Rave Chart, Grid etc.)
  175. * @param domElement the dom parent node.
  176. */
  177. placeAt: function placeAt(visualization, domElement) {
  178. if (!domElement) {
  179. domElement = this.el;
  180. }
  181. if (this._currVis) {
  182. this._currVis.remove( /*finalRemove*/false);
  183. }
  184. this._currVis = visualization;
  185. this._currVis.predictData = this.predictData;
  186. this.visualizationDfd.resolve(visualization);
  187. this.setLayoutProperties({
  188. pannable: this._currVis.isPannable,
  189. mobilePannable: this._currVis.isMobilePannable,
  190. noRotate: this._currVis.noRotate,
  191. maximizable: this._currVis.isMaximizable
  192. });
  193. $(domElement).children('.dataview').detach();
  194. if (visualization.placeAt) {
  195. visualization.placeAt(domElement, /*index (when theres no canvas, index is always 0*/0);
  196. } else {
  197. $(visualization.el).appendTo(domElement);
  198. }
  199. },
  200. /**
  201. * @returns the current dataset (also known as a dataSource object).
  202. */
  203. getDataSet: function getDataSet() {
  204. return this.dataSet;
  205. },
  206. _refreshWidgets: function _refreshWidgets(event) {
  207. /**
  208. * Check the sender with the following conditions to avoid unnecessary refresh or infinite refresh.
  209. * 1. Check the event is NOT triggered by the current widget itself.
  210. * 2. Check if the refresh is already done by checking if the current widget is included in refreshedWidgets.
  211. */
  212. if (event.sender.widget !== this && this.visAPI && (!event.sender.refreshedWidgets || event.sender.refreshedWidgets.indexOf(this) === -1)) {
  213. //only check if item is in used if it is specified
  214. if (event.dataItemId && !this.visAPI.isDataItemMapped(event.dataItemId)) {
  215. return;
  216. }
  217. var sender = event.sender;
  218. if (!sender) {
  219. sender = {};
  220. }
  221. if (!sender.refreshedWidgets) {
  222. sender.refreshedWidgets = [];
  223. }
  224. sender.refreshedWidgets.push(this);
  225. this.reRender({
  226. sender: sender
  227. });
  228. if (this.visExpandMode) {
  229. this.visExpandMode.renderSlotsView();
  230. }
  231. }
  232. },
  233. // perform the menu action
  234. onMenuAction: function onMenuAction() {},
  235. _applyingExternalFilter: {},
  236. _createEventTransactionToken: function _createEventTransactionToken(event) {
  237. var transactionToken = void 0;
  238. if (event && event.data) {
  239. if (event.data.transactionToken && this.transactionApi.isValidTransaction(event.data.transactionToken)) {
  240. // create a sub transaction token
  241. transactionToken = this.transactionApi.startTransaction(event.data.transactionToken);
  242. } else {
  243. if (event.data.undoRedoTransactionId) {
  244. // create a new transaction with the legacy undoRedoTransactionId
  245. transactionToken = this.transactionApi.startTransactionById(event.data.undoRedoTransactionId);
  246. } else {
  247. // create a new transaction from scratch
  248. transactionToken = this.transactionApi.startTransaction();
  249. }
  250. event.data.transactionToken = transactionToken;
  251. }
  252. } else {
  253. transactionToken = this.transactionApi.startTransaction();
  254. event.data = {
  255. transactionToken: transactionToken
  256. };
  257. }
  258. return transactionToken;
  259. },
  260. /**
  261. * Widget Life cycle handler - gets called when board spec gets changed e.g. when undo/redo happens.
  262. *
  263. * For all events, notify the appropriate support object(s) that it changed (so it can notify the views)
  264. * For external events, trigger a 'dw:'<name> (to be caught and processed by other widgets)
  265. *
  266. * @param options The updated model
  267. */
  268. _onModelChange: function _onModelChange(event) {
  269. var _this2 = this,
  270. _arguments = arguments;
  271. if (event.data && event.data.saveOnly) {
  272. return;
  273. }
  274. // TODO - temporary until the events cleanup is complete
  275. // we no longer need to send intermediate events for properties and localFiters and searchFlter
  276. if (['properties', 'localFilters', 'searchFilters', 'visId'].indexOf(event.name) !== -1) {
  277. return;
  278. }
  279. var transactionToken = this._createEventTransactionToken(event);
  280. // Reset error state on change of page context.
  281. if (this.visAPI) {
  282. this.visAPI.clearModelInvalid();
  283. }
  284. this.readyDfd.promise.then(function () {
  285. // execute super class
  286. DeprecateWidgetBase.inherited('_onModelChange', _this2, _arguments);
  287. }).finally(function () {
  288. _this2.trigger('dwChange:' + event.name, event, _this2);
  289. _this2.transactionApi.endTransaction(transactionToken);
  290. });
  291. /*
  292. * If the model has changed and we are being told about it from the UndoRedoController then we should probably
  293. * update our properties spec. Of course, we only really need to if we are in focus. If we aren't then the
  294. * properties are refreshed anyway when we gain focus. Lucky for us, this is actually all taken care of in the
  295. * WidgetBase object we inherit from. Yeah us!
  296. */
  297. DeprecateWidgetBase.inherited('_onModelChange', this, arguments);
  298. },
  299. getUnavailableLocalFilter: function getUnavailableLocalFilter() {
  300. return this.visModelManager.filterSupport.getUnavailableLocalFilter();
  301. },
  302. updateMissingFilters: function updateMissingFilters() {
  303. this.visModelManager.filterSupport.updateMissingFilters();
  304. },
  305. resize: function resize(options) {
  306. if (!this.visAPI || !this.el) {
  307. return;
  308. }
  309. this.visAPI.resize(this.$el.innerWidth(), this.$el.innerHeight(), options);
  310. },
  311. /**
  312. * This method checks if the property specified is one of the
  313. * vis properties that we can override.
  314. * @param property - property of interest
  315. * @returns true if its one of the overridable properties.
  316. */
  317. isAnOverridableVisProperty: function isAnOverridableVisProperty(property) {
  318. // TODO: we should build this automatically fro the viz definitions
  319. var asOverride = ['fillDirection', 'legendPosition', 'lineColor', 'maintainAxisScales', 'showItemLabel', 'colorPalette', 'symbolShape', 'symbolFill', 'hideLegend', 'elementColor', 'interpolation', 'shortNumbers', 'hideAxisTitleLabels', 'heatScalePalette', 'contColorPalette', 'hideRadialTitle', 'hideRadialValue', 'valueColor', 'hideLabel', 'hideValue', 'hideTreeMapLeafLabels', 'pieAsDonut', 'hideGridLines', 'hideSymbols', 'hideDataLines', 'transpose', 'rangeSlider', 'labelLocation', 'condColorPalette', 'condColorOrder', 'hideSummaries', 'legend.position', 'donutRadius', 'labelLocation', 'lineWithPoints.symbol', 'itemLabel.display', 'tiledmap.style', 'labels.visible', 'label.format'];
  320. return asOverride.indexOf(property) !== -1;
  321. },
  322. /**
  323. * Returns the conditional color palette with the given name
  324. * @param paletteName - conditional color palette name
  325. * @returns the conditional color palette
  326. */
  327. getConditionalPalette: function getConditionalPalette(paletteName) {
  328. return this.colorsService.getPalette({
  329. paletteId: paletteName,
  330. type: 'ConditionalPalette',
  331. defaultIfNotFound: true
  332. });
  333. },
  334. /**
  335. * return new array of colors with 'at' property replaced with value in reverse order.
  336. * example:
  337. * input palette: [
  338. * {"at":"0.0%","color":"#000033"},
  339. * {"at":"50.0%","color":"#319bd4"},
  340. * {"at":"100%", "color": "#EEEEFF"}
  341. * ]
  342. * output palette: [
  343. * {"at":"100.0%","color":"#000033"},
  344. * {"at":"50.0%","color":"#319bd4"},
  345. * {"at":"0%", "color": "#EEEEFF"}
  346. * ]
  347. */
  348. _reverseColorPointAt: function _reverseColorPointAt(palette) {
  349. //Reverse 'at' value
  350. var newPalette = _.map(palette, _.clone);
  351. var count = newPalette.length;
  352. _.each(newPalette, function (item, idx) {
  353. var reverseIdx = count - idx - 1;
  354. var newAt = palette[reverseIdx].at;
  355. item.at = newAt;
  356. });
  357. return newPalette;
  358. },
  359. /**
  360. * The following method is called when the heat scale palette property is changed by the
  361. * user in the properties panel.
  362. * @param info - information needed to change the heat scale palette property to the
  363. * state the user specified.
  364. */
  365. onHeatScalePaletteChanged: function onHeatScalePaletteChanged(info) {
  366. // For heat scale palette order we just need to handle it like any other property
  367. // change in the data widget base.
  368. this.onPropertyUpdate(info);
  369. },
  370. onPaletteDeleted: function onPaletteDeleted(_ref) {
  371. var paletteId = _ref.paletteId;
  372. this.onCustomPaletteChanged(paletteId, 'delete');
  373. },
  374. onPaletteUpdated: function onPaletteUpdated(_ref2) {
  375. var paletteId = _ref2.paletteId;
  376. this.onCustomPaletteChanged(paletteId, 'update');
  377. },
  378. onCustomPaletteChanged: function onCustomPaletteChanged() {
  379. // Sub widgets that have palette properties should override this
  380. },
  381. onColorPaletteChanged: function onColorPaletteChanged(info) {
  382. this.onPropertyUpdate(info);
  383. },
  384. _reMapBundle: function _reMapBundle(bundleDefinition, visDefinitions) {
  385. var def = visDefinitions.find(function (visDefinition) {
  386. return visDefinition.id === bundleDefinition.id;
  387. });
  388. if (!def) {
  389. //TODO: Remove this condition
  390. def = visDefinitions.find(function (visDefinition) {
  391. return visDefinition.id === bundleDefinition.minimalVisId;
  392. });
  393. }
  394. return def;
  395. },
  396. /**
  397. * UI update support function: Update the vis properties with the given properties
  398. *
  399. * This function is called to update the widget model in response to a user change to the UI for an
  400. * overridable property (one that is persisted to the widgetModel).
  401. *
  402. * It is done by silently synching the properties collection to the UI updates, then serializing
  403. * that colletion into the widget model. Views update themselves via the onModelChange event when
  404. * the widgetModel set is processed. (This is important because undo/redo does NOT call this function).
  405. *
  406. * @param updatedProperties New set of properties to update the widget with
  407. * @param options Update options:
  408. */
  409. updateVisProperties: function updateVisProperties(updatedProperties) {
  410. var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
  411. var extendedOptions = _.extend({}, options, this.boardModel.getLanguageModelOptions(true));
  412. // Update the properties on the vismodel
  413. this.model.properties.set(updatedProperties, _.extend({
  414. merge: true,
  415. remove: false
  416. }, extendedOptions));
  417. },
  418. _getInteractionConfig: function _getInteractionConfig() {
  419. return this.dashboardApi.getAppConfig('interactions') || {};
  420. },
  421. /**
  422. * Check whether a particular interaction is enabled.
  423. * Perspective drives this config.
  424. *
  425. * @param {string} name - interaction name
  426. *
  427. * @return {boolean} TRUE if interaction is enabled and FALSE if not
  428. */
  429. _isInteractionEnabled: function _isInteractionEnabled(name) {
  430. var config = this._getInteractionConfig();
  431. if (config.hasOwnProperty(name) && [false, 'false'].indexOf(config[name]) !== -1) {
  432. return false;
  433. }
  434. return true;
  435. },
  436. doesWidgetSupportContextualGrid: function doesWidgetSupportContextualGrid() {
  437. var visualization = this._currVis;
  438. if (!visualization) {
  439. return false;
  440. } else if (visualization.doesVisPropertyMatchExpected('isMultilayersWidget', true)) {
  441. return false;
  442. } else if (visualization.doesVisPropertyMatchExpected('noDataQuery', true)) {
  443. return false;
  444. }
  445. return true;
  446. },
  447. suppressAnimations: function suppressAnimations(suppress) {
  448. if (this.visModelManager) {
  449. this.visModelManager.setSuppressViewAnimations(suppress);
  450. }
  451. },
  452. _getRefreshValueInUnits: function _getRefreshValueInUnits(value, timeUnit) {
  453. var maxIntervalForUnits = this._getMaxRefreshValuesForUnits(timeUnit);
  454. return Math.min(maxIntervalForUnits, value);
  455. },
  456. onPropertyUpdate: function onPropertyUpdate(info) {
  457. DeprecateWidgetBase.inherited('onPropertyUpdate', this, arguments);
  458. if (info.category === 'queryRefresh' && info.item) {
  459. var value = info.item.value ? this._getRefreshValueInUnits(info.item.value, info.item.unit) : null;
  460. this.model.set({
  461. 'queryRefresh': $.extend(info.item, {
  462. value: value
  463. })
  464. });
  465. }
  466. },
  467. validateInput: function validateInput(options) {
  468. var interval = options.value;
  469. var isValid = interval && $.isNumeric(interval);
  470. if (isValid) {
  471. interval = Math.ceil(interval);
  472. isValid = this._getTimeIntervalInSeconds(interval, options.unit) >= 5;
  473. }
  474. return isValid;
  475. },
  476. /**
  477. * @param timeUnit - 'seconds', 'minutes', 'hours'
  478. * @returns max seconds for the specified timeUnit
  479. *
  480. */
  481. _getMaxRefreshValuesForUnits: function _getMaxRefreshValuesForUnits(timeUnit) {
  482. /*
  483. * The browser method used to provide a timed delay between refresh calls has
  484. * a max size of a signed integer. We must ensure we stay below this number
  485. * depending on the time unit
  486. */
  487. var maxIntervalInSeconds = (Math.pow(2, 31) - 1) / 1000;
  488. var maxForTimeUnit;
  489. var maxTime;
  490. switch (timeUnit) {
  491. case 'minutes':
  492. maxForTimeUnit = maxIntervalInSeconds / 60;
  493. maxTime = Math.ceil(maxForTimeUnit - 1);
  494. break;
  495. case 'hours':
  496. maxForTimeUnit = maxIntervalInSeconds / 3600;
  497. maxTime = Math.ceil(maxForTimeUnit - 1);
  498. break;
  499. default:
  500. // includes seconds
  501. maxTime = Math.ceil(maxIntervalInSeconds - 1);
  502. }
  503. return maxTime;
  504. },
  505. _getTimeIntervalInSeconds: function _getTimeIntervalInSeconds(timeIntervalInSeconds, timeUnit) {
  506. var result = null;
  507. if ($.isNumeric(timeIntervalInSeconds)) {
  508. // Need to guard against setting out of bound values for different units.
  509. var maxIntervalInSeconds = this._getMaxRefreshValuesForUnits(timeUnit);
  510. switch (timeUnit) {
  511. case 'minutes':
  512. result = Math.min(maxIntervalInSeconds, timeIntervalInSeconds *= 60);
  513. break;
  514. case 'hours':
  515. result = Math.min(maxIntervalInSeconds, timeIntervalInSeconds *= 3600);
  516. break;
  517. default:
  518. // includes seconds
  519. result = Math.min(maxIntervalInSeconds, timeIntervalInSeconds);
  520. }
  521. }
  522. return result;
  523. },
  524. registerRefreshTimer: function registerRefreshTimer() {
  525. this.clearRefreshTimer();
  526. var queryRefreshInfo = this.get('queryRefresh');
  527. if (queryRefreshInfo) {
  528. this._startRefreshTimer(queryRefreshInfo);
  529. this.trigger('dwChange:refreshTimerIndicator', {
  530. autoRefresh: queryRefreshInfo.autoRefresh
  531. });
  532. }
  533. },
  534. _startRefreshTimer: function _startRefreshTimer(queryRefreshInfo) {
  535. if (!queryRefreshInfo || !queryRefreshInfo.autoRefresh || !queryRefreshInfo.value) {
  536. return;
  537. }
  538. this.visibilityHandler = function () {
  539. if (this._isDashboardActive === true) {
  540. if (document.hidden || !document.visibilityState) {
  541. this._isTimerActive = false;
  542. } else {
  543. this._isTimerActive = true;
  544. }
  545. }
  546. }.bind(this);
  547. this._isTimerActive = true;
  548. this._queryRefreshFinished = true;
  549. this._setLastRefreshedTime();
  550. this._refreshTimer = setInterval(function () {
  551. if (this._isTimerActive && this._queryRefreshFinished) {
  552. $(document).on('visibilitychange', this.visibilityHandler);
  553. this._autoRefresh();
  554. }
  555. }.bind(this), this._getTimeIntervalInSeconds(queryRefreshInfo.value, queryRefreshInfo.unit) * 1000);
  556. },
  557. _autoRefresh: function _autoRefresh() {
  558. if (!this.visAPI) {
  559. return;
  560. }
  561. this._queryRefreshFinished = false;
  562. if (this._currVis) {
  563. this._currVis.animationType = this._currVis.ANIMATION_TYPES.TRANSITION;
  564. }
  565. return this.reRender( /*extraInfo*/{
  566. sender: 'realtimeRefresh',
  567. queryRefresh: this.model.queryRefresh
  568. }).then(function () {
  569. this._queryRefreshFinished = true;
  570. this._setLastRefreshedTime();
  571. }.bind(this), function (e) {
  572. // If error details is turned on, then don't let the timer continue. This is so for long running
  573. // load tests the first error to occure will stay on the widget
  574. if (!window.dashboardErrorDetailsEnabled) {
  575. this._queryRefreshFinished = true;
  576. }
  577. throw e;
  578. }.bind(this));
  579. },
  580. _setLastRefreshedTime: function _setLastRefreshedTime() {
  581. this.model.set({
  582. 'queryRefresh': $.extend(this.get('queryRefresh'), {
  583. lastRefreshed: new Date().getTime()
  584. })
  585. }, {
  586. silent: true
  587. });
  588. },
  589. clearRefreshTimer: function clearRefreshTimer() {
  590. if (this._refreshTimer) {
  591. clearInterval(this._refreshTimer);
  592. this._refreshTimer = null;
  593. if (this.visibilityHandler) {
  594. $(document).off('visibilitychange', this.visibilityHandler);
  595. this.visibilityHandler = null;
  596. }
  597. }
  598. },
  599. /**
  600. * Abstract function. The implementation should be in subclasses.
  601. */
  602. _rebuildVis: function _rebuildVis() /* widget, undoRedo, forceRerender */{},
  603. /**
  604. * @deprecated should be removed once we no longer use old query api
  605. * Save the prompt spec with picked values to widget.
  606. */
  607. savePromptSpec: function savePromptSpec(promptSpec) {
  608. var oSavedPrompts = this.get('savedPrompts') || {};
  609. oSavedPrompts[promptSpec.name] = promptSpec;
  610. this.model.set({
  611. 'savedPrompts': oSavedPrompts
  612. });
  613. this._updateFilterIndicator();
  614. },
  615. /**
  616. * @deprecated should be removed once we no longer use old query api
  617. */
  618. getSavedPrompts: function getSavedPrompts() {
  619. return this.get('savedPrompts') || {};
  620. },
  621. /**
  622. * @deprecated should be removed once we no longer use old query api
  623. */
  624. setPromptSpecs: function setPromptSpecs(promptSpecs) {
  625. this.model.set({
  626. 'savedPrompts': promptSpecs
  627. });
  628. this._updateFilterIndicator();
  629. },
  630. /**
  631. * @deprecated should be removed once we no longer use old query api
  632. */
  633. _updateFilterIndicator: function _updateFilterIndicator() {
  634. if (this._currVis && this._currVis.filterIndicator) {
  635. this._currVis.filterIndicator.update();
  636. }
  637. },
  638. /**
  639. * @deprecated should be removed once we no longer use old query api
  640. */
  641. getPromptSpec: function getPromptSpec(promptName) {
  642. var oSavedPrompts = this.get('savedPrompts');
  643. if (!promptName) {
  644. return oSavedPrompts;
  645. }
  646. return oSavedPrompts ? oSavedPrompts[promptName] : null;
  647. },
  648. /**
  649. * TODO remove method and all calls to is once new queryApi goes live
  650. */
  651. useNewQueryApi: function useNewQueryApi() {
  652. if (this._useNewQueryApi !== undefined) {
  653. return this._useNewQueryApi;
  654. }
  655. if (['kpi', 'summary', 'crosstab', 'JQGrid'].indexOf(this.visAPI.getDefinition().id) !== -1) {
  656. return true;
  657. }
  658. return !this.dashboardApi.getGlassCoreSvc('.FeatureChecker').checkValue('dashboard', 'queryApi', 'disabled');
  659. },
  660. rePrompt: function rePrompt(sPromptName) {
  661. var _this3 = this;
  662. if (!sPromptName) {
  663. this.logger.error('Could not find prompt info to rePrompt', sPromptName, this);
  664. return Promise.resolve();
  665. }
  666. var savedPromptSpec = this.getPromptSpec(sPromptName);
  667. if (!savedPromptSpec) {
  668. this.logger.error('Could not find prompt info for ' + sPromptName, this);
  669. return Promise.resolve();
  670. }
  671. // TODO remove _useAPI logic once licve
  672. if (this.useNewQueryApi()) {
  673. var openSpec = _.extend({}, savedPromptSpec);
  674. openSpec.rePrompt = true;
  675. var prompts = this.dashboardApi.getFeature('Prompts');
  676. var visualization = this.dashboardApi.getCanvas().getContent(this.getId()).getFeature('Visualization.internal');
  677. var savedPrompts = visualization.getSavedPrompts();
  678. return prompts.openPromptView([openSpec], visualization).then(function (oNewPromptSpec) {
  679. savedPrompts.save(oNewPromptSpec[0]);
  680. });
  681. } else {
  682. var oOptions = {
  683. promptSpec: [savedPromptSpec],
  684. id: this.visModelManager.getModuleId(),
  685. 'preferences': this.dashboardApi.getGlassCoreSvc('.UserProfile').preferences
  686. };
  687. _.extend(oOptions, this.visAPI.getQueryExecution().getPromptQueries());
  688. return PromptManager.openPromptView(oOptions).then(function (oNewPromptSpec) {
  689. _this3.savePromptSpec(oNewPromptSpec[0]);
  690. _this3.reRender();
  691. });
  692. }
  693. },
  694. /**
  695. * @public
  696. * Handle the event when a prompt dialog is canceled, i.e. the prompt parameter is not resolved.
  697. * The intend is to:
  698. * 1. remove the widget if the metadata item referencing a prompt is the one dropped to the widget.
  699. * 2. remove the slot with the metadata item referencing a prompt.
  700. */
  701. onCancelPromptDialog: function onCancelPromptDialog() {
  702. if (this.isAuthoringMode) {
  703. this.dashboardApi.undo();
  704. }
  705. },
  706. onUnSupportedPrompt: function onUnSupportedPrompt(message) {
  707. DynamicFileLoader.load(['dashboard-analytics/lib/@waca/core-client/js/core-client/ui/dialogs/ConfirmationDialog']).then(function (modules) {
  708. var dlg = new modules[0]('warning', '', message);
  709. dlg.confirm(function () {
  710. this.onCancelPromptDialog();
  711. }.bind(this));
  712. dlg._cancelCallback = function () {
  713. this.onCancelPromptDialog();
  714. }.bind(this);
  715. }.bind(this));
  716. }
  717. });
  718. return DeprecateWidgetBase;
  719. });
  720. //# sourceMappingURL=DeprecateWidgetBase.js.map