SmartTitleFeatureProvider.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371
  1. 'use strict';
  2. function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
  3. /**
  4. * Licensed Materials - Property of IBM
  5. * IBM Cognos Products: BI Cloud (C) Copyright IBM Corp. 2020
  6. * US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
  7. */
  8. define(['gemini/lib/@waca/dashboard-common/dist/core/APIFactory', './SmartTitleAPI', 'underscore'], function (APIFactory, SmartTitleAPI, _) {
  9. var SmartTitleFeatureProvider = function () {
  10. function SmartTitleFeatureProvider(options) {
  11. var _this = this;
  12. _classCallCheck(this, SmartTitleFeatureProvider);
  13. this._dashboard = options.dashboardAPI;
  14. this._content = options.content;
  15. this._dashboardInternal = options.features['Dashboard.internal'];
  16. this._widgetApiHandlers = {};
  17. //tracking event to detect if this widget was added after dashboard open
  18. //event listener will be removed on render state change
  19. this._addedContent = [];
  20. var canvas = this._dashboard.getCanvas();
  21. if (canvas) {
  22. this._addContentEvent = canvas.on('add:content:child', function (event) {
  23. _this._addedContent.push(event.info.newContentId);
  24. });
  25. }
  26. this._state = {
  27. setupDone: false,
  28. setupCheckDone: false,
  29. initialWidgetRenderDone: false,
  30. shouldUseGeneratedTitle: undefined,
  31. smartTitleEnabled: undefined,
  32. toEnableGeneratedTitle: undefined,
  33. toSetNoTitle: undefined,
  34. toSetSmartTitle: undefined
  35. };
  36. }
  37. SmartTitleFeatureProvider.prototype._isSmartTitleFeatureEnabled = function _isSmartTitleFeatureEnabled() {
  38. return !this._dashboard.getGlassCoreSvc('.FeatureChecker').checkValue('dashboard', 'SmartTitle', 'disabled');
  39. };
  40. SmartTitleFeatureProvider.prototype._isSmartTitleEnabled = function _isSmartTitleEnabled() {
  41. return this._isSmartTitleFeatureEnabled() && this._state.smartTitleEnabled;
  42. };
  43. SmartTitleFeatureProvider.prototype.getAPI = function getAPI() {
  44. return APIFactory.createAPI(this, [SmartTitleAPI]); //each content object has its own 'feature' impl
  45. };
  46. SmartTitleFeatureProvider.prototype.initialize = function initialize() {
  47. this.prepare();
  48. };
  49. SmartTitleFeatureProvider.prototype.prepare = function prepare() {
  50. if (!this._isSmartTitleFeatureEnabled()) {
  51. return;
  52. }
  53. this.upgradeIfNeeded();
  54. this._setupTitle();
  55. this._addChangeHandlerForTitleModeProperty();
  56. };
  57. SmartTitleFeatureProvider.prototype._getModelAttr = function _getModelAttr(name) {
  58. var boardModel = this._dashboardInternal.getBoardModel();
  59. var id = this._content.getId();
  60. var widgetModel = boardModel && boardModel.getWidgetModel(id);
  61. if (widgetModel) {
  62. return widgetModel.get(name);
  63. }
  64. return undefined;
  65. };
  66. SmartTitleFeatureProvider.prototype._setModelAttr = function _setModelAttr(attribs) {
  67. var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : { silent: true };
  68. var boardModel = this._dashboardInternal.getBoardModel();
  69. var id = this._content.getId();
  70. var widgetModel = boardModel && boardModel.getWidgetModel(id);
  71. widgetModel && widgetModel.set(attribs, options);
  72. };
  73. SmartTitleFeatureProvider.prototype._setProp = function _setProp(name, value) {
  74. var _this2 = this;
  75. if (this._state.initialWidgetRenderDone) {
  76. this._content.setPropertyValue(name, value);
  77. } else {
  78. var stateAPI = this._content.getFeature('state');
  79. stateAPI.whenStatusChanges('rendered').then(function () {
  80. //Content api does not allow SKIP undo/red0 event yet. Need to set in the model and skip the event for the first time
  81. //this._content.setPropertyValue(name, value);
  82. var boardModel = _this2._dashboardInternal.getBoardModel();
  83. var id = _this2._content.getId();
  84. var widgetModel = boardModel && boardModel.getWidgetModel(id);
  85. if (widgetModel) {
  86. var attribs = {};
  87. attribs[name] = value;
  88. widgetModel.set(attribs, { payloadData: { skipUndoRedo: true } });
  89. }
  90. });
  91. }
  92. };
  93. SmartTitleFeatureProvider.prototype.upgradeIfNeeded = function upgradeIfNeeded() {
  94. //TODO: feature manages its own upgrade, but could we allow others to customize upgrade process ?
  95. var container = this._content.getContainer();
  96. var containerType = container && container.getType();
  97. var forceSmartTitle = containerType && containerType === 'exploreCard';
  98. if (forceSmartTitle) {
  99. var attribs = {
  100. showTitle: undefined,
  101. titleMode: 'smartTitle'
  102. };
  103. this._setModelAttr(attribs);
  104. this._setProp('titleMode', 'smartTitle');
  105. this._setProp('showTitle', undefined);
  106. return;
  107. }
  108. var showTitle = this._getModelAttr('showTitle');
  109. var name = this._getModelAttr('name');
  110. var titleMode = this._getModelAttr('titleMode');
  111. if (showTitle !== undefined) {
  112. var _attribs = {
  113. showTitle: undefined
  114. };
  115. if (name && (!titleMode || titleMode !== 'noTitle')) {
  116. if (showTitle === true) {
  117. _attribs.titleMode = 'customTitle';
  118. this._setProp('titleMode', 'customTitle');
  119. } else {
  120. _attribs.titleMode = 'noTitle';
  121. this._setProp('titleMode', 'noTitle');
  122. }
  123. }
  124. this._setModelAttr(_attribs);
  125. this._setProp('showTitle', undefined);
  126. }
  127. };
  128. SmartTitleFeatureProvider.prototype._setupTitle = function _setupTitle() {
  129. var _this3 = this;
  130. //if no title set & showTitle prop is true and generatedTitle is undefined, enable smart title
  131. //if showTitle is true & generatedTitle true, enable smart title (does not matter if title is set or not)
  132. var stateAPI = this._content.getFeature('state');
  133. stateAPI.whenStatusChanges('rendered').then(function () {
  134. _this3._state.initialWidgetRenderDone = true;
  135. });
  136. this._stateInitPromise = stateAPI.whenStatusChanges('rendering');
  137. this._stateInitPromise.then(function () {
  138. _this3._ensureStateCheckOnInit();
  139. _this3._state.setupCheckDone = true;
  140. if (!_this3._state.setupDone) {
  141. _this3._state.setupDone = true;
  142. if (_this3._state.toEnableGeneratedTitle && _this3._state.toSetSmartTitle) {
  143. _this3.enableAndSetSmartTitle();
  144. } else if (_this3._state.toEnableGeneratedTitle) {
  145. _this3._enableSmartTitle();
  146. } else if (_this3._state.toSetNoTitle) {
  147. _this3._setProp('titleMode', 'noTitle');
  148. }
  149. }
  150. });
  151. };
  152. SmartTitleFeatureProvider.prototype._removeAddContentEventListener = function _removeAddContentEventListener() {
  153. if (this._addContentEvent && this._addContentEvent.remove) {
  154. this._addContentEvent.remove();
  155. this._addContentEvent = null;
  156. }
  157. };
  158. SmartTitleFeatureProvider.prototype._ensureStateCheckOnInit = function _ensureStateCheckOnInit() {
  159. this._removeAddContentEventListener();
  160. var id = this._content.getId();
  161. var isWidgetLoadedAfterDashboardOpen = this._addedContent.indexOf(id) !== -1;
  162. var name = this._getModelAttr('name');
  163. var titleMode = this._content.getPropertyValue('titleMode');
  164. var shouldUseGeneratedTitle = false;
  165. if (name) {
  166. if (titleMode === 'smartTitle' || !titleMode && isWidgetLoadedAfterDashboardOpen) {
  167. this._state.toEnableGeneratedTitle = true;
  168. shouldUseGeneratedTitle = true;
  169. } else if (titleMode !== 'customTitle') {
  170. this._setProp('titleMode', 'noTitle');
  171. }
  172. } else {
  173. if (titleMode === undefined) {
  174. if (name !== undefined && name !== null && name === '' && !isWidgetLoadedAfterDashboardOpen) {
  175. this._state.toSetNoTitle = true;
  176. } else {
  177. //newly added widget
  178. this._state.toEnableGeneratedTitle = true;
  179. this._state.toSetSmartTitle = true;
  180. shouldUseGeneratedTitle = true;
  181. }
  182. } else if (titleMode === 'smartTitle') {
  183. this._state.toEnableGeneratedTitle = true;
  184. this._state.toSetSmartTitle = true;
  185. shouldUseGeneratedTitle = true;
  186. }
  187. }
  188. this._state.shouldUseGeneratedTitle = shouldUseGeneratedTitle;
  189. return this._state;
  190. };
  191. SmartTitleFeatureProvider.prototype.shouldUseGeneratedTitle = function shouldUseGeneratedTitle() {
  192. var smartTitleEnabledConfig = this._dashboard.getAppConfig('smartTitle');
  193. if (smartTitleEnabledConfig) {
  194. var state = this._ensureStateCheckOnInit();
  195. return state.shouldUseGeneratedTitle;
  196. }
  197. return false;
  198. };
  199. SmartTitleFeatureProvider.prototype._addChangeHandlerForTitleModeProperty = function _addChangeHandlerForTitleModeProperty() {
  200. var _this4 = this;
  201. this._content.on('change:property:titleMode', function (event) {
  202. if (event.info.value === 'smartTitle') {
  203. _this4.enableAndSetSmartTitle();
  204. } else {
  205. _this4.disableSmartTitle(event.info.value);
  206. }
  207. });
  208. };
  209. SmartTitleFeatureProvider.prototype.enableAndSetSmartTitle = function enableAndSetSmartTitle() {
  210. if (this._isSmartTitleEnabled()) {
  211. return;
  212. }
  213. var widgetAPI = this._content.getFeature('WidgetAPI.deprecated');
  214. this._enableSmartTitle();
  215. this._triggerTitleUpdate(widgetAPI, true);
  216. };
  217. SmartTitleFeatureProvider.prototype._enableSmartTitle = function _enableSmartTitle() {
  218. if (this._isSmartTitleEnabled()) {
  219. return;
  220. }
  221. this._state.smartTitleEnabled = true;
  222. var widgetAPI = this._content.getFeature('WidgetAPI.deprecated');
  223. var visAPI = widgetAPI.getVisApi();
  224. this._deregisterListener();
  225. this._widgetApiHandlers = {
  226. _onChangeDefinition: visAPI && visAPI.on('change:definition', this._triggerTitleUpdate.bind(this, widgetAPI))
  227. };
  228. this._setProp('titleMode', 'smartTitle');
  229. };
  230. SmartTitleFeatureProvider.prototype.disableSmartTitle = function disableSmartTitle() {
  231. var newTitleMode = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'customTitle';
  232. if (this._isSmartTitleEnabled() === false) {
  233. return;
  234. }
  235. this._state.smartTitleEnabled = false;
  236. this._deregisterListener();
  237. this._setProp('titleMode', newTitleMode);
  238. };
  239. SmartTitleFeatureProvider.prototype.getTitleState = function getTitleState() {
  240. var name = this._getModelAttr('name');
  241. return {
  242. generatedTitle: this._isSmartTitleEnabled(),
  243. title: name
  244. };
  245. };
  246. SmartTitleFeatureProvider.prototype.shouldSetTitle = function shouldSetTitle(newTitle) {
  247. var name = this._getModelAttr('name');
  248. if (name != newTitle) {
  249. return true;
  250. }
  251. if (this._isTitlePartiallyFormatted(name)) {
  252. return true;
  253. }
  254. return false;
  255. };
  256. SmartTitleFeatureProvider.prototype._isTitlePartiallyFormatted = function _isTitlePartiallyFormatted(name) {
  257. //If the rawTitle can't be found in the titleHtml, then its been formatted.
  258. return !this._findRawTitleInHtml(name);
  259. };
  260. SmartTitleFeatureProvider.prototype.getTitleHtmlWithPreviousFormat = function getTitleHtmlWithPreviousFormat(title) {
  261. //If the previous unformatted title is found in the html, replace it with the new title to preserve the surrounding format
  262. var htmlTitleInfo = this._findRawTitleInHtml(this._getModelAttr('name'));
  263. if (htmlTitleInfo) {
  264. htmlTitleInfo.spanContainingTheTitle.innerHTML = _.escape(title);
  265. var newTitleHtml = htmlTitleInfo.titleRoot.innerHTML;
  266. return newTitleHtml;
  267. }
  268. //Null means the title itself had mixed format and can't be replaced.
  269. return null;
  270. };
  271. SmartTitleFeatureProvider.prototype._findRawTitleInHtml = function _findRawTitleInHtml(rawTitle) {
  272. var titleHtml = this._getModelAttr('titleHtml');
  273. if (rawTitle && titleHtml) {
  274. //When escaped html is set in the title control, some characters are changed (eg encoded single quotes are decoded)
  275. //Use innerHTML for both titleHtml and the escaped rawTitle to make sure things match.
  276. var rawTitleDiv = document.createElement('div');
  277. rawTitleDiv.innerHTML = _.escape(rawTitle);
  278. //The only titleHtml structure we count on is that there's a span somewhere with a title that matches rawTitle.
  279. var root = document.createElement('div'); //Create a node and set its html content to be titleHtml.
  280. root.innerHTML = titleHtml;
  281. var spans = root.getElementsByTagName('span');
  282. var spanContainingTheTitle = null;
  283. for (var i = 0; i < spans.length; ++i) {
  284. if (spans[i].innerHTML === rawTitleDiv.innerHTML) {
  285. spanContainingTheTitle = spans[i];
  286. }
  287. }
  288. return spanContainingTheTitle && { spanContainingTheTitle: spanContainingTheTitle, titleRoot: root };
  289. }
  290. return null;
  291. };
  292. SmartTitleFeatureProvider.prototype.destroy = function destroy() {
  293. this._deregisterListener();
  294. return Promise.resolve(true);
  295. };
  296. SmartTitleFeatureProvider.prototype._deregisterListener = function _deregisterListener() {
  297. if (this._widgetApiHandlers._onChangeDefinition) {
  298. this._widgetApiHandlers._onChangeDefinition.remove();
  299. this._widgetApiHandlers._onChangeDefinition = null;
  300. }
  301. this._removeAddContentEventListener();
  302. };
  303. SmartTitleFeatureProvider.prototype._triggerTitleUpdate = function _triggerTitleUpdate(widgetAPI) {
  304. if (widgetAPI) {
  305. widgetAPI.updateTitle();
  306. }
  307. };
  308. return SmartTitleFeatureProvider;
  309. }();
  310. return SmartTitleFeatureProvider;
  311. });
  312. //# sourceMappingURL=SmartTitleFeatureProvider.js.map