diff --git a/testing/web-platform/tests/html/dom/elements/global-attributes/dir-assorted.window.js b/testing/web-platform/tests/html/dom/elements/global-attributes/dir-assorted.window.js index 64f99724a95ca..a4b30f0e4ac72 100644 --- a/testing/web-platform/tests/html/dom/elements/global-attributes/dir-assorted.window.js +++ b/testing/web-platform/tests/html/dom/elements/global-attributes/dir-assorted.window.js @@ -27,3 +27,21 @@ test(() => { ele.append(ele2); assert_true(ele2.matches(":dir(rtl)")); }, "Non-HTML element without direction has parent element direction"); + +test(() => { + let container1 = document.createElement("div"); + document.body.appendChild(container1); + let container2 = document.createElement("div"); + + for (let container of [container1, container2]) { + container.dir = "rtl"; + let e = document.createElement("div"); + assert_true(e.matches(":dir(ltr)")); + container.appendChild(e); + assert_false(e.matches(":dir(ltr)")); + e.remove(); + assert_true(e.matches(":dir(ltr)")); + } + + container1.remove(); +}, "dir inheritance is correct after insertion and removal from document"); diff --git a/testing/web-platform/tests/html/dom/elements/global-attributes/dir-auto-dynamic-changes.window.js b/testing/web-platform/tests/html/dom/elements/global-attributes/dir-auto-dynamic-changes.window.js new file mode 100644 index 0000000000000..5df996d285f46 --- /dev/null +++ b/testing/web-platform/tests/html/dom/elements/global-attributes/dir-auto-dynamic-changes.window.js @@ -0,0 +1,169 @@ +function setup_tree(light_tree, shadow_tree) { + let body = document.body; + let old_length = body.childNodes.length; + body.insertAdjacentHTML("beforeend", light_tree.trim()); + if (body.childNodes.length != old_length + 1) { + throw "unexpected markup"; + } + let result = body.lastChild; + if (shadow_tree) { + let shadow = result.querySelector("#root").attachShadow({mode: "open"}); + shadow.innerHTML = shadow_tree.trim(); + return [result, shadow]; + } + return result; +} + +test(t => { + let a = setup_tree(` +
+
+ hello +
+ `); + + let acs = getComputedStyle(a); + assert_true(a.matches(":dir(ltr)"), ":dir(ltr) matches before insertion"); + assert_false(a.matches(":dir(rtl)"), ":dir(rtl) does not match before insertion"); + assert_equals(acs.direction, "ltr", "CSSdirection before insertion"); + b.innerHTML = "\u05D0"; + assert_false(a.matches(":dir(ltr)"), ":dir(ltr) does not match after insertion"); + assert_true(a.matches(":dir(rtl)"), ":dir(rtl) matches after insertion"); + assert_equals(acs.direction, "rtl", "CSSdirection after insertion"); + + a.remove(); +}, "dynamic insertion of RTL text in a child element"); + +test(() => { + let div_rtlchar = document.createElement("div"); + div_rtlchar.innerHTML = "\u05D0"; + + let container1 = document.createElement("div"); + document.body.appendChild(container1); + let container2 = document.createElement("div"); + + for (let container of [container1, container2]) { + container.dir = "auto"; + assert_true(container.matches(":dir(ltr)")); + container.appendChild(div_rtlchar); + assert_false(container.matches(":dir(ltr)")); + div_rtlchar.remove(); + assert_true(container.matches(":dir(ltr)")); + } + + container1.remove(); +}, "dir=auto changes for content insertion and removal, in and out of document"); + +test(() => { + let tree, shadow; + [tree, shadow] = setup_tree(` +
+
+ A + \u05D0 +
+
+ `, ` + \u05D0 + + `); + + let one = shadow.getElementById("one"); + let two = shadow.getElementById("two"); + let l = tree.querySelector("#l"); + let r = tree.querySelector("#r"); + assert_false(one.matches(":dir(ltr)"), "#one while empty"); + assert_true(two.matches(":dir(ltr)"), "#two with both spans"); + l.slot = "one"; + assert_true(one.matches(":dir(ltr)"), "#one with LTR child span"); + assert_false(two.matches(":dir(ltr)"), "#two with RTL child span"); + r.slot = "one"; + assert_true(one.matches(":dir(ltr)"), "#one with both child spans"); + assert_true(two.matches(":dir(ltr)"), "#two while empty"); + l.slot = ""; + assert_false(one.matches(":dir(ltr)"), "#one with RTL child span"); + assert_true(two.matches(":dir(ltr)"), "#two with LTR child span"); + + tree.remove(); +}, "dir=auto changes for slot reassignment"); + +test(() => { + let tree, shadow; + [tree, shadow] = setup_tree(` +
+
+
A
+
+
+ `, ` +
+ +
+ `); + + let text = tree.querySelector("#text"); + let slot = shadow.querySelector("#slot"); + + assert_true(tree.matches(":dir(ltr)"), "node tree ancestor before first text change"); + assert_true(slot.matches(":dir(ltr)"), "slot before first text change"); + text.innerText = "\u05D0"; + assert_false(tree.matches(":dir(ltr)"), "node tree ancestor after first text change"); + assert_false(slot.matches(":dir(ltr)"), "slot after first text change"); + tree.dir = "rtl"; + assert_false(tree.matches(":dir(ltr)"), "node tree ancestor before second text change"); + assert_false(slot.matches(":dir(ltr)"), "slot before second text change"); + text.innerText = "A"; + assert_false(tree.matches(":dir(ltr)"), "node tree ancestor after second text change"); + assert_true(slot.matches(":dir(ltr)"), "slot after second text change"); + slot.dir = "ltr"; + assert_false(tree.matches(":dir(ltr)"), "node tree ancestor before third text change"); + assert_true(slot.matches(":dir(ltr)"), "slot before third text change"); + text.innerText = "\u05D0"; + assert_false(tree.matches(":dir(ltr)"), "node tree ancestor after third text change"); + assert_true(slot.matches(":dir(ltr)"), "slot after third text change"); + slot.dir = "auto"; + tree.dir = "auto"; + assert_false(tree.matches(":dir(ltr)"), "node tree ancestor after fourth text change"); + assert_false(slot.matches(":dir(ltr)"), "slot after fourth text change"); + text.innerText = "A"; + assert_true(tree.matches(":dir(ltr)"), "node tree ancestor before fourth text change"); + assert_true(slot.matches(":dir(ltr)"), "slot before fourth text change"); + slot.dir = "rtl"; + assert_true(tree.matches(":dir(ltr)"), "node tree ancestor before fifth text change"); + assert_false(slot.matches(":dir(ltr)"), "slot before fifth text change"); + text.innerText = "\u05D0"; + assert_false(tree.matches(":dir(ltr)"), "node tree ancestor before fifth text change"); + assert_false(slot.matches(":dir(ltr)"), "slot before fifth text change"); +}, "text changes affecting both slot and ancestor with dir=auto"); + +test(() => { + let tree = setup_tree(` +
+ A + \u05D0 + A + \u05D0 +
+ `); + + let a1 = tree.querySelector("#a1"); + let aleph1 = tree.querySelector("#aleph1"); + assert_true(tree.matches(":dir(ltr)"), "initial state"); + assert_false(tree.matches(":dir(rtl)"), "initial state"); + a1.dir = "ltr"; + assert_false(tree.matches(":dir(ltr)"), "after change 1"); + a1.dir = "invalid"; + assert_true(tree.matches(":dir(ltr)"), "after change 2"); + a1.dir = "rtl"; + assert_false(tree.matches(":dir(ltr)"), "after change 3"); + a1.removeAttribute("dir"); + assert_true(tree.matches(":dir(ltr)"), "after change 4"); + a1.dir = "invalid"; + assert_true(tree.matches(":dir(ltr)"), "after change 5"); + a1.dir = "rtl"; + assert_false(tree.matches(":dir(ltr)"), "after change 6"); + aleph1.dir = "auto"; + assert_true(tree.matches(":dir(ltr)"), "after change 7"); + aleph1.dir = "invalid"; + assert_false(tree.matches(":dir(ltr)"), "after change 8"); +}, "dynamic changes to subtrees excluded as a result of the dir attribute");