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 
 27 /**
 28  * create a webgl context
 29  * @param {HTMLCanvasElement} canvas
 30  * @param {Object} opt_attribs
 31  * @return {WebGLRenderingContext}
 32  */
 33 cc.create3DContext = function (canvas, opt_attribs) {
 34     var names = ["webgl", "experimental-webgl", "webkit-3d", "moz-webgl"];
 35     var context = null;
 36     for (var ii = 0; ii < names.length; ++ii) {
 37         try {
 38             context = canvas.getContext(names[ii], opt_attribs);
 39         } catch (e) {
 40         }
 41         if (context) {
 42             break;
 43         }
 44     }
 45     return context;
 46 };
 47 
 48 /**
 49  * Browser detection, based on mootools<br/>
 50  * platform will print out win32, mac, etc<br/>
 51  * type is the browser type, chrome, firefox etc
 52  * @type {Object}
 53  */
 54 cc.Browser = {};
 55 
 56 /**
 57  * Browsers that Cocos2d-HTML5 support well in WebGL render mode
 58  * @type {Array}
 59  */
 60 cc.Browser.webglWhiteList = ["baidubrowser", "opera", "firefox", "chrome", "safari"];
 61 
 62 /**
 63  * Browsers that multiple audio support well
 64  * @type {Array}
 65  */
 66 cc.Browser.multipleAudioWhiteList = ["baidubrowser", "opera", "firefox", "chrome", "safari", "ucbrowser", "qqbrowser", "mqqbrowser", "ie"];
 67 
 68 (function () {
 69     var ua = navigator.userAgent;
 70     cc.Browser.ua = ua.toLowerCase();
 71     cc.Browser.platform = navigator.platform.toLowerCase();
 72     cc.Browser.isMobile = (cc.Browser.ua.indexOf('mobile') != -1 || cc.Browser.ua.indexOf('android') != -1);
 73     cc.Browser.type = (function () {
 74         var browserTypes = cc.Browser.ua.match(/micromessenger|qqbrowser|mqqbrowser|ucbrowser|360browser|baiduboxapp|baidubrowser|maxthon|ie|opera|miuibrowser|firefox/)
 75             || cc.Browser.ua.match(/chrome|safari/);
 76 
 77         if (browserTypes && browserTypes.length > 0) {
 78             var el = browserTypes[0];
 79             if (el == 'micromessenger') {
 80                 return 'wechat';
 81             }else if( el === "safari" && (cc.Browser.ua.match(/android.*applewebkit/) != null))
 82                 return "androidbrowser";
 83             return el;
 84         }
 85         return "unknow";
 86     })();
 87     cc.Browser.mode = cc.Browser.type == 'ie' && document.documentMode;
 88 
 89     if (!document["ccConfig"])
 90         document["ccConfig"] = {};
 91 
 92     var c = document["ccConfig"];
 93     // check supportWebGL item
 94     cc._userRenderMode = parseInt(c["renderMode"]) || 0;
 95 
 96     var notInWhiteList = cc.Browser.webglWhiteList.indexOf(cc.Browser.type) == -1;
 97     if (cc._userRenderMode === 1 || (cc._userRenderMode === 0 && (cc.Browser.isMobile || notInWhiteList))) {
 98         //canvas only
 99         cc.Browser.supportWebGL = false;
100     } else {
101         // WebGL first
102         cc.Browser.supportWebGL = !(window.WebGLRenderingContext == null);
103         var tempCanvas = document.createElement("Canvas");
104         var tempContext = cc.create3DContext(tempCanvas, {'stencil': true, 'preserveDrawingBuffer': true });
105         cc.Browser.supportWebGL = !(tempContext == null)
106     }
107     if (cc._userRenderMode === 2 && !cc.Browser.supportWebGL) {
108         // WebGL render only, but browser doesn't support WebGL.
109         cc.__renderDoesnotSupport = true;
110     }
111 
112     // check if browser supports Web Audio
113     cc.Browser.supportWebAudio = (function () {
114         // check Web Audio's context
115         try {
116             var ctx = new (window.AudioContext || window.webkitAudioContext || window.mozAudioContext)();
117             return ctx ? true : false;
118         } catch (e) {
119             return false;
120         }
121     })();
122 
123 
124     cc.Browser.openURL = function (url) {
125         if (this.isMobile) {
126             var size = cc.Director.getInstance().getWinSize();
127             var w = size.width + "px";
128             var h = size.height + "px";
129 
130             var div = cc.$new("div");
131             div.style.backgroundColor = "#ffffff";
132             div.style.width = w;
133             div.style.height = h;
134             div.style.zindex = 1000;
135             div.style.position = 'absolute';
136             div.style.top = 0 + 'px';
137             div.style.left = 0 + 'px';
138             div.id = "cocos2d-browser";
139 
140             var iframe = cc.$new("iframe");
141             iframe.src = url;
142             iframe.style.width = w;
143             iframe.style.height = h;
144             iframe.setAttribute("frameborder", "no");
145             iframe.setAttribute("scrolling", "no");
146             div.appendChild(iframe);
147 
148             iframe.onload = function () {
149                 var close = document.createElement('img');
150                 close.src = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACEAAAAhCAYAAABX5MJvAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyRpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoTWFjaW50b3NoKSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDo5OERBMEM3OUQzRTMxMUUyODg2Q0RFNjU1QkU1RjlFQSIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDo5OERBMEM3QUQzRTMxMUUyODg2Q0RFNjU1QkU1RjlFQSI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOjk4REEwQzc3RDNFMzExRTI4ODZDREU2NTVCRTVGOUVBIiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOjk4REEwQzc4RDNFMzExRTI4ODZDREU2NTVCRTVGOUVBIi8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+NwBuoAAAA/tJREFUeNrEWF0sW3EUb6+28zFhbGadsBaNhazV+kpDYhFWKRGWbHvwFV5IvPiIFw9evElEPEiWSUgsIWoIglhmUomPxj6aKC0zKVJjtPU5o9j5J7dLdbf33jKc5Jfc3v+v5/+755x7/j1lMoiNBRDh4AO88HvO2m+ACbAC+AJQAyz2JCbBFyMBWQA/xv+3DUAXLuivudhcY4BMwCuAB+NqDPmNAnAAOsCZvQgk4BnjeiwEwAbM2YoQA14yrteQEANgDcML7gXjZgw9OAuJkADu3JAIb7Q/hr+GtCwuLs6LDq+iooLvhBAREhFEl11ZWRne0tIiIeNIpVKv4uJi4dTUVApNt0EY3ohILSIiwqO7u1sql8vD8vLyJJ2dnXH2HDabzczPz3/Y1taWzOfz78XExDxSq9Vyd3d3jMK9F2pWr6lEtLa2RmVnZ4tt7w0NDWlTU1OVtkK7urqSQ0NDzzW5hYWFjcTExAGDwXDkyD+VSkZ7e3tsWlpamP19mUwWplQqk9B1UlKST3NzczxE4K49D4mCiDwn24PyPMjIyHjs6urKIVpLSEgInp6eZsM6Kzw8nEvEMZvNBxC1BbI9KCMhkUgUy8vLRpL1QIFA4EcSyZmcnJzpS4mYnZ3dj46O7p2fn193xIGi/CeiFovlFIp5pqGhYZ5qD1qFiQxCjk1OTsqEQmEAFReloL+/X0sVAadFWE2n02VA+O+TcVZXV01QkO8ODw9P6fjEnO2zvb2936g4XC7XG4rWm65P2iL8/f05kN8nBQUFQkqnGMYcGBjIys3N5dLxjY7ydDrE6urqsNLSUqmbmxuH1tOBkMzMTIHRaNxSqVTmS4soKyvjFRUViTw9PV2dTR901WAOh7M/MjKyeeHCbGpqEhcWFkY5Wl9aWtpUKBRaONziSbsii/Xm5OTk7EIdU6/X7zpaW1xc/Al5HxkfH9/e2dk5rqmpeUrE6+vr06ADzpEIlI5kMjFwPhh5PB5DJBKdK7KDg4Oj2tpaVUdHxw/0eWxszIjyj8Jvy4N60FdVVX2Grnt4dkaowYJESAG3yaLR09Oz5uvrexwbGxuAR2erpKTkI6RqxW5DM6RnLT09PQQV5vDwsDYlJWUU+I4EIDMhEQLAA6q0DA4OrqMCg/c/qL6+XtXY2Kgn4sGJuavRaFbFYrFPeXn5FIj6ReFa64KnIpJOpaMK39vbM9XV1X13lF9kc3Nz+xMTEwZo89s03A4ycRE1N/RjF/WPKgyfDRU39Gu7w1qYyNYAtwDB1yhgGPDBfgzU4bMi7xoEjAI6iWZRdGMGH80Cr2goRlP5W8B7qwBHfw1YO6kEH4yC8EnJ5QKbnuDFh17nr4BPRP9P/BFgAHo7ZNgI9EbHAAAAAElFTkSuQmCC";
151                 div.appendChild(close);
152                 close.style.zindex = 1000;
153                 close.style.position = 'absolute';
154                 close.style.bottom = 10 + 'px';
155                 close.style.right = 10 + 'px';
156                 close.onclick = function () {
157                     div.remove();
158                 }
159             };
160 
161             var tag = document['ccConfig'].tag;
162             var parent = document.getElementById(tag).parentNode;
163             if (parent) {
164                 parent.appendChild(div);
165             }
166         }
167         else {
168             window.open(url);
169         }
170     }
171 })();
172 
173 cc.RenderDoesnotSupport = function () {
174     if (cc.__renderDoesnotSupport === "undefined")
175         return false;
176     return cc.__renderDoesnotSupport;
177 };
178 
179 
180 /**
181  * the dollar sign, classic like jquery, this selector add extra methods to HTMLElement without touching its prototype</br>
182  * it is also chainable like jquery
183  * @param {HTMLElement|String} x pass in a css selector in string or the whole HTMLElement
184  * @class
185  * @return {cc.$}
186  */
187 cc.$ = function (x) {
188     /** @lends cc.$# */
189     var parent = (this == cc) ? document : this;
190 
191     /**
192      * @type {HTMLElement}
193      */
194     var el = (x instanceof HTMLElement) ? x : parent.querySelector(x);
195 
196     if (el) {
197         /**
198          * find and return the child wth css selector (same as jquery.find)
199          * @param {HTMLElement|String} x pass in a css selector in string or the whole HTMLElement
200          * @return {cc.$}
201          */
202         el.find = el.find || cc.$;
203         /**
204          * check if a DOMNode has a specific class
205          * @param {String} cls
206          * @return {Boolean}
207          */
208         el.hasClass = el.hasClass || function (cls) {
209             return this.className.match(new RegExp('(\\s|^)' + cls + '(\\s|$)'));
210         };
211         /**
212          * add a class to a DOMNode, returns self to allow chaining
213          * @param {String} cls
214          * @return {cc.$}
215          */
216         el.addClass = el.addClass || function (cls) {
217             if (!this.hasClass(cls)) {
218                 if (this.className) {
219                     this.className += " ";
220                 }
221                 this.className += cls;
222             }
223             return this;
224         };
225         /**
226          * remove a specific class from a DOMNode, returns self to allow chaining
227          * @param {String} cls
228          * @return {cc.$}
229          */
230         el.removeClass = el.removeClass || function (cls) {
231             if (this.hasClass(cls)) {
232                 this.className = this.className.replace(cls, '');
233             }
234             return this;
235         };
236         /**
237          * detach it self from parent
238          * @function
239          */
240         el.remove = el.remove || function () {
241             if (this.parentNode)
242                 this.parentNode.removeChild(this);
243             return this;
244         };
245 
246         /**
247          * add to another element as a child
248          * @param {HTMLElement|cc.$} x
249          * @return {cc.$}
250          */
251         el.appendTo = el.appendTo || function (x) {
252             x.appendChild(this);
253             return this;
254         };
255 
256         /**
257          * add to another element as a child and place on the top of the children list
258          * @param {HTMLElement|cc.$} x
259          * @return {cc.$}
260          */
261         el.prependTo = el.prependTo || function (x) {
262             ( x.childNodes[0]) ? x.insertBefore(this, x.childNodes[0]) : x.appendChild(this);
263             return this;
264         };
265 
266         /**
267          * helper function for updating the css transform
268          * @return {cc.$}
269          */
270         el.transforms = el.transforms || function () {
271             this.style[cc.$.trans] = cc.$.translate(this.position) + cc.$.rotate(this.rotation) + cc.$.scale(this.scale) + cc.$.skew(this.skew);
272             return this;
273         };
274 
275         el.position = el.position || {x: 0, y: 0};
276         el.rotation = el.rotation || 0;
277         el.scale = el.scale || {x: 1, y: 1};
278         el.skew = el.skew || {x: 0, y: 0};
279 
280         /**
281          * move the element
282          * @param {Number} x in pixel
283          * @param {Number} y in pixel
284          * @return {cc.$}
285          */
286         el.translates = function (x, y) {
287             this.position.x = x;
288             this.position.y = y;
289             this.transforms();
290             return this
291         };
292 
293         /**
294          * rotate the element
295          * @param {Number} x in degrees
296          * @return {cc.$}
297          */
298         el.rotate = function (x) {
299             this.rotation = x;
300             this.transforms();
301             return this
302         };
303 
304         /**
305          * resize the element
306          * @param {Number} x
307          * @param {Number} y
308          * @return {cc.$}
309          */
310         el.resize = function (x, y) {
311             this.scale.x = x;
312             this.scale.y = y;
313             this.transforms();
314             return this
315         };
316 
317         /**
318          * skews the element
319          * @param {Number} x in degrees
320          * @param {Number} y
321          * @return {cc.$}
322          */
323         el.setSkew = function (x, y) {
324             this.skew.x = x;
325             this.skew.y = y;
326             this.transforms();
327             return this
328         };
329     }
330     return el;
331 };
332 //getting the prefix and css3 3d support
333 switch (cc.Browser.type) {
334     case "firefox":
335         cc.$.pfx = "Moz";
336         cc.$.hd = true;
337         break;
338     case "chrome":
339     case "safari":
340         cc.$.pfx = "webkit";
341         cc.$.hd = true;
342         break;
343     case "opera":
344         cc.$.pfx = "O";
345         cc.$.hd = false;
346         break;
347     case "ie":
348         cc.$.pfx = "ms";
349         cc.$.hd = false;
350         break;
351     default:
352         cc.$.pfx = "webkit";
353         cc.$.hd = true;
354 }
355 //cache for prefixed transform
356 cc.$.trans = cc.$.pfx + "Transform";
357 //helper function for constructing transform strings
358 cc.$.translate = (cc.$.hd) ? function (a) {
359     return "translate3d(" + a.x + "px, " + a.y + "px, 0) "
360 } : function (a) {
361     return "translate(" + a.x + "px, " + a.y + "px) "
362 };
363 cc.$.rotate = (cc.$.hd) ? function (a) {
364     return "rotateZ(" + a + "deg) ";
365 } : function (a) {
366     return "rotate(" + a + "deg) ";
367 };
368 cc.$.scale = function (a) {
369     return "scale(" + a.x + ", " + a.y + ") "
370 };
371 cc.$.skew = function (a) {
372     return "skewX(" + -a.x + "deg) skewY(" + a.y + "deg)";
373 };
374 
375 
376 /**
377  * Creates a new element, and adds cc.$ methods
378  * @param {String} x name of the element tag to create
379  * @return {cc.$}
380  */
381 cc.$new = function (x) {
382     return cc.$(document.createElement(x))
383 };
384 cc.$.findpos = function (obj) {
385     var curleft = 0;
386     var curtop = 0;
387     do {
388         curleft += obj.offsetLeft;
389         curtop += obj.offsetTop;
390     } while (obj = obj.offsetParent);
391     return {x: curleft, y: curtop};
392 };
393