Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/toolkit/content/widgets/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 46 kB image not shown  

Quelle  tree.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/. */


/* globals XULTreeElement */

"use strict";

// This is loaded into all XUL windows. Wrap in a block to prevent
// leaking to window scope.
{
  const { AppConstants } = ChromeUtils.importESModule(
    "resource://gre/modules/AppConstants.sys.mjs"
  );

  class MozTreeChildren extends MozElements.BaseControl {
    constructor() {
      super();

      /**
       * If there is no modifier key, we select on mousedown, not
       * click, so that drags work correctly.
       */

      this.addEventListener("mousedown", event => {
        if (this.parentNode.disabled) {
          return;
        }
        if (
          ((!event.getModifierState("Accel") ||
            !this.parentNode.pageUpOrDownMovesSelection) &&
            !event.shiftKey &&
            !event.metaKey) ||
          this.parentNode.view.selection.single
        ) {
          var b = this.parentNode;
          var cell = b.getCellAt(event.clientX, event.clientY);
          var view = this.parentNode.view;

          // save off the last selected row
          this._lastSelectedRow = cell.row;

          if (cell.row == -1) {
            return;
          }

          if (cell.childElt == "twisty") {
            return;
          }

          if (cell.col && event.button == 0) {
            if (cell.col.cycler) {
              view.cycleCell(cell.row, cell.col);
              return;
            } else if (cell.col.type == window.TreeColumn.TYPE_CHECKBOX) {
              if (
                this.parentNode.editable &&
                cell.col.editable &&
                view.isEditable(cell.row, cell.col)
              ) {
                var value = view.getCellValue(cell.row, cell.col);
                value = value == "true" ? "false" : "true";
                view.setCellValue(cell.row, cell.col, value);
                return;
              }
            }
          }

          if (!view.selection.isSelected(cell.row)) {
            view.selection.select(cell.row);
            b.ensureRowIsVisible(cell.row);
          }
        }
      });

      /**
       * On a click (up+down on the same item), deselect everything
       * except this item.
       */

      this.addEventListener("click", event => {
        if (event.button != 0) {
          return;
        }
        if (this.parentNode.disabled) {
          return;
        }
        var b = this.parentNode;
        var cell = b.getCellAt(event.clientX, event.clientY);
        var view = this.parentNode.view;

        if (cell.row == -1) {
          return;
        }

        if (cell.childElt == "twisty") {
          if (
            view.selection.currentIndex >= 0 &&
            view.isContainerOpen(cell.row)
          ) {
            var parentIndex = view.getParentIndex(view.selection.currentIndex);
            while (parentIndex >= 0 && parentIndex != cell.row) {
              parentIndex = view.getParentIndex(parentIndex);
            }
            if (parentIndex == cell.row) {
              var parentSelectable = true;
              if (parentSelectable) {
                view.selection.select(parentIndex);
              }
            }
          }
          this.parentNode.changeOpenState(cell.row);
          return;
        }

        if (!view.selection.single) {
          var augment = event.getModifierState("Accel");
          if (event.shiftKey) {
            view.selection.rangedSelect(-1, cell.row, augment);
            b.ensureRowIsVisible(cell.row);
            return;
          }
          if (augment) {
            view.selection.toggleSelect(cell.row);
            b.ensureRowIsVisible(cell.row);
            view.selection.currentIndex = cell.row;
            return;
          }
        }

        /* We want to deselect all the selected items except what was
          clicked, UNLESS it was a right-click.  We have to do this
          in click rather than mousedown so that you can drag a
          selected group of items */


        if (!cell.col) {
          return;
        }

        // if the last row has changed in between the time we
        // mousedown and the time we click, don't fire the select handler.
        // see bug #92366
        if (
          !cell.col.cycler &&
          this._lastSelectedRow == cell.row &&
          cell.col.type != window.TreeColumn.TYPE_CHECKBOX
        ) {
          view.selection.select(cell.row);
          b.ensureRowIsVisible(cell.row);
        }
      });

      /**
       * double-click
       */

      this.addEventListener("dblclick", event => {
        if (this.parentNode.disabled) {
          return;
        }
        var tree = this.parentNode;
        var view = this.parentNode.view;
        var row = view.selection.currentIndex;

        if (row == -1) {
          return;
        }

        var cell = tree.getCellAt(event.clientX, event.clientY);

        if (cell.childElt != "twisty") {
          this.parentNode.startEditing(row, cell.col);
        }

        if (this.parentNode._editingColumn || !view.isContainer(row)) {
          return;
        }

        // Cyclers and twisties respond to single clicks, not double clicks
        if (cell.col && !cell.col.cycler && cell.childElt != "twisty") {
          this.parentNode.changeOpenState(row);
        }
      });
    }

    connectedCallback() {
      if (this.delayConnectedCallback()) {
        return;
      }

      this.setAttribute("slot""treechildren");

      this._lastSelectedRow = -1;

      if ("_ensureColumnOrder" in this.parentNode) {
        this.parentNode._ensureColumnOrder();
      }
    }
  }

  customElements.define("treechildren", MozTreeChildren);

  class MozTreecolPicker extends MozElements.BaseControl {
    static get markup() {
      return `
      <button class="tree-columnpicker-button"/>
      <menupopup anonid="popup">
        <menuseparator anonid="menuseparator"/>
        <menuitem anonid="menuitem" data-l10n-id="tree-columnpicker-restore-order"/>
      </menupopup>
      `;
    }
    constructor() {
      super();

      window.MozXULElement.insertFTLIfNeeded("toolkit/global/tree.ftl");
    }

    connectedCallback() {
      if (this.delayConnectedCallback()) {
        return;
      }

      this.textContent = "";
      this.appendChild(this.constructor.fragment);

      let button = this.querySelector(".tree-columnpicker-button");
      let popup = this.querySelector('[anonid="popup"]');
      let menuitem = this.querySelector('[anonid="menuitem"]');

      button.addEventListener("command", e => {
        this.buildPopup(popup);
        popup.openPopup(this"after_end");
        e.preventDefault();
      });

      menuitem.addEventListener("command", e => {
        let tree = this.parentNode.parentNode;
        tree.stopEditing(true);
        this.style.order = "";
        tree._ensureColumnOrder(tree.NATURAL_ORDER);
        e.preventDefault();
      });
    }

    buildPopup(aPopup) {
      // We no longer cache the picker content, remove the old content related to
      // the cols - menuitem and separator should stay.
      aPopup.querySelectorAll("[colindex]").forEach(e => {
        e.remove();
      });

      var refChild = aPopup.firstChild;

      var tree = this.parentNode.parentNode;
      for (
        var currCol = tree.columns.getFirstColumn();
        currCol;
        currCol = currCol.getNext()
      ) {
        // Construct an entry for each column in the row, unless
        // it is not being shown.
        var currElement = currCol.element;
        if (!currElement.hasAttribute("ignoreincolumnpicker")) {
          var popupChild = document.createXULElement("menuitem");
          popupChild.setAttribute("type""checkbox");
          var columnName =
            currElement.getAttribute("display") ||
            currElement.getAttribute("label");
          popupChild.setAttribute("label", columnName);
          popupChild.setAttribute("colindex", currCol.index);
          if (currElement.getAttribute("hidden") != "true") {
            popupChild.setAttribute("checked""true");
          }
          if (currCol.primary) {
            popupChild.setAttribute("disabled""true");
          }
          if (currElement.hasAttribute("closemenu")) {
            popupChild.setAttribute(
              "closemenu",
              currElement.getAttribute("closemenu")
            );
          }

          popupChild.addEventListener("command"function () {
            let colindex = this.getAttribute("colindex");
            let column = tree.columns[colindex];
            if (column) {
              var element = column.element;
              element.hidden = !element.hidden;
            }
          });

          aPopup.insertBefore(popupChild, refChild);
        }
      }

      var hidden = !tree.enableColumnDrag;
      aPopup.querySelectorAll(":scope > :not([colindex])").forEach(e => {
        e.hidden = hidden;
      });
    }
  }

  customElements.define("treecolpicker", MozTreecolPicker);

  class MozTreecol extends MozElements.BaseControl {
    static get observedAttributes() {
      return ["primary", ...super.observedAttributes];
    }

    static get inheritedAttributes() {
      return {
        ".treecol-sortdirection""sortdirection,hidden=hideheader",
        ".treecol-text""value=label,crop",
      };
    }

    static get markup() {
      return `
        <label class="treecol-text" flex="1" crop="end"></label>
        <image class="treecol-sortdirection"></image>
      `;
    }

    get _tree() {
      return this.parentNode?.parentNode;
    }

    _invalidate() {
      let tree = this._tree;
      if (!tree || !XULTreeElement.isInstance(tree)) {
        return;
      }
      tree.invalidate();
      tree.columns?.invalidateColumns();
    }

    constructor() {
      super();

      this.addEventListener("mousedown", event => {
        if (event.button != 0) {
          return;
        }
        if (this._tree.enableColumnDrag) {
          var XUL_NS =
            "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
          var cols = this.parentNode.getElementsByTagNameNS(XUL_NS, "treecol");

          // only start column drag operation if there are at least 2 visible columns
          var visible = 0;
          for (var i = 0; i < cols.length; ++i) {
            if (cols[i].getBoundingClientRect().width > 0) {
              ++visible;
            }
          }

          if (visible > 1) {
            window.addEventListener("mousemove"this._onDragMouseMove, true);
            window.addEventListener("mouseup"this._onDragMouseUp, true);
            document.treecolDragging = this;
            this.mDragGesturing = true;
            this.mStartDragX = event.clientX;
            this.mStartDragY = event.clientY;
          }
        }
      });

      this.addEventListener("click", event => {
        if (event.button != 0) {
          return;
        }
        if (event.target != event.originalTarget) {
          return;
        }

        // On Windows multiple clicking on tree columns only cycles one time
        // every 2 clicks.
        if (AppConstants.platform == "win" && event.detail % 2 == 0) {
          return;
        }

        var tree = this._tree;
        if (tree.columns) {
          tree.view.cycleHeader(tree.columns.getColumnFor(this));
        }
      });
    }

    connectedCallback() {
      if (this.delayConnectedCallback()) {
        return;
      }

      this.textContent = "";
      this.appendChild(this.constructor.fragment);
      this.initializeAttributeInheritance();
      if (this.hasAttribute("ordinal")) {
        this.style.order = this.getAttribute("ordinal");
      }
      if (this.hasAttribute("width")) {
        this.style.width = this.getAttribute("width") + "px";
      }

      this._resizeObserver = new ResizeObserver(() => {
        this._invalidate();
      });
      this._resizeObserver.observe(this);
    }

    disconnectedCallback() {
      this._resizeObserver?.unobserve(this);
      this._resizeObserver = null;
    }

    attributeChangedCallback(name, oldValue, newValue) {
      super.attributeChangedCallback(name, oldValue, newValue);
      this._invalidate();
    }

    set ordinal(val) {
      this.style.order = val;
      this.setAttribute("ordinal", val);
    }

    get ordinal() {
      var val = this.style.order;
      if (val == "") {
        return "1";
      }

      return "" + (val == "0" ? 0 : parseInt(val));
    }

    get _previousVisibleColumn() {
      var tree = this.parentNode.parentNode;
      let sib = tree.columns.getColumnFor(this).previousColumn;
      while (sib) {
        if (sib.element && sib.element.getBoundingClientRect().width > 0) {
          return sib.element;
        }

        sib = sib.previousColumn;
      }

      return null;
    }

    _onDragMouseMove(aEvent) {
      var col = document.treecolDragging;
      if (!col) {
        return;
      }

      // determine if we have moved the mouse far enough
      // to initiate a drag
      if (col.mDragGesturing) {
        if (
          Math.abs(aEvent.clientX - col.mStartDragX) < 5 &&
          Math.abs(aEvent.clientY - col.mStartDragY) < 5
        ) {
          return;
        }
        col.mDragGesturing = false;
        col.setAttribute("dragging""true");
        window.addEventListener("click", col._onDragMouseClick, true);
      }

      var pos = {};
      var targetCol = col.parentNode.parentNode._getColumnAtX(
        aEvent.clientX,
        0.5,
        pos
      );

      // bail if we haven't mousemoved to a different column
      if (col.mTargetCol == targetCol && col.mTargetDir == pos.value) {
        return;
      }

      var tree = col.parentNode.parentNode;
      var sib;
      var column;
      if (col.mTargetCol) {
        // remove previous insertbefore/after attributes
        col.mTargetCol.removeAttribute("insertbefore");
        col.mTargetCol.removeAttribute("insertafter");
        column = tree.columns.getColumnFor(col.mTargetCol);
        tree.invalidateColumn(column);
        sib = col.mTargetCol._previousVisibleColumn;
        if (sib) {
          sib.removeAttribute("insertafter");
          column = tree.columns.getColumnFor(sib);
          tree.invalidateColumn(column);
        }
        col.mTargetCol = null;
        col.mTargetDir = null;
      }

      if (targetCol) {
        // set insertbefore/after attributes
        if (pos.value == "after") {
          targetCol.setAttribute("insertafter""true");
        } else {
          targetCol.setAttribute("insertbefore""true");
          sib = targetCol._previousVisibleColumn;
          if (sib) {
            sib.setAttribute("insertafter""true");
            column = tree.columns.getColumnFor(sib);
            tree.invalidateColumn(column);
          }
        }
        column = tree.columns.getColumnFor(targetCol);
        tree.invalidateColumn(column);
        col.mTargetCol = targetCol;
        col.mTargetDir = pos.value;
      }
    }

    _onDragMouseUp() {
      var col = document.treecolDragging;
      if (!col) {
        return;
      }

      if (!col.mDragGesturing) {
        if (col.mTargetCol) {
          // remove insertbefore/after attributes
          var before = col.mTargetCol.hasAttribute("insertbefore");
          col.mTargetCol.removeAttribute(
            before ? "insertbefore" : "insertafter"
          );

          var sib = col.mTargetCol._previousVisibleColumn;
          if (before && sib) {
            sib.removeAttribute("insertafter");
          }

          // Move the column only if it will result in a different column
          // ordering
          var move = true;

          // If this is a before move and the previous visible column is
          // the same as the column we're moving, don't move
          if (before && col == sib) {
            move = false;
          } else if (!before && col == col.mTargetCol) {
            // If this is an after move and the column we're moving is
            // the same as the target column, don't move.
            move = false;
          }

          if (move) {
            col.parentNode.parentNode._reorderColumn(
              col,
              col.mTargetCol,
              before
            );
          }

          // repaint to remove lines
          col.parentNode.parentNode.invalidate();

          col.mTargetCol = null;
        }
      } else {
        col.mDragGesturing = false;
      }

      document.treecolDragging = null;
      col.removeAttribute("dragging");

      window.removeEventListener("mousemove", col._onDragMouseMove, true);
      window.removeEventListener("mouseup", col._onDragMouseUp, true);
      // we have to wait for the click event to fire before removing
      // cancelling handler
      var clickHandler = function (handler) {
        window.removeEventListener("click", handler, true);
      };
      window.setTimeout(clickHandler, 0, col._onDragMouseClick);
    }

    _onDragMouseClick(aEvent) {
      // prevent click event from firing after column drag and drop
      aEvent.stopPropagation();
      aEvent.preventDefault();
    }
  }

  customElements.define("treecol", MozTreecol);

  class MozTreecols extends MozElements.BaseControl {
    static get inheritedAttributes() {
      return {
        treecolpicker: "tooltiptext=pickertooltiptext",
      };
    }

    static get markup() {
      return `
      <treecolpicker fixed="true"></treecolpicker>
      `;
    }

    connectedCallback() {
      if (this.delayConnectedCallback()) {
        return;
      }

      this.setAttribute("slot""treecols");

      if (!this.querySelector("treecolpicker")) {
        this.appendChild(this.constructor.fragment);
        this.initializeAttributeInheritance();
      }

      // Set resizeafter="farthest" on the splitters if nothing else has been
      // specified.
      for (let splitter of this.getElementsByTagName("splitter")) {
        if (!splitter.hasAttribute("resizeafter")) {
          splitter.setAttribute("resizeafter""farthest");
        }
      }
    }
  }

  customElements.define("treecols", MozTreecols);

  class MozTree extends MozElements.BaseControlMixin(
    MozElements.MozElementMixin(XULTreeElement)
  ) {
    static get markup() {
      return `
      <html:link rel="stylesheet" href="chrome://global/content/widgets.css" />
      <html:slot name="treecols"></html:slot>
      <stack class="tree-stack" flex="1">
        <hbox class="tree-rows" flex="1">
          <html:slot name="treechildren"></html:slot>
          <scrollbar height="0" minwidth="0" minheight="0" orient="vertical"
                     class="hidevscroll-scrollbar scrollbar-topmost"
                     ></scrollbar>
        </hbox>
        <html:input class="tree-input" type="text" hidden="true"/>
      </stack>
      `;
    }

    constructor() {
      super();

      // These enumerated constants are used as the first argument to
      // _ensureColumnOrder to specify what column ordering should be used.
      this.CURRENT_ORDER = 0;
      this.NATURAL_ORDER = 1; // The original order, which is the DOM ordering

      this.attachShadow({ mode: "open" });
      let handledElements = this.constructor.fragment.querySelectorAll(
        "scrollbar,scrollcorner"
      );
      let stopAndPrevent = e => {
        e.stopPropagation();
        e.preventDefault();
      };
      let stopProp = e => e.stopPropagation();
      for (let el of handledElements) {
        el.addEventListener("click", stopAndPrevent);
        el.addEventListener("contextmenu", stopAndPrevent);
        el.addEventListener("dblclick", stopProp);
        el.addEventListener("command", stopProp);
      }
      this.shadowRoot.appendChild(this.constructor.fragment);

      this.#verticalScrollbar = this.shadowRoot.querySelector(
        "scrollbar[orient='vertical']"
      );
    }

    static get inheritedAttributes() {
      return {
        ".hidevscroll-scrollbar""collapsed=hidevscroll",
        ".hidevscroll-scrollcorner""collapsed=hidevscroll",
      };
    }

    connectedCallback() {
      if (this.delayConnectedCallback()) {
        return;
      }
      if (!this._eventListenersSetup) {
        this._eventListenersSetup = true;
        this.setupEventListeners();
      }

      this.setAttribute("hidevscroll""true");

      this.initializeAttributeInheritance();

      this.pageUpOrDownMovesSelection = AppConstants.platform != "macosx";

      this._inputField = null;

      this._editingRow = -1;

      this._editingColumn = null;

      this._columnsDirty = true;

      this._lastKeyTime = 0;

      this._incrementalString = "";

      this._touchY = -1;
    }

    setupEventListeners() {
      this.addEventListener("underflow", event => {
        // Scrollport event orientation
        // 0: vertical
        // 1: horizontal
        // 2: both (not used)
        if (event.target.tagName != "treechildren") {
          return;
        }
        if (event.detail == 0) {
          this.setAttribute("hidevscroll""true");
        }
        event.stopPropagation();
      });

      this.addEventListener("overflow", event => {
        if (event.target.tagName != "treechildren") {
          return;
        }
        if (event.detail == 0) {
          this.removeAttribute("hidevscroll");
        }
        event.stopPropagation();
      });

      this.addEventListener("touchstart", event => {
        function isScrollbarElement(target) {
          return (
            (target.localName == "thumb" || target.localName == "slider") &&
            target.namespaceURI ==
              "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
          );
        }
        if (
          event.touches.length > 1 ||
          isScrollbarElement(event.touches[0].target)
        ) {
          // Multiple touch points detected, abort. In particular this aborts
          // the panning gesture when the user puts a second finger down after
          // already panning with one finger. Aborting at this point prevents
          // the pan gesture from being resumed until all fingers are lifted
          // (as opposed to when the user is back down to one finger).
          // Additionally, if the user lands on the scrollbar don't use this
          // code for scrolling, instead allow gecko to handle scrollbar
          // interaction normally.
          this._touchY = -1;
        } else {
          this._touchY = event.touches[0].screenY;
        }
      });

      this.addEventListener("touchmove", event => {
        if (event.touches.length == 1 && this._touchY >= 0) {
          var deltaY = this._touchY - event.touches[0].screenY;
          var lines = Math.trunc(deltaY / this.rowHeight);
          if (Math.abs(lines) > 0) {
            this.scrollByLines(lines);
            deltaY -= lines * this.rowHeight;
            this._touchY = event.touches[0].screenY + deltaY;
          }
          event.preventDefault();
        }
      });

      this.addEventListener("touchend", () => {
        this._touchY = -1;
      });

      // This event doesn't retarget, so listen on the shadow DOM directly
      this.shadowRoot.addEventListener("MozMousePixelScroll", event => {
        if (this.#canScroll(event)) {
          event.preventDefault();
        }
      });

      // This event doesn't retarget, so listen on the shadow DOM directly
      this.shadowRoot.addEventListener("DOMMouseScroll", event => {
        if (!this.#canScroll(event)) {
          return;
        }

        event.preventDefault();

        if (this._editingColumn) {
          return;
        }

        var rows = event.detail;
        if (rows == UIEvent.SCROLL_PAGE_UP) {
          this.scrollByPages(-1);
        } else if (rows == UIEvent.SCROLL_PAGE_DOWN) {
          this.scrollByPages(1);
        } else {
          this.scrollByLines(rows);
        }
      });

      this.addEventListener("MozSwipeGesture", event => {
        // Figure out which row to show
        let targetRow = 0;

        // Only handle swipe gestures up and down
        switch (event.direction) {
          case event.DIRECTION_DOWN:
            targetRow = this.view.rowCount - 1;
          // Fall through for actual action
          case event.DIRECTION_UP:
            this.ensureRowIsVisible(targetRow);
            break;
        }
      });

      this.addEventListener("select", event => {
        if (event.originalTarget == this) {
          this.stopEditing(true);
        }
      });

      this.addEventListener("focus", () => {
        this.focused = true;
        if (this.currentIndex == -1 && this.view.rowCount > 0) {
          this.currentIndex = this.getFirstVisibleRow();
        }
      });

      this.addEventListener(
        "blur",
        event => {
          this.focused = false;
          if (event.target == this.inputField) {
            this.stopEditing(true);
          }
        },
        true
      );

      this.addEventListener("keydown", event => {
        if (event.altKey) {
          return;
        }

        let toggleClose = () => {
          if (this._editingColumn) {
            return;
          }

          let row = this.currentIndex;
          if (row < 0) {
            return;
          }

          if (this.changeOpenState(this.currentIndex, false)) {
            event.preventDefault();
            return;
          }

          let parentIndex = this.view.getParentIndex(this.currentIndex);
          if (parentIndex >= 0) {
            this.view.selection.select(parentIndex);
            this.ensureRowIsVisible(parentIndex);
            event.preventDefault();
          }
        };

        let toggleOpen = () => {
          if (this._editingColumn) {
            return;
          }

          let row = this.currentIndex;
          if (row < 0) {
            return;
          }

          if (this.changeOpenState(row, true)) {
            event.preventDefault();
            return;
          }
          let c = row + 1;
          let view = this.view;
          if (c < view.rowCount && view.getParentIndex(c) == row) {
            // If already opened, select the first child.
            // The getParentIndex test above ensures that the children
            // are already populated and ready.
            this.view.selection.timedSelect(c, this._selectDelay);
            this.ensureRowIsVisible(c);
            event.preventDefault();
          }
        };

        switch (event.keyCode) {
          case KeyEvent.DOM_VK_RETURN: {
            if (this._handleEnter(event)) {
              event.stopPropagation();
              event.preventDefault();
            }
            break;
          }
          case KeyEvent.DOM_VK_ESCAPE: {
            if (this._editingColumn) {
              this.stopEditing(false);
              this.focus();
              event.stopPropagation();
              event.preventDefault();
            }
            break;
          }
          case KeyEvent.DOM_VK_LEFT: {
            if (!this.isRTL) {
              toggleClose();
            } else {
              toggleOpen();
            }
            break;
          }
          case KeyEvent.DOM_VK_RIGHT: {
            if (!this.isRTL) {
              toggleOpen();
            } else {
              toggleClose();
            }
            break;
          }
          case KeyEvent.DOM_VK_UP: {
            if (this._editingColumn) {
              return;
            }

            if (event.getModifierState("Shift")) {
              this._moveByOffsetShift(-1, 0, event);
            } else {
              this._moveByOffset(-1, 0, event);
            }
            break;
          }
          case KeyEvent.DOM_VK_DOWN: {
            if (this._editingColumn) {
              return;
            }
            if (event.getModifierState("Shift")) {
              this._moveByOffsetShift(1, this.view.rowCount - 1, event);
            } else {
              this._moveByOffset(1, this.view.rowCount - 1, event);
            }
            break;
          }
          case KeyEvent.DOM_VK_PAGE_UP: {
            if (this._editingColumn) {
              return;
            }

            if (event.getModifierState("Shift")) {
              this._moveByPageShift(-1, 0, event);
            } else {
              this._moveByPage(-1, 0, event);
            }
            break;
          }
          case KeyEvent.DOM_VK_PAGE_DOWN: {
            if (this._editingColumn) {
              return;
            }

            if (event.getModifierState("Shift")) {
              this._moveByPageShift(1, this.view.rowCount - 1, event);
            } else {
              this._moveByPage(1, this.view.rowCount - 1, event);
            }
            break;
          }
          case KeyEvent.DOM_VK_HOME: {
            if (this._editingColumn) {
              return;
            }

            if (event.getModifierState("Shift")) {
              this._moveToEdgeShift(0, event);
            } else {
              this._moveToEdge(0, event);
            }
            break;
          }
          case KeyEvent.DOM_VK_END: {
            if (this._editingColumn) {
              return;
            }

            if (event.getModifierState("Shift")) {
              this._moveToEdgeShift(this.view.rowCount - 1, event);
            } else {
              this._moveToEdge(this.view.rowCount - 1, event);
            }
            break;
          }
        }
      });

      this.addEventListener("keypress", event => {
        if (this._editingColumn) {
          return;
        }

        if (event.charCode == " ".charCodeAt(0)) {
          var c = this.currentIndex;
          if (
            !this.view.selection.isSelected(c) ||
            (!this.view.selection.single && event.getModifierState("Accel"))
          ) {
            this.view.selection.toggleSelect(c);
            event.preventDefault();
          }
        } else if (
          !this.disableKeyNavigation &&
          event.charCode > 0 &&
          !event.altKey &&
          !event.getModifierState("Accel") &&
          !event.metaKey &&
          !event.ctrlKey
        ) {
          var l = this._keyNavigate(event);
          if (l >= 0) {
            this.view.selection.timedSelect(l, this._selectDelay);
            this.ensureRowIsVisible(l);
          }
          event.preventDefault();
        }
      });
    }

    get body() {
      return this.treeBody;
    }

    get isRTL() {
      return document.defaultView.getComputedStyle(this).direction == "rtl";
    }

    set editable(val) {
      if (val) {
        this.setAttribute("editable""true");
      } else {
        this.removeAttribute("editable");
      }
    }

    get editable() {
      return this.getAttribute("editable") == "true";
    }
    /**
     * ///////////////// nsIDOMXULSelectControlElement /////////////////  ///////////////// nsIDOMXULMultiSelectControlElement /////////////////
     */

    set selType(val) {
      this.setAttribute("seltype", val);
    }

    get selType() {
      return this.getAttribute("seltype") || "";
    }

    set currentIndex(val) {
      if (this.view) {
        this.view.selection.currentIndex = val;
      }
    }

    get currentIndex() {
      if (this.view && this.view.selection) {
        return this.view.selection.currentIndex;
      }
      return -1;
    }

    set keepCurrentInView(val) {
      if (val) {
        this.setAttribute("keepcurrentinview""true");
      } else {
        this.removeAttribute("keepcurrentinview");
      }
    }

    get keepCurrentInView() {
      return this.getAttribute("keepcurrentinview") == "true";
    }

    set enableColumnDrag(val) {
      if (val) {
        this.setAttribute("enableColumnDrag""true");
      } else {
        this.removeAttribute("enableColumnDrag");
      }
    }

    get enableColumnDrag() {
      return this.hasAttribute("enableColumnDrag");
    }

    get inputField() {
      if (!this._inputField) {
        this._inputField = this.shadowRoot.querySelector(".tree-input");
        this._inputField.addEventListener("blur", () => this.stopEditing(true));
      }
      return this._inputField;
    }

    set disableKeyNavigation(val) {
      if (val) {
        this.setAttribute("disableKeyNavigation""true");
      } else {
        this.removeAttribute("disableKeyNavigation");
      }
    }

    get disableKeyNavigation() {
      return this.hasAttribute("disableKeyNavigation");
    }

    get editingRow() {
      return this._editingRow;
    }

    get editingColumn() {
      return this._editingColumn;
    }

    set _selectDelay(val) {
      this.setAttribute("_selectDelay", val);
    }

    get _selectDelay() {
      return this.getAttribute("_selectDelay") || 50;
    }

    // The first argument (order) can be either one of these constants:
    //   this.CURRENT_ORDER
    //   this.NATURAL_ORDER
    _ensureColumnOrder(order = this.CURRENT_ORDER) {
      if (this.columns) {
        // update the ordinal position of each column to assure that it is
        // an odd number and 2 positions above its next sibling
        var cols = [];

        if (order == this.CURRENT_ORDER) {
          for (
            let col = this.columns.getFirstColumn();
            col;
            col = col.getNext()
          ) {
            cols.push(col.element);
          }
        } else {
          // order == this.NATURAL_ORDER
          cols = this.getElementsByTagName("treecol");
        }

        for (let i = 0; i < cols.length; ++i) {
          cols[i].ordinal = i * 2 + 1;
        }
        // update the ordinal positions of splitters to even numbers, so that
        // they are in between columns
        var splitters = this.getElementsByTagName("splitter");
        for (let i = 0; i < splitters.length; ++i) {
          splitters[i].style.order = (i + 1) * 2;
        }
      }
    }

    _reorderColumn(aColMove, aColBefore, aBefore) {
      this._ensureColumnOrder();

      var i;
      var cols = [];
      var col = this.columns.getColumnFor(aColBefore);
      if (parseInt(aColBefore.ordinal) < parseInt(aColMove.ordinal)) {
        if (aBefore) {
          cols.push(aColBefore);
        }
        for (
          col = col.getNext();
          col.element != aColMove;
          col = col.getNext()
        ) {
          cols.push(col.element);
        }

        aColMove.ordinal = cols[0].ordinal;
        for (i = 0; i < cols.length; ++i) {
          cols[i].ordinal = parseInt(cols[i].ordinal) + 2;
        }
      } else if (aColBefore.ordinal != aColMove.ordinal) {
        if (!aBefore) {
          cols.push(aColBefore);
        }
        for (
          col = col.getPrevious();
          col.element != aColMove;
          col = col.getPrevious()
        ) {
          cols.push(col.element);
        }

        aColMove.ordinal = cols[0].ordinal;
        for (i = 0; i < cols.length; ++i) {
          cols[i].ordinal = parseInt(cols[i].ordinal) - 2;
        }
      } else {
        return;
      }
      this.columns.invalidateColumns();
    }

    _getColumnAtX(aX, aThresh, aPos) {
      let isRTL = this.isRTL;

      if (aPos) {
        aPos.value = isRTL ? "after" : "before";
      }

      var columns = [];
      var col = this.columns.getFirstColumn();
      while (col) {
        columns.push(col);
        col = col.getNext();
      }
      if (isRTL) {
        columns.reverse();
      }
      var currentX = this.getBoundingClientRect().x;
      for (var i = 0; i < columns.length; ++i) {
        col = columns[i];
        var cw = col.element.getBoundingClientRect().width;
        if (cw > 0) {
          currentX += cw;
          if (currentX - cw * aThresh > aX) {
            return col.element;
          }
        }
      }

      if (aPos) {
        aPos.value = isRTL ? "before" : "after";
      }
      return columns.pop().element;
    }

    changeOpenState(row, openState) {
      if (row < 0 || !this.view.isContainer(row)) {
        return false;
      }

      if (this.view.isContainerOpen(row) != openState) {
        this.view.toggleOpenState(row);
        if (row == this.currentIndex) {
          // Only fire event when current row is expanded or collapsed
          // because that's all the assistive technology really cares about.
          var event = document.createEvent("Events");
          event.initEvent("OpenStateChange"truetrue);
          this.dispatchEvent(event);
        }
        return true;
      }
      return false;
    }

    _keyNavigate(event) {
      var key = String.fromCharCode(event.charCode).toLowerCase();
      if (event.timeStamp - this._lastKeyTime > 1000) {
        this._incrementalString = key;
      } else {
        this._incrementalString += key;
      }
      this._lastKeyTime = event.timeStamp;

      var length = this._incrementalString.length;
      var incrementalString = this._incrementalString;
      var charIndex = 1;
      while (
        charIndex < length &&
        incrementalString[charIndex] == incrementalString[charIndex - 1]
      ) {
        charIndex++;
      }
      // If all letters in incremental string are same, just try to match the first one
      if (charIndex == length) {
        length = 1;
        incrementalString = incrementalString.substring(0, length);
      }

      var keyCol = this.columns.getKeyColumn();
      var rowCount = this.view.rowCount;
      var start = 1;

      var c = this.currentIndex;
      if (length > 1) {
        start = 0;
        if (c < 0) {
          c = 0;
        }
      }

      for (var i = 0; i < rowCount; i++) {
        var l = (i + start + c) % rowCount;
        var cellText = this.view.getCellText(l, keyCol);
        cellText = cellText.substring(0, length).toLowerCase();
        if (cellText == incrementalString) {
          return l;
        }
      }
      return -1;
    }

    startEditing(row, column) {
      if (!this.editable) {
        return false;
      }
      if (row < 0 || row >= this.view.rowCount || !column) {
        return false;
      }
      if (column.type !== window.TreeColumn.TYPE_TEXT) {
        return false;
      }
      if (column.cycler || !this.view.isEditable(row, column)) {
        return false;
      }

      // Beyond this point, we are going to edit the cell.
      if (this._editingColumn) {
        this.stopEditing();
      }

      var input = this.inputField;

      this.ensureCellIsVisible(row, column);

      // Get the coordinates of the text inside the cell.
      var textRect = this.getCoordsForCellItem(row, column, "text");

      // Get the coordinates of the cell itself.
      var cellRect = this.getCoordsForCellItem(row, column, "cell");

      // Calculate the top offset of the textbox.
      var style = window.getComputedStyle(input);
      var topadj = parseInt(style.borderTopWidth) + parseInt(style.paddingTop);
      input.style.top = `${textRect.y - topadj}px`;

      // The leftside of the textbox is aligned to the left side of the text
      // in LTR mode, and left side of the cell in RTL mode.
      let left = style.direction == "rtl" ? cellRect.x : textRect.x;
      let scrollbarWidth = window.windowUtils.getBoundsWithoutFlushing(
        this.#verticalScrollbar
      ).width;
      // Note: this won't be quite right in RTL for trees using twisties
      // or indentation. bug 1708159 tracks fixing the implementation
      // of getCoordsForCellItem which we called above so it provides
      // better numbers in those cases.
      let widthdiff = Math.abs(textRect.x - cellRect.x) - scrollbarWidth;

      input.style.left = `${left}px`;
      input.style.height = `${
        textRect.height +
        topadj +
        parseInt(style.borderBottomWidth) +
        parseInt(style.paddingBottom)
      }px`;
      input.style.width = `${cellRect.width - widthdiff}px`;
      input.hidden = false;

      input.value = this.view.getCellText(row, column);

      input.select();
      input.focus();

      this._editingRow = row;
      this._editingColumn = column;
      this.setAttribute("editing""true");

      this.invalidateCell(row, column);
      return true;
    }

    stopEditing(accept) {
      if (!this._editingColumn) {
        return;
      }

      var input = this.inputField;
      var editingRow = this._editingRow;
      var editingColumn = this._editingColumn;
      this._editingRow = -1;
      this._editingColumn = null;

      // `this.view` could be null if the tree was hidden before we were called.
      if (accept && this.view) {
        var value = input.value;
        this.view.setCellText(editingRow, editingColumn, value);
      }
      input.hidden = true;
      input.value = "";
      this.removeAttribute("editing");
    }

    _moveByOffset(offset, edge, event) {
      event.preventDefault();

      if (this.view.rowCount == 0) {
        return;
      }

      if (event.getModifierState("Accel") && this.view.selection.single) {
        this.scrollByLines(offset);
        return;
      }

      var c = this.currentIndex + offset;
      if (offset > 0 ? c > edge : c < edge) {
        if (
          this.view.selection.isSelected(edge) &&
          this.view.selection.count <= 1
        ) {
          return;
        }
        c = edge;
      }

      if (!event.getModifierState("Accel")) {
        this.view.selection.timedSelect(c, this._selectDelay);
      }
      // Ctrl+Up/Down moves the anchor without selecting
      else {
        this.currentIndex = c;
      }
      this.ensureRowIsVisible(c);
    }

    _moveByOffsetShift(offset, edge, event) {
      event.preventDefault();

      if (this.view.rowCount == 0) {
        return;
      }

      if (this.view.selection.single) {
        this.scrollByLines(offset);
        return;
      }

      if (this.view.rowCount == 1 && !this.view.selection.isSelected(0)) {
        this.view.selection.timedSelect(0, this._selectDelay);
        return;
      }

      var c = this.currentIndex;
      if (c == -1) {
        c = 0;
      }

      if (c == edge) {
        if (this.view.selection.isSelected(c)) {
          return;
        }
      }

      // Extend the selection from the existing pivot, if any
      this.view.selection.rangedSelect(
        -1,
        c + offset,
        event.getModifierState("Accel")
      );
      this.ensureRowIsVisible(c + offset);
    }

    _moveByPage(offset, edge, event) {
      event.preventDefault();

      if (this.view.rowCount == 0) {
        return;
      }

      if (this.pageUpOrDownMovesSelection == event.getModifierState("Accel")) {
        this.scrollByPages(offset);
        return;
      }

      if (this.view.rowCount == 1 && !this.view.selection.isSelected(0)) {
        this.view.selection.timedSelect(0, this._selectDelay);
        return;
      }

      var c = this.currentIndex;
      if (c == -1) {
        return;
      }

      if (c == edge && this.view.selection.isSelected(c)) {
        this.ensureRowIsVisible(c);
        return;
      }
      var i = this.getFirstVisibleRow();
      var p = this.getPageLength();

      if (offset > 0) {
        i += p - 1;
        if (c >= i) {
          i = c + p;
          this.ensureRowIsVisible(i > edge ? edge : i);
        }
        i = i > edge ? edge : i;
      } else if (c <= i) {
        i = c <= p ? 0 : c - p;
        this.ensureRowIsVisible(i);
      }
      this.view.selection.timedSelect(i, this._selectDelay);
    }

    _moveByPageShift(offset, edge, event) {
      event.preventDefault();

      if (this.view.rowCount == 0) {
        return;
      }

      if (
        this.view.rowCount == 1 &&
        !this.view.selection.isSelected(0) &&
        !(this.pageUpOrDownMovesSelection == event.getModifierState("Accel"))
      ) {
        this.view.selection.timedSelect(0, this._selectDelay);
        return;
      }

      if (this.view.selection.single) {
        return;
      }

      var c = this.currentIndex;
      if (c == -1) {
        return;
      }
      if (c == edge && this.view.selection.isSelected(c)) {
        this.ensureRowIsVisible(edge);
        return;
      }
      var i = this.getFirstVisibleRow();
      var p = this.getPageLength();

      if (offset > 0) {
        i += p - 1;
        if (c >= i) {
          i = c + p;
          this.ensureRowIsVisible(i > edge ? edge : i);
        }
        // Extend the selection from the existing pivot, if any
        this.view.selection.rangedSelect(
          -1,
          i > edge ? edge : i,
          event.getModifierState("Accel")
        );
      } else {
        if (c <= i) {
          i = c <= p ? 0 : c - p;
          this.ensureRowIsVisible(i);
        }
        // Extend the selection from the existing pivot, if any
        this.view.selection.rangedSelect(
          -1,
          i,
          event.getModifierState("Accel")
        );
      }
    }

    _moveToEdge(edge, event) {
      event.preventDefault();

      if (this.view.rowCount == 0) {
        return;
      }

      if (
        this.view.selection.isSelected(edge) &&
        this.view.selection.count == 1
      ) {
        this.currentIndex = edge;
        return;
      }

      // Normal behaviour is to select the first/last row
      if (!event.getModifierState("Accel")) {
        this.view.selection.timedSelect(edge, this._selectDelay);
      }
      // In a multiselect tree Ctrl+Home/End moves the anchor
      else if (!this.view.selection.single) {
        this.currentIndex = edge;
      }

      this.ensureRowIsVisible(edge);
    }

    _moveToEdgeShift(edge, event) {
      event.preventDefault();

      if (this.view.rowCount == 0) {
        return;
      }

      if (this.view.rowCount == 1 && !this.view.selection.isSelected(0)) {
        this.view.selection.timedSelect(0, this._selectDelay);
        return;
      }

      if (
        this.view.selection.single ||
        (this.view.selection.isSelected(edge) &&
          this.view.selection.isSelected(this.currentIndex))
      ) {
        return;
      }

      // Extend the selection from the existing pivot, if any.
      // -1 doesn't work here, so using currentIndex instead
      this.view.selection.rangedSelect(
        this.currentIndex,
        edge,
        event.getModifierState("Accel")
      );

      this.ensureRowIsVisible(edge);
    }

    _handleEnter() {
      if (this._editingColumn) {
        this.stopEditing(true);
        this.focus();
        return true;
      }

      return this.changeOpenState(this.currentIndex);
    }

    #verticalScrollbar = null;
    #lastScrollEventTimeStampMap = new Map();

    #canScroll(event) {
      const lastScrollEventTimeStamp = this.#lastScrollEventTimeStampMap.get(
        event.type
      );
      this.#lastScrollEventTimeStampMap.set(event.type, event.timeStamp);

      if (
        window.windowUtils.getWheelScrollTarget() ||
        event.axis == event.HORIZONTAL_AXIS ||
        (this.getAttribute("allowunderflowscroll") == "true" &&
          this.getAttribute("hidevscroll") == "true")
      ) {
        return false;
      }

      if (
        event.timeStamp - (lastScrollEventTimeStamp ?? 0) <
        Services.prefs.getIntPref("mousewheel.scroll_series_timeout")
      ) {
        // If the time difference of previous event does not over the timeout,
        // handle the event in tree as the same seies of events even if the
        // current position is edge.
        return true;
      }

      const curpos = Number(this.#verticalScrollbar.getAttribute("curpos"));
      return (
        (event.detail < 0 && 0 < curpos) ||
        (event.detail > 0 &&
          curpos < Number(this.#verticalScrollbar.getAttribute("maxpos")))
      );
    }
  }

  MozXULElement.implementCustomInterface(MozTree, [
    Ci.nsIDOMXULMultiSelectControlElement,
  ]);
  customElements.define("tree", MozTree);
}

Messung V0.5
C=95 H=94 G=94

¤ Dauer der Verarbeitung: 0.26 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 und die Messung sind noch experimentell.