I have a scenario where I need to split a node up to a given ancestor, e.g.
<strong>hi there, how <em>are <span>you</span> doing</em> today?</strong>
needs to be split into:
<strong>hi there, how <em>are <span>y</span></em></strong>
and
<strong><em><span>ou</span> doing</em> today?</strong>
How would I go about doing this?
I have a scenario where I need to split a node up to a given ancestor, e.g.
<strong>hi there, how <em>are <span>you</span> doing</em> today?</strong>
needs to be split into:
<strong>hi there, how <em>are <span>y</span></em></strong>
and
<strong><em><span>ou</span> doing</em> today?</strong>
How would I go about doing this?
Share Improve this question edited Aug 30, 2011 at 1:58 asked Aug 30, 2011 at 1:37 user193476user193476 4- based on what criteria? Is this only for this situation or are there other similar places where you would need to do this? – Joseph Marikle Commented Aug 30, 2011 at 1:41
-
Basically, I want to be able to take an offset (1, in this case) from a text node (
you
) and split it up to a given ancestor node (<strong>
). – user193476 Commented Aug 30, 2011 at 1:50 - interesting... but at what point does it stop? in theory you could do this all the way up to the window object. will it always be 2 parent levels deep? – Joseph Marikle Commented Aug 30, 2011 at 1:54
-
I need it to stop at an ancestor node I specify (in this case,
<strong>
), so something likesplitNode(textNode, offset, ancestorNode)
– user193476 Commented Aug 30, 2011 at 1:56
3 Answers
Reset to default 10Here is a solution that will work for modern browsers using Range
. Something similar could be done for IE < 9 using TextRange
, but I use Linux so I don't have easy access to those browsers. I wasn't sure what you wanted the function to do, return the nodes or just do a replace inline. I just took a guess and did the replace inline.
function splitNode(node, offset, limit) {
var parent = limit.parentNode;
var parentOffset = getNodeIndex(parent, limit);
var doc = node.ownerDocument;
var leftRange = doc.createRange();
leftRange.setStart(parent, parentOffset);
leftRange.setEnd(node, offset);
var left = leftRange.extractContents();
parent.insertBefore(left, limit);
}
function getNodeIndex(parent, node) {
var index = parent.childNodes.length;
while (index--) {
if (node === parent.childNodes[index]) {
break;
}
}
return index;
}
Demo: jsbin
It expects a TextNode
for node
, although it will work with an Element
; the offset will just function differently based on the behavior of Range.setStart
See the method Text.splitText
.
Not sure if this helps you, but this is what I came up with...
Pass the function an element and a node tag name string you wish to move up to.
<strong>hi there, how <em>are <span id="span">you</span> doing</em> today?</strong>
<script type="text/javascript">
function findParentNode(element,tagName){
tagName = tagName.toUpperCase();
var parentNode = element.parentNode;
if (parentNode.tagName == tagName){
//Erase data up to and including the node name we passed
console.log('Removing node: '+parentNode.tagName+' DATA: '+parentNode.firstChild.data);
parentNode.firstChild.data = '';
return parentNode;
}
else{
console.log('Removing node: '+parentNode.tagName+' DATA: '+parentNode.firstChild.data);
//Erase the first child's data (the first text node and leave the other nodes intact)
parentNode.firstChild.data = '';
//Move up chain of parents to find the tag we want. Return the results so we can do things with it after
return findParentNode(parentNode, tagName)
}
}
var ourNode = document.getElementById("span");
alert(findParentNode(ourNode,'strong').innerHTML);
</script>