ua-parser-js 2.0.0-alpha.2 → 2.0.0-alpha.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,5 +1,5 @@
1
1
  /////////////////////////////////////////////////////////////////////////////////
2
- /* UAParser.js v2.0.0-alpha.2
2
+ /* UAParser.js v2.0.0-alpha.3
3
3
  Copyright © 2012-2023 Faisal Salman <f@faisalman.com>
4
4
  MIT License *//*
5
5
  Detect Browser, Engine, OS, CPU, and Device type/model from User-Agent data.
@@ -8,16 +8,19 @@
8
8
  Source : https://github.com/faisalman/ua-parser-js */
9
9
  /////////////////////////////////////////////////////////////////////////////////
10
10
 
11
+ /* jshint esversion: 3 */
12
+ /* globals window */
13
+
11
14
  (function (window, undefined) {
12
15
 
13
16
  'use strict';
14
-
17
+
15
18
  //////////////
16
19
  // Constants
17
20
  /////////////
18
21
 
19
22
 
20
- var LIBVERSION = '2.0.0-alpha.2',
23
+ var LIBVERSION = '2.0.0-alpha.3',
21
24
  EMPTY = '',
22
25
  UNKNOWN = '?',
23
26
  FUNC_TYPE = 'function',
@@ -47,12 +50,12 @@
47
50
  CH_HEADER = 'sec-ch-ua',
48
51
  CH_HEADER_FULL_VER_LIST = CH_HEADER + '-full-version-list',
49
52
  CH_HEADER_ARCH = CH_HEADER + '-arch',
50
- CH_HEADER_BITNESS = CH_HEADER + '-bitness',
51
- CH_HEADER_MOBILE = CH_HEADER + '-mobile',
52
- CH_HEADER_MODEL = CH_HEADER + '-model',
53
- CH_HEADER_PLATFORM = CH_HEADER + '-platform',
53
+ CH_HEADER_BITNESS = CH_HEADER + '-' + BITNESS,
54
+ CH_HEADER_MOBILE = CH_HEADER + '-' + MOBILE,
55
+ CH_HEADER_MODEL = CH_HEADER + '-' + MODEL,
56
+ CH_HEADER_PLATFORM = CH_HEADER + '-' + PLATFORM,
54
57
  CH_HEADER_PLATFORM_VER = CH_HEADER_PLATFORM + '-version',
55
- CH_ALL_VALUES = ['brands', 'fullVersionList', MOBILE, MODEL, 'platform', 'platformVersion', ARCHITECTURE, 'bitness'],
58
+ CH_ALL_VALUES = [BRANDS, FULLVERLIST, MOBILE, MODEL, PLATFORM, PLATFORMVER, ARCHITECTURE, BITNESS],
56
59
  UA_BROWSER = 'browser',
57
60
  UA_CPU = 'cpu',
58
61
  UA_DEVICE = 'device',
@@ -93,18 +96,7 @@
93
96
  // Helper
94
97
  //////////
95
98
 
96
- var assignFromEntries = function (arr) {
97
- for (var i in arr) {
98
- var propName = arr[i];
99
- if (typeof propName == OBJ_TYPE && propName.length == 2) {
100
- this[propName[0]] = propName[1];
101
- } else {
102
- this[propName] = undefined;
103
- }
104
- }
105
- return this;
106
- },
107
- extend = function (regexes, extensions) {
99
+ var extend = function (regexes, extensions) {
108
100
  var mergedRegexes = {};
109
101
  for (var i in regexes) {
110
102
  mergedRegexes[i] = extensions[i] && extensions[i].length % 2 === 0 ? extensions[i].concat(regexes[i]) : regexes[i];
@@ -148,6 +140,17 @@
148
140
  majorize = function (version) {
149
141
  return typeof(version) === STR_TYPE ? strip(/[^\d\.]/g, version).split('.')[0] : undefined;
150
142
  },
143
+ setProps = function (arr) {
144
+ for (var i in arr) {
145
+ var propName = arr[i];
146
+ if (typeof propName == OBJ_TYPE && propName.length == 2) {
147
+ this[propName[0]] = propName[1];
148
+ } else {
149
+ this[propName] = undefined;
150
+ }
151
+ }
152
+ return this;
153
+ },
151
154
  strip = function (pattern, str) {
152
155
  return str.replace(pattern, EMPTY);
153
156
  },
@@ -241,18 +244,7 @@
241
244
  // String map
242
245
  //////////////
243
246
 
244
- // Safari < 3.0
245
- var oldSafariMap = {
246
- '1.0' : '/8',
247
- '1.2' : '/1',
248
- '1.3' : '/3',
249
- '2.0' : '/412',
250
- '2.0.2' : '/416',
251
- '2.0.3' : '/417',
252
- '2.0.4' : '/419',
253
- '?' : '/'
254
- },
255
- windowsVersionMap = {
247
+ var windowsVersionMap = {
256
248
  'ME' : '4.90',
257
249
  'NT 3.11' : 'NT3.51',
258
250
  'NT 4.0' : 'NT4.0',
@@ -355,7 +347,7 @@
355
347
  /(naver)\(.*?(\d+\.[\w\.]+).*\)/i, // Naver InApp
356
348
  /safari (line)\/([\w\.]+)/i, // Line App for iOS
357
349
  /\b(line)\/([\w\.]+)\/iab/i, // Line App for Android
358
- /(chromium|instagram)[\/ ]([-\w\.]+)/i // Chromium/Instagram
350
+ /(chromium|instagram|snapchat)[\/ ]([-\w\.]+)/i // Chromium/Instagram/Snapchat
359
351
  ], [NAME, VERSION], [
360
352
  /\bgsa\/([\w\.]+) .*safari\//i // Google Search Appliance on iOS
361
353
  ], [VERSION, [NAME, 'GSA']], [
@@ -384,7 +376,7 @@
384
376
  /version\/([\w\.\,]+) .*(safari)/i // Safari
385
377
  ], [VERSION, NAME], [
386
378
  /webkit.+?(mobile ?safari|safari)(\/[\w\.]+)/i // Safari < 3.0
387
- ], [NAME, [VERSION, strMapper, oldSafariMap]], [
379
+ ], [NAME, [VERSION, '1']], [
388
380
 
389
381
  /(webkit|khtml)\/([\w\.]+)/i
390
382
  ], [NAME, VERSION], [
@@ -425,7 +417,7 @@
425
417
  /((?:i[346]|x)86)[;\)]/i // IA32 (x86)
426
418
  ], [[ARCHITECTURE, 'ia32']], [
427
419
 
428
- /\b(aarch64|arm(v?8e?l?|_?64))\b/i // ARM64
420
+ /\b(aarch64|arm(v?8e?l?|_?64))\b/i // ARM64
429
421
  ], [[ARCHITECTURE, 'arm64']], [
430
422
 
431
423
  /\b(arm(?:v[67])?ht?n?[fl]p?)\b/i // ARMHF
@@ -482,7 +474,7 @@
482
474
  ], [MODEL, [VENDOR, HUAWEI], [TYPE, MOBILE]], [
483
475
 
484
476
  // Xiaomi
485
- /\b(poco[\w ]+)(?: bui|\))/i, // Xiaomi POCO
477
+ /\b(poco[\w ]+|m2\d{3}j\d\d[a-z]{2})(?: bui|\))/i, // Xiaomi POCO
486
478
  /\b; (\w+) build\/hm\1/i, // Xiaomi Hongmi 'numeric' models
487
479
  /\b(hm[-_ ]?note?[_ ]?(?:\d\w)?) bui/i, // Xiaomi Hongmi
488
480
  /\b(redmi[\-_ ]?(?:note|k)?[\w_ ]+)(?: bui|\))/i, // Xiaomi Redmi
@@ -590,7 +582,7 @@
590
582
  ], [MODEL, [VENDOR, 'Meizu'], [TYPE, MOBILE]], [
591
583
 
592
584
  // MIXED
593
- /(blackberry|benq|palm(?=\-)|sonyericsson|acer|asus|dell|meizu|motorola|polytron)[-_ ]?([-\w]*)/i,
585
+ /(blackberry|benq|palm(?=\-)|sonyericsson|acer|asus|dell|meizu|motorola|polytron|infinix|tecno)[-_ ]?([-\w]*)/i,
594
586
  // BlackBerry/BenQ/Palm/Sony-Ericsson/Acer/Asus/Dell/Meizu/Motorola/Polytron
595
587
  /(hp) ([\w ]+\w)/i, // HP iPAQ
596
588
  /(asus)-?(\w+)/i, // Asus
@@ -635,7 +627,7 @@
635
627
  ], [VENDOR, [MODEL, APPLE+' TV'], [TYPE, SMARTTV]], [
636
628
  /crkey/i // Google Chromecast
637
629
  ], [[MODEL, CHROME+'cast'], [VENDOR, GOOGLE], [TYPE, SMARTTV]], [
638
- /droid.+aft(\w)( bui|\))/i // Fire TV
630
+ /droid.+aft(\w+)( bui|\))/i // Fire TV
639
631
  ], [MODEL, [VENDOR, AMAZON], [TYPE, SMARTTV]], [
640
632
  /\(dtv[\);].+(aquos)/i,
641
633
  /(aquos-tv[\w ]+)\)/i // Sharp
