Return to Snippet

Revision: 13589
at April 28, 2009 14:59 by pdswan


Updated Code
(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);
			}
		}
	});
})();

Revision: 13588
at April 28, 2009 14:39 by pdswan


Initial Code
(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;
		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);
			}
		}
		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);
			}
		}
	});
})();

Initial URL


Initial Description
since the script observes mouseout, it should fire mouseleave events before mouseenter to preserve correct order.

Initial Title
Prototype custom event mouseenter mouseleave implementation

Initial Tags
javascript, event

Initial Language
JavaScript