Skip to content

Commit 4dc2963

Browse files
committed
fix(pat-autofocus): Refocus on DOM updates by other Patterns.
Set the focus if appropriate when the DOM has changed and a pat-update event has thrown. Please note, this does not use an IntersectionObserver but relies on other Patterns using the pat-update event. This behavior got lost in Patternslib 6.1 and is now restored. Fixes: #1092
1 parent 926de33 commit 4dc2963

File tree

3 files changed

+113
-0
lines changed

3 files changed

+113
-0
lines changed

src/pat/autofocus/autofocus.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import $ from "jquery";
12
import { BasePattern } from "../../core/basepattern";
23
import dom from "../../core/dom";
34
import registry from "../../core/registry";
@@ -22,6 +23,16 @@ class Pattern extends BasePattern {
2223
// Do not autofocus in iframes.
2324
return;
2425
}
26+
27+
// Re-focus after relevant DOM changes.
28+
$(document).on("pat-update", (e, data) => {
29+
const updated = data?.dom;
30+
if (updated?.contains(this.el)) {
31+
// Only focus if the updated element is a parent of this autofocus element.
32+
this.set_focus();
33+
}
34+
});
35+
2536
this.set_focus();
2637
}
2738

src/pat/autofocus/autofocus.test.js

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import $ from "jquery";
12
import "./autofocus";
23
import registry from "../../core/registry";
34
import utils from "../../core/utils";
@@ -44,4 +45,88 @@ describe("pat-autofocus", function () {
4445
const should_be_active = document.querySelector("input[name=i3]");
4546
expect(document.activeElement).toBe(should_be_active);
4647
});
48+
49+
describe("pat-update and pat-inject support", function () {
50+
it("4.1 - Re-focus on pat-update.", async () => {
51+
document.body.innerHTML = `
52+
<div id="c1">
53+
<input name="i1" type="text" class="pat-autofocus"/>
54+
</div>
55+
<div id="c2">
56+
<input name="i2" type="text" class="pat-autofocus" hidden/>
57+
</div>
58+
`;
59+
registry.scan(document.body);
60+
await utils.timeout(1); // Wait for async pattern initialization.
61+
await utils.timeout(100); // Wait for autofocus timeout.
62+
63+
expect(document.activeElement).toBe(
64+
document.querySelector("input[name=i1]")
65+
);
66+
67+
document.querySelector("input[name=i2]").removeAttribute("hidden");
68+
$(document).trigger("pat-update", { dom: document.querySelector("#c2") });
69+
await utils.timeout(100); // Wait for autofocus timeout.
70+
71+
expect(document.activeElement).toBe(
72+
document.querySelector("input[name=i2]")
73+
);
74+
});
75+
76+
it("4.2 - Re-focus on pat-update / collapsible.", async () => {
77+
await import("../collapsible/collapsible");
78+
79+
document.body.innerHTML = `
80+
<input name="i1" type="text" class="pat-autofocus"/>
81+
<div class="pat-collapsible closed"
82+
data-pat-collapsible="transition: none">
83+
<h4>Open collapsible.</h4>
84+
<input name="i2" class="pat-autofocus" />
85+
</div>
86+
`;
87+
registry.scan(document.body);
88+
await utils.timeout(1); // Wait for async pattern initialization.
89+
await utils.timeout(100); // Wait for autofocus timeout.
90+
91+
expect(document.activeElement).toBe(
92+
document.querySelector("input[name=i1]")
93+
);
94+
95+
document.querySelector(".pat-collapsible h4").click();
96+
await utils.timeout(100); // Wait for autofocus timeout.
97+
98+
expect(document.activeElement).toBe(
99+
document.querySelector("input[name=i2]")
100+
);
101+
});
102+
103+
it("4.3 - Re-focus on pat-inject.", async () => {
104+
await import("../inject/inject");
105+
106+
document.body.innerHTML = `
107+
<input name="i1" type="text" class="pat-autofocus"/>
108+
<a href="#autofocus-demo-input"
109+
class="pat-inject"
110+
data-pat-inject="target: self::after">inject</a>
111+
<template id="autofocus-demo-input">
112+
<input name="i2" class="pat-autofocus" />
113+
</template>
114+
`;
115+
registry.scan(document.body);
116+
await utils.timeout(1); // Wait for async pattern initialization.
117+
await utils.timeout(100); // Wait for autofocus timeout.
118+
119+
expect(document.activeElement).toBe(
120+
document.querySelector("input[name=i1]")
121+
);
122+
123+
document.querySelector("a.pat-inject").click();
124+
await utils.timeout(2); // Wait for inject.
125+
await utils.timeout(100); // Wait for autofocus timeout.
126+
127+
expect(document.activeElement).toBe(
128+
document.querySelector("input[name=i2]")
129+
);
130+
});
131+
});
47132
});

src/pat/autofocus/index.html

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,19 @@
2929
type="text"
3030
/>
3131
</label>
32+
33+
<h3>Input 4 - should get focus when collapsible is opened.</h3>
34+
<div class="pat-collapsible closed">
35+
<h4>Open collapsible.</h4>
36+
37+
<input class="pat-autofocus" />
38+
</div>
39+
40+
<h3>Input 5 - inject element with autofocus.</h3>
41+
<a href="#autofocus-demo-input"
42+
class="pat-inject"
43+
data-pat-inject="target: self::after">inject autofocus input here</a>
44+
3245
</fieldset>
3346
</form>
3447

@@ -37,5 +50,9 @@
3750
src="./index-iframed.html"
3851
style="width: 400px; height: 300px; border: 1px solid black"
3952
></iframe>
53+
54+
<template id="autofocus-demo-input">
55+
<input class="pat-autofocus" />
56+
</template>
4057
</body>
4158
</html>

0 commit comments

Comments
 (0)