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