Forum Moderators: open

Message Too Old, No Replies

Dynamically assigning rollover behavior

onmouseover, onmouseout = function()?

         

whoisgregg

2:32 pm on Aug 2, 2005 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



I'd like to reduce both code bloat and the ease of updating the HTML for a page that has a number of standard rollover images. I figure it's easier for a less knowledgeable person to add a class="rollover" and name the files with a "_out" or "_over" than to have to modify each onmouseover and onmouseout bit. But I've hit a snag and I can't decipher it.

I'm coding the images like so:

<img src="images/somefile_out.gif" class="rollover" />

And I call this function from an external file right before the closing </body> tag:

function addRollovers() { 
var rollers;
if(document.getElementById)
rollers = document.getElementsByTagName('img');
else if(document.all)
rollers = document.all.tags('img');
else return
for (var i=0; i<rollers.length; i++) {
var roller = rollers[i];
if (roller.className == 'rollover'){
var rolloverSRC = roller.src.replace('_out',"_over");
roller.onmouseover = function(){ this.src=rolloverSRC; }
roller.onmouseout = function(){ this.src=roller.src; }
}
}
}

Problem: The script gives every matching image a onmouseover to change into the SRC of the last img in the array and an onmouseout of the next to last img in the array. So, all the rollover images do the same thing, as if they are using the last written version of the function instead of the version written on their iteration of the loop.

Bernard Marx

8:25 pm on Aug 2, 2005 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



I believe there's a closure going on there, due to the use of inner functions. The var, roller, is preserved at it's final value (the last elm referenced). Lots of workarounds, but I've gone for the one of doing a simple conditional swap of the suffices.

I've put the function declaration outside the loop for a little pedantic efficiency.

(Haven't tested this myself as yet).

function addRollovers()
{
var rollers;
if(document.getElementById)
rollers = document.getElementsByTagName('img');
else if(document.all)
rollers = document.all.tags('img');
else return

for(var k=0,roller; roller=rollers[k]; )
{
if (roller.className!= 'rollover') continue;
roller.onmouseover = roller.onmouseout = roll;
}

function roll()
{
if( /_out/.test(this.src) )
this.src = this.src.replace('_out','_over');
else
this.src = this.src.replace('_over','_out');
}
}

Bernard Marx

8:43 pm on Aug 2, 2005 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



..but you could give this a try. It doesn't bother assigning event handlers to the images. Instead, it catches the bubbled mouse events at the document level. This way, there's no initialisation needed - good if there are many images on the page.

The assignment can be placed in the HEAD, or linked script.

document.onmouseover =
document.onmouseout = function(e)
{
// Get source element of bubbled event (X-browser)
e = e ¦¦ event;
var elm = e.srcElement ¦¦ e.target;
// Allow possibility of multiple className
if(! /\brollover\b/.test(elm.className) ) return;
elm.src = /_out/.test(elm.src)
? elm.src.replace('_out','_over')
: elm.src = this.src.replace('_over','_out');
}

(This approach does work- but there may be a silly mistake in the above)

whoisgregg

7:42 pm on Aug 3, 2005 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



I went with the second script to avoid the initialization. One problem, the mouseover works correctly, but on mouseout it is not changing back.

I think it's because this part:

 elm.src = /_out/.test(elm.src) 

Always tests true because it's testing the actual code and not the modified src? Or is there something else going on here?

Also, thanks very much! I didn't even know about .test and was concerned about multiple class names fouling my original script. :D

whoisgregg

8:46 pm on Aug 3, 2005 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



Nevermind, I fixed it. The last line should read:

  : elm.src = [blue]elm[/blue].src.replace('_over','_out'); 

Thanks again Bernard! :)

Bernard Marx

9:06 pm on Aug 3, 2005 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



I should've said "I guarantee there's a silly mistake in the above".

In fact, the assignment in that line came from a copy'n'paste error, and shouldn't be there at all (although it is legal, results in the same value with your correction). So..


: elm.src.replace('_over','_out');

B.