|
1 | 1 | import "../../core/jquery-ext"; // for findInclusive |
| 2 | +import "../../core/polyfills"; // SubmitEvent.submitter for Safari < 15.4 and jsDOM |
2 | 3 | import $ from "jquery"; |
3 | 4 | import ajax from "../ajax/ajax"; |
4 | 5 | import dom from "../../core/dom"; |
@@ -47,7 +48,14 @@ const inject = { |
47 | 48 | trigger: "a.pat-inject, form.pat-inject, .pat-subform.pat-inject", |
48 | 49 | parser: parser, |
49 | 50 |
|
50 | | - init($el, opts) { |
| 51 | + async init($el, opts) { |
| 52 | + // We need to wait a tick. Modern BasePattern based patterns like |
| 53 | + // pat-validation do always wait a tick before initializing. The |
| 54 | + // patterns registry always initializes pat-validation first but since |
| 55 | + // it is waiting a tick the event handlers are registerd after the ones |
| 56 | + // from pat-inject. Waiting a tick in pat-inject solves this - |
| 57 | + // pat-validation's event handlers are initialized first. |
| 58 | + await utils.timeout(1); |
51 | 59 | const cfgs = this.extractConfig($el, opts); |
52 | 60 | if (cfgs.some((e) => e.history === "record") && !("pushState" in history)) { |
53 | 61 | // if the injection shall add a history entry and HTML5 pushState |
@@ -95,21 +103,29 @@ const inject = { |
95 | 103 | } |
96 | 104 | }); |
97 | 105 | // setup event handlers |
98 | | - if ($el.is("form")) { |
99 | | - $el.on("submit.pat-inject", this.onTrigger.bind(this)) |
100 | | - .on( |
101 | | - "click.pat-inject", |
102 | | - `[type=submit]:not([formaction]), |
103 | | - button:not([formaction]):not([type=button])`, |
104 | | - ajax.onClickSubmit |
105 | | - ) |
106 | | - .on( |
107 | | - "click.pat-inject", |
108 | | - `[type=submit][formaction], |
109 | | - [type=image][formaction], |
110 | | - button[formaction]:not([type=button])`, |
111 | | - this.onFormActionSubmit.bind(this) |
| 106 | + if ($el[0]?.tagName === "FORM") { |
| 107 | + events.add_event_listener( |
| 108 | + $el[0], |
| 109 | + "submit", |
| 110 | + "pat-inject--form-submit", |
| 111 | + (e) => { |
| 112 | + this.onTrigger(e); |
| 113 | + } |
| 114 | + ); |
| 115 | + for (const button of $el[0].querySelectorAll( |
| 116 | + "[type=submit], button:not([type=button]), [type=image]" |
| 117 | + )) { |
| 118 | + events.add_event_listener( |
| 119 | + button, |
| 120 | + "click", |
| 121 | + "pat-inject--form-submit-click", |
| 122 | + (e) => { |
| 123 | + // make sure the submitting button is sent |
| 124 | + // with the form |
| 125 | + ajax.onClickSubmit(e); |
| 126 | + } |
112 | 127 | ); |
| 128 | + } |
113 | 129 | } else if ($el.is(".pat-subform")) { |
114 | 130 | log.debug("Initializing subform with injection"); |
115 | 131 | } else { |
@@ -165,37 +181,40 @@ const inject = { |
165 | 181 | /* Injection has been triggered, either via form submission or a |
166 | 182 | * link has been clicked. |
167 | 183 | */ |
168 | | - const $el = $(e.currentTarget); |
169 | | - const cfgs = $el.data("pat-inject"); |
170 | | - if ($el.is("form")) { |
171 | | - $(cfgs).each((i, v) => { |
172 | | - v.params = $.param($el.serializeArray()); |
173 | | - }); |
174 | | - } |
| 184 | + |
| 185 | + // Prevent the original event from doing it's work. |
| 186 | + // We want an AJAX request instead. |
175 | 187 | e.preventDefault && e.preventDefault(); |
176 | | - $el.trigger("patterns-inject-triggered"); |
177 | | - this.execute(cfgs, $el); |
178 | | - }, |
179 | 188 |
|
180 | | - onFormActionSubmit(e) { |
181 | | - ajax.onClickSubmit(e); // make sure the submitting button is sent with the form |
| 189 | + const $el = $(e.currentTarget); |
| 190 | + let cfgs = $el.data("pat-inject"); |
| 191 | + if ($el[0].tagName === "FORM" && e.type === "submit") { |
| 192 | + if ($el[0].matches(":invalid")) { |
| 193 | + // Do not submit invalid forms. |
| 194 | + // Works with native form validation and with pat-validation. |
| 195 | + log.debug("Form is invalid, aborting"); |
| 196 | + return; |
| 197 | + } |
182 | 198 |
|
183 | | - const $button = $(e.target); |
184 | | - const formaction = $button.attr("formaction"); |
185 | | - const $form = $button.parents(".pat-inject").first(); |
186 | | - const opts = { |
187 | | - url: formaction, |
188 | | - }; |
189 | | - const $cfg_node = $button.closest("[data-pat-inject]"); |
190 | | - const cfgs = this.extractConfig($cfg_node, opts); |
| 199 | + const submitter = e.submitter; |
| 200 | + const formaction = submitter?.getAttribute("formaction"); |
| 201 | + if (formaction) { |
| 202 | + const opts = { |
| 203 | + url: formaction, |
| 204 | + }; |
191 | 205 |
|
192 | | - $(cfgs).each((i, v) => { |
193 | | - v.params = $.param($form.serializeArray()); |
194 | | - }); |
| 206 | + // Support custom data-pat-inject on formaction buttons. |
| 207 | + const cfg_node = submitter.closest("[data-pat-inject]"); |
| 208 | + cfgs = this.extractConfig($(cfg_node), opts); |
| 209 | + } |
195 | 210 |
|
196 | | - e.preventDefault(); |
197 | | - $form.trigger("patterns-inject-triggered"); |
198 | | - this.execute(cfgs, $form); |
| 211 | + for (const cfg of cfgs) { |
| 212 | + cfg.params = $.param($el.serializeArray()); |
| 213 | + } |
| 214 | + } |
| 215 | + |
| 216 | + $el.trigger("patterns-inject-triggered"); |
| 217 | + this.execute(cfgs, $el); |
199 | 218 | }, |
200 | 219 |
|
201 | 220 | submitSubform($sub) { |
|
0 commit comments