/** * The main base class. Manages the signal system. * * @param signals Map with all connected signal handlers */ module.exports = new Class({ Tag: 'vn-object' ,Properties: {} ,_refCount: 1 ,_signalData: null ,initialize: function(props) { this.setProperties(props); } ,setProperties: function(props) { for (var prop in props) this[prop] = props[prop]; } ,ref: function() { this._refCount++; return this; } ,unref: function() { this._refCount--; if (this._refCount === 0) this._destroy(); } ,loadXml: function(builder, node) {} ,appendChild: function(child) {} ,_signalInit: function() { if (!this._signalData) this._signalData = { signals: {}, links: {} }; } /** * Conects a signal with a function. * * @param {String} id The signal identifier * @param {Function} callback The callback * @param {Object} instance The instance */ ,on: function(id, callback, instance) { if (!(callback instanceof Function)) { console.warn('Vn.Object: Invalid callback for signal \'%s\'', id); return; } this._signalInit(); var callbacks = this._signalData.signals[id]; if (!callbacks) callbacks = this._signalData.signals[id] = []; callbacks.push({ blocked: false ,callback: callback ,instance: instance }); } /** * Locks/Unlocks a signal emission to the specified object. * * @param {String} id The signal identifier * @param {Function} callback The callback * @param {Boolean} block %true for lock the signal, %false for unlock */ ,blockSignal: function(id, callback, block, instance) { if (!this._signalData) return; var callbacks = this._signalData.signals[id]; if (!callbacks) return; for (var i = 0; i < callbacks.length; i++) if (callbacks[i].callback == callback && callbacks[i].instance == instance) callbacks[i].blocked = block; } /** * Emits a signal in the current object. * * @param {String} id The signal identifier */ ,signalEmit: function(id) { if (!this._signalData) return; var callbacks = this._signalData.signals[id]; if (!callbacks) return; var callbackArgs = []; callbackArgs.push(this); for (var i = 1; i < arguments.length; i++) callbackArgs.push(arguments[i]); for (var i = 0; i < callbacks.length; i++) if (!callbacks[i].blocked) callbacks[i].callback.apply(callbacks[i].instance, callbackArgs); } /** * Disconnects a signal from current object. * * @param {String} id The signal identifier * @param {Function} callback The connected callback * @param {Object} instance The instance */ ,disconnect: function(id, callback, instance) { if (!this._signalData) return; var callbacks = this._signalData.signals[id]; if (!callbacks) return; for (var i = 0; i < callbacks.length; i++) if (callbacks[i].callback == callback && callbacks[i].instance == instance) callbacks.splice(i--, 1); } /** * Disconnects all signals for the given instance. * * @param {Object} instance The instance */ ,disconnectByInstance: function(instance) { if (!this._signalData) return; var signals = this._signalData.signals; for (var signalId in signals) { var callbacks = signals[signalId]; for (var i = 0; i < callbacks.length; i++) if (callbacks[i].instance == instance) callbacks.splice(i--, 1); } } /** * Destroys the object, this method should only be called before losing * the last reference to the object. */ ,_destroy: function() { if (!this._signalData) return; var links = this._signalData.links; for (var key in links) links[key].disconnectByInstance(this); this._signalData = null; } ,link: function(prop, handlers) { this._signalInit(); var links = this._signalData.links; for (var key in prop) { var newObject = prop[key]; var oldObject = this[key]; if (oldObject) { oldObject.disconnectByInstance(this); oldObject.unref(); } this[key] = newObject; if (newObject) { links[key] = newObject.ref(); for (var signal in handlers) newObject.on(signal, handlers[signal], this); } else if (oldObject) delete links[key]; } } });