%PDF- <> %âãÏÓ endobj 2 0 obj <> endobj 3 0 obj <>/ExtGState<>/ProcSet[/PDF/Text/ImageB/ImageC/ImageI] >>/Annots[ 28 0 R 29 0 R] /MediaBox[ 0 0 595.5 842.25] /Contents 4 0 R/Group<>/Tabs/S>> endobj ºaâÚÎΞ-ÌE1ÍØÄ÷{òò2ÿ ÛÖ^ÔÀá TÎ{¦?§®¥kuµùÕ5sLOšuY>endobj 2 0 obj<>endobj 2 0 obj<>endobj 2 0 obj<>endobj 2 0 obj<> endobj 2 0 obj<>endobj 2 0 obj<>es 3 0 R>> endobj 2 0 obj<> ox[ 0.000000 0.000000 609.600000 935.600000]/Fi endobj 3 0 obj<> endobj 7 1 obj<>/ProcSet[/PDF/Text/ImageB/ImageC/ImageI]>>/Subtype/Form>> stream
<!doctype html> <meta charset="utf8"> <meta name="timeout" content="long"> <title>Events must dispatch on disabled elements</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> <style> @keyframes fade { 0% { opacity: 1; } 100% { opacity: 0; } } </style> <body> <script> // HTML elements that can be disabled const formElements = ["button", "fieldset", "input", "select", "textarea"]; test(() => { for (const localName of formElements) { const elem = document.createElement(localName); elem.disabled = true; // pass becomes true if the event is called and it's the right type. let pass = false; const listener = ({ type }) => { pass = type === "click"; }; elem.addEventListener("click", listener, { once: true }); elem.dispatchEvent(new Event("click")); assert_true( pass, `Untrusted "click" Event didn't dispatch on ${elem.constructor.name}.` ); } }, "Can dispatch untrusted 'click' Events at disabled HTML elements."); test(() => { for (const localName of formElements) { const elem = document.createElement(localName); elem.disabled = true; // pass becomes true if the event is called and it's the right type. let pass = false; const listener = ({ type }) => { pass = type === "pass"; }; elem.addEventListener("pass", listener, { once: true }); elem.dispatchEvent(new Event("pass")); assert_true( pass, `Untrusted "pass" Event didn't dispatch on ${elem.constructor.name}` ); } }, "Can dispatch untrusted Events at disabled HTML elements."); test(() => { for (const localName of formElements) { const elem = document.createElement(localName); elem.disabled = true; // pass becomes true if the event is called and it's the right type. let pass = false; const listener = ({ type }) => { pass = type === "custom-pass"; }; elem.addEventListener("custom-pass", listener, { once: true }); elem.dispatchEvent(new CustomEvent("custom-pass")); assert_true( pass, `CustomEvent "custom-pass" didn't dispatch on ${elem.constructor.name}` ); } }, "Can dispatch CustomEvents at disabled HTML elements."); test(() => { for (const localName of formElements) { const elem = document.createElement(localName); // Element is disabled... so this click() MUST NOT fire an event. elem.disabled = true; let pass = true; elem.onclick = e => { pass = false; }; elem.click(); assert_true( pass, `.click() must not dispatch "click" event on disabled ${ elem.constructor.name }.` ); // Element is (re)enabled... so this click() fires an event. elem.disabled = false; pass = false; elem.onclick = e => { pass = true; }; elem.click(); assert_true( pass, `.click() must dispatch "click" event on enabled ${ elem.constructor.name }.` ); } }, "Calling click() on disabled elements must not dispatch events."); promise_test(async () => { // For each form element type, set up transition event handlers. for (const localName of formElements) { const elem = document.createElement(localName); elem.disabled = true; document.body.appendChild(elem); const eventPromises = [ "transitionrun", "transitionstart", "transitionend", ].map(eventType => { return new Promise(r => { elem.addEventListener(eventType, r); }); }); // Flushing style triggers transition. getComputedStyle(elem).opacity; elem.style.transition = "opacity .1s"; elem.style.opacity = 0; getComputedStyle(elem).opacity; // All the events fire... await Promise.all(eventPromises); elem.remove(); } }, "CSS Transitions transitionrun, transitionstart, transitionend events fire on disabled form elements"); promise_test(async () => { // For each form element type, set up transition event handlers. for (const localName of formElements) { const elem = document.createElement(localName); elem.disabled = true; document.body.appendChild(elem); getComputedStyle(elem).opacity; elem.style.transition = "opacity 100s"; // We use ontransitionstart to cancel the event. elem.ontransitionstart = () => { elem.style.display = "none"; }; const promiseToCancel = new Promise(r => { elem.ontransitioncancel = r; }); // Flushing style triggers the transition. elem.style.opacity = 0; getComputedStyle(elem).opacity; await promiseToCancel; // And we are done with this element. elem.remove(); } }, "CSS Transitions transitioncancel event fires on disabled form elements"); promise_test(async () => { // For each form element type, set up transition event handlers. for (const localName of formElements) { const elem = document.createElement(localName); document.body.appendChild(elem); elem.disabled = true; const animationStartPromise = new Promise(r => { elem.addEventListener("animationstart", () => { // Seek to the second iteration to trigger the animationiteration event elem.style.animationDelay = "-100s" r(); }); }); const animationIterationPromise = new Promise(r => { elem.addEventListener("animationiteration", ()=>{ elem.style.animationDelay = "-200s" r(); }); }); const animationEndPromise = new Promise(r => { elem.addEventListener("animationend", r); }); elem.style.animation = "fade 100s 2"; elem.classList.add("animate"); // All the events fire... await Promise.all([ animationStartPromise, animationIterationPromise, animationEndPromise, ]); elem.remove(); } }, "CSS Animation animationstart, animationiteration, animationend fire on disabled form elements"); promise_test(async () => { // For each form element type, set up transition event handlers. for (const localName of formElements) { const elem = document.createElement(localName); document.body.appendChild(elem); elem.disabled = true; const promiseToCancel = new Promise(r => { elem.addEventListener("animationcancel", r); }); elem.addEventListener("animationstart", () => { // Cancel the animation by hiding it. elem.style.display = "none"; }); // Trigger the animation elem.style.animation = "fade 100s"; elem.classList.add("animate"); await promiseToCancel; // And we are done with this element. elem.remove(); } }, "CSS Animation's animationcancel event fires on disabled form elements"); promise_test(async () => { for (const localName of formElements) { const elem = document.createElement(localName); elem.disabled = true; document.body.appendChild(elem); // Element is disabled, so clicking must not fire events let pass = true; elem.onclick = e => { pass = false; }; // Disabled elements are not clickable. await test_driver.click(elem); assert_true( pass, `${elem.constructor.name} is disabled, so onclick must not fire.` ); // Element is (re)enabled... so this click() will fire an event. pass = false; elem.disabled = false; elem.onclick = () => { pass = true; }; await test_driver.click(elem); assert_true( pass, `${elem.constructor.name} is enabled, so onclick must fire.` ); elem.remove(); } }, "Real clicks on disabled elements must not dispatch events."); </script>