218 lines
5.8 KiB
JavaScript
218 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();
|
||
|
}
|
||
|
});
|