1 /****************************************************************************
  2  Copyright (c) 2011-2012 cocos2d-x.org
  3  Copyright (c) 2013-2014 Chukong Technologies Inc.
  4 
  5  http://www.cocos2d-x.org
  6 
  7  Permission is hereby granted, free of charge, to any person obtaining a copy
  8  of this software and associated documentation files (the "Software"), to deal
  9  in the Software without restriction, including without limitation the rights
 10  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 11  copies of the Software, and to permit persons to whom the Software is
 12  furnished to do so, subject to the following conditions:
 13 
 14  The above copyright notice and this permission notice shall be included in
 15  all copies or substantial portions of the Software.
 16 
 17  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 18  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 19  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 20  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 21  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 22  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 23  THE SOFTWARE.
 24  ****************************************************************************/
 25 
 26 /**
 27  * The main namespace of Cocos2d-JS, all engine core classes, functions, properties and constants are defined in this namespace
 28  * @namespace
 29  * @name cc
 30  */
 31 var cc = cc || {};
 32 cc._tmp = cc._tmp || {};
 33 cc._LogInfos = {};
 34 
 35 /** @expose */
 36 window._p;
 37 _p = window;
 38 /** @expose */
 39 _p.gl;
 40 /** @expose */
 41 _p.WebGLRenderingContext;
 42 /** @expose */
 43 _p.DeviceOrientationEvent;
 44 /** @expose */
 45 _p.DeviceMotionEvent;
 46 /** @expose */
 47 _p.AudioContext;
 48 /** @expose */
 49 _p.webkitAudioContext;
 50 /** @expose */
 51 _p.mozAudioContext;
 52 _p = Object.prototype;
 53 /** @expose */
 54 _p._super;
 55 /** @expose */
 56 _p.ctor;
 57 delete window._p;
 58 
 59 cc.newElement = function (x) {
 60     return document.createElement(x);
 61 };
 62 
 63 cc._addEventListener = function (element, type, listener, useCapture) {
 64     element.addEventListener(type, listener, useCapture);
 65 };
 66 
 67 //is nodejs ? Used to support node-webkit.
 68 cc._isNodeJs = typeof require !== 'undefined' && require("fs");
 69 
 70 /**
 71  * Iterate over an object or an array, executing a function for each matched element.
 72  * @param {object|array} obj
 73  * @param {function} iterator
 74  * @param {object} [context]
 75  */
 76 cc.each = function (obj, iterator, context) {
 77     if (!obj)
 78         return;
 79     if (obj instanceof Array) {
 80         for (var i = 0, li = obj.length; i < li; i++) {
 81             if (iterator.call(context, obj[i], i) === false)
 82                 return;
 83         }
 84     } else {
 85         for (var key in obj) {
 86             if (iterator.call(context, obj[key], key) === false)
 87                 return;
 88         }
 89     }
 90 };
 91 
 92 /**
 93  * Copy all of the properties in source objects to target object and return the target object.
 94  * @param {object} target
 95  * @param {object} *sources
 96  * @returns {object}
 97  */
 98 cc.extend = function(target) {
 99     var sources = arguments.length >= 2 ? Array.prototype.slice.call(arguments, 1) : [];
100 
101     cc.each(sources, function(src) {
102         for(var key in src) {
103             if (src.hasOwnProperty(key)) {
104                 target[key] = src[key];
105             }
106         }
107     });
108     return target;
109 };
110 
111 /**
112  * Check the obj whether is function or not
113  * @param {*} obj
114  * @returns {boolean}
115  */
116 cc.isFunction = function(obj) {
117     return typeof obj === 'function';
118 };
119 
120 /**
121  * Check the obj whether is number or not
122  * @param {*} obj
123  * @returns {boolean}
124  */
125 cc.isNumber = function(obj) {
126     return typeof obj === 'number' || Object.prototype.toString.call(obj) === '[object Number]';
127 };
128 
129 /**
130  * Check the obj whether is string or not
131  * @param {*} obj
132  * @returns {boolean}
133  */
134 cc.isString = function(obj) {
135     return typeof obj === 'string' || Object.prototype.toString.call(obj) === '[object String]';
136 };
137 
138 /**
139  * Check the obj whether is array or not
140  * @param {*} obj
141  * @returns {boolean}
142  */
143 cc.isArray = function(obj) {
144     return Array.isArray(obj) ||
145         (typeof obj === 'object' && Object.prototype.toString.call(obj) === '[object Array]');
146 };
147 
148 /**
149  * Check the obj whether is undefined or not
150  * @param {*} obj
151  * @returns {boolean}
152  */
153 cc.isUndefined = function(obj) {
154     return typeof obj === 'undefined';
155 };
156 
157 /**
158  * Check the obj whether is object or not
159  * @param {*} obj
160  * @returns {boolean}
161  */
162 cc.isObject = function(obj) {
163     return typeof obj === "object" && Object.prototype.toString.call(obj) === '[object Object]';
164 };
165 
166 /**
167  * Check the url whether cross origin
168  * @param {String} url
169  * @returns {boolean}
170  */
171 cc.isCrossOrigin = function (url) {
172     if (!url) {
173         cc.log("invalid URL");
174         return false;
175     }
176     var startIndex = url.indexOf("://");
177     if (startIndex === -1)
178         return false;
179 
180     var endIndex = url.indexOf("/", startIndex + 3);
181     var urlOrigin = (endIndex === -1) ? url : url.substring(0, endIndex);
182     return urlOrigin !== location.origin;
183 };
184 
185 //+++++++++++++++++++++++++something about async begin+++++++++++++++++++++++++++++++
186 /**
187  * Async Pool class, a helper of cc.async
188  * @param {Object|Array} srcObj
189  * @param {Number} limit the limit of parallel number
190  * @param {function} iterator
191  * @param {function} onEnd
192  * @param {object} target
193  * @constructor
194  */
195 cc.AsyncPool = function(srcObj, limit, iterator, onEnd, target){
196     var self = this;
197     self._srcObj = srcObj;
198     self._limit = limit;
199     self._pool = [];
200     self._iterator = iterator;
201     self._iteratorTarget = target;
202     self._onEnd = onEnd;
203     self._onEndTarget = target;
204     self._results = srcObj instanceof Array ? [] : {};
205     self._isErr = false;
206 
207     cc.each(srcObj, function(value, index){
208         self._pool.push({index : index, value : value});
209     });
210 
211     self.size = self._pool.length;
212     self.finishedSize = 0;
213     self._workingSize = 0;
214 
215     self._limit = self._limit || self.size;
216 
217     self.onIterator = function(iterator, target){
218         self._iterator = iterator;
219         self._iteratorTarget = target;
220     };
221 
222     self.onEnd = function(endCb, endCbTarget){
223         self._onEnd = endCb;
224         self._onEndTarget = endCbTarget;
225     };
226 
227     self._handleItem = function(){
228         var self = this;
229         if(self._pool.length === 0 || self._workingSize >= self._limit)
230             return;                                                         //return directly if the array's length = 0 or the working size great equal limit number
231 
232         var item = self._pool.shift();
233         var value = item.value, index = item.index;
234         self._workingSize++;
235         self._iterator.call(self._iteratorTarget, value, index,
236             function(err) {
237                 if (self._isErr)
238                     return;
239 
240                 self.finishedSize++;
241                 self._workingSize--;
242                 if (err) {
243                     self._isErr = true;
244                     if (self._onEnd)
245                         self._onEnd.call(self._onEndTarget, err);
246                     return;
247                 }
248 
249                 var arr = Array.prototype.slice.call(arguments, 1);
250                 self._results[this.index] = arr[0];
251                 if (self.finishedSize === self.size) {
252                     if (self._onEnd)
253                         self._onEnd.call(self._onEndTarget, null, self._results);
254                     return;
255                 }
256                 self._handleItem();
257             }.bind(item),
258             self);
259     };
260 
261     self.flow = function(){
262         var self = this;
263         if(self._pool.length === 0) {
264             if(self._onEnd)
265                 self._onEnd.call(self._onEndTarget, null, []);
266                 return;
267         }
268         for(var i = 0; i < self._limit; i++)
269             self._handleItem();
270     }
271 };
272 
273 /**
274  * @class
275  */
276 cc.async = /** @lends cc.async# */{
277     /**
278      * Do tasks series.
279      * @param {Array|Object} tasks
280      * @param {function} [cb] callback
281      * @param {Object} [target]
282      * @return {cc.AsyncPool}
283      */
284     series : function(tasks, cb, target){
285         var asyncPool = new cc.AsyncPool(tasks, 1, function(func, index, cb1){
286             func.call(target, cb1);
287         }, cb, target);
288         asyncPool.flow();
289         return asyncPool;
290     },
291 
292     /**
293      * Do tasks parallel.
294      * @param {Array|Object} tasks
295      * @param {function} cb callback
296      * @param {Object} [target]
297      * @return {cc.AsyncPool}
298      */
299     parallel : function(tasks, cb, target){
300         var asyncPool = new cc.AsyncPool(tasks, 0, function(func, index, cb1){
301             func.call(target, cb1);
302         }, cb, target);
303         asyncPool.flow();
304         return asyncPool;
305     },
306 
307     /**
308      * Do tasks waterfall.
309      * @param {Array|Object} tasks
310      * @param {function} cb callback
311      * @param {Object} [target]
312      * @return {cc.AsyncPool}
313      */
314     waterfall : function(tasks, cb, target){
315         var args = [];
316         var lastResults = [null];//the array to store the last results
317         var asyncPool = new cc.AsyncPool(tasks, 1,
318             function (func, index, cb1) {
319                 args.push(function (err) {
320                     args = Array.prototype.slice.call(arguments, 1);
321                     if(tasks.length - 1 === index) lastResults = lastResults.concat(args);//while the last task
322                     cb1.apply(null, arguments);
323                 });
324                 func.apply(target, args);
325             }, function (err) {
326                 if (!cb)
327                     return;
328                 if (err)
329                     return cb.call(target, err);
330                 cb.apply(target, lastResults);
331             });
332         asyncPool.flow();
333         return asyncPool;
334     },
335 
336     /**
337      * Do tasks by iterator.
338      * @param {Array|Object} tasks
339      * @param {function|Object} iterator
340      * @param {function} [callback]
341      * @param {Object} [target]
342      * @return {cc.AsyncPool}
343      */
344     map : function(tasks, iterator, callback, target){
345         var locIterator = iterator;
346         if(typeof(iterator) === "object"){
347             callback = iterator.cb;
348             target = iterator.iteratorTarget;
349             locIterator = iterator.iterator;
350         }
351         var asyncPool = new cc.AsyncPool(tasks, 0, locIterator, callback, target);
352         asyncPool.flow();
353         return asyncPool;
354     },
355 
356     /**
357      * Do tasks by iterator limit.
358      * @param {Array|Object} tasks
359      * @param {Number} limit
360      * @param {function} iterator
361      * @param {function} cb callback
362      * @param {Object} [target]
363      */
364     mapLimit : function(tasks, limit, iterator, cb, target){
365         var asyncPool = new cc.AsyncPool(tasks, limit, iterator, cb, target);
366         asyncPool.flow();
367         return asyncPool;
368     }
369 };
370 //+++++++++++++++++++++++++something about async end+++++++++++++++++++++++++++++++++
371 
372 //+++++++++++++++++++++++++something about path begin++++++++++++++++++++++++++++++++
373 /**
374  * @class
375  */
376 cc.path = /** @lends cc.path# */{
377     /**
378      * Join strings to be a path.
379      * @example
380      cc.path.join("a", "b.png");//-->"a/b.png"
381      cc.path.join("a", "b", "c.png");//-->"a/b/c.png"
382      cc.path.join("a", "b");//-->"a/b"
383      cc.path.join("a", "b", "/");//-->"a/b/"
384      cc.path.join("a", "b/", "/");//-->"a/b/"
385      * @returns {string}
386      */
387     join: function () {
388         var l = arguments.length;
389         var result = "";
390         for (var i = 0; i < l; i++) {
391             result = (result + (result === "" ? "" : "/") + arguments[i]).replace(/(\/|\\\\)$/, "");
392         }
393         return result;
394     },
395 
396     /**
397      * Get the ext name of a path.
398      * @example
399      cc.path.extname("a/b.png");//-->".png"
400      cc.path.extname("a/b.png?a=1&b=2");//-->".png"
401      cc.path.extname("a/b");//-->null
402      cc.path.extname("a/b?a=1&b=2");//-->null
403      * @param {string} pathStr
404      * @returns {*}
405      */
406     extname: function (pathStr) {
407         var temp = /(\.[^\.\/\?\\]*)(\?.*)?$/.exec(pathStr);
408         return temp ? temp[1] : null;
409     },
410 
411     /**
412      * Get the main name of a file name
413      * @param {string} fileName
414      * @returns {string}
415      */
416     mainFileName: function(fileName){
417         if(fileName){
418            var idx = fileName.lastIndexOf(".");
419             if(idx !== -1)
420                return fileName.substring(0,idx);
421         }
422         return fileName;
423     },
424 
425     /**
426      * Get the file name of a file path.
427      * @example
428      cc.path.basename("a/b.png");//-->"b.png"
429      cc.path.basename("a/b.png?a=1&b=2");//-->"b.png"
430      cc.path.basename("a/b.png", ".png");//-->"b"
431      cc.path.basename("a/b.png?a=1&b=2", ".png");//-->"b"
432      cc.path.basename("a/b.png", ".txt");//-->"b.png"
433      * @param {string} pathStr
434      * @param {string} [extname]
435      * @returns {*}
436      */
437     basename: function (pathStr, extname) {
438         var index = pathStr.indexOf("?");
439         if (index > 0) pathStr = pathStr.substring(0, index);
440         var reg = /(\/|\\\\)([^(\/|\\\\)]+)$/g;
441         var result = reg.exec(pathStr.replace(/(\/|\\\\)$/, ""));
442         if (!result) return null;
443         var baseName = result[2];
444         if (extname && pathStr.substring(pathStr.length - extname.length).toLowerCase() === extname.toLowerCase())
445             return baseName.substring(0, baseName.length - extname.length);
446         return baseName;
447     },
448 
449     /**
450      * Get dirname of a file path.
451      * @example
452      * unix
453      cc.path.driname("a/b/c.png");//-->"a/b"
454      cc.path.driname("a/b/c.png?a=1&b=2");//-->"a/b"
455      cc.path.dirname("a/b/");//-->"a/b"
456      cc.path.dirname("c.png");//-->""
457      * windows
458      cc.path.driname("a\\b\\c.png");//-->"a\b"
459      cc.path.driname("a\\b\\c.png?a=1&b=2");//-->"a\b"
460      * @param {string} pathStr
461      * @returns {*}
462      */
463     dirname: function (pathStr) {
464         return pathStr.replace(/((.*)(\/|\\|\\\\))?(.*?\..*$)?/, '$2');
465     },
466 
467     /**
468      * Change extname of a file path.
469      * @example
470      cc.path.changeExtname("a/b.png", ".plist");//-->"a/b.plist"
471      cc.path.changeExtname("a/b.png?a=1&b=2", ".plist");//-->"a/b.plist?a=1&b=2"
472      * @param {string} pathStr
473      * @param {string} [extname]
474      * @returns {string}
475      */
476     changeExtname: function (pathStr, extname) {
477         extname = extname || "";
478         var index = pathStr.indexOf("?");
479         var tempStr = "";
480         if (index > 0) {
481             tempStr = pathStr.substring(index);
482             pathStr = pathStr.substring(0, index);
483         }
484         index = pathStr.lastIndexOf(".");
485         if (index < 0) return pathStr + extname + tempStr;
486         return pathStr.substring(0, index) + extname + tempStr;
487     },
488     /**
489      * Change file name of a file path.
490      * @example
491      cc.path.changeBasename("a/b/c.plist", "b.plist");//-->"a/b/b.plist"
492      cc.path.changeBasename("a/b/c.plist?a=1&b=2", "b.plist");//-->"a/b/b.plist?a=1&b=2"
493      cc.path.changeBasename("a/b/c.plist", ".png");//-->"a/b/c.png"
494      cc.path.changeBasename("a/b/c.plist", "b");//-->"a/b/b"
495      cc.path.changeBasename("a/b/c.plist", "b", true);//-->"a/b/b.plist"
496      * @param {String} pathStr
497      * @param {String} basename
498      * @param {Boolean} [isSameExt]
499      * @returns {string}
500      */
501     changeBasename: function (pathStr, basename, isSameExt) {
502         if (basename.indexOf(".") === 0) return this.changeExtname(pathStr, basename);
503         var index = pathStr.indexOf("?");
504         var tempStr = "";
505         var ext = isSameExt ? this.extname(pathStr) : "";
506         if (index > 0) {
507             tempStr = pathStr.substring(index);
508             pathStr = pathStr.substring(0, index);
509         }
510         index = pathStr.lastIndexOf("/");
511         index = index <= 0 ? 0 : index + 1;
512         return pathStr.substring(0, index) + basename + ext + tempStr;
513     }
514 };
515 //+++++++++++++++++++++++++something about path end++++++++++++++++++++++++++++++++
516 
517 //+++++++++++++++++++++++++something about loader start+++++++++++++++++++++++++++
518 /**
519  * Loader for resource loading process. It's a singleton object.
520  * @class
521  */
522 cc.loader = /** @lends cc.loader# */{
523     _jsCache: {},//cache for js
524     _register: {},//register of loaders
525     _langPathCache: {},//cache for lang path
526     _aliases: {},//aliases for res url
527 
528     resPath: "",//root path of resource
529     audioPath: "",//root path of audio
530     cache: {},//cache for data loaded
531 
532     /**
533      * Get XMLHttpRequest.
534      * @returns {XMLHttpRequest}
535      */
536     getXMLHttpRequest: function () {
537         return window.XMLHttpRequest ? new window.XMLHttpRequest() : new ActiveXObject("MSXML2.XMLHTTP");
538     },
539 
540     //@MODE_BEGIN DEV
541 
542     _getArgs4Js: function (args) {
543         var a0 = args[0], a1 = args[1], a2 = args[2], results = ["", null, null];
544 
545         if (args.length === 1) {
546             results[1] = a0 instanceof Array ? a0 : [a0];
547         } else if (args.length === 2) {
548             if (typeof a1 === "function") {
549                 results[1] = a0 instanceof Array ? a0 : [a0];
550                 results[2] = a1;
551             } else {
552                 results[0] = a0 || "";
553                 results[1] = a1 instanceof Array ? a1 : [a1];
554             }
555         } else if (args.length === 3) {
556             results[0] = a0 || "";
557             results[1] = a1 instanceof Array ? a1 : [a1];
558             results[2] = a2;
559         } else throw "arguments error to load js!";
560         return results;
561     },
562 
563     /**
564      * Load js files.
565      * If the third parameter doesn't exist, then the baseDir turns to be "".
566      *
567      * @param {string} [baseDir]   The pre path for jsList or the list of js path.
568      * @param {array} jsList    List of js path.
569      * @param {function} [cb]  Callback function
570      * @returns {*}
571      */
572     loadJs: function (baseDir, jsList, cb) {
573         var self = this, localJsCache = self._jsCache,
574             args = self._getArgs4Js(arguments);
575 
576         var preDir = args[0], list = args[1], callback = args[2];
577         if (navigator.userAgent.indexOf("Trident/5") > -1) {
578             self._loadJs4Dependency(preDir, list, 0, callback);
579         } else {
580             cc.async.map(list, function (item, index, cb1) {
581                 var jsPath = cc.path.join(preDir, item);
582                 if (localJsCache[jsPath]) return cb1(null);
583                 self._createScript(jsPath, false, cb1);
584             }, callback);
585         }
586     },
587     /**
588      * Load js width loading image.
589      *
590      * @param {string} [baseDir]
591      * @param {array} jsList
592      * @param {function} [cb]
593      */
594     loadJsWithImg: function (baseDir, jsList, cb) {
595         var self = this, jsLoadingImg = self._loadJsImg(),
596             args = self._getArgs4Js(arguments);
597         this.loadJs(args[0], args[1], function (err) {
598             if (err) throw err;
599             jsLoadingImg.parentNode.removeChild(jsLoadingImg);//remove loading gif
600             if (args[2]) args[2]();
601         });
602     },
603     _createScript: function (jsPath, isAsync, cb) {
604         var d = document, self = this, s = cc.newElement('script');
605         s.async = isAsync;
606         self._jsCache[jsPath] = true;
607         if(cc.game.config["noCache"] && typeof jsPath === "string"){
608             if(self._noCacheRex.test(jsPath))
609                 s.src = jsPath + "&_t=" + (new Date() - 0);
610             else
611                 s.src = jsPath + "?_t=" + (new Date() - 0);
612         }else{
613             s.src = jsPath;
614         }
615         cc._addEventListener(s, 'load', function () {
616             s.parentNode.removeChild(s);
617             this.removeEventListener('load', arguments.callee, false);
618             cb();
619         }, false);
620         cc._addEventListener(s, 'error', function () {
621             s.parentNode.removeChild(s);
622             cb("Load " + jsPath + " failed!");
623         }, false);
624         d.body.appendChild(s);
625     },
626     _loadJs4Dependency: function (baseDir, jsList, index, cb) {
627         if (index >= jsList.length) {
628             if (cb) cb();
629             return;
630         }
631         var self = this;
632         self._createScript(cc.path.join(baseDir, jsList[index]), false, function (err) {
633             if (err) return cb(err);
634             self._loadJs4Dependency(baseDir, jsList, index + 1, cb);
635         });
636     },
637     _loadJsImg: function () {
638         var d = document, jsLoadingImg = d.getElementById("cocos2d_loadJsImg");
639         if (!jsLoadingImg) {
640             jsLoadingImg = cc.newElement('img');
641 
642             if (cc._loadingImage)
643                 jsLoadingImg.src = cc._loadingImage;
644 
645             var canvasNode = d.getElementById(cc.game.config["id"]);
646             canvasNode.style.backgroundColor = "black";
647             canvasNode.parentNode.appendChild(jsLoadingImg);
648 
649             var canvasStyle = getComputedStyle ? getComputedStyle(canvasNode) : canvasNode.currentStyle;
650             if (!canvasStyle)
651                 canvasStyle = {width: canvasNode.width, height: canvasNode.height};
652             jsLoadingImg.style.left = canvasNode.offsetLeft + (parseFloat(canvasStyle.width) - jsLoadingImg.width) / 2 + "px";
653             jsLoadingImg.style.top = canvasNode.offsetTop + (parseFloat(canvasStyle.height) - jsLoadingImg.height) / 2 + "px";
654             jsLoadingImg.style.position = "absolute";
655         }
656         return jsLoadingImg;
657     },
658     //@MODE_END DEV
659 
660     /**
661      * Load a single resource as txt.
662      * @param {string} url
663      * @param {function} [cb] arguments are : err, txt
664      */
665     loadTxt: function (url, cb) {
666         if (!cc._isNodeJs) {
667             var xhr = this.getXMLHttpRequest(),
668                 errInfo = "load " + url + " failed!";
669             xhr.open("GET", url, true);
670             if (/msie/i.test(navigator.userAgent) && !/opera/i.test(navigator.userAgent)) {
671                 // IE-specific logic here
672                 xhr.setRequestHeader("Accept-Charset", "utf-8");
673                 xhr.onreadystatechange = function () {
674                     if(xhr.readyState === 4)
675                         xhr.status === 200 ? cb(null, xhr.responseText) : cb(errInfo);
676                 };
677             } else {
678                 if (xhr.overrideMimeType) xhr.overrideMimeType("text\/plain; charset=utf-8");
679                 xhr.onload = function () {
680                     if(xhr.readyState === 4)
681                         xhr.status === 200 ? cb(null, xhr.responseText) : cb(errInfo);
682                 };
683             }
684             xhr.send(null);
685         } else {
686             var fs = require("fs");
687             fs.readFile(url, function (err, data) {
688                 err ? cb(err) : cb(null, data.toString());
689             });
690         }
691     },
692     _loadTxtSync: function (url) {
693         if (!cc._isNodeJs) {
694             var xhr = this.getXMLHttpRequest();
695             xhr.open("GET", url, false);
696             if (/msie/i.test(navigator.userAgent) && !/opera/i.test(navigator.userAgent)) {
697                 // IE-specific logic here
698                 xhr.setRequestHeader("Accept-Charset", "utf-8");
699             } else {
700                 if (xhr.overrideMimeType) xhr.overrideMimeType("text\/plain; charset=utf-8");
701             }
702             xhr.send(null);
703             if (!xhr.readyState === 4 || xhr.status !== 200) {
704                 return null;
705             }
706             return xhr.responseText;
707         } else {
708             var fs = require("fs");
709             return fs.readFileSync(url).toString();
710         }
711     },
712 
713     loadCsb: function(url, cb){
714         var xhr = new XMLHttpRequest();
715         xhr.open("GET", url, true);
716         xhr.responseType = "arraybuffer";
717 
718         xhr.onload = function () {
719             var arrayBuffer = xhr.response; // Note: not oReq.responseText
720             if (arrayBuffer) {
721                 window.msg = arrayBuffer;
722             }
723             if(xhr.readyState === 4)
724                 xhr.status === 200 ? cb(null, xhr.response) : cb("load " + url + " failed!");
725         };
726 
727         xhr.send(null);
728     },
729 
730     /**
731      * Load a single resource as json.
732      * @param {string} url
733      * @param {function} [cb] arguments are : err, json
734      */
735     loadJson: function (url, cb) {
736         this.loadTxt(url, function (err, txt) {
737             if (err) {
738                 cb(err);
739             }
740             else {
741                 try {
742                     var result = JSON.parse(txt);
743                 }
744                 catch (e) {
745                     throw "parse json [" + url + "] failed : " + e;
746                     return;
747                 }
748                 cb(null, result);
749             }
750         });
751     },
752 
753     _checkIsImageURL: function (url) {
754         var ext = /(\.png)|(\.jpg)|(\.bmp)|(\.jpeg)|(\.gif)/.exec(url);
755         return (ext != null);
756     },
757     /**
758      * Load a single image.
759      * @param {!string} url
760      * @param {object} [option]
761      * @param {function} callback
762      * @returns {Image}
763      */
764     loadImg: function (url, option, callback) {
765         var opt = {
766             isCrossOrigin: true
767         };
768         if (callback !== undefined)
769             opt.isCrossOrigin = option.isCrossOrigin === null ? opt.isCrossOrigin : option.isCrossOrigin;
770         else if (option !== undefined)
771             callback = option;
772 
773         var img = this.getRes(url);
774         if (img) {
775             callback && callback(null, img);
776             return img;
777         }
778 
779         img = new Image();
780         if (opt.isCrossOrigin && location.origin !== "file://")
781             img.crossOrigin = "Anonymous";
782 
783         var loadCallback = function () {
784             this.removeEventListener('load', loadCallback, false);
785             this.removeEventListener('error', errorCallback, false);
786 
787             if (callback)
788                 callback(null, img);
789         };
790 
791         var self = this;
792         var errorCallback = function () {
793             this.removeEventListener('error', errorCallback, false);
794 
795             if(img.crossOrigin && img.crossOrigin.toLowerCase() === "anonymous"){
796                 opt.isCrossOrigin = false;
797                 self.release(url);
798                 cc.loader.loadImg(url, opt, callback);
799             }else{
800                 typeof callback === "function" && callback("load image failed");
801             }
802         };
803 
804         cc._addEventListener(img, "load", loadCallback);
805         cc._addEventListener(img, "error", errorCallback);
806         img.src = url;
807         return img;
808     },
809 
810     /**
811      * Iterator function to load res
812      * @param {object} item
813      * @param {number} index
814      * @param {function} [cb]
815      * @returns {*}
816      * @private
817      */
818     _loadResIterator: function (item, index, cb) {
819         var self = this, url = null;
820         var type = item.type;
821         if (type) {
822             type = "." + type.toLowerCase();
823             url = item.src ? item.src : item.name + type;
824         } else {
825             url = item;
826             type = cc.path.extname(url);
827         }
828 
829         var obj = self.getRes(url);
830         if (obj)
831             return cb(null, obj);
832         var loader = null;
833         if (type) {
834             loader = self._register[type.toLowerCase()];
835         }
836         if (!loader) {
837             cc.error("loader for [" + type + "] not exists!");
838             return cb();
839         }
840         var realUrl = url;
841         if (!cc._urlRegExp.test(url))
842         {
843             var basePath = loader.getBasePath ? loader.getBasePath() : self.resPath;
844             realUrl = self.getUrl(basePath, url);
845         }
846 
847         if(cc.game.config["noCache"] && typeof realUrl === "string"){
848             if(self._noCacheRex.test(realUrl))
849                 realUrl += "&_t=" + (new Date() - 0);
850             else
851                 realUrl += "?_t=" + (new Date() - 0);
852         }
853         loader.load(realUrl, url, item, function (err, data) {
854             if (err) {
855                 cc.log(err);
856                 self.cache[url] = null;
857                 delete self.cache[url];
858                 cb();
859             } else {
860                 self.cache[url] = data;
861                 cb(null, data);
862             }
863         });
864     },
865     _noCacheRex: /\?/,
866 
867     /**
868      * Get url with basePath.
869      * @param {string} basePath
870      * @param {string} [url]
871      * @returns {*}
872      */
873     getUrl: function (basePath, url) {
874         var self = this, langPathCache = self._langPathCache, path = cc.path;
875         if (basePath !== undefined && url === undefined) {
876             url = basePath;
877             var type = path.extname(url);
878             type = type ? type.toLowerCase() : "";
879             var loader = self._register[type];
880             if (!loader)
881                 basePath = self.resPath;
882             else
883                 basePath = loader.getBasePath ? loader.getBasePath() : self.resPath;
884         }
885         url = cc.path.join(basePath || "", url);
886         if (url.match(/[\/(\\\\)]lang[\/(\\\\)]/i)) {
887             if (langPathCache[url])
888                 return langPathCache[url];
889             var extname = path.extname(url) || "";
890             url = langPathCache[url] = url.substring(0, url.length - extname.length) + "_" + cc.sys.language + extname;
891         }
892         return url;
893     },
894 
895     /**
896      * Load resources then call the callback.
897      * @param {string} resources
898      * @param {function} [option] callback or trigger
899      * @param {function|Object} [loadCallback]
900      * @return {cc.AsyncPool}
901      */
902     load : function(resources, option, loadCallback){
903         var self = this;
904         var len = arguments.length;
905         if(len === 0)
906             throw "arguments error!";
907 
908         if(len === 3){
909             if(typeof option === "function"){
910                 if(typeof loadCallback === "function")
911                     option = {trigger : option, cb : loadCallback };
912                 else
913                     option = { cb : option, cbTarget : loadCallback};
914             }
915         }else if(len === 2){
916             if(typeof option === "function")
917                 option = {cb : option};
918         }else if(len === 1){
919             option = {};
920         }
921 
922         if(!(resources instanceof Array))
923             resources = [resources];
924         var asyncPool = new cc.AsyncPool(
925             resources, 0,
926             function (value, index, AsyncPoolCallback, aPool) {
927                 self._loadResIterator(value, index, function (err) {
928                     if (err)
929                         return AsyncPoolCallback(err);
930                     var arr = Array.prototype.slice.call(arguments, 1);
931                     if (option.trigger)
932                         option.trigger.call(option.triggerTarget, arr[0], aPool.size, aPool.finishedSize);   //call trigger
933                     AsyncPoolCallback(null, arr[0]);
934                 });
935             },
936             option.cb, option.cbTarget);
937         asyncPool.flow();
938         return asyncPool;
939     },
940 
941     _handleAliases: function (fileNames, cb) {
942         var self = this, aliases = self._aliases;
943         var resList = [];
944         for (var key in fileNames) {
945             var value = fileNames[key];
946             aliases[key] = value;
947             resList.push(value);
948         }
949         this.load(resList, cb);
950     },
951 
952     /**
953      * <p>
954      *     Loads alias map from the contents of a filename.                                        <br/>
955      *                                                                                                                 <br/>
956      *     @note The plist file name should follow the format below:                                                   <br/>
957      *     <?xml version="1.0" encoding="UTF-8"?>                                                                      <br/>
958      *         <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">  <br/>
959      *             <plist version="1.0">                                                                               <br/>
960      *                 <dict>                                                                                          <br/>
961      *                     <key>filenames</key>                                                                        <br/>
962      *                     <dict>                                                                                      <br/>
963      *                         <key>sounds/click.wav</key>                                                             <br/>
964      *                         <string>sounds/click.caf</string>                                                       <br/>
965      *                         <key>sounds/endgame.wav</key>                                                           <br/>
966      *                         <string>sounds/endgame.caf</string>                                                     <br/>
967      *                         <key>sounds/gem-0.wav</key>                                                             <br/>
968      *                         <string>sounds/gem-0.caf</string>                                                       <br/>
969      *                     </dict>                                                                                     <br/>
970      *                     <key>metadata</key>                                                                         <br/>
971      *                     <dict>                                                                                      <br/>
972      *                         <key>version</key>                                                                      <br/>
973      *                         <integer>1</integer>                                                                    <br/>
974      *                     </dict>                                                                                     <br/>
975      *                 </dict>                                                                                         <br/>
976      *              </plist>                                                                                           <br/>
977      * </p>
978      * @param {String} url  The plist file name.
979      * @param {Function} [callback]
980      */
981     loadAliases: function (url, callback) {
982         var self = this, dict = self.getRes(url);
983         if (!dict) {
984             self.load(url, function (err, results) {
985                 self._handleAliases(results[0]["filenames"], callback);
986             });
987         } else
988             self._handleAliases(dict["filenames"], callback);
989     },
990 
991     /**
992      * Register a resource loader into loader.
993      * @param {string} extNames
994      * @param {function} loader
995      */
996     register: function (extNames, loader) {
997         if (!extNames || !loader) return;
998         var self = this;
999         if (typeof extNames === "string")
1000             return this._register[extNames.trim().toLowerCase()] = loader;
1001         for (var i = 0, li = extNames.length; i < li; i++) {
1002             self._register["." + extNames[i].trim().toLowerCase()] = loader;
1003         }
1004     },
1005 
1006     /**
1007      * Get resource data by url.
1008      * @param url
1009      * @returns {*}
1010      */
1011     getRes: function (url) {
1012         return this.cache[url] || this.cache[this._aliases[url]];
1013     },
1014 
1015     /**
1016      * Release the cache of resource by url.
1017      * @param url
1018      */
1019     release: function (url) {
1020         var cache = this.cache, aliases = this._aliases;
1021         delete cache[url];
1022         delete cache[aliases[url]];
1023         delete aliases[url];
1024     },
1025 
1026     /**
1027      * Resource cache of all resources.
1028      */
1029     releaseAll: function () {
1030         var locCache = this.cache, aliases = this._aliases;
1031         for (var key in locCache)
1032             delete locCache[key];
1033         for (var key in aliases)
1034             delete aliases[key];
1035     }
1036 };
1037 //+++++++++++++++++++++++++something about loader end+++++++++++++++++++++++++++++
1038 
1039 /**
1040  * A string tool to construct a string with format string.
1041  * for example:
1042  *      cc.formatStr("a: %d, b: %b", a, b);
1043  *      cc.formatStr(a, b, c);
1044  * @returns {String}
1045  */
1046 cc.formatStr = function(){
1047     var args = arguments;
1048     var l = args.length;
1049     if(l < 1)
1050         return "";
1051 
1052     var str = args[0];
1053     var needToFormat = true;
1054     if(typeof str === "object"){
1055         needToFormat = false;
1056     }
1057     for(var i = 1; i < l; ++i){
1058         var arg = args[i];
1059         if(needToFormat){
1060             while(true){
1061                 var result = null;
1062                 if(typeof arg === "number"){
1063                     result = str.match(/(%d)|(%s)/);
1064                     if(result){
1065                         str = str.replace(/(%d)|(%s)/, arg);
1066                         break;
1067                     }
1068                 }
1069                 result = str.match(/%s/);
1070                 if(result)
1071                     str = str.replace(/%s/, arg);
1072                 else
1073                     str += "    " + arg;
1074                 break;
1075             }
1076         }else
1077             str += "    " + arg;
1078     }
1079     return str;
1080 };
1081 
1082 
1083 //+++++++++++++++++++++++++something about window events begin+++++++++++++++++++++++++++
1084 (function () {
1085     var win = window, hidden, visibilityChange, _undef = "undefined";
1086     if (!cc.isUndefined(document.hidden)) {
1087         hidden = "hidden";
1088         visibilityChange = "visibilitychange";
1089     } else if (!cc.isUndefined(document.mozHidden)) {
1090         hidden = "mozHidden";
1091         visibilityChange = "mozvisibilitychange";
1092     } else if (!cc.isUndefined(document.msHidden)) {
1093         hidden = "msHidden";
1094         visibilityChange = "msvisibilitychange";
1095     } else if (!cc.isUndefined(document.webkitHidden)) {
1096         hidden = "webkitHidden";
1097         visibilityChange = "webkitvisibilitychange";
1098     }
1099 
1100     var onHidden = function () {
1101         if (cc.eventManager && cc.game._eventHide)
1102             cc.eventManager.dispatchEvent(cc.game._eventHide);
1103     };
1104     var onShow = function () {
1105         if (cc.eventManager && cc.game._eventShow)
1106             cc.eventManager.dispatchEvent(cc.game._eventShow);
1107 
1108         if(cc.game._intervalId){
1109             window.cancelAnimationFrame(cc.game._intervalId);
1110 
1111             cc.game._runMainLoop();
1112         }
1113     };
1114 
1115     if (hidden) {
1116         cc._addEventListener(document, visibilityChange, function () {
1117             if (document[hidden]) onHidden();
1118             else onShow();
1119         }, false);
1120     } else {
1121         cc._addEventListener(win, "blur", onHidden, false);
1122         cc._addEventListener(win, "focus", onShow, false);
1123     }
1124 
1125     if(navigator.userAgent.indexOf("MicroMessenger") > -1){
1126         win.onfocus = function(){ onShow() };
1127     }
1128 
1129     if ("onpageshow" in window && "onpagehide" in window) {
1130         cc._addEventListener(win, "pagehide", onHidden, false);
1131         cc._addEventListener(win, "pageshow", onShow, false);
1132     }
1133     win = null;
1134     visibilityChange = null;
1135 })();
1136 //+++++++++++++++++++++++++something about window events end+++++++++++++++++++++++++++++
1137 
1138 //+++++++++++++++++++++++++something about log start++++++++++++++++++++++++++++
1139 
1140 //to make sure the cc.log, cc.warn, cc.error and cc.assert would not throw error before init by debugger mode.
1141 
1142 cc.log = cc.warn = cc.error = cc.assert = function () {
1143 };
1144 
1145 //+++++++++++++++++++++++++something about log end+++++++++++++++++++++++++++++
1146 
1147 /**
1148  * create a webgl context
1149  * @param {HTMLCanvasElement} canvas
1150  * @param {Object} opt_attribs
1151  * @return {WebGLRenderingContext}
1152  */
1153 cc.create3DContext = function (canvas, opt_attribs) {
1154     var names = ["webgl", "experimental-webgl", "webkit-3d", "moz-webgl"];
1155     var context = null;
1156     for (var ii = 0; ii < names.length; ++ii) {
1157         try {
1158             context = canvas.getContext(names[ii], opt_attribs);
1159         } catch (e) {
1160         }
1161         if (context) {
1162             break;
1163         }
1164     }
1165     return context;
1166 };
1167 //+++++++++++++++++++++++++something about sys begin+++++++++++++++++++++++++++++
1168 cc._initSys = function (config, CONFIG_KEY) {
1169     /**
1170      * Canvas of render type
1171      * @constant
1172      * @type {Number}
1173      */
1174     cc._RENDER_TYPE_CANVAS = 0;
1175 
1176     /**
1177      * WebGL of render type
1178      * @constant
1179      * @type {Number}
1180      */
1181     cc._RENDER_TYPE_WEBGL = 1;
1182 
1183     /**
1184      * System variables
1185      * @namespace
1186      * @name cc.sys
1187      */
1188     cc.sys = {};
1189     var sys = cc.sys;
1190 
1191     /**
1192      * English language code
1193      * @memberof cc.sys
1194      * @name LANGUAGE_ENGLISH
1195      * @constant
1196      * @type {Number}
1197      */
1198     sys.LANGUAGE_ENGLISH = "en";
1199 
1200     /**
1201      * Chinese language code
1202      * @memberof cc.sys
1203      * @name LANGUAGE_CHINESE
1204      * @constant
1205      * @type {Number}
1206      */
1207     sys.LANGUAGE_CHINESE = "zh";
1208 
1209     /**
1210      * French language code
1211      * @memberof cc.sys
1212      * @name LANGUAGE_FRENCH
1213      * @constant
1214      * @type {Number}
1215      */
1216     sys.LANGUAGE_FRENCH = "fr";
1217 
1218     /**
1219      * Italian language code
1220      * @memberof cc.sys
1221      * @name LANGUAGE_ITALIAN
1222      * @constant
1223      * @type {Number}
1224      */
1225     sys.LANGUAGE_ITALIAN = "it";
1226 
1227     /**
1228      * German language code
1229      * @memberof cc.sys
1230      * @name LANGUAGE_GERMAN
1231      * @constant
1232      * @type {Number}
1233      */
1234     sys.LANGUAGE_GERMAN = "de";
1235 
1236     /**
1237      * Spanish language code
1238      * @memberof cc.sys
1239      * @name LANGUAGE_SPANISH
1240      * @constant
1241      * @type {Number}
1242      */
1243     sys.LANGUAGE_SPANISH = "es";
1244 
1245     /**
1246      * Spanish language code
1247      * @memberof cc.sys
1248      * @name LANGUAGE_DUTCH
1249      * @constant
1250      * @type {Number}
1251      */
1252     sys.LANGUAGE_DUTCH = "du";
1253 
1254     /**
1255      * Russian language code
1256      * @memberof cc.sys
1257      * @name LANGUAGE_RUSSIAN
1258      * @constant
1259      * @type {Number}
1260      */
1261     sys.LANGUAGE_RUSSIAN = "ru";
1262 
1263     /**
1264      * Korean language code
1265      * @memberof cc.sys
1266      * @name LANGUAGE_KOREAN
1267      * @constant
1268      * @type {Number}
1269      */
1270     sys.LANGUAGE_KOREAN = "ko";
1271 
1272     /**
1273      * Japanese language code
1274      * @memberof cc.sys
1275      * @name LANGUAGE_JAPANESE
1276      * @constant
1277      * @type {Number}
1278      */
1279     sys.LANGUAGE_JAPANESE = "ja";
1280 
1281     /**
1282      * Hungarian language code
1283      * @memberof cc.sys
1284      * @name LANGUAGE_HUNGARIAN
1285      * @constant
1286      * @type {Number}
1287      */
1288     sys.LANGUAGE_HUNGARIAN = "hu";
1289 
1290     /**
1291      * Portuguese language code
1292      * @memberof cc.sys
1293      * @name LANGUAGE_PORTUGUESE
1294      * @constant
1295      * @type {Number}
1296      */
1297     sys.LANGUAGE_PORTUGUESE = "pt";
1298 
1299     /**
1300      * Arabic language code
1301      * @memberof cc.sys
1302      * @name LANGUAGE_ARABIC
1303      * @constant
1304      * @type {Number}
1305      */
1306     sys.LANGUAGE_ARABIC = "ar";
1307 
1308     /**
1309      * Norwegian language code
1310      * @memberof cc.sys
1311      * @name LANGUAGE_NORWEGIAN
1312      * @constant
1313      * @type {Number}
1314      */
1315     sys.LANGUAGE_NORWEGIAN = "no";
1316 
1317     /**
1318      * Polish language code
1319      * @memberof cc.sys
1320      * @name LANGUAGE_POLISH
1321      * @constant
1322      * @type {Number}
1323      */
1324     sys.LANGUAGE_POLISH = "pl";
1325 
1326     /**
1327      * @memberof cc.sys
1328      * @name OS_IOS
1329      * @constant
1330      * @type {string}
1331      */
1332     sys.OS_IOS = "iOS";
1333     /**
1334      * @memberof cc.sys
1335      * @name OS_ANDROID
1336      * @constant
1337      * @type {string}
1338      */
1339     sys.OS_ANDROID = "Android";
1340     /**
1341      * @memberof cc.sys
1342      * @name OS_WINDOWS
1343      * @constant
1344      * @type {string}
1345      */
1346     sys.OS_WINDOWS = "Windows";
1347     /**
1348      * @memberof cc.sys
1349      * @name OS_MARMALADE
1350      * @constant
1351      * @type {string}
1352      */
1353     sys.OS_MARMALADE = "Marmalade";
1354     /**
1355      * @memberof cc.sys
1356      * @name OS_LINUX
1357      * @constant
1358      * @type {string}
1359      */
1360     sys.OS_LINUX = "Linux";
1361     /**
1362      * @memberof cc.sys
1363      * @name OS_BADA
1364      * @constant
1365      * @type {string}
1366      */
1367     sys.OS_BADA = "Bada";
1368     /**
1369      * @memberof cc.sys
1370      * @name OS_BLACKBERRY
1371      * @constant
1372      * @type {string}
1373      */
1374     sys.OS_BLACKBERRY = "Blackberry";
1375     /**
1376      * @memberof cc.sys
1377      * @name OS_OSX
1378      * @constant
1379      * @type {string}
1380      */
1381     sys.OS_OSX = "OS X";
1382     /**
1383      * @memberof cc.sys
1384      * @name OS_WP8
1385      * @constant
1386      * @type {string}
1387      */
1388     sys.OS_WP8 = "WP8";
1389     /**
1390      * @memberof cc.sys
1391      * @name OS_WINRT
1392      * @constant
1393      * @type {string}
1394      */
1395     sys.OS_WINRT = "WINRT";
1396     /**
1397      * @memberof cc.sys
1398      * @name OS_UNKNOWN
1399      * @constant
1400      * @type {string}
1401      */
1402     sys.OS_UNKNOWN = "Unknown";
1403 
1404     /**
1405      * @memberof cc.sys
1406      * @name UNKNOWN
1407      * @constant
1408      * @default
1409      * @type {Number}
1410      */
1411     sys.UNKNOWN = -1;
1412     /**
1413      * @memberof cc.sys
1414      * @name WIN32
1415      * @constant
1416      * @default
1417      * @type {Number}
1418      */
1419     sys.WIN32 = 0;
1420     /**
1421      * @memberof cc.sys
1422      * @name LINUX
1423      * @constant
1424      * @default
1425      * @type {Number}
1426      */
1427     sys.LINUX = 1;
1428     /**
1429      * @memberof cc.sys
1430      * @name MACOS
1431      * @constant
1432      * @default
1433      * @type {Number}
1434      */
1435     sys.MACOS = 2;
1436     /**
1437      * @memberof cc.sys
1438      * @name ANDROID
1439      * @constant
1440      * @default
1441      * @type {Number}
1442      */
1443     sys.ANDROID = 3;
1444     /**
1445      * @memberof cc.sys
1446      * @name IOS
1447      * @constant
1448      * @default
1449      * @type {Number}
1450      */
1451     sys.IPHONE = 4;
1452     /**
1453      * @memberof cc.sys
1454      * @name IOS
1455      * @constant
1456      * @default
1457      * @type {Number}
1458      */
1459     sys.IPAD = 5;
1460     /**
1461      * @memberof cc.sys
1462      * @name BLACKBERRY
1463      * @constant
1464      * @default
1465      * @type {Number}
1466      */
1467     sys.BLACKBERRY = 6;
1468     /**
1469      * @memberof cc.sys
1470      * @name NACL
1471      * @constant
1472      * @default
1473      * @type {Number}
1474      */
1475     sys.NACL = 7;
1476     /**
1477      * @memberof cc.sys
1478      * @name EMSCRIPTEN
1479      * @constant
1480      * @default
1481      * @type {Number}
1482      */
1483     sys.EMSCRIPTEN = 8;
1484     /**
1485      * @memberof cc.sys
1486      * @name TIZEN
1487      * @constant
1488      * @default
1489      * @type {Number}
1490      */
1491     sys.TIZEN = 9;
1492     /**
1493      * @memberof cc.sys
1494      * @name WINRT
1495      * @constant
1496      * @default
1497      * @type {Number}
1498      */
1499     sys.WINRT = 10;
1500     /**
1501      * @memberof cc.sys
1502      * @name WP8
1503      * @constant
1504      * @default
1505      * @type {Number}
1506      */
1507     sys.WP8 = 11;
1508     /**
1509      * @memberof cc.sys
1510      * @name MOBILE_BROWSER
1511      * @constant
1512      * @default
1513      * @type {Number}
1514      */
1515     sys.MOBILE_BROWSER = 100;
1516     /**
1517      * @memberof cc.sys
1518      * @name DESKTOP_BROWSER
1519      * @constant
1520      * @default
1521      * @type {Number}
1522      */
1523     sys.DESKTOP_BROWSER = 101;
1524 
1525     sys.BROWSER_TYPE_WECHAT = "wechat";
1526     sys.BROWSER_TYPE_ANDROID = "androidbrowser";
1527     sys.BROWSER_TYPE_IE = "ie";
1528     sys.BROWSER_TYPE_QQ = "qqbrowser";
1529     sys.BROWSER_TYPE_MOBILE_QQ = "mqqbrowser";
1530     sys.BROWSER_TYPE_UC = "ucbrowser";
1531     sys.BROWSER_TYPE_360 = "360browser";
1532     sys.BROWSER_TYPE_BAIDU_APP = "baiduboxapp";
1533     sys.BROWSER_TYPE_BAIDU = "baidubrowser";
1534     sys.BROWSER_TYPE_MAXTHON = "maxthon";
1535     sys.BROWSER_TYPE_OPERA = "opera";
1536     sys.BROWSER_TYPE_OUPENG = "oupeng";
1537     sys.BROWSER_TYPE_MIUI = "miuibrowser";
1538     sys.BROWSER_TYPE_FIREFOX = "firefox";
1539     sys.BROWSER_TYPE_SAFARI = "safari";
1540     sys.BROWSER_TYPE_CHROME = "chrome";
1541     sys.BROWSER_TYPE_LIEBAO = "liebao";
1542     sys.BROWSER_TYPE_QZONE = "qzone";
1543     sys.BROWSER_TYPE_SOUGOU = "sogou";
1544     sys.BROWSER_TYPE_UNKNOWN = "unknown";
1545 
1546     /**
1547      * Is native ? This is set to be true in jsb auto.
1548      * @memberof cc.sys
1549      * @name isNative
1550      * @type {Boolean}
1551      */
1552     sys.isNative = false;
1553 
1554     var win = window, nav = win.navigator, doc = document, docEle = doc.documentElement;
1555     var ua = nav.userAgent.toLowerCase();
1556 
1557     /**
1558      * Indicate whether system is mobile system
1559      * @memberof cc.sys
1560      * @name isMobile
1561      * @type {Boolean}
1562      */
1563     sys.isMobile = ua.indexOf('mobile') !== -1 || ua.indexOf('android') !== -1;
1564 
1565     /**
1566      * Indicate the running platform
1567      * @memberof cc.sys
1568      * @name platform
1569      * @type {Number}
1570      */
1571     sys.platform = sys.isMobile ? sys.MOBILE_BROWSER : sys.DESKTOP_BROWSER;
1572 
1573     var currLanguage = nav.language;
1574     currLanguage = currLanguage ? currLanguage : nav.browserLanguage;
1575     currLanguage = currLanguage ? currLanguage.split("-")[0] : sys.LANGUAGE_ENGLISH;
1576 
1577     /**
1578      * Indicate the current language of the running system
1579      * @memberof cc.sys
1580      * @name language
1581      * @type {String}
1582      */
1583     sys.language = currLanguage;
1584 
1585     var browserType = sys.BROWSER_TYPE_UNKNOWN;
1586     var browserTypes = ua.match(/sogou|qzone|liebao|micromessenger|qqbrowser|ucbrowser|360 aphone|360browser|baiduboxapp|baidubrowser|maxthon|trident|oupeng|opera|miuibrowser|firefox/i)
1587         || ua.match(/chrome|safari/i);
1588     if (browserTypes && browserTypes.length > 0) {
1589         browserType = browserTypes[0];
1590         if (browserType === 'micromessenger') {
1591             browserType = sys.BROWSER_TYPE_WECHAT;
1592         } else if (browserType === "safari" && (ua.match(/android.*applewebkit/)))
1593             browserType = sys.BROWSER_TYPE_ANDROID;
1594         else if (browserType === "trident") browserType = sys.BROWSER_TYPE_IE;
1595         else if (browserType === "360 aphone") browserType = sys.BROWSER_TYPE_360;
1596     }else if(ua.indexOf("iphone") && ua.indexOf("mobile")){
1597         browserType = "safari";
1598     }
1599     /**
1600      * Indicate the running browser type
1601      * @memberof cc.sys
1602      * @name browserType
1603      * @type {String}
1604      */
1605     sys.browserType = browserType;
1606 
1607     // Get the os of system
1608     var iOS = ( ua.match(/(iPad|iPhone|iPod)/i) ? true : false );
1609     var isAndroid = ua.match(/android/i) || nav.platform.match(/android/i) ? true : false;
1610     var osName = sys.OS_UNKNOWN;
1611     if (nav.appVersion.indexOf("Win") !== -1) osName = sys.OS_WINDOWS;
1612     else if (iOS) osName = sys.OS_IOS;
1613     else if (nav.appVersion.indexOf("Mac") !== -1) osName = sys.OS_OSX;
1614     else if (nav.appVersion.indexOf("X11") !== -1 && nav.appVersion.indexOf("Linux") === -1) osName = sys.OS_UNIX;
1615     else if (isAndroid) osName = sys.OS_ANDROID;
1616     else if (nav.appVersion.indexOf("Linux") !== -1) osName = sys.OS_LINUX;
1617 
1618     /**
1619      * Indicate the running os name
1620      * @memberof cc.sys
1621      * @name os
1622      * @type {String}
1623      */
1624     sys.os = osName;
1625 
1626     var multipleAudioWhiteList = [
1627         sys.BROWSER_TYPE_BAIDU, sys.BROWSER_TYPE_OPERA, sys.BROWSER_TYPE_FIREFOX, sys.BROWSER_TYPE_CHROME, sys.BROWSER_TYPE_BAIDU_APP,
1628         sys.BROWSER_TYPE_SAFARI, sys.BROWSER_TYPE_UC, sys.BROWSER_TYPE_QQ, sys.BROWSER_TYPE_MOBILE_QQ, sys.BROWSER_TYPE_IE
1629     ];
1630 
1631     sys._supportMultipleAudio = multipleAudioWhiteList.indexOf(sys.browserType) > -1;
1632 
1633 
1634     //++++++++++++++++++something about cc._renderTYpe and cc._supportRender begin++++++++++++++++++++++++++++
1635 
1636     (function(sys, config){
1637         var userRenderMode = config[CONFIG_KEY.renderMode] - 0;
1638         if(isNaN(userRenderMode) || userRenderMode > 2 || userRenderMode < 0)
1639             userRenderMode = 0;
1640         var shieldOs = [sys.OS_ANDROID];
1641         var shieldBrowser = [];
1642         var tmpCanvas = cc.newElement("canvas");
1643         cc._renderType = cc._RENDER_TYPE_CANVAS;
1644         cc._supportRender = false;
1645 
1646         var supportWebGL = win.WebGLRenderingContext;
1647 
1648         if(userRenderMode === 2 || (userRenderMode === 0 && supportWebGL && shieldOs.indexOf(sys.os) === -1 && shieldBrowser.indexOf(sys.browserType) === -1))
1649             try{
1650                 var context = cc.create3DContext(tmpCanvas, {'stencil': true, 'preserveDrawingBuffer': true });
1651                 if(context){
1652                     cc._renderType = cc._RENDER_TYPE_WEBGL;
1653                     cc._supportRender = true;
1654                 }
1655             }catch(e){}
1656 
1657         if(userRenderMode === 1 || (userRenderMode === 0 && cc._supportRender === false))
1658             try {
1659                 tmpCanvas.getContext("2d");
1660                 cc._renderType = cc._RENDER_TYPE_CANVAS;
1661                 cc._supportRender = true;
1662             } catch (e) {}
1663     })(sys, config);
1664 
1665     sys._canUseCanvasNewBlendModes = function(){
1666         var canvas = document.createElement('canvas');
1667         canvas.width = 1;
1668         canvas.height = 1;
1669         var context = canvas.getContext('2d');
1670         context.fillStyle = '#000';
1671         context.fillRect(0,0,1,1);
1672         context.globalCompositeOperation = 'multiply';
1673 
1674         var canvas2 = document.createElement('canvas');
1675         canvas2.width = 1;
1676         canvas2.height = 1;
1677         var context2 = canvas2.getContext('2d');
1678         context2.fillStyle = '#fff';
1679         context2.fillRect(0,0,1,1);
1680 
1681         context.drawImage(canvas2, 0, 0, 1, 1);
1682 
1683         return context.getImageData(0,0,1,1).data[0] === 0;
1684     };
1685 
1686     //Whether or not the Canvas BlendModes are supported.
1687     sys._supportCanvasNewBlendModes = sys._canUseCanvasNewBlendModes();
1688 
1689     //++++++++++++++++++something about cc._renderType and cc._supportRender end++++++++++++++++++++++++++++++
1690 
1691     // check if browser supports Web Audio
1692     // check Web Audio's context
1693     try {
1694         sys._supportWebAudio = !!(win.AudioContext || win.webkitAudioContext || win.mozAudioContext);
1695     } catch (e) {
1696         sys._supportWebAudio = false;
1697     }
1698 
1699     /**
1700      * cc.sys.localStorage is a local storage component.
1701      * @memberof cc.sys
1702      * @name localStorage
1703      * @type {Object}
1704      */
1705     try {
1706         var localStorage = sys.localStorage = win.localStorage;
1707         localStorage.setItem("storage", "");
1708         localStorage.removeItem("storage");
1709         localStorage = null;
1710     } catch (e) {
1711         var warn = function () {
1712             cc.warn("Warning: localStorage isn't enabled. Please confirm browser cookie or privacy option");
1713         }
1714         sys.localStorage = {
1715             getItem : warn,
1716             setItem : warn,
1717             removeItem : warn,
1718             clear : warn
1719         };
1720     }
1721 
1722     var capabilities = sys.capabilities = {"canvas": true};
1723     if (cc._renderType === cc._RENDER_TYPE_WEBGL)
1724         capabilities["opengl"] = true;
1725     if (docEle['ontouchstart'] !== undefined || doc['ontouchstart'] !== undefined || nav.msPointerEnabled)
1726         capabilities["touches"] = true;
1727     if (docEle['onmouseup'] !== undefined)
1728         capabilities["mouse"] = true;
1729     if (docEle['onkeyup'] !== undefined)
1730         capabilities["keyboard"] = true;
1731     if (win.DeviceMotionEvent || win.DeviceOrientationEvent)
1732         capabilities["accelerometer"] = true;
1733 
1734     /**
1735      * Forces the garbage collection, only available in JSB
1736      * @memberof cc.sys
1737      * @name garbageCollect
1738      * @function
1739      */
1740     sys.garbageCollect = function () {
1741         // N/A in cocos2d-html5
1742     };
1743 
1744     /**
1745      * Dumps rooted objects, only available in JSB
1746      * @memberof cc.sys
1747      * @name dumpRoot
1748      * @function
1749      */
1750     sys.dumpRoot = function () {
1751         // N/A in cocos2d-html5
1752     };
1753 
1754     /**
1755      * Restart the JS VM, only available in JSB
1756      * @memberof cc.sys
1757      * @name restartVM
1758      * @function
1759      */
1760     sys.restartVM = function () {
1761         // N/A in cocos2d-html5
1762     };
1763 
1764     /**
1765      * Clean a script in the JS VM, only available in JSB
1766      * @memberof cc.sys
1767      * @name cleanScript
1768      * @param {String} jsfile
1769      * @function
1770      */
1771     sys.cleanScript = function (jsfile) {
1772         // N/A in cocos2d-html5
1773     };
1774 
1775     /**
1776      * Check whether an object is valid,
1777      * In web engine, it will return true if the object exist
1778      * In native engine, it will return true if the JS object and the correspond native object are both valid
1779      * @memberof cc.sys
1780      * @name isObjectValid
1781      * @param {Object} obj
1782      * @return {boolean} Validity of the object
1783      * @function
1784      */
1785     sys.isObjectValid = function (obj) {
1786         if (obj) return true;
1787         else return false;
1788     };
1789 
1790     /**
1791      * Dump system informations
1792      * @memberof cc.sys
1793      * @name dump
1794      * @function
1795      */
1796     sys.dump = function () {
1797         var self = this;
1798         var str = "";
1799         str += "isMobile : " + self.isMobile + "\r\n";
1800         str += "language : " + self.language + "\r\n";
1801         str += "browserType : " + self.browserType + "\r\n";
1802         str += "capabilities : " + JSON.stringify(self.capabilities) + "\r\n";
1803         str += "os : " + self.os + "\r\n";
1804         str += "platform : " + self.platform + "\r\n";
1805         cc.log(str);
1806     }
1807 
1808     /**
1809      * Open a url in browser
1810      * @memberof cc.sys
1811      * @name openURL
1812      * @param {String} url
1813      */
1814     sys.openURL = function(url){
1815         window.open(url);
1816     }
1817 };
1818 
1819 //+++++++++++++++++++++++++something about sys end+++++++++++++++++++++++++++++
1820 
1821 //+++++++++++++++++++++++++something about CCGame begin+++++++++++++++++++++++++++
1822 
1823 /**
1824  * Device oriented vertically, home button on the bottom
1825  * @constant
1826  * @type {Number}
1827  */
1828 cc.ORIENTATION_PORTRAIT = 0;
1829 
1830 /**
1831  * Device oriented vertically, home button on the top
1832  * @constant
1833  * @type {Number}
1834  */
1835 cc.ORIENTATION_PORTRAIT_UPSIDE_DOWN = 1;
1836 
1837 /**
1838  * Device oriented horizontally, home button on the right
1839  * @constant
1840  * @type {Number}
1841  */
1842 cc.ORIENTATION_LANDSCAPE_LEFT = 2;
1843 
1844 /**
1845  * Device oriented horizontally, home button on the left
1846  * @constant
1847  * @type {Number}
1848  */
1849 cc.ORIENTATION_LANDSCAPE_RIGHT = 3;
1850 
1851 /**
1852  * drawing primitive of game engine
1853  * @type {cc.DrawingPrimitive}
1854  */
1855 cc._drawingUtil = null;
1856 
1857 /**
1858  * main Canvas 2D/3D Context of game engine
1859  * @type {CanvasRenderingContext2D|WebGLRenderingContext}
1860  */
1861 cc._renderContext = null;
1862 
1863 /**
1864  * main Canvas of game engine
1865  * @type {HTMLCanvasElement}
1866  */
1867 cc._canvas = null;
1868 
1869 /**
1870  * This Div element contain all game canvas
1871  * @type {HTMLDivElement}
1872  */
1873 cc._gameDiv = null;
1874 
1875 cc._rendererInitialized = false;
1876 /**
1877  * <p>
1878  *   setup game main canvas,renderContext,gameDiv and drawingUtil with argument  <br/>
1879  *   <br/>
1880  *   can receive follow type of arguemnt: <br/>
1881  *      - empty: create a canvas append to document's body, and setup other option    <br/>
1882  *      - string: search the element by document.getElementById(),    <br/>
1883  *          if this element is HTMLCanvasElement, set this element as main canvas of engine, and set it's ParentNode as cc._gameDiv.<br/>
1884  *          if this element is HTMLDivElement, set it's ParentNode to cc._gameDiv, and create a canvas as main canvas of engine.   <br/>
1885  * </p>
1886  * @function
1887  * @example
1888  * //setup with null
1889  * cc._setup();
1890  *
1891  * // setup with HTMLCanvasElement, gameCanvas is Canvas element
1892  * // declare like this: <canvas id="gameCanvas" width="800" height="450"></canvas>
1893  * cc._setup("gameCanvas");
1894  *
1895  * //setup with HTMLDivElement, gameDiv is Div element
1896  * // declare like this: <div id="Cocos2dGameContainer" width="800" height="450"></div>
1897  * cc._setup("Cocos2dGameContainer");
1898  */
1899 cc._setupCalled = false;
1900 cc._setup = function (el, width, height) {
1901     // Avoid setup to be called twice.
1902     if (cc._setupCalled) return;
1903     else cc._setupCalled = true;
1904     var win = window;
1905     var element = cc.$(el) || cc.$('#' + el);
1906     var localCanvas, localContainer, localConStyle;
1907 
1908     cc.game._setAnimFrame();
1909 
1910     if (element.tagName === "CANVAS") {
1911         width = width || element.width;
1912         height = height || element.height;
1913 
1914         //it is already a canvas, we wrap it around with a div
1915         localContainer = cc.container = cc.newElement("DIV");
1916         localCanvas = cc._canvas = element;
1917         localCanvas.parentNode.insertBefore(localContainer, localCanvas);
1918         localCanvas.appendTo(localContainer);
1919         localContainer.setAttribute('id', 'Cocos2dGameContainer');
1920     } else {//we must make a new canvas and place into this element
1921         if (element.tagName !== "DIV") {
1922             cc.log("Warning: target element is not a DIV or CANVAS");
1923         }
1924         width = width || element.clientWidth;
1925         height = height || element.clientHeight;
1926         localContainer = cc.container = element;
1927         localCanvas = cc._canvas = cc.$(cc.newElement("CANVAS"));
1928         element.appendChild(localCanvas);
1929     }
1930 
1931     localCanvas.addClass("gameCanvas");
1932     localCanvas.setAttribute("width", width || 480);
1933     localCanvas.setAttribute("height", height || 320);
1934     localCanvas.setAttribute("tabindex", 99);
1935     localCanvas.style.outline = "none";
1936     localConStyle = localContainer.style;
1937     localConStyle.width = (width || 480) + "px";
1938     localConStyle.height = (height || 320) + "px";
1939     localConStyle.margin = "0 auto";
1940 
1941     localConStyle.position = 'relative';
1942     localConStyle.overflow = 'hidden';
1943     localContainer.top = '100%';
1944 
1945     if (cc._renderType === cc._RENDER_TYPE_WEBGL)
1946         cc._renderContext = cc.webglContext = cc.create3DContext(localCanvas, {
1947             'stencil': true,
1948             'preserveDrawingBuffer': true,
1949             'antialias': !cc.sys.isMobile,
1950             'alpha': false
1951         });
1952     if (cc._renderContext) {
1953         win.gl = cc._renderContext; // global variable declared in CCMacro.js
1954         cc._drawingUtil = new cc.DrawingPrimitiveWebGL(cc._renderContext);
1955         cc._rendererInitialized = true;
1956         cc.textureCache._initializingRenderer();
1957         cc.shaderCache._init();
1958     } else {
1959         cc._renderContext = new cc.CanvasContextWrapper(localCanvas.getContext("2d"));
1960         cc._drawingUtil = cc.DrawingPrimitiveCanvas ? new cc.DrawingPrimitiveCanvas(cc._renderContext) : null;
1961     }
1962 
1963     cc._gameDiv = localContainer;
1964     cc.log(cc.ENGINE_VERSION);
1965     cc._setContextMenuEnable(false);
1966 
1967     if (cc.sys.isMobile) {
1968         var fontStyle = cc.newElement("style");
1969         fontStyle.type = "text/css";
1970         document.body.appendChild(fontStyle);
1971 
1972         fontStyle.textContent = "body,canvas,div{ -moz-user-select: none;-webkit-user-select: none;-ms-user-select: none;-khtml-user-select: none;"
1973             + "-webkit-tap-highlight-color:rgba(0,0,0,0);}";
1974     }
1975 
1976     // Init singletons
1977 
1978     /**
1979      * @type {cc.EGLView}
1980      * @name cc.view
1981      * cc.view is the shared view object.
1982      */
1983     cc.view = cc.EGLView._getInstance();
1984     // register system events
1985     cc.inputManager.registerSystemEvent(cc._canvas);
1986 
1987     /**
1988      * @type {cc.Director}
1989      * @name cc.director
1990      */
1991     cc.director = cc.Director._getInstance();
1992     if (cc.director.setOpenGLView)
1993         cc.director.setOpenGLView(cc.view);
1994     /**
1995      * @type {cc.Size}
1996      * @name cc.winSize
1997      * cc.winSize is the alias object for the size of the current game window.
1998      */
1999     cc.winSize = cc.director.getWinSize();
2000 
2001     // Parsers
2002     cc.saxParser = new cc.SAXParser();
2003     /**
2004      * @type {cc.PlistParser}
2005      * @name cc.plistParser
2006      * A Plist Parser
2007      */
2008     cc.plistParser = new cc.PlistParser();
2009 };
2010 
2011 cc._checkWebGLRenderMode = function () {
2012     if (cc._renderType !== cc._RENDER_TYPE_WEBGL)
2013         throw "This feature supports WebGL render mode only.";
2014 };
2015 
2016 cc._isContextMenuEnable = false;
2017 /**
2018  * enable/disable contextMenu for Canvas
2019  * @param {Boolean} enabled
2020  */
2021 cc._setContextMenuEnable = function (enabled) {
2022     cc._isContextMenuEnable = enabled;
2023     cc._canvas.oncontextmenu = function () {
2024         if (!cc._isContextMenuEnable) return false;
2025     };
2026 };
2027 
2028 /**
2029  * An object to boot the game.
2030  * @class
2031  * @name cc.game
2032  */
2033 cc.game = /** @lends cc.game# */{
2034     DEBUG_MODE_NONE: 0,
2035     DEBUG_MODE_INFO: 1,
2036     DEBUG_MODE_WARN: 2,
2037     DEBUG_MODE_ERROR: 3,
2038     DEBUG_MODE_INFO_FOR_WEB_PAGE: 4,
2039     DEBUG_MODE_WARN_FOR_WEB_PAGE: 5,
2040     DEBUG_MODE_ERROR_FOR_WEB_PAGE: 6,
2041 
2042     EVENT_HIDE: "game_on_hide",
2043     EVENT_SHOW: "game_on_show",
2044     EVENT_RESIZE: "game_on_resize",
2045     _eventHide: null,
2046     _eventShow: null,
2047     _onBeforeStartArr: [],
2048 
2049     /**
2050      * Key of config
2051      * @constant
2052      * @type {Object}
2053      */
2054     CONFIG_KEY: {
2055         engineDir: "engineDir",
2056         dependencies: "dependencies",
2057         debugMode: "debugMode",
2058         showFPS: "showFPS",
2059         frameRate: "frameRate",
2060         id: "id",
2061         renderMode: "renderMode",
2062         jsList: "jsList",
2063         classReleaseMode: "classReleaseMode"
2064     },
2065 
2066     _prepareCalled: false,//whether the prepare function has been called
2067     _prepared: false,//whether the engine has prepared
2068     _paused: true,//whether the game is paused
2069 
2070     _intervalId: null,//interval target of main
2071     
2072     _lastTime: null,
2073     _frameTime: null,
2074 
2075     /**
2076      * Config of game
2077      * @type {Object}
2078      */
2079     config: null,
2080 
2081     /**
2082      * Callback when the scripts of engine have been load.
2083      * @type {Function}
2084      */
2085     onStart: null,
2086 
2087     /**
2088      * Callback when game exits.
2089      * @type {Function}
2090      */
2091     onStop: null,
2092 
2093     /**
2094      * Set frameRate of game.
2095      * @param frameRate
2096      */
2097     setFrameRate: function (frameRate) {
2098         var self = this, config = self.config, CONFIG_KEY = self.CONFIG_KEY;
2099         config[CONFIG_KEY.frameRate] = frameRate;
2100         if (self._intervalId)
2101             window.cancelAnimationFrame(self._intervalId);
2102         self._paused = true;
2103         self._setAnimFrame();
2104         self._runMainLoop();
2105     },
2106     _setAnimFrame: function () {
2107         this._lastTime = new Date();
2108         this._frameTime = 1000 / cc.game.config[cc.game.CONFIG_KEY.frameRate];
2109         if((cc.sys.os === cc.sys.OS_IOS && cc.sys.browserType === cc.sys.BROWSER_TYPE_WECHAT) || cc.game.config[cc.game.CONFIG_KEY.frameRate] !== 60) {
2110             window.requestAnimFrame = this._stTime;
2111             window.cancelAnimationFrame = this._ctTime;
2112         }
2113         else {
2114             window.requestAnimFrame = window.requestAnimationFrame ||
2115             window.webkitRequestAnimationFrame ||
2116             window.mozRequestAnimationFrame ||
2117             window.oRequestAnimationFrame ||
2118             window.msRequestAnimationFrame ||
2119             this._stTime;
2120             window.cancelAnimationFrame = window.cancelAnimationFrame ||
2121             window.cancelRequestAnimationFrame ||
2122             window.msCancelRequestAnimationFrame ||
2123             window.mozCancelRequestAnimationFrame ||
2124             window.oCancelRequestAnimationFrame ||
2125             window.webkitCancelRequestAnimationFrame ||
2126             window.msCancelAnimationFrame ||
2127             window.mozCancelAnimationFrame ||
2128             window.webkitCancelAnimationFrame ||
2129             window.oCancelAnimationFrame ||
2130             this._ctTime;
2131         }
2132     },
2133     _stTime: function(callback){
2134         var currTime = new Date().getTime();
2135         var timeToCall = Math.max(0, cc.game._frameTime - (currTime - cc.game._lastTime));
2136         var id = window.setTimeout(function() { callback(); },
2137             timeToCall);
2138         cc.game._lastTime = currTime + timeToCall;
2139         return id;
2140     },
2141     _ctTime: function(id){
2142         window.clearTimeout(id);
2143     },
2144     //Run game.
2145     _runMainLoop: function () {
2146         var self = this, callback, config = self.config, CONFIG_KEY = self.CONFIG_KEY,
2147             director = cc.director;
2148 
2149         director.setDisplayStats(config[CONFIG_KEY.showFPS]);
2150 
2151         callback = function () {
2152             if (!self._paused) {
2153                 director.mainLoop();
2154                 if(self._intervalId)
2155                     window.cancelAnimationFrame(self._intervalId);
2156                 self._intervalId = window.requestAnimFrame(callback);
2157             }
2158         };
2159 
2160         window.requestAnimFrame(callback);
2161         self._paused = false;
2162     },
2163 
2164     /**
2165      * Restart game.
2166      */
2167     restart: function () {
2168         cc.director.popToSceneStackLevel(0);
2169         // Clean up audio
2170         cc.audioEngine && cc.audioEngine.end();
2171 
2172         cc.game.onStart();
2173     },
2174 
2175     /**
2176      * Run game.
2177      */
2178     run: function (id) {
2179         var self = this;
2180         var _run = function () {
2181             if (id) {
2182                 self.config[self.CONFIG_KEY.id] = id;
2183             }
2184             if (!self._prepareCalled) {
2185                 self.prepare(function () {
2186                     self._prepared = true;
2187                 });
2188             }
2189             if (cc._supportRender) {
2190                 self._checkPrepare = setInterval(function () {
2191                     if (self._prepared) {
2192                         cc._setup(self.config[self.CONFIG_KEY.id]);
2193                         self._runMainLoop();
2194                         self._eventHide = self._eventHide || new cc.EventCustom(self.EVENT_HIDE);
2195                         self._eventHide.setUserData(self);
2196                         self._eventShow = self._eventShow || new cc.EventCustom(self.EVENT_SHOW);
2197                         self._eventShow.setUserData(self);
2198                         self.onStart();
2199                         clearInterval(self._checkPrepare);
2200                     }
2201                 }, 10);
2202             }
2203         };
2204         document.body ?
2205             _run() :
2206             cc._addEventListener(window, 'load', function () {
2207                 this.removeEventListener('load', arguments.callee, false);
2208                 _run();
2209             }, false);
2210     },
2211 
2212     _initConfig: function () {
2213         var self = this, CONFIG_KEY = self.CONFIG_KEY;
2214         var _init = function (cfg) {
2215             cfg[CONFIG_KEY.engineDir] = cfg[CONFIG_KEY.engineDir] || "frameworks/cocos2d-html5";
2216             if(cfg[CONFIG_KEY.debugMode] == null)
2217                 cfg[CONFIG_KEY.debugMode] = 0;
2218             cfg[CONFIG_KEY.frameRate] = cfg[CONFIG_KEY.frameRate] || 60;
2219             if(cfg[CONFIG_KEY.renderMode] == null)
2220                 cfg[CONFIG_KEY.renderMode] = 1;
2221             return cfg;
2222         };
2223         if (document["ccConfig"]) {
2224             self.config = _init(document["ccConfig"]);
2225         } else {
2226             try {
2227                 var cocos_script = document.getElementsByTagName('script');
2228                 for(var i=0;i<cocos_script.length;i++){
2229                     var _t = cocos_script[i].getAttribute('cocos');
2230                     if(_t === '' || _t){break;}
2231                 }
2232                 var _src, txt, _resPath;
2233                 if(i < cocos_script.length){
2234                     _src = cocos_script[i].src;
2235                     if(_src){
2236                         _resPath = /(.*)\//.exec(_src)[0];
2237                         cc.loader.resPath = _resPath;
2238                         _src = cc.path.join(_resPath, 'project.json');
2239                     }
2240                     txt = cc.loader._loadTxtSync(_src);
2241                 }
2242                 if(!txt){
2243                     txt = cc.loader._loadTxtSync("project.json");
2244                 }
2245                 var data = JSON.parse(txt);
2246                 self.config = _init(data || {});
2247             } catch (e) {
2248                 cc.log("Failed to read or parse project.json");
2249                 self.config = _init({});
2250             }
2251         }
2252         //init debug move to CCDebugger
2253         cc._initSys(self.config, CONFIG_KEY);
2254     },
2255 
2256     //cache for js and module that has added into jsList to be loaded.
2257     _jsAddedCache: {},
2258     _getJsListOfModule: function (moduleMap, moduleName, dir) {
2259         var jsAddedCache = this._jsAddedCache;
2260         if (jsAddedCache[moduleName]) return null;
2261         dir = dir || "";
2262         var jsList = [];
2263         var tempList = moduleMap[moduleName];
2264         if (!tempList) throw "can not find module [" + moduleName + "]";
2265         var ccPath = cc.path;
2266         for (var i = 0, li = tempList.length; i < li; i++) {
2267             var item = tempList[i];
2268             if (jsAddedCache[item]) continue;
2269             var extname = ccPath.extname(item);
2270             if (!extname) {
2271                 var arr = this._getJsListOfModule(moduleMap, item, dir);
2272                 if (arr) jsList = jsList.concat(arr);
2273             } else if (extname.toLowerCase() === ".js") jsList.push(ccPath.join(dir, item));
2274             jsAddedCache[item] = 1;
2275         }
2276         return jsList;
2277     },
2278     /**
2279      * Prepare game.
2280      * @param cb
2281      */
2282     prepare: function (cb) {
2283         var self = this;
2284         var config = self.config, CONFIG_KEY = self.CONFIG_KEY, engineDir = config[CONFIG_KEY.engineDir], loader = cc.loader;
2285         if (!cc._supportRender) {
2286             throw "The renderer doesn't support the renderMode " + config[CONFIG_KEY.renderMode];
2287         }
2288         self._prepareCalled = true;
2289 
2290         var jsList = config[CONFIG_KEY.jsList] || [];
2291         if (cc.Class) {//is single file
2292             //load user's jsList only
2293             loader.loadJsWithImg("", jsList, function (err) {
2294                 if (err) throw err;
2295                 self._prepared = true;
2296                 if (cb) cb();
2297             });
2298         } else {
2299             //load cc's jsList first
2300             var ccModulesPath = cc.path.join(engineDir, "moduleConfig.json");
2301             loader.loadJson(ccModulesPath, function (err, modulesJson) {
2302                 if (err) throw err;
2303                 var modules = config["modules"] || [];
2304                 var moduleMap = modulesJson["module"];
2305                 var newJsList = [];
2306                 if (cc._renderType === cc._RENDER_TYPE_WEBGL) modules.splice(0, 0, "shaders");
2307                 else if (modules.indexOf("core") < 0) modules.splice(0, 0, "core");
2308                 for (var i = 0, li = modules.length; i < li; i++) {
2309                     var arr = self._getJsListOfModule(moduleMap, modules[i], engineDir);
2310                     if (arr) newJsList = newJsList.concat(arr);
2311                 }
2312                 newJsList = newJsList.concat(jsList);
2313                 cc.loader.loadJsWithImg(newJsList, function (err) {
2314                     if (err) throw err;
2315                     self._prepared = true;
2316                     if (cb) cb();
2317                 });
2318             });
2319         }
2320     }
2321 };
2322 cc.game._initConfig();
2323 //+++++++++++++++++++++++++something about CCGame end+++++++++++++++++++++++++++++
2324 
2325 Function.prototype.bind = Function.prototype.bind || function (oThis) {
2326     if (!cc.isFunction(this)) {
2327         // closest thing possible to the ECMAScript 5
2328         // internal IsCallable function
2329         throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");
2330     }
2331 
2332     var aArgs = Array.prototype.slice.call(arguments, 1),
2333         fToBind = this,
2334         fNOP = function () {},
2335         fBound = function () {
2336             return fToBind.apply(this instanceof fNOP && oThis
2337                 ? this
2338                 : oThis,
2339                 aArgs.concat(Array.prototype.slice.call(arguments)));
2340         };
2341 
2342     fNOP.prototype = this.prototype;
2343     fBound.prototype = new fNOP();
2344 
2345     return fBound;
2346 };
2347 
2348 cc._urlRegExp = new RegExp(
2349     "^" +
2350         // protocol identifier
2351         "(?:(?:https?|ftp)://)" +
2352         // user:pass authentication
2353         "(?:\\S+(?::\\S*)?@)?" +
2354         "(?:" +
2355             // IP address dotted notation octets
2356             // excludes loopback network 0.0.0.0
2357             // excludes reserved space >= 224.0.0.0
2358             // excludes network & broacast addresses
2359             // (first & last IP address of each class)
2360             "(?:[1-9]\\d?|1\\d\\d|2[01]\\d|22[0-3])" +
2361             "(?:\\.(?:1?\\d{1,2}|2[0-4]\\d|25[0-5])){2}" +
2362             "(?:\\.(?:[1-9]\\d?|1\\d\\d|2[0-4]\\d|25[0-4]))" +
2363         "|" +
2364             // host name
2365             "(?:(?:[a-z\\u00a1-\\uffff0-9]-*)*[a-z\\u00a1-\\uffff0-9]+)" +
2366             // domain name
2367             "(?:\\.(?:[a-z\\u00a1-\\uffff0-9]-*)*[a-z\\u00a1-\\uffff0-9]+)*" +
2368             // TLD identifier
2369             "(?:\\.(?:[a-z\\u00a1-\\uffff]{2,}))" +
2370         "|" +
2371             "(?:localhost)" +
2372         ")" +
2373         // port number
2374         "(?::\\d{2,5})?" +
2375         // resource path
2376         "(?:/\\S*)?" +
2377     "$", "i"
2378 );
2379