Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  ToolboxTabs.js   Sprache: JAVA

 
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
 * You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

const {
  Component,
  createFactory,
  createRef,
} = require("resource://devtools/client/shared/vendor/react.js");
const dom = require("resource://devtools/client/shared/vendor/react-dom-factories.js");
const PropTypes = require("resource://devtools/client/shared/vendor/react-prop-types.js");
const {
  ToolboxTabsOrderManager,
} = require("resource://devtools/client/framework/toolbox-tabs-order-manager.js");

const { div } = dom;

const ToolboxTab = createFactory(
  require("resource://devtools/client/framework/components/ToolboxTab.js")
);

loader.lazyGetter(this"MenuButton"function () {
  return createFactory(
    require("resource://devtools/client/shared/components/menu/MenuButton.js")
  );
});
loader.lazyGetter(this"MenuItem"function () {
  return createFactory(
    require("resource://devtools/client/shared/components/menu/MenuItem.js")
  );
});
loader.lazyGetter(this"MenuList"function () {
  return createFactory(
    require("resource://devtools/client/shared/components/menu/MenuList.js")
  );
});

// 26px is chevron devtools button width.(i.e. tools-chevronmenu)
const CHEVRON_BUTTON_WIDTH = 26;

class ToolboxTabs extends Component {
  // See toolbox-toolbar propTypes for details on the props used here.
  static get propTypes() {
    return {
      currentToolId: PropTypes.string,
      focusButton: PropTypes.func,
      focusedButton: PropTypes.string,
      highlightedTools: PropTypes.object,
      panelDefinitions: PropTypes.array,
      selectTool: PropTypes.func,
      toolbox: PropTypes.object,
      visibleToolboxButtonCount: PropTypes.number.isRequired,
      L10N: PropTypes.object,
      onTabsOrderUpdated: PropTypes.func.isRequired,
    };
  }

  constructor(props) {
    super(props);

    this.state = {
      // Array of overflowed tool id.
      overflowedTabIds: [],
    };

    this.wrapperEl = createRef();

    // Map with tool Id and its width size. This lifecycle is out of React's
    // lifecycle. If a tool is registered, ToolboxTabs will add target tool id
    // to this map. ToolboxTabs will never remove tool id from this cache.
    this._cachedToolTabsWidthMap = new Map();

    this._resizeTimerId = null;
    this.resizeHandler = this.resizeHandler.bind(this);

    const { toolbox, onTabsOrderUpdated, panelDefinitions } = props;
    this._tabsOrderManager = new ToolboxTabsOrderManager(
      toolbox,
      onTabsOrderUpdated,
      panelDefinitions
    );
  }

  componentDidMount() {
    window.addEventListener("resize"this.resizeHandler);
    this.updateCachedToolTabsWidthMap();
    this.updateOverflowedTabs();
  }

  // FIXME: https://bugzilla.mozilla.org/show_bug.cgi?id=1774507
  UNSAFE_componentWillUpdate(nextProps, nextState) {
    if (this.shouldUpdateToolboxTabs(this.props, nextProps)) {
      // Force recalculate and render in this cycle if panel definition has
      // changed or selected tool has changed.
      nextState.overflowedTabIds = [];
    }
  }

  componentDidUpdate(prevProps) {
    if (this.shouldUpdateToolboxTabs(prevProps, this.props)) {
      this.updateCachedToolTabsWidthMap();
      this.updateOverflowedTabs();
      this._tabsOrderManager.setCurrentPanelDefinitions(
        this.props.panelDefinitions
      );
    }
  }

  componentWillUnmount() {
    window.removeEventListener("resize"this.resizeHandler);
    window.cancelIdleCallback(this._resizeTimerId);
    this._tabsOrderManager.destroy();
  }

  /**
   * Check if two array of ids are the same or not.
   */

  equalToolIdArray(prevPanels, nextPanels) {
    if (prevPanels.length !== nextPanels.length) {
      return false;
    }

    // Check panel definitions even if both of array size is same.
    // For example, the case of changing the tab's order.
    return prevPanels.join("-") === nextPanels.join("-");
  }

  /**
   * Return true if we should update the overflowed tabs.
   */

  shouldUpdateToolboxTabs(prevProps, nextProps) {
    if (
      prevProps.currentToolId !== nextProps.currentToolId ||
      prevProps.visibleToolboxButtonCount !==
        nextProps.visibleToolboxButtonCount
    ) {
      return true;
    }

    const prevPanels = prevProps.panelDefinitions.map(def => def.id);
    const nextPanels = nextProps.panelDefinitions.map(def => def.id);
    return !this.equalToolIdArray(prevPanels, nextPanels);
  }

  /**
   * Update the Map of tool id and tool tab width.
   */

