/    Sign up×
Community /Pin to ProfileBookmark

Hi,

I am learning JavaScript and I am using Christian Heilmann’s book to do so.

I am struggling on a piece of code.

[code]
closestSibling:function(node,direction){
var tempObj;
if(direction==-1 && node.previousSibling!=null){
tempObj=node.previousSibling;
while(tempObj.nodeType!=1 && tempObj.previousSibling!=null){
tempObj=tempObj.previousSibling;
}
}else if(direction==1 && node.nextSibling!=null){
tempObj=node.nextSibling;
while(tempObj.nodeType!=1 && tempObj.nextSibling!=null){
tempObj=tempObj.nextSibling;
}
}
return tempObj.nodeType==1?tempObj:false;
}
[/code]

I’m actually confused by this:

[code]
while(tempObj.nodeType!=1 && tempObj.previousSibling!=null){
tempObj=tempObj.previousSibling;
}
[/code]

and

[code]
return tempObj.nodeType==1?tempObj:false;
[/code]

Any help or advice would be most appreciated.

to post a comment
JavaScript

46 Comments(s)

Copy linkTweet thisAlerts:
@OverstatementJan 23.2007 — <i>
</i>while(tempObj.nodeType!=1 &amp;&amp; tempObj.previousSibling!=null){
tempObj=tempObj.previousSibling;
}

<i>
</i>while(tempObj is a DOM element and therefore has a previousSibling AND tempObj is NOT the first born)
{
resign tempObj to reference it's older brother/sister;
}

Basically, it makes tempObj point to the first appended element of it's parent (makes tempObj point to the first child of it's parent).
<i>
</i>return tempObj.nodeType==1?tempObj:false;

<i>
</i>if(tempObj is an element node)
return tempObj;
else
return false;

What I don't understand is:
<i>
</i>closestSibling:function(node,direction)
Copy linkTweet thisAlerts:
@NickToyeauthorJan 23.2007 — Its part of a Library of help functions. If you have the book its on page 121 - Beginning JavaScript with DOM Scripting and Ajax.
Copy linkTweet thisAlerts:
@NickToyeauthorJan 23.2007 — Yes but surely:
<i>
</i>while(tempObj.nodeType!=1 &amp;&amp; tempObj.previousSibling!=null){
tempObj=tempObj.previousSibling;
}

is saying while tempObj's node type is not an element and tempObj's previous sibling is not null, the last being a double negative. So if all that is true then tempObj becomes the previousSibling.
Copy linkTweet thisAlerts:
@mrhooJan 23.2007 — The second argument (direction) determines whether you are searching for the [B]next [/B]or [B]previous [/B]element sibling of node. If you pass -1. you search for elements before node, otherwise you look for the nextSibling. The point is to skip over any textNodes and return only elements.

This returns the same value as your more verbose function:
[CODE]function findSib(node,direction){
var X= (direction!=-1)? 'nextSibling': 'previousSibling';
if(node[X]== null) return false;
var sib= node[X];
while(sib){
if(sib.nodeType== 1) return sib;
sib= sib[X];
}
return false;
}[/CODE]
Copy linkTweet thisAlerts:
@NickToyeauthorJan 23.2007 — Sorry, you've just confused me there. I appreciate the help, but it would be more helpful if you could help me with the example I used. My brain isn't quite in synch with JS yet. ?

Also what you are saying isn't what I was stuck about, it was this:
<i>
</i>while(tempObj.nodeType!=1 &amp;&amp; tempObj.previousSibling!=null){
tempObj=tempObj.previousSibling;
}


It seems there is a double negative in there.
Copy linkTweet thisAlerts:
@mrhooJan 23.2007 — while(tempObj.nodeType!=1 && tempObj.previousSibling!=null){

tempObj=tempObj.previousSibling;

}[/QUOTE]


As long as tempObj is NOT an element and there IS a previous sibling,

