Böngésző független eseménykezelés keretrendszer nélkül 2

Legutóbbi bejegyzésem óta gondolkodtam, hogy hogyan lehetne még szebben, ugyanakkor nem túl nagy méretben megoldani a böngésző független eseménykezelést. Továbbra is a minimalitás a cél, de most bekerült az esemény eltávolítása is. És mindezt sikerült elérnem egy kicsi függvénytárban, ami YUI Compressor-ral minify-olva mindössze 1Kb.

/*! Copyright (c) 2010-2011 Peter (Poetro) Galiba MIT Licensed */

/**
 * @fileoverview Browser independent basic event handling.
 * @author Peter (Poetro) Galiba
 */
(function (window) {
  /**
   * Normalizáljuk az event objektumot.
   *
   * A normalizált tulajdonságok:
   *   - target
   *   - preventDefault
   *   - stopPropagation
   *
   * @param {Object} event
   *   Event objektum
   * @returns {Element}
   *   Az esemény célpontja
   */
  function normalizeEvent(event) {
    var target;

    if (!event) {
      event = window.event;
    }
    if (event.target) {
      target = event.target;
    }
    else if (event.srcElement) {
      target = event.srcElement;
    }
    if (target && target.nodeType == 3) {
      target = target.parentNode;
    }
    event.preventDefault = event.preventDefault || function () {
      this.returnValue = false;
    };
    event.stopPropagation = event.stopPropagation || function () {
      this.cancelBubble = true;
    };

    return target;
  }

  /**
   * addEvent callback függvényének előkészítése.
   *
   * @param {Function} func
   *   A callback függvény.
   * @returns {Function}
   *   Az új callback függvény.
   *
   * @see addEvent
   */
  function prepareCallback(func) {
    // Olyan függvényt állítunk elő amiben a this már az esemény célpontja.
    return function (event) {
      var target = normalizeEvent(event),
          returnValue = func.call(target, event);

      if (returnValue === false) {
        event.preventDefault();
        event.stopPropagation();
      }

      return returnValue;
    };
  }

  /**
   * Lekérdezi a megadott függvényhez tartozó callback függvényt.
   *
   * @param {Function} func
   *   A függvény, amihez kell a callback függvény.
   * @param {String} [op]
   *   A művelet, amit esetleg végezni kell.
   *   A getCallback függvény karabantart egy listát a callback függvényekről.
   *   Ezt az op értékével a következőképpen lehet módosítani:
   *    - 'add' : hozzáadja a listához,
   *    - 'remove' : eltávolítja a listából.
   */
  function getCallback(func, op) {
    var gc = getCallback, fl, i, map, f, index = -1;

    // Karbantartott `static` függvény lista.
    if (!gc.fl) {
      gc.fl = [];
    }
    fl = gc.fl;

    // Végigmegyünk a listán, hogy megtaláljuk benne a függvényt.
    for (i = fl.length - 1; i >= 0; i -= 1) {
      map = fl[i];
      if (map && map.original === func) {
        index = i;
        f = map.generated;
        break;
      }
    }

    if (op === 'remove') {
      if (index !== -1) {
        fl[ index ].counter -= 1;
        if (fl[ index ].counter <= 0) {
          delete fl[ index ];
        }
      }
    }
    else if (op === 'add') {
      if (index !== -1) {
        fl[ index ].counter += 1;
      }
      else {
        f = prepareCallback(func);
        fl[fl.length] = {
          original  : func,
          generated : f,
          counter   : 1
        };
      }
    }

    return f;
  }

  /**
   * Eltávolítja a megadott eseménykezelőt az elemről.
   *
   * @param {Element} elm
   *   A DOM elem, amiről el kell távolítani az eseményt.
   * @param {String} evt
   *   Az esemény neve, például `click`.
   * @param {Function} func
   *   A callback függvény, ami meghívódik amikor az esemény kiváltódik.
   */
  this.removeEvent = function (elm, evt, func) {
    var f = getCallback(func, 'remove'),
        removeEventListener = elm.removeEventListener,
        detachEvent = elm.detachEvent;

    if (removeEventListener) {
      removeEventListener.call(elm, evt, f, false);
    }
    else if (detachEvent) {
      detachEvent.call(elm, 'on' + evt, f);
    }
    else {
      elm['on' + evt] = null;
    }
  };

  /**
   * Hozzáadja a megadott eseménykezelőt az elemhez.
   *
   * @param {Element} elm
   *   A DOM elem, amihez hozzá kell adni az eseményt.
   * @param {String} evt
   *   Az esemény neve, például `click`.
   * @param {Function} func
   *   A callback függvény, ami meghívódik amikor az esemény kiváltódik.
   */
  this.addEvent = function (elm, evt, func) {
    var f = getCallback(func, 'add'),
        addEventListener = elm.addEventListener,
        attachEvent = elm.attachEvent;

    if (addEventListener) {
      addEventListener.call(elm, evt, f, false);
    }
    else if (attachEvent) {
      attachEvent.call(elm, 'on' + evt, f);
    }
    else {
      elm['on' + evt] = f;
    }
  };
}).call(this, this);
comments powered by Disqus