Friday, October 10, 2008

jquery.delegate

This is a jquery plugin which handles event delegation. There are a bunch of delegation plugins out there, and this is just an example of additional functionality, that I wanted to try before delegation gets added to the core.

Download - jQuery 1.2.6+ required.

The "delegate" method takes 3 or 4 arguments:

  • type - The type(s) of event being bound/delegated. Seperate multiple events with spaces.
  • selector - The selector(s) to match against event.targets and execute the provided handler. Seperate multiple selectors with commas (extra spaces are allowed).
  • handler - The function to call against the matching selector(s). The scope (this) will be the matched element.
  • data - (optional) Any data to be shared between handlers via the event.data property. Currently, only the initial binding of a delegate handler will bind the data. This will be easily fixed for the next release.

Here are some examples of the API:

// delegate clicks on every span inside a div $('div').delegate( 'click', 'span', function( event ){ $( this ).toggleClass('selected'); });
 
// delegate clicks but stop propagation $('div').delegate( 'click', 'span', function( event ){ $( this ).toggleClass('selected'); return false; });
 
// delegate multiple comma-seperated selectors $('div').delegate( 'click', 'span, div', function( event ){ $( this ).toggleClass('selected'); });
 
// delegate multiple space-seperated events $('div').delegate( 'mouseover mouseout', 'span', function( event ){ $( this ).toggleClass('selected'); });

The "undelegate" method takes 0 to 3:

  • type - (optional) The type(s) of event being unbound. Seperate multiple events with spaces.
  • selector - The selector(s) to be removed. Seperate multiple selectors with commas (extra spaces are allowed).
  • handler - The function to be removed. This must also match the selector that the function was paired with.

Here are some examples of the API:

// undelegate clicks on every span inside a div $('div').undelegate( 'click', 'span' );
 
// undelegate multiple comma-seperated selectors $('div').undelegate( 'click', 'span, div' );
 
// undelegate multiple space-seperated events $('div').undelegate( 'mouseover mouseout', 'span' );
 
// undelegate all selectors for a given event type $('div').undelegate( 'click' );
 
// undelegate every event and every selector $('div').undelegate();

Please direct any feedback to http://groups.google.com/group/threedubmedia

Friday, August 8, 2008

$.event.special.drop

This plugin leverages the special event api, to add bind-able drop behavior events. This plugin is designed to work exclusively with $.event.special.drag, actually, it doesn't work without it.

Download - jQuery 1.2.6+ required, jquery.event.drag 1.0+ required.

This plugin compares "dragProxy" position and registered drop target positions asynchronously, based on some tolerance mode. Some plugins check positions over often on every mousemove event, which can hinder performance. This plugin uses a fixed delay and only compares positions while the mouse is moving.

The available events using this plugin are...

  • dropstart - When a drop target becomes active, depends on tolerance mode and dragProxy. Return false to prevent drop.
  • drop - When a dragged element is released within an active drop target. Return false to null the "dropTarget" event property prior to calling "dragend".
  • dropend - When a drop target becomes inactive.

The "dropTarget" event property is updated (in addition to drag event properties) to reflect the single active drop target element. When completing your drag/drop interaction, in the "dragend" handler the "dropTarget" property can be used to detrmine whether a drop happend or not.

The drop target position and size is captured and cached at the time of the drag event binding. If your application is highly dynamic, you can use the $.dropManage utility to filter and re-cache drop target element locations.

// bind a drop event handler $( elems ).bind( "drop", function(){ ... });

There are several stored tolerance modes already...

  • mouse - This mode is not explicitly defined, but is the fallback mode if no other mode is properly specified.
  • overlap - The target element which shares the most overlapping area with the proxy element wins.
  • intersect (Default) - The target element which contains the mouse (cursor) wins, else target element with most overlapping area wins.
  • fit - The proxy element is completely contained within target element bounds.
  • middle - The center point of the proxy element is contained within target element bounds.

Demo - Use the select to try different tolerance mode settings.

$.dropManage( options )

"dropManage" is a global utility function, that takes a single options argument in the form of an object literal. The options will extend the $.event.special.drop object, which allows you to use the following keys for configuration. The function returns a jquery collection of filtered drop target elements.

  • delay - The async timeout delay (default: 100) in milliseconds between target tolerance checks.
  • mode - Key string (default:'intersect') for stored tolerance modes.
  • tolerance - Create a function to make a custom tolerance mode.
  • filter - jQuery filter method argument (string expression or function) to filter the all currently bound drop target elements and cache the position and size.

The most typical place to use the $.dropManage function, is inside of a "dragstart" event. In dynamic applications, where the drop target elements will change size or position, you can re-locate elements quite easily. It also makes it easy to interact with a restricted subset of all bound drop target elements and different tolerance modes.

// filter drop elements, set new tolerance mode $.dropManage({ mode:'fit', filter:'.red' });

