[ Index ] |
PHP Cross Reference of Unnamed Project |
[Summary view] [Print] [Text view]
1 /* 2 YUI 3.17.2 (build 9c3c78e) 3 Copyright 2014 Yahoo! Inc. All rights reserved. 4 Licensed under the BSD License. 5 http://yuilibrary.com/license/ 6 */ 7 8 YUI.add('event-custom-complex', function (Y, NAME) { 9 10 11 /** 12 * Adds event facades, preventable default behavior, and bubbling. 13 * events. 14 * @module event-custom 15 * @submodule event-custom-complex 16 */ 17 18 var FACADE, 19 FACADE_KEYS, 20 YObject = Y.Object, 21 key, 22 EMPTY = {}, 23 CEProto = Y.CustomEvent.prototype, 24 ETProto = Y.EventTarget.prototype, 25 26 mixFacadeProps = function(facade, payload) { 27 var p; 28 29 for (p in payload) { 30 if (!(FACADE_KEYS.hasOwnProperty(p))) { 31 facade[p] = payload[p]; 32 } 33 } 34 }; 35 36 /** 37 * Wraps and protects a custom event for use when emitFacade is set to true. 38 * Requires the event-custom-complex module 39 * @class EventFacade 40 * @param e {Event} the custom event 41 * @param currentTarget {HTMLElement} the element the listener was attached to 42 */ 43 44 Y.EventFacade = function(e, currentTarget) { 45 46 if (!e) { 47 e = EMPTY; 48 } 49 50 this._event = e; 51 52 /** 53 * The arguments passed to fire 54 * @property details 55 * @type Array 56 */ 57 this.details = e.details; 58 59 /** 60 * The event type, this can be overridden by the fire() payload 61 * @property type 62 * @type string 63 */ 64 this.type = e.type; 65 66 /** 67 * The real event type 68 * @property _type 69 * @type string 70 * @private 71 */ 72 this._type = e.type; 73 74 ////////////////////////////////////////////////////// 75 76 /** 77 * Node reference for the targeted eventtarget 78 * @property target 79 * @type Node 80 */ 81 this.target = e.target; 82 83 /** 84 * Node reference for the element that the listener was attached to. 85 * @property currentTarget 86 * @type Node 87 */ 88 this.currentTarget = currentTarget; 89 90 /** 91 * Node reference to the relatedTarget 92 * @property relatedTarget 93 * @type Node 94 */ 95 this.relatedTarget = e.relatedTarget; 96 97 }; 98 99 Y.mix(Y.EventFacade.prototype, { 100 101 /** 102 * Stops the propagation to the next bubble target 103 * @method stopPropagation 104 */ 105 stopPropagation: function() { 106 this._event.stopPropagation(); 107 this.stopped = 1; 108 }, 109 110 /** 111 * Stops the propagation to the next bubble target and 112 * prevents any additional listeners from being exectued 113 * on the current target. 114 * @method stopImmediatePropagation 115 */ 116 stopImmediatePropagation: function() { 117 this._event.stopImmediatePropagation(); 118 this.stopped = 2; 119 }, 120 121 /** 122 * Prevents the event's default behavior 123 * @method preventDefault 124 */ 125 preventDefault: function() { 126 this._event.preventDefault(); 127 this.prevented = 1; 128 }, 129 130 /** 131 * Stops the event propagation and prevents the default 132 * event behavior. 133 * @method halt 134 * @param immediate {boolean} if true additional listeners 135 * on the current target will not be executed 136 */ 137 halt: function(immediate) { 138 this._event.halt(immediate); 139 this.prevented = 1; 140 this.stopped = (immediate) ? 2 : 1; 141 } 142 143 }); 144 145 CEProto.fireComplex = function(args) { 146 147 var es, 148 ef, 149 q, 150 queue, 151 ce, 152 ret = true, 153 events, 154 subs, 155 ons, 156 afters, 157 afterQueue, 158 postponed, 159 prevented, 160 preventedFn, 161 defaultFn, 162 self = this, 163 host = self.host || self, 164 next, 165 oldbubble, 166 stack = self.stack, 167 yuievt = host._yuievt, 168 hasPotentialSubscribers; 169 170 if (stack) { 171 172 // queue this event if the current item in the queue bubbles 173 if (self.queuable && self.type !== stack.next.type) { 174 self.log('queue ' + self.type); 175 176 if (!stack.queue) { 177 stack.queue = []; 178 } 179 stack.queue.push([self, args]); 180 181 return true; 182 } 183 } 184 185 hasPotentialSubscribers = self.hasSubs() || yuievt.hasTargets || self.broadcast; 186 187 self.target = self.target || host; 188 self.currentTarget = host; 189 190 self.details = args.concat(); 191 192 if (hasPotentialSubscribers) { 193 194 es = stack || { 195 196 id: self.id, // id of the first event in the stack 197 next: self, 198 silent: self.silent, 199 stopped: 0, 200 prevented: 0, 201 bubbling: null, 202 type: self.type, 203 // defaultFnQueue: new Y.Queue(), 204 defaultTargetOnly: self.defaultTargetOnly 205 206 }; 207 208 subs = self.getSubs(); 209 ons = subs[0]; 210 afters = subs[1]; 211 212 self.stopped = (self.type !== es.type) ? 0 : es.stopped; 213 self.prevented = (self.type !== es.type) ? 0 : es.prevented; 214 215 if (self.stoppedFn) { 216 // PERF TODO: Can we replace with callback, like preventedFn. Look into history 217 events = new Y.EventTarget({ 218 fireOnce: true, 219 context: host 220 }); 221 self.events = events; 222 events.on('stopped', self.stoppedFn); 223 } 224 225 // self.log("Firing " + self + ", " + "args: " + args); 226 self.log("Firing " + self.type); 227 228 self._facade = null; // kill facade to eliminate stale properties 229 230 ef = self._createFacade(args); 231 232 if (ons) { 233 self._procSubs(ons, args, ef); 234 } 235 236 // bubble if this is hosted in an event target and propagation has not been stopped 237 if (self.bubbles && host.bubble && !self.stopped) { 238 oldbubble = es.bubbling; 239 240 es.bubbling = self.type; 241 242 if (es.type !== self.type) { 243 es.stopped = 0; 244 es.prevented = 0; 245 } 246 247 ret = host.bubble(self, args, null, es); 248 249 self.stopped = Math.max(self.stopped, es.stopped); 250 self.prevented = Math.max(self.prevented, es.prevented); 251 252 es.bubbling = oldbubble; 253 } 254 255 prevented = self.prevented; 256 257 if (prevented) { 258 preventedFn = self.preventedFn; 259 if (preventedFn) { 260 preventedFn.apply(host, args); 261 } 262 } else { 263 defaultFn = self.defaultFn; 264 265 if (defaultFn && ((!self.defaultTargetOnly && !es.defaultTargetOnly) || host === ef.target)) { 266 defaultFn.apply(host, args); 267 } 268 } 269 270 // broadcast listeners are fired as discreet events on the 271 // YUI instance and potentially the YUI global. 272 if (self.broadcast) { 273 self._broadcast(args); 274 } 275 276 if (afters && !self.prevented && self.stopped < 2) { 277 278 // Queue the after 279 afterQueue = es.afterQueue; 280 281 if (es.id === self.id || self.type !== yuievt.bubbling) { 282 283 self._procSubs(afters, args, ef); 284 285 if (afterQueue) { 286 while ((next = afterQueue.last())) { 287 next(); 288 } 289 } 290 } else { 291 postponed = afters; 292 293 if (es.execDefaultCnt) { 294 postponed = Y.merge(postponed); 295 296 Y.each(postponed, function(s) { 297 s.postponed = true; 298 }); 299 } 300 301 if (!afterQueue) { 302 es.afterQueue = new Y.Queue(); 303 } 304 305 es.afterQueue.add(function() { 306 self._procSubs(postponed, args, ef); 307 }); 308 } 309 310 } 311 312 self.target = null; 313 314 if (es.id === self.id) { 315 316 queue = es.queue; 317 318 if (queue) { 319 while (queue.length) { 320 q = queue.pop(); 321 ce = q[0]; 322 // set up stack to allow the next item to be processed 323 es.next = ce; 324 ce._fire(q[1]); 325 } 326 } 327 328 self.stack = null; 329 } 330 331 ret = !(self.stopped); 332 333 if (self.type !== yuievt.bubbling) { 334 es.stopped = 0; 335 es.prevented = 0; 336 self.stopped = 0; 337 self.prevented = 0; 338 } 339 340 } else { 341 defaultFn = self.defaultFn; 342 343 if(defaultFn) { 344 ef = self._createFacade(args); 345 346 if ((!self.defaultTargetOnly) || (host === ef.target)) { 347 defaultFn.apply(host, args); 348 } 349 } 350 } 351 352 // Kill the cached facade to free up memory. 353 // Otherwise we have the facade from the last fire, sitting around forever. 354 self._facade = null; 355 356 return ret; 357 }; 358 359 /** 360 * @method _hasPotentialSubscribers 361 * @for CustomEvent 362 * @private 363 * @return {boolean} Whether the event has potential subscribers or not 364 */ 365 CEProto._hasPotentialSubscribers = function() { 366 return this.hasSubs() || this.host._yuievt.hasTargets || this.broadcast; 367 }; 368 369 /** 370 * Internal utility method to create a new facade instance and 371 * insert it into the fire argument list, accounting for any payload 372 * merging which needs to happen. 373 * 374 * This used to be called `_getFacade`, but the name seemed inappropriate 375 * when it was used without a need for the return value. 376 * 377 * @method _createFacade 378 * @private 379 * @param fireArgs {Array} The arguments passed to "fire", which need to be 380 * shifted (and potentially merged) when the facade is added. 381 * @return {EventFacade} The event facade created. 382 */ 383 384 // TODO: Remove (private) _getFacade alias, once synthetic.js is updated. 385 CEProto._createFacade = CEProto._getFacade = function(fireArgs) { 386 387 var userArgs = this.details, 388 firstArg = userArgs && userArgs[0], 389 firstArgIsObj = (firstArg && (typeof firstArg === "object")), 390 ef = this._facade; 391 392 if (!ef) { 393 ef = new Y.EventFacade(this, this.currentTarget); 394 } 395 396 if (firstArgIsObj) { 397 // protect the event facade properties 398 mixFacadeProps(ef, firstArg); 399 400 // Allow the event type to be faked http://yuilibrary.com/projects/yui3/ticket/2528376 401 if (firstArg.type) { 402 ef.type = firstArg.type; 403 } 404 405 if (fireArgs) { 406 fireArgs[0] = ef; 407 } 408 } else { 409 if (fireArgs) { 410 fireArgs.unshift(ef); 411 } 412 } 413 414 // update the details field with the arguments 415 ef.details = this.details; 416 417 // use the original target when the event bubbled to this target 418 ef.target = this.originalTarget || this.target; 419 420 ef.currentTarget = this.currentTarget; 421 ef.stopped = 0; 422 ef.prevented = 0; 423 424 this._facade = ef; 425 426 return this._facade; 427 }; 428 429 /** 430 * Utility method to manipulate the args array passed in, to add the event facade, 431 * if it's not already the first arg. 432 * 433 * @method _addFacadeToArgs 434 * @private 435 * @param {Array} The arguments to manipulate 436 */ 437 CEProto._addFacadeToArgs = function(args) { 438 var e = args[0]; 439 440 // Trying not to use instanceof, just to avoid potential cross Y edge case issues. 441 if (!(e && e.halt && e.stopImmediatePropagation && e.stopPropagation && e._event)) { 442 this._createFacade(args); 443 } 444 }; 445 446 /** 447 * Stop propagation to bubble targets 448 * @for CustomEvent 449 * @method stopPropagation 450 */ 451 CEProto.stopPropagation = function() { 452 this.stopped = 1; 453 if (this.stack) { 454 this.stack.stopped = 1; 455 } 456 if (this.events) { 457 this.events.fire('stopped', this); 458 } 459 }; 460 461 /** 462 * Stops propagation to bubble targets, and prevents any remaining 463 * subscribers on the current target from executing. 464 * @method stopImmediatePropagation 465 */ 466 CEProto.stopImmediatePropagation = function() { 467 this.stopped = 2; 468 if (this.stack) { 469 this.stack.stopped = 2; 470 } 471 if (this.events) { 472 this.events.fire('stopped', this); 473 } 474 }; 475 476 /** 477 * Prevents the execution of this event's defaultFn 478 * @method preventDefault 479 */ 480 CEProto.preventDefault = function() { 481 if (this.preventable) { 482 this.prevented = 1; 483 if (this.stack) { 484 this.stack.prevented = 1; 485 } 486 } 487 }; 488 489 /** 490 * Stops the event propagation and prevents the default 491 * event behavior. 492 * @method halt 493 * @param immediate {boolean} if true additional listeners 494 * on the current target will not be executed 495 */ 496 CEProto.halt = function(immediate) { 497 if (immediate) { 498 this.stopImmediatePropagation(); 499 } else { 500 this.stopPropagation(); 501 } 502 this.preventDefault(); 503 }; 504 505 /** 506 * Registers another EventTarget as a bubble target. Bubble order 507 * is determined by the order registered. Multiple targets can 508 * be specified. 509 * 510 * Events can only bubble if emitFacade is true. 511 * 512 * Included in the event-custom-complex submodule. 513 * 514 * @method addTarget 515 * @chainable 516 * @param o {EventTarget} the target to add 517 * @for EventTarget 518 */ 519 ETProto.addTarget = function(o) { 520 var etState = this._yuievt; 521 522 if (!etState.targets) { 523 etState.targets = {}; 524 } 525 526 etState.targets[Y.stamp(o)] = o; 527 etState.hasTargets = true; 528 529 return this; 530 }; 531 532 /** 533 * Returns an array of bubble targets for this object. 534 * @method getTargets 535 * @return EventTarget[] 536 */ 537 ETProto.getTargets = function() { 538 var targets = this._yuievt.targets; 539 return targets ? YObject.values(targets) : []; 540 }; 541 542 /** 543 * Removes a bubble target 544 * @method removeTarget 545 * @chainable 546 * @param o {EventTarget} the target to remove 547 * @for EventTarget 548 */ 549 ETProto.removeTarget = function(o) { 550 var targets = this._yuievt.targets; 551 552 if (targets) { 553 delete targets[Y.stamp(o, true)]; 554 555 if (YObject.size(targets) === 0) { 556 this._yuievt.hasTargets = false; 557 } 558 } 559 560 return this; 561 }; 562 563 /** 564 * Propagate an event. Requires the event-custom-complex module. 565 * @method bubble 566 * @param evt {CustomEvent} the custom event to propagate 567 * @return {boolean} the aggregated return value from Event.Custom.fire 568 * @for EventTarget 569 */ 570 ETProto.bubble = function(evt, args, target, es) { 571 572 var targs = this._yuievt.targets, 573 ret = true, 574 t, 575 ce, 576 i, 577 bc, 578 ce2, 579 type = evt && evt.type, 580 originalTarget = target || (evt && evt.target) || this, 581 oldbubble; 582 583 if (!evt || ((!evt.stopped) && targs)) { 584 585 for (i in targs) { 586 if (targs.hasOwnProperty(i)) { 587 588 t = targs[i]; 589 590 ce = t._yuievt.events[type]; 591 592 if (t._hasSiblings) { 593 ce2 = t.getSibling(type, ce); 594 } 595 596 if (ce2 && !ce) { 597 ce = t.publish(type); 598 } 599 600 oldbubble = t._yuievt.bubbling; 601 t._yuievt.bubbling = type; 602 603 // if this event was not published on the bubble target, 604 // continue propagating the event. 605 if (!ce) { 606 if (t._yuievt.hasTargets) { 607 t.bubble(evt, args, originalTarget, es); 608 } 609 } else { 610 611 if (ce2) { 612 ce.sibling = ce2; 613 } 614 615 // set the original target to that the target payload on the facade is correct. 616 ce.target = originalTarget; 617 ce.originalTarget = originalTarget; 618 ce.currentTarget = t; 619 bc = ce.broadcast; 620 ce.broadcast = false; 621 622 // default publish may not have emitFacade true -- that 623 // shouldn't be what the implementer meant to do 624 ce.emitFacade = true; 625 626 ce.stack = es; 627 628 // TODO: See what's getting in the way of changing this to use 629 // the more performant ce._fire(args || evt.details || []). 630 631 // Something in Widget Parent/Child tests is not happy if we 632 // change it - maybe evt.details related? 633 ret = ret && ce.fire.apply(ce, args || evt.details || []); 634 635 ce.broadcast = bc; 636 ce.originalTarget = null; 637 638 // stopPropagation() was called 639 if (ce.stopped) { 640 break; 641 } 642 } 643 644 t._yuievt.bubbling = oldbubble; 645 } 646 } 647 } 648 649 return ret; 650 }; 651 652 /** 653 * @method _hasPotentialSubscribers 654 * @for EventTarget 655 * @private 656 * @param {String} fullType The fully prefixed type name 657 * @return {boolean} Whether the event has potential subscribers or not 658 */ 659 ETProto._hasPotentialSubscribers = function(fullType) { 660 661 var etState = this._yuievt, 662 e = etState.events[fullType]; 663 664 if (e) { 665 return e.hasSubs() || etState.hasTargets || e.broadcast; 666 } else { 667 return false; 668 } 669 }; 670 671 FACADE = new Y.EventFacade(); 672 FACADE_KEYS = {}; 673 674 // Flatten whitelist 675 for (key in FACADE) { 676 FACADE_KEYS[key] = true; 677 } 678 679 680 }, '3.17.2', {"requires": ["event-custom-base"]});
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Thu Aug 11 10:00:09 2016 | Cross-referenced by PHPXref 0.7.1 |