2 * noVNC: HTML5 VNC client
3 * Copyright (C) 2019 The noVNC Authors
4 * Licensed under MPL 2.0 (see LICENSE.txt)
6 * See README.md for usage and integration instructions.
8 * Browser feature support detection
11import * as Log from './logging.js';
14export 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);
20window.addEventListener('touchstart', function onFirstTouch() {
22 window.removeEventListener('touchstart', onFirstTouch, false);
26// The goal is to find a certain physical width, the devicePixelRatio
27// brings us a bit closer but is not optimal.
28export let dragThreshold = 10 * (window.devicePixelRatio || 1);
30let _supportsCursorURIs = false;
33 const target = document.createElement('canvas');
34 target.style.cursor = 'url("data:image/x-icon;base64,AAACAAEACAgAAAIAAgA4AQAAFgAAACgAAAAIAAAAEAAAAAEAIAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAD/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////AAAAAAAAAAAAAAAAAAAAAA==") 2 2, default';
36 if (target.style.cursor.indexOf("url") === 0) {
37 Log.Info("Data URI scheme cursor supported");
38 _supportsCursorURIs = true;
40 Log.Warn("Data URI scheme cursor not supported");
43 Log.Error("Data URI scheme cursor test exception: " + exc);
46export const supportsCursorURIs = _supportsCursorURIs;
48let _hasScrollbarGutter = true;
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);
56 // Create a div and place it in the container
57 const child = document.createElement('div');
58 container.appendChild(child);
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);
65 container.parentNode.removeChild(container);
67 _hasScrollbarGutter = scrollbarWidth != 0;
69 Log.Error("Scrollbar test exception: " + exc);
71export const hasScrollbarGutter = _hasScrollbarGutter;
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.
77 * It's better to use feature detection than platform detection.
82export function isMac() {
83 return !!(/mac/i).exec(navigator.platform);
86export function isWindows() {
87 return !!(/win/i).exec(navigator.platform);
90export function isIOS() {
91 return (!!(/ipad/i).exec(navigator.platform) ||
92 !!(/iphone/i).exec(navigator.platform) ||
93 !!(/ipod/i).exec(navigator.platform));
96export function isAndroid() {
97 /* Android sets navigator.platform to Linux :/ */
98 return !!navigator.userAgent.match('Android ');
101export function isChromeOS() {
102 /* ChromeOS sets navigator.platform to Linux :/ */
103 return !!navigator.userAgent.match(' CrOS ');
108export function isSafari() {
109 return !!navigator.userAgent.match('Safari/...') &&
110 !navigator.userAgent.match('Chrome/...') &&
111 !navigator.userAgent.match('Chromium/...') &&
112 !navigator.userAgent.match('Epiphany/...');
115export function isFirefox() {
116 return !!navigator.userAgent.match('Firefox/...') &&
117 !navigator.userAgent.match('Seamonkey/...');
120export function isChrome() {
121 return !!navigator.userAgent.match('Chrome/...') &&
122 !navigator.userAgent.match('Chromium/...') &&
123 !navigator.userAgent.match('Edg/...') &&
124 !navigator.userAgent.match('OPR/...');
127export function isChromium() {
128 return !!navigator.userAgent.match('Chromium/...');
131export function isOpera() {
132 return !!navigator.userAgent.match('OPR/...');
135export function isEdge() {
136 return !!navigator.userAgent.match('Edg/...');
141export function isGecko() {
142 return !!navigator.userAgent.match('Gecko/...');
145export function isWebKit() {
146 return !!navigator.userAgent.match('AppleWebKit/...') &&
147 !navigator.userAgent.match('Chrome/...');
150export function isBlink() {
151 return !!navigator.userAgent.match('Chrome/...');