Skip to content

Instantly share code, notes, and snippets.

@bennadel
Created June 27, 2012 15:04
Show Gist options
  • Save bennadel/3004656 to your computer and use it in GitHub Desktop.
Save bennadel/3004656 to your computer and use it in GitHub Desktop.
Tracing Event Binding And Event Triggering In jQuery
// Create a private scope.
(function( $, on ){
// I proxy the given function and return the resultant GUID
// value that jQuery has attached to the function.
var createAndReturnProxyID = function( target ){
// When generating the proxy, it doesn't matter what the
// "context" is (window in this case); we never actually
// use the proxy - we just need the GUID that is tied to
// it.
var proxy = $.proxy( target, window );
return( proxy.guid );
};
// Given an arguments collection (as the first argument), I return
// the first value that is a function.
var getFirstFunctionInstance = function( args ){
for (var i = 0 ; i < args.length ; i++){
// If this is a function, return it.
if ($.isFunction( args[ i ])){
return( args[ i ] );
}
}
};
// I print a horizontal rule to the console.
var printHRule = function(){
console.log( ". . . . . ." );
};
// I attempt to print the current stack trace.
var printStackTrace = function(){
// In order to gain access to the stack trace, let's throw
// and catch an error object.
try {
throw new Error( "printStackTraceError" );
} catch (error){
// Get the raw trace (cross-browser).
var rawTrace = (error.stack || error.stacktrace || "");
// Break the raw trace into individual lines for printing.
var stackTrace = rawTrace.split( /\n/g );
// When printing the stack trace, we are going to start
// on index 3. This allows us to skip the common parts:
// 1 - *this* function.
// 2 - the on() wrapper.
// 3 - the core on() method.
for (var i = 3 ; i < stackTrace.length ; i ++){
if (stackTrace[ i ].length){
console.log( " > " + stackTrace[ i ] );
}
}
}
};
// I use a timer to debounce hrule requests. This way, several
// successive calls to the function only result in one HRule
// printing.
var showHRuleAfterPause = function(){
clearTimeout( hruleTimer );
// Print the hrule if the timer is allowed to run its course.
hruleTimer = setTimeout( printHRule, hruleTimerDuration );
};
// We are going to be overriding the core on() method in the
// jQuery library. But, we do want to have access to the core
// version of the on() method for binding. Let's get a reference
// to it for later use.
var coreOnMethod = $.fn.on;
// To help keep track of the bind-trigger relationship, we are
// going to assign a unique ID to each bind instance.
var bindCount = 0;
// I enable the debouncing of the hrule print.
var hruleTimer = null;
var hruleTimerDuration = (.5 * 1000);
// Override the core on() method so that we can inject logging
// around the binding / trigger of the event handlers.
$.fn.on = function( types, selector, data, fn, /*INTERNAL*/ one ){
// Get the unique bind index for this event handler. We can
// use this index value to connect the bind to the subsequent
// trigger events.
var bindIndex = ++bindCount;
// Print the general bind() properties.
console.log(
("Bind[ " + bindIndex + " ][ " + types + " ]:"),
(selector || "*no-selector*"),
this
);
// Print the stack trace at the time of the binding (so that
// we can more easily track down where bindings are coming
// from).
printStackTrace();
// the on() method accepts different argument schemes; as
// such, the fn arguemnt may NOT be the actual function. Let's
// just grab the first Function instance.
var fnArgument = getFirstFunctionInstance( arguments );
// Wrap the incoming event handler so that we can log
// information surrounding its use.
var fnWrapper = function( event ){
// Log the event handler usage and event.
console.log(
("Trigger[ " + bindIndex + " ]:"),
event.type,
event
);
// Print the HRULE (so the console is easer to read).
showHRuleAfterPause();
// Execute the underlying event handler.
return(
fnArgument.apply( this, arguments )
);
};
// Tie the wrapper and the underlying event handler together
// using jQuery's proxy() functionality - this way, the events
// can be property unbind() with the wrapper in place.
fnWrapper.guid = createAndReturnProxyID( fnArgument );
// Bind the wrapper as the event handler using the core,
// underlying on() method.
return(
coreOnMethod.call( this, types, selector, data, fnWrapper, one )
);
};
})( jQuery );
<!doctype html>
<html>
<head>
<title>Tracing Events In jQuery</title>
<!-- Include the jQuery UI classes. -->
<link type="text/css" rel="stylesheet" href="./css/ui-lightness/jquery-ui-1.8.21.custom.css"></link>
<!-- Include the jQuery library. -->
<script type="text/javascript" src="../jquery-1.7.2.js"></script>
<!--
Include the TRACE library before any other jQuery-related
libraries so that we have a chance to intercept event bindings.
-->
<script type="text/javascript" src="./jquery.event-trace.js"></script>
<script type="text/javascript" src="jquery-ui-1.8.21.custom.min.js"></script>
<script type="text/javascript">
// When the DOM has loaded, initialize scripts.
jQuery(function( $ ){
// Bind to the BUTTON click.
$( document ).on(
"click",
"form > button",
function( event ){
console.log( "Button clicked!" );
}
);
// Bind the MODAL link.
$( "a.modal" ).click(
function( event ){
$( "div.modal" ).dialog({
modal: true
});
}
);
// Bind to the BUTTON click.
$( "button" ).click(
function( event ){
return( false );
}
);
});
</script>
</head>
<body>
<h1>
Tracing Events In jQuery
</h1>
<form>
<button type="button">Trigger Click!</button>
</form>
<p>
<a href="#" class="modal">Open Modal</a>
</p>
<div class="modal" style="display: none ;">
Hello!
</div>
</body>
</html>
@abariatti
Copy link

Hi thanks a lot for your code ! Very useful to track binding especially when working on code you didn't write :-).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment