From 66502e79ba6a2ea6a80f88cd55e1ea382c9b4c05 Mon Sep 17 00:00:00 2001 From: "L. David Baron" Date: Tue, 1 Aug 2023 10:08:54 -0700 Subject: [PATCH] Enforce
exclusivity in disconnected subtrees. See discussions in: https://github.com/whatwg/html/pull/9400#discussion_r1231851118 https://github.com/openui/open-ui/issues/778#issuecomment-1634732524 Bug: 1444057 Change-Id: I901e4e3958cdf55a07cb9e5126ed235a07819228 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4734191 Reviewed-by: Mason Freed Commit-Queue: David Baron Cr-Commit-Position: refs/heads/main@{#1177898} --- .../name-attribute.tentative.html | 98 +++++++++++++++++++ .../support/empty-html-document.html | 2 + 2 files changed, 100 insertions(+) create mode 100644 html/semantics/interactive-elements/the-details-element/support/empty-html-document.html diff --git a/html/semantics/interactive-elements/the-details-element/name-attribute.tentative.html b/html/semantics/interactive-elements/the-details-element/name-attribute.tentative.html index 48980d0a5e257f7..271577efe5ec074 100644 --- a/html/semantics/interactive-elements/the-details-element/name-attribute.tentative.html +++ b/html/semantics/interactive-elements/the-details-element/name-attribute.tentative.html @@ -228,4 +228,102 @@ assert_element_states(elements, [1, 1, 1, 1, 1, 1], "after setting all elements open"); }, "empty and missing name attributes do not create groups"); +const connected_scenarios = { + "connected": { + "create": data => container, + "cleanup": data => {}, + }, + "disconnected": { + "create": data => document.createElement("div"), + "cleanup": data => {}, + }, + "shadow": { + "create": data => { + let e = document.createElement("div"); + container.appendChild(e); + data.wrapper = e; + let shadowRoot = e.attachShadow({ mode: "open" }); + let d = document.createElement("div"); + shadowRoot.appendChild(d); + return d; + }, + "cleanup": data => { data.wrapper.remove(); }, + }, + "shadow-in-disconnected": { + "create": data => { + let e = document.createElement("div"); + let shadowRoot = e.attachShadow({ mode: "open" }); + let d = document.createElement("div"); + shadowRoot.appendChild(d); + return d; + }, + "cleanup": data => {}, + }, + "template-in-disconnected": { + "create": data => { + let e = document.createElement("div"); + e.innerHTML = ` + + `; + return e.firstElementChild.content.firstElementChild; + }, + "cleanup": data => {}, + }, + "connected-in-xhr-response": { + "create": data => new Promise((resolve, reject) => { + let xhr = new XMLHttpRequest(); + xhr.open("GET", "support/empty-html-document.html"); + xhr.responseType = "document"; + xhr.send(); + xhr.addEventListener("load", event => { resolve(xhr.response.body); }); + let reject_with_type = + event => { reject(`${event.type} event received`); } + xhr.addEventListener("error", reject_with_type); + xhr.addEventListener("abort", reject_with_type); + }), + "cleanup": data => {}, + }, + "connected-in-implementation-create-document": { + "create": data => { + let doc = document.implementation.createHTMLDocument("impl-created"); + return doc.body; + }, + "cleanup": data => {}, + }, + "connected-in-template": { + "create": data => { + container.innerHTML = ` + + `; + return container.firstElementChild.content.firstElementChild; + }, + "cleanup": data => { container.innerHTML = ""; }, + }, +}; + +for (const [scenario, scenario_callbacks] of Object.entries(connected_scenarios)) { + promise_test(async t => { + let data = {}; + let container = await scenario_callbacks.create(data); + t.add_cleanup(async () => await scenario_callbacks.cleanup(data)); + assert_true(container instanceof HTMLDivElement || + container instanceof HTMLBodyElement, + "error in test setup"); + + container.innerHTML = ` +
+
+ `; + + let elements = Array.from(container.querySelectorAll("details[name='scenariotest']")); + assert_element_states(elements, [1, 0], "state before toggle"); + elements[1].open = true; + assert_element_states(elements, [0, 1], "state after toggle enforces exclusivity"); + }, `exclusivity enforcement with attachment scenario ${scenario}`); +} + diff --git a/html/semantics/interactive-elements/the-details-element/support/empty-html-document.html b/html/semantics/interactive-elements/the-details-element/support/empty-html-document.html new file mode 100644 index 000000000000000..56415b84762b7a3 --- /dev/null +++ b/html/semantics/interactive-elements/the-details-element/support/empty-html-document.html @@ -0,0 +1,2 @@ + +Empty HTML Document