ua-parser-js 2.0.6 → 2.0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/dist/ua-parser.min.js +3 -3
- package/dist/ua-parser.min.mjs +3 -3
- package/dist/ua-parser.pack.js +3 -3
- package/dist/ua-parser.pack.mjs +3 -3
- package/package.json +23 -5
- package/script/cli.js +1 -1
- package/src/bot-detection/bot-detection.d.ts +7 -0
- package/src/bot-detection/bot-detection.js +196 -0
- package/src/bot-detection/bot-detection.mjs +200 -0
- package/src/browser-detection/browser-detection.d.ts +10 -0
- package/src/browser-detection/browser-detection.js +30 -0
- package/src/browser-detection/browser-detection.mjs +34 -0
- package/src/device-detection/device-detection.d.ts +8 -0
- package/src/device-detection/device-detection.js +43 -0
- package/src/device-detection/device-detection.mjs +47 -0
- package/src/enums/ua-parser-enums.d.ts +80 -7
- package/src/enums/ua-parser-enums.js +80 -7
- package/src/enums/ua-parser-enums.mjs +80 -7
- package/src/extensions/ua-parser-extensions.d.ts +1 -1
- package/src/extensions/ua-parser-extensions.js +76 -30
- package/src/extensions/ua-parser-extensions.mjs +76 -30
- package/src/helpers/ua-parser-helpers.d.ts +29 -3
- package/src/helpers/ua-parser-helpers.js +85 -159
- package/src/helpers/ua-parser-helpers.mjs +85 -159
- package/src/main/ua-parser.d.ts +1 -1
- package/src/main/ua-parser.js +223 -215
- package/src/main/ua-parser.mjs +223 -215
- package/dist/ua-parser.html +0 -1
package/src/main/ua-parser.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/////////////////////////////////////////////////////////////////////////////////
|
|
2
|
-
/* UAParser.js v2.0.
|
|
3
|
-
Copyright © 2012-
|
|
2
|
+
/* UAParser.js v2.0.9
|
|
3
|
+
Copyright © 2012-2026 Faisal Salman <f@faisalman.com>
|
|
4
4
|
AGPLv3 License *//*
|
|
5
5
|
Detect Browser, Engine, OS, CPU, and Device type/model from User-Agent data.
|
|
6
6
|
Supports browser & node.js environment.
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
// Constants
|
|
20
20
|
/////////////
|
|
21
21
|
|
|
22
|
-
var LIBVERSION = '2.0.
|
|
22
|
+
var LIBVERSION = '2.0.9',
|
|
23
23
|
UA_MAX_LENGTH = 500,
|
|
24
24
|
USER_AGENT = 'user-agent',
|
|
25
25
|
EMPTY = '',
|
|
@@ -57,6 +57,7 @@
|
|
|
57
57
|
EMBEDDED = 'embedded',
|
|
58
58
|
|
|
59
59
|
// browser types
|
|
60
|
+
FETCHER = 'fetcher',
|
|
60
61
|
INAPP = 'inapp',
|
|
61
62
|
|
|
62
63
|
// client hints
|
|
@@ -375,10 +376,11 @@
|
|
|
375
376
|
/(avant|iemobile|slim(?:browser|boat|jet))[\/ ]?([\d\.]*)/i, // Avant/IEMobile/SlimBrowser/SlimBoat/Slimjet
|
|
376
377
|
/(?:ms|\()(ie) ([\w\.]+)/i, // Internet Explorer
|
|
377
378
|
|
|
378
|
-
// Blink/Webkit/KHTML based // Flock/RockMelt/Midori/Epiphany/Silk/Skyfire/Bolt/Iron/Iridium/PhantomJS/Bowser/QupZilla/Falkon/LG Browser/Otter/qutebrowser/Dooble/Palemoon
|
|
379
|
-
/(flock|rockmelt|midori|epiphany|silk|skyfire|
|
|
380
|
-
// Rekonq/Puffin/
|
|
381
|
-
/(
|
|
379
|
+
// Blink/Webkit/KHTML based // Flock/RockMelt/Midori/Epiphany/Silk/Skyfire/Bolt/Iron/Iridium/PhantomJS/Bowser/QupZilla/Falkon/LG Browser/Otter/qutebrowser/Dooble/Palemoon/HiBrowser
|
|
380
|
+
/(atlas|flock|rockmelt|midori|epiphany|silk|skyfire|bolt|iron|vivaldi|iridium|phantomjs|bowser|qupzilla|falkon|rekonq|puffin|whale(?!.+naver)|qqbrowserlite|duckduckgo|klar|helio|(?=comodo_)?dragon|otter|dooble|(?:hi|lg |ovi|qute)browser|palemoon)\/v?([-\w\.]+)/i,
|
|
381
|
+
// Atlas/Rekonq/Puffin/Whale/QQBrowserLite/QQ//Vivaldi/DuckDuckGo/Klar/Helio/Dragon
|
|
382
|
+
/(brave)(?: chrome)?\/([\d\.]+)/i, // Brave
|
|
383
|
+
/(aloha|heytap|ovi|115|surf|qwant)browser\/([\d\.]+)/i, // Aloha/HeyTap/Ovi/115/Surf
|
|
382
384
|
/(qwant)(?:ios|mobile)\/([\d\.]+)/i, // Qwant
|
|
383
385
|
/(ecosia|weibo)(?:__| \w+@)([\d\.]+)/i // Ecosia/Weibo
|
|
384
386
|
], [NAME, VERSION], [
|
|
@@ -400,11 +402,15 @@
|
|
|
400
402
|
], [VERSION, [NAME, 'Yandex']], [
|
|
401
403
|
/slbrowser\/([\w\.]+)/i // Smart Lenovo Browser
|
|
402
404
|
], [VERSION, [NAME, 'Smart ' + LENOVO + SUFFIX_BROWSER]], [
|
|
403
|
-
/(
|
|
405
|
+
/(av(?:ast|g|ira))\/([\w\.]+)/i // Avast/AVG/Avira Secure Browser
|
|
404
406
|
], [[NAME, /(.+)/, '$1 Secure' + SUFFIX_BROWSER], VERSION], [
|
|
407
|
+
/norton\/([\w\.]+)/i // Norton Private Browser
|
|
408
|
+
], [VERSION, [NAME, 'Norton Private' + SUFFIX_BROWSER]], [
|
|
405
409
|
/\bfocus\/([\w\.]+)/i // Firefox Focus
|
|
406
410
|
], [VERSION, [NAME, FIREFOX+' Focus']], [
|
|
407
|
-
|
|
411
|
+
/ mms\/([\w\.]+)$/i // Opera Neon
|
|
412
|
+
], [VERSION, [NAME, OPERA+' Neon']], [
|
|
413
|
+
/ opt\/([\w\.]+)$/i // Opera Touch
|
|
408
414
|
], [VERSION, [NAME, OPERA+' Touch']], [
|
|
409
415
|
/coc_coc\w+\/([\w\.]+)/i // Coc Coc Browser
|
|
410
416
|
], [VERSION, [NAME, 'Coc Coc']], [
|
|
@@ -432,10 +438,9 @@
|
|
|
432
438
|
/(tesla)(?: qtcarbrowser|\/(20\d\d\.[-\w\.]+))/i, // Tesla
|
|
433
439
|
/m?(qqbrowser|2345(?=browser|chrome|explorer))\w*[\/ ]?v?([\w\.]+)/i // QQ/2345
|
|
434
440
|
], [NAME, VERSION], [
|
|
435
|
-
/(lbbrowser|rekonq)/i
|
|
441
|
+
/(lbbrowser|luakit|rekonq|steam(?= (clie|tenf|gameo)))/i // LieBao Browser/Luakit/Rekonq/Steam
|
|
436
442
|
], [NAME], [
|
|
437
|
-
/ome\/([\w\.]+)
|
|
438
|
-
/ome\/([\w\.]+).+qihu (360)[es]e/i // 360
|
|
443
|
+
/ome\/([\w\.]+).+(iron(?= saf)|360(?=[es]e$))/i // Iron / 360
|
|
439
444
|
], [VERSION, NAME], [
|
|
440
445
|
|
|
441
446
|
// WebView
|
|
@@ -453,7 +458,7 @@
|
|
|
453
458
|
], [NAME, VERSION, [TYPE, INAPP]], [
|
|
454
459
|
/\bgsa\/([\w\.]+) .*safari\//i // Google Search Appliance on iOS
|
|
455
460
|
], [VERSION, [NAME, 'GSA'], [TYPE, INAPP]], [
|
|
456
|
-
/musical_ly(?:.+app_?version\/|_)([\w\.]+)/i
|
|
461
|
+
/(?:musical_ly|trill)(?:.+app_?version\/|_)([\w\.]+)/i // TikTok
|
|
457
462
|
], [VERSION, [NAME, 'TikTok'], [TYPE, INAPP]], [
|
|
458
463
|
/\[(linkedin)app\]/i // LinkedIn App for iOS & Android
|
|
459
464
|
], [NAME, [TYPE, INAPP]], [
|
|
@@ -463,6 +468,9 @@
|
|
|
463
468
|
/(chromium)[\/ ]([-\w\.]+)/i // Chromium
|
|
464
469
|
], [NAME, VERSION], [
|
|
465
470
|
|
|
471
|
+
/ome-(lighthouse)$/i // Chrome Lighthouse
|
|
472
|
+
], [NAME, [TYPE, FETCHER]], [
|
|
473
|
+
|
|
466
474
|
/headlesschrome(?:\/([\w\.]+)| )/i // Chrome Headless
|
|
467
475
|
], [VERSION, [NAME, CHROME+' Headless']], [
|
|
468
476
|
|
|
@@ -598,17 +606,17 @@
|
|
|
598
606
|
/\b(?:xiao)?((?:red)?mi[-_ ]?pad[\w- ]*)(?: bui|\))/i // Mi Pad tablets
|
|
599
607
|
],[[MODEL, /_/g, ' '], [VENDOR, XIAOMI], [TYPE, TABLET]], [
|
|
600
608
|
|
|
601
|
-
/\b(poco[\w ]+|m2\d{3}j\d\d[a-z]{2})(?: bui|\))/i, // Xiaomi POCO
|
|
602
609
|
/\b; (\w+) build\/hm\1/i, // Xiaomi Hongmi 'numeric' models
|
|
603
610
|
/\b(hm[-_ ]?note?[_ ]?(?:\d\w)?) bui/i, // Xiaomi Hongmi
|
|
604
|
-
|
|
605
|
-
/oid[^\)]+; (m?[12][
|
|
606
|
-
|
|
611
|
+
// Xiaomi Redmi / POCO / Black Shark / Qin
|
|
612
|
+
/oid[^\)]+; (redmi[\-_ ]?(?:note|k)?[\w_ ]+|m?[12]\d[01]\d\w{3,6}|poco[\w ]+|(shark )?\w{3}-[ah]0|qin ?[1-3](s\+|ultra| pro)?)( bui|; wv|\))/i,
|
|
613
|
+
// Xiaomi Mi
|
|
614
|
+
/\b(mi[-_ ]?(?:a\d|one|one[_ ]plus|note|max|cc)?[_ ]?(?:\d{0,2}\w?)[_ ]?(?:plus|se|lite|pro)?( 5g|lte)?)(?: bui|\))/i,
|
|
607
615
|
/ ([\w ]+) miui\/v?\d/i
|
|
608
616
|
], [[MODEL, /_/g, ' '], [VENDOR, XIAOMI], [TYPE, MOBILE]], [
|
|
609
617
|
|
|
610
618
|
// OnePlus
|
|
611
|
-
/droid.+; (cph2[3-6]\d[13579]|((gm|hd)19|(ac|be|in|kb)20|(d[en]|eb|le|mt)21|ne22)[0-2]\d|p[g-
|
|
619
|
+
/droid.+; (cph2[3-6]\d[13579]|((gm|hd)19|(ac|be|in|kb)20|(d[en]|eb|le|mt)21|ne22)[0-2]\d|p[g-l]\w[1m]10)\b/i,
|
|
612
620
|
/(?:one)?(?:plus)? (a\d0\d\d)(?: b|\))/i
|
|
613
621
|
], [MODEL, [VENDOR, ONEPLUS], [TYPE, MOBILE]], [
|
|
614
622
|
|
|
@@ -648,7 +656,7 @@
|
|
|
648
656
|
], [MODEL, [VENDOR, MOTOROLA], [TYPE, TABLET]], [
|
|
649
657
|
|
|
650
658
|
// LG
|
|
651
|
-
|
|
659
|
+
/\b(?:lg)?([vl]k\-?\d{3}) bui| 3\.[-\w; ]{10}lg?-([06cv9]{3,4})/i
|
|
652
660
|
], [MODEL, [VENDOR, LG], [TYPE, TABLET]], [
|
|
653
661
|
/(lm(?:-?f100[nv]?|-[\w\.]+)(?= bui|\))|nexus [45])/i,
|
|
654
662
|
/\blg[-e;\/ ]+(?!.*(?:browser|netcast|android tv|watch|webos))(\w+)/i,
|
|
@@ -852,10 +860,10 @@
|
|
|
852
860
|
], [MODEL, [VENDOR, MICROSOFT], [TYPE, CONSOLE]], [
|
|
853
861
|
/(ouya)/i, // Ouya
|
|
854
862
|
/(nintendo) (\w+)/i, // Nintendo
|
|
855
|
-
/(retroid) (pocket ([^\)]+))/i
|
|
856
|
-
|
|
857
|
-
/droid.+; (shield)( bui|\))/i
|
|
858
|
-
], [
|
|
863
|
+
/(retroid) (pocket ([^\)]+))/i, // Retroid Pocket
|
|
864
|
+
/(valve).+(steam deck)/i,
|
|
865
|
+
/droid.+; ((shield|rgcube|gr0006))( bui|\))/i // Nvidia Portable/Anbernic/Logitech
|
|
866
|
+
], [[VENDOR, strMapper, { 'Nvidia': 'Shield', 'Anbernic': 'RGCUBE', 'Logitech': 'GR0006' }], MODEL, [TYPE, CONSOLE]], [
|
|
859
867
|
|
|
860
868
|
///////////////////
|
|
861
869
|
// WEARABLES
|
|
@@ -864,7 +872,7 @@
|
|
|
864
872
|
/\b(sm-[lr]\d\d[0156][fnuw]?s?|gear live)\b/i // Samsung Galaxy Watch
|
|
865
873
|
], [MODEL, [VENDOR, SAMSUNG], [TYPE, WEARABLE]], [
|
|
866
874
|
/((pebble))app/i, // Pebble
|
|
867
|
-
/(asus|google|lg|oppo) ((pixel |zen)?watch[\w ]*)( bui|\))/i
|
|
875
|
+
/(asus|google|lg|oppo|xiaomi) ((pixel |zen)?watch[\w ]*)( bui|\))/i // Asus ZenWatch / LG Watch / Pixel Watch / Xiaomi Watch
|
|
868
876
|
], [VENDOR, MODEL, [TYPE, WEARABLE]], [
|
|
869
877
|
/(ow(?:19|20)?we?[1-3]{1,3})/i // Oppo Watch
|
|
870
878
|
], [MODEL, [VENDOR, OPPO], [TYPE, WEARABLE]], [
|
|
@@ -939,7 +947,7 @@
|
|
|
939
947
|
/(presto)\/([\w\.]+)/i, // Presto
|
|
940
948
|
/(webkit|trident|netfront|netsurf|amaya|lynx|w3m|goanna|servo)\/([\w\.]+)/i, // WebKit/Trident/NetFront/NetSurf/Amaya/Lynx/w3m/Goanna/Servo
|
|
941
949
|
/ekioh(flow)\/([\w\.]+)/i, // Flow
|
|
942
|
-
/(khtml|tasman|links)[\/ ]\(?([\w\.]+)/i,
|
|
950
|
+
/(khtml|tasman|links|dillo)[\/ ]\(?([\w\.]+)/i, // KHTML/Tasman/Links/Dillo
|
|
943
951
|
/(icab)[\/ ]([23]\.[\d\.]+)/i, // iCab
|
|
944
952
|
|
|
945
953
|
/\b(libweb)/i // LibWeb
|
|
@@ -968,7 +976,8 @@
|
|
|
968
976
|
|
|
969
977
|
// iOS/macOS
|
|
970
978
|
/[adehimnop]{4,7}\b(?:.*os ([\w]+) like mac|; opera)/i, // iOS
|
|
971
|
-
/(?:ios;fbsv|ios(?=.+ip(?:ad|hone))|ip(?:ad|hone)(?: |.+i(?:pad)?)os)[\/ ]([\w\.]+)/i,
|
|
979
|
+
/(?:ios;fbsv|ios(?=.+ip(?:ad|hone)|.+apple ?tv)|ip(?:ad|hone)(?: |.+i(?:pad)?)os|apple ?tv.+ios)[\/ ]([\w\.]+)/i,
|
|
980
|
+
/\btvos ?([\w\.]+)/i,
|
|
972
981
|
/cfnetwork\/.+darwin/i
|
|
973
982
|
], [[VERSION, /_/g, '.'], [NAME, 'iOS']], [
|
|
974
983
|
/(mac os x) ?([\w\. ]*)/i,
|
|
@@ -1000,7 +1009,7 @@
|
|
|
1000
1009
|
], [VERSION, [NAME, BLACKBERRY]], [
|
|
1001
1010
|
/(?:symbian ?os|symbos|s60(?=;)|series ?60)[-\/ ]?([\w\.]*)/i // Symbian
|
|
1002
1011
|
], [VERSION, [NAME, 'Symbian']], [
|
|
1003
|
-
/mozilla\/[\d\.]+ \((?:mobile
|
|
1012
|
+
/mozilla\/[\d\.]+ \((?:mobile[;\w ]*|tablet|tv|[^\)]*(?:viera|lg(?:l25|-d300)|alcatel ?o.+|y300-f1)); rv:([\w\.]+)\).+gecko\//i // Firefox OS
|
|
1004
1013
|
], [VERSION, [NAME, FIREFOX+' OS']], [
|
|
1005
1014
|
/\b(?:hp)?wos(?:browser)?\/([\w\.]+)/i, // WebOS
|
|
1006
1015
|
/webos(?:[ \/]?|\.tv-20(?=2[2-9]))(\d[\d\.]*)/i
|
|
@@ -1008,15 +1017,16 @@
|
|
|
1008
1017
|
/web0s;.+?(?:chr[o0]me|safari)\/(\d+)/i
|
|
1009
1018
|
// https://webostv.developer.lge.com/develop/specifications/web-api-and-web-engine
|
|
1010
1019
|
], [[VERSION, strMapper, {'25':'120','24':'108','23':'94','22':'87','6':'79','5':'68','4':'53','3':'38','2':'538','1':'537','*':'TV'}], [NAME, 'webOS']], [
|
|
1011
|
-
/watch(?: ?os[,\/]|\d,\d\/)([\d\.]+)/i // watchOS
|
|
1020
|
+
/watch(?: ?os[,\/ ]|\d,\d\/)([\d\.]+)/i // watchOS
|
|
1012
1021
|
], [VERSION, [NAME, 'watchOS']], [
|
|
1013
1022
|
|
|
1014
1023
|
// Google ChromeOS
|
|
1015
|
-
/
|
|
1016
|
-
], [[NAME,
|
|
1024
|
+
/cros [\w]+(?:\)| ([\w\.]+)\b)/i // Chromium OS
|
|
1025
|
+
], [VERSION, [NAME, 'Chrome OS']],[
|
|
1017
1026
|
|
|
1018
1027
|
// Smart TVs
|
|
1019
|
-
/
|
|
1028
|
+
/kepler ([\w\.]+); (aft|aeo)/i // Vega OS
|
|
1029
|
+
], [VERSION, [NAME, 'Vega OS']],[
|
|
1020
1030
|
/(netrange)mmh/i, // Netrange
|
|
1021
1031
|
/(nettv)\/(\d+\.[\w\.]+)/i, // NetTV
|
|
1022
1032
|
|
|
@@ -1142,25 +1152,25 @@
|
|
|
1142
1152
|
};
|
|
1143
1153
|
}
|
|
1144
1154
|
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
var
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
this[prop] = that[prop];
|
|
1152
|
-
}
|
|
1155
|
+
IData.prototype.then = function (cb) {
|
|
1156
|
+
var that = this;
|
|
1157
|
+
var IDataResolve = function () {
|
|
1158
|
+
for (var prop in that) {
|
|
1159
|
+
if (that.hasOwnProperty(prop)) {
|
|
1160
|
+
this[prop] = that[prop];
|
|
1153
1161
|
}
|
|
1154
|
-
}
|
|
1155
|
-
IDataResolve.prototype = {
|
|
1156
|
-
is : IData.prototype.is,
|
|
1157
|
-
toString : IData.prototype.toString
|
|
1158
|
-
};
|
|
1159
|
-
var resolveData = new IDataResolve();
|
|
1160
|
-
cb(resolveData);
|
|
1161
|
-
return resolveData;
|
|
1162
|
+
}
|
|
1162
1163
|
};
|
|
1163
|
-
|
|
1164
|
+
IDataResolve.prototype = {
|
|
1165
|
+
is : IData.prototype.is,
|
|
1166
|
+
toString : IData.prototype.toString,
|
|
1167
|
+
withClientHints : IData.prototype.withClientHints,
|
|
1168
|
+
withFeatureCheck : IData.prototype.withFeatureCheck
|
|
1169
|
+
};
|
|
1170
|
+
var resolveData = new IDataResolve();
|
|
1171
|
+
cb(resolveData);
|
|
1172
|
+
return resolveData;
|
|
1173
|
+
};
|
|
1164
1174
|
|
|
1165
1175
|
return new IData();
|
|
1166
1176
|
};
|
|
@@ -1192,199 +1202,197 @@
|
|
|
1192
1202
|
}
|
|
1193
1203
|
|
|
1194
1204
|
function UAItem (itemType, ua, rgxMap, uaCH) {
|
|
1205
|
+
setProps.call(this, [
|
|
1206
|
+
['itemType', itemType],
|
|
1207
|
+
['ua', ua],
|
|
1208
|
+
['uaCH', uaCH],
|
|
1209
|
+
['rgxMap', rgxMap],
|
|
1210
|
+
['data', createIData(this, itemType)]
|
|
1211
|
+
]);
|
|
1212
|
+
return this;
|
|
1213
|
+
}
|
|
1195
1214
|
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
this.set = function (prop, val) {
|
|
1202
|
-
this.data[prop] = val;
|
|
1203
|
-
return this;
|
|
1204
|
-
};
|
|
1215
|
+
UAItem.prototype.get = function (prop) {
|
|
1216
|
+
if (!prop) return this.data;
|
|
1217
|
+
return this.data.hasOwnProperty(prop) ? this.data[prop] : undefined;
|
|
1218
|
+
};
|
|
1205
1219
|
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1220
|
+
UAItem.prototype.set = function (prop, val) {
|
|
1221
|
+
this.data[prop] = val;
|
|
1222
|
+
return this;
|
|
1223
|
+
};
|
|
1210
1224
|
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
// Brave-specific detection
|
|
1216
|
-
if (NAVIGATOR.brave && typeof NAVIGATOR.brave.isBrave == TYPEOF.FUNCTION) {
|
|
1217
|
-
this.set(NAME, 'Brave');
|
|
1218
|
-
}
|
|
1219
|
-
break;
|
|
1220
|
-
case DEVICE:
|
|
1221
|
-
// Chrome-specific detection: check for 'mobile' value of navigator.userAgentData
|
|
1222
|
-
if (!this.get(TYPE) && NAVIGATOR_UADATA && NAVIGATOR_UADATA[MOBILE]) {
|
|
1223
|
-
this.set(TYPE, MOBILE);
|
|
1224
|
-
}
|
|
1225
|
-
// iPadOS-specific detection: identified as Mac, but has some iOS-only properties
|
|
1226
|
-
if (this.get(MODEL) == 'Macintosh' && NAVIGATOR && typeof NAVIGATOR.standalone !== TYPEOF.UNDEFINED && NAVIGATOR.maxTouchPoints && NAVIGATOR.maxTouchPoints > 2) {
|
|
1227
|
-
this.set(MODEL, 'iPad')
|
|
1228
|
-
.set(TYPE, TABLET);
|
|
1229
|
-
}
|
|
1230
|
-
break;
|
|
1231
|
-
case OS:
|
|
1232
|
-
// Chrome-specific detection: check for 'platform' value of navigator.userAgentData
|
|
1233
|
-
if (!this.get(NAME) && NAVIGATOR_UADATA && NAVIGATOR_UADATA[PLATFORM]) {
|
|
1234
|
-
this.set(NAME, NAVIGATOR_UADATA[PLATFORM]);
|
|
1235
|
-
}
|
|
1236
|
-
break;
|
|
1237
|
-
case RESULT:
|
|
1238
|
-
var data = this.data;
|
|
1239
|
-
var detect = function (itemType) {
|
|
1240
|
-
return data[itemType]
|
|
1241
|
-
.getItem()
|
|
1242
|
-
.detectFeature()
|
|
1243
|
-
.get();
|
|
1244
|
-
};
|
|
1245
|
-
this.set(BROWSER, detect(BROWSER))
|
|
1246
|
-
.set(CPU, detect(CPU))
|
|
1247
|
-
.set(DEVICE, detect(DEVICE))
|
|
1248
|
-
.set(ENGINE, detect(ENGINE))
|
|
1249
|
-
.set(OS, detect(OS));
|
|
1250
|
-
}
|
|
1251
|
-
}
|
|
1252
|
-
return this;
|
|
1253
|
-
};
|
|
1225
|
+
UAItem.prototype.setCH = function (ch) {
|
|
1226
|
+
this.uaCH = ch;
|
|
1227
|
+
return this;
|
|
1228
|
+
};
|
|
1254
1229
|
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
rgxMapper.call(this.data, this.ua, this.rgxMap);
|
|
1258
|
-
}
|
|
1230
|
+
UAItem.prototype.detectFeature = function () {
|
|
1231
|
+
if (NAVIGATOR && NAVIGATOR.userAgent == this.ua) {
|
|
1259
1232
|
switch (this.itemType) {
|
|
1260
1233
|
case BROWSER:
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
if (this.get(NAME) == 'iOS' && this.get(VERSION) == '18.6') {
|
|
1265
|
-
// Based on the assumption that iOS version is tightly coupled with Safari version
|
|
1266
|
-
var realVersion = /\) Version\/([\d\.]+)/.exec(this.ua); // Get Safari version
|
|
1267
|
-
if (realVersion && parseInt(realVersion[1].substring(0,2), 10) >= 26) {
|
|
1268
|
-
this.set(VERSION, realVersion[1]); // Set as iOS version
|
|
1269
|
-
}
|
|
1270
|
-
}
|
|
1271
|
-
break;
|
|
1272
|
-
}
|
|
1273
|
-
return this;
|
|
1274
|
-
};
|
|
1275
|
-
|
|
1276
|
-
this.parseCH = function () {
|
|
1277
|
-
var uaCH = this.uaCH,
|
|
1278
|
-
rgxMap = this.rgxMap;
|
|
1279
|
-
|
|
1280
|
-
switch (this.itemType) {
|
|
1281
|
-
case BROWSER:
|
|
1282
|
-
case ENGINE:
|
|
1283
|
-
var brands = uaCH[FULLVERLIST] || uaCH[BRANDS], prevName;
|
|
1284
|
-
if (brands) {
|
|
1285
|
-
for (var i=0; i<brands.length; i++) {
|
|
1286
|
-
var brandName = brands[i].brand || brands[i],
|
|
1287
|
-
brandVersion = brands[i].version;
|
|
1288
|
-
if (this.itemType == BROWSER &&
|
|
1289
|
-
!/not.a.brand/i.test(brandName) &&
|
|
1290
|
-
(!prevName ||
|
|
1291
|
-
(/Chrom/.test(prevName) && brandName != CHROMIUM) ||
|
|
1292
|
-
(prevName == EDGE && /WebView2/.test(brandName))
|
|
1293
|
-
)) {
|
|
1294
|
-
brandName = strMapper(brandName, browserHintsMap);
|
|
1295
|
-
prevName = this.get(NAME);
|
|
1296
|
-
if (!(prevName && !/Chrom/.test(prevName) && /Chrom/.test(brandName))) {
|
|
1297
|
-
this.set(NAME, brandName)
|
|
1298
|
-
.set(VERSION, brandVersion)
|
|
1299
|
-
.set(MAJOR, majorize(brandVersion));
|
|
1300
|
-
}
|
|
1301
|
-
prevName = brandName;
|
|
1302
|
-
}
|
|
1303
|
-
if (this.itemType == ENGINE && brandName == CHROMIUM) {
|
|
1304
|
-
this.set(VERSION, brandVersion);
|
|
1305
|
-
}
|
|
1306
|
-
}
|
|
1307
|
-
}
|
|
1308
|
-
break;
|
|
1309
|
-
case CPU:
|
|
1310
|
-
var archName = uaCH[ARCHITECTURE];
|
|
1311
|
-
if (archName) {
|
|
1312
|
-
if (archName && uaCH[BITNESS] == '64') archName += '64';
|
|
1313
|
-
rgxMapper.call(this.data, archName + ';', rgxMap);
|
|
1234
|
+
// Brave-specific detection
|
|
1235
|
+
if (NAVIGATOR.brave && typeof NAVIGATOR.brave.isBrave == TYPEOF.FUNCTION) {
|
|
1236
|
+
this.set(NAME, 'Brave');
|
|
1314
1237
|
}
|
|
1315
1238
|
break;
|
|
1316
1239
|
case DEVICE:
|
|
1317
|
-
|
|
1240
|
+
// Chrome-specific detection: check for 'mobile' value of navigator.userAgentData
|
|
1241
|
+
if (!this.get(TYPE) && NAVIGATOR_UADATA && NAVIGATOR_UADATA[MOBILE]) {
|
|
1318
1242
|
this.set(TYPE, MOBILE);
|
|
1319
1243
|
}
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
rgxMapper.call(reParse, 'droid 9; ' + uaCH[MODEL] + ')', rgxMap);
|
|
1325
|
-
if (!this.get(TYPE) && !!reParse.type) {
|
|
1326
|
-
this.set(TYPE, reParse.type);
|
|
1327
|
-
}
|
|
1328
|
-
if (!this.get(VENDOR) && !!reParse.vendor) {
|
|
1329
|
-
this.set(VENDOR, reParse.vendor);
|
|
1330
|
-
}
|
|
1331
|
-
}
|
|
1332
|
-
}
|
|
1333
|
-
if (uaCH[FORMFACTORS]) {
|
|
1334
|
-
var ff;
|
|
1335
|
-
if (typeof uaCH[FORMFACTORS] !== 'string') {
|
|
1336
|
-
var idx = 0;
|
|
1337
|
-
while (!ff && idx < uaCH[FORMFACTORS].length) {
|
|
1338
|
-
ff = strMapper(uaCH[FORMFACTORS][idx++], formFactorsMap);
|
|
1339
|
-
}
|
|
1340
|
-
} else {
|
|
1341
|
-
ff = strMapper(uaCH[FORMFACTORS], formFactorsMap);
|
|
1342
|
-
}
|
|
1343
|
-
this.set(TYPE, ff);
|
|
1244
|
+
// iPadOS-specific detection: identified as Mac, but has some iOS-only properties
|
|
1245
|
+
if (this.get(MODEL) == 'Macintosh' && NAVIGATOR && typeof NAVIGATOR.standalone !== TYPEOF.UNDEFINED && NAVIGATOR.maxTouchPoints && NAVIGATOR.maxTouchPoints > 2) {
|
|
1246
|
+
this.set(MODEL, 'iPad')
|
|
1247
|
+
.set(TYPE, TABLET);
|
|
1344
1248
|
}
|
|
1345
1249
|
break;
|
|
1346
1250
|
case OS:
|
|
1347
|
-
|
|
1348
|
-
if(
|
|
1349
|
-
|
|
1350
|
-
if (osName == WINDOWS) osVersion = (parseInt(majorize(osVersion), 10) >= 13 ? '11' : '10');
|
|
1351
|
-
this.set(NAME, osName)
|
|
1352
|
-
.set(VERSION, osVersion);
|
|
1251
|
+
// Chrome-specific detection: check for 'platform' value of navigator.userAgentData
|
|
1252
|
+
if (!this.get(NAME) && NAVIGATOR_UADATA && NAVIGATOR_UADATA[PLATFORM]) {
|
|
1253
|
+
this.set(NAME, NAVIGATOR_UADATA[PLATFORM]);
|
|
1353
1254
|
}
|
|
1354
|
-
// Xbox-Specific Detection
|
|
1355
|
-
if (this.get(NAME) == WINDOWS && uaCH[MODEL] == 'Xbox') {
|
|
1356
|
-
this.set(NAME, 'Xbox')
|
|
1357
|
-
.set(VERSION, undefined);
|
|
1358
|
-
}
|
|
1359
1255
|
break;
|
|
1360
1256
|
case RESULT:
|
|
1361
1257
|
var data = this.data;
|
|
1362
|
-
var
|
|
1258
|
+
var detect = function (itemType) {
|
|
1363
1259
|
return data[itemType]
|
|
1364
1260
|
.getItem()
|
|
1365
|
-
.
|
|
1366
|
-
.parseCH()
|
|
1261
|
+
.detectFeature()
|
|
1367
1262
|
.get();
|
|
1368
1263
|
};
|
|
1369
|
-
this.set(BROWSER,
|
|
1370
|
-
.set(CPU,
|
|
1371
|
-
.set(DEVICE,
|
|
1372
|
-
.set(ENGINE,
|
|
1373
|
-
.set(OS,
|
|
1264
|
+
this.set(BROWSER, detect(BROWSER))
|
|
1265
|
+
.set(CPU, detect(CPU))
|
|
1266
|
+
.set(DEVICE, detect(DEVICE))
|
|
1267
|
+
.set(ENGINE, detect(ENGINE))
|
|
1268
|
+
.set(OS, detect(OS));
|
|
1374
1269
|
}
|
|
1375
|
-
|
|
1376
|
-
|
|
1270
|
+
}
|
|
1271
|
+
return this;
|
|
1272
|
+
};
|
|
1377
1273
|
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1274
|
+
UAItem.prototype.parseUA = function () {
|
|
1275
|
+
if (this.itemType != RESULT) {
|
|
1276
|
+
rgxMapper.call(this.data, this.ua, this.rgxMap);
|
|
1277
|
+
}
|
|
1278
|
+
switch (this.itemType) {
|
|
1279
|
+
case BROWSER:
|
|
1280
|
+
this.set(MAJOR, majorize(this.get(VERSION)));
|
|
1281
|
+
break;
|
|
1282
|
+
case OS:
|
|
1283
|
+
if (this.get(NAME) == 'iOS' && this.get(VERSION) == '18.6') {
|
|
1284
|
+
// Based on the assumption that iOS version is tightly coupled with Safari version
|
|
1285
|
+
var realVersion = /\) Version\/([\d\.]+)/.exec(this.ua); // Get Safari version
|
|
1286
|
+
if (realVersion && parseInt(realVersion[1].substring(0,2), 10) >= 26) {
|
|
1287
|
+
this.set(VERSION, realVersion[1]); // Set as iOS version
|
|
1288
|
+
}
|
|
1289
|
+
}
|
|
1290
|
+
break;
|
|
1291
|
+
}
|
|
1292
|
+
return this;
|
|
1293
|
+
};
|
|
1385
1294
|
|
|
1295
|
+
UAItem.prototype.parseCH = function () {
|
|
1296
|
+
var uaCH = this.uaCH,
|
|
1297
|
+
rgxMap = this.rgxMap;
|
|
1298
|
+
|
|
1299
|
+
switch (this.itemType) {
|
|
1300
|
+
case BROWSER:
|
|
1301
|
+
case ENGINE:
|
|
1302
|
+
var brands = uaCH[FULLVERLIST] || uaCH[BRANDS], prevName;
|
|
1303
|
+
if (brands) {
|
|
1304
|
+
for (var i=0; i<brands.length; i++) {
|
|
1305
|
+
var brandName = brands[i].brand || brands[i],
|
|
1306
|
+
brandVersion = brands[i].version;
|
|
1307
|
+
if (this.itemType == BROWSER &&
|
|
1308
|
+
!/not.a.brand/i.test(brandName) &&
|
|
1309
|
+
(!prevName ||
|
|
1310
|
+
(/Chrom/.test(prevName) && brandName != CHROMIUM) ||
|
|
1311
|
+
(prevName == EDGE && /WebView2/.test(brandName))
|
|
1312
|
+
)) {
|
|
1313
|
+
brandName = strMapper(brandName, browserHintsMap);
|
|
1314
|
+
prevName = this.get(NAME);
|
|
1315
|
+
if (!(prevName && !/Chrom/.test(prevName) && /Chrom/.test(brandName))) {
|
|
1316
|
+
this.set(NAME, brandName)
|
|
1317
|
+
.set(VERSION, brandVersion)
|
|
1318
|
+
.set(MAJOR, majorize(brandVersion));
|
|
1319
|
+
}
|
|
1320
|
+
prevName = brandName;
|
|
1321
|
+
}
|
|
1322
|
+
if (this.itemType == ENGINE && brandName == CHROMIUM) {
|
|
1323
|
+
this.set(VERSION, brandVersion);
|
|
1324
|
+
}
|
|
1325
|
+
}
|
|
1326
|
+
}
|
|
1327
|
+
break;
|
|
1328
|
+
case CPU:
|
|
1329
|
+
var archName = uaCH[ARCHITECTURE];
|
|
1330
|
+
if (archName) {
|
|
1331
|
+
if (archName && uaCH[BITNESS] == '64') archName += '64';
|
|
1332
|
+
rgxMapper.call(this.data, archName + ';', rgxMap);
|
|
1333
|
+
}
|
|
1334
|
+
break;
|
|
1335
|
+
case DEVICE:
|
|
1336
|
+
if (uaCH[MOBILE]) {
|
|
1337
|
+
this.set(TYPE, MOBILE);
|
|
1338
|
+
}
|
|
1339
|
+
if (uaCH[MODEL]) {
|
|
1340
|
+
this.set(MODEL, uaCH[MODEL]);
|
|
1341
|
+
if (!this.get(TYPE) || !this.get(VENDOR)) {
|
|
1342
|
+
var reParse = {};
|
|
1343
|
+
rgxMapper.call(reParse, 'droid 9; ' + uaCH[MODEL] + ')', rgxMap);
|
|
1344
|
+
if (!this.get(TYPE) && !!reParse.type) {
|
|
1345
|
+
this.set(TYPE, reParse.type);
|
|
1346
|
+
}
|
|
1347
|
+
if (!this.get(VENDOR) && !!reParse.vendor) {
|
|
1348
|
+
this.set(VENDOR, reParse.vendor);
|
|
1349
|
+
}
|
|
1350
|
+
}
|
|
1351
|
+
}
|
|
1352
|
+
if (uaCH[FORMFACTORS]) {
|
|
1353
|
+
var ff;
|
|
1354
|
+
if (typeof uaCH[FORMFACTORS] !== 'string') {
|
|
1355
|
+
var idx = 0;
|
|
1356
|
+
while (!ff && idx < uaCH[FORMFACTORS].length) {
|
|
1357
|
+
ff = strMapper(uaCH[FORMFACTORS][idx++], formFactorsMap);
|
|
1358
|
+
}
|
|
1359
|
+
} else {
|
|
1360
|
+
ff = strMapper(uaCH[FORMFACTORS], formFactorsMap);
|
|
1361
|
+
}
|
|
1362
|
+
this.set(TYPE, ff);
|
|
1363
|
+
}
|
|
1364
|
+
break;
|
|
1365
|
+
case OS:
|
|
1366
|
+
var osName = uaCH[PLATFORM];
|
|
1367
|
+
if(osName) {
|
|
1368
|
+
var osVersion = uaCH[PLATFORMVER];
|
|
1369
|
+
if (osName == WINDOWS) osVersion = (parseInt(majorize(osVersion), 10) >= 13 ? '11' : '10');
|
|
1370
|
+
this.set(NAME, osName)
|
|
1371
|
+
.set(VERSION, osVersion);
|
|
1372
|
+
}
|
|
1373
|
+
// Xbox-Specific Detection
|
|
1374
|
+
if (this.get(NAME) == WINDOWS && uaCH[MODEL] == 'Xbox') {
|
|
1375
|
+
this.set(NAME, 'Xbox')
|
|
1376
|
+
.set(VERSION, undefined);
|
|
1377
|
+
}
|
|
1378
|
+
break;
|
|
1379
|
+
case RESULT:
|
|
1380
|
+
var data = this.data;
|
|
1381
|
+
var parse = function (itemType) {
|
|
1382
|
+
return data[itemType]
|
|
1383
|
+
.getItem()
|
|
1384
|
+
.setCH(uaCH)
|
|
1385
|
+
.parseCH()
|
|
1386
|
+
.get();
|
|
1387
|
+
};
|
|
1388
|
+
this.set(BROWSER, parse(BROWSER))
|
|
1389
|
+
.set(CPU, parse(CPU))
|
|
1390
|
+
.set(DEVICE, parse(DEVICE))
|
|
1391
|
+
.set(ENGINE, parse(ENGINE))
|
|
1392
|
+
.set(OS, parse(OS));
|
|
1393
|
+
}
|
|
1386
1394
|
return this;
|
|
1387
|
-
}
|
|
1395
|
+
};
|
|
1388
1396
|
|
|
1389
1397
|
function UAParser (ua, extensions, headers) {
|
|
1390
1398
|
|