This is an archived snapshot of W3C's public bugzilla bug tracker, decommissioned in April 2019. Please see the home page for more details.

Bug 21957 - Adjust the Reset the form owner algorithm to match reality
Summary: Adjust the Reset the form owner algorithm to match reality
Status: RESOLVED WONTFIX
Alias: None
Product: HTML WG
Classification: Unclassified
Component: HTML5 spec (show other bugs)
Version: unspecified
Hardware: PC Windows NT
: P2 normal
Target Milestone: ---
Assignee: Travis Leithead [MSFT]
QA Contact: HTML WG Bugzilla archive list
URL:
Whiteboard:
Keywords:
Depends on:
Blocks: 22183
  Show dependency treegraph
 
Reported: 2013-05-07 21:48 UTC by Travis Leithead [MSFT]
Modified: 2014-02-05 18:53 UTC (History)
10 users (show)

See Also:


Attachments

Description Travis Leithead [MSFT] 2013-05-07 21:48:34 UTC
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)
Comment 1 Ian 'Hixie' Hickson 2013-06-18 23:35:19 UTC
Travis, please see the discussion in bug 22183 comment 1. It might be best to just get Chrome/Safari changed rather than adding more complexity here. Your suggestions (and any information you have on whether there's other breakage here, or if it's really just that one page) would be really helpful.
Comment 2 Travis Leithead [MSFT] 2013-07-12 21:44:46 UTC
Ideally, as noted in the linked bug, Chrome might be fixed to avoid this behavior. Since we're now circling while waiting on the results of the Chrome bug (https://code.google.com/p/chromium/issues/detail?id=256797 -- looks like a fix may be forthcoming) I'm going to consider this issue non-blocking for CR (5.0) and move this bug to 5.1.
Comment 3 Travis Leithead [MSFT] 2014-02-05 18:53:07 UTC
The spec changed, and Chrome's behavior has been fixed (not WebKit though). With only one exception, the existing spec'd behavior is web-compatible, so I'm resolving this bug now.