onMouseOver/onMouseOut not working

E

Epetruk

Hi all,

I want a page where the contents of a table cell are replaced with an image
when the mouse moves over the cell, and the text is restored when the mouse
moves out. Here's the html for the page:


<HTML>
<HEAD>
<style type="text/css">
td.col1
{
background-color:Silver;
color:Black;
}

td.col3
{
background-color:Aqua;
color:Blue;
}
</style>

<script language="javascript">
function changeCellContents(cell, toPic)
{
if (toPic)
{
cell.innerHtml = "<img src=\"images/myimage.jpg\">";
}
else
{
cell.innerText = cell.CellText;
}
}
</script>

</HEAD>
<body>
<form name="TableDBForm">
<table bordercolor="White" border="0" cellspacing="1" width="100%">
<tr>
<td Class="col1" CellText="cell 1"
onMouseOver="changeCellContents(this, true)"
onMouseOut="changeCellContents(this, false)">cell 1</td>
<td Class="col1" CellText="cell 2"
onMouseOver="changeCellContents(this, true)"
onMouseOut="changeCellContents(this, false)">cell 2</td>
</tr>
</table>
</form>
</body>
</HTML>


Unfortunately, it doesn't seem to work. Any reason why?
 
L

Lee

Epetruk said:
function changeCellContents(cell, toPic)
{
if (toPic)
{
cell.innerHtml = "<img src=\"images/myimage.jpg\">";
}
else
{
cell.innerText = cell.CellText;
}
}
</script>
Unfortunately, it doesn't seem to work. Any reason why?

There is no attribute named "innerHtml". It's "innerHTML".

On the other hand, "innerText" is correct, but doesn't exist
in all browsers. It's better to use innerHTML in both cases.

You also can't expect to be able to access custom HTML
attributes like "CellText" in all browsers, so it would be
better to store the current innerHTML value before you change
it.

if (toPic)
{
cell.CellText = cell.innerHTML;
cell.innerHTML = "<img src=\"images/myimage.jpg\">";
}
else
{
cell.innerHTML = cell.CellText;
}
 
R

Richard

I want a page where the contents of a table cell are replaced with an
image
when the mouse moves over the cell, and the text is restored when the
mouse
moves out. Here's the html for the page:

I think you'd be better off using a method where a divsion is hidden or
visible.
This is what I use.

var kid = "FirstOn"
function ShowInfo(DivId)
{
document.getElementById(kid).style.display = 'none';
document.getElementById(DivId).style.display = 'block';
kid = DivId;
}

<div id="FirstOn" style="display:block;">
blah blah blah blah
</div>

<div id="ShowMe" style="display:none;">
<img src="name.jpg">

<tr><td onmouseover="ShowInfo('ShowMe') onmouseout="ShowInfo('FirstOn')>
 
R

RobG

Lee wrote:
[...]
On the other hand, "innerText" is correct, but doesn't exist
in all browsers. It's better to use innerHTML in both cases.

Whilst innerHTML is widely supported, there are likely to be some
browsers that don't support it. Also, it isn't part of the W3C
HTML specification (and is unlikely to ever be).

Therefore it's worth feature testing before attempting to use it
and provide an alternative if it doesn't work.
You also can't expect to be able to access custom HTML
attributes like "CellText" in all browsers, so it would be
better to store the current innerHTML value before you change
it.

Good point about the custom attribute, but if you store the
current contents of the cell, the onmouseout will pick up the
image and re-display it. The contents have to be specified
independently of onmouseover/out.

But there are greater problems. Once you mouseover the td and
put an image in there, as soon as the cursor goes over the image
it is "out" of the td, so the onmouseout fires and replaces the
image with the text again. I've tried to stop propagation but
have failed, perhaps someone else here has a suggestion.

I tried putting a mouseover on the cell and mouseout on the
table. When the mouse is over a cell, the last mouseover cell is
restored and the new cell has the image put in it. When going
out of the table, a mouseout just restores the cell.

You can put the cell text and images in an array, that way you
can call a different image or text for each cell. The script
below uses DOM with feature testing and offers an innerHTML
method if the DOM methods aren't supported. I have used the cell
id to define the text and image to swap, but some other method
could be used.

The OP should remember that the pages should stay fully
functional even if JavaScript is disabled.

