master
js 152 lines 4.84 KB
Raw
1 /*
2 * noVNC: HTML5 VNC client
3 * Copyright (C) 2019 The noVNC Authors
4 * Licensed under MPL 2.0 (see LICENSE.txt)
5 *
6 * See README.md for usage and integration instructions.
7 *
8 * Browser feature support detection
9 */
10
11 import * as Log from './logging.js';
12
13 // Touch detection
14 export let isTouchDevice = ('ontouchstart' in document.documentElement) ||
15 // requried for Chrome debugger
16 (document.ontouchstart !== undefined) ||
17 // required for MS Surface
18 (navigator.maxTouchPoints > 0) ||
19 (navigator.msMaxTouchPoints > 0);
20 window.addEventListener('touchstart', function onFirstTouch() {
21 isTouchDevice = true;
22 window.removeEventListener('touchstart', onFirstTouch, false);
23 }, false);
24
25
26 // The goal is to find a certain physical width, the devicePixelRatio
27 // brings us a bit closer but is not optimal.
28 export let dragThreshold = 10 * (window.devicePixelRatio || 1);
29
30 let _supportsCursorURIs = false;
31
32 try {
33 const target = document.createElement('canvas');
34 target.style.cursor = 'url("data:image/x-icon;base64,AAACAAEACAgAAAIAAgA4AQAAFgAAACgAAAAIAAAAEAAAAAEAIAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAD/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////AAAAAAAAAAAAAAAAAAAAAA==") 2 2, default';
35
36 if (target.style.cursor.indexOf("url") === 0) {
37 Log.Info("Data URI scheme cursor supported");
38 _supportsCursorURIs = true;
39 } else {
40 Log.Warn("Data URI scheme cursor not supported");
41 }
42 } catch (exc) {
43 Log.Error("Data URI scheme cursor test exception: " + exc);
44 }
45
46 export const supportsCursorURIs = _supportsCursorURIs;
47
48 let _hasScrollbarGutter = true;
49 try {
50 // Create invisible container
51 const container = document.createElement('div');
52 container.style.visibility = 'hidden';
53 container.style.overflow = 'scroll'; // forcing scrollbars
54 document.body.appendChild(container);
55
56 // Create a div and place it in the container
57 const child = document.createElement('div');
58 container.appendChild(child);
59
60 // Calculate the difference between the container's full width
61 // and the child's width - the difference is the scrollbars
62 const scrollbarWidth = (container.offsetWidth - child.offsetWidth);
63
64 // Clean up
65 container.parentNode.removeChild(container);
66
67 _hasScrollbarGutter = scrollbarWidth != 0;
68 } catch (exc) {
69 Log.Error("Scrollbar test exception: " + exc);
70 }
71 export const hasScrollbarGutter = _hasScrollbarGutter;
72
73 /*
74 * The functions for detection of platforms and browsers below are exported
75 * but the use of these should be minimized as much as possible.
76 *
77 * It's better to use feature detection than platform detection.
78 */
79
80 /* OS */
81
82 export function isMac() {
83 return !!(/mac/i).exec(navigator.platform);
84 }
85
86 export function isWindows() {
87 return !!(/win/i).exec(navigator.platform);
88 }
89
90 export function isIOS() {
91 return (!!(/ipad/i).exec(navigator.platform) ||
92 !!(/iphone/i).exec(navigator.platform) ||
93 !!(/ipod/i).exec(navigator.platform));
94 }
95
96 export function isAndroid() {
97 /* Android sets navigator.platform to Linux :/ */
98 return !!navigator.userAgent.match('Android ');
99 }
100
101 export function isChromeOS() {
102 /* ChromeOS sets navigator.platform to Linux :/ */
103 return !!navigator.userAgent.match(' CrOS ');
104 }
105
106 /* Browser */
107
108 export function isSafari() {
109 return !!navigator.userAgent.match('Safari/...') &&
110 !navigator.userAgent.match('Chrome/...') &&
111 !navigator.userAgent.match('Chromium/...') &&
112 !navigator.userAgent.match('Epiphany/...');
113 }
114
115 export function isFirefox() {
116 return !!navigator.userAgent.match('Firefox/...') &&
117 !navigator.userAgent.match('Seamonkey/...');
118 }
119
120 export function isChrome() {
121 return !!navigator.userAgent.match('Chrome/...') &&
122 !navigator.userAgent.match('Chromium/...') &&
123 !navigator.userAgent.match('Edg/...') &&
124 !navigator.userAgent.match('OPR/...');
125 }
126
127 export function isChromium() {
128 return !!navigator.userAgent.match('Chromium/...');
129 }
130
131 export function isOpera() {
132 return !!navigator.userAgent.match('OPR/...');
133 }
134
135 export function isEdge() {
136 return !!navigator.userAgent.match('Edg/...');
137 }
138
139 /* Engine */
140
141 export function isGecko() {
142 return !!navigator.userAgent.match('Gecko/...');
143 }
144
145 export function isWebKit() {
146 return !!navigator.userAgent.match('AppleWebKit/...') &&
147 !navigator.userAgent.match('Chrome/...');
148 }
149
150 export function isBlink() {
151 return !!navigator.userAgent.match('Chrome/...');
152 }