/* * 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)); } /* 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/...'); }