Skip to content

Commit

Permalink
Merge pull request #1190 from Patternslib/fix-autosubmit
Browse files Browse the repository at this point in the history
Fix auto submit on non-form elements
  • Loading branch information
thet authored Nov 9, 2023
2 parents b0b57b1 + a2530f3 commit a51baeb
Show file tree
Hide file tree
Showing 6 changed files with 165 additions and 21 deletions.
20 changes: 20 additions & 0 deletions src/core/dom.js
Original file line number Diff line number Diff line change
Expand Up @@ -557,6 +557,25 @@ const element_uuid = (el) => {
return get_data(el, "uuid");
};

/**
* Find a related form element.
*
* @param {Node} el - The DOM node to start the search from.
* @returns {Node} - The closest form element.
*
* @example
* find_form(document.querySelector("input"));
*/
const find_form = (el) => {
// Prefer input.form which allows for input outside form elements and fall
// back to search for a parent form.
return (
el.form ||
el.querySelector("input, select, textarea, button")?.form ||
el.closest("form")
);
};

const dom = {
toNodeArray: toNodeArray,
querySelectorAllAndMe: querySelectorAllAndMe,
Expand Down Expand Up @@ -585,6 +604,7 @@ const dom = {
get_visible_ratio: get_visible_ratio,
escape_css_id: escape_css_id,
element_uuid: element_uuid,
find_form: find_form,
add_event_listener: events.add_event_listener, // BBB export. TODO: Remove in an upcoming version.
remove_event_listener: events.remove_event_listener, // BBB export. TODO: Remove in an upcoming version.
};
Expand Down
100 changes: 100 additions & 0 deletions src/core/dom.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -903,3 +903,103 @@ describe("element_uuid", function () {
window.crypto.randomUUID = orig_randomUUID;
});
});

