All Downloads are FREE. Search and download functionalities are using the official Maven repository.

scout.desktop.outline.Outline.js Maven / Gradle / Ivy

There is a newer version: 25.1.0-beta.0
Show newest version
/*******************************************************************************
 * Copyright (c) 2014-2015 BSI Business Systems Integration AG.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     BSI Business Systems Integration AG - initial API and implementation
 ******************************************************************************/
scout.Outline = function() {
  scout.Outline.parent.call(this);
  this._addAdapterProperties(['defaultDetailForm', 'views', 'dialogs', 'messageBoxes', 'fileChoosers']);
  this.navigateUpInProgress = false; // see NavigateUpButton.js
  this._additionalContainerClasses += ' outline';
  this._treeItemPaddingLeft = 37;
  this._treeItemPaddingLevel = 20;
  this._detailTableListener;
  this.inBackground = false;
  this.embedDetailContent = false;
  this.compact = false;
  this.formController;
  this.messageBoxController;
  this.fileChooserController;
  this._nodeIdToRowMap = {};
  this._scrolldirections = 'y';
};
scout.inherits(scout.Outline, scout.Tree);

scout.Outline.prototype._init = function(model) {
  //add filter before first traversal of tree-> tree is only traversed once.
  this.addFilter(new scout.DetailTableTreeFilter(), true);
  scout.Outline.parent.prototype._init.call(this, model);

  this.formController = new scout.FormController(this, this.session);
  this.messageBoxController = new scout.MessageBoxController(this, this.session);
  this.fileChooserController = new scout.FileChooserController(this, this.session);
  this.titleVisible = true;
  this._syncDefaultDetailForm(this.defaultDetailForm);
  this.titleMenuBar = scout.create('MenuBar', {
    parent: this,
    menuOrder: new scout.GroupBoxMenuItemsOrder()
  });
  this._updateTitleMenuBar();
  this.nodeMenuBar = scout.create('MenuBar', {
    parent: this,
    menuOrder: new scout.GroupBoxMenuItemsOrder()
  });
  this.nodeMenuBar.bottom();
  this.detailMenuBar = scout.create('MenuBar', {
    parent: this,
    menuOrder: new scout.GroupBoxMenuItemsOrder()
  });
  this.detailMenuBar.bottom();
  this.updateDetailContent();
};

scout.Outline.prototype._createKeyStrokeContext = function() {
  return new scout.OutlineKeyStrokeContext(this);
};

scout.Outline.prototype._filterMenus = function(menus, destination, onlyVisible, enableDisableKeyStroke) {
  //show no contextmenues
  return [];
};

/**
 * @override Tree.js
 */
scout.Outline.prototype._initTreeKeyStrokeContext = function(keyStrokeContext) {
  var modifierBitMask = scout.keyStrokeModifier.CTRL | scout.keyStrokeModifier.SHIFT;

  keyStrokeContext.registerKeyStroke([
    new scout.TreeNavigationUpKeyStroke(this, modifierBitMask),
    new scout.TreeNavigationDownKeyStroke(this, modifierBitMask),
    new scout.OutlineNavigateToTopKeyStroke(this, modifierBitMask),
    new scout.TreeNavigationEndKeyStroke(this, modifierBitMask),
    new scout.TreeCollapseOrDrillUpKeyStroke(this, modifierBitMask),
    new scout.TreeExpandOrDrillDownKeyStroke(this, modifierBitMask)
  ]);

  keyStrokeContext.$bindTarget = function() {
    return this.session.$entryPoint;
  }.bind(this);
};

/**
 * @override
 */
scout.Outline.prototype._render = function($parent) {
  scout.Outline.parent.prototype._render.call(this, $parent);

  // Override layout
  this.htmlComp.setLayout(new scout.OutlineLayout(this));
  this._renderCompact();
  this._renderEmbedDetailContent();
  this._renderDetailContent();
  this._renderDetailMenuBarVisible();
  this._renderNodeMenuBarVisible();
};

scout.Outline.prototype._renderProperties = function() {
  this._renderTitleVisible();
  scout.Outline.parent.prototype._renderProperties.call(this);
};

