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


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

  class MozDialog extends MozXULElement {
    #subDialogObserver = null;

    constructor() {
      super();
    }

    static get observedAttributes() {
      return super.observedAttributes.concat(
        "subdialog",
        "extra1-is-secondary"
      );
    }

    #onSubDialogEnabled() {
      console.assert(
        document.documentElement.hasAttribute("subdialog"),
        `Turning off subdialog style is not supported`
      );
      this.shadowRoot.appendChild(
        MozXULElement.parseXULToFragment(this.inContentStyle)
      );
    }

    attributeChangedCallback(name, oldValue, newValue) {
      // Only move the button on UNIX, since it's already in the correct spot on Windows
      if (name === "extra1-is-secondary" && AppConstants.XP_UNIX) {
        this.getButton("cancel").after(this.getButton("extra1"));
      }
      super.attributeChangedCallback(name, oldValue, newValue);
    }

    static get inheritedAttributes() {
      return {
        ".dialog-button-box":
          "pack=buttonpack,align=buttonalign,dir=buttondir,orient=buttonorient",
        "[dlgtype='accept']""disabled=buttondisabledaccept",
      };
    }

    get inContentStyle() {
      return `
      <html:link rel="stylesheet" href="chrome://global/skin/in-content/common.css" />
    `;
    }

    get _markup() {
      let buttons = AppConstants.XP_UNIX
        ? `
      <hbox class="dialog-button-box">
        <button part="dialog-button" dlgtype="disclosure" hidden="true"/>
        <button part="dialog-button" dlgtype="extra2" hidden="true"/>
        <button part="dialog-button" dlgtype="extra1" hidden="true"/>
        <spacer part="button-spacer" class="button-spacer" flex="1"/>
        <button part="dialog-button" dlgtype="cancel"/>
        <button part="dialog-button" dlgtype="accept"/>
      </hbox>`
        : `
      <hbox class="dialog-button-box" pack="end">
        <button part="dialog-button" dlgtype="extra2" hidden="true"/>
        <spacer part="button-spacer" class="button-spacer" flex="1" hidden="true"/>
        <button part="dialog-button" dlgtype="accept"/>
        <button part="dialog-button" dlgtype="extra1" hidden="true"/>
        <button part="dialog-button" dlgtype="cancel"/>
        <button part="dialog-button" dlgtype="disclosure" hidden="true"/>
      </hbox>`;

      return `
      <html:link rel="stylesheet" href="chrome://global/skin/button.css"/>
      <html:link rel="stylesheet" href="chrome://global/skin/dialog.css"/>
      ${
        document.documentElement.hasAttribute("subdialog")
          ? this.inContentStyle
          : ""
      }
      <vbox class="box-inherit" part="content-box">
        <html:slot></html:slot>
      </vbox>
      ${buttons}`;
    }

    connectedCallback() {
      if (this.delayConnectedCallback()) {
        return;
      }
      if (this.hasConnected) {
        return;
      }
      this.hasConnected = true;
      this.attachShadow({ mode: "open" });

      let docRoot = document.documentElement;
      docRoot.setAttribute("role""dialog");
      if (!docRoot.hasAttribute("subdialog")) {
        this.#subDialogObserver = new MutationObserver(() => {
          this.#onSubDialogEnabled();
          this.#subDialogObserver.disconnect();
          this.#subDialogObserver = null;
        });
        this.#subDialogObserver.observe(docRoot, {
          attributes: true,
          attributeFilter: ["subdialog"],
        });
      }
      document.l10n?.connectRoot(this.shadowRoot);

      this.shadowRoot.textContent = "";
      this.shadowRoot.appendChild(
        MozXULElement.parseXULToFragment(this._markup)
      );
      this.initializeAttributeInheritance();

      this._configureButtons(this.buttons);

      window.moveToAlertPosition = this.moveToAlertPosition;
      window.centerWindowOnScreen = this.centerWindowOnScreen;

      document.addEventListener(
        "keypress",
        event => {
          if (event.keyCode == KeyEvent.DOM_VK_RETURN) {
            this._hitEnter(event);
          } else if (
            event.keyCode == KeyEvent.DOM_VK_ESCAPE &&
            !event.defaultPrevented
          ) {
            this.cancelDialog();
          }
        },
        { mozSystemGroup: true }
      );

      if (AppConstants.platform == "macosx") {
        document.addEventListener(
          "keypress",
          event => {
            if (event.key == "." && event.metaKey) {
              this.cancelDialog();
            }
          },
          true
        );
      } else {
        this.addEventListener("focus"thistrue);
        this.shadowRoot.addEventListener("focus"thistrue);
      }

      // listen for when window is closed via native close buttons
      window.addEventListener("close", event => {
        if (!this.cancelDialog()) {
          event.preventDefault();
        }
      });

      // Call postLoadInit for things that we need to initialize after onload.
      if (document.readyState == "complete") {
        this._postLoadInit();
      } else {
        window.addEventListener("load", () => this._postLoadInit());
      }
    }

    set buttons(val) {
      this._configureButtons(val);
    }

    get buttons() {
      return this.getAttribute("buttons");
    }

    set defaultButton(val) {
      this._setDefaultButton(val);
    }

    get defaultButton() {
      if (this.hasAttribute("defaultButton")) {
        return this.getAttribute("defaultButton");
      }
      return "accept"// default to the accept button
    }

    get _strBundle() {
      if (!this.__stringBundle) {
        this.__stringBundle = Services.strings.createBundle(
          "chrome://global/locale/dialog.properties"
        );
      }
      return this.__stringBundle;
    }

    acceptDialog() {
      return this._doButtonCommand("accept");
    }

    cancelDialog() {
      return this._doButtonCommand("cancel");
    }

    getButton(aDlgType) {
      return this._buttons[aDlgType];
    }

    get buttonBox() {
      return this.shadowRoot.querySelector(".dialog-button-box");
    }

    // NOTE(emilio): This has to match AppWindow::IntrinsicallySizeShell, to
    // prevent flickering, see bug 1799394.
    _sizeToPreferredSize() {
      const docEl = document.documentElement;
      const prefWidth = (() => {
        if (docEl.hasAttribute("width")) {
          return parseInt(docEl.getAttribute("width"));
        }
        let prefWidthProp = docEl.getAttribute("prefwidth");
        if (prefWidthProp) {
          let minWidth = parseFloat(
            getComputedStyle(docEl).getPropertyValue(prefWidthProp)
          );
          if (isFinite(minWidth)) {
            return minWidth;
          }
        }
        return 0;
      })();
      window.sizeToContent({ prefWidth });
    }

    moveToAlertPosition() {
      // hack. we need this so the window has something like its final size
      if (window.outerWidth == 1) {
        dump(
          "Trying to position a sizeless window; caller should have called sizeToContent() or sizeTo(). See bug 75649.\n"
        );
        this._sizeToPreferredSize();
      }

      if (opener) {
        var xOffset = (opener.outerWidth - window.outerWidth) / 2;
        var yOffset = opener.outerHeight / 5;

        var newX = opener.screenX + xOffset;
        var newY = opener.screenY + yOffset;
      } else {
        newX = (screen.availWidth - window.outerWidth) / 2;
        newY = (screen.availHeight - window.outerHeight) / 2;
      }

      // ensure the window is fully onscreen (if smaller than the screen)
      if (newX < screen.availLeft) {
        newX = screen.availLeft + 20;
      }
      if (newX + window.outerWidth > screen.availLeft + screen.availWidth) {
        newX = screen.availLeft + screen.availWidth - window.outerWidth - 20;
      }

      if (newY < screen.availTop) {
        newY = screen.availTop + 20;
      }
      if (newY + window.outerHeight > screen.availTop + screen.availHeight) {
        newY = screen.availTop + screen.availHeight - window.outerHeight - 60;
      }

      window.moveTo(newX, newY);
    }

    centerWindowOnScreen() {
      var xOffset = screen.availWidth / 2 - window.outerWidth / 2;
      var yOffset = screen.availHeight / 2 - window.outerHeight / 2;

      xOffset = xOffset > 0 ? xOffset : 0;
      yOffset = yOffset > 0 ? yOffset : 0;
      window.moveTo(xOffset, yOffset);
    }

    // Give focus to the first focusable element in the dialog
    _setInitialFocusIfNeeded() {
      let focusedElt = document.commandDispatcher.focusedElement;
      if (focusedElt) {
        return;
      }

      const defaultButton = this.getButton(this.defaultButton);
      Services.focus.moveFocus(
        window,
        null,
        Services.focus.MOVEFOCUS_FORWARD,
        Services.focus.FLAG_NOPARENTFRAME
      );

      focusedElt = document.commandDispatcher.focusedElement;
      if (!focusedElt) {
        return// No focusable element?
      }

      let firstFocusedElt = focusedElt;
      while (
        focusedElt.localName == "tab" ||
        focusedElt.getAttribute("noinitialfocus") == "true"
      ) {
        Services.focus.moveFocus(
          window,
          focusedElt,
          Services.focus.MOVEFOCUS_FORWARD,
          Services.focus.FLAG_NOPARENTFRAME
        );
        focusedElt = document.commandDispatcher.focusedElement;
        if (focusedElt == firstFocusedElt) {
          if (focusedElt.getAttribute("noinitialfocus") == "true") {
            focusedElt.blur();
          }
          // Didn't find anything else to focus, we're done.
          return;
        }
      }

      if (firstFocusedElt.localName == "tab") {
        if (focusedElt.hasAttribute("dlgtype")) {
          // We don't want to focus on anonymous OK, Cancel, etc. buttons,
          // so return focus to the tab itself
          firstFocusedElt.focus();
        }
      } else if (
        AppConstants.platform != "macosx" &&
        focusedElt.hasAttribute("dlgtype") &&
        focusedElt != defaultButton
      ) {
        defaultButton.focus();
        if (document.commandDispatcher.focusedElement != defaultButton) {
          // If the default button is not focusable, then return focus to the
          // initial element if possible, or blur otherwise.
          if (firstFocusedElt.getAttribute("noinitialfocus") == "true") {
            focusedElt.blur();
          } else {
            firstFocusedElt.focus();
          }
        }
      }
    }

    async _postLoadInit() {
      this._setInitialFocusIfNeeded();
      let finalStep = () => {
        this._sizeToPreferredSize();
        this._snapCursorToDefaultButtonIfNeeded();
      };
      // As a hack to ensure Windows sizes the window correctly,
      // _sizeToPreferredSize() needs to happen after
      // AppWindow::OnChromeLoaded. That one is called right after the load
      // event dispatch but within the same task. Using direct dispatch let's
      // all this code run before the next task (which might be a task to
      // paint the window).
      // But, MacOS doesn't like resizing after window/dialog becoming visible.
      // Linux seems to be able to handle both cases.
      if (Services.appinfo.OS == "Darwin") {
        finalStep();
      } else {
        Services.tm.dispatchDirectTaskToCurrentThread(finalStep);
      }
    }

    // This snaps the cursor to the default button rect on windows, when
    // SPI_GETSNAPTODEFBUTTON is set.
    async _snapCursorToDefaultButtonIfNeeded() {
      const defaultButton = this.getButton(this.defaultButton);
      if (!defaultButton) {
        return;
      }
      try {
        // FIXME(emilio, bug 1797624): This setTimeout() ensures enough time
        // has passed so that the dialog vertical margin has been set by the
        // front-end. For subdialogs, cursor positioning should probably be
        // done by the opener instead, once the dialog is positioned.
        await new Promise(r => setTimeout(r, 0));
        await window.promiseDocumentFlushed(() => {});
        window.notifyDefaultButtonLoaded(defaultButton);
      } catch (e) {}
    }

    _configureButtons(aButtons) {
      // by default, get all the anonymous button elements
      var buttons = {};
      this._buttons = buttons;

      for (let type of ["accept""cancel""extra1""extra2""disclosure"]) {
        buttons[type] = this.shadowRoot.querySelector(`[dlgtype="${type}"]`);
      }

      // look for any overriding explicit button elements
      var exBtns = this.getElementsByAttribute("dlgtype""*");
      var dlgtype;
      for (let i = 0; i < exBtns.length; ++i) {
        dlgtype = exBtns[i].getAttribute("dlgtype");
        buttons[dlgtype].hidden = true// hide the anonymous button
        buttons[dlgtype] = exBtns[i];
      }

      // add the label and oncommand handler to each button
      for (dlgtype in buttons) {
        var button = buttons[dlgtype];
        button.addEventListener(
          "command",
          this._handleButtonCommand.bind(this),
          true
        );

        // don't override custom labels with pre-defined labels on explicit buttons
        if (!button.hasAttribute("label")) {
          // dialog attributes override the default labels in dialog.properties
          if (this.hasAttribute("buttonlabel" + dlgtype)) {
            button.setAttribute(
              "label",
              this.getAttribute("buttonlabel" + dlgtype)
            );
            if (this.hasAttribute("buttonaccesskey" + dlgtype)) {
              button.setAttribute(
                "accesskey",
                this.getAttribute("buttonaccesskey" + dlgtype)
              );
            }
          } else if (this.hasAttribute("buttonid" + dlgtype)) {
            document.l10n.setAttributes(
              button,
              this.getAttribute("buttonid" + dlgtype)
            );
          } else if (dlgtype != "extra1" && dlgtype != "extra2") {
            button.setAttribute(
              "label",
              this._strBundle.GetStringFromName("button-" + dlgtype)
            );
            var accessKey = this._strBundle.GetStringFromName(
              "accesskey-" + dlgtype
            );
            if (accessKey) {
              button.setAttribute("accesskey", accessKey);
            }
          }
        }
      }

      // ensure that hitting enter triggers the default button command
      // eslint-disable-next-line no-self-assign
      this.defaultButton = this.defaultButton;

      // if there is a special button configuration, use it
      if (aButtons) {
        // expect a comma delimited list of dlgtype values
        var list = aButtons.split(",");

        // mark shown dlgtypes as true
        var shown = {
          accept: false,
          cancel: false,
          disclosure: false,
          extra1: false,
          extra2: false,
        };
        for (let i = 0; i < list.length; ++i) {
          shown[list[i].replace(/ /g, "")] = true;
        }

        // hide/show the buttons we want
        for (dlgtype in buttons) {
          buttons[dlgtype].hidden = !shown[dlgtype];
        }

        // show the spacer on Windows only when the extra2 button is present
        if (AppConstants.platform == "win") {
          let spacer = this.shadowRoot.querySelector(".button-spacer");
          spacer.removeAttribute("hidden");
          spacer.setAttribute("flex", shown.extra2 ? "1" : "0");
        }
      }
    }

    _setDefaultButton(aNewDefault) {
      // remove the default attribute from the previous default button, if any
      var oldDefaultButton = this.getButton(this.defaultButton);
      if (oldDefaultButton) {
        oldDefaultButton.removeAttribute("default");
      }

      var newDefaultButton = this.getButton(aNewDefault);
      if (newDefaultButton) {
        this.setAttribute("defaultButton", aNewDefault);
        newDefaultButton.setAttribute("default""true");
      } else {
        this.setAttribute("defaultButton""none");
        if (aNewDefault != "none") {
          dump(
            "invalid new default button: " + aNewDefault + ", assuming: none\n"
          );
        }
      }
    }

    _handleButtonCommand(aEvent) {
      return this._doButtonCommand(aEvent.target.getAttribute("dlgtype"));
    }

    _doButtonCommand(aDlgType) {
      var button = this.getButton(aDlgType);
      if (!button.disabled) {
        var noCancel = this._fireButtonEvent(aDlgType);
        if (noCancel) {
          if (aDlgType == "accept" || aDlgType == "cancel") {
            var closingEvent = new CustomEvent("dialogclosing", {
              bubbles: true,
              detail: { button: aDlgType },
            });
            this.dispatchEvent(closingEvent);
            window.close();
          }
        }
        return noCancel;
      }
      return true;
    }

    _fireButtonEvent(aDlgType) {
      var event = document.createEvent("Events");
      event.initEvent("dialog" + aDlgType, truetrue);

      // handle dom event handlers
      return this.dispatchEvent(event);
    }

    _hitEnter(evt) {
      if (evt.defaultPrevented) {
        return;
      }

      var btn = this.getButton(this.defaultButton);
      if (btn && !btn.hidden) {
        this._doButtonCommand(this.defaultButton);
      }
    }

    on_focus(event) {
      let btn = this.getButton(this.defaultButton);
      if (btn) {
        btn.setAttribute(
          "default",
          event.originalTarget == btn ||
            !(
              event.originalTarget.localName == "button" ||
              event.originalTarget.localName == "toolbarbutton"
            )
        );
      }
    }
  }

  customElements.define("dialog", MozDialog);
}

Messung V0.5
C=98 H=100 G=98

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






                                                                                                                                                                                                                                                                                                                                                                                                     


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