diff options
Diffstat (limited to 'components/script/dom/range.rs')
-rw-r--r-- | components/script/dom/range.rs | 95 |
1 files changed, 91 insertions, 4 deletions
diff --git a/components/script/dom/range.rs b/components/script/dom/range.rs index 78f1e9ba6ab..e94fd2d9e9f 100644 --- a/components/script/dom/range.rs +++ b/components/script/dom/range.rs @@ -4,17 +4,20 @@ use dom::bindings::codegen::Bindings::NodeBinding::NodeConstants; use dom::bindings::codegen::Bindings::NodeBinding::NodeMethods; +use dom::bindings::codegen::Bindings::NodeListBinding::NodeListMethods; use dom::bindings::codegen::Bindings::RangeBinding::{self, RangeConstants}; use dom::bindings::codegen::Bindings::RangeBinding::RangeMethods; +use dom::bindings::codegen::Bindings::TextBinding::TextMethods; use dom::bindings::codegen::Bindings::WindowBinding::WindowMethods; -use dom::bindings::codegen::InheritTypes::NodeCast; +use dom::bindings::codegen::InheritTypes::{NodeCast, TextCast}; use dom::bindings::error::{Error, ErrorResult, Fallible}; +use dom::bindings::error::Error::HierarchyRequest; use dom::bindings::global::GlobalRef; -use dom::bindings::js::{JS, Root}; +use dom::bindings::js::{JS, Root, RootedReference}; use dom::bindings::utils::{Reflector, reflect_dom_object}; +use dom::characterdata::CharacterDataTypeId; use dom::document::{Document, DocumentHelpers}; -use dom::node::{Node, NodeHelpers}; - +use dom::node::{Node, NodeHelpers, NodeTypeId}; use std::cell::RefCell; use std::cmp::{Ord, Ordering, PartialEq, PartialOrd}; use std::rc::Rc; @@ -288,6 +291,90 @@ impl<'a> RangeMethods for &'a Range { fn Detach(self) { // This method intentionally left blank. } + + // https://dom.spec.whatwg.org/#dom-range-insertnode + // https://dom.spec.whatwg.org/#concept-range-insert + fn InsertNode(self, node: &Node) -> ErrorResult { + let (start_node, start_offset) = { + let inner = self.inner().borrow(); + let start = &inner.start; + (start.node(), start.offset()) + }; + + // Step 1. + match start_node.type_id() { + // Handled under step 2. + NodeTypeId::CharacterData(CharacterDataTypeId::Text) => (), + NodeTypeId::CharacterData(_) => return Err(HierarchyRequest), + _ => () + } + + // Step 2. + let (reference_node, parent) = + if start_node.type_id() == NodeTypeId::CharacterData(CharacterDataTypeId::Text) { + // Step 3. + let parent = match start_node.GetParentNode() { + Some(parent) => parent, + // Step 1. + None => return Err(HierarchyRequest) + }; + // Step 5. + (Some(Root::from_ref(start_node.r())), parent) + } else { + // Steps 4-5. + let child = start_node.ChildNodes().Item(start_offset); + (child, Root::from_ref(start_node.r())) + }; + + // Step 6. + try!(Node::ensure_pre_insertion_validity(node, + parent.r(), + reference_node.r())); + + // Step 7. + let split_text; + let reference_node = + match TextCast::to_ref(start_node.r()) { + Some(text) => { + split_text = try!(text.SplitText(start_offset)); + let new_reference = NodeCast::from_root(split_text); + assert!(new_reference.GetParentNode().r() == Some(parent.r())); + Some(new_reference) + }, + _ => reference_node + }; + + // Step 8. + let reference_node = if Some(node) == reference_node.r() { + node.GetNextSibling() + } else { + reference_node + }; + + // Step 9. + node.remove_self(); + + // Step 10. + let new_offset = + reference_node.r().map_or(parent.len(), |node| node.index()); + + // Step 11 + let new_offset = new_offset + if node.type_id() == NodeTypeId::DocumentFragment { + node.len() + } else { + 1 + }; + + // Step 12. + try!(Node::pre_insert(node, parent.r(), reference_node.r())); + + // Step 13. + if self.Collapsed() { + self.inner().borrow_mut().set_end(parent.r(), new_offset); + } + + Ok(()) + } } #[derive(JSTraceable)] |