/**
 * @override
 */
scout.Outline.prototype._remove = function() {
  scout.Outline.parent.prototype._remove.call(this);
  this._removeTitle();
};

scout.Outline.prototype._renderTitle = function() {
  if (!this.$title) {
    this.$title = this.$container.prependDiv('outline-title');
    this.$titleText = this.$title.prependDiv('outline-title-text');
  }
  this.$titleText.text(this.title).on('click', this._onTitleClick.bind(this));
  this._renderTitleMenuBar();
};

scout.Outline.prototype._renderTitleMenuBar = function() {
  if (this.$title) {
    this.titleMenuBar.render(this.$title);
    this.titleMenuBar.$container.toggleClass('prevent-initial-focus', true);
  }
};

scout.Outline.prototype._removeTitleMenuBar = function() {
  this.titleMenuBar.remove();
};

scout.Outline.prototype._removeTitle = function() {
  if (this.$title) {
    this.$title.remove();
    this.$title = null;
    this._removeTitleMenuBar();
  }
};

scout.Outline.prototype.setTitleVisible = function(visible) {
  this.titleVisible = visible;
  if (this.rendered) {
    this._renderTitleVisible();
  }
};

scout.Outline.prototype._renderTitleVisible = function() {
  if (this.titleVisible) {
    this._renderTitle();
  } else {
    this._removeTitle();
  }
};

scout.Outline.prototype._postRender = function() {
  //used to render glasspane
  this.trigger('rendered');
  scout.Outline.parent.prototype._postRender.call(this);
};

/**
 * @override
 */
scout.Outline.prototype._renderEnabled = function() {
  scout.Outline.parent.prototype._renderEnabled.call(this);
  this.$container.setTabbable(false);
};

/**
 * @override
 */
scout.Outline.prototype._initTreeNodeInternal = function(node, parentNode) {
  scout.Outline.parent.prototype._initTreeNodeInternal.call(this, node, parentNode);
  node.detailFormVisibleByUi = true;
  if (node.detailTable) {
    node.detailTable = this.session.getOrCreateModelAdapter(node.detailTable, this);
    this._initDetailTable(node);
  }
  if (node.detailForm) {
    node.detailForm = this.session.getOrCreateModelAdapter(node.detailForm, this);
    this._initDetailForm(node);
  }

  if (node.parentNode && node.parentNode.detailTable) {
    // link node with row, if it hasn't been linked yet
    if (node.id in this._nodeIdToRowMap) {
      node.row = this._nodeIdToRowMap[node.id];
      if (!node.row) {
        throw new Error('node.row is not defined');
      }
      delete this._nodeIdToRowMap[node.id];
    }
  }
};

scout.Outline.prototype._initDetailTable = function(node) {
  var that = this;

  if (this.navigateButtonsVisible) {
    this._appendNavigateButtonsForDetailTable(node);
  }

  // link already existing rows (rows which are inserted later are linked by _onDetailTableRowInitialized)
  node.detailTable.rows.forEach(function(row) {
    this._linkNodeWithRow(row);
  }, this);

  this._detailTableListener = {
    func: function(event) {
      event.detailTable = node.detailTable;
      that._onDetailTableEvent(event);
    }
  };
  node.detailTable.events.addListener(this._detailTableListener);
};

scout.Outline.prototype._initDetailForm = function(node) {
  if (this.navigateButtonsVisible) {
    this._appendNavigateButtonsForDetailForm(node);
  }

  // Mark form as detail form
  node.detailForm.detailForm = true;

  node.detailForm.one('destroy', function() {
    // Unlink detail form if it was closed. May happen in the following case:
    // The form gets closed on execPageDeactivated. No pageChanged event will
    // be fired because the deactivated page is not selected anymore.
    node.detailForm = null;
    // Also make sure other objects hold no reference to a destroyed form (e.g. bench)
    this._triggerPageChanged(node);
  }.bind(this));
};

