Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
SeleniumHQ
GitHub Repository: SeleniumHQ/Selenium
Path: blob/trunk/third_party/closure/goog/labs/useragent/util.js
4143 views
1
/**
2
* @license
3
* Copyright The Closure Library Authors.
4
* SPDX-License-Identifier: Apache-2.0
5
*/
6
7
/**
8
* @fileoverview Utilities used by goog.labs.userAgent tools. These functions
9
* should not be used outside of goog.labs.userAgent.*.
10
*
11
*/
12
13
goog.module('goog.labs.userAgent.util');
14
goog.module.declareLegacyNamespace();
15
16
const {caseInsensitiveContains, contains} = goog.require('goog.string.internal');
17
const {useClientHints} = goog.require('goog.labs.userAgent');
18
19
/**
20
* @const {boolean} If true, use navigator.userAgentData without check.
21
* TODO(user): FEATURESET_YEAR >= 2024 if it supports mobile and all the
22
* brands we need. See https://caniuse.com/mdn-api_navigator_useragentdata.
23
*/
24
const ASSUME_CLIENT_HINTS_SUPPORT = false;
25
26
/**
27
* Gets the native userAgent string from navigator if it exists.
28
* If navigator or navigator.userAgent string is missing, returns an empty
29
* string.
30
* @return {string}
31
*/
32
function getNativeUserAgentString() {
33
const navigator = getNavigator();
34
if (navigator) {
35
const userAgent = navigator.userAgent;
36
if (userAgent) {
37
return userAgent;
38
}
39
}
40
return '';
41
}
42
43
/**
44
* Gets the native userAgentData object from navigator if it exists.
45
* If navigator.userAgentData object is missing returns null.
46
* @return {?NavigatorUAData}
47
*/
48
function getNativeUserAgentData() {
49
const navigator = getNavigator();
50
// TODO(user): Use navigator?.userAgent ?? null once it's supported.
51
if (navigator) {
52
return navigator.userAgentData || null;
53
}
54
return null;
55
}
56
57
/**
58
* Getter for the native navigator.
59
* @return {!Navigator}
60
*/
61
function getNavigator() {
62
return goog.global.navigator;
63
}
64
65
/**
66
* A possible override for applications which wish to not check
67
* navigator.userAgent but use a specified value for detection instead.
68
* @type {?string}
69
*/
70
let userAgentInternal = null;
71
72
/**
73
* A possible override for applications which wish to not check
74
* navigator.userAgentData but use a specified value for detection instead.
75
* @type {?NavigatorUAData}
76
*/
77
let userAgentDataInternal = getNativeUserAgentData();
78
79
/**
80
* Override the user agent string with the given value.
81
* This should only be used for testing within the goog.labs.userAgent
82
* namespace.
83
* Pass `null` to use the native browser object instead.
84
* @param {?string=} userAgent The userAgent override.
85
* @return {void}
86
*/
87
function setUserAgent(userAgent = undefined) {
88
userAgentInternal =
89
typeof userAgent === 'string' ? userAgent : getNativeUserAgentString();
90
}
91
92
/** @return {string} The user agent string. */
93
function getUserAgent() {
94
return userAgentInternal == null ? getNativeUserAgentString() :
95
userAgentInternal;
96
}
97
98
/**
99
* Override the user agent data object with the given value.
100
* This should only be used for testing within the goog.labs.userAgent
101
* namespace.
102
* Pass `null` to specify the absence of userAgentData. Note that this behavior
103
* is different from setUserAgent.
104
* @param {?NavigatorUAData} userAgentData The userAgentData override.
105
*/
106
function setUserAgentData(userAgentData) {
107
userAgentDataInternal = userAgentData;
108
}
109
110
/**
111
* If the user agent data object was overridden using setUserAgentData,
112
* reset it so that it uses the native browser object instead, if it exists.
113
*/
114
function resetUserAgentData() {
115
userAgentDataInternal = getNativeUserAgentData();
116
}
117
118
/** @return {?NavigatorUAData} Navigator.userAgentData if exist */
119
function getUserAgentData() {
120
return userAgentDataInternal;
121
}
122
123
/**
124
* Checks if any string in userAgentData.brands matches str.
125
* Returns false if userAgentData is not supported.
126
* @param {string} str
127
* @return {boolean} Whether any brand string from userAgentData contains the
128
* given string.
129
*/
130
function matchUserAgentDataBrand(str) {
131
if (!useClientHints()) return false;
132
const data = getUserAgentData();
133
if (!data) return false;
134
return data.brands.some(({brand}) => brand && contains(brand, str));
135
}
136
137
/**
138
* @param {string} str
139
* @return {boolean} Whether the user agent contains the given string.
140
*/
141
function matchUserAgent(str) {
142
const userAgent = getUserAgent();
143
return contains(userAgent, str);
144
}
145
146
/**
147
* @param {string} str
148
* @return {boolean} Whether the user agent contains the given string, ignoring
149
* case.
150
*/
151
function matchUserAgentIgnoreCase(str) {
152
const userAgent = getUserAgent();
153
return caseInsensitiveContains(userAgent, str);
154
}
155
156
/**
157
* Parses the user agent into tuples for each section.
158
* @param {string} userAgent
159
* @return {!Array<!Array<string>>} Tuples of key, version, and the contents of
160
* the parenthetical.
161
*/
162
function extractVersionTuples(userAgent) {
163
// Matches each section of a user agent string.
164
// Example UA:
165
// Mozilla/5.0 (iPad; U; CPU OS 3_2_1 like Mac OS X; en-us)
166
// AppleWebKit/531.21.10 (KHTML, like Gecko) Mobile/7B405
167
// This has three version tuples: Mozilla, AppleWebKit, and Mobile.
168
169
const versionRegExp = new RegExp(
170
// Key. Note that a key may have a space.
171
// (i.e. 'Mobile Safari' in 'Mobile Safari/5.0')
172
'([A-Z][\\w ]+)' +
173
174
'/' + // slash
175
'([^\\s]+)' + // version (i.e. '5.0b')
176
'\\s*' + // whitespace
177
'(?:\\((.*?)\\))?', // parenthetical info. parentheses not matched.
178
'g');
179
180
const data = [];
181
let match;
182
183
// Iterate and collect the version tuples. Each iteration will be the
184
// next regex match.
185
while (match = versionRegExp.exec(userAgent)) {
186
data.push([
187
match[1], // key
188
match[2], // value
189
// || undefined as this is not undefined in IE7 and IE8
190
match[3] || undefined // info
191
]);
192
}
193
194
return data;
195
}
196
197
exports = {
198
ASSUME_CLIENT_HINTS_SUPPORT,
199
extractVersionTuples,
200
getNativeUserAgentString,
201
getUserAgent,
202
getUserAgentData,
203
matchUserAgent,
204
matchUserAgentDataBrand,
205
matchUserAgentIgnoreCase,
206
resetUserAgentData,
207
setUserAgent,
208
setUserAgentData,
209
};
210
211