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


Quelle  CommonDialog.sys.mjs   Sprache: unbekannt

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

const lazy = {};
ChromeUtils.defineESModuleGetters(lazy, {
  EnableDelayHelper: "resource://gre/modules/PromptUtils.sys.mjs",
});

import { AppConstants } from "resource://gre/modules/AppConstants.sys.mjs";

export class CommonDialog {
  constructor(args, ui) {
    this.args = args;
    this.ui = ui;
    this.initialFocusPromise = new Promise(resolve => {
      this.initialFocusResolver = resolve;
    });
  }

  static DEFAULT_APP_ICON_CSS = `image-set(url("chrome://branding/content/icon16.png") 1x,
    url("chrome://branding/content/icon32.png") 2x,
    url("chrome://branding/content/icon64.png") 4x)`;

  args = null;
  ui = null;

  hasInputField = true;
  numButtons = undefined;
  iconClass = undefined;
  soundID = undefined;
  focusTimer = null;
  initialFocusPromise = null;
  initialFocusResolver = null;

  /**
   * @param [commonDialogEl] - Dialog element from commonDialog.xhtml.
   */
  async onLoad(commonDialogEl) {
    let isEmbedded = !!commonDialogEl.ownerGlobal.docShell.chromeEventHandler;

    switch (this.args.promptType) {
      case "alert":
      case "alertCheck":
        this.hasInputField = false;
        this.numButtons = 1;
        this.iconClass = ["alert-icon"];
        this.soundID = Ci.nsISound.EVENT_ALERT_DIALOG_OPEN;
        break;
      case "confirmCheck":
      case "confirm":
        this.hasInputField = false;
        this.numButtons = 2;
        this.iconClass = ["question-icon"];
        this.soundID = Ci.nsISound.EVENT_CONFIRM_DIALOG_OPEN;
        break;
      case "confirmEx":
        var numButtons = 0;
        if (this.args.button0Label) {
          numButtons++;
        }
        if (this.args.button1Label) {
          numButtons++;
        }
        if (this.args.button2Label) {
          numButtons++;
        }
        if (this.args.button3Label) {
          numButtons++;
        }
        if (numButtons == 0 && !this.args.allowNoButtons) {
          throw new Error(
            "A dialog with no buttons requires the allowNoButtons argument"
          );
        }
        this.numButtons = numButtons;
        this.hasInputField = false;
        this.iconClass = ["question-icon"];
        this.soundID = Ci.nsISound.EVENT_CONFIRM_DIALOG_OPEN;
        break;
      case "prompt":
        this.numButtons = 2;
        this.iconClass = ["question-icon"];
        this.soundID = Ci.nsISound.EVENT_PROMPT_DIALOG_OPEN;
        this.initTextbox("login", this.args.value);
        // Clear the label, since this isn't really a username prompt.
        this.ui.loginLabel.setAttribute("value", "");
        // Ensure the labeling for the prompt is correct.
        this.ui.loginTextbox.setAttribute("aria-labelledby", "infoBody");
        break;
      case "promptUserAndPass":
        this.numButtons = 2;
        this.iconClass = ["authentication-icon", "question-icon"];
        this.soundID = Ci.nsISound.EVENT_PROMPT_DIALOG_OPEN;
        this.initTextbox("login", this.args.user);
        this.initTextbox("password1", this.args.pass);
        break;
      case "promptPassword":
        this.numButtons = 2;
        this.iconClass = ["authentication-icon", "question-icon"];
        this.soundID = Ci.nsISound.EVENT_PROMPT_DIALOG_OPEN;
        this.initTextbox("password1", this.args.pass);
        // Clear the label, since the message presumably indicates its purpose.
        this.ui.password1Label.setAttribute("value", "");
        break;
      default:
        console.error(
          "commonDialog opened for unknown type: ",
          this.args.promptType
        );
        throw new Error("unknown dialog type");
    }

    commonDialogEl.setAttribute("windowtype", "prompt:" + this.args.promptType);

    // set the document title
    let title = this.args.title;
    let infoTitle = this.ui.infoTitle;
    infoTitle.appendChild(infoTitle.ownerDocument.createTextNode(title));

    // After making these preventative checks, we can determine to show it if we're on
    // macOS (where there is no titlebar) or if the prompt is a common dialog document
    // and has been embedded (has a chromeEventHandler).
    infoTitle.hidden = !(AppConstants.platform === "macosx" || isEmbedded);

    commonDialogEl.ownerDocument.title = title;

    // Set button labels and visibility
    //
    // This assumes that button0 defaults to a visible "ok" button, and
    // button1 defaults to a visible "cancel" button. The other 2 buttons
    // have no default labels (and are hidden).
    switch (this.numButtons) {
      case 4:
        this.setLabelForNode(this.ui.button3, this.args.button3Label);
        this.ui.button3.hidden = false;
      // fall through
      case 3:
        this.setLabelForNode(this.ui.button2, this.args.button2Label);
        this.ui.button2.hidden = false;
      // fall through
      case 2:
        // Defaults to a visible "cancel" button
        if (this.args.button1Label) {
          this.setLabelForNode(this.ui.button1, this.args.button1Label);
        }
        break;
      case 0:
        this.ui.button0.hidden = true;
      // fall through
      case 1:
        this.ui.button1.hidden = true;
        break;
    }
    // Defaults to a visible "ok" button
    if (this.args.button0Label) {
      this.setLabelForNode(this.ui.button0, this.args.button0Label);
    }

    // display the main text
    let croppedMessage = "";
    if (this.args.text) {
      // Bug 317334 - crop string length as a workaround.
      croppedMessage = this.args.text.substr(0, 10000);
      // TabModalPrompts don't have an infoRow to hide / not hide here, so
      // guard on that here so long as they are in use.
      if (this.ui.infoRow) {
        this.ui.infoRow.hidden = false;
      }
    }
    let infoBody = this.ui.infoBody;
    infoBody.appendChild(infoBody.ownerDocument.createTextNode(croppedMessage));

    let label = this.args.checkLabel;
    if (label) {
      // Only show the checkbox if label has a value.
      this.ui.checkboxContainer.hidden = false;
      this.ui.checkboxContainer.clientTop; // style flush to assure binding is attached
      this.setLabelForNode(this.ui.checkbox, label);
      this.ui.checkbox.checked = this.args.checked;
    }

    // set the icon
    let icon = this.ui.infoIcon;
    if (icon) {
      this.iconClass.forEach(el => icon.classList.add(el));
    }

    // set default result to cancelled
    this.args.ok = false;
    this.args.buttonNumClicked = 1;

    // Set the default button
    let b = this.args.defaultButtonNum || 0;
    commonDialogEl.defaultButton = ["accept", "cancel", "extra1", "extra2"][b];

    if (!isEmbedded && !this.ui.promptContainer?.hidden) {
      // Set default focus and select textbox contents if applicable. If we're
      // embedded SubDialogManager will call setDefaultFocus for us.
      this.setDefaultFocus(true);
    }

    if (this.args.enableDelay) {
      this.delayHelper = new lazy.EnableDelayHelper({
        disableDialog: () => this.setButtonsEnabledState(false),
        enableDialog: () => this.setButtonsEnabledState(true),
        focusTarget: this.ui.focusTarget,
      });
    }

    // Play a sound (unless we're showing a content prompt -- don't want those
    //               to feel like OS prompts).
    try {
      if (this.soundID && !this.args.openedWithTabDialog) {
        Cc["@mozilla.org/sound;1"]
          .getService(Ci.nsISound)
          .playEventSound(this.soundID);
      }
    } catch (e) {
      console.error("Couldn't play common dialog event sound: ", e);
    }

    if (isEmbedded) {
      // If we delayed default focus above, wait for it to be ready before
      // sending the notification.
      await this.initialFocusPromise;
    }
    Services.obs.notifyObservers(this.ui.prompt, "common-dialog-loaded");
  }

