diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 47fa4521ecd..a313f1786ed 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -8,6 +8,9 @@
+
+ SubmitEvent support added.
+
Avoid usage of org.w3c.dom.ranges.Range - this is not available on android.
diff --git a/src/main/java/org/htmlunit/html/HtmlForm.java b/src/main/java/org/htmlunit/html/HtmlForm.java
index 1ff3fd79773..9ce11857efa 100644
--- a/src/main/java/org/htmlunit/html/HtmlForm.java
+++ b/src/main/java/org/htmlunit/html/HtmlForm.java
@@ -56,6 +56,7 @@
import org.htmlunit.WebWindow;
import org.htmlunit.httpclient.HttpClientConverter;
import org.htmlunit.javascript.host.event.Event;
+import org.htmlunit.javascript.host.event.SubmitEvent;
import org.htmlunit.protocol.javascript.JavaScriptURLConnection;
import org.htmlunit.util.EncodingSniffer;
import org.htmlunit.util.NameValuePair;
@@ -152,8 +153,8 @@ && getAttributeDirect(ATTRIBUTE_NOVALIDATE) != ATTRIBUTE_NOT_DEFINED) {
if (validate && !areChildrenValid()) {
return;
}
-
- final ScriptResult scriptResult = fireEvent(Event.TYPE_SUBMIT);
+ final ScriptResult scriptResult = fireEvent(new SubmitEvent(this,
+ ((HtmlElement) submitElement).getScriptableObject()));
if (isPreventDefault_) {
// null means 'nothing executed'
if (scriptResult == null) {
diff --git a/src/main/java/org/htmlunit/javascript/configuration/JavaScriptConfiguration.java b/src/main/java/org/htmlunit/javascript/configuration/JavaScriptConfiguration.java
index 63321faa8c9..851e44a0a61 100644
--- a/src/main/java/org/htmlunit/javascript/configuration/JavaScriptConfiguration.java
+++ b/src/main/java/org/htmlunit/javascript/configuration/JavaScriptConfiguration.java
@@ -231,6 +231,7 @@
import org.htmlunit.javascript.host.event.SecurityPolicyViolationEvent;
import org.htmlunit.javascript.host.event.SpeechSynthesisEvent;
import org.htmlunit.javascript.host.event.StorageEvent;
+import org.htmlunit.javascript.host.event.SubmitEvent;
import org.htmlunit.javascript.host.event.TextEvent;
import org.htmlunit.javascript.host.event.TimeEvent;
import org.htmlunit.javascript.host.event.TouchEvent;
@@ -610,7 +611,7 @@ public final class JavaScriptConfiguration extends AbstractJavaScriptConfigurati
SpeechSynthesis.class, SpeechSynthesisErrorEvent.class, SpeechSynthesisEvent.class,
SpeechSynthesisUtterance.class, SpeechSynthesisVoice.class,
StereoPannerNode.class, Storage.class, StorageEvent.class, StorageManager.class,
- StyleMedia.class, StyleSheet.class, StyleSheetList.class, SubtleCrypto.class,
+ StyleMedia.class, StyleSheet.class, StyleSheetList.class, SubmitEvent.class, SubtleCrypto.class,
SVGAElement.class, SVGAngle.class, SVGAnimatedAngle.class,
SVGAnimatedBoolean.class, SVGAnimatedEnumeration.class, SVGAnimatedInteger.class,
SVGAnimatedLength.class, SVGAnimatedLengthList.class, SVGAnimatedNumber.class, SVGAnimatedNumberList.class,
diff --git a/src/main/java/org/htmlunit/javascript/host/event/SubmitEvent.java b/src/main/java/org/htmlunit/javascript/host/event/SubmitEvent.java
new file mode 100644
index 00000000000..85e70ba2aa9
--- /dev/null
+++ b/src/main/java/org/htmlunit/javascript/host/event/SubmitEvent.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2002-2023 Gargoyle Software Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.htmlunit.javascript.host.event;
+
+import static org.htmlunit.javascript.configuration.SupportedBrowser.CHROME;
+import static org.htmlunit.javascript.configuration.SupportedBrowser.EDGE;
+import static org.htmlunit.javascript.configuration.SupportedBrowser.FF;
+import static org.htmlunit.javascript.configuration.SupportedBrowser.FF_ESR;
+
+import org.htmlunit.corejs.javascript.ScriptableObject;
+import org.htmlunit.corejs.javascript.Undefined;
+import org.htmlunit.html.DomNode;
+import org.htmlunit.javascript.configuration.JsxClass;
+import org.htmlunit.javascript.configuration.JsxConstructor;
+import org.htmlunit.javascript.configuration.JsxGetter;
+import org.htmlunit.javascript.host.html.HTMLElement;
+
+/**
+ * A JavaScript object for {@code SubmitEvent}.
+ *
+ * @author Ronald Brill
+ */
+@JsxClass
+public class SubmitEvent extends Event {
+
+ private HTMLElement submitter_;
+
+ /**
+ * Default constructor.
+ */
+ public SubmitEvent() {
+ }
+
+ /**
+ * Ctor.
+ * @param domNode the DOM node that triggered the event
+ * @param submitElement
+ *
+ */
+ public SubmitEvent(final DomNode domNode, final HTMLElement submitElement) {
+ super(domNode, Event.TYPE_SUBMIT);
+ submitter_ = submitElement;
+ }
+
+ /**
+ * JavaScript constructor.
+ *
+ * @param type the event type
+ * @param details the event details (optional)
+ */
+ @Override
+ @JsxConstructor({CHROME, EDGE, FF, FF_ESR})
+ public void jsConstructor(final String type, final ScriptableObject details) {
+ super.jsConstructor(type, details);
+
+ if (details != null && !Undefined.isUndefined(details)) {
+ final Object submitter = details.get("submitter");
+ if (submitter instanceof HTMLElement) {
+ submitter_ = (HTMLElement) submitter;
+ }
+ }
+ }
+
+ /**
+ * @return the submitter
+ */
+ @JsxGetter
+ public HTMLElement getSubmitter() {
+ return submitter_;
+ }
+}
diff --git a/src/test/java/org/htmlunit/javascript/host/event/SubmitEventTest.java b/src/test/java/org/htmlunit/javascript/host/event/SubmitEventTest.java
new file mode 100644
index 00000000000..d545824501b
--- /dev/null
+++ b/src/test/java/org/htmlunit/javascript/host/event/SubmitEventTest.java
@@ -0,0 +1,286 @@
+/*
+ * Copyright (c) 2002-2023 Gargoyle Software Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.htmlunit.javascript.host.event;
+
+import org.htmlunit.WebDriverTestCase;
+import org.htmlunit.html.HtmlPageTest;
+import org.htmlunit.junit.BrowserRunner;
+import org.htmlunit.junit.BrowserRunner.Alerts;
+import org.htmlunit.junit.BrowserRunner.HtmlUnitNYI;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Tests for {@link SubmitEvent}.
+ *
+ * @author Ronald Brill
+ */
+@RunWith(BrowserRunner.class)
+public class SubmitEventTest extends WebDriverTestCase {
+
+ private static final String DUMP_EVENT_FUNCTION = " function dump(event) {\n"
+ + " log(event);\n"
+ + " log(event.type);\n"
+ + " log(event.bubbles);\n"
+ + " log(event.cancelable);\n"
+ + " log(event.composed);\n"
+ + " log(event.submitter);\n"
+ + " }\n";
+
+ /**
+ * @throws Exception if the test fails
+ */
+ @Test
+ @Alerts(DEFAULT = {"[object SubmitEvent]", "submit", "false", "false", "false", "null"},
+ IE = "exception")
+ public void create_ctor() throws Exception {
+ final String html = HtmlPageTest.STANDARDS_MODE_PREFIX_
+ + "\n"
+ + "";
+
+ loadPageVerifyTitle2(html);
+ }
+
+ /**
+ * @throws Exception if the test fails
+ */
+ @Test
+ @Alerts("exception")
+ @HtmlUnitNYI(CHROME = {"[object SubmitEvent]", "undefined", "false", "false", "false", "null"},
+ EDGE = {"[object SubmitEvent]", "undefined", "false", "false", "false", "null"},
+ FF = {"[object SubmitEvent]", "undefined", "false", "false", "false", "null"},
+ FF_ESR = {"[object SubmitEvent]", "undefined", "false", "false", "false", "null"})
+ public void create_ctorWithoutType() throws Exception {
+ final String html = HtmlPageTest.STANDARDS_MODE_PREFIX_
+ + "\n"
+ + "";
+
+ loadPageVerifyTitle2(html);
+ }
+
+ /**
+ * @throws Exception if the test fails
+ */
+ @Test
+ @Alerts(DEFAULT = {"[object SubmitEvent]", "42", "false", "false", "false", "null"},
+ IE = "exception")
+ public void create_ctorNumericType() throws Exception {
+ final String html = HtmlPageTest.STANDARDS_MODE_PREFIX_
+ + "\n"
+ + "";
+
+ loadPageVerifyTitle2(html);
+ }
+
+ /**
+ * @throws Exception if the test fails
+ */
+ @Test
+ @Alerts(DEFAULT = {"[object SubmitEvent]", "null", "false", "false", "false", "null"},
+ IE = "exception")
+ public void create_ctorNullType() throws Exception {
+ final String html = HtmlPageTest.STANDARDS_MODE_PREFIX_
+ + "\n"
+ + "";
+
+ loadPageVerifyTitle2(html);
+ }
+
+ /**
+ * @throws Exception if the test fails
+ */
+ @Test
+ @Alerts("exception")
+ public void create_ctorUnknownType() throws Exception {
+ final String html = HtmlPageTest.STANDARDS_MODE_PREFIX_
+ + "\n"
+ + "";
+
+ loadPageVerifyTitle2(html);
+ }
+
+ /**
+ * @throws Exception if the test fails
+ */
+ @Test
+ @Alerts(DEFAULT = {"[object SubmitEvent]", "HtmlUnitEvent", "false", "false", "false", "null"},
+ IE = "exception")
+ public void create_ctorArbitraryType() throws Exception {
+ final String html = HtmlPageTest.STANDARDS_MODE_PREFIX_
+ + "\n"
+ + "";
+
+ loadPageVerifyTitle2(html);
+ }
+
+ /**
+ * @throws Exception if the test fails
+ */
+ @Test
+ @Alerts(DEFAULT = {"[object SubmitEvent]", "submit", "false", "false", "false", "null"},
+ IE = "exception")
+ public void create_ctorAllDetails() throws Exception {
+ final String html = HtmlPageTest.STANDARDS_MODE_PREFIX_
+ + "\n"
+ + "";
+
+ loadPageVerifyTitle2(html);
+ }
+
+ /**
+ * @throws Exception if the test fails
+ */
+ @Test
+ @Alerts(DEFAULT = {"[object SubmitEvent]", "submit", "false", "false", "false", "null"},
+ IE = "exception")
+ public void create_ctorAllDetailsMissingData() throws Exception {
+ final String html = HtmlPageTest.STANDARDS_MODE_PREFIX_
+ + "\n"
+ + "";
+
+ loadPageVerifyTitle2(html);
+ }
+
+ /**
+ * @throws Exception if the test fails
+ */
+ @Test
+ @Alerts("exception")
+ @HtmlUnitNYI(CHROME = {"[object SubmitEvent]", "submit", "false", "false", "false", "null"},
+ EDGE = {"[object SubmitEvent]", "submit", "false", "false", "false", "null"},
+ FF = {"[object SubmitEvent]", "submit", "false", "false", "false", "null"},
+ FF_ESR = {"[object SubmitEvent]", "submit", "false", "false", "false", "null"})
+ public void create_ctorAllDetailsWrongData() throws Exception {
+ final String html = HtmlPageTest.STANDARDS_MODE_PREFIX_
+ + "\n"
+ + "";
+
+ loadPageVerifyTitle2(html);
+ }
+
+ /**
+ * @throws Exception if the test fails
+ */
+ @Test
+ @Alerts("true")
+ public void inWindow() throws Exception {
+ final String html
+ = "\n"
+ + "\n"
+ + " \n"
+ + "\n"
+ + "\n"
+ + "\n"
+ + "";
+
+ loadPageVerifyTitle2(html);
+ }
+}
diff --git a/src/test/java/org/htmlunit/javascript/host/html/HTMLFormElementTest.java b/src/test/java/org/htmlunit/javascript/host/html/HTMLFormElementTest.java
index dbc41ad3a6e..67cfba571dd 100644
--- a/src/test/java/org/htmlunit/javascript/host/html/HTMLFormElementTest.java
+++ b/src/test/java/org/htmlunit/javascript/host/html/HTMLFormElementTest.java
@@ -2138,7 +2138,8 @@ public void dispatchEventSubmitTriggersHandlers() throws Exception {
* @throws Exception if the test fails
*/
@Test
- @Alerts({"srcElement null: false", "srcElement==form: true",
+ @Alerts({"type: submit", "submitter: [object HTMLInputElement]",
+ "srcElement null: false", "srcElement==form: true",
"target null: false", "target==form: true"})
public void onSubmitEvent() throws Exception {
final String html = "\n"
@@ -2146,6 +2147,8 @@ public void onSubmitEvent() throws Exception {
+ LOG_TITLE_FUNCTION
+ "function test(_event) {\n"
+ " var oEvent = _event ? _event : window.event;\n"
+ + " log('type: ' + oEvent.type);\n"
+ + " log('submitter: ' + oEvent.submitter);\n"
+ " log('srcElement null: ' + (oEvent.srcElement == null));\n"
+ " log('srcElement==form: ' + (oEvent.srcElement == document.forms[0]));\n"
+ " log('target null: ' + (oEvent.target == null));\n"
diff --git a/src/test/java/org/htmlunit/libraries/HtmxTest1x9x1.java b/src/test/java/org/htmlunit/libraries/HtmxTest1x9x1.java
index 6ee3400a57c..5b0ff18504f 100644
--- a/src/test/java/org/htmlunit/libraries/HtmxTest1x9x1.java
+++ b/src/test/java/org/htmlunit/libraries/HtmxTest1x9x1.java
@@ -35,11 +35,11 @@ public class HtmxTest1x9x1 extends HtmxTest {
@Alerts(DEFAULT = "passes:528failures:0",
IE = "not testable")
@HtmlUnitNYI(
- CHROME = "passes:512failures:16",
- EDGE = "passes:512failures:16",
- FF = "passes:512failures:16",
- FF_ESR = "passes:512failures:16",
- IE = "passes:411failures:109")
+ CHROME = "passes:513failures:15",
+ EDGE = "passes:513failures:15",
+ FF = "passes:513failures:15",
+ FF_ESR = "passes:513failures:15",
+ IE = "passes:412failures:108")
public void htmx() throws Exception {
htmx("htmx-1.9.1");
}