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