| 2 | | create: function() { |
|---|
| 3 | | return function() { |
|---|
| 4 | | this.initialize.apply(this, arguments); |
|---|
| | 2 | |
|---|
| | 3 | // You'll definitely want to check out |
|---|
| | 4 | // http://groupspace.org/devben/proto-svn/demo/ |
|---|
| | 5 | // to get a mile-high understanding of why I |
|---|
| | 6 | // bothered with all of this. |
|---|
| | 7 | |
|---|
| | 8 | NAME: "Class", |
|---|
| | 9 | VERSION: Prototype.Version || 2.0, |
|---|
| | 10 | // put your name here if you've helped in any way! |
|---|
| | 11 | AUTHORS: "Ben Newman (of groupspace.org), et al.", |
|---|
| | 12 | |
|---|
| | 13 | __repr__: function() { |
|---|
| | 14 | return "[" + this.NAME + " " + this.VERSION + "]"; |
|---|
| | 15 | }, |
|---|
| | 16 | |
|---|
| | 17 | toString: function() { |
|---|
| | 18 | return this.__repr__(); |
|---|
| | 19 | }, |
|---|
| | 20 | |
|---|
| | 21 | _doNotInit: {}, |
|---|
| | 22 | |
|---|
| | 23 | create: function(declarations) { |
|---|
| | 24 | |
|---|
| | 25 | var ctor = function() { |
|---|
| | 26 | if (arguments[0] !== Class._doNotInit && this.initialize) |
|---|
| | 27 | this.initialize.apply(this, arguments); |
|---|
| | 28 | }; |
|---|
| | 29 | |
|---|
| | 30 | if (declarations) { |
|---|
| | 31 | var ownPrototype = function() { |
|---|
| | 32 | for (var i in declarations) |
|---|
| | 33 | Class._attachClassProperty(i, declarations[i], this); |
|---|
| | 34 | Class._ensureDefaults(this, declarations); |
|---|
| | 35 | }; |
|---|
| | 36 | |
|---|
| | 37 | if (declarations.extending) { |
|---|
| | 38 | var parentPrototype = Class._inherit(ownPrototype, declarations.extending); |
|---|
| | 39 | declarations['sup'] = Class._makeSup(parentPrototype); |
|---|
| | 40 | } |
|---|
| | 41 | |
|---|
| | 42 | Class._inherit(ctor, ownPrototype); |
|---|
| | 44 | |
|---|
| | 45 | return ctor; |
|---|
| | 46 | }, |
|---|
| | 47 | |
|---|
| | 48 | _attachClassProperty: function(propName, prop, ownPrototype) { |
|---|
| | 49 | ownPrototype[propName] = prop; |
|---|
| | 50 | if (typeof(prop) == 'function') |
|---|
| | 51 | Class._addStackLogic(ownPrototype, propName); |
|---|
| | 52 | }, |
|---|
| | 53 | |
|---|
| | 54 | _setUpAndHideCallStack: function() { |
|---|
| | 55 | |
|---|
| | 56 | var __callStack = []; // stores [function-name, receiver] pairs |
|---|
| | 57 | |
|---|
| | 58 | Class._lastOnCallStack = function() { |
|---|
| | 59 | if (__callStack.length == 0) return ['', null]; |
|---|
| | 60 | else return __callStack[__callStack.length - 1]; |
|---|
| | 61 | }; |
|---|
| | 62 | |
|---|
| | 63 | Class._addStackLogic = function(obj, fnName) { |
|---|
| | 64 | switch (fnName) { |
|---|
| | 65 | case 'sup': |
|---|
| | 66 | case 'toString': |
|---|
| | 67 | case 'valueOf': return; |
|---|
| | 68 | default: |
|---|
| | 69 | var __func = obj[fnName]; |
|---|
| | 70 | obj[fnName] = function() { |
|---|
| | 71 | var lastRef = Class._refOfLastCallingObject(); |
|---|
| | 72 | if (Class.followsPrivateNamingConvention(fnName) && |
|---|
| | 73 | (lastRef || {}).constructor !== this.constructor) { |
|---|
| | 74 | Class.privateCallError(fnName); |
|---|
| | 75 | } else { |
|---|
| | 76 | __callStack.push([fnName, this]); |
|---|
| | 77 | var result = __func.apply(this, arguments); |
|---|
| | 78 | __callStack.pop(); |
|---|
| | 79 | return result; |
|---|
| | 80 | } |
|---|
| | 81 | }; |
|---|
| | 82 | } |
|---|
| | 83 | }; |
|---|
| | 84 | |
|---|
| | 85 | Class._grant = function(obj) { |
|---|
| | 86 | var __func = this; |
|---|
| | 87 | var __callStackMemory = Class._lastOnCallStack(); |
|---|
| | 88 | return function() { |
|---|
| | 89 | __callStack.push(__callStackMemory); |
|---|
| | 90 | var result = __func.apply(obj || this, arguments); |
|---|
| | 91 | __callStack.pop(); |
|---|
| | 92 | return result; |
|---|
| | 93 | } |
|---|
| | 94 | } |
|---|
| | 95 | |
|---|
| | 96 | // this function commits seppuku |
|---|
| | 97 | Class._setUpAndHideCallStack = undefined; |
|---|
| | 98 | |
|---|
| | 99 | }, // ends: _setUpAndHideCallStack |
|---|
| | 100 | |
|---|
| | 101 | _nameOfLastCalledMethod: function() { |
|---|
| | 102 | return Class._lastOnCallStack()[0]; |
|---|
| | 103 | }, |
|---|
| | 104 | |
|---|
| | 105 | _refOfLastCallingObject: function() { |
|---|
| | 106 | return Class._lastOnCallStack()[1]; |
|---|
| | 107 | }, |
|---|
| | 108 | |
|---|
| | 109 | // change this at will |
|---|
| | 110 | followsPrivateNamingConvention: function(propName) { |
|---|
| | 111 | return propName.charAt(0) == '_'; |
|---|
| | 112 | }, |
|---|
| | 113 | |
|---|
| | 114 | privateCallError: function(fnName) { |
|---|
| | 115 | alert("Error: Tried to access private member " + fnName + |
|---|
| | 116 | " from from non-member method " + |
|---|
| | 117 | Class._nameOfLastCalledMethod()); |
|---|
| | 118 | }, |
|---|
| | 119 | |
|---|
| | 120 | _ensureDefaults: function(ownPrototype, declarations) { |
|---|
| | 121 | ['toString', |
|---|
| | 122 | 'toLocaleString', |
|---|
| | 123 | 'valueOf'].each(function(prop) { |
|---|
| | 124 | if (declarations[prop]) { |
|---|
| | 125 | Class._attachClassProperty(prop, declarations[prop], ownPrototype); |
|---|
| | 126 | } |
|---|
| | 127 | }); |
|---|
| | 128 | |
|---|
| | 129 | // see whether property was implemented by *this* class |
|---|
| | 130 | ownPrototype.ownPrototypeHas = function(property) { |
|---|
| | 131 | return (typeof(declarations[property]) != 'undefined'); |
|---|
| | 132 | } |
|---|
| | 133 | }, |
|---|
| | 134 | |
|---|
| | 135 | _makeSup: function(parentPrototype) { |
|---|
| | 136 | Class._skipOver = false; |
|---|
| | 137 | |
|---|
| | 138 | return function() { |
|---|
| | 139 | var origin = Class._nameOfLastCalledMethod(); |
|---|
| | 140 | |
|---|
| | 141 | if (!Class._skipOver && !this.ownPrototypeHas(origin) && |
|---|
| | 142 | parentPrototype.sup && !parentPrototype.ownPrototypeHas(origin)) { |
|---|
| | 143 | return parentPrototype.sup.apply(this, arguments); |
|---|
| | 144 | } |
|---|
| | 145 | |
|---|
| | 146 | if (parentPrototype.sup && !Class._skipOver) { |
|---|
| | 147 | Class._skipOver = true; // skip this test next time |
|---|
| | 148 | return parentPrototype.sup.apply(this, arguments); |
|---|
| | 149 | } |
|---|
| | 150 | |
|---|
| | 151 | Class._skipOver = false; |
|---|
| | 152 | |
|---|
| | 153 | var args = $A(arguments); |
|---|
| | 154 | with (this.sup = parentPrototype.sup || this.sup) |
|---|
| | 155 | return parentPrototype[origin].apply(this, args); |
|---|
| | 156 | }; |
|---|
| | 157 | }, |
|---|
| | 158 | |
|---|
| | 159 | encap: function(__val, mutable) { |
|---|
| | 160 | if (!mutable) return function() { return __val; } |
|---|
| | 161 | else return function(/* optional new value */) { |
|---|
| | 162 | if (arguments.length > 0) __val = arguments[0]; |
|---|
| | 163 | return __val; |
|---|
| | 164 | } |
|---|
| | 165 | }, |
|---|
| | 166 | |
|---|
| | 167 | // superclass can be a constructor function or an existing object |
|---|
| | 168 | _inherit: function(subclass, superclass) { |
|---|
| | 169 | if (typeof(superclass) == 'function') { |
|---|
| | 170 | superclass.getInstance = superclass.getInstance || |
|---|
| | 171 | Class.encap(new superclass(Class._doNotInit)); |
|---|
| | 172 | subclass.prototype = superclass.getInstance(); |
|---|
| | 173 | } else if (typeof(superclass) == 'object') |
|---|
| | 174 | subclass.prototype = superclass; |
|---|
| | 175 | return subclass.prototype; |
|---|