support for desktop versions #20
This commit is contained in:
54
src/application/Environment/BrowserOs/BrowserOsDetector.ts
Normal file
54
src/application/Environment/BrowserOs/BrowserOsDetector.ts
Normal file
@@ -0,0 +1,54 @@
|
||||
import { OperatingSystem } from '../OperatingSystem';
|
||||
import { DetectorBuilder } from './DetectorBuilder';
|
||||
import { IBrowserOsDetector } from './IBrowserOsDetector';
|
||||
|
||||
export class BrowserOsDetector implements IBrowserOsDetector {
|
||||
private readonly detectors = BrowserDetectors;
|
||||
public detect(userAgent: string): OperatingSystem {
|
||||
if (!userAgent) {
|
||||
return OperatingSystem.Unknown;
|
||||
}
|
||||
for (const detector of this.detectors) {
|
||||
const os = detector.detect(userAgent);
|
||||
if (os !== OperatingSystem.Unknown) {
|
||||
return os;
|
||||
}
|
||||
}
|
||||
return OperatingSystem.Unknown;
|
||||
}
|
||||
}
|
||||
|
||||
// Reference: https://github.com/keithws/browser-report/blob/master/index.js#L304
|
||||
const BrowserDetectors =
|
||||
[
|
||||
define(OperatingSystem.KaiOS, (b) =>
|
||||
b.mustInclude('KAIOS')),
|
||||
define(OperatingSystem.ChromeOS, (b) =>
|
||||
b.mustInclude('CrOS')),
|
||||
define(OperatingSystem.BlackBerryOS, (b) =>
|
||||
b.mustInclude('BlackBerry')),
|
||||
define(OperatingSystem.BlackBerryTabletOS, (b) =>
|
||||
b.mustInclude('RIM Tablet OS')),
|
||||
define(OperatingSystem.BlackBerry, (b) =>
|
||||
b.mustInclude('BB10')),
|
||||
define(OperatingSystem.Android, (b) =>
|
||||
b.mustInclude('Android').mustNotInclude('Windows Phone')),
|
||||
define(OperatingSystem.Android, (b) =>
|
||||
b.mustInclude('Adr').mustNotInclude('Windows Phone')),
|
||||
define(OperatingSystem.iOS, (b) =>
|
||||
b.mustInclude('like Mac OS X')),
|
||||
define(OperatingSystem.Linux, (b) =>
|
||||
b.mustInclude('Linux').mustNotInclude('Android').mustNotInclude('Adr')),
|
||||
define(OperatingSystem.Windows, (b) =>
|
||||
b.mustInclude('Windows').mustNotInclude('Windows Phone')),
|
||||
define(OperatingSystem.WindowsPhone, (b) =>
|
||||
b.mustInclude('Windows Phone')),
|
||||
define(OperatingSystem.macOS, (b) =>
|
||||
b.mustInclude('OS X').mustNotInclude('Android').mustNotInclude('like Mac OS X')),
|
||||
];
|
||||
|
||||
function define(os: OperatingSystem, applyRules: (builder: DetectorBuilder) => DetectorBuilder): IBrowserOsDetector {
|
||||
const builder = new DetectorBuilder(os);
|
||||
applyRules(builder);
|
||||
return builder.build();
|
||||
}
|
||||
49
src/application/Environment/BrowserOs/DetectorBuilder.ts
Normal file
49
src/application/Environment/BrowserOs/DetectorBuilder.ts
Normal file
@@ -0,0 +1,49 @@
|
||||
import { IBrowserOsDetector } from './IBrowserOsDetector';
|
||||
import { OperatingSystem } from '../OperatingSystem';
|
||||
|
||||
export class DetectorBuilder {
|
||||
private readonly existingPartsInUserAgent = new Array<string>();
|
||||
private readonly notExistingPartsInUserAgent = new Array<string>();
|
||||
|
||||
constructor(private readonly os: OperatingSystem) { }
|
||||
|
||||
public mustInclude(str: string): DetectorBuilder {
|
||||
if (!str) {
|
||||
throw new Error('part to include is empty or undefined');
|
||||
}
|
||||
this.existingPartsInUserAgent.push(str);
|
||||
return this;
|
||||
}
|
||||
|
||||
public mustNotInclude(str: string): DetectorBuilder {
|
||||
if (!str) {
|
||||
throw new Error('part to not include is empty or undefined');
|
||||
}
|
||||
this.notExistingPartsInUserAgent.push(str);
|
||||
return this;
|
||||
}
|
||||
|
||||
public build(): IBrowserOsDetector {
|
||||
if (!this.existingPartsInUserAgent.length) {
|
||||
throw new Error('Must include at least a part');
|
||||
}
|
||||
return {
|
||||
detect: (userAgent) => {
|
||||
if (!userAgent) {
|
||||
throw new Error('User agent is null or undefined');
|
||||
}
|
||||
for (const exitingPart of this.existingPartsInUserAgent) {
|
||||
if (!userAgent.includes(exitingPart)) {
|
||||
return OperatingSystem.Unknown;
|
||||
}
|
||||
}
|
||||
for (const notExistingPart of this.notExistingPartsInUserAgent) {
|
||||
if (userAgent.includes(notExistingPart)) {
|
||||
return OperatingSystem.Unknown;
|
||||
}
|
||||
}
|
||||
return this.os;
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
import { OperatingSystem } from '../OperatingSystem';
|
||||
|
||||
export interface IBrowserOsDetector {
|
||||
detect(userAgent: string): OperatingSystem;
|
||||
}
|
||||
80
src/application/Environment/Environment.ts
Normal file
80
src/application/Environment/Environment.ts
Normal file
@@ -0,0 +1,80 @@
|
||||
import { BrowserOsDetector } from './BrowserOs/BrowserOsDetector';
|
||||
import { IBrowserOsDetector } from './BrowserOs/IBrowserOsDetector';
|
||||
import { IEnvironment } from './IEnvironment';
|
||||
import { OperatingSystem } from './OperatingSystem';
|
||||
|
||||
interface IEnvironmentVariables {
|
||||
readonly window: Window & typeof globalThis;
|
||||
readonly process: NodeJS.Process;
|
||||
readonly navigator: Navigator;
|
||||
}
|
||||
|
||||
export class Environment implements IEnvironment {
|
||||
public static readonly CurrentEnvironment: IEnvironment = new Environment({
|
||||
window,
|
||||
process,
|
||||
navigator,
|
||||
});
|
||||
public readonly isDesktop: boolean;
|
||||
public readonly os: OperatingSystem;
|
||||
protected constructor(
|
||||
variables: IEnvironmentVariables,
|
||||
browserOsDetector: IBrowserOsDetector = new BrowserOsDetector()) {
|
||||
if (!variables) {
|
||||
throw new Error('variables is null or empty');
|
||||
}
|
||||
this.isDesktop = isDesktop(variables);
|
||||
this.os = this.isDesktop ?
|
||||
getDesktopOsType(getProcessPlatform(variables))
|
||||
: browserOsDetector.detect(getUserAgent(variables));
|
||||
}
|
||||
}
|
||||
|
||||
function getUserAgent(variables: IEnvironmentVariables): string {
|
||||
if (!variables.window || !variables.window.navigator) {
|
||||
return undefined;
|
||||
}
|
||||
return variables.window.navigator.userAgent;
|
||||
}
|
||||
|
||||
function getProcessPlatform(variables: IEnvironmentVariables): string {
|
||||
if (!variables.process || !variables.process.platform) {
|
||||
return undefined;
|
||||
}
|
||||
return variables.process.platform;
|
||||
}
|
||||
|
||||
function getDesktopOsType(processPlatform: string): OperatingSystem {
|
||||
// https://nodejs.org/api/process.html#process_process_platform
|
||||
if (processPlatform === 'darwin') {
|
||||
return OperatingSystem.macOS;
|
||||
} else if (processPlatform === 'win32') {
|
||||
return OperatingSystem.Windows;
|
||||
} else if (processPlatform === 'linux') {
|
||||
return OperatingSystem.Linux;
|
||||
}
|
||||
return OperatingSystem.Unknown;
|
||||
}
|
||||
|
||||
function isDesktop(variables: IEnvironmentVariables): boolean {
|
||||
// More: https://github.com/electron/electron/issues/2288
|
||||
// Renderer process
|
||||
if (variables.window
|
||||
&& variables.window.process
|
||||
&& variables.window.process.type === 'renderer') {
|
||||
return true;
|
||||
}
|
||||
// Main process
|
||||
if (variables.process
|
||||
&& variables.process.versions
|
||||
&& Boolean(variables.process.versions.electron)) {
|
||||
return true;
|
||||
}
|
||||
// Detect the user agent when the `nodeIntegration` option is set to true
|
||||
if (variables.navigator
|
||||
&& variables.navigator.userAgent
|
||||
&& variables.navigator.userAgent.includes('Electron')) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
6
src/application/Environment/IEnvironment.ts
Normal file
6
src/application/Environment/IEnvironment.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
import { OperatingSystem } from './OperatingSystem';
|
||||
|
||||
export interface IEnvironment {
|
||||
isDesktop: boolean;
|
||||
os: OperatingSystem;
|
||||
}
|
||||
14
src/application/Environment/OperatingSystem.ts
Normal file
14
src/application/Environment/OperatingSystem.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
export enum OperatingSystem {
|
||||
macOS,
|
||||
Windows,
|
||||
Linux,
|
||||
KaiOS,
|
||||
ChromeOS,
|
||||
BlackBerryOS,
|
||||
BlackBerry,
|
||||
BlackBerryTabletOS,
|
||||
Android,
|
||||
iOS,
|
||||
WindowsPhone,
|
||||
Unknown,
|
||||
}
|
||||
Reference in New Issue
Block a user