...

onfocus tooltips

brothercake
04-22-2003, 10:15 AM
I mentioned this a while ago in a few different threads ... and now here it is. Works in Mac/IE5 Win/IE6 NS6/7/Mozilla and Opera 7, but not in the XML DOM (not yet ;))

This HTML and CSS:

<!DOCTYPE html PUBLIC
"-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">

<head>

<title>onfocus tooltips</title>

<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />

<style type="text/css">
<!--

div.tooltip,div.heretooltip {
font:0.7em verdana,helvetica,arial,sans-serif;
border:1px solid #000;
background-color:#ffffe1;
color:#000;
padding:2px 4px 2px 4px;
text-align:left;
filter:progid:DXImageTransform.Microsoft.Shadow(color=#666666,direction=135,strength=1);
position:absolute;
width:auto;
height:auto;
}

div.heretooltip {
border:1px solid #003;
background-color:#fefefe;
color:#003;
}

-->
</style>

</head>

<body>


<script type="text/javascript" src="tooltips.js"></script>



<p>Use the TAB and Shift-TAB keys to navigate this list.</p>


<ul>
<li><a href="/" title="Home Page" tabindex="10">Home</a>
<ul>
<li><a href="/sitemap.php" title="A guide to the areas of this website" tabindex="20">Sitemap</a></li>
<li><a href="/preferences.php" title="Change the design scheme and functionality" tabindex="30">Preferences</a></li>
<li><a href="/brothercake.php" title="About this site and its webmaster :)" tabindex="40">About brothercake</a></li>
</ul>
</li>
</ul>







</body></html>

And this in tooltips.js

// global vars
var i, pos, obj, tempObj, tempEle, winSize, extent, scrollHeight;


//toolTip object
var toolTip = null;
var toolTipParent = null;


//find object position
function getRealPos(ele,dir)
{
(dir=="x") ? pos = ele.offsetLeft : pos = ele.offsetTop;
tempEle = ele.offsetParent;
while(tempEle != null)
{
pos += (dir=="x") ? tempEle.offsetLeft : tempEle.offsetTop;
tempEle = tempEle.offsetParent;
}
return pos;
}




//delay timer
var goTip = false;
var goTimer = null;
function focusTimer(e)
{
//second loop
if(goTimer != null)
{
//clear timer
clearInterval(goTimer);
goTimer = null;
//pass object to create tooltip
focusTip(e);
}
//first loop
else
{
//get focussed object
(e) ? obj = e.target : obj = event.srcElement;
//pass object back through timer
tempObj = obj;
//set interval
goTimer = setInterval('focusTimer(tempObj)',400);
}
}


//create tooltip
function focusTip(obj)
{

//remove any existing tooltip
blurTip();

//if tooltip is null
if(toolTip == null)
{
//get window dimensions
if(typeof window.innerWidth!="undefined")
{
winSize = {
x : window.innerWidth,
y : window.innerHeight
};
}
else if(typeof document.documentElement.offsetWidth!="undefined")
{
winSize = {
x : document.documentElement.offsetWidth,
y : document.documentElement.offsetHeight
};
}
else
{
winSize = {
x : document.body.offsetWidth,
y : document.body.offsetHeight
};
}

//create toolTip
toolTip = document.createElement('div');

//add classname
toolTip.setAttribute('class','');
toolTip.className = (obj.className == 'youAreHere') ? 'heretooltip' : 'tooltip';

//get focussed object co-ordinates
if(toolTipParent == null)
{
toolTipParent = {
x : getRealPos(obj,'x') - 3,
y : getRealPos(obj,'y') + 2
};
}

// offset tooltip from object
toolTipParent.y += obj.offsetHeight;

//apply tooltip position
toolTip.style.left = toolTipParent.x + 'px';
toolTip.style.top = toolTipParent.y + 'px';

//write in title attribute (with 'you are here' string)
toolTip.innerHTML = (obj.className == 'youAreHere') ? obj.title + ' <b>[You Are Here]</b>' : obj.title;

//add to document
document.body.appendChild(toolTip);

//restrict width
if(toolTip.offsetWidth > 300)
{
toolTip.style.width = '300px';
}

//get tooltip extent
extent = {
x : toolTip.offsetWidth,
y : toolTip.offsetHeight
};

//if tooltip exceeds window width
if((toolTipParent.x + extent.x) >= winSize.x)
{
//shift tooltip left
toolTipParent.x -= extent.x;
toolTip.style.left = toolTipParent.x + 'px';
}

//get scroll height
if(typeof window.pageYOffset!="undefined")
{
scrollHeight = window.pageYOffset;
}
else if(typeof document.documentElement.scrollTop!="undefined")
{
scrollHeight = document.documentElement.scrollTop;
}
else
{
scrollHeight = document.body.scrollTop;
}

//if tooltip exceeds window height
if((toolTipParent.y + extent.y) >= (winSize.y + scrollHeight))
{
//shift tooltip up
toolTipParent.y -= (extent.y+obj.offsetHeight+4);
toolTip.style.top = toolTipParent.y + 'px';
}


}

}


function blurTip()
{
//if tooltip exists
if(toolTip != null)
{
//remove and nullify tooltip
document.body.removeChild(toolTip);
toolTip = null;
toolTipParent = null;
}
//cancel timer
clearInterval(goTimer);
goTimer = null;
}



window.onload = function()
{
if(typeof document.getElementsByTagName!="undefined")
{

//get tags collection
var allTags = document.getElementsByTagName('*');
var allTagsLen = allTags.length;

for (var i=0;i<allTagsLen;i++)
{

//if tag has title attribute
if(allTags[i].title)
{
//attach event
allTags[i].onfocus = focusTimer;
allTags[i].onblur = blurTip;
allTags[i].onmouseover = blurTip;

}

}

}
}

Vladdy
04-22-2003, 11:37 AM
May I suggest instead of defining window.onload in your js file, use initialization function that is called using <body onload="
Two scripts that use window.onload= is one of the most common reasons for "two scripts do not work together" posts. :thumbsup:

brothercake
04-22-2003, 12:52 PM
Originally posted by Vladdy
May I suggest instead of defining window.onload in your js file, use initialization function that is called using <body onload="
Two scripts that use window.onload= is one of the most common reasons for "two scripts do not work together" posts. :thumbsup:
Oh I know - and it does my head in. But if you're working with a global JS archive, you don't want to be putting body onload into every single page ...

and anyway; I just don't like HTML hard-coded event handlers; I've developed an aversion to them ;)

