|
2 | 2 |
|
3 | 3 |
|
4 | 4 |
|
| 5 | +use dom::bindings::codegen::Bindings::CharacterDataBinding::CharacterDataMethods; |
5 | 6 | use dom::bindings::codegen::Bindings::NodeBinding::NodeConstants;
|
6 | 7 | use dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
|
7 | 8 | use dom::bindings::codegen::Bindings::NodeListBinding::NodeListMethods;
|
8 | 9 | use dom::bindings::codegen::Bindings::RangeBinding::{self, RangeConstants};
|
9 | 10 | use dom::bindings::codegen::Bindings::RangeBinding::RangeMethods;
|
10 | 11 | use dom::bindings::codegen::Bindings::TextBinding::TextMethods;
|
11 | 12 | use dom::bindings::codegen::Bindings::WindowBinding::WindowMethods;
|
12 |
| -use dom::bindings::codegen::InheritTypes::{NodeCast, TextCast}; |
| 13 | +use dom::bindings::codegen::InheritTypes::{CharacterDataCast, NodeCast, TextCast}; |
13 | 14 | use dom::bindings::error::{Error, ErrorResult, Fallible};
|
14 | 15 | use dom::bindings::error::Error::HierarchyRequest;
|
15 | 16 | use dom::bindings::global::GlobalRef;
|
16 | 17 | use dom::bindings::js::{JS, Root, RootedReference};
|
17 | 18 | use dom::bindings::utils::{Reflector, reflect_dom_object};
|
18 | 19 | use dom::characterdata::CharacterDataTypeId;
|
19 | 20 | use dom::document::{Document, DocumentHelpers};
|
| 21 | +use dom::documentfragment::DocumentFragment; |
20 | 22 | use dom::node::{Node, NodeHelpers, NodeTypeId};
|
| 23 | + |
21 | 24 | use std::cell::RefCell;
|
22 | 25 | use std::cmp::{Ord, Ordering, PartialEq, PartialOrd};
|
23 | 26 | use std::rc::Rc;
|
@@ -60,6 +63,25 @@ impl Range {
|
60 | 63 | let document = global.as_window().Document();
|
61 | 64 | Ok(Range::new_with_doc(document.r()))
|
62 | 65 | }
|
| 66 | + |
| 67 | + |
| 68 | + fn contains(&self, node: &Node) -> bool { |
| 69 | + let inner = self.inner.borrow(); |
| 70 | + let start = &inner.start; |
| 71 | + let end = &inner.end; |
| 72 | + match (bp_position(node, 0, start.node().r(), start.offset()), |
| 73 | + bp_position(node, node.len(), end.node().r(), end.offset())) { |
| 74 | + (Some(Ordering::Greater), Some(Ordering::Less)) => true, |
| 75 | + _ => false |
| 76 | + } |
| 77 | + } |
| 78 | + |
| 79 | + |
| 80 | + fn partially_contains(&self, node: &Node) -> bool { |
| 81 | + let inner = self.inner.borrow(); |
| 82 | + inner.start.node().inclusive_ancestors().any(|n| n.r() == node) != |
| 83 | + inner.end.node().inclusive_ancestors().any(|n| n.r() == node) |
| 84 | + } |
63 | 85 | }
|
64 | 86 |
|
65 | 87 | pub trait RangeHelpers<'a> {
|
@@ -288,6 +310,145 @@ impl<'a> RangeMethods for &'a Range {
|
288 | 310 | }
|
289 | 311 |
|
290 | 312 |
|
| 313 | + |
| 314 | + fn CloneContents(self) -> Fallible<Root<DocumentFragment>> { |
| 315 | + let inner = self.inner.borrow(); |
| 316 | + let start = &inner.start; |
| 317 | + let end = &inner.end; |
| 318 | + |
| 319 | + |
| 320 | + let start_node = start.node(); |
| 321 | + let start_offset = start.offset(); |
| 322 | + let end_node = end.node(); |
| 323 | + let end_offset = end.offset(); |
| 324 | + |
| 325 | + |
| 326 | + let fragment = DocumentFragment::new(start_node.owner_doc().r()); |
| 327 | + |
| 328 | + |
| 329 | + if start == end { |
| 330 | + return Ok(fragment); |
| 331 | + } |
| 332 | + |
| 333 | + if end_node == start_node { |
| 334 | + if let Some(text) = CharacterDataCast::to_ref(start_node.r()) { |
| 335 | + |
| 336 | + let clone = start_node.CloneNode(true); |
| 337 | + |
| 338 | + let text = text.SubstringData(start_offset, end_offset - start_offset); |
| 339 | + CharacterDataCast::to_ref(clone.r()).unwrap().SetData(text.unwrap()); |
| 340 | + |
| 341 | + try!(NodeCast::from_ref(fragment.r()).AppendChild(clone.r())); |
| 342 | + |
| 343 | + return Ok(fragment); |
| 344 | + } |
| 345 | + } |
| 346 | + |
| 347 | + |
| 348 | + let common_ancestor = self.CommonAncestorContainer(); |
| 349 | + |
| 350 | + let first_contained_child = |
| 351 | + if start_node.is_inclusive_ancestor_of(end_node.r()) { |
| 352 | + |
| 353 | + None |
| 354 | + } else { |
| 355 | + |
| 356 | + common_ancestor.children() |
| 357 | + .find(|node| Range::partially_contains(self, node)) |
| 358 | + }; |
| 359 | + |
| 360 | + let last_contained_child = |
| 361 | + if end_node.is_inclusive_ancestor_of(start_node.r()) { |
| 362 | + |
| 363 | + None |
| 364 | + } else { |
| 365 | + |
| 366 | + common_ancestor.rev_children() |
| 367 | + .find(|node| Range::partially_contains(self, node)) |
| 368 | + }; |
| 369 | + |
| 370 | + |
| 371 | + let contained_children = |
| 372 | + common_ancestor.children().filter(|n| Range::contains(self, n)); |
| 373 | + |
| 374 | + |
| 375 | + if common_ancestor.children() |
| 376 | + .filter(|n| Range::contains(self, n)) |
| 377 | + .any(|n| n.is_doctype()) { |
| 378 | + return Err(HierarchyRequest); |
| 379 | + } |
| 380 | + |
| 381 | + if let Some(child) = first_contained_child { |
| 382 | + |
| 383 | + if let Some(text) = CharacterDataCast::to_ref(child.r()) { |
| 384 | + assert!(child == start_node); |
| 385 | + |
| 386 | + let clone = start_node.CloneNode(true); |
| 387 | + |
| 388 | + let text = text.SubstringData(start_offset, start_node.len() - start_offset); |
| 389 | + CharacterDataCast::to_ref(clone.r()).unwrap().SetData(text.unwrap()); |
| 390 | + |
| 391 | + try!(NodeCast::from_ref(fragment.r()).AppendChild(clone.r())); |
| 392 | + } else { |
| 393 | + |
| 394 | + let clone = child.CloneNode(false); |
| 395 | + |
| 396 | + try!(NodeCast::from_ref(fragment.r()).AppendChild(clone.r())); |
| 397 | + |
| 398 | + let subrange = Range::new(clone.owner_doc().r(), |
| 399 | + start_node.r(), |
| 400 | + start_offset, |
| 401 | + child.r(), |
| 402 | + child.len()); |
| 403 | + |
| 404 | + let subfragment = try!(subrange.CloneContents()); |
| 405 | + |
| 406 | + try!(clone.AppendChild(NodeCast::from_ref(subfragment.r()))); |
| 407 | + } |
| 408 | + } |
| 409 | + |
| 410 | + |
| 411 | + for child in contained_children { |
| 412 | + |
| 413 | + let clone = child.CloneNode(true); |
| 414 | + |
| 415 | + try!(NodeCast::from_ref(fragment.r()).AppendChild(clone.r())); |
| 416 | + } |
| 417 | + |
| 418 | + if let Some(child) = last_contained_child { |
| 419 | + |
| 420 | + if let Some(text) = CharacterDataCast::to_ref(child.r()) { |
| 421 | + assert!(child == end_node); |
| 422 | + |
| 423 | + let clone = end_node.CloneNode(true); |
| 424 | + |
| 425 | + let text = text.SubstringData(0, end_offset); |
| 426 | + CharacterDataCast::to_ref(clone.r()).unwrap().SetData(text.unwrap()); |
| 427 | + |
| 428 | + try!(NodeCast::from_ref(fragment.r()).AppendChild(clone.r())); |
| 429 | + } else { |
| 430 | + |
| 431 | + let clone = child.CloneNode(false); |
| 432 | + |
| 433 | + try!(NodeCast::from_ref(fragment.r()).AppendChild(clone.r())); |
| 434 | + |
| 435 | + let subrange = Range::new(clone.owner_doc().r(), |
| 436 | + child.r(), |
| 437 | + 0, |
| 438 | + end_node.r(), |
| 439 | + end_offset); |
| 440 | + |
| 441 | + let subfragment = try!(subrange.CloneContents()); |
| 442 | + |
| 443 | + try!(clone.AppendChild(NodeCast::from_ref(subfragment.r()))); |
| 444 | + } |
| 445 | + } |
| 446 | + |
| 447 | + |
| 448 | + Ok(fragment) |
| 449 | + } |
| 450 | + |
| 451 | + |
291 | 452 | fn Detach(self) {
|
292 | 453 |
|
293 | 454 | }
|
|
0 commit comments