From 444d123f0debc59c3eadc89ce2f6a3b838753912 Mon Sep 17 00:00:00 2001 From: Penar Musaraj Date: Mon, 30 Sep 2019 13:56:39 -0400 Subject: [PATCH] UX: Use Visual Viewport API for iOS composer height This applies to iPhones running iOS 13+. Previous technique remains in place for iOS 12 and below. Note that this does not apply to iPads on iOS 13 due to Apple no longer identifying iPads in the user agent string. --- .../discourse/components/composer-body.js.es6 | 22 +++++++++++++++++++ .../discourse/lib/safari-hacks.js.es6 | 21 +++++++++++++----- app/assets/stylesheets/mobile/compose.scss | 8 +++++++ 3 files changed, 45 insertions(+), 6 deletions(-) diff --git a/app/assets/javascripts/discourse/components/composer-body.js.es6 b/app/assets/javascripts/discourse/components/composer-body.js.es6 index 1d89f93f1a8..b1af547ebb2 100644 --- a/app/assets/javascripts/discourse/components/composer-body.js.es6 +++ b/app/assets/javascripts/discourse/components/composer-body.js.es6 @@ -131,6 +131,25 @@ export default Ember.Component.extend(KeyEnterEscape, { $document.on(DRAG_EVENTS, throttledPerformDrag); $document.on(END_EVENTS, endDrag); }); + + if (window.visualViewport !== undefined) { + this.viewportResize(); + window.visualViewport.addEventListener("resize", this.viewportResize); + } + }, + + viewportResize() { + const composerVH = window.visualViewport.height * 0.01; + + if (window.visualViewport.height !== window.innerHeight) { + document.documentElement.classList.add("keyboard-visible"); + } else { + document.documentElement.classList.remove("keyboard-visible"); + } + document.documentElement.style.setProperty( + "--composer-vh", + `${composerVH}px` + ); }, didInsertElement() { @@ -155,6 +174,9 @@ export default Ember.Component.extend(KeyEnterEscape, { willDestroyElement() { this._super(...arguments); this.appEvents.off("composer:resize", this, this.resize); + if (window.visualViewport !== undefined) { + window.visualViewport.removeEventListener("resize", this.viewportResize); + } }, click() { diff --git a/app/assets/javascripts/discourse/lib/safari-hacks.js.es6 b/app/assets/javascripts/discourse/lib/safari-hacks.js.es6 index 1c234632e7d..3744c825bce 100644 --- a/app/assets/javascripts/discourse/lib/safari-hacks.js.es6 +++ b/app/assets/javascripts/discourse/lib/safari-hacks.js.es6 @@ -1,6 +1,9 @@ import debounce from "discourse/lib/debounce"; import { isAppleDevice, safariHacksDisabled } from "discourse/lib/utilities"; +// TODO: remove calcHeight once iOS 13 adoption > 90% +// In iOS 13 and up we use visualViewport API to calculate height + // we can't tell what the actual visible window height is // because we cannot account for the height of the mobile keyboard // and any other mobile autocomplete UI that may appear @@ -89,9 +92,14 @@ function positioningWorkaround($fixedElement) { fixedElement.style.position = ""; fixedElement.style.top = ""; - fixedElement.style.height = oldHeight; - Ember.run.later(() => $(fixedElement).removeClass("no-transition"), 500); + if (window.visualViewport === undefined) { + fixedElement.style.height = oldHeight; + Ember.run.later( + () => $(fixedElement).removeClass("no-transition"), + 500 + ); + } $(window).scrollTop(originalScrollTop); @@ -165,10 +173,11 @@ function positioningWorkaround($fixedElement) { fixedElement.style.top = "0px"; - const height = calcHeight(); - fixedElement.style.height = height + "px"; - - $(fixedElement).addClass("no-transition"); + if (window.visualViewport === undefined) { + const height = calcHeight(); + fixedElement.style.height = height + "px"; + $(fixedElement).addClass("no-transition"); + } evt.preventDefault(); this.focus(); diff --git a/app/assets/stylesheets/mobile/compose.scss b/app/assets/stylesheets/mobile/compose.scss index f9da09f0ad1..4c8c05bf038 100644 --- a/app/assets/stylesheets/mobile/compose.scss +++ b/app/assets/stylesheets/mobile/compose.scss @@ -21,6 +21,14 @@ height: 250px; &.edit-title { height: 100%; + height: calc(var(--composer-vh, 1vh) * 100); + } + } + + html.keyboard-visible &.open { + height: calc(var(--composer-vh, 1vh) * 100); + .reply-area { + padding-bottom: 0px; } }