LayoutBaseView.js 46 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418
  1. 'use strict';
  2. /**
  3. * Licensed Materials - Property of IBM
  4. * IBM Cognos Products: BI Cloud (C) Copyright IBM Corp. 2013, 2020
  5. * US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
  6. */
  7. define(['../../../lib/@waca/core-client/js/core-client/ui/core/Class', '../../../view/features/content/contentViewDom/api/impl/ContentViewDomImpl', '../../../lib/@waca/baglass/js/baglass/utils/Utils', 'jquery', 'underscore', '../../../lib/@waca/core-client/js/core-client/utils/ClassFactory', '../../../app/nls/StringResources', '../../widgets/PropertiesUtil', 'react-dom', '../../../lib/@waca/dashboard-common/dist/ui/CenterLoadingSpinner', '../../../api/impl/Layout', '../LayoutHelper', '../../../lib/@waca/core-client/js/core-client/ui/dialogs/ConfirmationDialog', '../../widgets/PropertyListUtil', '../../util/ContentRegistryUtil', '../../../app/util/UnderscoreExt'], function (Class, ContentViewDomImpl, Utils, $, _, ClassFactory, StringResources, PropertiesUtil, ReactDOM, CenterLoadingSpinner, LayoutApi, LayoutHelper, ConfirmationDialog, PropertiesListUtil, ContentRegistryUtil) {
  8. var MINIMUM_PAGESIZE = { width: 320, height: 200 };
  9. var PAGESIZES = {
  10. '16:9': {
  11. 'width': 1280,
  12. 'height': 720
  13. },
  14. '4:3': {
  15. 'width': 1280,
  16. 'height': 960
  17. },
  18. 'letter': {
  19. 'width': 612,
  20. 'height': 792
  21. },
  22. 'legal': {
  23. 'width': 612,
  24. 'height': 1008
  25. },
  26. 'a4': {
  27. 'width': 595,
  28. 'height': 842
  29. },
  30. 'tabloid': {
  31. 'width': 792,
  32. 'height': 1224
  33. },
  34. 'infographic': {
  35. 'width': 512,
  36. 'height': 1024
  37. }
  38. };
  39. var BaseLayout = Class.extend({
  40. init: function init(options) {
  41. BaseLayout.inherited('init', this, arguments);
  42. this.layoutController = options.layoutController;
  43. this.isAuthoringMode = this.layoutController.isAuthoring;
  44. this.model = options.model;
  45. this.id = this.model.id;
  46. this.parentLayout = options.parentLayout;
  47. this.glassContext = options.services.biGlass.glassContext;
  48. this.appSettings = options.appSettings;
  49. this.dashboardApi = options.dashboardApi;
  50. this.additionalWidgetData = options.additionalWidgetData;
  51. this.contentFeatureLoader = options.contentFeatureLoader;
  52. this.content = options.content;
  53. if (this.dashboardApi) {
  54. this.colorsService = this.dashboardApi.getFeature('Colors');
  55. this.translationService = this.dashboardApi.getDashboardCoreSvc('TranslationService');
  56. this.contentTypeRegistry = this.dashboardApi.getFeature('ContentTypeRegistry');
  57. }
  58. var nodeId = this.layoutController.modelIdToNodeId(this.id);
  59. var widgetExistsInDOM = false;
  60. if (this.parentLayout) {
  61. this.domNode = $(this.parentLayout.domNode).find('#' + nodeId)[0];
  62. // If a widget has already been loaded into the DOM (outside canvas)
  63. // bring it in the canvas
  64. if (!this.domNode) {
  65. this.domNode = document.getElementById(nodeId);
  66. if (this.domNode) {
  67. widgetExistsInDOM = true;
  68. }
  69. }
  70. } else {
  71. this.domNode = document.getElementById(nodeId);
  72. }
  73. this._attachedHandles = [];
  74. if (this._isTopLevelPage()) {
  75. this._attachedHandles.push(this.model.on('change:pageSize', this.onPageSizeChange.bind(this), this));
  76. }
  77. // If the node does not exist, then we create one
  78. var htmlTemplate = options.services.getSvcSync('htmlTemplates');
  79. if (!this.domNode) {
  80. this.domNode = $(htmlTemplate.getHtml(this.model, this.model.boardModel.widgetInstances))[0];
  81. } else if (widgetExistsInDOM) {
  82. //bring existing widget into a layout view
  83. var n = $(this.domNode);
  84. var children = n.children();
  85. var prev = n;
  86. this.domNode = $(htmlTemplate.getHtml(this.model, this.model.boardModel.widgetInstances))[0];
  87. var n$ = $(this.domNode);
  88. children.appendTo(n$);
  89. prev.remove();
  90. // resize the node since it previously existed outside of the canvas.
  91. this.layoutController.layoutReady(this.model.id).then(this.onResize.bind(this));
  92. }
  93. this.domNode._layout = this;
  94. this.authorHelper = options.authorHelper; //author mode addon
  95. //static widgets end up using a LayoutBaseView (not a 'Widget') when moving to author mode
  96. //need to save onto the widget chrome event router
  97. this.widgetChromeEventRouter = options.widgetChromeEventRouter;
  98. this.widgetChromeEventRouter_disposeEvents = [];
  99. this.$el = $(this.domNode);
  100. this.logger = this.glassContext.getCoreSvc('.Logger');
  101. this.services = options.services;
  102. this.api = new LayoutApi(this);
  103. if (!this.eventRouter) {
  104. this.eventRouter = this.layoutController.eventRouter;
  105. if (this.eventRouter) {
  106. this.eventRouter.on('properties:hasRendered', this.setInitialEnabledState, this);
  107. this._enableToggleEvents();
  108. // While it would be better to listen to change:layoutPositioning and change:pageSize events,
  109. // those are listened to by the child layout classes and need to be processed before we resize
  110. // the layout. Listen to this event which will be fired after the properties are modified.
  111. this.eventRouter.on('layout:resize', this._onResize, this);
  112. }
  113. }
  114. this._debouncedOnResize = _.doubleDebounce(this._onResize.bind(this), 200);
  115. this._subLayoutViews = [];
  116. },
  117. setInitialEnabledState: function setInitialEnabledState() {
  118. // TODO : using events to achieve this seems wrong and hacky. We must find a better way to achieve this
  119. if (this.model.getValueFromSelfOrParent('layoutPositioning') !== 'relative') {
  120. this.eventRouter.trigger('properties:updateEnabled', { propertyName: 'fitPage', enabled: false });
  121. }
  122. },
  123. _enableToggleEvents: function _enableToggleEvents() {
  124. this.model.on('change:fitPage', this._updatePropertiesPaneToggle, this);
  125. this.model.on('change:showGrid', this._updatePropertiesPaneToggle, this);
  126. this.model.on('change:snapGrid', this._updatePropertiesPaneToggle, this);
  127. this.model.on('change:snapObjects', this._updatePropertiesPaneToggle, this);
  128. },
  129. _disableToggleEvents: function _disableToggleEvents() {
  130. this.model.off('change:fitPage', this._updatePropertiesPaneToggle.bind(this), this);
  131. this.model.off('change:showGrid', this._updatePropertiesPaneToggle.bind(this), this);
  132. this.model.off('change:snapGrid', this._updatePropertiesPaneToggle.bind(this), this);
  133. this.model.off('change:snapObjects', this._updatePropertiesPaneToggle.bind(this), this);
  134. },
  135. /**
  136. * Updates the state of a properties pane toggle after an undo/redo
  137. */
  138. _updatePropertiesPaneToggle: function _updatePropertiesPaneToggle(event) {
  139. var checked = event.value || false;
  140. this.eventRouter.trigger('properties:setValue', { propertyName: event.name, value: checked });
  141. },
  142. /**
  143. * Return the id of the node associated with the model id. If we start prefixing the node, this method can calculate the proper node id.
  144. */
  145. getNodeId: function getNodeId(modelId) {
  146. return this.layoutController.modelIdToNodeId(modelId);
  147. },
  148. _destroyAuthoringHelper: function _destroyAuthoringHelper() {
  149. if (this.authorHelper) {
  150. this.authorHelper.destroy();
  151. this.authorHelper = null;
  152. }
  153. },
  154. destroy: function destroy(event) {
  155. this._subLayoutViews = null;
  156. this.widgetChromeEventRouter_disposeEvents.forEach(function (dispose) {
  157. return dispose.remove();
  158. });
  159. this.widgetChromeEventRouter_disposeEvents = [];
  160. if (this._debouncedOnResize) {
  161. this._debouncedOnResize.cancel();
  162. }
  163. this._destroyAuthoringHelper();
  164. if (this.eventRouter) {
  165. this.eventRouter.off('properties:hasRendered', this.setInitialEnabledState, this);
  166. this._disableToggleEvents();
  167. this.eventRouter.off('layout:resize', this._onResize, this);
  168. }
  169. this._attachedHandles.forEach(function (handle) {
  170. return handle.remove();
  171. });
  172. this._attachedHandles = [];
  173. if (this.domNode) {
  174. var $domNode = $(this.domNode);
  175. $domNode.off('contextmenu.baselayout');
  176. $('.page,.widget', $domNode).each(function () {
  177. if (this._layout && this._layout.destroy) {
  178. this._layout.destroy(event);
  179. }
  180. });
  181. $domNode.remove();
  182. this.domNode._layout = null;
  183. }
  184. if (this._contentTitle) {
  185. this._contentTitle = null;
  186. }
  187. if (this.layoutController) {
  188. this.layoutController.removeView(this);
  189. }
  190. if (this.api) {
  191. this.api.destroy();
  192. this.api = null;
  193. }
  194. this.layoutController = null;
  195. this.model = null;
  196. this.id = null;
  197. this.parentLayout = null;
  198. this.glassContext = null;
  199. this.appSettings = null;
  200. this.dashboardApi = null;
  201. this.colorsService = null;
  202. this.translationService = null;
  203. this.additionalWidgetData = null;
  204. this.contentFeatureLoader = null;
  205. this.content = null;
  206. this.widgetChromeEventRouter = null;
  207. this.logger = null;
  208. this.services = null;
  209. this.authorHelper = null;
  210. this.domNode = null;
  211. this.layoutController = null;
  212. this._debouncedOnResize = null;
  213. BaseLayout.inherited('destroy', this, arguments);
  214. },
  215. _renderContentTitle: function _renderContentTitle() {
  216. var capabilitiesFeature = ContentRegistryUtil.getCapabilities(this.content);
  217. var supportTitle = capabilitiesFeature ? capabilitiesFeature.getCapabilities()['title'] : false;
  218. if (supportTitle) {
  219. this._contentTitle = this.content.getFeature('ContentTitle.internal');
  220. this.$el.addClass('titleSupported');
  221. return this._contentTitle.render({
  222. id: this.domNode.id,
  223. model: this.model,
  224. widgetChromeEventRouter: this.widgetChromeEventRouter,
  225. eventRouter: this.eventRouter
  226. });
  227. }
  228. },
  229. // lifecycle_cleanup -- this should render but we currently have a render that call onShow.
  230. // clean this up
  231. renderContent: function renderContent() {
  232. var _this2 = this;
  233. var stateApi = this.content.getFeature('state.internal');
  234. stateApi.setStatus(stateApi.STATUS.RENDERING);
  235. if (this._isRendered) {
  236. var promises = this._subLayoutViews.map(function (layout) {
  237. return layout.renderContent();
  238. });
  239. return Promise.all(promises).then(function () {
  240. stateApi.setStatus(stateApi.STATUS.RENDERED);
  241. });
  242. } else {
  243. var _promises = [];
  244. var renderer = this.content.getFeature('renderer');
  245. if (renderer) {
  246. var childNode = this.domNode;
  247. childNode.className = 'widget content ' + this.content.getType();
  248. var canRotate = this.content.getPropertyValue('canRotate');
  249. if (!canRotate) {
  250. childNode.className += ' noRotate';
  251. }
  252. var rendererPromise = renderer.render({
  253. parent: childNode
  254. }).then(function () {
  255. var titleContent = _this2._renderContentTitle();
  256. if (titleContent) {
  257. childNode.prepend(titleContent);
  258. }
  259. _this2.contentFeatureLoader.registerFeature(_this2.content.getId(), 'ContentViewDOM', new ContentViewDomImpl(childNode));
  260. });
  261. _promises.push(rendererPromise);
  262. }
  263. (this.model.items || []).forEach(function (_ref) {
  264. var id = _ref.id;
  265. _promises.push(_this2.layoutController.createLayoutModule(id, _this2, _this2.additionalWidgetData).then(function (layout) {
  266. if (layout) {
  267. _this2._subLayoutViews.push(layout);
  268. return layout.renderContent();
  269. }
  270. }));
  271. });
  272. return Promise.all(_promises).then(function () {
  273. return _this2.registerViewFeatures();
  274. }).then(function () {
  275. stateApi.setStatus(stateApi.STATUS.RENDERED);
  276. _this2.layoutController.markViewAsReady(_this2);
  277. _this2._isRendered = true;
  278. });
  279. }
  280. },
  281. registerViewFeatures: function registerViewFeatures() {
  282. var _this3 = this;
  283. // this will be called from the render content.. which might be called more than once as we switch between author and consume mode
  284. // make sure we only call it once.
  285. if (!this._viewFeatureRegistered) {
  286. this._viewFeatureRegistered = true;
  287. // Add a view dom feature and then register the content-view-features collection
  288. return this.contentFeatureLoader.registerFeature(this.id, 'ContentViewDOM', new ContentViewDomImpl(this.domNode)).then(function () {
  289. return _this3.contentFeatureLoader.registerFeatureCollection(_this3.id, 'com.ibm.bi.dashboard.content-view-features');
  290. });
  291. } else {
  292. return Promise.resolve();
  293. }
  294. },
  295. onResize: function onResize(renderOptions) {
  296. this._debouncedOnResize(renderOptions);
  297. },
  298. _onResize: function _onResize(renderOptions) {
  299. var _this4 = this;
  300. if (this.model.items) {
  301. _.each(this.model.items, function (item) {
  302. var view = _this4.layoutController.getLayoutView(item.id);
  303. if (view && view.onResize) {
  304. // do not try re-sizing hidden elements, as their sizes won't be accurate
  305. if (!view.$el.is(':hidden')) {
  306. view.onResize(renderOptions);
  307. } else {
  308. view.resizeOnShow();
  309. }
  310. }
  311. });
  312. }
  313. },
  314. /**
  315. * Invoked when Widget chrome is selected, derived classes to override
  316. */
  317. onSelect: function onSelect(isGroupSelect) {
  318. if (this.contentTypeRegistry.isTypeRegistered(this.content.getType()) && this.widgetChromeEventRouter && this.isAuthoringMode && !isGroupSelect) {
  319. this.widgetChromeEventRouter.trigger('title:chromeSelected');
  320. }
  321. },
  322. /**
  323. * Invoked when Widget chrome is deselected, derived classes to override
  324. */
  325. onDeselect: function onDeselect() {
  326. if (this.contentTypeRegistry.isTypeRegistered(this.content.getType()) && this.widgetChromeEventRouter && this.isAuthoringMode) {
  327. this.widgetChromeEventRouter.trigger('title:chromeDeselected');
  328. }
  329. },
  330. /**
  331. * Invoked when a hidden layout is shown
  332. */
  333. onShow: function onShow() {
  334. this._callChildrenFunction('onShow');
  335. if (this.isResizeOnShow) {
  336. this.isResizeOnShow = false;
  337. this.onResize();
  338. }
  339. },
  340. /**
  341. * Invoke when a layout is hidden
  342. */
  343. onHide: function onHide() {
  344. this._callChildrenFunction('onHide');
  345. },
  346. /**
  347. * Invoke when a is transitioning from one view to another.
  348. */
  349. onTransition: function onTransition(event) {
  350. return this._callChildrenFunctionAsync('onTransition', event);
  351. },
  352. /**
  353. * Invoke when a layout has transitioned.
  354. */
  355. afterTransition: function afterTransition(event) {
  356. return this._callChildrenFunctionAsync('afterTransition', event);
  357. },
  358. /**
  359. * Indicates that we need to call resize the next time onShow is called.
  360. */
  361. resizeOnShow: function resizeOnShow() {
  362. this.isResizeOnShow = true;
  363. },
  364. _callChildrenFunctionAsync: function _callChildrenFunctionAsync(name, event) {
  365. var _this5 = this;
  366. var promises = [];
  367. _.each(this.model.items, function (item) {
  368. var view = _this5.layoutController.getLayoutView(item.id);
  369. if (view && view[name]) {
  370. promises.push(view[name](event));
  371. }
  372. });
  373. return Promise.all(promises);
  374. },
  375. _callChildrenFunction: function _callChildrenFunction(name) {
  376. var _this6 = this;
  377. _.each(this.model.items, function (item) {
  378. var view = _this6.layoutController.getLayoutView(item.id);
  379. if (view && view[name]) {
  380. view[name]();
  381. }
  382. });
  383. },
  384. getProperties: function getProperties() {
  385. var _this7 = this;
  386. var items = [];
  387. items.push(this.getBannerProperty());
  388. if (this._isTopLevelPage()) {
  389. var _items;
  390. // If this is the top level layout, then we add the dashboard properties
  391. (_items = items).push.apply(_items, this._getCanvasProperties());
  392. return this._fetchThemes().then(function (themeListing) {
  393. items.push({
  394. type: 'DropDown',
  395. label: StringResources.get('propTheme'),
  396. name: 'theme',
  397. id: 'theme',
  398. defaultValue: _this7.layoutController.boardModel.get('theme'),
  399. options: themeListing,
  400. tabName: StringResources.get('tabName_general'),
  401. sectionName: StringResources.get('sectionName_colorsAndThemes'),
  402. sectionPosition: 2,
  403. showLabels: true,
  404. onChange: function onChange(propertyName, propertyValue) {
  405. _this7.layoutController.boardModel.set({
  406. 'theme': propertyValue
  407. });
  408. }
  409. });
  410. return Promise.all([_this7._getDashboardColorSetPropertySpec(), _this7._getBackgroundColorPropertySpec()]).then(function (propertySpecs) {
  411. items = items.concat(propertySpecs);
  412. items.push(_this7._getFredIsRedSpec());
  413. items.push(_this7._getDataCacheSpec());
  414. if (_this7.translationService.getDefaultLanguage() === 'Default') {
  415. _this7._addLanguageSpecWhenNoLocaleSet(items);
  416. } else {
  417. _this7._addMultilingualProperties(items);
  418. }
  419. return items;
  420. });
  421. }).catch(function (error) {
  422. _this7.logger.error(error, _this7);
  423. throw error;
  424. });
  425. } else {
  426. // Not a top level layout (e.g. embedded layout that is not a widget)
  427. // We only support the background color for now
  428. return this._getBackgroundColorPropertySpec().then(function (backgroundSpec) {
  429. items.push(backgroundSpec);
  430. return items;
  431. });
  432. }
  433. },
  434. _getDashboardColorSetPropertySpec: function _getDashboardColorSetPropertySpec() {
  435. var _this8 = this;
  436. var dashboardColorSet = {
  437. id: 'dashboardColorSet',
  438. name: 'dashboardColorSet',
  439. type: 'NewPalette',
  440. sectionLabel: StringResources.get('propDashboardColorPalette'),
  441. newPaletteLabel: StringResources.get('propNewDashboardPaletteLabel'),
  442. linkLabel: StringResources.get('propDashboardChangePaletteLink'),
  443. ariaLabel: StringResources.get('propDashboardColorPalette'),
  444. tabName: StringResources.get('tabName_general'),
  445. sectionName: StringResources.get('sectionName_colorsAndThemes'),
  446. paletteType: 'ColorPalette',
  447. defaultValue: 'userPaletteColor',
  448. includeUserColorPalette: true
  449. };
  450. var onChangeCallback = function onChangeCallback(propertyName, paletteItem) {
  451. _this8.layoutController.boardModel.get('properties').set({
  452. dashboardColorSet: paletteItem.id
  453. });
  454. _this8.eventRouter.trigger('properties:refreshPane', {
  455. 'sender': _this8.layoutController.boardModel.get('properties').id
  456. });
  457. };
  458. return PropertiesUtil.handleNewPaletteProperty(dashboardColorSet, this.layoutController.boardModel.get('properties'), this.dashboardApi, onChangeCallback);
  459. },
  460. _getBackgroundColorPropertySpec: function _getBackgroundColorPropertySpec() {
  461. var _this9 = this;
  462. var colorPickerSpec = {
  463. 'name': 'fillColor',
  464. 'id': 'fillColor',
  465. 'type': 'ColorPicker',
  466. 'label': StringResources.get('propDashboardBackgroundColor'),
  467. 'open': false,
  468. 'ariaLabel': StringResources.get('propDashboardBackgroundColor'),
  469. 'paletteType': 'DashboardColorSet',
  470. 'showHexValue': true,
  471. 'addButton': true,
  472. 'tabName': StringResources.get('tabName_general'),
  473. 'sectionName': StringResources.get('sectionName_colorsAndThemes'),
  474. 'defaultValue': 'transparent'
  475. };
  476. return PropertiesUtil.handleColorPickerProperty(colorPickerSpec, this, this.dashboardApi).then(function (colorPickerSpec) {
  477. colorPickerSpec.onChange = function (propertyName, propertyValueInfo) {
  478. // get layout and update CSS
  479. var oLayout = _this9.model;
  480. var data = {
  481. undoRedoTransactionId: _.uniqueId('layout_fillColorChange_')
  482. };
  483. var payload = {
  484. fillColor: propertyValueInfo.name
  485. };
  486. // This step is done because we used to set the "css" model property to have the fill color classname in addition to fillColor property
  487. // This is bad because it was overriding the css values that are part of the layout definition
  488. // We stopped doing this, but the following code is to handle an older dashboard that has the fill set in the css property (e.g. css = fill-color1)
  489. // We either have an upgrade to remove the layout 'css' property that contains the fill color, or we do it here.
  490. if (oLayout.get('css') === 'fill-' + oLayout.get('fillColor')) {
  491. // If the css was prreviously set , just remove it
  492. payload.css = undefined;
  493. }
  494. _this9.colorsService.prepareForColorModelChange(payload, 'fillColor');
  495. oLayout.set(payload, {
  496. sender: _this9.senderId,
  497. payloadData: data
  498. });
  499. };
  500. return colorPickerSpec;
  501. });
  502. },
  503. _getFredIsRedSpec: function _getFredIsRedSpec() {
  504. var _this10 = this;
  505. return {
  506. type: 'ToggleButton',
  507. label: StringResources.get('propFredIsRed'),
  508. name: 'fredIsRed',
  509. id: 'fredIsRed',
  510. checked: this.model.boardModel && this.model.boardModel.properties && this.model.boardModel.properties.fredIsRed,
  511. 'tabName': StringResources.get('tabName_general'),
  512. 'sectionName': StringResources.get('sectionName_advanced'),
  513. onChange: function onChange(propertyName, propertyValue) {
  514. _this10.layoutController.boardModel.properties.set({
  515. 'fredIsRed': propertyValue
  516. });
  517. }
  518. };
  519. },
  520. _getDataCacheSpec: function _getDataCacheSpec() {
  521. var _this11 = this;
  522. return {
  523. 'type': 'DropDown',
  524. 'label': StringResources.get('dataCache'),
  525. 'name': 'dataCache',
  526. 'id': 'dataCache',
  527. 'defaultValue': this.model.boardModel && this.model.boardModel.properties && this.model.boardModel.properties.localCache || 'automatic',
  528. 'options': [{
  529. label: StringResources.get('dataCache_auto'),
  530. value: 'automatic'
  531. }, {
  532. label: StringResources.get('dataCache_on'),
  533. value: 'yes'
  534. }, {
  535. label: StringResources.get('dataCache_off'),
  536. value: 'no'
  537. }],
  538. sectionPosition: 99,
  539. 'tabName': StringResources.get('tabName_general'),
  540. 'sectionName': StringResources.get('sectionName_advanced'),
  541. onChange: function onChange(propertyName, propertyValue) {
  542. if (propertyValue === 'automatic') {
  543. _this11.model.boardModel.properties.set({
  544. 'localCache': undefined
  545. });
  546. } else {
  547. _this11.model.boardModel.properties.set({
  548. 'localCache': propertyValue
  549. });
  550. }
  551. }
  552. };
  553. },
  554. _addMultilingualProperties: function _addMultilingualProperties(properties) {
  555. var _this12 = this;
  556. var defaultLanguage = this.translationService.getDefaultLanguage();
  557. var tabName = StringResources.get('tabName_general');
  558. properties.push({
  559. type: 'SingleLineLinks',
  560. tabName: tabName,
  561. name: 'Languages',
  562. sectionName: StringResources.get('sectionName_advanced'),
  563. disabled: this.translationService.translationModeOn,
  564. items: [{
  565. align: 'left',
  566. items: [{
  567. type: 'text',
  568. value: StringResources.get('multilingualDashboardsLabel')
  569. }]
  570. }]
  571. });
  572. // Create the Default language row - it's always first
  573. properties.push(this._createLanguageRow(defaultLanguage, tabName, true));
  574. // Rows for all other available languages
  575. this.translationService.getSelectedLanguages().sort(function (a, b) {
  576. return _this12.translationService.getLanguageName(a) > _this12.translationService.getLanguageName(b) ? 1 : -1;
  577. }).forEach(function (language) {
  578. if (language !== defaultLanguage && language !== 'Default') {
  579. properties.push(_this12._createLanguageRow(language, tabName, false));
  580. }
  581. });
  582. properties.push({
  583. type: 'SingleLineLinks',
  584. tabName: tabName,
  585. name: 'addLanguage',
  586. sectionName: StringResources.get('sectionName_advanced'),
  587. disabled: this.translationService.translationModeOn,
  588. items: [{
  589. align: 'right',
  590. items: [{
  591. type: 'text',
  592. value: StringResources.get('multilingualDashboardsAddLinkText'),
  593. clickCallback: function clickCallback() {
  594. _this12.launchLanguageSelectSlideout(null, true);
  595. }
  596. }]
  597. }]
  598. });
  599. return properties;
  600. },
  601. /**
  602. * Language property spec when no language has been selected yet
  603. */
  604. _addLanguageSpecWhenNoLocaleSet: function _addLanguageSpecWhenNoLocaleSet(properties) {
  605. var _this13 = this;
  606. var tabName = StringResources.get('tabName_general');
  607. var defaultLanguage = this.translationService.getDefaultLanguage();
  608. properties.push({
  609. type: 'SingleLineLinks',
  610. tabName: tabName,
  611. name: 'language_' + defaultLanguage,
  612. sectionName: StringResources.get('sectionName_advanced'),
  613. items: [{
  614. align: 'left',
  615. items: [{
  616. type: 'text',
  617. id: 'text' + defaultLanguage,
  618. value: StringResources.get('multilingualDashboardsLabel')
  619. }]
  620. }, {
  621. align: 'right',
  622. items: [{
  623. type: 'text',
  624. value: StringResources.get('multilingualDashboardsSetDefault'),
  625. clickCallback: function clickCallback() {
  626. _this13.launchLanguageSelectSlideout(defaultLanguage, false);
  627. }
  628. }]
  629. }]
  630. });
  631. },
  632. /**
  633. * Creats a SingleLineLink property spec that describes a language
  634. */
  635. _createLanguageRow: function _createLanguageRow(locale, tabName, isDefaultLocale) {
  636. var _this14 = this;
  637. var leftItems = [];
  638. var rightItems = [];
  639. var languageName = this.translationService.getLanguageName(locale);
  640. rightItems.push({
  641. type: 'text',
  642. id: 'text' + locale,
  643. value: isDefaultLocale ? StringResources.get('multilingualDashboardsDefault', { defaultLanguage: languageName }) : languageName
  644. });
  645. rightItems.push({
  646. type: 'icon',
  647. svgIcon: 'common-menuoverflow',
  648. iconTooltip: StringResources.get('multilingualDashboardIconMore', {
  649. currentLanguage: languageName
  650. }),
  651. clickCallback: function clickCallback(evt) {
  652. _this14.launchLanguageMenu(evt, locale);
  653. }
  654. });
  655. return {
  656. type: 'SingleLineLinks',
  657. tabName: tabName,
  658. id: 'language_' + locale,
  659. sectionName: StringResources.get('sectionName_advanced'),
  660. indent: 2,
  661. disabled: this.translationService.translationModeOn,
  662. items: [{
  663. align: 'left',
  664. items: leftItems
  665. }, {
  666. align: 'right',
  667. items: rightItems
  668. }]
  669. };
  670. },
  671. /**
  672. * When picking a language, we launch an overlay slideout with all the content locales
  673. */
  674. launchLanguageSelectSlideout: function launchLanguageSelectSlideout(selectedLocale, addLanguage) {
  675. var _this15 = this;
  676. var propertiesManager = this.layoutController.canvasController.getExtension('propertiesManager');
  677. propertiesManager.addChild({
  678. overlay: true,
  679. label: StringResources.get('multilingualSelectLanguage'),
  680. content: {
  681. module: 'dashboard-core/js/dashboard/contentpane/PropertyUIControlView',
  682. items: [{
  683. value: StringResources.get('multilingualSelectLanguage'),
  684. centerLabel: true,
  685. type: 'Banner',
  686. backButton: true,
  687. ariaLabel: StringResources.get('multilingualSelectLanguage')
  688. }, {
  689. type: 'RadioButtonGroup',
  690. name: 'language',
  691. separator: true,
  692. ariaLabel: StringResources.get('multilingualSelectLanguage'),
  693. value: selectedLocale,
  694. selectOnNavigation: false,
  695. items: this.translationService.getLanguageRadioItems(),
  696. onChange: function onChange(name, newLocale) {
  697. propertiesManager.closeChild();
  698. if (selectedLocale === 'Default') {
  699. _this15.translationService.changeDefaultLanguage(newLocale);
  700. } else if (addLanguage) {
  701. _this15.translationService.startTranslationMode(newLocale);
  702. } else {
  703. _this15.translationService.switchLanguage({
  704. from: selectedLocale,
  705. to: newLocale
  706. });
  707. }
  708. }
  709. }]
  710. }
  711. });
  712. },
  713. /**
  714. * User clicked on the ..., so show the menu
  715. */
  716. launchLanguageMenu: function launchLanguageMenu(evt, locale) {
  717. var position = {};
  718. if (evt.pageX === undefined || evt.gesture && (evt.gesture.center === undefined || evt.gesture.center.pageX === undefined)) {
  719. position = $(evt.target).offset();
  720. } else {
  721. position.left = evt.pageX || evt.gesture.center.pageX;
  722. position.top = evt.pageY || evt.gesture.center.pageY;
  723. }
  724. this.glassContext.appController.showContextMenu({
  725. position: {
  726. pageX: position.left,
  727. pageY: position.top
  728. },
  729. menuId: 'com.ibm.bi.dashboard.languageMenu',
  730. activeObject: {
  731. selectedLocale: locale,
  732. translationService: this.translationService,
  733. layoutBaseView: this
  734. }
  735. });
  736. },
  737. _isTopLevelPage: function _isTopLevelPage() {
  738. return this.model && this.layoutController.boardModel && this.model === this.layoutController.boardModel.layout;
  739. },
  740. getBannerProperty: function getBannerProperty() {
  741. return {
  742. 'value': this._isTopLevelPage() ? StringResources.get('dashboardProperties') : StringResources.get('settings'),
  743. 'name': 'banner',
  744. 'type': 'Banner',
  745. 'editable': false
  746. };
  747. },
  748. _getCanvasProperties: function _getCanvasProperties() {
  749. var items = [this._getLayoutPositioningSpec()];
  750. items = items.concat(this._getPageSizeSpec());
  751. items = items.concat(this._getGridOptionsSpec());
  752. return items;
  753. },
  754. _getLayoutPositioningSpec: function _getLayoutPositioningSpec() {
  755. var defaultValue = this._getLayoutPositioning();
  756. var layoutPositioningOptions = this._getLayoutPositioningSpecOptions(defaultValue);
  757. var _this = this;
  758. return {
  759. 'type': 'DropDown',
  760. 'label': StringResources.get('propLayoutPositioning'),
  761. 'name': 'layoutPositioning',
  762. 'id': 'layoutPositioning',
  763. 'defaultValue': defaultValue,
  764. 'options': layoutPositioningOptions,
  765. 'tabName': StringResources.get('tabName_general'),
  766. 'sectionName': StringResources.get('sectionName_canvas'),
  767. sectionPosition: 1,
  768. 'coachMark': {
  769. render: function render(options) {
  770. Utils.addCoachmark({
  771. id: 'com.ibm.bi.dashboard.dashboardCoreProperties.layoutPositioning',
  772. title: StringResources.get('propLayoutPositioningCoachmarkTitle'),
  773. contents: StringResources.get('propLayoutPositioningCoachmarkContent'),
  774. placement: 'bottom',
  775. glassContext: options.glassContext,
  776. $el: options.$el
  777. });
  778. }
  779. },
  780. onChange: function onChange(propertyName, propertyValue) {
  781. _this._onChangeLayoutPosition(this, propertyValue);
  782. }
  783. };
  784. },
  785. _getLayoutPositioningSpecOptions: function _getLayoutPositioningSpecOptions(defaultValue) {
  786. var layoutPositioningOptions = [];
  787. if (!defaultValue) {
  788. layoutPositioningOptions.push({
  789. label: '',
  790. value: 'undefined'
  791. });
  792. }
  793. layoutPositioningOptions.push({
  794. label: StringResources.get('propLayoutRelative'),
  795. value: 'relative'
  796. }, {
  797. label: StringResources.get('propLayoutAbsolute'),
  798. value: 'absolute'
  799. });
  800. return layoutPositioningOptions;
  801. },
  802. _getLayoutPositioning: function _getLayoutPositioning() {
  803. return this.model.getValueFromSelfOrParent('layoutPositioning');
  804. },
  805. _setLayoutPositioning: function _setLayoutPositioning(value) {
  806. var data = {
  807. undoRedoTransactionId: _.uniqueId('layout_layoutPositioningChange_')
  808. };
  809. this.model.set({ layoutPositioning: value }, {
  810. payloadData: data,
  811. sender: this.senderId
  812. });
  813. this.onResize();
  814. },
  815. _setFitPageLayoutPositioning: function _setFitPageLayoutPositioning(layoutPos, fitPage) {
  816. var data = {
  817. undoRedoTransactionId: _.uniqueId('layout_layoutPositioningChange_')
  818. };
  819. this.model.set({
  820. layoutPositioning: layoutPos,
  821. fitPage: fitPage
  822. }, {
  823. payloadData: data,
  824. sender: this.senderId
  825. });
  826. this.onResize();
  827. },
  828. _onChangeLayoutPosition: function _onChangeLayoutPosition(property, propertyValue) {
  829. var _this16 = this;
  830. var oldLayoutPositioning = this._getLayoutPositioning();
  831. if (oldLayoutPositioning) {
  832. if (propertyValue === 'absolute') {
  833. this.eventRouter.trigger('properties:updateEnabled', { propertyName: 'fitPage', enabled: false });
  834. this.eventRouter.trigger('properties:setValue', { propertyName: 'fitPage', value: false });
  835. this._setFitPageLayoutPositioning(propertyValue, false);
  836. } else {
  837. this.eventRouter.trigger('properties:updateEnabled', { propertyName: 'fitPage', enabled: true });
  838. var pageSize = this.model.get('pageSize');
  839. var preset = this._getPageSizePreset(pageSize.width, pageSize.height);
  840. if (preset === '16:9' || preset === '4:3') {
  841. this.eventRouter.trigger('properties:setValue', { propertyName: 'fitPage', value: true });
  842. this._setFitPageLayoutPositioning(propertyValue, true);
  843. } else {
  844. this.eventRouter.trigger('properties:setValue', { propertyName: 'fitPage', value: false });
  845. this._setFitPageLayoutPositioning(propertyValue, false);
  846. }
  847. }
  848. } else {
  849. // Confirm layout upgrade with user
  850. var onOK = function onOK() {
  851. _this16._setLayoutPositioning(propertyValue);
  852. // Update property control - which should remove "undefined" as an option
  853. // Ideally we should only be updating the one control of interest.
  854. // But, this doesn't currently work right for items in a section block.
  855. // let event = {
  856. // 'propertySpec': this._getLayoutPositioningSpec(),
  857. // 'removeProperty': false
  858. // };
  859. // this.eventRouter.trigger('properties:refreshProperty', event);
  860. _this16.eventRouter.trigger('properties:refreshPane');
  861. };
  862. var onCancel = function onCancel() {
  863. // Reset back to undefined state
  864. property._lastChangedValue = 'undefined'; // Bug in glass, setValue doesn't reset _lastChangedValue.
  865. property.setValue('undefined');
  866. };
  867. var oConfirmationDialog = new ConfirmationDialog('warning', StringResources.get('confirmLayoutStyleUpgradeTitle'), StringResources.get('confirmLayoutStyleUpgrade'));
  868. oConfirmationDialog.confirm(onOK, onCancel);
  869. }
  870. },
  871. _getGridOptionsSpec: function _getGridOptionsSpec() {
  872. var _this17 = this;
  873. return [{
  874. type: 'SectionLabel',
  875. label: StringResources.get('gridLabel'),
  876. id: 'gridLabel',
  877. name: 'gridLabel',
  878. 'tabName': StringResources.get('tabName_general'),
  879. 'sectionName': StringResources.get('sectionName_canvas')
  880. }, {
  881. type: 'ToggleButton',
  882. label: StringResources.get('gridText'),
  883. name: 'showGrid',
  884. id: 'showGrid',
  885. checked: this.model.get('showGrid') === undefined ? false : this.model.get('showGrid'),
  886. 'tabName': StringResources.get('tabName_general'),
  887. 'sectionName': StringResources.get('sectionName_canvas'),
  888. onChange: function onChange(propertyName, propertyValue) {
  889. _this17.model.set({
  890. 'showGrid': propertyValue
  891. });
  892. }
  893. }, {
  894. type: 'ToggleButton',
  895. label: StringResources.get('snapText'),
  896. name: 'snapGrid',
  897. id: 'snapGrid',
  898. checked: this.model.get('snapGrid') === undefined ? false : this.model.get('snapGrid'),
  899. 'tabName': StringResources.get('tabName_general'),
  900. 'sectionName': StringResources.get('sectionName_canvas'),
  901. onChange: function onChange(propertyName, propertyValue) {
  902. _this17.model.set({
  903. 'snapGrid': propertyValue
  904. });
  905. }
  906. }, {
  907. type: 'ToggleButton',
  908. label: StringResources.get('snapObjectsText'),
  909. name: 'snapObjects',
  910. id: 'snapObjects',
  911. checked: this.model.get('snapObjects') === undefined ? true : this.model.get('snapObjects'),
  912. 'tabName': StringResources.get('tabName_general'),
  913. 'sectionName': StringResources.get('sectionName_canvas'),
  914. onChange: function onChange(propertyName, propertyValue) {
  915. _this17.model.set({
  916. 'snapObjects': propertyValue
  917. });
  918. }
  919. }];
  920. },
  921. _getPageSizePreset: function _getPageSizePreset(width, height) {
  922. var preset = 'custom';
  923. var checkWidth = parseInt(width, 10),
  924. checkHeight = parseInt(height, 10);
  925. for (var value in PAGESIZES) {
  926. if (PAGESIZES.hasOwnProperty(value)) {
  927. var currentPreset = PAGESIZES[value];
  928. if (currentPreset.width === checkWidth && currentPreset.height === checkHeight) {
  929. preset = value;
  930. break;
  931. }
  932. }
  933. }
  934. return preset;
  935. },
  936. _wrapPageSizeTextProperty: function _wrapPageSizeTextProperty() {
  937. var action = this;
  938. return function () {
  939. var args = [action].concat(Array.prototype.slice.call(arguments));
  940. action._pageSizeTextOnChange.apply(this, args);
  941. };
  942. },
  943. _pageSizeTextOnChange: function _pageSizeTextOnChange(action, id, value) {
  944. if (this.propertiesManagerChange) {
  945. this.onChangeValueHold = value;
  946. } else {
  947. var numericValue = parseInt(value, 10);
  948. var model = action.model;
  949. var direction = id === 'pageSizeWidth' ? 'width' : 'height';
  950. var newPageSize = {};
  951. if (model.pageSize) {
  952. newPageSize = _.extend(newPageSize, model.pageSize);
  953. }
  954. if (!isNaN(numericValue) && newPageSize[direction] !== numericValue) {
  955. newPageSize[direction] = numericValue;
  956. newPageSize = action._setPageSize(newPageSize);
  957. numericValue = newPageSize[direction];
  958. }
  959. var propertyNameList = ['pageSizeSplit', id];
  960. if (isNaN(numericValue)) {
  961. action.eventRouter.trigger('properties:setValue', { propertyName: propertyNameList, value: this.onChangeValueHold });
  962. } else if (value !== this.onChangeValueHold) {
  963. this.onChangeValueHold = PropertiesListUtil.getPropertyDisplayString(numericValue, StringResources.get('pixelUnit'), true);
  964. action.eventRouter.trigger('properties:setValue', { propertyName: propertyNameList, value: this.onChangeValueHold });
  965. }
  966. }
  967. },
  968. _setPageSize: function _setPageSize(newSize, undoRedoTransactionId) {
  969. var model = this.model;
  970. var sizeChanged = false;
  971. var minimumSize = LayoutHelper.getBoundingPageSize(model, MINIMUM_PAGESIZE);
  972. if (minimumSize) {
  973. if (isNaN(newSize.width) || minimumSize.width > newSize.width) {
  974. newSize.width = minimumSize.width;
  975. sizeChanged = true;
  976. }
  977. if (isNaN(newSize.height) || minimumSize.height > newSize.height) {
  978. newSize.height = minimumSize.height;
  979. sizeChanged = true;
  980. }
  981. if (sizeChanged) {
  982. this.layoutController.glassContext.appController.showToast(StringResources.get('propPageSizeAdjustedMessage'), {
  983. type: 'info'
  984. });
  985. }
  986. }
  987. model.set({
  988. 'pageSize': newSize
  989. }, {
  990. payloadData: { undoRedoTransactionId: undoRedoTransactionId }
  991. });
  992. this.onResize();
  993. return newSize;
  994. },
  995. _getPageSizeDisplayValues: function _getPageSizeDisplayValues() {
  996. var model = this.model;
  997. var widthValue = model.pageSize && model.pageSize.width ? PropertiesListUtil.getPropertyDisplayString(model.pageSize.width, StringResources.get('pixelUnit'), true) : '';
  998. var heightValue = model.pageSize && model.pageSize.height ? PropertiesListUtil.getPropertyDisplayString(model.pageSize.height, StringResources.get('pixelUnit'), true) : '';
  999. return {
  1000. width: widthValue,
  1001. height: heightValue,
  1002. preset: this._getPageSizePreset(widthValue, heightValue)
  1003. };
  1004. },
  1005. onPageSizeChange: function onPageSizeChange() {
  1006. var currentValues = this._getPageSizeDisplayValues();
  1007. this.eventRouter.trigger('properties:setValue', { propertyName: ['pageSizeSplit', 'pageSizeWidth'], value: currentValues.width });
  1008. this.eventRouter.trigger('properties:setValue', { propertyName: ['pageSizeSplit', 'pageSizeHeight'], value: currentValues.height });
  1009. this.eventRouter.trigger('properties:setValue', { propertyName: 'pageSizePreset', value: currentValues.preset });
  1010. },
  1011. _getPageSizeSpec: function _getPageSizeSpec() {
  1012. var _this18 = this;
  1013. var defaultValues = this._getPageSizeDisplayValues();
  1014. var properties = [{
  1015. 'type': 'SectionLabel',
  1016. 'id': 'pageSizeLabel',
  1017. 'name': 'pageSizeLabel',
  1018. 'label': StringResources.get('propPageSizeLabel'),
  1019. 'tabName': StringResources.get('tabName_general'),
  1020. 'sectionName': StringResources.get('sectionName_canvas')
  1021. }, {
  1022. 'type': 'DropDown',
  1023. 'label': StringResources.get('propPageSizePreset'),
  1024. 'ariaLabel': StringResources.get('propPageSizePresetAriaLabel'),
  1025. 'name': 'pageSizePreset',
  1026. 'id': 'pageSizePreset',
  1027. 'readOnly': false,
  1028. 'defaultValue': defaultValues.preset,
  1029. 'options': [{
  1030. label: StringResources.get('propPageSizePresetCustom'),
  1031. value: 'custom'
  1032. }, {
  1033. label: StringResources.get('propPageSizePreset16x9'),
  1034. value: '16:9'
  1035. }, {
  1036. label: StringResources.get('propPageSizePreset4x3'),
  1037. value: '4:3'
  1038. }, {
  1039. label: StringResources.get('letter'),
  1040. value: 'letter'
  1041. }, {
  1042. label: StringResources.get('legal'),
  1043. value: 'legal'
  1044. }, {
  1045. label: StringResources.get('a4'),
  1046. value: 'a4'
  1047. }, {
  1048. label: StringResources.get('tabloid'),
  1049. value: 'tabloid'
  1050. }, {
  1051. label: StringResources.get('propPageSizePresetInfographic'),
  1052. value: 'infographic'
  1053. }],
  1054. 'onChange': this._onChangePageSizePreset.bind(this),
  1055. 'tabName': StringResources.get('tabName_general'),
  1056. 'sectionName': StringResources.get('sectionName_canvas'),
  1057. sectionPosition: 1
  1058. }, {
  1059. type: 'ToggleButton',
  1060. label: StringResources.get('fitPageText'),
  1061. name: 'fitPage',
  1062. id: 'fitPage',
  1063. checked: this.getFitPage(),
  1064. 'tabName': StringResources.get('tabName_general'),
  1065. 'sectionName': StringResources.get('sectionName_canvas'),
  1066. onChange: function onChange(propertyName, propertyValue) {
  1067. _this18.model.set({
  1068. 'fitPage': propertyValue
  1069. });
  1070. }
  1071. }, {
  1072. 'type': 'Split',
  1073. 'name': 'pageSizeSplit',
  1074. 'id': 'pageSizeSplit',
  1075. 'tabName': StringResources.get('tabName_general'),
  1076. 'sectionName': StringResources.get('sectionName_canvas'),
  1077. 'items': [{
  1078. align: 'left',
  1079. items: [{
  1080. 'type': 'InputLabel',
  1081. 'label': StringResources.get('propPageSizeWidth'),
  1082. 'ariaLabel': StringResources.get('propPageSizeWidthAriaLabel'),
  1083. 'name': 'pageSizeWidth',
  1084. 'id': 'pageSizeWidth',
  1085. 'readOnly': false,
  1086. 'value': defaultValues.width,
  1087. 'onChangeValueHold': defaultValues.width,
  1088. 'multiline': true,
  1089. 'handleReturnKey': true,
  1090. 'onChange': this._wrapPageSizeTextProperty()
  1091. }]
  1092. }, {
  1093. align: 'right',
  1094. items: [{
  1095. 'type': 'InputLabel',
  1096. 'label': StringResources.get('propPageSizeHeight'),
  1097. 'ariaLabel': StringResources.get('propPageSizeHeightAriaLabel'),
  1098. 'name': 'pageSizeHeight',
  1099. 'id': 'pageSizeHeight',
  1100. 'readOnly': false,
  1101. 'value': defaultValues.height,
  1102. 'onChangeValueHold': defaultValues.height,
  1103. 'multiline': true,
  1104. 'handleReturnKey': true,
  1105. 'onChange': this._wrapPageSizeTextProperty()
  1106. }]
  1107. }]
  1108. }];
  1109. return properties;
  1110. },
  1111. _onChangePageSizePreset: function _onChangePageSizePreset(id, value) {
  1112. var presetValues = PAGESIZES[value];
  1113. if (presetValues) {
  1114. var payloadData = {
  1115. undoRedoTransactionId: _.uniqueId('layout_layoutPageSizeChange_')
  1116. };
  1117. var model = this.model;
  1118. if (model.get('layoutPositioning') !== 'absolute') {
  1119. var fitPageValue = value === '16:9' || value === '4:3';
  1120. model.set({
  1121. 'fitPage': fitPageValue
  1122. }, {
  1123. payloadData: payloadData
  1124. });
  1125. this.eventRouter.trigger('properties:setValue', { propertyName: 'fitPage', value: fitPageValue });
  1126. }
  1127. if (!model.pageSize || model.pageSize.width !== presetValues.width || model.pageSize.height !== presetValues.height) {
  1128. this._setPageSize({
  1129. width: presetValues.width,
  1130. height: presetValues.height
  1131. }, payloadData.undoRedoTransactionId);
  1132. }
  1133. }
  1134. },
  1135. getFitPage: function getFitPage() {
  1136. var fitPage = false;
  1137. if (this.model.getValueFromSelfOrParent('layoutPositioning') !== 'absolute') {
  1138. fitPage = this.model.getValueFromSelfOrParent('fitPage') || false;
  1139. }
  1140. return fitPage;
  1141. },
  1142. _fetchThemes: function _fetchThemes() {
  1143. var _this19 = this;
  1144. if (!this._themeListing) {
  1145. this._themeListing = [];
  1146. return ClassFactory.loadModule('text!dashboard-core/js/lib/@waca/dashboard-common/dist/themes/themeListing.json').then(function (themeListing) {
  1147. var themesInfo = JSON.parse(themeListing);
  1148. _.each(themesInfo.themes, function (theme) {
  1149. _this19._themeListing.push({
  1150. label: StringResources.get(theme.name + 'Label'),
  1151. value: theme.name
  1152. });
  1153. });
  1154. return _this19._themeListing;
  1155. }, function () {
  1156. _this19._themeListing = [];
  1157. return _this19._themeListing;
  1158. });
  1159. } else {
  1160. return Promise.resolve(this._themeListing);
  1161. }
  1162. },
  1163. /**
  1164. * Reduces this view and all its descendants to a single value.
  1165. *
  1166. * @param {function} callback function(view, accumulator)
  1167. * @param {object} acc accumulator.
  1168. *
  1169. * returns the accumulated value returned by the last invocation of callback.
  1170. */
  1171. reduce: function reduce(callback, acc) {
  1172. acc = callback(this, acc);
  1173. if (this.model.items) {
  1174. this.model.items.forEach(function (model) {
  1175. var view = this.layoutController.getLayoutView(model.id);
  1176. if (view && view.reduce) {
  1177. acc = view.reduce(callback, acc);
  1178. }
  1179. }, this);
  1180. }
  1181. return acc;
  1182. },
  1183. /**
  1184. * @param {Boolean} loading indicating if the loading animation should be displayed.
  1185. */
  1186. setLoading: function setLoading(loading) {
  1187. if (!this._$loadingIndicatorBlocker && !loading) {
  1188. // if we are called for the first time with false, don't bother loading the animation at all.
  1189. return Promise.resolve(null);
  1190. }
  1191. if (!this._$loadingIndicatorBlocker) {
  1192. this._$loadingIndicatorBlocker = $('<div></div>');
  1193. }
  1194. if (loading) {
  1195. this.$el.append(this._$loadingIndicatorBlocker);
  1196. ReactDOM.render(CenterLoadingSpinner({ size: 'normal', variant: 'circle' }), this._$loadingIndicatorBlocker[0]);
  1197. } else {
  1198. ReactDOM.unmountComponentAtNode(this._$loadingIndicatorBlocker[0]);
  1199. this._$loadingIndicatorBlocker.remove();
  1200. this._$loadingIndicatorBlocker = null;
  1201. }
  1202. return Promise.resolve(null);
  1203. },
  1204. /** If the layout has 'subviews' (ie. tabs or scenes), return the id of the current one. */
  1205. getSelectedSubViewId: function getSelectedSubViewId() {
  1206. // sub-classes are expected to implement this as appropriate.
  1207. return this.id;
  1208. },
  1209. /** If the layout has 'subviews' (ie. tabs or scenes), return the title of the current one. */
  1210. getSelectedSubViewTitle: function getSelectedSubViewTitle() {
  1211. // sub-classes are expected to implement this as appropriate.
  1212. return null;
  1213. },
  1214. /**
  1215. * Get layout ratio from parent layout
  1216. *
  1217. * Note: the method has a limitation.
  1218. * The method only supports horizontal layout ratios, so the Y axis
  1219. * ratio (height) will always be fixed to 1.
  1220. * This should be implemented when vertical ratios are needed. (TODO)
  1221. *
  1222. * @return {Object} ratio; has properties `width` and `height` with the appropriate ratios
  1223. */
  1224. getSelfRatio: function getSelfRatio() {
  1225. var childCount = this.parentLayout.model.getVisualizations().length || 1;
  1226. var width = 1 / childCount;
  1227. var height = 1;
  1228. return {
  1229. width: width,
  1230. height: height
  1231. };
  1232. },
  1233. /**
  1234. * Get parent layout API
  1235. *
  1236. * @return {Object}
  1237. */
  1238. getParentLayout: function getParentLayout() {
  1239. return this.parentLayout.getAPI();
  1240. },
  1241. /**
  1242. * Get layout API
  1243. *
  1244. * @return {LayoutApi} layout API
  1245. */
  1246. getAPI: function getAPI() {
  1247. return this.api.getAPI();
  1248. },
  1249. /**
  1250. * Render layout
  1251. *
  1252. * Note:
  1253. * historically we were calling onShow when we needed a widget to render.
  1254. * renaming this across so many components is hard right now, but
  1255. * let's try to use `render` instead of `onShow`.
  1256. */
  1257. render: function render(options) {
  1258. this.onShow(options);
  1259. }
  1260. });
  1261. return BaseLayout;
  1262. });
  1263. //# sourceMappingURL=LayoutBaseView.js.map