avm2: Make XML [[Delete]] follow the spec more closely
This commit is contained in:
parent
c869505e88
commit
a4f03173c2
|
@ -636,6 +636,7 @@ impl<'gc> TObject<'gc> for XmlObject<'gc> {
|
|||
}
|
||||
}
|
||||
|
||||
// ECMA-357 9.1.1.3 [[Delete]] (P)
|
||||
fn delete_property_local(
|
||||
self,
|
||||
activation: &mut Activation<'_, 'gc>,
|
||||
|
@ -643,40 +644,71 @@ impl<'gc> TObject<'gc> for XmlObject<'gc> {
|
|||
) -> Result<bool, Error<'gc>> {
|
||||
let name = handle_input_multiname(name.clone(), activation);
|
||||
|
||||
if name.has_explicit_namespace() {
|
||||
return Err(format!(
|
||||
"Can not set property {:?} with an explicit namespace yet",
|
||||
name
|
||||
)
|
||||
.into());
|
||||
// 1. If ToString(ToUint32(P)) == P, throw a TypeError exception
|
||||
// NOTE: This doesn't actually throw in Flash.
|
||||
if let Some(local_name) = name.local_name() {
|
||||
if local_name.parse::<usize>().is_ok() {
|
||||
return Ok(true);
|
||||
}
|
||||
}
|
||||
|
||||
let mc = activation.context.gc_context;
|
||||
let node = self.0.node.get();
|
||||
let mut kind = node.kind_mut(mc);
|
||||
let E4XNodeKind::Element {
|
||||
children,
|
||||
attributes,
|
||||
..
|
||||
} = &mut *kind
|
||||
|
||||
// 2. Let n = ToXMLName(P)
|
||||
|
||||
// 3. If Type(n) is AttributeName
|
||||
if name.is_attribute() {
|
||||
let E4XNodeKind::Element { attributes, .. } = &mut *node.kind_mut(activation.gc())
|
||||
else {
|
||||
return Ok(false);
|
||||
return Ok(true);
|
||||
};
|
||||
|
||||
let retain_non_matching = |node: &E4XNode<'gc>| {
|
||||
if node.matches_name(&name) {
|
||||
node.set_parent(None, mc);
|
||||
// 3.a. For each a in x.[[Attributes]]
|
||||
attributes.retain(|attr| {
|
||||
// 3.a.i. If ((n.[[Name]].localName == "*") or
|
||||
// (n.[[Name]].localName == a.[[Name]].localName))
|
||||
// and ((n.[[Name]].uri == null) or (n.[[Name]].uri == a.[[Name]].uri))
|
||||
if attr.matches_name(&name) {
|
||||
// 3.a.i.1. Let a.[[Parent]] = null
|
||||
attr.set_parent(None, activation.gc());
|
||||
// 3.a.i.2. Remove the attribute a from x.[[Attributes]]
|
||||
false
|
||||
} else {
|
||||
true
|
||||
}
|
||||
});
|
||||
|
||||
// 3.b. Return true
|
||||
return Ok(true);
|
||||
}
|
||||
|
||||
let E4XNodeKind::Element { children, .. } = &mut *node.kind_mut(activation.gc()) else {
|
||||
return Ok(true);
|
||||
};
|
||||
|
||||
if name.is_attribute() {
|
||||
attributes.retain(retain_non_matching);
|
||||
// 4. Let dp = 0
|
||||
// 5. For q = 0 to x.[[Length]]-1
|
||||
children.retain(|child| {
|
||||
// 5.a. If ((n.localName == "*")
|
||||
// or (x[q].[[Class]] == "element" and x[q].[[Name]].localName == n.localName))
|
||||
// and ((n.uri == null) or (x[q].[[Class]] == “element” and n.uri == x[q].[[Name]].uri ))
|
||||
let should_retain = if name.is_any_name() {
|
||||
false
|
||||
} else if child.is_element() {
|
||||
!child.matches_name(&name)
|
||||
} else {
|
||||
children.retain(retain_non_matching);
|
||||
true
|
||||
};
|
||||
|
||||
if !should_retain {
|
||||
child.set_parent(None, activation.gc());
|
||||
}
|
||||
|
||||
should_retain
|
||||
});
|
||||
|
||||
// 6. Let x.[[Length]] = x.[[Length]] - dp
|
||||
// 7. Return true.
|
||||
Ok(true)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue