Skip to content

Commit

Permalink
Add showPicker() method to HTMLSelectElement interface
Browse files Browse the repository at this point in the history
This CL adds an experimental method to the HTMLSelectElement interface
to allow web developers to show the browser picker for select elements.
It requires a user gesture and is disallowed for cross-origin iframes.

Intent to prototype:
https://groups.google.com/a/chromium.org/g/blink-dev/c/6MUAqY2r3Hg

Demo: https://select-show-picker.glitch.me/
Spec: whatwg/html#9754
Bug: 1485010
Change-Id: I822bff7b313dfa840b2a72edb66fcb4a2c7cb58d
  • Loading branch information
lukewarlow authored and chromium-wpt-export-bot committed Sep 29, 2023
1 parent 59cd10c commit 5c03eaa
Show file tree
Hide file tree
Showing 6 changed files with 170 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<!DOCTYPE html>
<title>Test showPicker() in an iframe</title>
<script type=module>
const urlParams = new URLSearchParams(location.search);
const documentDomain = urlParams.get('documentDomain');
if (documentDomain) {
document.domain = documentDomain;
}

let securityErrors = [];
const select = document.createElement("select");
try {
select.showPicker();
} catch (error) {
if (error instanceof DOMException && error.name == 'SecurityError') {
securityErrors.push("select");
}
}
parent.postMessage(securityErrors.join(','), "*");
</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
<!DOCTYPE html>
<title>Test showPicker() called from cross-origin iframe</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/common/get-host-info.sub.js"></script>
<body>
<iframe id="iframe1"></iframe>
<iframe id="iframe2"></iframe>
<iframe id="iframe3"></iframe>
<iframe id="iframe4"></iframe>
</body>
<script>
function waitForSecurityErrors() {
return new Promise((resolve) => {
window.addEventListener("message", (event) => resolve(event.data), {
once: true,
});
});
}

promise_test(async (t) => {
iframe1.src =
new URL("resources/", self.location).pathname +
"show-picker-child-iframe.html";

// Wait for the iframe to report security errors when calling showPicker().
const securityErrors = await waitForSecurityErrors();
assert_equals(
securityErrors,
"",
"In same-origin iframes, showPicker() does not throw a SecurityError."
);
});

promise_test(async (t) => {
iframe2.src =
get_host_info().HTTP_NOTSAMESITE_ORIGIN +
new URL("resources/", self.location).pathname +
"show-picker-child-iframe.html";

// Wait for the iframe to report security errors when calling showPicker().
const securityErrors = await waitForSecurityErrors();
assert_equals(
securityErrors,
"select",
"In cross-origin iframes, showPicker() throws a SecurityError."
);
});

promise_test(async (t) => {
iframe3.src =
new URL("resources/", self.location).pathname +
"show-picker-child-iframe.html?documentDomain=" + get_host_info().ORIGINAL_HOST;

// Wait for the iframe to report security errors when calling showPicker().
const securityErrors = await waitForSecurityErrors();
assert_equals(
securityErrors,
"",
"In same-origin but cross-origin-domain iframes, showPicker() does not throw a SecurityError."
);
});

promise_test(async (t) => {
document.domain = get_host_info().ORIGINAL_HOST;
iframe4.src =
get_host_info().HTTP_REMOTE_ORIGIN +
new URL("resources/", self.location).pathname +
"show-picker-child-iframe.html?documentDomain=" + get_host_info().ORIGINAL_HOST;

// Wait for the iframe to report security errors when calling showPicker().
const securityErrors = await waitForSecurityErrors();
assert_equals(
securityErrors,
"select",
"In cross-origin but same-origin-domain iframes, showPicker() throws a SecurityError."
);
});
</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<!DOCTYPE html>
<title>Test showPicker() disabled requirement</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/resources/testdriver.js"></script>
<script src="/resources/testdriver-vendor.js"></script>
<select id="select" disabled>
<option>Item 1</option>
</select>
<script>
test(() => {
assert_throws_dom('InvalidStateError', () => { select.showPicker(); });
}, 'select showPicker() throws when disabled');
</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<!DOCTYPE html>
<title>Test showPicker() on multiple selects</title>
<meta name="timeout" content="long">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/resources/testdriver.js"></script>
<script src="/resources/testdriver-vendor.js"></script>
<select id="select" multiple>
<option>Item 1</option>
</select>
<script>
promise_test(async t => {
await test_driver.bless('show picker');
select.showPicker();
select.blur();
}, `select showPicker() does not throw when called on a <select multiple>`);
</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<!DOCTYPE html>
<title>Test showPicker() on sized selects</title>
<meta name="timeout" content="long">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/resources/testdriver.js"></script>
<script src="/resources/testdriver-vendor.js"></script>
<select id="select" size="4">
<option>Item 1</option>
</select>
<script>
promise_test(async t => {
await test_driver.bless('show picker');
select.showPicker();
select.blur();
}, `select showPicker() does not throw when called on a <select size="4">`);
</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<!DOCTYPE html>
<title>Test showPicker() user gesture requirement</title>
<meta name="timeout" content="long">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/resources/testdriver.js"></script>
<script src="/resources/testdriver-vendor.js"></script>
<body></body>
<script type=module>
test(() => {
const select = document.createElement("select");

assert_throws_dom('NotAllowedError', () => { select.showPicker(); });
}, `select showPicker() requires a user gesture`);

promise_test(async t => {
const select = document.createElement("select");

await test_driver.bless('show picker');
select.showPicker();
select.blur();
}, `select showPicker() does not throw when user activation is active`);
</script>

0 comments on commit 5c03eaa

Please sign in to comment.