1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "mozilla/dom/HTMLAnchorElement.h"
9 #include "mozilla/dom/BindContext.h"
10 #include "mozilla/dom/HTMLAnchorElementBinding.h"
11 #include "mozilla/dom/HTMLDNSPrefetch.h"
12 #include "mozilla/EventDispatcher.h"
13 #include "mozilla/MemoryReporting.h"
15 #include "nsContentUtils.h"
16 #include "nsGkAtoms.h"
17 #include "nsAttrValueOrString.h"
18 #include "mozilla/dom/Document.h"
19 #include "nsPresContext.h"
21 #include "nsWindowSizes.h"
23 NS_IMPL_NS_NEW_HTML_ELEMENT(Anchor
)
25 namespace mozilla::dom
{
27 HTMLAnchorElement::~HTMLAnchorElement() {
28 SupportsDNSPrefetch::Destroyed(*this);
31 bool HTMLAnchorElement::IsInteractiveHTMLContent() const {
32 return HasAttr(nsGkAtoms::href
) ||
33 nsGenericHTMLElement::IsInteractiveHTMLContent();
36 NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED(HTMLAnchorElement
,
37 nsGenericHTMLElement
, Link
)
39 NS_IMPL_CYCLE_COLLECTION_INHERITED(HTMLAnchorElement
, nsGenericHTMLElement
,
42 NS_IMPL_ELEMENT_CLONE(HTMLAnchorElement
)
44 JSObject
* HTMLAnchorElement::WrapNode(JSContext
* aCx
,
45 JS::Handle
<JSObject
*> aGivenProto
) {
46 return HTMLAnchorElement_Binding::Wrap(aCx
, this, aGivenProto
);
49 int32_t HTMLAnchorElement::TabIndexDefault() { return 0; }
51 bool HTMLAnchorElement::Draggable() const {
52 // links can be dragged as long as there is an href and the
53 // draggable attribute isn't false
54 if (!HasAttr(nsGkAtoms::href
)) {
55 // no href, so just use the same behavior as other elements
56 return nsGenericHTMLElement::Draggable();
59 return !AttrValueIs(kNameSpaceID_None
, nsGkAtoms::draggable
,
60 nsGkAtoms::_false
, eIgnoreCase
);
63 nsresult
HTMLAnchorElement::BindToTree(BindContext
& aContext
,
65 nsresult rv
= nsGenericHTMLElement::BindToTree(aContext
, aParent
);
66 NS_ENSURE_SUCCESS(rv
, rv
);
68 Link::BindToTree(aContext
);
71 if (IsInComposedDoc()) {
72 TryDNSPrefetch(*this);
78 void HTMLAnchorElement::UnbindFromTree(UnbindContext
& aContext
) {
79 // Cancel any DNS prefetches
80 // Note: Must come before ResetLinkState. If called after, it will recreate
81 // mCachedURI based on data that is invalid - due to a call to Link::GetURI()
82 // via GetURIForDNSPrefetch().
83 CancelDNSPrefetch(*this);
85 nsGenericHTMLElement::UnbindFromTree(aContext
);
87 // Without removing the link state we risk a dangling pointer in the
88 // mStyledLinks hashtable
89 Link::UnbindFromTree();
92 bool HTMLAnchorElement::IsHTMLFocusable(bool aWithMouse
, bool* aIsFocusable
,
94 if (nsGenericHTMLElement::IsHTMLFocusable(aWithMouse
, aIsFocusable
,
99 // cannot focus links if there is no link handler
100 if (!OwnerDoc()->LinkHandlingEnabled()) {
102 *aIsFocusable
= false;
106 // Links that are in an editable region should never be focusable, even if
107 // they are in a contenteditable="false" region.
108 if (nsContentUtils::IsNodeInEditableRegion(this)) {
110 *aIsFocusable
= false;
114 if (GetTabIndexAttrValue().isNothing()) {
115 // check whether we're actually a link
117 // Not tabbable or focusable without href (bug 17605), unless
118 // forced to be via presence of nonnegative tabindex attribute
120 *aIsFocusable
= false;
125 if ((sTabFocusModel
& eTabFocus_linksMask
) == 0) {
128 *aIsFocusable
= true;
132 void HTMLAnchorElement::GetEventTargetParent(EventChainPreVisitor
& aVisitor
) {
133 GetEventTargetParentForAnchors(aVisitor
);
136 nsresult
HTMLAnchorElement::PostHandleEvent(EventChainPostVisitor
& aVisitor
) {
137 return PostHandleEventForAnchors(aVisitor
);
140 void HTMLAnchorElement::GetLinkTarget(nsAString
& aTarget
) {
141 GetAttr(nsGkAtoms::target
, aTarget
);
142 if (aTarget
.IsEmpty()) {
143 GetBaseTarget(aTarget
);
147 void HTMLAnchorElement::GetTarget(nsAString
& aValue
) const {
148 if (!GetAttr(nsGkAtoms::target
, aValue
)) {
149 GetBaseTarget(aValue
);
153 nsDOMTokenList
* HTMLAnchorElement::RelList() {
156 new nsDOMTokenList(this, nsGkAtoms::rel
, sAnchorAndFormRelValues
);
161 void HTMLAnchorElement::GetText(nsAString
& aText
,
162 mozilla::ErrorResult
& aRv
) const {
164 !nsContentUtils::GetNodeTextContent(this, true, aText
, fallible
))) {
165 aRv
.Throw(NS_ERROR_OUT_OF_MEMORY
);
169 void HTMLAnchorElement::SetText(const nsAString
& aText
, ErrorResult
& aRv
) {
170 aRv
= nsContentUtils::SetNodeTextContent(this, aText
, false);
173 already_AddRefed
<nsIURI
> HTMLAnchorElement::GetHrefURI() const {
174 if (nsCOMPtr
<nsIURI
> uri
= GetCachedURI()) {
177 return GetHrefURIForAnchors();
180 void HTMLAnchorElement::BeforeSetAttr(int32_t aNamespaceID
, nsAtom
* aName
,
181 const nsAttrValue
* aValue
, bool aNotify
) {
182 if (aNamespaceID
== kNameSpaceID_None
&& aName
== nsGkAtoms::href
) {
183 CancelDNSPrefetch(*this);
185 return nsGenericHTMLElement::BeforeSetAttr(aNamespaceID
, aName
, aValue
,
189 void HTMLAnchorElement::AfterSetAttr(int32_t aNamespaceID
, nsAtom
* aName
,
190 const nsAttrValue
* aValue
,
191 const nsAttrValue
* aOldValue
,
192 nsIPrincipal
* aSubjectPrincipal
,
194 if (aNamespaceID
== kNameSpaceID_None
) {
195 if (aName
== nsGkAtoms::href
) {
196 Link::ResetLinkState(aNotify
, !!aValue
);
197 if (aValue
&& IsInComposedDoc()) {
198 TryDNSPrefetch(*this);
203 return nsGenericHTMLElement::AfterSetAttr(
204 aNamespaceID
, aName
, aValue
, aOldValue
, aSubjectPrincipal
, aNotify
);
207 void HTMLAnchorElement::AddSizeOfExcludingThis(nsWindowSizes
& aSizes
,
208 size_t* aNodeSize
) const {
209 nsGenericHTMLElement::AddSizeOfExcludingThis(aSizes
, aNodeSize
);
210 *aNodeSize
+= Link::SizeOfExcludingThis(aSizes
.mState
);
213 } // namespace mozilla::dom