[ Index ]

PHP Cross Reference of Unnamed Project

title

Body

[close]

/lib/yuilib/3.17.2/event-custom-complex/ -> event-custom-complex-debug.js (source)

   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"]});


Generated: Thu Aug 11 10:00:09 2016 Cross-referenced by PHPXref 0.7.1