PropertiesUtil.js 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757
  1. 'use strict';
  2. /*
  3. *+------------------------------------------------------------------------+
  4. *| Licensed Materials - Property of IBM
  5. *| IBM Cognos Products: Dashboard
  6. *| (C) Copyright IBM Corp. 2017, 2020
  7. *|
  8. *| US Government Users Restricted Rights - Use, duplication or disclosure
  9. *| restricted by GSA ADP Schedule Contract with IBM Corp.
  10. *+------------------------------------------------------------------------+
  11. */
  12. define(['jquery', 'underscore', '../../app/nls/StringResources'], function ($, _, StringResources) {
  13. var _singletonInstance = null;
  14. var PropertiesUtil = function PropertiesUtil() {
  15. if (PropertiesUtil.prototype._singletonInstance) {
  16. return PropertiesUtil.prototype._singletonInstance;
  17. }
  18. };
  19. /**
  20. Loops through an array of properties to add appropriate callbacks and default values
  21. @param {object} properties - the array of properties to process
  22. @param {object} widgetInstance - the widget instance which wants to display these properties
  23. @return {Promise} resolved once all the properties have been processed
  24. **/
  25. PropertiesUtil.prototype.processProperties = function (properties, widgetInstance, dashboardApi) {
  26. var _this = this;
  27. if (!properties) {
  28. return false;
  29. }
  30. var translationService = dashboardApi.getDashboardCoreSvc('TranslationService');
  31. var removeTranslationIcon = function removeTranslationIcon(property) {
  32. // if the property has a tanslationIconNode defined then we were showing the missing translation dot.
  33. // Since we're just changed the property make sure the dot gets removed.
  34. if (translationService && property.translationIconNode) {
  35. translationService.removeTranslationIcon(property.translationIconNode);
  36. property.translationIconNode = null;
  37. }
  38. };
  39. var onChangeCallback = function onChangeCallback(property, propertyName, propertyValue) {
  40. if (property.displayMultiplier) {
  41. propertyValue = Math.round(propertyValue / property.displayMultiplier);
  42. }
  43. this._callPropertyOnChangeCallback(property, widgetInstance, propertyName, propertyValue);
  44. widgetInstance.onPropertyChange(propertyName, propertyValue);
  45. removeTranslationIcon(property);
  46. };
  47. var promises = [];
  48. properties.forEach(function (property, i) {
  49. var customOnChangeCallback = _this._findCallbackFunction(property, 'onChange', widgetInstance);
  50. // Ignore hidden properties or the banner
  51. if (property.public === false || property.type === 'Banner') {
  52. return;
  53. }
  54. var propertiesOverride = _this._getPropertiesOverride(property, widgetInstance);
  55. if (propertiesOverride.removeProperty === true) {
  56. properties.splice(i, 1);
  57. i--;
  58. return;
  59. }
  60. // Replace any overriden properties
  61. $.extend(property, propertiesOverride);
  62. // Property UI Controls always need a name property
  63. if (property.id && !property.name) {
  64. property.name = property.id;
  65. }
  66. // If the property is tagged as multilingual and we're in translation mode and we're missing the translation for the current locale
  67. if (property.multilingual && translationService && translationService.isInTranslationMode()) {
  68. var model = widgetInstance.visModelManager || widgetInstance.model;
  69. var multilingualAttributeInfo = model.getMultilingualAttribute(property.id);
  70. if (!multilingualAttributeInfo) {
  71. return;
  72. }
  73. var multilingualProperty = multilingualAttributeInfo.multilingualProperty;
  74. if (multilingualProperty && multilingualProperty.needsTranslation()) {
  75. // This will end up being called by PropertyUIControlView after the property has been rendered.
  76. property.appendTranslationIcon = translationService.appendTranslationIcon;
  77. }
  78. }
  79. if (property.type === 'IconPicker') {
  80. _this._handleIconPickerProperty(property, widgetInstance);
  81. } else if (property.items && property.items instanceof Array) {
  82. promises.push(_this.processProperties(property.items, widgetInstance, dashboardApi));
  83. } else if (property.type === 'ColorPicker') {
  84. promises.push(_this.handleColorPickerProperty(property, widgetInstance, dashboardApi));
  85. } else if (property.type === 'NewPalette' || property.type === 'Palette') {
  86. property.type = 'NewPalette';
  87. promises.push(_this.handleNewPaletteProperty(property, widgetInstance, dashboardApi));
  88. } else if (property.type === 'ToggledCombo') {
  89. _this._handleToggledComboProperty(property, widgetInstance);
  90. } else if (property.module && property.module.indexOf('UiSlider') >= 0) {
  91. _this._handleUISlider(property, widgetInstance);
  92. } else if (!property.type) {
  93. //If there is no type, this is not a property by itself
  94. } else {
  95. var currentProp = _this._getPropertyValue(widgetInstance, property.name);
  96. var currentPropValue = currentProp && currentProp.value ? currentProp.value : currentProp;
  97. if (property.type === 'CheckBox' || property.type === 'ToggleButton') {
  98. if (currentPropValue === false) {
  99. property.checked = false;
  100. } else {
  101. property.checked = currentPropValue === true || property.defaultValue === true;
  102. }
  103. } else if (property.type === 'DropDown') {
  104. var valueToUse = void 0;
  105. /*
  106. * Enums - Dropdowns, are difficult because of Vida. Basically, we want
  107. * to check if the the current value returned is a valid. If it isn't,
  108. * use the property default. If it is, then we should check if it is an
  109. * object with property called 'name', which Vida enums do. If it does,
  110. * then use the name prop. All else fails, use the current prop value.
  111. */
  112. if (currentPropValue !== null && currentPropValue !== undefined) {
  113. if (currentPropValue.hasOwnProperty('name')) {
  114. valueToUse = currentPropValue.name;
  115. } else {
  116. valueToUse = currentPropValue;
  117. }
  118. } else {
  119. valueToUse = property.defaultValue;
  120. }
  121. property.defaultValue = valueToUse;
  122. } else {
  123. property.value = currentPropValue || currentPropValue === 0 ? currentPropValue : '';
  124. }
  125. if (property.displayMultiplier && property.value) {
  126. var scaledValue = property.value * property.displayMultiplier;
  127. property.value = property.decimalPlaces ? scaledValue.toFixed(property.decimalPlaces) : Math.round(scaledValue);
  128. }
  129. property.onChange = onChangeCallback.bind(_this, property);
  130. }
  131. if (customOnChangeCallback) {
  132. property.onChange = function (property, propertyName, propertyValue) {
  133. customOnChangeCallback(propertyName, propertyValue);
  134. removeTranslationIcon(property);
  135. }.bind(_this, property);
  136. }
  137. var customValidatorCallback = _this._findCallbackFunction(property, 'customValidatorCallback', widgetInstance);
  138. if (customValidatorCallback) {
  139. property.customValidatorCallback = customValidatorCallback;
  140. }
  141. // Replace any overriden properties once again in case we set defaults
  142. $.extend(property, propertiesOverride);
  143. });
  144. return Promise.all(promises);
  145. };
  146. /**
  147. If the property object defines a 'preRenderCallback' property then call it to get any dynamic properties
  148. that should be applied to the property UI control
  149. @param {object} property - the property object for which to get any dynamically generated member variables
  150. @param {object} widgetInstance - the widget instance which wants to display these properties
  151. @return {object} - returns the member variables (properties) to override
  152. **/
  153. PropertiesUtil.prototype._getPropertiesOverride = function (property, widgetInstance) {
  154. var propertiesOverride = {};
  155. var callbackFunction = this._findCallbackFunction(property, 'preRenderCallback', widgetInstance);
  156. // Call the callback to get any dynamic property info
  157. if (callbackFunction) {
  158. propertiesOverride = callbackFunction(property, widgetInstance.visModel || widgetInstance.model);
  159. }
  160. return propertiesOverride;
  161. };
  162. /**
  163. Callback properties can either be a function or a string representing the name of the function. Use this method
  164. to always get back a function object
  165. @param {object} property - the property object for which to get any dynamically generated member variables
  166. @param {string} propertyName - the widget instance which wants to display these properties
  167. @return - the callback function or null
  168. **/
  169. PropertiesUtil.prototype._findCallbackFunction = function (property, propertyName, widgetInstance) {
  170. if (property && property[propertyName]) {
  171. if (typeof property[propertyName] === 'function') {
  172. return property[propertyName].bind(property);
  173. } else {
  174. var functionName = property[propertyName];
  175. var currentVis = widgetInstance.getCurrentVis ? widgetInstance.getCurrentVis() : null;
  176. if (typeof widgetInstance[functionName] === 'function') {
  177. return widgetInstance[functionName].bind(widgetInstance);
  178. } else if (currentVis && typeof currentVis[functionName] === 'function') {
  179. return currentVis[functionName].bind(currentVis);
  180. } else {
  181. throw new Error('preRenderCallback defined but function isn\'t available to call.', property);
  182. }
  183. }
  184. }
  185. return null;
  186. };
  187. /**
  188. A property can define a custom onChange callback. This is mostly used when one property change effects other properties,
  189. for example the show/hide legend property to hide/show the legened position property.
  190. @param {object} property - the property object for which to get any dynamically generated member variables
  191. @param {object} widgetInstance - the widget instance which wants to display these properties
  192. @param {string} propertyName - the name of the property
  193. @param {object} propertyValue - the value of the property
  194. **/
  195. PropertiesUtil.prototype._callPropertyOnChangeCallback = function (property, widgetInstance, propertyName, propertyValue) {
  196. if (property.onChangeCallback) {
  197. property.onChangeCallback(propertyName, propertyValue, widgetInstance.visModel || widgetInstance.model);
  198. }
  199. };
  200. /**
  201. Handles setting the callbacks and dynamic properties of a slider property control
  202. @param {object} property - the property object for which to get any dynamically generated member variables
  203. @param {object} widgetInstance - the widget instance which wants to display these properties
  204. **/
  205. PropertiesUtil.prototype._handleUISlider = function (property, widgetInstance) {
  206. var currentPropValue = this._getPropertyValue(widgetInstance, property.name);
  207. if (currentPropValue || currentPropValue === 0 && property.sliderType === 'percentage') {
  208. currentPropValue = parseInt(currentPropValue * 100, 10);
  209. }
  210. property.start = currentPropValue || currentPropValue === 0 ? [currentPropValue] : [property.defaultValue];
  211. property.startLabels = [property.description || property.label];
  212. property.onChange = function (sliderValues) {
  213. // All our sliders currently only have one 'slide'
  214. var value = sliderValues[0];
  215. // The value with have the postfix at the end, for example 75%
  216. if (property.format && property.format.postfix) {
  217. value = value.substring(0, value.indexOf(property.format.postfix));
  218. }
  219. if (property.sliderType === 'percentage') {
  220. value = value * 0.01;
  221. }
  222. this._callPropertyOnChangeCallback(property, widgetInstance, property.name, value);
  223. widgetInstance.onPropertyChange(property.name, value);
  224. }.bind(this);
  225. };
  226. /**
  227. Handles setting the callbacks and dynamic properties of a toggleCombo (auto refresh) property
  228. @param {object} property - the property object for which to get any dynamically generated member variables
  229. @param {object} widgetInstance - the widget instance which wants to display these properties
  230. **/
  231. PropertiesUtil.prototype._handleToggledComboProperty = function (property, widgetInstance) {
  232. var propInfo = this._getPropertyValue(widgetInstance, property.name);
  233. if (!property.inputOptions) {
  234. property.inputOptions = {};
  235. }
  236. if (!property.checkBoxOptions) {
  237. property.checkBoxOptions = {};
  238. }
  239. if (!property.dropDownOptions) {
  240. property.dropDownOptions = {};
  241. }
  242. property.useToggleButton = true;
  243. if (propInfo) {
  244. property.dropDownOptions.defaultValue = propInfo.unit;
  245. property.inputOptions.value = propInfo.value;
  246. property.checkBoxOptions.checked = propInfo.autoRefresh;
  247. } else {
  248. property.inputOptions.value = property.inputOptions.defaultValue || '';
  249. property.checkBoxOptions.checked = false;
  250. }
  251. property.validateInput = this._validateToggleComboProperty.bind(this);
  252. property.onChange = function (propertyName, propertyValue) {
  253. this._callPropertyOnChangeCallback(property, widgetInstance, propertyName, propertyValue);
  254. widgetInstance.onPropertyChange(propertyName, propertyValue);
  255. }.bind(this);
  256. };
  257. /**
  258. Handles setting the callbacks and dynamic properties of an IconPicker property
  259. @param {object} property - the property object for which to get any dynamically generated member variables
  260. @param {object} widgetInstance - the widget instance which wants to display these properties
  261. **/
  262. PropertiesUtil.prototype._handleIconPickerProperty = function (property, widgetInstance) {
  263. var currentProp = this._getPropertyValue(widgetInstance, property.name);
  264. var currentPropValue = currentProp && currentProp.value ? currentProp.value : currentProp;
  265. if (currentPropValue !== null && currentPropValue !== undefined) {
  266. property.values = currentPropValue;
  267. } else if (property.defaultValue !== undefined) {
  268. property.values = property.defaultValue;
  269. }
  270. property.onChange = function (propertyName, propertyValue) {
  271. var values = propertyValue;
  272. if (propertyValue.length && propertyValue.length === 1) {
  273. values = propertyValue[0].name;
  274. } else if (propertyValue.length) {
  275. values = [];
  276. propertyValue.forEach(function (value) {
  277. values.push(value.name);
  278. });
  279. }
  280. this._callPropertyOnChangeCallback(property, widgetInstance, propertyName, values);
  281. widgetInstance.onPropertyChange(propertyName, values);
  282. }.bind(this);
  283. };
  284. /**
  285. * @param timeUnit - 'seconds', 'minutes', 'hours'
  286. * @returns a structure stating the min and max of the specified timeUnit
  287. *
  288. */
  289. PropertiesUtil.prototype._getMaxMinRefreshValuesForUnits = function (timeUnit) {
  290. /*
  291. * The browser method used to provide a timed delay between refresh calls has
  292. * a max size of a signed integer. We must ensure we stay below this number
  293. * depending on the time unit
  294. */
  295. var maxIntervalInSeconds = (Math.pow(2, 31) - 1) / 1000;
  296. var maxForTimeUnit;
  297. var values = {};
  298. switch (timeUnit) {
  299. case 'minutes':
  300. values.min = 1;
  301. maxForTimeUnit = maxIntervalInSeconds / 60;
  302. values.max = Math.ceil(maxForTimeUnit - 1);
  303. break;
  304. case 'hours':
  305. values.min = 1;
  306. maxForTimeUnit = maxIntervalInSeconds / 3600;
  307. values.max = Math.ceil(maxForTimeUnit - 1);
  308. break;
  309. default:
  310. // includes seconds
  311. values.min = 5;
  312. values.max = Math.ceil(maxIntervalInSeconds - 1);
  313. }
  314. return values;
  315. };
  316. /**
  317. Called when the toggleCombo (auto refresh) property changes
  318. @param {string} valueOfInput
  319. @param {string} valueOfDropDown
  320. **/
  321. PropertiesUtil.prototype._validateToggleComboProperty = function (valueOfInput, valueOfDropDown) {
  322. if (!valueOfInput || !valueOfDropDown) {
  323. return false;
  324. }
  325. var isValid = $.isNumeric(valueOfInput);
  326. if (isValid) {
  327. var maxMinValuesForUnit = this._getMaxMinRefreshValuesForUnits(valueOfDropDown);
  328. // ensure the valueOfInput is between our current min and max.
  329. isValid = valueOfInput >= maxMinValuesForUnit.min && valueOfInput <= maxMinValuesForUnit.max;
  330. }
  331. return isValid;
  332. };
  333. /**
  334. Handles setting the callbacks and dynamic properties of a Palette property
  335. @param {object} property - the property object for which to get any dynamically generated member variables
  336. @param {object} widgetInstance - the widget instance which wants to display these properties
  337. @param {object} dashboardApi
  338. @param {function} [onChangeCallback] - optional to override the default onchange behavior
  339. **/
  340. PropertiesUtil.prototype.handleNewPaletteProperty = function (property, widgetInstance, dashboardApi, onChangeCallback) {
  341. var _this2 = this;
  342. if (!property.paletteType) {
  343. throw new Error('Palette property needs a "paletteType"', property);
  344. }
  345. var colorsService = dashboardApi.getFeature('Colors');
  346. var getPaletteId = function getPaletteId() {
  347. var paletteId = _this2._getPropertyValue(widgetInstance, property.name);
  348. paletteId = paletteId || property.defaultValue || colorsService.getDefaultPaletteName(property.paletteType);
  349. return paletteId;
  350. };
  351. var paletteId = getPaletteId();
  352. var continuousPalette = property.paletteType === 'HeatPalette';
  353. var createPaletteType = continuousPalette ? 'continuous' : 'standard';
  354. var isReverse = function isReverse() {
  355. var currentOrder = _this2._getPropertyValue(widgetInstance, property.reversePalettePropName);
  356. return currentOrder === 'DarkerForLowerValue' && continuousPalette;
  357. };
  358. property.menuItems = [];
  359. if (continuousPalette) {
  360. property.menuItems.push('reverse');
  361. }
  362. property.reverse = isReverse();
  363. property.createPaletteType = createPaletteType;
  364. return colorsService.getPalette({
  365. paletteId: paletteId,
  366. type: property.paletteType,
  367. defaultPaletteId: property.defaultValue,
  368. addMissingBaseColors: property.addMissingBaseColors,
  369. defaultIfNotFound: true,
  370. forProperties: true
  371. }).then(function (selPalette) {
  372. property.palette = selPalette;
  373. property.hasSection = true;
  374. property.readOnly = true;
  375. if (selPalette.my && !selPalette.public) {
  376. property.menuItems.push('edit');
  377. }
  378. property.onChangePalette = onChangeCallback ? onChangeCallback : function (propertyName, paletteItem) {
  379. _this2._callPropertyOnChangeCallback(property, widgetInstance, propertyName, paletteItem.id);
  380. widgetInstance.onColorPaletteChanged(_this2.buildPropChangePayload(propertyName, paletteItem.id)).then(function () {
  381. widgetInstance.refreshPropertiesPane();
  382. });
  383. };
  384. // Handle selection when creating a palette
  385. var onCreatePalette = function onCreatePalette(paletteId) {
  386. var prefixCMId = '__CM__';
  387. var cmId = prefixCMId + paletteId;
  388. property.onChangePalette(property.name, { id: cmId });
  389. return cmId;
  390. };
  391. property.onCreatePalette = onCreatePalette;
  392. property.onChange = function (propertyName, paletteItem) {
  393. var orderValue = paletteItem.reverse === true ? 'DarkerForLowerValue' : 'DarkerForHigherValue';
  394. _this2._callPropertyOnChangeCallback(property, widgetInstance, property.reversePalettePropName, orderValue);
  395. widgetInstance.onHeatScalePaletteChanged(_this2.buildPropChangePayload(property.reversePalettePropName, orderValue));
  396. };
  397. property.changePaletteCb = function () {
  398. widgetInstance.dashboardApi.getDashboardSvc('propertiesManager').then(function (propertyManager) {
  399. var options = {
  400. label: property.linkLabel,
  401. overlay: true,
  402. width: '320px',
  403. content: {
  404. module: 'authoring-common/changePaletteView',
  405. selectedId: paletteId,
  406. onCreatePalette: onCreatePalette,
  407. createPaletteType: createPaletteType,
  408. name: property.name,
  409. getPalettes: function getPalettes() {
  410. return colorsService.getPalettes({
  411. type: property.paletteType,
  412. includeUserColorPalette: property.includeUserColorPalette,
  413. forProperties: true
  414. });
  415. },
  416. getPaletteId: getPaletteId.bind(widgetInstance),
  417. reverse: isReverse(),
  418. onChange: property.onChangePalette,
  419. component: 'dashboard'
  420. }
  421. };
  422. widgetInstance.dashboardApi.prepareGlassOptions(options);
  423. propertyManager.addChild(options);
  424. });
  425. };
  426. return property;
  427. });
  428. };
  429. /**
  430. Builds the payload needed for the property change event
  431. @param {string} propName - the name of the property changing
  432. @param {object} propValue - the new value for the property
  433. **/
  434. PropertiesUtil.prototype.buildPropChangePayload = function (propName, propValue) {
  435. return {
  436. 'category': propName,
  437. 'item': propValue,
  438. 'transactionId': _.uniqueId('prop_change')
  439. };
  440. };
  441. /**
  442. Add the ability to a color picker to handle custom colors
  443. @param {object} property - Property object
  444. @param {object} colorsService - ref to the color service
  445. **/
  446. PropertiesUtil.prototype.addCustomColorCapability = function (property, colorsService) {
  447. property.createCustomColor = function (hex) {
  448. var className = colorsService.addCustomColor(hex);
  449. var colorProp = colorsService.createColorDefinition(className, hex, hex);
  450. colorProp.type = 'ColorCode';
  451. colorProp.hidden = true;
  452. return colorProp;
  453. };
  454. if (colorsService.isCustomColor(property.selectedName) && property.items) {
  455. var hex = colorsService.getHexColorFromClassName(property.selectedName);
  456. var colorProp = colorsService.createColorDefinition(property.selectedName, hex, hex);
  457. colorProp.hidden = true;
  458. property.items.push(colorProp);
  459. }
  460. return property;
  461. };
  462. /**
  463. Checks to see if the palette property is set in the model, if it isn't will return the default palette name for the type
  464. of palette being asked for
  465. @param {object} widgetInstance - the widget instance which wants to display these properties
  466. @param {object} dashboardApi
  467. @param {string} palettePropertyName - the name of the property which contains the palette name
  468. @param {string} paletteType - the type of palette being asked for
  469. **/
  470. PropertiesUtil.prototype._getColorPalettePropertyValue = function (widgetInstance, colorsService, palettePropertyName, paletteType) {
  471. var propertyValue = this._getPropertyValue(widgetInstance, palettePropertyName);
  472. return propertyValue || colorsService.getDefaultPaletteName(paletteType);
  473. };
  474. /**
  475. Checks the model and the visModel to see if the property has been set and return the value if found.
  476. @param {object} widgetInstance - the widget instance which wants to display these properties
  477. @param {string} propertyName - the name of the property
  478. @return {object} - the value of the set property or null if the property isn't set in the model
  479. **/
  480. PropertiesUtil.prototype._getPropertyValue = function (widgetInstance, propertyName) {
  481. if (widgetInstance.model && widgetInstance.model[propertyName] !== undefined) {
  482. return widgetInstance.model[propertyName];
  483. } else if (widgetInstance.visModel && widgetInstance.visModel.getPropertyValue(propertyName) !== null) {
  484. return widgetInstance.visModel.getPropertyValue(propertyName);
  485. } else if (widgetInstance.visAPI && widgetInstance.visAPI.getPropertyValue(propertyName) !== null) {
  486. return widgetInstance.visAPI.getPropertyValue(propertyName);
  487. } else if (widgetInstance[propertyName] !== 'undefined' && typeof widgetInstance[propertyName] !== 'function') {
  488. return widgetInstance[propertyName];
  489. }
  490. return null;
  491. };
  492. /**
  493. Handles setting the callbacks and dynamic properties of a ColorPicker property
  494. @param {object} property - the property object for which to get any dynamically generated member variables
  495. @param {object} widgetInstance - the widget instance which wants to display these properties
  496. @param {object} dashboardApi
  497. **/
  498. PropertiesUtil.prototype.handleColorPickerProperty = function (property, widgetInstance, dashboardApi) {
  499. var _this3 = this;
  500. if (!property.paletteType) {
  501. throw new Error('Color picker property needs a "paletteType"', property);
  502. }
  503. var colorsService = dashboardApi.getFeature('Colors');
  504. property.onChange = function (propertyName, propertyValueInfo) {
  505. this._callPropertyOnChangeCallback(property, widgetInstance, property.propertyName, propertyValueInfo.name);
  506. widgetInstance.onPropertyChange(propertyName, propertyValueInfo.name);
  507. }.bind(this);
  508. var currentValue = this._getPropertyValue(widgetInstance, property.name);
  509. // when current value is 0, it should keep it
  510. property.selectedName = !currentValue && currentValue !== 0 && property.defaultValue ? property.defaultValue : currentValue;
  511. return this._getColorPickerColors(property, widgetInstance, dashboardApi).then(function (colors) {
  512. // If the colors being show are based off another property, then we need to tweak to payload for backwards compatibility
  513. if (property.palettePropertyName) {
  514. property.items = [];
  515. colors.forEach(function (color, index) {
  516. property.items.push({
  517. 'id': index,
  518. 'name': index,
  519. 'value': color.hexValue,
  520. 'type': 'ColorCode',
  521. 'label': color.label
  522. });
  523. });
  524. } else {
  525. property.items = colors;
  526. }
  527. //
  528. if (property.addButton) {
  529. property = _this3.addCustomColorCapability(property, colorsService);
  530. }
  531. // If the current value saved in the model is higher then the number of colors available, default
  532. // back to the first color
  533. if (property.selectedName > colors.length) {
  534. property.selectedName = 0;
  535. } else if (!property.selectedName && property.selectedName !== 0 && property.defaultColorIndex !== undefined) {
  536. // when selectedName value is 0, it should keep it
  537. property.selectedName = property.defaultColorIndex;
  538. } else if (property.missingIsLast && property.selectedName) {
  539. var selectedColor = _.find(property.items, function (color) {
  540. return color.name === property.selectedName;
  541. });
  542. if (!selectedColor) {
  543. property.selectedName = property.items[property.items.length - 1].name;
  544. }
  545. }
  546. return property;
  547. });
  548. };
  549. PropertiesUtil.prototype._getColorPickerColors = function (property, widgetInstance, dashboardApi) {
  550. var colorsService = dashboardApi.getFeature('Colors');
  551. if (property.paletteType === 'DashboardColorSet') {
  552. return Promise.resolve(colorsService.getDashboardColorSet().slice(0));
  553. }
  554. var paletteId = property.palettePropertyName ? this._getColorPalettePropertyValue(widgetInstance, colorsService, property.palettePropertyName, property.paletteType) : colorsService.getColorSetId();
  555. return colorsService.getPaletteColors({
  556. paletteId: paletteId,
  557. type: property.paletteType,
  558. addMissingBaseColors: property.addMissingBaseColors
  559. }).then(function (colors) {
  560. return colors.slice(0);
  561. });
  562. };
  563. /**
  564. Currently only being called by the custom widget since it doesn't use contributions like our other widgets. Returns
  565. the default properties to show on the general property tab.
  566. **/
  567. PropertiesUtil.prototype.getGeneralProperties = function (widgetInstance, dashboardApi) {
  568. var properties = [{
  569. 'id': 'fillColor',
  570. 'type': 'ColorPicker',
  571. 'label': StringResources.get('propFillColor'),
  572. 'showHexValue': true,
  573. 'addButton': true,
  574. 'open': false,
  575. 'ariaLabel': StringResources.get('propFillColor'),
  576. 'paletteType': 'ColorPalette',
  577. 'defaultValue': 'color1',
  578. 'tabName': StringResources.get('tabName_general'),
  579. 'sectionName': StringResources.get('sectionName_appearance')
  580. }, {
  581. 'id': 'borderColor',
  582. 'type': 'ColorPicker',
  583. 'label': StringResources.get('propBorderColor'),
  584. 'open': false,
  585. 'showHexValue': true,
  586. 'addButton': true,
  587. 'ariaLabel': StringResources.get('propBorderColor'),
  588. 'paletteType': 'ColorPalette',
  589. 'defaultValue': 'transparent',
  590. 'tabName': StringResources.get('tabName_general'),
  591. 'sectionName': StringResources.get('sectionName_appearance')
  592. }];
  593. if (widgetInstance) {
  594. return this.processProperties(properties, widgetInstance, dashboardApi).then(function () {
  595. return properties;
  596. });
  597. } else {
  598. return Promise.resolve(properties);
  599. }
  600. };
  601. /**
  602. * Method that takes our propertyUIControl spec and generates properties for our public API. This is temporary until
  603. * we clean up our properties logic throughout the code
  604. * @param {*} properties
  605. * @param {*} widgetInstance
  606. * @param {*} dashboardApi
  607. */
  608. PropertiesUtil.prototype.propertyUIControlToPublicAPI = function (properties, widgetInstance, dashboardApi) {
  609. var _this4 = this;
  610. var propertiesList = [];
  611. var setValue = function setValue(property, value) {
  612. if (dashboardApi.getMode() !== 'authoring') {
  613. dashboardApi.getGlassCoreSvc('.Logger').error('Trying to set a property without being in authoring mode.');
  614. return false;
  615. }
  616. if (property.customValidatorCallback) {
  617. var validInfo = property.customValidatorCallback(value);
  618. if (validInfo && validInfo.isValid === false) {
  619. dashboardApi.getGlassCoreSvc('.Logger').error(validInfo.message);
  620. return false;
  621. }
  622. }
  623. if (property.onChange) {
  624. if (property.module && property.module.indexOf('UiSlider') >= 0) {
  625. property.onChange([value]);
  626. } else if (property.type === 'ColorPicker') {
  627. var valueToSet = value && value.startsWith('#') ? dashboardApi.getFeature('Colors').addCustomColor(value) : value;
  628. property.onChange(property.name, {
  629. name: valueToSet
  630. });
  631. } else if (property.type === 'NewPalette') {
  632. property.onChangePalette(property.name, {
  633. id: value
  634. });
  635. } else {
  636. property.onChange(property.name, value);
  637. }
  638. return true;
  639. }
  640. };
  641. var getValue = function getValue(property, widgetInstance) {
  642. var propValue = _this4._getPropertyValue(widgetInstance, property.name);
  643. if (propValue) {
  644. return propValue;
  645. }
  646. return property.defaultValue !== undefined ? property.defaultValue : null;
  647. };
  648. properties.forEach(function (property) {
  649. // For now guard against not having an onChange property. This currently happens with complex property where the onChange is
  650. // buried inside of the items property.
  651. if (property.type === 'Banner' || property.public === false || !property.onChange) {
  652. return null;
  653. }
  654. // Currently only expose the minimum needed for system tests. Once this starts being used for our UI we'll
  655. // need to augment what's exposed in the API
  656. var propertyApi = {
  657. name: property.name,
  658. getValue: getValue.bind(_this4, property, widgetInstance),
  659. setValue: setValue.bind(_this4, property)
  660. };
  661. propertiesList.push(propertyApi);
  662. });
  663. return propertiesList;
  664. };
  665. var _static = {
  666. getInstance: function getInstance() {
  667. if (!_singletonInstance) {
  668. _singletonInstance = new PropertiesUtil();
  669. }
  670. return _singletonInstance;
  671. }
  672. };
  673. return _static.getInstance();
  674. });
  675. //# sourceMappingURL=PropertiesUtil.js.map