Skip to main content

script/dom/
namednodemap.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5use dom_struct::dom_struct;
6use html5ever::LocalName;
7use js::context::JSContext;
8use script_bindings::reflector::{Reflector, reflect_dom_object};
9
10use crate::dom::attr::Attr;
11use crate::dom::bindings::codegen::Bindings::ElementBinding::ElementMethods;
12use crate::dom::bindings::codegen::Bindings::NamedNodeMapBinding::NamedNodeMapMethods;
13use crate::dom::bindings::domname::namespace_from_domstring;
14use crate::dom::bindings::error::{Error, Fallible};
15use crate::dom::bindings::root::{Dom, DomRoot};
16use crate::dom::bindings::str::DOMString;
17use crate::dom::element::Element;
18use crate::dom::window::Window;
19use crate::script_runtime::CanGc;
20
21#[dom_struct]
22pub(crate) struct NamedNodeMap {
23    reflector_: Reflector,
24    owner: Dom<Element>,
25}
26
27impl NamedNodeMap {
28    fn new_inherited(elem: &Element) -> NamedNodeMap {
29        NamedNodeMap {
30            reflector_: Reflector::new(),
31            owner: Dom::from_ref(elem),
32        }
33    }
34
35    pub(crate) fn new(window: &Window, elem: &Element, can_gc: CanGc) -> DomRoot<NamedNodeMap> {
36        reflect_dom_object(Box::new(NamedNodeMap::new_inherited(elem)), window, can_gc)
37    }
38}
39
40impl NamedNodeMapMethods<crate::DomTypeHolder> for NamedNodeMap {
41    /// <https://dom.spec.whatwg.org/#dom-namednodemap-length>
42    fn Length(&self) -> u32 {
43        self.owner.attrs().borrow().len() as u32
44    }
45
46    /// <https://dom.spec.whatwg.org/#dom-namednodemap-item>
47    fn Item(&self, cx: &mut JSContext, index: u32) -> Option<DomRoot<Attr>> {
48        let index: usize = index as _;
49        if self.owner.attrs().borrow().len() <= index {
50            None
51        } else {
52            Some(self.owner.attrs().ensure_dom(cx, index, &self.owner))
53        }
54    }
55
56    /// <https://dom.spec.whatwg.org/#dom-namednodemap-getnameditem>
57    fn GetNamedItem(&self, cx: &mut JSContext, name: DOMString) -> Option<DomRoot<Attr>> {
58        self.owner.get_attribute_by_name(cx, name)
59    }
60
61    /// <https://dom.spec.whatwg.org/#dom-namednodemap-getnameditemns>
62    fn GetNamedItemNS(
63        &self,
64        cx: &mut JSContext,
65        namespace: Option<DOMString>,
66        local_name: DOMString,
67    ) -> Option<DomRoot<Attr>> {
68        let ns = namespace_from_domstring(namespace);
69        self.owner
70            .get_attribute_with_namespace(cx, &ns, &LocalName::from(local_name))
71    }
72
73    /// <https://dom.spec.whatwg.org/#dom-namednodemap-setnameditem>
74    fn SetNamedItem(&self, cx: &mut JSContext, attr: &Attr) -> Fallible<Option<DomRoot<Attr>>> {
75        self.owner.SetAttributeNode(cx, attr)
76    }
77
78    /// <https://dom.spec.whatwg.org/#dom-namednodemap-setnameditemns>
79    fn SetNamedItemNS(&self, cx: &mut JSContext, attr: &Attr) -> Fallible<Option<DomRoot<Attr>>> {
80        self.SetNamedItem(cx, attr)
81    }
82
83    /// <https://dom.spec.whatwg.org/#dom-namednodemap-removenameditem>
84    fn RemoveNamedItem(&self, cx: &mut JSContext, name: DOMString) -> Fallible<DomRoot<Attr>> {
85        let name = self.owner.parsed_name(name);
86        self.owner
87            .remove_attribute_by_name(cx, &name)
88            .ok_or(Error::NotFound(None))
89    }
90
91    /// <https://dom.spec.whatwg.org/#dom-namednodemap-removenameditemns>
92    fn RemoveNamedItemNS(
93        &self,
94        cx: &mut JSContext,
95        namespace: Option<DOMString>,
96        local_name: DOMString,
97    ) -> Fallible<DomRoot<Attr>> {
98        let ns = namespace_from_domstring(namespace);
99        self.owner
100            .remove_attribute(cx, &ns, &LocalName::from(local_name))
101            .ok_or(Error::NotFound(None))
102    }
103
104    /// <https://dom.spec.whatwg.org/#dom-namednodemap-item>
105    fn IndexedGetter(&self, cx: &mut JSContext, index: u32) -> Option<DomRoot<Attr>> {
106        self.Item(cx, index)
107    }
108
109    // check-tidy: no specs after this line
110    fn NamedGetter(&self, cx: &mut JSContext, name: DOMString) -> Option<DomRoot<Attr>> {
111        self.GetNamedItem(cx, name)
112    }
113
114    /// <https://heycam.github.io/webidl/#dfn-supported-property-names>
115    fn SupportedPropertyNames(&self) -> Vec<DOMString> {
116        let mut names = vec![];
117        let html_element_in_html_document = self.owner.html_element_in_html_document();
118        for attr in self.owner.attrs().borrow().iter() {
119            let s = &**attr.name();
120            if html_element_in_html_document && !s.bytes().all(|b| b.to_ascii_lowercase() == b) {
121                continue;
122            }
123
124            if !names.iter().any(|name| name == s) {
125                names.push(DOMString::from(s));
126            }
127        }
128        names
129    }
130}