1429656 - Implement ShadowRoot.activeElement.

master
Fedor 2020-09-17 07:34:32 +03:00
parent a3008768e1
commit 08796d3b0f
14 changed files with 88 additions and 72 deletions

View File

@ -6,6 +6,8 @@
#include "DocumentOrShadowRoot.h"
#include "mozilla/dom/StyleSheetList.h"
#include "nsDocument.h"
#include "nsFocusManager.h"
#include "ShadowRoot.h"
#include "XULDocument.h"
@ -100,5 +102,48 @@ DocumentOrShadowRoot::GetElementsByClassName(const nsAString& aClasses)
return nsContentUtils::GetElementsByClassName(&AsNode(), aClasses);
}
nsIContent*
DocumentOrShadowRoot::Retarget(nsIContent* aContent) const
{
for (nsIContent* cur = aContent;
cur;
cur = cur->GetContainingShadowHost()) {
if (cur->SubtreeRoot() == &AsNode()) {
return cur;
}
}
return nullptr;
}
Element*
DocumentOrShadowRoot::GetRetargetedFocusedElement()
{
if (nsCOMPtr<nsPIDOMWindowOuter> window = AsNode().OwnerDoc()->GetWindow()) {
nsCOMPtr<nsPIDOMWindowOuter> focusedWindow;
nsIContent* focusedContent =
nsFocusManager::GetFocusedDescendant(window,
false,
getter_AddRefs(focusedWindow));
// be safe and make sure the element is from this document
if (focusedContent && focusedContent->OwnerDoc() == AsNode().OwnerDoc()) {
if (focusedContent->ChromeOnlyAccess()) {
focusedContent = focusedContent->FindFirstNonChromeOnlyAccessContent();
}
if (focusedContent) {
if (!nsDocument::IsWebComponentsEnabled(focusedContent)) {
return focusedContent->AsElement();
}
if (nsIContent* retarget = Retarget(focusedContent)) {
return retarget->AsElement();
}
}
}
}
return nullptr;
}
}
}

View File

@ -116,6 +116,15 @@ public:
~DocumentOrShadowRoot() = default;
protected:
nsIContent* Retarget(nsIContent* aContent) const;
/**
* If focused element's subtree root is this document or shadow root, return
* focused element, otherwise, get the shadow host recursively until the
* shadow host's subtree root is this document or shadow root.
*/
Element* GetRetargetedFocusedElement();
nsTArray<RefPtr<mozilla::StyleSheet>> mStyleSheets;
RefPtr<mozilla::dom::StyleSheetList> mDOMStyleSheets;

View File