scout.Outline.prototype._linkNodeWithRow = function(row) {
  var node = this.nodesMap[row.nodeId];
  if (node) {
    node.row = row;
    if (!node.row) {
      throw new Error('node.row is not defined');
    }
  } else {
    // Prepare for linking later because node has not been inserted yet
    this._nodeIdToRowMap[row.nodeId] = row;
  }
};

/**
 * @override
 */
scout.Outline.prototype._decorateNode = function(node) {
  scout.Outline.parent.prototype._decorateNode.call(this, node);
  scout.inspector.applyInfo(node, node.$node);
};

scout.Outline.prototype._createNavigateButtons = function(node, staticMenus) {
  var menus = scout.arrays.ensure(staticMenus);
  if (!this._hasMenu(menus, scout.NavigateUpButton)) {
    var upButton = scout.create('NavigateUpButton', {
      parent: this,
      outline: this,
      node: node
    });
    menus.push(upButton);
  }
  if (!this._hasMenu(menus, scout.NavigateDownButton)) {
    var downButton = scout.create('NavigateDownButton', {
      parent: this,
      outline: this,
      node: node
    });
    menus.push(downButton);
  }
  return menus;
};

scout.Outline.prototype._getMenu = function(menus, menuClass) {
  for (var i = 0; i < menus.length; i++) {
    if (menus[i] instanceof menuClass) {
      return menus[i];
    }
  }
  return null;
};

scout.Outline.prototype._hasMenu = function(menus, menuClass) {
  return this._getMenu(menus, menuClass) !== null;
};

scout.Outline.prototype._onTitleClick = function(event) {
  this.navigateToTop();
};

scout.Outline.prototype.navigateToTop = function() {
  this.deselectAll();
  this.collapseAll();
  this.handleInitialExpanded();
};

scout.Outline.prototype.handleInitialExpanded = function() {
  this._visitNodes(this.nodes, function(node) {
    if (node.initialExpanded) {
      this.expandNode(node, {
        renderExpansion: true
      });
    }
  }.bind(this));
};

scout.Outline.prototype._onNodeDeleted = function(node) {
  // Destroy table, which is attached at the root adapter. Form gets destroyed by form close event
  if (node.detailTable) {
    node.detailTable.events.removeListener(this._detailTableListener);
    node.detailTable.destroy();
    node.detailTable = null;
  }
  // If last node is removed, navigate back to top
  if (this.nodes.length === 0) {
    this.navigateToTop();
  }
};

scout.Outline.prototype.selectNodes = function(nodes, notifyServer, debounceSend) {
  nodes = scout.arrays.ensure(nodes);
  if (nodes.length > 0 && this.isNodeSelected(nodes[0])) {
    // Already selected, do nothing
    return;
  }
  if (nodes.length === 0 && this.selectedNodes.length === 0) {
    // Already unselected, do nothing
    return;
  }
  if (this.navigateUpInProgress) {
    this.navigateUpInProgress = false;
  } else {
    if (nodes.length === 1) {
      // When a node is selected, the detail form should never be hidden
      this.setDetailFormVisibleByUi(nodes[0], true);
    }
  }
  scout.Outline.parent.prototype.selectNodes.call(this, nodes, notifyServer, debounceSend);
  this.updateDetailContent();
};

scout.Outline.prototype._renderDefaultDetailForm = function() {
  // nop
};

scout.Outline.prototype._syncDefaultDetailForm = function(defaultDetailForm) {
  this.defaultDetailForm = defaultDetailForm;
  if (this.defaultDetailForm) {
    if (this.outlineOverview) {
      this.outlineOverview.destroy();
      this.outlineOverview = null;
    }
  } else {
    if (!this.outlineOverview) {
      // Create outlineOverview if no defaultDetailForm is available
      this.outlineOverview = scout.create('OutlineOverview', {
        parent: this,
        outline: this
      });
    }
  }
};

scout.Outline.prototype._syncNavigateButtonsVisible = function(navigateButtonsVisible) {
  this.navigateButtonsVisible = navigateButtonsVisible;
  this._visitNodes(this.nodes, this._syncNavigateButtonsVisibleForNode.bind(this));
};

