]> git.proxmox.com Git - mirror_novnc.git/blob - core/util/browser.js
Properly detect scrollbar gutter
[mirror_novnc.git] / core / util / browser.js
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
9 import * as Log from './logging.js';
10
11 // Touch detection
12 export let isTouchDevice = ('ontouchstart' in document.documentElement) ||
13 // requried for Chrome debugger
14 (document.ontouchstart !== undefined) ||
15 // required for MS Surface
16 (navigator.maxTouchPoints > 0) ||
17 (navigator.msMaxTouchPoints > 0);
18 window.addEventListener('touchstart', function onFirstTouch() {
19 isTouchDevice = true;
20 window.removeEventListener('touchstart', onFirstTouch, false);
21 }, false);
22
23
24 // The goal is to find a certain physical width, the devicePixelRatio
25 // brings us a bit closer but is not optimal.
26 export let dragThreshold = 10 * (window.devicePixelRatio || 1);
27
28 let _supportsCursorURIs = false;
29
30 try {
31 const target = document.createElement('canvas');
32 target.style.cursor = 'url("data:image/x-icon;base64,AAACAAEACAgAAAIAAgA4AQAAFgAAACgAAAAIAAAAEAAAAAEAIAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAD/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////AAAAAAAAAAAAAAAAAAAAAA==") 2 2, default';
33
34 if (target.style.cursor.indexOf("url") === 0) {
35 Log.Info("Data URI scheme cursor supported");
36 _supportsCursorURIs = true;
37 } else {
38 Log.Warn("Data URI scheme cursor not supported");
39 }
40 } catch (exc) {
41 Log.Error("Data URI scheme cursor test exception: " + exc);
42 }
43
44 export const supportsCursorURIs = _supportsCursorURIs;
45
46 let _supportsImageMetadata = false;
47 try {
48 new ImageData(new Uint8ClampedArray(4), 1, 1);
49 _supportsImageMetadata = true;
50 } catch (ex) {
51 // ignore failure
52 }
53 export const supportsImageMetadata = _supportsImageMetadata;
54
55 let _hasScrollbarGutter = true;
56 try {
57 // Create invisible container
58 const container = document.createElement('div');
59 container.style.visibility = 'hidden';
60 container.style.overflow = 'scroll'; // forcing scrollbars
61 document.body.appendChild(container);
62
63 // Create a div and place it in the container
64 const child = document.createElement('div');
65 container.appendChild(child);
66
67 // Calculate the difference between the container's full width
68 // and the child's width - the difference is the scrollbars
69 const scrollbarWidth = (container.offsetWidth - child.offsetWidth);
70
71 // Clean up
72 container.parentNode.removeChild(container);
73
74 _hasScrollbarGutter = scrollbarWidth != 0;
75 } catch (exc) {
76 Log.Error("Scrollbar test exception: " + exc);
77 }
78 export const hasScrollbarGutter = _hasScrollbarGutter;
79
80 export function isMac() {
81 return navigator && !!(/mac/i).exec(navigator.platform);
82 }
83
84 export function isWindows() {
85 return navigator && !!(/win/i).exec(navigator.platform);
86 }
87
88 export function isIOS() {
89 return navigator &&
90 (!!(/ipad/i).exec(navigator.platform) ||
91 !!(/iphone/i).exec(navigator.platform) ||
92 !!(/ipod/i).exec(navigator.platform));
93 }
94
95 export function isSafari() {
96 return navigator && (navigator.userAgent.indexOf('Safari') !== -1 &&
97 navigator.userAgent.indexOf('Chrome') === -1);
98 }
99
100 export function isIE() {
101 return navigator && !!(/trident/i).exec(navigator.userAgent);
102 }
103
104 export function isEdge() {
105 return navigator && !!(/edge/i).exec(navigator.userAgent);
106 }
107
108 export function isFirefox() {
109 return navigator && !!(/firefox/i).exec(navigator.userAgent);
110 }
111