Question is - is there another way; is it possible to bind winow.onload without overriding any existing window.onload or <body onload> handlers that may be present. As it goes, Opera 7 treats window.onload and <body onload> as different - they both happen if they're both there.

eggman
04-22-2003, 03:26 PM
var x=window.onload.toString()
x=x.substr(x.indexOf("{")+1)
x=x.substr(0,x.lastIndexOf("}")-1)
window.onload=new Function(x+";alert('there')")

beetle
04-22-2003, 03:49 PM
Nice eggman, I think I've seen that onload-absorption function someplace, or something similar anyhow.

Hey bcake, there's always attachEvent and addEventListener :D Go grab global.js from DHTML Kitchen so it will work with Macs too :thumbsup:

Of course, worrying about onload conflicts is a bit moot when you have that many global variables :eek:

brothercake
04-23-2003, 03:34 AM
Originally posted by beetle
Of course, worrying about onload conflicts is a bit moot when you have that many global variables :eek:
What? I gave them all sensible names ... :D Fair comment though - it should be OO really ...

Not too happy with attachEvent and addEventListener - they leave opera and safari in the cold. I'll try eggman's idea though - sounds good. I've also been trying to eval() the body onload event:

eval(document.getElementsByTagName('body')[0].getAttribute('onload'));

which works in moz, safari and O7

beetle
04-23-2003, 04:01 AM
Hey brothercake, that element wrapper in global.js from DHTML Kitchen should enable those methods for Opera and Safari too. Sorry to be misleading when I said "macs" -- the code in the file is mean to supply that method to browsers that don't have it.

brothercake
04-23-2003, 04:32 AM
Yeah you're quite right; jkd's just put me right there - safari and opera can both do addEventListener

What confused me was that mozilla has window.addEventListener, which opera doesn't.

So yeah

document.addEventListener('load',loadFunction,false);

works okay in O7 and safari, but curiously not in moz; I had to go

window.addEventListener('load',loadFunction,false);