scout.Outline.prototype._syncNavigateButtonsVisibleForNode = function(node, parentNode) {
  if (this.navigateButtonsVisible) {
    if (node.detailForm) {
      this._appendNavigateButtonsForDetailForm(node);
    }
    if (node.detailTable) {
      this._appendNavigateButtonsForDetailTable(node);
    }
  } else {
    if (node.detailForm) {
      this._removeNavigateButtonsForDetailForm(node);
    }
    if (node.detailTable) {
      this._removeNavigateButtonsForDetailTable(node);
    }
  }
};

scout.Outline.prototype._appendNavigateButtonsForDetailForm = function(node) {
  var menus = this._createNavigateButtons(node, node.detailForm.staticMenus);
  node.detailForm.rootGroupBox.setStaticMenus(menus);
};

scout.Outline.prototype._appendNavigateButtonsForDetailTable = function(node) {
  var menus = this._createNavigateButtons(node, node.detailTable.staticMenus);
  node.detailTable.setStaticMenus(menus);
};

scout.Outline.prototype._removeNavigateButtonsForDetailForm = function(node) {
  var staticMenus = [];
  node.detailForm.rootGroupBox.staticMenus.forEach(function(menu) {
    if (menu instanceof scout.NavigateUpButton || menu instanceof scout.NavigateDownButton) {
      menu.destroy();
    } else {
      staticMenus.push(menu);
    }
  });
  node.detailForm.rootGroupBox.setStaticMenus(staticMenus);
};

scout.Outline.prototype._removeNavigateButtonsForDetailTable = function(node) {
  var menus = [];
  var staticMenus = [];
  node.detailTable.staticMenus.forEach(function(menu) {
    if (menu instanceof scout.NavigateUpButton || menu instanceof scout.NavigateDownButton) {
      menu.destroy();
    } else {
      staticMenus.push(menu);
    }
  });
  node.detailTable.setStaticMenus(staticMenus);
};

scout.Outline.prototype._renderNavigateButtonsVisible = function() {
  // nop
};

/**
 * Returns the selected row or null when no row is selected. When multiple rows are selected
 * the first selected row is returned.
 */
scout.Outline.prototype.selectedRow = function() {
  var table, node,
    nodes = this.selectedNodes;
  if (nodes.length === 0) {
    return null;
  }
  node = nodes[0];
  if (!node.detailTable) {
    return null;
  }
  table = node.detailTable;
  if (table.selectedRows.length === 0) {
    return null;
  }
  return table.selectedRows[0];
};

scout.Outline.prototype._applyUpdatedNodeProperties = function(oldNode, updatedNode) {
  var propertiesChanged = scout.Outline.parent.prototype._applyUpdatedNodeProperties.call(this, oldNode, updatedNode);
  if (oldNode.modelClass !== updatedNode.modelClass) {
    oldNode.modelClass = updatedNode.modelClass;
    propertiesChanged = true;
  }
  if (oldNode.classId !== updatedNode.classId) {
    oldNode.classId = updatedNode.classId;
    propertiesChanged = true;
  }
  if (oldNode.nodeType !== updatedNode.nodeType) {
    oldNode.nodeType = updatedNode.nodeType;
    propertiesChanged = true;
  }
  return propertiesChanged;
};

/**
 * Called by updateItemPath.
 *
 * @override
 */
scout.Outline.prototype._isGroupingEnd = function(node) {
  return node.nodeType === 'table';
};

/**
 * Disabled for outlines because outline may be resized.
 */
scout.Outline.prototype._isTruncatedNodeTooltipEnabled = function() {
  return false;
};

scout.Outline.prototype.setDetailFormVisibleByUi = function(node, visible) {
  node.detailFormVisibleByUi = visible;
  this._triggerPageChanged(node);
};

scout.Outline.prototype.validateFocus = function() {
  this.session.focusManager.validateFocus();
};

scout.Outline.prototype.sendToBack = function() {
  this.inBackground = true;
  this._renderInBackground();

  // Detach child dialogs, message boxes and file choosers, not views.
  this.formController.detachDialogs();
  this.messageBoxController.detach();
  this.fileChooserController.detach();
};

