From 2ad223aedd1f93c783d98d60adc9fda3bdfbb4b6 Mon Sep 17 00:00:00 2001 From: Brandon Aaron Date: Sun, 22 Apr 2007 03:16:53 +0000 Subject: [PATCH] Use DOM 2 event handlers, do not trigger click on a tags and event.data no longer global --- src/event/event.js | 60 +++++++++++++++++++++++++----------------- src/event/eventTest.js | 48 +++++++++------------------------ 2 files changed, 48 insertions(+), 60 deletions(-) diff --git a/src/event/event.js b/src/event/event.js index e0d4b908..0d820459 100644 --- a/src/event/event.js +++ b/src/event/event.js @@ -13,9 +13,23 @@ jQuery.event = { if ( jQuery.browser.msie && element.setInterval != undefined ) element = window; - // if data is passed, bind to handler - if( data ) - handler.data = data; + // if data is passed, bind to handler + if( data != undefined ) { + // Create temporary function pointer to original handler + var fn = handler; + + // Create unique handler function, wrapped around original handler + handler = function() { + // Pass arguments and context to original handler + return fn.apply(this, arguments); + }; + + // Store data in unique handler + handler.data = data; + + // Set the guid of unique handler to the same of original handler, so it can be removed + handler.guid = fn.guid; + } // Make sure that the function being executed has a unique ID if ( !handler.guid ) @@ -28,21 +42,18 @@ jQuery.event = { // Get the current list of functions bound to this event var handlers = element.$events[type]; - // If it hasn't been initialized yet - if (!handlers) { - // Init the event handler queue + // Init the event handler queue + if (!handlers) handlers = element.$events[type] = {}; - // Remember an existing handler, if it's already there - if (element["on" + type]) - handlers[0] = element["on" + type]; - } - // Add the function to the element's handler list handlers[handler.guid] = handler; // And bind the global event handler to the element - element["on" + type] = this.handle; + if (element.addEventListener) + element.addEventListener(type, this.handle, false); + else if (element.attachEvent) + element.attachEvent("on" + type, this.handle, false); // Remember the function in a global list (for triggering) if (!this.global[type]) @@ -81,7 +92,11 @@ jQuery.event = { // remove generic event handler if no more handlers exist for ( ret in events[type] ) break; if ( !ret ) { - ret = element["on" + type] = null; + ret = null; + if (element.removeEventListener) + element.removeEventListener(type, this.handle, false); + else if (element.detachEvent) + element.detachEvent("on" + type, this.handle, false); delete events[type]; } } @@ -105,19 +120,16 @@ jQuery.event = { // Handle triggering a single element else { - var handler = element["on" + type ], val, - fn = jQuery.isFunction( element[ type ] ); + var val, ret, fn = jQuery.isFunction( element[ type ] ); + + // Pass along a fake event + data.unshift( this.fix({ type: type, target: element }) ); - if ( handler ) { - // Pass along a fake event - data.unshift( this.fix({ type: type, target: element }) ); - - // Trigger the event - if ( (val = handler.apply( element, data )) !== false ) - this.triggered = true; - } + // Trigger the event + if ( (val = this.handle.apply( element, data )) !== false ) + this.triggered = true; - if ( fn && val !== false ) + if ( fn && val !== false && !jQuery.nodeName(element, 'a') ) element[ type ](); this.triggered = false; diff --git a/src/event/eventTest.js b/src/event/eventTest.js index 0ad4ffb7..63359252 100644 --- a/src/event/eventTest.js +++ b/src/event/eventTest.js @@ -1,7 +1,7 @@ module("event"); test("bind()", function() { - expect(11); + expect(9); var handler = function(event) { ok( event.data, "bind() with data, check passed data exists" ); @@ -17,32 +17,10 @@ test("bind()", function() { ok( data.bar == "foo", "Check value of trigger data" ); } $("#firstp").bind("click", {foo: "bar"}, handler).trigger("click", [{bar: "foo"}]); - - // events don't work with iframes, see #939 - var tmp = document.createElement('iframe'); - document.body.appendChild( tmp ); - var doc = tmp.contentDocument; - doc.open(); - doc.write(""); - doc.close(); - - var input = doc.getElementsByTagName("input")[0]; - - input.addEventListener('click', function() { - ok( true, "Event handling via DOM 2 methods" ); - }, false); - - $(input).bind("click",function() { - ok( true, "Event handling via jQuery's handler" ); - }); - - triggerEvent( input, "click" ); - - document.body.removeChild( tmp ); var counter = 0; function selectOnChange(event) { - equals( event.data, counter++, "Event.data is a global event object" ); + equals( event.data, counter++, "Event.data is not a global event object" ); } $("select").each(function(i){ $(this).bind('change', i, selectOnChange); @@ -50,17 +28,17 @@ test("bind()", function() { }); test("click()", function() { - expect(3); - $('
  • Change location
  • ').prependTo('#firstUL').find('a').bind('click', function() { - var close = $('spanx', this); // same with $(this).find('span'); - ok( close.length == 0, "Context element does not exist, length must be zero" ); - ok( !close[0], "Context element does not exist, direct access to element must return undefined" ); - return false; + expect(3); + $('
  • Change location
  • ').prependTo('#firstUL').find('a').bind('click', function() { + var close = $('spanx', this); // same with $(this).find('span'); + ok( close.length == 0, "Context element does not exist, length must be zero" ); + ok( !close[0], "Context element does not exist, direct access to element must return undefined" ); + return false; }).click(); $("#check1").click(function() { ok( true, "click event handler for checkbox gets fired twice, see #815" ); - }).click(); + }).click(); }); test("unbind(event)", function() { @@ -81,7 +59,8 @@ test("unbind(event)", function() { el.click(function() { return; }); el.unbind('change',function(){ return; }); - ok( el[0].onclick, "Extra handlers weren't accidentally removed." ); + for (var ret in el[0].$events['click']) break; + ok( ret, "Extra handlers weren't accidentally removed." ); el.unbind('click'); ok( !el[0].$events, "Removed the events expando after all handlers are unbound." ); @@ -104,10 +83,7 @@ test("toggle(Function, Function)", function() { fn2 = function(e) { count--; }, preventDefault = function(e) { e.preventDefault() }, link = $('#mark'); - if ( $.browser.msie || $.browser.opera || /konquerer/i.test(navigator.userAgent) ) - ok( false, "click() on link gets executed in IE/Opera/Konquerer, not intended behaviour!" ); - else - link.click(preventDefault).click().toggle(fn1, fn2).click().click().click().click().click(); + link.click(preventDefault).click().toggle(fn1, fn2).click().click().click().click().click(); ok( count == 1, "Check for toggle(fn, fn)" ); var first = 0;