JSClass.js

/**
 * I'm not sure how this differs from classmanager or which came first.
 *
 * I'm guessing this came first
 */

function JSClass(declaration, closure) {  
  if (JSClass.processor.verify(declaration,closure)!==true)return;
  JSClass.processor.addToWindow(declaration,closure);
}
JSClass.processor = {
    staticDomId: 0,
    allObjects: [],
    getClassName: function(declaration){
      //assumes that declaration has been verified
      if (declaration.indexOf("extends") != -1) {
        var parts = declaration.split("extends");
        className = parts[0].trim();
      } else {
        className = declaration.trim();
      }
      return className;
    },
    getParentClassName: function(declaration){
      //assumes that declaration has been verified
      if (declaration.indexOf("extends") != -1) {
        var parts = declaration.split("extends");
        parentClassName = parts[1].trim();
        return parentClassName;
      } else {
        return null;
      }
    },
    verify: function(declaration, closure) {
      var errorNotice = "\nProblem declaration is '" + declaration + "'. \n";
      var errorTips =
        "Proper declaration is JSClass('MyClass',function(){BODY}). \n" +
        "To extend, try JSClass('MyClass extends ParentClass',function(){BODY}).";
      var className;
      var parentClassName;
      var functype = typeof function() {};
      //set and derive the class name and parent class name, checking for syntax errors
      //make sure the closure is a function
      if (typeof closure != functype) {
        console.log(
          "closure must be a function. See JSClass(name,closure). " +
            errorNotice +
            errorTips
        );
      }
      if (declaration.indexOf("extends") != -1) {
        var parts = declaration.split("extends");
        if (parts.length != 2) {
          console.log(
            "You can only declare one extends. " + errorNotice + errorTips
          );
          return false;
        }
        className = parts[0].trim();
        parentClassName = parts[1].trim();

        if (parentClassName.length < 1) {
          console.log(
            "If using 'extends', Parent Class Name must not be empty. " +
              errorNotice +
              errorTips
          );
          return false;
        }
        if (parentClassName.indexOf(" ") != -1) {
          console.log(
            "Parent class name must not contain any spaces. " +
              errorNotice +
              errorTips
          );
          return false;
        }
      } else {
        className = declaration.trim();
      }

      if (className.length < 1) {
        console.log("Class name cannot be empty. " + errorNotice + errorTips);
        return false;
      }
      if (className.indexOf(" ") != -1) {
        console.log(
          "Class name must not contain any spaces. " + errorNotice + errorTips
        );
        return false;
      }
      //className and parentClassName are valid.
      //parentClassName may be null, if not extending
      return true;
    },
    addToWindow: function(declaration,closure){
      var closureWrapper = function(){
        JSClass.processor.allObjects.push(this);
        JSClass.processor.instantiate.call(this,declaration,closure);
        if ('construct' in this){
          this.construct.apply(this,arguments);
        }
      };
      this.applyStaticParamaters(declaration,closure,closureWrapper);
      window[this.getClassName(declaration)] = closureWrapper;
    },
    applyStaticParamaters: function(declaration,closure,closureWrapper){
      closure.prototype.static = {};
      var obj = new closure();
      for (var staticVar in obj.static){
        closureWrapper[staticVar] = obj.static[staticVar];
      }
      return obj;
    },
    instantiate: function(declaration, closure){
      //this refers to the object that is being created
      closure.prototype.static = window[JSClass.processor.getClassName(declaration)];
      closure.prototype.dom = {};
      
      var parentName = JSClass.processor.getParentClassName(declaration);
      if (parentName!=null){
        JSClass.processor.extendClass.call(this,parentName);
      }
      closure.apply(this);//
      // var obj = new closure();
      // for (var propName in obj){
      //   this[propName] = obj[propName];
      // }
    },
    extendClass: function(parentName){
      if (!(parentName in window)){
        console.log("Class '"+parentName+"' does not exist, so it cannot be extended.");
        return;
      }
      window[parentName].apply(this);
      var newObj = function(){};
      this.parent = this;
      window[parentName].apply(this.parent);
      var funcType = typeof function(){};
      for (var propName in this.parent){
          if ((typeof this.parent[propName])!==funcType
             &&propName in this
             &&propName in this.parent){
            console.log("overwrite "+propName);
            this.parent[propName] = this[propName];
          }
      }
    },
    getElements: function(){
      var nodeList = document.getElementsByClassName("jsclass");
      var node;
      var elements = [];
      for (var i=0;i<nodeList.length;i++){
        node = nodeList[i];
        elements.push(node);
      }
      return elements;
    },
    getJSClassFromElement: function(element){
      var classList = element.classList;
      for (var z=0;z<classList.length;z++){
          var classListName=classList[z];
          if (classListName.indexOf("jsclass-")===0){
            var className = classListName.substring(8);
            if (!(className in window)){
              console.log("Class '"+className+"' has not been declared in javascript");
              return null;
            }
            return className;
          }
        }
    },
    attachClassToElement: function(element){
        var className = JSClass.processor.getJSClassFromElement(element);
        if (className===null){
          console.log("Classname was null for element:");
          console.log(element);
          return;
        }
        if (!(className in window)){
          console.log("class '"+className+"' does not exist.");
        }
        var obj = new window[className]();
        obj.dom = element;
        element.jsclass = obj;
        obj.attach.call(obj,element);
    },
    attachClassesToDom: function(){
      var elements = JSClass.processor.getElements();
      for (var i=0; i<elements.length;i++){
        var element = elements[i];
        JSClass.processor.attachClassToElement(element);
      }
    },
    setEventListener: function(){
      if (window.readyState == "complete") {
        JSClass.processor.attachClassesToDom();
      } else if (window.addEventListener != null) {
        document.addEventListener("DOMContentLoaded", function() {
          if (document.readyState=="interactive"){
            JSClass.processor.attachClassesToDom();
          }
        });
      } else {
        window.onload = function() {
              JSClass.processor.attachClassesToDom();
        };
      }

    }
  };
JSClass.processor.setEventListener();