Issue #2403 - Implement SubmitEvent functionality (#2919)

# Summary

Added SubmitEvent support (constructor, submitter attribute) and wired form submit events to produce SubmitEvent instances.

Implemented SubmitEvent DOM class, WebIDL, and build hooks.

Added a test file (logs to console).

# Notes

Form submissions already carry the originating control in `InternalFormEvent::mOriginator`, so `SubmitEvent.submitter` can be populated directly from the existing event data without invasive changes to form submission logic.

`EventDispatcher` now returns `SubmitEvent` specifically for `eFormSubmit`, keeping other form events (e.g., reset) unchanged.

`event.submitter` is set for user-initiated submits via the originating submit control.

`new SubmitEvent("submit", { submitter })` returns the provided submitter (or `null` if omitted).

# Ways to test
Go to repo.palemoon.org. You will no longer see the message `This browser doesn't have "SubmitEvent" support, use a tricky method to polyfill` in the console. The site will work as expected without loading this polyfill anymore.

Go to GitHub. You will now be able to mark notifications as read.

Open the test file submitted in this PR. You will see the results of the test in the browser console.

Reviewed-on: https://repo.palemoon.org/MoonchildProductions/UXP/pulls/2919
Co-authored-by: Basilisk-Dev <basiliskdev@protonmail.com>
Co-committed-by: Basilisk-Dev <basiliskdev@protonmail.com>
This commit is contained in:
Basilisk-Dev
2026-01-29 00:40:09 +00:00
committed by roytam1
parent 20525d238b
commit 9b3d172a95
8 changed files with 232 additions and 0 deletions
+7
View File
@@ -40,6 +40,7 @@
#include "mozilla/dom/ScrollAreaEvent.h"
#include "mozilla/dom/SimpleGestureEvent.h"
#include "mozilla/dom/StorageEvent.h"
#include "mozilla/dom/SubmitEvent.h"
#include "mozilla/dom/TimeEvent.h"
#include "mozilla/dom/TouchEvent.h"
#include "mozilla/dom/TransitionEvent.h"
@@ -1066,6 +1067,12 @@ EventDispatcher::CreateEvent(EventTarget* aOwner,
case eAnimationEventClass:
return NS_NewDOMAnimationEvent(aOwner, aPresContext,
aEvent->AsAnimationEvent());
case eFormEventClass:
if (aEvent->mMessage == eFormSubmit) {
return NS_NewDOMSubmitEvent(aOwner, aPresContext,
aEvent->AsFormEvent());
}
return NS_NewDOMEvent(aOwner, aPresContext, aEvent);
default:
// For all other types of events, create a vanilla event object.
return NS_NewDOMEvent(aOwner, aPresContext, aEvent);
+64
View File
@@ -0,0 +1,64 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/SubmitEvent.h"
#include "mozilla/ContentEvents.h"
#include "nsIContent.h"
namespace mozilla {
namespace dom {
NS_IMPL_CYCLE_COLLECTION_INHERITED(SubmitEvent, Event, mSubmitter)
NS_IMPL_ADDREF_INHERITED(SubmitEvent, Event)
NS_IMPL_RELEASE_INHERITED(SubmitEvent, Event)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(SubmitEvent)
NS_INTERFACE_MAP_END_INHERITING(Event)
SubmitEvent::SubmitEvent(EventTarget* aOwner,
nsPresContext* aPresContext,
InternalFormEvent* aEvent)
: Event(aOwner, aPresContext, aEvent)
{
if (aEvent) {
nsIContent* originator = aEvent->mOriginator;
if (originator && originator->IsHTMLElement()) {
mSubmitter = static_cast<::nsGenericHTMLElement*>(originator);
}
}
}
already_AddRefed<SubmitEvent>
SubmitEvent::Constructor(const GlobalObject& aGlobal,
const nsAString& aType,
const SubmitEventInit& aParam,
ErrorResult& aRv)
{
nsCOMPtr<EventTarget> t = do_QueryInterface(aGlobal.GetAsSupports());
RefPtr<SubmitEvent> e = new SubmitEvent(t, nullptr, nullptr);
bool trusted = e->Init(t);
e->InitEvent(aType, aParam.mBubbles, aParam.mCancelable);
e->mSubmitter = aParam.mSubmitter;
e->SetTrusted(trusted);
e->SetComposed(aParam.mComposed);
return e.forget();
}
} // namespace dom
} // namespace mozilla
using namespace mozilla;
using namespace mozilla::dom;
already_AddRefed<SubmitEvent>
NS_NewDOMSubmitEvent(EventTarget* aOwner,
nsPresContext* aPresContext,
InternalFormEvent* aEvent)
{
RefPtr<SubmitEvent> it = new SubmitEvent(aOwner, aPresContext, aEvent);
return it.forget();
}
+61
View File
@@ -0,0 +1,61 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/. */
#ifndef mozilla_dom_SubmitEvent_h_
#define mozilla_dom_SubmitEvent_h_
#include "mozilla/dom/Event.h"
#include "mozilla/dom/SubmitEventBinding.h"
#include "mozilla/EventForwards.h"
class nsGenericHTMLElement;
namespace mozilla {
namespace dom {
class SubmitEvent final : public Event
{
public:
SubmitEvent(EventTarget* aOwner,
nsPresContext* aPresContext,
InternalFormEvent* aEvent);
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(SubmitEvent, Event)
// Forward to base class
NS_FORWARD_TO_EVENT
static already_AddRefed<SubmitEvent> Constructor(const GlobalObject& aGlobal,
const nsAString& aType,
const SubmitEventInit& aParam,
ErrorResult& aRv);
::nsGenericHTMLElement* GetSubmitter() const
{
return mSubmitter;
}
virtual JSObject* WrapObjectInternal(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override
{
return SubmitEventBinding::Wrap(aCx, this, aGivenProto);
}
protected:
~SubmitEvent() {}
private:
RefPtr<::nsGenericHTMLElement> mSubmitter;
};
} // namespace dom
} // namespace mozilla
already_AddRefed<mozilla::dom::SubmitEvent>
NS_NewDOMSubmitEvent(mozilla::dom::EventTarget* aOwner,
nsPresContext* aPresContext,
mozilla::InternalFormEvent* aEvent);
#endif // mozilla_dom_SubmitEvent_h_
+2
View File
@@ -65,6 +65,7 @@ EXPORTS.mozilla.dom += [
'ScrollAreaEvent.h',
'SimpleGestureEvent.h',
'StorageEvent.h',
'SubmitEvent.h',
'TextClause.h',
'Touch.h',
'TouchEvent.h',
@@ -115,6 +116,7 @@ UNIFIED_SOURCES += [
'ScrollAreaEvent.cpp',
'SimpleGestureEvent.cpp',
'StorageEvent.cpp',
'SubmitEvent.cpp',
'TextClause.cpp',
'TextComposition.cpp',
'Touch.cpp',
+1
View File
@@ -170,6 +170,7 @@ skip-if = toolkit == 'android' #CRASH_DUMP, RANDOM
skip-if = toolkit == 'android' #TIMED_OUT
[test_eventctors.html]
skip-if = toolkit == 'android' #CRASH_DUMP, RANDOM
[test_submit_event.html]
[test_eventhandler_scoping.html]
[test_eventTimeStamp.html]
[test_focus_disabled.html]
+80
View File
@@ -0,0 +1,80 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test for SubmitEvent and submitter</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<pre id="test">
<script type="application/javascript">
var hasSimpleTest = typeof SimpleTest !== "undefined";
function finishIfPossible() {
if (hasSimpleTest) {
SimpleTest.finish();
}
}
function okMaybe(cond, msg) {
if (hasSimpleTest) {
ok(cond, msg);
} else {
console.log((cond ? "OK: " : "FAIL: ") + msg);
}
}
function isMaybe(a, b, msg) {
if (hasSimpleTest) {
is(a, b, msg);
} else {
console.log((a === b ? "OK: " : "FAIL: ") + msg + " (got " + a + " expected " + b + ")");
}
}
if (hasSimpleTest) {
SimpleTest.waitForExplicitFinish();
}
function testConstructor() {
okMaybe("SubmitEvent" in window, "SubmitEvent constructor exists");
var button = document.createElement("button");
var ev = new SubmitEvent("submit", { submitter: button, bubbles: true, cancelable: true });
isMaybe(ev.type, "submit", "constructor type matches");
okMaybe(!ev.isTrusted, "constructed SubmitEvent is not trusted");
isMaybe(ev.submitter, button, "constructor submitter matches");
var ev2 = new SubmitEvent("submit");
isMaybe(ev2.submitter, null, "default submitter is null");
}
function testDispatch() {
var form = document.createElement("form");
var button = document.createElement("button");
button.type = "submit";
button.textContent = "Submit";
form.appendChild(button);
document.body.appendChild(form);
form.addEventListener("submit", function(e) {
okMaybe(e instanceof SubmitEvent, "submit event is SubmitEvent");
isMaybe(e.submitter, button, "submitter is the clicked button");
e.preventDefault();
form.remove();
finishIfPossible();
});
if (hasSimpleTest) {
SimpleTest.executeSoon(function() {
button.click();
});
} else {
setTimeout(function() {
button.click();
}, 0);
}
}
testConstructor();
testDispatch();
</script>
</pre>
</body>
</html>
+16
View File
@@ -0,0 +1,16 @@
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/.
*/
[Constructor(DOMString type, optional SubmitEventInit eventInitDict)]
interface SubmitEvent : Event
{
readonly attribute HTMLElement? submitter;
};
dictionary SubmitEventInit : EventInit
{
HTMLElement? submitter = null;
};
+1
View File
@@ -412,6 +412,7 @@ WEBIDL_FILES = [
'StorageType.webidl',
'StyleSheet.webidl',
'StyleSheetList.webidl',
'SubmitEvent.webidl',
'SubtleCrypto.webidl',
'SVGAElement.webidl',
'SVGAngle.webidl',