src/cm/media/js/lib/yui/yui3.0.0/build/event/event-delegate-debug.js
changeset 0 40c8f766c9b8
equal deleted inserted replaced
-1:000000000000 0:40c8f766c9b8
       
     1 /*
       
     2 Copyright (c) 2009, Yahoo! Inc. All rights reserved.
       
     3 Code licensed under the BSD License:
       
     4 http://developer.yahoo.net/yui/license.txt
       
     5 version: 3.0.0
       
     6 build: 1549
       
     7 */
       
     8 YUI.add('event-delegate', function(Y) {
       
     9 
       
    10 /**
       
    11  * Adds event delegation support to the library.
       
    12  * 
       
    13  * @module event
       
    14  * @submodule event-delegate
       
    15  */
       
    16 
       
    17 var Event = Y.Event,
       
    18 	Lang = Y.Lang,
       
    19 
       
    20 	delegates = {},
       
    21 	
       
    22 	specialTypes = {
       
    23 		mouseenter: "mouseover",
       
    24 		mouseleave: "mouseout"
       
    25 	},
       
    26 
       
    27 	resolveTextNode = function(n) {
       
    28 	    try {
       
    29 	        if (n && 3 == n.nodeType) {
       
    30 	            return n.parentNode;
       
    31 	        }
       
    32 	    } catch(e) { }
       
    33 	    return n;
       
    34 	},
       
    35 
       
    36     delegateHandler = function(delegateKey, e, el) {
       
    37 
       
    38         var target = resolveTextNode((e.target || e.srcElement)), 
       
    39             tests  = delegates[delegateKey],
       
    40             spec, 
       
    41 			ename,
       
    42 			matched,
       
    43 			fn,
       
    44 			ev;
       
    45 
       
    46 
       
    47 		var getMatch = function(el, selector, container) {
       
    48 			
       
    49 			var returnVal;
       
    50 			
       
    51 			if (!el || el === container) {
       
    52 				returnVal = false;
       
    53 			}
       
    54 			else {
       
    55 				returnVal = Y.Selector.test(el, selector) ? el: getMatch(el.parentNode, selector, container);
       
    56 			}
       
    57 			
       
    58 			return returnVal;
       
    59 			
       
    60 		};
       
    61 
       
    62 
       
    63         for (spec in tests) {
       
    64 
       
    65             if (tests.hasOwnProperty(spec)) {
       
    66 
       
    67                 ename  = tests[spec];
       
    68 				fn	= tests.fn;
       
    69 				matched = null;
       
    70 
       
    71 
       
    72 				if (Y.Selector.test(target, spec, el)) {
       
    73 					matched = target;
       
    74 				}
       
    75 				else if (Y.Selector.test(target, ((spec.replace(/,/gi, " *,")) + " *"), el)) {
       
    76 						
       
    77 					//	The target is a descendant of an element matching 
       
    78 					//	the selector, so crawl up to find the ancestor that 
       
    79 					//	matches the selector
       
    80 					
       
    81 					matched = getMatch(target, spec, el);
       
    82 					
       
    83 				}
       
    84 
       
    85 
       
    86 				if (matched) {
       
    87 
       
    88                     if (!ev) {
       
    89                         ev = new Y.DOMEventFacade(e, el);
       
    90                         ev.container = ev.currentTarget;
       
    91                     }
       
    92 
       
    93                     ev.currentTarget = Y.Node.get(matched);
       
    94 
       
    95 					Y.publish(ename, {
       
    96 			               contextFn: function() {
       
    97 			                   return ev.currentTarget;
       
    98 			               }
       
    99 			           });
       
   100 
       
   101 					if (fn) {
       
   102 						fn(ev, ename);
       
   103 					}
       
   104 					else {
       
   105                     	Y.fire(ename, ev);								
       
   106 					}
       
   107 					
       
   108 				}
       
   109 
       
   110             }
       
   111         }
       
   112 
       
   113     },
       
   114 
       
   115 	attach = function (type, key, element) {
       
   116 
       
   117 		var focusMethods = {
       
   118 				focus: Event._attachFocus,
       
   119 				blur: Event._attachBlur
       
   120 			},
       
   121 
       
   122 			attachFn = focusMethods[type],
       
   123 
       
   124 			args = [type, 
       
   125 			function (e) {
       
   126 	            delegateHandler(key, (e || window.event), element);
       
   127 			}, 
       
   128 			element];
       
   129 
       
   130 
       
   131 		if (attachFn) {
       
   132 			return attachFn(args, { capture: true, facade: false });
       
   133 		}
       
   134 		else {
       
   135 			return Event._attach(args, { facade: false });
       
   136 		}
       
   137 		
       
   138 	},
       
   139 
       
   140     sanitize = Y.cached(function(str) {
       
   141         return str.replace(/[|,:]/g, '~');
       
   142     });
       
   143 
       
   144 /**
       
   145  * Sets up event delegation on a container element.  The delegated event
       
   146  * will use a supplied selector to test if the target or one of the
       
   147  * descendants of the target match it.  The supplied callback function 
       
   148  * will only be executed if a match was encountered, and, in fact, 
       
   149  * will be executed for each element that matches if you supply an 
       
   150  * ambiguous selector.
       
   151  *
       
   152  * The event object for the delegated event is supplied to the callback
       
   153  * function.  It is modified slightly in order to support all properties
       
   154  * that may be needed for event delegation.  'currentTarget' is set to
       
   155  * the element that matched the delegation specifcation.  'container' is
       
   156  * set to the element that the listener is bound to (this normally would
       
   157  * be the 'currentTarget').
       
   158  *
       
   159  * @event delegate
       
   160  * @param type {string} 'delegate'
       
   161  * @param fn {function} the callback function to execute.  This function
       
   162  * will be provided the event object for the delegated event.
       
   163  * @param el {string|node} the element that is the delegation container
       
   164  * @param delegateType {string} the event type to delegate
       
   165  * @param spec {string} a selector that must match the target of the
       
   166  * event.
       
   167  * @param context optional argument that specifies what 'this' refers to.
       
   168  * @param args* 0..n additional arguments to pass on to the callback function.
       
   169  * These arguments will be added after the event object.
       
   170  * @return {EventHandle} the detach handle
       
   171  * @for YUI
       
   172  * @deprecated use Y.delegate
       
   173  */
       
   174 Y.Env.evt.plugins.delegate = {
       
   175 
       
   176     on: function(type, fn, el, delegateType, spec) {
       
   177 
       
   178         Y.log('delegate event is deprecated, use Y.delegate()', 'warn', 'deprecated');
       
   179 
       
   180 		var args = Y.Array(arguments, 0, true);
       
   181 		
       
   182 		args.splice(3, 1);
       
   183 		
       
   184 		args[0] = delegateType;
       
   185 
       
   186 		return Y.delegate.apply(Y, args);
       
   187 
       
   188     }
       
   189 
       
   190 };
       
   191 
       
   192 
       
   193 /**
       
   194  * Sets up event delegation on a container element.  The delegated event
       
   195  * will use a supplied selector to test if the target or one of the
       
   196  * descendants of the target match it.  The supplied callback function 
       
   197  * will only be executed if a match was encountered, and, in fact, 
       
   198  * will be executed for each element that matches if you supply an 
       
   199  * ambiguous selector.
       
   200  *
       
   201  * The event object for the delegated event is supplied to the callback
       
   202  * function.  It is modified slightly in order to support all properties
       
   203  * that may be needed for event delegation.  'currentTarget' is set to
       
   204  * the element that matched the delegation specifcation.  'container' is
       
   205  * set to the element that the listener is bound to (this normally would
       
   206  * be the 'currentTarget').
       
   207  *
       
   208  * @method delegate
       
   209  * @param type {string} the event type to delegate
       
   210  * @param fn {function} the callback function to execute.  This function
       
   211  * will be provided the event object for the delegated event.
       
   212  * @param el {string|node} the element that is the delegation container
       
   213  * @param spec {string} a selector that must match the target of the
       
   214  * event.
       
   215  * @param context optional argument that specifies what 'this' refers to.
       
   216  * @param args* 0..n additional arguments to pass on to the callback function.
       
   217  * These arguments will be added after the event object.
       
   218  * @return {EventHandle} the detach handle
       
   219  * @for YUI
       
   220  */
       
   221 Event.delegate = function (type, fn, el, spec) {
       
   222 
       
   223     if (!spec) {
       
   224         Y.log('delegate: no spec, nothing to do', 'warn', 'event');
       
   225         return false;
       
   226     }
       
   227 
       
   228 
       
   229     var args = Y.Array(arguments, 0, true),	    
       
   230 		element = el,	// HTML element serving as the delegation container
       
   231 		availHandle;	
       
   232 
       
   233 
       
   234 	if (Lang.isString(el)) {
       
   235 		
       
   236 		//	Y.Selector.query returns an array of matches unless specified 
       
   237 		//	to return just the first match.  Since the primary use case for
       
   238 		//	event delegation is to use a single event handler on a container,
       
   239 		//	Y.delegate doesn't currently support being able to bind a 
       
   240 		//	single listener to multiple containers.
       
   241 		
       
   242 		element = Y.Selector.query(el, null, true);
       
   243 		
       
   244 		if (!element) { // Not found, check using onAvailable
       
   245 
       
   246 			availHandle = Event.onAvailable(el, function() {
       
   247 
       
   248 				availHandle.handle = Event.delegate.apply(Event, args);
       
   249 
       
   250             }, Event, true, false);
       
   251 
       
   252             return availHandle;
       
   253 			
       
   254 		}
       
   255 		
       
   256 	}
       
   257 
       
   258 
       
   259 	element = Y.Node.getDOMNode(element);
       
   260 
       
   261 
       
   262 	var	guid = Y.stamp(element),
       
   263             
       
   264         // The Custom Event for the delegation spec
       
   265         ename = 'delegate:' + guid + type + sanitize(spec),
       
   266 
       
   267         // The key to the listener for the event type and container
       
   268         delegateKey = type + guid,
       
   269 
       
   270 		delegate = delegates[delegateKey],
       
   271 
       
   272 		domEventHandle,
       
   273 		
       
   274 		ceHandle,
       
   275 		
       
   276 		listeners;
       
   277 	
       
   278 
       
   279     if (!delegate) {
       
   280 
       
   281 		delegate = {};
       
   282 
       
   283 		if (specialTypes[type]) {
       
   284 			
       
   285 			if (!Event._fireMouseEnter) {
       
   286 				Y.log("Delegating a " + type + " event requires the event-mouseenter submodule.", "error", "Event");
       
   287 				return false;				
       
   288 			}
       
   289 			
       
   290 			type = specialTypes[type];
       
   291 			delegate.fn = Event._fireMouseEnter;
       
   292 			
       
   293 		}
       
   294 
       
   295 		//	Create the DOM Event wrapper that will fire the Custom Event
       
   296 
       
   297 		domEventHandle = attach(type, delegateKey, element);
       
   298 
       
   299 
       
   300 		//	Hook into the _delete method for the Custom Event wrapper of this
       
   301 		//	DOM Event in order to clean up the 'delegates' map and unsubscribe
       
   302 		//	the associated Custom Event listeners fired by this DOM event
       
   303 		//	listener if/when the user calls "purgeElement" OR removes all 
       
   304 		//	listeners of the Custom Event.
       
   305 		
       
   306 		Y.after(function (sub) {
       
   307 
       
   308 			if (domEventHandle.sub == sub) {
       
   309 
       
   310 				//	Delete this event from the map of known delegates
       
   311 				delete delegates[delegateKey];
       
   312 
       
   313 				Y.log("DOM event listener associated with the " + ename + " Custom Event removed.  Removing all " + ename + " listeners.", "info", "Event");
       
   314 
       
   315 				//	Unsubscribe all listeners of the Custom Event fired 
       
   316 				//	by this DOM event.
       
   317 				Y.detachAll(ename);
       
   318 				
       
   319 			}
       
   320 
       
   321 		}, domEventHandle.evt, "_delete");
       
   322 			
       
   323 		delegate.handle = domEventHandle;
       
   324 
       
   325         delegates[delegateKey] = delegate;
       
   326 
       
   327     }
       
   328 
       
   329 
       
   330 	listeners = delegate.listeners;
       
   331 
       
   332 	delegate.listeners = listeners ? (listeners + 1) : 1;
       
   333     delegate[spec] = ename;
       
   334 
       
   335 
       
   336     args[0] = ename;
       
   337 
       
   338     // Remove element, delegation spec
       
   339     args.splice(2, 2);
       
   340         
       
   341 
       
   342     // Subscribe to the Custom Event for the delegation spec
       
   343 
       
   344 	ceHandle = Y.on.apply(Y, args);
       
   345 
       
   346 
       
   347 	//	Hook into the detach method of the handle in order to clean up the 
       
   348 	//	'delegates' map and remove the associated DOM event handler 
       
   349 	//	responsible for firing this Custom Event if all listener for this 
       
   350 	//	event have been removed.
       
   351 
       
   352 	Y.after(function () {
       
   353 			
       
   354 		delegate.listeners = (delegate.listeners - 1);
       
   355 		
       
   356 		if (delegate.listeners === 0) {
       
   357 			Y.log("No more listeners for the " + ename + " Custom Event.  Removing its associated DOM event listener.", "info", "Event");
       
   358 			delegate.handle.detach();
       
   359 		}
       
   360 
       
   361 	}, ceHandle, "detach");
       
   362 
       
   363     return ceHandle;
       
   364 	
       
   365 };
       
   366 
       
   367 Y.delegate = Event.delegate;
       
   368 
       
   369 
       
   370 }, '3.0.0' ,{requires:['node-base']});