beetle
04-23-2003, 04:39 AM
Originally posted by brothercake
What? I gave them all sensible names ... :D Fair comment though - it should be OO really ... Sensible names, sure, but i?? That's asking for problems :p

brothercake
04-23-2003, 04:46 AM
Originally posted by beetle
Sensible names, sure, but i?? That's asking for problems :p
Not at all; anyone with an ounce of sense knows not to use i except except for iterators; if it never stores a value you need permanently, then that's fine.

I only declared it globally cos I'm too lazy to type for(var i=0 each time ;)

beetle
04-23-2003, 04:52 AM
hehe, just giving ya a hard time, bcake ;)

kwhubby
04-23-2003, 06:26 AM
wow thats a great little tooltip script... nice an easy to use too...
but.... weres a link to an example?

brothercake
04-23-2003, 03:21 PM
http://www.brothercake.com/scripts/tooltips/tooltips.html

liorean
04-23-2003, 04:35 PM
Brothercake, loops doesn't introduce their own scoping, so for(var i... is a way to declare i globally as well. (If you have the loop in the global scope, that is.)

Wrapping the code in an anonymous function, object basing it or making it object oriented (too much extra work to be worth it, if you ask me) would fix that.

Roy Sinclair
04-23-2003, 06:22 PM
Brothercake,

Here's a working example I keep of how to programatically handle an existing onload event, it even works in Netscape 4.


<html>
<head>
<title>Testing</title>
<style>
</style>
<script>
function S1_Onload() // Sample script 1
{
alert("Script 1"); // Show that the script is being run
S1_Onload_Save(); // Run saved onload function
}
S1_Onload_Save = (window.onload) ? window.onload : new Function; // Create or save current onload function
window.onload = S1_Onload // Set onload event to our function
</script>
</head>
<body>
<h1>Event conflict resolution</h1>
<script>
function S2_Onload() // Sample script 2
{
alert("Script 2"); // Show that the script is being run
S2_Onload_Save(); // Run saved onload function
}
S2_Onload_Save = (window.onload) ? window.onload : new Function; // Create or save current onload function
window.onload = S2_Onload // Set onload event to our function
</script>
<p>
This sample page shows the cross-browser scripting technique which allows multiple scripts to hook a single event
without requiring the builder of the page to worry about a conflict. Of course this technique requires that the scripts
hooking an event use this technique or that the scripts using this technique are declared after scripts on the page that
don't use this technique.
</p>
</body>
</html>

brothercake
04-23-2003, 08:54 PM
thanks all - that's good info :)

Skyzyx
04-26-2003, 04:15 PM
A question: What advantage is it to use your tooltips over the TITLE attribute? I think your tooltips are fantastic, but I typically use title=" ".

brothercake
04-26-2003, 04:25 PM
title attributes don't show up when you tab to elements, only when you mouseover them. That's all this script does - when an element receives focus, its TITLE attribute is presented as a tooltip.

Skyzyx
04-26-2003, 06:31 PM
Aaaaaaaahhhhhhhhhhhhhh........

That's really nifty! Normally, I just use my mouse, but... accessibility, right?

Outstanding!

brothercake
04-27-2003, 06:04 AM
Exactly :)

course the question I can't help wondering is, why is this necessary at all - why don't modern GUIs just do this anyway?

jkd
04-27-2003, 07:22 AM
Originally posted by brothercake
Exactly :)

course the question I can't help wondering is, why is this necessary at all - why don't modern GUIs just do this anyway?

http://www.w3.org/TR/html401/struct/global.html#adef-title

It explicitly describes the tooltip behavior for a visual browser - engaged by hovering the pointer.

However, it definitely seems like an accessibility feature to have it appear onfocus as well as onmouseover... I'd recommend a trip to http://bugzilla.mozilla.org and filing an accessibility enhancement.
I frequently use type-ahead find, which focuses links... even lacking a disability, this would help me out as I'd need to go to the mouse for less. (i.e. seeing the title tooltip)

brothercake
04-27-2003, 08:04 AM
Originally posted by jkd
I'd recommend a trip to http://bugzilla.mozilla.org and filing an accessibility enhancement.
Good idea; I'll do that :)



EZ Archive Ads Plugin for vBulletin Copyright 2006 Computer Help Forum