1/*! 2 * Bowser - a browser detector 3 * https://github.com/ded/bowser 4 * MIT License | (c) Dustin Diaz 2015 5 */ 6 7!function (root, name, definition) { 8 if (typeof module != 'undefined' && module.exports) module.exports = definition() 9 else if (typeof define == 'function' && define.amd) define(name, definition) 10 else root[name] = definition() 11}(this, 'bowser', function () { 12 /** 13 * See useragents.js for examples of navigator.userAgent 14 */ 15 16 var t = true 17 18 function detect(ua) { 19 20 function getFirstMatch(regex) { 21 var match = ua.match(regex); 22 return (match && match.length > 1 && match[1]) || ''; 23 } 24 25 function getSecondMatch(regex) { 26 var match = ua.match(regex); 27 return (match && match.length > 1 && match[2]) || ''; 28 } 29 30 var iosdevice = getFirstMatch(/(ipod|iphone|ipad)/i).toLowerCase() 31 , likeAndroid = /like android/i.test(ua) 32 , android = !likeAndroid && /android/i.test(ua) 33 , nexusMobile = /nexus\s*[0-6]\s*/i.test(ua) 34 , nexusTablet = !nexusMobile && /nexus\s*[0-9]+/i.test(ua) 35 , chromeos = /CrOS/.test(ua) 36 , silk = /silk/i.test(ua) 37 , sailfish = /sailfish/i.test(ua) 38 , tizen = /tizen/i.test(ua) 39 , webos = /(web|hpw)os/i.test(ua) 40 , windowsphone = /windows phone/i.test(ua) 41 , samsungBrowser = /SamsungBrowser/i.test(ua) 42 , windows = !windowsphone && /windows/i.test(ua) 43 , mac = !iosdevice && !silk && /macintosh/i.test(ua) 44 , linux = !android && !sailfish && !tizen && !webos && /linux/i.test(ua) 45 , edgeVersion = getFirstMatch(/edge\/(\d+(\.\d+)?)/i) 46 , versionIdentifier = getFirstMatch(/version\/(\d+(\.\d+)?)/i) 47 , tablet = /tablet/i.test(ua) 48 , mobile = !tablet && /[^-]mobi/i.test(ua) 49 , xbox = /xbox/i.test(ua) 50 , result 51 52 if (/opera/i.test(ua)) { 53 // an old Opera 54 result = { 55 name: 'Opera' 56 , opera: t 57 , version: versionIdentifier || getFirstMatch(/(?:opera|opr|opios)[\s\/](\d+(\.\d+)?)/i) 58 } 59 } else if (/opr|opios/i.test(ua)) { 60 // a new Opera 61 result = { 62 name: 'Opera' 63 , opera: t 64 , version: getFirstMatch(/(?:opr|opios)[\s\/](\d+(\.\d+)?)/i) || versionIdentifier 65 } 66 } 67 else if (/SamsungBrowser/i.test(ua)) { 68 result = { 69 name: 'Samsung Internet for Android' 70 , samsungBrowser: t 71 , version: versionIdentifier || getFirstMatch(/(?:SamsungBrowser)[\s\/](\d+(\.\d+)?)/i) 72 } 73 } 74 else if (/coast/i.test(ua)) { 75 result = { 76 name: 'Opera Coast' 77 , coast: t 78 , version: versionIdentifier || getFirstMatch(/(?:coast)[\s\/](\d+(\.\d+)?)/i) 79 } 80 } 81 else if (/yabrowser/i.test(ua)) { 82 result = { 83 name: 'Yandex Browser' 84 , yandexbrowser: t 85 , version: versionIdentifier || getFirstMatch(/(?:yabrowser)[\s\/](\d+(\.\d+)?)/i) 86 } 87 } 88 else if (/ucbrowser/i.test(ua)) { 89 result = { 90 name: 'UC Browser' 91 , ucbrowser: t 92 , version: getFirstMatch(/(?:ucbrowser)[\s\/](\d+(?:\.\d+)+)/i) 93 } 94 } 95 else if (/mxios/i.test(ua)) { 96 result = { 97 name: 'Maxthon' 98 , maxthon: t 99 , version: getFirstMatch(/(?:mxios)[\s\/](\d+(?:\.\d+)+)/i) 100 } 101 } 102 else if (/epiphany/i.test(ua)) { 103 result = { 104 name: 'Epiphany' 105 , epiphany: t 106 , version: getFirstMatch(/(?:epiphany)[\s\/](\d+(?:\.\d+)+)/i) 107 } 108 } 109 else if (/puffin/i.test(ua)) { 110 result = { 111 name: 'Puffin' 112 , puffin: t 113 , version: getFirstMatch(/(?:puffin)[\s\/](\d+(?:\.\d+)?)/i) 114 } 115 } 116 else if (/sleipnir/i.test(ua)) { 117 result = { 118 name: 'Sleipnir' 119 , sleipnir: t 120 , version: getFirstMatch(/(?:sleipnir)[\s\/](\d+(?:\.\d+)+)/i) 121 } 122 } 123 else if (/k-meleon/i.test(ua)) { 124 result = { 125 name: 'K-Meleon' 126 , kMeleon: t 127 , version: getFirstMatch(/(?:k-meleon)[\s\/](\d+(?:\.\d+)+)/i) 128 } 129 } 130 else if (windowsphone) { 131 result = { 132 name: 'Windows Phone' 133 , windowsphone: t 134 } 135 if (edgeVersion) { 136 result.msedge = t 137 result.version = edgeVersion 138 } 139 else { 140 result.msie = t 141 result.version = getFirstMatch(/iemobile\/(\d+(\.\d+)?)/i) 142 } 143 } 144 else if (/msie|trident/i.test(ua)) { 145 result = { 146 name: 'Internet Explorer' 147 , msie: t 148 , version: getFirstMatch(/(?:msie |rv:)(\d+(\.\d+)?)/i) 149 } 150 } else if (chromeos) { 151 result = { 152 name: 'Chrome' 153 , chromeos: t 154 , chromeBook: t 155 , chrome: t 156 , version: getFirstMatch(/(?:chrome|crios|crmo)\/(\d+(\.\d+)?)/i) 157 } 158 } else if (/chrome.+? edge/i.test(ua)) { 159 result = { 160 name: 'Microsoft Edge' 161 , msedge: t 162 , version: edgeVersion 163 } 164 } 165 else if (/vivaldi/i.test(ua)) { 166 result = { 167 name: 'Vivaldi' 168 , vivaldi: t 169 , version: getFirstMatch(/vivaldi\/(\d+(\.\d+)?)/i) || versionIdentifier 170 } 171 } 172 else if (sailfish) { 173 result = { 174 name: 'Sailfish' 175 , sailfish: t 176 , version: getFirstMatch(/sailfish\s?browser\/(\d+(\.\d+)?)/i) 177 } 178 } 179 else if (/seamonkey\//i.test(ua)) { 180 result = { 181 name: 'SeaMonkey' 182 , seamonkey: t 183 , version: getFirstMatch(/seamonkey\/(\d+(\.\d+)?)/i) 184 } 185 } 186 else if (/firefox|iceweasel|fxios/i.test(ua)) { 187 result = { 188 name: 'Firefox' 189 , firefox: t 190 , version: getFirstMatch(/(?:firefox|iceweasel|fxios)[ \/](\d+(\.\d+)?)/i) 191 } 192 if (/\((mobile|tablet);[^\)]*rv:[\d\.]+\)/i.test(ua)) { 193 result.firefoxos = t 194 } 195 } 196 else if (silk) { 197 result = { 198 name: 'Amazon Silk' 199 , silk: t 200 , version : getFirstMatch(/silk\/(\d+(\.\d+)?)/i) 201 } 202 } 203 else if (/phantom/i.test(ua)) { 204 result = { 205 name: 'PhantomJS' 206 , phantom: t 207 , version: getFirstMatch(/phantomjs\/(\d+(\.\d+)?)/i) 208 } 209 } 210 else if (/slimerjs/i.test(ua)) { 211 result = { 212 name: 'SlimerJS' 213 , slimer: t 214 , version: getFirstMatch(/slimerjs\/(\d+(\.\d+)?)/i) 215 } 216 } 217 else if (/blackberry|\bbb\d+/i.test(ua) || /rim\stablet/i.test(ua)) { 218 result = { 219 name: 'BlackBerry' 220 , blackberry: t 221 , version: versionIdentifier || getFirstMatch(/blackberry[\d]+\/(\d+(\.\d+)?)/i) 222 } 223 } 224 else if (webos) { 225 result = { 226 name: 'WebOS' 227 , webos: t 228 , version: versionIdentifier || getFirstMatch(/w(?:eb)?osbrowser\/(\d+(\.\d+)?)/i) 229 }; 230 /touchpad\//i.test(ua) && (result.touchpad = t) 231 } 232 else if (/bada/i.test(ua)) { 233 result = { 234 name: 'Bada' 235 , bada: t 236 , version: getFirstMatch(/dolfin\/(\d+(\.\d+)?)/i) 237 }; 238 } 239 else if (tizen) { 240 result = { 241 name: 'Tizen' 242 , tizen: t 243 , version: getFirstMatch(/(?:tizen\s?)?browser\/(\d+(\.\d+)?)/i) || versionIdentifier 244 }; 245 } 246 else if (/qupzilla/i.test(ua)) { 247 result = { 248 name: 'QupZilla' 249 , qupzilla: t 250 , version: getFirstMatch(/(?:qupzilla)[\s\/](\d+(?:\.\d+)+)/i) || versionIdentifier 251 } 252 } 253 else if (/chromium/i.test(ua)) { 254 result = { 255 name: 'Chromium' 256 , chromium: t 257 , version: getFirstMatch(/(?:chromium)[\s\/](\d+(?:\.\d+)?)/i) || versionIdentifier 258 } 259 } 260 else if (/chrome|crios|crmo/i.test(ua)) { 261 result = { 262 name: 'Chrome' 263 , chrome: t 264 , version: getFirstMatch(/(?:chrome|crios|crmo)\/(\d+(\.\d+)?)/i) 265 } 266 } 267 else if (android) { 268 result = { 269 name: 'Android' 270 , version: versionIdentifier 271 } 272 } 273 else if (/safari|applewebkit/i.test(ua)) { 274 result = { 275 name: 'Safari' 276 , safari: t 277 } 278 if (versionIdentifier) { 279 result.version = versionIdentifier 280 } 281 } 282 else if (iosdevice) { 283 result = { 284 name : iosdevice == 'iphone' ? 'iPhone' : iosdevice == 'ipad' ? 'iPad' : 'iPod' 285 } 286 // WTF: version is not part of user agent in web apps 287 if (versionIdentifier) { 288 result.version = versionIdentifier 289 } 290 } 291 else if(/googlebot/i.test(ua)) { 292 result = { 293 name: 'Googlebot' 294 , googlebot: t 295 , version: getFirstMatch(/googlebot\/(\d+(\.\d+))/i) || versionIdentifier 296 } 297 } 298 else { 299 result = { 300 name: getFirstMatch(/^(.*)\/(.*) /), 301 version: getSecondMatch(/^(.*)\/(.*) /) 302 }; 303 } 304 305 // set webkit or gecko flag for browsers based on these engines 306 if (!result.msedge && /(apple)?webkit/i.test(ua)) { 307 if (/(apple)?webkit\/537\.36/i.test(ua)) { 308 result.name = result.name || "Blink" 309 result.blink = t 310 } else { 311 result.name = result.name || "Webkit" 312 result.webkit = t 313 } 314 if (!result.version && versionIdentifier) { 315 result.version = versionIdentifier 316 } 317 } else if (!result.opera && /gecko\//i.test(ua)) { 318 result.name = result.name || "Gecko" 319 result.gecko = t 320 result.version = result.version || getFirstMatch(/gecko\/(\d+(\.\d+)?)/i) 321 } 322 323 // set OS flags for platforms that have multiple browsers 324 if (!result.windowsphone && !result.msedge && (android || result.silk)) { 325 result.android = t 326 } else if (!result.windowsphone && !result.msedge && iosdevice) { 327 result[iosdevice] = t 328 result.ios = t 329 } else if (mac) { 330 result.mac = t 331 } else if (xbox) { 332 result.xbox = t 333 } else if (windows) { 334 result.windows = t 335 } else if (linux) { 336 result.linux = t 337 } 338 339 // OS version extraction 340 var osVersion = ''; 341 if (result.windowsphone) { 342 osVersion = getFirstMatch(/windows phone (?:os)?\s?(\d+(\.\d+)*)/i); 343 } else if (iosdevice) { 344 osVersion = getFirstMatch(/os (\d+([_\s]\d+)*) like mac os x/i); 345 osVersion = osVersion.replace(/[_\s]/g, '.'); 346 } else if (android) { 347 osVersion = getFirstMatch(/android[ \/-](\d+(\.\d+)*)/i); 348 } else if (result.webos) { 349 osVersion = getFirstMatch(/(?:web|hpw)os\/(\d+(\.\d+)*)/i); 350 } else if (result.blackberry) { 351 osVersion = getFirstMatch(/rim\stablet\sos\s(\d+(\.\d+)*)/i); 352 } else if (result.bada) { 353 osVersion = getFirstMatch(/bada\/(\d+(\.\d+)*)/i); 354 } else if (result.tizen) { 355 osVersion = getFirstMatch(/tizen[\/\s](\d+(\.\d+)*)/i); 356 } 357 if (osVersion) { 358 result.osversion = osVersion; 359 } 360 361 // device type extraction 362 var osMajorVersion = osVersion.split('.')[0]; 363 if ( 364 tablet 365 || nexusTablet 366 || iosdevice == 'ipad' 367 || (android && (osMajorVersion == 3 || (osMajorVersion >= 4 && !mobile))) 368 || result.silk 369 ) { 370 result.tablet = t 371 } else if ( 372 mobile 373 || iosdevice == 'iphone' 374 || iosdevice == 'ipod' 375 || android 376 || nexusMobile 377 || result.blackberry 378 || result.webos 379 || result.bada 380 ) { 381 result.mobile = t 382 } 383 384 // Graded Browser Support
385 // http://developer.yahoo.com/yui/articles/gbs 386 if (result.msedge || 387 (result.msie && result.version >= 10) || 388 (result.yandexbrowser && result.version >= 15) || 389 (result.vivaldi && result.version >= 1.0) || 390 (result.chrome && result.version >= 20) || 391 (result.samsungBrowser && result.version >= 4) || 392 (result.firefox && result.version >= 20.0) || 393 (result.safari && result.version >= 6) || 394 (result.opera && result.version >= 10.0) || 395 (result.ios && result.osversion && result.osversion.split(".")[0] >= 6) || 396 (result.blackberry && result.version >= 10.1) 397 || (result.chromium && result.version >= 20) 398 ) { 399 result.a = t; 400 } 401 else if ((result.msie && result.version < 10) || 402 (result.chrome && result.version < 20) || 403 (result.firefox && result.version < 20.0) || 404 (result.safari && result.version < 6) || 405 (result.opera && result.version < 10.0) || 406 (result.ios && result.osversion && result.osversion.split(".")[0] < 6) 407 || (result.chromium && result.version < 20) 408 ) { 409 result.c = t 410 } else result.x = t 411 412 return result 413 } 414 415 var bowser = detect(typeof navigator !== 'undefined' ? navigator.userAgent || '' : '') 416 417 bowser.test = function (browserList) { 418 for (var i = 0; i < browserList.length; ++i) { 419 var browserItem = browserList[i]; 420 if (typeof browserItem=== 'string') { 421 if (browserItem in bowser) { 422 return true; 423 } 424 } 425 } 426 return false; 427 } 428 429 /** 430 * Get version precisions count 431 * 432 * @example 433 * getVersionPrecision("1.10.3") // 3 434 * 435 * @param {string} version 436 * @return {number} 437 */ 438 function getVersionPrecision(version) { 439 return version.split(".").length; 440 } 441 442 /** 443 * Array::map polyfill 444 * 445 * @param {Array} arr 446 * @param {Function} iterator 447 * @return {Array} 448 */ 449 function map(arr, iterator) { 450 var result = [], i; 451 if (Array.prototype.map) { 452 return Array.prototype.map.call(arr, iterator); 453 } 454 for (i = 0; i < arr.length; i++) { 455 result.push(iterator(arr[i])); 456 } 457 return result; 458 } 459 460 /** 461 * Calculate browser version weight 462 * 463 * @example 464 * compareVersions(['1.10.2.1', '1.8.2.1.90']) // 1 465 * compareVersions(['1.010.2.1', '1.09.2.1.90']); // 1 466 * compareVersions(['1.10.2.1', '1.10.2.1']); // 0 467 * compareVersions(['1.10.2.1', '1.0800.2']); // -1 468 * 469 * @param {Array<String>} versions versions to compare 470 * @return {Number} comparison result 471 */ 472 function compareVersions(versions) { 473 // 1) get common precision for both versions, for example for "10.0" and "9" it should be 2 474 var precision = Math.max(getVersionPrecision(versions[0]), getVersionPrecision(versions[1])); 475 var chunks = map(versions, function (version) { 476 var delta = precision - getVersionPrecision(version); 477 478 // 2) "9" -> "9.0" (for precision = 2) 479 version = version + new Array(delta + 1).join(".0"); 480 481 // 3) "9.0" -> ["000000000"", "000000009"] 482 return map(version.split("."), function (chunk) { 483 return new Array(20 - chunk.length).join("0") + chunk; 484 }).reverse(); 485 }); 486 487 // iterate in reverse order by reversed chunks array 488 while (--precision >= 0) { 489 // 4) compare: "000000009" > "000000010" = false (but "9" > "10" = true) 490 if (chunks[0][precision] > chunks[1][precision]) { 491 return 1; 492 } 493 else if (chunks[0][precision] === chunks[1][precision]) { 494 if (precision === 0) { 495 // all version chunks are same 496 return 0; 497 } 498 } 499 else { 500 return -1; 501 } 502 } 503 } 504 505 /** 506 * Check if browser is unsupported 507 * 508 * @example 509 * bowser.isUnsupportedBrowser({ 510 * msie: "10", 511 * firefox: "23", 512 * chrome: "29", 513 * safari: "5.1", 514 * opera: "16", 515 * phantom: "534" 516 * }); 517 * 518 * @param {Object} minVersions map of minimal version to browser 519 * @param {Boolean} [strictMode = false] flag to return false if browser wasn't found in map 520 * @param {String} [ua] user agent string 521 * @return {Boolean} 522 */ 523 function isUnsupportedBrowser(minVersions, strictMode, ua) { 524 var _bowser = bowser; 525 526 // make strictMode param optional with ua param usage 527 if (typeof strictMode === 'string') { 528 ua = strictMode;
529 strictMode = void(0); 530 } 531 532 if (strictMode === void(0)) { 533 strictMode = false; 534 } 535 if (ua) { 536 _bowser = detect(ua); 537 } 538 539 var version = "" + _bowser.version; 540 for (var browser in minVersions) { 541 if (minVersions.hasOwnProperty(browser)) { 542 if (_bowser[browser]) { 543 if (typeof minVersions[browser] !== 'string') { 544 throw new Error('Browser version in the minVersion map should be a string: ' + browser + ': ' + String(minVersions)); 545 } 546 547 // browser version and min supported version. 548 return compareVersions([version, minVersions[browser]]) < 0; 549 } 550 } 551 } 552 553 return strictMode; // not found 554 } 555 556 /** 557 * Check if browser is supported 558 * 559 * @param {Object} minVersions map of minimal version to browser 560 * @param {Boolean} [strictMode = false] flag to return false if browser wasn't found in map 561 * @param {String} [ua] user agent string 562 * @return {Boolean} 563 */ 564 function check(minVersions, strictMode, ua) { 565 return !isUnsupportedBrowser(minVersions, strictMode, ua); 566 } 567 568 bowser.isUnsupportedBrowser = isUnsupportedBrowser; 569 bowser.compareVersions = compareVersions; 570 bowser.check = check; 571 572 /* 573 * Set our detect method to the main bowser object so we can 574 * reuse it to test other user agents. 575 * This is needed to implement future tests. 576 */ 577 bowser._detect = detect; 578 579 return bowser 580});
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.