initial commit
This commit is contained in:
Executable
+211
@@ -0,0 +1,211 @@
|
||||
/**
|
||||
* @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,
|
||||
};
|
||||
Reference in New Issue
Block a user