| /* |
| * noVNC: HTML5 VNC client |
| * Copyright (C) 2019 The noVNC Authors |
| * Licensed under MPL 2.0 (see LICENSE.txt) |
| * |
| * See README.md for usage and integration instructions. |
| * |
| * Browser feature support detection |
| */ |
| |
| import * as Log from './logging.js'; |
| |
| // Touch detection |
| export let isTouchDevice = ('ontouchstart' in document.documentElement) || |
| // requried for Chrome debugger |
| (document.ontouchstart !== undefined) || |
| // required for MS Surface |
| (navigator.maxTouchPoints > 0) || |
| (navigator.msMaxTouchPoints > 0); |
| window.addEventListener('touchstart', function onFirstTouch() { |
| isTouchDevice = true; |
| window.removeEventListener('touchstart', onFirstTouch, false); |
| }, false); |
| |
| |
| // The goal is to find a certain physical width, the devicePixelRatio |
| // brings us a bit closer but is not optimal. |
| export let dragThreshold = 10 * (window.devicePixelRatio || 1); |
| |
| let _supportsCursorURIs = false; |
| |
| try { |
| const target = document.createElement('canvas'); |
| target.style.cursor = 'url("data:image/x-icon;base64,AAACAAEACAgAAAIAAgA4AQAAFgAAACgAAAAIAAAAEAAAAAEAIAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAD/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////AAAAAAAAAAAAAAAAAAAAAA==") 2 2, default'; |
| |
| if (target.style.cursor.indexOf("url") === 0) { |
| Log.Info("Data URI scheme cursor supported"); |
| _supportsCursorURIs = true; |
| } else { |
| Log.Warn("Data URI scheme cursor not supported"); |
| } |
| } catch (exc) { |
| Log.Error("Data URI scheme cursor test exception: " + exc); |
| } |
| |
| export const supportsCursorURIs = _supportsCursorURIs; |
| |
| let _hasScrollbarGutter = true; |
| try { |
| // Create invisible container |
| const container = document.createElement('div'); |
| container.style.visibility = 'hidden'; |
| container.style.overflow = 'scroll'; // forcing scrollbars |
| document.body.appendChild(container); |
| |
| // Create a div and place it in the container |
| const child = document.createElement('div'); |
| container.appendChild(child); |
| |
| // Calculate the difference between the container's full width |
| // and the child's width - the difference is the scrollbars |
| const scrollbarWidth = (container.offsetWidth - child.offsetWidth); |
| |
| // Clean up |
| container.parentNode.removeChild(container); |
| |
| _hasScrollbarGutter = scrollbarWidth != 0; |
| } catch (exc) { |
| Log.Error("Scrollbar test exception: " + exc); |
| } |
| export const hasScrollbarGutter = _hasScrollbarGutter; |
| |
| /* |
| * The functions for detection of platforms and browsers below are exported |
| * but the use of these should be minimized as much as possible. |
| * |
| * It's better to use feature detection than platform detection. |
| */ |
| |
| /* OS */ |
| |
| export function isMac() { |
| return !!(/mac/i).exec(navigator.platform); |
| } |
| |
| export function isWindows() { |
| return !!(/win/i).exec(navigator.platform); |
| } |
| |
| export function isIOS() { |
| return (!!(/ipad/i).exec(navigator.platform) || |
| !!(/iphone/i).exec(navigator.platform) || |
| !!(/ipod/i).exec(navigator.platform)); |
| } |
| |
| export function isAndroid() { |
| /* Android sets navigator.platform to Linux :/ */ |
| return !!navigator.userAgent.match('Android '); |
| } |
| |
| export function isChromeOS() { |
| /* ChromeOS sets navigator.platform to Linux :/ */ |
| return !!navigator.userAgent.match(' CrOS '); |
| } |
| |
| /* Browser */ |
| |
| export function isSafari() { |
| return !!navigator.userAgent.match('Safari/...') && |
| !navigator.userAgent.match('Chrome/...') && |
| !navigator.userAgent.match('Chromium/...') && |
| !navigator.userAgent.match('Epiphany/...'); |
| } |
| |
| export function isFirefox() { |
| return !!navigator.userAgent.match('Firefox/...') && |
| !navigator.userAgent.match('Seamonkey/...'); |
| } |
| |
| export function isChrome() { |
| return !!navigator.userAgent.match('Chrome/...') && |
| !navigator.userAgent.match('Chromium/...') && |
| !navigator.userAgent.match('Edg/...') && |
| !navigator.userAgent.match('OPR/...'); |
| } |
| |
| export function isChromium() { |
| return !!navigator.userAgent.match('Chromium/...'); |
| } |
| |
| export function isOpera() { |
| return !!navigator.userAgent.match('OPR/...'); |
| } |
| |
| export function isEdge() { |
| return !!navigator.userAgent.match('Edg/...'); |
| } |
| |
| /* Engine */ |
| |
| export function isGecko() { |
| return !!navigator.userAgent.match('Gecko/...'); |
| } |
| |
| export function isWebKit() { |
| return !!navigator.userAgent.match('AppleWebKit/...') && |
| !navigator.userAgent.match('Chrome/...'); |
| } |
| |
| export function isBlink() { |
| return !!navigator.userAgent.match('Chrome/...'); |
| } |