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 function ClassManager(){ 38 //tells own name 39 return arguments.callee.name || (arguments.callee.toString()).match(/^function ([^(]+)/)[1]; 40 } 41 ClassManager.id=(0|(Math.random()*998)); 42 ClassManager.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 //find name of ClassManager 71 var Cstr = arguments.callee.ClassManager(); 72 73 //replace this._super 74 str = str.substring(0, sp)+ Cstr+'['+id+'].'+name+'.call(this'+coma+str.substring(bp+1); 75 } 76 return Function(params, str); 77 }; 78 ClassManager.compileSuper.ClassManager = ClassManager; 79 ClassManager.getNewID=function(){ 80 return this.id++; 81 }; 82 83 84 (function () { 85 var initializing = false, fnTest = /\b_super\b/; 86 var releaseMode = (document['ccConfig'] && document['ccConfig']['CLASS_RELEASE_MODE']) ? document['ccConfig']['CLASS_RELEASE_MODE'] : null; 87 if(releaseMode) { 88 console.log("release Mode"); 89 } 90 91 /** 92 * The base Class implementation (does nothing) 93 * @class 94 */ 95 cc.Class = function () { 96 }; 97 98 /** 99 * Create a new Class that inherits from this Class 100 * @param {object} prop 101 * @return {function} 102 */ 103 cc.Class.extend = function (prop) { 104 var _super = this.prototype; 105 106 // Instantiate a base Class (but only create the instance, 107 // don't run the init constructor) 108 var prototype = Object.create(_super); 109 110 var classId = ClassManager.getNewID(); 111 ClassManager[classId] = _super; 112 // Copy the properties over onto the new prototype. We make function 113 // properties non-eumerable as this makes typeof === 'function' check 114 // unneccessary in the for...in loop used 1) for generating Class() 115 // 2) for cc.clone and perhaps more. It is also required to make 116 // these function properties cacheable in Carakan. 117 var desc = { writable: true, enumerable: false, configurable: true }; 118 for (var name in prop) { 119 if(releaseMode && typeof prop[name] == "function" && typeof _super[name] == "function" && fnTest.test(prop[name])) { 120 desc.value = ClassManager.compileSuper(prop[name], name, classId); 121 Object.defineProperty(prototype, name, desc); 122 } else if(typeof prop[name] == "function" && typeof _super[name] == "function" && fnTest.test(prop[name])){ 123 desc.value = (function (name, fn) { 124 return function () { 125 var tmp = this._super; 126 127 // Add a new ._super() method that is the same method 128 // but on the super-Class 129 this._super = _super[name]; 130 131 // The method only need to be bound temporarily, so we 132 // remove it when we're done executing 133 var ret = fn.apply(this, arguments); 134 this._super = tmp; 135 136 return ret; 137 }; 138 })(name, prop[name]); 139 Object.defineProperty(prototype, name, desc); 140 } else if(typeof prop[name] == "function") { 141 desc.value = prop[name]; 142 Object.defineProperty(prototype, name, desc); 143 } else{ 144 prototype[name] = prop[name]; 145 } 146 } 147 148 // The dummy Class constructor. The properties are initialized in 149 // the constructor in advance so that the hidden class an instance 150 // of this belongs is stable. We need to create this constructor on 151 // the fly with "new Function" intead of doing 152 // 153 // function Class () { 154 // for (var p in this) 155 // this[p] = this[p]; 156 // } 157 // 158 // because using keyed assignment (this[x] = y instead of this.x = y) 159 // to append new proeprties is almost certainly going to make an object 160 // turn into dictionary mode in V8. 161 // 162 // See https://github.com/oupengsoftware/v8/wiki/Dictionary-mode-%28English%29#wiki-append-property 163 // 164 // for principles under the hood. 165 /*var functionBody = releaseMode? "": "this._super=null;"; 166 for (var p in prototype) { 167 functionBody += "this." + p + "=this." + p + ";"; 168 } 169 if (prototype.ctor) 170 functionBody += "this.ctor.apply(this,arguments)"; 171 var Class = new Function(functionBody);*/ 172 173 // The dummy Class constructor 174 function Class() { 175 // All construction is actually done in the init method 176 if (this.ctor) 177 this.ctor.apply(this, arguments); 178 } 179 180 Class.id = classId; 181 // desc = { writable: true, enumerable: false, configurable: true, 182 // value: XXX }; Again, we make this non-enumerable. 183 desc.value = classId; 184 Object.defineProperty(prototype, '__pid', desc); 185 186 // Populate our constructed prototype object 187 Class.prototype = prototype; 188 189 // Enforce the constructor to be what we expect 190 desc.value = Class; 191 Object.defineProperty(Class.prototype, 'constructor', desc); 192 193 // And make this Class extendable 194 Class.extend = arguments.callee; 195 196 //add implementation method 197 Class.implement = function (prop) { 198 for (var name in prop) { 199 prototype[name] = prop[name]; 200 } 201 }; 202 return Class; 203 }; 204 205 Function.prototype.bind = Function.prototype.bind || function (bind) { 206 var self = this; 207 return function () { 208 var args = Array.prototype.slice.call(arguments); 209 return self.apply(bind || null, args); 210 }; 211 }; 212 213 })(); 214 215 // 216 // Another way to subclass: Using Google Closure. 217 // The following code was copied + pasted from goog.base / goog.inherits 218 // 219 cc.inherits = function (childCtor, parentCtor) { 220 /** @constructor */ 221 function tempCtor() {} 222 tempCtor.prototype = parentCtor.prototype; 223 childCtor.superClass_ = parentCtor.prototype; 224 childCtor.prototype = new tempCtor(); 225 childCtor.prototype.constructor = childCtor; 226 227 // Copy "static" method, but doesn't generate subclasses. 228 // for( var i in parentCtor ) { 229 // childCtor[ i ] = parentCtor[ i ]; 230 // } 231 }; 232 cc.base = function(me, opt_methodName, var_args) { 233 var caller = arguments.callee.caller; 234 if (caller.superClass_) { 235 // This is a constructor. Call the superclass constructor. 236 ret = caller.superClass_.constructor.apply( me, Array.prototype.slice.call(arguments, 1)); 237 return ret; 238 } 239 240 var args = Array.prototype.slice.call(arguments, 2); 241 var foundCaller = false; 242 for (var ctor = me.constructor; 243 ctor; ctor = ctor.superClass_ && ctor.superClass_.constructor) { 244 if (ctor.prototype[opt_methodName] === caller) { 245 foundCaller = true; 246 } else if (foundCaller) { 247 return ctor.prototype[opt_methodName].apply(me, args); 248 } 249 } 250 251 // If we did not find the caller in the prototype chain, 252 // then one of two things happened: 253 // 1) The caller is an instance method. 254 // 2) This method was not called by the right caller. 255 if (me[opt_methodName] === caller) { 256 return me.constructor.prototype[opt_methodName].apply(me, args); 257 } else { 258 throw Error( 259 'cc.base called from a method of one name ' + 260 'to a method of a different name'); 261 } 262 }; 263 264 cc.concatObjectProperties = function(dstObject, srcObject){ 265 if(!dstObject) 266 dstObject = {}; 267 268 for(var selKey in srcObject){ 269 dstObject[selKey] = srcObject[selKey]; 270 } 271 return dstObject; 272 }; 273 274