script/dom/html/
htmlbaseelement.rs1use dom_struct::dom_struct;
6use html5ever::{LocalName, Prefix, local_name, ns};
7use js::rust::HandleObject;
8use servo_url::ServoUrl;
9
10use crate::dom::attr::Attr;
11use crate::dom::bindings::codegen::Bindings::HTMLBaseElementBinding::HTMLBaseElementMethods;
12use crate::dom::bindings::inheritance::Castable;
13use crate::dom::bindings::root::DomRoot;
14use crate::dom::bindings::str::DOMString;
15use crate::dom::document::Document;
16use crate::dom::element::{AttributeMutation, Element};
17use crate::dom::html::htmlelement::HTMLElement;
18use crate::dom::node::{BindContext, Node, NodeTraits, UnbindContext};
19use crate::dom::virtualmethods::VirtualMethods;
20use crate::script_runtime::CanGc;
21
22#[dom_struct]
23pub(crate) struct HTMLBaseElement {
24 htmlelement: HTMLElement,
25}
26
27impl HTMLBaseElement {
28 fn new_inherited(
29 local_name: LocalName,
30 prefix: Option<Prefix>,
31 document: &Document,
32 ) -> HTMLBaseElement {
33 HTMLBaseElement {
34 htmlelement: HTMLElement::new_inherited(local_name, prefix, document),
35 }
36 }
37
38 #[cfg_attr(crown, allow(crown::unrooted_must_root))]
39 pub(crate) fn new(
40 local_name: LocalName,
41 prefix: Option<Prefix>,
42 document: &Document,
43 proto: Option<HandleObject>,
44 can_gc: CanGc,
45 ) -> DomRoot<HTMLBaseElement> {
46 Node::reflect_node_with_proto(
47 Box::new(HTMLBaseElement::new_inherited(local_name, prefix, document)),
48 document,
49 proto,
50 can_gc,
51 )
52 }
53
54 pub(crate) fn frozen_base_url(&self) -> ServoUrl {
56 let href = self
57 .upcast::<Element>()
58 .get_attribute(&ns!(), &local_name!("href"))
59 .expect(
60 "The frozen base url is only defined for base elements \
61 that have a base url.",
62 );
63 let document = self.owner_document();
64 let base = document.fallback_base_url();
65 let parsed = base.join(&href.value());
66 parsed.unwrap_or(base)
67 }
68
69 pub(crate) fn bind_unbind(&self, tree_in_doc: bool) {
72 if !tree_in_doc || self.upcast::<Node>().containing_shadow_root().is_some() {
73 return;
74 }
75
76 if self.upcast::<Element>().has_attribute(&local_name!("href")) {
77 let document = self.owner_document();
78 document.refresh_base_element();
79 }
80 }
81}
82
83impl HTMLBaseElementMethods<crate::DomTypeHolder> for HTMLBaseElement {
84 fn Href(&self) -> DOMString {
86 let document = self.owner_document();
88
89 let attr = self
91 .upcast::<Element>()
92 .get_attribute(&ns!(), &local_name!("href"));
93 let value = attr.as_ref().map(|attr| attr.value());
94 let url = value.as_ref().map_or("", |value| &**value);
95
96 let url_record = document.fallback_base_url().join(url);
98
99 match url_record {
100 Err(_) => {
101 url.into()
103 },
104 Ok(url_record) => {
105 url_record.into_string().into()
107 },
108 }
109 }
110
111 make_setter!(SetHref, "href");
113}
114
115impl VirtualMethods for HTMLBaseElement {
116 fn super_type(&self) -> Option<&dyn VirtualMethods> {
117 Some(self.upcast::<HTMLElement>() as &dyn VirtualMethods)
118 }
119
120 fn attribute_mutated(&self, attr: &Attr, mutation: AttributeMutation, can_gc: CanGc) {
121 self.super_type()
122 .unwrap()
123 .attribute_mutated(attr, mutation, can_gc);
124 if *attr.local_name() == local_name!("href") {
125 self.owner_document().refresh_base_element();
126 }
127 }
128
129 fn bind_to_tree(&self, context: &BindContext, can_gc: CanGc) {
130 self.super_type().unwrap().bind_to_tree(context, can_gc);
131 self.bind_unbind(context.tree_is_in_a_document_tree);
132 }
133
134 fn unbind_from_tree(&self, context: &UnbindContext, can_gc: CanGc) {
135 self.super_type().unwrap().unbind_from_tree(context, can_gc);
136 self.bind_unbind(context.tree_is_in_a_document_tree);
137 }
138}