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 29 kB image not shown  

Quelle  richlistbox.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";

// 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"
  );

  /**
   * XUL:richlistbox element.
   */

  MozElements.RichListBox = class RichListBox extends MozElements.BaseControl {
    constructor() {
      super();

      this.selectedItems = new ChromeNodeList();
      this._currentIndex = null;
      this._lastKeyTime = 0;
      this._incrementalString = "";
      this._suppressOnSelect = false;
      this._userSelecting = false;
      this._selectTimeout = null;
      this._currentItem = null;
      this._selectionStart = null;

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

          switch (event.keyCode) {
            case KeyEvent.DOM_VK_UP:
              this._moveByOffsetFromUserEvent(-1, event);
              break;
            case KeyEvent.DOM_VK_DOWN:
              this._moveByOffsetFromUserEvent(1, event);
              break;
            case KeyEvent.DOM_VK_HOME:
              this._moveByOffsetFromUserEvent(-this.currentIndex, event);
              break;
            case KeyEvent.DOM_VK_END:
              this._moveByOffsetFromUserEvent(
                this.getRowCount() - this.currentIndex - 1,
                event
              );
              break;
            case KeyEvent.DOM_VK_PAGE_UP:
              this._moveByOffsetFromUserEvent(this.scrollOnePage(-1), event);
              break;
            case KeyEvent.DOM_VK_PAGE_DOWN:
              this._moveByOffsetFromUserEvent(this.scrollOnePage(1), event);
              break;
          }
        },
        { mozSystemGroup: true }
      );

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

        if (
          event.key == " " &&
          event.ctrlKey &&
          !event.shiftKey &&
          !event.altKey &&
          !event.metaKey &&
          this.currentItem &&
          this.selType == "multiple"
        ) {
          this.toggleItemSelection(this.currentItem);
        }

        if (!event.charCode || event.altKey || event.ctrlKey || event.metaKey) {
          return;
        }

        if (event.timeStamp - this._lastKeyTime > 1000) {
          this._incrementalString = "";
        }

        var key = String.fromCharCode(event.charCode).toLowerCase();
        this._incrementalString += key;
        this._lastKeyTime = event.timeStamp;

        // If all letters in the incremental string are the same, just
        // try to match the first one
        var incrementalString = /^(.)\1+$/.test(this._incrementalString)
          ? RegExp.$1
          : this._incrementalString;
        var length = incrementalString.length;

        var rowCount = this.getRowCount();
        var l = this.selectedItems.length;
        var start = l > 0 ? this.getIndexOfItem(this.selectedItems[l - 1]) : -1;
        // start from the first element if none was selected or from the one
        // following the selected one if it's a new or a repeated-letter search
        if (start == -1 || length == 1) {
          start++;
        }

        for (var i = 0; i < rowCount; i++) {
          var k = (start + i) % rowCount;
          var listitem = this.getItemAtIndex(k);
          if (!this.canUserSelect(listitem)) {
            continue;
          }
          // allow richlistitems to specify the string being searched for
          var searchText =
            "searchLabel" in listitem
              ? listitem.searchLabel
              : listitem.getAttribute("label") || ""// (see also bug 250123)
          searchText = searchText.substring(0, length).toLowerCase();
          if (searchText == incrementalString) {
            this.ensureIndexIsVisible(k);
            this.timedSelect(listitem, this._selectDelay);
            break;
          }
        }
      });

      this.addEventListener("focus", () => {
        if (this.getRowCount() > 0) {
          if (this.currentIndex == -1) {
            this.currentIndex = this.getIndexOfFirstVisibleRow();
            let currentItem = this.getItemAtIndex(this.currentIndex);
            if (currentItem) {
              this.selectItem(currentItem);
            }
          } else {
            this._fireEvent(this.currentItem, "DOMMenuItemActive");
          }
        }
        this._lastKeyTime = 0;
      });

      this.addEventListener("click", event => {
        // clicking into nothing should unselect multiple selections
        if (event.originalTarget == this && this.selType == "multiple") {
          this.clearSelection();
          this.currentItem = null;
        }
      });

      this.addEventListener("MozSwipeGesture", event => {
        // Only handle swipe gestures up and down
        switch (event.direction) {
          case event.DIRECTION_DOWN:
            this.scrollTop = this.scrollHeight;
            break;
          case event.DIRECTION_UP:
            this.scrollTop = 0;
            break;
        }
      });
    }

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

      this.setAttribute("allowevents""true");
      this._refreshSelection();
    }

    // nsIDOMXULSelectControlElement
    set selectedItem(val) {
      this.selectItem(val);
    }
    get selectedItem() {
      return this.selectedItems.length ? this.selectedItems[0] : null;
    }

    // nsIDOMXULSelectControlElement
    set selectedIndex(val) {
      if (val >= 0) {
        // This is a micro-optimization so that a call to getIndexOfItem or
        // getItemAtIndex caused by _fireOnSelect (especially for derived
        // widgets) won't loop the children.
        this._selecting = {
          item: this.getItemAtIndex(val),
          index: val,
        };
        this.selectItem(this._selecting.item);
        delete this._selecting;
      } else {
        this.clearSelection();
        this.currentItem = null;
      }
    }
    get selectedIndex() {
      if (this.selectedItems.length) {
        return this.getIndexOfItem(this.selectedItems[0]);
      }
      return -1;
    }

    // nsIDOMXULSelectControlElement
    set value(val) {
      var kids = this.getElementsByAttribute("value", val);
      if (kids && kids.item(0)) {
        this.selectItem(kids[0]);
      }
    }
    get value() {
      if (this.selectedItems.length) {
        return this.selectedItem.value;
      }
      return null;
    }

    // nsIDOMXULSelectControlElement
    get itemCount() {
      return this.itemChildren.length;
    }

    // nsIDOMXULSelectControlElement
    set selType(val) {
      this.setAttribute("seltype", val);
    }
    get selType() {
      return this.getAttribute("seltype") || "";
    }

    // nsIDOMXULSelectControlElement
    set currentItem(val) {
      if (this._currentItem == val) {
        return;
      }

      if (this._currentItem) {
        this._currentItem.current = false;
        if (!val && !this.suppressMenuItemEvent) {
          // An item is losing focus and there is no new item to focus.
          // Notify a11y that there is no focused item.
          this._fireEvent(this._currentItem, "DOMMenuItemInactive");
        }
      }
      this._currentItem = val;

      if (val) {
        val.current = true;
        if (!this.suppressMenuItemEvent) {
          // Notify a11y that this item got focus.
          this._fireEvent(val, "DOMMenuItemActive");
        }
      }
    }
    get currentItem() {
      return this._currentItem;
    }

    // nsIDOMXULSelectControlElement
    set currentIndex(val) {
      if (val >= 0) {
        this.currentItem = this.getItemAtIndex(val);
      } else {
        this.currentItem = null;
      }
    }
    get currentIndex() {
      return this.currentItem ? this.getIndexOfItem(this.currentItem) : -1;
    }

    // nsIDOMXULSelectControlElement
    get selectedCount() {
      return this.selectedItems.length;
    }

    get itemChildren() {
      let children = Array.from(this.children).filter(
        node => node.localName == "richlistitem"
      );
      return children;
    }

    set suppressOnSelect(val) {
      this.setAttribute("suppressonselect", val);
    }
    get suppressOnSelect() {
      return this.getAttribute("suppressonselect") == "true";
    }

    set _selectDelay(val) {
      this.setAttribute("_selectDelay", val);
    }
    get _selectDelay() {
      return this.getAttribute("_selectDelay") || 50;
    }

    _fireOnSelect() {
      // make sure not to modify last-selected when suppressing select events
      // (otherwise we'll lose the selection when a template gets rebuilt)
      if (this._suppressOnSelect || this.suppressOnSelect) {
        return;
      }

      // remember the current item and all selected items with IDs
      var state = this.currentItem ? this.currentItem.id : "";
      if (this.selType == "multiple" && this.selectedCount) {
        let getId = function getId(aItem) {
          return aItem.id;
        };
        state +=
          " " + [...this.selectedItems].filter(getId).map(getId).join(" ");
      }
      if (state) {
        this.setAttribute("last-selected", state);
      } else {
        this.removeAttribute("last-selected");
      }

      // preserve the index just in case no IDs are available
      if (this.currentIndex > -1) {
        this._currentIndex = this.currentIndex + 1;
      }

      var event = document.createEvent("Events");
      event.initEvent("select"truetrue);
      this.dispatchEvent(event);

      // always call this (allows a commandupdater without controller)
      document.commandDispatcher.updateCommands("richlistbox-select");
    }

    getNextItem(aStartItem, aDelta) {
      while (aStartItem) {
        aStartItem = aStartItem.nextSibling;
        if (
          aStartItem &&
          aStartItem.localName == "richlistitem" &&
          (!this._userSelecting || this.canUserSelect(aStartItem))
        ) {
          --aDelta;
          if (aDelta == 0) {
            return aStartItem;
          }
        }
      }
      return null;
    }

    getPreviousItem(aStartItem, aDelta) {
      while (aStartItem) {
        aStartItem = aStartItem.previousSibling;
        if (
          aStartItem &&
          aStartItem.localName == "richlistitem" &&
          (!this._userSelecting || this.canUserSelect(aStartItem))
        ) {
          --aDelta;
          if (aDelta == 0) {
            return aStartItem;
          }
        }
      }
      return null;
    }

    appendItem(aLabel, aValue) {
      var item = this.ownerDocument.createXULElement("richlistitem");
      item.setAttribute("value", aValue);

      var label = this.ownerDocument.createXULElement("label");
      label.setAttribute("value", aLabel);
      label.setAttribute("flex""1");
      label.setAttribute("crop""end");
      item.appendChild(label);

      this.appendChild(item);

      return item;
    }

    // nsIDOMXULSelectControlElement
    getIndexOfItem(aItem) {
      // don't search the children, if we're looking for none of them
      if (aItem == null) {
        return -1;
      }
      if (this._selecting && this._selecting.item == aItem) {
        return this._selecting.index;
      }
      return this.itemChildren.indexOf(aItem);
    }

    // nsIDOMXULSelectControlElement
    getItemAtIndex(aIndex) {
      if (this._selecting && this._selecting.index == aIndex) {
        return this._selecting.item;
      }
      return this.itemChildren[aIndex] || null;
    }

    // nsIDOMXULMultiSelectControlElement
    addItemToSelection(aItem) {
      if (this.selType != "multiple" && this.selectedCount) {
        return;
      }

      if (aItem.selected) {
        return;
      }

      this.selectedItems.append(aItem);
      aItem.selected = true;

      this._fireOnSelect();
    }

    // nsIDOMXULMultiSelectControlElement
    removeItemFromSelection(aItem) {
      if (!aItem.selected) {
        return;
      }

      this.selectedItems.remove(aItem);
      aItem.selected = false;
      this._fireOnSelect();
    }

    // nsIDOMXULMultiSelectControlElement
    toggleItemSelection(aItem) {
      if (aItem.selected) {
        this.removeItemFromSelection(aItem);
      } else {
        this.addItemToSelection(aItem);
      }
    }

    // nsIDOMXULMultiSelectControlElement
    selectItem(aItem) {
      if (!aItem || aItem.disabled) {
        return;
      }

      if (this.selectedItems.length == 1 && this.selectedItems[0] == aItem) {
        return;
      }

      this._selectionStart = null;

      var suppress = this._suppressOnSelect;
      this._suppressOnSelect = true;

      this.clearSelection();
      this.addItemToSelection(aItem);
      this.currentItem = aItem;

      this._suppressOnSelect = suppress;
      this._fireOnSelect();
    }

    // nsIDOMXULMultiSelectControlElement
    selectItemRange(aStartItem, aEndItem) {
      if (this.selType != "multiple") {
        return;
      }

      if (!aStartItem) {
        aStartItem = this._selectionStart
          ? this._selectionStart
          : this.currentItem;
      }

      if (!aStartItem) {
        aStartItem = aEndItem;
      }

      var suppressSelect = this._suppressOnSelect;
      this._suppressOnSelect = true;

      this._selectionStart = aStartItem;

      var currentItem;
      var startIndex = this.getIndexOfItem(aStartItem);
      var endIndex = this.getIndexOfItem(aEndItem);
      if (endIndex < startIndex) {
        currentItem = aEndItem;
        aEndItem = aStartItem;
        aStartItem = currentItem;
      } else {
        currentItem = aStartItem;
      }

      while (currentItem) {
        this.addItemToSelection(currentItem);
        if (currentItem == aEndItem) {
          currentItem = this.getNextItem(currentItem, 1);
          break;
        }
        currentItem = this.getNextItem(currentItem, 1);
      }

      // Clear around new selection
      // Don't use clearSelection() because it causes a lot of noise
      // with respect to selection removed notifications used by the
      // accessibility API support.
      var userSelecting = this._userSelecting;
      this._userSelecting = false// that's US automatically unselecting
      for (; currentItem; currentItem = this.getNextItem(currentItem, 1)) {
        this.removeItemFromSelection(currentItem);
      }

      for (
        currentItem = this.getItemAtIndex(0);
        currentItem != aStartItem;
        currentItem = this.getNextItem(currentItem, 1)
      ) {
        this.removeItemFromSelection(currentItem);
      }
      this._userSelecting = userSelecting;

      this._suppressOnSelect = suppressSelect;

      this._fireOnSelect();
    }

    // nsIDOMXULMultiSelectControlElement
    selectAll() {
      this._selectionStart = null;

      var suppress = this._suppressOnSelect;
      this._suppressOnSelect = true;

      var item = this.getItemAtIndex(0);
      while (item) {
        this.addItemToSelection(item);
        item = this.getNextItem(item, 1);
      }

      this._suppressOnSelect = suppress;
      this._fireOnSelect();
    }

    // nsIDOMXULMultiSelectControlElement
    clearSelection() {
      if (this.selectedItems) {
        while (this.selectedItems.length) {
          let item = this.selectedItems[0];
          item.selected = false;
          this.selectedItems.remove(item);
        }
      }

      this._selectionStart = null;
      this._fireOnSelect();
    }

    // nsIDOMXULMultiSelectControlElement
    getSelectedItem(aIndex) {
      return aIndex < this.selectedItems.length
        ? this.selectedItems[aIndex]
        : null;
    }

    ensureIndexIsVisible(aIndex) {
      return this.ensureElementIsVisible(this.getItemAtIndex(aIndex));
    }

    ensureElementIsVisible(aElement, aAlignToTop) {
      if (!aElement) {
        return;
      }

      // These calculations assume that there is no padding on the
      // "richlistbox" element, although there might be a margin.
      var targetRect = aElement.getBoundingClientRect();
      var scrollRect = this.getBoundingClientRect();
      var offset = targetRect.top - scrollRect.top;
      if (!aAlignToTop && offset >= 0) {
        // scrollRect.bottom wouldn't take a horizontal scroll bar into account
        let scrollRectBottom = scrollRect.top + this.clientHeight;
        offset = targetRect.bottom - scrollRectBottom;
        if (offset <= 0) {
          return;
        }
      }
      this.scrollTop += offset;
    }

    getIndexOfFirstVisibleRow() {
      var children = this.itemChildren;

      for (var ix = 0; ix < children.length; ix++) {
        if (this._isItemVisible(children[ix])) {
          return ix;
        }
      }

      return -1;
    }

    getRowCount() {
      return this.itemChildren.length;
    }

    scrollOnePage(aDirection) {
      var children = this.itemChildren;

      if (!children.length) {
        return 0;
      }

      // If nothing is selected, we just select the first element
      // at the extreme we're moving away from
      if (!this.currentItem) {
        return aDirection == -1 ? children.length : 0;
      }

      // If the current item is visible, scroll by one page so that
      // the new current item is at approximately the same position as
      // the existing current item.
      let height = this.getBoundingClientRect().height;
      if (this._isItemVisible(this.currentItem)) {
        this.scrollBy(0, height * aDirection);
      }

      // Figure out, how many items fully fit into the view port
      // (including the currently selected one), and determine
      // the index of the first one lying (partially) outside
      let currentItemRect = this.currentItem.getBoundingClientRect();
      var startBorder = currentItemRect.y;
      if (aDirection == -1) {
        startBorder += currentItemRect.height;
      }

      var index = this.currentIndex;
      for (var ix = index; 0 <= ix && ix < children.length; ix += aDirection) {
        let childRect = children[ix].getBoundingClientRect();
        if (childRect.height == 0) {
          continue// hidden children have a y of 0
        }
        var endBorder = childRect.y + (aDirection == -1 ? childRect.height : 0);
        if ((endBorder - startBorder) * aDirection > height) {
          break// we've reached the desired distance
        }
        index = ix;
      }

      return index != this.currentIndex
        ? index - this.currentIndex
        : aDirection;
    }

    _refreshSelection() {
      // when this method is called, we know that either the currentItem
      // and selectedItems we have are null (ctor) or a reference to an
      // element no longer in the DOM (template).

      // first look for the last-selected attribute
      var state = this.getAttribute("last-selected");
      if (state) {
        var ids = state.split(" ");

        var suppressSelect = this._suppressOnSelect;
        this._suppressOnSelect = true;
        this.clearSelection();
        for (let i = 1; i < ids.length; i++) {
          var selectedItem = document.getElementById(ids[i]);
          if (selectedItem) {
            this.addItemToSelection(selectedItem);
          }
        }

        var currentItem = document.getElementById(ids[0]);
        if (!currentItem && this._currentIndex) {
          currentItem = this.getItemAtIndex(
            Math.min(this._currentIndex - 1, this.getRowCount())
          );
        }
        if (currentItem) {
          this.currentItem = currentItem;
          if (this.selType != "multiple" && this.selectedCount == 0) {
            this.selectedItem = currentItem;
          }

          if (this.getBoundingClientRect().height) {
            this.ensureElementIsVisible(currentItem);
          } else {
            // XXX hack around a bug in ensureElementIsVisible as it will
            // scroll beyond the last element, bug 493645.
            this.ensureElementIsVisible(currentItem.previousElementSibling);
          }
        }
        this._suppressOnSelect = suppressSelect;
        // XXX actually it's just a refresh, but at least
        // the Extensions manager expects this:
        this._fireOnSelect();
        return;
      }

      // try to restore the selected items according to their IDs
      // (applies after a template rebuild, if last-selected was not set)
      if (this.selectedItems) {
        let itemIds = [];
        for (let i = this.selectedCount - 1; i >= 0; i--) {
          let selectedItem = this.selectedItems[i];
          itemIds.push(selectedItem.id);
          this.selectedItems.remove(selectedItem);
        }
        for (let i = 0; i < itemIds.length; i++) {
          let selectedItem = document.getElementById(itemIds[i]);
          if (selectedItem) {
            this.selectedItems.append(selectedItem);
          }
        }
      }
      if (this.currentItem && this.currentItem.id) {
        this.currentItem = document.getElementById(this.currentItem.id);
      } else {
        this.currentItem = null;
      }

      // if we have no previously current item or if the above check fails to
      // find the previous nodes (which causes it to clear selection)
      if (!this.currentItem && this.selectedCount == 0) {
        this.currentIndex = this._currentIndex ? this._currentIndex - 1 : 0;

        // cf. listbox constructor:
        // select items according to their attributes
        var children = this.itemChildren;
        for (let i = 0; i < children.length; ++i) {
          if (children[i].getAttribute("selected") == "true") {
            this.selectedItems.append(children[i]);
          }
        }
      }

      if (this.selType != "multiple" && this.selectedCount == 0) {
        this.selectedItem = this.currentItem;
      }
    }

    _isItemVisible(aItem) {
      if (!aItem) {
        return false;
      }

      var y = this.getBoundingClientRect().y;

      // Partially visible items are also considered visible
      let itemRect = aItem.getBoundingClientRect();
      return (
        itemRect.y + itemRect.height > y && itemRect.y < y + this.clientHeight
      );
    }

    moveByOffset(aOffset, aIsSelecting, aIsSelectingRange, aEvent) {
      if ((aIsSelectingRange || !aIsSelecting) && this.selType != "multiple") {
        return;
      }

      var newIndex = this.currentIndex + aOffset;
      if (newIndex < 0) {
        newIndex = 0;
      }

      var numItems = this.getRowCount();
      if (newIndex > numItems - 1) {
        newIndex = numItems - 1;
      }

      var newItem = this.getItemAtIndex(newIndex);
      // make sure that the item is actually visible/selectable
      if (this._userSelecting && newItem && !this.canUserSelect(newItem)) {
        newItem =
          aOffset > 0
            ? this.getNextItem(newItem, 1) || this.getPreviousItem(newItem, 1)
            : this.getPreviousItem(newItem, 1) || this.getNextItem(newItem, 1);
      }
      if (newItem) {
        let hadFocus = this.currentItem.contains(document.activeElement);
        this.ensureIndexIsVisible(this.getIndexOfItem(newItem));
        if (aIsSelectingRange) {
          this.selectItemRange(null, newItem);
        } else if (aIsSelecting) {
          this.selectItem(newItem);
        }
        if (hadFocus) {
          let flags =
            Services.focus[
              aEvent.type.startsWith("key") ? "FLAG_BYKEY" : "FLAG_BYJS"
            ];
          Services.focus.moveFocus(
            window,
            newItem,
            Services.focus.MOVEFOCUS_FIRST,
            flags
          );
        }

        this.currentItem = newItem;
      }
    }

    _moveByOffsetFromUserEvent(aOffset, aEvent) {
      if (!aEvent.defaultPrevented) {
        this._userSelecting = true;
        this.moveByOffset(aOffset, !aEvent.ctrlKey, aEvent.shiftKey, aEvent);
        this._userSelecting = false;
        aEvent.preventDefault();
      }
    }

    canUserSelect(aItem) {
      if (aItem.disabled) {
        return false;
      }

      var style = document.defaultView.getComputedStyle(aItem);
      return (
        style.display != "none" &&
        style.visibility == "visible" &&
        style.MozUserInput != "none"
      );
    }

    _selectTimeoutHandler(aMe) {
      aMe._fireOnSelect();
      aMe._selectTimeout = null;
    }

    timedSelect(aItem, aTimeout) {
      var suppress = this._suppressOnSelect;
      if (aTimeout != -1) {
        this._suppressOnSelect = true;
      }

      this.selectItem(aItem);

      this._suppressOnSelect = suppress;

      if (aTimeout != -1) {
        if (this._selectTimeout) {
          window.clearTimeout(this._selectTimeout);
        }
        this._selectTimeout = window.setTimeout(
          this._selectTimeoutHandler,
          aTimeout,
          this
        );
      }
    }

    /**
     * For backwards-compatibility and for convenience.
     * Use ensureElementIsVisible instead
     */

    ensureSelectedElementIsVisible() {
      return this.ensureElementIsVisible(this.selectedItem);
    }

    _fireEvent(aTarget, aName) {
      let event = document.createEvent("Events");
      event.initEvent(aName, truetrue);
      aTarget.dispatchEvent(event);
    }
  };

  MozXULElement.implementCustomInterface(MozElements.RichListBox, [
    Ci.nsIDOMXULSelectControlElement,
    Ci.nsIDOMXULMultiSelectControlElement,
  ]);

  customElements.define("richlistbox", MozElements.RichListBox);

  /**
   * XUL:richlistitem element.
   */

  MozElements.MozRichlistitem = class MozRichlistitem extends (
    MozElements.BaseText
  ) {
    constructor() {
      super();

      this.selectedByMouseOver = false;

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

      this.addEventListener("mousedown", event => {
        var control = this.control;
        if (!control || this.disabled || control.disabled) {
          return;
        }
        if (
          (!event.ctrlKey ||
            (AppConstants.platform == "macosx" && event.button == 2)) &&
          !event.shiftKey &&
          !event.metaKey
        ) {
          if (!this.selected) {
            control.selectItem(this);
          }
          control.currentItem = this;
        }
      });

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

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

        var control = this.control;
        if (!control || this.disabled || control.disabled) {
          return;
        }
        control._userSelecting = true;
        if (control.selType != "multiple") {
          control.selectItem(this);
        } else if (event.ctrlKey || event.metaKey) {
          control.toggleItemSelection(this);
          control.currentItem = this;
        } else if (event.shiftKey) {
          control.selectItemRange(nullthis);
          control.currentItem = this;
        } else {
          /* 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 */


          // use selectItemRange instead of selectItem, because this
          // doesn't de- and reselect this item if it is selected
          control.selectItemRange(thisthis);
        }
        control._userSelecting = false;
      });
    }

    connectedCallback() {
      this._updateInnerControlsForSelection(this.selected);
    }

    /**
     * nsIDOMXULSelectControlItemElement
     */

    get label() {
      const XUL_NS =
        "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
      return Array.from(
        this.getElementsByTagNameNS(XUL_NS, "label"),
        label => label.value
      ).join(" ");
    }

    set searchLabel(val) {
      if (val !== null) {
        this.setAttribute("searchlabel", val);
      }
      // fall back to the label property (default value)
      else {
        this.removeAttribute("searchlabel");
      }
    }

    get searchLabel() {
      return this.hasAttribute("searchlabel")
        ? this.getAttribute("searchlabel")
        : this.label;
    }
    /**
     * nsIDOMXULSelectControlItemElement
     */

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

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

    /**
     * nsIDOMXULSelectControlItemElement
     */

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

    get selected() {
      return this.getAttribute("selected") == "true";
    }
    /**
     * nsIDOMXULSelectControlItemElement
     */

    get control() {
      var parent = this.parentNode;
      while (parent) {
        if (parent.localName == "richlistbox") {
          return parent;
        }
        parent = parent.parentNode;
      }
      return null;
    }

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

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

    _updateInnerControlsForSelection(selected) {
      for (let control of this.querySelectorAll("button,menulist")) {
        if (!selected && control.tabIndex == 0) {
          control.tabIndex = -1;
        } else if (selected && control.tabIndex == -1) {
          control.tabIndex = 0;
        }
      }
    }
  };

  MozXULElement.implementCustomInterface(MozElements.MozRichlistitem, [
    Ci.nsIDOMXULSelectControlItemElement,
  ]);

  customElements.define("richlistitem", MozElements.MozRichlistitem);
}

Messung V0.5
C=92 H=92 G=91

¤ Dauer der Verarbeitung: 0.19 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.