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 releaseMode = (document['ccConfig'] && document['ccConfig']['CLASS_RELEASE_MODE']) ? document['ccConfig']['CLASS_RELEASE_MODE'] : null;
 89     if(releaseMode) {
 90         console.log("release Mode");
 91     }
 92 
 93     /**
 94      * The base Class implementation (does nothing)
 95      * @class
 96      */
 97     cc.Class = function () {
 98     };
 99 
100     /**
101      * Create a new Class that inherits from this Class
102      * @param {object} prop
103      * @return {function}
104      */
105     cc.Class.extend = function (prop) {
106         var _super = this.prototype;
107 
108         // Instantiate a base Class (but only create the instance,
109         // don't run the init constructor)
110         var prototype = Object.create(_super);
111 
112         var classId = ClassManager.getNewID();
113         ClassManager[classId] = _super;
114         // Copy the properties over onto the new prototype. We make function
115         // properties non-eumerable as this makes typeof === 'function' check
116         // unneccessary in the for...in loop used 1) for generating Class()
117         // 2) for cc.clone and perhaps more. It is also required to make
118         // these function properties cacheable in Carakan.
119         var desc = { writable: true, enumerable: false, configurable: true };
120         for (var name in prop) {
121             if(releaseMode && typeof prop[name] == "function" && typeof _super[name] == "function" && fnTest.test(prop[name])) {
122                 desc.value = ClassManager.compileSuper(prop[name], name, classId);
123                 Object.defineProperty(prototype, name, desc);
124             } else if(typeof prop[name] == "function" && typeof _super[name] == "function" && fnTest.test(prop[name])){
125                 desc.value = (function (name, fn) {
126                     return function () {
127                         var tmp = this._super;
128 
129                         // Add a new ._super() method that is the same method
130                         // but on the super-Class
131                         this._super = _super[name];
132 
133                         // The method only need to be bound temporarily, so we
134                         // remove it when we're done executing
135                         var ret = fn.apply(this, arguments);
136                         this._super = tmp;
137 
138                         return ret;
139                     };
140                 })(name, prop[name]);
141                 Object.defineProperty(prototype, name, desc);
142             } else if(typeof prop[name] == "function") {
143                 desc.value = prop[name];
144                 Object.defineProperty(prototype, name, desc);
145             } else{
146                 prototype[name] = prop[name];
147             }
148         }
149         prototype.__instanceId = null;
150 
151         // The dummy Class constructor
152         function Class() {
153             this.__instanceId = ClassManager.getNewInstanceId();
154             // All construction is actually done in the init method
155             if (this.ctor)
156                 this.ctor.apply(this, arguments);
157         }
158 
159         Class.id = classId;
160         // desc = { writable: true, enumerable: false, configurable: true,
161         //          value: XXX }; Again, we make this non-enumerable.
162         desc.value = classId;
163         Object.defineProperty(prototype, '__pid', desc);
164 
165         // Populate our constructed prototype object
166         Class.prototype = prototype;
167 
168         // Enforce the constructor to be what we expect
169         desc.value = Class;
170         Object.defineProperty(Class.prototype, 'constructor', desc);
171 
172         // And make this Class extendable
173         Class.extend = cc.Class.extend;
174 
175         //add implementation method
176         Class.implement = function (prop) {
177             for (var name in prop) {
178                 prototype[name] = prop[name];
179             }
180         };
181         return Class;
182     };
183 
184     Function.prototype.bind = Function.prototype.bind || function (bind) {
185         var self = this;
186         var args = Array.prototype.slice.call(arguments, 1);
187         return function () {
188             return self.apply(bind || null, args.concat(Array.prototype.slice.call(arguments)));
189         };
190     };
191 
192 })();
193 
194 //
195 // Another way to subclass: Using Google Closure.
196 // The following code was copied + pasted from goog.base / goog.inherits
197 //
198 cc.inherits = function (childCtor, parentCtor) {
199     /** @constructor */
200     function tempCtor() {}
201     tempCtor.prototype = parentCtor.prototype;
202     childCtor.superClass_ = parentCtor.prototype;
203     childCtor.prototype = new tempCtor();
204     childCtor.prototype.constructor = childCtor;
205 
206     // Copy "static" method, but doesn't generate subclasses.
207 //  for( var i in parentCtor ) {
208 //      childCtor[ i ] = parentCtor[ i ];
209 //  }
210 };
211 cc.base = function(me, opt_methodName, var_args) {
212     var caller = arguments.callee.caller;
213     if (caller.superClass_) {
214         // This is a constructor. Call the superclass constructor.
215         ret =  caller.superClass_.constructor.apply( me, Array.prototype.slice.call(arguments, 1));
216         return ret;
217     }
218 
219     var args = Array.prototype.slice.call(arguments, 2);
220     var foundCaller = false;
221     for (var ctor = me.constructor; ctor; ctor = ctor.superClass_ && ctor.superClass_.constructor) {
222         if (ctor.prototype[opt_methodName] === caller) {
223             foundCaller = true;
224         } else if (foundCaller) {
225             return ctor.prototype[opt_methodName].apply(me, args);
226         }
227     }
228 
229     // If we did not find the caller in the prototype chain,
230     // then one of two things happened:
231     // 1) The caller is an instance method.
232     // 2) This method was not called by the right caller.
233     if (me[opt_methodName] === caller) {
234         return me.constructor.prototype[opt_methodName].apply(me, args);
235     } else {
236         throw Error(
237             'cc.base called from a method of one name ' +
238                 'to a method of a different name');
239     }
240 };
241 
242 cc.concatObjectProperties = function(dstObject, srcObject){
243     if(!dstObject)
244         dstObject = {};
245 
246     for(var selKey in srcObject){
247         dstObject[selKey] = srcObject[selKey];
248     }
249     return dstObject;
250 };
251 
252