This is an automated email from the ASF dual-hosted git repository.

reiern70 pushed a commit to branch firefox-triggered-submit
in repository https://gitbox.apache.org/repos/asf/wicket.git

commit ef55f0ec92505528d3205ecb6a8294a533a240eb
Author: reiern70 <[email protected]>
AuthorDate: Mon Oct 5 10:59:49 2026 -0500

    Keep Firefox from submitting a form for the triggered submit event
    
    An AjaxFormSubmitBehavior whose shouldTriggerJavaScriptSubmitEvent() returns
    true fires a submit event on the form before its Ajax request, so that 
submit
    handlers run - UploadProgressBar starts its bar from one. Since the 
jQuery-free
    engine, the precondition fired it with dispatchEvent(). Firefox still 
submits
    a form for a submit event fired by a script unless the event is cancelled, 
so
    an AjaxButton like the one of the upload example sent its Ajax request and
    submitted the form the normal way as well: the page was reloaded behind the
    Ajax response. Chrome does not submit for such an event.
    
    The precondition now calls the new Wicket.Event.triggerSubmit(form) of both
    engines. It fires the event, tells whether a submit handler cancelled it, 
and
    cancels it once it has bubbled up to the window, so no browser submits the
    form; the Ajax request does. A handler cancelling the event still stops the
    request.
    
    Applications see the Ajax request only, as in Chrome. Wicket 10.x is not
    affected: its precondition triggers the event through jQuery and cancels it.
    
    GitHub issue #1650
---
 .../ajax/form/AjaxFormSubmitBehaviorTest.java      | 27 ++++++++++
 .../wicket/ajax/form/AjaxFormSubmitBehavior.java   |  5 +-
 .../wicket/ajax/res/js/wicket-ajax-jquery.js       | 26 ++++++++++
 .../org/apache/wicket/ajax/res/js/wicket-ajax.js   | 26 ++++++++++
 wicket-core/src/test/js/event.js                   | 60 ++++++++++++++++++++++
 5 files changed, 143 insertions(+), 1 deletion(-)

diff --git 
a/wicket-core-tests/src/test/java/org/apache/wicket/ajax/form/AjaxFormSubmitBehaviorTest.java
 
b/wicket-core-tests/src/test/java/org/apache/wicket/ajax/form/AjaxFormSubmitBehaviorTest.java
index 48d5007cc1..f7a85e844a 100644
--- 
a/wicket-core-tests/src/test/java/org/apache/wicket/ajax/form/AjaxFormSubmitBehaviorTest.java
+++ 
b/wicket-core-tests/src/test/java/org/apache/wicket/ajax/form/AjaxFormSubmitBehaviorTest.java
@@ -78,6 +78,33 @@ class AjaxFormSubmitBehaviorTest extends WicketTestCase
                formTester.submit("submit");
        }
 
