1YUI.add('event-custom-base', function (Y, NAME) { 2 3/** 4 * Custom event engine, DOM event listener abstraction layer, synthetic DOM 5 * events. 6 * @module event-custom 7 */ 8 9Y.Env.evt = { 10 handles: {}, 11 plugins: {} 12}; 13 14/** 15 * Custom event engine, DOM event listener abstraction layer, synthetic DOM 16 * events. 17 * @module event-custom 18 * @submodule event-custom-base 19 */ 20 21/** 22 * Allows for the insertion of methods that are executed before or after 23 * a specified method 24 * @class Do 25 * @static 26 */ 27 28var DO_BEFORE = 0, 29 DO_AFTER = 1, 30 31DO = { 32 33 /** 34 * Cache of objects touched by the utility 35 * @property objs 36 * @static 37 * @deprecated Since 3.6.0. The `_yuiaop` property on the AOP'd object 38 * replaces the role of this property, but is considered to be private, and 39 * is only mentioned to provide a migration path. 40 * 41 * If you have a use case which warrants migration to the _yuiaop property, 42 * please file a ticket to let us know what it's used for and we can see if 43 * we need to expose hooks for that functionality more formally. 44 */ 45 objs: null, 46 47 /** 48 * <p>Execute the supplied method before the specified function. Wrapping 49 * function may optionally return an instance of the following classes to 50 * further alter runtime behavior:</p> 51 * <dl> 52 * <dt></code>Y.Do.Halt(message, returnValue)</code></dt> 53 * <dd>Immediatly stop execution and return 54 * <code>returnValue</code>. No other wrapping functions will be 55 * executed.</dd> 56 * <dt></code>Y.Do.AlterArgs(message, newArgArray)</code></dt> 57 * <dd>Replace the arguments that the original function will be 58 * called with.</dd> 59 * <dt></code>Y.Do.Prevent(message)</code></dt> 60 * <dd>Don't execute the wrapped function. Other before phase 61 * wrappers will be executed.</dd> 62 * </dl> 63 * 64 * @method before 65 * @param fn {Function} the function to execute 66 * @param obj the object hosting the method to displace 67 * @param sFn {string} the name of the method to displace 68 * @param c The execution context for fn 69 * @param arg* {mixed} 0..n additional arguments to supply to the subscriber 70 * when the event fires. 71 * @return {EventHandle} handle for the subscription 72 * @static 73 */ 74 before: function(fn, obj, sFn, c) { 75 var f = fn, a; 76 if (c) { 77 a = [fn, c].concat(Y.Array(arguments, 4, true)); 78 f = Y.rbind.apply(Y, a); 79 } 80 81 return this._inject(DO_BEFORE, f, obj, sFn); 82 }, 83 84 /** 85 * <p>Execute the supplied method after the specified function. Wrapping 86 * function may optionally return an instance of the following classes to 87 * further alter runtime behavior:</p> 88 * <dl> 89 * <dt></code>Y.Do.Halt(message, returnValue)</code></dt> 90 * <dd>Immediatly stop execution and return 91 * <code>returnValue</code>. No other wrapping functions will be 92 * executed.</dd> 93 * <dt></code>Y.Do.AlterReturn(message, returnValue)</code></dt> 94 * <dd>Return <code>returnValue</code> instead of the wrapped 95 * method's original return value. This can be further altered by 96 * other after phase wrappers.</dd> 97 * </dl> 98 * 99 * <p>The static properties <code>Y.Do.originalRetVal</code> and 100 * <code>Y.Do.currentRetVal</code> will be populated for reference.</p> 101 * 102 * @method after 103 * @param fn {Function} the function to execute 104 * @param obj the object hosting the method to displace 105 * @param sFn {string} the name of the method to displace 106 * @param c The execution context for fn 107 * @param arg* {mixed} 0..n additional arguments to supply to the subscriber 108 * @return {EventHandle} handle for the subscription 109 * @static 110 */ 111 after: function(fn, obj, sFn, c) { 112 var f = fn, a; 113 if (c) { 114 a = [fn, c].concat(Y.Array(arguments, 4, true)); 115 f = Y.rbind.apply(Y, a); 116 } 117 118 return this._inject(DO_AFTER, f, obj, sFn); 119 }, 120 121 /** 122 * Execute the supplied method before or after the specified function. 123 * Used by <code>before</code> and <code>after</code>. 124 * 125 * @method _inject 126 * @param when {string} before or after 127 * @param fn {Function} the function to execute 128 * @param obj the object hosting the method to displace 129 * @param sFn {string} the name of the method to displace 130 * @param c The execution context for fn 131 * @return {EventHandle} handle for the subscription 132 * @private 133 * @static 134 */ 135 _inject: function(when, fn, obj, sFn) { 136 // object id 137 var id = Y.stamp(obj), o, sid; 138 139 if (!obj._yuiaop) { 140 // create a map entry for the obj if it doesn't exist, to hold overridden methods 141 obj._yuiaop = {}; 142 } 143 144 o = obj._yuiaop; 145 146 if (!o[sFn]) { 147 // create a map entry for the method if it doesn't exist 148 o[sFn] = new Y.Do.Method(obj, sFn); 149 150 // re-route the method to our wrapper 151 obj[sFn] = function() { 152 return o[sFn].exec.apply(o[sFn], arguments); 153 }; 154 } 155 156 // subscriber id 157 sid = id + Y.stamp(fn) + sFn; 158 159 // register the callback 160 o[sFn].register(sid, fn, when); 161 162 return new Y.EventHandle(o[sFn], sid); 163 }, 164 165 /** 166 * Detach a before or after subscription. 167 * 168 * @method detach 169 * @param handle {EventHandle} the subscription handle 170 * @static 171 */ 172 detach: function(handle) { 173 if (handle.detach) { 174 handle.detach(); 175 } 176 } 177}; 178 179Y.Do = DO; 180 181////////////////////////////////////////////////////////////////////////// 182 183/** 184 * Contains the return value from the wrapped method, accessible 185 * by 'after' event listeners. 186 * 187 * @property originalRetVal 188 * @static 189 * @since 3.2.0 190 */ 191
192/** 193 * Contains the current state of the return value, consumable by 194 * 'after' event listeners, and updated if an after subscriber 195 * changes the return value generated by the wrapped function. 196 * 197 * @property currentRetVal 198 * @static 199 * @since 3.2.0 200 */ 201 202////////////////////////////////////////////////////////////////////////// 203 204/** 205 * Wrapper for a displaced method with aop enabled 206 * @class Do.Method 207 * @constructor 208 * @param obj The object to operate on 209 * @param sFn The name of the method to displace 210 */ 211DO.Method = function(obj, sFn) { 212 this.obj = obj; 213 this.methodName = sFn; 214 this.method = obj[sFn]; 215 this.before = {}; 216 this.after = {}; 217}; 218 219/** 220 * Register a aop subscriber 221 * @method register 222 * @param sid {string} the subscriber id 223 * @param fn {Function} the function to execute 224 * @param when {string} when to execute the function 225 */ 226DO.Method.prototype.register = function (sid, fn, when) { 227 if (when) { 228 this.after[sid] = fn; 229 } else { 230 this.before[sid] = fn; 231 } 232}; 233 234/** 235 * Unregister a aop subscriber 236 * @method delete 237 * @param sid {string} the subscriber id 238 * @param fn {Function} the function to execute 239 * @param when {string} when to execute the function 240 */ 241DO.Method.prototype._delete = function (sid) { 242 delete this.before[sid]; 243 delete this.after[sid]; 244}; 245 246/** 247 * <p>Execute the wrapped method. All arguments are passed into the wrapping 248 * functions. If any of the before wrappers return an instance of 249 * <code>Y.Do.Halt</code> or <code>Y.Do.Prevent</code>, neither the wrapped 250 * function nor any after phase subscribers will be executed.</p> 251 * 252 * <p>The return value will be the return value of the wrapped function or one 253 * provided by a wrapper function via an instance of <code>Y.Do.Halt</code> or 254 * <code>Y.Do.AlterReturn</code>. 255 * 256 * @method exec 257 * @param arg* {any} Arguments are passed to the wrapping and wrapped functions 258 * @return {any} Return value of wrapped function unless overwritten (see above) 259 */ 260DO.Method.prototype.exec = function () { 261 262 var args = Y.Array(arguments, 0, true), 263 i, ret, newRet, 264 bf = this.before, 265 af = this.after, 266 prevented = false; 267 268 // execute before 269 for (i in bf) { 270 if (bf.hasOwnProperty(i)) { 271 ret = bf[i].apply(this.obj, args); 272 if (ret) { 273 switch (ret.constructor) { 274 case DO.Halt: 275 return ret.retVal; 276 case DO.AlterArgs: 277 args = ret.newArgs; 278 break; 279 case DO.Prevent: 280 prevented = true; 281 break; 282 default: 283 } 284 } 285 } 286 } 287 288 // execute method 289 if (!prevented) { 290 ret = this.method.apply(this.obj, args); 291 } 292 293 DO.originalRetVal = ret; 294 DO.currentRetVal = ret; 295 296 // execute after methods. 297 for (i in af) { 298 if (af.hasOwnProperty(i)) { 299 newRet = af[i].apply(this.obj, args); 300 // Stop processing if a Halt object is returned 301 if (newRet && newRet.constructor === DO.Halt) { 302 return newRet.retVal; 303 // Check for a new return value 304 } else if (newRet && newRet.constructor === DO.AlterReturn) { 305 ret = newRet.newRetVal; 306 // Update the static retval state 307 DO.currentRetVal = ret; 308 } 309 } 310 } 311 312 return ret; 313}; 314 315////////////////////////////////////////////////////////////////////////// 316 317/** 318 * Return an AlterArgs object when you want to change the arguments that 319 * were passed into the function. Useful for Do.before subscribers. An 320 * example would be a service that scrubs out illegal characters prior to 321 * executing the core business logic. 322 * @class Do.AlterArgs 323 * @constructor 324 * @param msg {String} (optional) Explanation of the altered return value 325 * @param newArgs {Array} Call parameters to be used for the original method 326 * instead of the arguments originally passed in. 327 */ 328DO.AlterArgs = function(msg, newArgs) { 329 this.msg = msg; 330 this.newArgs = newArgs; 331}; 332 333/** 334 * Return an AlterReturn object when you want to change the result returned 335 * from the core method to the caller. Useful for Do.after subscribers. 336 * @class Do.AlterReturn 337 * @constructor 338 * @param msg {String} (optional) Explanation of the altered return value 339 * @param newRetVal {any} Return value passed to code that invoked the wrapped 340 * function. 341 */ 342DO.AlterReturn = function(msg, newRetVal) { 343 this.msg = msg; 344 this.newRetVal = newRetVal; 345}; 346 347/** 348 * Return a Halt object when you want to terminate the execution 349 * of all subsequent subscribers as well as the wrapped method 350 * if it has not exectued yet. Useful for Do.before subscribers. 351 * @class Do.Halt 352 * @constructor 353 * @param msg {String} (optional) Explanation of why the termination was done 354 * @param retVal {any} Return value passed to code that invoked the wrapped 355 * function. 356 */ 357DO.Halt = function(msg, retVal) { 358 this.msg = msg; 359 this.retVal = retVal; 360}; 361 362/** 363 * Return a Prevent object when you want to prevent the wrapped function 364 * from executing, but want the remaining listeners to execute. Useful 365 * for Do.before subscribers. 366 * @class Do.Prevent 367 * @constructor 368 * @param msg {String} (optional) Explanation of why the termination was done 369 */ 370DO.Prevent = function(msg) { 371 this.msg = msg; 372}; 373 374/** 375 * Return an Error object when you want to terminate the execution 376 * of all subsequent method calls. 377 * @class Do.Error 378 * @constructor 379 * @param msg {String} (optional) Explanation of the altered return value 380 * @param retVal {any} Return value passed to code that invoked the wrapped 381 * function. 382 * @deprecated use Y.Do.Halt or Y.Do.Prevent 383 */ 384DO.Error = DO.Halt; 385 386
387////////////////////////////////////////////////////////////////////////// 388 389/** 390 * Custom event engine, DOM event listener abstraction layer, synthetic DOM 391 * events. 392 * @module event-custom 393 * @submodule event-custom-base 394 */ 395 396 397// var onsubscribeType = "_event:onsub", 398var YArray = Y.Array, 399 400 AFTER = 'after', 401 CONFIGS = [ 402 'broadcast', 403 'monitored', 404 'bubbles', 405 'context', 406 'contextFn', 407 'currentTarget', 408 'defaultFn', 409 'defaultTargetOnly', 410 'details', 411 'emitFacade', 412 'fireOnce', 413 'async', 414 'host', 415 'preventable', 416 'preventedFn', 417 'queuable', 418 'silent', 419 'stoppedFn', 420 'target', 421 'type' 422 ], 423 424 CONFIGS_HASH = YArray.hash(CONFIGS), 425 426 nativeSlice = Array.prototype.slice, 427 428 YUI3_SIGNATURE = 9, 429 YUI_LOG = 'yui:log', 430 431 mixConfigs = function(r, s, ov) { 432 var p; 433 434 for (p in s) { 435 if (CONFIGS_HASH[p] && (ov || !(p in r))) { 436 r[p] = s[p]; 437 } 438 } 439 440 return r; 441 }; 442 443/** 444 * The CustomEvent class lets you define events for your application 445 * that can be subscribed to by one or more independent component. 446 * 447 * @param {String} type The type of event, which is passed to the callback 448 * when the event fires. 449 * @param {object} defaults configuration object. 450 * @class CustomEvent 451 * @constructor 452 */ 453 454 /** 455 * The type of event, returned to subscribers when the event fires 456 * @property type 457 * @type string 458 */ 459 460/** 461 * By default all custom events are logged in the debug build, set silent 462 * to true to disable debug outpu for this event. 463 * @property silent 464 * @type boolean 465 */ 466 467Y.CustomEvent = function(type, defaults) { 468 469 this._kds = Y.CustomEvent.keepDeprecatedSubs; 470 471 this.id = Y.guid(); 472 473 this.type = type; 474 this.silent = this.logSystem = (type === YUI_LOG); 475 476 if (this._kds) { 477 /** 478 * The subscribers to this event 479 * @property subscribers 480 * @type Subscriber {} 481 * @deprecated 482 */ 483 484 /** 485 * 'After' subscribers 486 * @property afters 487 * @type Subscriber {} 488 * @deprecated 489 */ 490 this.subscribers = {}; 491 this.afters = {}; 492 } 493 494 if (defaults) { 495 mixConfigs(this, defaults, true); 496 } 497}; 498 499/** 500 * Static flag to enable population of the <a href="#property_subscribers">`subscribers`</a> 501 * and <a href="#property_subscribers">`afters`</a> properties held on a `CustomEvent` instance. 502 * 503 * These properties were changed to private properties (`_subscribers` and `_afters`), and 504 * converted from objects to arrays for performance reasons. 505 * 506 * Setting this property to true will populate the deprecated `subscribers` and `afters` 507 * properties for people who may be using them (which is expected to be rare). There will 508 * be a performance hit, compared to the new array based implementation. 509 * 510 * If you are using these deprecated properties for a use case which the public API 511 * does not support, please file an enhancement request, and we can provide an alternate 512 * public implementation which doesn't have the performance cost required to maintiain the 513 * properties as objects. 514 * 515 * @property keepDeprecatedSubs 516 * @static 517 * @for CustomEvent 518 * @type boolean 519 * @default false 520 * @deprecated 521 */ 522Y.CustomEvent.keepDeprecatedSubs = false; 523 524Y.CustomEvent.mixConfigs = mixConfigs; 525 526Y.CustomEvent.prototype = { 527 528 constructor: Y.CustomEvent, 529 530 /** 531 * Monitor when an event is attached or detached. 532 * 533 * @property monitored 534 * @type boolean 535 */ 536 537 /** 538 * If 0, this event does not broadcast. If 1, the YUI instance is notified 539 * every time this event fires. If 2, the YUI instance and the YUI global 540 * (if event is enabled on the global) are notified every time this event 541 * fires. 542 * @property broadcast 543 * @type int 544 */ 545 546 /** 547 * Specifies whether this event should be queued when the host is actively 548 * processing an event. This will effect exectution order of the callbacks 549 * for the various events. 550 * @property queuable 551 * @type boolean 552 * @default false 553 */ 554 555 /** 556 * This event has fired if true 557 * 558 * @property fired 559 * @type boolean 560 * @default false; 561 */ 562 563 /** 564 * An array containing the arguments the custom event 565 * was last fired with. 566 * @property firedWith 567 * @type Array 568 */ 569 570 /** 571 * This event should only fire one time if true, and if 572 * it has fired, any new subscribers should be notified 573 * immediately. 574 * 575 * @property fireOnce 576 * @type boolean 577 * @default false; 578 */ 579 580 /** 581 * fireOnce listeners will fire syncronously unless async 582 * is set to true 583 * @property async 584 * @type boolean 585 * @default false 586 */ 587 588 /** 589 * Flag for stopPropagation that is modified during fire() 590 * 1 means to stop propagation to bubble targets. 2 means
591 * to also stop additional subscribers on this target. 592 * @property stopped 593 * @type int 594 */ 595 596 /** 597 * Flag for preventDefault that is modified during fire(). 598 * if it is not 0, the default behavior for this event 599 * @property prevented 600 * @type int 601 */ 602 603 /** 604 * Specifies the host for this custom event. This is used 605 * to enable event bubbling 606 * @property host 607 * @type EventTarget 608 */ 609 610 /** 611 * The default function to execute after event listeners 612 * have fire, but only if the default action was not 613 * prevented. 614 * @property defaultFn 615 * @type Function 616 */ 617 618 /** 619 * Flag for the default function to execute only if the 620 * firing event is the current target. This happens only 621 * when using custom event delegation and setting the 622 * flag to `true` mimics the behavior of event delegation 623 * in the DOM. 624 * 625 * @property defaultTargetOnly 626 * @type Boolean 627 * @default false 628 */ 629 630 /** 631 * The function to execute if a subscriber calls 632 * stopPropagation or stopImmediatePropagation 633 * @property stoppedFn 634 * @type Function 635 */ 636 637 /** 638 * The function to execute if a subscriber calls 639 * preventDefault 640 * @property preventedFn 641 * @type Function 642 */ 643 644 /** 645 * The subscribers to this event 646 * @property _subscribers 647 * @type Subscriber [] 648 * @private 649 */ 650 651 /** 652 * 'After' subscribers 653 * @property _afters 654 * @type Subscriber [] 655 * @private 656 */ 657 658 /** 659 * If set to true, the custom event will deliver an EventFacade object 660 * that is similar to a DOM event object. 661 * @property emitFacade 662 * @type boolean 663 * @default false 664 */ 665 666 /** 667 * Supports multiple options for listener signatures in order to 668 * port YUI 2 apps. 669 * @property signature 670 * @type int 671 * @default 9 672 */ 673 signature : YUI3_SIGNATURE, 674 675 /** 676 * The context the the event will fire from by default. Defaults to the YUI 677 * instance. 678 * @property context 679 * @type object 680 */ 681 context : Y, 682 683 /** 684 * Specifies whether or not this event's default function 685 * can be cancelled by a subscriber by executing preventDefault() 686 * on the event facade 687 * @property preventable 688 * @type boolean 689 * @default true 690 */ 691 preventable : true, 692 693 /** 694 * Specifies whether or not a subscriber can stop the event propagation 695 * via stopPropagation(), stopImmediatePropagation(), or halt() 696 * 697 * Events can only bubble if emitFacade is true. 698 * 699 * @property bubbles 700 * @type boolean 701 * @default true 702 */ 703 bubbles : true, 704 705 /** 706 * Returns the number of subscribers for this event as the sum of the on() 707 * subscribers and after() subscribers. 708 * 709 * @method hasSubs 710 * @return Number 711 */ 712 hasSubs: function(when) { 713 var s = 0, 714 a = 0, 715 subs = this._subscribers, 716 afters = this._afters, 717 sib = this.sibling; 718 719 if (subs) { 720 s = subs.length; 721 } 722 723 if (afters) { 724 a = afters.length; 725 } 726 727 if (sib) { 728 subs = sib._subscribers; 729 afters = sib._afters; 730 731 if (subs) { 732 s += subs.length; 733 } 734 735 if (afters) { 736 a += afters.length; 737 } 738 } 739 740 if (when) { 741 return (when === 'after') ? a : s; 742 } 743 744 return (s + a); 745 }, 746 747 /** 748 * Monitor the event state for the subscribed event. The first parameter 749 * is what should be monitored, the rest are the normal parameters when 750 * subscribing to an event. 751 * @method monitor 752 * @param what {string} what to monitor ('detach', 'attach', 'publish'). 753 * @return {EventHandle} return value from the monitor event subscription. 754 */ 755 monitor: function(what) { 756 this.monitored = true; 757 var type = this.id + '|' + this.type + '_' + what, 758 args = nativeSlice.call(arguments, 0); 759 args[0] = type;
760 return this.host.on.apply(this.host, args); 761 }, 762 763 /** 764 * Get all of the subscribers to this event and any sibling event 765 * @method getSubs 766 * @return {Array} first item is the on subscribers, second the after. 767 */ 768 getSubs: function() { 769 770 var sibling = this.sibling, 771 subs = this._subscribers, 772 afters = this._afters, 773 siblingSubs, 774 siblingAfters; 775 776 if (sibling) { 777 siblingSubs = sibling._subscribers; 778 siblingAfters = sibling._afters; 779 } 780 781 if (siblingSubs) { 782 if (subs) { 783 subs = subs.concat(siblingSubs); 784 } else { 785 subs = siblingSubs.concat(); 786 } 787 } else { 788 if (subs) { 789 subs = subs.concat(); 790 } else { 791 subs = []; 792 } 793 } 794 795 if (siblingAfters) { 796 if (afters) { 797 afters = afters.concat(siblingAfters); 798 } else { 799 afters = siblingAfters.concat(); 800 } 801 } else { 802 if (afters) { 803 afters = afters.concat(); 804 } else { 805 afters = []; 806 } 807 } 808 809 return [subs, afters]; 810 }, 811 812 /** 813 * Apply configuration properties. Only applies the CONFIG whitelist 814 * @method applyConfig 815 * @param o hash of properties to apply. 816 * @param force {boolean} if true, properties that exist on the event 817 * will be overwritten. 818 */ 819 applyConfig: function(o, force) { 820 mixConfigs(this, o, force); 821 }, 822 823 /** 824 * Create the Subscription for subscribing function, context, and bound 825 * arguments. If this is a fireOnce event, the subscriber is immediately 826 * notified. 827 * 828 * @method _on 829 * @param fn {Function} Subscription callback 830 * @param [context] {Object} Override `this` in the callback 831 * @param [args] {Array} bound arguments that will be passed to the callback after the arguments generated by fire() 832 * @param [when] {String} "after" to slot into after subscribers 833 * @return {EventHandle} 834 * @protected 835 */ 836 _on: function(fn, context, args, when) { 837 838 839 var s = new Y.Subscriber(fn, context, args, when), 840 firedWith; 841 842 if (this.fireOnce && this.fired) { 843 844 firedWith = this.firedWith; 845 846 // It's a little ugly for this to know about facades, 847 // but given the current breakup, not much choice without 848 // moving a whole lot of stuff around. 849 if (this.emitFacade && this._addFacadeToArgs) { 850 this._addFacadeToArgs(firedWith); 851 } 852 853 if (this.async) { 854 setTimeout(Y.bind(this._notify, this, s, firedWith), 0); 855 } else { 856 this._notify(s, firedWith); 857 } 858 } 859 860 if (when === AFTER) { 861 if (!this._afters) { 862 this._afters = []; 863 } 864 this._afters.push(s); 865 } else { 866 if (!this._subscribers) { 867 this._subscribers = []; 868 } 869 this._subscribers.push(s); 870 } 871 872 if (this._kds) { 873 if (when === AFTER) { 874 this.afters[s.id] = s; 875 } else { 876 this.subscribers[s.id] = s; 877 } 878 } 879 880 return new Y.EventHandle(this, s); 881 }, 882 883 /** 884 * Listen for this event 885 * @method subscribe 886 * @param {Function} fn The function to execute. 887 * @return {EventHandle} Unsubscribe handle. 888 * @deprecated use on. 889 */ 890 subscribe: function(fn, context) { 891 var a = (arguments.length > 2) ? nativeSlice.call(arguments, 2) : null; 892 return this._on(fn, context, a, true); 893 }, 894 895 /** 896 * Listen for this event 897 * @method on 898 * @param {Function} fn The function to execute. 899 * @param {object} context optional execution context. 900 * @param {mixed} arg* 0..n additional arguments to supply to the subscriber 901 * when the event fires. 902 * @return {EventHandle} An object with a detach method to detch the handler(s). 903 */ 904 on: function(fn, context) { 905 var a = (arguments.length > 2) ? nativeSlice.call(arguments, 2) : null; 906 907 if (this.monitored && this.host) { 908 this.host._monitor('attach', this, { 909 args: arguments 910 }); 911 } 912 return this._on(fn, context, a, true); 913 }, 914 915 /** 916 * Listen for this event after the normal subscribers have been notified and 917 * the default behavior has been applied. If a normal subscriber prevents the 918 * default behavior, it also prevents after listeners from firing. 919 * @method after 920 * @param {Function} fn The function to execute. 921 * @param {object} context optional execution context. 922 * @param {mixed} arg* 0..n additional arguments to supply to the subscriber 923 * when the event fires. 924 * @return {EventHandle} handle Unsubscribe handle. 925 */ 926 after: function(fn, context) { 927 var a = (arguments.length > 2) ? nativeSlice.call(arguments, 2) : null; 928 return this._on(fn, context, a, AFTER); 929 }, 930 931 /** 932 * Detach listeners. 933 * @method detach 934 * @param {Function} fn The subscribed function to remove, if not supplied 935 * all will be removed. 936 * @param {Object} context The context object passed to subscribe. 937 * @return {Number} returns the number of subscribers unsubscribed. 938 */ 939 detach: function(fn, context) { 940 // unsubscribe handle 941 if (fn && fn.detach) { 942 return fn.detach(); 943 } 944 945 var i, s, 946 found = 0, 947 subs = this._subscribers, 948 afters = this._afters; 949 950 if (subs) { 951 for (i = subs.length; i >= 0; i--) { 952 s = subs[i]; 953 if (s && (!fn || fn === s.fn)) { 954 this._delete(s, subs, i); 955 found++; 956 } 957 } 958 } 959 960 if (afters) { 961 for (i = afters.length; i >= 0; i--) { 962 s = afters[i]; 963 if (s && (!fn || fn === s.fn)) { 964 this._delete(s, afters, i); 965 found++; 966 } 967 } 968 } 969 970 return found; 971 }, 972 973 /** 974 * Detach listeners. 975 * @method unsubscribe 976 * @param {Function} fn The subscribed function to remove, if not supplied 977 * all will be removed. 978 * @param {Object} context The context object passed to subscribe. 979 * @return {int|undefined} returns the number of subscribers unsubscribed. 980 * @deprecated use detach. 981 */ 982 unsubscribe: function() { 983 return this.detach.apply(this, arguments); 984 }, 985 986 /** 987 * Notify a single subscriber 988 * @method _notify 989 * @param {Subscriber} s the subscriber. 990 * @param {Array} args the arguments array to apply to the listener. 991 * @protected 992 */ 993 _notify: function(s, args, ef) { 994 995 996 var ret; 997 998 ret = s.notify(args, this); 999 1000 if (false === ret || this.stopped > 1) { 1001 return false;
1002 } 1003 1004 return true; 1005 }, 1006 1007 /** 1008 * Logger abstraction to centralize the application of the silent flag 1009 * @method log 1010 * @param {string} msg message to log. 1011 * @param {string} cat log category. 1012 */ 1013 log: function(msg, cat) { 1014 }, 1015 1016 /** 1017 * Notifies the subscribers. The callback functions will be executed 1018 * from the context specified when the event was created, and with the 1019 * following parameters: 1020 * <ul> 1021 * <li>The type of event</li> 1022 * <li>All of the arguments fire() was executed with as an array</li> 1023 * <li>The custom object (if any) that was passed into the subscribe() 1024 * method</li> 1025 * </ul> 1026 * @method fire 1027 * @param {Object*} arguments an arbitrary set of parameters to pass to 1028 * the handler. 1029 * @return {boolean} false if one of the subscribers returned false, 1030 * true otherwise. 1031 * 1032 */ 1033 fire: function() { 1034 1035 // push is the fastest way to go from arguments to arrays 1036 // for most browsers currently 1037 // http://jsperf.com/push-vs-concat-vs-slice/2 1038 1039 var args = []; 1040 args.push.apply(args, arguments); 1041 1042 return this._fire(args); 1043 }, 1044 1045 /** 1046 * Private internal implementation for `fire`, which is can be used directly by 1047 * `EventTarget` and other event module classes which have already converted from 1048 * an `arguments` list to an array, to avoid the repeated overhead. 1049 * 1050 * @method _fire 1051 * @private 1052 * @param {Array} args The array of arguments passed to be passed to handlers. 1053 * @return {boolean} false if one of the subscribers returned false, true otherwise. 1054 */ 1055 _fire: function(args) { 1056 1057 if (this.fireOnce && this.fired) { 1058 return true; 1059 } else { 1060 1061 // this doesn't happen if the event isn't published 1062 // this.host._monitor('fire', this.type, args); 1063 1064 this.fired = true; 1065 1066 if (this.fireOnce) { 1067 this.firedWith = args; 1068 } 1069 1070 if (this.emitFacade) { 1071 return this.fireComplex(args); 1072 } else { 1073 return this.fireSimple(args); 1074 } 1075 } 1076 }, 1077 1078 /** 1079 * Set up for notifying subscribers of non-emitFacade events. 1080 * 1081 * @method fireSimple 1082 * @param args {Array} Arguments passed to fire() 1083 * @return Boolean false if a subscriber returned false 1084 * @protected 1085 */ 1086 fireSimple: function(args) { 1087 this.stopped = 0; 1088 this.prevented = 0; 1089 if (this.hasSubs()) { 1090 var subs = this.getSubs(); 1091 this._procSubs(subs[0], args); 1092 this._procSubs(subs[1], args); 1093 } 1094 if (this.broadcast) { 1095 this._broadcast(args); 1096 } 1097 return this.stopped ? false : true; 1098 }, 1099 1100 // Requires the event-custom-complex module for full funcitonality. 1101 fireComplex: function(args) { 1102 args[0] = args[0] || {}; 1103 return this.fireSimple(args); 1104 }, 1105 1106 /** 1107 * Notifies a list of subscribers. 1108 * 1109 * @method _procSubs 1110 * @param subs {Array} List of subscribers 1111 * @param args {Array} Arguments passed to fire() 1112 * @param ef {} 1113 * @return Boolean false if a subscriber returns false or stops the event 1114 * propagation via e.stopPropagation(), 1115 * e.stopImmediatePropagation(), or e.halt() 1116 * @private 1117 */ 1118 _procSubs: function(subs, args, ef) { 1119 var s, i, l; 1120 1121 for (i = 0, l = subs.length; i < l; i++) { 1122 s = subs[i]; 1123 if (s && s.fn) { 1124 if (false === this._notify(s, args, ef)) { 1125 this.stopped = 2; 1126 } 1127 if (this.stopped === 2) { 1128 return false; 1129 } 1130 } 1131 } 1132 1133 return true; 1134 }, 1135 1136 /** 1137 * Notifies the YUI instance if the event is configured with broadcast = 1, 1138 * and both the YUI instance and Y.Global if configured with broadcast = 2. 1139 * 1140 * @method _broadcast 1141 * @param args {Array} Arguments sent to fire() 1142 * @private 1143 */ 1144 _broadcast: function(args) { 1145 if (!this.stopped && this.broadcast) { 1146 1147 var a = args.concat(); 1148 a.unshift(this.type); 1149 1150 if (this.host !== Y) { 1151 Y.fire.apply(Y, a); 1152 } 1153 1154 if (this.broadcast === 2) { 1155 Y.Global.fire.apply(Y.Global, a); 1156 } 1157 } 1158 }, 1159 1160 /** 1161 * Removes all listeners 1162 * @method unsubscribeAll 1163 * @return {Number} The number of listeners unsubscribed. 1164 * @deprecated use detachAll. 1165 */ 1166 unsubscribeAll: function() { 1167 return this.detachAll.apply(this, arguments); 1168 }, 1169 1170 /** 1171 * Removes all listeners 1172 * @method detachAll 1173 * @return {Number} The number of listeners unsubscribed. 1174 */ 1175 detachAll: function() { 1176 return this.detach(); 1177 }, 1178 1179 /** 1180 * Deletes the subscriber from the internal store of on() and after() 1181 * subscribers. 1182 * 1183 * @method _delete 1184 * @param s subscriber object. 1185 * @param subs (optional) on or after subscriber array 1186 * @param index (optional) The index found. 1187 * @private 1188 */ 1189 _delete: function(s, subs, i) { 1190 var when = s._when; 1191 1192 if (!subs) { 1193 subs = (when === AFTER) ? this._afters : this._subscribers; 1194 } 1195 1196 if (subs) { 1197 i = YArray.indexOf(subs, s, 0); 1198 1199 if (s && subs[i] === s) { 1200 subs.splice(i, 1); 1201 } 1202 } 1203 1204 if (this._kds) { 1205 if (when === AFTER) { 1206 delete this.afters[s.id]; 1207 } else { 1208 delete this.subscribers[s.id]; 1209 } 1210 } 1211 1212 if (this.monitored && this.host) { 1213 this.host._monitor('detach', this, { 1214 ce: this, 1215 sub: s 1216 }); 1217 } 1218 1219 if (s) { 1220 s.deleted = true; 1221 } 1222 } 1223}; 1224/** 1225 * Stores the subscriber information to be used when the event fires. 1226 * @param {Function} fn The wrapped function to execute. 1227 * @param {Object} context The value of the keyword 'this' in the listener. 1228 * @param {Array} args* 0..n additional arguments to supply the listener. 1229 * 1230 * @class Subscriber 1231 * @constructor 1232 */ 1233Y.Subscriber = function(fn, context, args, when) { 1234 1235 /** 1236 * The callback that will be execute when the event fires 1237 * This is wrapped by Y.rbind if obj was supplied.
1238 * @property fn 1239 * @type Function 1240 */ 1241 this.fn = fn; 1242 1243 /** 1244 * Optional 'this' keyword for the listener 1245 * @property context 1246 * @type Object 1247 */ 1248 this.context = context; 1249 1250 /** 1251 * Unique subscriber id 1252 * @property id 1253 * @type String 1254 */ 1255 this.id = Y.guid(); 1256 1257 /** 1258 * Additional arguments to propagate to the subscriber 1259 * @property args 1260 * @type Array 1261 */ 1262 this.args = args; 1263 1264 this._when = when; 1265 1266 /** 1267 * Custom events for a given fire transaction. 1268 * @property events 1269 * @type {EventTarget} 1270 */ 1271 // this.events = null; 1272 1273 /** 1274 * This listener only reacts to the event once 1275 * @property once 1276 */ 1277 // this.once = false; 1278 1279}; 1280 1281Y.Subscriber.prototype = { 1282 constructor: Y.Subscriber, 1283 1284 _notify: function(c, args, ce) { 1285 if (this.deleted && !this.postponed) { 1286 if (this.postponed) { 1287 delete this.fn; 1288 delete this.context; 1289 } else { 1290 delete this.postponed; 1291 return null; 1292 } 1293 } 1294 var a = this.args, ret; 1295 switch (ce.signature) { 1296 case 0: 1297 ret = this.fn.call(c, ce.type, args, c); 1298 break; 1299 case 1: 1300 ret = this.fn.call(c, args[0] || null, c); 1301 break; 1302 default: 1303 if (a || args) { 1304 args = args || []; 1305 a = (a) ? args.concat(a) : args; 1306 ret = this.fn.apply(c, a); 1307 } else { 1308 ret = this.fn.call(c); 1309 } 1310 } 1311 1312 if (this.once) { 1313 ce._delete(this); 1314 } 1315 1316 return ret; 1317 }, 1318 1319 /** 1320 * Executes the subscriber. 1321 * @method notify 1322 * @param args {Array} Arguments array for the subscriber. 1323 * @param ce {CustomEvent} The custom event that sent the notification. 1324 */ 1325 notify: function(args, ce) { 1326 var c = this.context, 1327 ret = true; 1328 1329 if (!c) { 1330 c = (ce.contextFn) ? ce.contextFn() : ce.context; 1331 } 1332 1333 // only catch errors if we will not re-throw them. 1334 if (Y.config && Y.config.throwFail) { 1335 ret = this._notify(c, args, ce); 1336 } else { 1337 try { 1338 ret = this._notify(c, args, ce); 1339 } catch (e) { 1340 Y.error(this + ' failed: ' + e.message, e); 1341 } 1342 } 1343 1344 return ret; 1345 }, 1346 1347 /** 1348 * Returns true if the fn and obj match this objects properties. 1349 * Used by the unsubscribe method to match the right subscriber. 1350 * 1351 * @method contains 1352 * @param {Function} fn the function to execute. 1353 * @param {Object} context optional 'this' keyword for the listener. 1354 * @return {boolean} true if the supplied arguments match this 1355 * subscriber's signature. 1356 */ 1357 contains: function(fn, context) { 1358 if (context) { 1359 return ((this.fn === fn) && this.context === context); 1360 } else { 1361 return (this.fn === fn); 1362 } 1363 }, 1364 1365 valueOf : function() { 1366 return this.id; 1367 } 1368 1369}; 1370/** 1371 * Return value from all subscribe operations 1372 * @class EventHandle 1373 * @constructor 1374 * @param {CustomEvent} evt the custom event. 1375 * @param {Subscriber} sub the subscriber. 1376 */ 1377Y.EventHandle = function(evt, sub) { 1378 1379 /** 1380 * The custom event 1381 * 1382 * @property evt 1383 * @type CustomEvent 1384 */ 1385 this.evt = evt; 1386 1387 /** 1388 * The subscriber object 1389 * 1390 * @property sub 1391 * @type Subscriber 1392 */ 1393 this.sub = sub; 1394}; 1395 1396Y.EventHandle.prototype = { 1397 batch: function(f, c) { 1398 f.call(c || this, this); 1399 if (Y.Lang.isArray(this.evt)) { 1400 Y.Array.each(this.evt, function(h) { 1401 h.batch.call(c || h, f); 1402 }); 1403 } 1404 }, 1405 1406 /** 1407 * Detaches this subscriber 1408 * @method detach 1409 * @return {Number} the number of detached listeners 1410 */ 1411 detach: function() { 1412 var evt = this.evt, detached = 0, i; 1413 if (evt) { 1414 if (Y.Lang.isArray(evt)) { 1415 for (i = 0; i < evt.length; i++) { 1416 detached += evt[i].detach(); 1417 } 1418 } else { 1419 evt._delete(this.sub); 1420 detached = 1; 1421 } 1422 1423 } 1424 1425 return detached; 1426 }, 1427 1428 /** 1429 * Monitor the event state for the subscribed event. The first parameter 1430 * is what should be monitored, the rest are the normal parameters when 1431 * subscribing to an event. 1432 * @method monitor 1433 * @param what {string} what to monitor ('attach', 'detach', 'publish'). 1434 * @return {EventHandle} return value from the monitor event subscription. 1435 */ 1436 monitor: function(what) { 1437 return this.evt.monitor.apply(this.evt, arguments); 1438 } 1439}; 1440 1441/** 1442 * Custom event engine, DOM event listener abstraction layer, synthetic DOM 1443 * events. 1444 * @module event-custom 1445 * @submodule event-custom-base 1446 */ 1447 1448/** 1449 * EventTarget provides the implementation for any object to 1450 * publish, subscribe and fire to custom events, and also 1451 * alows other EventTargets to target the object with events 1452 * sourced from the other object. 1453 * EventTarget is designed to be used with Y.augment to wrap 1454 * EventCustom in an interface that allows events to be listened to
1455 * and fired by name. This makes it possible for implementing code to 1456 * subscribe to an event that either has not been created yet, or will 1457 * not be created at all. 1458 * @class EventTarget 1459 * @param opts a configuration object 1460 * @config emitFacade {boolean} if true, all events will emit event 1461 * facade payloads by default (default false) 1462 * @config prefix {String} the prefix to apply to non-prefixed event names 1463 */ 1464 1465var L = Y.Lang, 1466 PREFIX_DELIMITER = ':', 1467 CATEGORY_DELIMITER = '|', 1468 AFTER_PREFIX = '~AFTER~', 1469 WILD_TYPE_RE = /(.*?)(:)(.*?)/, 1470 1471 _wildType = Y.cached(function(type) { 1472 return type.replace(WILD_TYPE_RE, "*$2$3"); 1473 }), 1474 1475 /** 1476 * If the instance has a prefix attribute and the 1477 * event type is not prefixed, the instance prefix is 1478 * applied to the supplied type. 1479 * @method _getType 1480 * @private 1481 */ 1482 _getType = function(type, pre) { 1483 1484 if (!pre || (typeof type !== "string") || type.indexOf(PREFIX_DELIMITER) > -1) { 1485 return type; 1486 } 1487 1488 return pre + PREFIX_DELIMITER + type; 1489 }, 1490 1491 /** 1492 * Returns an array with the detach key (if provided), 1493 * and the prefixed event name from _getType 1494 * Y.on('detachcategory| menu:click', fn) 1495 * @method _parseType 1496 * @private 1497 */ 1498 _parseType = Y.cached(function(type, pre) { 1499 1500 var t = type, detachcategory, after, i; 1501 1502 if (!L.isString(t)) { 1503 return t; 1504 } 1505 1506 i = t.indexOf(AFTER_PREFIX); 1507 1508 if (i > -1) { 1509 after = true; 1510 t = t.substr(AFTER_PREFIX.length); 1511 } 1512 1513 i = t.indexOf(CATEGORY_DELIMITER); 1514 1515 if (i > -1) { 1516 detachcategory = t.substr(0, (i)); 1517 t = t.substr(i+1); 1518 if (t === '*') { 1519 t = null; 1520 } 1521 } 1522 1523 // detach category, full type with instance prefix, is this an after listener, short type 1524 return [detachcategory, (pre) ? _getType(t, pre) : t, after, t]; 1525 }), 1526 1527 ET = function(opts) { 1528 1529 var etState = this._yuievt, 1530 etConfig; 1531 1532 if (!etState) { 1533 etState = this._yuievt = { 1534 events: {}, // PERF: Not much point instantiating lazily. We're bound to have events 1535 targets: null, // PERF: Instantiate lazily, if user actually adds target, 1536 config: { 1537 host: this, 1538 context: this 1539 }, 1540 chain: Y.config.chain 1541 }; 1542 } 1543 1544 etConfig = etState.config; 1545 1546 if (opts) { 1547 mixConfigs(etConfig, opts, true); 1548 1549 if (opts.chain !== undefined) { 1550 etState.chain = opts.chain; 1551 } 1552 1553 if (opts.prefix) { 1554 etConfig.prefix = opts.prefix; 1555 } 1556 } 1557 }; 1558 1559ET.prototype = { 1560 1561 constructor: ET, 1562 1563 /** 1564 * Listen to a custom event hosted by this object one time. 1565 * This is the equivalent to <code>on</code> except the 1566 * listener is immediatelly detached when it is executed. 1567 * @method once 1568 * @param {String} type The name of the event 1569 * @param {Function} fn The callback to execute in response to the event 1570 * @param {Object} [context] Override `this` object in callback 1571 * @param {Any} [arg*] 0..n additional arguments to supply to the subscriber 1572 * @return {EventHandle} A subscription handle capable of detaching the 1573 * subscription 1574 */ 1575 once: function() { 1576 var handle = this.on.apply(this, arguments); 1577 handle.batch(function(hand) { 1578 if (hand.sub) { 1579 hand.sub.once = true; 1580 } 1581 }); 1582 return handle; 1583 }, 1584 1585 /** 1586 * Listen to a custom event hosted by this object one time. 1587 * This is the equivalent to <code>after</code> except the 1588 * listener is immediatelly detached when it is executed. 1589 * @method onceAfter 1590 * @param {String} type The name of the event 1591 * @param {Function} fn The callback to execute in response to the event 1592 * @param {Object} [context] Override `this` object in callback 1593 * @param {Any} [arg*] 0..n additional arguments to supply to the subscriber 1594 * @return {EventHandle} A subscription handle capable of detaching that 1595 * subscription 1596 */ 1597 onceAfter: function() { 1598 var handle = this.after.apply(this, arguments); 1599 handle.batch(function(hand) { 1600 if (hand.sub) { 1601 hand.sub.once = true; 1602 } 1603 }); 1604 return handle; 1605 }, 1606 1607 /** 1608 * Takes the type parameter passed to 'on' and parses out the 1609 * various pieces that could be included in the type. If the 1610 * event type is passed without a prefix, it will be expanded 1611 * to include the prefix one is supplied or the event target 1612 * is configured with a default prefix. 1613 * @method parseType 1614 * @param {String} type the type 1615 * @param {String} [pre] The prefix. Defaults to this._yuievt.config.prefix 1616 * @since 3.3.0 1617 * @return {Array} an array containing: 1618 * * the detach category, if supplied, 1619 * * the prefixed event type, 1620 * * whether or not this is an after listener, 1621 * * the supplied event type 1622 */ 1623 parseType: function(type, pre) { 1624 return _parseType(type, pre || this._yuievt.config.prefix); 1625 }, 1626 1627 /** 1628 * Subscribe a callback function to a custom event fired by this object or 1629 * from an object that bubbles its events to this object. 1630 * 1631 * this.on("change", this._onChange, this); 1632 * 1633 * Callback functions for events published with `emitFacade = true` will 1634 * receive an `EventFacade` as the first argument (typically named "e"). 1635 * These callbacks can then call `e.preventDefault()` to disable the 1636 * behavior published to that event's `defaultFn`. See the `EventFacade` 1637 * API for all available properties and methods. Subscribers to 1638 * non-`emitFacade` events will receive the arguments passed to `fire()` 1639 * after the event name. 1640 * 1641 * To subscribe to multiple events at once, pass an object as the first 1642 * argument, where the key:value pairs correspond to the eventName:callback. 1643 * 1644 * this.on({ 1645 * "attrChange" : this._onAttrChange, 1646 * "change" : this._onChange 1647 * }); 1648 * 1649 * You can also pass an array of event names as the first argument to 1650 * subscribe to all listed events with the same callback. 1651 * 1652 * this.on([ "change", "attrChange" ], this._onChange); 1653 * 1654 * Returning `false` from a callback is supported as an alternative to 1655 * calling `e.preventDefault(); e.stopPropagation();`. However, it is 1656 * recommended to use the event methods whenever possible. 1657 * 1658 * @method on 1659 * @param {String} type The name of the event 1660 * @param {Function} fn The callback to execute in response to the event 1661 * @param {Object} [context] Override `this` object in callback 1662 * @param {Any} [arg*] 0..n additional arguments to supply to the subscriber 1663 * @return {EventHandle} A subscription handle capable of detaching that 1664 * subscription 1665 */ 1666 on: function(type, fn, context) { 1667 1668 var yuievt = this._yuievt, 1669 parts = _parseType(type, yuievt.config.prefix), f, c, args, ret, ce, 1670 detachcategory, handle, store = Y.Env.evt.handles, after, adapt, shorttype, 1671 Node = Y.Node, n, domevent, isArr; 1672 1673 // full name, args, detachcategory, after 1674 this._monitor('attach', parts[1], { 1675 args: arguments, 1676 category: parts[0], 1677 after: parts[2] 1678 }); 1679 1680 if (L.isObject(type)) { 1681 1682 if (L.isFunction(type)) { 1683 return Y.Do.before.apply(Y.Do, arguments); 1684 } 1685 1686 f = fn; 1687 c = context; 1688 args = nativeSlice.call(arguments, 0); 1689 ret = []; 1690 1691 if (L.isArray(type)) { 1692 isArr = true; 1693 } 1694 1695 after = type._after; 1696 delete type._after; 1697 1698 Y.each(type, function(v, k) { 1699 1700 if (L.isObject(v)) { 1701 f = v.fn || ((L.isFunction(v)) ? v : f); 1702 c = v.context || c; 1703 } 1704 1705 var nv = (after) ? AFTER_PREFIX : ''; 1706 1707 args[0] = nv + ((isArr) ? v : k); 1708 args[1] = f; 1709 args[2] = c; 1710
1711 ret.push(this.on.apply(this, args)); 1712 1713 }, this); 1714 1715 return (yuievt.chain) ? this : new Y.EventHandle(ret); 1716 } 1717 1718 detachcategory = parts[0]; 1719 after = parts[2]; 1720 shorttype = parts[3]; 1721 1722 // extra redirection so we catch adaptor events too. take a look at this. 1723 if (Node && Y.instanceOf(this, Node) && (shorttype in Node.DOM_EVENTS)) { 1724 args = nativeSlice.call(arguments, 0); 1725 args.splice(2, 0, Node.getDOMNode(this)); 1726 return Y.on.apply(Y, args); 1727 } 1728 1729 type = parts[1]; 1730 1731 if (Y.instanceOf(this, YUI)) { 1732 1733 adapt = Y.Env.evt.plugins[type]; 1734 args = nativeSlice.call(arguments, 0); 1735 args[0] = shorttype; 1736 1737 if (Node) { 1738 n = args[2]; 1739 1740 if (Y.instanceOf(n, Y.NodeList)) { 1741 n = Y.NodeList.getDOMNodes(n); 1742 } else if (Y.instanceOf(n, Node)) { 1743 n = Node.getDOMNode(n); 1744 } 1745 1746 domevent = (shorttype in Node.DOM_EVENTS); 1747 1748 // Captures both DOM events and event plugins. 1749 if (domevent) { 1750 args[2] = n; 1751 } 1752 } 1753 1754 // check for the existance of an event adaptor 1755 if (adapt) { 1756 handle = adapt.on.apply(Y, args); 1757 } else if ((!type) || domevent) { 1758 handle = Y.Event._attach(args); 1759 } 1760 1761 } 1762 1763 if (!handle) { 1764 ce = yuievt.events[type] || this.publish(type); 1765 handle = ce._on(fn, context, (arguments.length > 3) ? nativeSlice.call(arguments, 3) : null, (after) ? 'after' : true); 1766 1767 // TODO: More robust regex, accounting for category 1768 if (type.indexOf("*:") !== -1) { 1769 this._hasSiblings = true; 1770 } 1771 } 1772 1773 if (detachcategory) { 1774 store[detachcategory] = store[detachcategory] || {}; 1775 store[detachcategory][type] = store[detachcategory][type] || []; 1776 store[detachcategory][type].push(handle); 1777 } 1778 1779 return (yuievt.chain) ? this : handle; 1780 1781 }, 1782 1783 /** 1784 * subscribe to an event 1785 * @method subscribe 1786 * @deprecated use on 1787 */ 1788 subscribe: function() { 1789 return this.on.apply(this, arguments); 1790 }, 1791 1792 /** 1793 * Detach one or more listeners the from the specified event 1794 * @method detach 1795 * @param type {string|Object} Either the handle to the subscriber or the 1796 * type of event. If the type 1797 * is not specified, it will attempt to remove 1798 * the listener from all hosted events. 1799 * @param fn {Function} The subscribed function to unsubscribe, if not 1800 * supplied, all subscribers will be removed. 1801 * @param context {Object} The custom object passed to subscribe. This is 1802 * optional, but if supplied will be used to 1803 * disambiguate multiple listeners that are the same 1804 * (e.g., you subscribe many object using a function 1805 * that lives on the prototype) 1806 * @return {EventTarget} the host 1807 */ 1808 detach: function(type, fn, context) { 1809 1810 var evts = this._yuievt.events, 1811 i, 1812 Node = Y.Node, 1813 isNode = Node && (Y.instanceOf(this, Node)); 1814 1815 // detachAll disabled on the Y instance. 1816 if (!type && (this !== Y)) { 1817 for (i in evts) { 1818 if (evts.hasOwnProperty(i)) { 1819 evts[i].detach(fn, context); 1820 } 1821 } 1822 if (isNode) { 1823 Y.Event.purgeElement(Node.getDOMNode(this)); 1824 } 1825 1826 return this; 1827 } 1828 1829 var parts = _parseType(type, this._yuievt.config.prefix), 1830 detachcategory = L.isArray(parts) ? parts[0] : null, 1831 shorttype = (parts) ? parts[3] : null, 1832 adapt, store = Y.Env.evt.handles, detachhost, cat, args, 1833 ce, 1834 1835 keyDetacher = function(lcat, ltype, host) { 1836 var handles = lcat[ltype], ce, i; 1837 if (handles) { 1838 for (i = handles.length - 1; i >= 0; --i) { 1839 ce = handles[i].evt; 1840 if (ce.host === host || ce.el === host) { 1841 handles[i].detach(); 1842 } 1843 } 1844 } 1845 }; 1846 1847 if (detachcategory) { 1848 1849 cat = store[detachcategory]; 1850 type = parts[1]; 1851 detachhost = (isNode) ? Y.Node.getDOMNode(this) : this; 1852 1853 if (cat) { 1854 if (type) { 1855 keyDetacher(cat, type, detachhost); 1856 } else { 1857 for (i in cat) { 1858 if (cat.hasOwnProperty(i)) { 1859 keyDetacher(cat, i, detachhost); 1860 } 1861 } 1862 } 1863 1864 return this; 1865 } 1866 1867 // If this is an event handle, use it to detach 1868 } else if (L.isObject(type) && type.detach) { 1869 type.detach(); 1870 return this; 1871 // extra redirection so we catch adaptor events too. take a look at this. 1872 } else if (isNode && ((!shorttype) || (shorttype in Node.DOM_EVENTS))) { 1873 args = nativeSlice.call(arguments, 0); 1874 args[2] = Node.getDOMNode(this); 1875 Y.detach.apply(Y, args); 1876 return this; 1877 } 1878 1879 adapt = Y.Env.evt.plugins[shorttype]; 1880 1881 // The YUI instance handles DOM events and adaptors 1882 if (Y.instanceOf(this, YUI)) { 1883 args = nativeSlice.call(arguments, 0); 1884 // use the adaptor specific detach code if 1885 if (adapt && adapt.detach) { 1886 adapt.detach.apply(Y, args); 1887 return this; 1888 // DOM event fork 1889 } else if (!type || (!adapt && Node && (type in Node.DOM_EVENTS))) { 1890 args[0] = type; 1891 Y.Event.detach.apply(Y.Event, args); 1892 return this; 1893 } 1894 } 1895 1896 // ce = evts[type]; 1897 ce = evts[parts[1]]; 1898 if (ce) { 1899 ce.detach(fn, context); 1900 } 1901 1902 return this; 1903 }, 1904 1905 /** 1906 * detach a listener 1907 * @method unsubscribe 1908 * @deprecated use detach 1909 */ 1910 unsubscribe: function() { 1911 return this.detach.apply(this, arguments); 1912 }, 1913 1914 /** 1915 * Removes all listeners from the specified event. If the event type 1916 * is not specified, all listeners from all hosted custom events will 1917 * be removed. 1918 * @method detachAll 1919 * @param type {String} The type, or name of the event 1920 */ 1921 detachAll: function(type) { 1922 return this.detach(type); 1923 }, 1924 1925 /** 1926 * Removes all listeners from the specified event. If the event type 1927 * is not specified, all listeners from all hosted custom events will 1928 * be removed. 1929 * @method unsubscribeAll 1930 * @param type {String} The type, or name of the event 1931 * @deprecated use detachAll 1932 */ 1933 unsubscribeAll: function() { 1934 return this.detachAll.apply(this, arguments); 1935 }, 1936 1937 /** 1938 * Creates a new custom event of the specified type. If a custom event 1939 * by that name already exists, it will not be re-created. In either 1940 * case the custom event is returned. 1941 * 1942 * @method publish 1943 * 1944 * @param type {String} the type, or name of the event 1945 * @param opts {object} optional config params. Valid properties are: 1946 * @param [opts.broadcast=false] {Boolean} whether or not the YUI instance and YUI global 1947 * are notified when the event is fired. 1948 * @param [opts.bubbles=true] {Boolean} Whether or not this event bubbles. Events can 1949 * only bubble if `emitFacade` is true.
1950 * @param [opts.context=this] {Object} the default execution context for the listeners. 1951 * @param [opts.defaultFn] {Function} the default function to execute when this event 1952 * fires if preventDefault was not called. 1953 * @param [opts.emitFacade=false] {Boolean} whether or not this event emits a facade. 1954 * @param [opts.prefix] {String} the prefix for this targets events, e.g., 'menu' in 'menu:click'. 1955 * @param [opts.fireOnce=false] {Boolean} if an event is configured to fire once, 1956 * new subscribers after the fire will be notified immediately. 1957 * @param [opts.async=false] {Boolean} fireOnce event listeners will fire synchronously 1958 * if the event has already fired unless `async` is `true`. 1959 * @param [opts.preventable=true] {Boolean} whether or not `preventDefault()` has an effect. 1960 * @param [opts.preventedFn] {Function} a function that is executed when `preventDefault()` is called. 1961 * @param [opts.queuable=false] {Boolean} whether or not this event can be queued during bubbling. 1962 * @param [opts.silent] {Boolean} if silent is true, debug messages are not provided for this event. 1963 * @param [opts.stoppedFn] {Function} a function that is executed when stopPropagation is called. 1964 * @param [opts.monitored] {Boolean} specifies whether or not this event should send notifications about 1965 * when the event has been attached, detached, or published. 1966 * @param [opts.type] {String} the event type (valid option if not provided as the first parameter to publish). 1967 * 1968 * @return {CustomEvent} the custom event 1969 * 1970 */ 1971 publish: function(type, opts) { 1972 1973 var ret, 1974 etState = this._yuievt, 1975 etConfig = etState.config, 1976 pre = etConfig.prefix; 1977 1978 if (typeof type === "string") { 1979 if (pre) { 1980 type = _getType(type, pre); 1981 } 1982 ret = this._publish(type, etConfig, opts); 1983 } else { 1984 ret = {}; 1985 1986 Y.each(type, function(v, k) { 1987 if (pre) { 1988 k = _getType(k, pre); 1989 } 1990 ret[k] = this._publish(k, etConfig, v || opts); 1991 }, this); 1992 1993 } 1994 1995 return ret; 1996 }, 1997 1998 /** 1999 * Returns the fully qualified type, given a short type string. 2000 * That is, returns "foo:bar" when given "bar" if "foo" is the configured prefix. 2001 * 2002 * NOTE: This method, unlike _getType, does no checking of the value passed in, and 2003 * is designed to be used with the low level _publish() method, for critical path 2004 * implementations which need to fast-track publish for performance reasons. 2005 * 2006 * @method _getFullType 2007 * @private 2008 * @param {String} type The short type to prefix 2009 * @return {String} The prefixed type, if a prefix is set, otherwise the type passed in 2010 */ 2011 _getFullType : function(type) { 2012 2013 var pre = this._yuievt.config.prefix; 2014 2015 if (pre) { 2016 return pre + PREFIX_DELIMITER + type; 2017 } else { 2018 return type; 2019 } 2020 }, 2021 2022 /** 2023 * The low level event publish implementation. It expects all the massaging to have been done 2024 * outside of this method. e.g. the `type` to `fullType` conversion. It's designed to be a fast 2025 * path publish, which can be used by critical code paths to improve performance. 2026 * 2027 * @method _publish 2028 * @private 2029 * @param {String} fullType The prefixed type of the event to publish. 2030 * @param {Object} etOpts The EventTarget specific configuration to mix into the published event. 2031 * @param {Object} ceOpts The publish specific configuration to mix into the published event. 2032 * @return {CustomEvent} The published event. If called without `etOpts` or `ceOpts`, this will 2033 * be the default `CustomEvent` instance, and can be configured independently. 2034 */ 2035 _publish : function(fullType, etOpts, ceOpts) { 2036 2037 var ce, 2038 etState = this._yuievt, 2039 etConfig = etState.config, 2040 host = etConfig.host, 2041 context = etConfig.context, 2042 events = etState.events; 2043 2044 ce = events[fullType]; 2045 2046 // PERF: Hate to pull the check out of monitor, but trying to keep critical path tight. 2047 if ((etConfig.monitored && !ce) || (ce && ce.monitored)) { 2048 this._monitor('publish', fullType, { 2049 args: arguments 2050 }); 2051 } 2052 2053 if (!ce) { 2054 // Publish event 2055 ce = events[fullType] = new Y.CustomEvent(fullType, etOpts); 2056 2057 if (!etOpts) { 2058 ce.host = host; 2059 ce.context = context; 2060 } 2061 } 2062 2063 if (ceOpts) { 2064 mixConfigs(ce, ceOpts, true); 2065 } 2066 2067 return ce; 2068 }, 2069 2070 /** 2071 * This is the entry point for the event monitoring system. 2072 * You can monitor 'attach', 'detach', 'fire', and 'publish'. 2073 * When configured, these events generate an event. click -> 2074 * click_attach, click_detach, click_publish -- these can 2075 * be subscribed to like other events to monitor the event 2076 * system. Inividual published events can have monitoring 2077 * turned on or off (publish can't be turned off before it 2078 * it published) by setting the events 'monitor' config. 2079 * 2080 * @method _monitor 2081 * @param what {String} 'attach', 'detach', 'fire', or 'publish' 2082 * @param eventType {String|CustomEvent} The prefixed name of the event being monitored, or the CustomEvent object. 2083 * @param o {Object} Information about the event interaction, such as 2084 * fire() args, subscription category, publish config 2085 * @private 2086 */ 2087 _monitor: function(what, eventType, o) {
2088 var monitorevt, ce, type; 2089 2090 if (eventType) { 2091 if (typeof eventType === "string") { 2092 type = eventType; 2093 ce = this.getEvent(eventType, true); 2094 } else { 2095 ce = eventType; 2096 type = eventType.type; 2097 } 2098 2099 if ((this._yuievt.config.monitored && (!ce || ce.monitored)) || (ce && ce.monitored)) { 2100 monitorevt = type + '_' + what; 2101 o.monitored = what; 2102 this.fire.call(this, monitorevt, o); 2103 } 2104 } 2105 }, 2106 2107 /** 2108 * Fire a custom event by name. The callback functions will be executed 2109 * from the context specified when the event was created, and with the 2110 * following parameters. 2111 * 2112 * The first argument is the event type, and any additional arguments are 2113 * passed to the listeners as parameters. If the first of these is an 2114 * object literal, and the event is configured to emit an event facade, 2115 * that object is mixed into the event facade and the facade is provided 2116 * in place of the original object. 2117 * 2118 * If the custom event object hasn't been created, then the event hasn't 2119 * been published and it has no subscribers. For performance sake, we 2120 * immediate exit in this case. This means the event won't bubble, so 2121 * if the intention is that a bubble target be notified, the event must 2122 * be published on this object first. 2123 * 2124 * @method fire 2125 * @param type {String|Object} The type of the event, or an object that contains 2126 * a 'type' property. 2127 * @param arguments {Object*} an arbitrary set of parameters to pass to 2128 * the handler. If the first of these is an object literal and the event is 2129 * configured to emit an event facade, the event facade will replace that 2130 * parameter after the properties the object literal contains are copied to 2131 * the event facade. 2132 * @return {Boolean} True if the whole lifecycle of the event went through, 2133 * false if at any point the event propagation was halted. 2134 */ 2135 fire: function(type) { 2136 2137 var typeIncluded = (typeof type === "string"), 2138 argCount = arguments.length, 2139 t = type, 2140 yuievt = this._yuievt, 2141 etConfig = yuievt.config, 2142 pre = etConfig.prefix, 2143 ret, 2144 ce, 2145 ce2, 2146 args; 2147 2148 if (typeIncluded && argCount <= 3) { 2149 2150 // PERF: Try to avoid slice/iteration for the common signatures 2151 2152 // Most common 2153 if (argCount === 2) { 2154 args = [arguments[1]]; // fire("foo", {}) 2155 } else if (argCount === 3) { 2156 args = [arguments[1], arguments[2]]; // fire("foo", {}, opts) 2157 } else { 2158 args = []; // fire("foo") 2159 } 2160 2161 } else { 2162 args = nativeSlice.call(arguments, ((typeIncluded) ? 1 : 0)); 2163 } 2164 2165 if (!typeIncluded) { 2166 t = (type && type.type); 2167 } 2168 2169 if (pre) { 2170 t = _getType(t, pre); 2171 } 2172 2173 ce = yuievt.events[t]; 2174 2175 if (this._hasSiblings) { 2176 ce2 = this.getSibling(t, ce); 2177 2178 if (ce2 && !ce) { 2179 ce = this.publish(t); 2180 } 2181 } 2182 2183 // PERF: trying to avoid function call, since this is a critical path 2184 if ((etConfig.monitored && (!ce || ce.monitored)) || (ce && ce.monitored)) { 2185 this._monitor('fire', (ce || t), { 2186 args: args 2187 }); 2188 } 2189 2190 // this event has not been published or subscribed to 2191 if (!ce) { 2192 if (yuievt.hasTargets) { 2193 return this.bubble({ type: t }, args, this); 2194 } 2195 2196 // otherwise there is nothing to be done 2197 ret = true; 2198 } else { 2199 2200 if (ce2) { 2201 ce.sibling = ce2; 2202 } 2203 2204 ret = ce._fire(args); 2205 } 2206 2207 return (yuievt.chain) ? this : ret; 2208 }, 2209 2210 getSibling: function(type, ce) { 2211 var ce2; 2212 2213 // delegate to *:type events if there are subscribers 2214 if (type.indexOf(PREFIX_DELIMITER) > -1) { 2215 type = _wildType(type); 2216 ce2 = this.getEvent(type, true); 2217 if (ce2) { 2218 ce2.applyConfig(ce); 2219 ce2.bubbles = false;
2220 ce2.broadcast = 0; 2221 } 2222 } 2223 2224 return ce2; 2225 }, 2226 2227 /** 2228 * Returns the custom event of the provided type has been created, a 2229 * falsy value otherwise 2230 * @method getEvent 2231 * @param type {String} the type, or name of the event 2232 * @param prefixed {String} if true, the type is prefixed already 2233 * @return {CustomEvent} the custom event or null 2234 */ 2235 getEvent: function(type, prefixed) { 2236 var pre, e; 2237 2238 if (!prefixed) { 2239 pre = this._yuievt.config.prefix; 2240 type = (pre) ? _getType(type, pre) : type; 2241 } 2242 e = this._yuievt.events; 2243 return e[type] || null; 2244 }, 2245 2246 /** 2247 * Subscribe to a custom event hosted by this object. The 2248 * supplied callback will execute after any listeners add 2249 * via the subscribe method, and after the default function, 2250 * if configured for the event, has executed. 2251 * 2252 * @method after 2253 * @param {String} type The name of the event 2254 * @param {Function} fn The callback to execute in response to the event 2255 * @param {Object} [context] Override `this` object in callback 2256 * @param {Any} [arg*] 0..n additional arguments to supply to the subscriber 2257 * @return {EventHandle} A subscription handle capable of detaching the 2258 * subscription 2259 */ 2260 after: function(type, fn) { 2261 2262 var a = nativeSlice.call(arguments, 0); 2263 2264 switch (L.type(type)) { 2265 case 'function': 2266 return Y.Do.after.apply(Y.Do, arguments); 2267 case 'array': 2268 // YArray.each(a[0], function(v) { 2269 // v = AFTER_PREFIX + v; 2270 // }); 2271 // break; 2272 case 'object': 2273 a[0]._after = true; 2274 break; 2275 default: 2276 a[0] = AFTER_PREFIX + type; 2277 } 2278 2279 return this.on.apply(this, a); 2280 2281 }, 2282 2283 /** 2284 * Executes the callback before a DOM event, custom event 2285 * or method. If the first argument is a function, it 2286 * is assumed the target is a method. For DOM and custom 2287 * events, this is an alias for Y.on. 2288 * 2289 * For DOM and custom events: 2290 * type, callback, context, 0-n arguments 2291 * 2292 * For methods: 2293 * callback, object (method host), methodName, context, 0-n arguments 2294 * 2295 * @method before 2296 * @return detach handle 2297 */ 2298 before: function() { 2299 return this.on.apply(this, arguments); 2300 } 2301 2302}; 2303 2304Y.EventTarget = ET; 2305 2306// make Y an event target 2307Y.mix(Y, ET.prototype); 2308ET.call(Y, { bubbles: false }); 2309 2310YUI.Env.globalEvents = YUI.Env.globalEvents || new ET(); 2311 2312/** 2313 * Hosts YUI page level events. This is where events bubble to 2314 * when the broadcast config is set to 2. This property is 2315 * only available if the custom event module is loaded. 2316 * @property Global 2317 * @type EventTarget 2318 * @for YUI 2319 */ 2320Y.Global = YUI.Env.globalEvents; 2321 2322// @TODO implement a global namespace function on Y.Global? 2323 2324/** 2325`Y.on()` can do many things: 2326 2327<ul> 2328 <li>Subscribe to custom events `publish`ed and `fire`d from Y</li> 2329 <li>Subscribe to custom events `publish`ed with `broadcast` 1 or 2 and 2330 `fire`d from any object in the YUI instance sandbox</li> 2331 <li>Subscribe to DOM events</li> 2332 <li>Subscribe to the execution of a method on any object, effectively 2333 treating that method as an event</li> 2334</ul> 2335 2336For custom event subscriptions, pass the custom event name as the first argument 2337and callback as the second. The `this` object in the callback will be `Y` unless 2338an override is passed as the third argument. 2339 2340 Y.on('io:complete', function () { 2341 Y.MyApp.updateStatus('Transaction complete'); 2342 }); 2343 2344To subscribe to DOM events, pass the name of a DOM event as the first argument 2345and a CSS selector string as the third argument after the callback function. 2346Alternately, the third argument can be a `Node`, `NodeList`, `HTMLElement`, 2347array, or simply omitted (the default is the `window` object). 2348 2349 Y.on('click', function (e) { 2350 e.preventDefault(); 2351 2352 // proceed with ajax form submission 2353 var url = this.get('action'); 2354 ... 2355 }, '#my-form'); 2356 2357The `this` object in DOM event callbacks will be the `Node` targeted by the CSS 2358selector or other identifier. 2359 2360`on()` subscribers for DOM events or custom events `publish`ed with a 2361`defaultFn` can prevent the default behavior with `e.preventDefault()` from the 2362event object passed as the first parameter to the subscription callback. 2363 2364To subscribe to the execution of an object method, pass arguments corresponding to the call signature for 2365<a href="../classes/Do.html#methods_before">`Y.Do.before(...)`</a>. 2366 2367NOTE: The formal parameter list below is for events, not for function 2368injection. See `Y.Do.before` for that signature. 2369 2370@method on 2371@param {String} type DOM or custom event name 2372@param {Function} fn The callback to execute in response to the event 2373@param {Object} [context] Override `this` object in callback 2374@param {Any} [arg*] 0..n additional arguments to supply to the subscriber 2375@return {EventHandle} A subscription handle capable of detaching the 2376 subscription 2377@see Do.before 2378@for YUI
2379**/ 2380 2381/** 2382Listen for an event one time. Equivalent to `on()`, except that 2383the listener is immediately detached when executed. 2384 2385See the <a href="#methods_on">`on()` method</a> for additional subscription 2386options. 2387 2388@see on 2389@method once 2390@param {String} type DOM or custom event name 2391@param {Function} fn The callback to execute in response to the event 2392@param {Object} [context] Override `this` object in callback 2393@param {Any} [arg*] 0..n additional arguments to supply to the subscriber 2394@return {EventHandle} A subscription handle capable of detaching the 2395 subscription 2396@for YUI 2397**/ 2398 2399/** 2400Listen for an event one time. Equivalent to `once()`, except, like `after()`, 2401the subscription callback executes after all `on()` subscribers and the event's 2402`defaultFn` (if configured) have executed. Like `after()` if any `on()` phase 2403subscriber calls `e.preventDefault()`, neither the `defaultFn` nor the `after()` 2404subscribers will execute. 2405 2406The listener is immediately detached when executed. 2407 2408See the <a href="#methods_on">`on()` method</a> for additional subscription 2409options. 2410 2411@see once 2412@method onceAfter 2413@param {String} type The custom event name 2414@param {Function} fn The callback to execute in response to the event 2415@param {Object} [context] Override `this` object in callback 2416@param {Any} [arg*] 0..n additional arguments to supply to the subscriber 2417@return {EventHandle} A subscription handle capable of detaching the 2418 subscription 2419@for YUI 2420**/ 2421 2422/** 2423Like `on()`, this method creates a subscription to a custom event or to the 2424execution of a method on an object. 2425 2426For events, `after()` subscribers are executed after the event's 2427`defaultFn` unless `e.preventDefault()` was called from an `on()` subscriber. 2428 2429See the <a href="#methods_on">`on()` method</a> for additional subscription 2430options. 2431 2432NOTE: The subscription signature shown is for events, not for function 2433injection. See <a href="../classes/Do.html#methods_after">`Y.Do.after`</a> 2434for that signature. 2435 2436@see on 2437@see Do.after 2438@method after 2439@param {String} type The custom event name 2440@param {Function} fn The callback to execute in response to the event 2441@param {Object} [context] Override `this` object in callback 2442@param {Any} [args*] 0..n additional arguments to supply to the subscriber 2443@return {EventHandle} A subscription handle capable of detaching the 2444 subscription 2445@for YUI 2446**/ 2447 2448 2449}, 'patched-v3.18.7', {"requires": ["oop"]});
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.