<html><head><title>play</title>
<style type="text/css">
td.col1 {background-color:Silver; color:Black;}
td.col3 {background-color:Aqua; color:Blue;}
</style>
<script language="javascript">
var lastMouseOverCell;
var cellTxtArray = ['cell 1','cell 2']
var cellImgArray = ['a.jpg','b.gif']

function changeCellContents(cell,evt) {
var e = evt || window.event;
if (cell.nodeName == 'TABLE' && e.type == 'mouseover') {
if (e.stopPropagation) e.stopPropagation();
e.cancelBubble = true;
return;
}

if (lastMouseOverCell)
restore(lastMouseOverCell);
if(cell.nodeName.toLowerCase() == 'td') {
lastMouseOverCell = cell;
insertImage(cell);
} else {
lastMouseOverCell = '';
}

if (e.stopPropagation) e.stopPropagation();
e.cancelBubble = true;
}

function delContents(x) {
if(x.firstChild) {
while (x.firstChild) {
x.removeChild(x.firstChild);
}
} else if (x.innerHTML) {
x.innerHTML = '';
}
}

function restore(x) {
delContents(x);
if (x.appendChild) {
oTxt = document.createTextNode(cellTxtArray[x.id]);
x.appendChild(oTxt);
} else if (x.innerHTML) {
x.innerHTML = cellTxtArray[x.id];
}
}

function insertImage(x) {
delContents(x)
if (x.appendChild) {
var oImg = document.createElement('img');
oImg.src = cellImgArray[x.id];
x.appendChild(oImg);
} else if (x.innerHTML) {
x.innerHTML = '<img src="'+cellImgArray[x.id]+'"'
+ ' alt="goofy image">';
}
}
</script>

</head>
<body>
<table bordercolor="White" border="0"
cellspacing="1" width="100%" onmouseout="
changeCellContents(this,event);
">
<tr>
<td Class="col1" id="0" onmouseover="
changeCellContents(this,event);
">cell 1</td>
<td Class="col1" id="1" onmouseover="
changeCellContents(this,event);
">cell 2</td>
</tr>
<tr>
<td Class="col1" id="0" onmouseover="
changeCellContents(this,event);
">cell 1</td>
<td Class="col1" id="1" onmouseover="
changeCellContents(this,event);
">cell 2</td>
</tr>
</table>
</body>
</html>
 
N

Nick Robins

RobG said:
But there are greater problems. Once you mouseover the td and
put an image in there, as soon as the cursor goes over the image
it is "out" of the td, so the onmouseout fires and replaces the
image with the text again. I've tried to stop propagation but
have failed, perhaps someone else here has a suggestion.
rather than inserting and removing an image element, it might be better
to use css,
eg:
x.style.backgroundImage = "url(' + cellImgArray[x.id] + '")';

and:
x.style.backgroundImage = "";

Nick
 
L

Lee

RobG said:
Lee wrote:
[...]
On the other hand, "innerText" is correct, but doesn't exist
in all browsers. It's better to use innerHTML in both cases.

Whilst innerHTML is widely supported, there are likely to be some
browsers that don't support it. Also, it isn't part of the W3C
HTML specification (and is unlikely to ever be).

Therefore it's worth feature testing before attempting to use it
and provide an alternative if it doesn't work.
You also can't expect to be able to access custom HTML
attributes like "CellText" in all browsers, so it would be
better to store the current innerHTML value before you change
it.

Good point about the custom attribute, but if you store the
current contents of the cell, the onmouseout will pick up the
image and re-display it. The contents have to be specified
independently of onmouseover/out.

No it won't. The only value to ever be stored is the text.
But there are greater problems. Once you mouseover the td and
put an image in there, as soon as the cursor goes over the image
it is "out" of the td, so the onmouseout fires and replaces the
image with the text again.

Whether or not this problem is obvious depends on the size of the
image. Another problem is that the cells resize, possibly moving
the current cell out from under the pointer.

There are other problems with the idea, but I thought the OP
should be allowed to encounter them stepwise.
 
R

RobG

Nick said:
RobG said:
But there are greater problems. Once you mouseover the td and
put an image in there, as soon as the cursor goes over the image
it is "out" of the td, so the onmouseout fires and replaces the
image with the text again. I've tried to stop propagation but
have failed, perhaps someone else here has a suggestion.