  setLabelForNode(aNode, aLabel) {
    // This is for labels which may contain embedded access keys.
    // If we end in (&X) where X represents the access key, optionally preceded
    // by spaces and/or followed by the ':' character, store the access key and
    // remove the access key placeholder + leading spaces from the label.
    // Otherwise a character preceded by one but not two &s is the access key.
    // Store it and remove the &.

    // Note that if you change the following code, see the comment of
    // nsTextBoxFrame::UpdateAccessTitle.
    var accessKey = null;
    if (/ *\(\&([^&])\)(:?)$/.test(aLabel)) {
      aLabel = RegExp.leftContext + RegExp.$2;
      accessKey = RegExp.$1;
    } else if (/^([^&]*)\&(([^&]).*$)/.test(aLabel)) {
      aLabel = RegExp.$1 + RegExp.$2;
      accessKey = RegExp.$3;
    }

    // && is the magic sequence to embed an & in your label.
    aLabel = aLabel.replace(/\&\&/g, "&");
    aNode.label = aLabel;

    // XXXjag bug 325251
    // Need to set this after aNode.setAttribute("value", aLabel);
    if (accessKey) {
      aNode.accessKey = accessKey;
    }
  }

  initTextbox(aName, aValue) {
    this.ui[aName + "Container"].hidden = false;
    this.ui[aName + "Textbox"].setAttribute(
      "value",
      aValue !== null ? aValue : ""
    );
  }