temObj= the previous sibling.

As soon as temObj finds an element it returns the element-

if it never does, it returns false.
Copy linkTweet thisAlerts:
@NickToyeauthorJan 23.2007 — Well for arguments sake, I have a H3 tag and the function is to find the closestSibling which happens to be the address tag. Now the address tag is an element right?

So what is the purpose of the while loop? Does it keep looping until it finds a node that is an element and that doesn't have a previous sibling?
Copy linkTweet thisAlerts:
@OverstatementJan 23.2007 — Ok, now that I've taken the time to read this function. It makes no sense. It checks for !=1 in the for loop but then checks for ==1 in the return statement. So the only way it will ever return anything other than false would be if it has no siblings (in the direction you asked it to look) or if the sibling adjactent to your node(in the same direction) is an element. You need to check your copy and pasted job carefully because either you or Christian Heilmann is less than sober (or maybe I'm not, maybe).
Copy linkTweet thisAlerts:
@mrhooJan 23.2007 — There can be childNodes of an element that are not elements- there are also textNodes, comments, and cdata nodes. The while loop skips over any nodes that are not elements and returns the first node that IS and element, or false, if it finds none.
Copy linkTweet thisAlerts:
@NickToyeauthorJan 23.2007 — Well thats what I'm concerned about. I don't think there is an error, and I have copied it right. However, you may be slighyly drunk as there is no for loop there. ?
Copy linkTweet thisAlerts:
@OverstatementJan 23.2007 — Damn, that backfired. Still doesn't make sense and I meant the [b]while[/b] loop. I don't use the while loop much anyway, they all look like for loops.
Copy linkTweet thisAlerts:
@NickToyeauthorJan 23.2007 — So is it definitely not a working code? I'm still in the early stages and I am trying to understand the logic on paper before I commit to real code.

So do you think the same as me, and that there are double negatives that don't work?
Copy linkTweet thisAlerts:
@OverstatementJan 23.2007 — Yes, your both drunk. Tell us what you need to function to do and we'll (probably me) will write it up.
Copy linkTweet thisAlerts:
@NickToyeauthorJan 23.2007 — I'm trying to learn with the book. If this code is clearly wrong then I would need to tell the author and see if there has been a correction in the errata.

This is the main function:
<i>
</i>sc = {
init:function(){
sc.head = document.getElementsByTagName('h3')[0];
if(!sc.head){return;}
sc.ad = DOMhelp.closestSibling(sc.head,1);
sc.ad.style.display='none';
var t = DOMhelp.getText(sc.head);
var collapseLink = DOMhelp.createLink('#',t);
sc.head.replaceChild(collapseLink,sc.head.firstChild);
DOMhelp.addEvent(collapseLink,'click',sc.peekaboo,false)
collapseLink.onclick = function(){return;} // Safari Fix
},
peekaboo:function(e){
sc.ad.style.display=sc.ad.style.display=='none'? '':'none';
DOMhelp.cancelLink(e);
}
}
DOMhelp.addEvent(window,'load',sc.init,false);


What it is basically doing is taking this markup:
<i>
</i>&lt;body&gt;
&lt;h3&gt;Contact Details&lt;/h3&gt;
&lt;address&gt;
Awesome Web Production Company&lt;br /&gt;
Going Nowhere Lane 0&lt;br /&gt;
Catch 22&lt;br /&gt;
N4 2XX&lt;br /&gt;
England&lt;br /&gt;
&lt;/address&gt;
&lt;/body&gt;


And turning the H3 element into a link and hiding the address element.

