mirror of
https://github.com/faisalman/ua-parser-js.git
synced 2025-09-28 00:18:45 +03:00
Expose UA-CH data in getResult()
This commit is contained in:
parent
3c3c03ceeb
commit
5672a2e15c
167
src/ua-parser.js
167
src/ua-parser.js
@ -95,20 +95,34 @@
|
|||||||
has = function (str1, str2) {
|
has = function (str1, str2) {
|
||||||
return typeof str1 === STR_TYPE ? lowerize(str2).indexOf(lowerize(str1)) !== -1 : false;
|
return typeof str1 === STR_TYPE ? lowerize(str2).indexOf(lowerize(str1)) !== -1 : false;
|
||||||
},
|
},
|
||||||
|
initialize = function (arr) {
|
||||||
|
for (var i in arr) {
|
||||||
|
var propName = arr[i];
|
||||||
|
if (typeof propName == OBJ_TYPE && propName.length == 2) {
|
||||||
|
this[propName[0]] = propName[1];
|
||||||
|
} else {
|
||||||
|
this[propName] = undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
},
|
||||||
isExtensions = function (obj) {
|
isExtensions = function (obj) {
|
||||||
for (var prop in obj) {
|
for (var prop in obj) {
|
||||||
return /^(browser|cpu|device|engine|os)$/.test(prop);
|
return /^(browser|cpu|device|engine|os)$/.test(prop);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
lowerize = function (str, rgx) {
|
lowerize = function (str, rgx) {
|
||||||
return typeof(str) === STR_TYPE ? str.toLowerCase().replace((rgx ? new RegExp(rgx, 'i') : EMPTY), EMPTY) : str;
|
return typeof(str) === STR_TYPE ? strip((rgx ? new RegExp(rgx, 'i') : EMPTY), str.toLowerCase()) : str;
|
||||||
},
|
},
|
||||||
majorize = function (version) {
|
majorize = function (version) {
|
||||||
return typeof(version) === STR_TYPE ? version.replace(/[^\d\.]/g, EMPTY).split('.')[0] : undefined;
|
return typeof(version) === STR_TYPE ? strip(/[^\d\.]/g, version).split('.')[0] : undefined;
|
||||||
|
},
|
||||||
|
strip = function (pattern, str) {
|
||||||
|
return str.replace(pattern, EMPTY);
|
||||||
},
|
},
|
||||||
trim = function (str, len) {
|
trim = function (str, len) {
|
||||||
if (typeof(str) === STR_TYPE) {
|
if (typeof(str) === STR_TYPE) {
|
||||||
str = str.replace(/^\s\s*/, EMPTY);
|
str = strip(/^\s\s*/, str);
|
||||||
return typeof(len) === UNDEF_TYPE ? str : str.substring(0, UA_MAX_LENGTH);
|
return typeof(len) === UNDEF_TYPE ? str : str.substring(0, UA_MAX_LENGTH);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -799,20 +813,45 @@
|
|||||||
// Constructor
|
// Constructor
|
||||||
////////////////
|
////////////////
|
||||||
|
|
||||||
|
function UACHData (uach, isBrowser) {
|
||||||
|
uach = uach || {};
|
||||||
|
if (!isBrowser) {
|
||||||
|
initialize.call(this, ['brands', MOBILE, MODEL, 'platform', 'platformVersion', ARCHITECTURE, 'bitness']);
|
||||||
|
if ((uach[CH_HEADER_FULL_VER_LIST] || uach[CH_HEADER])) {
|
||||||
|
this.brands = [];
|
||||||
|
var tokens = strip(/\\?\"/g, (uach[CH_HEADER_FULL_VER_LIST] || uach[CH_HEADER])).split(', ');
|
||||||
|
for (var i = 0; i < tokens.length; i++) {
|
||||||
|
var token = tokens[i].split(';v=');
|
||||||
|
this.brands[i] = { brand : token[0], version : token[1] };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.mobile = uach[CH_HEADER_MOBILE] == '?1';
|
||||||
|
var setHeader = function (header) {
|
||||||
|
return header ? strip(/\"/g, header) : undefined;
|
||||||
|
};
|
||||||
|
this.model = setHeader(uach[CH_HEADER_MODEL]);
|
||||||
|
this.platform = setHeader(uach[CH_HEADER_PLATFORM]);
|
||||||
|
this.platformVersion = setHeader(uach[CH_HEADER_PLATFORM_VER]);
|
||||||
|
this.architecture = setHeader(uach[CH_HEADER_ARCH]);
|
||||||
|
this.bitness = setHeader(uach[CH_HEADER_BITNESS]);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
function UAItem (data) {
|
function UAItem (data) {
|
||||||
if (!data) return;
|
if (!data) return;
|
||||||
this.ua = data[0];
|
this.ua = data[0];
|
||||||
this.rgxMap = data[1];
|
this.rgxMap = data[1];
|
||||||
|
this.uaCH = data[2];
|
||||||
this.data = (function (data) {
|
this.data = (function (data) {
|
||||||
var is_ignoreProps = data[3],
|
var init_props = data[3],
|
||||||
is_ignoreRgx = data[4],
|
is_ignoreProps = data[4],
|
||||||
toString_props = data[5];
|
is_ignoreRgx = data[5],
|
||||||
|
toString_props = data[6];
|
||||||
|
|
||||||
var UAData = function () {
|
function UAData () {
|
||||||
for (var init_props in data[2]) {
|
initialize.call(this, init_props);
|
||||||
this[data[2][init_props]] = undefined;
|
|
||||||
}
|
}
|
||||||
};
|
|
||||||
UAData.prototype.is = function (strToCheck) {
|
UAData.prototype.is = function (strToCheck) {
|
||||||
var is = false;
|
var is = false;
|
||||||
for (var i in this) {
|
for (var i in this) {
|
||||||
@ -851,10 +890,11 @@
|
|||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
function UABrowser (ua, browserMap) {
|
function UABrowser (ua, browserMap, uach) {
|
||||||
UAItem.call(this, [
|
UAItem.call(this, [
|
||||||
ua,
|
ua,
|
||||||
browserMap,
|
browserMap,
|
||||||
|
uach,
|
||||||
[NAME, VERSION, MAJOR],
|
[NAME, VERSION, MAJOR],
|
||||||
[VERSION, MAJOR],
|
[VERSION, MAJOR],
|
||||||
' ?browser$',
|
' ?browser$',
|
||||||
@ -862,31 +902,27 @@
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
UABrowser.prototype = new UAItem();
|
UABrowser.prototype = new UAItem();
|
||||||
UABrowser.prototype.parse = function (uach) {
|
UABrowser.prototype.parseCH = function () {
|
||||||
if (uach) {
|
var brands = this.uaCH.brands;
|
||||||
var brands = uach[CH_HEADER_FULL_VER_LIST] || uach[CH_HEADER];
|
|
||||||
if (brands) {
|
if (brands) {
|
||||||
brands = brands.replace(/\\?\"/g, EMPTY).split(', ');
|
|
||||||
for (var i in brands) {
|
for (var i in brands) {
|
||||||
var brand = brands[i].split(';v='),
|
var brandName = brands[i].brand,
|
||||||
brandName = brand[0],
|
brandVersion = brands[i].version;
|
||||||
brandVersion = brand[1];
|
|
||||||
if (!/not.a.brand/i.test(brandName) && (!this.get(NAME) || /chromi/i.test(this.get(NAME)))) {
|
if (!/not.a.brand/i.test(brandName) && (!this.get(NAME) || /chromi/i.test(this.get(NAME)))) {
|
||||||
this.set(NAME, brandName.replace(GOOGLE+' ', EMPTY))
|
this.set(NAME, strip(GOOGLE+' ', brandName))
|
||||||
.set(VERSION, brandVersion)
|
.set(VERSION, brandVersion)
|
||||||
.set(MAJOR, majorize(brandVersion));
|
.set(MAJOR, majorize(brandVersion));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if (!this.get(NAME)) UAItem.prototype.parse.call(this);
|
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
function UACPU (ua, cpuMap) {
|
function UACPU (ua, cpuMap, uach) {
|
||||||
UAItem.call(this, [
|
UAItem.call(this, [
|
||||||
ua,
|
ua,
|
||||||
cpuMap,
|
cpuMap,
|
||||||
|
uach,
|
||||||
[ARCHITECTURE],
|
[ARCHITECTURE],
|
||||||
[],
|
[],
|
||||||
null,
|
null,
|
||||||
@ -894,20 +930,18 @@
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
UACPU.prototype = new UAItem();
|
UACPU.prototype = new UAItem();
|
||||||
UACPU.prototype.parse = function (uach) {
|
UACPU.prototype.parseCH = function () {
|
||||||
if (uach) {
|
var archName = this.uaCH.architecture;
|
||||||
var archName = uach[CH_HEADER_ARCH];
|
archName += (archName && this.uaCH.bitness == '64') ? '64' : EMPTY;
|
||||||
archName += (archName && uach[CH_HEADER_BITNESS] == '64') ? '64' : EMPTY;
|
|
||||||
rgxMapper.call(this.data, archName, this.rgxMap);
|
rgxMapper.call(this.data, archName, this.rgxMap);
|
||||||
}
|
|
||||||
if (!this.get(ARCHITECTURE)) UAItem.prototype.parse.call(this);
|
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
function UADevice (ua, deviceMap) {
|
function UADevice (ua, deviceMap, uach) {
|
||||||
UAItem.call(this, [
|
UAItem.call(this, [
|
||||||
ua,
|
ua,
|
||||||
deviceMap,
|
deviceMap,
|
||||||
|
uach,
|
||||||
[TYPE, MODEL, VENDOR],
|
[TYPE, MODEL, VENDOR],
|
||||||
[],
|
[],
|
||||||
null,
|
null,
|
||||||
@ -915,16 +949,13 @@
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
UADevice.prototype = new UAItem();
|
UADevice.prototype = new UAItem();
|
||||||
UADevice.prototype.parse = function (uach) {
|
UADevice.prototype.parseCH = function () {
|
||||||
if (uach) {
|
if (this.uaCH.mobile) {
|
||||||
this.set(TYPE, uach[CH_HEADER_MOBILE] == '?1' ?
|
this.set(TYPE, MOBILE);
|
||||||
MOBILE :
|
}
|
||||||
this.get(TYPE))
|
if (this.uaCH.model) {
|
||||||
.set(MODEL, uach[CH_HEADER_MODEL] ?
|
this.set(MODEL, strip(/\"/g, this.uaCH.model));
|
||||||
uach[CH_HEADER_MODEL].replace(/\"/g, EMPTY) :
|
|
||||||
this.get(MODEL));
|
|
||||||
}
|
}
|
||||||
if (!this.get(TYPE) && !this.get(MODEL)) UAItem.prototype.parse.call(this);
|
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -932,6 +963,7 @@
|
|||||||
UAItem.call(this, [
|
UAItem.call(this, [
|
||||||
ua,
|
ua,
|
||||||
engineMap,
|
engineMap,
|
||||||
|
null,
|
||||||
[NAME, VERSION],
|
[NAME, VERSION],
|
||||||
[VERSION],
|
[VERSION],
|
||||||
null,
|
null,
|
||||||
@ -940,10 +972,11 @@
|
|||||||
}
|
}
|
||||||
UAEngine.prototype = new UAItem();
|
UAEngine.prototype = new UAItem();
|
||||||
|
|
||||||
function UAOS (ua, osMap) {
|
function UAOS (ua, osMap, uach) {
|
||||||
UAItem.call(this, [
|
UAItem.call(this, [
|
||||||
ua,
|
ua,
|
||||||
osMap,
|
osMap,
|
||||||
|
uach,
|
||||||
[NAME, VERSION],
|
[NAME, VERSION],
|
||||||
[VERSION],
|
[VERSION],
|
||||||
' ?os$',
|
' ?os$',
|
||||||
@ -951,23 +984,16 @@
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
UAOS.prototype = new UAItem();
|
UAOS.prototype = new UAItem();
|
||||||
UAOS.prototype.parse = function (uach) {
|
UAOS.prototype.parseCH = function (uach) {
|
||||||
if (uach) {
|
var osName = this.uaCH.platform;
|
||||||
var osName = uach[CH_HEADER_PLATFORM] ? uach[CH_HEADER_PLATFORM].replace(/\"/g, EMPTY) : undefined;
|
var osVersion = this.uaCH.platformVersion;
|
||||||
var osVersion = uach[CH_HEADER_PLATFORM_VER] ? uach[CH_HEADER_PLATFORM_VER].replace(/\"/g, EMPTY) : undefined;
|
osVersion = (osName == WINDOWS) ? (parseInt(majorize(osVersion), 10) >= 13 ? '11' : '10') : osVersion;
|
||||||
osVersion = (osName == WINDOWS) ? (majorize(osVersion) >= 13 ? '11' : '10') : osVersion;
|
|
||||||
this.set(NAME, osName)
|
this.set(NAME, osName)
|
||||||
.set(VERSION, osVersion);
|
.set(VERSION, osVersion);
|
||||||
}
|
|
||||||
if (!this.get(NAME)) UAItem.prototype.parse.call(this);
|
|
||||||
if (/(chrome |mac)os/.test(this.get(NAME))) {
|
|
||||||
this.set(NAME, this.get(NAME)
|
|
||||||
.replace(/chrome os/i, CHROMIUM_OS)
|
|
||||||
.replace(/macos/i, MAC_OS));
|
|
||||||
}
|
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
function UAParser (ua, extensions, headers) {
|
function UAParser (ua, extensions, headers) {
|
||||||
|
|
||||||
if (typeof ua === OBJ_TYPE) {
|
if (typeof ua === OBJ_TYPE) {
|
||||||
@ -1001,7 +1027,9 @@
|
|||||||
headers[USER_AGENT] :
|
headers[USER_AGENT] :
|
||||||
EMPTY)),
|
EMPTY)),
|
||||||
|
|
||||||
clientHints = (navigator && navigator.userAgentData) ?
|
clientHints = new UACHData(headers, false),
|
||||||
|
|
||||||
|
userAgentData = (navigator && navigator.userAgentData) ?
|
||||||
navigator.userAgentData :
|
navigator.userAgentData :
|
||||||
undefined,
|
undefined,
|
||||||
|
|
||||||
@ -1011,10 +1039,11 @@
|
|||||||
|
|
||||||
// public methods
|
// public methods
|
||||||
this.getBrowser = function () {
|
this.getBrowser = function () {
|
||||||
var browser = new UABrowser(userAgent, regexMap.browser);
|
var browser = new UABrowser(userAgent, regexMap.browser, clientHints);
|
||||||
if (headers && (headers[CH_HEADER_FULL_VER_LIST] || headers[CH_HEADER])) {
|
if (headers && (headers[CH_HEADER_FULL_VER_LIST] || headers[CH_HEADER])) {
|
||||||
browser.parse(headers);
|
browser.parseCH();
|
||||||
} else {
|
}
|
||||||
|
if (!browser.get(NAME)) {
|
||||||
browser.parse();
|
browser.parse();
|
||||||
// Brave-specific detection
|
// Brave-specific detection
|
||||||
if (navigator && navigator.brave && typeof navigator.brave.isBrave == FUNC_TYPE) {
|
if (navigator && navigator.brave && typeof navigator.brave.isBrave == FUNC_TYPE) {
|
||||||
@ -1027,22 +1056,24 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
this.getCPU = function () {
|
this.getCPU = function () {
|
||||||
var cpu = new UACPU(userAgent, regexMap.cpu);
|
var cpu = new UACPU(userAgent, regexMap.cpu, clientHints);
|
||||||
if (headers && headers[CH_HEADER_ARCH]) {
|
if (headers && headers[CH_HEADER_ARCH]) {
|
||||||
cpu.parse(headers);
|
cpu.parseCH();
|
||||||
} else {
|
}
|
||||||
|
if (!cpu.get(ARCHITECTURE)) {
|
||||||
cpu.parse();
|
cpu.parse();
|
||||||
}
|
}
|
||||||
return cpu.get();
|
return cpu.get();
|
||||||
};
|
};
|
||||||
|
|
||||||
this.getDevice = function () {
|
this.getDevice = function () {
|
||||||
var device = new UADevice(userAgent, regexMap.device);
|
var device = new UADevice(userAgent, regexMap.device, clientHints);
|
||||||
if (headers && (headers[CH_HEADER_MOBILE] || headers[CH_HEADER_MODEL])) {
|
if (headers && (headers[CH_HEADER_MOBILE] || headers[CH_HEADER_MODEL])) {
|
||||||
device.parse(headers);
|
device.parseCH();
|
||||||
} else {
|
}
|
||||||
|
if (!device.get(TYPE) || !device.get(MODEL)) {
|
||||||
device.parse();
|
device.parse();
|
||||||
if (!device.get(TYPE) && clientHints && clientHints.mobile) {
|
if (!device.get(TYPE) && userAgentData && userAgentData.mobile) {
|
||||||
device.set(TYPE, MOBILE);
|
device.set(TYPE, MOBILE);
|
||||||
}
|
}
|
||||||
// iPadOS-specific detection: identified as Mac, but has some iOS-only properties
|
// iPadOS-specific detection: identified as Mac, but has some iOS-only properties
|
||||||
@ -1062,13 +1093,14 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
this.getOS = function () {
|
this.getOS = function () {
|
||||||
var os = new UAOS(userAgent, regexMap.os);
|
var os = new UAOS(userAgent, regexMap.os, clientHints);
|
||||||
if (headers && headers[CH_HEADER_PLATFORM]) {
|
if (headers && headers[CH_HEADER_PLATFORM]) {
|
||||||
os.parse(headers);
|
os.parseCH();
|
||||||
} else {
|
}
|
||||||
|
if (!os.get(NAME)) {
|
||||||
os.parse();
|
os.parse();
|
||||||
if (!os.get(NAME) && clientHints && clientHints.platform != 'Unknown') {
|
if (!os.get(NAME) && userAgentData && userAgentData.platform != 'Unknown') {
|
||||||
os.set(NAME, clientHints.platform
|
os.set(NAME, userAgentData.platform
|
||||||
.replace(/chrome os/i, CHROMIUM_OS)
|
.replace(/chrome os/i, CHROMIUM_OS)
|
||||||
.replace(/macos/i, MAC_OS)); // backward compatibility
|
.replace(/macos/i, MAC_OS)); // backward compatibility
|
||||||
}
|
}
|
||||||
@ -1079,6 +1111,7 @@
|
|||||||
this.getResult = function () {
|
this.getResult = function () {
|
||||||
return {
|
return {
|
||||||
'ua' : userAgent,
|
'ua' : userAgent,
|
||||||
|
'ua_ch' : clientHints,
|
||||||
'browser' : this.getBrowser(),
|
'browser' : this.getBrowser(),
|
||||||
'cpu' : this.getCPU(),
|
'cpu' : this.getCPU(),
|
||||||
'device' : this.getDevice(),
|
'device' : this.getDevice(),
|
||||||
|
@ -82,6 +82,7 @@ describe('Returns', function () {
|
|||||||
assert.deepEqual(new UAParser('').getResult(),
|
assert.deepEqual(new UAParser('').getResult(),
|
||||||
{
|
{
|
||||||
ua : '',
|
ua : '',
|
||||||
|
ua_ch : { architecture: undefined, bitness: undefined, brands: undefined, mobile: false, model: undefined, platform: undefined, platformVersion: undefined },
|
||||||
browser: { name: undefined, version: undefined, major: undefined },
|
browser: { name: undefined, version: undefined, major: undefined },
|
||||||
cpu: { architecture: undefined },
|
cpu: { architecture: undefined },
|
||||||
device: { vendor: undefined, model: undefined, type: undefined },
|
device: { vendor: undefined, model: undefined, type: undefined },
|
||||||
|
Loading…
x
Reference in New Issue
Block a user