|
/*! |
|
* jQuery outside events - v1.1 - 3/16/2010 |
|
* http://benalman.com/projects/jquery-outside-events-plugin/ |
|
* |
|
* Copyright (c) 2010 "Cowboy" Ben Alman |
|
* Dual licensed under the MIT and GPL licenses. |
|
* http://benalman.com/about/license/ |
|
*/ |
|
|
|
// Script: jQuery outside events |
|
// |
|
// *Version: 1.1, Last updated: 3/16/2010* |
|
// |
|
// Project Home - http://benalman.com/projects/jquery-outside-events-plugin/ |
|
// GitHub - http://github.com/cowboy/jquery-outside-events/ |
|
// Source - http://github.com/cowboy/jquery-outside-events/raw/master/jquery.ba-outside-events.js |
|
// (Minified) - http://github.com/cowboy/jquery-outside-events/raw/master/jquery.ba-outside-events.min.js (0.9kb) |
|
// |
|
// About: License |
|
// |
|
// Copyright (c) 2010 "Cowboy" Ben Alman, |
|
// Dual licensed under the MIT and GPL licenses. |
|
// http://benalman.com/about/license/ |
|
// |
|
// About: Examples |
|
// |
|
// These working examples, complete with fully commented code, illustrate a few |
|
// ways in which this plugin can be used. |
|
// |
|
// clickoutside - http://benalman.com/code/projects/jquery-outside-events/examples/clickoutside/ |
|
// dblclickoutside - http://benalman.com/code/projects/jquery-outside-events/examples/dblclickoutside/ |
|
// mouseoveroutside - http://benalman.com/code/projects/jquery-outside-events/examples/mouseoveroutside/ |
|
// focusoutside - http://benalman.com/code/projects/jquery-outside-events/examples/focusoutside/ |
|
// |
|
// About: Support and Testing |
|
// |
|
// Information about what version or versions of jQuery this plugin has been |
|
// tested with, what browsers it has been tested in, and where the unit tests |
|
// reside (so you can test it yourself). |
|
// |
|
// jQuery Versions - 1.4.2 |
|
// Browsers Tested - Internet Explorer 6-8, Firefox 2-3.6, Safari 3-4, Chrome, Opera 9.6-10.1. |
|
// Unit Tests - http://benalman.com/code/projects/jquery-outside-events/unit/ |
|
// |
|
// About: Release History |
|
// |
|
// 1.1 - (3/16/2010) Made "clickoutside" plugin more general, resulting in a |
|
// whole new plugin with more than a dozen default "outside" events and |
|
// a method that can be used to add new ones. |
|
// 1.0 - (2/27/2010) Initial release |
|
// |
|
// Topic: Default "outside" events |
|
// |
|
// Note that each "outside" event is powered by an "originating" event. Only |
|
// when the originating event is triggered on an element outside the element |
|
// to which that outside event is bound will the bound event be triggered. |
|
// |
|
// Because each outside event is powered by a separate originating event, |
|
// stopping propagation of that originating event will prevent its related |
|
// outside event from triggering. |
|
// |
|
// OUTSIDE EVENT - ORIGINATING EVENT |
|
// clickoutside - click |
|
// dblclickoutside - dblclick |
|
// focusoutside - focusin |
|
// bluroutside - focusout |
|
// mousemoveoutside - mousemove |
|
// mousedownoutside - mousedown |
|
// mouseupoutside - mouseup |
|
// mouseoveroutside - mouseover |
|
// mouseoutoutside - mouseout |
|
// keydownoutside - keydown |
|
// keypressoutside - keypress |
|
// keyupoutside - keyup |
|
// changeoutside - change |
|
// selectoutside - select |
|
// submitoutside - submit |
|
|
|
(function($,doc,outside){ |
|
'$:nomunge'; // Used by YUI compressor. |
|
|
|
$.map( |
|
// All these events will get an "outside" event counterpart by default. |
|
'click dblclick mousemove mousedown mouseup mouseover mouseout change select submit keydown keypress keyup'.split(' '), |
|
function( event_name ) { jq_addOutsideEvent( event_name ); } |
|
); |
|
|
|
// The focus and blur events are really focusin and focusout when it comes |
|
// to delegation, so they are a special case. |
|
jq_addOutsideEvent( 'focusin', 'focus' + outside ); |
|
jq_addOutsideEvent( 'focusout', 'blur' + outside ); |
|
|
|
// Method: jQuery.addOutsideEvent |
|
// |
|
// Register a new "outside" event to be with this method. Adding an outside |
|
// event that already exists will probably blow things up, so check the |
|
// <Default "outside" events> list before trying to add a new one. |
|
// |
|
// Usage: |
|
// |
|
// > jQuery.addOutsideEvent( event_name [, outside_event_name ] ); |
|
// |
|
// Arguments: |
|
// |
|
// event_name - (String) The name of the originating event that the new |
|
// "outside" event will be powered by. This event can be a native or |
|
// custom event, as long as it bubbles up the DOM tree. |
|
// outside_event_name - (String) An optional name for the new "outside" |
|
// event. If omitted, the outside event will be named whatever the |
|
// value of `event_name` is plus the "outside" suffix. |
|
// |
|
// Returns: |
|
// |
|
// Nothing. |
|
|
|
$.addOutsideEvent = jq_addOutsideEvent; |
|
|
|
function jq_addOutsideEvent( event_name, outside_event_name ) { |
|
|
|
// The "outside" event name. |
|
outside_event_name = outside_event_name || event_name + outside; |
|
|
|
// A jQuery object containing all elements to which the "outside" event is |
|
// bound. |
|
var elems = $(), |
|
|
|
// The "originating" event, namespaced for easy unbinding. |
|
event_namespaced = event_name + '.' + outside_event_name + '-special-event'; |
|
|
|
// Event: outside events |
|
// |
|
// An "outside" event is triggered on an element when its corresponding |
|
// "originating" event is triggered on an element outside the element in |
|
// question. See the <Default "outside" events> list for more information. |
|
// |
|
// Usage: |
|
// |
|
// > jQuery('selector').bind( 'clickoutside', function(event) { |
|
// > var clicked_elem = $(event.target); |
|
// > ... |
|
// > }); |
|
// |
|
// > jQuery('selector').bind( 'dblclickoutside', function(event) { |
|
// > var double_clicked_elem = $(event.target); |
|
// > ... |
|
// > }); |
|
// |
|
// > jQuery('selector').bind( 'mouseoveroutside', function(event) { |
|
// > var moused_over_elem = $(event.target); |
|
// > ... |
|
// > }); |
|
// |
|
// > jQuery('selector').bind( 'focusoutside', function(event) { |
|
// > var focused_elem = $(event.target); |
|
// > ... |
|
// > }); |
|
// |
|
// You get the idea, right? |
|
|
|
$.event.special[ outside_event_name ] = { |
|
|
|
// Called only when the first "outside" event callback is bound per |
|
// element. |
|
setup: function(){ |
|
|
|
// Add this element to the list of elements to which this "outside" |
|
// event is bound. |
|
elems = elems.add( this ); |
|
|
|
// If this is the first element getting the event bound, bind a handler |
|
// to document to catch all corresponding "originating" events. |
|
if ( elems.length === 1 ) { |
|
$(doc).bind( event_namespaced, handle_event ); |
|
} |
|
}, |
|
|
|
// Called only when the last "outside" event callback is unbound per |
|
// element. |
|
teardown: function(){ |
|
|
|
// Remove this element from the list of elements to which this |
|
// "outside" event is bound. |
|
elems = elems.not( this ); |
|
|
|
// If this is the last element removed, remove the "originating" event |
|
// handler on document that powers this "outside" event. |
|
if ( elems.length === 0 ) { |
|
$(doc).unbind( event_namespaced ); |
|
} |
|
}, |
|
|
|
// Called every time a "outside" event callback is bound to an element. |
|
add: function( handleObj ) { |
|
var old_handler = handleObj.handler; |
|
|
|
// This function is executed every time the event is triggered. This is |
|
// used to override the default event.target reference with one that is |
|
// more useful. |
|
handleObj.handler = function( event, elem ) { |
|
|
|
// Set the event object's .target property to the element that the |
|
// user interacted with, not the element that the "outside" event was |
|
// was triggered on. |
|
event.target = elem; |
|
|
|
// Execute the actual bound handler. |
|
old_handler.apply( this, arguments ); |
|
}; |
|
} |
|
}; |
|
|
|
// When the "originating" event is triggered.. |
|
function handle_event( event ) { |
|
|
|
// Iterate over all elements to which this "outside" event is bound. |
|
$(elems).each(function(){ |
|
var elem = $(this); |
|
|
|
// If this element isn't the element on which the event was triggered, |
|
// and this element doesn't contain said element, then said element is |
|
// considered to be outside, and the "outside" event will be triggered! |
|
if ( this !== event.target && !elem.has(event.target).length ) { |
|
|
|
// Use triggerHandler instead of trigger so that the "outside" event |
|
// doesn't bubble. Pass in the "originating" event's .target so that |
|
// the "outside" event.target can be overridden with something more |
|
// meaningful. |
|
elem.triggerHandler( outside_event_name, [ event.target ] ); |
|
} |
|
}); |
|
}; |
|
|
|
}; |
|
|
|
})(jQuery,document,"outside"); |