From e52a278ed7aca2f2c0831e3ceabefcdb39581620 Mon Sep 17 00:00:00 2001 From: Samuel Mannehed Date: Wed, 23 Oct 2019 17:09:41 +0200 Subject: [PATCH 1/3] Properly detect scrollbar gutter As a rule, instead of hard-coding a behavior on specific platforms we should do dynamic detection. This commit moves away from always hiding scrollbars on Android and iOS and instead detects the rendered width of scrollbars in the browser. --- app/ui.js | 7 ++++--- core/util/browser.js | 29 +++++++++++++++++++++++++---- 2 files changed, 29 insertions(+), 7 deletions(-) diff --git a/app/ui.js b/app/ui.js index 347a2af8..766736ae 100644 --- a/app/ui.js +++ b/app/ui.js @@ -8,7 +8,7 @@ import * as Log from '../core/util/logging.js'; import _, { l10n } from './localization.js'; -import { isTouchDevice, isSafari, isIOS, isAndroid, dragThreshold } +import { isTouchDevice, isSafari, hasScrollbarGutter, dragThreshold } from '../core/util/browser.js'; import { setCapture, getPointerEvent } from '../core/util/events.js'; import KeyTable from "../core/input/keysym.js"; @@ -1269,8 +1269,9 @@ const UI = { // Can't be clipping if viewport is scaled to fit UI.forceSetting('view_clip', false); UI.rfb.clipViewport = false; - } else if (isIOS() || isAndroid()) { - // iOS and Android usually have shit scrollbars + } else if (!hasScrollbarGutter) { + // Some platforms have scrollbars that are difficult + // to use in our case, so we always use our own panning UI.forceSetting('view_clip', true); UI.rfb.clipViewport = true; } else { diff --git a/core/util/browser.js b/core/util/browser.js index 4b371e30..9a6d2c8a 100644 --- a/core/util/browser.js +++ b/core/util/browser.js @@ -52,6 +52,31 @@ try { } export const supportsImageMetadata = _supportsImageMetadata; +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; + export function isMac() { return navigator && !!(/mac/i).exec(navigator.platform); } @@ -67,10 +92,6 @@ export function isIOS() { !!(/ipod/i).exec(navigator.platform)); } -export function isAndroid() { - return navigator && !!(/android/i).exec(navigator.userAgent); -} - export function isSafari() { return navigator && (navigator.userAgent.indexOf('Safari') !== -1 && navigator.userAgent.indexOf('Chrome') === -1); From c32d4f3cd0c19c0cf1a96207adc253f6073014d4 Mon Sep 17 00:00:00 2001 From: Samuel Mannehed Date: Wed, 23 Oct 2019 17:08:56 +0200 Subject: [PATCH 2/3] Add short description at the top of browser.js --- core/util/browser.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core/util/browser.js b/core/util/browser.js index 9a6d2c8a..8262692c 100644 --- a/core/util/browser.js +++ b/core/util/browser.js @@ -4,6 +4,8 @@ * 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'; From 11ae8f0ef4dc1edffb497c0ed56e66054f897b20 Mon Sep 17 00:00:00 2001 From: Samuel Mannehed Date: Thu, 24 Oct 2019 16:43:07 +0200 Subject: [PATCH 3/3] Add comment for browser and platform detection --- core/util/browser.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/core/util/browser.js b/core/util/browser.js index 8262692c..15548014 100644 --- a/core/util/browser.js +++ b/core/util/browser.js @@ -79,6 +79,13 @@ try { } 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. + */ + export function isMac() { return navigator && !!(/mac/i).exec(navigator.platform); }