PropertiesManager.js 47 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380
  1. 'use strict';
  2. var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
  3. /*
  4. *+------------------------------------------------------------------------+
  5. *| Licensed Materials - Property of IBM
  6. *| IBM Cognos Products: Dashboard
  7. *| (C) Copyright IBM Corp. 2017, 2020
  8. *|
  9. *| US Government Users Restricted Rights - Use, duplication or disclosure
  10. *| restricted by GSA ADP Schedule Contract with IBM Corp.
  11. *+------------------------------------------------------------------------+
  12. */
  13. define(['../../lib/@waca/core-client/js/core-client/ui/core/Class', './SlideoutHelper', 'jquery', 'underscore', '../widgets/PropertyListUtil', '../../app/nls/StringResources', '../../lib/@waca/dashboard-common/dist/ui/interaction/Utils', '../contentpane/PropertyUIControlView'], function (Class, SlideoutHelper, $, _, PropertyListUtil, StringResources, Utils, PropertyUIControlView) {
  14. var PropertiesManager = Class.extend([SlideoutHelper], {
  15. /**
  16. options.glassContext
  17. options.canvasController
  18. options.context - this is the context passed to our perspective controllers
  19. **/
  20. init: function init(options) {
  21. PropertiesManager.inherited('init', this, arguments);
  22. _.extend(this, options);
  23. this.dashboard = this.canvasController.dashboardApi;
  24. this._layoutController = this.canvasController.layoutController;
  25. this._eventRouter = this.canvasController.eventRouter;
  26. this.canvas = this.dashboard.getFeature('Canvas');
  27. this.canvas.on('change:content:property', this.onContentPropertyChange, this);
  28. this.canvas.on('change:property', this.onDashboardPropertyChange, this);
  29. this.slideoutFeature = this.dashboard.getFeature('InAppSlideoutState');
  30. this.slideoutDOMFeature = this.dashboard.getFeature('InAppSlideoutDOM');
  31. this._eventRouter.on('properties:refreshProperty', this.refreshProperty, this);
  32. this._eventRouter.on('properties:updateVisiblilty', this.updateVisiblilty, this);
  33. this._eventRouter.on('properties:updateEnabled', this.updateEnabled, this);
  34. this._eventRouter.on('properties:setValue', this.setPropertyValue, this);
  35. this._eventRouter.on('selection:ready', this.onPropertiesSelectionReady, this);
  36. this._eventRouter.on('properties:refreshPane', this.refreshApplicationPropertiesPane, this);
  37. this._eventRouter.on('properties:refreshChild', this.refreshChildProperty, this);
  38. this._eventRouter.on('properties:setChildValue', this.setChildValue, this);
  39. this._lastEventId = '';
  40. this._expandedSections = {};
  41. this._defaultTabOrder = [StringResources.get('tabName_visualization'), StringResources.get('tabName_visDetails'), StringResources.get('tabName_textDetails'), StringResources.get('tabName_mediaDetails'), StringResources.get('tabName_webDetails'), StringResources.get('tabName_imageDetails'), StringResources.get('tabName_animation'), StringResources.get('tabName_general')];
  42. this.logger = options.glassContext.getCoreSvc('.Logger');
  43. //keep track of children
  44. this._children = [];
  45. },
  46. onContentPropertyChange: function onContentPropertyChange() {
  47. var _this = this;
  48. var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
  49. if (!options.info) {
  50. return;
  51. }
  52. var infoList = [options.info];
  53. // In case of event list
  54. var events = options.info.events;
  55. if (events) {
  56. var eventsMap = {};
  57. // get the events info list for unique content ids
  58. events.forEach(function (event) {
  59. if (event.info && event.info.contentId) {
  60. eventsMap[event.info.contentId] = event.info;
  61. }
  62. });
  63. infoList = Object.values(eventsMap);
  64. }
  65. infoList.forEach(function (info) {
  66. var contentId = info.contentId;
  67. var content = contentId && _this.canvas.getContent(contentId);
  68. // if the content is live widget, then we do not refreshPropertiesPane here,
  69. // because in live widget renderTask, it will refreshPropertiesPane as needed.
  70. // TODO when livewidget side gets rid of the legacy event `properties:refreshPane`
  71. // then we can remove this condition
  72. if (content && content.getType() !== 'widget.live') {
  73. var eventOptions = info.options || {};
  74. if (_this.getCurrentChild()) {
  75. // if child property pane is open, then refresh child property pane
  76. _this.refreshChildProperty(_extends({
  77. content: _this.canvas.getContent(contentId)
  78. }, eventOptions));
  79. } else {
  80. _this.refreshApplicationPropertiesPane(_extends({}, eventOptions));
  81. }
  82. }
  83. });
  84. },
  85. onDashboardPropertyChange: function onDashboardPropertyChange() {
  86. var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
  87. if (options.info && options.info.supportsUndoRedo) {
  88. var eventOptions = options.info.options || {};
  89. this.refreshApplicationPropertiesPane(_extends({}, eventOptions));
  90. }
  91. },
  92. //TODO: remove this function when the focus mode epic is ready
  93. show: function show(options) {
  94. var _this2 = this;
  95. var context = options && options.context;
  96. this._hideChild();
  97. var selectedNodes = this._layoutController.getSelectedNodes();
  98. var selectedLayouts = this._getSelectedLayouts(selectedNodes);
  99. this._selectedTab = '';
  100. this._expandedSections = {};
  101. this._handleButtonState(true);
  102. return this.getProperties(selectedLayouts).then(function (properties) {
  103. var label = properties && properties[0] && properties[0].type === 'Banner' ? properties[0].value : '';
  104. return _this2.createAndShowSlideout({
  105. 'enableTabLooping': true,
  106. 'width': '320px',
  107. 'position': 'right',
  108. 'pinning': {
  109. 'isPinned': true,
  110. 'float': false,
  111. 'display': false
  112. },
  113. 'content': {
  114. 'module': 'dashboard-core/js/dashboard/contentpane/PropertyUIControlView',
  115. 'glassContext': _this2.glassContext,
  116. 'renderCallback': _this2._renderCallback.bind(_this2),
  117. 'items': properties,
  118. 'onSetFocus': options ? options.onSetFocus : null
  119. },
  120. 'label': label
  121. }, context);
  122. });
  123. },
  124. /**
  125. * Get the properties ui view
  126. *
  127. * @param {string} contentId the id of a given content
  128. * @returns {Promise}
  129. */
  130. getPropertiesView: function getPropertiesView(contentId) {
  131. var _this3 = this;
  132. var content = this.dashboard.getCanvas().getContent(contentId);
  133. var propertyLayoutList = void 0;
  134. if (contentId) {
  135. propertyLayoutList = this.getPropertyLayoutList([content]);
  136. } else {
  137. // Getting the default canvas property as no contentId provided
  138. var layouts = this._getSelectedLayouts([]);
  139. propertyLayoutList = this.getProperties(layouts);
  140. }
  141. return propertyLayoutList.then(function (properties) {
  142. var propertyUIControlView = new PropertyUIControlView({
  143. node: document.createElement('div'),
  144. items: properties,
  145. glassContext: _this3.glassContext,
  146. renderCallback: _this3._renderCallback.bind(_this3)
  147. });
  148. _this3.contentView = propertyUIControlView;
  149. return propertyUIControlView.render();
  150. });
  151. },
  152. _renderCallback: function _renderCallback() {
  153. if (this._eventRouter) {
  154. this._eventRouter.trigger('properties:hasRendered', {});
  155. }
  156. },
  157. //TODO: remove this function when the focus mode epic is ready
  158. hide: function hide() {
  159. this._hideChild();
  160. this._handleButtonState(false);
  161. this._closeSlideout();
  162. this._clearSelectedNodeIds();
  163. },
  164. //TODO: remove this function when the focus mode epic is ready
  165. _handleButtonState: function _handleButtonState(pressed) {
  166. var propertyButton = this.glassContext.appController.findPlugin('com.ibm.bi.dashboard.propertyBtn');
  167. if (!propertyButton) {
  168. return;
  169. }
  170. if (pressed === true) {
  171. propertyButton.setPressed();
  172. } else if (pressed === false) {
  173. propertyButton.setUnpressed();
  174. }
  175. },
  176. getProperties: function getProperties(selected) {
  177. var canvas = this.dashboard.getCanvas();
  178. var isTopLevel = selected && selected.length && !selected[0].parentLayout;
  179. var contents = isTopLevel ? [canvas] : _.map(selected, function (layout) {
  180. return canvas.getContent(layout.id);
  181. });
  182. return this.getPropertyLayoutList(contents);
  183. },
  184. // START of USE NEW API
  185. /**
  186. * Get the combined layouts from the given contents
  187. * @param {ContentAPI[]} contents array of selected contents
  188. */
  189. getPropertyLayoutList: function getPropertyLayoutList(contents) {
  190. var _this4 = this;
  191. var promises = [];
  192. var groupCounter = 0;
  193. var bannerControl = void 0;
  194. _.each(contents, function (content) {
  195. var layouts = content && content.getPropertyLayoutList && content.getPropertyLayoutList();
  196. if (!_.isEmpty(layouts)) {
  197. // collect the first banner control
  198. if (!bannerControl) {
  199. var banner = _.find(layouts, function (layout) {
  200. return layout.type === 'Banner';
  201. });
  202. bannerControl = _this4._getCoreClientLayout(banner);
  203. }
  204. // collect all tabs
  205. var tabs = _.chain(layouts).filter(function (layout) {
  206. return layout.type === 'Group';
  207. }).sortBy(function (tab) {
  208. if (tab.position !== undefined) {
  209. return tab.position;
  210. }
  211. var index = _this4._defaultTabOrder.indexOf(tab.label);
  212. return index >= 0 ? index : 10;
  213. }).map(_this4._getCoreClientLayout.bind(_this4)).value();
  214. // asyncronously process all properties starting from the tabs
  215. if (content.getType && content.getType() === 'group') {
  216. // if the content is a group, put the promise at the end of the promise array
  217. groupCounter++;
  218. promises.push(PropertyListUtil.processProperties(tabs, content, _this4.dashboard).then(function () {
  219. return tabs;
  220. }));
  221. } else {
  222. // if the content is not a group, put the promise at the front of the promise array
  223. promises.unshift(PropertyListUtil.processProperties(tabs, content, _this4.dashboard).then(function () {
  224. return tabs;
  225. }));
  226. }
  227. }
  228. });
  229. return Promise.all(promises).then(function (tabItems) {
  230. // merge all non-group tab layouts
  231. while (tabItems.length > 1 + groupCounter) {
  232. tabItems[0] = _this4._mergePropertySpecs(tabItems[1], tabItems[0], true);
  233. tabItems.splice(1, 1);
  234. }
  235. var commonSharedTabItems = tabItems[0];
  236. var commonSharedGroupTabItems = void 0;
  237. if (groupCounter > 0) {
  238. tabItems.splice(0, 1);
  239. // merge all group tab layouts
  240. while (tabItems.length > 1) {
  241. tabItems[0] = _this4._mergePropertySpecs(tabItems[1], tabItems[0], true);
  242. tabItems.splice(1, 1);
  243. }
  244. commonSharedGroupTabItems = tabItems[0];
  245. }
  246. // merge all layouts
  247. if (commonSharedTabItems) {
  248. tabItems[0] = _this4._mergeGroupPropertySpecs(commonSharedTabItems, commonSharedGroupTabItems);
  249. }
  250. var uiControlList = [];
  251. if (tabItems.length < 1) {
  252. return uiControlList;
  253. }
  254. uiControlList.push(bannerControl);
  255. if (tabItems[0].length > 1) {
  256. var tabControl = {
  257. 'type': 'TabControl',
  258. 'name': 'tabControl',
  259. 'items': tabItems[0],
  260. 'onTabChange': function (propName, tab) {
  261. this._selectedTab = tab.name;
  262. }.bind(_this4)
  263. };
  264. uiControlList.push(tabControl);
  265. }
  266. // Hide the tab if there is only one tab
  267. if (tabItems[0].length === 1) {
  268. uiControlList.push.apply(uiControlList, tabItems[0][0].items);
  269. }
  270. return uiControlList;
  271. });
  272. },
  273. _getCoreClientLayout: function _getCoreClientLayout(layout, index) {
  274. var _this5 = this;
  275. var coreClientSpec = _.extend({}, layout);
  276. if (layout) {
  277. // expand the children
  278. if (layout.items && layout.items.length) {
  279. _.extend(coreClientSpec, {
  280. items: _.chain(layout.items).map(function (item, idx) {
  281. return _this5._getCoreClientLayout(item, idx);
  282. }).flatten().value()
  283. });
  284. }
  285. // process the current layout
  286. switch (coreClientSpec.type) {
  287. case 'Group':
  288. return this._processCoreClientTabControl(coreClientSpec);
  289. case 'Section':
  290. return this._processCoreClientSectionControl(coreClientSpec, index);
  291. case 'DropDown':
  292. return this._processCoreClientDropDownControl(coreClientSpec);
  293. }
  294. }
  295. return coreClientSpec;
  296. },
  297. _processCoreClientTabControl: function _processCoreClientTabControl(layout) {
  298. return _.extend(layout, {
  299. // tab uses the name as label
  300. name: layout.label,
  301. selected: this._selectedTab === layout.label,
  302. module: 'dashboard-core/js/dashboard/contentpane/PropertyUIControlView'
  303. });
  304. },
  305. _getSectionExpandState: function _getSectionExpandState(section, index) {
  306. if (this._expandedSections[section.id] === undefined) {
  307. var state = section.open;
  308. if (state === undefined) {
  309. // keep the first section open (default) unless if the state is defined or changed
  310. state = index === 0;
  311. }
  312. // keep track of the state
  313. this._expandedSections[section.id] = state;
  314. }
  315. return this._expandedSections[section.id];
  316. },
  317. _processCoreClientSectionControl: function _processCoreClientSectionControl(layout, index) {
  318. var section = _.extend(layout, {
  319. name: layout.id,
  320. styleAsSimpleRow: true,
  321. // rename the type to CollapsibleSection
  322. type: layout.collapsible === false ? 'SectionLabel' : 'CollapsibleSection',
  323. // manager the section expand state
  324. open: this._getSectionExpandState(layout, index),
  325. onOpenChange: function (name, isOpen) {
  326. this._expandedSections[name] = isOpen;
  327. }.bind(this)
  328. });
  329. var controls = index > 0 && !layout.noSeparator ? [{ 'type': 'Separator' }, section] : [section];
  330. if (section.type === 'SectionLabel') {
  331. // Since the section label is not expandable
  332. // move the section controls adjacent to the section label
  333. controls.push.apply(controls, section.items);
  334. delete section.items;
  335. }
  336. return controls;
  337. },
  338. _processCoreClientDropDownControl: function _processCoreClientDropDownControl(layout) {
  339. // give the control a unique name
  340. layout.name = layout.id;
  341. // handle delayed async dropdown options
  342. if (!layout.options && layout.getOptions) {
  343. layout.options = layout.getOptions();
  344. }
  345. return layout;
  346. },
  347. // END of USE NEW API
  348. //TODO: remove this function when the focus mode epic is ready
  349. _hideChild: function _hideChild() {
  350. var child = this.getCurrentChild();
  351. if (child) {
  352. child.hide({
  353. force: true
  354. });
  355. }
  356. },
  357. closeChild: function closeChild() {
  358. var onCloseCb = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;
  359. var child = this.getCurrentChild();
  360. if (child) {
  361. // when explore side calls closeChild,it pass in an callback function
  362. // but when the properties ui control call it, it pass in an
  363. // object which includes changes properties. so it is very confusing and the api should be consistent
  364. // TODO explore side and here should be refactored and not inject a custom callback
  365. if (onCloseCb && typeof onCloseCb === 'function') {
  366. onCloseCb();
  367. } else {
  368. if (child.node && child.node.parentNode && child.node.parentNode.contains(child.node)) {
  369. child.node.nextElementSibling.style.display = 'block';
  370. child.node.parentNode.removeChild(child.node);
  371. } else if (child.$el && child.parentNode && child.parentNode.contains(child.$el[0])) {
  372. // Required for changePallete child slideout
  373. // Reason: changePallette renders the child differently
  374. child.$el.next().show();
  375. child.parentNode.removeChild(child.$el[0]);
  376. }
  377. }
  378. this._children.pop();
  379. if (child.remove) {
  380. child.remove();
  381. }
  382. }
  383. },
  384. closeAllChild: function closeAllChild() {
  385. var numChildren = this._children.length;
  386. while (numChildren > 0) {
  387. this.closeChild();
  388. --numChildren;
  389. }
  390. },
  391. getChildPropertiesView: function getChildPropertiesView(options) {
  392. var _this6 = this;
  393. options.glassContext = this.glassContext;
  394. // pass the provider closeChild callback to the closeChild function of PropertiesManager
  395. // For R7, with the new CF, only changePaletteView and ConditionalFormattingUI need a closeChild callback for Explore
  396. options.onCloseCb = this.closeChild.bind(this, options.onCloseCb);
  397. var module = options.module.split('/').pop();
  398. var promise = new Promise(function (resolve, reject) {
  399. switch (module) {
  400. case 'PropertyUIControlView':
  401. resolve(_this6._createChildPropertyUIControlView(options.items));
  402. break;
  403. case 'changePaletteView':
  404. // authoring-common is only available in run time env, ensuring that it's loaded only when needed
  405. require(['authoring-common'], function (AuthoringCommon) {
  406. resolve(new AuthoringCommon.ChangePaletteView(options));
  407. }, function (error) {
  408. reject(error);
  409. });
  410. break;
  411. case 'ConditionalFormatting':
  412. require([options.module], function (CondFormattingUI) {
  413. resolve(new CondFormattingUI.CurrentConditionalPalette(options));
  414. }, function (error) {
  415. reject(error);
  416. });
  417. break;
  418. default:
  419. resolve();
  420. break;
  421. }
  422. });
  423. return promise.then(function (uiControlView) {
  424. if (!uiControlView) {
  425. return Promise.resolve();
  426. }
  427. // The options is safe for that it can be retrieved at a later time when
  428. // needed to refresh to re-render the child panel
  429. uiControlView.options = options;
  430. // Put the new child panel on top of stack of the children panel list
  431. _this6._children.push(uiControlView);
  432. return uiControlView.render();
  433. });
  434. },
  435. /**
  436. * @return {Slideout} Returns the current child slideout view or null if none.
  437. */
  438. getCurrentChild: function getCurrentChild() {
  439. return this._children.length > 0 ? this._children[this._children.length - 1] : null;
  440. },
  441. /**
  442. * Adds and shows a child slideout
  443. * It waits for 600ms till the slideout is open before adding it; otherwise showing the child may occur before the parent is actually
  444. * shown. In this case the child is not displayed
  445. * @public
  446. * @param {object} [options] - same options as the constructor except for position, glassContext which are retrieved from the current slideout and extra properties
  447. * @param {Boolean} [options.overlay=false] - the child is shown on the top of the parent if true
  448. * @param {Number} [options.width] - Width of the child slideout - if slideout is an overlay and is smaller, will be overriden with the width of the parent
  449. * @param {launchPoint} [options.launchPoint] - Optional, The UI dom element that launched the slideout. The last active element if not specified.
  450. * @param {String} [options.label] - The aria-label for the slideout. If no label is provided a default label is used.
  451. * @return {Slideout} Child slideout; It may be returned before the slideout is actually shown
  452. */
  453. addChild: function addChild() {
  454. var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
  455. this.childPropertyDisplayed = true;
  456. options.content = options.content || {};
  457. options.content.isChild = true;
  458. // The unique child panel identifier that is use to refresh to re-render the child
  459. options.content.childPanelId = _.uniqueId('childPanelId_');
  460. // individual page id
  461. if (options.pageChildId) {
  462. this.pageChildId = options.pageChildId;
  463. }
  464. this.slideoutDOMFeature.render(options.content);
  465. return true;
  466. },
  467. /**
  468. Remove any property that's tagged with public: false from the array of properties
  469. @param [array] properties - the array of properties to loop through to remove any non public properties
  470. **/
  471. _removeNonPublicProperties: function _removeNonPublicProperties(properties) {
  472. for (var i = 0; i < properties.length; i++) {
  473. var property = properties[i];
  474. if (property.public === false) {
  475. properties.splice(i, 1);
  476. i--;
  477. } else if (properties.items) {
  478. this._removeNonPublicProperties(properties.items);
  479. }
  480. }
  481. },
  482. /**
  483. Groups all the properties in their defined tabs.
  484. @param [array] properties - the array of properties to loop through and group into tabs
  485. **/
  486. _groupIntoTabs: function _groupIntoTabs(properties) {
  487. var _this7 = this;
  488. if (!properties) {
  489. return;
  490. }
  491. var tabsMap = {};
  492. var tabControlProperty = null;
  493. this._sectionMap = {};
  494. for (var i = 0; i < properties.length; i++) {
  495. var property = properties[i];
  496. if (property.tabName) {
  497. if (tabsMap[property.tabName]) {
  498. if (property.tabPosition !== undefined) {
  499. tabsMap[property.tabName].tabPosition = property.tabPosition;
  500. }
  501. } else {
  502. if (!tabControlProperty) {
  503. tabControlProperty = {
  504. 'type': 'TabControl',
  505. 'name': 'tabControl',
  506. 'onTabChange': function (propName, tab) {
  507. this._selectedTab = tab.name;
  508. }.bind(this),
  509. 'items': []
  510. };
  511. properties.splice(i, 0, tabControlProperty);
  512. i++;
  513. }
  514. var newTab = this._genTabUIControlSpec(property);
  515. tabControlProperty.items.push(newTab);
  516. tabsMap[property.tabName] = newTab;
  517. this._sectionMap[property.tabName] = {};
  518. }
  519. this._insertPropIntoTab(property, tabsMap[property.tabName]);
  520. properties.splice(i, 1);
  521. i--;
  522. }
  523. }
  524. if (tabControlProperty) {
  525. var selectedTab = $.grep(tabControlProperty.items, function (tab) {
  526. return tab.selected === true;
  527. });
  528. if (selectedTab.length === 0) {
  529. this._selectedTab = '';
  530. }
  531. // Sort the tabs
  532. tabControlProperty.items = _.sortBy(tabControlProperty.items, function (tab) {
  533. if (tab.tabPosition !== undefined) {
  534. return tab.tabPosition;
  535. }
  536. var index = _this7._defaultTabOrder.indexOf(tab.name);
  537. return index >= 0 ? index : 10;
  538. });
  539. //Sort the collapsible sections, and open the first one if only collapsible sections are present.
  540. _.each(tabControlProperty.items, function (tab) {
  541. if (tab.items) {
  542. tab.items = _.sortBy(tab.items, 'sectionPosition');
  543. var openFirst = true;
  544. for (var _i = 0; _i < tab.items.length; _i++) {
  545. if (tab.items[_i].type !== 'CollapsibleSection' || tab.items[_i].open || tab.items[_i].expansionRuleExists) {
  546. openFirst = false;
  547. break;
  548. }
  549. }
  550. _this7._addSeparatorBetweenSections(tab.items);
  551. if (openFirst) {
  552. tab.items[0].open = true;
  553. }
  554. }
  555. });
  556. }
  557. this._sectionMap = null;
  558. },
  559. _addSeparatorBetweenSections: function _addSeparatorBetweenSections(items) {
  560. if (!items) {
  561. return;
  562. }
  563. for (var i = 0; i < items.length; i++) {
  564. var property = items[i];
  565. if (property.type === 'CollapsibleSection' && i < items.length - 1) {
  566. items.splice(i + 1, 0, {
  567. 'type': 'Separator'
  568. });
  569. }
  570. }
  571. },
  572. /**
  573. Inserts a given property into the tab items array. Will add the property in the correct location based on the displayPos of the property
  574. @param {object} property - the property object to insert into the array of properties for the tab
  575. @param {object} tab - the tab object in which to add the property
  576. **/
  577. _insertPropIntoTab: function _insertPropIntoTab(property, tab) {
  578. var container = tab;
  579. if (property.sectionName) {
  580. var tabName = property.tabName;
  581. if (!this._sectionMap[tabName][property.sectionName]) {
  582. var newSection = this._genSectionUIControlSpec(property);
  583. this._insertPropIntoItemContainer(newSection, tab);
  584. this._sectionMap[tabName][property.sectionName] = newSection;
  585. container = newSection;
  586. } else {
  587. container = this._sectionMap[tabName][property.sectionName];
  588. }
  589. if (property.sectionPosition !== undefined) {
  590. container.sectionPosition = property.sectionPosition;
  591. }
  592. // if we already have an expansion rule we keep it.
  593. if (property.sectionOpened !== undefined && !container.expansionRuleExists) {
  594. container.open = property.sectionOpened;
  595. container.expansionRuleExists = true;
  596. }
  597. }
  598. this._insertPropIntoItemContainer(property, container);
  599. },
  600. /**
  601. Inserts a given property into the container items array. Will add the property in the correct location based on the displayPos of the property
  602. @param {object} property - the property object to insert into the array of properties for the container
  603. @param {object} container - the container object in which to add the property
  604. **/
  605. _insertPropIntoItemContainer: function _insertPropIntoItemContainer(property, container) {
  606. var inserted = false;
  607. for (var i = 0; i < container.items.length; i++) {
  608. // If the current property doesn't have a displayPos and we've hit a property in the tab that has a display position then insert the new property in before.
  609. // Or if the current items display position is bigger then the new items display position
  610. if (!property.displayPos && container.items[i].displayPos || (container.items[i].displayPos || -1) > (property.displayPos || -1)) {
  611. container.items.splice(i, 0, property);
  612. inserted = true;
  613. break;
  614. }
  615. }
  616. if (!inserted) {
  617. container.items.push(property);
  618. }
  619. },
  620. /**
  621. Creates the tabControl object
  622. @param {object} property - a property for which the tabName is defined
  623. **/
  624. _genTabUIControlSpec: function _genTabUIControlSpec(property) {
  625. var tabModule = property.tabModule ? property.tabModule : 'dashboard-core/js/dashboard/contentpane/PropertyUIControlView';
  626. var tabSpec = {
  627. 'name': property.tabName,
  628. 'module': tabModule,
  629. 'items': []
  630. };
  631. if (property.tabName === this._selectedTab) {
  632. tabSpec.selected = true;
  633. }
  634. if (property.tabPosition !== undefined) {
  635. tabSpec.tabPosition = property.tabPosition;
  636. }
  637. return tabSpec;
  638. },
  639. /**
  640. Creates the CollapsibleSection object
  641. @param {object} property - a property for which the sectionName is defined
  642. **/
  643. _genSectionUIControlSpec: function _genSectionUIControlSpec(property) {
  644. var _this8 = this;
  645. var sectionName = property.tabName + '|' + property.sectionName;
  646. var sectionSpec = {
  647. label: property.sectionName,
  648. name: sectionName,
  649. type: 'CollapsibleSection',
  650. items: [],
  651. styleAsSimpleRow: true,
  652. onOpenChange: function onOpenChange(name, isOpen) {
  653. _this8._expandedSections[name] = isOpen;
  654. }
  655. };
  656. if (this._expandedSections[sectionName] != undefined) {
  657. sectionSpec.open = this._expandedSections[sectionName];
  658. sectionSpec.expansionRuleExists = true;
  659. }
  660. return sectionSpec;
  661. },
  662. _mergeGroupPropertySpecs: function _mergeGroupPropertySpecs(commonSharedTabItems, commonSharedGroupTabItems) {
  663. var _this9 = this;
  664. if (!commonSharedGroupTabItems) {
  665. return commonSharedTabItems;
  666. }
  667. var result = [];
  668. commonSharedTabItems.forEach(function (commonSharedTabItem) {
  669. if (!commonSharedTabItem.name) {
  670. result.push(commonSharedTabItem);
  671. } else {
  672. // if item exists in both group and children, group property will be pushed to the result
  673. var matchedItem = null;
  674. for (var i = 0; i < commonSharedGroupTabItems.length; i++) {
  675. if (commonSharedGroupTabItems[i].name === commonSharedTabItem.name) {
  676. matchedItem = commonSharedGroupTabItems[i];
  677. break;
  678. }
  679. }
  680. if (matchedItem) {
  681. if (matchedItem.items && commonSharedTabItem.items) {
  682. matchedItem.items = _this9._mergeGroupPropertySpecs(commonSharedTabItem.items, matchedItem.items);
  683. }
  684. result.push(matchedItem);
  685. } else {
  686. // if item only exists in children, push the property to the result
  687. result.push(commonSharedTabItem);
  688. }
  689. }
  690. });
  691. return result;
  692. },
  693. /**
  694. Merges two uiPropertyControl specifications together
  695. @param spec1 - a propertyUIControl specification object
  696. @param spec2 - a propertyUIControl specification object
  697. @param bOnlyKeepCommonProperties {boolean} - wether we should only be keeping properties found in both specs
  698. **/
  699. _mergePropertySpecs: function _mergePropertySpecs(spec1, spec2, bOnlyKeepCommonProperties) {
  700. if (!spec1) {
  701. return spec2;
  702. } else if (!spec2) {
  703. return spec1;
  704. }
  705. var result = bOnlyKeepCommonProperties ? [] : spec1;
  706. spec2.forEach(function (spec2Item) {
  707. // If the property doesn't have a name then simply append it
  708. if (!spec2Item.name) {
  709. result.push(spec2Item);
  710. } else {
  711. var matchedItem = null;
  712. for (var i = 0; i < spec1.length; i++) {
  713. if (spec1[i].name === spec2Item.name) {
  714. matchedItem = spec1[i];
  715. break;
  716. }
  717. }
  718. if (matchedItem) {
  719. if (matchedItem.items && spec2Item.items) {
  720. // Recursively merge the child item arrays
  721. matchedItem.items = this._mergePropertySpecs(matchedItem.items, spec2Item.items, bOnlyKeepCommonProperties);
  722. }
  723. // Since we're merging the properties, keep track of the two onChange callbacks
  724. this._mergeCallback('onChange', matchedItem, spec2Item);
  725. // Palatte propertties have two 'change' callbacks, make sure the onChangePalette callback is also merged
  726. this._mergeCallback('onChangePalette', matchedItem, spec2Item);
  727. if (bOnlyKeepCommonProperties) {
  728. result.push(matchedItem);
  729. }
  730. } else if (!bOnlyKeepCommonProperties) {
  731. result.push(spec2Item);
  732. }
  733. }
  734. }.bind(this));
  735. return result;
  736. },
  737. /**
  738. * Given two property specs, create one callback function that will call the callbacks for both properties.
  739. */
  740. _mergeCallback: function _mergeCallback(callbackPropertyName, propertySpec1, propertySpec2) {
  741. if (propertySpec1[callbackPropertyName] || propertySpec2[callbackPropertyName]) {
  742. var originalOnChange = propertySpec1[callbackPropertyName];
  743. // Since we're merging the properties, keep track of the two onChange callbacks
  744. propertySpec1[callbackPropertyName] = function (propertyName, propertyValueInfo) {
  745. if (originalOnChange) {
  746. originalOnChange.call(propertySpec1, propertyName, propertyValueInfo);
  747. }
  748. if (propertySpec2[callbackPropertyName]) {
  749. propertySpec2[callbackPropertyName].call(propertySpec2, propertyName, propertyValueInfo);
  750. }
  751. };
  752. }
  753. },
  754. /**
  755. Shows or hides a property
  756. @param {object} options
  757. @param {string} options.propertyName - the name of the property to update
  758. @param {boolean} options.visible - if the property should be visible or not
  759. **/
  760. updateVisiblilty: function updateVisiblilty(options) {
  761. if (!options) {
  762. return false;
  763. }
  764. var propertyControl = this.getPropertyControl(options.propertyName);
  765. if (!propertyControl) {
  766. return false;
  767. }
  768. if (options.visible === true) {
  769. propertyControl.show();
  770. } else {
  771. propertyControl.hide();
  772. }
  773. return true;
  774. },
  775. /**
  776. Enables or disables a property
  777. @param {object} options
  778. @param {string} options.propertyName - the name of the property to update
  779. @param {boolean} options.enabled - if the property should be visible or not
  780. **/
  781. updateEnabled: function updateEnabled(options) {
  782. if (!options) {
  783. return false;
  784. }
  785. var propertyControl = this.getPropertyControl(options.propertyName);
  786. if (!propertyControl) {
  787. return false;
  788. }
  789. if (options.enabled === true) {
  790. propertyControl.readOnly = false;
  791. propertyControl.enable();
  792. } else {
  793. propertyControl.disable();
  794. }
  795. return true;
  796. },
  797. /**
  798. Re-renders a given property with an updated spec
  799. @param {object} - options
  800. @param {object} - options.propertySpec
  801. **/
  802. refreshProperty: function refreshProperty(options) {
  803. if (!options || !options.propertySpec) {
  804. return false;
  805. }
  806. var propertyControl = this.getPropertyControl(options.propertySpec.name);
  807. if (!propertyControl) {
  808. return false;
  809. }
  810. propertyControl.$el.empty();
  811. if (options.removeProperty !== true) {
  812. _.extend(propertyControl, options.propertySpec);
  813. propertyControl.doRender();
  814. }
  815. return true;
  816. },
  817. /**
  818. *
  819. * Set the value of a child property, only works if the propertyControl has setValue method
  820. * @param {object} options
  821. * @param {string} options.propertyName - the name of the property to update
  822. * @param {boolean||string||number} options.value - value to set
  823. * @param {string} options.contentId - the id of the child page
  824. * @returns
  825. */
  826. //TODO: remove this function when the focus mode epic is ready
  827. setChildPropertyValue: function setChildPropertyValue(options) {
  828. if (!this.isSlideoutOpen()) {
  829. return;
  830. }
  831. var child = this.getCurrentChild();
  832. // only set the value if the child page properties panel exists
  833. if (child && child.pageChildId === options.contentId && options.value) {
  834. var propertyControl = this.getPropertyControl(options.propertyName, child);
  835. propertyControl && propertyControl.setValue && propertyControl.setValue(options.value);
  836. }
  837. },
  838. setChildValue: function setChildValue(options) {
  839. if (!this._isPropertiesPaneOpen()) {
  840. return;
  841. }
  842. var child = this.getCurrentChild();
  843. // only set the value if the child page properties panel exists
  844. if (child && this.pageChildId === options.contentId && options.value) {
  845. var propertyControl = this.getPropertyControl(options.propertyName, child);
  846. propertyControl && propertyControl.setValue && propertyControl.setValue(options.value);
  847. }
  848. },
  849. refreshChildProperty: function refreshChildProperty(options) {
  850. var _this10 = this;
  851. return Promise.resolve().then(function () {
  852. if (!_this10._isPropertiesPaneOpen()) {
  853. return;
  854. }
  855. var child = _this10.getCurrentChild();
  856. var content = options && options.content;
  857. if (content && child && _this10.pageChildId === content.getId()) {
  858. // refresh the child property
  859. _this10.slideoutDOMFeature.render({ content: content, refreshChild: true, isChild: true });
  860. }
  861. });
  862. },
  863. /**
  864. * Call by the PropertiesPaneDOM instance to refresh the child panel and add to the Properties Panel reside with InAppSlideout
  865. * @param {object} options - the options use to refresh and render the child panel
  866. * @return {promise} Returns a resolved promise after the child is refreshed and get rendered
  867. */
  868. updateChildPropertiesView: function updateChildPropertiesView() {
  869. var _this11 = this;
  870. var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
  871. var promise = options.refreshChild && options.content ? this.getPropertyLayoutList([options.content]) : Promise.resolve();
  872. return promise.then(function (properties) {
  873. if (properties) {
  874. options.items = properties;
  875. }
  876. // Remove the current (or old) child property from the children list
  877. // when childPanelId matched
  878. var child = _this11.getCurrentChild();
  879. if (child && child.options && child.options.childPanelId === options.childPanelId) {
  880. if (child instanceof PropertyUIControlView) {
  881. if (child.getPropertyUIControl()) {
  882. child.getPropertyUIControl().remove();
  883. }
  884. _this11._children.pop();
  885. options.module = options.module || 'dashboard-core/js/dashboard/contentpane/PropertyUIControlView';
  886. } else {
  887. options.onCloseCb();
  888. }
  889. }
  890. options.onCloseCb = options.originalOnCloseCb;
  891. return _this11.getChildPropertiesView(options);
  892. });
  893. },
  894. _createChildPropertyUIControlView: function _createChildPropertyUIControlView(properties) {
  895. return new PropertyUIControlView({
  896. node: document.createElement('div'),
  897. items: properties,
  898. glassContext: this.glassContext,
  899. onCloseCb: this.closeChild,
  900. closeCallback: this.closeChild.bind(this),
  901. renderCallback: this._renderCallback.bind(this)
  902. });
  903. },
  904. //TODO: remove this function when the focus mode epic is ready
  905. refreshChild: function refreshChild(options) {
  906. var _this12 = this;
  907. // If there are multiple events triggering at the same time, we want the setContent to run before the next refreshChild kick in
  908. return Promise.resolve().then(function () {
  909. if (!_this12.isSlideoutOpen()) {
  910. return;
  911. }
  912. var content = options && options.content;
  913. var child = _this12.getCurrentChild();
  914. if (content && child && child.pageChildId === content.getId()) {
  915. return _this12.getPropertyLayoutList([content]).then(function (properties) {
  916. var uiContent = {
  917. module: 'dashboard/contentpane/PropertyUIControlView',
  918. items: properties
  919. };
  920. uiContent.onCloseCb = _this12._hideChild.bind(_this12);
  921. uiContent.closeCallback = _this12._hideChild.bind(_this12);
  922. // Need to check the contentView to avoid rendering multiple times
  923. if (child.contentView) {
  924. return child.setContent(uiContent).then(function () {
  925. if (options.focusSelector) {
  926. child.$el.find(options.focusSelector).focus();
  927. }
  928. });
  929. }
  930. return false;
  931. });
  932. }
  933. });
  934. },
  935. /**
  936. Sets the value of a property
  937. @param {object} options
  938. @param {string||string[]} options.propertyName - the name of the property to update, or an array containing container and property names to get a contained property
  939. @param {boolean||string||number} options.value - value to set
  940. **/
  941. setPropertyValue: function setPropertyValue(options) {
  942. if (!options || options.value === undefined) {
  943. return false;
  944. }
  945. var propertyControl = this.getPropertyControl(options.propertyName);
  946. if (!propertyControl || !propertyControl.setValue) {
  947. return false;
  948. }
  949. propertyControl.propertiesManagerChange = true;
  950. if (options.subPropertyName) {
  951. propertyControl.setValue(options.subPropertyName, options.value);
  952. } else {
  953. propertyControl.setValue(options.value);
  954. }
  955. propertyControl._lastChangedValue = 'undefined'; // Bug in glass, setValue doesn't reset _lastChangedValue.
  956. propertyControl.propertiesManagerChange = false;
  957. return true;
  958. },
  959. getPropertyControl: function getPropertyControl(propertyName, slideout) {
  960. if (!this._isPropertiesPaneOpen()) {
  961. return null;
  962. }
  963. if (!slideout) {
  964. slideout = this._slideout;
  965. }
  966. var contentView = slideout || this.contentView;
  967. var propertyUIControl = contentView.getPropertyUIControl();
  968. return this._getPropertyControlFromUIControl(propertyName, propertyUIControl);
  969. },
  970. _getPropertyControlFromUIControl: function _getPropertyControlFromUIControl(propertyName, propertyUIControl) {
  971. if (!propertyUIControl) {
  972. return null;
  973. }
  974. var name = propertyName,
  975. childNames;
  976. if (typeof propertyName !== 'string' && propertyName.length) {
  977. childNames = propertyName.slice();
  978. name = childNames.shift();
  979. }
  980. var property = propertyUIControl.getProperty(name);
  981. if (!property && propertyUIControl.propertyUIControlLeft) {
  982. property = propertyUIControl.propertyUIControlLeft.getProperty(name);
  983. if (!property && propertyUIControl.propertyUIControlRight) {
  984. property = propertyUIControl.propertyUIControlRight.getProperty(name);
  985. }
  986. }
  987. if (!property) {
  988. return null;
  989. }
  990. if (childNames && childNames.length) {
  991. return this._getPropertyControlFromUIControl(childNames, property);
  992. } else {
  993. return property;
  994. }
  995. },
  996. _isPropertiesPaneOpen: function _isPropertiesPaneOpen() {
  997. if (!this.slideoutFeature.isOpen()) {
  998. return false;
  999. }
  1000. var currentContribution = this.slideoutFeature.getCurrent();
  1001. if (!currentContribution || currentContribution.id !== 'PropertiesPane') {
  1002. return false;
  1003. }
  1004. return true;
  1005. },
  1006. /**
  1007. * Refreshes the UI to update with the properties option for newly selected element
  1008. * @param {String} options.sender - The id of the newly selected element
  1009. * @param {String} options.selectedTab - String containing the the tab to be selected in the properties pane
  1010. */
  1011. refreshApplicationPropertiesPane: function refreshApplicationPropertiesPane() {
  1012. var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
  1013. if (!this._isPropertiesPaneOpen()) {
  1014. return;
  1015. }
  1016. var selectedNodes = this._layoutController.getSelectedNodes();
  1017. var selectedLayouts = selectedNodes && this._getSelectedLayouts(selectedNodes);
  1018. if (selectedLayouts) {
  1019. if (options.selectedTab) {
  1020. this._selectedTab = options.selectedTab;
  1021. }
  1022. var contributionID = this.slideoutFeature.getCurrent().id;
  1023. var propertiesPaneContainerNode = this.slideoutDOMFeature.getView(contributionID).instance.getRenderNode();
  1024. options.currentScrollTop = propertiesPaneContainerNode.scrollTop;
  1025. this.updatePropertiesPanel(selectedLayouts, options);
  1026. }
  1027. },
  1028. //TODO: remove this function when the focus mode epic is ready
  1029. refreshPropertiesPane: function refreshPropertiesPane(options) {
  1030. if (!this.isSlideoutOpen()) {
  1031. return;
  1032. }
  1033. this._dashboardPropertiesPane = this._slideout.el.querySelector('.pane-content');
  1034. if (options && options.selectedTab) {
  1035. this._selectedTab = options.selectedTab;
  1036. }
  1037. var selectedNodes = this._layoutController.getSelectedNodes();
  1038. if (options) {
  1039. options.currentScrollTop = this._dashboardPropertiesPane.scrollTop;
  1040. } else {
  1041. options = {
  1042. currentScrollTop: this._dashboardPropertiesPane.scrollTop
  1043. };
  1044. }
  1045. var selectedLayouts = this._getSelectedLayouts(selectedNodes);
  1046. this._updatePropertiesPane(selectedLayouts, options);
  1047. },
  1048. /**
  1049. * Renders the Properties UI when a new selection on the canvas is made
  1050. * @param {Object} options.event - The selection event
  1051. * @param {Array} options.selectedNodes - An array containing the dom elements of the selected nodes
  1052. */
  1053. onPropertiesSelectionReady: function onPropertiesSelectionReady(options) {
  1054. if (!this._isPropertiesPaneOpen()) {
  1055. return;
  1056. }
  1057. var selectedNodeIds = options.selectedNodes.map(function (item) {
  1058. return item.id;
  1059. }).sort().join();
  1060. if (selectedNodeIds !== this._lastSelectedNodeIds) {
  1061. if (options.selectedNodes && options.selectedNodes.length === 1) {
  1062. this._selectedTab = '';
  1063. this._expandedSections = {};
  1064. }
  1065. var layouts = this._getSelectedLayouts(options.selectedNodes);
  1066. // Close all current open child panels when switch between vis - vis or vis - canvas selections
  1067. this.closeAllChild();
  1068. this.updatePropertiesPanel(layouts, options);
  1069. this._lastSelectedNodeIds = selectedNodeIds;
  1070. }
  1071. },
  1072. /**
  1073. options.events
  1074. options.selectedNodes
  1075. **/
  1076. //TODO: remove this function when the focus mode epic is ready
  1077. onSelectionReady: function onSelectionReady(options) {
  1078. if (!this.isSlideoutOpen()) {
  1079. return;
  1080. }
  1081. var selectedNodeIds = options.selectedNodes.map(function (item) {
  1082. return item.id;
  1083. }).sort().join();
  1084. if (selectedNodeIds !== this._lastSelectedNodeIds) {
  1085. if (options.selectedNodes && options.selectedNodes.length === 1) {
  1086. this._selectedTab = '';
  1087. this._expandedSections = {};
  1088. }
  1089. var layouts = this._getSelectedLayouts(options.selectedNodes);
  1090. this._hideChild();
  1091. this._updatePropertiesPane(layouts);
  1092. this._lastSelectedNodeIds = selectedNodeIds;
  1093. }
  1094. },
  1095. updatePropertiesPanel: function updatePropertiesPanel(layouts) {
  1096. var _this13 = this;
  1097. var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
  1098. var uniqueId = _.uniqueId('eventQueue_');
  1099. this._lastEventId = uniqueId;
  1100. setTimeout(function () {
  1101. //The promises seem to have the option of executing synchronously in some cases, in which case this could invalidate events which are in the process of firing. Delay execution of this code to allow all event handlers to fire before re-rendering. This allows the existing pane time to update.
  1102. if (!_this13._isPropertiesPaneOpen()) {
  1103. return;
  1104. }
  1105. _this13.getProperties(layouts).then(function (properties) {
  1106. if (uniqueId === _this13._lastEventId) {
  1107. _this13.contentView.setPropertySpec(properties);
  1108. _this13.contentView.render(true).then(function (propertyUIControlView) {
  1109. if (options.currentScrollTop) {
  1110. propertyUIControlView.el.parentNode.scrollTop = options.currentScrollTop;
  1111. }
  1112. if (options.focusSelector) {
  1113. propertyUIControlView.$el.find(options.focusSelector).focus();
  1114. }
  1115. _this13._updateChildPropertiesSelection();
  1116. });
  1117. }
  1118. });
  1119. }, 0);
  1120. },
  1121. /**
  1122. * Call by the PropertiesPaneDOM instance to get the most recent child panel options to be use to render the child
  1123. * The most recent child is the one that was last pushed onto the _children panel list of this class
  1124. * @param {object} options - the options use to retrieve the most recent child options
  1125. * @return {object} the options to be use to render the child panel
  1126. */
  1127. getMostRecentChildOptions: function getMostRecentChildOptions(options) {
  1128. // If does not have a valid options or if the options has a childPanelId then it is already a child options so just return the options
  1129. if (!options || options.childPanelId) {
  1130. return options;
  1131. }
  1132. var child = this.getCurrentChild();
  1133. return child && child.options && child.options.childPanelId ? _.clone(child.options) : options;
  1134. },
  1135. /**
  1136. * @param {Object} layouts - The layout whose properties will be displayed.
  1137. * @param {Object} options - options.
  1138. * Note: The setTimeout is here because we need a chance to trigger blur before
  1139. * actually udpate the property panel.
  1140. */
  1141. //TODO: remove this function when the focus mode epic is ready
  1142. _updatePropertiesPane: function _updatePropertiesPane(layouts, options) {
  1143. var _this14 = this;
  1144. var uniqueId = _.uniqueId('eventQueue_');
  1145. this._lastEventId = uniqueId;
  1146. // The promises seem to have the option of executing synchronously in some cases,
  1147. // in which case this could invalidate events which are in the process of firing.
  1148. // Delay execution of this code to allow all event handlers to fire before re-rendering.
  1149. // This allows the existing pane time to update.
  1150. setTimeout(function () {
  1151. if (!_this14.isSlideoutOpen()) {
  1152. //As this is deferred code, the slideout may have closed. Check before continuing.
  1153. return;
  1154. }
  1155. _this14.getProperties(layouts).then(function (properties) {
  1156. if (uniqueId === _this14._lastEventId) {
  1157. _this14._slideout.contentView.setPropertySpec(properties);
  1158. _this14._slideout.contentView.render(true).then(function () {
  1159. if (options && options.focusSelector) {
  1160. _this14._slideout.$el.find(options.focusSelector).focus();
  1161. }
  1162. if (options && options.currentScrollTop) {
  1163. _this14._dashboardPropertiesPane.scrollTop = options.currentScrollTop;
  1164. }
  1165. });
  1166. _this14._updateChildSelection();
  1167. }
  1168. });
  1169. }, 0);
  1170. },
  1171. _getSelectedLayouts: function _getSelectedLayouts(selectedNodes) {
  1172. var _this15 = this;
  1173. var layouts = [];
  1174. selectedNodes.forEach(function (node) {
  1175. if (node._layout) {
  1176. if (node._layout.model && node._layout.model.type === 'group') {
  1177. var children = Utils.getContentWithoutDecoration(node);
  1178. for (var i = 0; i < children.length; i++) {
  1179. $.merge(layouts, _this15._getSelectedLayouts([children[i]]));
  1180. }
  1181. }
  1182. layouts.push(node._layout);
  1183. }
  1184. });
  1185. if (layouts.length === 0) {
  1186. var topLayoutView = this._layoutController.getTopLayoutView();
  1187. if (topLayoutView) {
  1188. layouts.push(topLayoutView);
  1189. }
  1190. }
  1191. return layouts;
  1192. },
  1193. _getSelectedContents: function _getSelectedContents() {
  1194. var canvas = this.dashboard.getCanvas();
  1195. return _.map(canvas.getSelectedWidgets(), function (widget) {
  1196. return canvas.getContent(widget.getId());
  1197. });
  1198. },
  1199. _clearSelectedNodeIds: function _clearSelectedNodeIds() {
  1200. delete this._lastSelectedNodeIds;
  1201. },
  1202. /**
  1203. * If there is an open child, attempts to update the UI selection on it
  1204. */
  1205. _updateChildPropertiesSelection: function _updateChildPropertiesSelection() {
  1206. var child = this.getCurrentChild();
  1207. if (child && child.updateSelection) {
  1208. child.updateSelection();
  1209. }
  1210. },
  1211. /**
  1212. * If there is an open child, attempts to update the UI selection on it
  1213. */
  1214. //TODO: remove this function when the focus mode epic is ready
  1215. _updateChildSelection: function _updateChildSelection() {
  1216. var openChild = this._slideout.child && this._slideout.child.open ? this._slideout.child : null;
  1217. if (openChild && openChild.contentView.updateSelection) {
  1218. openChild.contentView.updateSelection();
  1219. }
  1220. }
  1221. });
  1222. return PropertiesManager;
  1223. });
  1224. //# sourceMappingURL=PropertiesManager.js.map