123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380 |
- 'use strict';
- 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; };
- /*
- *+------------------------------------------------------------------------+
- *| Licensed Materials - Property of IBM
- *| IBM Cognos Products: Dashboard
- *| (C) Copyright IBM Corp. 2017, 2020
- *|
- *| US Government Users Restricted Rights - Use, duplication or disclosure
- *| restricted by GSA ADP Schedule Contract with IBM Corp.
- *+------------------------------------------------------------------------+
- */
- 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) {
- var PropertiesManager = Class.extend([SlideoutHelper], {
- /**
- options.glassContext
- options.canvasController
- options.context - this is the context passed to our perspective controllers
- **/
- init: function init(options) {
- PropertiesManager.inherited('init', this, arguments);
- _.extend(this, options);
- this.dashboard = this.canvasController.dashboardApi;
- this._layoutController = this.canvasController.layoutController;
- this._eventRouter = this.canvasController.eventRouter;
- this.canvas = this.dashboard.getFeature('Canvas');
- this.canvas.on('change:content:property', this.onContentPropertyChange, this);
- this.canvas.on('change:property', this.onDashboardPropertyChange, this);
- this.slideoutFeature = this.dashboard.getFeature('InAppSlideoutState');
- this.slideoutDOMFeature = this.dashboard.getFeature('InAppSlideoutDOM');
- this._eventRouter.on('properties:refreshProperty', this.refreshProperty, this);
- this._eventRouter.on('properties:updateVisiblilty', this.updateVisiblilty, this);
- this._eventRouter.on('properties:updateEnabled', this.updateEnabled, this);
- this._eventRouter.on('properties:setValue', this.setPropertyValue, this);
- this._eventRouter.on('selection:ready', this.onPropertiesSelectionReady, this);
- this._eventRouter.on('properties:refreshPane', this.refreshApplicationPropertiesPane, this);
- this._eventRouter.on('properties:refreshChild', this.refreshChildProperty, this);
- this._eventRouter.on('properties:setChildValue', this.setChildValue, this);
- this._lastEventId = '';
- this._expandedSections = {};
- 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')];
- this.logger = options.glassContext.getCoreSvc('.Logger');
- //keep track of children
- this._children = [];
- },
- onContentPropertyChange: function onContentPropertyChange() {
- var _this = this;
- var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
- if (!options.info) {
- return;
- }
- var infoList = [options.info];
- // In case of event list
- var events = options.info.events;
- if (events) {
- var eventsMap = {};
- // get the events info list for unique content ids
- events.forEach(function (event) {
- if (event.info && event.info.contentId) {
- eventsMap[event.info.contentId] = event.info;
- }
- });
- infoList = Object.values(eventsMap);
- }
- infoList.forEach(function (info) {
- var contentId = info.contentId;
- var content = contentId && _this.canvas.getContent(contentId);
- // if the content is live widget, then we do not refreshPropertiesPane here,
- // because in live widget renderTask, it will refreshPropertiesPane as needed.
- // TODO when livewidget side gets rid of the legacy event `properties:refreshPane`
- // then we can remove this condition
- if (content && content.getType() !== 'widget.live') {
- var eventOptions = info.options || {};
- if (_this.getCurrentChild()) {
- // if child property pane is open, then refresh child property pane
- _this.refreshChildProperty(_extends({
- content: _this.canvas.getContent(contentId)
- }, eventOptions));
- } else {
- _this.refreshApplicationPropertiesPane(_extends({}, eventOptions));
- }
- }
- });
- },
- onDashboardPropertyChange: function onDashboardPropertyChange() {
- var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
- if (options.info && options.info.supportsUndoRedo) {
- var eventOptions = options.info.options || {};
- this.refreshApplicationPropertiesPane(_extends({}, eventOptions));
- }
- },
- //TODO: remove this function when the focus mode epic is ready
- show: function show(options) {
- var _this2 = this;
- var context = options && options.context;
- this._hideChild();
- var selectedNodes = this._layoutController.getSelectedNodes();
- var selectedLayouts = this._getSelectedLayouts(selectedNodes);
- this._selectedTab = '';
- this._expandedSections = {};
- this._handleButtonState(true);
- return this.getProperties(selectedLayouts).then(function (properties) {
- var label = properties && properties[0] && properties[0].type === 'Banner' ? properties[0].value : '';
- return _this2.createAndShowSlideout({
- 'enableTabLooping': true,
- 'width': '320px',
- 'position': 'right',
- 'pinning': {
- 'isPinned': true,
- 'float': false,
- 'display': false
- },
- 'content': {
- 'module': 'dashboard-core/js/dashboard/contentpane/PropertyUIControlView',
- 'glassContext': _this2.glassContext,
- 'renderCallback': _this2._renderCallback.bind(_this2),
- 'items': properties,
- 'onSetFocus': options ? options.onSetFocus : null
- },
- 'label': label
- }, context);
- });
- },
- /**
- * Get the properties ui view
- *
- * @param {string} contentId the id of a given content
- * @returns {Promise}
- */
- getPropertiesView: function getPropertiesView(contentId) {
- var _this3 = this;
- var content = this.dashboard.getCanvas().getContent(contentId);
- var propertyLayoutList = void 0;
- if (contentId) {
- propertyLayoutList = this.getPropertyLayoutList([content]);
- } else {
- // Getting the default canvas property as no contentId provided
- var layouts = this._getSelectedLayouts([]);
- propertyLayoutList = this.getProperties(layouts);
- }
- return propertyLayoutList.then(function (properties) {
- var propertyUIControlView = new PropertyUIControlView({
- node: document.createElement('div'),
- items: properties,
- glassContext: _this3.glassContext,
- renderCallback: _this3._renderCallback.bind(_this3)
- });
- _this3.contentView = propertyUIControlView;
- return propertyUIControlView.render();
- });
- },
- _renderCallback: function _renderCallback() {
- if (this._eventRouter) {
- this._eventRouter.trigger('properties:hasRendered', {});
- }
- },
- //TODO: remove this function when the focus mode epic is ready
- hide: function hide() {
- this._hideChild();
- this._handleButtonState(false);
- this._closeSlideout();
- this._clearSelectedNodeIds();
- },
- //TODO: remove this function when the focus mode epic is ready
- _handleButtonState: function _handleButtonState(pressed) {
- var propertyButton = this.glassContext.appController.findPlugin('com.ibm.bi.dashboard.propertyBtn');
- if (!propertyButton) {
- return;
- }
- if (pressed === true) {
- propertyButton.setPressed();
- } else if (pressed === false) {
- propertyButton.setUnpressed();
- }
- },
- getProperties: function getProperties(selected) {
- var canvas = this.dashboard.getCanvas();
- var isTopLevel = selected && selected.length && !selected[0].parentLayout;
- var contents = isTopLevel ? [canvas] : _.map(selected, function (layout) {
- return canvas.getContent(layout.id);
- });
- return this.getPropertyLayoutList(contents);
- },
- // START of USE NEW API
- /**
- * Get the combined layouts from the given contents
- * @param {ContentAPI[]} contents array of selected contents
- */
- getPropertyLayoutList: function getPropertyLayoutList(contents) {
- var _this4 = this;
- var promises = [];
- var groupCounter = 0;
- var bannerControl = void 0;
- _.each(contents, function (content) {
- var layouts = content && content.getPropertyLayoutList && content.getPropertyLayoutList();
- if (!_.isEmpty(layouts)) {
- // collect the first banner control
- if (!bannerControl) {
- var banner = _.find(layouts, function (layout) {
- return layout.type === 'Banner';
- });
- bannerControl = _this4._getCoreClientLayout(banner);
- }
- // collect all tabs
- var tabs = _.chain(layouts).filter(function (layout) {
- return layout.type === 'Group';
- }).sortBy(function (tab) {
- if (tab.position !== undefined) {
- return tab.position;
- }
- var index = _this4._defaultTabOrder.indexOf(tab.label);
- return index >= 0 ? index : 10;
- }).map(_this4._getCoreClientLayout.bind(_this4)).value();
- // asyncronously process all properties starting from the tabs
- if (content.getType && content.getType() === 'group') {
- // if the content is a group, put the promise at the end of the promise array
- groupCounter++;
- promises.push(PropertyListUtil.processProperties(tabs, content, _this4.dashboard).then(function () {
- return tabs;
- }));
- } else {
- // if the content is not a group, put the promise at the front of the promise array
- promises.unshift(PropertyListUtil.processProperties(tabs, content, _this4.dashboard).then(function () {
- return tabs;
- }));
- }
- }
- });
- return Promise.all(promises).then(function (tabItems) {
- // merge all non-group tab layouts
- while (tabItems.length > 1 + groupCounter) {
- tabItems[0] = _this4._mergePropertySpecs(tabItems[1], tabItems[0], true);
- tabItems.splice(1, 1);
- }
- var commonSharedTabItems = tabItems[0];
- var commonSharedGroupTabItems = void 0;
- if (groupCounter > 0) {
- tabItems.splice(0, 1);
- // merge all group tab layouts
- while (tabItems.length > 1) {
- tabItems[0] = _this4._mergePropertySpecs(tabItems[1], tabItems[0], true);
- tabItems.splice(1, 1);
- }
- commonSharedGroupTabItems = tabItems[0];
- }
- // merge all layouts
- if (commonSharedTabItems) {
- tabItems[0] = _this4._mergeGroupPropertySpecs(commonSharedTabItems, commonSharedGroupTabItems);
- }
- var uiControlList = [];
- if (tabItems.length < 1) {
- return uiControlList;
- }
- uiControlList.push(bannerControl);
- if (tabItems[0].length > 1) {
- var tabControl = {
- 'type': 'TabControl',
- 'name': 'tabControl',
- 'items': tabItems[0],
- 'onTabChange': function (propName, tab) {
- this._selectedTab = tab.name;
- }.bind(_this4)
- };
- uiControlList.push(tabControl);
- }
- // Hide the tab if there is only one tab
- if (tabItems[0].length === 1) {
- uiControlList.push.apply(uiControlList, tabItems[0][0].items);
- }
- return uiControlList;
- });
- },
- _getCoreClientLayout: function _getCoreClientLayout(layout, index) {
- var _this5 = this;
- var coreClientSpec = _.extend({}, layout);
- if (layout) {
- // expand the children
- if (layout.items && layout.items.length) {
- _.extend(coreClientSpec, {
- items: _.chain(layout.items).map(function (item, idx) {
- return _this5._getCoreClientLayout(item, idx);
- }).flatten().value()
- });
- }
- // process the current layout
- switch (coreClientSpec.type) {
- case 'Group':
- return this._processCoreClientTabControl(coreClientSpec);
- case 'Section':
- return this._processCoreClientSectionControl(coreClientSpec, index);
- case 'DropDown':
- return this._processCoreClientDropDownControl(coreClientSpec);
- }
- }
- return coreClientSpec;
- },
- _processCoreClientTabControl: function _processCoreClientTabControl(layout) {
- return _.extend(layout, {
- // tab uses the name as label
- name: layout.label,
- selected: this._selectedTab === layout.label,
- module: 'dashboard-core/js/dashboard/contentpane/PropertyUIControlView'
- });
- },
- _getSectionExpandState: function _getSectionExpandState(section, index) {
- if (this._expandedSections[section.id] === undefined) {
- var state = section.open;
- if (state === undefined) {
- // keep the first section open (default) unless if the state is defined or changed
- state = index === 0;
- }
- // keep track of the state
- this._expandedSections[section.id] = state;
- }
- return this._expandedSections[section.id];
- },
- _processCoreClientSectionControl: function _processCoreClientSectionControl(layout, index) {
- var section = _.extend(layout, {
- name: layout.id,
- styleAsSimpleRow: true,
- // rename the type to CollapsibleSection
- type: layout.collapsible === false ? 'SectionLabel' : 'CollapsibleSection',
- // manager the section expand state
- open: this._getSectionExpandState(layout, index),
- onOpenChange: function (name, isOpen) {
- this._expandedSections[name] = isOpen;
- }.bind(this)
- });
- var controls = index > 0 && !layout.noSeparator ? [{ 'type': 'Separator' }, section] : [section];
- if (section.type === 'SectionLabel') {
- // Since the section label is not expandable
- // move the section controls adjacent to the section label
- controls.push.apply(controls, section.items);
- delete section.items;
- }
- return controls;
- },
- _processCoreClientDropDownControl: function _processCoreClientDropDownControl(layout) {
- // give the control a unique name
- layout.name = layout.id;
- // handle delayed async dropdown options
- if (!layout.options && layout.getOptions) {
- layout.options = layout.getOptions();
- }
- return layout;
- },
- // END of USE NEW API
- //TODO: remove this function when the focus mode epic is ready
- _hideChild: function _hideChild() {
- var child = this.getCurrentChild();
- if (child) {
- child.hide({
- force: true
- });
- }
- },
- closeChild: function closeChild() {
- var onCloseCb = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;
- var child = this.getCurrentChild();
- if (child) {
- // when explore side calls closeChild,it pass in an callback function
- // but when the properties ui control call it, it pass in an
- // object which includes changes properties. so it is very confusing and the api should be consistent
- // TODO explore side and here should be refactored and not inject a custom callback
- if (onCloseCb && typeof onCloseCb === 'function') {
- onCloseCb();
- } else {
- if (child.node && child.node.parentNode && child.node.parentNode.contains(child.node)) {
- child.node.nextElementSibling.style.display = 'block';
- child.node.parentNode.removeChild(child.node);
- } else if (child.$el && child.parentNode && child.parentNode.contains(child.$el[0])) {
- // Required for changePallete child slideout
- // Reason: changePallette renders the child differently
- child.$el.next().show();
- child.parentNode.removeChild(child.$el[0]);
- }
- }
- this._children.pop();
- if (child.remove) {
- child.remove();
- }
- }
- },
- closeAllChild: function closeAllChild() {
- var numChildren = this._children.length;
- while (numChildren > 0) {
- this.closeChild();
- --numChildren;
- }
- },
- getChildPropertiesView: function getChildPropertiesView(options) {
- var _this6 = this;
- options.glassContext = this.glassContext;
- // pass the provider closeChild callback to the closeChild function of PropertiesManager
- // For R7, with the new CF, only changePaletteView and ConditionalFormattingUI need a closeChild callback for Explore
- options.onCloseCb = this.closeChild.bind(this, options.onCloseCb);
- var module = options.module.split('/').pop();
- var promise = new Promise(function (resolve, reject) {
- switch (module) {
- case 'PropertyUIControlView':
- resolve(_this6._createChildPropertyUIControlView(options.items));
- break;
- case 'changePaletteView':
- // authoring-common is only available in run time env, ensuring that it's loaded only when needed
- require(['authoring-common'], function (AuthoringCommon) {
- resolve(new AuthoringCommon.ChangePaletteView(options));
- }, function (error) {
- reject(error);
- });
- break;
- case 'ConditionalFormatting':
- require([options.module], function (CondFormattingUI) {
- resolve(new CondFormattingUI.CurrentConditionalPalette(options));
- }, function (error) {
- reject(error);
- });
- break;
- default:
- resolve();
- break;
- }
- });
- return promise.then(function (uiControlView) {
- if (!uiControlView) {
- return Promise.resolve();
- }
- // The options is safe for that it can be retrieved at a later time when
- // needed to refresh to re-render the child panel
- uiControlView.options = options;
- // Put the new child panel on top of stack of the children panel list
- _this6._children.push(uiControlView);
- return uiControlView.render();
- });
- },
- /**
- * @return {Slideout} Returns the current child slideout view or null if none.
- */
- getCurrentChild: function getCurrentChild() {
- return this._children.length > 0 ? this._children[this._children.length - 1] : null;
- },
- /**
- * Adds and shows a child slideout
- * It waits for 600ms till the slideout is open before adding it; otherwise showing the child may occur before the parent is actually
- * shown. In this case the child is not displayed
- * @public
- * @param {object} [options] - same options as the constructor except for position, glassContext which are retrieved from the current slideout and extra properties
- * @param {Boolean} [options.overlay=false] - the child is shown on the top of the parent if true
- * @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
- * @param {launchPoint} [options.launchPoint] - Optional, The UI dom element that launched the slideout. The last active element if not specified.
- * @param {String} [options.label] - The aria-label for the slideout. If no label is provided a default label is used.
- * @return {Slideout} Child slideout; It may be returned before the slideout is actually shown
- */
- addChild: function addChild() {
- var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
- this.childPropertyDisplayed = true;
- options.content = options.content || {};
- options.content.isChild = true;
- // The unique child panel identifier that is use to refresh to re-render the child
- options.content.childPanelId = _.uniqueId('childPanelId_');
- // individual page id
- if (options.pageChildId) {
- this.pageChildId = options.pageChildId;
- }
- this.slideoutDOMFeature.render(options.content);
- return true;
- },
- /**
- Remove any property that's tagged with public: false from the array of properties
- @param [array] properties - the array of properties to loop through to remove any non public properties
- **/
- _removeNonPublicProperties: function _removeNonPublicProperties(properties) {
- for (var i = 0; i < properties.length; i++) {
- var property = properties[i];
- if (property.public === false) {
- properties.splice(i, 1);
- i--;
- } else if (properties.items) {
- this._removeNonPublicProperties(properties.items);
- }
- }
- },
- /**
- Groups all the properties in their defined tabs.
- @param [array] properties - the array of properties to loop through and group into tabs
- **/
- _groupIntoTabs: function _groupIntoTabs(properties) {
- var _this7 = this;
- if (!properties) {
- return;
- }
- var tabsMap = {};
- var tabControlProperty = null;
- this._sectionMap = {};
- for (var i = 0; i < properties.length; i++) {
- var property = properties[i];
- if (property.tabName) {
- if (tabsMap[property.tabName]) {
- if (property.tabPosition !== undefined) {
- tabsMap[property.tabName].tabPosition = property.tabPosition;
- }
- } else {
- if (!tabControlProperty) {
- tabControlProperty = {
- 'type': 'TabControl',
- 'name': 'tabControl',
- 'onTabChange': function (propName, tab) {
- this._selectedTab = tab.name;
- }.bind(this),
- 'items': []
- };
- properties.splice(i, 0, tabControlProperty);
- i++;
- }
- var newTab = this._genTabUIControlSpec(property);
- tabControlProperty.items.push(newTab);
- tabsMap[property.tabName] = newTab;
- this._sectionMap[property.tabName] = {};
- }
- this._insertPropIntoTab(property, tabsMap[property.tabName]);
- properties.splice(i, 1);
- i--;
- }
- }
- if (tabControlProperty) {
- var selectedTab = $.grep(tabControlProperty.items, function (tab) {
- return tab.selected === true;
- });
- if (selectedTab.length === 0) {
- this._selectedTab = '';
- }
- // Sort the tabs
- tabControlProperty.items = _.sortBy(tabControlProperty.items, function (tab) {
- if (tab.tabPosition !== undefined) {
- return tab.tabPosition;
- }
- var index = _this7._defaultTabOrder.indexOf(tab.name);
- return index >= 0 ? index : 10;
- });
- //Sort the collapsible sections, and open the first one if only collapsible sections are present.
- _.each(tabControlProperty.items, function (tab) {
- if (tab.items) {
- tab.items = _.sortBy(tab.items, 'sectionPosition');
- var openFirst = true;
- for (var _i = 0; _i < tab.items.length; _i++) {
- if (tab.items[_i].type !== 'CollapsibleSection' || tab.items[_i].open || tab.items[_i].expansionRuleExists) {
- openFirst = false;
- break;
- }
- }
- _this7._addSeparatorBetweenSections(tab.items);
- if (openFirst) {
- tab.items[0].open = true;
- }
- }
- });
- }
- this._sectionMap = null;
- },
- _addSeparatorBetweenSections: function _addSeparatorBetweenSections(items) {
- if (!items) {
- return;
- }
- for (var i = 0; i < items.length; i++) {
- var property = items[i];
- if (property.type === 'CollapsibleSection' && i < items.length - 1) {
- items.splice(i + 1, 0, {
- 'type': 'Separator'
- });
- }
- }
- },
- /**
- Inserts a given property into the tab items array. Will add the property in the correct location based on the displayPos of the property
- @param {object} property - the property object to insert into the array of properties for the tab
- @param {object} tab - the tab object in which to add the property
- **/
- _insertPropIntoTab: function _insertPropIntoTab(property, tab) {
- var container = tab;
- if (property.sectionName) {
- var tabName = property.tabName;
- if (!this._sectionMap[tabName][property.sectionName]) {
- var newSection = this._genSectionUIControlSpec(property);
- this._insertPropIntoItemContainer(newSection, tab);
- this._sectionMap[tabName][property.sectionName] = newSection;
- container = newSection;
- } else {
- container = this._sectionMap[tabName][property.sectionName];
- }
- if (property.sectionPosition !== undefined) {
- container.sectionPosition = property.sectionPosition;
- }
- // if we already have an expansion rule we keep it.
- if (property.sectionOpened !== undefined && !container.expansionRuleExists) {
- container.open = property.sectionOpened;
- container.expansionRuleExists = true;
- }
- }
- this._insertPropIntoItemContainer(property, container);
- },
- /**
- Inserts a given property into the container items array. Will add the property in the correct location based on the displayPos of the property
- @param {object} property - the property object to insert into the array of properties for the container
- @param {object} container - the container object in which to add the property
- **/
- _insertPropIntoItemContainer: function _insertPropIntoItemContainer(property, container) {
- var inserted = false;
- for (var i = 0; i < container.items.length; i++) {
- // 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.
- // Or if the current items display position is bigger then the new items display position
- if (!property.displayPos && container.items[i].displayPos || (container.items[i].displayPos || -1) > (property.displayPos || -1)) {
- container.items.splice(i, 0, property);
- inserted = true;
- break;
- }
- }
- if (!inserted) {
- container.items.push(property);
- }
- },
- /**
- Creates the tabControl object
- @param {object} property - a property for which the tabName is defined
- **/
- _genTabUIControlSpec: function _genTabUIControlSpec(property) {
- var tabModule = property.tabModule ? property.tabModule : 'dashboard-core/js/dashboard/contentpane/PropertyUIControlView';
- var tabSpec = {
- 'name': property.tabName,
- 'module': tabModule,
- 'items': []
- };
- if (property.tabName === this._selectedTab) {
- tabSpec.selected = true;
- }
- if (property.tabPosition !== undefined) {
- tabSpec.tabPosition = property.tabPosition;
- }
- return tabSpec;
- },
- /**
- Creates the CollapsibleSection object
- @param {object} property - a property for which the sectionName is defined
- **/
- _genSectionUIControlSpec: function _genSectionUIControlSpec(property) {
- var _this8 = this;
- var sectionName = property.tabName + '|' + property.sectionName;
- var sectionSpec = {
- label: property.sectionName,
- name: sectionName,
- type: 'CollapsibleSection',
- items: [],
- styleAsSimpleRow: true,
- onOpenChange: function onOpenChange(name, isOpen) {
- _this8._expandedSections[name] = isOpen;
- }
- };
- if (this._expandedSections[sectionName] != undefined) {
- sectionSpec.open = this._expandedSections[sectionName];
- sectionSpec.expansionRuleExists = true;
- }
- return sectionSpec;
- },
- _mergeGroupPropertySpecs: function _mergeGroupPropertySpecs(commonSharedTabItems, commonSharedGroupTabItems) {
- var _this9 = this;
- if (!commonSharedGroupTabItems) {
- return commonSharedTabItems;
- }
- var result = [];
- commonSharedTabItems.forEach(function (commonSharedTabItem) {
- if (!commonSharedTabItem.name) {
- result.push(commonSharedTabItem);
- } else {
- // if item exists in both group and children, group property will be pushed to the result
- var matchedItem = null;
- for (var i = 0; i < commonSharedGroupTabItems.length; i++) {
- if (commonSharedGroupTabItems[i].name === commonSharedTabItem.name) {
- matchedItem = commonSharedGroupTabItems[i];
- break;
- }
- }
- if (matchedItem) {
- if (matchedItem.items && commonSharedTabItem.items) {
- matchedItem.items = _this9._mergeGroupPropertySpecs(commonSharedTabItem.items, matchedItem.items);
- }
- result.push(matchedItem);
- } else {
- // if item only exists in children, push the property to the result
- result.push(commonSharedTabItem);
- }
- }
- });
- return result;
- },
- /**
- Merges two uiPropertyControl specifications together
- @param spec1 - a propertyUIControl specification object
- @param spec2 - a propertyUIControl specification object
- @param bOnlyKeepCommonProperties {boolean} - wether we should only be keeping properties found in both specs
- **/
- _mergePropertySpecs: function _mergePropertySpecs(spec1, spec2, bOnlyKeepCommonProperties) {
- if (!spec1) {
- return spec2;
- } else if (!spec2) {
- return spec1;
- }
- var result = bOnlyKeepCommonProperties ? [] : spec1;
- spec2.forEach(function (spec2Item) {
- // If the property doesn't have a name then simply append it
- if (!spec2Item.name) {
- result.push(spec2Item);
- } else {
- var matchedItem = null;
- for (var i = 0; i < spec1.length; i++) {
- if (spec1[i].name === spec2Item.name) {
- matchedItem = spec1[i];
- break;
- }
- }
- if (matchedItem) {
- if (matchedItem.items && spec2Item.items) {
- // Recursively merge the child item arrays
- matchedItem.items = this._mergePropertySpecs(matchedItem.items, spec2Item.items, bOnlyKeepCommonProperties);
- }
- // Since we're merging the properties, keep track of the two onChange callbacks
- this._mergeCallback('onChange', matchedItem, spec2Item);
- // Palatte propertties have two 'change' callbacks, make sure the onChangePalette callback is also merged
- this._mergeCallback('onChangePalette', matchedItem, spec2Item);
- if (bOnlyKeepCommonProperties) {
- result.push(matchedItem);
- }
- } else if (!bOnlyKeepCommonProperties) {
- result.push(spec2Item);
- }
- }
- }.bind(this));
- return result;
- },
- /**
- * Given two property specs, create one callback function that will call the callbacks for both properties.
- */
- _mergeCallback: function _mergeCallback(callbackPropertyName, propertySpec1, propertySpec2) {
- if (propertySpec1[callbackPropertyName] || propertySpec2[callbackPropertyName]) {
- var originalOnChange = propertySpec1[callbackPropertyName];
- // Since we're merging the properties, keep track of the two onChange callbacks
- propertySpec1[callbackPropertyName] = function (propertyName, propertyValueInfo) {
- if (originalOnChange) {
- originalOnChange.call(propertySpec1, propertyName, propertyValueInfo);
- }
- if (propertySpec2[callbackPropertyName]) {
- propertySpec2[callbackPropertyName].call(propertySpec2, propertyName, propertyValueInfo);
- }
- };
- }
- },
- /**
- Shows or hides a property
- @param {object} options
- @param {string} options.propertyName - the name of the property to update
- @param {boolean} options.visible - if the property should be visible or not
- **/
- updateVisiblilty: function updateVisiblilty(options) {
- if (!options) {
- return false;
- }
- var propertyControl = this.getPropertyControl(options.propertyName);
- if (!propertyControl) {
- return false;
- }
- if (options.visible === true) {
- propertyControl.show();
- } else {
- propertyControl.hide();
- }
- return true;
- },
- /**
- Enables or disables a property
- @param {object} options
- @param {string} options.propertyName - the name of the property to update
- @param {boolean} options.enabled - if the property should be visible or not
- **/
- updateEnabled: function updateEnabled(options) {
- if (!options) {
- return false;
- }
- var propertyControl = this.getPropertyControl(options.propertyName);
- if (!propertyControl) {
- return false;
- }
- if (options.enabled === true) {
- propertyControl.readOnly = false;
- propertyControl.enable();
- } else {
- propertyControl.disable();
- }
- return true;
- },
- /**
- Re-renders a given property with an updated spec
- @param {object} - options
- @param {object} - options.propertySpec
- **/
- refreshProperty: function refreshProperty(options) {
- if (!options || !options.propertySpec) {
- return false;
- }
- var propertyControl = this.getPropertyControl(options.propertySpec.name);
- if (!propertyControl) {
- return false;
- }
- propertyControl.$el.empty();
- if (options.removeProperty !== true) {
- _.extend(propertyControl, options.propertySpec);
- propertyControl.doRender();
- }
- return true;
- },
- /**
- *
- * Set the value of a child property, only works if the propertyControl has setValue method
- * @param {object} options
- * @param {string} options.propertyName - the name of the property to update
- * @param {boolean||string||number} options.value - value to set
- * @param {string} options.contentId - the id of the child page
- * @returns
- */
- //TODO: remove this function when the focus mode epic is ready
- setChildPropertyValue: function setChildPropertyValue(options) {
- if (!this.isSlideoutOpen()) {
- return;
- }
- var child = this.getCurrentChild();
- // only set the value if the child page properties panel exists
- if (child && child.pageChildId === options.contentId && options.value) {
- var propertyControl = this.getPropertyControl(options.propertyName, child);
- propertyControl && propertyControl.setValue && propertyControl.setValue(options.value);
- }
- },
- setChildValue: function setChildValue(options) {
- if (!this._isPropertiesPaneOpen()) {
- return;
- }
- var child = this.getCurrentChild();
- // only set the value if the child page properties panel exists
- if (child && this.pageChildId === options.contentId && options.value) {
- var propertyControl = this.getPropertyControl(options.propertyName, child);
- propertyControl && propertyControl.setValue && propertyControl.setValue(options.value);
- }
- },
- refreshChildProperty: function refreshChildProperty(options) {
- var _this10 = this;
- return Promise.resolve().then(function () {
- if (!_this10._isPropertiesPaneOpen()) {
- return;
- }
- var child = _this10.getCurrentChild();
- var content = options && options.content;
- if (content && child && _this10.pageChildId === content.getId()) {
- // refresh the child property
- _this10.slideoutDOMFeature.render({ content: content, refreshChild: true, isChild: true });
- }
- });
- },
- /**
- * Call by the PropertiesPaneDOM instance to refresh the child panel and add to the Properties Panel reside with InAppSlideout
- * @param {object} options - the options use to refresh and render the child panel
- * @return {promise} Returns a resolved promise after the child is refreshed and get rendered
- */
- updateChildPropertiesView: function updateChildPropertiesView() {
- var _this11 = this;
- var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
- var promise = options.refreshChild && options.content ? this.getPropertyLayoutList([options.content]) : Promise.resolve();
- return promise.then(function (properties) {
- if (properties) {
- options.items = properties;
- }
- // Remove the current (or old) child property from the children list
- // when childPanelId matched
- var child = _this11.getCurrentChild();
- if (child && child.options && child.options.childPanelId === options.childPanelId) {
- if (child instanceof PropertyUIControlView) {
- if (child.getPropertyUIControl()) {
- child.getPropertyUIControl().remove();
- }
- _this11._children.pop();
- options.module = options.module || 'dashboard-core/js/dashboard/contentpane/PropertyUIControlView';
- } else {
- options.onCloseCb();
- }
- }
- options.onCloseCb = options.originalOnCloseCb;
- return _this11.getChildPropertiesView(options);
- });
- },
- _createChildPropertyUIControlView: function _createChildPropertyUIControlView(properties) {
- return new PropertyUIControlView({
- node: document.createElement('div'),
- items: properties,
- glassContext: this.glassContext,
- onCloseCb: this.closeChild,
- closeCallback: this.closeChild.bind(this),
- renderCallback: this._renderCallback.bind(this)
- });
- },
- //TODO: remove this function when the focus mode epic is ready
- refreshChild: function refreshChild(options) {
- var _this12 = this;
- // If there are multiple events triggering at the same time, we want the setContent to run before the next refreshChild kick in
- return Promise.resolve().then(function () {
- if (!_this12.isSlideoutOpen()) {
- return;
- }
- var content = options && options.content;
- var child = _this12.getCurrentChild();
- if (content && child && child.pageChildId === content.getId()) {
- return _this12.getPropertyLayoutList([content]).then(function (properties) {
- var uiContent = {
- module: 'dashboard/contentpane/PropertyUIControlView',
- items: properties
- };
- uiContent.onCloseCb = _this12._hideChild.bind(_this12);
- uiContent.closeCallback = _this12._hideChild.bind(_this12);
- // Need to check the contentView to avoid rendering multiple times
- if (child.contentView) {
- return child.setContent(uiContent).then(function () {
- if (options.focusSelector) {
- child.$el.find(options.focusSelector).focus();
- }
- });
- }
- return false;
- });
- }
- });
- },
- /**
- Sets the value of a property
- @param {object} options
- @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
- @param {boolean||string||number} options.value - value to set
- **/
- setPropertyValue: function setPropertyValue(options) {
- if (!options || options.value === undefined) {
- return false;
- }
- var propertyControl = this.getPropertyControl(options.propertyName);
- if (!propertyControl || !propertyControl.setValue) {
- return false;
- }
- propertyControl.propertiesManagerChange = true;
- if (options.subPropertyName) {
- propertyControl.setValue(options.subPropertyName, options.value);
- } else {
- propertyControl.setValue(options.value);
- }
- propertyControl._lastChangedValue = 'undefined'; // Bug in glass, setValue doesn't reset _lastChangedValue.
- propertyControl.propertiesManagerChange = false;
- return true;
- },
- getPropertyControl: function getPropertyControl(propertyName, slideout) {
- if (!this._isPropertiesPaneOpen()) {
- return null;
- }
- if (!slideout) {
- slideout = this._slideout;
- }
- var contentView = slideout || this.contentView;
- var propertyUIControl = contentView.getPropertyUIControl();
- return this._getPropertyControlFromUIControl(propertyName, propertyUIControl);
- },
- _getPropertyControlFromUIControl: function _getPropertyControlFromUIControl(propertyName, propertyUIControl) {
- if (!propertyUIControl) {
- return null;
- }
- var name = propertyName,
- childNames;
- if (typeof propertyName !== 'string' && propertyName.length) {
- childNames = propertyName.slice();
- name = childNames.shift();
- }
- var property = propertyUIControl.getProperty(name);
- if (!property && propertyUIControl.propertyUIControlLeft) {
- property = propertyUIControl.propertyUIControlLeft.getProperty(name);
- if (!property && propertyUIControl.propertyUIControlRight) {
- property = propertyUIControl.propertyUIControlRight.getProperty(name);
- }
- }
- if (!property) {
- return null;
- }
- if (childNames && childNames.length) {
- return this._getPropertyControlFromUIControl(childNames, property);
- } else {
- return property;
- }
- },
- _isPropertiesPaneOpen: function _isPropertiesPaneOpen() {
- if (!this.slideoutFeature.isOpen()) {
- return false;
- }
- var currentContribution = this.slideoutFeature.getCurrent();
- if (!currentContribution || currentContribution.id !== 'PropertiesPane') {
- return false;
- }
- return true;
- },
- /**
- * Refreshes the UI to update with the properties option for newly selected element
- * @param {String} options.sender - The id of the newly selected element
- * @param {String} options.selectedTab - String containing the the tab to be selected in the properties pane
- */
- refreshApplicationPropertiesPane: function refreshApplicationPropertiesPane() {
- var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
- if (!this._isPropertiesPaneOpen()) {
- return;
- }
- var selectedNodes = this._layoutController.getSelectedNodes();
- var selectedLayouts = selectedNodes && this._getSelectedLayouts(selectedNodes);
- if (selectedLayouts) {
- if (options.selectedTab) {
- this._selectedTab = options.selectedTab;
- }
- var contributionID = this.slideoutFeature.getCurrent().id;
- var propertiesPaneContainerNode = this.slideoutDOMFeature.getView(contributionID).instance.getRenderNode();
- options.currentScrollTop = propertiesPaneContainerNode.scrollTop;
- this.updatePropertiesPanel(selectedLayouts, options);
- }
- },
- //TODO: remove this function when the focus mode epic is ready
- refreshPropertiesPane: function refreshPropertiesPane(options) {
- if (!this.isSlideoutOpen()) {
- return;
- }
- this._dashboardPropertiesPane = this._slideout.el.querySelector('.pane-content');
- if (options && options.selectedTab) {
- this._selectedTab = options.selectedTab;
- }
- var selectedNodes = this._layoutController.getSelectedNodes();
- if (options) {
- options.currentScrollTop = this._dashboardPropertiesPane.scrollTop;
- } else {
- options = {
- currentScrollTop: this._dashboardPropertiesPane.scrollTop
- };
- }
- var selectedLayouts = this._getSelectedLayouts(selectedNodes);
- this._updatePropertiesPane(selectedLayouts, options);
- },
- /**
- * Renders the Properties UI when a new selection on the canvas is made
- * @param {Object} options.event - The selection event
- * @param {Array} options.selectedNodes - An array containing the dom elements of the selected nodes
- */
- onPropertiesSelectionReady: function onPropertiesSelectionReady(options) {
- if (!this._isPropertiesPaneOpen()) {
- return;
- }
- var selectedNodeIds = options.selectedNodes.map(function (item) {
- return item.id;
- }).sort().join();
- if (selectedNodeIds !== this._lastSelectedNodeIds) {
- if (options.selectedNodes && options.selectedNodes.length === 1) {
- this._selectedTab = '';
- this._expandedSections = {};
- }
- var layouts = this._getSelectedLayouts(options.selectedNodes);
- // Close all current open child panels when switch between vis - vis or vis - canvas selections
- this.closeAllChild();
- this.updatePropertiesPanel(layouts, options);
- this._lastSelectedNodeIds = selectedNodeIds;
- }
- },
- /**
- options.events
- options.selectedNodes
- **/
- //TODO: remove this function when the focus mode epic is ready
- onSelectionReady: function onSelectionReady(options) {
- if (!this.isSlideoutOpen()) {
- return;
- }
- var selectedNodeIds = options.selectedNodes.map(function (item) {
- return item.id;
- }).sort().join();
- if (selectedNodeIds !== this._lastSelectedNodeIds) {
- if (options.selectedNodes && options.selectedNodes.length === 1) {
- this._selectedTab = '';
- this._expandedSections = {};
- }
- var layouts = this._getSelectedLayouts(options.selectedNodes);
- this._hideChild();
- this._updatePropertiesPane(layouts);
- this._lastSelectedNodeIds = selectedNodeIds;
- }
- },
- updatePropertiesPanel: function updatePropertiesPanel(layouts) {
- var _this13 = this;
- var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
- var uniqueId = _.uniqueId('eventQueue_');
- this._lastEventId = uniqueId;
- setTimeout(function () {
- //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.
- if (!_this13._isPropertiesPaneOpen()) {
- return;
- }
- _this13.getProperties(layouts).then(function (properties) {
- if (uniqueId === _this13._lastEventId) {
- _this13.contentView.setPropertySpec(properties);
- _this13.contentView.render(true).then(function (propertyUIControlView) {
- if (options.currentScrollTop) {
- propertyUIControlView.el.parentNode.scrollTop = options.currentScrollTop;
- }
- if (options.focusSelector) {
- propertyUIControlView.$el.find(options.focusSelector).focus();
- }
- _this13._updateChildPropertiesSelection();
- });
- }
- });
- }, 0);
- },
- /**
- * Call by the PropertiesPaneDOM instance to get the most recent child panel options to be use to render the child
- * The most recent child is the one that was last pushed onto the _children panel list of this class
- * @param {object} options - the options use to retrieve the most recent child options
- * @return {object} the options to be use to render the child panel
- */
- getMostRecentChildOptions: function getMostRecentChildOptions(options) {
- // 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
- if (!options || options.childPanelId) {
- return options;
- }
- var child = this.getCurrentChild();
- return child && child.options && child.options.childPanelId ? _.clone(child.options) : options;
- },
- /**
- * @param {Object} layouts - The layout whose properties will be displayed.
- * @param {Object} options - options.
- * Note: The setTimeout is here because we need a chance to trigger blur before
- * actually udpate the property panel.
- */
- //TODO: remove this function when the focus mode epic is ready
- _updatePropertiesPane: function _updatePropertiesPane(layouts, options) {
- var _this14 = this;
- var uniqueId = _.uniqueId('eventQueue_');
- this._lastEventId = uniqueId;
- // 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.
- setTimeout(function () {
- if (!_this14.isSlideoutOpen()) {
- //As this is deferred code, the slideout may have closed. Check before continuing.
- return;
- }
- _this14.getProperties(layouts).then(function (properties) {
- if (uniqueId === _this14._lastEventId) {
- _this14._slideout.contentView.setPropertySpec(properties);
- _this14._slideout.contentView.render(true).then(function () {
- if (options && options.focusSelector) {
- _this14._slideout.$el.find(options.focusSelector).focus();
- }
- if (options && options.currentScrollTop) {
- _this14._dashboardPropertiesPane.scrollTop = options.currentScrollTop;
- }
- });
- _this14._updateChildSelection();
- }
- });
- }, 0);
- },
- _getSelectedLayouts: function _getSelectedLayouts(selectedNodes) {
- var _this15 = this;
- var layouts = [];
- selectedNodes.forEach(function (node) {
- if (node._layout) {
- if (node._layout.model && node._layout.model.type === 'group') {
- var children = Utils.getContentWithoutDecoration(node);
- for (var i = 0; i < children.length; i++) {
- $.merge(layouts, _this15._getSelectedLayouts([children[i]]));
- }
- }
- layouts.push(node._layout);
- }
- });
- if (layouts.length === 0) {
- var topLayoutView = this._layoutController.getTopLayoutView();
- if (topLayoutView) {
- layouts.push(topLayoutView);
- }
- }
- return layouts;
- },
- _getSelectedContents: function _getSelectedContents() {
- var canvas = this.dashboard.getCanvas();
- return _.map(canvas.getSelectedWidgets(), function (widget) {
- return canvas.getContent(widget.getId());
- });
- },
- _clearSelectedNodeIds: function _clearSelectedNodeIds() {
- delete this._lastSelectedNodeIds;
- },
- /**
- * If there is an open child, attempts to update the UI selection on it
- */
- _updateChildPropertiesSelection: function _updateChildPropertiesSelection() {
- var child = this.getCurrentChild();
- if (child && child.updateSelection) {
- child.updateSelection();
- }
- },
- /**
- * If there is an open child, attempts to update the UI selection on it
- */
- //TODO: remove this function when the focus mode epic is ready
- _updateChildSelection: function _updateChildSelection() {
- var openChild = this._slideout.child && this._slideout.child.open ? this._slideout.child : null;
- if (openChild && openChild.contentView.updateSelection) {
- openChild.contentView.updateSelection();
- }
- }
- });
- return PropertiesManager;
- });
- //# sourceMappingURL=PropertiesManager.js.map
|