LayoutPropertiesProvider.js 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520
  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: Dashboard
  6. * (C) Copyright IBM Corp. 2019, 2020
  7. * US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
  8. */
  9. define(['../../../app/nls/StringResources', '../../../dashboard/layout/LayoutHelper', '../../../lib/@waca/dashboard-common/dist/core/APIFactory', '../../../lib/@waca/dashboard-common/dist/ui/interaction/Utils', '../../../lib/@waca/baglass/js/baglass/utils/Utils', '../../../lib/@waca/core-client/js/core-client/ui/dialogs/ConfirmationDialog', '../../../lib/@waca/dashboard-common/dist/api/PropertiesProviderAPI', 'underscore', '../../../dashboard/widgets/PropertyListUtil', '../../../dashboard/util/ContentRegistryUtil'], function (StringResources, LayoutHelper, APIFactory, CommonUtils, Utils, ConfirmationDialog, PropertiesProviderAPI, _, PropertyListUtil, ContentRegistryUtil) {
  10. var WIDGET_SIZES = {
  11. 'widget.text': {
  12. min: {
  13. width: 100,
  14. height: 40
  15. }
  16. },
  17. default: {
  18. min: {
  19. width: 25,
  20. height: 25
  21. }
  22. }
  23. };
  24. var LayoutProperties = function () {
  25. function LayoutProperties(options) {
  26. _classCallCheck(this, LayoutProperties);
  27. this.dashboard = options.dashboardApi || options.dashboardAPI;
  28. this._canvas = options.features['Canvas'];
  29. this.content = options.content;
  30. this.content.getFeature('Properties').registerProvider(this.getAPI());
  31. }
  32. LayoutProperties.prototype.getLayoutModel = function getLayoutModel() {
  33. var boardModel = this.dashboard.getFeature('internal').getBoardModel();
  34. return boardModel.layout.findModel(this.content.getId());
  35. };
  36. LayoutProperties.prototype.getAPI = function getAPI() {
  37. return APIFactory.createAPI(this, [PropertiesProviderAPI]);
  38. };
  39. LayoutProperties.prototype._getCommonType = function _getCommonType(contentType) {
  40. return contentType && contentType.split('.')[0];
  41. };
  42. LayoutProperties.prototype._getSubType = function _getSubType(contentType) {
  43. if (contentType && contentType.indexOf('.') !== -1) {
  44. return contentType.split('.')[1];
  45. } else {
  46. return null;
  47. }
  48. };
  49. LayoutProperties.prototype.getPropertyList = function getPropertyList() {
  50. var _this = this;
  51. var propertyList = [];
  52. var contentType = this.content.getType();
  53. var commonType = this._getCommonType(contentType);
  54. var subType = this._getSubType(contentType);
  55. if (commonType === 'widget' || commonType === 'group' || this._isTypeRegistered(commonType)) {
  56. propertyList.push.apply(propertyList, this._getWidgetPropertyList(subType));
  57. }
  58. // Default the setPropertyValue and getPropertyValue for any property that doesn't define those methods
  59. //propertyList.forEach((property) => {
  60. if (propertyList) {
  61. var _loop = function _loop(i) {
  62. var property = propertyList[i];
  63. if (!property.setPropertyValue) {
  64. property.setPropertyValue = function (value) {
  65. return _this._setPropertyValueInModel(property.id, value);
  66. };
  67. }
  68. if (!property.getPropertyValue) {
  69. property.getPropertyValue = function () {
  70. return _this._getPropertyValueFromModel(property.id);
  71. };
  72. }
  73. };
  74. for (var i = 0; i < propertyList.length; i++) {
  75. _loop(i);
  76. }
  77. }
  78. //});
  79. return propertyList;
  80. };
  81. LayoutProperties.prototype._isTypeRegistered = function _isTypeRegistered(type) {
  82. var contentTypeRegistry = this.dashboard.getFeature('ContentTypeRegistry');
  83. return contentTypeRegistry.isTypeRegistered(type);
  84. };
  85. LayoutProperties.prototype.getPropertyLayoutList = function getPropertyLayoutList() {
  86. var propertiesLayoutSpec = [];
  87. if (!this._isTopLevelPage()) {
  88. propertiesLayoutSpec.push({
  89. 'value': StringResources.get('settings'),
  90. 'id': 'banner',
  91. 'type': 'Banner',
  92. 'editable': false,
  93. 'override': false // a flag means if we already have the banner defined by other property provider, then do not override
  94. });
  95. }
  96. var commonType = this._getCommonType(this.content.getType());
  97. if (this._isTypeRegistered(commonType) || commonType === 'widget' || commonType === 'group') {
  98. propertiesLayoutSpec.push({
  99. id: 'general',
  100. type: 'Group',
  101. label: StringResources.get('tabName_general')
  102. }, {
  103. id: 'appearance',
  104. type: 'Section',
  105. open: false,
  106. label: StringResources.get('sectionName_appearance'),
  107. position: 1
  108. }, {
  109. id: 'layout',
  110. type: 'Section',
  111. open: true,
  112. label: StringResources.get('sectionName_layout'),
  113. position: 2
  114. }, {
  115. id: 'widgetPosition',
  116. type: 'Section',
  117. collapsible: false,
  118. label: StringResources.get('propPositionLabel'),
  119. position: 2
  120. }, {
  121. id: 'moveWidgetSplit',
  122. type: 'Split',
  123. items: [{
  124. id: 'left',
  125. align: 'left',
  126. items: []
  127. }, {
  128. id: 'right',
  129. align: 'right',
  130. items: []
  131. }]
  132. }, {
  133. id: 'resizeWidget',
  134. type: 'Section',
  135. collapsible: false,
  136. label: StringResources.get('propResizeLabel'),
  137. position: 3
  138. }, {
  139. id: 'rotate',
  140. type: 'Section',
  141. collapsible: false,
  142. label: StringResources.get('propRotateLabel'),
  143. position: 4
  144. }, {
  145. id: 'resizeWidgetSplit',
  146. type: 'Split',
  147. items: [{
  148. id: 'left',
  149. align: 'left',
  150. items: []
  151. }, {
  152. id: 'right',
  153. align: 'right',
  154. items: []
  155. }]
  156. });
  157. }
  158. return propertiesLayoutSpec;
  159. };
  160. LayoutProperties.prototype.getUnit = function getUnit() {
  161. return this._canvas.getPropertyValue('layoutPositioning') === 'absolute' ? 'px' : '%';
  162. };
  163. LayoutProperties.prototype._getMaxValueForConstraint = function _getMaxValueForConstraint(constrainedBy) {
  164. if (this._canvas.getPropertyValue('layoutPositioning') === 'relative') {
  165. return 100;
  166. } else {
  167. if (constrainedBy === 'width' || constrainedBy === 'left') {
  168. return parseFloat(this._canvas.getPropertyValue('pageSizeWidth'));
  169. } else {
  170. return parseFloat(this._canvas.getPropertyValue('pageSizeHeight'));
  171. }
  172. }
  173. };
  174. LayoutProperties.prototype._getNumericValueWithConstraint = function _getNumericValueWithConstraint(constrainedBy, propertyValue, minimum) {
  175. var numericValue = parseFloat(propertyValue);
  176. if (isNaN(numericValue)) {
  177. numericValue = 0;
  178. }
  179. var constraint = this.content.getPropertyValue(constrainedBy) || 0;
  180. var maxValue = this._getMaxValueForConstraint(constrainedBy);
  181. numericValue = Math.max(Math.min(maxValue, numericValue), minimum || 0);
  182. constraint = parseFloat(constraint);
  183. if (constraint + numericValue > maxValue) {
  184. numericValue = maxValue - constraint;
  185. }
  186. return numericValue;
  187. };
  188. LayoutProperties.prototype._onChangePercentOrPixelProperty = function _onChangePercentOrPixelProperty(constrainedBy, propertyName, propertyValue, options) {
  189. var units = this.getUnit();
  190. var minimum = WIDGET_SIZES[this.content.getType()] ? WIDGET_SIZES[this.content.getType()].min[propertyName] : WIDGET_SIZES.default.min[propertyName];
  191. if (minimum && units === '%') {
  192. // get the minimum value to percent
  193. var domFeature = this.content.getContainer().getFeature('ContentViewDOM');
  194. if (domFeature) {
  195. var node = domFeature.getNode();
  196. var size = propertyName === 'height' ? node.clientHeight : node.clientWidth;
  197. minimum = 100 * minimum / size;
  198. } else {
  199. // without a dom we can't figure out the minimum percent.. so we use 0
  200. minimum = 0;
  201. }
  202. }
  203. var numericValue = this._getNumericValueWithConstraint(constrainedBy, propertyValue, minimum);
  204. var formattedValue = PropertyListUtil.getPropertyDisplayString(numericValue, units);
  205. this.content.setPropertyValue(propertyName, formattedValue, options);
  206. };
  207. LayoutProperties.prototype._onChangeAngle = function _onChangeAngle(propertyName, propertyValue) {
  208. this.content.setPropertyValue(propertyName, propertyValue);
  209. };
  210. LayoutProperties.prototype._getWidgetPropertyList = function _getWidgetPropertyList() {
  211. var _this2 = this;
  212. var model = this.getLayoutModel();
  213. var isInGroup = false;
  214. var selection = this._canvas.getSelectedContentList();
  215. if (selection && selection.length) {
  216. var selectionParent = selection[0].getContainer();
  217. if (selectionParent) {
  218. isInGroup = selectionParent.getType() === 'group';
  219. }
  220. }
  221. var propertyList = [{
  222. getPropertyValue: function getPropertyValue() {
  223. if (model.style && (model.style.opacity || model.style.opacity === 0)) {
  224. return model.style.opacity;
  225. } else {
  226. return 1;
  227. }
  228. },
  229. setPropertyValue: function setPropertyValue(value, options) {
  230. _this2._updateStyleValueInModel('opacity', value, options);
  231. },
  232. id: 'opacity',
  233. editor: {
  234. sectionId: 'general.appearance',
  235. position: 4,
  236. uiControl: {
  237. label: StringResources.get('propOpacity'),
  238. description: StringResources.get('propOpacityDescription'),
  239. module: '../ui/UiSlider',
  240. sliderType: 'percentage',
  241. connect: [true, false],
  242. noInputView: true,
  243. step: 1,
  244. start: [100],
  245. startLabels: [StringResources.get('propOpacityDescription')],
  246. range: {
  247. 'min': 0,
  248. 'max': 100
  249. },
  250. format: {
  251. 'decimals': 0,
  252. 'postfix': '%'
  253. }
  254. }
  255. }
  256. }];
  257. var leftProperty = {
  258. id: 'left',
  259. getPropertyValue: function getPropertyValue() {
  260. if (model.style) {
  261. return model.style.left;
  262. }
  263. },
  264. setPropertyValue: function setPropertyValue(value, options) {
  265. _this2._updateStyleValueInModel('left', value, options);
  266. },
  267. editor: {
  268. sectionId: 'general.layout.widgetPosition.moveWidgetSplit.left',
  269. uiControl: {
  270. type: 'InputLabel',
  271. label: StringResources.get('propPositionXAxis'),
  272. multiline: true,
  273. handleReturnKey: true,
  274. decimalPlaces: 2,
  275. onChange: this._onChangePercentOrPixelProperty.bind(this, 'width')
  276. }
  277. },
  278. onPropertyChange: {
  279. refresh: {
  280. propertiesPane: true
  281. }
  282. }
  283. };
  284. if (isInGroup) {
  285. delete leftProperty.editor;
  286. }
  287. propertyList.push(leftProperty);
  288. var topProperty = {
  289. id: 'top',
  290. getPropertyValue: function getPropertyValue() {
  291. if (model.style) {
  292. return model.style.top;
  293. }
  294. },
  295. setPropertyValue: function setPropertyValue(value, options) {
  296. _this2._updateStyleValueInModel('top', value, options);
  297. },
  298. editor: {
  299. sectionId: 'general.layout.widgetPosition.moveWidgetSplit.right',
  300. uiControl: {
  301. type: 'InputLabel',
  302. label: StringResources.get('propPositionYAxis'),
  303. multiline: true,
  304. handleReturnKey: true,
  305. decimalPlaces: 2,
  306. onChange: this._onChangePercentOrPixelProperty.bind(this, 'height')
  307. }
  308. },
  309. onPropertyChange: {
  310. refresh: {
  311. propertiesPane: true
  312. }
  313. }
  314. };
  315. if (isInGroup) {
  316. delete topProperty.editor;
  317. }
  318. propertyList.push(topProperty);
  319. var widthProperty = {
  320. id: 'width',
  321. getPropertyValue: function getPropertyValue() {
  322. if (model.style) {
  323. return model.style.width;
  324. }
  325. },
  326. setPropertyValue: function setPropertyValue(value, options) {
  327. _this2._updateStyleValueInModel('width', value, options);
  328. },
  329. editor: {
  330. sectionId: 'general.layout.resizeWidget.resizeWidgetSplit.left',
  331. uiControl: {
  332. type: 'InputLabel',
  333. label: StringResources.get('propResizeWidth'),
  334. multiline: true,
  335. handleReturnKey: true,
  336. decimalPlaces: 2,
  337. onChange: this._onChangePercentOrPixelProperty.bind(this, 'left')
  338. }
  339. },
  340. onPropertyChange: {
  341. refresh: {
  342. propertiesPane: true
  343. }
  344. }
  345. };
  346. if (isInGroup) {
  347. delete widthProperty.editor;
  348. }
  349. propertyList.push(widthProperty);
  350. var heightProperty = {
  351. id: 'height',
  352. getPropertyValue: function getPropertyValue() {
  353. if (model.style) {
  354. return model.style.height;
  355. }
  356. },
  357. setPropertyValue: function setPropertyValue(value, options) {
  358. _this2._updateStyleValueInModel('height', value, options);
  359. },
  360. editor: {
  361. sectionId: 'general.layout.resizeWidget.resizeWidgetSplit.right',
  362. uiControl: {
  363. type: 'InputLabel',
  364. label: StringResources.get('propResizeHeight'),
  365. multiline: true,
  366. handleReturnKey: true,
  367. decimalPlaces: 2,
  368. onChange: this._onChangePercentOrPixelProperty.bind(this, 'top')
  369. }
  370. },
  371. onPropertyChange: {
  372. refresh: {
  373. propertiesPane: true
  374. }
  375. }
  376. };
  377. if (isInGroup) {
  378. delete heightProperty.editor;
  379. }
  380. propertyList.push(heightProperty);
  381. var rotationSupported = this._isCapabilityEnabled('rotation');
  382. propertyList.push({
  383. id: 'canRotate',
  384. getPropertyValue: function getPropertyValue() {
  385. return rotationSupported;
  386. },
  387. setPropertyValue: function setPropertyValue() {
  388. throw new Error('not supported');
  389. }
  390. });
  391. if (rotationSupported) {
  392. var rotationProperty = {
  393. id: 'rotateAngle',
  394. getPropertyValue: function getPropertyValue() {
  395. var transform = model.style && model.style.transform;
  396. if (transform) {
  397. var deg = /-?\d*\.?\d*deg/.exec(transform);
  398. if (deg) {
  399. var str = deg[0];
  400. var value = str.substr(0, str.length - 3);
  401. return parseFloat(value) || 0;
  402. } else {
  403. return CommonUtils.getAngleFromMatrix(transform);
  404. }
  405. } else {
  406. return 0;
  407. }
  408. },
  409. setPropertyValue: function setPropertyValue(value, options) {
  410. value = parseFloat(value);
  411. var sanitizedValue = (value % 360 + 360) % 360;
  412. if (!isNaN(sanitizedValue)) {
  413. _this2._updateStyleValueInModel('-webkit-transform', 'rotate( ' + sanitizedValue + 'deg )', options);
  414. _this2._updateStyleValueInModel('transform', 'rotate( ' + sanitizedValue + 'deg )', options);
  415. }
  416. },
  417. editor: {
  418. sectionId: 'general.layout.rotate',
  419. uiControl: {
  420. type: 'InputLabel',
  421. label: StringResources.get('propRotateAngle'),
  422. handleReturnKey: true,
  423. onChange: this._onChangeAngle.bind(this)
  424. }
  425. }
  426. };
  427. if (isInGroup) {
  428. delete rotationProperty.editor;
  429. }
  430. propertyList.push(rotationProperty);
  431. }
  432. return propertyList;
  433. };
  434. LayoutProperties.prototype._isCapabilityEnabled = function _isCapabilityEnabled(capability) {
  435. var capabilitiesFeature = ContentRegistryUtil.getCapabilities(this.content);
  436. return this.content.getType() !== 'widget.live' && (capabilitiesFeature ? capabilitiesFeature.getCapabilities()[capability] : true);
  437. };
  438. LayoutProperties.prototype._getPropertyValueFromModel = function _getPropertyValueFromModel(propName) {
  439. var model = this.getLayoutModel();
  440. // In case of livewidget previews, we have a content but it is not attached to the layout, which causes the model to be null.
  441. return model && model.get(propName);
  442. };
  443. LayoutProperties.prototype._setPropertyValueInModel = function _setPropertyValueInModel(propName, propValue, options) {
  444. var payload = {};
  445. var model = this.getLayoutModel();
  446. payload[propName] = propValue;
  447. model.set(payload, options);
  448. };
  449. LayoutProperties.prototype._updateStyleValueInModel = function _updateStyleValueInModel(styleName, value) {
  450. var styleValue = value;
  451. var model = this.getLayoutModel();
  452. var newStyle = _.extend({}, model.style);
  453. newStyle[styleName] = styleValue;
  454. // Todo: we can stop using the topLayoutModel once the undo/redo uses
  455. // the API events, but for now using the model directly doesn't add to the stack
  456. // if the widget is not on the same tab that it was initally added on.
  457. model.getTopLayoutModel().updateModel({
  458. updateArray: [{
  459. id: model.id,
  460. style: newStyle
  461. }]
  462. }, this, {
  463. skipUndoRedo: true
  464. });
  465. return styleValue;
  466. };
  467. LayoutProperties.prototype._isTopLevelPage = function _isTopLevelPage() {
  468. return !this.content.getContainer();
  469. };
  470. return LayoutProperties;
  471. }();
  472. return LayoutProperties;
  473. });
  474. //# sourceMappingURL=LayoutPropertiesProvider.js.map