UNPKG

5.53 kBPlain TextView Raw
1import Cookies from "js-cookie";
2import { UAParser } from "ua-parser-js";
3export { UAParser };
4
5import { BrowserCompatibility } from "./browserCompatibility";
6
7export namespace BrowserHelper {
8 /**
9 * @hidden
10 */
11 interface Browser {
12 name?: string;
13 version?: string;
14 }
15
16 /**
17 * @hidden
18 */
19 interface CPU {
20 architecture?: string;
21 }
22
23 /**
24 * @hidden
25 */
26 interface Device {
27 model?: string;
28 vendor?: string;
29 // tslint:disable-next-line:no-reserved-keywords
30 type?: string;
31 }
32
33 /**
34 * @hidden
35 */
36 interface Engine {
37 name?: string;
38 version?: string;
39 }
40
41 /**
42 * @hidden
43 */
44 interface OS {
45 name?: string;
46 version?: string;
47 }
48
49 /**
50 * @hidden
51 */
52 export const userAgentInfo: {
53 getBrowser(): Browser;
54 getOS(): OS;
55 getEngine(): Engine;
56 getDevice(): Device;
57 getCPU(): CPU;
58 getUA(): string;
59 setUA(uastring: string): void;
60 } = new UAParser(navigator.userAgent);
61
62 /**
63 * @hidden
64 */
65 export const canvas: HTMLCanvasElement = document.createElement("canvas");
66
67 /**
68 * @returns The built [[BrowserCompatibility]] object representing the current OS/Browser's support for features.
69 */
70 export function checkBrowserCompatibility(): BrowserCompatibility {
71 function objectHasPropertyWithType(object: object, propertyNames: string[], propertyType: string): boolean {
72 // tslint:disable-next-line:no-any
73 const objectProperty: any = (<any>object)[propertyNames[0]];
74 if (objectProperty == null) {
75 return false;
76 }
77 if (propertyNames.length === 1) {
78 return typeof objectProperty === propertyType;
79 } else {
80 return (
81 (typeof objectProperty === "function" || typeof objectProperty === "object") &&
82 objectHasPropertyWithType(objectProperty, propertyNames.slice(1), propertyType)
83 );
84 }
85 }
86
87 function isBrokenWebAssemblyOS(os: OS): boolean {
88 return os.name === "iOS" && os.version != null && ["11.2.2", "11.2.5", "11.2.6"].includes(os.version);
89 }
90
91 let fullSupport: boolean = true;
92 let scannerSupport: boolean = true;
93 const missingFeatures: BrowserCompatibility.Feature[] = [];
94
95 if (
96 !objectHasPropertyWithType(navigator, ["mediaDevices", "getUserMedia"], "function") &&
97 !objectHasPropertyWithType(navigator, ["enumerateDevices"], "function") &&
98 !objectHasPropertyWithType(window, ["MediaStreamTrack", "getSources"], "function")
99 ) {
100 missingFeatures.push(BrowserCompatibility.Feature.MEDIA_DEVICES);
101 fullSupport = false;
102 }
103
104 if (!objectHasPropertyWithType(window, ["Worker"], "function")) {
105 missingFeatures.push(BrowserCompatibility.Feature.WEB_WORKERS);
106 fullSupport = scannerSupport = false;
107 }
108
109 if (!objectHasPropertyWithType(window, ["WebAssembly"], "object")) {
110 missingFeatures.push(BrowserCompatibility.Feature.WEB_ASSEMBLY);
111 fullSupport = scannerSupport = false;
112 }
113
114 if (!objectHasPropertyWithType(window, ["Blob"], "function")) {
115 missingFeatures.push(BrowserCompatibility.Feature.BLOB);
116 fullSupport = scannerSupport = false;
117 }
118
119 if (!objectHasPropertyWithType(window, ["URL", "createObjectURL"], "function")) {
120 missingFeatures.push(BrowserCompatibility.Feature.URL_OBJECT);
121 fullSupport = scannerSupport = false;
122 }
123
124 if (!objectHasPropertyWithType(window, ["OffscreenCanvas"], "function")) {
125 missingFeatures.push(BrowserCompatibility.Feature.OFFSCREEN_CANVAS);
126 }
127
128 try {
129 if (
130 !objectHasPropertyWithType(window, ["WebGLRenderingContext"], "function") ||
131 (canvas.getContext("webgl") == null && canvas.getContext("experimental-webgl") == null)
132 ) {
133 throw new Error();
134 }
135 } catch {
136 missingFeatures.push(BrowserCompatibility.Feature.WEBGL);
137 }
138
139 const userAgentOS: OS = userAgentInfo.getOS();
140 if (isBrokenWebAssemblyOS(userAgentOS)) {
141 missingFeatures.push(BrowserCompatibility.Feature.WEB_ASSEMBLY_ERROR_FREE);
142 fullSupport = scannerSupport = false;
143 }
144
145 return {
146 fullSupport,
147 scannerSupport,
148 missingFeatures
149 };
150 }
151
152 /**
153 * @hidden
154 *
155 * Get a device id for the current browser, when available it's retrieved from a cookie,
156 * when not it's randomly generated and stored in a cookie to be retrieved by later calls.
157 *
158 * @returns The device id for the current browser.
159 */
160 export function getDeviceId(): string {
161 const cookieKey: string = "scandit-device-id";
162 const storedDeviceId: string | undefined = Cookies.get("scandit-device-id");
163 if (storedDeviceId != null && storedDeviceId !== "") {
164 return storedDeviceId;
165 }
166 const hexCharacters: string = "0123456789abcdef";
167 let randomDeviceId: string = "";
168 for (let i: number = 0; i < 40; ++i) {
169 // tslint:disable-next-line:insecure-random
170 randomDeviceId += hexCharacters.charAt(Math.floor(Math.random() * 16));
171 }
172 Cookies.set(cookieKey, randomDeviceId, { expires: 3650 });
173
174 return randomDeviceId;
175 }
176
177 /**
178 * @hidden
179 *
180 * Check if a given object is a valid HTMLElement
181 *
182 * @param object The object to check.
183 * @returns Whether the given object is a valid HTMLElement.
184 */
185 // tslint:disable-next-line:no-any
186 export function isValidHTMLElement(object: any): boolean {
187 return (
188 object instanceof HTMLElement ||
189 (object != null && typeof object === "object" && typeof object.tagName === "string")
190 );
191 }
192}