Skip to content

Commit df74a52

Browse files
committed
Fix perspective_viewer::restore calls blurring
Signed-off-by: Andrew Stein <[email protected]>
1 parent e1ac495 commit df74a52

File tree

3 files changed

+101
-5
lines changed

3 files changed

+101
-5
lines changed

rust/perspective-viewer/src/rust/utils/browser/focus.rs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,11 @@ use web_sys::{Document, HtmlElement};
1919
#[extend::ext]
2020
pub impl Document {
2121
fn blur_active_element(&self) {
22-
self.active_element()
23-
.unwrap()
24-
.unchecked_into::<HtmlElement>()
25-
.blur()
26-
.unwrap();
22+
if let Some(active_element) = self.active_element() {
23+
let active_element = active_element.unchecked_into::<HtmlElement>();
24+
if active_element.tag_name().starts_with("PERSPECTIVE-") {
25+
active_element.blur().unwrap();
26+
}
27+
}
2728
}
2829
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<script type="module" src="/node_modules/@finos/perspective-viewer/dist/cdn/perspective-viewer.js"></script>
5+
<script type="module" src="/node_modules/@finos/perspective-test/load-viewer-csv.js"></script>
6+
<link rel="stylesheet" href="../css/demo.css" />
7+
<link rel="stylesheet" href="/node_modules/@finos/perspective-viewer/dist/css/pro.css" />
8+
<link rel="stylesheet" href="/node_modules/@fontsource/roboto-mono/400.css" />
9+
<style>
10+
perspective-viewer {
11+
top: 50px !important;
12+
}
13+
</style>
14+
</head>
15+
<body>
16+
<input />
17+
<perspective-viewer></perspective-viewer>
18+
</body>
19+
</html>
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
// ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
2+
// ┃ ██████ ██████ ██████ █ █ █ █ █ █▄ ▀███ █ ┃
3+
// ┃ ▄▄▄▄▄█ █▄▄▄▄▄ ▄▄▄▄▄█ ▀▀▀▀▀█▀▀▀▀▀ █ ▀▀▀▀▀█ ████████▌▐███ ███▄ ▀█ █ ▀▀▀▀▀ ┃
4+
// ┃ █▀▀▀▀▀ █▀▀▀▀▀ █▀██▀▀ ▄▄▄▄▄ █ ▄▄▄▄▄█ ▄▄▄▄▄█ ████████▌▐███ █████▄ █ ▄▄▄▄▄ ┃
5+
// ┃ █ ██████ █ ▀█▄ █ ██████ █ ███▌▐███ ███████▄ █ ┃
6+
// ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
7+
// ┃ Copyright (c) 2017, the Perspective Authors. ┃
8+
// ┃ ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ ┃
9+
// ┃ This file is part of the Perspective library, distributed under the terms ┃
10+
// ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
11+
// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
12+
13+
import { test, expect } from "@finos/perspective-test";
14+
15+
test.describe("browser focus", async () => {
16+
test.beforeEach(async function init({ page }) {
17+
await page.goto(
18+
"/node_modules/@finos/perspective-viewer/test/html/superstore_with_input.html"
19+
);
20+
21+
await page.evaluate(async () => {
22+
while (!window["__TEST_PERSPECTIVE_READY__"]) {
23+
await new Promise((x) => setTimeout(x, 10));
24+
}
25+
});
26+
27+
await page.evaluate(async () => {
28+
await document.querySelector("perspective-viewer").restore({
29+
plugin: "Debug",
30+
});
31+
});
32+
});
33+
34+
test("Focus is not lost on external widgets when a restore call takes place", async ({
35+
page,
36+
}) => {
37+
const viewer = page.locator("perspective-viewer");
38+
const tagName = await viewer.evaluate(async (viewer) => {
39+
const input = document.querySelector("input");
40+
input.focus();
41+
await viewer.restore({ group_by: ["State"] });
42+
return document.activeElement.tagName;
43+
});
44+
45+
expect(tagName).toEqual("INPUT");
46+
});
47+
48+
test("Focus is list when a perspective dropdown is active", async ({
49+
page,
50+
}) => {
51+
const viewer = page.locator("perspective-viewer");
52+
const split_by = page.locator("#split_by input");
53+
54+
await viewer.evaluate(async (viewer) => {
55+
await viewer.restore({ settings: true });
56+
});
57+
58+
await split_by.evaluate(async (split_by) => {
59+
split_by.focus();
60+
split_by.value = "V";
61+
const event = new Event("input", {
62+
bubbles: true,
63+
cancelable: true,
64+
});
65+
66+
split_by.dispatchEvent(event);
67+
});
68+
69+
const tagName = await viewer.evaluate(async (viewer) => {
70+
await viewer.restore({ group_by: ["State"] });
71+
return document.activeElement.tagName;
72+
});
73+
74+
expect(tagName).toEqual("BODY");
75+
});
76+
});

0 commit comments

Comments
 (0)