Demo - Drag the drop target to a different location, this demo uses "$.dropManage" to relocate elements on each "dragstart" event.

You can create and store your own custom tolerance modes be extending the "$.event.special.drop.modes" object with a new function. The function scope, when called, is the "$.event.special.drop" (this keyword). The function receives three arguments:

  • event - the most recent mousemove/drag event.
  • proxy - a location object representing the drag proxy element.
  • target - a location object representing the drop target element.

A location object is a handy object literal that is returned from the "$.event.special.drop.locate" helper function. The location object values are:

  • elem - the DOM element that is represented.
  • L - the LEFT position of the element.
  • W - the WIDTH of the element
  • R - the RIGHT position of the element (Left + Width).
  • T - the TOP position of the element.
  • B - the BOTTOM position of the element (Top + Height).
  • H - the HEIGHT of the element.

Another helper function is "$.event.special.drop.contains" which takes two arguments: the target location, and the test location. The first argument should always be the drop element "location" object, the second argument could be the drag proxy location or a 2 value array representing XY coordinates respectively. The "contains" function returns true or false.

Using the helper functions to determine you custom tolerance mode, your tolerance function can return the target location object of the outright winning element, or null to continue comparing. In addition, you can set the "best" parameter of the "$.event.special.drop" object to continue comparing all drop targets before choosing a winner. Hopefully the examples below will help make things more clear.

// tolerance function scope is '$.event.special.drop' // 'fit' tolerance mode uses the 'contains' function $.event.special.drop.modes['fit'] = function( event, proxy, target ){ // returns an outright winner, or null return this.contains( target, proxy ) ? target : null; }; // 'intersect' mode is a complex example $.event.special.drop.modes['intersect'] = function( event, proxy, target ){ // returns an outright winner if cursor is inside return this.contains( target, [ event.pageX, event.pageY ] ) ? // else reverts to 'overlap' mode target : this.modes['overlap'].apply( this, arguments ); };

Lastly, there is an overloaded jquery method called "drop" which takes zero to three arguments.

// 0 args, trigger "drop" handler $( elems ).drop(); // 1 arg, binds "drop" handler $( elems ).drop( dropFn ); // 2 args, binds "dropstart" and "drop" handlers $( elems ).drop( dropstartFn, dropFn ); // 3 args, binds "dropstart" and "drop" and "dropend" handlers $( elems ).drop( dropstartFn, dropFn, dropendFn );

Please direct any feedback to http://groups.google.com/group/threedubmedia

$.event.special.drag

This is a jquery special event implementation of a drag event model. It is intended for use by developers who don't need one bloated script full of idiot-proof logic and a million different options. For people who plan a drag interaction model and decide how to set up pages and position elements, and don't need a script to figure that out...

Downloads - jQuery 1.2.x or 1.3.x required.

This plugin is designed to work seamlessly with $.special.event.drop, though it is not required.

To begin, let us look at the anatomy of a drag event model using standard DOM events...

  1. "mousedown" - The user depresses a mouse button within the draggable element
  2. "mousemove" - The user holds the mouse button and moves the mouse
  3. "mouseup" - The user releases the mousebutton

Makes sense? Now consider the interesting moments of a drag interaction...

  1. "dragstart" - Dragging begins, after the mouse has moved past some tolerance threshold
  2. "drag" - The mouse is moving, element dragging
  3. "dragend" - The dragging stops

This plugin simplifies all of this, by taking care of the DOM events when you bind a "drag" event handler, and triggering any other handlers at the appropriate time.

This plugin does NOT move elements! You have to do that yourself, but I think that is best in many cases (containment, snapping to a grid, axis restriction, and non-linear movement, to name a few). This plugin does update many helpful event properties for your use...

  • event.dragTarget - The originating element of the drag event
  • event.dragProxy - The proxy element or dragTarget
  • event.cursorOffsetX - The horizontal difference between the click and element position
  • event.cursorOffsetY - The vertical difference between the click and element position
  • event.offsetX - The adjusted (by cursorOffset) dragged horizontal element position
  • event.offsetY - The adjusted (by cursorOffset) dragged vertical element position
// bind a drag event, update position $( elems ).bind( 'drag', function( event ){ $( this ).css({ top:event.offsetY, left:event.offsetX }); });

Demo - Try dragging the box around...

To achieve more complex behaviors, consider handling these relatively simple events.

  • dragstart - return false to prevent drag, return an element, jquery collection, or selector string to set the proxy element which will be accessible from event.dragProxy, and will be considered for drop target tolerance
  • drag - return false to prevent further dragging and immediately trigger "dragend"
  • dragend - a drag callback
// bind a dragstart event, return the proxy element $( elems ).bind( 'dragstart', function( event ){ return $( this ).clone().appendTo( this.parentNode ); }); // bind a drag event, update proxy position $( elems ).bind( 'drag', function( event ){ $( event.dragProxy ).css({ top:event.offsetY, left:event.offsetX }); }); // bind a dragend event, remove proxy $( elems ).bind( 'dragend', function( event ){ $( event.dragProxy ).fadeOut(); });

