2016-09-26 09:28:47 +00:00
|
|
|
|
2015-01-23 13:09:30 +00:00
|
|
|
/**
|
2022-05-30 01:30:33 +00:00
|
|
|
* The main base class. Manages the signal system. Objects based on this class
|
|
|
|
* can be instantiated declaratively using XML.
|
2022-05-26 06:08:31 +00:00
|
|
|
*/
|
2022-05-28 15:49:46 +00:00
|
|
|
module.exports = new Class({
|
2022-05-30 01:30:33 +00:00
|
|
|
/**
|
|
|
|
* Tag to be used when the class instance is defined via XML. All classes
|
|
|
|
* must define this attribute, even if it is not used.
|
|
|
|
*/
|
2015-01-23 13:09:30 +00:00
|
|
|
Tag: 'vn-object'
|
2022-05-30 01:30:33 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Class public properties.
|
|
|
|
*/
|
2015-01-23 13:09:30 +00:00
|
|
|
,Properties: {}
|
2015-07-28 19:14:26 +00:00
|
|
|
|
2022-05-30 01:30:33 +00:00
|
|
|
/*
|
|
|
|
* Reference count.
|
|
|
|
*/
|
2015-11-09 08:14:33 +00:00
|
|
|
,_refCount: 1
|
2015-01-23 13:09:30 +00:00
|
|
|
|
2022-05-30 01:30:33 +00:00
|
|
|
/*
|
|
|
|
* Signal handlers data.
|
|
|
|
*/
|
|
|
|
,_thisArg: null
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Initializes the object and sets all properties passed to the class
|
|
|
|
* constructor.
|
|
|
|
*
|
|
|
|
* @param {Object} props The properties passed to the contructor
|
|
|
|
*/
|
2022-05-28 15:49:46 +00:00
|
|
|
,initialize: function(props) {
|
|
|
|
this.setProperties(props);
|
2015-11-17 10:34:33 +00:00
|
|
|
}
|
|
|
|
|
2022-05-30 01:30:33 +00:00
|
|
|
/**
|
|
|
|
* Sets a group of object properties.
|
|
|
|
*
|
|
|
|
* @param {Object} props Properties
|
|
|
|
*/
|
2022-05-28 15:49:46 +00:00
|
|
|
,setProperties: function(props) {
|
2015-01-23 13:09:30 +00:00
|
|
|
for (var prop in props)
|
|
|
|
this[prop] = props[prop];
|
|
|
|
}
|
|
|
|
|
2022-05-30 01:30:33 +00:00
|
|
|
/**
|
|
|
|
* Increases the object reference count.
|
|
|
|
*/
|
2022-05-28 15:49:46 +00:00
|
|
|
,ref: function() {
|
2015-11-09 08:14:33 +00:00
|
|
|
this._refCount++;
|
2015-07-28 19:14:26 +00:00
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
2022-05-30 01:30:33 +00:00
|
|
|
/**
|
|
|
|
* Decreases the object reference count.
|
|
|
|
*/
|
2022-05-28 15:49:46 +00:00
|
|
|
,unref: function() {
|
2015-11-09 08:14:33 +00:00
|
|
|
this._refCount--;
|
2015-07-28 19:14:26 +00:00
|
|
|
|
2015-11-09 08:14:33 +00:00
|
|
|
if (this._refCount === 0)
|
2022-05-28 15:49:46 +00:00
|
|
|
this._destroy();
|
2015-07-28 19:14:26 +00:00
|
|
|
}
|
2022-05-30 01:30:33 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Called from @Vn.Builder when it finds a custom tag as a child of the
|
|
|
|
* element.
|
|
|
|
*
|
|
|
|
* @param {Vn.Scope} scope The scope instance
|
|
|
|
* @param {Node} node The custom tag child nodes
|
|
|
|
*/
|
|
|
|
,loadXml: function() {}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Called from @Vn.Builder when it finds a a child tag that isn't
|
|
|
|
* associated to any property.
|
|
|
|
*
|
|
|
|
* @param {Object} child The child object instance
|
|
|
|
*/
|
|
|
|
,appendChild: function() {}
|
2015-01-23 13:09:30 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Conects a signal with a function.
|
|
|
|
*
|
2022-05-30 01:30:33 +00:00
|
|
|
* @param {string} id The signal identifier
|
|
|
|
* @param {function} callback The callback
|
2015-01-23 13:09:30 +00:00
|
|
|
* @param {Object} instance The instance
|
2022-05-26 06:08:31 +00:00
|
|
|
*/
|
2022-05-28 15:49:46 +00:00
|
|
|
,on: function(id, callback, instance) {
|
|
|
|
if (!(callback instanceof Function)) {
|
|
|
|
console.warn('Vn.Object: Invalid callback for signal \'%s\'', id);
|
2015-07-17 14:34:42 +00:00
|
|
|
return;
|
2015-11-09 08:14:33 +00:00
|
|
|
}
|
|
|
|
|
2022-05-28 15:49:46 +00:00
|
|
|
this._signalInit();
|
2022-05-30 01:30:33 +00:00
|
|
|
var callbacks = this._thisArg.signals[id];
|
2015-11-09 08:14:33 +00:00
|
|
|
|
|
|
|
if (!callbacks)
|
2022-05-30 01:30:33 +00:00
|
|
|
callbacks = this._thisArg.signals[id] = [];
|
2015-01-23 13:09:30 +00:00
|
|
|
|
2022-05-28 15:49:46 +00:00
|
|
|
callbacks.push({
|
2022-05-30 01:30:33 +00:00
|
|
|
blocked: false
|
2015-01-23 13:09:30 +00:00
|
|
|
,callback: callback
|
|
|
|
,instance: instance
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Locks/Unlocks a signal emission to the specified object.
|
|
|
|
*
|
2022-05-30 01:30:33 +00:00
|
|
|
* @param {string} id The signal identifier
|
|
|
|
* @param {function} callback The callback
|
|
|
|
* @param {boolean} block %true for lock the signal, %false for unlock
|
2022-05-26 06:08:31 +00:00
|
|
|
*/
|
2022-05-28 15:49:46 +00:00
|
|
|
,blockSignal: function(id, callback, block, instance) {
|
2022-05-30 01:30:33 +00:00
|
|
|
if (!this._thisArg)
|
2015-11-09 08:14:33 +00:00
|
|
|
return;
|
|
|
|
|
2022-05-30 01:30:33 +00:00
|
|
|
var callbacks = this._thisArg.signals[id];
|
2015-01-23 13:09:30 +00:00
|
|
|
|
|
|
|
if (!callbacks)
|
|
|
|
return;
|
|
|
|
|
|
|
|
for (var i = 0; i < callbacks.length; i++)
|
2015-07-28 19:14:26 +00:00
|
|
|
if (callbacks[i].callback == callback
|
|
|
|
&& callbacks[i].instance == instance)
|
2015-01-23 13:09:30 +00:00
|
|
|
callbacks[i].blocked = block;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2022-05-30 01:30:33 +00:00
|
|
|
* Emits a signal in the object.
|
2015-01-23 13:09:30 +00:00
|
|
|
*
|
2022-05-30 01:30:33 +00:00
|
|
|
* @param {string} id The signal identifier
|
2022-05-26 06:08:31 +00:00
|
|
|
*/
|
2022-05-30 01:30:33 +00:00
|
|
|
,emit: function(id) {
|
|
|
|
if (!this._thisArg)
|
2015-11-09 08:14:33 +00:00
|
|
|
return;
|
|
|
|
|
2022-05-30 01:30:33 +00:00
|
|
|
var callbacks = this._thisArg.signals[id];
|
2015-01-23 13:09:30 +00:00
|
|
|
|
|
|
|
if (!callbacks)
|
|
|
|
return;
|
|
|
|
|
|
|
|
var callbackArgs = [];
|
2022-05-28 15:49:46 +00:00
|
|
|
callbackArgs.push(this);
|
2015-01-23 13:09:30 +00:00
|
|
|
|
|
|
|
for (var i = 1; i < arguments.length; i++)
|
2022-05-28 15:49:46 +00:00
|
|
|
callbackArgs.push(arguments[i]);
|
2015-01-23 13:09:30 +00:00
|
|
|
|
|
|
|
for (var i = 0; i < callbacks.length; i++)
|
|
|
|
if (!callbacks[i].blocked)
|
2022-05-28 15:49:46 +00:00
|
|
|
callbacks[i].callback.apply(callbacks[i].instance, callbackArgs);
|
2015-01-23 13:09:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Disconnects a signal from current object.
|
|
|
|
*
|
2022-05-30 01:30:33 +00:00
|
|
|
* @param {string} id The signal identifier
|
|
|
|
* @param {function} callback The connected callback
|
2015-01-23 13:09:30 +00:00
|
|
|
* @param {Object} instance The instance
|
2022-05-26 06:08:31 +00:00
|
|
|
*/
|
2022-05-28 15:49:46 +00:00
|
|
|
,disconnect: function(id, callback, instance) {
|
2022-05-30 01:30:33 +00:00
|
|
|
if (!this._thisArg)
|
2015-11-09 08:14:33 +00:00
|
|
|
return;
|
|
|
|
|
2022-05-30 01:30:33 +00:00
|
|
|
var callbacks = this._thisArg.signals[id];
|
2015-01-23 13:09:30 +00:00
|
|
|
|
2022-05-30 01:30:33 +00:00
|
|
|
if (callbacks)
|
|
|
|
for (var i = callbacks.length; i--;)
|
|
|
|
if (callbacks[i].callback === callback
|
|
|
|
&& callbacks[i].instance === instance)
|
|
|
|
callbacks.splice(i, 1);
|
2015-01-23 13:09:30 +00:00
|
|
|
}
|
2015-07-28 19:14:26 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Disconnects all signals for the given instance.
|
|
|
|
*
|
|
|
|
* @param {Object} instance The instance
|
2022-05-26 06:08:31 +00:00
|
|
|
*/
|
2022-05-28 15:49:46 +00:00
|
|
|
,disconnectByInstance: function(instance) {
|
2022-05-30 01:30:33 +00:00
|
|
|
if (!this._thisArg)
|
2015-11-09 08:14:33 +00:00
|
|
|
return;
|
|
|
|
|
2022-05-30 01:30:33 +00:00
|
|
|
var signals = this._thisArg.signals;
|
2015-11-09 08:14:33 +00:00
|
|
|
|
2022-05-28 15:49:46 +00:00
|
|
|
for (var signalId in signals) {
|
2015-11-09 08:14:33 +00:00
|
|
|
var callbacks = signals[signalId];
|
2015-07-28 19:14:26 +00:00
|
|
|
|
2022-05-30 01:30:33 +00:00
|
|
|
if (callbacks)
|
|
|
|
for (var i = callbacks.length; i--;)
|
|
|
|
if (callbacks[i].instance === instance)
|
|
|
|
callbacks.splice(i, 1);
|
2015-07-28 19:14:26 +00:00
|
|
|
}
|
|
|
|
}
|
2015-01-23 13:09:30 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Destroys the object, this method should only be called before losing
|
2022-05-30 01:30:33 +00:00
|
|
|
* the last reference to the object. It can be overwritten by child classes
|
|
|
|
* but should always call the parent method.
|
2022-05-26 06:08:31 +00:00
|
|
|
*/
|
2022-05-28 15:49:46 +00:00
|
|
|
,_destroy: function() {
|
2022-05-30 01:30:33 +00:00
|
|
|
if (!this._thisArg)
|
2015-11-09 08:14:33 +00:00
|
|
|
return;
|
|
|
|
|
2022-05-30 01:30:33 +00:00
|
|
|
var links = this._thisArg.links;
|
2015-07-28 19:14:26 +00:00
|
|
|
|
|
|
|
for (var key in links)
|
2022-05-30 01:30:33 +00:00
|
|
|
this._unlink(links[key]);
|
2015-07-28 19:14:26 +00:00
|
|
|
|
2022-05-30 01:30:33 +00:00
|
|
|
this._thisArg = null;
|
2015-01-23 13:09:30 +00:00
|
|
|
}
|
|
|
|
|
2022-05-30 01:30:33 +00:00
|
|
|
/**
|
|
|
|
* Links the object with another object.
|
|
|
|
*
|
|
|
|
* @param {Object} prop The linked property
|
|
|
|
* @param {Object} handlers The object events to listen with
|
|
|
|
*/
|
2022-05-28 15:49:46 +00:00
|
|
|
,link: function(prop, handlers) {
|
|
|
|
this._signalInit();
|
2022-05-30 01:30:33 +00:00
|
|
|
var links = this._thisArg.links;
|
2015-11-09 08:14:33 +00:00
|
|
|
|
2022-05-28 15:49:46 +00:00
|
|
|
for (var key in prop) {
|
2015-01-23 13:09:30 +00:00
|
|
|
var newObject = prop[key];
|
|
|
|
var oldObject = this[key];
|
|
|
|
|
2022-05-30 01:30:33 +00:00
|
|
|
if (oldObject)
|
|
|
|
this._unlink(oldObject);
|
2015-01-23 13:09:30 +00:00
|
|
|
|
|
|
|
this[key] = newObject;
|
|
|
|
|
2022-05-28 15:49:46 +00:00
|
|
|
if (newObject) {
|
|
|
|
links[key] = newObject.ref();
|
2015-07-28 19:14:26 +00:00
|
|
|
|
|
|
|
for (var signal in handlers)
|
2022-05-28 15:49:46 +00:00
|
|
|
newObject.on(signal, handlers[signal], this);
|
|
|
|
} else if (oldObject)
|
2022-05-30 01:30:33 +00:00
|
|
|
links[key] = undefined;
|
2015-01-23 13:09:30 +00:00
|
|
|
}
|
|
|
|
}
|
2015-10-14 11:51:43 +00:00
|
|
|
|
2022-05-30 01:30:33 +00:00
|
|
|
,_unlink: function(object) {
|
|
|
|
object.disconnectByInstance(this);
|
|
|
|
object.unref();
|
|
|
|
}
|
|
|
|
|
|
|
|
,_signalInit: function() {
|
|
|
|
if (!this._thisArg)
|
|
|
|
this._thisArg = {
|
|
|
|
signals: {},
|
|
|
|
links: {}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
});
|