script/dom/node/
children_mutation.rs1use std::slice;
6
7use js::context::NoGC;
8
9use crate::dom::Node;
10use crate::dom::bindings::inheritance::Castable;
11use crate::dom::bindings::root::DomRoot;
12use crate::dom::element::Element;
13
14pub(crate) enum ChildrenMutation<'a> {
15 Append {
16 prev: &'a Node,
17 added: &'a [&'a Node],
18 },
19 Insert {
20 prev: &'a Node,
21 added: &'a [&'a Node],
22 next: &'a Node,
23 },
24 Prepend {
25 added: &'a [&'a Node],
26 next: &'a Node,
27 },
28 Replace {
29 prev: Option<&'a Node>,
30 removed: &'a Node,
31 added: &'a [&'a Node],
32 next: Option<&'a Node>,
33 },
34 ReplaceAll {
35 removed: &'a [&'a Node],
36 added: &'a [&'a Node],
37 },
38 ChangeText,
43}
44
45impl<'a> ChildrenMutation<'a> {
46 pub(super) fn insert(
47 prev: Option<&'a Node>,
48 added: &'a [&'a Node],
49 next: Option<&'a Node>,
50 ) -> ChildrenMutation<'a> {
51 match (prev, next) {
52 (None, None) => ChildrenMutation::ReplaceAll {
53 removed: &[],
54 added,
55 },
56 (Some(prev), None) => ChildrenMutation::Append { prev, added },
57 (None, Some(next)) => ChildrenMutation::Prepend { added, next },
58 (Some(prev), Some(next)) => ChildrenMutation::Insert { prev, added, next },
59 }
60 }
61
62 pub(super) fn replace(
63 prev: Option<&'a Node>,
64 removed: &'a Option<&'a Node>,
65 added: &'a [&'a Node],
66 next: Option<&'a Node>,
67 ) -> ChildrenMutation<'a> {
68 if let Some(ref removed) = *removed {
69 if let (None, None) = (prev, next) {
70 ChildrenMutation::ReplaceAll {
71 removed: slice::from_ref(removed),
72 added,
73 }
74 } else {
75 ChildrenMutation::Replace {
76 prev,
77 removed,
78 added,
79 next,
80 }
81 }
82 } else {
83 ChildrenMutation::insert(prev, added, next)
84 }
85 }
86
87 pub(super) fn replace_all(
88 removed: &'a [&'a Node],
89 added: &'a [&'a Node],
90 ) -> ChildrenMutation<'a> {
91 ChildrenMutation::ReplaceAll { removed, added }
92 }
93
94 pub(crate) fn next_child(&self) -> Option<&Node> {
99 match *self {
100 ChildrenMutation::Append { .. } => None,
101 ChildrenMutation::Insert { next, .. } => Some(next),
102 ChildrenMutation::Prepend { next, .. } => Some(next),
103 ChildrenMutation::Replace { next, .. } => next,
104 ChildrenMutation::ReplaceAll { .. } => None,
105 ChildrenMutation::ChangeText => None,
106 }
107 }
108
109 pub(crate) fn modified_edge_element(&self, no_gc: &NoGC) -> Option<DomRoot<Node>> {
116 match *self {
117 ChildrenMutation::Prepend { next, .. } |
119 ChildrenMutation::Replace {
120 prev: None,
121 next: Some(next),
122 ..
123 } => next
124 .inclusively_following_siblings_unrooted(no_gc)
125 .find(|node| node.is::<Element>())
126 .map(|node| node.as_rooted()),
127 ChildrenMutation::Append { prev, .. } |
129 ChildrenMutation::Replace {
130 prev: Some(prev),
131 next: None,
132 ..
133 } => prev
134 .inclusively_preceding_siblings_unrooted(no_gc)
135 .find(|node| node.is::<Element>())
136 .map(|node| node.as_rooted()),
137 ChildrenMutation::Insert { prev, next, .. } |
139 ChildrenMutation::Replace {
140 prev: Some(prev),
141 next: Some(next),
142 ..
143 } => {
144 if prev
145 .inclusively_preceding_siblings_unrooted(no_gc)
146 .all(|node| !node.is::<Element>())
147 {
148 next.inclusively_following_siblings_unrooted(no_gc)
150 .find(|node| node.is::<Element>())
151 .map(|node| node.as_rooted())
152 } else if next
153 .inclusively_following_siblings_unrooted(no_gc)
154 .all(|node| !node.is::<Element>())
155 {
156 prev.inclusively_preceding_siblings_unrooted(no_gc)
158 .find(|node| node.is::<Element>())
159 .map(|node| node.as_rooted())
160 } else {
161 None
162 }
163 },
164
165 ChildrenMutation::Replace {
166 prev: None,
167 next: None,
168 ..
169 } => unreachable!(),
170 ChildrenMutation::ReplaceAll { .. } => None,
171 ChildrenMutation::ChangeText => None,
172 }
173 }
174}