| <!DOCTYPE HTML> |
| <meta charset="UTF-8"> |
| <title>CSS Toggles: activation of toggles</title> |
| <link rel="author" title="L. David Baron" href="https://dbaron.org/"> |
| <link rel="author" title="Google" href="http://www.google.com/"> |
| <link rel="help" href="https://tabatkins.github.io/css-toggle/#toggle-trigger-property"> |
| <link rel="help" href="https://tabatkins.github.io/css-toggle/#fire-a-toggle-activation"> |
| <script src="/resources/testharness.js"></script> |
| <script src="/resources/testharnessreport.js"></script> |
| <script src="support/toggle-helpers.js"></script> |
| <style> |
| :toggle(finding-test 0) { --finding-test:0; } |
| :toggle(finding-test 1) { --finding-test:1; } |
| :toggle(test-states 0) { --test-states:0; } |
| :toggle(test-states 1) { --test-states:1; } |
| :toggle(test-states 2) { --test-states:2; } |
| :toggle(test-group 0) { --test-group:0; } |
| :toggle(test-group 1) { --test-group:1; } |
| :toggle(test-overflow 0) { --test-overflow:0; } |
| :toggle(test-overflow 1) { --test-overflow:1; } |
| :toggle(set-num 0) { --set-num:0; } |
| :toggle(set-num 1) { --set-num:1; } |
| :toggle(set-num 2) { --set-num:2; } |
| :toggle(set-names zero) { --set-names:0; } |
| :toggle(set-names one) { --set-names:1; } |
| :toggle(set-names two) { --set-names:2; } |
| :toggle(set-names three) { --set-names:3; } |
| </style> |
| |
| <body> |
| |
| <div id="container"></div> |
| <script> |
| |
| let container = document.getElementById("container"); |
| |
| let toggle_finding_tests = [ |
| { |
| description: "wide toggle on previous sibling", |
| markup: `<div> |
| <div id="toggle"></div> |
| <div id="target"></div> |
| </div>`, |
| found: true |
| }, |
| { |
| description: "narrow toggle on previous sibling", |
| markup: `<div> |
| <div id="toggle"></div> |
| <div id="target"></div> |
| </div>`, |
| found: false, |
| self: true |
| }, |
| { |
| description: "wide toggle on previous sibling with intervening narrow toggle", |
| markup: `<div> |
| <div id="toggle"></div> |
| <div style="toggle: finding-test self"></div> |
| <div id="target"></div> |
| </div>`, |
| found: true |
| }, |
| { |
| description: "wide toggle on parent with intervening narrow toggle", |
| markup: `<div id="toggle"> |
| <div style="toggle: finding-test self"></div> |
| <div id="target"></div> |
| </div>`, |
| found: true |
| }, |
| { |
| description: "wide toggle on parent's prior sibling with intervening narrow toggle", |
| markup: `<div id="toggle"></div> |
| <div> |
| <div style="toggle: finding-test self"></div> |
| <div id="target"></div> |
| </div>`, |
| found: true |
| }, |
| { |
| description: "wide toggle on later sibling", |
| markup: `<div id="target"></div> |
| <div id="toggle"></div>`, |
| found: false |
| }, |
| { |
| description: "wide toggle on child", |
| markup: `<div id="target"> |
| <div id="toggle"></div> |
| </div>`, |
| found: false |
| } |
| ]; |
| |
| for (let toggle_finding_test of toggle_finding_tests) { |
| promise_test(async function() { |
| container.innerHTML = toggle_finding_test.markup; |
| let toggle = document.getElementById("toggle"); |
| let toggle_cs = getComputedStyle(toggle); |
| let target = document.getElementById("target"); |
| let toggle_root_style = "finding-test"; |
| if (toggle_finding_test.self) { |
| toggle_root_style += " self"; |
| } |
| toggle.style.toggleRoot = toggle_root_style; |
| target.style.toggleTrigger = "finding-test"; |
| await wait_for_toggle_creation(toggle); |
| assert_true(toggle.matches(':toggle(finding-test 0)'), |
| "matches before click"); |
| assert_equals(toggle_cs.getPropertyValue("--finding-test"), "0", |
| "computed style before click"); |
| target.click(); |
| if (toggle_finding_test.found) { |
| assert_true(toggle.matches(':toggle(finding-test 1)'), |
| "matches after click"); |
| assert_equals(toggle_cs.getPropertyValue("--finding-test"), "1", |
| "computed style after click"); |
| } else { |
| assert_true(toggle.matches(':toggle(finding-test 0)'), |
| "matches after click"); |
| assert_equals(toggle_cs.getPropertyValue("--finding-test"), "0", |
| "computed style after click"); |
| } |
| }, `finding toggle: ${toggle_finding_test.description}`); |
| } |
| |
| promise_test(async function() { |
| let e = await set_up_single_toggle_in(container, "test-states 1 at 0"); |
| let cs = getComputedStyle(e); |
| assert_true(e.matches(":toggle(test-states 0)")); |
| assert_equals(cs.getPropertyValue("--test-states"), "0"); |
| e.click(); |
| assert_true(e.matches(":toggle(test-states 1)")); |
| assert_equals(cs.getPropertyValue("--test-states"), "1"); |
| e.click(); |
| assert_true(e.matches(":toggle(test-states 0)")); |
| assert_equals(cs.getPropertyValue("--test-states"), "0"); |
| e.style.toggleRoot = "test-states 2 at 2"; |
| await wait_for_toggle_creation(e); |
| assert_true(e.matches(":toggle(test-states 0)")); |
| assert_equals(cs.getPropertyValue("--test-states"), "0"); |
| e.click(); |
| e.click(); |
| assert_true(e.matches(":toggle(test-states 2)")); |
| assert_equals(cs.getPropertyValue("--test-states"), "2"); |
| e.style.toggleRoot = ""; |
| await wait_for_toggle_creation(e); |
| assert_true(e.matches(":toggle(test-states 2)")); |
| assert_equals(cs.getPropertyValue("--test-states"), "2"); |
| e.click(); |
| assert_true(e.matches(":toggle(test-states 0)")); |
| assert_equals(cs.getPropertyValue("--test-states"), "0"); |
| e.click(); |
| assert_true(e.matches(":toggle(test-states 1)")); |
| assert_equals(cs.getPropertyValue("--test-states"), "1"); |
| e.click(); |
| assert_true(e.matches(":toggle(test-states 0)")); |
| assert_equals(cs.getPropertyValue("--test-states"), "0"); |
| }, "states used from toggle or toggle specifier as appropriate (integer)"); |
| |
| promise_test(async function() { |
| let e = await set_up_single_toggle_in(container, "test-states [one two] at 0"); |
| let cs = getComputedStyle(e); |
| let t = e.toggles.get("test-states"); |
| assert_equals(t.value, 0); |
| assert_true(e.matches(":toggle(test-states 0)")); |
| assert_true(e.matches(":toggle(test-states one)")); |
| assert_equals(cs.getPropertyValue("--test-states"), "0"); |
| e.click(); |
| assert_equals(t.value, "two"); |
| assert_true(e.matches(":toggle(test-states 1)")); |
| assert_true(e.matches(":toggle(test-states two)")); |
| assert_equals(cs.getPropertyValue("--test-states"), "1"); |
| e.click(); |
| assert_equals(t.value, "one"); |
| assert_true(e.matches(":toggle(test-states 0)")); |
| assert_true(e.matches(":toggle(test-states one)")); |
| assert_equals(cs.getPropertyValue("--test-states"), "0"); |
| e.style.toggleRoot = "test-states [zero one two] at 2"; |
| await wait_for_toggle_creation(e); |
| assert_equals(t.value, "one"); |
| assert_true(e.matches(":toggle(test-states 0)")); |
| assert_true(e.matches(":toggle(test-states one)")); |
| assert_equals(cs.getPropertyValue("--test-states"), "0"); |
| e.click(); |
| assert_equals(t.value, "two"); |
| assert_true(e.matches(":toggle(test-states 1)")); |
| assert_true(e.matches(":toggle(test-states two)")); |
| assert_equals(cs.getPropertyValue("--test-states"), "1"); |
| e.click(); |
| assert_equals(t.value, "zero"); |
| assert_true(e.matches(":toggle(test-states zero)")); |
| assert_equals(cs.getPropertyValue("--test-states"), ""); |
| e.style.toggleRoot = ""; |
| await wait_for_toggle_creation(e); |
| assert_equals(t.value, "zero"); |
| assert_true(e.matches(":toggle(test-states zero)")); |
| assert_equals(cs.getPropertyValue("--test-states"), ""); |
| e.click(); |
| assert_equals(t.value, "one"); |
| assert_true(e.matches(":toggle(test-states 0)")); |
| assert_true(e.matches(":toggle(test-states one)")); |
| assert_equals(cs.getPropertyValue("--test-states"), "0"); |
| e.click(); |
| assert_equals(t.value, "two"); |
| assert_true(e.matches(":toggle(test-states 1)")); |
| assert_true(e.matches(":toggle(test-states two)")); |
| assert_equals(cs.getPropertyValue("--test-states"), "1"); |
| e.click(); |
| assert_equals(t.value, "one"); |
| assert_true(e.matches(":toggle(test-states 0)")); |
| assert_true(e.matches(":toggle(test-states one)")); |
| assert_equals(cs.getPropertyValue("--test-states"), "0"); |
| }, "states used from toggle or toggle specifier as appropriate (names)"); |
| |
| promise_test(async function() { |
| container.innerHTML = ` |
| <div style="toggle-group: test-group"> |
| <div id="t" style="toggle: test-group 1 at 0 group"></div> |
| <div id="other" style="toggle: test-group 1 at 0 group"></div> |
| </div> |
| `; |
| let t = document.getElementById("t"); |
| let other = document.getElementById("other"); |
| let t_cs = getComputedStyle(t); |
| let other_cs = getComputedStyle(other); |
| await wait_for_toggle_creation(t); |
| await wait_for_toggle_creation(other); |
| other.click(); |
| assert_true(t.matches(":toggle(test-group 0)")); |
| assert_equals(t_cs.getPropertyValue("--test-group"), "0"); |
| assert_true(other.matches(":toggle(test-group 1)")); |
| assert_equals(other_cs.getPropertyValue("--test-group"), "1"); |
| t.click(); |
| assert_true(t.matches(":toggle(test-group 1)")); |
| assert_equals(t_cs.getPropertyValue("--test-group"), "1"); |
| assert_true(other.matches(":toggle(test-group 0)")); |
| assert_equals(other_cs.getPropertyValue("--test-group"), "0"); |
| other.click(); |
| assert_true(t.matches(":toggle(test-group 0)")); |
| assert_equals(t_cs.getPropertyValue("--test-group"), "0"); |
| assert_true(other.matches(":toggle(test-group 1)")); |
| assert_equals(other_cs.getPropertyValue("--test-group"), "1"); |
| |
| // Test that we use the group value from the toggle specifier when it's |
| // different from the toggle, but only when that's the toggle we're |
| // changing. |
| t.style.toggleRoot = "test-group 1 at 0"; |
| t.click(); |
| assert_true(t.matches(":toggle(test-group 1)")); |
| assert_equals(t_cs.getPropertyValue("--test-group"), "1"); |
| assert_true(other.matches(":toggle(test-group 1)")); |
| assert_equals(other_cs.getPropertyValue("--test-group"), "1"); |
| other.click(); |
| assert_true(t.matches(":toggle(test-group 1)")); |
| assert_equals(t_cs.getPropertyValue("--test-group"), "1"); |
| assert_true(other.matches(":toggle(test-group 0)")); |
| assert_equals(other_cs.getPropertyValue("--test-group"), "0"); |
| other.click(); |
| assert_true(t.matches(":toggle(test-group 0)")); |
| assert_equals(t_cs.getPropertyValue("--test-group"), "0"); |
| assert_true(other.matches(":toggle(test-group 1)")); |
| assert_equals(other_cs.getPropertyValue("--test-group"), "1"); |
| |
| // Test that we use the group value from the toggle when there is no toggle |
| // specifier. |
| t.style.toggleRoot = ""; |
| t.click(); |
| assert_true(t.matches(":toggle(test-group 1)")); |
| assert_equals(t_cs.getPropertyValue("--test-group"), "1"); |
| assert_true(other.matches(":toggle(test-group 0)")); |
| assert_equals(other_cs.getPropertyValue("--test-group"), "0"); |
| other.click(); |
| assert_true(t.matches(":toggle(test-group 0)")); |
| assert_equals(t_cs.getPropertyValue("--test-group"), "0"); |
| assert_true(other.matches(":toggle(test-group 1)")); |
| assert_equals(other_cs.getPropertyValue("--test-group"), "1"); |
| other.click(); |
| assert_true(t.matches(":toggle(test-group 0)")); |
| assert_equals(t_cs.getPropertyValue("--test-group"), "0"); |
| assert_true(other.matches(":toggle(test-group 0)")); |
| assert_equals(other_cs.getPropertyValue("--test-group"), "0"); |
| }, "group used from toggle or toggle specifier as appropriate"); |
| |
| promise_test(async function() { |
| let e = await set_up_single_toggle_in(container, "test-overflow sticky"); |
| let cs = getComputedStyle(e); |
| assert_true(e.matches(":toggle(test-overflow 0)")); |
| assert_equals(cs.getPropertyValue("--test-overflow"), "0"); |
| e.click(); |
| assert_true(e.matches(":toggle(test-overflow 1)")); |
| assert_equals(cs.getPropertyValue("--test-overflow"), "1"); |
| e.click(); |
| assert_true(e.matches(":toggle(test-overflow 1)")); |
| assert_equals(cs.getPropertyValue("--test-overflow"), "1"); |
| e.style.toggleRoot = "test-overflow"; |
| await wait_for_toggle_creation(e); |
| assert_true(e.matches(":toggle(test-overflow 1)")); |
| assert_equals(cs.getPropertyValue("--test-overflow"), "1"); |
| e.click(); |
| assert_true(e.matches(":toggle(test-overflow 0)")); |
| assert_equals(cs.getPropertyValue("--test-overflow"), "0"); |
| e.style.toggleRoot = ""; |
| await wait_for_toggle_creation(e); |
| assert_true(e.matches(":toggle(test-overflow 0)")); |
| assert_equals(cs.getPropertyValue("--test-overflow"), "0"); |
| e.click(); |
| assert_true(e.matches(":toggle(test-overflow 1)")); |
| assert_equals(cs.getPropertyValue("--test-overflow"), "1"); |
| e.click(); |
| assert_true(e.matches(":toggle(test-overflow 1)")); |
| assert_equals(cs.getPropertyValue("--test-overflow"), "1"); |
| }, "overflow used from toggle or toggle specifier as appropriate"); |
| |
| promise_test(async function() { |
| container.innerHTML = `<div id="t" style="toggle-root: set-num 5 at 1"></div> |
| <div id="a" style="toggle-trigger: set-num set 2"></div> |
| <div id="b" style="toggle-trigger: set-num set 0"></div> |
| <div id="c" style="toggle-trigger: set-num set named-state"></div> |
| <div id="m"></div> |
| `; |
| let t = document.getElementById("t"); |
| let a = document.getElementById("a"); |
| let b = document.getElementById("b"); |
| let c = document.getElementById("c"); |
| let m = document.getElementById("m"); |
| let cs = getComputedStyle(m); |
| await wait_for_toggle_creation(t); |
| assert_true(m.matches(':toggle(set-num 1)'), "initial state"); |
| assert_equals(cs.getPropertyValue("--set-num"), "1"); |
| a.click(); |
| assert_true(m.matches(':toggle(set-num 2)'), "state after clicking a"); |
| assert_equals(cs.getPropertyValue("--set-num"), "2"); |
| b.click(); |
| assert_true(m.matches(':toggle(set-num 0)'), "state after clicking b"); |
| assert_equals(cs.getPropertyValue("--set-num"), "0"); |
| c.click(); |
| assert_true(m.matches(':toggle(set-num named-state)'), "state after clicking c"); |
| assert_equals(cs.getPropertyValue("--set-num"), ""); |
| }, "changing with toggle-trigger: set (numbers)"); |
| |
| promise_test(async function() { |
| container.innerHTML = `<div id="t" style="toggle-root: set-names [zero one two three four five] at two"></div> |
| <div id="a" style="toggle-trigger: set-names set one"></div> |
| <div id="b" style="toggle-trigger: set-names set 3"></div> |
| <div id="c" style="toggle-trigger: set-names set zero"></div> |
| <div id="d" style="toggle-trigger: set-names set named-state"></div> |
| <div id="m"></div> |
| `; |
| let t = document.getElementById("t"); |
| let a = document.getElementById("a"); |
| let b = document.getElementById("b"); |
| let c = document.getElementById("c"); |
| let d = document.getElementById("d"); |
| let m = document.getElementById("m"); |
| let cs = getComputedStyle(m); |
| await wait_for_toggle_creation(t); |
| assert_true(m.matches(':toggle(set-names two)')); |
| assert_true(m.matches(':toggle(set-names 2)')); |
| assert_equals(cs.getPropertyValue("--set-names"), "2"); |
| a.click(); |
| assert_true(m.matches(':toggle(set-names one)')); |
| assert_true(m.matches(':toggle(set-names 1)')); |
| assert_equals(cs.getPropertyValue("--set-names"), "1"); |
| b.click(); |
| assert_true(m.matches(':toggle(set-names three)')); |
| assert_true(m.matches(':toggle(set-names 3)')); |
| assert_equals(cs.getPropertyValue("--set-names"), "3"); |
| c.click(); |
| assert_true(m.matches(':toggle(set-names zero)')); |
| assert_true(m.matches(':toggle(set-names 0)')); |
| assert_equals(cs.getPropertyValue("--set-names"), "0"); |
| d.click(); |
| assert_true(m.matches(':toggle(set-names named-state)')); |
| assert_false(m.matches(':toggle(set-names 0)')); |
| assert_equals(cs.getPropertyValue("--set-names"), ""); |
| b.click(); |
| assert_true(m.matches(':toggle(set-names 3)')); |
| assert_equals(cs.getPropertyValue("--set-names"), "3"); |
| d.click(); |
| assert_false(m.matches(':toggle(set-names 3)')); |
| assert_equals(cs.getPropertyValue("--set-names"), ""); |
| }, "changing with toggle-trigger: set (named states)"); |
| |
| function test_action_and_cycle(states_and_cycle, start, action, result) { |
| promise_test(async function() { |
| container.innerHTML = ` |
| <div id="toggle" style="toggle-root: test ${states_and_cycle}"></div> |
| <div id="start" style="toggle-trigger: test set ${start}"></div> |
| <div id="action" style="toggle-trigger: test ${action}"></div> |
| `; |
| let toggle = document.getElementById("toggle"); |
| await wait_for_toggle_creation(toggle); |
| document.getElementById("start").click(); |
| assert_true(toggle.matches(`:toggle(test ${start})`), "value after set"); |
| document.getElementById("action").click(); |
| assert_true(toggle.matches(`:toggle(test ${result})`), "value after action"); |
| }, `toggle with "${states_and_cycle}" changing from "${start}" with action "${action}"`); |
| } |
| |
| function test_action_and_all_cycles(states, start, action, result_cycle, result_cycle_on, result_sticky) { |
| test_action_and_cycle(states, start, action, result_cycle); |
| test_action_and_cycle(`${states} cycle`, start, action, result_cycle); |
| test_action_and_cycle(`${states} cycle-on`, start, action, result_cycle_on); |
| test_action_and_cycle(`${states} sticky`, start, action, result_sticky); |
| } |
| |
| test_action_and_all_cycles("2", "0", "next", "1", "1", "1"); |
| test_action_and_all_cycles("2", "1", "next", "2", "2", "2"); |
| test_action_and_all_cycles("2", "2", "next", "0", "1", "2"); |
| test_action_and_all_cycles("3", "5", "next", "0", "1", "3"); |
| test_action_and_all_cycles("4", "3", "next", "4", "4", "4"); |
| test_action_and_all_cycles("4", "3", "next 3", "0", "1", "4"); |
| test_action_and_all_cycles("3", "named-value", "next", "0", "1", "3"); |
| test_action_and_all_cycles("[a b c d]", "a", "next", "b", "b", "b"); |
| test_action_and_all_cycles("[a b c d]", "a", "next 5", "a", "b", "d"); |
| test_action_and_all_cycles("[a b c d]", "c", "next", "d", "d", "d"); |
| test_action_and_all_cycles("[a b c d]", "d", "next", "a", "b", "d"); |
| test_action_and_all_cycles("[a b c d]", "extra-state", "next", "a", "b", "d"); |
| |
| test_action_and_all_cycles("2", "0", "prev", "2", "2", "0"); |
| test_action_and_all_cycles("2", "1", "prev", "0", "2", "0"); |
| test_action_and_all_cycles("2", "2", "prev", "1", "1", "1"); |
| test_action_and_all_cycles("2", "5", "prev", "2", "2", "2"); |
| test_action_and_all_cycles("3", "5", "prev 3", "2", "2", "2"); |
| test_action_and_all_cycles("3", "2", "prev 3", "3", "3", "0"); |
| test_action_and_all_cycles("3", "named-value", "prev", "3", "3", "3"); |
| test_action_and_all_cycles("[a b c d]", "a", "prev", "d", "d", "a"); |
| test_action_and_all_cycles("[a b c d]", "b", "prev", "a", "d", "a"); |
| test_action_and_all_cycles("[a b c d]", "d", "prev", "c", "c", "c"); |
| test_action_and_all_cycles("[a b c d]", "c", "prev 5", "d", "d", "a"); |
| test_action_and_all_cycles("[a b c d]", "extra-state", "prev", "d", "d", "d"); |
| |
| // TODO(https://github.com/tabatkins/css-toggle/issues/39): This set of |
| // tests is testing proposed behavior; the spec currently says something |
| // that we agree is wrong. |
| promise_test(async function() { |
| container.innerHTML = ` |
| <button id="toggle" style="toggle: test"></button> |
| `; |
| let toggle = document.getElementById("toggle"); |
| await wait_for_toggle_creation(toggle); |
| assert_true(!toggle.matches(`:toggle(test)`), "value before click"); |
| toggle.click(); |
| assert_true(toggle.matches(`:toggle(test)`), "value after click"); |
| }, "toggle activation on button with toggle-trigger (1)"); |
| promise_test(async function() { |
| container.innerHTML = ` |
| <div id="toggle" style="toggle-root: test"> |
| <button id="trigger" style="toggle-trigger: test"></button> |
| </div> |
| `; |
| let toggle = document.getElementById("toggle"); |
| await wait_for_toggle_creation(toggle); |
| assert_true(!toggle.matches(`:toggle(test)`), "value before click"); |
| document.getElementById("trigger").click(); |
| assert_true(toggle.matches(`:toggle(test)`), "value after click"); |
| }, "toggle activation on button with toggle-trigger (2)"); |
| promise_test(async function() { |
| container.innerHTML = ` |
| <div id="toggle" style="toggle: test"> |
| <button id="button"></button> |
| </div> |
| `; |
| let toggle = document.getElementById("toggle"); |
| await wait_for_toggle_creation(toggle); |
| assert_true(!toggle.matches(`:toggle(test)`), "value before click"); |
| document.getElementById("button").click(); |
| assert_true(!toggle.matches(`:toggle(test)`), "value after button click"); |
| toggle.click(); |
| assert_true(toggle.matches(`:toggle(test)`), "value after div click"); |
| }, "toggle activation on button inside element with toggle-trigger"); |
| promise_test(async function() { |
| container.innerHTML = ` |
| <div id="toggle" style="toggle: test"> |
| <div id="div"></div> |
| </div> |
| `; |
| let toggle = document.getElementById("toggle"); |
| await wait_for_toggle_creation(toggle); |
| assert_true(!toggle.matches(`:toggle(test)`), "value before click"); |
| document.getElementById("div").click(); |
| assert_true(toggle.matches(`:toggle(test)`), "value after inner div click"); |
| toggle.click(); |
| assert_true(!toggle.matches(`:toggle(test)`), "value after outer div click"); |
| }, "toggle activation on div inside element with toggle-trigger"); |
| |
| </script> |