]> source.dussan.org Git - jquery.git/commitdiff
propHooks now an object with `props` array and `filter` function.
authorDave Methvin <dave.methvin@gmail.com>
Sun, 25 Sep 2011 23:56:34 +0000 (19:56 -0400)
committerDave Methvin <dave.methvin@gmail.com>
Sun, 25 Sep 2011 23:56:34 +0000 (19:56 -0400)
Use the originalEvent to grab properties in filter functions since they often won't have been copied to event. Mark a few current props in the main jQuery.event.props list as deprecated, they aren't supported across all browsers.

src/event.js
test/unit/event.js

index 699b9381ef5900b49171c1688b9680080e0076f3..00b332c5b1ba6c95de3b139f8d9ed0151e6a7e0e 100644 (file)
@@ -7,6 +7,8 @@ var rnamespaces = /\.(.*)$/,
        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 );
@@ -407,12 +409,6 @@ jQuery.event = {
                // 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 ),
@@ -469,55 +465,89 @@ jQuery.event = {
                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
@@ -1026,58 +1056,14 @@ jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblcl
                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 );
 
index 103b7f00aec20e154072a41ab7882909b0759e11..319569ab926f4edf77a8eec7e9f6bebf04aac45a 100644 (file)
@@ -2383,6 +2383,38 @@ test("delegated events quickIs", function() {
        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!
@@ -2457,72 +2489,4 @@ test("delegated events quickIs", function() {
 
 })();
 
-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();
-});
-*/