It uses this Help Library code:
<i>
</i>DOMhelp=
{
// Find the last sibling of the current node
lastSibling:function(node){
var tempObj=node.parentNode.lastChild;
while(tempObj.nodeType!=1 &amp;&amp; tempObj.previousSibling!=null){
tempObj=tempObj.previousSibling;
}
return (tempObj.nodeType==1)?tempObj:false;
},

<i> </i>// Find the first sibling of the current node
<i> </i>firstSibling:function(node){
<i> </i> var tempObj=node.parentNode.firstChild;
<i> </i> while(tempObj.nodeType!=1 &amp;&amp; tempObj.nextSibling!=null){
<i> </i> tempObj=tempObj.nextSibling;
<i> </i> }
<i> </i> return (tempObj.nodeType==1)?tempObj:false;
<i> </i>},

<i> </i>// Retrieve the content of the first text node sibling of the current node
<i> </i>getText:function(node){
<i> </i> if(!node.hasChildNodes()){return false;}
<i> </i> var reg=/^s+$/;
<i> </i> var tempObj=node.firstChild;
<i> </i> while(tempObj.nodeType!=3 &amp;&amp; tempObj.nextSibling!=null || reg.test(tempObj.nodeValue)){
<i> </i> tempObj=tempObj.nextSibling;
<i> </i> }
<i> </i> return tempObj.nodeType==3?tempObj.nodeValue:false;
<i> </i>},

<i> </i>// Set the content of the first text node sibling of the current node
<i> </i>setText:function(node,txt){
<i> </i> if(!node.hasChildNodes()){return false;}
<i> </i> var reg=/^s+$/;
<i> </i> var tempObj=node.firstChild;
<i> </i> while(tempObj.nodeType!=3 &amp;&amp; tempObj.nextSibling!=null || reg.test(tempObj.nodeValue)){
<i> </i> tempObj=tempObj.nextSibling;
<i> </i> }
<i> </i> if(tempObj.nodeType==3){tempObj.nodeValue=txt}else{return false;}
<i> </i>},



<i> </i>// Create a new link containing the given text
<i> </i>createLink:function(to,txt){
<i> </i> var tempObj=document.createElement('a');
<i> </i> tempObj.appendChild(document.createTextNode(txt));
<i> </i> tempObj.setAttribute('href',to);
<i> </i> return tempObj;
<i> </i>},

<i> </i>// Create a new element containing the given text
<i> </i>createTextElm:function(elm,txt){
<i> </i> var tempObj=document.createElement(elm);
<i> </i> tempObj.appendChild(document.createTextNode(txt));
<i> </i> return tempObj;
<i> </i>},

<i> </i>// Find the next or previous sibling that is an element and not a text node or line break
<i> </i>closestSibling:function(node,direction){
<i> </i> var tempObj;
<i> </i> if(direction==-1 &amp;&amp; node.previousSibling!=null){
<i> </i> tempObj=node.previousSibling;
<i> </i> while(tempObj.nodeType!=1 &amp;&amp; tempObj.previousSibling!=null){
<i> </i> tempObj=tempObj.previousSibling;
<i> </i> }
<i> </i> }else if(direction==1 &amp;&amp; node.nextSibling!=null){
<i> </i> tempObj=node.nextSibling;
<i> </i> while(tempObj.nodeType!=1 &amp;&amp; tempObj.nextSibling!=null){
<i> </i> tempObj=tempObj.nextSibling;
<i> </i> }
<i> </i> }
<i> </i> return tempObj.nodeType==1?tempObj:false;
<i> </i>},

<i> </i>// Simulate a debugging console to avoid the need for alerts
<i> </i>initDebug:function(){
<i> </i> if(DOMhelp.debug){DOMhelp.stopDebug();}
<i> </i> DOMhelp.debug=document.createElement('div');
<i> </i> DOMhelp.debug.setAttribute('id', DOMhelp.debugWindowId);
<i> </i> document.body.insertBefore(DOMhelp.debug,document.body.firstChild);
<i> </i>},

<i> </i>setDebug:function(bug){
<i> </i> if(!DOMhelp.debug){DOMhelp.initDebug();}
<i> </i> DOMhelp.debug.innerHTML+=bug+'n';
<i> </i>},

<i> </i>stopDebug:function(){
<i> </i> if(DOMhelp.debug){
<i> </i> DOMhelp.debug.parentNode.removeChild(DOMhelp.debug);
<i> </i> DOMhelp.debug=null;
<i> </i> }
<i> </i>},
<i> </i> getKey:function(e){
<i> </i> if(window.event){
<i> </i> var key = window.event.keyCode;
<i> </i> } else if(e){
<i> </i> var key=e.keyCode;
<i> </i> }
<i> </i> return key;
<i> </i> },
<i> </i>/* helper methods */
<i> </i> getTarget:function(e){
<i> </i> var target = window.event ? window.event.srcElement : e ? e.target : null;
<i> </i> if (!target){return false;}
<i> </i> while(target.nodeType!=1 &amp;&amp; target.nodeName.toLowerCase()!='body'){
<i> </i> target=target.parentNode;
<i> </i> }
<i> </i> return target;
<i> </i> },
<i> </i> stopBubble:function(e){
<i> </i> if(window.event &amp;&amp; window.event.cancelBubble){
<i> </i> window.event.cancelBubble = true;
<i> </i> }
<i> </i> if (e &amp;&amp; e.stopPropagation){
<i> </i> e.stopPropagation();
<i> </i> }
<i> </i> },
<i> </i> stopDefault:function(e){
<i> </i> if(window.event &amp;&amp; window.event.returnValue){
<i> </i> window.event.returnValue = false;
<i> </i> }
<i> </i> if (e &amp;&amp; e.preventDefault){
<i> </i> e.preventDefault();
<i> </i> }
<i> </i> },

<i> </i> addEvent: function(elm, evType, fn, useCapture){
<i> </i> if (elm.addEventListener){
<i> </i> elm.addEventListener(evType, fn, useCapture);
<i> </i> return true;
<i> </i> } else if (elm.attachEvent) {
<i> </i> var r = elm.attachEvent('on' + evType, fn);
<i> </i> return r;
<i> </i> } else {
<i> </i> elm['on' + evType] = fn;
<i> </i> }
<i> </i> },

<i> </i> function cssjs(a,o,c1,c2){
<i> </i> switch (a){
<i> </i> case 'swap':
<i> </i> if(!domtab.cssjs('check',o,c1)){
<i> </i> o.className.replace(c2,c1)
<i> </i> }else{
<i> </i> o.className.replace(c1,c2);
<i> </i> }
<i> </i> break;
<i> </i> case 'add':
<i> </i> if(!domtab.cssjs('check',o,c1)){
<i> </i> o.className+=o.className?' '+c1:c1;
<i> </i> }
<i> </i> break;
<i> </i> case 'remove':
<i> </i> var rep=o.className.match(' '+c1)?' '+c1:c1;
<i> </i> o.className=o.className.replace(rep,'');
<i> </i> break;
<i> </i> case 'check':
<i> </i> var found=false;
<i> </i> var temparray=o.className.split(' ');
<i> </i> for(var i=0;i&lt;temparray.length;i++){
<i> </i> if(temparray[i]==c1){found=true;}
<i> </i> }
<i> </i> return found;
<i> </i> break;
<i> </i> }
<i> </i> },

<i> </i> safariClickFix:function(){
<i> </i> return false;
<i> </i> }
<i> </i>}
Copy linkTweet thisAlerts:
@OverstatementJan 23.2007 — Oh wait, the function now makes sense. Yeah, I'm sober, shut up! The loop escapes when it sees that tempObj is an element. So when it exits, tempObj will reference an element. So the while loop is to find the first node that is an element and assign tempObj to it.
Copy linkTweet thisAlerts:
@NickToyeauthorJan 23.2007 — but what about this part

<i>
</i>&amp;&amp; tempObj.previousSibling!=null)
Copy linkTweet thisAlerts:
@OverstatementJan 23.2007 — How are you suppose to set something to tempObj.previousSibling if it has no value? How can you play with your brother/sister if they don't exist?
Copy linkTweet thisAlerts:
@NickToyeauthorJan 23.2007 — This to me says, [B]and tempObj's previousSibling is not null[/B].

Ok, so this says if there is no previous sibling then there is no result and the loop goes on?
Copy linkTweet thisAlerts:
@OverstatementJan 23.2007 — It says

while(there is an older/younger sibling)

{

go up/down the family tree;

}

If there aren't anymore sibling in the direction your traveling, the loop stops traveling (end of the road).
Copy linkTweet thisAlerts:
@NickToyeauthorJan 23.2007 — Ok, and what if there are more siblings? Its trying to find the closest sibling isn't it?

Sorry if I'm being a little dumb, its a learning curve.
Copy linkTweet thisAlerts:
@OverstatementJan 23.2007 — The closest element sibling. The "tempObj's previousSibling is not null" only applies if tempObj is not an element. If tempObj is an element, it would have exited already.
Copy linkTweet thisAlerts:
@NickToyeauthorJan 23.2007 — ok, so say that tempObj is not an element, how will that effect things?
Copy linkTweet thisAlerts:
@OverstatementJan 23.2007 — tempObj is always changing. We are looking for the closest sibling that is an element. Lets say we're going forward/up (direction=1). First, we look at the node and see that the node is not the top branch. So we assign the next node up as tempObj(just to keep track of which tree node we're at, like a reference to a branch). Next, we check if tempObj IS an element. If it is, we return it. If it isn't, we go to the next node in the tree. And we repeat that until either we're at the top of the tree or we find an element.
Copy linkTweet thisAlerts:
@NickToyeauthorJan 23.2007 — Ok, so if tempObj is not an element and is a text node then it will not have a sibling?

I think its going in, slowly. Your a good teacher, despite what your tag says. ?
Copy linkTweet thisAlerts:
@OverstatementJan 23.2007 — Anything can have a sibling. We're just checking that a) we have not already found our element b) we can't go any further because it's the end of the line (tip of the tree).

And I already gave bad advice on this thread.
Copy linkTweet thisAlerts:
@NickToyeauthorJan 23.2007 — Ok, so let me get this straight:

the while loop is checking to see that the tempObj is not an element and it doesn't have a previous sibling, if it doesn't then it gives tempObj the value of the previous tempObj's previousSibling?
Copy linkTweet thisAlerts:
@OverstatementJan 23.2007 — NO! I don't think you understand the concept of null. null means that the variable has no value. If previousSibling has no value, then it means it has no siblings. If previousSibling is not null, it means it has a value which means it has a sibling.
Copy linkTweet thisAlerts:
@NickToyeauthorJan 23.2007 — ah right, so a node with a value will always have a sibling, at least one. What about the html node, that won't have a sibling will it. Just out of curiosity.
Copy linkTweet thisAlerts:
@NickToyeauthorJan 23.2007 — and this part:
<i>
</i>tempObj=tempObj.previousSibling;


is only utilised if tempObj does not equal 1 (element node type) and has a previousSibling?
Copy linkTweet thisAlerts:
@OverstatementJan 23.2007 — Usually (and officially?) no but browsers allow all sorts of strange things happen. What kind of programmer would put more than one HTML node in their page anyway?

Edit: Damn it all, it's page 3...
Copy linkTweet thisAlerts:
@NickToyeauthorJan 23.2007 — Yep, but I think I'm nearly there, was my last eulogy right?
Copy linkTweet thisAlerts:
@OverstatementJan 23.2007 — Yes it was
Copy linkTweet thisAlerts:
@NickToyeauthorJan 23.2007 — So otherwise it just skips on down to:

<i>
</i>return tempObj.nodeType==1?tempObj:false;


