<!DOCTYPE html>
<html>
<head>
	<title>Determine Link Trigger Method With jQuery</title>
</head>
<body>

	<h1>
		Determine Link Trigger Method With jQuery
	</h1>

	<p>
		<a href="#" class="link">Click me please</a>!<br />
		<a href="#" class="link">Click me please</a>!<br />
		<a href="#" class="link">Click me please</a>!<br />
		<a href="#" class="link">Click me please</a>!<br />
	</p>


	<!-- Configure scripts. -->
	<script type="text/javascript" src="../jquery-1.7.1.js"></script>
	<script type="text/javascript">


		// Set up a special Event Type which will help us to
		// determine what physical device was used to initiate the
		// click event on a given element: Mouse or Keywboard. Since
		// there doesn't appear to be anything inherent to the click
		// event that denotes device (cross-browser), we'll have to
		// use some surrounding events to setup the click event
		// handler data. The default device is considered the Mouse;
		// the alternate device is the keyboard.
		(function( $ ){


			// When a key is depressed, we want to signal that this
			// might be a keyboard-initiated click event. As such,
			// we'll store a boolean to be used in the click event.
			function handleKeyDown( event ){

				// Check to make sure that this key is one that is
				// capable of triggering a click event (ie. the enter
				// button, 13).
				if (event.which === 13){

					$.data( this, "clickwithevent:keyboard", true );

				}

			}

			// When a key is released, we know that the click event
			// will have already take place (if at all); as such, we
			// set the boolean flag to false since any subsequent
			// click event will be triggered by a mouse (or preceeded
			// by a keydown event).
			function handleKeyUp( event ){

				$.data( this, "clickwithevent:keyboard", false );

			}

			// When the click event is triggered, we need to
			// determine if the event was initiated by the keyboard
			// or the mouse. If the boolean flag is true, it means
			// that the click event was preceeded by the depression
			// of the Enter key, which indicates that the click event
			// was initiated by the keyboard.
			function handleClick( event ){

				// Get the flag for keyboard-based click.
				var isKeyPress = $.data( this, "clickwithevent:keyboard" );

				// Let's create a new event that extends the click
				// event. This way, when we trigger our "clickwith"
				// event, we get all of the contextual information
				// associated with the click; but, we don't
				// accidientally trigger click events.
				var clickEvent = createEvent( "clickwith", event )

				// Tell jQuery to trigger the new event with a second
				// argument that indicates the initiator of the click
				// event.
				$.event.handle.apply(
					this,
					[clickEvent, (isKeyPress ? "keyboard" : "mouse")]
				);

			}

			// I create a new jQuery event object using the given
			// event object as the collection of properties to copy.
			// This way, we can "extend" an existing Event object
			// without worrying about copying data we shouldn't.
			function createEvent( eventType, event ){

				// For each event object, we will try to copy all of
				// the following properties that are available.
				var properties = [
					"altKey", "bubbles", "button", "cancelable",
					"charCode", "clientX", "clientY", "ctrlKey",
					"currentTarget", "data", "detail", "eventPhase",
					"metaKey", "offsetX", "offsetY", "originalTarget",
					"pageX", "pageY", "prevValue", "relatedTarget",
					"screenX", "screenY", "shiftKey", "target",
					"view", "which"
				];

				// Create a new properties object that will be used
				// to create the new event.
				var eventProperties = {}

				// Copy over all properties from the old event.
				$.each(
					properties,
					function( index, property ){

						// Make sure this property is available on
						// the original event.
						if (property in event){

							// Copy it over to the new event property
							// collection.
							eventProperties[ property ] = event[ property ];

						}

					}
				);

				// Create and return the new event object with the
				// duplicated properties.
				return(
					new $.Event( eventType, eventProperties )
				);

			}


			// Configure the special event, "clickwith", so that
			// jQuery knows how to bind and unbind event handlers.
			$.event.special.clickwith = {

				// I configure each element that is bound to the
				// clickwith event. I am only called once per element.
				setup: function( data, namespaces ){

					// Set up the key events that surround the click
					// events that setup the meta data.
					$( this )
						.data( "clickwithevent:keyboard", false )
						.on( "keydown.clickwithevent", handleKeyDown )
						.on( "keyup.clickwithevent", handleKeyUp )
						.on( "click.clickwithevent", handleClick )
					;

				},

				// I remove the configuration from each element that
				// is bound to the clickwith event. I am only called
				// oncer per element.s
				teardown: function( namespaces ){

					// Remove all traces of the special event.
					$( this )
						.removeData( "clickwithevent:keyboard" )
						.off( "keydown.clickwithevent" )
						.off( "keyup.clickwithevent" )
						.off( "click.clickwithevent" )
					;

				}

			};


		})( jQuery );


		// -------------------------------------------------- //
		// -------------------------------------------------- //


		// Make sure this event works on a direct event binding.
		$( "a.link" ).on(
			"clickwith",
			function( event, trigger ){

				console.log( "LOCAL[ " + trigger + " ]", event );

			}
		);

		// Make sure this event works on a delegated event binding.
		$( document ).on(
			"clickwith",
			"a.link",
			function( event, trigger ){

				console.log( "GLOBAL[ " + trigger + " ]", event );

			}
		);

		// Try manually triggering a click event (which should, in
		// turn, trigger a clickwith event, using the Mouse as the
		// default device trigger).
		$( "a.link:first" )
			.trigger( "click" )
		;

	</script>
</body>
</html>