text: /**
   * äº‹ä»¶æ‰©å±•
   * @module zrender/mixin/Eventful
   * @author Kener (@Kener-æž—å³°, kener.linfeng@gmail.com)
   *         pissang (https://www.github.com/pissang)
   */
  define(function (require) {
  
      var arrySlice = Array.prototype.slice;
      var zrUtil = require('../core/util.js');
      var indexOf = zrUtil.indexOf;
  
      /**
       * äº‹ä»¶åˆ†å‘å™¨
       * @alias module:zrender/mixin/Eventful
       * @constructor
       */
      var Eventful = function () {
          this._$handlers = {};
      };
  
      Eventful.prototype = {
  
          constructor: Eventful,
  
          /**
           * å•æ¬¡è§¦å‘ç»‘å®šï¼ŒtriggeråŽé”€æ¯
           *
           * @param {string} event äº‹ä»¶å
           * @param {Function} handler å“åº”å‡½æ•°
           * @param {Object} context
           */
          one: function (event, handler, context) {
              var _h = this._$handlers;
  
              if (!handler || !event) {
                  return this;
              }
  
              if (!_h[event]) {
                  _h[event] = [];
              }
  
              if (indexOf(_h[event], event) >= 0) {
                  return this;
              }
  
              _h[event].push({
                  h: handler,
                  one: true,
                  ctx: context || this
              });
  
              return this;
          },
  
          /**
           * ç»‘å®šäº‹ä»¶
           * @param {string} event äº‹ä»¶å
           * @param {Function} handler äº‹ä»¶å¤„ç†å‡½æ•°
           * @param {Object} [context]
           */
          on: function (event, handler, context) {
              var _h = this._$handlers;
  
              if (!handler || !event) {
                  return this;
              }
  
              if (!_h[event]) {
                  _h[event] = [];
              }
  
              _h[event].push({
                  h: handler,
                  one: false,
                  ctx: context || this
              });
  
              return this;
          },
  
          /**
           * æ˜¯å¦ç»‘å®šäº†äº‹ä»¶
           * @param  {string}  event
           * @return {boolean}
           */
          isSilent: function (event) {
              var _h = this._$handlers;
              return _h[event] && _h[event].length;
          },
  
          /**
           * è§£ç»‘äº‹ä»¶
           * @param {string} event äº‹ä»¶å
           * @param {Function} [handler] äº‹ä»¶å¤„ç†å‡½æ•°
           */
          off: function (event, handler) {
              var _h = this._$handlers;
  
              if (!event) {
                  this._$handlers = {};
                  return this;
              }
  
              if (handler) {
                  if (_h[event]) {
                      var newList = [];
                      for (var i = 0, l = _h[event].length; i < l; i++) {
                          if (_h[event][i]['h'] != handler) {
                              newList.push(_h[event][i]);
                          }
                      }
                      _h[event] = newList;
                  }
  
                  if (_h[event] && _h[event].length === 0) {
                      delete _h[event];
                  }
              }
              else {
                  delete _h[event];
              }
  
              return this;
          },
  
          /**
           * äº‹ä»¶åˆ†å‘
           *
           * @param {string} type äº‹ä»¶ç±»åž‹
           */
          trigger: function (type) {
              if (this._$handlers[type]) {
                  var args = arguments;
                  var argLen = args.length;
  
                  if (argLen > 3) {
                      args = arrySlice.call(args, 1);
                  }
  
                  var _h = this._$handlers[type];
                  var len = _h.length;
                  for (var i = 0; i < len;) {
                      // Optimize advise from backbone
                      switch (argLen) {
                          case 1:
                              _h[i]['h'].call(_h[i]['ctx']);
                              break;
                          case 2:
                              _h[i]['h'].call(_h[i]['ctx'], args[1]);
                              break;
                          case 3:
                              _h[i]['h'].call(_h[i]['ctx'], args[1], args[2]);
                              break;
                          default:
                              // have more than 2 given arguments
                              _h[i]['h'].apply(_h[i]['ctx'], args);
                              break;
                      }
  
                      if (_h[i]['one']) {
                          _h.splice(i, 1);
                          len--;
                      }
                      else {
                          i++;
                      }
                  }
              }
  
              return this;
          },
  
          /**
           * å¸¦æœ‰contextçš„äº‹ä»¶åˆ†å‘, æœ€åŽä¸€ä¸ªå‚æ•°æ˜¯äº‹ä»¶å›žè°ƒçš„context
           * @param {string} type äº‹ä»¶ç±»åž‹
           */
          triggerWithContext: function (type) {
              if (this._$handlers[type]) {
                  var args = arguments;
                  var argLen = args.length;
  
                  if (argLen > 4) {
                      args = arrySlice.call(args, 1, args.length - 1);
                  }
                  var ctx = args[args.length - 1];
  
                  var _h = this._$handlers[type];
                  var len = _h.length;
                  for (var i = 0; i < len;) {
                      // Optimize advise from backbone
                      switch (argLen) {
                          case 1:
                              _h[i]['h'].call(ctx);
                              break;
                          case 2:
                              _h[i]['h'].call(ctx, args[1]);
                              break;
                          case 3:
                              _h[i]['h'].call(ctx, args[1], args[2]);
                              break;
                          default:
                              // have more than 2 given arguments
                              _h[i]['h'].apply(ctx, args);
                              break;
                      }
  
                      if (_h[i]['one']) {
                          _h.splice(i, 1);
                          len--;
                      }
                      else {
                          i++;
                      }
                  }
              }
  
              return this;
          }
      };
  
      // å¯¹è±¡å¯ä»¥é€šè¿‡ onxxxx ç»‘å®šäº‹ä»¶
      /**
       * @event module:zrender/mixin/Eventful#onclick
       * @type {Function}
       * @default null
       */
      /**
       * @event module:zrender/mixin/Eventful#onmouseover
       * @type {Function}
       * @default null
       */
      /**
       * @event module:zrender/mixin/Eventful#onmouseout
       * @type {Function}
       * @default null
       */
      /**
       * @event module:zrender/mixin/Eventful#onmousemove
       * @type {Function}
       * @default null
       */
      /**
       * @event module:zrender/mixin/Eventful#onmousewheel
       * @type {Function}
       * @default null
       */
      /**
       * @event module:zrender/mixin/Eventful#onmousedown
       * @type {Function}
       * @default null
       */
      /**
       * @event module:zrender/mixin/Eventful#onmouseup
       * @type {Function}
       * @default null
       */
      /**
       * @event module:zrender/mixin/Eventful#ondragstart
       * @type {Function}
       * @default null
       */
      /**
       * @event module:zrender/mixin/Eventful#ondragend
       * @type {Function}
       * @default null
       */
      /**
       * @event module:zrender/mixin/Eventful#ondragenter
       * @type {Function}
       * @default null
       */
      /**
       * @event module:zrender/mixin/Eventful#ondragleave
       * @type {Function}
       * @default null
       */
      /**
       * @event module:zrender/mixin/Eventful#ondragover
       * @type {Function}
       * @default null
       */
      /**
       * @event module:zrender/mixin/Eventful#ondrop
       * @type {Function}
       * @default null
       */
  
      return Eventful;
  });
  