If so, what does this mean?
Copy linkTweet thisAlerts:
@OverstatementJan 23.2007 — It just tries to return the right thing. If you notice, the code takes a step (does a tempObj=node.previousSibling before the while loop) to get it started but it doesn't check if it's an element so he does it here. Also, what if we stopped because there weren't any prevousSiblings? We can't return tempObject because it's not an element so instead we return false. So it basically says, "if tempObj is an element, return it. Else, return false".
Copy linkTweet thisAlerts:
@NickToyeauthorJan 23.2007 — right, Eureka!!!

I do believe that has sunk in, right need to make some notes quick.

?
Copy linkTweet thisAlerts:
@NickToyeauthorJan 23.2007 — One more thing. If the while loop finds that there are no nodes with the type element, does it then just end or will it keep looping till it finds a node with an element?
Copy linkTweet thisAlerts:
@OverstatementJan 23.2007 — It will keep looking until it finds one or can't look anymore (end of tree).
Copy linkTweet thisAlerts:
@NickToyeauthorJan 23.2007 — So if it ends up at this code:

<i>
</i>tempObj=tempObj.previousSibling;


It will keep looping?

Sorry am I going backwards?
Copy linkTweet thisAlerts:
@OverstatementJan 23.2007 — Well, you just assigned tempObj to a completely different object which hasn't been checked to see if it's an element or an ending branch yet. It can't know to continue until this new tempObj is checked.
Copy linkTweet thisAlerts:
@NickToyeauthorJan 23.2007 — so how does it exit the loop?

Or should I say how does the loop successfully resolve?
Copy linkTweet thisAlerts:
@OverstatementJan 23.2007 — It will exit when the stuff in the brackets after the keyword 'while' resolves to false. Now you're going in circles, get more experince and these things will come to you. Also, try reading something else on stuff you don't get. Two sources are better than one.
Copy linkTweet thisAlerts:
@NickToyeauthorJan 23.2007 — Right so it goes through the while loop then steps down to:
<i>
</i>return tempObj.nodeType==1?tempObj.false;
Copy linkTweet thisAlerts:
@OverstatementJan 23.2007 — Yes, that's how the if statement works...now you're pushing it.
Copy linkTweet thisAlerts:
@NickToyeauthorJan 23.2007 — What do you mean? Now I'm pushing it?
Copy linkTweet thisAlerts:
@OverstatementJan 23.2007 — I understand if you don't yet think like a programmer and need help on logic problems. But I don't want you to get dependant on me for asking how Javascript statements work when you can read it off a website. Yes, it does jump down because that's how the 'else if' statement works, [url=http://www.w3schools.com/js/js_if_else.asp]see?[/url] You can't excute more than one else if statement at a time so it drops to the end of the entire chain of if statements.

ARGH! Fourth Page!
Copy linkTweet thisAlerts:
@NickToyeauthorJan 23.2007 — I understand if else statements, I do quite a lot of XSLT, so I understand the concepts. Its just I'm struggling to grasp the while loop.
×

Success!

Help @NickToye spread the word by sharing this article on Twitter...

Tweet This
Sign in
Forgot password?
Sign in with TwitchSign in with GithubCreate Account
about: ({
version: 0.1.9 BETA 5.25,
whats_new: community page,
up_next: more Davinci•003 tasks,
coming_soon: events calendar,
social: @webDeveloperHQ
});

legal: ({
terms: of use,
privacy: policy
});
changelog: (
version: 0.1.9,
notes: added community page

version: 0.1.8,
notes: added Davinci•003

version: 0.1.7,
notes: upvote answers to bounties

version: 0.1.6,
notes: article editor refresh
)...
recent_tips: (
tipper: @AriseFacilitySolutions09,
tipped: article
amount: 1000 SATS,

tipper: @Yussuf4331,
tipped: article
amount: 1000 SATS,

tipper: @darkwebsites540,
tipped: article
amount: 10 SATS,
)...