  setButtonsEnabledState(enabled) {
    this.ui.button0.disabled = !enabled;
    // button1 (cancel) remains enabled.
    this.ui.button2.disabled = !enabled;
    this.ui.button3.disabled = !enabled;
  }

  setDefaultFocus(isInitialLoad) {
    let b = this.args.defaultButtonNum || 0;
    let button = this.ui["button" + b];

    if (!this.hasInputField) {
      let isOSX = "nsILocalFileMac" in Ci;
      // If the infoRow exists and is is hidden, then the infoBody is also hidden,
      // which means it can't be focused. At that point, we fall back to focusing
      // the default button, regardless of platform.
      if (isOSX && !(this.ui.infoRow && this.ui.infoRow.hidden)) {
        this.ui.infoBody.focus();
      } else {
        button.focus({ focusVisible: false });
      }
    } else if (this.args.promptType == "promptPassword") {
      // When the prompt is initialized, focus and select the textbox
      // contents. Afterwards, only focus the textbox.
      if (isInitialLoad) {
        this.ui.password1Textbox.select();
      } else {
        this.ui.password1Textbox.focus();
      }
    } else if (isInitialLoad) {
      this.ui.loginTextbox.select();
    } else {
      this.ui.loginTextbox.focus();
    }

    if (isInitialLoad) {
      this.initialFocusResolver();
    }
  }

  onCheckbox() {
    this.args.checked = this.ui.checkbox.checked;
  }

  onButton0() {
    this.args.promptActive = false;
    this.args.ok = true;
    this.args.buttonNumClicked = 0;

    let username = this.ui.loginTextbox.value;
    let password = this.ui.password1Textbox.value;

    // Return textfield values
    switch (this.args.promptType) {
      case "prompt":
        this.args.value = username;
        break;
      case "promptUserAndPass":
        this.args.user = username;
        this.args.pass = password;
        break;
      case "promptPassword":
        this.args.pass = password;
        break;
    }
  }

  onButton1() {
    this.args.promptActive = false;
    this.args.buttonNumClicked = 1;
  }

  onButton2() {
    this.args.promptActive = false;
    this.args.buttonNumClicked = 2;
  }

  onButton3() {
    this.args.promptActive = false;
    this.args.buttonNumClicked = 3;
  }

  abortPrompt() {
    this.args.promptActive = false;
    this.args.promptAborted = true;
  }
}

[ Dauer der Verarbeitung: 0.15 Sekunden  (vorverarbeitet)  ]

                                                                                                                                                                                                                                                                                                                                                                                                     


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