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 pub(crate) fn new(
39 local_name: LocalName,
40 prefix: Option<Prefix>,
41 document: &Document,
42 proto: Option<HandleObject>,
43 can_gc: CanGc,
44 ) -> DomRoot<HTMLBaseElement> {
45 Node::reflect_node_with_proto(
46 Box::new(HTMLBaseElement::new_inherited(local_name, prefix, document)),
47 document,
48 proto,
49 can_gc,
50 )
51 }
52
53 pub(crate) fn frozen_base_url(&self) -> ServoUrl {
55 let href = self
56 .upcast::<Element>()
57 .get_attribute(&ns!(), &local_name!("href"))
58 .expect(
59 "The frozen base url is only defined for base elements \
60 that have a base url.",
61 );
62 let document = self.owner_document();
63 let base = document.fallback_base_url();
64 let parsed = base.join(&href.value());
65 parsed.unwrap_or(base)
66 }
67
68 pub(crate) fn bind_unbind(&self, tree_in_doc: bool) {
71 if !tree_in_doc || self.upcast::<Node>().containing_shadow_root().is_some() {
72 return;
73 }
74
75 if self.upcast::<Element>().has_attribute(&local_name!("href")) {
76 let document = self.owner_document();
77 document.refresh_base_element();
78 }
79 }
80}
81
82impl HTMLBaseElementMethods<crate::DomTypeHolder> for HTMLBaseElement {
83 fn Href(&self) -> DOMString {
85 let document = self.owner_document();
87
88 let attr = self
90 .upcast::<Element>()
91 .get_attribute(&ns!(), &local_name!("href"));
92 let value = attr.as_ref().map(|attr| attr.value());
93 let url = value.as_ref().map_or("", |value| &**value);
94
95 let url_record = document.fallback_base_url().join(url);
97
98 match url_record {
99 Err(_) => {
100 url.into()
102 },
103 Ok(url_record) => {
104 url_record.into_string().into()
106 },
107 }
108 }
109
110 make_setter!(SetHref, "href");
112}
113
114impl VirtualMethods for HTMLBaseElement {
115 fn super_type(&self) -> Option<&dyn VirtualMethods> {
116 Some(self.upcast::<HTMLElement>() as &dyn VirtualMethods)
117 }
118
119 fn attribute_mutated(&self, attr: &Attr, mutation: AttributeMutation, can_gc: CanGc) {
120 self.super_type()
121 .unwrap()
122 .attribute_mutated(attr, mutation, can_gc);
123 if *attr.local_name() == local_name!("href") {
124 self.owner_document().refresh_base_element();
125 }
126 }
127
128 fn bind_to_tree(&self, context: &BindContext, can_gc: CanGc) {
129 self.super_type().unwrap().bind_to_tree(context, can_gc);
130 self.bind_unbind(context.tree_is_in_a_document_tree);
131 }
132
133 fn unbind_from_tree(&self, context: &UnbindContext, can_gc: CanGc) {
134 self.super_type().unwrap().unbind_from_tree(context, can_gc);
135 self.bind_unbind(context.tree_is_in_a_document_tree);
136 }
137}