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