Demo - Try dragging the box around, observe the use of a proxy...

There is one parameter for customizing drag interaction, jQuery.event.special.drag.distance (default: 0), and it is used to define the length in pixels that must be moved before triggering "dragstart." This property is captured at the time the drag event is bound, and in jQuery 1.3, you will be able pass options using the already existing "bind" data argument.

// bind with data parameters (jQuery 1.3) $( elems ).bind( "drag", { distance:10 }, function(){ ... });

Lastly, there is an overloaded jquery method called "drag" which takes zero to three arguments.

// 0 args, trigger "drag" handler $( elems ).drag(); // 1 arg, binds "drag" handler $( elems ).drag( dragFn ); // 2 args, binds "dragstart" and "drag" handlers $( elems ).drag( dragstartFn, dragFn ); // 3 args, binds "dragstart" and "drag" and "dragend" handlers $( elems ).drag( dragstartFn, dragFn, dragendFn );

Please direct any feedback to http://groups.google.com/group/threedubmedia

Thursday, August 7, 2008

$.event.special.hover

A new and improved special event implementation Brian Cherne's "hoverIntent" plugin (http://plugins.jquery.com/project/hoverIntent).

Download - jQuery 1.2.6+ required.

This new "hover" event works like Brian Cherne's "hoverIntent" (http://plugins.jquery.com/project/hoverIntent), only better. When the cursor enters an element, the average speed of the mouse is checked asynchronously over a fixed delay interval. If the speed is below the specified limit, the "hover" event is triggered. This plugin leverages the special event api.

// bind a hover event handler $( elems ).bind( "hover", function(){ ... });

Additional related events can be handled.

  • hoverstart - is triggered on mouseenter and can return false to prevent "hover"
  • hover - is triggered between mouseenter and mouseleave when the mouse speed is below the specified limit, can return false to prevent "hoverend"
  • hoverend - is triggered on mouseleave only after "hover" has been triggered

The handlers for these events can be added/removed at any time, but the "hoverstart/hoverend" events will only fire while a "hover" handler is bound.

There are two parameters for controlling the hover event interaction. These values are captured at the time the "hover" event is bound, so for better or worse, changing these values in the global sense will not alter pre-existing bound hover events.

  • $.event.special.hover.delay (default: 100) - Defines the delay (milliseconds) while mouse is inside the element between speed checks.
  • $.event.special.hover.speed (default: 100) - Defines the maximum speed (pixels per second) the mouse may be moving to trigger the hover event.

A change (http://dev.jquery.com/changeset/5777) that should be included in 1.3 allows the passing of data from "bind" to the special event "setup" function. This change allows the parameters to be included from the bind method, using the existing, optional data argument.

// bind with data parameters (jQuery 1.3) $( elems ).bind( "hover", { speed:200, delay:200 }, function(){ ... });

Lastly, there is an overloaded jquery method called "hover" (Because a "hover" method already exists, this plugin renames the existing method "_hover" - If you have any problems with this, rename the new or old methods as you see fit). The method takes zero to three arguments.

// 0 args, trigger "hover" handler $( elems ).hover(); // 1 arg, binds "hover" handler $( elems ).hover( hoverFn ); // 2 args, binds "hover" and "hoverend" handlers $( elems ).hover( hoverFn, hoverendFn ); // 3 args, binds "hoverstart" and "hover" and "hoverend" handlers $( elems ).hover( hoverstartFn, hoverFn, hoverendFn );

Demo - Mouseover over the three blocks below... The blocks will only change color when the cursor speed is less than 100 pixels per second.

Please direct any feedback to http://groups.google.com/group/threedubmedia

$.event.special.wheel

A smaller, simplified interpretation of Brandon Aaron's special event "Mouse Wheel Extension" (http://plugins.jquery.com/project/mousewheel).

Download - jQuery 1.2.6+ required.

The event is called "wheel" and can be created using the "bind" method...

// bind a wheel event $(body).bind('wheel',function(event,delta){ alert( delta>0 ? "up" : "down" ); });

a "wheel" method is also created which behaves just like "click"

// trigger a wheel handler $(body).wheel(); // bind a wheel handler $(body).wheel(function(){ ... });

The second argument passed to the event handler, is the same normalized "delta" representation of scrolling used in the other mousewheel event (brandon aaron's), however that value is also stored in a delta property on the event object ("event.delta"). Firefox 3 has corrected the "DOMMouseScroll" event bug found in Firefox 2, so this plugin only fixes event properties (using mousemove) in versions of firefox prior to 3.

Demo - Mousewheel inside the three blocks below to cycle through colors.

Please direct any feedback to http://groups.google.com/group/threedubmedia