scout.Outline.prototype.bringToFront = function() {
  this.inBackground = false;
  this._renderInBackground();

  // Attach child dialogs, message boxes and file choosers.
  this.formController.attachDialogs();
  this.messageBoxController.attach();
  this.fileChooserController.attach();
};

scout.Outline.prototype._renderInBackground = function() {
  this.$container.toggleClass('in-background', this.inBackground);
};

scout.Outline.prototype._renderCompact = function() {
  this.$container.toggleClass('compact', this.compact);
};

scout.Outline.prototype._renderEmbedDetailContent = function() {
  this.$data.toggleClass('has-detail-content', this.embedDetailContent);
};

scout.Outline.prototype._renderDetailContent = function() {
  if (!this.detailContent || this.detailContent.rendered) {
    return;
  }
  var page = this.selectedNodes[0];
  if (!page.rendered) {
    return;
  }

  this.detailContent.render(page.$node);
  if (this.detailContent.htmlComp) {
    this.detailContent.htmlComp.validateRoot = false;
    this.detailContent.htmlComp.pixelBasedSizing = true;
  }
  this._ensurePageLayout(page);
  this.$data.addClass('detail-content-visible');
};

scout.Outline.prototype._ensurePageLayout = function(page) {
  // selected page now has content (menubar and form) -> needs a layout
  // always create new htmlComp, otherwise we would have to remove them when $node or outline gets remvoed
  page.htmlComp = new scout.HtmlComponent(page.$node, this.session);
  page.htmlComp.setLayout(new scout.PageLayout(this, page));
};

scout.Outline.prototype._removeDetailContent = function() {
  if (!this.detailContent) {
    return;
  }
  this.detailContent.remove();
  this.$data.removeClass('detail-content-visible');
};

scout.Outline.prototype._postRenderViewRange = function() {
  scout.Outline.parent.prototype._postRenderViewRange.call(this);
  this._renderDetailContent();
  this._renderDetailMenuBarVisible();
  this._renderNodeMenuBarVisible();
};

scout.Outline.prototype.setCompact = function(compact) {
  this.compact = compact;
  if (this.rendered) {
    this._renderCompact();
    this.invalidateLayoutTree();
  }
};

scout.Outline.prototype.setEmbedDetailContent = function(embed) {
  this.embedDetailContent = embed;
  if (this.rendered) {
    this._renderEmbedDetailContent();
    this.invalidateLayoutTree();
  }
  this.updateDetailContent();
};

scout.Outline.prototype.setDetailContent = function(content) {
  if (this.detailContent === content) {
    return;
  }
  if (this.rendered) {
    this._removeDetailContent();
  }
  this.detailContent = content;
  if (this.rendered) {
    this._renderDetailContent();
  }
  this.invalidateLayoutTree();
};

scout.Outline.prototype.updateDetailContent = function() {
  if (!this.embedDetailContent) {
    this.setDetailContent(null);
    this.setDetailMenus([]);
    return;
  }

  this.setDetailMenuBarVisible(false);
  this.setNodeMenuBarVisible(false);
  this.setDetailContent(this._computeDetailContent());
  this.updateDetailMenus();

  // Layout immediate to prevent 'laggy' form visualization,
  // but not initially while desktop gets rendered because it will be done at the end anyway
  if (this.rendered) {
    this.validateLayoutTree();
  }
};

scout.Outline.prototype._computeDetailContent = function() {
  var selectedPage = this.selectedNodes[0];
  if (!selectedPage) {
    // Detail content is shown for the selected node only
    return null;
  }
  if (selectedPage.nodeType === 'virtual') {
    // If node is virtual it is not known yet whether there is a detail form or not -> wait until node gets resolved
    return null;
  }

  // if there is a detail form, use this
  if (selectedPage.detailForm && selectedPage.detailFormVisible && selectedPage.detailFormVisibleByUi) {
    return selectedPage.detailForm;
    // otherwise show the content of the table row
    // but never if parent is a node page -> the table contains only one column with no essential information
  } else if (selectedPage.row && selectedPage.parentNode.nodeType === 'table') {
    return scout.create('TableRowDetail', {
      parent: this,
      table: selectedPage.parentNode.detailTable,
      tableRow: selectedPage.row
    });
  }
  return null;
};

