Displaying a popup on mouseover
I was adding an employee profiles database to my d-works intranet solution, and one of the features has to be: when a user mouses over a name, a popup is displayed with the employees reference card. The user can then click on the card to open the profile.
The problem
When the mouse is moved from the link to the popup itself, the popup should stay on the screen. So I had to build in a delay for the closing of the popup and disable the closing on mouseover of the popup itself. So far so good. But then another problem arised: whenever the mouse moves to an element inside the popup, the mouse out event of the popup is triggered. Weird enough, this is common behaviour of all browsers.
So in the end, I had not only to calculate where the popup is shown - function pos(element) - but also if on mouse out the mouse moves to a target inside or outside the popup - function outside(event, element). The functions over() and out() are set on the link, over2() and out2() on the popup div.
The JavaScript
G.pop={
init:function(){
var m=this,o=$$('a'),i
for(i=0;i<o.length;i++){if(o[i].className=='popup')G.set(o[i],{onmouseover:m.over,onmouseout:m.out})}
m.win=$('pop-win')
G.set(m.win,{onmouseover:m.over2,onmouseout:m.out2})
},
over:function(){
var m=G.pop,p=m.pos(this)
G.set(m.win.style,{left:p.x+'px',top:p.y+10+'px',visibility:'visible'})
},
out:function(){var m=G.pop;m.timer=setTimeout(m.close,200)},
over2:function(){clearTimeout(G.pop.timer)},
out2:function(e){var m=G.pop;if(m.outside(e,m.win))m.close()},
close:function(){G.pop.win.style.visibility='hidden'},
pos:function(a){
var x=a.offsetLeft,y=a.offsetTop
while(a.offsetParent){a=a.offsetParent;x+=a.offsetLeft,y+=a.offsetTop}
return{x:x,y:y}
},
outside:function(e,a){
var ee=e||window.event,o=(ee.toElement)?ee.toElement:ee.relatedTarget
while(o!=a && o.nodeName!='BODY')o=o.parentNode
return o!=a
}
}
The HTML
I use one div that is repositioned and filled in with the data. I use a .png file and the sliding doors CSS technique to obtain a nice shadow:
<div id="pop-win">
<div id="pop-a"><div id="pop-test">Test</div></div>
<div id="pop-b"></div>
</div>
The CSS
#pop-win{position:absolute;top:0;left:0;width:370px;visibility:hidden}
#pop-a,#pop-b{background:url(popup-bg.png)}
#pop-a{;padding:20px;padding-bottom:0}
#pop-b{background-position:bottom;height:20px}
The .png file is included in the download. Observe that I don't work with display='none'/'block' for the popup window: later on I have to obtain the offsetWidth and offsetHeight to make sure the popup fits in the visible area, and these are not available when the element has display='none'. So I play with the visibility instead.
Next
The zip contains a working sample of the script. I still have to do the Ajax call to retrieve the information shown in the popup and also prevent the popup from showing outside the visible area. More on that another time.
Comments
09/02/2009 04:55:06 PM, Alan Olsen
How can this be used in a loop that builds out a new popup message for each of the database comments.
Here is an example..Which is actualy building it out in the loop correctly but showing the last comment only on each mouseover.. <style type="text/css">
#pop-win2{position:absolute;top:0;left:0;width:270px;visibility:hidden} #pop-a2,#pop-b2{background:url(images/popup-bg.png)} #pop-a2{;padding:10px;padding-bottom:0} #pop-b2{background-position:bottom;height:20px} #pop-test2{background:#fff;height:50px} </style>
<script language="JavaScript"> //<![CDATA[ var G={ base:'', gecko:navigator.product=='Gecko', ie6:(!!document.all && !(typeof window.XMLHttpRequest=='object')), init:function(){for(var n in G)if(G.init)G.init()}, set:function(a,b){for(var o in b)a=b;return a}, create:function(a,b,c,d){var o=(d||document).createElement(a);G.set(o,b);G.set(o.style,c);return o}, append:function(a,b,c,d){var o=b.tagName?b:G.create(b,c,d);a.appendChild(o);return o} } function $(a){return document.getElementById(a)} function $$(a,b){return (b||document).getElementsByTagName(a)} window.onload=G.init
G.pop2={ init:function(){ var m=this,o=$$('a'),i for(i=0;i<o.length;i++){if(o.className=='popup')G.set(o,{onmouseover:m.over,onmouseout:m.out})} m.win2=$('pop-win2') G.set(m.win2,{onmouseover:m.over2,onmouseout:m.out2}) }, over:function(){ var m=G.pop2,p=m.pos(this) G.set(m.win2.style,{left:p.x+'px',top:p.y+10+'px',visibility:'visible'}) }, out:function(){var m=G.pop2;m.timer=setTimeout(m.close,200)}, over2:function(){clearTimeout(G.pop2.timer)}, out2:function(e){var m=G.pop2;if(m.outside(e,m.win))m.close()}, close:function(){G.pop2.win2.style.visibility='hidden'}, pos:function(a){ var x=a.offsetLeft,y=a.offsetTop while(a.offsetParent){a=a.offsetParent;x+=a.offsetLeft,y+=a.offsetTop} return{x:x,y:y} }, outside:function(e,a){ var ee=e||window.event,o=(ee.toElement)?ee.toElement:ee.relatedTarget while(o!=a && o.nodeName!='BODY')o=o.parentNode return o!=a } } //]]>
</script>
<div id="pop-win2"> <div id="pop-a2"><div id="pop-test2">7/29/2009--P/N S3FC3L0C4 EXCLUDED ON BOM - NO PARTS ON ORDER. PART NOT ON CONTRACT. </div></div> <div id="pop-b2"></div> </div>
To add a comment, log in or register as new user. It's free and safe.