123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194 |
- 'use strict';
- /*
- *+------------------------------------------------------------------------+
- *| Licensed Materials - Property of IBM
- *| IBM Cognos Products: Dashboard
- *| (C) Copyright IBM Corp. 2015, 2021
- *|
- *| US Government Users Restricted Rights - Use, duplication or disclosure
- *| restricted by GSA ADP Schedule Contract with IBM Corp.
- *+------------------------------------------------------------------------+
- */
- define(['./BaseView', 'jquery', 'underscore', '../services/ServicesHelper', '../../app/EventRouter', '../loader/BoardLoader', '../layout/authoring/interaction/ChangeModeAction', '../util/ButtonHideHelper', '../../app/util/ErrorUtils', '../../app/ui/dialogs/EditableDialog', '../../lib/@waca/core-client/js/core-client/utils/PerfUtils', '../../lib/@waca/core-client/js/core-client/ui/KeyCodes', '../services/CanvasExtensions', '../../api/impl/Dashboard', '../../features/dashboard/undoRedo/api/impl/UndoRedo', '../../lib/@waca/dashboard-common/dist/core/APIFactory', '../../lib/@waca/dashboard-common/dist/utils/EventChainLocal', '../../app/nls/StringResources', '../../lib/@waca/dashboard-common/dist/utils/DialogBlocker', '../../extension/Extensions', '../widgets/WidgetRegistry', '../../dashboard/model/BoardModelFactory', '../../lib/@waca/dashboard-common/dist/utils/MemUtil', '../../api/core/glass/GlassDashboardFactory'], function (BaseView, $, _, ServicesHelper, EventRouter, BoardLoader, ChangeModeAction, ButtonHideHelper, ErrorUtils, EditableDialog, PerfUtils, KeyCodes, CanvasExtensions, DashboardController, UndoRedo, APIFactory, EventChainLocal, StringResources, DialogBlocker, Extensions, WidgetRegistry, BoardModelFactory, MemUtil, GlassDashboardFactory) {
- var BaseBoardView = BaseView.extend({
- buttonIds: {
- UNDO: 'com.ibm.bi.dashboard.undo',
- REDO: 'com.ibm.bi.dashboard.redo'
- },
- init: function init(options) {
- BaseBoardView.inherited('init', this, arguments);
- this.dashboardApi = null;
- this.initialize(options);
- if (typeof window.__getDashboardAPI === 'undefined') {
- window.__getDashboardAPI = function () {
- return window.__glassAppController.Glass.getCurrentContentView().getDashboardApi();
- };
- }
- this.firstRender = true;
- },
- initialize: function initialize(options) {
- this._resolveOptions(options);
- _.extend(this, options);
- this.options = options || {};
- var dirtyOption = String(options._isDirty).toLowerCase() === 'true';
- this.options['isDirtyOption'] = dirtyOption;
- this._pressed = {};
- this._boardLoaderClass = options.boardLoaderClass || BoardLoader;
- this.eventRouter = new EventRouter();
- this._buttonHideHelper = options._buttonHideHelper || ButtonHideHelper;
- this._splitterItems = [];
- this._modifiedDataset = [];
- this.upgradesCollectionPath = 'dashboard/upgrades';
- this.logger = options.glassContext.getCoreSvc('.Logger');
- this.$content = null;
- this.widgetRegistry = options.widgetRegistry || new WidgetRegistry();
- this._createController(options);
- this._prepareForRendering(options);
- },
- /**
- * Creates services and extensions required for rendering the dashboard
- * @param {object} options consist of attributes required to create services & extensions for rendering dashboard
- */
- _prepareForRendering: function _prepareForRendering(options) {
- this._createServices();
- // merge the containerApp (API container) configuration with the content options config
- if (options.containerAppOptions) {
- _.extend(this.options.options.config, options.containerAppOptions.configuration);
- }
- // Allow preprocessKeyDown to be both overwritten by an extending class directly or via a call to super
- if (options.preprocessKeyDown) this.preprocessKeyDown = options.preprocessKeyDown;
- this.specHelper = null;
- this.extensions = options.extensions || new Extensions(this.dashboardApi);
- this.boardModelFactory = options.boardModelFactory;
- this.dashboardFactory = new GlassDashboardFactory({
- glassContext: this.glassContext
- });
- },
- _createController: function _createController(options) {
- var DashboardControllerClass = options.overrideDashboardController ? options.overrideDashboardController : DashboardController;
- this.dashboardController = options.dashboardController || new DashboardControllerClass({
- glassContext: this.glassContext,
- view: this,
- services: this.services,
- featureLoader: this.featureLoader,
- eventRouter: this.eventRouter,
- appSettings: this.getContent({
- dirty: this.options.isDirtyOption
- }),
- widgetRegistry: this.widgetRegistry
- });
- if (this.dashboardApi) {
- this.dashboardApi = APIFactory.refreshAPI(this.dashboardApi, [this.dashboardController]);
- this.internalDashboardApi = APIFactory.refreshAPI(this.internalDashboardApi, [this.dashboardController, this.dashboardController.internalImpl]);
- } else {
- this.dashboardApi = this.dashboardController.getAPI();
- this.internalDashboardApi = this.dashboardController.getInternalAPI();
- }
- },
- getApplicationLabel: function getApplicationLabel() {
- return StringResources.get('dashboard');
- },
- getContentNode: function getContentNode() {
- if (this.$content === null) {
- var $contentNode = this.$('.pageViewContent', this.el);
- if ($contentNode.length === 0) {
- $contentNode = $('<div class="pageViewContent"></div>').prependTo(this.el);
- }
- this.$content = $contentNode;
- }
- return this.$content;
- },
- /*
- * Used to a reset dashboard. Save a copy of the board spec as a string.
- */
- setSavedInstance: function setSavedInstance(specString) {
- this.savedInstance = specString;
- },
- getSavedInstance: function getSavedInstance() {
- return this.savedInstance;
- },
- /**
- * Add an object that needs to be reloaded when the dashboard view is reloaded.
- * This is used to reload the data sources panel, properties when the dashboard is reloaded (e.g. relink)
- * @param {string} id A name for the reloadable object
- * @param {object} reloadable An object that has the "reload" method. The "reload" method is required on the object
- */
- addReloadableObject: function addReloadableObject(id, reloadable) {
- if (!this.reloadables) {
- this.reloadables = {};
- }
- // Only add the reloadable if it has the "reload" method
- if (reloadable.reload && typeof reloadable.reload === 'function') {
- this.reloadables[id] = reloadable;
- }
- },
- /*
- * remove and object that was previously added to the reload list
- */
- removeReloadableObject: function removeReloadableObject(id) {
- if (this.reloadables) {
- delete this.reloadables[id];
- }
- },
- /**
- * Important: use a collection to determine if the DatasetExecutionService needs to be setup
- * a better glass API might be required
- */
- _registerDatasetExecution: function _registerDatasetExecution() {
- var _this = this;
- return this.glassContext.appController.findCollection('com.ibm.bi.dashboard.services').then(function (collection) {
- var services = collection || [];
- var setDatasetHandler = false;
- var i = 0;
- while (i < services.length && setDatasetHandler === false) {
- setDatasetHandler = 'com.ibm.bi.dashboard.services.datasetExecutionService' === services[i].id;
- i++;
- }
- if (setDatasetHandler) {
- return _this.glassContext.getSvc('.DatasetExecutionService').then(function (DatasetExecutionService) {
- _this.datasetRefreshEventHandler = DatasetExecutionService.on('loadComplete', _this._onDatasetRefresh.bind(_this));
- });
- }
- });
- },
- _resolveOptions: function _resolveOptions(options) {
- // EmbedAPI param: objRef
- // set a objRef as a boardId
- options.boardId = options.boardId || options.objRef;
- // EmbedAPI param: action
- // convert action to isAuthoringMode flag
- options.isAuthoringMode = this.hasAuthoringCapability() && (String(options.isAuthoringMode).toLowerCase() === 'true' || options.action === 'edit');
- },
- // this method will be called by glass
- isDirty: function isDirty() {
- var dashboardState = this.dashboardApi.getFeature('DashboardState');
- return dashboardState ? dashboardState.getUiState().dirty : this.options.isDirtyOption;
- },
- setPermissions: function setPermissions(permissions) {
- this.permissions = permissions;
- },
- isNew: function isNew() {
- return !this.getBoardId();
- },
- canAuthor: function canAuthor() {
- return _.indexOf(this.permissions, 'write') !== -1;
- },
- getBoardId: function getBoardId() {
- return this.boardModel && this.boardModel.id;
- },
- /**
- * @returns an object containing dashboard information (isDirty, dashboard id and dashboard search path)
- */
- getBoardInfo: function getBoardInfo() {
- return {
- isDirty: this.isDirty(),
- boardId: this.getBoardId(),
- searchPath: this.boardModel.searchPath,
- type: 'exploration'
- };
- },
- /**
- * This method is called by glass to get the content view type which, in turn, be used to match the sharing action handlers.
- * It is overridden in <code>StoryView</code> where the 'storytelling' is returned to match its corresponding action handler.
- */
- getType: function getType() {
- return 'exploration';
- },
- getLoadedWidget: function getLoadedWidget(id) {
- var _boardLoader = this.boardLoader;
- _boardLoader = _boardLoader === undefined ? {} : _boardLoader;
- var widgetLoader = _boardLoader.widgetLoader;
- if (widgetLoader) {
- var widget = widgetLoader.getWidget(id);
- if (widget) {
- return widget.getAPI();
- }
- }
- },
- getContent: function getContent() {
- var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
- var state = _.pick(this.options, 'id', 'objRef', 'options', 'subView', 'filters');
- state.isAuthoringMode = this.isAuthoringMode;
- if (this.options.boardId) {
- state.boardId = this.options.boardId;
- }
- // the glass checks the content id for the cache. This needs to be revisited after the glass cache cleanup
- if (state.objRef) {
- state.id = state.objRef;
- }
- this.id = state.id;
- if (this.boardModel && this.boardModel.id) {
- state.boardId = this.boardModel.id;
- state.id = this.boardModel.id;
- state.objRef = this.boardModel.id;
- this.id = this.boardModel.id;
- }
- var isBookmark = options && options.mode === this.glassContext.bookmarkMode;
- // save a version of the spec when we are not requesting the state for a bookmark
- if (!isBookmark) {
- state.boardSpec = this.options.boardSpec;
- if (this._isDashboardFeatureLoaded('DashboardState')) {
- state._isDirty = this.dashboardApi.getFeature('DashboardState').getUiState().dirty;
- } else {
- state._isDirty = options.dirty;
- }
- if (this._isDashboardFeatureLoaded('Serializer')) {
- state.boardSpec = this.dashboardApi.getFeature('Serializer').toJSON();
- }
- }
- return state;
- },
- _isDashboardFeatureLoaded: function _isDashboardFeatureLoaded(featureName) {
- if (this.dashboardApi) {
- return !!this.dashboardApi.getFeature(featureName);
- }
- return false;
- },
- preprocessKeyDown: function preprocessKeyDown(e) {
- return e;
- }, // overwriteable function, implemented in child classes
- /**
- * @param keyArr {Number | String | Array of numbers/string}
- * @return {Boolean} returns true if and only if specified keys are pressed (ignores cmd/ctrl keys)
- */
- isPressed: function isPressed(keyArr) {
- var _this2 = this;
- var getPressedKeyCodes = _.filter(_.keys(this._pressed), function (key) {
- return _this2._pressed[key] && [KeyCodes.LEFT_WINDOW_KEY, KeyCodes.CTRL, KeyCodes.CAPSLOCK, //filter out CapsLock because Chrome/FireFox only fire keydown event for CapsLock on
- KeyCodes.F11 //filter out F11 for FireFox, it only fire keydown event for f11
- ].indexOf(parseInt(key)) == -1;
- });
- var normalizedKeyArr = keyArr.length ? _.map(keyArr, function (n) {
- return String(n);
- }) : [String(keyArr)];
- return _.isEqual(getPressedKeyCodes, normalizedKeyArr);
- },
- /**
- * @return {Boolean} returns true if and only if any text is selected
- */
- isTextSelected: function isTextSelected() {
- return window.getSelection().toString() !== '';
- },
- getECLProp: function getECLProp(e, key) {
- var eventProps = new EventChainLocal(e);
- return eventProps.getProperty(key);
- },
- hasAuthoringCapability: function hasAuthoringCapability() {
- return true;
- },
- _processKeyDown: function _processKeyDown(e) {
- var _this3 = this;
- e = this.preprocessKeyDown(e);
- if (e.target.tagName && e.target.tagName.match(/input|textarea|select/igm)) {
- return;
- }
- if ($(e.target).closest('[contentEditable=true]').length > 0) {
- return;
- }
- // for FireFox;
- // in FireFox, CapsLock only fire keydown event, no keyup event, so key code 20 will never be remove by _processKeyUp()
- // should be removed when user turn Caps off (like Chrome)
- if (e.keyCode == KeyCodes.CAPSLOCK && this._pressed[KeyCodes.CAPSLOCK]) {
- delete this._pressed[KeyCodes.CAPSLOCK];
- } else {
- this._pressed[e.keyCode] = true;
- }
- var getECLProp = function getECLProp() {
- return _this3.getECLProp(e, 'doNotHandle');
- };
- var canHandleKey = function canHandleKey(arr) {
- if (_this3.isPressed(arr) && !getECLProp()) {
- e.preventDefault();
- return true;
- }
- return false;
- };
- if ((e.ctrlKey || e.metaKey) && !DialogBlocker.isShowingDialogBlocker()) {
- if (canHandleKey(KeyCodes.V)) {
- if (this.isAuthorMode()) {
- // paste functionality
- this.doPaste();
- }
- } else if (canHandleKey(KeyCodes.S)) {
- if (this.hasAuthoringCapability()) {
- this.doSave();
- }
- } else if (canHandleKey(KeyCodes.Y) || canHandleKey([KeyCodes.SHIFT, KeyCodes.Z])) {
- this.doRedo();
- } else if (canHandleKey(KeyCodes.Z)) {
- this.doUndo();
- } else if (canHandleKey([KeyCodes.Q, KeyCodes.FORWARDSLASH])) {
- //brings up message box, used to help debugging
- if (this.hasAuthoringCapability()) {
- this._openBoardSpecificationDialog();
- }
- } else if (canHandleKey([KeyCodes.Q, KeyCodes.L])) {
- //log the Rave test spec to the console
- window.gLogRaveTestSpec = window.gLogRaveTestSpec !== true;
- } else if (!this.isTextSelected() && canHandleKey(KeyCodes.C)) {
- // copy functionality. Does not work for consumer only user when cosumer feature is on
- if (this.hasAuthoringCapability()) {
- this.doCopy();
- }
- } else if (canHandleKey([KeyCodes.Q, KeyCodes.COMMA])) {
- //activate error details
- window.dashboardErrorDetailsEnabled = true;
- this.eventRouter.trigger('widget:onDetailErrors');
- }
- }
- // - The meta key in iOS blockkey up events so in the case of cmd-z/cmd-shift-z/cmd-y/cmd-s
- //the key will never actually be release causing the s, y, and z to be sticky. This is why
- //in case of the meta key they need to be release here.
- // - for multi-key combo possibilities hold off on manually triggering keyup
- if (e.metaKey && e.keyCode !== KeyCodes.Q && e.keyCode !== KeyCodes.SHIFT) {
- delete this._pressed[e.keyCode];
- }
- },
- _openBoardSpecificationDialog: function _openBoardSpecificationDialog() {
- new EditableDialog({
- sType: 'editableInfo',
- sTitle: 'Board Specification',
- sValue: JSON.stringify(this.dashboardApi.getFeature('Serializer').toJSON(), null, 4),
- actionHandler: this._updateBoardModelFromDialog.bind(this),
- updateable: true
- }).open();
- },
- /**
- * Handler function for board model dialog to get and parse new board spec, which then updates the canvas to match the board spec
- * @returns True if JSON is valid and false if not
- */
- _updateBoardModelFromDialog: function _updateBoardModelFromDialog(newBoardModelString) {
- // Parse JSON of board model spec the user entered. Do not handle if it is bad JSON
- try {
- this.reloadFromJSONSpec(JSON.parse(newBoardModelString));
- } catch (err) {
- this.logger.debug('Invalid JSON provided', err, this);
- this.glassContext.appController.showToast(this.stringService.get('invalidJSONResponse'), {
- 'type': 'error',
- 'preventDuplicates': true
- });
- return false;
- }
- return true;
- },
- doCopy: function doCopy() {
- return this.boardController.copyPasteController.doCopy();
- },
- doPaste: function doPaste() {
- return this.boardController.copyPasteController.doPaste();
- },
- _processKeyUp: function _processKeyUp() {
- this._pressed = {};
- },
- doSave: function doSave() {
- var savePlugin = this.glassContext.appController.findPlugin('com.ibm.bi.dashboard.saveMenu');
- if (savePlugin) {
- savePlugin.defaultButton.$el.trigger('click');
- }
- },
- doUndo: function doUndo() {
- var popover = $('.popover');
- if (popover.length > 0) {
- popover.popover('hide'); // remove popovers, they aren't updated on undo/redo and aren't cleared when clicking in the Glass buttons.
- }
- this.boardController.undoRedoController.undo();
- },
- doRedo: function doRedo() {
- var popover = $('.popover');
- if (popover.length > 0) {
- popover.popover('hide'); // remove popovers, they aren't updated on undo/redo and aren't cleared when clicking in the Glass buttons.
- }
- this.boardController.undoRedoController.redo();
- },
- _onWidgetMaximize: function _onWidgetMaximize() {
- this._buttonHideHelper.changeMode(this.glassContext, 'widgetMaximized');
- },
- _onWidgetRestore: function _onWidgetRestore() {
- this._buttonHideHelper.changeMode(this.glassContext, this.dashboardController.getMode());
- },
- /**
- * Toggles the event group mode.
- * @param {String} mode The optional mode to explicitly toggle to (default: 'authoring')
- */
- toggleEventGroupMode: function toggleEventGroupMode(mode) {
- var isEventGroupViewMode = this.isEventGroupViewMode;
- if (isEventGroupViewMode) {
- if (mode !== 'eventGroups') {
- // this._buttonHideHelper.changeMode(this.glassContext, mode || 'authoring');
- return this.turnOffEventGroupView(mode);
- } else {
- // we are already in eventGroup mode
- return Promise.resolve();
- }
- } else {
- this._buttonHideHelper.changeMode(this.glassContext, mode);
- return this.turnOnEventGroupView();
- }
- },
- /**
- * Toggles between authoring & consume mode
- */
- toggleMode: function toggleMode(options) {
- var _this4 = this;
- // clear data sources cache
- var dataSourcesSvc = this.dashboardApi.getFeature('dataSources.deprecated');
- if (dataSourcesSvc) {
- dataSourcesSvc.clearShapingCache();
- }
- return (this.isAuthoringMode ? this.turnOffEditMode() : this.turnOnEditMode()).then(function () {
- _this4._finishModeChange(options);
- });
- },
- _addChangeModeActionToUndoRedoStack: function _addChangeModeActionToUndoRedoStack(options) {
- if (!options || options.sender !== 'UndoRedoController') {
- this.boardController.undoRedoController.addToUndoRedoStack(new ChangeModeAction(this, {
- glassContext: this.glassContext
- }));
- }
- },
- _triggerWindowResize: function _triggerWindowResize() {
- try {
- $(window).resize();
- } catch (e) {
- console.error(e);
- }
- },
- _finishModeChange: function _finishModeChange() {
- var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
- // We are switching to authoring mode.
- this.eventRouter.trigger('mode:change', {
- authoring: this.isAuthoringMode,
- isStoryMode: this.options.isStoryMode
- });
- // dont add if options.addToUndoRedoStack is false
- if (options.addToUndoRedoStack !== false) {
- // avoid infinite undo
- this._addChangeModeActionToUndoRedoStack(options);
- }
- // Resize to redraw the visualization because the canvas will change in size between consumption and edit mode
- // This also re-renders the grid
- this._triggerWindowResize();
- },
- isAuthorMode: function isAuthorMode() {
- return !!this.isAuthoringMode;
- },
- turnOnEditMode: function turnOnEditMode() {
- var _this5 = this;
- this.isAuthoringMode = true;
- return this.lifeCycleManager.invokeLifeCycleHandlers('pre:mode.edit').then(this.boardController.changeToAuthorMode.bind(this.boardController)).then(function () {
- // check for group view mode in authoring mode
- var isEventGroupViewMode = _this5.isEventGroupViewMode;
- if (isEventGroupViewMode) {
- return _this5.turnOnEventGroupView().then(_this5.applyModeToGlassPlugins.bind(_this5));
- } else {
- _this5.applyModeToGlassPlugins();
- }
- }).then(this.lifeCycleManager.invokeLifeCycleHandlers.bind(this.lifeCycleManager, 'post:mode.edit'));
- },
- turnOffEditMode: function turnOffEditMode() {
- this.isAuthoringMode = false;
- return this.lifeCycleManager.invokeLifeCycleHandlers('pre:mode.consume').then(this.boardController.changeToConsumeMode.bind(this.boardController)).then(this.applyModeToGlassPlugins.bind(this)).then(this.lifeCycleManager.invokeLifeCycleHandlers.bind(this.lifeCycleManager, 'post:mode.consume'));
- },
- turnOnEventGroupView: function turnOnEventGroupView() {
- var _this6 = this;
- this.isEventGroupViewMode = true;
- this.isAuthoringMode = true;
- this.boardController.undoRedoController.setMode('eventGroups');
- return this.boardController.changeToEventGroupMode().then(function () {
- _this6.applyModeToGlassPlugins();
- });
- },
- turnOffEventGroupView: function turnOffEventGroupView(mode) {
- var _this7 = this;
- this.isEventGroupViewMode = false;
- this.boardController.undoRedoController.setMode(null);
- var consumptionMode = mode === 'consumption';
- return (consumptionMode ? this.turnOffEditMode() : this.turnOnEditMode()).then(function () {
- return _this7._finishModeChange({
- addToUndoRedoStack: consumptionMode
- });
- });
- },
- applyModeToGlassPlugins: function applyModeToGlassPlugins() {
- if (this.isAuthoringMode) {
- if (this.isEventGroupViewMode) {
- this._buttonHideHelper.changeMode(this.glassContext, 'connections', this.options);
- } else {
- this._buttonHideHelper.changeMode(this.glassContext, 'authoring', this.options);
- }
- } else {
- this._buttonHideHelper.changeMode(this.glassContext, 'consume', this.options);
- }
- },
- _createServices: function _createServices() {
- this.servicesHelper = new ServicesHelper({
- glassContext: this.glassContext,
- eventRouter: this.eventRouter,
- appSettings: this.getContent(),
- logger: this.logger,
- dashboardAPI: this.dashboardApi,
- internalDashboardAPI: this.internalDashboardApi
- });
- var dashboardServices = this.servicesHelper.createServices();
- this.stringService = dashboardServices.stringService;
- this.lifeCycleManager = dashboardServices.lifeCycleManager;
- this.dnDManager = dashboardServices.dnDManager;
- this.services = dashboardServices.serviceRegistry;
- this.featureLoader = dashboardServices.featureLoader;
- this.dashboardController.setServices(this.services);
- this.dashboardController.setFeatureLoader(this.featureLoader);
- },
- getDeprecatedCanvas: function getDeprecatedCanvas() {
- if (this.boardController) {
- return this.boardController.getDeprecatedCanvas();
- }
- return null;
- },
- getDeprecatedCanvasWhenReady: function getDeprecatedCanvasWhenReady() {
- var _this8 = this;
- if (this._boardRendered) {
- return this._boardRendered.then(function () {
- return _this8.boardController.getDeprecatedCanvas();
- });
- }
- return Promise.reject(new Error('Unable to getCanvas . Board is not rendered yet.'));
- },
- /**
- * NOTE: This is overridden in other components such as Explore.
- *
- * @returns whether the user has the dashboard capability or not.
- */
- hasCapability: function hasCapability() {
- return ErrorUtils.hasCapability(this.glassContext);
- },
- _registerBootstrapFeatures: function _registerBootstrapFeatures() {
- var featureLoader = this.dashboardController.featureLoader;
- return this.dashboardFactory.getBootstrapFeatures().then(function (features) {
- Object.keys(features).forEach(function (featureName) {
- featureLoader.registerFeature(featureName, features[featureName], undefined, true);
- });
- });
- },
- render: function render() {
- var _this9 = this;
- BaseBoardView.inherited('render', this, arguments);
- this.$el.addClass('boardPageView');
- // Todo -- lifecycle_cleanup -- we shouldn't have to do this
- // This will create the content node .. if not done here, the toolbar will be at the bottom of the page
- // because it will be created before the content node
- this.getContentNode();
- if (!this.hasCapability()) {
- return Promise.reject({
- code: 'noCapability',
- message: this.stringService.get('noDashboardCapability')
- });
- }
- this.setupKeyboardHandlers();
- this.ajaxSvc = this.glassContext.getCoreSvc('.Ajax');
- var isAuthoringMode = this.isAuthoringMode;
- this.eventRouter.on('widget:maximize', this._onWidgetMaximize, this);
- this.eventRouter.on('widget:restore', this._onWidgetRestore, this);
- PerfUtils.createPerformanceMark({
- 'component': 'dashboard',
- 'name': 'LoadBoard',
- 'state': 'start'
- });
- this.boardModelFactory = this.boardModelFactory || new BoardModelFactory({
- dashboardAPI: this.dashboardApi,
- glassContext: this.glassContext,
- boardId: this.boardId,
- objectUrl: this.objectUrl,
- boardSpec: this.boardSpec,
- widgetRegistry: this.widgetRegistry,
- extensions: this.extensions,
- stringResources: this.dashboardApi.getDashboardCoreSvc('.StringResources'),
- eventRouter: this.eventRouter,
- logger: this.logger,
- createLayoutModel: this.createLayoutModel
- });
- this._boardRendered = this._registerBootstrapFeatures().then(this.extensions.load.bind(this.extensions)).then(this.widgetRegistry.initialize.bind(this.widgetRegistry, this.dashboardApi)).then(this.boardModelFactory.createBoardModel.bind(this.boardModelFactory)).then(function (boardModelInfo) {
- _this9.boardModel = boardModelInfo.boardModel;
- _this9.boardSpec = boardModelInfo.boardSpec;
- _this9.boardId = boardModelInfo.boardId;
- }).then(this.glassContext.appController.findCollection.bind(this.glassContext.appController, 'com.ibm.bi.dashboard.templates')).then(function (templateItems) {
- return _this9.glassContext.appController.findCollection('com.ibm.bi.dashboard.contentTypes').then(function (contentTypes) {
- return _this9.servicesHelper.createRuntimeServices({
- dashboardApi: _this9.getDashboardApi(),
- collections: {
- templates: templateItems,
- contentTypes: contentTypes
- }
- });
- });
- }).then(this._registerDatasetExecution.bind(this)).then(function () {
- _this9.boardLoader = new _this9._boardLoaderClass({
- // beging - To be removed
- glassContext: _this9.glassContext,
- isAuthoringMode: isAuthoringMode,
- services: _this9.services,
- ajaxSvc: _this9.ajaxSvc,
- appSettings: _this9.getContent(),
- // end - To be removed
- dashboardApi: _this9.getDashboardApi(),
- eventRouter: _this9.eventRouter,
- setDirty: _this9.boardModel.isUpgraded,
- //TOOO maybe remove
- boardSpec: _this9.boardSpec,
- boardModel: _this9.boardModel,
- el: _this9.getContentNode()[0],
- $viewEl: _this9.$el,
- widgetRegistry: _this9.widgetRegistry,
- gatewayUrl: 'v1',
- cdnUrl: _this9.getCDNUrl(),
- featureLoader: _this9.featureLoader,
- extensions: _this9.extensions,
- dashboardController: _this9.dashboardController
- });
- return _this9.boardLoader.loadBoard();
- }).then(function () {
- return _this9.boardLoader.getCanvasController().then(function (canvasController) {
- _this9.boardController = canvasController;
- });
- }).then(function () {
- _this9.canUndo = false;
- _this9.canRedo = false;
- _this9.applyModeToGlassPlugins();
- _this9._registerUndoRedoListener(_this9.buttonIds.UNDO);
- _this9._registerUndoRedoListener(_this9.buttonIds.REDO);
- _this9.boardModel.on('change:name', _this9._onNameChange, _this9);
- _this9.boardModel.on('all', _this9._onAllModelEvents, _this9);
- _this9.dashboardApi.getCanvas().on('all', _this9._manageDirtyFlagForCanvasEvents.bind(_this9));
- _this9.boardController.onPageRenderComplete().then(function () {
- PerfUtils.createPerformanceMark({
- 'component': 'dashboard',
- 'name': 'LoadBoard',
- 'state': 'end'
- });
- });
- if (_this9.containerAppOptions && _this9.containerAppOptions.callbacks) {
- _this9.containerAppOptions.callbacks.resolve(_this9.getDashboardApi());
- }
- _this9.canvasExtensions = new CanvasExtensions({
- topNode: _this9.getCanvasExtensionsTopNode(),
- bottomNode: _this9.getCanvasExtensionsBottomNode(),
- splitterItems: _this9._splitterItems,
- canvasExtensions: _this9.extensions.getCanvasExtensions() || [],
- dashboardApi: _this9.getDashboardApi(),
- services: _this9.services,
- eventRouter: _this9.eventRouter,
- appSettings: _this9.getContent(),
- handlers: {
- getParentSize: function getParentSize() {
- return {
- height: _this9.$el.height(),
- width: _this9.$el.width()
- };
- },
- isAuthorMode: _this9.isAuthorMode.bind(_this9),
- getSplitterState: _this9.getSplitterState.bind(_this9)
- }
- });
- _this9.services.register('.CanvasExtensions', _this9.canvasExtensions);
- _this9.services.register('.CopyPasteController', _this9.boardController.copyPasteController);
- _this9.featureLoader.registerFeature('UndoRedo', new UndoRedo(_this9.boardController.undoRedoController));
- if (_this9.firstRender) {
- var dashboardState = _this9.dashboardApi.getFeature('DashboardState');
- dashboardState.setDirty(_this9.options.isDirtyOption);
- _this9.firstRender = false;
- }
- // The dashboard is not saved yet
- if (!_this9.getBoardId() || _this9.boardLoader.setDirty) {
- var _dashboardState = _this9.dashboardApi.getFeature('DashboardState');
- _dashboardState.setDirty(true);
- if (!_this9.getBoardId()) {
- _this9.title = _this9.stringService.get('defaultName');
- }
- _this9.boardLoader.setDirty = false;
- } else {
- _this9.title = _this9.getTitle();
- }
- _this9.dashboardApi.getFeature('DashboardState').setActive(true);
- _this9.logger.debug('Authored View created', _this9.options, _this9);
- _this9.onCanvasReady();
- // Waiting for pageReady causes issues with the glass not showing the page at the right time.
- return _this9.boardController.onPageReady().then(function () {
- if (_this9.sources) {
- var dataSourcesFeature = _this9.dashboardApi.getFeature('DataSources');
- _this9.sources.forEach(function (source) {
- return dataSourcesFeature.addDataSource(source, false, {
- silent: true,
- payloadData: {
- skipUndoRedo: true
- }
- });
- });
- // Once we've added the initial source to the dataSources feature, clear the property so we don't readd them during a relink
- _this9.options.sources = _this9.sources = null;
- }
- var printFeature = _this9.dashboardApi.getFeature('Print');
- var dashboardPrint = _this9.dashboardApi.getFeature('DashboardPrint');
- printFeature.registerContent('tab', dashboardPrint);
- printFeature.registerContent('page', dashboardPrint);
- }).then(function () {
- return _this9.canvasExtensions.render();
- }).then(function () {
- return undefined;
- });
- });
- return this._boardRendered.catch(function (e) {
- if (_this9.logger) {
- _this9.logger.log('An error occured while rendering the baseBoardView');
- _this9.logger.error(e);
- }
- throw e;
- });
- },
- getSplitterState: function getSplitterState() {
- // to be implemented by the concrete class
- },
- _onNameChange: function _onNameChange(event) {
- this.trigger('change:title', event);
- this.title = event.value;
- },
- _onAllModelEvents: function _onAllModelEvents(event) {
- // This is done so that the edit button does not trigger the dirty flag
- var isUndoRedo = event && (event.stack === 'undo' || event.stack === 'redo');
- var isRuntimeChange = event && event.data && event.data.runtimeOnly;
- var isEventGroupsChange = !this.isAuthoringMode && event && event.eventName && event.eventName === 'change:eventGroups';
- var skipUndoRedo = event && event.data && event.data.skipUndoRedo;
- var dashboardState = this.dashboardApi.getFeature('DashboardState');
- if (!isRuntimeChange && !isEventGroupsChange) {
- var _dashboardState$getUi = dashboardState.getUiState(),
- dirty = _dashboardState$getUi.dirty;
- if (!isUndoRedo && !dirty && !skipUndoRedo) {
- dashboardState.setDirty(true);
- } else if (isUndoRedo) {
- var isUndoRedoDirty = this.boardController.undoRedoController.isDirty();
- if (dirty && !isUndoRedoDirty) {
- dashboardState.setDirty(false);
- } else if (!dirty && isUndoRedoDirty) {
- dashboardState.setDirty(true);
- }
- }
- }
- },
- _manageDirtyFlagForCanvasEvents: function _manageDirtyFlagForCanvasEvents(event) {
- if (event.info && event.info.supportsUndoRedo && event.context && event.context.undoRedo !== true) {
- if (!this.isDirty()) {
- var dashboardState = this.dashboardApi.getFeature('DashboardState');
- dashboardState.setDirty(true);
- }
- }
- },
- getCanvasExtensionsTopNode: function getCanvasExtensionsTopNode() {
- if (!this.$top) {
- var $parentNode = this.getContentNode();
- var $top = $('.canvasExtensionTop', $parentNode);
- if ($top.length === 0) {
- $top = $('<div class="canvasExtensionTop"></div>');
- $parentNode.prepend($top);
- }
- this.$top = $top;
- }
- return this.$top;
- },
- getCanvasExtensionsBottomNode: function getCanvasExtensionsBottomNode() {
- if (!this.$bottom) {
- var $bottom = $('.canvasExtensionBottom', this.el);
- if ($bottom.length === 0) {
- $bottom = $('<div class="canvasExtensionBottom"></div>');
- this.$el.append($bottom);
- }
- this.$bottom = $bottom;
- }
- return this.$bottom;
- },
- getDashboardApi: function getDashboardApi() {
- return this.dashboardApi;
- },
- onCanvasReady: function onCanvasReady() {
- // to be implemented by the concrete class
- },
- _registerUndoRedoListener: function _registerUndoRedoListener(id) {
- var plugin = this.glassContext.appController.findPlugin(id);
- if (plugin) {
- this.boardController.undoRedoController.addListener(id, plugin);
- }
- },
- remove: function remove() {
- BaseBoardView.inherited('remove', this, arguments);
- this.teardownKeyboardHandlers();
- this.eventRouter.off('widget:maximize', this._onWidgetMaximize, this);
- this.eventRouter.off('widget:restore', this._onWidgetRestore, this);
- // Destroy the view before the services and APIs
- try {
- this.boardLoader.destroyViews();
- } catch (e) {
- if (this.logger) {
- this.logger.error(e);
- }
- }
- try {
- this.boardLoader.destroyCanvasAPI();
- } catch (e) {
- if (this.logger) {
- this.logger.error(e);
- }
- }
- if (this.datasetRefreshEventHandler) {
- this.datasetRefreshEventHandler.remove();
- }
- this.boardLoader = null;
- this.dashboardController.destroy();
- MemUtil.destroy(this);
- },
- getTitle: function getTitle() {
- return this.boardModel && this.boardModel.get('name') || '';
- },
- setTitle: function setTitle(title) {
- this.title = title;
- this.trigger('change:title', { value: title });
- },
- openDatasetpane: function openDatasetpane() {
- var plugin = this.glassContext.appController.findPlugin('com.ibm.bi.dashboard.dataSources.sourcesBtn');
- if (plugin && !plugin.isPressed()) {
- plugin.$el.trigger('click', {
- expandFirstEntry: true
- });
- }
- },
- setupKeyboardHandlers: function setupKeyboardHandlers() {
- if (!this._keyDownBind) {
- this._keyDownBind = this._processKeyDown.bind(this);
- this._keyUpBind = this._processKeyUp.bind(this);
- this._windowBlur = this._processKeyUp.bind(this);
- $(document).on('keydown', this._keyDownBind);
- $(document).on('keyup', this._keyUpBind);
- $(window).on('blur', this._windowBlur);
- }
- },
- teardownKeyboardHandlers: function teardownKeyboardHandlers() {
- $(document).off('keydown', this._keyDownBind);
- $(document).off('keyup', this._keyUpBind);
- $(window).off('blur', this._windowBlur);
- this._keyDownBind = null;
- this._keyUpBind = null;
- this._windowBlur = null;
- },
- _onDatasetRefresh: function _onDatasetRefresh(payload) {
- this._modifiedDataset.push(payload.id);
- },
- /**
- * Called by the glass when the view is deactivated (e.g. switching to a different view)
- */
- deactivate: function deactivate() {
- // CADBC-892 dashboard state may not be available in hardnav scenarios
- var dashboardState = this.dashboardApi.getFeature('DashboardState');
- dashboardState && dashboardState.setActive(false);
- if (this.boardLoader) {
- this.boardLoader.deactivate();
- }
- this.teardownKeyboardHandlers();
- if (this.canvasExtensions) {
- this.canvasExtensionState = this.canvasExtensions.getState();
- }
- this.dashboardApi.triggerDashboardEvent('dashboard:deactivate');
- return BaseBoardView.inherited('deactivate', this, arguments);
- },
- /**
- * Called by the glass just before the view is being shown
- * @param {Object} content - content object from Glass. { perspective: xx, id: xx, content:xx }
- */
- activate: function activate(content) {
- var _this10 = this;
- this.dashboardApi.getFeature('DashboardState').setActive(true);
- if (!this.boardLoader) {
- this.setupKeyboardHandlers();
- return BaseBoardView.inherited('activate', this, [content]);
- }
- var always = function always() {
- var promise = _this10.boardLoader.activate();
- if (!promise || !promise.then) {
- promise = Promise.resolve();
- }
- return promise.then(function () {
- _this10.dashboardApi.triggerDashboardEvent('dashboard:show');
- return _this10.setupKeyboardHandlers();
- });
- };
- return BaseBoardView.inherited('activate', this, [content]).then(function () {
- // Before activating the dashboard view, check if any data source is changed, in which case we need to
- // reload metadata and re-execute widgets
- var result = void 0;
- if (_this10._modifiedDataset.length > 0) {
- result = _this10._refreshDataSource().then(function () {
- _this10._modifiedDataset = [];
- });
- } else {
- result = Promise.resolve();
- }
- _this10.canvasExtensions.setState(_this10.canvasExtensionState);
- return result;
- }).then(always).catch(always);
- },
- /**
- * Refresh datasources that are referenced in dashboard and were modified
- */
- _refreshDataSource: function _refreshDataSource() {
- var _this11 = this;
- var dataSourcesSvc = this.dashboardApi.getFeature('dataSources.deprecated');
- var sourcesCollection = dataSourcesSvc.getSourcesCollection();
- var aDataSources = sourcesCollection.getSources();
- var datasourcePromises = [];
- _.each(aDataSources, function (source) {
- if (_this11._modifiedDataset.indexOf(source.getAssetId()) >= 0) {
- datasourcePromises.push(source.reloadMetadata());
- }
- });
- return Promise.all(datasourcePromises);
- },
- _removeForReload: function _removeForReload() {
- this.teardownKeyboardHandlers();
- this.boardLoader.destroyViews();
- this.boardLoader.destroyCanvasAPI();
- this.boardLoader = null;
- if (this.datasetRefreshEventHandler) {
- this.datasetRefreshEventHandler.remove();
- }
- if (this.services) {
- this.services.destroy();
- }
- this.dashboardApi.destroy();
- this.dashboardApi = null;
- this.boardModel = null;
- this.$el.empty();
- this.$bottom = null;
- this.$top = null;
- },
- reloadFromJSONSpec: function reloadFromJSONSpec(JSONSpec) {
- var _this12 = this;
- var extOptions = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
- var isAuthoringMode = extOptions.isAuthoringMode,
- _extOptions$clearDirt = extOptions.clearDirtyFlag,
- clearDirtyFlag = _extOptions$clearDirt === undefined ? false : _extOptions$clearDirt;
- this.dashboardController.toggleProperties(false);
- this._removeForReload();
- var options = this.options;
- options.boardSpec = JSONSpec;
- options.isAuthoringMode = typeof isAuthoringMode !== 'undefined' ? isAuthoringMode : this.isAuthoringMode;
- if (extOptions.boardId) {
- options.boardId = extOptions.boardId; //Reload from JSON Spec with passed in board ID
- }
- this.initialize(options);
- return this.render().then(function () {
- if (_this12.reloadables) {
- Object.values(_this12.reloadables).filter(function (reloadable) {
- return typeof reloadable.reload === 'function';
- }).forEach(function (reloadable) {
- return reloadable.reload();
- });
- }
- _this12.setFocus();
- // Reset the flag, otherwise the current flag state propagates
- var dashboardState = _this12.dashboardApi.getFeature('DashboardState');
- if (clearDirtyFlag && !_this12.boardLoader.setDirty) {
- dashboardState.setDirty(false);
- } else {
- dashboardState.setDirty(true);
- }
- return _this12.dashboardApi;
- });
- },
- /**
- * Temp until glass provides us with an official API to know when we're visible.
- * @return {[type]} [description]
- */
- setFocus: function setFocus() {
- var _this13 = this;
- BaseBoardView.inherited('setFocus', this, arguments);
- this.lifeCycleManager.invokeLifeCycleHandlers('pre:dashboard.focus').then(this.boardLoader.getCanvasController.bind(this.boardLoader)).then(function (canvasController) {
- return canvasController.layoutController.getTopLayoutViewWhenReady();
- }).then(function (layoutView) {
- // Call onShow which will do nothing if they had already rendered or make them render correctly
- if (layoutView) {
- layoutView.onShow();
- }
- return _this13.lifeCycleManager.invokeLifeCycleHandlers('post:dashboard.focus');
- }).catch(function (err) {
- _this13.logger.error('Failed to setFocus', err, _this13);
- });
- }
- });
- return BaseBoardView;
- });
- //# sourceMappingURL=BaseBoardView.js.map
|