[ 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 175 if (!stack.queue) { 176 stack.queue = []; 177 } 178 stack.queue.push([self, args]); 179 180 return true; 181 } 182 } 183 184 hasPotentialSubscribers = self.hasSubs() || yuievt.hasTargets || self.broadcast; 185 186 self.target = self.target || host; 187 self.currentTarget = host; 188 189 self.details = args.concat(); 190 191 if (hasPotentialSubscribers) { 192 193 es = stack || { 194 195 id: self.id, // id of the first event in the stack 196 next: self, 197 silent: self.silent, 198 stopped: 0, 199 prevented: 0, 200 bubbling: null, 201 type: self.type, 202 // defaultFnQueue: new Y.Queue(), 203 defaultTargetOnly: self.defaultTargetOnly 204 205 }; 206 207 subs = self.getSubs(); 208 ons = subs[0]; 209 afters = subs[1]; 210 211 self.stopped = (self.type !== es.type) ? 0 : es.stopped; 212 self.prevented = (self.type !== es.type) ? 0 : es.prevented; 213 214 if (self.stoppedFn) { 215 // PERF TODO: Can we replace with callback, like preventedFn. Look into history 216 events = new Y.EventTarget({ 217 fireOnce: true, 218 context: host 219 }); 220 self.events = events; 221 events.on('stopped', self.stoppedFn); 222 } 223 224 225 self._facade = null; // kill facade to eliminate stale properties 226 227 ef = self._createFacade(args); 228 229 if (ons) { 230 self._procSubs(ons, args, ef); 231 } 232 233 // bubble if this is hosted in an event target and propagation has not been stopped 234 if (self.bubbles && host.bubble && !self.stopped) { 235 oldbubble = es.bubbling; 236 237 es.bubbling = self.type; 238 239 if (es.type !== self.type) { 240 es.stopped = 0; 241 es.prevented = 0; 242 } 243 244 ret = host.bubble(self, args, null, es); 245 246 self.stopped = Math.max(self.stopped, es.stopped); 247 self.prevented = Math.max(self.prevented, es.prevented); 248 249 es.bubbling = oldbubble; 250 } 251 252 prevented = self.prevented; 253 254 if (prevented) { 255 preventedFn = self.preventedFn; 256 if (preventedFn) { 257 preventedFn.apply(host, args); 258 } 259 } else { 260 defaultFn = self.defaultFn; 261 262 if (defaultFn && ((!self.defaultTargetOnly && !es.defaultTargetOnly) || host === ef.target)) { 263 defaultFn.apply(host, args); 264 } 265 } 266 267 // broadcast listeners are fired as discreet events on the 268 // YUI instance and potentially the YUI global. 269 if (self.broadcast) { 270 self._broadcast(args); 271 } 272 273 if (afters && !self.prevented && self.stopped < 2) { 274 275 // Queue the after 276 afterQueue = es.afterQueue; 277 278 if (es.id === self.id || self.type !== yuievt.bubbling) { 279 280 self._procSubs(afters, args, ef); 281 282 if (afterQueue) { 283 while ((next = afterQueue.last())) { 284 next(); 285 } 286 } 287 } else { 288 postponed = afters; 289 290 if (es.execDefaultCnt) { 291 postponed = Y.merge(postponed); 292 293 Y.each(postponed, function(s) { 294 s.postponed = true; 295 }); 296 } 297 298 if (!afterQueue) { 299 es.afterQueue = new Y.Queue(); 300 } 301 302 es.afterQueue.add(function() { 303 self._procSubs(postponed, args, ef); 304 }); 305 } 306 307 } 308 309 self.target = null; 310 311 if (es.id === self.id) { 312 313 queue = es.queue; 314 315 if (queue) { 316 while (queue.length) { 317 q = queue.pop(); 318 ce = q[0]; 319 // set up stack to allow the next item to be processed 320 es.next = ce; 321 ce._fire(q[1]); 322 } 323 } 324 325 self.stack = null; 326 } 327 328 ret = !(self.stopped); 329 330 if (self.type !== yuievt.bubbling) { 331 es.stopped = 0; 332 es.prevented = 0; 333 self.stopped = 0; 334 self.prevented = 0; 335 } 336 337 } else { 338 defaultFn = self.defaultFn; 339 340 if(defaultFn) { 341 ef = self._createFacade(args); 342 343 if ((!self.defaultTargetOnly) || (host === ef.target)) { 344 defaultFn.apply(host, args); 345 } 346 } 347 } 348 349 // Kill the cached facade to free up memory. 350 // Otherwise we have the facade from the last fire, sitting around forever. 351 self._facade = null; 352 353 return ret; 354 }; 355 356 /** 357 * @method _hasPotentialSubscribers 358 * @for CustomEvent 359 * @private 360 * @return {boolean} Whether the event has potential subscribers or not 361 */ 362 CEProto._hasPotentialSubscribers = function() { 363 return this.hasSubs() || this.host._yuievt.hasTargets || this.broadcast; 364 }; 365 366 /** 367 * Internal utility method to create a new facade instance and 368 * insert it into the fire argument list, accounting for any payload 369 * merging which needs to happen. 370 * 371 * This used to be called `_getFacade`, but the name seemed inappropriate 372 * when it was used without a need for the return value. 373 * 374 * @method _createFacade 375 * @private 376 * @param fireArgs {Array} The arguments passed to "fire", which need to be 377 * shifted (and potentially merged) when the facade is added. 378 * @return {EventFacade} The event facade created. 379 */ 380 381 // TODO: Remove (private) _getFacade alias, once synthetic.js is updated. 382 CEProto._createFacade = CEProto._getFacade = function(fireArgs) { 383 384 var userArgs = this.details, 385 firstArg = userArgs && userArgs[0], 386 firstArgIsObj = (firstArg && (typeof firstArg === "object")), 387 ef = this._facade; 388 389 if (!ef) { 390 ef = new Y.EventFacade(this, this.currentTarget); 391 } 392 393 if (firstArgIsObj) { 394 // protect the event facade properties 395 mixFacadeProps(ef, firstArg); 396 397 // Allow the event type to be faked http://yuilibrary.com/projects/yui3/ticket/2528376 398 if (firstArg.type) { 399 ef.type = firstArg.type; 400 } 401 402 if (fireArgs) { 403 fireArgs[0] = ef; 404 } 405 } else { 406 if (fireArgs) { 407 fireArgs.unshift(ef); 408 } 409 } 410 411 // update the details field with the arguments 412 ef.details = this.details; 413 414 // use the original target when the event bubbled to this target 415 ef.target = this.originalTarget || this.target; 416 417 ef.currentTarget = this.currentTarget; 418 ef.stopped = 0; 419 ef.prevented = 0; 420 421 this._facade = ef; 422 423 return this._facade; 424 }; 425 426 /** 427 * Utility method to manipulate the args array passed in, to add the event facade, 428 * if it's not already the first arg. 429 * 430 * @method _addFacadeToArgs 431 * @private 432 * @param {Array} The arguments to manipulate 433 */ 434 CEProto._addFacadeToArgs = function(args) { 435 var e = args[0]; 436 437 // Trying not to use instanceof, just to avoid potential cross Y edge case issues. 438 if (!(e && e.halt && e.stopImmediatePropagation && e.stopPropagation && e._event)) { 439 this._createFacade(args); 440 } 441 }; 442 443 /** 444 * Stop propagation to bubble targets 445 * @for CustomEvent 446 * @method stopPropagation 447 */ 448 CEProto.stopPropagation = function() { 449 this.stopped = 1; 450 if (this.stack) { 451 this.stack.stopped = 1; 452 } 453 if (this.events) { 454 this.events.fire('stopped', this); 455 } 456 }; 457 458 /** 459 * Stops propagation to bubble targets, and prevents any remaining 460 * subscribers on the current target from executing. 461 * @method stopImmediatePropagation 462 */ 463 CEProto.stopImmediatePropagation = function() { 464 this.stopped = 2; 465 if (this.stack) { 466 this.stack.stopped = 2; 467 } 468 if (this.events) { 469 this.events.fire('stopped', this); 470 } 471 }; 472 473 /** 474 * Prevents the execution of this event's defaultFn 475 * @method preventDefault 476 */ 477 CEProto.preventDefault = function() { 478 if (this.preventable) { 479 this.prevented = 1; 480 if (this.stack) { 481 this.stack.prevented = 1; 482 } 483 } 484 }; 485 486 /** 487 * Stops the event propagation and prevents the default 488 * event behavior. 489 * @method halt 490 * @param immediate {boolean} if true additional listeners 491 * on the current target will not be executed 492 */ 493 CEProto.halt = function(immediate) { 494 if (immediate) { 495 this.stopImmediatePropagation(); 496 } else { 497 this.stopPropagation(); 498 } 499 this.preventDefault(); 500 }; 501 502 /** 503 * Registers another EventTarget as a bubble target. Bubble order 504 * is determined by the order registered. Multiple targets can 505 * be specified. 506 * 507 * Events can only bubble if emitFacade is true. 508 * 509 * Included in the event-custom-complex submodule. 510 * 511 * @method addTarget 512 * @chainable 513 * @param o {EventTarget} the target to add 514 * @for EventTarget 515 */ 516 ETProto.addTarget = function(o) { 517 var etState = this._yuievt; 518 519 if (!etState.targets) { 520 etState.targets = {}; 521 } 522 523 etState.targets[Y.stamp(o)] = o; 524 etState.hasTargets = true; 525 526 return this; 527 }; 528 529 /** 530 * Returns an array of bubble targets for this object. 531 * @method getTargets 532 * @return EventTarget[] 533 */ 534 ETProto.getTargets = function() { 535 var targets = this._yuievt.targets; 536 return targets ? YObject.values(targets) : []; 537 }; 538 539 /** 540 * Removes a bubble target 541 * @method removeTarget 542 * @chainable 543 * @param o {EventTarget} the target to remove 544 * @for EventTarget 545 */ 546 ETProto.removeTarget = function(o) { 547 var targets = this._yuievt.targets; 548 549 if (targets) { 550 delete targets[Y.stamp(o, true)]; 551 552 if (YObject.size(targets) === 0) { 553 this._yuievt.hasTargets = false; 554 } 555 } 556 557 return this; 558 }; 559 560 /** 561 * Propagate an event. Requires the event-custom-complex module. 562 * @method bubble 563 * @param evt {CustomEvent} the custom event to propagate 564 * @return {boolean} the aggregated return value from Event.Custom.fire 565 * @for EventTarget 566 */ 567 ETProto.bubble = function(evt, args, target, es) { 568 569 var targs = this._yuievt.targets, 570 ret = true, 571 t, 572 ce, 573 i, 574 bc, 575 ce2, 576 type = evt && evt.type, 577 originalTarget = target || (evt && evt.target) || this, 578 oldbubble; 579 580 if (!evt || ((!evt.stopped) && targs)) { 581 582 for (i in targs) { 583 if (targs.hasOwnProperty(i)) { 584 585 t = targs[i]; 586 587 ce = t._yuievt.events[type]; 588 589 if (t._hasSiblings) { 590 ce2 = t.getSibling(type, ce); 591 } 592 593 if (ce2 && !ce) { 594 ce = t.publish(type); 595 } 596 597 oldbubble = t._yuievt.bubbling; 598 t._yuievt.bubbling = type; 599 600 // if this event was not published on the bubble target, 601 // continue propagating the event. 602 if (!ce) { 603 if (t._yuievt.hasTargets) { 604 t.bubble(evt, args, originalTarget, es); 605 } 606 } else { 607 608 if (ce2) { 609 ce.sibling = ce2; 610 } 611 612 // set the original target to that the target payload on the facade is correct. 613 ce.target = originalTarget; 614 ce.originalTarget = originalTarget; 615 ce.currentTarget = t; 616 bc = ce.broadcast; 617 ce.broadcast = false; 618 619 // default publish may not have emitFacade true -- that 620 // shouldn't be what the implementer meant to do 621 ce.emitFacade = true; 622 623 ce.stack = es; 624 625 // TODO: See what's getting in the way of changing this to use 626 // the more performant ce._fire(args || evt.details || []). 627 628 // Something in Widget Parent/Child tests is not happy if we 629 // change it - maybe evt.details related? 630 ret = ret && ce.fire.apply(ce, args || evt.details || []); 631 632 ce.broadcast = bc; 633 ce.originalTarget = null; 634 635 // stopPropagation() was called 636 if (ce.stopped) { 637 break; 638 } 639 } 640 641 t._yuievt.bubbling = oldbubble; 642 } 643 } 644 } 645 646 return ret; 647 }; 648 649 /** 650 * @method _hasPotentialSubscribers 651 * @for EventTarget 652 * @private 653 * @param {String} fullType The fully prefixed type name 654 * @return {boolean} Whether the event has potential subscribers or not 655 */ 656 ETProto._hasPotentialSubscribers = function(fullType) { 657 658 var etState = this._yuievt, 659 e = etState.events[fullType]; 660 661 if (e) { 662 return e.hasSubs() || etState.hasTargets || e.broadcast; 663 } else { 664 return false; 665 } 666 }; 667 668 FACADE = new Y.EventFacade(); 669 FACADE_KEYS = {}; 670 671 // Flatten whitelist 672 for (key in FACADE) { 673 FACADE_KEYS[key] = true; 674 } 675 676 677 }, '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 |