+var fcleanup = function( nm ) {
+ return nm.replace(/[^\w\s\.\|`]/g, function( ch ) {
+ return "\\" + ch;
+ });
+};
+
/*
* A number of helper functions used for managing events.
* Many of the ideas behind this code originated from
// 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
var fn = handler;
// Create unique handler function, wrapped around original handler
- handler = this.proxy( fn );
+ handler = jQuery.proxy( fn );
// Store data in unique handler
handler.data = data;
// 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() {
+ handle = jQuery.data( elem, "handle" ), eventHandle;
+
+ if ( !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( arguments.callee.elem, arguments ) :
+ jQuery.event.handle.apply( eventHandle.elem, arguments ) :
undefined;
- });
+ };
+
+ handle = jQuery.data( elem, "handle", eventHandle );
+ }
+
+ // If no handle is found then we must be trying to bind to one of the
+ // banned noData elements
+ if ( !handle ) {
+ return;
+ }
+
// Add elem as a property of the handle function
// This is to prevent a memory leak with non-native
// event in IE.
elem = null;
},
- guid: 1,
global: {},
// Detach an event or set of events from an element
var namespaces = type.split(".");
type = namespaces.shift();
var all = !namespaces.length,
- cleaned = jQuery.map( namespaces.slice(0).sort() , function(nm){ return nm.replace(/[^\w\s\.\|`]/g, function(ch){return "\\"+ch; }); }),
+ cleaned = jQuery.map( namespaces.slice(0).sort(), fcleanup ),
namespace = new RegExp("(^|\\.)" + cleaned.join("\\.(?:.*\\.)?") + "(\\.|$)"),
special = this.special[ type ] || {};
if ( !elem ) {
// Don't bubble custom events when global (to avoid too much overhead)
event.stopPropagation();
+
// Only trigger if we've ever bound an event for it
if ( this.global[ type ] ) {
jQuery.each( jQuery.cache, function() {
var nativeFn, nativeHandler;
try {
- nativeFn = elem[ type ];
- nativeHandler = elem[ "on" + type ];
+ if ( !(elem && elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()]) ) {
+ nativeFn = elem[ type ];
+ nativeHandler = elem[ "on" + type ];
+ }
// prevent IE from throwing an error for some elements with some event types, see #3533
} catch (e) {}
if ( !bubbling && nativeFn && !event.isDefaultPrevented() && !isClick ) {
this.triggered = true;
try {
- nativeFn();
+ elem[ type ]();
// prevent IE from throwing an error for some hidden elements
} catch (e) {}
// Handle triggering native .onfoo handlers
- } else if ( nativeHandler && nativeHandler.apply( elem, data ) === false ) {
+ } else if ( nativeHandler && elem[ "on" + type ].apply( elem, data ) === false ) {
event.result = false;
}
event.metaKey = event.ctrlKey;
}
- // Add which for click: 1 == left; 2 == middle; 3 == right
+ // 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 !== undefined ) {
event.which = (event.button & 1 ? 1 : ( event.button & 2 ? 3 : ( event.button & 4 ? 2 : 0 ) ));
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++;
- // So proxy can be declared as an argument
- return proxy;
- },
+ // Deprecated, use jQuery.guid instead
+ guid: 1E8,
+
+ // Deprecated, use jQuery.proxy instead
+ proxy: jQuery.proxy,
special: {
ready: {
// Make sure the ready event is setup
- setup: bindReady,
- teardown: function() {}
+ setup: jQuery.bindReady,
+ teardown: jQuery.noop
},
live: {
}
};
-jQuery.Event = function( src ){
+jQuery.Event = function( src ) {
// Allow instantiation without the 'new' keyword
if ( !this.preventDefault ) {
return new jQuery.Event( src );
// otherwise set the cancelBubble property of the original event to true (IE)
e.cancelBubble = true;
},
- stopImmediatePropagation: function(){
+ stopImmediatePropagation: function() {
this.isImmediatePropagationStopped = returnTrue;
this.stopPropagation();
},
isPropagationStopped: returnFalse,
isImmediatePropagationStopped: returnFalse
};
+
// Checks if an event happened on an element within another element
// Used in jQuery.event.special.mouseenter and mouseleave handlers
var withinElement = function( event ) {
// Check if mouse(over|out) are still within the same parent element
var parent = event.relatedTarget;
+
// Traverse up the tree
- while ( parent && parent != this ) {
+ while ( parent && parent !== this ) {
// Firefox sometimes assigns relatedTarget a XUL element
// which we cannot access the parentNode property of
- try { parent = parent.parentNode; }
+ try {
+ parent = parent.parentNode;
+
// assuming we've left the element since we most likely mousedover a xul element
- catch(e) { break; }
+ } catch(e) {
+ break;
+ }
}
- if ( parent != this ) {
+ 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 );
}
mouseleave: "mouseout"
}, function( orig, fix ) {
jQuery.event.special[ orig ] = {
- setup: function(data){
+ setup: function( data ) {
jQuery.event.add( this, fix, data && data.selector ? delegate : withinElement, orig );
},
- teardown: function(data){
+ teardown: function( data ) {
jQuery.event.remove( this, fix, data && data.selector ? delegate : withinElement );
}
};
});
// submit delegation
+if ( !jQuery.support.submitBubbles ) {
+
jQuery.event.special.submit = {
setup: function( data, namespaces, fn ) {
- if ( !jQuery.support.submitBubbles && this.nodeName.toLowerCase() !== "form" ) {
+ if ( this.nodeName.toLowerCase() !== "form" ) {
jQuery.event.add(this, "click.specialSubmit." + fn.guid, function( e ) {
var elem = e.target, type = elem.type;
return trigger( "submit", this, arguments );
}
});
- }
- return false;
+ } else {
+ return false;
+ }
},
remove: function( namespaces, fn ) {
}
};
+}
+
// change delegation, happens here so we have bind.
-jQuery.event.special.change = {
- filters: {
- click: function( e ) {
- var elem = e.target;
+if ( !jQuery.support.changeBubbles ) {
- if ( elem.nodeName.toLowerCase() === "input" && elem.type === "checkbox" ) {
- return trigger( "change", this, arguments );
- }
+var formElems = /textarea|input|select/i;
- return changeFilters.keyup.call( this, e );
- },
- keyup: function( e ) {
- var elem = e.target, data, index = elem.selectedIndex + "";
+function getVal( elem ) {
+ var type = elem.type, val = elem.value;
- if ( elem.nodeName.toLowerCase() === "select" ) {
- data = jQuery.data( elem, "_change_data" );
- jQuery.data( elem, "_change_data", index );
+ if ( type === "radio" || type === "checkbox" ) {
+ val = elem.checked;
- if ( (elem.type === "select-multiple" || data != null) && data !== index ) {
- return trigger( "change", this, arguments );
- }
- }
- },
- beforeactivate: function( e ) {
- var elem = e.target;
+ } else if ( type === "select-multiple" ) {
+ val = elem.selectedIndex > -1 ?
+ jQuery.map( elem.options, function( elem ) {
+ return elem.selected;
+ }).join("-") :
+ "";
+
+ } else if ( elem.nodeName.toLowerCase() === "select" ) {
+ val = elem.selectedIndex;
+ }
- if ( elem.nodeName.toLowerCase() === "input" && elem.type === "radio" && !elem.checked ) {
- return trigger( "change", this, arguments );
+ return val;
+}
+
+function testChange( e ) {
+ var elem = e.target, data, val;
+
+ if ( !formElems.test( elem.nodeName ) || elem.readOnly ) {
+ return;
+ }
+
+ 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 ( elem.type !== "select" && (data != null || val) ) {
+ e.type = "change";
+ return jQuery.event.trigger( e, arguments[1], this );
+ }
+}
+
+jQuery.event.special.change = {
+ filters: {
+ focusout: testChange,
+
+ click: function( e ) {
+ var elem = e.target, type = elem.type;
+
+ if ( type === "radio" || type === "checkbox" || elem.nodeName.toLowerCase() === "select" ) {
+ return testChange.call( this, e );
}
},
- blur: function( e ) {
- var elem = e.target, nodeName = elem.nodeName.toLowerCase();
- if ( (nodeName === "textarea" || (nodeName === "input" && (elem.type === "text" || elem.type === "password")))
- && jQuery.data(elem, "_change_data") !== elem.value ) {
+ // Change has to be called before submit
+ // Keydown will be called before keypress, which is used in submit-event delegation
+ keydown: function( e ) {
+ var elem = e.target, type = elem.type;
- return trigger( "change", this, arguments );
+ if ( (e.keyCode === 13 && elem.nodeName.toLowerCase() !== "textarea") ||
+ (e.keyCode === 32 && (type === "checkbox" || type === "radio")) ||
+ type === "select-multiple" ) {
+ return testChange.call( this, e );
}
},
- focus: function( e ) {
- var elem = e.target, nodeName = elem.nodeName.toLowerCase();
- if ( nodeName === "textarea" || (nodeName === "input" && (elem.type === "text" || elem.type === "password" ) ) ) {
- jQuery.data( elem, "_change_data", elem.value );
+ // 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
+ beforeactivate: function( e ) {
+ var elem = e.target;
+
+ if ( elem.nodeName.toLowerCase() === "input" && elem.type === "radio" ) {
+ jQuery.data( elem, "_change_data", getVal(elem) );
}
}
},
setup: function( data, namespaces, fn ) {
- // return false if we bubble
- if ( !jQuery.support.changeBubbles ) {
- for ( var type in changeFilters ) {
- jQuery.event.add( this, type + ".specialChange." + fn.guid, changeFilters[type] );
- }
+ for ( var type in changeFilters ) {
+ jQuery.event.add( this, type + ".specialChange." + fn.guid, changeFilters[type] );
}
-
- // always want to listen for change for trigger
- return false;
+
+ return formElems.test( this.nodeName );
},
remove: function( namespaces, fn ) {
- if ( !jQuery.support.changeBubbles ) {
- for ( var type in changeFilters ) {
- jQuery.event.remove( this, type + ".specialChange" + (fn ? "."+fn.guid : ""), changeFilters[type] );
- }
+ for ( var type in changeFilters ) {
+ jQuery.event.remove( this, type + ".specialChange" + (fn ? "."+fn.guid : ""), changeFilters[type] );
}
+
+ return formElems.test( this.nodeName );
}
};
var changeFilters = jQuery.event.special.change.filters;
+}
+
function trigger( type, elem, args ) {
args[0].type = type;
return jQuery.event.handle.apply( elem, args );
}
// Create "bubbling" focus and blur events
-jQuery.each({
- focus: "focusin",
- blur: "focusout"
-}, function( orig, fix ){
- var event = jQuery.event,
- handle = event.handle;
-
- function ieHandler() {
- arguments[0].type = orig;
- return handle.apply(this, arguments);
- }
-
- event.special[orig] = {
- setup:function() {
- if ( this.addEventListener ) {
- this.addEventListener( orig, handle, true );
- } else {
- event.add( this, fix, ieHandler );
+if ( document.addEventListener ) {
+ jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) {
+ jQuery.event.special[ fix ] = {
+ setup: function() {
+ this.addEventListener( orig, handler, true );
+ },
+ teardown: function() {
+ this.removeEventListener( orig, handler, true );
}
- },
- teardown:function() {
- if ( this.removeEventListener ) {
- this.removeEventListener( orig, handle, true );
- } else {
- event.remove( this, fix, ieHandler );
- }
- }
- };
-});
+ };
-jQuery.fn.extend({
- // TODO: make bind(), unbind() and one() DRY!
- bind: function( type, data, fn, thisObject ) {
- // Handle object literals
- if ( typeof type === "object" ) {
- for ( var key in type ) {
- this.bind(key, data, type[key], fn);
- }
- return this;
+ function handler( e ) {
+ e = jQuery.event.fix( e );
+ e.type = fix;
+ return jQuery.event.handle.call( this, e );
}
-
- if ( jQuery.isFunction( data ) ) {
- 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, thisObject ) {
+jQuery.each(["bind", "one"], function( i, name ) {
+ jQuery.fn[ name ] = function( type, data, fn ) {
// Handle object literals
if ( typeof type === "object" ) {
for ( var key in type ) {
- this.one(key, data, type[key], fn);
+ this[ name ](key, data, type[key], fn);
}
return this;
}
if ( jQuery.isFunction( data ) ) {
- 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 );
+
+ var handler = name === "one" ? jQuery.proxy( fn, function( event ) {
+ jQuery( this ).unbind( event, handler );
return fn.apply( this, arguments );
- });
- return this.each(function() {
- jQuery.event.add( this, type, one, data );
- });
- },
+ }) : fn;
+ return type === "unload" && name !== "one" ?
+ this.one( type, data, fn ) :
+ this.each(function() {
+ jQuery.event.add( this, type, handler, data );
+ });
+ };
+});
+
+jQuery.fn.extend({
unbind: function( type, fn ) {
// Handle object literals
if ( typeof type === "object" && !type.preventDefault ) {
}
return this;
}
-
+
return this.each(function() {
jQuery.event.remove( this, type, fn );
});
},
-
trigger: function( type, data ) {
return this.each(function() {
jQuery.event.trigger( type, data, this );
var args = arguments, i = 1;
// link all the functions, so any of them can unbind this click handler
- while( i < args.length ) {
- jQuery.event.proxy( fn, args[ i++ ] );
+ while ( i < args.length ) {
+ 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 );
+ 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();
return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
},
- ready: function( fn ) {
- // Attach the listeners
- bindReady();
-
- // If the DOM is already ready
- if ( jQuery.isReady ) {
- // Execute the function immediately
- fn.call( document, jQuery );
-
- // Otherwise, remember the function for later
- } else {
- // Add the function to the wait list
- jQuery.readyList.push( fn );
- }
-
- return this;
- },
-
- live: function( type, data, fn, thisObject ) {
+ live: function( type, data, fn ) {
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 );
+ }, fn );
+
return this;
},
}
function liveConvert( type, selector ) {
- return ["live", type, selector//.replace(/[^\w\s\.]/g, function(ch){ return "\\"+ch})
- .replace(/\./g, "`")
- .replace(/ /g, "|")].join(".");
+ return ["live", type, selector.replace(/\./g, "`").replace(/ /g, "&")].join(".");
}
-jQuery.extend({
- isReady: false,
- readyList: [],
- // Handle when the DOM is ready
- ready: function() {
- // Make sure that the DOM is not already loaded
- if ( !jQuery.isReady ) {
- if ( !document.body ) {
- return setTimeout( jQuery.ready, 13 );
- }
-
- // Remember that the DOM is ready
- jQuery.isReady = true;
-
- // If there are functions bound, to execute
- if ( jQuery.readyList ) {
- // Execute all of them
- var fn, i = 0;
- while ( (fn = jQuery.readyList[ i++ ]) ) {
- fn.call( document, jQuery );
- }
-
- // Reset the list of functions
- jQuery.readyList = null;
- }
-
- // Trigger any bound ready events
- jQuery( document ).triggerHandler( "ready" );
- }
- }
-});
-
-var readyBound = false;
-
-function bindReady() {
- 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
- document.addEventListener( "DOMContentLoaded", function() {
- document.removeEventListener( "DOMContentLoaded", arguments.callee, false );
- jQuery.ready();
- }, false );
-
- // If IE event model is used
- } else if ( document.attachEvent ) {
- // ensure firing before onload,
- // maybe late but safe also for iframes
- document.attachEvent("onreadystatechange", function() {
- // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
- if ( document.readyState === "complete" ) {
- document.detachEvent( "onreadystatechange", arguments.callee );
- jQuery.ready();
- }
- });
-
- // If IE and not a frame
- // continually check to see if the document is ready
- var toplevel = false;
-
- try {
- toplevel = window.frameElement == null;
- } catch(e){}
-
- if ( document.documentElement.doScroll && toplevel ) {
- (function() {
- if ( jQuery.isReady ) {
- return;
- }
-
- try {
- // If IE is used, use the trick by Diego Perini
- // http://javascript.nwbox.com/IEContentLoaded/
- document.documentElement.doScroll("left");
- } catch( error ) {
- setTimeout( arguments.callee, 0 );
- return;
- }
-
- // and execute any waiting functions
- jQuery.ready();
- })();
- }
- }
-
- // A fallback to window.onload, that will always work
- jQuery.event.add( window, "load", jQuery.ready );
-}
-
-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 ) {
jQuery.fn[ name ] = function( fn ) {
return fn ? this.bind( name, fn ) : this.trigger( name );
};
+
+ if ( jQuery.attrFn ) {
+ jQuery.attrFn[ name ] = true;
+ }
});
// 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/
-/*@cc_on
-jQuery( window ).bind( 'unload', function() {
- for ( var id in jQuery.cache ) {
- // Skip the window
- if ( id != 1 && jQuery.cache[ id ].handle ) {
- jQuery.event.remove( jQuery.cache[ id ].handle.elem );
+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) {}
+ }
}
- }
-});
-@*/
+ });
+}