Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/dom/html/   (Firefox Browser Version 153.0.1©)  Datei vom 27.6.2026 mit Größe 28 kB image not shown  

Quelle  HTMLDialogElement.cpp

  Sprache: C
 

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


#include "mozilla/dom/HTMLDialogElement.h"

#include "mozilla/dom/AncestorIterator.h"
#include "mozilla/dom/BindContext.h"
#include "mozilla/dom/CloseWatcher.h"
#include "mozilla/dom/CloseWatcherManager.h"
#include "mozilla/dom/ElementBinding.h"
#include "mozilla/dom/HTMLButtonElement.h"
#include "mozilla/dom/HTMLDialogElementBinding.h"
#include "mozilla/dom/UnbindContext.h"
#include "nsContentUtils.h"
#include "nsFocusManager.h"
#include "nsIDOMEventListener.h"
#include "nsIFrame.h"

NS_IMPL_NS_NEW_HTML_ELEMENT(Dialog)

namespace mozilla::dom {

static constexpr nsAttrValue::EnumTableEntry kClosedbyTable[] = {
    {"", HTMLDialogElement::ClosedBy::Auto},
    {"none", HTMLDialogElement::ClosedBy::None},
    {"any", HTMLDialogElement::ClosedBy::Any},
    {"closerequest", HTMLDialogElement::ClosedBy::CloseRequest},
};

static constexpr const nsAttrValue::EnumTableEntry* kClosedbyAuto =
    &kClosedbyTable[0];
static constexpr const nsAttrValue::EnumTableEntry* kClosedbyDefault =
    &kClosedbyTable[1];
static constexpr const nsAttrValue::EnumTableEntry* kClosedbyModalDefault =
    &kClosedbyTable[3];

HTMLDialogElement::~HTMLDialogElement() = default;

NS_IMPL_ELEMENT_CLONE(HTMLDialogElement)

class DialogCloseWatcherListener : public nsIDOMEventListener {
 public:
  NS_DECL_ISUPPORTS

  explicit DialogCloseWatcherListener(HTMLDialogElement* aDialog) {
    mDialog = do_GetWeakReference(aDialog);
  }

  // https://html.spec.whatwg.org/#set-the-dialog-close-watcher
  NS_IMETHODIMP HandleEvent(Event* aEvent) override {
    RefPtr<nsINode> node = do_QueryReferent(mDialog);
    if (HTMLDialogElement* dialog = HTMLDialogElement::FromNodeOrNull(node)) {
      nsAutoString eventType;
      aEvent->GetType(eventType);
      if (eventType.EqualsLiteral("cancel")) {
        // 3. - cancelAction given canPreventClose being to return the result of
        // firing an event named cancel at dialog, with the cancelable attribute
        // initialized to canPreventClose.
        bool defaultAction = true;
        auto cancelable =
            aEvent->Cancelable() ? Cancelable::eYes : Cancelable::eNo;
        nsContentUtils::DispatchTrustedEvent(dialog->OwnerDoc(), dialog,
                                             u"cancel"_ns, CanBubble::eNo,
                                             cancelable, &defaultAction);
        if (!defaultAction) {
          aEvent->PreventDefault();
        }
      } else if (eventType.EqualsLiteral("close")) {
        // 3. - closeAction being to close the dialog given dialog, dialog's
        // request close return value, and dialog's request close source
        // element.
        Maybe<nsAutoString> retValue;
        dialog->GetRequestCloseReturnValue(retValue);
        RefPtr<Element> source = dialog->GetRequestCloseSourceElement();
        dialog->Close(source, retValue);
      }
    }
    return NS_OK;
  }

