summaryrefslogtreecommitdiff
path: root/dom
diff options
context:
space:
mode:
authorMatt A. Tobin <email@mattatobin.com>2020-06-13 08:23:21 -0400
committerMatt A. Tobin <email@mattatobin.com>2020-06-13 08:23:21 -0400
commitc770115aacdef9464341dd8b76681f07cc3cf49d (patch)
treeead6813f00c5ff538adad2b2aa8406732ffeb2b4 /dom
parent7b2976598712391cdde55b2cff903b164079400e (diff)
downloadaura-central-c770115aacdef9464341dd8b76681f07cc3cf49d.tar.gz
Bug 1429656 - Implement ShadowRoot.activeElement
Tag mcp-graveyard/UXP%1375
Diffstat (limited to 'dom')
-rw-r--r--dom/base/DocumentOrShadowRoot.cpp45
-rw-r--r--dom/base/DocumentOrShadowRoot.h9
-rw-r--r--dom/base/FragmentOrElement.cpp9
-rw-r--r--dom/base/ShadowRoot.cpp6
-rw-r--r--dom/base/ShadowRoot.h2
-rw-r--r--dom/base/nsDocument.cpp17
-rw-r--r--dom/base/nsFocusManager.cpp7
-rw-r--r--dom/base/nsIContent.h8
-rw-r--r--dom/webidl/ShadowRoot.webidl2
9 files changed, 88 insertions, 17 deletions
diff --git a/dom/base/DocumentOrShadowRoot.cpp b/dom/base/DocumentOrShadowRoot.cpp
index 8376ab97e..13ee3cb15 100644
--- a/dom/base/DocumentOrShadowRoot.cpp
+++ b/dom/base/DocumentOrShadowRoot.cpp
@@ -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;
+}
+
}
}
diff --git a/dom/base/DocumentOrShadowRoot.h b/dom/base/DocumentOrShadowRoot.h
index 59be0c2a9..2092cd54f 100644
--- a/dom/base/DocumentOrShadowRoot.h
+++ b/dom/base/DocumentOrShadowRoot.h
@@ -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;
diff --git a/dom/base/FragmentOrElement.cpp b/dom/base/FragmentOrElement.cpp
index 6fbe04d25..e33d3c63a 100644
--- a/dom/base/FragmentOrElement.cpp
+++ b/dom/base/FragmentOrElement.cpp
@@ -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)
{
diff --git a/dom/base/ShadowRoot.cpp b/dom/base/ShadowRoot.cpp
index 4aab9e435..c354e04c1 100644
--- a/dom/base/ShadowRoot.cpp
+++ b/dom/base/ShadowRoot.cpp
@@ -461,6 +461,12 @@ ShadowRoot::DistributeAllNodes()
DistributionChanged();
}
+Element*
+ShadowRoot::GetActiveElement()
+{
+ return GetRetargetedFocusedElement();
+}
+
void
ShadowRoot::GetInnerHTML(nsAString& aInnerHTML)
{
diff --git a/dom/base/ShadowRoot.h b/dom/base/ShadowRoot.h
index eb772d49a..f83a6f774 100644
--- a/dom/base/ShadowRoot.h
+++ b/dom/base/ShadowRoot.h
@@ -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();
diff --git a/dom/base/nsDocument.cpp b/dom/base/nsDocument.cpp
index a1b1408a5..40bfa97e2 100644
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -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.
diff --git a/dom/base/nsFocusManager.cpp b/dom/base/nsFocusManager.cpp
index c14087c8a..3fc9546e8 100644
--- a/dom/base/nsFocusManager.cpp
+++ b/dom/base/nsFocusManager.cpp
@@ -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);
diff --git a/dom/base/nsIContent.h b/dom/base/nsIContent.h
index ce0a4e596..101d5e931 100644
--- a/dom/base/nsIContent.h
+++ b/dom/base/nsIContent.h
@@ -697,6 +697,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.
*
* @return The assigned slot element or null.
diff --git a/dom/webidl/ShadowRoot.webidl b/dom/webidl/ShadowRoot.webidl
index 47e6cf5ec..81b50e58b 100644
--- a/dom/webidl/ShadowRoot.webidl
+++ b/dom/webidl/ShadowRoot.webidl
@@ -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;