1 /** 2 * @fileOverview BTM Browser/Rendering engine sniffer. 3 * @author <a href="http://www.bobs-bits.com">Stephen Reay</a> 4 * @author Browser detection based a <a href="http://www.quirksmode.org/js/detect.html">concept</a> by <a href="mailto:xyz@quirksmode.org">Peter-Paul Koch</a> 5 */ 6 7 /** 8 * @namespace Functionality and Properties for identifying/targetting Browser features, functionality and quirks 9 */ 10 BTM.Browser = {}; 11 12 (function () { 13 var browserData = [ 14 { 15 nameString: navigator.userAgent, 16 namesearch: "Chrome", 17 versionString: navigator.userAgent, 18 versionSearch: /Chrome\/([^\r\n\s]*)/, 19 identity: "Chrome" 20 }, 21 { nameString: navigator.userAgent, 22 nameSearch: "OmniWeb", 23 versionString: navigator.userAgent, 24 versionSearch: /OmniWeb\/v?([^\r\n\s]*)/, 25 identity: "OmniWeb" 26 }, 27 { 28 nameString: navigator.vendor, 29 nameSearch: "Apple", 30 versionString: navigator.userAgent, 31 versionSearch: /(Safari|Version)\/([^\r\n\s]*)/, 32 versionPosition: 2, 33 versionMatrix: { 34 '85.5' : '1', 35 '85.5' : '1', 36 '85.7' : '1.0.2', 37 '85.8' : '1.0.3', 38 '85.8.1' : '1.0.3', 39 '100' : '1.1', 40 '100.1' : '1.1.1', 41 '125.7' : '1.2.2', 42 '125.8' : '1.2.2', 43 '125.9' : '1.2.3', 44 '125.11' : '1.2.4', 45 '125.12' : '1.2.4', 46 '312' : '1.3', 47 '312.3' : '1.3.1', 48 '312.3.1' : '1.3.1', 49 '312.5' : '1.3.2', 50 '312.6' : '1.3.2', 51 '412' : '2', 52 '412.2' : '2', 53 '412.2.2' : '2', 54 '412.5' : '2.0.1', 55 '416.12' : '2.0.2', 56 '416.13' : '2.0.2', 57 '417.8' : '2.0.3', 58 '417.9.2' : '2.0.3', 59 '417.9.3' : '2.0.3', 60 '419.3' : '2.0.4' 61 }, 62 identity: "Safari" 63 }, 64 { 65 nameProp: window.opera, 66 versionString: navigator.userAgent, 67 versionSearch: /Opera[\/ ]([^\r\n\s]*)/, 68 identity: "Opera" 69 }, 70 { 71 nameString: navigator.vendor, 72 nameSearch: "iCab", 73 versionString: navigator.userAgent, 74 versionSearch: /iCab[\/ ]([^\r\n\s]*)/, 75 identity: "iCab" 76 }, 77 { 78 nameString: navigator.vendor, 79 nameSearch: "KDE", 80 versionString: navigator.userAgent, 81 versionSearch: /Konqueror\/([^\r\n\s]*?);/, 82 identity: "Konqueror" 83 }, 84 { 85 nameString: navigator.userAgent, 86 nameSearch: "Firefox", 87 versionString: navigator.userAgent, 88 versionSearch: /Firefox\/([^\r\n\s]*)/, 89 identity: "Firefox" 90 }, 91 { 92 nameString: navigator.userAgent, 93 nameSearch: "Camino", 94 versionString: navigator.userAgent, 95 versionSearch: /Camino\/([^\r\n\s]*)/, 96 identity: "Camino" 97 }, 98 { // for newer Netscapes (6+) 99 nameString: navigator.userAgent, 100 nameSearch: "Netscape", 101 versionString: navigator.userAgent, 102 versionSearch: /Netscape6?\/([^\r\n\s]*)|Navigator\/([^\r\n\s]*)/, 103 identity: "Netscape" 104 }, 105 { 106 nameString: navigator.userAgent, 107 nameSearch: "MSIE", 108 versionString: navigator.userAgent, 109 versionSearch: new RegExp('MSIE ([^\r\n\s]*);'), 110 identity: "Explorer" 111 }, 112 { 113 nameString: navigator.userAgent, 114 nameSearch: "Gecko", 115 versionString: navigator.userAgent, 116 versionSearch: /rv:([^\r\n\s]*)/, 117 identity: "Mozilla" 118 }, 119 { // for older Netscapes (4-) 120 nameString: navigator.userAgent, 121 nameSearch: "Mozilla", 122 versionString: navigator.userAgent, 123 versionSearch: /Mozilla\/([^\r\n\s\-]*)/, 124 identity: "Netscape" 125 } 126 127 ]; 128 BTM.log("Defined Browser checks: " + browserData.length); 129 130 var osData = [ 131 { 132 nameString: navigator.platform, 133 nameSearch: "Win", 134 identity: "Windows" 135 }, 136 { 137 nameString: navigator.platform, 138 nameSearch: "Mac", 139 identity: "Mac" 140 }, 141 { 142 nameString: navigator.platform, 143 nameSearch: "Linux", 144 identity: "Linux" 145 } 146 147 ]; 148 BTM.log("Defined Operating System checks: " + osData.length); 149 150 var engineData = [ 151 { 152 nameString: navigator.userAgent, 153 nameSearch: /AppleWebKit/, 154 versionString: navigator.userAgent, 155 versionSearch: /AppleWebKit\/([\d\.]*\+?)/, 156 identity: "WebKit" 157 }, 158 { 159 nameString: navigator.userAgent, 160 nameSearch: /Opera/, 161 versionString: navigator.userAgent, 162 versionSearch: /Opera[\/ ]([\d\.]*)/, 163 identity: "Presto" 164 }, 165 { 166 nameString: navigator.userAgent, 167 nameSearch: /iCab/, 168 versionString: navigator.userAgent, 169 versionSearch: /iCab[\/ ]([0-3][\d\.]*)/, 170 identity: "iCab" 171 }, 172 { 173 nameString: navigator.userAgent, 174 nameSearch: /KHTML/, 175 versionString: navigator.userAgent, 176 versionSearch: /KHTML\/([\d\.]*)/, 177 identity: "KHTML" 178 }, 179 { 180 nameString: navigator.userAgent, 181 nameSearch: /MSIE/, 182 versionString: navigator.userAgent, 183 versionSearch: /MSIE (.*?)\;/, 184 identity: "Trident" 185 }, 186 { 187 nameString: navigator.userAgent, 188 nameSearch: /Gecko/, 189 versionString: navigator.userAgent, 190 versionSearch: /rv:(.*?)\)/, 191 identity: "Gecko" 192 } 193 ]; 194 BTM.log("Defined Rendering Engine checks: " + engineData.length); 195 196 197 var combos = [ 198 ['name'], 199 ['name', '_', 'version'], 200 ['engine'], 201 ['engine', '_', 'engineVersion'], 202 ['platform'] 203 /* 204 ['platform','_','name'], 205 ['platform','_','name','_','version'], 206 ['platform','_','engine'], 207 ['platform','_','engine','_','engineVersion'] 208 */ 209 ]; 210 BTM.log("Defined Browser/OS/Engine class combinations:" + combos.length); 211 212 var targets = { 213 'width': [ 214 640, 215 800, 216 1024, 217 1280, 218 1680, 219 1920, 220 2560 221 ], 222 'height' : [ 223 480, 224 600, 225 720, 226 768, 227 800, 228 1024, 229 1050, 230 1080, 231 1200, 232 1400, 233 1440, 234 1536, 235 1600 236 ] 237 }; 238 239 /* BTM.Browser.findDimensions = findDimensions; */ 240 function findDimensions(axis) { 241 //Window size code from http://www.howtocreate.co.uk/tutorials/javascript/browserwindow 242 var dimensions = {}; 243 BTM.log("Finding Window dimension values"); 244 if (Object.isNumber(window.innerWidth)) { 245 //Non-IE 246 dimensions.width = window.innerWidth; 247 dimensions.height = window.innerHeight; 248 } 249 else if (document.documentElement && (document.documentElement.clientWidth || document.documentElement.clientHeight)) { 250 //IE 6+ in 'standards compliant mode' 251 dimensions.width = document.documentElement.clientWidth; 252 dimensions.height = document.documentElement.clientHeight; 253 } 254 else if (document.body && (document.body.clientWidth || document.body.clientHeight)) { 255 //IE 4 compatible 256 dimensions.width = document.body.clientWidth; 257 dimensions.height = document.body.clientHeight; 258 } 259 260 Object.update(BTM.Browser, dimensions); 261 262 BTM.log("Window dimensions detected: " + dimensions.width + 'x' + dimensions.height); 263 264 if (Object.isString(axis)) { 265 return dimensions[axis]; 266 } 267 else { 268 return dimensions; 269 } 270 } 271 272 function findName(data) { 273 for (var i = 0; i < data.length; i++) { 274 if (data[i].nameSearch && data[i].nameString) { 275 var test = data[i].nameString.match(data[i].nameSearch); 276 if (test) { 277 return data[i].identity; 278 } 279 } 280 else if (data[i].prop) { 281 return data[i].identity; 282 } 283 } 284 } 285 286 function findVersion(data) { 287 for (var i = 0; i < data.length; i++) { 288 var match = data[i].versionString.match(data[i].versionSearch); 289 if (match) { 290 var index = data[i].versionPosition || 1; 291 if (data[i].versionMatrix && data[i].versionMatrix[match[index]]) { 292 return data[i].versionMatrix[match[index]]; 293 } 294 else { 295 return match[index]; 296 } 297 } 298 } 299 } 300 301 function makeCombo(data) { 302 var str = ''; 303 for (var i = 0; i < data.length; i++) { 304 if (BTM.Browser[data[i]]) { 305 str += BTM.Browser[data[i]]; 306 } 307 else { 308 str += data[i]; 309 } 310 } 311 312 return str.replaceMulti(['\\.', '\\#', '\\!', '\\~'], '-').toLowerCase(); 313 } 314 315 function addBrowserClasses(data) { 316 BTM.log('Adding Browser Targetting classes', data); 317 for (var i = 0; i < data.length; i++) { 318 var className = makeCombo(data[i]); 319 BTM.DOM.addClass(document.body, className); 320 } 321 } 322 323 324 function addResClasses(data) { 325 BTM.log('Adding Resolution Targetting classes', data); 326 for (var i = 0; i < data.length; i++) { 327 var className = makeCombo(data[i]); 328 BTM.DOM.addClass(document.body, className); 329 } 330 } 331 332 function findMode() { 333 BTM.log("Finding Browser mode", document.compatMode); 334 if (document.compatMode === 'BackCompat') { 335 return 'quirks'; 336 } 337 else if (document.compatMode === 'CSS1Compat') { 338 return 'strict'; 339 } 340 } 341 342 /** 343 * Convenience function to check a Browsers name/engine/version information 344 * @param {String} name the name of the Browser to check. Checks engine name first, then browser name 345 * @param {Number|String} [version] the version to check for. Checks against browser/engine version depending on what the name parameter matches. Checks against the version/versionString depending if it's a Number or String, respectively. 346 * @param {String} [mode='eq'] the mode to check the version. Accepted values are 'eq', 'lt', 'lte', 'gt' and 'gte' which are tested with the operators ===, <, <=, > and >= respectively 347 * @returns {Boolean} true or false, if supplied parameters match the current Browser environment 348 */ 349 BTM.Browser.is = function is(name, version, mode) { 350 351 mode = mode || 'eq'; 352 version = version || false; 353 354 //Matching an engine name 355 if (BTM.Browser.engine === name) { 356 var ver = BTM.Browser.engineVersion; 357 var verStr = BTM.Browser.engineVersionString; 358 } 359 // Matching a browser name 360 else if (BTM.Browser.name === name) { 361 var ver = BTM.Browser.version; 362 var verStr = BTM.Browser.versionString; 363 } 364 // Can't match browser or engine name 365 else { 366 return false; 367 } 368 369 // Just checking a name 370 if (version === false) { 371 return true; 372 } 373 374 // Matching a version string 375 if (Object.isString(version)) { 376 return (verStr === version); 377 } 378 //Matching a version number 379 else { 380 switch(mode) { 381 // Less than mode 382 case 'lt': 383 return ver < version; 384 break; 385 386 // Less than or equal mode 387 case 'lte': 388 return ver <= version; 389 break; 390 391 // Greater than mode 392 case 'gt': 393 return ver > version; 394 break; 395 396 // Greater than or equal mode 397 case 'gte': 398 return ver >= version; 399 break; 400 401 // Equals mode 402 case 'eq': 403 default: 404 return (ver === version); 405 break; 406 } 407 } 408 }; 409 410 411 BTM.log("Finding Browser/Engine/Platform information"); 412 413 /** 414 * The Browser name 415 * @type {String} 416 */ 417 BTM.Browser.name = findName(browserData); 418 419 /** 420 * The Browser version string 421 * @type {String} 422 */ 423 BTM.Browser.versionString = findVersion(browserData); 424 425 /** 426 * The Browser version 427 * @type {Number} 428 */ 429 BTM.Browser.version = parseFloat(BTM.Browser.versionString); 430 431 /** 432 * The Browser Engine 433 * @type {String} 434 */ 435 BTM.Browser.engine = findName(engineData); 436 437 /** 438 * The Browser Engine version string 439 * @type {String} 440 */ 441 BTM.Browser.engineVersionString = findVersion(engineData); 442 443 /** 444 * The Browser Engine version 445 * @type {Number} 446 */ 447 BTM.Browser.engineVersion = parseFloat(BTM.Browser.engineVersionString); 448 449 /** 450 * The Browser Platform (OS) 451 * @type {String} 452 */ 453 BTM.Browser.platform = findName(osData); 454 455 /** 456 * The Browser mode - 'quirks' or 'strict' 457 * @type {String} 458 */ 459 BTM.Browser.mode = findMode(); 460 461 BTM.log("Browser/Egnine/Platform information found", BTM.Browser); 462 463 BTM.observe(document, 'DOMContentLoaded', addBrowserClasses.curry(combos), 0); 464 BTM.observe(document, 'DOMContentLoaded', findDimensions, 0); 465 466 BTM.observe(window, 'resize', findDimensions, 0); 467 })(); 468