rescape = /[^\w\s.|`]/g,
rtypenamespace = /^([^\.]*)?(?:\.(.+))?$/,
rhoverHack = /\bhover(\.\S+)?/,
+ rkeyEvent = /^key/,
+ rmouseEvent = /^(?:mouse|contextmenu)|click/,
rquickIs = /^([\w\-]+)?(?:#([\w\-]+))?(?:\.([\w\-]+))?(?:\[([\w+\-]+)=["']?([\w\-]*)["']?\])?$/,
quickParse = function( selector ) {
var quick = rquickIs.exec( selector );
// Make a writable jQuery.Event from the native event object
event = jQuery.event.fix( event || window.event );
- var propHook = jQuery.event.propHooks[ event.type ];
-
- if ( propHook ) {
- event = propHook( event );
- }
-
var handlers = ((jQuery._data( this, "events" ) || {})[ event.type ] || []),
delegateCount = handlers.delegateCount,
args = Array.prototype.slice.call( arguments, 0 ),
return event.result;
},
- props: "altKey attrName bubbles button cancelable charCode ctrlKey currentTarget data detail eventPhase fromElement handler keyCode metaKey relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view which".split(" "),
+ // Includes some event props shared by KeyEvent and MouseEvent
+ // *** attrChange attrName relatedNode srcElement are not normalized, non-W3C, deprecated, will be removed in 1.8 ***
+ props: "attrChange attrName relatedNode srcElement altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp type view which".split(" "),
propHooks: {},
+ keyHooks: {
+ props: "char charCode key keyCode".split(" "),
+ filter: function( event, original ) {
+
+ // Add which for key events
+ if ( event.which == null ) {
+ event.which = original.charCode != null ? original.charCode : original.keyCode;
+ }
+
+ return event;
+ }
+ },
+
+ mouseHooks: {
+ props: "button buttons clientX clientY fromElement layerX layerY offsetX offsetY pageX pageY screenX screenY toElement wheelDelta".split(" "),
+ filter: function( event, original ) {
+ var eventDoc, doc, body,
+ button = original.button;
+
+ // Calculate pageX/Y if missing and clientX/Y available
+ if ( event.pageX == null && original.clientX != null ) {
+ eventDoc = event.target.ownerDocument || document;
+ doc = eventDoc.documentElement;
+ body = eventDoc.body;
+
+ event.pageX = original.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc && doc.clientLeft || body && body.clientLeft || 0);
+ event.pageY = original.clientY + (doc && doc.scrollTop || body && body.scrollTop || 0) - (doc && doc.clientTop || body && body.clientTop || 0);
+ }
+
+ // Add relatedTarget, if necessary
+ if ( !event.relatedTarget && original.fromElement ) {
+ event.relatedTarget = original.fromElement === event.target ? original.toElement : original.fromElement;
+ }
+
+ // Add which for click: 1 === left; 2 === middle; 3 === right
+ // Note: button is not normalized, so don't use it
+ if ( !event.which && button !== undefined ) {
+ event.which = (button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ));
+ }
+
+ return event;
+ }
+ },
+
fix: function( event ) {
if ( event[ jQuery.expando ] ) {
return event;
}
- // store a copy of the original event object
- // and "clone" to set read-only properties
+ // Create a writable copy of the event object and normalize some properties
var originalEvent = event,
- propHook = jQuery.event.propHooks[ event.type ],
- copy = this.props;
+ propHook = jQuery.event.propHooks[ event.type ] || {},
+ copy = propHook.props? this.props.concat( propHook.props ) : this.props;
event = jQuery.Event( originalEvent );
- if ( propHook ) {
- copy.push.apply( copy, propHook() || [] );
- }
-
for ( var i = copy.length, prop; i; ) {
prop = copy[ --i ];
event[ prop ] = originalEvent[ prop ];
}
- // Fix target property, if necessary
- // Removal will crash IE6,7,8
+ // Fix target property, if necessary (#1925, IE 6/7/8 & Safari2)
if ( !event.target ) {
- // Fixes #1925 where srcElement might not be defined either
- event.target = event.srcElement || document;
+ event.target = originalEvent.srcElement || document;
}
- // check if target is a textnode (safari)
- // Removal will crash IE6,7,8
+ // Target should not be a text node (#504, Safari)
if ( event.target.nodeType === 3 ) {
event.target = event.target.parentNode;
}
- // Add relatedTarget, if necessary
- if ( !event.relatedTarget && event.fromElement ) {
- event.relatedTarget = event.fromElement === event.target ? event.toElement : event.fromElement;
+ // For mouse/key events; add metaKey if it's not there (#3368, IE6/7/8)
+ if ( event.metaKey === undefined ) {
+ event.metaKey = event.ctrlKey;
}
- if ( propHook ) {
- event = propHook( event, originalEvent );
- }
-
- return event;
+ return propHook.filter? propHook.filter( event, originalEvent ) : event;
},
// Deprecated, use jQuery.guid instead
jQuery.attrFn[ name ] = true;
}
- // Key Event property hooks
if ( rkeyEvent.test( name ) ) {
- jQuery.event.propHooks[ name ] = function( event, original ) {
-
- var charCode = event.charCode,
- keyCode = event.keyCode,
- ctrlKey = event.ctrlKey;
-
- // Add which for key events
- if ( event.which == null && (charCode != null || keyCode != null) ) {
- event.which = charCode != null ? charCode : keyCode;
- }
-
- // Add metaKey to non-Mac browsers (use ctrl for PC's and Meta for Macs)
- if ( !event.metaKey && ctrlKey ) {
- event.metaKey = ctrlKey;
- }
-
- return event;
- };
+ jQuery.event.propHooks[ name ] = jQuery.event.keyHooks;
}
- // Mouse Event property hooks
if ( rmouseEvent.test( name ) ) {
- jQuery.event.propHooks[ name ] = function( event, original ) {
-
- if ( !event ) {
- return mouseProps;
- }
-
- var eventDoc, doc, body,
- button = event.button;
-
- // Calculate pageX/Y if missing and clientX/Y available
- if ( event.pageX == null && event.clientX != null ) {
- eventDoc = event.target.ownerDocument || document;
- doc = eventDoc.documentElement;
- body = eventDoc.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 click: 1 === left; 2 === middle; 3 === right
- // Note: button is not normalized, so don't use it
- if ( !event.which && button !== undefined ) {
- event.which = (button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ));
- }
-
- return event;
- };
- }});
+ jQuery.event.propHooks[ name ] = jQuery.event.mouseHooks;
+ }
+});
})( jQuery );
markup.remove();
});
+test("propHooks extensions", function() {
+ expect( 3 );
+
+ jQuery( "<a id='hook-fixture' href=''></a>" ).appendTo( "#qunit-fixture" );
+
+ var $fixture = jQuery( "#hook-fixture" );
+
+ // Ensure the property doesn't exist
+ $fixture.bind( "focus", function( event ) {
+ ok( !("blurrinessLevel" in event), "event.blurrinessLevel does not exist" );
+ })[0].focus();
+
+ // Must blur the link so focus works below
+ $fixture.unbind( "focus" )[0].blur();
+
+ // Define a custom property for "focus" events via the filter function
+ ok( !jQuery.event.propHooks.focus, "We aren't clobbering an existing focus hook" );
+ jQuery.event.propHooks.focus = {
+ filter: function( event, originalEvent ) {
+ event.blurrinessLevel = 42;
+ return event;
+ }
+ };
+
+ // Trigger a native focus and ensure the property is set
+ $fixture.bind( "focus", function( event ) {
+ equals( event.blurrinessLevel, 42, "event.blurrinessLevel was set" );
+ })[0].focus();
+
+ delete jQuery.event.propHooks.focus;
+ $fixture.unbind( "focus" ).remove();
+});
(function(){
// This code must be run before DOM ready!
})();
-test("jQuery.event.propHooks", function() {
- expect( 1 );
- ok( jQuery.event.propHooks, "jQuery.event.propHooks exists" );
-});
-
-test("jQuery.event.propHooks as function", function() {
-
- expect( 2 );
-
- jQuery( "<div id='hook-fixture'></div>" ).appendTo( "#qunit-fixture" );
-
- var $fixture = jQuery( "#hook-fixture" );
-
- // Does not exist
- $fixture.bind( "click", function( event ) {
- ok( !("propC" in event), "event.propC Does not exist" );
- }).trigger( "click" );
-
- $fixture.unbind( "click" );
-
- // Store as function
- jQuery.event.propHooks[ "custom" ] = function( event ) {
- // receives the event object for processing
- event.propC = true;
- return event;
- };
-
- $fixture.bind( "custom", function( event ) {
- ok( event.propC, "event.propC exists" );
- }).trigger( "custom" );
-});
-
-test("jQuery.event.propHooks usecase", function() {
-
- expect( 3 );
-
- jQuery( "<div id='hook-fixture'></div>" ).appendTo( "#qunit-fixture" );
-
- var $fixture = jQuery( "#hook-fixture" );
-
- $fixture.bind( "fakedrop", function( event ) {
- ok( !("dataTransfer" in event), "event.dataTransfer is not available" );
- }).trigger( "fakedrop" );
-
- $fixture.unbind( "fakedrop" );
-
- jQuery.event.propHooks[ "fakedrop" ] = function( event ) {
- event.dataTransfer = "some val";
- return event;
- };
-
- $fixture.bind( "fakedrop", function( event ) {
- ok( ("dataTransfer" in event), "event.dataTransfer exists, just copied" );
- equal( event.dataTransfer, "some val", "event.dataTransfer equal 'some val'" );
- }).trigger( "fakedrop" );
-
- $fixture.unbind( "fakedrop" );
-});
-
-/*
-test("event properties", function() {
- stop();
- jQuery("#simon1").click(function(event) {
- ok( event.timeStamp, "assert event.timeStamp is present" );
- start();
- }).click();
-});
-*/