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