// Init the element's event structure
var events = jQuery.data(elem, "events") || jQuery.data(elem, "events", {}),
handle = jQuery.data(elem, "handle") || jQuery.data(elem, "handle", function(){
- // returned undefined or false
- var val;
-
// Handle the second event of a trigger and when
// an event is called after a page has unloaded
- if ( typeof jQuery == "undefined" || jQuery.event.triggered )
- return val;
-
- val = jQuery.event.handle.apply(arguments.callee.elem, arguments);
-
- return val;
+ if ( typeof jQuery != "undefined" && !jQuery.event.triggered )
+ return jQuery.event.handle.apply(arguments.callee.elem, arguments);
});
// Add elem as a property of the handle function
// This is to prevent a memory leak with non-native
if ( events ) {
// Unbind all events for the element
- if ( types == undefined )
+ if ( types == undefined || (typeof types == "string" && types.charAt(0) == ".") )
for ( var type in events )
- this.remove( elem, type );
+ this.remove( elem, type + (types || "") );
else {
// types is actually an event object here
if ( types.type ) {
trigger: function(type, data, elem, donative, extra) {
// Clone the incoming data, if any
- data = jQuery.makeArray(data || []);
+ data = jQuery.makeArray(data);
+
+ if ( type.indexOf("!") >= 0 ) {
+ type = type.slice(0, -1);
+ var exclusive = true;
+ }
// Handle a global trigger
if ( !elem ) {
// Enforce the right trigger type
data[0].type = type;
+ if ( exclusive )
+ data[0].exclusive = true;
- // Trigger the event
- if ( jQuery.isFunction( jQuery.data(elem, "handle") ) )
- val = jQuery.data(elem, "handle").apply( elem, data );
+ // Trigger the event, it is assumed that "handle" is a function
+ var handle = jQuery.data(elem, "handle");
+ if ( handle )
+ val = handle.apply( elem, data );
- // Handle triggering native .onfoo handlers
- if ( !fn && elem["on"+type] && elem["on"+type].apply( elem, data ) === false )
+ // Handle triggering native .onfoo handlers (and on links since we don't call .click() for links)
+ if ( (!fn || (jQuery.nodeName(elem, 'a') && type == "click")) && elem["on"+type] && elem["on"+type].apply( elem, data ) === false )
val = false;
// Extra functions don't get the custom event object
// Handle triggering of extra function
if ( extra && jQuery.isFunction( extra ) ) {
// call the extra function and tack the current return value on the end for possible inspection
- var ret = extra.apply( elem, data.concat( val ) );
+ ret = extra.apply( elem, val == null ? data : data.concat( val ) );
// if anything is returned, give it precedence and have it overwrite the previous value
if (ret !== undefined)
val = ret;
handle: function(event) {
// returned undefined or false
- var val;
+ var val, ret, namespace, all, handlers;
- // Empty object is for triggered events with no data
- event = jQuery.event.fix( event || window.event || {} );
+ event = arguments[0] = jQuery.event.fix( event || window.event );
// Namespaced event handlers
- var parts = event.type.split(".");
- event.type = parts[0];
+ namespace = event.type.split(".");
+ event.type = namespace[0];
+ namespace = namespace[1];
+ all = !namespace && !event.exclusive; //cache this now, all = true means, any handler
- var handlers = jQuery.data(this, "events") && jQuery.data(this, "events")[event.type], args = Array.prototype.slice.call( arguments, 1 );
- args.unshift( event );
+ handlers = ( jQuery.data(this, "events") || {} )[event.type];
for ( var j in handlers ) {
var handler = handlers[j];
- // Pass in a reference to the handler function itself
- // So that we can later remove it
- args[0].handler = handler;
- args[0].data = handler.data;
// Filter the functions by class
- if ( !parts[1] || handler.type == parts[1] ) {
- var ret = handler.apply( this, args );
+ if ( all || handler.type == namespace ) {
+ // Pass in a reference to the handler function itself
+ // So that we can later remove it
+ event.handler = handler;
+ event.data = handler.data;
+
+ ret = handler.apply( this, arguments );
if ( val !== false )
val = ret;
originalEvent.cancelBubble = true;
};
+ // Fix timeStamp
+ event.timeStamp = event.timeStamp || +new Date;
+
// Fix target property, if necessary
if ( !event.target )
event.target = event.srcElement || document; // Fixes #1925 where srcElement might not be defined either
}
// Add which for key events
- if ( !event.which && (event.charCode || event.keyCode) )
+ if ( !event.which && ((event.charCode || event.charCode === 0) ? event.charCode : event.keyCode) )
event.which = event.charCode || event.keyCode;
// Add metaKey to non-Mac browsers (use ctrl for PC's and Meta for Macs)
// Check if mouse(over|out) are still within the same parent element
var parent = event.relatedTarget;
// Traverse up the tree
- while ( parent && parent != elem ) try { parent = parent.parentNode } catch(error) { parent = elem; };
+ while ( parent && parent != elem ) try { parent = parent.parentNode; } catch(error) { parent = elem; }
// Return true if we actually just moused on to a sub-element
return parent == elem;
};