 private:
  virtual ~DialogCloseWatcherListener() = default;
  nsWeakPtr mDialog;
};
NS_IMPL_ISUPPORTS(DialogCloseWatcherListener, nsIDOMEventListener)

// https://html.spec.whatwg.org/#computed-closed-by-state
void HTMLDialogElement::GetClosedBy(nsAString& aResult) const {
  aResult.Truncate();
  MOZ_ASSERT(StaticPrefs::dom_dialog_light_dismiss_enabled());
  const nsAttrValue* val = mAttrs.GetAttr(nsGkAtoms::closedby);
  // 1. If the state of dialog's closedby attribute is Auto:
  if (!val || val->GetEnumValue() == kClosedbyAuto->value) {
    //  1.1. If dialog's is modal is true, then return Close Request.
    //  1.2. Return None.
    const char* tag =
        (IsInTopLayer() ? kClosedbyModalDefault->tag : kClosedbyDefault->tag);
    AppendASCIItoUTF16(nsDependentCString(tag), aResult);
    return;
  }
  // 2. Return the state of dialog's closedby attribute.
  val->GetEnumString(aResult, true);
}

// https://html.spec.whatwg.org/#computed-closed-by-state
HTMLDialogElement::ClosedBy HTMLDialogElement::GetClosedBy() const {
  if (!StaticPrefs::dom_dialog_light_dismiss_enabled()) {
    return static_cast<ClosedBy>(IsInTopLayer() ? kClosedbyModalDefault->value
                                                : kClosedbyDefault->value);
  }
  const nsAttrValue* val = mAttrs.GetAttr(nsGkAtoms::closedby);
  // 1. If the state of dialog's closedby attribute is Auto:
  if (!val || val->GetEnumValue() == kClosedbyAuto->value) {
    //  1.1. If dialog's is modal is true, then return Close Request.
    //  1.2. Return None.
    return static_cast<ClosedBy>(IsInTopLayer() ? kClosedbyModalDefault->value
                                                : kClosedbyDefault->value);
  }
  // 2. Return the state of dialog's closedby attribute.
  return static_cast<ClosedBy>(val->GetEnumValue());
}

bool HTMLDialogElement::ParseClosedByAttribute(const nsAString& aValue,
                                               nsAttrValue& aResult) {
  return aResult.ParseEnumValue(aValue, kClosedbyTable,
                                /* aCaseSensitive = */ false, kClosedbyAuto);
}

bool HTMLDialogElement::ParseAttribute(int32_t aNamespaceID, nsAtom* aAttribute,
                                       const nsAString& aValue,
                                       nsIPrincipal* aMaybeScriptedPrincipal,
                                       nsAttrValue& aResult) {
  if (aNamespaceID == kNameSpaceID_None) {
    if (StaticPrefs::dom_dialog_light_dismiss_enabled() &&
        aAttribute == nsGkAtoms::closedby) {
      return ParseClosedByAttribute(aValue, aResult);
    }
  }
  return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
                                              aMaybeScriptedPrincipal, aResult);
}

