handler.type = namespaces.slice().sort().join(".");
// Get the current list of functions bound to this event
- var handlers = events[ type ];
-
- if ( this.specialAll[ type ] ) {
- this.specialAll[ type ].setup.call( elem, data, namespaces );
+ var handlers = events[ type ],
+ special = this.special[ type ] || {};
+
+ if ( special.add ) {
+ var modifiedHandler = special.add.call( elem, handler, data, namespaces );
+ if ( modifiedHandler && jQuery.isFunction( modifiedHandler ) ) {
+ modifiedHandler.guid = modifiedHandler.guid || handler.guid;
+ handler = modifiedHandler;
+ }
}
// Init the event handler queue
// Check for a special event handler
// Only use addEventListener/attachEvent if the special
// events handler returns false
- if ( !this.special[ type ] || this.special[ type ].setup.call( elem, data, namespaces ) === false ) {
+ if ( !special.setup || special.setup.call( elem, data, namespaces ) === false ) {
// Bind the global event handler to the element
if ( elem.addEventListener ) {
elem.addEventListener( type, handle, false );
var namespaces = type.split(".");
type = namespaces.shift();
var all = !namespaces.length,
- namespace = new RegExp("(^|\\.)" + namespaces.slice().sort().join(".*\\.") + "(\\.|$)");
+ namespace = new RegExp("(^|\\.)" + namespaces.slice().sort().join(".*\\.") + "(\\.|$)"),
+ special = this.special[ type ] || {};
- if ( events[type] ) {
+ if ( events[ type ] ) {
// remove the given handler for the given type
if ( handler ) {
delete events[ type ][ handler.guid ];
}
}
- if ( this.specialAll[ type ] ) {
- this.specialAll[ type ].teardown.call( elem, namespaces );
+ if ( special.remove ) {
+ special.remove.call( elem, namespaces );
}
// remove generic event handler if no more handlers exist
break;
}
if ( !ret ) {
- if ( !this.special[ type ] || this.special[ type ].teardown.call( elem, namespaces ) === false ) {
+ if ( !special.teardown || special.teardown.call( elem, namespaces ) === false ) {
if ( elem.removeEventListener ) {
elem.removeEventListener( type, jQuery.data( elem, "handle" ), false );
} else if ( elem.detachEvent ) {
event.stopPropagation();
// Only trigger if we've ever bound an event for it
if ( this.global[ type ] ) {
- for ( var cached in jQuery.cache ) {
- if ( cached.events && cached.events[ type ] ) {
- this.trigger( event, data, cached.handle.elem );
+ jQuery.each( jQuery.cache, function() {
+ if ( this.events && this.events[type] ) {
+ jQuery.event.trigger( event, data, this.handle.elem );
}
- }
+ });
}
}
// Calculate pageX/Y if missing and clientX/Y available
if ( event.pageX == null && event.clientX != null ) {
var doc = document.documentElement, body = document.body;
- event.pageX = event.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc.clientLeft || 0);
- event.pageY = event.clientY + (doc && doc.scrollTop || body && body.scrollTop || 0) - (doc.clientTop || 0);
+ event.pageX = event.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc && doc.clientLeft || body && body.clientLeft || 0);
+ event.pageY = event.clientY + (doc && doc.scrollTop || body && body.scrollTop || 0) - (doc && doc.clientTop || body && body.clientTop || 0);
}
// Add which for key events
// Make sure the ready event is setup
setup: bindReady,
teardown: function() {}
- }
- },
+ },
- specialAll: {
live: {
- setup: function( selector, namespaces ) {
- jQuery.event.add( this, namespaces[0], liveHandler );
+ add: function( proxy, data, namespaces ) {
+ jQuery.extend( proxy, data || {} );
+ proxy.guid += data.selector + data.live;
+ jQuery.event.add( this, data.live, liveHandler );
},
- teardown: function( namespaces ) {
- if ( namespaces.length ) {
- var remove = 0, name = new RegExp("(^|\\.)" + namespaces[0] + "(\\.|$)");
- jQuery.each( (jQuery.data(this, "events").live || {}), function() {
- if ( name.test(this.type) ) {
- remove++;
- }
- });
-
- if ( remove < 1 ) {
- jQuery.event.remove( this, namespaces[0], liveHandler );
- }
- }
+ teardown: function( namespaces ) {
+ jQuery.event.remove( this, namespaces[0], liveHandler );
}
}
}
var parent = event.relatedTarget;
// Traverse up the tree
while ( parent && parent != this ) {
+ // Firefox sometimes assigns relatedTarget a XUL element
+ // which we cannot access the parentNode property of
try { parent = parent.parentNode; }
- catch(e) { parent = this; }
+ // assuming we've left the element since we most likely mousedover a xul element
+ catch(e) { break; }
}
if ( parent != this ) {
},
hover: function( fnOver, fnOut ) {
- return this.mouseenter( fnOver ).mouseleave( fnOut );
+ return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
},
ready: function( fn ) {
return this;
},
- live: function( type, fn ) {
- var proxy = jQuery.event.proxy( fn );
- proxy.guid += this.selector + type;
-
- jQuery( this.context ).bind( liveConvert( type, this.selector ), this.selector, proxy );
-
+ live: function( type, data, fn ) {
+ jQuery( this.context ).bind( liveConvert( type, this.selector ), {
+ data: fn && data, selector: this.selector, live: type
+ }, fn || data );
return this;
},
die: function( type, fn ) {
- jQuery( this.context ).unbind( liveConvert(type, this.selector), fn ? { guid: fn.guid + this.selector + type } : null );
+ jQuery( this.context ).unbind( liveConvert( type, this.selector ), fn ? { guid: fn.guid + this.selector + type } : null );
return this;
}
});
function liveHandler( event ) {
- var check = new RegExp("(^|\\.)" + event.type + "(\\.|$)"),
- stop = true, elems = [];
+ var stop = true, elems = [], args = arguments;
jQuery.each( jQuery.data( this, "events" ).live || [], function( i, fn ) {
- if ( check.test( fn.type ) ) {
- var elem = jQuery( event.target ).closest( fn.data )[0];
+ if ( fn.live === event.type ) {
+ var elem = jQuery( event.target ).closest( fn.selector )[0];
if ( elem ) {
elems.push({ elem: elem, fn: fn });
}
jQuery.each(elems, function() {
event.currentTarget = this.elem;
- if ( this.fn.call( this.elem, event, this.fn.data ) === false ) {
+ event.data = this.fn.data
+ if ( this.fn.apply( this.elem, args ) === false ) {
return (stop = false);
}
});