(function () { var signals = namespace("signals"); var tabs = namespace("tabs"); var _sigCount = {}; var _byName = {}; var _byId = {}; var _getByCallback = function(callback) { var id; for (id in _byId) { if (callback == _byId[id].callback) { return _byId[id]; } } return null; }; var _getBySelfOrCallback = function(selfOrCallback) { if (selfOrCallback instanceof Signal) return selfOrCallback; return _getByCallback(selfOrCallback); }; Object.defineProperty(this, "Signal", { writable : true, value : (function() { var id = 0; return function(name, callback, predicate) { if (!name) throw new Error("new Signal() : missing signal name"); id++; return Object.create(Signal.prototype, { "id" : { value : id }, "callback" : { value : callback, writable : true }, "predicate" : { value : predicate || null, writable : true }, "name" : { value : name }, "disconnect" : { value : function() { if (!this.connected) return this; var name = this.name, id = this.id; if (_sigCount[name] > 0) _sigCount[name]--; _byName[name][id] = null; delete _byName[name][id]; _byId[id] = null; delete _byId[id]; if (_sigCount[name] == 0) signals[name] = null; return this; } }, "connect" : { value : function(callback, predicate) { if (callback) this.callback = callback; if (predicate) this.predicate = predicate; if (this.connected) return this; if (!this.callback) throw new Error("Signal.connect() : missing callback"); var name = this.name, id = this.id; if (!_sigCount[name]) _sigCount[name] = 0; if (!_byName[name]) _byName[name] = {}; if (_sigCount[name] == 0) signals[name] = function() { return Signal.emit(name, arguments); }; _sigCount[name]++; _byName[name][id] = this; _byId[id] = this; return this; } }, "connected" : { get : function() { return Boolean(_byId[this.id]); } }, "toggle" : { value : function() { var connected = this.connected; if (connected) this.disconnect(); else this.connect(); return !connected; } }, "remove" : { value : function() { this.disconnect(); } } } ); }; })() }); Object.defineProperties(Signal, { "connect" : { value : function(name, callback, predicate) { return new Signal(name, callback, predicate).connect(); } }, "once" : { value : function(name, callback, predicate) { return new Signal(name, function() { var ret = false; if (!this.predicate || this.predicate.apply(this, arguments)) { this.disconnect(); ret = callback.apply(this, arguments); } return ret; }, predicate).connect(); } }, "disconnect" : { value : function(selfOrCallback) { var signal = _getBySelfOrCallback(selfOrCallback); if (signal) signal.disconnect(); return signal; } }, "connectWebView" : { value : function(name, callback) { var wv; tabs.forEach(function(w) { w.connect(name, function() { callback.apply(w, arguments); }); }); Signal.connect("createTab", function(wv) { wv.connect(name, function() { callback.apply(wv, arguments);}); }); } }, "emit" : { value : function(signal, args) { var id, current; var ret = false; var connected = _byName[signal]; for (id in connected) { current = connected[id]; if (!current.predicate || current.predicate.apply(current, args)) { ret = current.callback.apply(current, args) || ret; } } return ret; } }, "disconnectAll" : { value : function(callback) { var signals = []; var signal; while((signal = _getBySelfOrCallback(callback))) { if (signal.connected) { signals.push(signal); signal.disconnect(); } } return signals; } }, "connectAll" : { value : function(signalOrArray, callback) { var i, l; if (signalOrArray instanceof Signal) signalOrArray.connect(callback); else { for (i=signalOrArray.length-1; i>=0; i--) signalOrArray[i].connect(callback); } } } }); })(); 