By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
434,572 Members | 963 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 434,572 IT Pros & Developers. It's quick & easy.

Traversing the DOM & maintaining node hierarchy

P: n/a
I've been working on something that deals with handling a user's
selection within the DOM and I'm tripping up on one last, but crucial,
detail.
Forgive me for the length of the code, but my question is pretty
straightforward and my brain hasn't been working.

Problem: The way I'm iterating through the nodes doesn't allow me to
preserve the node hierarchy.

Instead of:
<div></div><b></b>text

I want:
<div><b>text</b></div>

function RangeIterator() {
this.onNode = function (str, node) {
commonplaceLogMain.cplNodes += '<' + node.nodeName + '>' + str + '</'
+ node.nodeName + '>' ;
};

this.iterate = function (r) {
var me = this, node = r.startContainer, offset = r.startOffset,
finalNode = r.endContainer, finalOffset = r.endOffset;

function visitNode(node, offset) {
var isFinal = (node == finalNode), lastChildIndex, i, c, str = '';

switch (node.nodeType) {
case 3:
case 4:
case 7:
case 8:
str = node.nodeValue;
if (isFinal) {
str = str.substring(0, finalOffset);
}
if (offset) {
str = str.substring(offset);
}
me.onNode(str, node);
break;
default:
me.onNode(str, node);
lastChildIndex = isFinal ? finalOffset : node.childNodes.length;
for (i = offset, c = node.childNodes.item(i); i < lastChildIndex; c =
c.nextSibling, i++) {
if (!visitNode(c, 0)) {
return false;
}
}
}
return !isFinal;
}

while (visitNode(node, offset)) {
if (!node.nextSibling) {
node = node.parentNode;
offset = node.childNodes.length;
} else {
node = node.nextSibling;
offset = 0;
}
}
return true;
};
}
Feb 4 '08 #1
Share this Question
Share on Google+
4 Replies


P: n/a
On Feb 4, 8:04*am, matth <matt...@gmail.comwrote:
Bummer, the closing tag is the important part! But thanks though, I'll
take a look, it'll be cool to see how you traverse the DOM anyway. I
might learn a thing or two.- Hide quoted text -
Let's say you keep up with your 'opening tags' in a string called
startTags

You could also create a string to keep up with the closing tags called
endTags

endTags = '';

You could have a little function like:

function makeEndTags(tag){
endTags = tag + endTags;
}

Then when you come to a tag, like "<body>", you could do

makeEndTags('</body>')

Then say the next 'tag' is '<div>' do makeEndTags('</div>')

then if the next is '<p>' do makeEndTags('</p>')

so that you construct a string in endTags that looks like this

</p></div></body>

So at the end you print

startTags + endTags and you get

<body><div><p></p></div></body>

And just insert whatever formatting you like in the two strings as you
go.


Feb 4 '08 #2

P: n/a
On Feb 4, 10:42 am, Doug Gunnoe <douggun...@gmail.comwrote:
On Feb 4, 8:04 am, matth <matt...@gmail.comwrote:
Bummer, the closing tag is the important part! But thanks though, I'll
take a look, it'll be cool to see how you traverse the DOM anyway. I
might learn a thing or two.- Hide quoted text -

Let's say you keep up with your 'opening tags' in a string called
startTags

You could also create a string to keep up with the closing tags called
endTags

endTags = '';

You could have a little function like:

function makeEndTags(tag){
endTags = tag + endTags;

}

Then when you come to a tag, like "<body>", you could do

makeEndTags('</body>')

Then say the next 'tag' is '<div>' do makeEndTags('</div>')

then if the next is '<p>' do makeEndTags('</p>')

so that you construct a string in endTags that looks like this

</p></div></body>

So at the end you print

startTags + endTags and you get

<body><div><p></p></div></body>

And just insert whatever formatting you like in the two strings as you
go.
I started out with something very similiar to what you pointed out,
but that solution breaks down once you get to something like this:
<div><b></b></div><div><b></b></div>

When is it the right time to add those end tags? Here's a copy of an
approach that I tried but never finished up:
// TESTING

var allowed_html = new Array('b', 'u', 'i', 'h1', 'h2',
'h3', 'h4', 'code', 'pre', 'a', 'li', 'p', 'br');
var parentNode = node.parentNode;
var open_tags = new Array();
while (parentNode) {
if (in_array(allowed_html, parentNode)) {
if (in_array(open_tags, parentNode) == false)
{
//close old tag
commonplaceLogMain.cplNodes += '</' +
parentNode.nodeName.toLowerCase() + '';
break;
}
if (in_array(open_tags, parentNode)) {
//open new tag
commonplaceLogMain.cplNodes += '<' +
parentNode.nodeName.toLowerCase() + '';
break;
}
}
parentNode = parentNode.parentNode;
}
function in_array (array, value) {
var i;
for (i = 0; i < this.length; i++) {
if (array[i] == value) {
return true;
}
}
return false;
}
Feb 4 '08 #3

P: n/a
On Feb 4, 11:24 am, matth <matt...@gmail.comwrote:
>
I started out with something very similiar to what you pointed out,
but that solution breaks down once you get to something like this:
<div><b></b></div><div><b></b></div>
You're right.
When is it the right time to add those end tags? Here's a copy of an
approach that I tried but never finished up:
// TESTING

var allowed_html = new Array('b', 'u', 'i', 'h1', 'h2',
'h3', 'h4', 'code', 'pre', 'a', 'li', 'p', 'br');
var parentNode = node.parentNode;
var open_tags = new Array();
while (parentNode) {
if (in_array(allowed_html, parentNode)) {
if (in_array(open_tags, parentNode) == false)
{
//close old tag
commonplaceLogMain.cplNodes += '</' +
parentNode.nodeName.toLowerCase() + '';
break;
}
if (in_array(open_tags, parentNode)) {
//open new tag
commonplaceLogMain.cplNodes += '<' +
parentNode.nodeName.toLowerCase() + '';
break;
}
}
parentNode = parentNode.parentNode;
}
function in_array (array, value) {
var i;
for (i = 0; i < this.length; i++) {
if (array[i] == value) {
return true;
}
}
return false;
}
When looking at my example I found a logic error. It does not traverse
back up the tree like it should. Anyway, I thought of the solution but
have not had time try it.

Create an array for the end tags 'stack = []'. When going down the
tree, push the end tags onto the array.

stack.push('</' + node.nodeName + '>');

anytime you move to node.nextSibling or node.parentNode do stack.pop()
and add that to the string.

This way it should only add the end tags at the right time.


Feb 5 '08 #4

P: n/a
When looking at my example I found a logic error. It does not traverse
back up the tree like it should. Anyway, I thought of the solution but
have not had time try it.

Create an array for the end tags 'stack = []'. When going down the
tree, push the end tags onto the array.

stack.push('</' + node.nodeName + '>');

anytime you move to node.nextSibling or node.parentNode do stack.pop()
and add that to the string.

This way it should only add the end tags at the right time.
matth,

I don't know if you ever found a solution to this, but it was a pretty
good problem.

No doubt one that was already solved a thousand times, but hey, what
is time for anyway, right? :)

So I finally got a chance to try my use of a stack to track the end
tags and insert them at the right time and I think it works.

http://polisick.com/domTraverseExample.html

Doug
Feb 12 '08 #5

This discussion thread is closed

Replies have been disabled for this discussion.