1use std::cell::Cell;
6use std::default::Default;
7
8use dom_struct::dom_struct;
9use html5ever::{LocalName, Prefix, local_name};
10use js::rust::HandleObject;
11use num_traits::ToPrimitive;
12use servo_url::ServoUrl;
13use style::attr::AttrValue;
14use stylo_atoms::Atom;
15use xml5ever::ns;
16
17use crate::dom::activation::Activatable;
18use crate::dom::attr::Attr;
19use crate::dom::bindings::cell::DomRefCell;
20use crate::dom::bindings::codegen::Bindings::HTMLAnchorElementBinding::HTMLAnchorElementMethods;
21use crate::dom::bindings::codegen::Bindings::MouseEventBinding::MouseEventMethods;
22use crate::dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
23use crate::dom::bindings::inheritance::Castable;
24use crate::dom::bindings::root::{DomRoot, MutNullableDom};
25use crate::dom::bindings::str::{DOMString, USVString};
26use crate::dom::document::Document;
27use crate::dom::domtokenlist::DOMTokenList;
28use crate::dom::element::{AttributeMutation, Element, reflect_referrer_policy_attribute};
29use crate::dom::event::Event;
30use crate::dom::eventtarget::EventTarget;
31use crate::dom::html::htmlelement::HTMLElement;
32use crate::dom::html::htmlhyperlinkelementutils::{HyperlinkElement, HyperlinkElementTraits};
33use crate::dom::html::htmlimageelement::HTMLImageElement;
34use crate::dom::mouseevent::MouseEvent;
35use crate::dom::node::{BindContext, Node, NodeTraits};
36use crate::dom::virtualmethods::VirtualMethods;
37use crate::links::{LinkRelations, follow_hyperlink};
38use crate::script_runtime::CanGc;
39
40#[dom_struct]
41pub(crate) struct HTMLAnchorElement {
42 htmlelement: HTMLElement,
43 rel_list: MutNullableDom<DOMTokenList>,
44 #[no_trace]
45 relations: Cell<LinkRelations>,
46 #[no_trace]
47 url: DomRefCell<Option<ServoUrl>>,
48}
49
50impl HTMLAnchorElement {
51 fn new_inherited(
52 local_name: LocalName,
53 prefix: Option<Prefix>,
54 document: &Document,
55 ) -> HTMLAnchorElement {
56 HTMLAnchorElement {
57 htmlelement: HTMLElement::new_inherited(local_name, prefix, document),
58 rel_list: Default::default(),
59 relations: Cell::new(LinkRelations::empty()),
60 url: DomRefCell::new(None),
61 }
62 }
63
64 #[cfg_attr(crown, allow(crown::unrooted_must_root))]
65 pub(crate) fn new(
66 local_name: LocalName,
67 prefix: Option<Prefix>,
68 document: &Document,
69 proto: Option<HandleObject>,
70 can_gc: CanGc,
71 ) -> DomRoot<HTMLAnchorElement> {
72 Node::reflect_node_with_proto(
73 Box::new(HTMLAnchorElement::new_inherited(
74 local_name, prefix, document,
75 )),
76 document,
77 proto,
78 can_gc,
79 )
80 }
81
82 pub(crate) fn full_href_url_for_user_interface(&self) -> Option<ServoUrl> {
85 self.upcast::<Element>()
86 .get_attribute(&ns!(), &local_name!("href"))?;
87 self.owner_document().base_url().join(&self.Href()).ok()
88 }
89}
90
91impl HyperlinkElement for HTMLAnchorElement {
92 fn get_url(&self) -> &DomRefCell<Option<ServoUrl>> {
93 &self.url
94 }
95}
96
97impl VirtualMethods for HTMLAnchorElement {
98 fn super_type(&self) -> Option<&dyn VirtualMethods> {
99 Some(self.upcast::<HTMLElement>() as &dyn VirtualMethods)
100 }
101
102 fn parse_plain_attribute(&self, name: &LocalName, value: DOMString) -> AttrValue {
103 match name {
104 &local_name!("rel") => AttrValue::from_serialized_tokenlist(value.into()),
105 _ => self
106 .super_type()
107 .unwrap()
108 .parse_plain_attribute(name, value),
109 }
110 }
111
112 fn attribute_mutated(&self, attr: &Attr, mutation: AttributeMutation, can_gc: CanGc) {
113 self.super_type()
114 .unwrap()
115 .attribute_mutated(attr, mutation, can_gc);
116
117 match *attr.local_name() {
118 local_name!("rel") | local_name!("rev") => {
119 self.relations
120 .set(LinkRelations::for_element(self.upcast()));
121 },
122 _ => {},
123 }
124 }
125
126 fn bind_to_tree(&self, context: &BindContext, can_gc: CanGc) {
127 if let Some(s) = self.super_type() {
128 s.bind_to_tree(context, can_gc);
129 }
130
131 self.relations
132 .set(LinkRelations::for_element(self.upcast()));
133 }
134}
135
136impl HTMLAnchorElementMethods<crate::DomTypeHolder> for HTMLAnchorElement {
137 fn Text(&self) -> DOMString {
139 self.upcast::<Node>().GetTextContent().unwrap()
140 }
141
142 fn SetText(&self, value: DOMString, can_gc: CanGc) {
144 self.upcast::<Node>()
145 .set_text_content_for_element(Some(value), can_gc)
146 }
147
148 make_getter!(Rel, "rel");
150
151 fn SetRel(&self, rel: DOMString, can_gc: CanGc) {
153 self.upcast::<Element>()
154 .set_tokenlist_attribute(&local_name!("rel"), rel, can_gc);
155 }
156
157 fn RelList(&self, can_gc: CanGc) -> DomRoot<DOMTokenList> {
159 self.rel_list.or_init(|| {
160 DOMTokenList::new(
161 self.upcast(),
162 &local_name!("rel"),
163 Some(vec![
164 Atom::from("noopener"),
165 Atom::from("noreferrer"),
166 Atom::from("opener"),
167 ]),
168 can_gc,
169 )
170 })
171 }
172
173 make_getter!(Coords, "coords");
175
176 make_setter!(SetCoords, "coords");
178
179 make_getter!(Name, "name");
181
182 make_atomic_setter!(SetName, "name");
184
185 make_getter!(Rev, "rev");
187
188 make_setter!(SetRev, "rev");
190
191 make_getter!(Shape, "shape");
193
194 make_setter!(SetShape, "shape");
196
197 make_getter!(Target, "target");
199
200 make_setter!(SetTarget, "target");
202
203 fn Href(&self) -> USVString {
205 self.get_href()
206 }
207
208 fn SetHref(&self, value: USVString, can_gc: CanGc) {
210 self.set_href(value, can_gc);
211 }
212
213 fn Origin(&self) -> USVString {
215 self.get_origin()
216 }
217
218 fn Protocol(&self) -> USVString {
220 self.get_protocol()
221 }
222
223 fn SetProtocol(&self, value: USVString, can_gc: CanGc) {
225 self.set_protocol(value, can_gc);
226 }
227
228 fn Password(&self) -> USVString {
230 self.get_password()
231 }
232
233 fn SetPassword(&self, value: USVString, can_gc: CanGc) {
235 self.set_password(value, can_gc);
236 }
237
238 fn Hash(&self) -> USVString {
240 self.get_hash()
241 }
242
243 fn SetHash(&self, value: USVString, can_gc: CanGc) {
245 self.set_hash(value, can_gc);
246 }
247
248 fn Host(&self) -> USVString {
250 self.get_host()
251 }
252
253 fn SetHost(&self, value: USVString, can_gc: CanGc) {
255 self.set_host(value, can_gc);
256 }
257
258 fn Hostname(&self) -> USVString {
260 self.get_hostname()
261 }
262
263 fn SetHostname(&self, value: USVString, can_gc: CanGc) {
265 self.set_hostname(value, can_gc);
266 }
267
268 fn Port(&self) -> USVString {
270 self.get_port()
271 }
272
273 fn SetPort(&self, value: USVString, can_gc: CanGc) {
275 self.set_port(value, can_gc);
276 }
277
278 fn Pathname(&self) -> USVString {
280 self.get_pathname()
281 }
282
283 fn SetPathname(&self, value: USVString, can_gc: CanGc) {
285 self.set_pathname(value, can_gc);
286 }
287
288 fn Search(&self) -> USVString {
290 self.get_search()
291 }
292
293 fn SetSearch(&self, value: USVString, can_gc: CanGc) {
295 self.set_search(value, can_gc);
296 }
297
298 fn Username(&self) -> USVString {
300 self.get_username()
301 }
302
303 fn SetUsername(&self, value: USVString, can_gc: CanGc) {
305 self.set_username(value, can_gc);
306 }
307
308 fn ReferrerPolicy(&self) -> DOMString {
310 reflect_referrer_policy_attribute(self.upcast::<Element>())
311 }
312
313 make_setter!(SetReferrerPolicy, "referrerpolicy");
315}
316
317impl Activatable for HTMLAnchorElement {
318 fn as_element(&self) -> &Element {
319 self.upcast::<Element>()
320 }
321
322 fn is_instance_activatable(&self) -> bool {
323 self.as_element().has_attribute(&local_name!("href"))
329 }
330
331 fn activation_behavior(&self, event: &Event, target: &EventTarget, _: CanGc) {
333 let element = self.as_element();
334 let mouse_event = event.downcast::<MouseEvent>().unwrap();
335 let mut ismap_suffix = None;
336
337 if let Some(element) = target.downcast::<Element>() {
340 if target.is::<HTMLImageElement>() && element.has_attribute(&local_name!("ismap")) {
341 let target_node = element.upcast::<Node>();
342 let rect = target_node.border_box().unwrap_or_default();
343 ismap_suffix = Some(format!(
344 "?{},{}",
345 mouse_event.ClientX().to_f32().unwrap() - rect.origin.x.to_f32_px(),
346 mouse_event.ClientY().to_f32().unwrap() - rect.origin.y.to_f32_px()
347 ))
348 }
349 }
350
351 follow_hyperlink(element, self.relations.get(), ismap_suffix);
354 }
355}