+(function( jQuery ) {
+
var rnamespaces = /\.(.*)$/,
+ rformElems = /^(?:textarea|input|select)$/i,
+ rperiod = /\./g,
+ rspace = / /g,
+ rescape = /[^\w\s.|`]/g,
fcleanup = function( nm ) {
- return nm.replace(/[^\w\s\.\|`]/g, function( ch ) {
- return "\\" + ch;
- });
- };
+ return nm.replace(rescape, "\\$&");
+ },
+ focusCounts = { focusin: 0, focusout: 0 };
/*
* A number of helper functions used for managing events.
// For whatever reason, IE has trouble passing the window object
// around, causing it to be cloned in the process
- if ( elem.setInterval && ( elem !== window && !elem.frameElement ) ) {
+ if ( jQuery.isWindow( elem ) && ( elem !== window && !elem.frameElement ) ) {
elem = window;
}
+ if ( handler === false ) {
+ handler = returnFalse;
+ } else if ( !handler ) {
+ // Fixes bug #7229. Fix recommended by jdalton
+ return;
+ }
+
var handleObjIn, handleObj;
if ( handler.handler ) {
return;
}
- var events = elemData.events = elemData.events || {},
- eventHandle = elemData.handle, eventHandle;
+ // Use a key less likely to result in collisions for plain JS objects.
+ // Fixes bug #7150.
+ var eventKey = elem.nodeType ? "events" : "__events__",
+ 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() {
}
handleObj.type = type;
- handleObj.guid = handler.guid;
+ if ( !handleObj.guid ) {
+ handleObj.guid = handler.guid;
+ }
// Get the current list of functions bound to this event
var handlers = events[ type ],
if ( special.add ) {
special.add.call( elem, handleObj );
+
+ if ( !handleObj.handler.guid ) {
+ handleObj.handler.guid = handler.guid;
+ }
}
// Add the function to the element's handler list
return;
}
- var ret, type, fn, i = 0, all, namespaces, namespace, special, eventType, handleObj, origType,
+ if ( handler === false ) {
+ handler = returnFalse;
+ }
+
+ var ret, type, fn, j, i = 0, all, namespaces, namespace, special, eventType, handleObj, origType,
+ eventKey = elem.nodeType ? "events" : "__events__",
elemData = jQuery.data( elem ),
- events = elemData && elemData.events;
+ 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 ) {
type = namespaces.shift();
namespace = new RegExp("(^|\\.)" +
- jQuery.map( namespaces.slice(0).sort(), fcleanup ).join("\\.(?:.*\\.)?") + "(\\.|$)")
+ jQuery.map( namespaces.slice(0).sort(), fcleanup ).join("\\.(?:.*\\.)?") + "(\\.|$)");
}
eventType = events[ type ];
}
if ( !handler ) {
- for ( var j = 0; j < eventType.length; j++ ) {
+ for ( j = 0; j < eventType.length; j++ ) {
handleObj = eventType[ j ];
if ( all || namespace.test( handleObj.namespace ) ) {
special = jQuery.event.special[ type ] || {};
- for ( var j = pos || 0; j < eventType.length; j++ ) {
+ for ( j = pos || 0; j < eventType.length; j++ ) {
handleObj = eventType[ j ];
if ( handler.guid === handleObj.guid ) {
// remove generic event handler if no more handlers exist
if ( eventType.length === 0 || pos != null && eventType.length === 1 ) {
if ( !special.teardown || special.teardown.call( elem, namespaces ) === false ) {
- removeEvent( elem, type, elemData.handle );
+ jQuery.removeEvent( elem, type, elemData.handle );
}
ret = null;
delete elemData.events;
delete elemData.handle;
- if ( jQuery.isEmptyObject( elemData ) ) {
+ if ( typeof elemData === "function" ) {
+ jQuery.removeData( elem, eventKey );
+
+ } else if ( jQuery.isEmptyObject( elemData ) ) {
jQuery.removeData( elem );
}
}
if ( !bubbling ) {
event = typeof event === "object" ?
// jQuery.Event object
- event[expando] ? event :
+ event[ jQuery.expando ] ? event :
// Object literal
jQuery.extend( jQuery.Event(type), event ) :
// Just the event type (string)
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, "__events__" ) || {}).handle;
+
if ( handle ) {
handle.apply( elem, data );
}
if ( !(elem && elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()]) ) {
if ( elem[ "on" + type ] && elem[ "on" + type ].apply( elem, data ) === false ) {
event.result = false;
+ event.preventDefault();
}
}
// prevent IE from throwing an error for some elements with some event types, see #3533
- } catch (e) {}
+ } catch (inlineError) {}
if ( !event.isPropagationStopped() && parent ) {
jQuery.event.trigger( event, data, parent, true );
} else if ( !event.isDefaultPrevented() ) {
- var target = event.target, old,
- isClick = jQuery.nodeName(target, "a") && type === "click",
- special = jQuery.event.special[ type ] || {};
+ var target = event.target, old, 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) &&
!isClick && !(target && target.nodeName && jQuery.noData[target.nodeName.toLowerCase()]) ) {
try {
- if ( target[ type ] ) {
+ if ( target[ targetType ] ) {
// Make sure that we don't accidentally re-trigger the onFOO events
- old = target[ "on" + type ];
+ old = target[ "on" + targetType ];
if ( old ) {
- target[ "on" + type ] = null;
+ target[ "on" + targetType ] = null;
}
jQuery.event.triggered = true;
- target[ type ]();
+ target[ targetType ]();
}
// prevent IE from throwing an error for some elements with some event types, see #3533
- } catch (e) {}
+ } catch (triggerError) {}
if ( old ) {
- target[ "on" + type ] = old;
+ target[ "on" + targetType ] = old;
}
jQuery.event.triggered = false;
},
handle: function( event ) {
- var all, handlers, namespaces, namespace, events;
+ var all, handlers, namespaces, namespace_sort = [], namespace_re, events, args = jQuery.makeArray( arguments );
- event = arguments[0] = jQuery.event.fix( event || window.event );
+ event = args[0] = jQuery.event.fix( event || window.event );
event.currentTarget = this;
// Namespaced event handlers
if ( !all ) {
namespaces = event.type.split(".");
event.type = namespaces.shift();
- namespace = new RegExp("(^|\\.)" + namespaces.slice(0).sort().join("\\.(?:.*\\.)?") + "(\\.|$)");
+ namespace_sort = namespaces.slice(0).sort();
+ namespace_re = new RegExp("(^|\\.)" + namespace_sort.join("\\.(?:.*\\.)?") + "(\\.|$)");
}
- var events = jQuery.data(this, "events"), handlers = events[ event.type ];
+ event.namespace = event.namespace || namespace_sort.join(".");
+
+ events = jQuery.data(this, this.nodeType ? "events" : "__events__");
+
+ if ( typeof events === "function" ) {
+ events = events.events;
+ }
+
+ handlers = (events || {})[ event.type ];
if ( events && handlers ) {
// Clone the handlers to prevent manipulation
var handleObj = handlers[ j ];
// Filter the functions by class
- if ( all || namespace.test( handleObj.namespace ) ) {
+ if ( all || namespace_re.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;
event.handleObj = handleObj;
- var ret = handleObj.handler.apply( this, arguments );
+ var ret = handleObj.handler.apply( this, args );
if ( ret !== undefined ) {
event.result = ret;
return event.result;
},
- props: "altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),
+ props: "altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),
fix: function( event ) {
- if ( event[ expando ] ) {
+ if ( event[ jQuery.expando ] ) {
return event;
}
}
// 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)
live: {
add: function( handleObj ) {
- jQuery.event.add( this, handleObj.origType, jQuery.extend({}, handleObj, {handler: liveHandler}) );
+ jQuery.event.add( this,
+ liveConvert( handleObj.origType, handleObj.selector ),
+ jQuery.extend({}, handleObj, {handler: liveHandler, guid: handleObj.handler.guid}) );
},
remove: function( handleObj ) {
- var remove = true,
- type = handleObj.origType.replace(rnamespaces, "");
-
- jQuery.each( jQuery.data(this, "events").live || [], function() {
- if ( type === this.origType.replace(rnamespaces, "") ) {
- remove = false;
- return false;
- }
- });
-
- if ( remove ) {
- jQuery.event.remove( this, handleObj.origType, liveHandler );
- }
+ jQuery.event.remove( this, liveConvert( handleObj.origType, handleObj.selector ), handleObj );
}
-
},
beforeunload: {
setup: function( data, namespaces, eventHandle ) {
// We only want to do this special case on windows
- if ( this.setInterval ) {
+ if ( jQuery.isWindow( this ) ) {
this.onbeforeunload = eventHandle;
}
-
- return false;
},
+
teardown: function( namespaces, eventHandle ) {
if ( this.onbeforeunload === eventHandle ) {
this.onbeforeunload = null;
}
};
-var removeEvent = document.removeEventListener ?
+jQuery.removeEvent = document.removeEventListener ?
function( elem, type, handle ) {
- elem.removeEventListener( type, handle, false );
+ if ( elem.removeEventListener ) {
+ elem.removeEventListener( type, handle, false );
+ }
} :
function( elem, type, handle ) {
- elem.detachEvent( "on" + type, handle );
+ if ( elem.detachEvent ) {
+ elem.detachEvent( "on" + type, handle );
+ }
};
jQuery.Event = function( src ) {
// timeStamp is buggy for some events on Firefox(#3843)
// So we won't rely on the native value
- this.timeStamp = now();
+ this.timeStamp = jQuery.now();
// Mark it as fixed
- this[ expando ] = true;
+ this[ jQuery.expando ] = true;
};
function returnFalse() {
// if preventDefault exists run it on the original event
if ( e.preventDefault ) {
e.preventDefault();
- }
+
// otherwise set the returnValue property of the original event to false (IE)
- e.returnValue = false;
+ } else {
+ e.returnValue = false;
+ }
},
stopPropagation: function() {
this.isPropagationStopped = returnTrue;
// Check if mouse(over|out) are still within the same parent element
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 {
+ // Firefox sometimes assigns relatedTarget a XUL element
+ // which we cannot access the parentNode property of
+ try {
+ // Traverse up the tree
+ while ( parent && parent !== this ) {
parent = parent.parentNode;
-
- // assuming we've left the element since we most likely mousedover a xul element
- } catch(e) {
- break;
}
- }
- if ( parent !== this ) {
- // set the correct event type
- event.type = event.data;
+ if ( parent !== this ) {
+ // set the correct event type
+ event.type = event.data;
- // handle event if we actually just moused on to a non sub-element
- jQuery.event.handle.apply( this, arguments );
- }
+ // handle event if we actually just moused on to a non sub-element
+ jQuery.event.handle.apply( this, arguments );
+ }
+ // assuming we've left the element since we most likely mousedover a xul element
+ } catch(e) { }
},
// In case of event delegation, we only need to rename the event.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 );
}
});
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 );
}
});
// change delegation, happens here so we have bind.
if ( !jQuery.support.changeBubbles ) {
- var formElems = /textarea|input|select/i,
-
- changeFilters,
+ var changeFilters,
getVal = function( elem ) {
var type = elem.type, val = elem.value;
testChange = function testChange( e ) {
var elem = e.target, data, val;
- if ( !formElems.test( elem.nodeName ) || elem.readOnly ) {
+ if ( !rformElems.test( elem.nodeName ) || elem.readOnly ) {
return;
}
if ( data != null || val ) {
e.type = "change";
+ e.liveFired = undefined;
return jQuery.event.trigger( e, arguments[1], elem );
}
};
filters: {
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.event.add( this, type + ".specialChange", changeFilters[type] );
}
- return formElems.test( this.nodeName );
+ return rformElems.test( this.nodeName );
},
teardown: function( namespaces ) {
jQuery.event.remove( this, ".specialChange" );
- return formElems.test( this.nodeName );
+ return rformElems.test( this.nodeName );
}
};
changeFilters = jQuery.event.special.change.filters;
+
+ // Handle when the input is .focus()'d
+ changeFilters.focus = changeFilters.beforeactivate;
}
function trigger( type, elem, args ) {
jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) {
jQuery.event.special[ fix ] = {
setup: function() {
- this.addEventListener( orig, handler, true );
+ if ( focusCounts[fix]++ === 0 ) {
+ document.addEventListener( orig, handler, true );
+ }
},
teardown: function() {
- this.removeEventListener( orig, handler, true );
+ if ( --focusCounts[fix] === 0 ) {
+ document.removeEventListener( orig, handler, true );
+ }
}
};
function handler( e ) {
e = jQuery.event.fix( e );
e.type = fix;
- return jQuery.event.handle.call( this, e );
+ return jQuery.event.trigger( e, null, e.target );
}
});
}
return this;
}
- if ( jQuery.isFunction( data ) ) {
+ if ( jQuery.isFunction( data ) || data === false ) {
fn = data;
data = undefined;
}
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;
+ }
if ( jQuery.isFunction( data ) ) {
fn = data;
}
preType = type;
- type = (liveMap[ type ] || type) + namespaces;
+
+ if ( type === "focus" || type === "blur" ) {
+ types.push( liveMap[ type ] + namespaces );
+ type = type + namespaces;
+
+ } else {
+ type = (liveMap[ type ] || type) + namespaces;
+ }
if ( name === "live" ) {
// bind live handler
- context.each(function(){
- jQuery.event.add( this, liveConvert( type, selector ),
+ for ( var j = 0, l = context.length; j < l; j++ ) {
+ jQuery.event.add( context[j], "live." + liveConvert( type, selector ),
{ data: data, selector: selector, handler: fn, origType: type, origHandler: fn, preType: preType } );
- });
+ }
} else {
// unbind live handler
- context.unbind( liveConvert( type, selector ), fn );
+ context.unbind( "live." + liveConvert( type, selector ), fn );
}
}
return this;
- }
+ };
});
function liveHandler( event ) {
- var stop, elems = [], selectors = [], args = arguments,
- related, match, handleObj, elem, j, i, l, data,
- events = jQuery.data( this, "events" );
+ var stop, maxLevel, elems = [], selectors = [],
+ related, match, handleObj, elem, j, i, l, data, close, namespace, ret,
+ events = jQuery.data( this, this.nodeType ? "events" : "__events__" );
+
+ 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" ) {
return;
}
+ if ( event.namespace ) {
+ namespace = new RegExp("(^|\\.)" + event.namespace.split(".").join("\\.(?:.*\\.)?") + "(\\.|$)");
+ }
+
event.liveFired = this;
var live = events.live.slice(0);
match = jQuery( event.target ).closest( selectors, event.currentTarget );
for ( i = 0, l = match.length; i < l; i++ ) {
+ close = match[i];
+
for ( j = 0; j < live.length; j++ ) {
handleObj = live[j];
- if ( match[i].selector === handleObj.selector ) {
- elem = match[i].elem;
+ if ( close.selector === handleObj.selector && (!namespace || namespace.test( handleObj.namespace )) ) {
+ elem = close.elem;
related = null;
// Those two events require additional checking
if ( handleObj.preType === "mouseenter" || handleObj.preType === "mouseleave" ) {
+ event.type = handleObj.preType;
related = jQuery( event.relatedTarget ).closest( handleObj.selector )[0];
}
if ( !related || related !== elem ) {
- elems.push({ elem: elem, handleObj: handleObj });
+ elems.push({ elem: elem, handleObj: handleObj, level: close.level });
}
}
}
for ( i = 0, l = elems.length; i < l; i++ ) {
match = elems[i];
+
+ if ( maxLevel && match.level > maxLevel ) {
+ break;
+ }
+
event.currentTarget = match.elem;
event.data = match.handleObj.data;
event.handleObj = match.handleObj;
- if ( match.handleObj.origHandler.apply( match.elem, args ) === false ) {
- stop = false;
- break;
+ ret = match.handleObj.origHandler.apply( match.elem, arguments );
+
+ if ( ret === false || event.isPropagationStopped() ) {
+ maxLevel = match.level;
+
+ if ( ret === false ) {
+ stop = false;
+ }
+ if ( event.isImmediatePropagationStopped() ) {
+ break;
+ }
}
}
}
function liveConvert( type, selector ) {
- return "live." + (type && type !== "*" ? type + "." : "") + selector.replace(/\./g, "`").replace(/ /g, "&");
+ return (type && type !== "*" ? type + "." : "") + selector.replace(rperiod, "`").replace(rspace, "&");
}
jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " +
"change select submit keydown keypress keyup error").split(" "), function( i, name ) {
// Handle event binding
- jQuery.fn[ name ] = function( fn ) {
- return fn ? this.bind( name, fn ) : this.trigger( name );
+ jQuery.fn[ name ] = function( data, fn ) {
+ if ( fn == null ) {
+ fn = data;
+ data = null;
+ }
+
+ return arguments.length > 0 ?
+ this.bind( name, data, fn ) :
+ this.trigger( name );
};
if ( jQuery.attrFn ) {
// More info:
// - http://isaacschlueter.com/2006/10/msie-memory-leaks/
if ( window.attachEvent && !window.addEventListener ) {
- window.attachEvent("onunload", function() {
+ jQuery(window).bind("unload", function() {
for ( var id in jQuery.cache ) {
if ( jQuery.cache[ id ].handle ) {
// Try/Catch is to handle iframes being unloaded, see #4280
}
});
}
+
+})( jQuery );