- From: <bugzilla@jessica.w3.org>
- Date: Tue, 07 May 2013 21:48:34 +0000
- To: public-html-bugzilla@w3.org
https://www.w3.org/Bugs/Public/show_bug.cgi?id=21957 Bug ID: 21957 Summary: Adjust the Reset the form owner algorithm to match reality Classification: Unclassified Product: HTML WG Version: unspecified Hardware: PC OS: Windows NT Status: NEW Severity: normal Priority: P2 Component: HTML5 spec Assignee: dave.null@w3.org Reporter: travil@microsoft.com QA Contact: public-html-bugzilla@w3.org CC: mike@w3.org, public-html-admin@w3.org, public-html-wg-issue-tracking@w3.org We recently came across a site bug [1] that is broken in IE10 and Firefox, but does work in Chrome and older versions of IE, and the root cause is due to a subtle variation on the reset the form owner algorithm that exists in Chrome. Because the site works in Chrome and old versions of IE, we believe it is appropriate to fix the HTML5 spec to match reality. Details on what we observed about Chrome's behavior follow -------------- The site's behavior boils down to the following problem where the submit button does not end up associated with the form: <div id="b"></div> <script> document.getElementById('b').innerHTML = '<table><form id="d" action="..." method="post"><tr><td><input id="e" type="submit" name="Submit"></td></tr></form>'; </script> <script> alert(document.getElementById('e').form.id); </script> In IE10/Firefox, the input element's form is null because: * Per step 2 of the reset the form owner algorithm (below), the form owner is cleared * Step 3 doesn't apply in this scenario * There is no ancestor form after foster-parenting in step 4 * In step 5, the form owner is left unassociated However, in Chrome, the element's form is "d". ===RESET the form owner algorithm (As currently defined)=== 1. If the element's form owner is not null, and the element's form content attribute is not present, and the element's form owner is its nearest form element ancestor after the change to the ancestor chain, then do nothing, and abort these steps. 2. Let the element's form owner be null. 3. If the element has a form content attribute and is itself in a Document, then run these substeps: 3.1. If the first element in the Document to have an ID that is case-sensitively equal to the element's form content attribute's value is a form element, then associate the form-associated element with that form element. 3.2. Abort the "reset the form owner" steps. 4. Otherwise, if the form-associated element in question has an ancestor form element, then associate the form-associated element with the nearest such ancestor form element. 5. Otherwise, the element is left unassociated. ================= >From what we've been able to deduce from various test cases, Chrome actually runs a variation of this algorithm: ===RESET the form owner algorithm (tweaked for Chrome compat)=== 1. If the element's form owner is not null, and the element's form content attribute is not present, and the element's form owner is its nearest form element ancestor after the change to the ancestor chain, then do nothing, and abort these steps. 2. If the element has a form content attribute and is itself in a Document, then run these substeps: 2.1. If the first element in the Document to have an ID that is case-sensitively equal to the element's form content attribute's value is a form element, then associate the form-associated element with that form element. 2.2. Abort the "reset the form owner" steps. 3. Otherwise, if the form-associated element in question has an ancestor form element, then associate the form-associated element with the nearest such ancestor form element. 4. Otherwise, if the element and its existing form owner belong to the same home subtree, then do nothing, and abort these steps. 5. Otherwise, let the element's form owner be null. ================= And Chome honors the existing removal condition, but applies these conditions on _any_ removal, not just from a document (for example, it can be observed in a removal from an orphaned fragment into another fragment): "When an element is removed **from a Document** resulting in a form-associated element and its form owner (if any) no longer being in the same home subtree, then the user agent must reset the form owner of that form-associated element." (** annotation added for emphasis) These changes cause the form owner association to no longer be unconditionally cleared as was previously done in step 2 of the original algorithm, but rather preserves the association with the previous form owner so long as you always move a common ancestor of the input and its form owner and no new appropriate form owner is found. --------- Here's some supporting testing and commentary. The following only preserve the form owner in Chrome: <!DOCTYPE html> <!--<form id="a">--> <div id="b"></div> <!--</form>--> <script> var b = document.getElementById('b'); var parent = b.parentNode; // === Remove b from the document to check if Chrome // uses a common home subtree, or the document as the basis // for perserving the form owner parent.removeChild(b); // === Run the foster-parent algorithm, then copy the contents // into b (not connected to the document) Per current // spec, the form owner should be null (no suitable ancestor) // Chrome maintains the association... b.innerHTML = '<table><form id="d" action="..." method="post"><tr><td><input id="e" type="submit" name="Submit"></td></tr></form>'; // === Chome's behavior is not limited to the HTML fragment // parsing algorithm, as the following move into the document // continues to preserve the form owner association... parent.appendChild(b); // === Defeat an optimization in Chrome (no-op append in // the second step) b.parentNode.appendChild(document.createTextNode('test')); // === Intra-document moves continue to preserve the association... b.parentNode.appendChild(b); </script> <script> // === Chrome alerts "d", IE10/Firefox script error (null) alert(document.querySelector('#e').form.id); </script> All browser currently drop the form owner association in this case (and it should stay that way): <!DOCTYPE html> <!--<form id="a">--> <div id="b"></div> <!--</form>--> <script> var b = document.getElementById('b'); var parent = b.parentNode; parent.removeChild(b); // === So far, same as the last test, Chrome maintains the // association... b.innerHTML = '<table><form id="d" action="..." method="post"><tr><td><input id="e" type="submit" name="Submit"></td></tr></form>'; // === Now, Chrome breaks the association because, as part // of the move, the form element and its form owner did // not share a common home subtree, and no other suitable // form owner was found parent.appendChild(b.querySelector('tbody')); </script> <script> // === All browsers have a script error here (null) alert(document.querySelector('#e').form.id); </script> All browsers currently get the right form owner association in the example case described in the current spec: <!DOCTYPE html> <form id="a"> <div id="b"></div> </form> <script> document.getElementById('b').innerHTML = '<table><tr><td><form id="c"><input id="d"></table>' + '<input id="e">'; </script> <script> // === Ultimately, form "a" is re-associated as "e"'s // form owner because it exists in the input's // ancestry chain as illustrated in the spec. If // the form "a" is commented out, then Chrome still does // not associate "e" with "c" because there is no common // home subtree in the innerHTML injection to "b" between // the two (the table element and "e" are siblings). // If, however, the form "a" is commented out AND a div // element wrapper is added around the innerHTML-injected // string, then Chrome retains "c" as the form owner for // both "d" and "e", while IE10/Firefox/HTML5 spec (currently) // make this a script error (null) alert(document.getElementById('e').form.id); </script> ----------- [1] http://sc.jz123.cn/tuku/ai/201161/TK21103.shtml (comment button doesn't work) -- You are receiving this mail because: You are the QA Contact for the bug.
Received on Tuesday, 7 May 2013 21:48:40 UTC