diff options
author | bors-servo <lbergstrom+bors@mozilla.com> | 2015-11-25 19:55:02 +0530 |
---|---|---|
committer | bors-servo <lbergstrom+bors@mozilla.com> | 2015-11-25 19:55:02 +0530 |
commit | e7b19249489eff7a7fd49bf458ee7bd681f8ad13 (patch) | |
tree | e8a3549701e0a1cdf23d47fa8a4184934528c279 /components/script/dom/range.rs | |
parent | 66848048465f5fee6c65eea1c0d0050b8fa27528 (diff) | |
parent | 25b7c9523c535ca6b57d0c9286a51cdf396fac8c (diff) | |
download | servo-e7b19249489eff7a7fd49bf458ee7bd681f8ad13.tar.gz servo-e7b19249489eff7a7fd49bf458ee7bd681f8ad13.zip |
Auto merge of #6826 - dzbarsky:deletecontents, r=jdm
Implement Range#deleteContents
Sadly calling ExtractContents and discarding the result doesn't do the right thing.
It may be worth having a CutContents method that takes an `Option<DocumentFragment>` and switch the behavior based on it, to share the code between DeleteContents and ExtractContents, like what Gecko does. Maybe a followup.
<!-- Reviewable:start -->
[<img src="https://reviewable.io/review_button.png" height=40 alt="Review on Reviewable"/>](https://reviewable.io/reviews/servo/servo/6826)
<!-- Reviewable:end -->
Diffstat (limited to 'components/script/dom/range.rs')
-rw-r--r-- | components/script/dom/range.rs | 75 |
1 files changed, 75 insertions, 0 deletions
diff --git a/components/script/dom/range.rs b/components/script/dom/range.rs index 6175ba4383e..efb27e3cfcd 100644 --- a/components/script/dom/range.rs +++ b/components/script/dom/range.rs @@ -16,6 +16,7 @@ use dom::bindings::inheritance::Castable; use dom::bindings::inheritance::{CharacterDataTypeId, NodeTypeId}; use dom::bindings::js::{JS, MutHeap, Root, RootedReference}; use dom::bindings::reflector::{Reflector, reflect_dom_object}; +use dom::bindings::trace::RootedVec; use dom::characterdata::CharacterData; use dom::document::Document; use dom::documentfragment::DocumentFragment; @@ -709,6 +710,80 @@ impl RangeMethods for Range { Ok(()) } + // https://dom.spec.whatwg.org/#dom-range-deletecontents + fn DeleteContents(&self) -> ErrorResult { + // Step 1. + if self.Collapsed() { + return Ok(()); + } + + // Step 2. + let start_node = self.StartContainer(); + let end_node = self.EndContainer(); + let start_offset = self.StartOffset(); + let end_offset = self.EndOffset(); + + // Step 3. + if start_node == end_node { + if let Some(text) = start_node.downcast::<CharacterData>() { + return text.ReplaceData(start_offset, + end_offset - start_offset, + DOMString::from("")); + } + } + + // Step 4. + let mut contained_children: RootedVec<JS<Node>> = RootedVec::new(); + let ancestor = self.CommonAncestorContainer(); + + for child in start_node.following_nodes(ancestor.r()) { + if self.contains(child.r()) && + !contained_children.contains(&JS::from_ref(child.GetParentNode().unwrap().r())) { + contained_children.push(JS::from_ref(child.r())); + } + } + + let (new_node, new_offset) = if start_node.is_inclusive_ancestor_of(end_node.r()) { + // Step 5. + (Root::from_ref(start_node.r()), start_offset) + } else { + // Step 6. + fn compute_reference(start_node: &Node, end_node: &Node) -> (Root<Node>, u32) { + let mut reference_node = Root::from_ref(start_node); + while let Some(parent) = reference_node.GetParentNode() { + if parent.is_inclusive_ancestor_of(end_node) { + return (parent, reference_node.index()) + } + reference_node = parent; + } + panic!() + } + + compute_reference(start_node.r(), end_node.r()) + }; + + // Step 7. + if let Some(text) = start_node.downcast::<CharacterData>() { + try!(text.ReplaceData(start_offset, + start_node.len() - start_offset, + DOMString::from(""))); + } + + // Step 8. + for child in contained_children.r() { + child.remove_self(); + } + + // Step 9. + if let Some(text) = end_node.downcast::<CharacterData>() { + try!(text.ReplaceData(0, end_offset, DOMString::from(""))); + } + + // Step 10. + try!(self.SetStart(new_node.r(), new_offset)); + self.SetEnd(new_node.r(), new_offset) + } + // https://dom.spec.whatwg.org/#dom-range-surroundcontents fn SurroundContents(&self, new_parent: &Node) -> ErrorResult { // Step 1. |