rather than inserting and removing an image element, it might be better
to use css,
eg:
x.style.backgroundImage = "url(' + cellImgArray[x.id] + '")';

and:
x.style.backgroundImage = "";

Nick

Or put both the image and text into the cell and toggle the
display of one or the other using style.display. Lee & I
just followed the OP, I didn't think it through enough.

Regardless, until a solution is proposed for the flicker problem
caused by the mouseover/out, it's not going to be useful. I
think Richard has a good idea - have the mouseover change an
adjoining cell.

<script type="text/javascript">
function toggle(x) {
var kids = x.childNodes;
for (var i=0, len=kids.length; i<len; i++){
if (kids.style) {
kids.style.display =
(kids.style.display == 'none')? '':'none';
}
}
}
</script>
<table><tr>
<td onmouseover="toggle(this);"><img src="1.gif"
alt="image" style="display: none"><span>cell 1</span>
</td>
</tr></table>
</body></html>
 
N

Nick Robins

RobG said:
Regardless, until a solution is proposed for the flicker problem
caused by the mouseover/out, it's not going to be useful. I
think Richard has a good idea - have the mouseover change an
adjoining cell.
That was the main reason I suggested using the style property, the
status of the pointer hasn't changed, there's no new element to alter
things thus the flicker is avoided.

The two alternatives I've found are using scripting:

<style type="text/css">
/* set the td size to stop the td collapsing when content is hidden */
td { width: 100px; height: 100px; }
</style>

<script type="text/javascript">
function addImage(tableCell) {
tableCell.style.backgroundImage = "url(path/to/image.jpg)";
tableCell.firstChild.style.display = "none";
}
function delImage(tableCell) {
tableCell.style.backgroundImage = "";
tableCell.firstChild.style.display = "inline";
}
</script>

<table><tr>
<td onmouseover="addImage(this)"
onmouseout="delImage(this)"><span>some text</span></td>
</tr></table>

