This repository has been archived on 2024-07-18. You can view files and clone it, but cannot push or open issues or pull requests.
lwb5/misc/Legacy Worlds.wdgt/lib/Base/Comp.js

217 lines
5.8 KiB
JavaScript

/** The Base.Comp class is the base class for all of the components. It provides the
* signal/slot framework that the components use, and allows access to components using
* their unique identifier.
*/
Base.Comp = Base.inherits({
/** The constructor initialises the component by assigning its identifier, creating the
* tables listing the slots, events and children, and creating the low-level slots and
* events common to all components.
*/
constructor: function () {
this._cid = ++ Base.Comp.lastId;
this._slots = new Base.Util.Hashtable();
this._evts = new Base.Util.Hashtable();
this._chld = new Base.Util.Hashtable();
this._cnt = null;
Base.Comp.list.put(this._cid, this);
Base.Comp.count ++;
this.destroyChildren = false;
this.addEvent('Destroy');
this.addSlot('addChild');
this.addSlot('removeChild');
},
/** This method is responsible for the destruction of a component. It
* starts by launching the onDestroy() event; it then detaches the
* component's children (or destroy them if the destroyChildren member
* is set to true), then detaches all of the component's slots and
* events. Finally, it removes the reference to the component in the
* global components list.
*/
destroy: function () {
this.onDestroy(this._cid);
var k = this._chld.keys();
for (var i in k) {
var c = this._chld.get(k[i]);
if (this.destroyChildren) {
c.destroy();
} else {
this.removeChild(c);
}
}
k = this._slots.keys();
for (var i in k) {
this._slots.get(k[i]).destroy();
}
this._slots.clear();
k = this._evts.keys();
for (var i in k) {
this._evts.get(k[i]).destroy();
}
this._evts.clear();
Base.Comp.list.remove(this._cid);
Base.Comp.count --;
for (var i in this) {
this[i] = null;
}
},
/** This method declares a new slot for the current component.
* @param name the name of the slot to be declared
*/
addSlot: function (name) {
if (this._slots.containsKey(name) || !this[name]) {
return;
}
this._slots.put(name, new Base.Comp.Slot(name, this));
},
/** This method generates a new event handler for the current component.
* @param name the name of the event to create
* @param propagate a boolean indicating the event propagates to the component's children
*/
addEvent: function (name, propagate) {
if (this._evts.containsKey(name) || this["on" + name]) {
return;
}
this._evts.put(name, new Base.Comp.Evt(name, propagate));
this["on" + name] = function() {
this.triggerEvent(name, arguments);
};
this.addSlot('on' + name);
},
/** This method binds an event from the current component to a slot on either the current
* component or, if the last parameter is present, another component.
* @param eName the name of the event to bind
* @param sName the name of the slots to bind an event to
* @param cmp the component on which to bind (if this parameter isn't passed, the current component is used)
*/
bindEvent: function (eName, sName, cmp) {
var e = this._evts.get(eName), c = (cmp ? cmp : this), s = c._slots.get(sName);
if (!(e && s)) {
return;
}
e.bind(s);
},
/** This method detaches an event from the current component from a slot to which it had been bound.
* @param eName the name of the event to detach
* @param sName the name of the slot to detach
* @param cmp the component on which the slot to detach is located
*/
detachEvent: function (eName, sName, cmp) {
var e = this._evts.get(eName), c = (cmp ? cmp : this), s = c._slots.get(sName);
if (!(e && s)) {
return;
}
e.detach(s);
},
/** This method triggers the execution of an event on the current component.
* @param eName the name of the event to trigger
* @param args an array containing the arguments to be passed to the event's handlers
*/
triggerEvent: function (eName, args) {
var e = this._evts.get(eName);
if (!e) {
return;
}
e.trigger.apply(e, args);
if (!e.propagate) {
return;
}
var k = this._chld.keys();
for (i=0;i<k.length;i++) {
this._chld.get(k[i]).triggerEvent(eName, args);
}
},
/** This method adds a child to the current component.
* @param cmp the component to add as a child of the current component
*/
addChild: function (cmp) {
if (!cmp || cmp._cid == this._cid || cmp.container != null) {
return;
}
cmp.container = this;
this._chld.put(cmp._cid, cmp);
cmp.bindEvent('Destroy', 'removeChild', this);
},
/** This method removes a child from the current component's list of children.
* @param cmp the child component to remove
*/
removeChild: function (cmp) {
if (!(cmp && this._chld.containsKey(cmp._cid))) {
return;
}
this._chld.remove(cmp._cid);
cmp.container = null;
cmp.detachEvent('Destroy', 'removeChild', this);
},
/** This method checks whether a component is a child of the current component.
* @param cmp the component to verify
* @returs true if the specified component is a child of the current component, false otherwise
*/
hasChild: function (cmp) {
return (cmp && cmp.container && cmp.container._cid == this._cid);
}
}, {
/** This class property contains the list of all available components;
* the components' identifiers are used as the key.
*/
list: new Base.Util.Hashtable(),
/** This class property stores the last identifier assigned to a
* component.
*/
lastId: -1,
/** This class property stores the amount of components currently
* being used.
*/
count: 0,
/** This static method returns a component from its identifier.
* @param id the component's identifier
*/
get: function (id) {
if (!Base.Comp.list.containsKey(id)) {
return null;
}
return Base.Comp.list.get(id);
},
/** This static method destroys all of the components.
*/
onUnload: function () {
var l = Base.Comp.list.values();
for (var i in l) {
if (l[i] && l[i].destroy) {
l[i].destroy();
}
}
Base.Comp.list.clear();
}
});