// https://html.spec.whatwg.org/#dom-dialog-close
// https://html.spec.whatwg.org/#close-the-dialog
void HTMLDialogElement::Close(Element* aSource,
                              const Maybe<nsAutoString>& aReturnValue) {
  // 1. If subject does not have an open attribute, then return.
  if (!Open()) {
    return;
  }

  // 2. Fire an event named beforetoggle, using ToggleEvent, with the oldState
  // attribute initialized to "open", the newState attribute initialized to
  // "closed", and the source attribute initialized to source at subject.
  FireToggleEvent(u"open"_ns, u"closed"_ns, u"beforetoggle"_ns, aSource);

  // 3. If subject does not have an open attribute, then return.
  if (!Open()) {
    return;
  }

  // 4. Queue a dialog toggle event task given subject, "open", "closed", and
  // source.
  QueueToggleEventTask(aSource);

  // 5. Remove subject's open attribute.
  SetOpen(false, IgnoreErrors());

  // 6. If is modal of subject is true, then request an element to be removed
  // from the top layer given subject.
  // 7. Let wasModal be the value of subject's is modal flag.
  bool wasModal = IsInTopLayer();
  // 8. Set is modal of subject to false.
  RemoveFromTopLayerIfNeeded();

  // 9. If result is not null, then set subject's returnValue attribute to
  // result.
  if (aReturnValue.isSome()) {
    SetReturnValue(aReturnValue.ref());
  }

  // 10. Set subject's request close return value to null.
  ClearRequestCloseReturnValue();

  // 11. Set subject's request close source element to null.
  mRequestCloseSourceElement = nullptr;

  MOZ_ASSERT(!OwnerDoc()->DialogIsInOpenDialogsList(*this),
             "Dialog should not being in Open Dialog List");

  // 12. If subject's previously focused element is not null, then:
  // 12.1. Let element be subject's previously focused element.
  RefPtr<Element> previouslyFocusedElement =
      do_QueryReferent(mPreviouslyFocusedElement);

  if (previouslyFocusedElement) {
    // 12.2. Set subject's previously focused element to null.
    mPreviouslyFocusedElement = nullptr;

    // 12.3. If subject's node document's focused area of the document's DOM
    // anchor is a shadow-including inclusive descendant of subject, or wasModal
    // is true, then run the focusing steps for element; the viewport should not
    // be scrolled by doing this step.
    bool resetFocus = true;
    if (!wasModal) {
      resetFocus = false;
      if (auto* focusedContent = OwnerDoc()->GetUnretargetedFocusedContent()) {
        // Actually use flat tree instead of shadow-including traversal to be
        // consistent with Chrome:
        // https://github.com/web-platform-tests/wpt/pull/39579#issuecomment-2666758496
        for (auto* dialog :
             focusedContent
                 ->InclusiveFlatTreeAncestorsOfType<HTMLDialogElement>()) {
          if (dialog == this) {
            resetFocus = true;
            break;
          }
        }
      }
    }
    if (resetFocus) {
      FocusOptions options;
      options.mPreventScroll = true;
      previouslyFocusedElement->Focus(options, CallerType::NonSystem,
                                      IgnoredErrorResult());
    }
  }

  // 13. Queue an element task on the user interaction task source given the
  // subject element to fire an event named close at subject.
  RefPtr<AsyncEventDispatcher> eventDispatcher =
      new AsyncEventDispatcher(this, u"close"_ns, CanBubble::eNo);
  eventDispatcher->PostDOMEvent();
}

// https://html.spec.whatwg.org/#dom-dialog-requestclose
// https://html.spec.whatwg.org/#dialog-request-close
void HTMLDialogElement::RequestClose(Element* aSource,
                                     const Maybe<nsAutoString>& aReturnValue) {
  RefPtr closeWatcher = mCloseWatcher;
  // 1. If subject does not have an open attribute, then return.
  if (!Open()) {
    return;
  }

  // 2. If subject is not connected or subject's node document is not fully
  // active, then return.
  if (!IsInComposedDoc() || !OwnerDoc()->IsFullyActive()) {
    return;
  }

  // 3. Assert: subject's close watcher is not null.
  if (StaticPrefs::dom_closewatcher_enabled()) {
    MOZ_ASSERT(closeWatcher, "RequestClose needs mCloseWatcher");
  }

  // 4. Set subject's enable close watcher for request close to true.
  if (StaticPrefs::dom_closewatcher_enabled()) {
    // XXX: Rather than store a "enable close watcher for request close" state,
    // we set the CloseWatcher Enabled state to true manually here, and revert
    // it lower down...
    closeWatcher->SetEnabled(true);
  }

  // 5. Set subject's request close return value to returnValue.
  if (aReturnValue.isSome()) {
    SetRequestCloseReturnValue(aReturnValue.ref());
  }

  // 6. Set subject's request close source element to source.
  mRequestCloseSourceElement = do_GetWeakReference(aSource);

  // 7. Request to close subject's close watcher with false.
  if (StaticPrefs::dom_closewatcher_enabled()) {
    closeWatcher->RequestToClose(false);
  } else {
    RunCancelDialogSteps();
  }

  // 8. Set subject's enable close watcher for request close to false.
  if (closeWatcher) {
    // XXX: Rather than store a "enable close watcher for request close" state,
    // we can simply set the close watcher enabled state to whatever it was
    // before we set it to true (above). SetCloseWatcherEnabledState() will do
    // this:
    SetCloseWatcherEnabledState();
  }
}

