| <!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 id="style"></style> | |
| <body> | |
| <div id="container"></div> | |
| <script> | |
| let container = document.getElementById("container"); | |
| function test_trigger_on_group(toggle_specifier, other_specifier, action, toggle_expected, group_expected) | |
| { | |
| promise_test(async function() { | |
| let group = document.createElement("div"); | |
| group.style.toggleGroup = "test-group"; | |
| let toggle = document.createElement("div"); | |
| toggle.style.toggle = `test-group ${toggle_specifier} group`; | |
| toggle.style.toggleTrigger = `test-group ${action}`; | |
| group.appendChild(toggle); | |
| let other = document.createElement("div"); | |
| other.style.toggle = `test-group ${other_specifier} group`; | |
| group.appendChild(other); | |
| let style = document.getElementById("style"); | |
| style.textContent = ` | |
| :toggle(test-group ${toggle_expected}) { --v:${toggle_expected}; } | |
| :toggle(test-group ${group_expected}) { --v:${group_expected}; } | |
| `; | |
| container.replaceChildren(group); | |
| await wait_for_toggle_creation(toggle); | |
| toggle.click(); | |
| assert_true(toggle.matches(`:toggle(test-group ${toggle_expected}`), "value of triggered toggle"); | |
| assert_equals(getComputedStyle(toggle).getPropertyValue("--v"), toggle_expected, "style on triggered toggle"); | |
| assert_true(other.matches(`:toggle(test-group ${group_expected}`), "value of other toggle in group"); | |
| assert_equals(getComputedStyle(other).getPropertyValue("--v"), group_expected, "style on other toggle in group"); | |
| }, `group behavior for toggle "${toggle_specifier}" and action "${action}" with other element in group "${other_specifier}"`); | |
| } | |
| test_trigger_on_group("", "", "next", "1", "0"); | |
| test_trigger_on_group("1 at 0", "1 at 0", "next", "1", "0"); | |
| test_trigger_on_group("", "1 at 1", "next", "1", "0"); | |
| test_trigger_on_group("1 at 1", "1 at 1", "next", "0", "1"); | |
| test_trigger_on_group("1 at 1 cycle", "1 at 1", "next", "0", "1"); | |
| test_trigger_on_group("1 at 1 cycle-on", "1 at 1", "next", "1", "0"); | |
| test_trigger_on_group("1 at 1 sticky", "1 at 1", "next", "1", "0"); | |
| test_trigger_on_group("1 at 1", "1 at 1", "set 3", "3", "0"); | |
| test_trigger_on_group("1 at 1", "1 at 1", "set 0", "0", "1"); | |
| test_trigger_on_group("1 at 7", "1 at 5", "set 9", "9", "0"); | |
| test_trigger_on_group("1 at 7", "1 at 5", "set 0", "0", "5"); | |
| test_trigger_on_group("", "1 at 1 cycle", "next", "1", "0"); | |
| test_trigger_on_group("", "1 at 1 cycle-on", "next", "1", "0"); | |
| test_trigger_on_group("", "1 at 1 sticky", "next", "1", "0"); | |
| test_trigger_on_group("1 at 0", "1 at 1", "prev", "1", "0"); | |
| test_trigger_on_group("1 at 0", "1 at 0", "prev", "1", "0"); | |
| test_trigger_on_group("1 at 1", "1 at 1", "prev", "0", "1"); | |
| test_trigger_on_group("1 at 1 cycle", "1 at 1", "prev", "0", "1"); | |
| test_trigger_on_group("1 at 1 cycle-on", "1 at 1", "prev", "1", "0"); | |
| test_trigger_on_group("1 at 1 sticky", "1 at 1", "prev", "0", "1"); | |
| test_trigger_on_group("", "1 at 1", "set 0", "0", "1"); | |
| test_trigger_on_group("", "1 at 1", "set 1", "1", "0"); | |
| test_trigger_on_group("", "1 at 1", "set 7", "7", "0"); | |
| test_trigger_on_group("", "1 at 1", "set named-state", "named-state", "0"); | |
| test_trigger_on_group("[a b c] at a", "1 at 1", "next", "b", "0"); | |
| test_trigger_on_group("[a b c] at c", "1 at 1", "next", "a", "1"); | |
| test_trigger_on_group("[a b c] at a", "1 at 1", "prev", "c", "0"); | |
| test_trigger_on_group("[a b c] at b", "1 at 1", "prev", "a", "1"); | |
| test_trigger_on_group("[a b c] at b", "1 at 1", "set 2", "c", "0"); | |
| test_trigger_on_group("[a b c] at b", "1 at 1", "set c", "c", "0"); | |
| test_trigger_on_group("[a b c] at b", "1 at 1", "set 0", "0", "1"); | |
| test_trigger_on_group("[a b c] at b", "1 at 1", "set a", "0", "1"); | |
| test_trigger_on_group("[a b c] at b", "1 at 1", "set new-state", "new-state", "0"); | |
| test_trigger_on_group("", "[a b c] at b", "next", "1", "a"); | |
| test_trigger_on_group("", "[a b c] at b", "prev", "1", "a"); | |
| test_trigger_on_group("", "[a b c] at b", "set 1", "1", "a"); | |
| test_trigger_on_group("", "[a b c] at b", "set 0", "0", "b"); | |
| let finding_group_tests = [ | |
| // Markup to create the test assertions: | |
| // class=assert-in: assert that this element's in-scope toggle is in the | |
| // test-group group and was not the activated toggle | |
| // class=assert-out: assert that this element's in-scope toggle is not in | |
| // the test-group group and was not the activated toggle | |
| // class=assert-activated: assert that this element's in-scope toggle was | |
| // the activated toggle | |
| // | |
| // Helper markup to create more markup: | |
| // class=establish: establish the group with the toggle-group property | |
| // class=establish-self: same, but with the self keyword (narrow scope) | |
| // class=root: create a test-group toggle with the toggle-root property | |
| // class=root-nogroup: same, but without the 'group' keyword | |
| // class=activate: toggle-trigger to activate test-group toggle | |
| // | |
| // class=activate (above) is *also* a helper to run the test; it will be | |
| // activated. There must only be one element with class=activate. | |
| ` | |
| <div class="establish"></div> | |
| <div class="root assert-in"></div> | |
| <div class="root-nogroup assert-out"></div> | |
| <div class="root activate assert-activated"></div> | |
| `, | |
| ` | |
| <div class="establish"></div> | |
| <div class="root assert-out"></div> | |
| <div class="establish"></div> | |
| <div class="root assert-in"></div> | |
| <div class="root activate assert-activated"></div> | |
| `, | |
| ` | |
| <div class="establish"></div> | |
| <div class="root activate assert-activated"></div> | |
| <div class="root assert-in"></div> | |
| <div class="establish"></div> | |
| <div class="root assert-out"></div> | |
| `, | |
| ` | |
| <div class="establish"></div> | |
| <div class="root assert-in"></div> | |
| <div class="establish-self"> | |
| <div class="root assert-out"></div> | |
| </div> | |
| <div class="root assert-in"></div> | |
| <div class="root activate assert-activated"></div> | |
| `, | |
| ` | |
| <div class="establish"></div> | |
| <div class="root assert-out"></div> | |
| <div class="establish"> | |
| <div class="root assert-in"></div> | |
| </div> | |
| <div class="root assert-in"></div> | |
| <div class="root activate assert-activated"></div> | |
| `, | |
| ` | |
| <div class="establish"></div> | |
| <div class="root activate assert-activated"></div> | |
| <div class="root assert-in"></div> | |
| <div class="establish"> | |
| <div class="root assert-out"></div> | |
| </div> | |
| <div class="root assert-out"></div> | |
| `, | |
| ` | |
| <div class="establish"></div> | |
| <div class="root assert-in"></div> | |
| <div class="establish-self"></div> | |
| <div class="root assert-activated"></div> | |
| <div class="activate"></div> | |
| `, | |
| ` | |
| <div class="root activate assert-activated"></div> | |
| <div class="root assert-in"></div> | |
| `, | |
| ` | |
| <div class="root assert-out"></div> | |
| <div class="establish-self"> | |
| <div class="root activate assert-activated"></div> | |
| <div class="root assert-in"></div> | |
| </div> | |
| <div class="root assert-out"></div> | |
| `, | |
| ` | |
| <div class="root assert-out"></div> | |
| <div style="toggle-group: test-group self, extra-group"> | |
| <div class="root activate assert-activated"></div> | |
| <div class="root assert-in"></div> | |
| </div> | |
| <div class="root assert-out"></div> | |
| `, | |
| ` | |
| <div class="root assert-out"></div> | |
| <div style="toggle-group: extra-group, test-group self"> | |
| <div class="root activate assert-activated"></div> | |
| <div class="root assert-in"></div> | |
| </div> | |
| <div class="root assert-out"></div> | |
| `, | |
| ` | |
| <div class="root activate assert-activated"> | |
| <div class="establish"> | |
| <div class="root assert-out"></div> | |
| </div> | |
| <div class="root assert-out"></div> | |
| </div> | |
| `, | |
| ` | |
| <div class="root activate assert-activated"> | |
| <div class="establish-self"> | |
| <div class="root assert-out"></div> | |
| </div> | |
| <div class="root assert-in"></div> | |
| </div> | |
| `, | |
| ` | |
| <div class="root activate assert-activated"> | |
| <div class="root assert-in"></div> | |
| <div> | |
| <div class="root assert-in"></div> | |
| <div class="establish"> | |
| <div class="root assert-out"></div> | |
| </div> | |
| <div class="root assert-out"></div> | |
| </div> | |
| <div class="root assert-in"></div> | |
| </div> | |
| `, | |
| ]; | |
| for (let t of finding_group_tests) { | |
| promise_test(async function() { | |
| document.getElementById("style").textContent = ` | |
| :toggle(test-group 0) { --v:0; } | |
| :toggle(test-group 1) { --v:1; } | |
| :toggle(test-group 2) { --v:2; } | |
| `; | |
| container.innerHTML = t; | |
| for (let e of container.querySelectorAll('.establish')) { | |
| e.style.toggleGroup = "test-group"; | |
| } | |
| for (let e of container.querySelectorAll('.establish-self')) { | |
| e.style.toggleGroup = "test-group self"; | |
| } | |
| for (let e of container.querySelectorAll('.root')) { | |
| e.style.toggleRoot = "test-group 1 at 1 cycle-on group"; | |
| } | |
| for (let e of container.querySelectorAll('.root-nogroup')) { | |
| e.style.toggleRoot = "test-group 1 at 1 cycle-on"; | |
| } | |
| let activate = container.querySelector('.activate'); | |
| activate.style.toggleTrigger = "test-group set 2"; | |
| for (let e of container.querySelectorAll('.root, .root-nogroup')) { | |
| await wait_for_toggle_creation(e); | |
| } | |
| activate.click(); | |
| for (let e of container.querySelectorAll('.assert-in')) { | |
| assert_true(e.matches(":toggle(test-group 0)"), "element in group"); | |
| assert_equals(getComputedStyle(e).getPropertyValue("--v"), "0", | |
| "style on element in group"); | |
| } | |
| for (let e of container.querySelectorAll('.assert-out')) { | |
| assert_true(e.matches(":toggle(test-group 1)"), "element not in group"); | |
| assert_equals(getComputedStyle(e).getPropertyValue("--v"), "1", | |
| "style on element not in group"); | |
| } | |
| for (let e of container.querySelectorAll('.assert-activated')) { | |
| assert_true(e.matches(":toggle(test-group 2)"), "element was activated"); | |
| assert_equals(getComputedStyle(e).getPropertyValue("--v"), "2", | |
| "style on activated element"); | |
| } | |
| }, `toggle groups test: ${t}`); | |
| } | |
| promise_test(async () => { | |
| container.innerHTML = ` | |
| <div id="e" style="toggle: tog [a b] at b self group"></div> | |
| <div id="f" style="toggle: tog [a b] at a self group"></div> | |
| `; | |
| let e = document.getElementById("e"); | |
| let f = document.getElementById("f"); | |
| await Promise.all([wait_for_toggle_creation(e), | |
| wait_for_toggle_creation(f)]); | |
| let te = e.toggles.get("tog"); | |
| let tf = f.toggles.get("tog"); | |
| assert_equals(te.value, "b", "e value before first click"); | |
| assert_true(e.matches(':toggle(tog b):toggle(tog 1)'), | |
| "e selector matching before first click"); | |
| assert_equals(tf.value, "a", "f value before first click"); | |
| assert_true(f.matches(':toggle(tog a):toggle(tog 0)'), | |
| "f selector matching before first click"); | |
| f.click(); | |
| assert_equals(te.value, 0, "e value after first click"); | |
| assert_equals(tf.value, "b", "f value after first click"); | |
| f.click(); | |
| assert_equals(te.value, 0, "e value after second click"); | |
| assert_equals(tf.value, "a", "f value after second click"); | |
| te.value = "b"; | |
| assert_equals(te.value, "b", "e value after first value set"); | |
| assert_equals(tf.value, 0, "f value after first value set"); | |
| tf.value = "b"; | |
| assert_equals(te.value, 0, "e value after second value set"); | |
| assert_equals(tf.value, "b", "f value after second value set"); | |
| tf.value = "a"; | |
| assert_equals(te.value, 0, "e value after third value set"); | |
| assert_equals(tf.value, "a", "f value after third value set"); | |
| // Swap the order of the state names in 'toggle-root'. This does not affect | |
| // the states on the toggle, but still affects the override specifier used | |
| // in some algorithms. | |
| e.style.toggleRoot = "tog [b a] at 0 self group"; | |
| f.style.toggleRoot = "tog [b a] at 0 self group"; | |
| await Promise.all([wait_for_toggle_creation(e), | |
| wait_for_toggle_creation(f)]); | |
| assert_equals(te.value, 0, "e value after changing toggle-root"); | |
| assert_equals(tf.value, "a", "f value after changing toggle-root"); | |
| e.click(); | |
| assert_equals(te.value, "a", "e value after third click"); | |
| assert_equals(tf.value, 0, "f value after third click"); | |
| e.click(); | |
| assert_equals(te.value, "b", "e value after fourth click"); | |
| assert_equals(tf.value, 0, "f value after fourth click"); | |
| assert_true(e.matches(':toggle(tog b):toggle(tog 1)'), | |
| "e selector matching after changing toggle-root"); | |
| assert_true(f.matches(':toggle(tog a):toggle(tog 0)'), | |
| "f selector matching after changing toggle-root"); | |
| tf.value = "a"; | |
| assert_equals(te.value, 0, "e value after fourth value set"); | |
| assert_equals(tf.value, "a", "f value after fourth value set"); | |
| tf.value = "b"; | |
| assert_equals(te.value, 0, "e value after fifth value set"); | |
| assert_equals(tf.value, "b", "f value after fifth value set"); | |
| te.value = "b"; | |
| assert_equals(te.value, "b", "e value after sixth value set"); | |
| assert_equals(tf.value, "b", "f value after sixth value set"); | |
| }, "zeroing toggle group uses states from override specifier"); | |
| // TODO(dbaron): This could probably use a few additional tests for multiple | |
| // values of the list-valued properties. (But they're hard to auto-generate.) | |
| </script> |