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