// Namespaced event handlers
var namespaces = type.split(".");
type = namespaces.shift();
- handler.type = namespaces.slice().sort().join(".");
+ handler.type = namespaces.slice(0).sort().join(".");
// Get the current list of functions bound to this event
var handlers = events[ type ],
var namespaces = type.split(".");
type = namespaces.shift();
var all = !namespaces.length,
- namespace = new RegExp("(^|\\.)" + namespaces.slice().sort().join(".*\\.") + "(\\.|$)"),
+ namespace = new RegExp("(^|\\.)" + namespaces.slice(0).sort().join(".*\\.") + "(\\.|$)"),
special = this.special[ type ] || {};
if ( events[ type ] ) {
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 ) {
},
// bubbling is internal
- trigger: function( event, data, elem, bubbling ) {
+ trigger: function( event, data, elem /*, bubbling */ ) {
// Event object or event type
- var type = event.type || event;
+ var type = event.type || event,
+ bubbling = arguments[3];
if ( !bubbling ) {
event = typeof event === "object" ?
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 );
}
- }
+ });
}
}
handle.apply( elem, data );
}
+ var nativeFn, nativeHandler;
+ try {
+ nativeFn = elem[ type ];
+ nativeHandler = elem[ "on" + type ];
+ // prevent IE from throwing an error for some elements with some event types, see #3533
+ } catch (e) {}
// Handle triggering native .onfoo handlers (and on links since we don't call .click() for links)
- if ( (!elem[ type ] || (jQuery.nodeName(elem, 'a') && type === "click")) && elem["on"+type] && elem["on"+type].apply( elem, data ) === false ) {
+ if ( (!nativeFn || (jQuery.nodeName(elem, 'a') && type === "click")) && nativeHandler && nativeHandler.apply( elem, data ) === false ) {
event.result = false;
}
// Trigger the native events (except for clicks on links)
- if ( !bubbling && elem[ type ] && !event.isDefaultPrevented() && !(jQuery.nodeName(elem, 'a') && type === "click") ) {
+ if ( !bubbling && nativeFn && !event.isDefaultPrevented() && !(jQuery.nodeName(elem, 'a') && type === "click") ) {
this.triggered = true;
try {
- elem[ type ]();
+ nativeFn();
// prevent IE from throwing an error for some hidden elements
} catch (e) {}
}
// Cache this now, all = true means, any handler
all = !namespaces.length && !event.exclusive;
- var namespace = new RegExp("(^|\\.)" + namespaces.slice().sort().join(".*\\.") + "(\\.|$)");
+ var namespace = new RegExp("(^|\\.)" + namespaces.slice(0).sort().join(".*\\.") + "(\\.|$)");
handlers = ( jQuery.data(this, "events") || {} )[ event.type ];
// 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
// Add which for click: 1 == left; 2 == middle; 3 == right
// Note: button is not normalized, so don't use it
- if ( !event.which && event.button ) {
+ if ( !event.which && event.button !== undefined ) {
event.which = (event.button & 1 ? 1 : ( event.button & 2 ? 3 : ( event.button & 4 ? 2 : 0 ) ));
}
return event;
},
- proxy: function( fn, proxy ) {
- proxy = proxy || function() { return fn.apply( this, arguments ); };
+ proxy: function( fn, proxy, thisObject ) {
+ if ( proxy !== undefined && !jQuery.isFunction( proxy ) ) {
+ thisObject = proxy;
+ proxy = undefined;
+ }
+ // FIXME: Should proxy be redefined to be applied with thisObject if defined?
+ proxy = proxy || function() { return fn.apply( thisObject !== undefined ? thisObject : this, arguments ); };
// Set the guid of unique handler to the same of original handler, so it can be removed
proxy.guid = fn.guid = fn.guid || proxy.guid || this.guid++;
// So proxy can be declared as an argument
setup: bindReady,
teardown: function() {}
},
-
+
live: {
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 ) {
- jQuery.event.remove( this, namespaces[0], liveHandler );
+
+ remove: 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 );
+ }
+ }
}
}
}
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 ) {
});
jQuery.fn.extend({
- bind: function( type, data, fn ) {
- return type === "unload" ? this.one(type, data, fn) : this.each(function() {
- jQuery.event.add( this, type, fn || data, fn && data );
+ bind: function( type, data, fn, thisObject ) {
+ if ( jQuery.isFunction( data ) ) {
+ if ( fn !== undefined ) {
+ thisObject = fn;
+ }
+ fn = data;
+ data = undefined;
+ }
+ fn = thisObject === undefined ? fn : jQuery.event.proxy( fn, thisObject );
+ return type === "unload" ? this.one(type, data, fn, thisObject) : this.each(function() {
+ jQuery.event.add( this, type, fn, data );
});
},
- one: function( type, data, fn ) {
- var one = jQuery.event.proxy( fn || data, function( event ) {
+ one: function( type, data, fn, thisObject ) {
+ if ( jQuery.isFunction( data ) ) {
+ if ( fn !== undefined ) {
+ thisObject = fn;
+ }
+ fn = data;
+ data = undefined;
+ }
+ fn = thisObject === undefined ? fn : jQuery.event.proxy( fn, thisObject );
+ var one = jQuery.event.proxy( fn, function( event ) {
jQuery( this ).unbind( event, one );
- return (fn || data).apply( this, arguments );
+ return fn.apply( this, arguments );
});
return this.each(function() {
- jQuery.event.add( this, type, one, fn && data );
+ jQuery.event.add( this, type, one, data );
});
},
},
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, data, fn ) {
+ live: function( type, data, fn, thisObject ) {
+ if ( jQuery.isFunction( data ) ) {
+ if ( fn !== undefined ) {
+ thisObject = fn;
+ }
+ fn = data;
+ data = undefined;
+ }
jQuery( this.context ).bind( liveConvert( type, this.selector ), {
- data: fn && data, selector: this.selector, live: type
- }, fn || data );
+ data: data, selector: this.selector, live: type
+ }, fn, thisObject );
return this;
},
jQuery.each(elems, function() {
event.currentTarget = this.elem;
- event.data = this.fn.data
+ event.data = this.fn.data;
if ( this.fn.apply( this.elem, args ) === false ) {
return (stop = false);
}
if ( readyBound ) return;
readyBound = true;
+ // Catch cases where $(document).ready() is called after the
+ // browser event has already occurred.
+ if ( document.readyState === "complete" ) {
+ return jQuery.ready();
+ }
+
// Mozilla, Opera and webkit nightlies currently support this event
if ( document.addEventListener ) {
// Use the handy event callback
// Handle event binding
jQuery.fn[ name ] = function( fn ) {
- return fn ? this.bind (name, fn ) : this.trigger( name );
+ return fn ? this.bind( name, fn ) : this.trigger( name );
};
});