David Posted November 30, 2012 Share Posted November 30, 2012 Attempted to generate a tooltip from code listed on pages 384 and 385. HTML was looking like this: <div> <label for="username">Username<span class="tooltip">Some snappy tooltip here</span></label> <input type="text" name="username" id="username"/> </div> Tested page. No tooltip. Instead, the console.log shows: TypeError: target.previousSibling.lastChild is null "target.previousSibling.lastChild.style.visibility = 'visible';" Tested the download files. Tooltip works. My code is exactly like the download files, and won't make a tooltip. So, after ((timeSpent >= 1 hour) && (currentHair < previousHair)), I remove the hard return after </label> on a whim . . . and Viola! - tooltip appears! Now the HTML code looks like this: <div> <label for="username">Username<span class="tooltip">Tooltip</span></label><input type="text" name="username" id="username"/> </div> Apparently adding hard returns (formating page for easier reading) introduces a new DOM node that prevents 'previousSibling' in the javascript function from reaching all the way back to <label>. So then, no hard returns if you expect to go tripping through the DOM. Hope this helps save some hair. ~ David Win 7 Home Premium Firefox 17.0 Link to comment Share on other sites More sharing options...
HartleySan Posted November 30, 2012 Share Posted November 30, 2012 Yes, different browsers have different ways of handling child nodes, and in some browsers, a single white space between tags will create a new text node (i.e., child node). That's why I always explicitly check for what I'm looking for by using if statements, etc. In your case, perhaps just using document.getElementsByTagName on the span elements would work best. Also, your if statement about time spent and hair loss cracked me up. Very amusing. Thanks. 1 Link to comment Share on other sites More sharing options...
simon Posted December 19, 2012 Share Posted December 19, 2012 Thanks... I just had the exact same problem (using firefox.) David's solution worked for me, but I am now looking at different ways to refer to the span element as the DOM traversal method seems too risky. Simon I've settled on this for now: target.parentNode.getElementsByTagName('span')[0].style.visibility = 'visible'; Link to comment Share on other sites More sharing options...
HartleySan Posted December 19, 2012 Share Posted December 19, 2012 simon, your method does work, but it's pretty darn inefficient. You might be better off assigning a particular class to all the span element tooltips, and then writing a custom getElementsByClassName function/method to handle grabbing them all. (Note: There are several good getElementsByClassName implementations on the Internet, and modern browsers have a built-in getElementsByClassName method, which is much more efficient than anything we could possibly write.) Link to comment Share on other sites More sharing options...
simon Posted December 21, 2012 Share Posted December 21, 2012 Thanks for looking at that HartleySan. I'm trying to stay away from libraries for the moment. I did see today that there is an API for traversing documents as trees of elements while ignoring text nodes. It's not implemented in IE though. Here's what I've been playing around with. It seems to work, but doesn't test for nextElementSibling or previousElementSibling: /*jslint browser: true*/ /*global U*/ /** * Return the nth sibling element of Element e. * If n is positive, return the nth next sibling element. * If n is negative, return the nth previous sibling element. * If n is 0, return e. * **/ function sibling(e, n) { 'use strict'; while (e && n !== 0) { if (n > 0) { // Find the next element sibling. // If e is not a text node (nodeType !== 1) // find the next sibling and decrement n by 1. if (e && e.nodeType !== 1) { e = e.nextSibling; n = n - 1; } else { // If e exists it's a text node. // Try the next sibling. Do not decrement. e = e.nextSibling; } } else { // Find the previous element sibling. if (e && e.nodeType !== 1) { e = e.previousSibling; n = n + 1; } else { e = e.previousSibling; } } } return e; } - based on Javascript - The Definitive Guide (pages 372 - 374) Link to comment Share on other sites More sharing options...
HartleySan Posted December 21, 2012 Share Posted December 21, 2012 Your solution seems okay, so use it if it works. For the record though, I was not recommending the use of a library. Some browsers have a built-in getElementsByClassName method that is really fast (because it's built-in). You could easily write a single if statement to feature test for the method, and if it's not supported, use whatever method works best for you. None of that involves using a library, and for browsers that have the built-in method, you'll get a huge performance boost. Link to comment Share on other sites More sharing options...
Recommended Posts