/**
 * Updates node and detail menubar.
 * Node menubar: Contains the table controls and right aligned menus.
 * Detail menubar: Contains the other menus.
 *
 * The menu items are gathered from various sources:
 * If the selected page has a detailForm, the menus are taken from there. Otherwise the detail table and the parent detail table provide the menus.
 * The detail table contributes the empty space menus and the parent detail the the single selection menus.
 *
 * The menus of the outline itself are not displayed. In fact the server won't deliver any.
 * One reason is that no menus are displayed in regular mode, so when switching to compact mode no menus would be available.
 * Another reason is that it would flicker because the menus are sent anew from the server every time a node gets selected because the menus are added to the outline and not to the node and are therefore not cached.
 */
scout.Outline.prototype.updateDetailMenus = function() {
  if (!this.embedDetailContent) {
    return;
  }
  var selectedPages = this.selectedNodes,
    selectedPage = selectedPages[0],
    menuItems = [],
    tableControls = [],
    nodeMenus = [],
    detailTable,
    detailMenus = [];

  if (this.detailContent && this.detailContent instanceof scout.Form) {
    // get menus from detail form
    var rootGroupBox = this.detailContent.rootGroupBox;
    menuItems = rootGroupBox.processMenus.concat(rootGroupBox.menus);
    rootGroupBox.setMenuBarVisible(false);
  } else if (selectedPage) {
    // get empty space menus and table controls from detail table
    if (selectedPage.detailTable) {
      detailTable = selectedPage.detailTable;
      menuItems = scout.menus.filter(detailTable.menus, ['Table.EmptySpace'], false, true);
      tableControls = detailTable.tableControls;
      this._attachDetailMenusListener(detailTable);
    }
    // get single selection menus from parent detail table
    var parentPage = selectedPage.parentNode;
    if (parentPage && parentPage.detailTable) {
      detailTable = parentPage.detailTable;
      menuItems = menuItems.concat(scout.menus.filter(detailTable.menus, ['Table.SingleSelection'], false, true));
      this._attachDetailMenusListener(detailTable);
    }
  }

  // Add table controls to nodeMenus
  tableControls.forEach(function(tableControl) {
    var menu = scout.create('TableControlAdapterMenu',
      scout.TableControlAdapterMenu.adaptTableControlProperties(tableControl, {
        parent: this,
        tableControl: tableControl,
        horizontalAlignment: 1
      }));
    nodeMenus.push(menu);
  }, this);

  // Add right aligned menus to node menus, other to detail menus
  menuItems.forEach(function(menuItem) {
    if (menuItem.horizontalAlignment === 1) {
      nodeMenus.push(menuItem);
    } else {
      detailMenus.push(menuItem);
    }
  }, this);

  this.setNodeMenus(nodeMenus);
  this.setDetailMenus(detailMenus);
};

/**
 * Attaches a listener to the given menu container (which is the detail table or the detail table of the parent node)
 * in order to get dynamic menu changes and update the detailMenus on such a change event.
 */
