/** * Event Mixin * @module zrender/mixin/Eventful * @author Kener (@Kener-林峰, kener.linfeng@gmail.com) * pissang (https://www.github.com/pissang) */ var arrySlice = Array.prototype.slice; /** * Event dispatcher. * * @alias module:zrender/mixin/Eventful * @constructor * @param {Object} [eventProcessor] The object eventProcessor is the scope when * `eventProcessor.xxx` called. * @param {Function} [eventProcessor.normalizeQuery] * param: {string|Object} Raw query. * return: {string|Object} Normalized query. * @param {Function} [eventProcessor.filter] Event will be dispatched only * if it returns `true`. * param: {string} eventType * param: {string|Object} query * return: {boolean} * @param {Function} [eventProcessor.afterTrigger] Called after all handlers called. * param: {string} eventType */ var Eventful = function (eventProcessor) { this._$handlers = {}; this._$eventProcessor = eventProcessor; }; Eventful.prototype = { constructor: Eventful, /** * The handler can only be triggered once, then removed. * * @param {string} event The event name. * @param {string|Object} [query] Condition used on event filter. * @param {Function} handler The event handler. * @param {Object} context */ one: function (event, query, handler, context) { return on(this, event, query, handler, context, true); }, /** * Bind a handler. * * @param {string} event The event name. * @param {string|Object} [query] Condition used on event filter. * @param {Function} handler The event handler. * @param {Object} [context] */ on: function (event, query, handler, context) { return on(this, event, query, handler, context, false); }, /** * Whether any handler has bound. * * @param {string} event * @return {boolean} */ isSilent: function (event) { var _h = this._$handlers; return !_h[event] || !_h[event].length; }, /** * Unbind a event. * * @param {string} [event] The event name. * If no `event` input, "off" all listeners. * @param {Function} [handler] The event handler. * If no `handler` input, "off" all listeners of the `event`. */ 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; }, /** * Dispatch a event. * * @param {string} type The event name. */ trigger: function (type) { var _h = this._$handlers[type]; var eventProcessor = this._$eventProcessor; if (_h) { var args = arguments; var argLen = args.length; if (argLen > 3) { args = arrySlice.call(args, 1); } var len = _h.length; for (var i = 0; i < len;) { var hItem = _h[i]; if (eventProcessor && eventProcessor.filter && hItem.query != null && !eventProcessor.filter(type, hItem.query)) { i++; continue; } // Optimize advise from backbone switch (argLen) { case 1: hItem.h.call(hItem.ctx); break; case 2: hItem.h.call(hItem.ctx, args[1]); break; case 3: hItem.h.call(hItem.ctx, args[1], args[2]); break; default: // have more than 2 given arguments hItem.h.apply(hItem.ctx, args); break; } if (hItem.one) { _h.splice(i, 1); len--; } else { i++; } } } eventProcessor && eventProcessor.afterTrigger && eventProcessor.afterTrigger(type); return this; }, /** * Dispatch a event with context, which is specified at the last parameter. * * @param {string} type The event name. */ triggerWithContext: function (type) { var _h = this._$handlers[type]; var eventProcessor = this._$eventProcessor; if (_h) { 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 len = _h.length; for (var i = 0; i < len;) { var hItem = _h[i]; if (eventProcessor && eventProcessor.filter && hItem.query != null && !eventProcessor.filter(type, hItem.query)) { i++; continue; } // Optimize advise from backbone switch (argLen) { case 1: hItem.h.call(ctx); break; case 2: hItem.h.call(ctx, args[1]); break; case 3: hItem.h.call(ctx, args[1], args[2]); break; default: // have more than 2 given arguments hItem.h.apply(ctx, args); break; } if (hItem.one) { _h.splice(i, 1); len--; } else { i++; } } } eventProcessor && eventProcessor.afterTrigger && eventProcessor.afterTrigger(type); return this; } }; function normalizeQuery(host, query) { var eventProcessor = host._$eventProcessor; if (query != null && eventProcessor && eventProcessor.normalizeQuery) { query = eventProcessor.normalizeQuery(query); } return query; } function on(eventful, event, query, handler, context, isOnce) { var _h = eventful._$handlers; if (typeof query === 'function') { context = handler; handler = query; query = null; } if (!handler || !event) { return eventful; } query = normalizeQuery(eventful, query); if (!_h[event]) { _h[event] = []; } for (var i = 0; i < _h[event].length; i++) { if (_h[event][i].h === handler) { return eventful; } } var wrap = { h: handler, one: isOnce, query: query, ctx: context || eventful, // FIXME // Do not publish this feature util it is proved that it makes sense. callAtLast: handler.zrEventfulCallAtLast }; var lastIndex = _h[event].length - 1; var lastWrap = _h[event][lastIndex]; lastWrap && lastWrap.callAtLast ? _h[event].splice(lastIndex, 0, wrap) : _h[event].push(wrap); return eventful; } // ---------------------- // The events in zrender // ---------------------- /** * @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#ondrag * @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 */ var _default = Eventful; module.exports = _default;