@@ -740,7 +732,7 @@
740
732
 
741
733
  // iOS/macOS
742
734
  /ip[honead]{2,4}\b(?:.*os ([\w]+) like mac|; opera)/i, // iOS
743
- /ios;fbsv\/([\d\.]+)/i,
735
+ /(?:ios;fbsv\/|iphone.+ios[\/ ])([\d\.]+)/i,
744
736
  /cfnetwork\/.+darwin/i
745
737
  ], [[VERSION, /_/g, '.'], [NAME, 'iOS']], [
746
738
  /(mac os x) ?([\w\. ]*)/i,
@@ -809,23 +801,23 @@
809
801
 
810
802
  var defaultProps = (function () {
811
803
  var props = { init : {}, isIgnore : {}, isIgnoreRgx : {}, toString : {}};
812
- assignFromEntries.call(props.init, [
804
+ setProps.call(props.init, [
813
805
  [UA_BROWSER, [NAME, VERSION, MAJOR]],
814
806
  [UA_CPU, [ARCHITECTURE]],
815
807
  [UA_DEVICE, [TYPE, MODEL, VENDOR]],
816
808
  [UA_ENGINE, [NAME, VERSION]],
817
809
  [UA_OS, [NAME, VERSION]]
818
810
  ]);
819
- assignFromEntries.call(props.isIgnore, [
811
+ setProps.call(props.isIgnore, [
820
812
  [UA_BROWSER, [VERSION, MAJOR]],
821
813
  [UA_ENGINE, [VERSION]],
822
814
  [UA_OS, [VERSION]]
823
815
  ]);
824
- assignFromEntries.call(props.isIgnoreRgx, [
816
+ setProps.call(props.isIgnoreRgx, [
825
817
  [UA_BROWSER, / ?browser$/i],
826
818
  [UA_OS, / ?os$/i]
827
819
  ]);
828
- assignFromEntries.call(props.toString, [
820
+ setProps.call(props.toString, [
829
821
  [UA_BROWSER, [NAME, VERSION]],
830
822
  [UA_CPU, [ARCHITECTURE]],
831
823
  [UA_DEVICE, [VENDOR, MODEL]],
@@ -835,34 +827,47 @@
835
827
  return props;
836
828
  })();
837
829
 
838
- var createUAParserData = function (itemType, ua, rgxMap, uaCH) {
830
+ var createIData = function (item, itemType) {
839
831
 
840
832
  var init_props = defaultProps.init[itemType],
841
833
  is_ignoreProps = defaultProps.isIgnore[itemType] || 0,
842
834
  is_ignoreRgx = defaultProps.isIgnoreRgx[itemType] || 0,
843
835
  toString_props = defaultProps.toString[itemType] || 0;
844
836
 
845
- function UAParserData () {
846
- assignFromEntries.call(this, init_props);
837
+ function IData () {
838
+ setProps.call(this, init_props);
847
839
  }
848
- UAParserData.prototype.withClientHints = function () {
849
-
840
+
841
+ IData.prototype.getItem = function () {
842
+ return item;
843
+ };
844
+
845
+ IData.prototype.withClientHints = function () {
846
+
850
847
  // nodejs / non-client-hints browsers
851
848
  if (!NAVIGATOR_UADATA) {
852
- return new UAParserItem(itemType, ua, rgxMap, uaCH).parseCH().get();
849
+ return item
850
+ .parseCH()
851
+ .get();
853
852
  }
854
853
 
855
854
  // browsers based on chromium 85+
856
855
  return NAVIGATOR_UADATA
857
856
  .getHighEntropyValues(CH_ALL_VALUES)
858
857
  .then(function (res) {
859
- var JS_UACH = new UAParserDataCH(res, false);
860
- return new UAParserItem(itemType, ua, rgxMap, JS_UACH).parseCH().get();
858
+ return item
859
+ .setCH(new UACHData(res, false))
860
+ .parseCH()
861
+ .get();
861
862
  });
862
863
  };
863
864
 
865
+ IData.prototype.withFeatureCheck = function () {
866
+ return item.detectFeature().get();
867
+ };
868
+
864
869
  if (itemType != UA_RESULT) {
865
- UAParserData.prototype.is = function (strToCheck) {
870
+ IData.prototype.is = function (strToCheck) {
866
871
  var is = false;
867
872
  for (var i in this) {
868
873
  if (this.hasOwnProperty(i) && !has(is_ignoreProps, i) && lowerize(is_ignoreRgx ? strip(is_ignoreRgx, this[i]) : this[i]) == lowerize(is_ignoreRgx ? strip(is_ignoreRgx, strToCheck) : strToCheck)) {
@@ -875,7 +880,7 @@
875
880
  }
876
881
  return is;
877
882
  };
878
- UAParserData.prototype.toString = function () {
883
+ IData.prototype.toString = function () {
879
884
  var str = EMPTY;
880
885
  for (var i in toString_props) {
881
886
  if (typeof(this[toString_props[i]]) !== UNDEF_TYPE) {
@@ -887,40 +892,39 @@
887
892
  }
888
893
 
889
894
  if (!NAVIGATOR_UADATA) {
890
- UAParserData.prototype.then = function (cb) {
895
+ IData.prototype.then = function (cb) {
891
896
  var that = this;
892
- var UAParserDataResolve = function () {
897
+ var IDataResolve = function () {
893
898
  for (var prop in that) {
894
899
  if (that.hasOwnProperty(prop)) {
895
900
  this[prop] = that[prop];
896
901
  }
897
902
  }
898
903
  };
899
- UAParserDataResolve.prototype = {
900
- is : UAParserData.prototype.is,
901
- toString : UAParserData.prototype.toString
904
+ IDataResolve.prototype = {
905
+ is : IData.prototype.is,
906
+ toString : IData.prototype.toString
902
907
  };
903
- var resolveData = new UAParserDataResolve();
908
+ var resolveData = new IDataResolve();
904
909
  cb(resolveData);
905
910
  return resolveData;
906
911
  };
907
912
  }
908
913
 
909
- return new UAParserData();
914
+ return new IData();
910
915
  };
911
916
 
912
917
  /////////////////
913
918
  // Constructor
914
919
  ////////////////
915
920
 
916
- function UAParserDataCH (uach, isHTTP_UACH) {
921
+ function UACHData (uach, isHttpUACH) {
917
922
  uach = uach || {};
918
- assignFromEntries.call(this, CH_ALL_VALUES);
919
- if (isHTTP_UACH) {
920
- assignFromEntries.call(this, [
923
+ setProps.call(this, CH_ALL_VALUES);
924
+ if (isHttpUACH) {
925
+ setProps.call(this, [
921
926
  [BRANDS, itemListToArray(uach[CH_HEADER])],
922
927
  [FULLVERLIST, itemListToArray(uach[CH_HEADER_FULL_VER_LIST])],
923
- [BRANDS, itemListToArray(uach[CH_HEADER])],
924
928
  [MOBILE, /\?1/.test(uach[CH_HEADER_MOBILE])],
925
929
  [MODEL, stripQuotes(uach[CH_HEADER_MODEL])],
926
930
  [PLATFORM, stripQuotes(uach[CH_HEADER_PLATFORM])],
@@ -933,127 +937,151 @@
933
937
  if(this.hasOwnProperty(prop) && typeof uach[prop] !== UNDEF_TYPE) this[prop] = uach[prop];
934
938
  }
935
939
  }
936
- return this;
937
940
  }
938
941
 
939
- function UAParserItem (itemType, ua, rgxMap, uaCH) {
940
- assignFromEntries.call(this, [
942
+ function UAItem (itemType, ua, rgxMap, uaCH) {
943
+
944
+ this.get = function (prop) {
945
+ if (!prop) return this.data;
946
+ return this.data.hasOwnProperty(prop) ? this.data[prop] : undefined;
947
+ };
948
+
949
+ this.set = function (prop, val) {
950
+ this.data[prop] = val;
951
+ return this;
952
+ };
953
+
954
+ this.setCH = function (ch) {
955
+ this.uaCH = ch;
956
+ return this;
957
+ };
958
+
959
+ this.detectFeature = function () {
960
+ if (NAVIGATOR && NAVIGATOR.userAgent == this.ua) {
961
+ switch (this.itemType) {
962
+ case UA_BROWSER:
963
+ // Brave-specific detection
964
+ if (NAVIGATOR.brave && typeof NAVIGATOR.brave.isBrave == FUNC_TYPE) {
965
+ this.set(NAME, 'Brave');
966
+ }
967
+ break;
968
+ case UA_DEVICE:
969
+ // Chrome-specific detection: check for 'mobile' value of navigator.userAgentData
970
+ if (!this.get(TYPE) && NAVIGATOR_UADATA && NAVIGATOR_UADATA[MOBILE]) {
971
+ this.set(TYPE, MOBILE);
972
+ }
973
+ // iPadOS-specific detection: identified as Mac, but has some iOS-only properties
974
+ if (this.get(MODEL) == 'Macintosh' && NAVIGATOR && typeof NAVIGATOR.standalone !== UNDEF_TYPE && NAVIGATOR.maxTouchPoints && NAVIGATOR.maxTouchPoints > 2) {
975
+ this.set(MODEL, 'iPad')
976
+ .set(TYPE, TABLET);
977
+ }
978
+ break;
979
+ case UA_OS:
980
+ // Chrome-specific detection: check for 'platform' value of navigator.userAgentData
981
+ if (!this.get(NAME) && NAVIGATOR_UADATA && NAVIGATOR_UADATA[PLATFORM]) {
982
+ this.set(NAME, NAVIGATOR_UADATA[PLATFORM]);
983
+ }
984
+ break;
985
+ case UA_RESULT:
986
+ var data = this.data;
987
+ var detect = function (itemType) {
988
+ return data[itemType]
989
+ .getItem()
990
+ .detectFeature()
991
+ .get();
992
+ };
993
+ this.set(UA_BROWSER, detect(UA_BROWSER))
994
+ .set(UA_CPU, detect(UA_CPU))
995
+ .set(UA_DEVICE, detect(UA_DEVICE))
996
+ .set(UA_ENGINE, detect(UA_ENGINE))
997
+ .set(UA_OS, detect(UA_OS));
998
+ }
999
+ }
1000
+ return this;
1001
+ };
1002
+
1003
+ this.parseUA = function () {
1004
+ if (this.itemType != UA_RESULT) {
1005
+ rgxMapper.call(this.data, this.ua, this.rgxMap);
1006
+ }
1007
+ if (this.itemType == UA_BROWSER) {
1008
+ this.set(MAJOR, majorize(this.get(VERSION)));
1009
+ }
1010
+ return this;
1011
+ };
1012
+
1013
+ this.parseCH = function () {
1014
+ var ua = this.ua,
1015
+ uaCH = this.uaCH,
1016
+ rgxMap = this.rgxMap;
1017
+
1018
+ switch (this.itemType) {
1019
+ case UA_BROWSER:
1020
+ var brands = uaCH[FULLVERLIST] || uaCH[BRANDS];
1021
+ if (brands) {
1022
+ for (var i in brands) {
1023
+ var brandName = brands[i].brand,
1024
+ brandVersion = brands[i].version;
1025
+ if (!/not.a.brand/i.test(brandName) && (i < 1 || /chromi/i.test(this.get(NAME)))) {
1026
+ this.set(NAME, strip(GOOGLE+' ', brandName))
1027
+ .set(VERSION, brandVersion)
1028
+ .set(MAJOR, majorize(brandVersion));
1029
+ }
1030
+ }
1031
+ }
1032
+ break;
1033
+ case UA_CPU:
1034
+ var archName = uaCH[ARCHITECTURE];
1035
+ if (archName) {
1036
+ if (archName && uaCH[BITNESS] == '64') archName += '64';
1037
+ rgxMapper.call(this.data, archName + ';', rgxMap);
1038
+ }
1039
+ break;
1040
+ case UA_DEVICE:
1041
+ if (uaCH[MOBILE]) {
1042
+ this.set(TYPE, MOBILE);
1043
+ }
1044
+ if (uaCH[MODEL]) {
1045
+ this.set(MODEL, uaCH[MODEL]);
1046
+ }
1047
+ break;
1048
+ case UA_OS:
1049
+ var osName = uaCH[PLATFORM];
1050
+ if(osName) {
1051
+ var osVersion = uaCH[PLATFORMVER];
1052
+ if (osName == WINDOWS) osVersion = (parseInt(majorize(osVersion), 10) >= 13 ? '11' : '10');
1053
+ this.set(NAME, osName)
1054
+ .set(VERSION, osVersion);
1055
+ }
1056
+ break;
1057
+ case UA_RESULT:
1058
+ var data = this.data;
1059
+ var parse = function (itemType) {
1060
+ return data[itemType]
1061
+ .getItem()
1062
+ .setCH(uaCH)
1063
+ .parseCH()
1064
+ .get();
1065
+ };
1066
+ this.set(UA_BROWSER, parse(UA_BROWSER))
1067
+ .set(UA_CPU, parse(UA_CPU))
1068
+ .set(UA_DEVICE, parse(UA_DEVICE))
1069
+ .set(UA_ENGINE, parse(UA_ENGINE))
1070
+ .set(UA_OS, parse(UA_OS));
1071
+ }
1072
+ return this;
1073
+ };
1074
+
1075
+ setProps.call(this, [
941
1076
  ['itemType', itemType],
942
1077
  ['ua', ua],
943
1078
  ['uaCH', uaCH],
944
1079
  ['rgxMap', rgxMap],
945
- ['data', createUAParserData(itemType, ua, rgxMap, uaCH)]
1080
+ ['data', createIData(this, itemType)]
946
1081
  ]);
947
- this.parse();
948
- var isSelfNav = NAVIGATOR && NAVIGATOR.userAgent == ua;
949
- switch(this.itemType) {
950
- case UA_BROWSER:
951
- // Brave-specific detection
952
- if (isSelfNav && NAVIGATOR.brave && typeof NAVIGATOR.brave.isBrave == FUNC_TYPE) {
953
- this.set(NAME, 'Brave');
954
- }
955
- this.set(MAJOR, majorize(this.get(VERSION)));
956
- break;
957
- case UA_DEVICE:
958
- if (isSelfNav && !this.get(TYPE) && NAVIGATOR_UADATA && NAVIGATOR_UADATA[MOBILE]) {
959
- this.set(TYPE, MOBILE);
960
- }
961
- // iPadOS-specific detection: identified as Mac, but has some iOS-only properties
962
- if (isSelfNav && this.get(MODEL) == 'Macintosh' && NAVIGATOR && typeof NAVIGATOR.standalone !== UNDEF_TYPE && NAVIGATOR.maxTouchPoints && NAVIGATOR.maxTouchPoints > 2) {
963
- this.set(MODEL, 'iPad')
964
- .set(TYPE, TABLET);
965
- }
966
- break;
967
- case UA_OS:
968
- if (isSelfNav && !this.get(NAME) && NAVIGATOR_UADATA && NAVIGATOR_UADATA[PLATFORM]) {
969
- this.set(NAME, NAVIGATOR_UADATA[PLATFORM]);
970
- }
971
- break;
972
- case UA_RESULT:
973
- var createUAParserItem = function (itemType) {
974
- return new UAParserItem(itemType, ua, rgxMap[itemType], uaCH).get();
975
- };
976
- this.set('ua', ua)
977
- .set(UA_BROWSER, createUAParserItem(UA_BROWSER))
978
- .set(UA_CPU, createUAParserItem(UA_CPU))
979
- .set(UA_DEVICE, createUAParserItem(UA_DEVICE))
980
- .set(UA_ENGINE, createUAParserItem(UA_ENGINE))
981
- .set(UA_OS, createUAParserItem(UA_OS))
982
- .get();
983
- }
1082
+
984
1083
  return this;
985
1084
  }
986
- UAParserItem.prototype.get = function (prop) {
987
- if (!prop) return this.data;
988
- return this.data.hasOwnProperty(prop) ? this.data[prop] : undefined;
989
- };
990
- UAParserItem.prototype.parse = function () {
991
- if (this.itemType != UA_RESULT) {
992
- rgxMapper.call(this.data, this.ua, this.rgxMap);
993
- }
994
- return this;
995
- };
996
- UAParserItem.prototype.parseCH = function () {
997
- var ua = this.ua,
998
- uaCH = this.uaCH,
999
- rgxMap = this.rgxMap;
1000
-
1001
- switch (this.itemType) {
1002
- case UA_BROWSER:
1003
- var brands = uaCH[FULLVERLIST] || uaCH[BRANDS];
1004
- if (brands) {
1005
- for (var i in brands) {
1006
- var brandName = brands[i].brand,
1007
- brandVersion = brands[i].version;
1008
- if (!/not.a.brand/i.test(brandName) && (i < 1 || /chromi/i.test(this.get(NAME)))) {
1009
- this.set(NAME, strip(GOOGLE+' ', brandName))
1010
- .set(VERSION, brandVersion)
1011
- .set(MAJOR, majorize(brandVersion));
1012
- }
1013
- }
1014
- }
1015
- break;
1016
- case UA_CPU:
1017
- var archName = uaCH[ARCHITECTURE];
1018
- if (archName) {
1019
- if (archName && uaCH[BITNESS] == '64') archName += '64';
1020
- rgxMapper.call(this.data, archName + ';', rgxMap);
1021
- }
1022
- break;
1023
- case UA_DEVICE:
1024
- if (uaCH[MOBILE]) {
1025
- this.set(TYPE, MOBILE);
1026
- }
1027
- if (uaCH[MODEL]) {
1028
- this.set(MODEL, uaCH[MODEL]);
1029
- }
1030
- break;
1031
- case UA_OS:
1032
- var osName = uaCH[PLATFORM];
1033
- if(osName) {
1034
- var osVersion = uaCH[PLATFORMVER];
1035
- if (osName == WINDOWS) osVersion = (parseInt(majorize(osVersion), 10) >= 13 ? '11' : '10');
1036
- this.set(NAME, osName)
1037
- .set(VERSION, osVersion);
1038
- }
1039
- break;
1040
- case UA_RESULT:
1041
- var createUAParserItemWithCH = function (itemType) {
1042
- return new UAParserItem(itemType, ua, rgxMap[itemType], uaCH).parseCH().get();
1043
- };
1044
- this.set('ua', ua)
1045
- .set(UA_BROWSER, createUAParserItemWithCH(UA_BROWSER))
1046
- .set(UA_CPU, createUAParserItemWithCH(UA_CPU))
1047
- .set(UA_DEVICE, createUAParserItemWithCH(UA_DEVICE))
1048
- .set(UA_ENGINE, createUAParserItemWithCH(UA_ENGINE))
1049
- .set(UA_OS, createUAParserItemWithCH(UA_OS));
1050
- }
1051
- return this;
1052
- };
1053
- UAParserItem.prototype.set = function (prop, val) {
1054
- this.data[prop] = val;
1055
- return this;
1056
- };
1057
1085
 
1058
1086
  function UAParser (ua, extensions, headers) {
1059
1087
 
@@ -1077,39 +1105,54 @@
1077
1105
  return new UAParser(ua, extensions, headers).getResult();
1078
1106
  }
1079
1107
 
1080
- var userAgent = ua ||
1081
- ((NAVIGATOR && NAVIGATOR.userAgent) ?
1082
- NAVIGATOR.userAgent :
1083
- (headers && headers[USER_AGENT] ?
1084
- headers[USER_AGENT] :
1085
- EMPTY)),
1086
-
1087
- HTTP_UACH = new UAParserDataCH(headers, true),
1108
+ var userAgent = typeof ua === STR_TYPE ? ua : // Passed user-agent string
1109
+ ((NAVIGATOR && NAVIGATOR.userAgent) ? NAVIGATOR.userAgent : // navigator.userAgent
1110
+ (headers && headers[USER_AGENT] ? headers[USER_AGENT] : // User-Agent from passed headers
1111
+ EMPTY)), // empty string
1088
1112
 
1113
+ httpUACH = new UACHData(headers, true),
1089
1114
  regexMap = extensions ?
1090
1115
  extend(defaultRegexes, extensions) :
1091
1116
  defaultRegexes,
1092
1117
 
1093
- createUAParserItemFunc = function (itemType) {
1094
- return function () {
1095
- return new UAParserItem(itemType, userAgent, itemType == UA_RESULT ? regexMap : regexMap[itemType], HTTP_UACH).get();
1096
- };
1118
+ createItemFunc = function (itemType) {
1119
+ if (itemType == UA_RESULT) {
1120
+ return function () {
1121
+ return new UAItem(itemType, userAgent, regexMap, httpUACH)
1122
+ .set('ua', userAgent)
1123
+ .set(UA_BROWSER, this.getBrowser())
1124
+ .set(UA_CPU, this.getCPU())
1125
+ .set(UA_DEVICE, this.getDevice())
1126
+ .set(UA_ENGINE, this.getEngine())
1127
+ .set(UA_OS, this.getOS())
1128
+ .get();
1129
+ };
1130
+ } else {
1131
+ return function () {
1132
+ return new UAItem(itemType, userAgent, regexMap[itemType], httpUACH)
1133
+ .parseUA()
1134
+ .get();
1135
+ };
1136
+ }
1097
1137
  };
1098
-
1138
+
1099
1139
  // public methods
1100
- assignFromEntries.call(this, [
1101
- ['getBrowser', createUAParserItemFunc(UA_BROWSER)],
1102
- ['getCPU', createUAParserItemFunc(UA_CPU)],
1103
- ['getDevice', createUAParserItemFunc(UA_DEVICE)],
1104
- ['getEngine', createUAParserItemFunc(UA_ENGINE)],
1105
- ['getOS', createUAParserItemFunc(UA_OS)],
1106
- ['getResult', createUAParserItemFunc(UA_RESULT)],
1140
+ setProps.call(this, [
1141
+ ['getBrowser', createItemFunc(UA_BROWSER)],
1142
+ ['getCPU', createItemFunc(UA_CPU)],
1143
+ ['getDevice', createItemFunc(UA_DEVICE)],
1144
+ ['getEngine', createItemFunc(UA_ENGINE)],
1145
+ ['getOS', createItemFunc(UA_OS)],
1146
+ ['getResult', createItemFunc(UA_RESULT)],
1107
1147
  ['getUA', function () { return userAgent; }],
1108
1148
  ['setUA', function (ua) {
1109
- userAgent = (typeof ua === STR_TYPE && ua.length > UA_MAX_LENGTH) ? trim(ua, UA_MAX_LENGTH) : ua;
1149
+ if (typeof ua === STR_TYPE)
1150
+ userAgent = ua.length > UA_MAX_LENGTH ? trim(ua, UA_MAX_LENGTH) : ua;
1110
1151
  return this;
1111
1152
  }]
1112
- ]).setUA(userAgent);
1153
+ ])
1154
+ .setUA(userAgent);
1155
+
1113
1156
  return this;
1114
1157
  }
1115
1158