RefPtr<Element> HTMLDialogElement::GetRequestCloseSourceElement() {
  return do_QueryReferent(mRequestCloseSourceElement);
}

// https://html.spec.whatwg.org/#dom-dialog-show
void HTMLDialogElement::Show(ErrorResult& aError) {
  // 1. If this has an open attribute and is modal of this is false, then
  // return.
  if (Open()) {
    if (!IsInTopLayer()) {
      return;
    }

    // 2. If this has an open attribute, then throw an "InvalidStateError"
    // DOMException.
    return aError.ThrowInvalidStateError(
        "Cannot call show() on an open modal dialog.");
  }

  // 3. If the result of firing an event named beforetoggle, using ToggleEvent,
  // with the cancelable attribute initialized to true, the oldState attribute
  // initialized to "closed", and the newState attribute initialized to "open"
  // at this is false, then return.
  if (FireToggleEvent(u"closed"_ns, u"open"_ns, u"beforetoggle"_ns, nullptr)) {
    return;
  }

  // 4. If this has an open attribute, then return.
  if (Open()) {
    return;
  }

  // 5. Queue a dialog toggle event task given this, "closed", and "open".
  QueueToggleEventTask(nullptr);

  // 6. Add an open attribute to this, whose value is the empty string.
  SetOpen(true, IgnoreErrors());

  // 7. Set this's previously focused element to the focused element.
  StorePreviouslyFocusedElement();

  // 8. Let document be this's node document.

  // 9. Let hideUntil be the result of running topmost popover ancestor given
  // this, null, and false.
  RefPtr<Element> hideUntil = GetTopmostPopoverAncestor(nullptr, false);

  // 10. Run hide popovers until given document, hideUntil, false, and true.
  OwnerDoc()->HidePopoversUntil(hideUntil, false, true);

  // 11. Run the dialog focusing steps given this.
  FocusDialog();
}

bool HTMLDialogElement::Open() const {
  MOZ_ASSERT(GetBoolAttr(nsGkAtoms::open) ==
             State().HasState(ElementState::OPEN));
  return State().HasState(ElementState::OPEN);
}

bool HTMLDialogElement::IsInTopLayer() const {
  return State().HasState(ElementState::MODAL);
}

void HTMLDialogElement::AddToTopLayerIfNeeded() {
  MOZ_ASSERT(IsInComposedDoc(), "AddToTopLayerIfNeeded needs IsInComposedDoc");
  if (IsInTopLayer()) {
    return;
  }

  OwnerDoc()->AddModalDialog(*this);

  // A change to the modal state may cause the CloseWatcher enabled state to
  // change, if the `closedby` attribute is missing and therefore in the Auto
  // (computed) state.
  SetCloseWatcherEnabledState();
}

void HTMLDialogElement::RemoveFromTopLayerIfNeeded() {
  if (!IsInTopLayer()) {
    return;
  }
  OwnerDoc()->RemoveModalDialog(*this);

  // A change to the modal state may cause the CloseWatcher enabled state to
  // change, if the `closedby` attribute is missing and therefore in the Auto
  // (computed) state.
  SetCloseWatcherEnabledState();
}

void HTMLDialogElement::StorePreviouslyFocusedElement() {
  if (Element* element = nsFocusManager::GetFocusedElementStatic()) {
    if (NS_SUCCEEDED(nsContentUtils::CheckSameOrigin(this, element))) {
      mPreviouslyFocusedElement = do_GetWeakReference(element);
    }
  } else if (Document* doc = GetComposedDoc()) {
    // Looks like there's a discrepancy sometimes when focus is moved
    // to a different in-process window.
    if (nsIContent* unretargetedFocus = doc->GetUnretargetedFocusedContent()) {
      mPreviouslyFocusedElement = do_GetWeakReference(unretargetedFocus);
    }
  }
}

nsresult HTMLDialogElement::BindToTree(BindContext& aContext,
                                       nsINode& aParent) {
  MOZ_TRY(nsGenericHTMLElement::BindToTree(aContext, aParent));

  // https://html.spec.whatwg.org/#the-dialog-element:html-element-insertion-steps
  // 1. If insertedNode's node document is not fully active, then return.
  // 2. If insertedNode is connected, then run the
  // dialog setup steps given insertedNode.
  if (Open() && IsInComposedDoc() && OwnerDoc()->IsFullyActive() &&
      !aContext.IsMove()) {
    SetupSteps();
  }

  return NS_OK;
}

// https://html.spec.whatwg.org/interactive-elements.html#the-dialog-element:html-element-removing-steps
void HTMLDialogElement::UnbindFromTree(UnbindContext& aContext) {
  if (!aContext.IsMove()) {
    // 1. If removedNode has an open attribute, then run the dialog cleanup
    // steps given removedNode.
    if (Open()) {
      CleanupSteps();
    }

    // 2. If removedNode's node document's top layer contains removedNode, then
    // remove an element from the top layer immediately given removedNode.
    RemoveFromTopLayerIfNeeded();

    // 3. Set is modal of removedNode to false.
  }

  nsGenericHTMLElement::UnbindFromTree(aContext);
}

// https://html.spec.whatwg.org/#show-a-modal-dialog
void HTMLDialogElement::ShowModal(Element* aSource, ErrorResult& aError) {
  // 1. If subject has an open attribute and is modal of subject is true, then
  // return.
  if (Open()) {
    if (IsInTopLayer()) {
      return;
    }

    // 2. If subject has an open attribute, then throw an "InvalidStateError"
    // DOMException.
    return aError.ThrowInvalidStateError(
        "Cannot call showModal() on an open non-modal dialog.");
  }

  // 3. If subject's node document is not fully active, then throw an
  // "InvalidStateError" DOMException.
  if (!OwnerDoc()->IsFullyActive()) {
    return aError.ThrowInvalidStateError(
        "The owner document is not fully active");
  }

  // 4. If subject is not connected, then throw an "InvalidStateError"
  // DOMException.
  if (!IsInComposedDoc()) {
    return aError.ThrowInvalidStateError("Dialog element is not connected");
  }

  // 5. If subject is in the popover showing state, then throw an
  // "InvalidStateError" DOMException.
  if (IsPopoverOpen()) {
    return aError.ThrowInvalidStateError(
        "Dialog element is already an open popover.");
  }

  // 6. If the result of firing an event named beforetoggle, using
  // ToggleEvent, with the cancelable attribute initialized to true, the
  // oldState attribute initialized to "closed", and the newState attribute
  // initialized to "open" at subject is false, then return.
  if (FireToggleEvent(u"closed"_ns, u"open"_ns, u"beforetoggle"_ns, aSource)) {
    return;
  }

  // 7. If subject has an open attribute, then return.
  // 8. If subject is not connected, then return.
  // 9. If subject is in the popover showing state, then return.
  if (Open() || !IsInComposedDoc() || IsPopoverOpen()) {
    return;
  }

  // 10. Queue a dialog toggle event task given subject, "closed", and "open".
  QueueToggleEventTask(aSource);

  // 11. Add an open attribute to subject, whose value is the empty string.
  SetOpen(true, aError);

  // 12. Assert: subject's close watcher is not null.
  if (StaticPrefs::dom_closewatcher_enabled()) {
    MOZ_ASSERT(mCloseWatcher, "ShowModal needs mCloseWatcher");
  }

  // 13. Set is modal of subject to true.
  // 14. Set subject's node document to be blocked by the modal dialog subject.
  // 15. If subject's node document's top layer does not already contain
  // subject, then add an element to the top layer given subject.
  AddToTopLayerIfNeeded();

  // 16. Set subject's previously focused element to the focused element.
  StorePreviouslyFocusedElement();

  // 17. Let document be subject's node document.

  // 18. Let hideUntil be the result of running topmost popover ancestor given
  // subject, null, and false.
  RefPtr<Element> hideUntil = GetTopmostPopoverAncestor(nullptr, false);

  // 19. Run hide popovers until given document, hideUntil, false, and true.
  OwnerDoc()->HidePopoversUntil(hideUntil, false, true);

  // 20. Run the dialog focusing steps given subject.
  FocusDialog();

  aError.SuppressException();
}

// https://html.spec.whatwg.org/#the-dialog-element:concept-element-attributes-change-ext
void HTMLDialogElement::AfterSetAttr(int32_t aNameSpaceID, nsAtom* aName,
                                     const nsAttrValue* aValue,
                                     const nsAttrValue* aOldValue,
                                     nsIPrincipal* aMaybeScriptedPrincipal,
                                     bool aNotify) {
  nsGenericHTMLElement::AfterSetAttr(aNameSpaceID, aName, aValue, aOldValue,
                                     aMaybeScriptedPrincipal, aNotify);
  // 1. If namespace is not null, then return.
  if (aNameSpaceID != kNameSpaceID_None) {
    return;
  }

  // https://html.spec.whatwg.org/#set-the-dialog-close-watcher
  // https://github.com/whatwg/html/issues/11267
  // XXX: CloseWatcher currently uses a `getEnabledState` algorithm to set a
  // boolean, but this is quite a lot of additional infrastructure which could
  // be simplified by CloseWatcher having an "Enabled" state.
  // If the closedby attribute changes, it may or may not toggle the
  // CloseWatcher enabled state.
  if (aName == nsGkAtoms::closedby) {
    SetCloseWatcherEnabledState();
  }

  // 2. If localName is not open, then return.
  if (aName != nsGkAtoms::open) {
    return;
  }

  bool wasOpen = !!aOldValue;
  bool isOpen = !!aValue;

  MOZ_ASSERT(GetBoolAttr(nsGkAtoms::open) == isOpen);
  SetStates(ElementState::OPEN, isOpen);

  // 3. If value is null and oldValue is not null, then run the dialog cleanup
  // steps given element.
  if (!isOpen && wasOpen) {
    CleanupSteps();
  }

  // 4. If element's node document is not fully active, then return.
  if (!OwnerDoc()->IsFullyActive()) {
    return;
  }

  // 5. If element is not connected, then return.
  if (!IsInComposedDoc()) {
    return;
  }

  // 6. If value is not null and oldValue is null, then run the dialog setup
  // steps given element.
  if (isOpen && !wasOpen) {
    SetupSteps();
  }
}

void HTMLDialogElement::AsyncEventRunning(AsyncEventDispatcher* aEvent) {
  if (mToggleEventDispatcher == aEvent) {
    mToggleEventDispatcher = nullptr;
  }
}

void HTMLDialogElement::FocusDialog() {
  // 1) If subject is inert, return.
  // 2) Let control be the first descendant element of subject, in tree
  // order, that is not inert and has the autofocus attribute specified.
  RefPtr<Document> doc = OwnerDoc();
  if (IsInComposedDoc()) {
    doc->FlushPendingNotifications(FlushType::Frames);
  }

  RefPtr<Element> control = HasAttr(nsGkAtoms::autofocus)
                                ? this
                                : GetFocusDelegate(IsFocusableFlags(0));

  // If there isn't one of those either, then let control be subject.
  if (!control) {
    control = this;
  }

  FocusCandidate(control, IsInTopLayer());
}

int32_t HTMLDialogElement::TabIndexDefault() { return 0; }

void HTMLDialogElement::QueueCancelDialog() {
  // queues an element task on the user interaction task source
  OwnerDoc()->Dispatch(
      NewRunnableMethod("HTMLDialogElement::RunCancelDialogSteps"this,
                        &HTMLDialogElement::RunCancelDialogSteps));
}

void HTMLDialogElement::RunCancelDialogSteps() {
  // 1) Let close be the result of firing an event named cancel at dialog,
  // with the cancelable attribute initialized to true.
  bool defaultAction = true;
  nsContentUtils::DispatchTrustedEvent(OwnerDoc(), this, u"cancel"_ns,
                                       CanBubble::eNo, Cancelable::eYes,
                                       &defaultAction);

  // 2) If close is true and dialog has an open attribute, then close the
  // dialog with ~~no return value.~~
  // XXX(keithamus): RequestClose's steps expect the return value to be
  // RequestCloseReturnValue. RunCancelDialogSteps has been refactored out of
  // the spec, over CloseWatcher though, so one day this code will need to be
  // refactored when the CloseWatcher specifications settle.
  if (defaultAction) {
    Maybe<nsAutoString> retValue;
    GetRequestCloseReturnValue(retValue);
    RefPtr<Element> source = GetRequestCloseSourceElement();
    Close(source, retValue);
  }
}

bool HTMLDialogElement::IsValidCommandAction(Command aCommand) const {
  return nsGenericHTMLElement::IsValidCommandAction(aCommand) ||
         aCommand == Command::ShowModal || aCommand == Command::Close ||
         aCommand == Command::RequestClose;
}

bool HTMLDialogElement::HandleCommandInternal(Element* aSource,
                                              Command aCommand,
                                              ErrorResult& aRv) {
  if (nsGenericHTMLElement::HandleCommandInternal(aSource, aCommand, aRv)) {
    return true;
  }

  MOZ_ASSERT(IsValidCommandAction(aCommand));

  if ((aCommand == Command::Close || aCommand == Command::RequestClose) &&
      Open()) {
    Maybe<nsAutoString> retValue;
    if (aSource->HasAttr(nsGkAtoms::value)) {
      if (auto* button = HTMLButtonElement::FromNodeOrNull(aSource)) {
        retValue.emplace();
        button->GetValue(retValue.ref());
      }
    }
    if (aCommand == Command::Close) {
      Close(aSource, retValue);
    } else {
      MOZ_ASSERT(aCommand == Command::RequestClose);
      RequestClose(aSource, retValue);
    }
    return true;
  }

  if (IsInComposedDoc() && !Open() && aCommand == Command::ShowModal) {
    ShowModal(aSource, aRv);
    return true;
  }

  return false;
}

void HTMLDialogElement::QueueToggleEventTask(Element* aSource) {
  nsAutoString oldState;
  auto newState = Open() ? u"closed"_ns : u"open"_ns;
  if (mToggleEventDispatcher) {
    oldState.Truncate();
    static_cast<ToggleEvent*>(mToggleEventDispatcher->mEvent.get())
        ->GetOldState(oldState);
    mToggleEventDispatcher->Cancel();
  } else {
    oldState.Assign(Open() ? u"open"_ns : u"closed"_ns);
  }
  RefPtr<ToggleEvent> toggleEvent = CreateToggleEvent(
      u"toggle"_ns, oldState, newState, Cancelable::eNo, aSource);
  mToggleEventDispatcher = new AsyncEventDispatcher(this, toggleEvent.forget());
  mToggleEventDispatcher->PostDOMEvent();
}

// https://html.spec.whatwg.org/#set-the-dialog-close-watcher
void HTMLDialogElement::SetDialogCloseWatcherIfNeeded() {
  MOZ_ASSERT(StaticPrefs::dom_closewatcher_enabled(), "CloseWatcher enabled");
  // 1. Assert: dialog's close watcher is null.
  MOZ_ASSERT(!mCloseWatcher);

  // 2. Assert: dialog has an open attribute and dialog's node document is
  // fully active.
  RefPtr<Document> doc = OwnerDoc();
  RefPtr window = doc->GetInnerWindow();
  MOZ_ASSERT(Open() && window && window->IsFullyActive());

  // 3. Set dialog's close watcher to the result of establishing a close
  // watcher given dialog's relevant global object, with:
  mCloseWatcher = new CloseWatcher(window);
  RefPtr<DialogCloseWatcherListener> eventListener =
      new DialogCloseWatcherListener(this);

  // - cancelAction given canPreventClose being to return the result of firing
  // an event named cancel at dialog, with the cancelable attribute
  // initialized to canPreventClose.
  mCloseWatcher->AddSystemEventListener(u"cancel"_ns, eventListener,
                                        false /* aUseCapture */,
                                        false /* aWantsUntrusted */);

  // - closeAction being to close the dialog given dialog and dialog's request
  // close return value.
  mCloseWatcher->AddSystemEventListener(u"close"_ns, eventListener,
                                        false /* aUseCapture */,
                                        false /* aWantsUntrusted */);

  // - getEnabledState being to return true if dialog's enable close watcher
  // for requestClose() is true or dialog's computed closed-by state is not
  // None; otherwise false.
  //
  // XXX: Rather than creating a function pointer to manage the state of two
  // boolean conditions, we set the enabled state of the close watcher
  // explicitly whenever the state of those two conditions change. The first
  // condition "enable close watcher for requestclose" is managed in
  // RequestClose(), the other condition is managed by this function:
  SetCloseWatcherEnabledState();

  mCloseWatcher->AddToWindowsCloseWatcherManager();
}

// https://html.spec.whatwg.org/multipage#dialog-setup-steps
void HTMLDialogElement::SetupSteps() {
  // 1. Assert: subject has an open attribute.
  MOZ_ASSERT(Open());

  // 2. Assert: subject is connected.
  MOZ_ASSERT(IsInComposedDoc(), "Dialog SetupSteps needs IsInComposedDoc");

  // 3. Assert: subject's node document's open dialogs list does not contain
  // subject.
  MOZ_ASSERT(!OwnerDoc()->DialogIsInOpenDialogsList(*this));

  // 4. Add subject to subject's node document's open dialogs list.
  OwnerDoc()->AddOpenDialog(*this);

  // 5. Set the dialog close watcher with subject.
  if (StaticPrefs::dom_closewatcher_enabled()) {
    SetDialogCloseWatcherIfNeeded();
  }
}

void HTMLDialogElement::SetCloseWatcherEnabledState() {
  if (StaticPrefs::dom_closewatcher_enabled() && mCloseWatcher) {
    mCloseWatcher->SetEnabled(GetClosedBy() != ClosedBy::None);
  }
}

// https://html.spec.whatwg.org/#dialog-cleanup-steps
void HTMLDialogElement::CleanupSteps() {
  // 1. Remove subject from subject's node document's open dialogs list.
  OwnerDoc()->RemoveOpenDialog(*this);

  // 2. If subject's close watcher is not null, and subject does not have an
  // open attribute, then:
  if (mCloseWatcher) {
    // 3. Destroy subject's close watcher.
    mCloseWatcher->Destroy();

    // 4. Set subject's close watcher to null.
    mCloseWatcher = nullptr;
  }
}

JSObject* HTMLDialogElement::WrapNode(JSContext* aCx,
                                      JS::Handle<JSObject*> aGivenProto) {
  return HTMLDialogElement_Binding::Wrap(aCx, this, aGivenProto);
}

}  // namespace mozilla::dom

Messung V0.5 in Prozent
C=75 H=100 G=88

¤ Dauer der Verarbeitung: 0.28 Sekunden  (vorverarbeitet am  2026-08-27) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

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.