script/dom/
mutationrecord.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, Namespace};
7
8use crate::dom::bindings::codegen::Bindings::MutationRecordBinding::MutationRecord_Binding::MutationRecordMethods;
9use crate::dom::bindings::reflector::{Reflector, reflect_dom_object};
10use crate::dom::bindings::root::{Dom, DomRoot, MutNullableDom};
11use crate::dom::bindings::str::DOMString;
12use crate::dom::node::{Node, NodeTraits};
13use crate::dom::nodelist::NodeList;
14use crate::script_runtime::CanGc;
15
16#[dom_struct]
17pub(crate) struct MutationRecord {
18    reflector_: Reflector,
19    record_type: DOMString,
20    target: Dom<Node>,
21    attribute_name: Option<DOMString>,
22    attribute_namespace: Option<DOMString>,
23    old_value: Option<DOMString>,
24    added_nodes: MutNullableDom<NodeList>,
25    removed_nodes: MutNullableDom<NodeList>,
26    next_sibling: Option<Dom<Node>>,
27    prev_sibling: Option<Dom<Node>>,
28}
29
30impl MutationRecord {
31    #[cfg_attr(crown, allow(crown::unrooted_must_root))]
32    pub(crate) fn attribute_mutated(
33        target: &Node,
34        attribute_name: &LocalName,
35        attribute_namespace: Option<&Namespace>,
36        old_value: Option<DOMString>,
37        can_gc: CanGc,
38    ) -> DomRoot<MutationRecord> {
39        let record = Box::new(MutationRecord::new_inherited(
40            "attributes",
41            target,
42            Some(DOMString::from(&**attribute_name)),
43            attribute_namespace.map(|n| DOMString::from(&**n)),
44            old_value,
45            None,
46            None,
47            None,
48            None,
49        ));
50        reflect_dom_object(record, &*target.owner_window(), can_gc)
51    }
52
53    pub(crate) fn character_data_mutated(
54        target: &Node,
55        old_value: Option<DOMString>,
56        can_gc: CanGc,
57    ) -> DomRoot<MutationRecord> {
58        reflect_dom_object(
59            Box::new(MutationRecord::new_inherited(
60                "characterData",
61                target,
62                None,
63                None,
64                old_value,
65                None,
66                None,
67                None,
68                None,
69            )),
70            &*target.owner_window(),
71            can_gc,
72        )
73    }
74
75    pub(crate) fn child_list_mutated(
76        target: &Node,
77        added_nodes: Option<&[&Node]>,
78        removed_nodes: Option<&[&Node]>,
79        next_sibling: Option<&Node>,
80        prev_sibling: Option<&Node>,
81        can_gc: CanGc,
82    ) -> DomRoot<MutationRecord> {
83        let window = target.owner_window();
84        let added_nodes =
85            added_nodes.map(|list| NodeList::new_simple_list_slice(&window, list, can_gc));
86        let removed_nodes =
87            removed_nodes.map(|list| NodeList::new_simple_list_slice(&window, list, can_gc));
88
89        reflect_dom_object(
90            Box::new(MutationRecord::new_inherited(
91                "childList",
92                target,
93                None,
94                None,
95                None,
96                added_nodes.as_deref(),
97                removed_nodes.as_deref(),
98                next_sibling,
99                prev_sibling,
100            )),
101            &*window,
102            can_gc,
103        )
104    }
105
106    #[allow(clippy::too_many_arguments)]
107    fn new_inherited(
108        record_type: &str,
109        target: &Node,
110        attribute_name: Option<DOMString>,
111        attribute_namespace: Option<DOMString>,
112        old_value: Option<DOMString>,
113        added_nodes: Option<&NodeList>,
114        removed_nodes: Option<&NodeList>,
115        next_sibling: Option<&Node>,
116        prev_sibling: Option<&Node>,
117    ) -> MutationRecord {
118        MutationRecord {
119            reflector_: Reflector::new(),
120            record_type: DOMString::from(record_type),
121            target: Dom::from_ref(target),
122            attribute_name,
123            attribute_namespace,
124            old_value,
125            added_nodes: MutNullableDom::new(added_nodes),
126            removed_nodes: MutNullableDom::new(removed_nodes),
127            next_sibling: next_sibling.map(Dom::from_ref),
128            prev_sibling: prev_sibling.map(Dom::from_ref),
129        }
130    }
131}
132
133impl MutationRecordMethods<crate::DomTypeHolder> for MutationRecord {
134    // https://dom.spec.whatwg.org/#dom-mutationrecord-type
135    fn Type(&self) -> DOMString {
136        self.record_type.clone()
137    }
138
139    // https://dom.spec.whatwg.org/#dom-mutationrecord-target
140    fn Target(&self) -> DomRoot<Node> {
141        DomRoot::from_ref(&*self.target)
142    }
143
144    // https://dom.spec.whatwg.org/#dom-mutationrecord-attributename
145    fn GetAttributeName(&self) -> Option<DOMString> {
146        self.attribute_name.clone()
147    }
148
149    // https://dom.spec.whatwg.org/#dom-mutationrecord-attributenamespace
150    fn GetAttributeNamespace(&self) -> Option<DOMString> {
151        self.attribute_namespace.clone()
152    }
153
154    // https://dom.spec.whatwg.org/#dom-mutationrecord-oldvalue
155    fn GetOldValue(&self) -> Option<DOMString> {
156        self.old_value.clone()
157    }
158
159    // https://dom.spec.whatwg.org/#dom-mutationrecord-addednodes
160    fn AddedNodes(&self) -> DomRoot<NodeList> {
161        self.added_nodes
162            .or_init(|| NodeList::empty(&self.target.owner_window(), CanGc::note()))
163    }
164
165    // https://dom.spec.whatwg.org/#dom-mutationrecord-removednodes
166    fn RemovedNodes(&self) -> DomRoot<NodeList> {
167        self.removed_nodes
168            .or_init(|| NodeList::empty(&self.target.owner_window(), CanGc::note()))
169    }
170
171    // https://dom.spec.whatwg.org/#dom-mutationrecord-previoussibling
172    fn GetPreviousSibling(&self) -> Option<DomRoot<Node>> {
173        self.prev_sibling
174            .as_ref()
175            .map(|node| DomRoot::from_ref(&**node))
176    }
177
178    // https://dom.spec.whatwg.org/#dom-mutationrecord-previoussibling
179    fn GetNextSibling(&self) -> Option<DomRoot<Node>> {
180        self.next_sibling
181            .as_ref()
182            .map(|node| DomRoot::from_ref(&**node))
183    }
184}