212 lines
5.8 KiB
JavaScript
Executable File
212 lines
5.8 KiB
JavaScript
Executable File
/**
|
|
* @license
|
|
* Copyright The Closure Library Authors.
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
/**
|
|
* @fileoverview Utilities used by goog.labs.userAgent tools. These functions
|
|
* should not be used outside of goog.labs.userAgent.*.
|
|
*
|
|
*/
|
|
|
|
goog.module('goog.labs.userAgent.util');
|
|
goog.module.declareLegacyNamespace();
|
|
|
|
const {USE_CLIENT_HINTS} = goog.require('goog.labs.userAgent');
|
|
const {caseInsensitiveContains, contains} = goog.require('goog.string.internal');
|
|
|
|
/**
|
|
* @const {boolean} If true, use navigator.userAgentData without check.
|
|
* TODO(user) FEATURESET_YEAR >= 2022 if it supports mobile and all the
|
|
* brands we need.
|
|
*/
|
|
const ASSUME_CLIENT_HINTS_SUPPORT = false;
|
|
|
|
/**
|
|
* Gets the native userAgent string from navigator if it exists.
|
|
* If navigator or navigator.userAgent string is missing, returns an empty
|
|
* string.
|
|
* @return {string}
|
|
*/
|
|
function getNativeUserAgentString() {
|
|
const navigator = getNavigator();
|
|
if (navigator) {
|
|
const userAgent = navigator.userAgent;
|
|
if (userAgent) {
|
|
return userAgent;
|
|
}
|
|
}
|
|
return '';
|
|
}
|
|
|
|
/**
|
|
* Gets the native userAgentData object from navigator if it exists.
|
|
* If navigator.userAgentData object is missing or USE_CLIENT_HINTS is set to
|
|
* false, returns null.
|
|
* @return {?NavigatorUAData}
|
|
*/
|
|
function getNativeUserAgentData() {
|
|
if (!USE_CLIENT_HINTS) {
|
|
return null;
|
|
}
|
|
const navigator = getNavigator();
|
|
// TODO(user): Use navigator?.userAgent ?? null once it's supported.
|
|
if (navigator) {
|
|
return navigator.userAgentData || null;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Getter for the native navigator.
|
|
* @return {!Navigator}
|
|
*/
|
|
function getNavigator() {
|
|
return goog.global.navigator;
|
|
}
|
|
|
|
/**
|
|
* A possible override for applications which wish to not check
|
|
* navigator.userAgent but use a specified value for detection instead.
|
|
* @type {string}
|
|
*/
|
|
let userAgentInternal = getNativeUserAgentString();
|
|
|
|
/**
|
|
* A possible override for applications which wish to not check
|
|
* navigator.userAgentData but use a specified value for detection instead.
|
|
* @type {?NavigatorUAData}
|
|
*/
|
|
let userAgentDataInternal = getNativeUserAgentData();
|
|
|
|
/**
|
|
* Override the user agent string with the given value.
|
|
* This should only be used for testing within the goog.labs.userAgent
|
|
* namespace.
|
|
* Pass `null` to use the native browser object instead.
|
|
* @param {?string=} userAgent The userAgent override.
|
|
* @return {void}
|
|
*/
|
|
function setUserAgent(userAgent = undefined) {
|
|
userAgentInternal =
|
|
typeof userAgent === 'string' ? userAgent : getNativeUserAgentString();
|
|
}
|
|
|
|
/** @return {string} The user agent string. */
|
|
function getUserAgent() {
|
|
return userAgentInternal;
|
|
}
|
|
|
|
/**
|
|
* Override the user agent data object with the given value.
|
|
* This should only be used for testing within the goog.labs.userAgent
|
|
* namespace.
|
|
* Pass `null` to specify the absence of userAgentData. Note that this behavior
|
|
* is different from setUserAgent.
|
|
* @param {?NavigatorUAData} userAgentData The userAgentData override.
|
|
*/
|
|
function setUserAgentData(userAgentData) {
|
|
userAgentDataInternal = userAgentData;
|
|
}
|
|
|
|
/**
|
|
* If the user agent data object was overridden using setUserAgentData,
|
|
* reset it so that it uses the native browser object instead, if it exists.
|
|
*/
|
|
function resetUserAgentData() {
|
|
userAgentDataInternal = getNativeUserAgentData();
|
|
}
|
|
|
|
/** @return {?NavigatorUAData} Navigator.userAgentData if exist */
|
|
function getUserAgentData() {
|
|
return userAgentDataInternal;
|
|
}
|
|
|
|
/**
|
|
* Checks if any string in userAgentData.brands matches str.
|
|
* Returns false if userAgentData is not supported.
|
|
* @param {string} str
|
|
* @return {boolean} Whether any brand string from userAgentData contains the
|
|
* given string.
|
|
*/
|
|
function matchUserAgentDataBrand(str) {
|
|
const data = getUserAgentData();
|
|
if (!data) return false;
|
|
return data.brands.some(({brand}) => brand && contains(brand, str));
|
|
}
|
|
|
|
/**
|
|
* @param {string} str
|
|
* @return {boolean} Whether the user agent contains the given string.
|
|
*/
|
|
function matchUserAgent(str) {
|
|
const userAgent = getUserAgent();
|
|
return contains(userAgent, str);
|
|
}
|
|
|
|
/**
|
|
* @param {string} str
|
|
* @return {boolean} Whether the user agent contains the given string, ignoring
|
|
* case.
|
|
*/
|
|
function matchUserAgentIgnoreCase(str) {
|
|
const userAgent = getUserAgent();
|
|
return caseInsensitiveContains(userAgent, str);
|
|
}
|
|
|
|
/**
|
|
* Parses the user agent into tuples for each section.
|
|
* @param {string} userAgent
|
|
* @return {!Array<!Array<string>>} Tuples of key, version, and the contents of
|
|
* the parenthetical.
|
|
*/
|
|
function extractVersionTuples(userAgent) {
|
|
// Matches each section of a user agent string.
|
|
// Example UA:
|
|
// Mozilla/5.0 (iPad; U; CPU OS 3_2_1 like Mac OS X; en-us)
|
|
// AppleWebKit/531.21.10 (KHTML, like Gecko) Mobile/7B405
|
|
// This has three version tuples: Mozilla, AppleWebKit, and Mobile.
|
|
|
|
const versionRegExp = new RegExp(
|
|
// Key. Note that a key may have a space.
|
|
// (i.e. 'Mobile Safari' in 'Mobile Safari/5.0')
|
|
'(\\w[\\w ]+)' +
|
|
|
|
'/' + // slash
|
|
'([^\\s]+)' + // version (i.e. '5.0b')
|
|
'\\s*' + // whitespace
|
|
'(?:\\((.*?)\\))?', // parenthetical info. parentheses not matched.
|
|
'g');
|
|
|
|
const data = [];
|
|
let match;
|
|
|
|
// Iterate and collect the version tuples. Each iteration will be the
|
|
// next regex match.
|
|
while (match = versionRegExp.exec(userAgent)) {
|
|
data.push([
|
|
match[1], // key
|
|
match[2], // value
|
|
// || undefined as this is not undefined in IE7 and IE8
|
|
match[3] || undefined // info
|
|
]);
|
|
}
|
|
|
|
return data;
|
|
}
|
|
|
|
exports = {
|
|
ASSUME_CLIENT_HINTS_SUPPORT,
|
|
extractVersionTuples,
|
|
getNativeUserAgentString,
|
|
getUserAgent,
|
|
getUserAgentData,
|
|
matchUserAgent,
|
|
matchUserAgentDataBrand,
|
|
matchUserAgentIgnoreCase,
|
|
resetUserAgentData,
|
|
setUserAgent,
|
|
setUserAgentData,
|
|
};
|