jdom.js

var manager = new function(){
    
    var pending = [];
    
    this.setThisArg = function(thisArg,func){
        var newProp = function(){
                        func.apply(thisArg,arguments);
                    };
        newProp.isThisWrapped = true;
        return newProp;
    }
    this.construct = function(){
        var className = arguments.shift();
        
        //within this code block, 'this' refers to the new instance being created
        var parent = window[className].prototype;
        var hierarchy = [];
        
        while ((typeof parent)=='function'){
            hierarchy.push(parent);
            if ('parent' in parent){
                   parent = parent.parent;
            }
        }
        hierarchy.reverse();
        for (clazz in hierarchy){
            clazz.apply(this,arguments);
        }
        window[className].apply(this,arguments);
        for (var propName in this){
            
            var oldProp = this[propName];
            if ((typeof oldProp)==typeof(function(){})){
                var newProp = manager.setThisArg(this,oldProp);
                
                this[propName] = newProp;
            } 
        }
    }
    /** closure is a function, not an object.
    *  ie, in this sample code, closure is a function 
    *       var closure = function(){};
    *  and in this sample code, instance is an object
    *       var instance = new closure();
    *  The first example (closure) is what should be passed in
    */
    this.Class = function(className,instanceClosure,staticClosure){

        var constructor = function(){
            var className = this.className;
            var func = window[this.className];
            if (func==undefined){
                console.log(this.className);
            } else if ('prototype' in func
                &&'parent' in func.prototype
                &&typeof func.prototype.parent == typeof 'string'){
                var parentClassName = func.prototype.parent
                parent = window[parentClassName];
                this.className = parentClassName;
                parent.apply(this,[]);
                this.className = className;
                var parentObj = new function(){};
                manager.apply(parentObj,this);
                parentObj.className = func.prototype.parent;
                this.parent = parentObj;
            }
            func.instance.apply(this,[]);
            if (typeof this.parent==typeof 'string'){
                this.parent = undefined;
            }
            if ('construct' in this &&typeof this.construct == typeof function(){}){
                this.construct.apply(this,arguments);
            }
        };
        constructor.prototype.className = className;  
        constructor.instance = instanceClosure;
        //static extend
        constructor.Extend = function(className){
            constructor.prototype.parent = className;
        }
        if (typeof staticClosure == typeof constructor)
            manager.apply(constructor,new staticClosure());
      
        window[className] = constructor;
        return constructor;
    }
    this.apply = function(object,instantiatedFunction){
        for (var propName in instantiatedFunction){
            if (propName in object){
                console.log('yes');
                if (!('parent' in object)||object.parent==null)object.parent = function(){};
                object.parent[propName] = instantiatedFunction[propName];
            } else {
               object[propName] = instantiatedFunction[propName]; 
            }
        }
    }
    this.setThisRecursive = function(thisArg,fromObject){
        for (propName in fromObject){
            if ((typeof fromObject[propName]) === (typeof new function(){})){
                manager.setThisRecursive(thisArg,fromObject[propName]);
              //  console.log('recursive thisify '+propName+ ' which has type '+(typeof fromObject[propName]));
            } else if ((typeof fromObject[propName]) === (typeof function(){})){
             //   console.log('thisify '+propName);
                fromObject[propName] = manager.setThisArg(thisArg,fromObject[propName]);
            } else {
             //   console.log('no thisify '+propName+ ' which has type '+(typeof fromObject[propName]));
            }
        }
    }
    this.override = function(child,parent,thisArg){
            for (propName in parent){
            //console.log('propName is type: '+typeof parent[propName]);
            
            // console.log('setRaw for '+propName+' with type '+typeof parent[propName]); 
             child[propName] = parent[propName]; 
                if (typeof child[propName]=== (typeof new function(){}) ){
                    console.log('setFunc', 'also');
                    manager.setThisRecursive(thisArg,child[propName]);
                }
            }
        child.parent = parent;
    }
    this.setClasses = function(rootElement) {
      if (rootElement==null)rootElement = document.body;
     var elementList = rootElement.getElementsByClassName('jdom');
     var funcType = typeof new function() {};
     if (elementList.length==0)return;
     for (var i = 0; i < elementList.length; i++) {
       var element = elementList[i];
       var parts = element.className.split("jdom")[1].trim();

       var clazz = parts.split(" ")[0];
       if (clazz in window)
         var newInstance = new window[clazz]();
       else {
         console.log("Error: class " + clazz + " is not defined");
         return;
       }
       manager.override(element, newInstance, element);


       if ('attach' in element &&
         typeof element['attach'] == typeof
         function() {})
         element.attach();
     }
     manager.setClasses();
   }
   }


if (window.loaded == 'complete'){
	manager.setClasses();
} else if (window.addEventListener != null){
		document.addEventListener('DOMContentLoaded',function(){
			manager.setClasses();
		});
} else {
	var oldLoad = window.onload;
	window.onload = function(){
		if (oldLoad!=null)oldLoad();
		manager.setClasses();
	}
}