// Make sure that the function being executed has a unique ID
if ( !handler.guid ) {
- handler.guid = this.guid++;
+ handler.guid = jQuery.guid++;
}
- // if data is passed, bind to handler
- if ( data !== undefined ) {
- // Create temporary function pointer to original handler
- var fn = handler;
-
- // Create unique handler function, wrapped around original handler
- handler = this.proxy( fn );
+ // Init the element's event structure
+ var elemData = jQuery.data( elem );
- // Store data in unique handler
- handler.data = data;
+ // If no elemData is found then we must be trying to bind to one of the
+ // banned noData elements
+ if ( !elemData ) {
+ return;
}
- // Init the element's event structure
- var events = jQuery.data( elem, "events" ) || jQuery.data( elem, "events", {} ),
- handle = jQuery.data( elem, "handle" ), eventHandle;
+ var events = elemData.events = elemData.events || {},
+ eventHandle = elemData.handle, eventHandle;
- if ( !handle ) {
- eventHandle = function() {
+ if ( !eventHandle ) {
+ elemData.handle = eventHandle = function() {
// Handle the second event of a trigger and when
// an event is called after a page has unloaded
return typeof jQuery !== "undefined" && !jQuery.event.triggered ?
jQuery.event.handle.apply( eventHandle.elem, arguments ) :
undefined;
};
-
- handle = jQuery.data( elem, "handle", eventHandle );
}
// Add elem as a property of the handle function
- // This is to prevent a memory leak with non-native
- // event in IE.
- handle.elem = elem;
+ // This is to prevent a memory leak with non-native events in IE.
+ eventHandle.elem = elem;
// Handle multiple events separated by a space
// jQuery(...).bind("mouseover mouseout", fn);
- types = types.split( /\s+/ );
- var type, i=0;
+ types = types.split(" ");
+
+ var type, i = 0, namespaces;
+
while ( (type = types[ i++ ]) ) {
+ var handleObj = {
+ handler: handler,
+ data: data,
+ namespace: "",
+ guid: handler.guid
+ };
+
// Namespaced event handlers
- var namespaces = type.split(".");
- type = namespaces.shift();
- handler.type = namespaces.slice(0).sort().join(".");
+ if ( type.indexOf(".") > -1 ) {
+ namespaces = type.split(".");
+ type = namespaces.shift();
+ handleObj.namespace = namespaces.slice(0).sort().join(".");
+
+ } else {
+ namespaces = [];
+ }
+
+ handleObj.type = type;
// Get the current list of functions bound to this event
var handlers = events[ type ],
- special = this.special[ type ] || {};
-
-
+ special = jQuery.event.special[ type ] || {};
// Init the event handler queue
if ( !handlers ) {
- handlers = events[ type ] = {};
+ handlers = events[ type ] = [];
// Check for a special event handler
// Only use addEventListener/attachEvent if the special
// events handler returns false
- if ( !special.setup || special.setup.call( elem, data, namespaces, handler) === false ) {
+ if ( !special.setup || special.setup.call( elem, data, namespaces, handler ) === false ) {
// Bind the global event handler to the element
if ( elem.addEventListener ) {
- elem.addEventListener( type, handle, false );
+ elem.addEventListener( type, eventHandle, false );
+
} else if ( elem.attachEvent ) {
- elem.attachEvent( "on" + type, handle );
+ elem.attachEvent( "on" + type, eventHandle );
}
}
}
if ( special.add ) {
- var modifiedHandler = special.add.call( elem, handler, data, namespaces, handlers );
- if ( modifiedHandler && jQuery.isFunction( modifiedHandler ) ) {
- modifiedHandler.guid = modifiedHandler.guid || handler.guid;
- handler = modifiedHandler;
- }
- }
+ special.add.call( elem, handleObj );
+ }
// Add the function to the element's handler list
- handlers[ handler.guid ] = handler;
+ handlers.push( handleObj );
// Keep track of which events have been used, for global triggering
- this.global[ type ] = true;
+ jQuery.event.global[ type ] = true;
}
// Nullify elem to prevent memory leaks in IE
elem = null;
},
- guid: 1,
global: {},
// Detach an event or set of events from an element
- remove: function( elem, types, handler ) {
+ remove: function( elem, types, handler, pos ) {
// don't do events on text and comment nodes
if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
return;
}
- var events = jQuery.data( elem, "events" ), ret, type, fn;
+ var ret, type, fn, i = 0, all, namespaces, namespace, special, eventType, handleObj, origType,
+ elemData = jQuery.data( elem ),
+ events = elemData && elemData.events;
- if ( events ) {
- // Unbind all events for the element
- if ( types === undefined || (typeof types === "string" && types.charAt(0) === ".") ) {
- for ( type in events ) {
- this.remove( elem, type + (types || "") );
- }
- } else {
- // types is actually an event object here
- if ( types.type ) {
- handler = types.handler;
- types = types.type;
+ if ( !elemData || !events ) {
+ return;
+ }
+
+ // types is actually an event object here
+ if ( types && types.type ) {
+ handler = types.handler;
+ types = types.type;
+ }
+
+ // Unbind all events for the element
+ if ( !types || typeof types === "string" && types.charAt(0) === "." ) {
+ types = types || "";
+
+ for ( type in events ) {
+ jQuery.event.remove( elem, type + types );
+ }
+
+ return;
+ }
+
+ // Handle multiple events separated by a space
+ // jQuery(...).unbind("mouseover mouseout", fn);
+ types = types.split(" ");
+
+ while ( (type = types[ i++ ]) ) {
+ origType = type;
+ handleObj = null;
+ all = type.indexOf(".") < 0;
+ namespaces = [];
+
+ if ( !all ) {
+ // Namespaced event handlers
+ namespaces = type.split(".");
+ type = namespaces.shift();
+
+ namespace = new RegExp("(^|\\.)" +
+ jQuery.map( namespaces.slice(0).sort(), fcleanup ).join("\\.(?:.*\\.)?") + "(\\.|$)")
+ }
+
+ eventType = events[ type ];
+
+ if ( !eventType ) {
+ continue;
+ }
+
+ if ( !handler ) {
+ for ( var j = 0; j < eventType.length; j++ ) {
+ handleObj = eventType[ j ];
+
+ if ( all || namespace.test( handleObj.namespace ) ) {
+ jQuery.event.remove( elem, origType, handleObj.handler, j );
+ eventType.splice( j--, 1 );
+ }
}
- // Handle multiple events separated by a space
- // jQuery(...).unbind("mouseover mouseout", fn);
- types = types.split(/\s+/);
- var i = 0;
- while ( (type = types[ i++ ]) ) {
- // Namespaced event handlers
- var namespaces = type.split(".");
- type = namespaces.shift();
- var all = !namespaces.length,
- cleaned = jQuery.map( namespaces.slice(0).sort(), fcleanup ),
- namespace = new RegExp("(^|\\.)" + cleaned.join("\\.(?:.*\\.)?") + "(\\.|$)"),
- special = this.special[ type ] || {};
-
- if ( events[ type ] ) {
- // remove the given handler for the given type
- if ( handler ) {
- fn = events[ type ][ handler.guid ];
- delete events[ type ][ handler.guid ];
-
- // remove all handlers for the given type
- } else {
- for ( var handle in events[ type ] ) {
- // Handle the removal of namespaced events
- if ( all || namespace.test( events[ type ][ handle ].type ) ) {
- delete events[ type ][ handle ];
- }
- }
+ continue;
+ }
+
+ special = jQuery.event.special[ type ] || {};
+
+ for ( var j = pos || 0; j < eventType.length; j++ ) {
+ handleObj = eventType[ j ];
+
+ if ( handler.guid === handleObj.guid ) {
+ // remove the given handler for the given type
+ if ( all || namespace.test( handleObj.namespace ) ) {
+ fn = handleObj.handler;
+
+ if ( pos == null ) {
+ eventType.splice( j--, 1 );
}
if ( special.remove ) {
- special.remove.call( elem, namespaces, fn);
+ special.remove.call( elem, namespaces, handleObj );
}
+ }
- // remove generic event handler if no more handlers exist
- for ( ret in events[ type ] ) {
- break;
- }
- if ( !ret ) {
- if ( !special.teardown || special.teardown.call( elem, namespaces ) === false ) {
- if ( elem.removeEventListener ) {
- elem.removeEventListener( type, jQuery.data( elem, "handle" ), false );
- } else if ( elem.detachEvent ) {
- elem.detachEvent( "on" + type, jQuery.data( elem, "handle" ) );
- }
- }
- ret = null;
- delete events[ type ];
- }
+ if ( pos != null ) {
+ break;
}
}
}
- // Remove the expando if it's no longer used
- for ( ret in events ) {
- break;
- }
- if ( !ret ) {
- var handle = jQuery.data( elem, "handle" );
- if ( handle ) {
- handle.elem = null;
+ // remove generic event handler if no more handlers exist
+ if ( jQuery.isEmptyObject( events[ type ] ) ) {
+ if ( !special.teardown || special.teardown.call( elem, namespaces ) === false ) {
+ removeEvent( elem, type, elemData.handle );
}
- jQuery.removeData( elem, "events" );
- jQuery.removeData( elem, "handle" );
+
+ ret = null;
+ delete events[ type ];
+ }
+ }
+
+ // Remove the expando if it's no longer used
+ if ( jQuery.isEmptyObject( events ) ) {
+ var handle = elemData.handle;
+ if ( handle ) {
+ handle.elem = null;
+ }
+
+ delete elemData.events;
+ delete elemData.handle;
+
+ if ( jQuery.isEmptyObject( elemData ) ) {
+ jQuery.removeData( elem );
}
}
},
event.stopPropagation();
// Only trigger if we've ever bound an event for it
- if ( this.global[ type ] ) {
+ if ( jQuery.event.global[ type ] ) {
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;
+ var parent = elem.parentNode || elem.ownerDocument;
+
+ // Trigger an inline bound script
try {
if ( !(elem && elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()]) ) {
- nativeFn = elem[ type ];
- nativeHandler = elem[ "on" + type ];
+ if ( elem[ "on" + type ] && elem[ "on" + type ].apply( elem, data ) === false ) {
+ event.result = false;
+ }
}
+
// prevent IE from throwing an error for some elements with some event types, see #3533
} catch (e) {}
- var isClick = jQuery.nodeName(elem, "a") && type === "click";
+ if ( !event.isPropagationStopped() && parent ) {
+ jQuery.event.trigger( event, data, parent, true );
- // Trigger the native events (except for clicks on links)
- if ( !bubbling && nativeFn && !event.isDefaultPrevented() && !isClick ) {
- this.triggered = true;
- try {
- elem[ type ]();
- // prevent IE from throwing an error for some hidden elements
- } catch (e) {}
+ } else if ( !event.isDefaultPrevented() ) {
+ var target = event.target, old,
+ isClick = jQuery.nodeName(target, "a") && type === "click",
+ special = jQuery.event.special[ type ] || {};
- // Handle triggering native .onfoo handlers
- } else if ( nativeHandler && elem[ "on" + type ].apply( elem, data ) === false ) {
- event.result = false;
- }
+ if ( (!special._default || special._default.call( elem, event ) === false) &&
+ !isClick && !(target && target.nodeName && jQuery.noData[target.nodeName.toLowerCase()]) ) {
+
+ try {
+ if ( target[ type ] ) {
+ // Make sure that we don't accidentally re-trigger the onFOO events
+ old = target[ "on" + type ];
+
+ if ( old ) {
+ target[ "on" + type ] = null;
+ }
+
+ jQuery.event.triggered = true;
+ target[ type ]();
+ }
- this.triggered = false;
+ // prevent IE from throwing an error for some elements with some event types, see #3533
+ } catch (e) {}
- if ( !event.isPropagationStopped() ) {
- var parent = elem.parentNode || elem.ownerDocument;
- if ( parent ) {
- jQuery.event.trigger( event, data, parent, true );
+ if ( old ) {
+ target[ "on" + type ] = old;
+ }
+
+ jQuery.event.triggered = false;
}
}
},
handle: function( event ) {
- // returned undefined or false
- var all, handlers;
+ var all, handlers, namespaces, namespace, events;
event = arguments[0] = jQuery.event.fix( event || window.event );
event.currentTarget = this;
// Namespaced event handlers
- var namespaces = event.type.split(".");
- event.type = namespaces.shift();
-
- // Cache this now, all = true means, any handler
- all = !namespaces.length && !event.exclusive;
-
- var namespace = new RegExp("(^|\\.)" + namespaces.slice(0).sort().join("\\.(?:.*\\.)?") + "(\\.|$)");
-
- handlers = ( jQuery.data(this, "events") || {} )[ event.type ];
-
- for ( var j in handlers ) {
- var handler = handlers[ j ];
+ all = event.type.indexOf(".") < 0;
- // Filter the functions by class
- if ( all || namespace.test(handler.type) ) {
- // Pass in a reference to the handler function itself
- // So that we can later remove it
- event.handler = handler;
- event.data = handler.data;
-
- var ret = handler.apply( this, arguments );
+ if ( !all ) {
+ namespaces = event.type.split(".");
+ event.type = namespaces.shift();
+ namespace = new RegExp("(^|\\.)" + namespaces.slice(0).sort().join("\\.(?:.*\\.)?") + "(\\.|$)");
+ }
- if ( ret !== undefined ) {
- event.result = ret;
- if ( ret === false ) {
- event.preventDefault();
- event.stopPropagation();
+ var events = jQuery.data(this, "events"), handlers = events[ event.type ];
+
+ if ( events && handlers ) {
+ // Clone the handlers to prevent manipulation
+ handlers = handlers.slice(0);
+
+ for ( var j = 0, l = handlers.length; j < l; j++ ) {
+ var handleObj = handlers[ j ];
+
+ // Filter the functions by class
+ if ( (all && !event.exclusive) || namespace.test( handleObj.namespace ) ) {
+ // Pass in a reference to the handler function itself
+ // So that we can later remove it
+ event.handler = handleObj.handler;
+ event.data = handleObj.data;
+
+ var ret = handleObj.handler.apply( this, arguments );
+
+ if ( ret !== undefined ) {
+ event.result = ret;
+ if ( ret === false ) {
+ event.preventDefault();
+ event.stopPropagation();
+ }
}
- }
- if ( event.isImmediatePropagationStopped() ) {
- break;
+ if ( event.isImmediatePropagationStopped() ) {
+ break;
+ }
}
-
}
}
return event;
},
- 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++;
+ // Deprecated, use jQuery.guid instead
+ guid: 1E8,
- // So proxy can be declared as an argument
- return proxy;
- },
+ // Deprecated, use jQuery.proxy instead
+ proxy: jQuery.proxy,
special: {
ready: {
jQuery.extend( proxy, data || {} );
proxy.guid += data.selector + data.live;
+ data.liveProxy = proxy;
+
jQuery.event.add( this, data.live, liveHandler, data );
},
}
};
+var removeEvent = document.removeEventListener ?
+ function( elem, type, handle ) {
+ elem.removeEventListener( type, handle, false );
+ } :
+ function( elem, type, handle ) {
+ elem.detachEvent( "on" + type, handle );
+ };
+
jQuery.Event = function( src ) {
// Allow instantiation without the 'new' keyword
if ( !this.preventDefault ) {
return trigger( "submit", this, arguments );
}
});
+
+ } else {
+ return false;
}
},
data = jQuery.data( elem, "_change_data" );
val = getVal(elem);
- if ( val === data ) {
- return;
- }
-
// the current data will be also retrieved by beforeactivate
if ( e.type !== "focusout" || elem.type !== "radio" ) {
jQuery.data( elem, "_change_data", val );
}
+
+ if ( data === undefined || val === data ) {
+ return;
+ }
- if ( elem.type !== "select" && (data != null || val) ) {
+ if ( data != null || val ) {
e.type = "change";
- return jQuery.event.trigger( e, arguments[1], this );
+ return jQuery.event.trigger( e, arguments[1], elem );
}
}
// information/focus[in] is not needed anymore
beforeactivate: function( e ) {
var elem = e.target;
-
- if ( elem.nodeName.toLowerCase() === "input" && elem.type === "radio" ) {
- jQuery.data( elem, "_change_data", getVal(elem) );
- }
+ jQuery.data( elem, "_change_data", getVal(elem) );
}
},
setup: function( data, namespaces, fn ) {
}
jQuery.each(["bind", "one"], function( i, name ) {
- jQuery.fn[ name ] = function( type, data, fn, thisObject ) {
+ jQuery.fn[ name ] = function( type, data, fn ) {
// Handle object literals
if ( typeof type === "object" ) {
for ( var key in type ) {
}
if ( jQuery.isFunction( data ) ) {
- thisObject = fn;
fn = data;
data = undefined;
}
- fn = thisObject === undefined ? fn : jQuery.event.proxy( fn, thisObject );
- var handler = name === "one" ? jQuery.event.proxy( fn, function( event ) {
+
+ var handler = name === "one" ? jQuery.proxy( fn, function( event ) {
jQuery( this ).unbind( event, handler );
return fn.apply( this, arguments );
}) : fn;
- return type === "unload" ? this.one(type, data, handler, thisObject) : this.each(function() {
- jQuery.event.add( this, type, handler, data );
- });
+
+ if ( type === "unload" && name !== "one" ) {
+ this.one( type, data, fn );
+
+ } else {
+ for ( var i = 0, l = this.length; i < l; i++ ) {
+ jQuery.event.add( this[i], type, handler, data );
+ }
+ }
+
+ return this;
};
});
for ( var key in type ) {
this.unbind(key, type[key]);
}
- return this;
+
+ } else {
+ for ( var i = 0, l = this.length; i < l; i++ ) {
+ jQuery.event.remove( this[i], type, fn );
+ }
}
- return this.each(function() {
- jQuery.event.remove( this, type, fn );
- });
+ 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 );
// link all the functions, so any of them can unbind this click handler
while ( i < args.length ) {
- jQuery.event.proxy( fn, args[ i++ ] );
+ jQuery.proxy( fn, args[ i++ ] );
}
- return this.click( jQuery.event.proxy( fn, function( event ) {
+ 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 );
hover: function( fnOver, fnOut ) {
return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
- },
+ }
+});
+
+jQuery.each(["live", "die"], function( i, name ) {
+ jQuery.fn[ name ] = function( types, data, fn, origSelector /* Internal Use Only */ ) {
+ var type, i = 0,
+ selector = origSelector || this.selector,
+ context = origSelector ? this : jQuery( this.context );
- 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: data, selector: this.selector, live: type
- }, fn, thisObject );
- return this;
- },
- die: function( type, fn ) {
- jQuery( this.context ).unbind( liveConvert( type, this.selector ), fn ? { guid: fn.guid + this.selector + type } : null );
+ types = (types || "").split( /\s+/ );
+
+ while ( (type = types[ i++ ]) != null ) {
+ type = type === "focus" ? "focusin" : // focus --> focusin
+ type === "blur" ? "focusout" : // blur --> focusout
+ type === "hover" ? types.push("mouseleave") && "mouseenter" : // hover support
+ type;
+
+ if ( name === "live" ) {
+ // bind live handler
+ context.bind( liveConvert( type, selector ), {
+ data: data, selector: selector, live: type
+ }, fn );
+
+ } else {
+ // unbind live handler
+ context.unbind( liveConvert( type, selector ), fn ? { guid: fn.guid + selector + type } : null );
+ }
+ }
+
return this;
}
});
function liveHandler( event ) {
- var stop = true, elems = [], selectors = [], args = arguments,
- related, match, fn, elem, j, i, data,
+ var stop, elems = [], selectors = [], args = arguments,
+ related, match, fn, elem, j, i, l, data,
live = jQuery.extend({}, jQuery.data( this, "events" ).live);
+ // Make sure we avoid non-left-click bubbling in Firefox (#3861)
+ if ( event.button && event.type === "click" ) {
+ return;
+ }
+
for ( j in live ) {
fn = live[j];
if ( fn.live === event.type ||
}
function liveConvert( type, selector ) {
- return ["live", type, selector.replace(/\./g, "`").replace(/ /g, "&")].join(".");
+ return "live." + (type && type !== "*" ? type + "." : "") + selector.replace(/\./g, "`").replace(/ /g, "&");
}
-jQuery.each( ("blur focus load resize scroll unload click dblclick " +
+jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " +
"mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
"change select submit keydown keypress keyup error").split(" "), function( i, name ) {
return fn ? this.bind( name, fn ) : this.trigger( name );
};
- if ( jQuery.fnAttr ) {
- jQuery.fnAttr[ name ] = true;
+ if ( jQuery.attrFn ) {
+ jQuery.attrFn[ name ] = true;
}
});