-
Notifications
You must be signed in to change notification settings - Fork 29
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
9531694
commit 51056fe
Showing
3 changed files
with
189 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,172 @@ | ||
const BROWSER_NAMES = { | ||
CHROME: 'Chrome', | ||
FIREFOX: 'Firefox', | ||
EDGE: 'Edg', | ||
OPERA: 'Opera', | ||
SAFARI: 'Safari', | ||
}; | ||
|
||
const CHROMIUM_BRAND_NAME = 'Chromium'; | ||
const GOOGLE_CHROME_BRAND_NAME = 'Google Chrome'; | ||
|
||
const SUPPORTED_BROWSERS_DATA = { | ||
[BROWSER_NAMES.CHROME]: { | ||
// avoid Chromium-based Edge browser | ||
MASK: /\s(Chrome)\/(\d+)\..+\s(?!.*Edg\/)/, | ||
MIN_VERSION: 55, | ||
}, | ||
[BROWSER_NAMES.FIREFOX]: { | ||
MASK: /\s(Firefox)\/(\d+)\./, | ||
MIN_VERSION: 52, | ||
}, | ||
[BROWSER_NAMES.EDGE]: { | ||
MASK: /\s(Edg)\/(\d+)\./, | ||
MIN_VERSION: 15, | ||
}, | ||
[BROWSER_NAMES.OPERA]: { | ||
MASK: /\s(OPR)\/(\d+)\./, | ||
MIN_VERSION: 42, | ||
}, | ||
[BROWSER_NAMES.SAFARI]: { | ||
MASK: /\sVersion\/(\d+)\..+\s(Safari)\//, | ||
MIN_VERSION: 11, | ||
}, | ||
}; | ||
|
||
/** | ||
* @typedef {Object} BrandData | ||
* @property {string} brand a string containing the brand, for example, "Google Chrome". | ||
* @property {string} version a string containing the version, for example, "91". | ||
*/ | ||
|
||
/** | ||
* Returns chromium brand object from navigator.userAgentData.brands or null if not supported. | ||
* Chromium because of all browsers based on it should be supported as well | ||
* and it is universal wey to check it | ||
* https://developer.mozilla.org/en-US/docs/Web/API/NavigatorUAData/brands | ||
* | ||
* @returns {BrandData|null} chromium brand object | ||
*/ | ||
const getChromiumBrand = () => { | ||
const brandsData = navigator.userAgentData?.brands; | ||
if (!brandsData) { | ||
return null; | ||
} | ||
// for chromium-based browsers | ||
const chromiumBrand = brandsData.find((brandData) => { | ||
return brandData.brand === CHROMIUM_BRAND_NAME | ||
|| brandData.brand === GOOGLE_CHROME_BRAND_NAME; | ||
}); | ||
return chromiumBrand || null; | ||
}; | ||
|
||
/** | ||
* Parses userAgent string | ||
* | ||
* @returns {Object|null} data object for supported browsers | ||
*/ | ||
const parseUserAgent = () => { | ||
let browserName; | ||
let currentVersion; | ||
const browserNames = Object.values(BROWSER_NAMES); | ||
|
||
for (let i = 0; i < browserNames.length; i += 1) { | ||
const match = SUPPORTED_BROWSERS_DATA[browserNames[i]].MASK.exec(navigator.userAgent); | ||
if (match) { | ||
// for safari order is different because of regexp | ||
if (match[2] === browserNames[i]) { | ||
// eslint-disable-next-line prefer-destructuring | ||
browserName = match[2]; | ||
currentVersion = Number(match[1]); | ||
} else { | ||
// for others first is name and second is version | ||
// eslint-disable-next-line prefer-destructuring | ||
browserName = match[1]; | ||
currentVersion = Number(match[2]); | ||
} | ||
return { browserName, currentVersion }; | ||
} | ||
} | ||
|
||
return null; | ||
}; | ||
|
||
/** | ||
* @typedef {Object} BrowserInfo | ||
* @property {string} browserName a string containing the brand, for example, "Google Chrome". | ||
* @property {number} currentVersion current browser version | ||
*/ | ||
|
||
/** | ||
* Gets info about current browser | ||
* | ||
* @returns {BrowserInfo} current browser info | ||
*/ | ||
const getCurrentBrowserInfoAsSupported = () => { | ||
const brandData = getChromiumBrand(); | ||
if (!brandData) { | ||
const uaInfo = parseUserAgent(); | ||
if (!uaInfo) { | ||
return null; | ||
} | ||
const { browserName, currentVersion } = uaInfo; | ||
return { browserName, currentVersion }; | ||
} | ||
|
||
// if navigator.userAgentData is supported | ||
const { brand, version } = brandData; | ||
// handle chromium-based browsers | ||
const browserName = brand === CHROMIUM_BRAND_NAME || brand === GOOGLE_CHROME_BRAND_NAME | ||
? BROWSER_NAMES.CHROME | ||
: brand; | ||
return { browserName, currentVersion: Number(version) }; | ||
}; | ||
|
||
/** | ||
* Checks whether the current browser is supported | ||
* | ||
* This function, it's dependencies and it's call are attached to each scriptlet | ||
* by injector, while building scriptlets | ||
* | ||
* @returns {boolean} if current browser is supported | ||
*/ | ||
export function isBrowserSupported() { | ||
const ua = navigator.userAgent; | ||
// do not support Internet Explorer | ||
if (ua.includes('MSIE') || ua.includes('Trident/')) { | ||
return false; | ||
} | ||
|
||
// for local testing purposes | ||
if (ua.includes('jsdom')) { | ||
return true; | ||
} | ||
|
||
const currentBrowserData = getCurrentBrowserInfoAsSupported(); | ||
if (!currentBrowserData) { | ||
return false; | ||
} | ||
|
||
const { browserName, currentVersion } = currentBrowserData; | ||
|
||
return currentVersion >= SUPPORTED_BROWSERS_DATA[browserName].MIN_VERSION; | ||
} | ||
|
||
/** | ||
* Checks if current browser is supported | ||
* to be injected to scriptlets at building | ||
* | ||
* @throws on unsupported browser | ||
*/ | ||
export function checkCompatibility() { | ||
if (!isBrowserSupported()) { | ||
throw new Error('Browser is not supported by Scriptlets.'); | ||
} | ||
} | ||
|
||
checkCompatibility.injections = [ | ||
isBrowserSupported, | ||
getCurrentBrowserInfoAsSupported, | ||
getChromiumBrand, | ||
parseUserAgent, | ||
]; |