which works fine on IE, Gecko and Opera but has some quirks in Konqueror
(the background image isn't always removed).

or using pure CSS:

<style type="text/css">
/* set the td size to stop the td collapsing when content is hidden */
td { width: 100px; height: 100px; }
td img { display: none; }
td:hover img { display: inline; }
td:hover span { display: none; }
</style>

<table><tr>
<td><img src="path/to/image.jpg" width="100" height="100" alt="some
text" /><span>some text</span></td>
</tr></table>

which isn't really an option since IE only supports :hover on anchors
(works fine in Gecko/Opera/KHTML).

Nick
 
R

RobG

Nick said:
That was the main reason I suggested using the style property, the
status of the pointer hasn't changed, there's no new element to alter
things thus the flicker is avoided.

Your method neatly avoids flicker, but so does hiding/showing
the elements without using CSS. Your CSS method is much more
reliable in Firefox however, as discussed below.

An artifact of mouseover/out in Firefox is that the events don't
always fire - rapid mouse movement can prevent them from
happening - however the CSS method does not display this.

Below is a test page that has two cells: the left one just
toggles the display of an image or text, the right hides the
text and uses CSS background image to display the image. Both
avoid flicker.

In the left cell, rapid mouse movement can cause the mouseout
event not to fire. The far right cell keeps a log of the last 10
events, the element that fired them and the cell the event is
registered to so it is easy to see a mouseover on the left cell
immediately followed by a mouseover on the right. The missing
mouseout means the image is still displayed in the left cell.

It also neatly shows the bubbling of events - sometimes the
mouseover is called by an image or span and not the td.
Internally, mouseout/over is being called constantly in the left
cell (it happens in the right cell too if something is
displayed).

Interestingly, in IE both cells behave completely reliably - if
mouseover fires, then mouseout is guaranteed (at least as far as
my testing can determine). Is this a bug with Firefox
mouseover/out events?

Comment?

<style type="text/css">
/* set the td size to stop the td collapsing
when content is hidden */
td { width: 150px; height: 100px; }
</style>

<script type="text/javascript">
var msgTxt = ['<br>','<br>','<br>','<br>','<br>',
'<br>','<br>','<br>','<br>','<br>'];
var evtCnt = 0;

function writeMsg(a,b,c){
var msgCel = document.getElementById('msgCel');
var col = 'red';
col = (c == 'left')? 'red' : 'green';

msgTxt.unshift(a + ' ' + b + ' '
+ '<span style="color: ' + col
+ '; font-weight: bold">' + c + '</span>'
+ ' ' + evtCnt + '<br>');
msgTxt.pop();
msgCel.innerHTML = msgTxt.join('');
evtCnt++;
}

function addImage(tableCell,evt) {
tableCell.style.backgroundImage = "url(1.gif)";
tableCell.firstChild.style.display = "none";

var e = evt || window.event;
var c = e.target || e.srcElement;
writeMsg(e.type,c.nodeName,tableCell.id);
}
function delImage(tableCell,evt) {
tableCell.style.backgroundImage = "";
tableCell.firstChild.style.display = "";

var e = evt || window.event;
var c = e.target || e.srcElement;
writeMsg(e.type,c.nodeName,tableCell.id);
}

function addImage1(tableCell,evt) {
tableCell.childNodes[0].style.display = "";
tableCell.childNodes[1].style.display = "none";

var e = evt || window.event;
var c = e.target || e.srcElement;
writeMsg(e.type,c.nodeName,tableCell.id);
}

function delImage1(tableCell,evt) {
tableCell.childNodes[0].style.display = "none";
tableCell.childNodes[1].style.display = "";

var e = evt || window.event;
var c = e.target || e.srcElement;
writeMsg(e.type,c.nodeName,tableCell.id);

}
</script>

<table border="1">
<tr>
<td id="left" onmouseover="addImage1(this,event)"
onmouseout="delImage1(this,event)"><img
src="1.gif" style="display: none"><span>some text</span>
</td>
<td id="right" onmouseover="addImage(this,event)"
onmouseout="delImage(this,event)"><span>some text</span>
</td>
<td style="width: 200px" id="msgCel">
<br><br><br><br><br><br><br><br><br><br>
</td>
</tr>
</table>
 
R

RobB

Nick said:
That was the main reason I suggested using the style property, the
status of the pointer hasn't changed, there's no new element to alter
things thus the flicker is avoided.

The two alternatives I've found are using scripting:

<style type="text/css">
/* set the td size to stop the td collapsing when content is hidden */
td { width: 100px; height: 100px; }
</style>

<script type="text/javascript">
function addImage(tableCell) {
tableCell.style.backgroundImage = "url(path/to/image.jpg)";
tableCell.firstChild.style.display = "none";
}
function delImage(tableCell) {
tableCell.style.backgroundImage = "";
tableCell.firstChild.style.display = "inline";
}
</script>

<table><tr>
<td onmouseover="addImage(this)"
onmouseout="delImage(this)"><span>some text</span></td>
</tr></table>

which works fine on IE, Gecko and Opera but has some quirks in Konqueror
(the background image isn't always removed).

or using pure CSS:

<style type="text/css">
/* set the td size to stop the td collapsing when content is hidden */
td { width: 100px; height: 100px; }
td img { display: none; }
td:hover img { display: inline; }
td:hover span { display: none; }
</style>

<table><tr>
<td><img src="path/to/image.jpg" width="100" height="100" alt="some
text" /><span>some text</span></td>
</tr></table>

which isn't really an option since IE only supports :hover on anchors
(works fine in Gecko/Opera/KHTML).

Nick

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<style type="text/css">

#foo td {
width: 143px;
height: 64px;
font: normal 16px tahoma;
padding: 3px;
border: 1px #000 solid;
cursor: crosshair;
}
#foo td img {
display: none;
width: 143px;
height: 53px;
border-width: 0;
}
#foo td:hover img, #foo td.sfhover img {
display: inline;
}
#foo td:hover span, #foo td.sfhover span {
display: none;
}

</style>
<script type="text/javascript">

var sfHover = function()
{
var sfEls = document.getElementById('foo').getElementsByTagName('td');
for (var i = 0; i < sfEls.length; i++)
{
sfEls.onmouseover = function()
{
this.className += ' sfhover';
}
sfEls.onmouseout = function()
{
this.className = this.className.replace(new RegExp(' sfhover\\b'),
'');
}
}
}

if (window.attachEvent)
window.attachEvent('onload', sfHover);

