############################## Work with ranges of the tree ############################## A :class:`~turbohtml.Range` marks a run of the tree between two boundary points and copies, moves, deletes, or wraps everything between them. Each boundary is a ``(container, offset)`` pair: the offset indexes the container's children, or its code points when the container is character data. Build one with a starting boundary, then move the end. ******************************** Copy or move a run of siblings ******************************** :meth:`~turbohtml.Range.clone_contents` returns a fragment copying the range without touching the tree; :meth:`~turbohtml.Range.extract_contents` moves the nodes out into the fragment instead, leaving the range collapsed: .. testcode:: from turbohtml import Range doc = turbohtml.parse("
Hello brave World
") text = doc.find("p").children[0] span = Range(text, 6) span.set_end(text, 12) span.delete_contents() print(doc.find("p").html) .. testoutput::Hello World
****************** Wrap a selection ****************** :meth:`~turbohtml.Range.surround_contents` extracts the range, wraps it in a new parent, and puts the parent back where the range was -- splitting the surrounding text as needed: .. testcode:: from turbohtml import Element doc = turbohtml.parse("one two three
") text = doc.find("p").children[0] span = Range(text, 4) span.set_end(text, 7) span.surround_contents(Element("em")) print(doc.find("p").html) .. testoutput::one two three
***************************** Insert a node at a boundary ***************************** :meth:`~turbohtml.Range.insert_node` places a node at the range's start. When that start sits inside a text node the text splits around it: .. testcode:: doc = turbohtml.parse("x
x