@ -1138,6 +1138,15 @@ FragmentOrElement::GetAssignedSlot() const
return slots ? slots->mAssignedSlot.get() : nullptr;
}
nsIContent*
nsIContent::GetContainingShadowHost() const
{
if (mozilla::dom::ShadowRoot* shadow = GetContainingShadow()) {
return shadow->GetHost();
}
return nullptr;
}
void
FragmentOrElement::SetAssignedSlot(HTMLSlotElement* aSlot)
{

View File

@ -461,6 +461,12 @@ ShadowRoot::DistributeAllNodes()
DistributionChanged();
}
Element*
ShadowRoot::GetActiveElement()
{
return GetRetargetedFocusedElement();
}
void
ShadowRoot::GetInnerHTML(nsAString& aInnerHTML)
{

View File

@ -120,6 +120,8 @@ public:
// WebIDL methods.
using mozilla::dom::DocumentOrShadowRoot::GetElementById;
Element* GetActiveElement();
void GetInnerHTML(nsAString& aInnerHTML);
void SetInnerHTML(const nsAString& aInnerHTML, ErrorResult& aError);
void StyleSheetChanged();

View File

@ -3031,20 +3031,9 @@ Element*
nsIDocument::GetActiveElement()
{
// Get the focused element.
if (nsCOMPtr<nsPIDOMWindowOuter> window = GetWindow()) {
nsCOMPtr<nsPIDOMWindowOuter> focusedWindow;
nsIContent* focusedContent =
nsFocusManager::GetFocusedDescendant(window, false,
getter_AddRefs(focusedWindow));
// be safe and make sure the element is from this document
if (focusedContent && focusedContent->OwnerDoc() == this) {
if (focusedContent->ChromeOnlyAccess()) {
focusedContent = focusedContent->FindFirstNonChromeOnlyAccessContent();
}
if (focusedContent) {
return focusedContent->AsElement();
}
}
Element* focusedElement = GetRetargetedFocusedElement();
if (focusedElement) {
return focusedElement;
}
// No focused element anywhere in this document. Try to get the BODY.

View File

@ -813,10 +813,11 @@ nsFocusManager::ContentRemoved(nsIDocument* aDocument, nsIContent* aContent)
if (!window)
return NS_OK;
// if the content is currently focused in the window, or is an ancestor
// of the currently focused element, reset the focus within that window.
// if the content is currently focused in the window, or is an
// shadow-including inclusive ancestor of the currently focused element,
// reset the focus within that window.
nsIContent* content = window->GetFocusedNode();
if (content && nsContentUtils::ContentIsDescendantOf(content, aContent)) {
if (content && nsContentUtils::ContentIsHostIncludingDescendantOf(content, aContent)) {
bool shouldShowFocusRing = window->ShouldShowFocusRing();
window->SetFocusedNode(nullptr);

View File

@ -696,6 +696,14 @@ public:
*/
virtual mozilla::dom::ShadowRoot *GetContainingShadow() const = 0;
/**
* Gets the shadow host if this content is in a shadow tree. That is, the host
* of |GetContainingShadow|, if its not null.
*
* @return The shadow host, if this is in shadow tree, or null.
*/
nsIContent* GetContainingShadowHost() const;
/**
* Gets the assigned slot associated with this content.
*

View File

@ -20,6 +20,8 @@ enum ShadowRootMode {
[Func="nsDocument::IsWebComponentsEnabled"]
interface ShadowRoot : DocumentFragment
{
readonly attribute Element? activeElement;
// Shadow DOM v1
readonly attribute ShadowRootMode mode;
readonly attribute Element host;

View File

@ -1,29 +0,0 @@
[ShadowRoot-interface.html]
type: testharness
[ShadowRoot.activeElement must return the focused element of the context object when shadow root is open.]
expected: FAIL
[ShadowRoot.activeElement must return the focused element of the context object when shadow root is closed.]
expected: FAIL
[ShadowRoot.host must return the shadow host of the context object.]
expected: FAIL
[ShadowRoot.innerHTML must return the result of the HTML fragment serialization algorithm when shadow root is open.]
expected: FAIL
[ShadowRoot.innerHTML must return the result of the HTML fragment serialization algorithm when shadow root is closed.]
expected: FAIL
[ShadowRoot.innerHTML must replace all with the result of invoking the fragment parsing algorithm when shadow root is open.]
expected: FAIL
[ShadowRoot.innerHTML must replace all with the result of invoking the fragment parsing algorithm when shadow root is closed.]
expected: FAIL
[ShadowRoot.styleSheets must return a StyleSheetList sequence containing the shadow root style sheets when shadow root is open.]
expected: FAIL
[ShadowRoot.styleSheets must return a StyleSheetList sequence containing the shadow root style sheets when shadow root is closed.]
expected: FAIL

View File

@ -1,11 +0,0 @@
[activeElement-confirm-return-null.html]
type: testharness
[confirm activeElement return null]
expected: FAIL
[confirm activeElement return null when there is other element in body]
expected: FAIL
[confirm activeElement return null when focus on the element in the outer shadow tree]
expected: FAIL

View File

@ -1,5 +0,0 @@
[test-007.html]
type: testharness
[A_10_01_01_03_01_T01]
expected: FAIL

View File

@ -1,5 +0,0 @@
[test-001.html]
type: testharness
[A_07_03_01_T01]
expected: FAIL

View File

@ -1,5 +0,0 @@
[test-002.html]
type: testharness
[A_07_03_02_T01]
expected: FAIL