export interface Detected { browser: string; version: string; opera: boolean; ie: boolean; support: boolean; filedrop: boolean; os: 'win' | 'mac' | 'linux'; platform: 'Windows' | 'Macintosh' | 'Linux' | 'Unknown'; isMobileWebKit: boolean; isMobileFirefox: boolean; browserLocales: string[]; host: string; } let _detected: Detected; export function utilDetect(refresh?: boolean) { if (_detected && !refresh) return _detected; _detected = {}; const ua = navigator.userAgent; let m; /* Browser */ m = ua.match(/(edge)\/?\s*(\.?\d+(\.\d+)*)/i); // Edge if (m !== null) { _detected.browser = m[1]; _detected.version = m[2]; } if (!_detected.browser) { m = ua.match(/Trident\/.*rv:([0-9]{1,}[\.0-9]{0,})/i); // IE11 if (m !== null) { _detected.browser = 'msie'; _detected.version = m[1]; } } if (!_detected.browser) { m = ua.match(/(opr)\/?\s*(\.?\d+(\.\d+)*)/i); // Opera 15+ if (m !== null) { _detected.browser = 'Opera'; _detected.version = m[2]; } } if (!_detected.browser) { m = ua.match(/(opera|chrome|safari|firefox|msie)\/?\s*(\.?\d+(\.\d+)*)/i); if (m !== null) { _detected.browser = m[1]; _detected.version = m[2]; m = ua.match(/version\/([\.\d]+)/i); if (m !== null) _detected.version = m[1]; } } if (!_detected.browser) { _detected.browser = navigator.appName; _detected.version = navigator.appVersion; } // keep major.minor version only.. _detected.version = _detected.version.split(/\W/).slice(0,2).join('.'); // detect other browser capabilities // Legacy Opera has incomplete svg style support. See #715 _detected.opera = (_detected.browser.toLowerCase() === 'opera' && Number(_detected.version) < 15 ); if (_detected.browser.toLowerCase() === 'msie') { _detected.ie = true; _detected.browser = 'Internet Explorer'; _detected.support = false; } else { _detected.ie = false; _detected.support = true; } _detected.filedrop = (window.FileReader && 'ondrop' in window); /* Platform */ if (/Win/.test(ua)) { _detected.os = 'win'; _detected.platform = 'Windows'; } else if (/Mac/.test(ua)) { _detected.os = 'mac'; _detected.platform = 'Macintosh'; } else if (/X11/.test(ua) || /Linux/.test(ua)) { _detected.os = 'linux'; _detected.platform = 'Linux'; } else { _detected.os = 'win'; _detected.platform = 'Unknown'; } _detected.isMobileWebKit = (/\b(iPad|iPhone|iPod)\b/.test(ua) || // HACK: iPadOS 13+ requests desktop sites by default by using a Mac user agent, // so assume any "mac" with multitouch is actually iOS (navigator.platform === 'MacIntel' && 'maxTouchPoints' in navigator && navigator.maxTouchPoints > 1)) && /WebKit/.test(ua) && !/Edge/.test(ua) && // @ts-expect-error -- this attribute is so old that there are no definitions in @types/web !window.MSStream; // https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/Browser_detection_using_the_user_agent#mobile_tablet_or_desktop _detected.isMobileFirefox = /Mobile|Tablet/.test(ua) && /Firefox/.test(ua); /* Locale */ // An array of locales requested by the browser in priority order. _detected.browserLocales = Array.from(new Set( // remove duplicates [navigator.language] .concat(navigator.languages || []) .concat([ // @ts-expect-error -- this attribute is so old that there are no definitions in @types/web // old property for backwards compatibility navigator.userLanguage ]) // remove any undefined values .filter(Boolean) )); /* Host */ let loc; try { loc = window.top!.location; } catch { loc = window.location; } _detected.host = loc.origin + loc.pathname; return _detected; }