form.html (9408B)
1 <!DOCTYPE HTML> 2 <html> 3 <head> 4 <script src="/resources/testharness.js"></script> 5 <script src="/resources/testharnessreport.js"></script> 6 <script src="/resources/testdriver.js"></script> 7 <script src="/resources/testdriver-vendor.js"></script> 8 <script src="/resources/testdriver-actions.js"></script> 9 </head> 10 11 <body> 12 <div> 13 <template shadowrootmode="open"> 14 <!-- This button shouldn't link to the real form in fancy-form-1 as it's in a different tree scope --> 15 <button id="button-in-shadow" form="fancy-form-1"></button> 16 </template> 17 </div> 18 19 <button id="reset-button-1" type="reset" form="fancy-form-1"></button> 20 <fancy-form-1 id="fancy-form-1"> 21 <template shadowrootmode="open" shadowrootreferencetarget="real-form"> 22 <form id="real-form"> 23 <input type="text" value="default value"> 24 </form> 25 </template> 26 </fancy-form-1> 27 28 <button id="reset-button-2" type="reset" form="fancy-form-2"></button> 29 <fancy-form-2 id="fancy-form-2"></fancy-form-2> 30 <script> 31 const fancyForm2 = document.querySelector('fancy-form-2'); 32 fancyForm2.attachShadow({ mode: 'open', referenceTarget: 'real-form' }); 33 fancyForm2.shadowRoot.innerHTML = '<form id="real-form"><input type="text" value="default value"></form>'; 34 </script> 35 36 <button id="reset-button-3" type="reset"></button> 37 <fancy-form-3 id="fancy-form-3"> 38 <template shadowrootmode="open" shadowrootreferencetarget="real-form"> 39 <form id="real-form"> 40 <input type="text" value="default value"> 41 </form> 42 </template> 43 </fancy-form-3> 44 45 <script> 46 function testFormWithReferenceTarget(formId, resetButtonId, name) { 47 test(function () { 48 const fancyForm = document.getElementById(formId); 49 const realForm = fancyForm.shadowRoot.getElementById("real-form"); 50 const input = realForm.firstElementChild; 51 52 input.value = "new value"; 53 const resetButton = document.getElementById(resetButtonId); 54 assert_equals(realForm.elements.length, 2, "The .elements property should have 2 elements."); 55 assert_equals(realForm.elements[0], resetButton, "The first element should be the referencing element."); 56 assert_equals(realForm.elements[1], input, "The 2nd element should be the input inside the real form."); 57 assert_equals(input.value, "new value", "The input value should be updated to the new value."); 58 resetButton.click(); 59 assert_equals(input.value, "default value", "The input value should be reset to the default value."); 60 }, name); 61 } 62 63 testFormWithReferenceTarget('fancy-form-1', 'reset-button-1', "Reference target works with form attribute."); 64 testFormWithReferenceTarget('fancy-form-2', 'reset-button-2', "Reference target works with form attribute via options."); 65 66 document.getElementById('reset-button-3').setAttribute('form', "fancy-form-3"); 67 testFormWithReferenceTarget('fancy-form-3', 'reset-button-3', "Reference target works with setAttribute('form')"); 68 </script> 69 70 <form-associated-custom-button id="custom-button" form="fancy-form-4"></form-associated-custom-button> 71 <fancy-form-4 id="fancy-form-4"> 72 <template shadowrootmode="open" shadowrootreferencetarget="real-form"> 73 <form id="real-form"> 74 <input type="text" value="default value"> 75 <!-- The internal button of the custom button below shouldn't be associated with real-form --> 76 <form-associated-custom-button id="custom-button-in-shadow"></form-associated-custom-button> 77 </form> 78 </template> 79 </fancy-form-4> 80 <script> 81 class FormAssociatedCustomButton extends HTMLElement { 82 static formAssociated = true; 83 constructor() { 84 super(); 85 this.internals_ = this.attachInternals(); 86 const shadow = this.attachShadow({ mode: 'open' }); 87 shadow.innerHTML = `<button>fancy button</button>`; 88 } 89 } 90 window.customElements.define("form-associated-custom-button", FormAssociatedCustomButton); 91 test(function () { 92 const customElement = document.getElementById("custom-button"); 93 const fancyForm = document.getElementById("fancy-form-4"); 94 const realForm = fancyForm.shadowRoot.getElementById("real-form"); 95 const customElementInShadow = fancyForm.shadowRoot.getElementById("custom-button-in-shadow"); 96 const input = realForm.firstElementChild; 97 98 assert_equals(realForm.elements.length, 3, "The .elements property should have 3 elements."); 99 assert_equals(realForm.elements[0], customElement, "The first element should be the form-associated custom element."); 100 assert_equals(realForm.elements[1], input, "The 2nd element should be the input inside the real form."); 101 assert_equals(realForm.elements[2], customElementInShadow, "The 3rd element should be the custom element inside the real form."); 102 103 // Swap the input and the custom element in real-form. 104 realForm.moveBefore(customElementInShadow, input); 105 assert_equals(realForm.elements.length, 3, "The .elements property should have 3 elements."); 106 assert_equals(realForm.elements[0], customElement, "The first element should be the form-associated custom element."); 107 assert_equals(realForm.elements[1], customElementInShadow, "The 2nd element should be the custom element inside the real form."); 108 assert_equals(realForm.elements[2], input, "The 3rd element should be the input inside the real form."); 109 110 // Swap the referencing element and the fancy form 111 customElement.parentNode.moveBefore(fancyForm, customElement); 112 assert_equals(realForm.elements.length, 3, "The .elements property should have 3 elements."); 113 assert_equals(realForm.elements[0], customElementInShadow, "The first element should be the custom element inside the real form."); 114 assert_equals(realForm.elements[1], input, "The 2nd element should be the input inside the real form."); 115 assert_equals(realForm.elements[2], customElement, "The 3rd element should be the form-associated custom element."); 116 }, "Reference target works with form-associated custom element."); 117 </script> 118 119 <button id="reset-button-5" type="reset" form="fancy-form-5"></button> 120 <fancy-form-5 id="fancy-form-5"> 121 <template shadowrootmode="open" shadowrootreferencetarget="nested-element"> 122 <nested-element id="nested-element"> 123 <template shadowrootmode="open" shadowrootreferencetarget="real-form"> 124 <form id="real-form"> 125 <input type="text" value="default value"> 126 </form> 127 </template> 128 </nested-element> 129 <button id="button-in-shadow" form="nested-element"></button> 130 <div> 131 <template shadowrootmode="open"> 132 <!-- This button shouldn't link to the real form in nested-element as it's in a different tree scope --> 133 <button id="button-in-different-shadow" form="nested-element"></button> 134 </template> 135 </div> 136 </template> 137 </fancy-form-5> 138 <script> 139 test(function () { 140 const fancyForm = document.getElementById("fancy-form-5"); 141 const nestedElement = fancyForm.shadowRoot.getElementById("nested-element"); 142 const buttonInShadow = fancyForm.shadowRoot.getElementById("button-in-shadow"); 143 const realForm = nestedElement.shadowRoot.getElementById("real-form"); 144 const input = realForm.firstElementChild; 145 146 input.value = "new value"; 147 const resetButton = document.getElementById("reset-button-5"); 148 assert_equals(realForm.elements.length, 3, "The .elements property should have 3 elements."); 149 // The elements in .elements property should be in tree order (preorder, depth-first). 150 assert_equals(realForm.elements[0], resetButton, "The first element should be the referencing element."); 151 assert_equals(realForm.elements[1], input, "The 2nd element should be the input inside the real form."); 152 assert_equals(realForm.elements[2], buttonInShadow, "The 3rd element should be the button in the shadow dom."); 153 assert_equals(input.value, "new value", "The input value should be updated to the new value."); 154 resetButton.click(); 155 assert_equals(input.value, "default value", "The input value should be reset to the default value."); 156 157 // Remove the button that's using reference target in the 1st level shadow. 158 buttonInShadow.remove(); 159 assert_equals(realForm.elements.length, 2, "The .elements property should have 2 elements after removing the button."); 160 161 // Add a new button using reference target in the 1st level shadow. 162 const newButtonInShadow = document.createElement("button"); 163 newButtonInShadow.setAttribute("form", "nested-element"); 164 nestedElement.parentNode.insertBefore(newButtonInShadow, nestedElement); 165 assert_equals(realForm.elements.length, 3, "The .elements property should have 3 elements after a new button is inserted."); 166 assert_equals(realForm.elements[0], resetButton, "The first element should be the referencing element."); 167 assert_equals(realForm.elements[1], newButtonInShadow, "The 2nd element should be the button in the shadow dom."); 168 assert_equals(realForm.elements[2], input, "The 3rd element should be the input inside the real form."); 169 }, "Reference target works with nested shadow trees."); 170 </script> 171 </body> 172 </html>