+       /**
+        * The submit event is triggered through {@code 
Wicket.Event.triggerSubmit()}, which keeps
+        * Firefox from submitting the form for it besides the Ajax request.
+        */
+       @Test
+       void theSubmitEventIsTriggeredWithoutSubmittingTheForm()
+       {
+               AjaxFormSubmitBehaviorTestPage page = new 
AjaxFormSubmitBehaviorTestPage();
+               page.getForm().getTextField().add(new 
AjaxFormSubmitBehavior("click")
+               {
+                       private static final long serialVersionUID = 1L;
+
+                       @Override
+                       protected boolean shouldTriggerJavaScriptSubmitEvent()
+                       {
+                               return true;
+                       }
+               });
+
+               tester.startPage(page);
+
+               String response = tester.getLastResponseAsString();
+               
assertTrue(response.contains("Wicket.Event.triggerSubmit(document.getElementById('"
 +
+                       page.getForm().getMarkupId() + "'))"), response);
+               assertFalse(response.contains("dispatchEvent"), response);
+       }
+
        public static class NestedFormTestPage extends NestedFormPage
        {
                
diff --git 
a/wicket-core/src/main/java/org/apache/wicket/ajax/form/AjaxFormSubmitBehavior.java
 
b/wicket-core/src/main/java/org/apache/wicket/ajax/form/AjaxFormSubmitBehavior.java
index 128ca2a514..aad70dbca2 100644
--- 
a/wicket-core/src/main/java/org/apache/wicket/ajax/form/AjaxFormSubmitBehavior.java
+++ 
b/wicket-core/src/main/java/org/apache/wicket/ajax/form/AjaxFormSubmitBehavior.java
@@ -143,6 +143,9 @@ public abstract class AjaxFormSubmitBehavior extends 
AjaxEventBehavior
        /**
         * Controls whether or not a JS <code>submit</code> should be triggered 
on the submitting form.
         * False by default.
+        * <p>
+        * The event runs the submit handlers of the form, and a handler 
cancelling it stops the Ajax
+        * request. The browser does not submit the form for this event; the 
Ajax request does.
         * 
         * @return true if <code>submit</code> should be triggered, false 
otherwise
         */
@@ -184,7 +187,7 @@ public abstract class AjaxFormSubmitBehavior extends 
AjaxEventBehavior
                                public CharSequence getPrecondition(Component 
component)
                                {
                                        return String.format(
-                                               "return 
document.getElementById('%s').dispatchEvent(new Event('submit', { cancelable: 
true, bubbles: true }));",
+                                               "return 
Wicket.Event.triggerSubmit(document.getElementById('%s'));",
                                                form.getMarkupId());
                                }
                        });
diff --git 
a/wicket-core/src/main/java/org/apache/wicket/ajax/res/js/wicket-ajax-jquery.js 
b/wicket-core/src/main/java/org/apache/wicket/ajax/res/js/wicket-ajax-jquery.js
index 288dcd004c..25c20d93c7 100644
--- 
a/wicket-core/src/main/java/org/apache/wicket/ajax/res/js/wicket-ajax-jquery.js
+++ 
b/wicket-core/src/main/java/org/apache/wicket/ajax/res/js/wicket-ajax-jquery.js
@@ -2505,6 +2505,32 @@
                                }
                        },
 
+                       /**
+                        * Fires a submit event on the given form, so that its 
submit handlers run, without
+                        * submitting the form: an Ajax request submits it 
instead. Firefox submits a form for
+                        * a submit event fired by a script unless the event is 
cancelled, so the event is
+                        * cancelled once it has bubbled up to the window.
+                        *
+                        * @param form {HTMLFormElement} the form
+                        * @returns {boolean} false if a submit handler 
cancelled the event
+                        */
+                       triggerSubmit: function(form) {
+                               let cancelledByHandler = null;
+                               const cancel = function (event) {
+                                       cancelledByHandler = 
event.defaultPrevented;
+                                       event.preventDefault();
+                               };
+                               let notCancelled;
+                               window.addEventListener('submit', cancel);
+                               try {
+                                       notCancelled = form.dispatchEvent(new 
Event('submit', { cancelable: true, bubbles: true }));
+                               } finally {
+                                       window.removeEventListener('submit', 
cancel);
+                               }
+                               // null when a handler stopped the propagation 
before the window
+                               return cancelledByHandler === null ? 
notCancelled : !cancelledByHandler;
+                       },
+
                        /**
                         * The names of the topics on which Wicket notifies
                         */
diff --git 
a/wicket-core/src/main/java/org/apache/wicket/ajax/res/js/wicket-ajax.js 
b/wicket-core/src/main/java/org/apache/wicket/ajax/res/js/wicket-ajax.js
index befb85810a..4d86bf3833 100644
--- a/wicket-core/src/main/java/org/apache/wicket/ajax/res/js/wicket-ajax.js
+++ b/wicket-core/src/main/java/org/apache/wicket/ajax/res/js/wicket-ajax.js
@@ -2785,6 +2785,32 @@
                        }
                },
 
