UNPKG

wqking-eventjs

Version:

eventjs is a JavaScript event library that provides tools that enable your application components to communicate with each other by dispatching events and listening for them. With eventpp you can easily implement signal/slot mechanism, or observer pattern

435 lines (430 loc) 14.6 kB
// eventjs library // Copyright (C) 2019 Wang Qi (wqking) // Github: https://github.com/wqking/eventjs // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // http://www.apache.org/licenses/LICENSE-2.0 // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. /*eventjs v0.0.1, by wqking, https://github.com/wqking/eventjs @preserve*/ if (eventjs === undefined) { var eventjs = {}; } if (typeof define === "function" && define.amd) { define(function() { return eventjs; }); } else if (typeof module === "object" && module.exports) { module.exports = eventjs; } (function(ns) { "use strict"; function Node(callback, counter) { this._previous = null; this._next = null; this._callback = callback; this._counter = counter; } function CallbackList(params) { this._head = null; this._tail = null; this._currentCounter = 0; params = params || {}; this._canContinueInvoking = params.hasOwnProperty("canContinueInvoking") ? params.canContinueInvoking : null; this._argumentsAsArray = params.hasOwnProperty("argumentsAsArray") ? !!params.argumentsAsArray : false; if (this._argumentsAsArray) { this.dispatch = this._dispatchArgumentsAsArray; this.applyDispatch = this._applyDispatchArgumentsAsArray; } else { this.dispatch = this._dispatchNotArgumentsAsArray; this.applyDispatch = this._applyDispatchNotArgumentsAsArray; } } var proto = CallbackList.prototype; proto.append = function(callback) { var node = new Node(callback, this._getNextCounter()); if (this._head) { node._previous = this._tail; this._tail._next = node; this._tail = node; } else { this._head = node; this._tail = node; } return node; }; proto.prepend = function(callback) { var node = new Node(callback, this._getNextCounter()); if (this._head) { node._next = this._head; this._head._previous = node; this._head = node; } else { this._head = node; this._tail = node; } return node; }; proto.insert = function(callback, before) { var beforeNode = this._doFindNode(before); if (!beforeNode) { return this.append(callback); } var node = new Node(callback, this._getNextCounter()); node._previous = beforeNode._previous; node._next = beforeNode; if (beforeNode._previous) { beforeNode._previous._next = node; } beforeNode._previous = node; if (beforeNode == this._head) { this._head = node; } return node; }; proto.remove = function(handle) { var node = this._doFindNode(handle); if (!node) { return false; } if (node._next) { node._next._previous = node._previous; } if (node._previous) { node._previous._next = node._next; } if (this._head == node) { this._head = node._next; } if (this._tail == node) { this._tail = node._previous; } // Mark it as deleted node._counter = 0; return true; }; proto.empty = function() { return !this._head; }; proto.has = function(handle) { return !!this._doFindNode(handle); }; proto.hasAny = function() { return !!this._head; } // duplicated code for performance reason ; proto._dispatchArgumentsAsArray = function() { var counter = this._currentCounter; var node = this._head; var canContinueInvoking = this._canContinueInvoking; while (node) { if (node._counter != 0 && counter >= node._counter) { node._callback.call(this, arguments); if (canContinueInvoking && !canContinueInvoking.call(this, arguments)) { break; } } node = node._next; } }; proto._dispatchNotArgumentsAsArray = function() { var counter = this._currentCounter; var node = this._head; var canContinueInvoking = this._canContinueInvoking; while (node) { if (node._counter != 0 && counter >= node._counter) { node._callback.apply(this, arguments); if (canContinueInvoking && !canContinueInvoking.apply(this, arguments)) { break; } } node = node._next; } }; proto._applyDispatchArgumentsAsArray = function(args) { var counter = this._currentCounter; var node = this._head; var canContinueInvoking = this._canContinueInvoking; while (node) { if (node._counter != 0 && counter >= node._counter) { node._callback.call(this, args); if (canContinueInvoking && !canContinueInvoking.call(this, args)) { break; } } node = node._next; } }; proto._applyDispatchNotArgumentsAsArray = function(args) { var counter = this._currentCounter; var node = this._head; var canContinueInvoking = this._canContinueInvoking; while (node) { if (node._counter != 0 && counter >= node._counter) { node._callback.apply(this, args); if (canContinueInvoking && !canContinueInvoking.apply(this, args)) { break; } } node = node._next; } }; proto.forEach = function(func) { var node = this._head; var counter = this._currentCounter; while (node) { if (node._counter != 0 && counter >= node._counter) { func(node._callback); } node = node._next; } }; proto.forEachIf = function(func) { var node = this._head; var counter = this._currentCounter; while (node) { if (node._counter != 0 && counter >= node._counter) { if (!func(node._callback)) { return false; } } node = node._next; } return true; }; proto._doFindNode = function(handle) { var node = this._head; while (node) { if (node === handle || node._callback === handle) { return node; } node = node._next; } return null; }; proto._getNextCounter = function() { var result = ++this._currentCounter; if (result == 0) { // overflow, let's reset all nodes' counters. var node = this._head; while (node) { node._counter = 1; node = node._next; } result = ++this._currentCounter; } return result; }; ns.CallbackList = CallbackList; })(eventjs); (function(ns) { "use strict"; function _extend(destination, source) { for (var k in source) { destination[k] = source[k]; } return destination; } function EventDispatcher(params) { this._eventCallbackListMap = {}; params = params || {}; this._params = params; this._getEvent = typeof params.getEvent === "function" ? params.getEvent : null; this._argumentPassingMode = params.hasOwnProperty("argumentPassingMode") ? params.argumentPassingMode : EventDispatcher.defaultArgumentPassingMode; this._argumentsAsArray = params.hasOwnProperty("argumentsAsArray") ? !!params.argumentsAsArray : false; this._mixins = params.mixins; this._hasMixins = this._mixins && this._mixins.length > 0; if (this._hasMixins) { for (var i = 0; i < this._mixins.length; ++i) { _extend(this, this._mixins[i]); } } } EventDispatcher.argumentPassingIncludeEvent = 1; EventDispatcher.argumentPassingExcludeEvent = 2; EventDispatcher.defaultArgumentPassingMode = 2; var proto = EventDispatcher.prototype; proto.appendListener = function(event, callback) { return this._doGetCallbackList(event, true).append(callback); }; proto.prependListener = function(event, callback) { return this._doGetCallbackList(event, true).prepend(callback); }; proto.insertListener = function(event, callback, before) { return this._doGetCallbackList(event, true).insert(callback, before); }; proto.removeListener = function(event, handle) { var cbList = this._doGetCallbackList(event, false); if (cbList) { return cbList.remove(handle); } return false; }; proto.hasListener = function(event, handle) { var cbList = this._doGetCallbackList(event, false); if (cbList) { return cbList.has(handle); } return false; }; proto.hasAnyListener = function(event) { var cbList = this._doGetCallbackList(event, false); if (cbList) { return cbList.hasAny(); } return false; }; proto.dispatch = function() { this.applyDispatch(arguments); }; proto.applyDispatch = function(args) { if (this._hasMixins) { for (var i = 0; i < this._mixins.length; ++i) { var mixin = this._mixins[i]; if (mixin.mixinBeforeDispatch && !mixin.mixinBeforeDispatch.call(this, args)) { return; } } } if (this._getEvent) { if (this._argumentsAsArray) { var event = this._getEvent.call(this, args); } else { var event = this._getEvent.apply(this, args); } var cbList = this._doGetCallbackList(event, false); if (cbList) { if (this._argumentPassingMode === EventDispatcher.argumentPassingIncludeEvent) { args = [ event ].concat(args); } cbList.dispatch.apply(cbList, args); } } else { var cbList = this._doGetCallbackList(args[0], false); if (cbList) { if (this._argumentPassingMode === EventDispatcher.argumentPassingExcludeEvent) { args = Array.prototype.slice.call(args, 1); } cbList.dispatch.apply(cbList, args); } } }; proto.forEach = function(event, func) { var cbList = this._doGetCallbackList(event, false); if (cbList) { cbList.forEach(event, func); } }; proto.forEachIf = function(event, func) { var cbList = this._doGetCallbackList(event, false); if (cbList) { return cbList.forEachIf(event, func); } return true; }; proto._doGetCallbackList = function(event, createOnNotFound) { if (this._eventCallbackListMap.hasOwnProperty(event)) { return this._eventCallbackListMap[event]; } if (createOnNotFound) { var cbList = new ns.CallbackList(this._params); this._eventCallbackListMap[event] = cbList; return cbList; } return null; }; ns.EventDispatcher = EventDispatcher; })(eventjs); (function(ns) { "use strict"; function EventQueue(params) { ns.EventDispatcher.call(this, params); this._queueList = []; } EventQueue.prototype = Object.create(ns.EventDispatcher.prototype); var proto = EventQueue.prototype; proto.enqueue = function() { this._queueList.push(arguments); }; proto.process = function() { var list = this._queueList; this._queueList = []; var count = list.length; for (var i = 0; i < count; ++i) { this.applyDispatch(list[i]); } }; proto.processOne = function() { if (this._queueList.length > 0) { this.applyDispatch(this._queueList.shift()); } }; proto.processIf = function(func) { var list = this._queueList; this._queueList = []; var unprocessedList = []; var count = list.length; for (var i = 0; i < count; ++i) { var item = list[i]; if (this._argumentsAsArray) { var ok = func.call(this, item); } else { var ok = func.apply(this, item); } if (ok) { this.applyDispatch(item); } else { unprocessedList.push(item); } } if (unprocessedList.length > 0) { this._queueList = this._queueList.concat(unprocessedList); } }; proto.empty = function() { return this._queueList.length === 0; }; proto.clearEvents = function() { this._queueList.length = 0; }; proto.peekEvent = function() { return this._queueList[0]; }; proto.takeEvent = function() { if (this._queueList.length > 0) { return this._queueList.shift(); } return null; }; ns.EventQueue = EventQueue; })(eventjs); (function(ns) { "use strict"; var _callbacklist = ns; function MixinFilter(params) { this._filterList = new _callbacklist.CallbackList(params); } var proto = MixinFilter.prototype; proto.appendFilter = function(filter) { this._filterList.append(filter); }; proto.removeFilter = function(handle) { this._filterList.remove(handle); }; proto.mixinBeforeDispatch = function(args) { if (!this._filterList.empty()) { if (!this._filterList.forEachIf(function(callback) { return callback.call(callback, args); })) { return false; } } return true; }; ns.MixinFilter = MixinFilter; })(eventjs);