TimelinePropertiesProvider.js 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358
  1. 'use strict';
  2. function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
  3. /**
  4. * Licensed Materials - Property of IBM
  5. * IBM Cognos Products: BI Cloud (C) Copyright IBM Corp. 2019
  6. * US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
  7. */
  8. define(['underscore', 'gemini/lib/@waca/dashboard-common/dist/core/APIFactory', 'gemini/lib/@waca/dashboard-common/dist/api/PropertiesProviderAPI'], function (_, APIFactory, PropertiesProviderAPI) {
  9. var TimelinePropertiesProvider = function () {
  10. function TimelinePropertiesProvider(options) {
  11. _classCallCheck(this, TimelinePropertiesProvider);
  12. this.dashboardApi = options.dashboardAPI;
  13. this.content = options.content;
  14. this.stringResources = this.dashboardApi.getFeature('.StringResources');
  15. this._api = APIFactory.createAPI(this, [PropertiesProviderAPI]);
  16. // register self as a properties provider contributing timeline properties
  17. this.content.getFeature('Properties').registerProvider(this.getAPI());
  18. }
  19. TimelinePropertiesProvider.prototype.getAPI = function getAPI() {
  20. return this._api;
  21. };
  22. TimelinePropertiesProvider.prototype.getPropertyLayoutList = function getPropertyLayoutList() {
  23. return [{
  24. id: 'animation',
  25. type: 'Group',
  26. label: this.stringResources.get('tabName_animation')
  27. }, {
  28. id: 'propAniEntrance',
  29. type: 'Section',
  30. label: this.stringResources.get('propAniEntrance'),
  31. position: 1
  32. }, {
  33. id: 'propAniExit',
  34. type: 'Section',
  35. label: this.stringResources.get('propAniExit'),
  36. position: 2
  37. }];
  38. };
  39. TimelinePropertiesProvider.prototype.getPropertyList = function getPropertyList() {
  40. return this._getTimelineProperties();
  41. };
  42. TimelinePropertiesProvider.prototype._getTimelineProperties = function _getTimelineProperties() {
  43. var properties = [];
  44. var timelineController = this.dashboardApi.getFeature('.StoryPaneService').timelineController;
  45. var episode = timelineController.getTimelineEpisodeById(this.content.getId());
  46. if (episode) {
  47. var duration = timelineController.getDuration();
  48. if (episode.touchesStart()) {
  49. properties.push({
  50. id: 'noEntranceAnimation',
  51. editor: {
  52. sectionId: 'animation.propAniEntrance',
  53. readOnly: true,
  54. position: 1,
  55. uiControl: {
  56. type: 'SectionLabel',
  57. label: this.stringResources.get('animationNoEntranceText'),
  58. tabName: this.stringResources.get('tabName_animation'),
  59. sectionName: this.stringResources.get('propAniEntrance')
  60. }
  61. }
  62. });
  63. } else {
  64. properties.push.apply(properties, this._getEntranceSectionItems(episode.getEntranceAct(), this.content));
  65. }
  66. if (episode.touchesEnd(duration)) {
  67. properties.push({
  68. id: 'noExitAnimation',
  69. editor: {
  70. sectionId: 'animation.propAniExit',
  71. readOnly: true,
  72. position: 1,
  73. uiControl: {
  74. type: 'SectionLabel',
  75. label: this.stringResources.get('animationNoExitText'),
  76. tabName: this.stringResources.get('tabName_animation'),
  77. sectionName: this.stringResources.get('propAniExit')
  78. }
  79. }
  80. });
  81. } else {
  82. properties.push.apply(properties, this._getExitSectionItems(episode.getExitAct(), this.content));
  83. }
  84. properties.push.apply(properties, this._getAnimationTimeProperties(episode, timelineController));
  85. }
  86. return properties;
  87. };
  88. TimelinePropertiesProvider.prototype._getEntranceSectionItems = function _getEntranceSectionItems(act, content) {
  89. var _this = this;
  90. var initialEntranceAnimation = act.action || 'show';
  91. var initialEntranceDirection = null;
  92. if (initialEntranceAnimation.indexOf('slide') >= 0) {
  93. initialEntranceDirection = initialEntranceAnimation;
  94. initialEntranceAnimation = 'slideIn';
  95. }
  96. return [{
  97. id: 'animationEntranceType',
  98. getPropertyValue: function getPropertyValue() {
  99. return initialEntranceAnimation;
  100. },
  101. setPropertyValue: function setPropertyValue(value) {
  102. if (value === 'slideIn') {
  103. value = content.getPropertyValue('animationEntranceDirection') || 'slideInLeft';
  104. }
  105. _this._updateActModel(act, { 'action': value });
  106. },
  107. editor: {
  108. sectionId: 'animation.propAniEntrance',
  109. position: 1,
  110. uiControl: {
  111. type: 'DropDown',
  112. name: 'animationEntranceType',
  113. label: this.stringResources.get('propAniAnimation'),
  114. ariaLabel: this.stringResources.get('propAniTypeEntrance'),
  115. options: [{ label: this.stringResources.get('propAniTypeEntranceFadeIn'), value: 'show' }, { label: this.stringResources.get('propAniTypeEntranceSlideIn'), value: 'slideIn' }, { label: this.stringResources.get('propAniTypeEntranceScaleIn'), value: 'scaleIn' }, { label: this.stringResources.get('propAniTypeEntranceShrinkIn'), value: 'shrinkIn' }, { label: this.stringResources.get('propAniTypeEntrancePivotIn'), value: 'pivotIn' }],
  116. onChange: function onChange(propertyName, propertyValue) {
  117. _this.dashboardApi.triggerDashboardEvent('properties:updateEnabled', { propertyName: 'animationEntranceDirection', enabled: propertyValue === 'slideIn' });
  118. _this.content.setPropertyValue(propertyName, propertyValue);
  119. }
  120. }
  121. }
  122. }, {
  123. id: 'animationEntranceDirection',
  124. getPropertyValue: function getPropertyValue() {
  125. return initialEntranceDirection;
  126. },
  127. setPropertyValue: function setPropertyValue(value) {
  128. return _this._updateActModel(act, { 'action': value });
  129. },
  130. editor: {
  131. sectionId: 'animation.propAniEntrance',
  132. position: 2,
  133. uiControl: {
  134. type: 'DropDown',
  135. name: 'animationEntranceDirection',
  136. label: this.stringResources.get('propAniDirection'),
  137. ariaLabel: this.stringResources.get('propAniDirectionIn'),
  138. disabled: initialEntranceAnimation !== 'slideIn',
  139. options: [{ label: this.stringResources.get('propAniDirectionInLeft'), value: 'slideInLeft' }, { label: this.stringResources.get('propAniDirectionInRight'), value: 'slideInRight' }, { label: this.stringResources.get('propAniDirectionInTop'), value: 'slideInTop' }, { label: this.stringResources.get('propAniDirectionInBottom'), value: 'slideInBottom' }]
  140. }
  141. }
  142. }];
  143. };
  144. TimelinePropertiesProvider.prototype._getExitSectionItems = function _getExitSectionItems(act, content) {
  145. var _this2 = this;
  146. var initialExitAnimation = act.action || 'hide';
  147. var initialExitDirection = null;
  148. if (initialExitAnimation.indexOf('slide') >= 0) {
  149. initialExitDirection = initialExitAnimation;
  150. initialExitAnimation = 'slideOut';
  151. }
  152. return [{
  153. id: 'animationExitType',
  154. getPropertyValue: function getPropertyValue() {
  155. return initialExitAnimation;
  156. },
  157. setPropertyValue: function setPropertyValue(value) {
  158. if (value === 'slideOut') {
  159. value = content.getPropertyValue('animationExitDirection') || 'slideOutLeft';
  160. }
  161. _this2._updateActModel(act, { 'action': value });
  162. },
  163. editor: {
  164. sectionId: 'animation.propAniExit',
  165. position: 1,
  166. uiControl: {
  167. type: 'DropDown',
  168. name: 'animationExitType',
  169. label: this.stringResources.get('propAniAnimation'),
  170. ariaLabel: this.stringResources.get('propAniTypeExit'),
  171. options: [{ label: this.stringResources.get('propAniTypeExitFadeIn'), value: 'hide' }, { label: this.stringResources.get('propAniTypeExitSlideIn'), value: 'slideOut' }, { label: this.stringResources.get('propAniTypeExitScaleIn'), value: 'scaleOut' }, { label: this.stringResources.get('propAniTypeExitExpandOut'), value: 'expandOut' }, { label: this.stringResources.get('propAniTypeExitPivotOut'), value: 'pivotOut' }],
  172. onChange: function onChange(propertyName, propertyValue) {
  173. _this2.dashboardApi.triggerDashboardEvent('properties:updateEnabled', { propertyName: 'animationExitDirection', enabled: propertyValue === 'slideOut' });
  174. _this2.content.setPropertyValue(propertyName, propertyValue);
  175. }
  176. }
  177. }
  178. }, {
  179. id: 'animationExitDirection',
  180. getPropertyValue: function getPropertyValue() {
  181. return initialExitDirection;
  182. },
  183. setPropertyValue: function setPropertyValue(value) {
  184. return _this2._updateActModel(act, { 'action': value });
  185. },
  186. editor: {
  187. sectionId: 'animation.propAniExit',
  188. position: 2,
  189. uiControl: {
  190. type: 'DropDown',
  191. name: 'animationExitDirection',
  192. label: this.stringResources.get('propAniDirection'),
  193. ariaLabel: this.stringResources.get('propAniDirectionOut'),
  194. disabled: initialExitAnimation !== 'slideOut',
  195. options: [{ label: this.stringResources.get('propAniDirectionOutLeft'), value: 'slideOutLeft' }, { label: this.stringResources.get('propAniDirectionOutRight'), value: 'slideOutRight' }, { label: this.stringResources.get('propAniDirectionOutTop'), value: 'slideOutTop' }, { label: this.stringResources.get('propAniDirectionOutBottom'), value: 'slideOutBottom' }]
  196. }
  197. }
  198. }];
  199. };
  200. TimelinePropertiesProvider.prototype._getAnimationTimeProperties = function _getAnimationTimeProperties(episode, timelineController) {
  201. var _this3 = this;
  202. return [{
  203. id: 'animationEntranceTime',
  204. getPropertyValue: function getPropertyValue() {
  205. return _this3._getValueString(episode.getEntranceAct().timer);
  206. },
  207. setPropertyValue: function setPropertyValue(value, act) {
  208. void act;
  209. //TODO this should be in the episode... or the act itself
  210. timelineController.updateTimelineDuration(_this3.content.getId(), value, episode.getExitAct().timer, {
  211. skipUndoRedo: true
  212. });
  213. },
  214. editor: {
  215. sectionId: 'animation.propAniEntrance',
  216. position: 3,
  217. uiControl: {
  218. type: 'InputLabel',
  219. name: 'animationEntranceTime',
  220. label: this.stringResources.get('propAniEntranceTime'),
  221. ariaLabel: this.stringResources.get('propAniEntranceTime'),
  222. decimalPlaces: 15, // Maxed to avoid Glass interfering with our number processing (see Glass's BaseProperty:_onBlur())
  223. handleReturnKey: true,
  224. onChange: function onChange(propertyName, propertyValue) {
  225. var act = episode.getEntranceAct();
  226. var value = 1000 * parseFloat(propertyValue); // Seconds to milliseconds, ignoring any trailing non-digits
  227. value = _this3._validateTimerValue(value, episode, 'Entrance');
  228. if (value != null) {
  229. // Update model and refresh properties if a change occurs vis-à-vis the episode touching the beginning or end
  230. var oldTouch = episode.touchesStart() + episode.touchesEnd(timelineController.getDuration());
  231. _this3.content.setPropertyValue(propertyName, value, act);
  232. var newTouch = episode.touchesStart() + episode.touchesEnd(timelineController.getDuration());
  233. if (newTouch != oldTouch) {
  234. _this3.dashboardApi.triggerDashboardEvent('properties:refreshPane');
  235. }
  236. }
  237. // Update UI
  238. var uiValue = _this3._getValueString(act.timer);
  239. _this3.dashboardApi.triggerDashboardEvent('properties:setValue', { propertyName: propertyName, value: uiValue });
  240. }
  241. }
  242. }
  243. }, {
  244. id: 'animationExitTime',
  245. getPropertyValue: function getPropertyValue() {
  246. return _this3._getValueString(episode.getExitAct().timer);
  247. },
  248. setPropertyValue: function setPropertyValue(value, act) {
  249. void act;
  250. //TODO this should be in the episode... or the act itself
  251. timelineController.updateTimelineDuration(_this3.content.getId(), episode.getEntranceAct().timer, value, {
  252. skipUndoRedo: true
  253. });
  254. },
  255. editor: {
  256. sectionId: 'animation.propAniExit',
  257. position: 3,
  258. uiControl: {
  259. type: 'InputLabel',
  260. name: 'animationExitTime',
  261. label: this.stringResources.get('propAniExitTime'),
  262. ariaLabel: this.stringResources.get('propAniExitTime'),
  263. decimalPlaces: 15, // Maxed to avoid Glass interfering with our number processing (see Glass's BaseProperty:_onBlur())
  264. handleReturnKey: true,
  265. onChange: function onChange(propertyName, propertyValue) {
  266. var act = episode.getExitAct();
  267. var value = 1000 * parseFloat(propertyValue); // Seconds to milliseconds, ignoring any trailing non-digits
  268. value = _this3._validateTimerValue(value, episode, 'Exit');
  269. if (value != null) {
  270. // Update model and refresh properties if a change occurs vis-à-vis the episode touching the beginning or end
  271. var oldTouch = episode.touchesStart() + episode.touchesEnd(timelineController.getDuration());
  272. _this3.content.setPropertyValue(propertyName, value, act);
  273. var newTouch = episode.touchesStart() + episode.touchesEnd(timelineController.getDuration());
  274. if (newTouch != oldTouch) {
  275. _this3.dashboardApi.triggerDashboardEvent('properties:refreshPane');
  276. }
  277. }
  278. // Update UI
  279. var uiValue = _this3._getValueString(act.timer);
  280. _this3.dashboardApi.triggerDashboardEvent('properties:setValue', { propertyName: propertyName, value: uiValue });
  281. }
  282. }
  283. }
  284. }];
  285. };
  286. TimelinePropertiesProvider.prototype._getValueString = function _getValueString(value) {
  287. return (parseFloat(value) / 1000).toFixed(2);
  288. };
  289. TimelinePropertiesProvider.prototype._validateTimerValue = function _validateTimerValue(value, episode, type) {
  290. var tick = 50; // snap values to nearest tick
  291. // tick must match _tickLength value set in TimeQueue.js:init()
  292. // TODO: Refactor to better deal with shared constants like this
  293. var minDuration = 200; // exit - entrance > minDuration
  294. if (isNaN(value)) {
  295. return null;
  296. }
  297. // Round number to nearest acceptable value
  298. // - nearest tick
  299. // - episode lasts at least for minDuration
  300. // - non-negative
  301. var rounded = tick * Math.round(value / tick);
  302. if (type == 'Entrance' && rounded >= episode.getExitAct().timer - minDuration) {
  303. rounded = episode.getExitAct().timer - minDuration;
  304. }
  305. if (type == 'Exit' && rounded <= episode.getEntranceAct().timer + minDuration) {
  306. rounded = episode.getEntranceAct().timer + minDuration;
  307. }
  308. if (rounded < 0) {
  309. rounded = 0;
  310. }
  311. return rounded;
  312. };
  313. TimelinePropertiesProvider.prototype._updateActModel = function _updateActModel(act, update) {
  314. act.set(update, {
  315. payloadData: {
  316. undoRedoTransactionId: _.uniqueId('_animationProp_'),
  317. // TODO: fix this. the property pane should always be in sync with the model.
  318. // at this point if we refresh it causes ugly flicker so I'm leaving this here.
  319. //
  320. // disable undo/redo for now since the property pane gets out of sync
  321. // with the model.
  322. skipUndoRedo: true
  323. }
  324. });
  325. };
  326. return TimelinePropertiesProvider;
  327. }();
  328. return TimelinePropertiesProvider;
  329. });
  330. //# sourceMappingURL=TimelinePropertiesProvider.js.map