describe("find_form", function () {
it("example 1", function () {
document.body.innerHTML = `
<form>
<div id="start"></div>
</form>
`;
const el = document.querySelector("#start");
const form = document.querySelector("form");
expect(dom.find_form(el)).toBe(form);
});

it("example 2", function () {
document.body.innerHTML = `
<form>
<input>
</form>
`;
const el = document.querySelector("input");
const form = document.querySelector("form");
expect(dom.find_form(el)).toBe(form);
});

it("example 3", function () {
document.body.innerHTML = `
<form id="the-form">
</form>
<input form="the-form">
`;
const el = document.querySelector("input");
const form = document.querySelector("#the-form");
expect(dom.find_form(el)).toBe(form);
});

it("example 4", function () {
document.body.innerHTML = `
<form id="the-form">
</form>
<form id="other-form">
<input form="the-form">
</form>
`;
const el = document.querySelector("input");
const form = document.querySelector("#the-form");
expect(dom.find_form(el)).toBe(form);
});

it("example 5", function () {
document.body.innerHTML = `
<form id="the-form">
</form>
<form id="other-form">
<input form="the-form">
</form>
`;
const el = document.querySelector("#other-form");
const form = document.querySelector("#the-form");
expect(dom.find_form(el)).toBe(form);
});

it("example 6", function () {
document.body.innerHTML = `
<form id="the-form">
</form>
<form id="other-form">
<select form="the-form"></select>
</form>
`;
const el = document.querySelector("#other-form");
const form = document.querySelector("#the-form");
expect(dom.find_form(el)).toBe(form);
});

it("example 7", function () {
document.body.innerHTML = `
<form id="the-form">
</form>
<form id="other-form">
<textarea form="the-form"></textarea>
</form>
`;
const el = document.querySelector("#other-form");
const form = document.querySelector("#the-form");
expect(dom.find_form(el)).toBe(form);
});

it("example 8", function () {
document.body.innerHTML = `
<form id="the-form">
</form>
<form id="other-form">
<button form="the-form"></button>
</form>
`;
const el = document.querySelector("#other-form");
const form = document.querySelector("#the-form");
expect(dom.find_form(el)).toBe(form);
});
});
13 changes: 10 additions & 3 deletions src/pat/auto-submit/auto-submit.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import "../../core/jquery-ext";
import $ from "jquery";
import Base from "../../core/base";
import dom from "../../core/dom";
import events from "../../core/events";
import input_change_events from "../../lib/input-change-events";
import logging from "../../core/logging";
Expand Down Expand Up @@ -46,7 +47,7 @@ export default Base.extend({
data?.pattern === "sortable"
) {
// Directly submit when removing a clone or changing the sorting.
this.el.dispatchEvent(events.submit_event());
dom.find_form(this.el).dispatchEvent(events.submit_event());
log.debug(
`triggered by pat-update, pattern: ${data.pattern}, action: ${data.action}`
);
Expand Down Expand Up @@ -128,7 +129,13 @@ export default Base.extend({

onInputChange(e) {
e.stopPropagation();
this.el.dispatchEvent(events.submit_event({ submitter: e.target }));
log.debug("triggered by " + e.type);
dom.find_form(this.el).dispatchEvent(
events.submit_event({ submitter: e.target })
);
log.debug(
`submit event triggered by event ${e.type} by submitter (1) on (2)`,
e.target,
this.el
);
},
});
37 changes: 25 additions & 12 deletions src/pat/auto-submit/auto-submit.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,17 +82,12 @@ describe("pat-autosubmit", function () {
`;
const input = document.querySelector(".pat-autosubmit");
new Pattern(input);
let submit_input_dispatched = false;
let submit_form_dispatched = false;
input.addEventListener("submit", () => {
submit_input_dispatched = true;
});
document.querySelector("form").addEventListener("submit", () => {
submit_form_dispatched = true;
});
input.dispatchEvent(events.input_event());
await utils.timeout(1);
expect(submit_input_dispatched).toBe(true);
expect(submit_form_dispatched).toBe(true);
});

Expand Down Expand Up @@ -179,23 +174,41 @@ describe("pat-autosubmit", function () {
`;
const input = document.querySelector(".pat-autosubmit");
new Pattern(input);
let submit_input_dispatched = false;
let submit_form_dispatched = false;
input.addEventListener("submit", () => {
submit_input_dispatched = true;
});
document.querySelector("form").addEventListener("submit", () => {
submit_form_dispatched = true;
});
input.dispatchEvent(events.input_event());
await utils.timeout(1);
expect(submit_input_dispatched).toBe(false);
expect(submit_form_dispatched).toBe(false);
await utils.timeout(9);
expect(submit_input_dispatched).toBe(false);
expect(submit_form_dispatched).toBe(false);
await utils.timeout(10);
expect(submit_input_dispatched).toBe(true);
expect(submit_form_dispatched).toBe(true);
});

it("2.6 - when pat-autosubmit is defined not on aform element", async function () {
document.body.innerHTML = `
<form>
<div
class="pat-autosubmit"
data-pat-autosubmit="delay: 0"
>
<input name="q">
</div>
</form>
`;
const input = document.querySelector("input");
const autosubmit = document.querySelector(".pat-autosubmit");
new Pattern(autosubmit);

let submit_form_dispatched = false;
document.querySelector("form").addEventListener("submit", () => {
submit_form_dispatched = true;
});

input.dispatchEvent(events.input_event());
await utils.timeout(1);
expect(submit_form_dispatched).toBe(true);
});
});
Expand Down
15 changes: 9 additions & 6 deletions src/pat/auto-suggest/auto-suggest.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -428,17 +428,20 @@ describe("pat-autosuggest", function () {
describe("4 - Integration...", function () {
it("4.1 - Works with pat-auto-submit", async function () {
document.body.innerHTML = `
<input
type="text"
class="pat-autosuggest pat-autosubmit"
data-pat-autosuggest="words: apple, orange, pear"
data-pat-autosubmit="delay:0" />
<form>
<input
type="text"
class="pat-autosuggest pat-autosubmit"
data-pat-autosuggest="words: apple, orange, pear"
data-pat-autosubmit="delay:0" />
</form>
`;

const pattern_autosubmit = (await import("../auto-submit/auto-submit")).default; // prettier-ignore
const input = document.querySelector("input");

let submit_dispatched = false;
input.addEventListener("submit", () => {
document.querySelector("form").addEventListener("submit", () => {
submit_dispatched = true;
});

Expand Down
1 change: 1 addition & 0 deletions src/pat/inject/inject.js
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ const inject = {
});
// setup event handlers
if ($el[0]?.tagName === "FORM") {
log.debug("Initializing form with injection on", $el[0]);
events.add_event_listener(
$el[0],
"submit",
Expand Down

0 comments on commit a51baeb

Please sign in to comment.