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