1 /**************************************************************************** 2 Copyright (c) 2010-2012 cocos2d-x.org 3 Copyright (c) 2008-2010 Ricardo Quesada 4 Copyright (c) 2011 Zynga Inc. 5 6 http://www.cocos2d-x.org 7 8 Permission is hereby granted, free of charge, to any person obtaining a copy 9 of this software and associated documentation files (the "Software"), to deal 10 in the Software without restriction, including without limitation the rights 11 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 copies of the Software, and to permit persons to whom the Software is 13 furnished to do so, subject to the following conditions: 14 15 The above copyright notice and this permission notice shall be included in 16 all copies or substantial portions of the Software. 17 18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 THE SOFTWARE. 25 ****************************************************************************/ 26 /* Managed JavaScript Inheritance 27 * Based on John Resig's Simple JavaScript Inheritance http://ejohn.org/blog/simple-javascript-inheritance/ 28 * MIT Licensed. 29 */ 30 31 /** 32 * @namespace 33 */ 34 var cc = cc || {}; 35 36 // 37 var ClassManager = { 38 id : (0|(Math.random()*998)), 39 40 instanceId : (0|(Math.random()*998)), 41 42 compileSuper : function(func, name, id){ 43 //make the func to a string 44 var str = func.toString(); 45 //find parameters 46 var pstart = str.indexOf('('); 47 var pend = str.indexOf(')'); 48 var params = str.substring(pstart+1, pend); 49 params = params.trim(); 50 51 //find function body 52 var bstart = str.indexOf('{'); 53 var bend = str.lastIndexOf('}'); 54 var str = str.substring(bstart+1, bend); 55 56 //now we have the content of the function, replace this._super 57 //find this._super 58 while(str.indexOf('this._super')!= -1) 59 { 60 var sp = str.indexOf('this._super'); 61 //find the first '(' from this._super) 62 var bp = str.indexOf('(', sp); 63 64 //find if we are passing params to super 65 var bbp = str.indexOf(')', bp); 66 var superParams = str.substring(bp+1, bbp); 67 superParams = superParams.trim(); 68 var coma = superParams? ',':''; 69 70 //replace this._super 71 str = str.substring(0, sp)+ 'ClassManager['+id+'].'+name+'.call(this'+coma+str.substring(bp+1); 72 } 73 return Function(params, str); 74 }, 75 76 getNewID : function(){ 77 return this.id++; 78 }, 79 80 getNewInstanceId : function(){ 81 return this.instanceId++; 82 } 83 }; 84 ClassManager.compileSuper.ClassManager = ClassManager; 85 86 (function () { 87 var initializing = false, fnTest = /\b_super\b/; 88 var config = cc.game.config; 89 var releaseMode = config[cc.game.CONFIG_KEY.classReleaseMode]; 90 if(releaseMode) { 91 console.log("release Mode"); 92 } 93 94 /** 95 * The base Class implementation (does nothing) 96 * @class 97 */ 98 cc.Class = function () { 99 }; 100 101 /** 102 * Create a new Class that inherits from this Class 103 * @param {object} prop 104 * @return {function} 105 */ 106 cc.Class.extend = function (prop) { 107 var _super = this.prototype; 108 109 // Instantiate a base Class (but only create the instance, 110 // don't run the init constructor) 111 var prototype = Object.create(_super); 112 113 var classId = ClassManager.getNewID(); 114 ClassManager[classId] = _super; 115 // Copy the properties over onto the new prototype. We make function 116 // properties non-eumerable as this makes typeof === 'function' check 117 // unneccessary in the for...in loop used 1) for generating Class() 118 // 2) for cc.clone and perhaps more. It is also required to make 119 // these function properties cacheable in Carakan. 120 var desc = { writable: true, enumerable: false, configurable: true }; 121 122 prototype.__instanceId = null; 123 124 // The dummy Class constructor 125 function Class() { 126 this.__instanceId = ClassManager.getNewInstanceId(); 127 // All construction is actually done in the init method 128 if (this.ctor) 129 this.ctor.apply(this, arguments); 130 } 131 132 Class.id = classId; 133 // desc = { writable: true, enumerable: false, configurable: true, 134 // value: XXX }; Again, we make this non-enumerable. 135 desc.value = classId; 136 Object.defineProperty(prototype, '__pid', desc); 137 138 // Populate our constructed prototype object 139 Class.prototype = prototype; 140 141 // Enforce the constructor to be what we expect 142 desc.value = Class; 143 Object.defineProperty(Class.prototype, 'constructor', desc); 144 145 // Copy getter/setter 146 this.__getters__ && (Class.__getters__ = cc.clone(this.__getters__)); 147 this.__setters__ && (Class.__setters__ = cc.clone(this.__setters__)); 148 149 for (var name in prop) { 150 var isFunc = (typeof prop[name] === "function"); 151 var override = (typeof _super[name] === "function"); 152 var hasSuperCall = fnTest.test(prop[name]); 153 154 if(releaseMode && isFunc && override && hasSuperCall) { 155 desc.value = ClassManager.compileSuper(prop[name], name, classId); 156 Object.defineProperty(prototype, name, desc); 157 } else if(isFunc && override && hasSuperCall){ 158 desc.value = (function (name, fn) { 159 return function () { 160 var tmp = this._super; 161 162 // Add a new ._super() method that is the same method 163 // but on the super-Class 164 this._super = _super[name]; 165 166 // The method only need to be bound temporarily, so we 167 // remove it when we're done executing 168 var ret = fn.apply(this, arguments); 169 this._super = tmp; 170 171 return ret; 172 }; 173 })(name, prop[name]); 174 Object.defineProperty(prototype, name, desc); 175 } else if(isFunc) { 176 desc.value = prop[name]; 177 Object.defineProperty(prototype, name, desc); 178 } else{ 179 prototype[name] = prop[name]; 180 } 181 182 if (isFunc) { 183 // Override registered getter/setter 184 var getter, setter, propertyName; 185 if( this.__getters__ && this.__getters__[name] ) { 186 propertyName = this.__getters__[name]; 187 for (var i in this.__setters__) { 188 if (this.__setters__[i] == propertyName) { 189 setter = i; 190 break; 191 } 192 } 193 cc.defineGetterSetter(prototype, propertyName, prop[name], prop[setter] ? prop[setter] : prototype[setter], name, setter); 194 } 195 if( this.__setters__ && this.__setters__[name] ) { 196 propertyName = this.__setters__[name]; 197 for (var i in this.__getters__) { 198 if (this.__getters__[i] == propertyName) { 199 getter = i; 200 break; 201 } 202 } 203 cc.defineGetterSetter(prototype, propertyName, prop[getter] ? prop[getter] : prototype[getter], prop[name], getter, name); 204 } 205 } 206 } 207 208 // And make this Class extendable 209 Class.extend = cc.Class.extend; 210 211 //add implementation method 212 Class.implement = function (prop) { 213 for (var name in prop) { 214 prototype[name] = prop[name]; 215 } 216 }; 217 return Class; 218 }; 219 220 Function.prototype.bind = Function.prototype.bind || function (bind) { 221 var self = this; 222 return function () { 223 var args = Array.prototype.slice.call(arguments); 224 return self.apply(bind || null, args); 225 }; 226 }; 227 228 })(); 229 230 // 231 // Another way to subclass: Using Google Closure. 232 // The following code was copied + pasted from goog.base / goog.inherits 233 // 234 cc.inherits = function (childCtor, parentCtor) { 235 function tempCtor() {} 236 tempCtor.prototype = parentCtor.prototype; 237 childCtor.superClass_ = parentCtor.prototype; 238 childCtor.prototype = new tempCtor(); 239 childCtor.prototype.constructor = childCtor; 240 241 // Copy "static" method, but doesn't generate subclasses. 242 // for( var i in parentCtor ) { 243 // childCtor[ i ] = parentCtor[ i ]; 244 // } 245 }; 246 cc.base = function(me, opt_methodName, var_args) { 247 var caller = arguments.callee.caller; 248 if (caller.superClass_) { 249 // This is a constructor. Call the superclass constructor. 250 ret = caller.superClass_.constructor.apply( me, Array.prototype.slice.call(arguments, 1)); 251 return ret; 252 } 253 254 var args = Array.prototype.slice.call(arguments, 2); 255 var foundCaller = false; 256 for (var ctor = me.constructor; ctor; ctor = ctor.superClass_ && ctor.superClass_.constructor) { 257 if (ctor.prototype[opt_methodName] === caller) { 258 foundCaller = true; 259 } else if (foundCaller) { 260 return ctor.prototype[opt_methodName].apply(me, args); 261 } 262 } 263 264 // If we did not find the caller in the prototype chain, 265 // then one of two things happened: 266 // 1) The caller is an instance method. 267 // 2) This method was not called by the right caller. 268 if (me[opt_methodName] === caller) { 269 return me.constructor.prototype[opt_methodName].apply(me, args); 270 } else { 271 throw Error( 272 'cc.base called from a method of one name ' + 273 'to a method of a different name'); 274 } 275 }; 276 277 cc.concatObjectProperties = function(dstObject, srcObject){ 278 if(!dstObject) 279 dstObject = {}; 280 281 for(var selKey in srcObject){ 282 dstObject[selKey] = srcObject[selKey]; 283 } 284 return dstObject; 285 }; 286 287