// For whatever reason, IE has trouble passing the window object
// around, causing it to be cloned in the process
- if ( jQuery.browser.msie && elem.setInterval )
+ if ( elem.setInterval && elem != window )
elem = window;
// Make sure that the function being executed has a unique ID
handle = jQuery.data(elem, "handle") || jQuery.data(elem, "handle", function(){
// 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 jQuery.event.handle.apply(arguments.callee.elem, arguments);
+ return typeof jQuery !== "undefined" && !jQuery.event.triggered ?
+ jQuery.event.handle.apply(arguments.callee.elem, arguments) :
+ undefined;
});
// Add elem as a property of the handle function
// This is to prevent a memory leak with non-native
// jQuery(...).bind("mouseover mouseout", fn);
jQuery.each(types.split(/\s+/), function(index, type) {
// Namespaced event handlers
- var parts = type.split(".");
- type = parts[0];
- handler.type = parts[1];
+ var namespaces = type.split(".");
+ type = namespaces.shift();
+ handler.type = namespaces.slice().sort().join(".");
// Get the current list of functions bound to this event
var handlers = events[type];
+
+ if ( jQuery.event.specialAll[type] )
+ jQuery.event.specialAll[type].setup.call(elem, data, namespaces);
// Init the event handler queue
if (!handlers) {
// Check for a special event handler
// Only use addEventListener/attachEvent if the special
// events handler returns false
- if ( !jQuery.event.special[type] || jQuery.event.special[type].setup.call(elem,data) === false ) {
+ if ( !jQuery.event.special[type] || jQuery.event.special[type].setup.call(elem, data, namespaces) === false ) {
// Bind the global event handler to the element
if (elem.addEventListener)
elem.addEventListener(type, handle, false);
// jQuery(...).unbind("mouseover mouseout", fn);
jQuery.each(types.split(/\s+/), function(index, type){
// Namespaced event handlers
- var parts = type.split(".");
- type = parts[0];
+ var namespaces = type.split(".");
+ type = namespaces.shift();
+ var namespace = RegExp("(^|\\.)" + namespaces.slice().sort().join(".*\\.") + "(\\.|$)");
if ( events[type] ) {
// remove the given handler for the given type
else
for ( handler in events[type] )
// Handle the removal of namespaced events
- if ( !parts[1] || events[type][handler].type == parts[1] )
+ if ( namespace.test(events[type][handler].type) )
delete events[type][handler];
+
+ if ( jQuery.event.specialAll[type] )
+ jQuery.event.specialAll[type].teardown.call(elem, namespaces);
// remove generic event handler if no more handlers exist
for ( ret in events[type] ) break;
if ( !ret ) {
- if ( !jQuery.event.special[type] || jQuery.event.special[type].teardown.call(elem) === false ) {
+ if ( !jQuery.event.special[type] || jQuery.event.special[type].teardown.call(elem, namespaces) === false ) {
if (elem.removeEventListener)
elem.removeEventListener(type, jQuery.data(elem, "handle"), false);
else if (elem.detachEvent)
}
},
- trigger: function(type, data, elem, donative, extra) {
+ trigger: function(type, data, elem, donative, extra, dohandlers) {
// Clone the incoming data, if any
data = jQuery.makeArray(data);
if ( this.global[type] )
jQuery.each( jQuery.cache, function(){
if ( this.events && this.events[type] )
- jQuery.event.trigger( type, data, this.handle.elem );
+ jQuery.event.trigger( type, data, this.handle.elem, false );
});
// Handle triggering a single element
if ( exclusive )
data[0].exclusive = true;
- // Trigger the event, it is assumed that "handle" is a function
- var handle = jQuery.data(elem, "handle");
- if ( handle )
- val = handle.apply( elem, data );
+ if ( dohandlers !== false ) {
+ // 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 (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;
+ // 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;
+ }
+
+ if ( donative !== false && val !== false ) {
+ var parent = elem.parentNode || elem.ownerDocument;
+ if ( parent )
+ jQuery.event.trigger(type, data, parent, donative);
+ }
// Extra functions don't get the custom event object
if ( event )
handle: function(event) {
// returned undefined or false
- var val, ret, namespace, all, handlers;
+ var val, ret, all, handlers;
event = arguments[0] = jQuery.event.fix( event || window.event );
// Namespaced event handlers
- namespace = event.type.split(".");
- event.type = namespace[0];
- namespace = namespace[1];
+ var namespaces = event.type.split(".");
+ event.type = namespaces.shift();
+
// Cache this now, all = true means, any handler
- all = !namespace && !event.exclusive;
+ all = !namespaces.length && !event.exclusive;
+
+ var namespace = RegExp("(^|\\.)" + namespaces.slice().sort().join(".*\\.") + "(\\.|$)");
handlers = ( jQuery.data(this, "events") || {} )[event.type];
var handler = handlers[j];
// Filter the functions by class
- if ( all || handler.type == namespace ) {
+ 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;
setup: bindReady,
teardown: function() {}
}
+ },
+
+ specialAll: {
+ live: {
+ setup: function( selector, namespaces ){
+ jQuery.event.add( this, namespaces[0], liveHandler );
+ },
+ teardown: function( namespaces ){
+ if ( namespaces.length ) {
+ var remove = 0, name = RegExp("(^|\\.)" + namespaces[0] + "(\\.|$)");
+
+ jQuery.each( (jQuery.data(this, "events").live || {}), function(){
+ if ( name.test(this.type) )
+ remove++;
+ });
+
+ if ( remove <= 1 )
+ jQuery.event.remove( this, namespaces[0], liveHandler );
+ }
+ }
+ }
}
};
this.stopPropagation();
}
-if ( !jQuery.browser.msie ){
- // 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 )
- try { parent = parent.parentNode; }
- catch(e) { 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 );
- }
- };
+// 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 )
+ try { parent = parent.parentNode; }
+ catch(e) { parent = this; }
- jQuery.each({
- mouseover: 'mouseenter',
- mouseout: 'mouseleave'
- }, function( orig, fix ){
- jQuery.event.special[ fix ] = {
- setup: function(){
- jQuery.event.add( this, orig, withinElement, fix );
- },
- teardown: function(){
- jQuery.event.remove( this, orig, withinElement );
- }
- };
- });
-}
+ 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 );
+ }
+};
+
+jQuery.each({
+ mouseover: 'mouseenter',
+ mouseout: 'mouseleave'
+}, function( orig, fix ){
+ jQuery.event.special[ fix ] = {
+ setup: function(){
+ jQuery.event.add( this, orig, withinElement, fix );
+ },
+ teardown: function(){
+ jQuery.event.remove( this, orig, withinElement );
+ }
+ };
+});
jQuery.fn.extend({
bind: function( type, data, fn ) {
jQuery.readyList.push( function() { return fn.call(this, jQuery); } );
return this;
+ },
+
+ live: function( type, fn ){
+ jQuery(document).bind( liveConvert(type, this.selector), this.selector, fn );
+ return this;
+ },
+
+ die: function( type, fn ){
+ jQuery(document).unbind( liveConvert(type, this.selector), fn );
+ return this;
}
});
+function liveHandler( event ){
+ var check = RegExp("(^|\\.)" + event.type + "(\\.|$)");
+ jQuery.each(jQuery.data(this, "events").live || [], function(i, fn){
+ if ( check.test(fn.type) ) {
+ var elem = jQuery(event.target).closest(fn.data)[0];
+ if ( elem )
+ jQuery.event.trigger( event.type, fn.data, elem, false, fn, false );
+ }
+ });
+}
+
+function liveConvert(type, selector){
+ return ["live", type, selector.replace(/\./g, "_")].join(".");
+}
+
jQuery.extend({
isReady: false,
readyList: [],