[webcomponents] [Shadow]: activeElement adjustment adjusts activeElement to the shadow root itself (bugzilla: 17089) (#251)

Title: [Shadow]: activeElement adjustment adjusts activeElement to the shadow root itself (bugzilla: 17089)

Migrated from: https://www.w3.org/Bugs/Public/show_bug.cgi?id=17089

----
comment: 0
comment_url: https://www.w3.org/Bugs/Public/show_bug.cgi?id=17089#c0
*Dominic Cooney* wrote on 2012-05-17 14:13:58 +0000.

Given this situation:

\<div id="d">
+ {SR}
  +\<input id="i">

and the input has focus, then intuitively the document.activeElement should be #d and the ShadowRoot.activeElement should be #i.

To do this adjustment, Section 8.3 says:

Run the retargeting algorithm with ELEMENT (ie #i) as input

The retargeting algorithm says:

Input
  NODE, a DOM node
Output
  TARGETS, a list of tuples, each containing NODE's ancestor and its relative target

[So NODE=#i]

Let BOUNDARY be a flag, initialized to false
[NODE=#i, BOUNDARY=false]
Let STACK be a stack of DOM nodes
[NODE=#i, BOUNDARY=false, STACK=[]]
Let ANCESTOR be NODE
[NODE=#i, ANCESTOR=#i, BOUNDARY=false,STACK=[]]
Repeat while ANCESTOR exists: {
[it exists]
  If ANCESTOR is a shadow root, set BOUNDARY to true
[ANCESTOR=#i is not a shadow root]
  If ANCESTOR is as an insertion point, push ANCESTOR into STACK
[ANCESTOR=#i is not an insertion point]
  If BOUNDARY is set to true {
[BOUNDARY=false is not set to true, so skip]
    Pop STACK if STACK is not empty
    Set BOUNDARY to false state
  If STACK is empty, push ANCESTOR into STACK
[NODE=#i, ANCESTOR=#i, BOUNDARY=false, STACK=[#i]]
  Let TARGET be the DOM node at the top of STACK
[TARGET=#i, NODE=#i, ANCESTOR=#i, BOUNDARY=false, STACK=[#i]]
  Add (TARGET, ANCESTOR) tuple to TARGETS
[TARGET=#i, NODE=#i, ANCESTOR=#i, BOUNDARY=false, STACK=[#i], TARGETS={(#i, #i)}]
  Set ANCESTOR to be the result of parent calculation algorithm, given ANCESTOR as input
[Since #i is not a shadow root, and not distributed to an insertion point, ANCESTOR=SR per the parent calculation algorithm]

The second iteration of the loop:

[TARGET=#i, NODE=#i, ANCESTOR=SR, BOUNDARY=false, STACK=[#i], TARGETS={(#i, #i)}]
If ANCESTOR is a shadow root, set BOUNDARY to true
[TARGET=#i, NODE=#i, ANCESTOR=SR, BOUNDARY=true, STACK=[#i], TARGETS={(#i, #i)}]
If ANCESTOR is as an insertion point, push ANCESTOR into STACK
[No]
If BOUNDARY is set to true {
[Yes]
  Pop STACK if STACK is not empty
[TARGET=#i, NODE=#i, ANCESTOR=SR, BOUNDARY=true, STACK=[], TARGETS={(#i, #i)}]
  Set BOUNDARY to false state
[TARGET=#i, NODE=#i, ANCESTOR=SR, BOUNDARY=false, STACK=[], TARGETS={(#i, #i)}]
}
If STACK is empty, push ANCESTOR into STACK
[TARGET=#i, NODE=#i, ANCESTOR=SR, BOUNDARY=false, STACK=[SR], TARGETS={(#i, #i)}]
Let TARGET be the DOM node at the top of STACK
[TARGET=SR, NODE=#i, ANCESTOR=SR, BOUNDARY=false, STACK=[SR], TARGETS={(#i, #i)}]
Add (TARGET, ANCESTOR) tuple to TARGETS
[TARGET=SR, NODE=#i, ANCESTOR=SR, BOUNDARY=false, STACK=[SR], TARGETS={(#i, #i), (SR, SR)}]
… (algorithm continues) …

Note that we are off the rails at this point by pushing (SR, SR) to TARGETS, because Section 8.3 continues:

For each TUPLE in the resulting list of tuples:
Let ADJUSTED be the first value of the TUPLE
Let NODE be the second value of the TUPLE
If NODE is a Document or a shadow root, set the value of the activeElement to ADJUSTED.

This means that the ShadowRoot.activeElement is set to the ShadowRoot, and hence information about the active element (ie #i) is lost. This is contrary to the goal of section 8.3, "To prevent loss of information when adjusting this value, each shadow root must also have an activeElement property to store the value of the focused element in the shadow DOM subtree."

---
Reply to this email directly or view it on GitHub:
https://github.com/w3c/webcomponents/issues/251

Received on Monday, 6 July 2015 07:43:44 UTC