| 1 | | var Class = { |
|---|
| 2 | | create: function() { |
|---|
| 3 | | return function() { |
|---|
| 4 | | this.initialize.apply(this, arguments); |
|---|
| | 1 | var Class = new (function(vocab) { |
|---|
| | 2 | |
|---|
| | 3 | this.AUTHOR = "Ben Newman (newmanb@stanford.edu)"; |
|---|
| | 4 | |
|---|
| | 5 | var $doNotInit = {}; |
|---|
| | 6 | |
|---|
| | 7 | this.create = function(declarations) { |
|---|
| | 8 | |
|---|
| | 9 | var constructor = function() { |
|---|
| | 10 | if (arguments[0] !== $doNotInit && this[vocab['init']]) |
|---|
| | 11 | this[vocab['init']].apply(this, arguments); |
|---|
| | 12 | }; |
|---|
| | 13 | |
|---|
| | 14 | if (declarations) { |
|---|
| | 15 | var ownPrototype = function() { |
|---|
| | 16 | for (var name in declarations) { |
|---|
| | 17 | declarations[name].ancestor = baseInstance[name]; |
|---|
| | 18 | __attachClassProperty(name, declarations[name], this); |
|---|
| | 19 | } |
|---|
| | 20 | __ensureDefaults(this, declarations); |
|---|
| | 21 | }; |
|---|
| | 22 | |
|---|
| | 23 | var base = declarations.extending || {}; |
|---|
| | 24 | var baseInstance = __inherit(ownPrototype, base); |
|---|
| | 25 | |
|---|
| | 26 | __setupAttachDelete(declarations); |
|---|
| | 27 | __inherit(constructor, ownPrototype); |
|---|
| | 28 | __enableMimicry(constructor); // experimental |
|---|
| | 29 | |
|---|
| | 30 | constructor['extend'] = function(declarations) { |
|---|
| | 31 | declarations['extending'] = constructor; |
|---|
| | 32 | return Class.create(declarations); |
|---|
| | 33 | } // a la Dean Edwards' Base.js |
|---|
| | 35 | |
|---|
| | 36 | return constructor; |
|---|
| | 37 | }; |
|---|
| | 38 | |
|---|
| | 39 | var __enableMimicry = function(__ctor) { |
|---|
| | 40 | var __old = __ctor.prototype; |
|---|
| | 41 | __ctor['mimic'] = function(obj) { |
|---|
| | 42 | var __new = Object.extend(obj, __old); |
|---|
| | 43 | __ensureDefaults(__new, __old); |
|---|
| | 44 | return Object.extend(function() { |
|---|
| | 45 | return __ctor.apply(this, arguments); |
|---|
| | 46 | }, { 'prototype': __new }); |
|---|
| | 47 | }; |
|---|
| | 48 | }; |
|---|
| | 49 | |
|---|
| | 50 | var __inherit = function(subclass, superclass) { |
|---|
| | 51 | switch (typeof(superclass)) { |
|---|
| | 52 | case 'object': default: |
|---|
| | 53 | superclass[vocab['init']] = superclass.constructor; |
|---|
| | 54 | subclass.prototype = superclass; break; |
|---|
| | 55 | case 'function': |
|---|
| | 56 | superclass.getInstance = superclass.getInstance || |
|---|
| | 57 | Class.encap(new superclass($doNotInit)); |
|---|
| | 58 | subclass.prototype = superclass.getInstance(); |
|---|
| | 59 | } |
|---|
| | 60 | return subclass.prototype; |
|---|
| | 61 | }; |
|---|
| | 62 | |
|---|
| | 63 | var __setupAttachDelete = function(declarations) { |
|---|
| | 64 | return Object.extend(declarations, { |
|---|
| | 65 | 'attachMethod': function(fnName, func) { |
|---|
| | 66 | func.ancestor = this[fnName]; |
|---|
| | 67 | __attachClassProperty(fnName, func, this); |
|---|
| | 68 | }, |
|---|
| | 69 | 'deleteMethod': function(fnName) { |
|---|
| | 70 | delete this[fnName]; |
|---|
| | 71 | } |
|---|
| | 72 | }); |
|---|
| | 73 | }; |
|---|
| | 74 | |
|---|
| | 75 | var __validOverride = function(propName) { |
|---|
| | 76 | switch (propName) { |
|---|
| | 77 | case vocab['super']: case 'valueOf': |
|---|
| | 78 | case 'attachMethod': case 'deleteMethod': |
|---|
| | 79 | case 'getBaseInstance': return false; |
|---|
| | 80 | default: return true; |
|---|
| | 81 | } |
|---|
| | 82 | }; |
|---|
| | 83 | |
|---|
| | 84 | // last receiving object |
|---|
| | 85 | var __context = window; |
|---|
| | 86 | |
|---|
| | 87 | var __attachClassProperty = function(propName, prop, obj) { |
|---|
| | 88 | |
|---|
| | 89 | if (typeof(obj[propName] = prop) == 'function') { |
|---|
| | 90 | |
|---|
| | 91 | if (__validOverride(propName)) { |
|---|
| | 92 | var __ancestor = prop.ancestor; |
|---|
| | 93 | |
|---|
| | 94 | obj[propName] = function() { |
|---|
| | 95 | __ensurePrivacy(propName, this); // optional |
|---|
| | 96 | // save this object reference globally |
|---|
| | 97 | var __savedContext = __context; |
|---|
| | 98 | __context = this; |
|---|
| | 99 | // save the current version of the super function |
|---|
| | 100 | var __superSaver = this[vocab['super']]; |
|---|
| | 101 | this[vocab['super']] = __ancestor; |
|---|
| | 102 | |
|---|
| | 103 | try { var result = prop.apply(this, arguments); } |
|---|
| | 104 | catch (ex) { throw ex; } |
|---|
| | 105 | finally { // restore super and object reference |
|---|
| | 106 | this[vocab['super']] = __superSaver; |
|---|
| | 107 | __context = __savedContext; |
|---|
| | 108 | } |
|---|
| | 109 | return result; |
|---|
| | 110 | }; |
|---|
| | 111 | |
|---|
| | 112 | obj[propName].valueOf = Class.encap(prop); |
|---|
| | 113 | } |
|---|
| | 114 | |
|---|
| | 115 | var __origStr = prop.toString(); |
|---|
| | 116 | prop.toString = obj[propName].toString = function() { |
|---|
| | 117 | return __origStr.replace(/^\s*function/, propName); |
|---|
| | 118 | }; |
|---|
| | 119 | } |
|---|
| | 120 | }; |
|---|
| | 121 | |
|---|
| | 122 | var __ensurePrivacy = function(propName, obj) { |
|---|
| | 123 | if ((!__context || obj.constructor !== __context.constructor) |
|---|
| | 124 | && propName[0] == '_') // private naming convention |
|---|
| | 125 | alert("Tried to call private method " + propName + |
|---|
| | 126 | " from foreign object " + __context + "."); |
|---|
| | 129 | // all the functionality of bind(), plus context-sensitivity |
|---|
| | 130 | Function.prototype.grant = function(obj) { |
|---|
| | 131 | var __func = this; |
|---|
| | 132 | var __originalContext = __context; |
|---|
| | 133 | return function() { |
|---|
| | 134 | __savedContext = __context; |
|---|
| | 135 | __context = __originalContext; |
|---|
| | 136 | try { var result = |
|---|
| | 137 | __func.apply(obj || this, arguments); } |
|---|
| | 138 | catch (ex) { throw ex; } |
|---|
| | 139 | finally { __context = __savedContext; } |
|---|
| | 140 | return result; |
|---|
| | 141 | } |
|---|
| | 142 | }; |
|---|
| | 143 | |
|---|
| | 144 | var __ensureDefaults = function(ownPrototype, declarations) { |
|---|
| | 145 | ['toString', 'toLocaleString', 'valueOf'].each(function(propName) { |
|---|
| | 146 | var prop = declarations[propName]; |
|---|
| | 147 | if (!!prop) { |
|---|
| | 148 | prop.ancestor = ownPrototype[propName]; |
|---|
| | 149 | __attachClassProperty(propName, prop, ownPrototype); |
|---|
| | 150 | } |
|---|
| | 151 | }); |
|---|
| | 152 | }; |
|---|
| | 153 | |
|---|
| | 154 | // convenient mechanism for creating accessor functions |
|---|
| | 155 | this.encap = function(__val, mutable) { |
|---|
| | 156 | if (!mutable) return function() { return __val; } |
|---|
| | 157 | else return function(/* optional new value */) { |
|---|
| | 158 | if (arguments.length > 0) __val = arguments[0]; |
|---|
| | 159 | return __val; |
|---|
| | 160 | } |
|---|
| | 161 | }; |
|---|
| | 162 | |
|---|
| | 163 | })( // the vocabulary is arbitrary: |
|---|
| | 164 | {'super': 'sup', 'init': 'initialize'}); |
|---|
| | 165 | |
|---|