  updateCachedToolTabsWidthMap() {
    const utils = window.windowUtils;
    // Force a reflow before calling getBoundingWithoutFlushing on each tab.
    this.wrapperEl.current.clientWidth;

    for (const tab of this.wrapperEl.current.querySelectorAll(
      ".devtools-tab"
    )) {
      const tabId = tab.id.replace("toolbox-tab-""");
      if (!this._cachedToolTabsWidthMap.has(tabId)) {
        const rect = utils.getBoundsWithoutFlushing(tab);
        this._cachedToolTabsWidthMap.set(tabId, rect.width);
      }
    }
  }

  /**
   * Update the overflowed tab array from currently displayed tool tab.
   * If calculated result is the same as the current overflowed tab array, this
   * function will not update state.
   */

  updateOverflowedTabs() {
    const toolboxWidth = parseInt(
      getComputedStyle(this.wrapperEl.current).width,
      10
    );
    const { currentToolId } = this.props;
    const enabledTabs = this.props.panelDefinitions.map(def => def.id);
    let sumWidth = 0;
    const visibleTabs = [];

    for (const id of enabledTabs) {
      const width = this._cachedToolTabsWidthMap.get(id);
      sumWidth += width;
      if (sumWidth <= toolboxWidth) {
        visibleTabs.push(id);
      } else {
        sumWidth = sumWidth - width + CHEVRON_BUTTON_WIDTH;

        // If toolbox can't display the Chevron, remove the last tool tab.
        if (sumWidth > toolboxWidth) {
          const removeTabId = visibleTabs.pop();
          sumWidth -= this._cachedToolTabsWidthMap.get(removeTabId);
        }
        break;
      }
    }

    // If the selected tab is in overflowed tabs, insert it into a visible
    // toolbox.
    if (
      !visibleTabs.includes(currentToolId) &&
      enabledTabs.includes(currentToolId)
    ) {
      const selectedToolWidth = this._cachedToolTabsWidthMap.get(currentToolId);
      while (
        sumWidth + selectedToolWidth > toolboxWidth &&
        visibleTabs.length
      ) {
        const removingToolId = visibleTabs.pop();
        const removingToolWidth =
          this._cachedToolTabsWidthMap.get(removingToolId);
        sumWidth -= removingToolWidth;
      }

      // If toolbox width is narrow, toolbox display only chevron menu.
      // i.e. All tool tabs will overflow.
      if (sumWidth + selectedToolWidth <= toolboxWidth) {
        visibleTabs.push(currentToolId);
      }
    }

    const willOverflowTabs = enabledTabs.filter(
      id => !visibleTabs.includes(id)
    );
    if (!this.equalToolIdArray(this.state.overflowedTabIds, willOverflowTabs)) {
      this.setState({ overflowedTabIds: willOverflowTabs });
    }
  }

  resizeHandler() {
    window.cancelIdleCallback(this._resizeTimerId);
    this._resizeTimerId = window.requestIdleCallback(
      () => {
        this.updateOverflowedTabs();
      },
      { timeout: 100 }
    );
  }

  renderToolsChevronMenuList() {
    const { panelDefinitions, selectTool } = this.props;

    const items = [];
    for (const { id, label, icon } of panelDefinitions) {
      if (this.state.overflowedTabIds.includes(id)) {
        items.push(
          MenuItem({
            key: id,
            id: "tools-chevron-menupopup-" + id,
            label,
            type: "checkbox",
            onClick: () => {
              selectTool(id, "tab_switch");
            },
            icon,
          })
        );
      }
    }

    return MenuList({ id: "tools-chevron-menupopup" }, items);
  }

  /**
   * Render a button to access overflowed tools, displayed only when the toolbar
   * presents an overflow.
   */

  renderToolsChevronButton() {
    const { toolbox } = this.props;

    return MenuButton(
      {
        id: "tools-chevron-menu-button",
        menuId: "tools-chevron-menu-button-panel",
        className: "devtools-tabbar-button tools-chevron-menu",
        toolboxDoc: toolbox.doc,
      },
      this.renderToolsChevronMenuList()
    );
  }

  /**
   * Render all of the tabs, based on the panel definitions and builds out
   * a toolbox tab for each of them. Will render the chevron button if the
   * container has an overflow.
   */

  render() {
    const {
      currentToolId,
      focusButton,
      focusedButton,
      highlightedTools,
      panelDefinitions,
      selectTool,
    } = this.props;

    const tabs = panelDefinitions.map(panelDefinition => {
      // Don't display overflowed tab.
      if (!this.state.overflowedTabIds.includes(panelDefinition.id)) {
        return ToolboxTab({
          key: panelDefinition.id,
          currentToolId,
          focusButton,
          focusedButton,
          highlightedTools,
          panelDefinition,
          selectTool,
        });
      }
      return null;
    });

    return div(
      {
        className: "toolbox-tabs-wrapper",
        ref: this.wrapperEl,
      },
      div(
        {
          className: "toolbox-tabs",
          onMouseDown: e => this._tabsOrderManager.onMouseDown(e),
        },
        tabs,
        this.state.overflowedTabIds.length
          ? this.renderToolsChevronButton()
          : null
      )
    );
  }
}

module.exports = ToolboxTabs;

93%


¤ Dauer der Verarbeitung: 0.2 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung ist noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge