Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/Firefox/dom/html/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 14 kB image not shown  

Quelle  HTMLButtonElement.cpp   Sprache: C

 
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/HTMLButtonElement.h"

#include "HTMLFormSubmissionConstants.h"
#include "mozilla/dom/FormData.h"
#include "mozilla/dom/HTMLButtonElementBinding.h"
#include "nsAttrValueInlines.h"
#include "nsIContentInlines.h"
#include "nsGkAtoms.h"
#include "nsPresContext.h"
#include "nsIFormControl.h"
#include "nsIFrame.h"
#include "mozilla/dom/Document.h"
#include "mozilla/ContentEvents.h"
#include "mozilla/FocusModel.h"
#include "mozilla/EventDispatcher.h"
#include "mozilla/EventStateManager.h"
#include "mozilla/MouseEvents.h"
#include "mozilla/PresShell.h"
#include "mozilla/TextEvents.h"
#include "nsUnicharUtils.h"
#include "nsLayoutUtils.h"
#include "mozilla/PresState.h"
#include "nsError.h"
#include "nsFocusManager.h"
#include "mozilla/dom/HTMLFormElement.h"
#include "mozAutoDocUpdate.h"

#define NS_IN_SUBMIT_CLICK (1 << 0)
#define NS_OUTER_ACTIVATE_EVENT (1 << 1)

NS_IMPL_NS_NEW_HTML_ELEMENT_CHECK_PARSER(Button)

namespace mozilla::dom {

static const nsAttrValue::EnumTable kButtonTypeTable[] = {
    {"button", FormControlType::ButtonButton},
    {"reset", FormControlType::ButtonReset},
    {"submit", FormControlType::ButtonSubmit},
    {nullptr, 0}};

// Default type is 'submit'.
static const nsAttrValue::EnumTable* kButtonDefaultType = &kButtonTypeTable[2];

// Construction, destruction
HTMLButtonElement::HTMLButtonElement(
    already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
    FromParser aFromParser)
    : nsGenericHTMLFormControlElementWithState(
          std::move(aNodeInfo), aFromParser,
          FormControlType(kButtonDefaultType->value)),
      mDisabledChanged(false),
      mInInternalActivate(false),
      mInhibitStateRestoration(aFromParser & FROM_PARSER_FRAGMENT) {
  // Set up our default state: enabled
  AddStatesSilently(ElementState::ENABLED);
}

HTMLButtonElement::~HTMLButtonElement() = default;

// nsISupports

NS_IMPL_CYCLE_COLLECTION_INHERITED(HTMLButtonElement,
                                   nsGenericHTMLFormControlElementWithState,
                                   mValidity)

NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED(
    HTMLButtonElement, nsGenericHTMLFormControlElementWithState,
    nsIConstraintValidation)

void HTMLButtonElement::SetCustomValidity(const nsAString& aError) {
  ConstraintValidation::SetCustomValidity(aError);
  UpdateValidityElementStates(true);
}

void HTMLButtonElement::UpdateBarredFromConstraintValidation() {
  SetBarredFromConstraintValidation(
      mType == FormControlType::ButtonButton ||
      mType == FormControlType::ButtonReset ||
      HasFlag(ELEMENT_IS_DATALIST_OR_HAS_DATALIST_ANCESTOR) || IsDisabled());
}

void HTMLButtonElement::FieldSetDisabledChanged(bool aNotify) {
  // FieldSetDisabledChanged *has* to be called *before*
  // UpdateBarredFromConstraintValidation, because the latter depends on our
  // disabled state.
  nsGenericHTMLFormControlElementWithState::FieldSetDisabledChanged(aNotify);

  UpdateBarredFromConstraintValidation();
  UpdateValidityElementStates(aNotify);
}

NS_IMPL_ELEMENT_CLONE(HTMLButtonElement)

void HTMLButtonElement::GetFormEnctype(nsAString& aFormEncType) {
  GetEnumAttr(nsGkAtoms::formenctype, "", kFormDefaultEnctype->tag,
              aFormEncType);
}

void HTMLButtonElement::GetFormMethod(nsAString& aFormMethod) {
  GetEnumAttr(nsGkAtoms::formmethod, "", kFormDefaultMethod->tag, aFormMethod);
}

void HTMLButtonElement::GetType(nsAString& aType) {
  GetEnumAttr(nsGkAtoms::type, kButtonDefaultType->tag, aType);
}

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

bool HTMLButtonElement::IsHTMLFocusable(IsFocusableFlags aFlags,
                                        bool* aIsFocusable,
                                        int32_t* aTabIndex) {
  if (nsGenericHTMLFormControlElementWithState::IsHTMLFocusable(
          aFlags, aIsFocusable, aTabIndex)) {
    return true;
  }
  *aIsFocusable = IsFormControlDefaultFocusable(aFlags) && !IsDisabled();
  return false;
}

bool HTMLButtonElement::ParseAttribute(int32_t aNamespaceID, nsAtom* aAttribute,
                                       const nsAString& aValue,
                                       nsIPrincipal* aMaybeScriptedPrincipal,
                                       nsAttrValue& aResult) {
  if (aNamespaceID == kNameSpaceID_None) {
    if (aAttribute == nsGkAtoms::type) {
      return aResult.ParseEnumValue(aValue, kButtonTypeTable, false,
                                    kButtonDefaultType);
    }

    if (aAttribute == nsGkAtoms::formmethod) {
      return aResult.ParseEnumValue(aValue, kFormMethodTable, false);
    }
    if (aAttribute == nsGkAtoms::formenctype) {
      return aResult.ParseEnumValue(aValue, kFormEnctypeTable, false);
    }
  }

  return nsGenericHTMLFormControlElementWithState::ParseAttribute(
      aNamespaceID, aAttribute, aValue, aMaybeScriptedPrincipal, aResult);
}

bool HTMLButtonElement::IsDisabledForEvents(WidgetEvent* aEvent) {
  return IsElementDisabledForEvents(aEvent, GetPrimaryFrame());
}

void HTMLButtonElement::GetEventTargetParent(EventChainPreVisitor& aVisitor) {
  aVisitor.mCanHandle = false;

  if (IsDisabledForEvents(aVisitor.mEvent)) {
    return;
  }

  // Track whether we're in the outermost Dispatch invocation that will
  // cause activation of the input.  That is, if we're a click event, or a
  // DOMActivate that was dispatched directly, this will be set, but if we're
  // a DOMActivate dispatched from click handling, it will not be set.
  WidgetMouseEvent* mouseEvent = aVisitor.mEvent->AsMouseEvent();
  bool outerActivateEvent =
      ((mouseEvent && mouseEvent->IsLeftClickEvent()) ||
       (aVisitor.mEvent->mMessage == eLegacyDOMActivate &&
        !mInInternalActivate && aVisitor.mEvent->mOriginalTarget == this));

  if (outerActivateEvent) {
    aVisitor.mItemFlags |= NS_OUTER_ACTIVATE_EVENT;
    aVisitor.mWantsActivationBehavior = true;
  }

  nsGenericHTMLElement::GetEventTargetParent(aVisitor);
}

void HTMLButtonElement::LegacyPreActivationBehavior(
    EventChainVisitor& aVisitor) {
  // out-of-spec legacy pre-activation behavior needed because of bug 1803805
  if (mType == FormControlType::ButtonSubmit && mForm) {
    aVisitor.mItemFlags |= NS_IN_SUBMIT_CLICK;
    aVisitor.mItemData = static_cast<Element*>(mForm);
    // tell the form that we are about to enter a click handler.
    // that means that if there are scripted submissions, the
    // latest one will be deferred until after the exit point of the handler.
    mForm->OnSubmitClickBegin(this);
  }
}

nsresult HTMLButtonElement::PostHandleEvent(EventChainPostVisitor& aVisitor) {
  nsresult rv = NS_OK;
  if (!aVisitor.mPresContext) {
    return rv;
  }

  if (aVisitor.mEventStatus != nsEventStatus_eConsumeNoDefault) {
    WidgetMouseEvent* mouseEvent = aVisitor.mEvent->AsMouseEvent();
    if (mouseEvent && mouseEvent->IsLeftClickEvent() &&
        OwnerDoc()->MayHaveDOMActivateListeners()) {
      // DOMActive event should be trusted since the activation is actually
      // occurred even if the cause is an untrusted click event.
      InternalUIEvent actEvent(true, eLegacyDOMActivate, mouseEvent);
      actEvent.mDetail = 1;

      if (RefPtr<PresShell> presShell = aVisitor.mPresContext->GetPresShell()) {
        nsEventStatus status = nsEventStatus_eIgnore;
        mInInternalActivate = true;
        presShell->HandleDOMEventWithTarget(this, &actEvent, &status);
        mInInternalActivate = false;

        // If activate is cancelled, we must do the same as when click is
        // cancelled (revert the checkbox to its original value).
        if (status == nsEventStatus_eConsumeNoDefault) {
          aVisitor.mEventStatus = status;
        }
      }
    }
  }

  if (nsEventStatus_eIgnore == aVisitor.mEventStatus) {
    WidgetKeyboardEvent* keyEvent = aVisitor.mEvent->AsKeyboardEvent();
    if (keyEvent && keyEvent->IsTrusted()) {
      HandleKeyboardActivation(aVisitor);
    }

    // Bug 1459231: Temporarily needed till links respect activation target
    // Then also remove NS_OUTER_ACTIVATE_EVENT
    if ((aVisitor.mItemFlags & NS_OUTER_ACTIVATE_EVENT) && mForm &&
        (mType == FormControlType::ButtonReset ||
         mType == FormControlType::ButtonSubmit)) {
      aVisitor.mEvent->mFlags.mMultipleActionsPrevented = true;
    }
  }

  return rv;
}

void EndSubmitClick(EventChainVisitor& aVisitor) {
  if ((aVisitor.mItemFlags & NS_IN_SUBMIT_CLICK)) {
    nsCOMPtr<nsIContent> content(do_QueryInterface(aVisitor.mItemData));
    RefPtr<HTMLFormElement> form = HTMLFormElement::FromNodeOrNull(content);
    MOZ_ASSERT(form);
    // Tell the form that we are about to exit a click handler,
    // so the form knows not to defer subsequent submissions.
    // The pending ones that were created during the handler
    // will be flushed or forgotten.
    form->OnSubmitClickEnd();
    // Tell the form to flush a possible pending submission.
    // the reason is that the script returned false (the event was
    // not ignored) so if there is a stored submission, it needs to
    // be submitted immediatelly.
    // Note, NS_IN_SUBMIT_CLICK is set only when we're in outer activate event.
    form->FlushPendingSubmission();
  }
}

void HTMLButtonElement::ActivationBehavior(EventChainPostVisitor& aVisitor) {
  if (!aVisitor.mPresContext) {
    // Should check whether EndSubmitClick is needed here.
    return;
  }

  if (!IsDisabled()) {
    if (mForm) {
      // Hold a strong ref while dispatching
      RefPtr<mozilla::dom::HTMLFormElement> form(mForm);
      if (mType == FormControlType::ButtonReset) {
        form->MaybeReset(this);
        aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault;
      } else if (mType == FormControlType::ButtonSubmit) {
        form->MaybeSubmit(this);
        aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault;
      }
      // https://html.spec.whatwg.org/multipage/form-elements.html#attr-button-type-button-state
      // NS_FORM_BUTTON_BUTTON do nothing.
    }
    if (!GetInvokeTargetElement()) {
      HandlePopoverTargetAction();
    } else {
      HandleInvokeTargetAction();
    }
  }

  EndSubmitClick(aVisitor);
}

void HTMLButtonElement::LegacyCanceledActivationBehavior(
    EventChainPostVisitor& aVisitor) {
  // still need to end submission, see bug 1803805
  // e.g. when parent element of button has event handler preventing default
  // legacy canceled instead of activation behavior will be run
  EndSubmitClick(aVisitor);
}

nsresult HTMLButtonElement::BindToTree(BindContext& aContext,
                                       nsINode& aParent) {
  nsresult rv =
      nsGenericHTMLFormControlElementWithState::BindToTree(aContext, aParent);
  NS_ENSURE_SUCCESS(rv, rv);

  UpdateBarredFromConstraintValidation();
  UpdateValidityElementStates(false);

  return NS_OK;
}

void HTMLButtonElement::UnbindFromTree(UnbindContext& aContext) {
  nsGenericHTMLFormControlElementWithState::UnbindFromTree(aContext);

  UpdateBarredFromConstraintValidation();
  UpdateValidityElementStates(false);
}

NS_IMETHODIMP
HTMLButtonElement::Reset() { return NS_OK; }

NS_IMETHODIMP
HTMLButtonElement::SubmitNamesValues(FormData* aFormData) {
  //
  // We only submit if we were the button pressed
  //
  if (aFormData->GetSubmitterElement() != this) {
    return NS_OK;
  }

  //
  // Get the name (if no name, no submit)
  //
  nsAutoString name;
  GetHTMLAttr(nsGkAtoms::name, name);
  if (name.IsEmpty()) {
    return NS_OK;
  }

  //
  // Get the value
  //
  nsAutoString value;
  GetHTMLAttr(nsGkAtoms::value, value);

  //
  // Submit
  //
  return aFormData->AddNameValuePair(name, value);
}

void HTMLButtonElement::DoneCreatingElement() {
  if (!mInhibitStateRestoration) {
    GenerateStateKey();
    RestoreFormControlState();
  }
}

void HTMLButtonElement::BeforeSetAttr(int32_t aNameSpaceID, nsAtom* aName,
                                      const nsAttrValue* aValue, bool aNotify) {
  if (aNotify && aName == nsGkAtoms::disabled &&
      aNameSpaceID == kNameSpaceID_None) {
    mDisabledChanged = true;
  }

  return nsGenericHTMLFormControlElementWithState::BeforeSetAttr(
      aNameSpaceID, aName, aValue, aNotify);
}

void HTMLButtonElement::AfterSetAttr(int32_t aNameSpaceID, nsAtom* aName,
                                     const nsAttrValue* aValue,
                                     const nsAttrValue* aOldValue,
                                     nsIPrincipal* aSubjectPrincipal,
                                     bool aNotify) {
  if (aNameSpaceID == kNameSpaceID_None) {
    if (aName == nsGkAtoms::type) {
      if (aValue) {
        mType = FormControlType(aValue->GetEnumValue());
      } else {
        mType = FormControlType(kButtonDefaultType->value);
      }
    }

    if (aName == nsGkAtoms::type || aName == nsGkAtoms::disabled) {
      if (aName == nsGkAtoms::disabled) {
        // This *has* to be called *before* validity state check because
        // UpdateBarredFromConstraintValidation depends on our disabled state.
        UpdateDisabledState(aNotify);
      }

      UpdateBarredFromConstraintValidation();
      UpdateValidityElementStates(aNotify);
    }
  }

  return nsGenericHTMLFormControlElementWithState::AfterSetAttr(
      aNameSpaceID, aName, aValue, aOldValue, aSubjectPrincipal, aNotify);
}

void HTMLButtonElement::SaveState() {
  if (!mDisabledChanged) {
    return;
  }

  PresState* state = GetPrimaryPresState();
  if (state) {
    // We do not want to save the real disabled state but the disabled
    // attribute.
    state->disabled() = HasAttr(nsGkAtoms::disabled);
    state->disabledSet() = true;
  }
}

bool HTMLButtonElement::RestoreState(PresState* aState) {
  if (aState && aState->disabledSet() && !aState->disabled()) {
    SetDisabled(false, IgnoreErrors());
  }
  return false;
}

void HTMLButtonElement::UpdateValidityElementStates(bool aNotify) {
  AutoStateChangeNotifier notifier(*this, aNotify);
  RemoveStatesSilently(ElementState::VALIDITY_STATES);
  if (!IsCandidateForConstraintValidation()) {
    return;
  }
  if (IsValid()) {
    AddStatesSilently(ElementState::VALID | ElementState::USER_VALID);
  } else {
    AddStatesSilently(ElementState::INVALID | ElementState::USER_INVALID);
  }
}

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

}  // namespace mozilla::dom

100%


¤ Dauer der Verarbeitung: 0.16 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 ist noch experimentell.