]>
Commit | Line | Data |
---|---|---|
6d6f0db0 SR |
1 | /* |
2 | * noVNC: HTML5 VNC client | |
412d9306 | 3 | * Copyright (C) 2019 The noVNC Authors |
6d6f0db0 SR |
4 | * Licensed under MPL 2.0 (see LICENSE.txt) |
5 | * | |
6 | * See README.md for usage and integration instructions. | |
c32d4f3c SM |
7 | * |
8 | * Browser feature support detection | |
6d6f0db0 SR |
9 | */ |
10 | ||
11 | import * as Log from './logging.js'; | |
12 | ||
6d6f0db0 | 13 | // Touch detection |
2b5f94fa | 14 | export let isTouchDevice = ('ontouchstart' in document.documentElement) || |
6d6f0db0 SR |
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 | ||
3b7c4741 SM |
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 | ||
41ddb354 | 30 | let _supportsCursorURIs = false; |
6d6f0db0 | 31 | |
41ddb354 JD |
32 | try { |
33 | const target = document.createElement('canvas'); | |
34 | target.style.cursor = 'url("data:image/x-icon;base64,AAACAAEACAgAAAIAAgA4AQAAFgAAACgAAAAIAAAAEAAAAAEAIAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAD/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////AAAAAAAAAAAAAAAAAAAAAA==") 2 2, default'; | |
35 | ||
a1afb2a2 | 36 | if (target.style.cursor.indexOf("url") === 0) { |
41ddb354 JD |
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); | |
8727f598 | 44 | } |
59ef2916 | 45 | |
41ddb354 JD |
46 | export const supportsCursorURIs = _supportsCursorURIs; |
47 | ||
44f4c554 JD |
48 | let _supportsImageMetadata = false; |
49 | try { | |
50 | new ImageData(new Uint8ClampedArray(4), 1, 1); | |
51 | _supportsImageMetadata = true; | |
52 | } catch (ex) { | |
53 | // ignore failure | |
54 | } | |
55 | export const supportsImageMetadata = _supportsImageMetadata; | |
56 | ||
e52a278e SM |
57 | let _hasScrollbarGutter = true; |
58 | try { | |
59 | // Create invisible container | |
60 | const container = document.createElement('div'); | |
61 | container.style.visibility = 'hidden'; | |
62 | container.style.overflow = 'scroll'; // forcing scrollbars | |
63 | document.body.appendChild(container); | |
64 | ||
65 | // Create a div and place it in the container | |
66 | const child = document.createElement('div'); | |
67 | container.appendChild(child); | |
68 | ||
69 | // Calculate the difference between the container's full width | |
70 | // and the child's width - the difference is the scrollbars | |
71 | const scrollbarWidth = (container.offsetWidth - child.offsetWidth); | |
72 | ||
73 | // Clean up | |
74 | container.parentNode.removeChild(container); | |
75 | ||
76 | _hasScrollbarGutter = scrollbarWidth != 0; | |
77 | } catch (exc) { | |
78 | Log.Error("Scrollbar test exception: " + exc); | |
79 | } | |
80 | export const hasScrollbarGutter = _hasScrollbarGutter; | |
81 | ||
11ae8f0e SM |
82 | /* |
83 | * The functions for detection of platforms and browsers below are exported | |
84 | * but the use of these should be minimized as much as possible. | |
85 | * | |
86 | * It's better to use feature detection than platform detection. | |
87 | */ | |
88 | ||
59ef2916 JD |
89 | export function isMac() { |
90 | return navigator && !!(/mac/i).exec(navigator.platform); | |
91 | } | |
92 | ||
97e23ebb SM |
93 | export function isWindows() { |
94 | return navigator && !!(/win/i).exec(navigator.platform); | |
95 | } | |
96 | ||
97 | export function isIOS() { | |
98 | return navigator && | |
99 | (!!(/ipad/i).exec(navigator.platform) || | |
100 | !!(/iphone/i).exec(navigator.platform) || | |
101 | !!(/ipod/i).exec(navigator.platform)); | |
102 | } | |
103 | ||
47b3eac8 SM |
104 | export function isSafari() { |
105 | return navigator && (navigator.userAgent.indexOf('Safari') !== -1 && | |
106 | navigator.userAgent.indexOf('Chrome') === -1); | |
107 | } | |
108 | ||
59ef2916 JD |
109 | export function isEdge() { |
110 | return navigator && !!(/edge/i).exec(navigator.userAgent); | |
111 | } | |
112 | ||
3a7c0c67 PO |
113 | export function isFirefox() { |
114 | return navigator && !!(/firefox/i).exec(navigator.userAgent); | |
115 | } | |
116 |