Helpful Information
 
 
Category: DOM and JSON scripting
Good way to flatten a hierarchy?

I've been struggling with a good way to eliminate a node in the middle of a hierarchy, and attach its children to its parent. This is the structure I'm working on:

parent
    theNode
        child
        child
        child

and I want to get

parent
    child
    child
    child

I tried iterating through the NodeList of theNode, but it's live, which is no good for this operation.

Ideas?

You are looking for the DOM2 Traversal interface. Read about it at www.w3.org

Currently, the only browser to support any of it is Mozilla/NS7, and of which is missing the NodeIterator interface (but does have NodeFilter and TreeWalker).

*Very* powerful way of navigating the node hierchy, and is a shame that Microsoft really doesn't seem to care about supporting any DOM2 in IE, among several other powerful standards...

Yes, but for an IE solution, use it's proprietary removeNode() method. It's only paremeter is a boolean value that indicates whether or not the children should be removed as well. 'false' is the default
<div style="color:blue" id="div1" onClick="this.removeNode();">
<span>hello</span><br>
<span>world</span><br>
<div style="color:red" id="div2" onClick="this.removeNode();">
<span>hello</span><br>
<span>world</span><br>
</div>
</div>Pretty durn handy if you ask me, and unlike some of IE's other crap, something I'd like to see in the DOM. Works in IE5+

Note:The node being removed MUST have an ID, otherwise it's children will be removed too.

Node.prototype.removeNode = function() { this.parentNode.removeChild(this) };

Emulates removeNode() when removing all the nodes...

Anyway, I misread your question - DOM2 Traversal is excellent for traversing the DOM, but not manipulating it (it actually is incapable of changing it, you need to use other DOM implementations such as Range or Core for that).

Anyway, assume that refToNode is a reference to the node you want to remove, and reparent its children to its parent:

var parent = refToNode.parentNode;

var range = document.createRange();
range.selectNodeContents(refToNode);
// initializes a range and selects the node's children


parent.replaceChild(range.extractContents(), refToNode);
// remove refToNode's children, return as a doc frag, replace refToNode with the document fragment


This is DOM2 Range mixed in with a touch of DOM2 Core. This only works in Moz.

Well, back again.

My question I think is some what related to this subject.

I need to be able to format or delete nodes that a given range covers.


Example:



Here is the text a user can select:
--------------------------------------------------
Subhead.
This is the paragraph I will be testing today.
Here is the second line of the paragraph. Weeeeee!
--------------------------------------------------

Here is the underling html:
----------------------------------------------------------------
<DIV>Subhead.</DIV>
<DIV>This is the paragraph I will be testing today.</DIV>
<DIV>Here is the second line of the paragraph. Weeeeee!</DIV>
----------------------------------------------------------------

Now say the user selects this text:
---------------------------
be testing today.
Here is the second
---------------------------



I need to grab the any of the nodes that that selection passes over.
So for this example I need to grab these two nodes . . .

<DIV>This is the paragraph I will be testing today.</DIV>
<DIV>Here is the second line of the paragraph. Weeeeee!</DIV>

based on the user selection shown above. Again this is for IE. I've toyed around quite a bit and can't seem to find a way to do this.

var sel = window.getSelection().getRangeAt(0).cloneRange();
sel.setStartBefore(sel.startContainer);
sel.setEndAfter(sel.endContainer);


sel is now the range you desire, in Mozilla at least. IE should have some simple TextRange commands to do the same.

Here is how I got it working in IE, don't know if it's the best but it works.




//Move through all the children.
for (var h=0;h<this.edit.body.children.length;h++) {

//create an empty textRange and move it to enclose the contents of the current child
var childSel = this.edit.selection.createRange();

//move this range to the current child
childSel.moveToElementText(this.edit.body.children[h]);

//Check to see if the selection starts in the current child node.
if(sel.compareEndPoints("StartToEnd", childSel) == -1 &&
(sel.compareEndPoints("StartToStart", childSel) == 1 ||
sel.compareEndPoints("StartToStart", childSel) == 0))
{
//Do whatever to this.edit.body.children[h]
}


//Check to see if the current child node is in the middle of the selection
if(sel.compareEndPoints("StartToEnd", childSel) == -1 &&
sel.compareEndPoints("StartToStart", childSel) == -1 &&
sel.compareEndPoints("EndToStart", childSel) == 1 &&
sel.compareEndPoints("EndToEnd", childSel) == 1)
{
//Do whatever to this.edit.body.children[h]
}

//Check to see if the selection ends in the current child node.
if(sel.compareEndPoints("EndToStart", childSel) == 1 &&
(sel.compareEndPoints("EndToEnd", childSel) == -1 ||
sel.compareEndPoints("EndToEnd", childSel) == 0))
{
//Do whatever to this.edit.body.children[h]
}

}



I could have done it by just checking if the child node was NOT in the selection area but for the sake of making it easy for next person who works with this code to see what is happening, I did it this way.










privacy (GDPR)