rescape = /[^\w\s.|`]/g,
fcleanup = function( nm ) {
return nm.replace(rescape, "\\$&");
- };
+ },
+ eventKey = "events";
/*
* A number of helper functions used for managing events.
if ( handler === false ) {
handler = returnFalse;
+ } else if ( !handler ) {
+ // Fixes bug #7229. Fix recommended by jdalton
+ return;
}
var handleObjIn, handleObj;
}
// Init the element's event structure
- var elemData = jQuery.data( elem );
+ var elemData = jQuery._data( elem );
// If no elemData is found then we must be trying to bind to one of the
// banned noData elements
return;
}
- var events = elemData.events = elemData.events || {},
+ var events = elemData[ eventKey ],
eventHandle = elemData.handle;
+ if ( typeof events === "function" ) {
+ // On plain objects events is a fn that holds the the data
+ // which prevents this data from being JSON serialized
+ // the function does not need to be called, it just contains the data
+ eventHandle = events.handle;
+ events = events.events;
+
+ } else if ( !events ) {
+ if ( !elem.nodeType ) {
+ // On plain objects, create a fn that acts as the holder
+ // of the values to avoid JSON serialization of event data
+ elemData[ eventKey ] = elemData = function(){};
+ }
+
+ elemData.events = events = {};
+ }
+
if ( !eventHandle ) {
elemData.handle = eventHandle = function() {
// Handle the second event of a trigger and when
}
}
}
-
- if ( special.add ) {
- special.add.call( elem, handleObj );
+
+ if ( special.add ) {
+ special.add.call( elem, handleObj );
if ( !handleObj.handler.guid ) {
handleObj.handler.guid = handler.guid;
}
var ret, type, fn, j, i = 0, all, namespaces, namespace, special, eventType, handleObj, origType,
- elemData = jQuery.data( elem ),
- events = elemData && elemData.events;
+ elemData = jQuery.hasData( elem ) && jQuery._data( elem ),
+ events = elemData && elemData[ eventKey ];
if ( !elemData || !events ) {
return;
}
+ if ( typeof events === "function" ) {
+ elemData = events;
+ events = events.events;
+ }
+
// types is actually an event object here
if ( types && types.type ) {
handler = types.handler;
namespaces = type.split(".");
type = namespaces.shift();
- namespace = new RegExp("(^|\\.)" +
+ namespace = new RegExp("(^|\\.)" +
jQuery.map( namespaces.slice(0).sort(), fcleanup ).join("\\.(?:.*\\.)?") + "(\\.|$)");
}
delete elemData.events;
delete elemData.handle;
- if ( jQuery.isEmptyObject( elemData ) ) {
- jQuery.removeData( elem );
+ if ( typeof elemData === "function" ) {
+ jQuery.removeData( elem, eventKey, true );
+
+ } else if ( jQuery.isEmptyObject( elemData ) ) {
+ jQuery.removeData( elem, undefined, true );
}
}
},
// Only trigger if we've ever bound an event for it
if ( jQuery.event.global[ type ] ) {
+ // XXX This code smells terrible. event.js should not be directly
+ // inspecting the data cache
jQuery.each( jQuery.cache, function() {
- if ( this.events && this.events[type] ) {
- jQuery.event.trigger( event, data, this.handle.elem );
+ // internalKey variable is just used to make it easier to find
+ // and potentially change this stuff later; currently it just
+ // points to jQuery.expando
+ var internalKey = jQuery.expando,
+ internalCache = this[ internalKey ];
+ if ( internalCache && internalCache.events && internalCache.events[type] ) {
+ jQuery.event.trigger( event, data, internalCache.handle.elem );
}
});
}
event.currentTarget = elem;
// Trigger the event, it is assumed that "handle" is a function
- var handle = jQuery.data( elem, "handle" );
+ var handle = elem.nodeType ?
+ jQuery._data( elem, "handle" ) :
+ (jQuery._data( elem, eventKey ) || {}).handle;
+
if ( handle ) {
handle.apply( elem, data );
}
jQuery.event.trigger( event, data, parent, true );
} else if ( !event.isDefaultPrevented() ) {
- var target = event.target, old, targetType = type.replace(rnamespaces, ""),
- isClick = jQuery.nodeName(target, "a") && targetType === "click",
+ var old,
+ target = event.target,
+ targetType = type.replace( rnamespaces, "" ),
+ isClick = jQuery.nodeName( target, "a" ) && targetType === "click",
special = jQuery.event.special[ targetType ] || {};
- if ( (!special._default || special._default.call( elem, event ) === false) &&
+ if ( (!special._default || special._default.call( elem, event ) === false) &&
!isClick && !(target && target.nodeName && jQuery.noData[target.nodeName.toLowerCase()]) ) {
try {
},
handle: function( event ) {
- var all, handlers, namespaces, namespace_sort = [], namespace_re, events, args = jQuery.makeArray( arguments );
+ var all, handlers, namespaces, namespace_re, events,
+ namespace_sort = [],
+ args = jQuery.makeArray( arguments );
event = args[0] = jQuery.event.fix( event || window.event );
event.currentTarget = this;
event.namespace = event.namespace || namespace_sort.join(".");
- events = jQuery.data(this, "events");
+ events = jQuery._data(this, eventKey);
+
+ if ( typeof events === "function" ) {
+ events = events.events;
+ }
+
handlers = (events || {})[ event.type ];
if ( events && handlers ) {
event.handler = handleObj.handler;
event.data = handleObj.data;
event.handleObj = handleObj;
-
+
var ret = handleObj.handler.apply( this, args );
if ( ret !== undefined ) {
// Fix target property, if necessary
if ( !event.target ) {
- event.target = event.srcElement || document; // Fixes #1925 where srcElement might not be defined either
+ // Fixes #1925 where srcElement might not be defined either
+ event.target = event.srcElement || document;
}
// check if target is a textnode (safari)
// Calculate pageX/Y if missing and clientX/Y available
if ( event.pageX == null && event.clientX != null ) {
- var doc = document.documentElement, body = document.body;
+ var doc = document.documentElement,
+ body = document.body;
+
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
- if ( !event.which && ((event.charCode || event.charCode === 0) ? event.charCode : event.keyCode) ) {
- event.which = event.charCode || event.keyCode;
+ if ( event.which == null && (event.charCode != null || event.keyCode != null) ) {
+ event.which = event.charCode != null ? event.charCode : event.keyCode;
}
// Add metaKey to non-Mac browsers (use ctrl for PC's and Meta for Macs)
add: function( handleObj ) {
jQuery.event.add( this,
liveConvert( handleObj.origType, handleObj.selector ),
- jQuery.extend({}, handleObj, {handler: liveHandler, guid: handleObj.handler.guid}) );
+ jQuery.extend({}, handleObj, {handler: liveHandler, guid: handleObj.handler.guid}) );
},
remove: function( handleObj ) {
if ( elem.removeEventListener ) {
elem.removeEventListener( type, handle, false );
}
- } :
+ } :
function( elem, type, handle ) {
if ( elem.detachEvent ) {
elem.detachEvent( "on" + type, handle );
if ( src && src.type ) {
this.originalEvent = src;
this.type = src.type;
+
+ // Events bubbling up the document may have been marked as prevented
+ // by a handler lower down the tree; reflect the correct value.
+ this.isDefaultPrevented = (src.defaultPrevented || src.returnValue === false ||
+ src.getPreventDefault && src.getPreventDefault()) ? returnTrue : returnFalse;
+
// Event type
} else {
this.type = src;
if ( !e ) {
return;
}
-
+
// if preventDefault exists run it on the original event
if ( e.preventDefault ) {
e.preventDefault();
jQuery.event.special.submit = {
setup: function( data, namespaces ) {
- if ( this.nodeName.toLowerCase() !== "form" ) {
+ if ( this.nodeName && this.nodeName.toLowerCase() !== "form" ) {
jQuery.event.add(this, "click.specialSubmit", function( e ) {
- var elem = e.target, type = elem.type;
+ var elem = e.target,
+ type = elem.type;
if ( (type === "submit" || type === "image") && jQuery( elem ).closest("form").length ) {
+ e.liveFired = undefined;
return trigger( "submit", this, arguments );
}
});
-
+
jQuery.event.add(this, "keypress.specialSubmit", function( e ) {
- var elem = e.target, type = elem.type;
+ var elem = e.target,
+ type = elem.type;
if ( (type === "text" || type === "password") && jQuery( elem ).closest("form").length && e.keyCode === 13 ) {
+ e.liveFired = undefined;
return trigger( "submit", this, arguments );
}
});
return;
}
- data = jQuery.data( elem, "_change_data" );
+ data = jQuery._data( elem, "_change_data" );
val = getVal(elem);
// the current data will be also retrieved by beforeactivate
if ( e.type !== "focusout" || elem.type !== "radio" ) {
- jQuery.data( elem, "_change_data", val );
+ jQuery._data( elem, "_change_data", val );
}
-
+
if ( data === undefined || val === data ) {
return;
}
if ( data != null || val ) {
e.type = "change";
+ e.liveFired = undefined;
return jQuery.event.trigger( e, arguments[1], elem );
}
};
jQuery.event.special.change = {
filters: {
- focusout: testChange,
+ focusout: testChange,
+
+ beforedeactivate: testChange,
click: function( e ) {
var elem = e.target, type = elem.type;
// Beforeactivate happens also before the previous element is blurred
// with this event you can't trigger a change event, but you can store
- // information/focus[in] is not needed anymore
+ // information
beforeactivate: function( e ) {
var elem = e.target;
- jQuery.data( elem, "_change_data", getVal(elem) );
+ jQuery._data( elem, "_change_data", getVal(elem) );
}
},
};
changeFilters = jQuery.event.special.change.filters;
+
+ // Handle when the input is .focus()'d
+ changeFilters.focus = changeFilters.beforeactivate;
}
function trigger( type, elem, args ) {
}
};
- function handler( e ) {
+ function handler( e ) {
e = jQuery.event.fix( e );
e.type = fix;
return jQuery.event.handle.call( this, e );
}
return this;
}
-
+
if ( jQuery.isFunction( data ) || data === false ) {
fn = data;
data = undefined;
return this;
},
-
+
delegate: function( selector, types, data, fn ) {
return this.live( types, data, fn, selector );
},
-
+
undelegate: function( selector, types, fn ) {
if ( arguments.length === 0 ) {
return this.unbind( "live" );
-
+
} else {
return this.die( types, null, fn, selector );
}
},
-
+
trigger: function( type, data ) {
return this.each(function() {
jQuery.event.trigger( type, data, this );
toggle: function( fn ) {
// Save reference to arguments for access in closure
- var args = arguments, i = 1;
+ var args = arguments,
+ i = 1;
// link all the functions, so any of them can unbind this click handler
while ( i < args.length ) {
return this.click( jQuery.proxy( fn, function( event ) {
// Figure out which function to execute
- var lastToggle = ( jQuery.data( this, "lastToggle" + fn.guid ) || 0 ) % i;
- jQuery.data( this, "lastToggle" + fn.guid, lastToggle + 1 );
+ var lastToggle = ( jQuery._data( this, "lastToggle" + fn.guid ) || 0 ) % i;
+ jQuery._data( this, "lastToggle" + fn.guid, lastToggle + 1 );
// Make sure that clicks stop
event.preventDefault();
var type, i = 0, match, namespaces, preType,
selector = origSelector || this.selector,
context = origSelector ? this : jQuery( this.context );
-
+
if ( typeof types === "object" && !types.preventDefault ) {
for ( var key in types ) {
context[ name ]( key, data, types[key], selector );
}
-
+
return this;
}
context.unbind( "live." + liveConvert( type, selector ), fn );
}
}
-
+
return this;
};
});
function liveHandler( event ) {
- var stop, maxLevel, elems = [], selectors = [],
- related, match, handleObj, elem, j, i, l, data, close, namespace, ret,
- events = jQuery.data( this, "events" );
+ var stop, maxLevel, related, match, handleObj, elem, j, i, l, data, close, namespace, ret,
+ elems = [],
+ selectors = [],
+ events = jQuery._data( this, eventKey );
+
+ if ( typeof events === "function" ) {
+ events = events.events;
+ }
- // Make sure we avoid non-left-click bubbling in Firefox (#3861)
- if ( event.liveFired === this || !events || !events.live || event.button && event.type === "click" ) {
+ // Make sure we avoid non-left-click bubbling in Firefox (#3861) and disabled elements in IE (#6911)
+ if ( event.liveFired === this || !events || !events.live || event.target.disabled || event.button && event.type === "click" ) {
return;
}
if ( ret === false ) {
stop = false;
}
+ if ( event.isImmediatePropagationStopped() ) {
+ break;
+ }
}
}
}
});
-// Prevent memory leaks in IE
-// Window isn't included so as not to unbind existing unload events
-// More info:
-// - http://isaacschlueter.com/2006/10/msie-memory-leaks/
-if ( window.attachEvent && !window.addEventListener ) {
- window.attachEvent("onunload", function() {
- for ( var id in jQuery.cache ) {
- if ( jQuery.cache[ id ].handle ) {
- // Try/Catch is to handle iframes being unloaded, see #4280
- try {
- jQuery.event.remove( jQuery.cache[ id ].handle.elem );
- } catch(e) {}
- }
- }
- });
-}
-
})( jQuery );