+               /**
+                * Fires a submit event on the given form, so that its submit 
handlers run, without
+                * submitting the form: an Ajax request submits it instead. 
Firefox submits a form for
+                * a submit event fired by a script unless the event is 
cancelled, so the event is
+                * cancelled once it has bubbled up to the window.
+                *
+                * @param form {HTMLFormElement} the form
+                * @returns {boolean} false if a submit handler cancelled the 
event
+                */
+               triggerSubmit: function(form) {
+                       let cancelledByHandler = null;
+                       const cancel = function (event) {
+                               cancelledByHandler = event.defaultPrevented;
+                               event.preventDefault();
+                       };
+                       let notCancelled;
+                       window.addEventListener('submit', cancel);
+                       try {
+                               notCancelled = form.dispatchEvent(new 
Event('submit', { cancelable: true, bubbles: true }));
+                       } finally {
+                               window.removeEventListener('submit', cancel);
+                       }
+                       // null when a handler stopped the propagation before 
the window
+                       return cancelledByHandler === null ? notCancelled : 
!cancelledByHandler;
+               },
+
                /**
                 * The names of the topics on which Wicket notifies
                 */
diff --git a/wicket-core/src/test/js/event.js b/wicket-core/src/test/js/event.js
index e23d5c043d..9bfa8c0098 100644
--- a/wicket-core/src/test/js/event.js
+++ b/wicket-core/src/test/js/event.js
@@ -252,6 +252,66 @@ Wicket.Event.add(window, 'domready', function() {
        });
 
 
+       module('Wicket.Event.triggerSubmit');
+
+       // a form posting into a hidden frame, so a submission the test fails 
to stop does not leave
+       // the test page
+       var createTestForm = function () {
+               var fixture = document.getElementById('qunit-fixture');
+               var frame = document.createElement('iframe');
+               frame.name = 'triggerSubmitSink';
+               fixture.appendChild(frame);
+               var form = document.createElement('form');
+               form.action = 'about:blank';
+               form.target = frame.name;
+               fixture.appendChild(form);
+               return form;
+       };
+
+       test('runs the submit handlers and keeps the browser from submitting', 
assert => {
+               var form = createTestForm();
+               var events = [];
+               form.addEventListener('submit', function (event) {
+                       events.push(event);
+               });
+               document.addEventListener('submit', function bubbled(event) {
+                       document.removeEventListener('submit', bubbled);
+                       assert.notOk(event.defaultPrevented, 'not cancelled 
while the handlers run');
+               });
+
+               assert.ok(Wicket.Event.triggerSubmit(form), 'the Ajax request 
may go on');
+               assert.equal(events.length, 1, 'the handler ran');
+               assert.ok(events[0].defaultPrevented, 'the browser does not 
submit the form');
+       });
+
+       test('a handler cancelling the event stops the Ajax request', assert => 
{
+               var form = createTestForm();
+               form.onsubmit = function () {
+                       return false;
+               };
+
+               assert.notOk(Wicket.Event.triggerSubmit(form));
+       });
+
+       test('a listener cancelling the event stops the Ajax request', assert 
=> {
+               var form = createTestForm();
+               document.addEventListener('submit', function cancel(event) {
+                       document.removeEventListener('submit', cancel);
+                       event.preventDefault();
+               });
+
+               assert.notOk(Wicket.Event.triggerSubmit(form));
+       });
+
+       test('a handler stopping the propagation without cancelling lets the 
Ajax request go on', assert => {
+               var form = createTestForm();
+               form.addEventListener('submit', function (event) {
+                       event.stopPropagation();
+               });
+
+               assert.ok(Wicket.Event.triggerSubmit(form));
+       });
+
        module('Wicket.Event.pubsub');
 
        test('specified topic', assert => {

Reply via email to