scout.Outline.prototype._attachDetailMenusListener = function(menuContainer) {
  if (!this._detailMenusChangeHandler) {
    this._detailMenusChangeHandler = function(event) {
      if (scout.arrays.containsAny(event.changedProperties, ['menus', 'tableControls'])) {
        this.updateDetailMenus();
      }
    }.bind(this);
  }
  if (!this._detailMenusDestroyHandler) {
    this._detailMenusDestroyHandler = function() {
      menuContainer.off('propertyChange', this._detailMenusChangeHandler);
    }.bind(this);
  }

  menuContainer.off('propertyChange', this._detailMenusChangeHandler);
  menuContainer.on('propertyChange', this._detailMenusChangeHandler);
  menuContainer.off('destroy', this._detailMenusDestroyHandler);
  menuContainer.one('destroy', this._detailMenusDestroyHandler);

  if (!this._detailMenusNodesSelectedHandler) {
    // This nodes selection listener removes the property change listeners from the old menu containers (detail content) whenever a node gets selected
    // UpdateDetailMenus is called afterwards and attaches the property change listeners to the new detail content
    // This guarantees that no events are fired for non selected nodes
    this._detailMenusNodesSelectedHandler = {
      outline: this,
      menuContainers: [],
      addMenuContainer: function(container) {
        if (this.menuContainers.indexOf(container) > -1) {
          return;
        }
        this.menuContainers.push(container);
      },
      func: function(event) {
        if (event.type !== 'nodesSelected') {
          return;
        }
        this.menuContainers.forEach(function(container) {
          container.off('propertyChange', this.outline._detailMenusChangeHandler);
          container.off('destroy', this.outline._detailMenusDestroyHandler);
        }, this);
        this.menuContainers = [];
      }
    };
    this.events.addListener(this._detailMenusNodesSelectedHandler);
  }
  this._detailMenusNodesSelectedHandler.addMenuContainer(menuContainer);
};

scout.Outline.prototype.setDetailMenus = function(detailMenus) {
  this.detailMenuBar.setMenuItems(detailMenus);
  this.setDetailMenuBarVisible(this.detailMenuBar.menuItems.length > 0);
};

scout.Outline.prototype._renderDetailMenuBarVisible = function() {
  if (this.detailMenuBarVisible) {
    this._renderDetailMenuBar();
  } else {
    this._removeDetailMenuBar();
  }
};

scout.Outline.prototype._renderDetailMenuBar = function() {
  if (this.detailMenuBar.rendered) {
    return;
  }
  if (this.selectedNodes.length === 0) {
    return;
  }
  var node = this.selectedNodes[0];
  if (!node.rendered) {
    return;
  }

  this.detailMenuBar.render(node.$node);
  this.detailMenuBar.$container.addClass('detail-menubar');
  if (this.detailContent && this.detailContent.rendered) {
    // move before content (e.g. form)
    this.detailMenuBar.$container.insertBefore(this.detailContent.$container);
  }
  this._ensurePageLayout(node);
  this.invalidateLayoutTree();
};

scout.Outline.prototype._removeDetailMenuBar = function() {
  if (!this.detailMenuBar.rendered) {
    return;
  }
  this.detailMenuBar.remove();
  this.invalidateLayoutTree();
};

scout.Outline.prototype.setDetailMenuBarVisible = function(visible) {
  this.detailMenuBarVisible = visible;
  if (this.rendered) {
    this._renderDetailMenuBarVisible();
  }
};

scout.Outline.prototype.setNodeMenus = function(nodeMenus) {
  this.nodeMenuBar.setMenuItems(nodeMenus);
  this.setNodeMenuBarVisible(this.nodeMenuBar.menuItems.length > 0);
};

scout.Outline.prototype._renderNodeMenuBarVisible = function() {
  if (this.nodeMenuBarVisible) {
    this._renderNodeMenuBar();
  } else {
    this._removeNodeMenuBar();
  }
};

scout.Outline.prototype._renderNodeMenuBar = function() {
  if (this.nodeMenuBar.rendered) {
    return;
  }
  if (this.selectedNodes.length === 0) {
    return;
  }
  var node = this.selectedNodes[0];
  if (!node.rendered) {
    return;
  }

  var $text = node.$node.children('.text');
  this.nodeMenuBar.render(node.$node);
  this.nodeMenuBar.$container.addClass('node-menubar');
  this.nodeMenuBar.$container.insertAfter($text);
  this.invalidateLayoutTree();
};

scout.Outline.prototype._removeNodeMenuBar = function() {
  if (!this.nodeMenuBar.rendered) {
    return;
  }
  this.nodeMenuBar.remove();
  this.invalidateLayoutTree();
};

