@kwiz/common
Version:
KWIZ common utilities and helpers for M365 platform
293 lines (269 loc) • 9.27 kB
text/typescript
//Unused file
export interface DetectedInfo<N extends string, O, V = null> {
readonly name: N;
readonly version: V;
readonly os: O;
}
export class BrowserInfo
implements DetectedInfo<Browser, OperatingSystem | null, string> {
public constructor(
public readonly name: Browser,
public readonly version: string,
public readonly os: OperatingSystem | null
) { }
}
export class BotInfo implements DetectedInfo<'bot', null, null> {
public readonly bot = true as const; // NOTE: deprecated test name instead
public readonly name = 'bot' as const;
public readonly version: null = null;
public readonly os: null = null;
}
export type Browser =
| 'aol'
| 'edge'
| 'yandexbrowser'
| 'vivaldi'
| 'kakaotalk'
| 'samsung'
| 'silk'
| 'miui'
| 'beaker'
| 'edge-chromium'
| 'chrome'
| 'chromium-webview'
| 'phantomjs'
| 'crios'
| 'firefox'
| 'fxios'
| 'opera-mini'
| 'opera'
| 'ie'
| 'bb10'
| 'android'
| 'ios'
| 'safari'
| 'facebook'
| 'instagram'
| 'ios-webview'
| 'searchbot'
| 'unknown';
export type OperatingSystem =
| 'iOS'
| 'Android OS'
| 'BlackBerry OS'
| 'Windows Mobile'
| 'Amazon OS'
| 'Windows 3.11'
| 'Windows 95'
| 'Windows 98'
| 'Windows 2000'
| 'Windows XP'
| 'Windows Server 2003'
| 'Windows Vista'
| 'Windows 7'
| 'Windows 8'
| 'Windows 8.1'
| 'Windows 10'
| 'Windows ME'
| 'Open BSD'
| 'Sun OS'
| 'Linux'
| 'Mac OS'
| 'QNX'
| 'BeOS'
| 'OS/2'
| 'Chrome OS'
| 'Search Bot'
| 'unknown';
type UserAgentRule = [Browser, RegExp];
type UserAgentMatch = [Browser, RegExpExecArray] | false;
type OperatingSystemRule = [OperatingSystem, RegExp];
const SEARCHBOX_UA_REGEX = /alexa|bot|crawl(er|ing)|facebookexternalhit|feedburner|google web preview|nagios|postrank|pingdom|slurp|spider|yahoo!|yandex/;
const SEARCHBOT_OS_REGEX = /(nuhk)|(Googlebot)|(Yammybot)|(Openbot)|(Slurp)|(MSNBot)|(Ask Jeeves\/Teoma)|(ia_archiver)/;
const REQUIRED_VERSION_PARTS = 3;
const userAgentRules: UserAgentRule[] = [
['aol', /AOLShield\/([0-9._]+)/],
['edge', /Edge\/([0-9._]+)/],
['yandexbrowser', /YaBrowser\/([0-9._]+)/],
['vivaldi', /Vivaldi\/([0-9.]+)/],
['kakaotalk', /KAKAOTALK\s([0-9.]+)/],
['samsung', /SamsungBrowser\/([0-9.]+)/],
['silk', /\bSilk\/([0-9._-]+)\b/],
['miui', /MiuiBrowser\/([0-9.]+)$/],
['beaker', /BeakerBrowser\/([0-9.]+)/],
['edge-chromium', /Edg\/([0-9.]+)/],
[
'chromium-webview',
/(?!Chrom.*OPR)wv\).*Chrom(?:e|ium)\/([0-9.]+)(:?\s|$)/,
],
['chrome', /(?!Chrom.*OPR)Chrom(?:e|ium)\/([0-9.]+)(:?\s|$)/],
['phantomjs', /PhantomJS\/([0-9.]+)(:?\s|$)/],
['crios', /CriOS\/([0-9.]+)(:?\s|$)/],
['firefox', /Firefox\/([0-9.]+)(?:\s|$)/],
['fxios', /FxiOS\/([0-9.]+)/],
['opera-mini', /Opera Mini.*Version\/([0-9.]+)/],
['opera', /Opera\/([0-9.]+)(?:\s|$)/],
['opera', /OPR\/([0-9.]+)(:?\s|$)/],
['ie', /Trident\/7\.0.*rv:([0-9.]+).*\).*Gecko$/],
['ie', /MSIE\s([0-9.]+);.*Trident\/[4-7].0/],
['ie', /MSIE\s(7\.0)/],
['bb10', /BB10;\sTouch.*Version\/([0-9.]+)/],
['android', /Android\s([0-9.]+)/],
['ios', /Version\/([0-9._]+).*Mobile.*Safari.*/],
['safari', /Version\/([0-9._]+).*Safari/],
['facebook', /FBAV\/([0-9.]+)/],
['instagram', /Instagram\s([0-9.]+)/],
['ios-webview', /AppleWebKit\/([0-9.]+).*Mobile/],
['ios-webview', /AppleWebKit\/([0-9.]+).*Gecko\)$/],
['searchbot', SEARCHBOX_UA_REGEX]
];
const operatingSystemRules: OperatingSystemRule[] = [
['iOS', /iP(hone|od|ad)/],
['Android OS', /Android/],
['BlackBerry OS', /BlackBerry|BB10/],
['Windows Mobile', /IEMobile/],
['Amazon OS', /Kindle/],
['Windows 3.11', /Win16/],
['Windows 95', /(Windows 95)|(Win95)|(Windows_95)/],
['Windows 98', /(Windows 98)|(Win98)/],
['Windows 2000', /(Windows NT 5.0)|(Windows 2000)/],
['Windows XP', /(Windows NT 5.1)|(Windows XP)/],
['Windows Server 2003', /(Windows NT 5.2)/],
['Windows Vista', /(Windows NT 6.0)/],
['Windows 7', /(Windows NT 6.1)/],
['Windows 8', /(Windows NT 6.2)/],
['Windows 8.1', /(Windows NT 6.3)/],
['Windows 10', /(Windows NT 10.0)/],
['Windows ME', /Windows ME/],
['Open BSD', /OpenBSD/],
['Sun OS', /SunOS/],
['Chrome OS', /CrOS/],
['Linux', /(Linux)|(X11)/],
['Mac OS', /(Mac_PowerPC)|(Macintosh)/],
['QNX', /QNX/],
['BeOS', /BeOS/],
['OS/2', /OS\/2/],
['Search Bot', SEARCHBOT_OS_REGEX],
];
export function detect(userAgent?: string): BrowserInfo | BotInfo | null {
if (userAgent) {
return parseUserAgent(userAgent);
}
if (typeof navigator !== 'undefined') {
return parseUserAgent(navigator.userAgent);
}
//return getNodeVersion();
return new BrowserInfo("unknown", "unknown", "unknown");
}
export function parseUserAgent(ua: string): BrowserInfo | BotInfo | null {
// opted for using reduce here rather than Array#first with a regex.test call
// this is primarily because using the reduce we only perform the regex
// execution once rather than once for the test and for the exec again below
// probably something that needs to be benchmarked though
const matchedRule: UserAgentMatch =
ua !== '' &&
userAgentRules.reduce<UserAgentMatch>(
(matched: UserAgentMatch, [browser, regex]) => {
if (matched) {
return matched;
}
const uaMatch = regex.exec(ua);
return !!uaMatch && [browser, uaMatch];
},
false,
);
if (!matchedRule) {
return null;
}
const [name, match] = matchedRule;
if (name === 'searchbot') {
return new BotInfo();
}
let versionParts = match[1] && match[1].split(/[._]/).slice(0, 3);
if (versionParts) {
if (versionParts.length < REQUIRED_VERSION_PARTS) {
versionParts = [
...versionParts,
...createVersionParts(REQUIRED_VERSION_PARTS - versionParts.length),
];
}
} else {
versionParts = [];
}
return new BrowserInfo(name, versionParts.join('.'), detectOS(ua));
}
export function detectOS(ua: string): OperatingSystem | null {
for (let ii = 0, count = operatingSystemRules.length; ii < count; ii++) {
const [os, regex] = operatingSystemRules[ii];
const match = regex.test(ua);
if (match) {
return os;
}
}
return null;
}
export function detectPDF() {
var browserInfo = parseUserAgent(navigator.userAgent);
if (browserInfo.name === 'ie') {
// load the activeX control
// AcroPDF.PDF is used by version 7 and later
// PDF.PdfCtrl is used by version 6 and earlier
return getActiveXObject('AcroPDF.PDF')
|| getActiveXObject('AcroPDF.PDF.1')
|| getActiveXObject('PDF.PdfCtrl')
|| getActiveXObject('PDF.PdfCtrl.1')
|| getActiveXObject('PDF.PdfCtrl.2')
|| getActiveXObject('PDF.PdfCtrl.3')
|| getActiveXObject('PDF.PdfCtrl.4')
|| getActiveXObject('PDF.PdfCtrl.5')
|| getActiveXObject('PDF.PdfCtrl.6')
|| getActiveXObject('PDF.PdfCtrl.7')
|| getActiveXObject('PDF.PdfCtrl.8')
|| getActiveXObject('PDF.PdfCtrl.9');
} else {
return getNavigatorPluginByMimeType("application/pdf");
}
}
function supportsActiveX() {
var _supportsActiveX = false;
try {
_supportsActiveX = (<any>window).ActiveXObject !== undefined;
} catch (e) {
}
return _supportsActiveX;
}
function getActiveXObject(name: string) {
if (supportsActiveX()) {
try {
return new (<any>window).ActiveXObject(name);
} catch (e) {
}
}
}
function getNavigatorPluginByMimeType(mimeTypeName: string) {
if (navigator && navigator.plugins) {
// eslint-disable-next-line guard-for-in
for (var key in navigator.plugins) {
var plugin = navigator.plugins[key];
var pdfMimeType = (plugin as any)[mimeTypeName];
if (!pdfMimeType && plugin.length) {
for (var mimeTypeIndex = 0; mimeTypeIndex < plugin.length; mimeTypeIndex++) {
var mimeType = plugin[mimeTypeIndex];
if (mimeType.type === mimeTypeName) {
pdfMimeType = mimeType;
break;
}
}
}
if (pdfMimeType) return plugin;
}
}
return null;
}
function createVersionParts(count: number): string[] {
const output = [];
for (let ii = 0; ii < count; ii++) {
output.push('0');
}
return output;
}