/* * todos: * - Performance metrics against techniques http://www.ajaxpath.com/javascript-inheritance (DONE) * - Support for imports/using/requires other classes. (DONE) * - Dynamically loading classes? - Not going to add this unless we really need it. ScriptsCache/ScriptsManager is the loader of choice * - Should this remain prototyped onto Function? Should I create my own base class? - Yes (DONE) * - get rid of reserved words (super, extends) as they cause problems in IE. (DONE) */ Function.getClassName = function() { return "Function"; }; /* Extend from another prototyped Function */ Function.prototype.Extend = function(superClass) { this.prototype = new superClass(); this.prototype.getSuperClass = function() { return superClass; }; this.getSuperClass = this.prototype.getSuperClass; return this; }; /* The Super method allows us to do the constructor (or any super call) chaining more easily. It looks like this: var A = function() { this.value = ["1"] } var B = function() { B.Super(this); this.value.push("2"); } Super calls for non constructor methods look like: Class.Super(this, "methodName", arguments); */ Function.prototype.Super = function(context, methodName, args) { if (null != methodName) { var method = this.getSuperClass().prototype[methodName]; } else { var method = this.getSuperClass(); } if (!args) { return method.call(context); } else { return method.apply(context, args); } }; /* Function.Implements It takes either an instanciated object or a functor, and a list of properties/methods and add them to the calling functor. Be careful not to apply methods that call other methods/object in the passed functor/object that do not exist in the calling functor. */ Function.prototype.Implements = function(obj, members) { if(typeof obj == "function") { obj = obj.prototype; } var tObj = {} for(var i = 0, len = members.length; i < len; ++i) { tObj[members[i]] = obj[members[i]] || null; } var o = WSDOM.Util.copyObject(tObj); for(var i in o) { this.prototype[i] = o[i]; } }; /* Used to be 'hitch'. Now it works right. */ Function.prototype.Context = function(obj) { var fnReference = this; return function () { return typeof fnReference == "function" ? fnReference.apply(obj, arguments) : obj[fnReference].apply(obj, arguments); }; }; Function.prototype.EmptyFunction = function() {}; WSDOM = new function() { var loadedClasses = {}; var usingReferences = []; this.defineClass = function(className, superClass, constructor) { loadedClasses[className] = constructor; if (null != superClass) { loadedClasses[className].Extend(superClass); } // both classes and instances should have references to their names loadedClasses[className].prototype.getClassName = function() { return className; }; loadedClasses[className].getClassName = loadedClasses[className].prototype.getClassName; return loadedClasses[className]; }; this.loadClass = function(className) { var classDef = parseClassName(className); var o = this.getClass(classDef.className); if (o) { this[o.getClassName()] = o; this[o.getClassName()].prototype.namespace = classDef.namespace; this[o.getClassName()].prototype.version = classDef.version; }; }; this.loadSingleton = function(className) { var classDef = parseClassName(className); var o = this.getClass(classDef.className); if (o) { this[o.getClassName()] = new o(); this[o.getClassName()].namespace = classDef.namespace; this[o.getClassName()].version = classDef.version; }; }; this.getClass = function(className) { return loadedClasses[className]; }; this.getLoadedClasses = function() { return loadedClasses; }; this.using = function(originatingClassName, className) { usingReferences.push({originatingClassName:originatingClassName, className:className}); } this._processUsingReferences = function() { var usingErrors = false; for (var x = 0; x < usingReferences.length; x++) { var originatingClassName = usingReferences[x].originatingClassName; var className = usingReferences[x].className; var classDef = parseClassName(className); if (!this[classDef.className]) { if (this.Console) { this.Console.warn("Missing class definition for " + className + ". Called from " + originatingClassName + "."); }; usingErrors = true; } else if (this[classDef.className].version != classDef.version) { if (this.Console) { this.Console.warn("Version incompatibility for loaded class, " + classDef.className + "." + this[classDef.className].version + ", versus requested class, version " + classDef.version + ". Called from " + originatingClassName + "."); }; usingErrors = false; }; }; if (!usingErrors) { this.Console.log("WSDOM Framework loaded successfully."); }; }; /* Light-weight 'onload' for management of 'using' statements */ this._onload = function() { var element = window; var eventType = "load"; var fnHandler = this._processUsingReferences.Context(this); if (element.addEventListener) { // firefox element.addEventListener(eventType, fnHandler, false); } else if (element.attachEvent) { // ie element.attachEvent("on" + eventType, fnHandler); }; }; this._onload(); function parseClassName(className) { var tokens = className.split('.'); var classDef = { namespace:tokens[0], className:tokens[1], version:tokens[2] }; return classDef; }; this.identity = function(x) { return x }; }(); WSDOM.using("WSDOM", "WSDOM.Console.1");