scout.Outline.prototype.setNodeMenuBarVisible = function(visible) {
  this.nodeMenuBarVisible = visible;
  if (this.rendered) {
    this._renderNodeMenuBarVisible();
  }
};

/**
 * === Method required for objects that act as 'displayParent' ===
 *
 * Returns the DOM elements to paint a glassPanes over, once a modal Form, message-box or file-chooser is showed with this Outline as its 'displayParent'.
 */
scout.Outline.prototype.glassPaneTargets = function() {
  if (this.rendered) {
    var desktop = this.session.desktop;
    var elements = [];
    if (desktop.navigation) {
      elements.push(desktop.navigation.$body);
    }
    if (desktop.bench) {
      elements.push(desktop.bench.$container);
    }
    return elements;
  } else {
    var deferred = new scout.DeferredGlassPaneTarget();
    var renderedHandler = function(event) {
      var desktop = event.source.session.desktop;
      var elements = [];
      if (desktop.navigation) {
        elements.push(desktop.navigation.$body);
      }
      if (desktop.bench) {
        elements.push(desktop.bench.$container);
      }
      deferred.ready(elements);
    };
    this.one('rendered', renderedHandler);
    this.one('destroy', function() {
      this.off('rendered', renderedHandler);
    }.bind(this));
    return [deferred];
  }
};

/**
 * === Method required for objects that act as 'displayParent' ===
 *
 * Returns true if this outline is active and not in background.
 */
scout.Outline.prototype.inFront = function() {
  return this.session.desktop.outline === this && !this.inBackground;
};

/**
 * Called if outline acts as display parent.

* Returns true if outline is active, even if it is not rendered (e.g. when navigation is invisible) */ scout.Outline.prototype.acceptDialog = function(dialog) { return this.session.desktop.outline === this; }; /** * Called if outline acts as display parent.

* Returns true if outline is active, even if it is not rendered (e.g. when navigation is invisible) */ scout.Outline.prototype.acceptView = function(view) { return this.session.desktop.outline === this; }; scout.Outline.prototype._syncMenus = function(menus, oldMenus) { this.updateKeyStrokes(menus, oldMenus); this.menus = menus; if (this.titleMenuBar) { // menuBar is not created yet when synMenus is called initially this._updateTitleMenuBar(); } }; scout.Outline.prototype._updateTitleMenuBar = function() { var menuItems = scout.menus.filter(this.menus, ['Tree.Header']); this.titleMenuBar.setMenuItems(menuItems); }; scout.Outline.prototype._triggerPageChanged = function(page) { this.trigger('pageChanged', { page: page }); }; /* event handling */ scout.Outline.prototype._onDetailTableRowsFiltered = function(event) { this.filter(); }; scout.Outline.prototype._onDetailTableRowInitialized = function(event) { this._linkNodeWithRow(event.row); }; scout.Outline.prototype._onDetailTableEvent = function(event) { if (event.type === 'rowInitialized') { this._onDetailTableRowInitialized(event); } else if (event.type === 'rowsFiltered') { this._onDetailTableRowsFiltered(event); } }; scout.Outline.prototype._onPageChanged = function(event) { var node; if (event.nodeId) { node = this.nodesMap[event.nodeId]; node.detailFormVisible = event.detailFormVisible; node.detailForm = this.session.getOrCreateModelAdapter(event.detailForm, this); if (node.detailForm) { this._initDetailForm(node); } node.detailTableVisible = event.detailTableVisible; node.detailTable = this.session.getOrCreateModelAdapter(event.detailTable, this); if (node.detailTable) { this._initDetailTable(node); } } else { this.defaultDetailForm = this.session.getOrCreateModelAdapter(event.detailForm, this); } var selectedPage = this.selectedNodes[0]; if (!node && !selectedPage || node === selectedPage) { this.updateDetailContent(); } this._triggerPageChanged(node); }; scout.Outline.prototype.onModelAction = function(event) { if (event.type === 'pageChanged') { this._onPageChanged(event); } else { scout.Outline.parent.prototype.onModelAction.call(this, event); } };





© 2015 - 2025 Weber Informatics LLC | Privacy Policy