</script>
</head>
<body>
<table id="foo">
<tbody>
<tr>
<td>
<img src="http://www.google.com/images/art.gif"
alt="some text" />
<span>some text</span>
</td>
<td>feh</td>
</tr>
</tbody>
</table>
</body>
</html>

Been using .htcs for this, but Suckerish makes some compelling
arguments for doing it their way...

http://www.htmldog.com/articles/suckerfish/
http://www.google.com/search?hl=en&q=hover+internet+explorer+htc
 
R

RobG

RobG wrote:
[...]
Interestingly, in IE both cells behave completely reliably - if
mouseover fires, then mouseout is guaranteed (at least as far as
my testing can determine). Is this a bug with Firefox
mouseover/out events?

I'll answer my own question: yes - Bug# 264236
 
N

Nick Robins

RobG said:
An artifact of mouseover/out in Firefox is that the events don't
always fire - rapid mouse movement can prevent them from
happening - however the CSS method does not display this.

Below is a test page that has two cells: the left one just
toggles the display of an image or text, the right hides the
text and uses CSS background image to display the image. Both
avoid flicker.

In the left cell, rapid mouse movement can cause the mouseout
event not to fire. The far right cell keeps a log of the last 10
events, the element that fired them and the cell the event is
registered to so it is easy to see a mouseover on the left cell
immediately followed by a mouseover on the right. The missing
mouseout means the image is still displayed in the left cell.

It also neatly shows the bubbling of events - sometimes the
mouseover is called by an image or span and not the td.
Internally, mouseout/over is being called constantly in the left
cell (it happens in the right cell too if something is
displayed).

Interestingly, in IE both cells behave completely reliably - if
mouseover fires, then mouseout is guaranteed (at least as far as
my testing can determine). Is this a bug with Firefox
mouseover/out events?
The only way I could reproduce the mouseout error in Mozilla (I don't
have FF installed atm) was by using rapid movement to move the pointer
out of the browser window, the mouseout won't fire until the pointer is
bought back into the cell and out again.

mouseover IMG left 4
mouseout TD left 3
mouseover TD left 2
mouseout TD right 1
mouseover TD right 0

it appears that when it fails (for me anyway) the last event is always
'mouseover IMG left', mozilla has actually 'failed' (kept the image
after mouseout) on the right cell, but only once, I haven't managed to
reproduce this.

On trying this (moving the pointer across the table and out of the
window rapidly) in IE, it takes longer (ie a noticeable length of time)
to fire the mouseout but it /will/ fire it, even if the IE window no
longer has focus.

/edit
After doing some more testing in mozilla, it seems that if either
'mouseover IMG' or 'mouseover SPAN' appears then the mouseout has
failed (ie I only see these appear on failure) for left and right cells
respectively (the right cell only fails infrequently, but then I can't
consistantly trip the left cell either).

Nick
 
R

RobG

Nick said:
RobG wrote: [...]
Interestingly, in IE both cells behave completely reliably - if
mouseover fires, then mouseout is guaranteed (at least as far as
my testing can determine). Is this a bug with Firefox
mouseover/out events?

The only way I could reproduce the mouseout error in Mozilla (I don't
have FF installed atm) was by using rapid movement to move the pointer
out of the browser window, the mouseout won't fire until the pointer is
bought back into the cell and out again.

That's the error exactly.

[...]
After doing some more testing in mozilla, it seems that if either
'mouseover IMG' or 'mouseover SPAN' appears then the mouseout has
failed (ie I only see these appear on failure) for left and right cells
respectively (the right cell only fails infrequently, but then I can't
consistantly trip the left cell either).

Interesting that you got it to happen on the right cell also -
it has implications for RobB's suggested solution. Testing on a
slow box (old or very busy) may reveal the same failure. The
inability to reproduce the error on the right cell seems purely
due to the greater efficiency of the method rather than avoiding
the bug.

The mouseover should be the last thing but it (occasionally)
isn't, hence the image lingers when it shouldn't. It is a
reported bug in Mozilla, which I guess means Geko. Any
mouseover/out event pair will produce unpredictable results,
much better to use click if possible.

To better understand event bubbling and some of the differences
between the Mozilla and IE models, read here:

<URL:http://www.quirksmode.org/js/events_order.html>
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top