The code that is generated from the interface builder which supports this looked pretty much like this.
Pman.on('beforeload', function()
{
Pman.register({
modKey : '500-Pman.Tab.Cash', // the order to build it..
module : Pman.Tab.Cash,
region : 'center',
parent : Pman, // where it should be added to..
name : "Cash",
disabled : false,
permname: ''
});
});
This registration event on Pman's before load listener was done originally to handle the situation that Parent, and module, may have not been defined by the stage at which registration occured.
The body of the component looked like this
Pman.Tab.Cash = new Roo.util.Observable({
panel : false,
disabled : false,
parentLayout: false,
add : function(parentLayout, region)
{
var _this = this;
this.parentLayout = parentLayout;
this.panel = parentLayout.addxtype({
... the js tree that makes the interface goes here.
});
this.layout = this.panel.layout;
}
});
This would be a typical tab on the interface, there was a method that looped through all the registered components and called that 'add' method with the correct parameters.
Having developed this for the Pman project, some time later I also needed to apply the similar concept to non-Pman projects, like the original web.mtrack code, and a few other projects where I wanted to use 'Component'ized code with plain old HTML. To solve this, I recreated most of the original logic from the Pman builder into a Class Called Roo.XComponent. The design implementation for this was considerably simpler, it learned the lessons from the first effort in Pman and improved on it.
Again the code is generally expected to be auto generated by an interface builder, but it can be hand coded..
The non-tree part looks pretty much like this..
Pman.Tab.MTrackTimeline = new Roo.XComponent({
part : ["MTrack","Timeline"],
order : 300,
region : 'center',
parent : 'Pman.Tab.DocumentsTab',
name : "unnamed module",
disabled : false,
permname : '',
_tree : function()
{
var _this = this;
var MODULE = this;
return {
... the js tree that makes the interface goes here ...
};
}
});
In this design, the constructor of XComponent registers the new component in XComponent.modules[] along with doing the universal contructor technique of applying all properties to the new Object instance. In this example parent is the name of another component, however if you use '#some-div' as the parent, the code will be rendered to a id="some-div" component if it exists.
This shows that by this time, the resolution of parent to a Javscript property is done a build time, so it does not matter what sequence these files are loaded.
If you are building a HTML application with Roo interface elements, you can now include all the Javascript files (compressed) on every page, marginally slower on first page load, but fast in the long run. Then if the element matching the '#id' is found it will render the required components into the page.
So to actually make the rendering occur you would do something like this.
Roo.onReady(function() {
Roo.XComponent.build();
});
In the Pman project, this build occurs after the login has been checked, along with this, since the Pman project does a few things after the rendering occurs, it also registers a handler for the build complete event:
Roo.XComponent.on('buildcomplete', function() { ... do some more stuff. });
I have now added code to Pman which supports both methods, it actually converts the 'old style' components into new XComponents, when registred in the old system. So that all the real building code is now done in the core Roo.XComponent class. There is also some code in Pman, that is used to decide if the system should render the user interface based on the user permissions in the Pman system.
app.Builder.js the interface / application builder
Having got this far, one of the few remaining bastions of pre-XComponent code was the application builder. That as mentioned on the blog before, is a wrapper around the Gtk Webkit widget, that includes the Webkit introspection debugger (the one you get with Ctrl-Shift-J). And all the tools to manipulate the interface and write the javascript event handler code.
The actual building code in the builder however has been very dated, and relyed on passing the JSON array into the webkit browser and rebuilding on the fly. In some respects this code duplicated a large part the code that writes the Javascript from the JSON code. This technique had some serious drawbacks however.
Bugs in the code to be rendered was always difficult to track down. As there was no real source code (it was all injected as a method call), whenever a variable was undefined, you got the exception, without any idea of where in the codebase it may be occuring. You could see the backtrack in the inspector, but it did not have much information..
Although the components are frequently quite small, the end result was that if the interface failed to render, you would either end up running the full application in a browser (slow), or just quickly opening the generated Javascript file and searching for the problematic code.
To solve all of this, I came up with the idea to actually generating a HTML page that includes the
Roo.XComponent code above. This now means that any error that occurs shows you the exact line in the Introspector of where the error occurs, and shows you the source code that the builder generates.
The only downside is that it currently breaks the code that was originally in there to highlight selected nodes and any code that would have allowed drag drop into the rendered view. However since most of that code was already broken, and dragging in the tree has been the way I've been working for years now. It's not a great loss, and a project for another day..