(function(){
function firstCommonAncestor(elm1, elm2){
var p = elm1.up();
while( !elm2.descendantOf(p) ){
p = p.up();
}
return p;
}
function stopEvent(e){
try{
e.stop();
}catch(ex){}
}
Event.observe(document, 'mouseout', function(e){
var from = e.element();
var to = e.relatedTarget;
p = null;
if ( !to || (from !== to && !to.descendantOf(from))) {
/* mouseleave should bubble up until the to element because we have left all elements up to that one */
var stopOn = null;
if( to ){
if( from.descendantOf(to) ){
stopOn = to.childElements();
}else{
p = firstCommonAncestor(from, to);
if( p && to.descendantOf(p) ){
stopOn = p.childElements();
}
}
}
if( stopOn ){
stopOn.invoke('observe', 'custom:mouseleave', stopEvent);
}
from.fire('custom:mouseleave');
if( stopOn ){
stopOn.invoke('stopObserving', 'custom:mouseleave', stopEvent);
}
}
var p = null;
if( to && !from.descendantOf(to)){
/* mouseenter can bubble, no problem! */
var stopOn = null;
if( to.descendantOf(from)){
stopOn = from.childElements();
}else{
// do first common ancestor's children, see below.
p = firstCommonAncestor(to, from);
stopOn = p.childElements();
}
if( stopOn ){
stopOn.invoke('observe', 'custom:mouseenter', stopEvent);
}
to.fire('custom:mouseenter');
if( stopOn ){
stopOn.invoke('stopObserving', 'custom:mouseenter', stopEvent);
}
}
});
})();