mirror of
https://github.com/discourse/discourse.git
synced 2024-11-30 10:05:24 +08:00
UX: Refactor iOS composer layout
This addresses the following issues: - on iPad, with keyboard attached, the composer is no longer forced to full screen - on iPad, with keyboard attached, the topic no longer scrolls when starting a reply and then cancelling it - switching between inputs and buttons (formatting, emojis, categories/tags, etc.) no longer causes layout to bounce around
This commit is contained in:
parent
d527f3a723
commit
c3a5a8e095
|
@ -142,11 +142,6 @@ export default Ember.Component.extend(KeyEnterEscape, {
|
|||
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`
|
||||
|
|
|
@ -85,18 +85,12 @@ function positioningWorkaround($fixedElement) {
|
|||
const fixedElement = $fixedElement[0];
|
||||
const oldHeight = fixedElement.style.height;
|
||||
|
||||
var done = false;
|
||||
var originalScrollTop = 0;
|
||||
let lastTouchedElement = null;
|
||||
|
||||
positioningWorkaround.blur = function(evt) {
|
||||
if (workaroundActive) {
|
||||
done = true;
|
||||
|
||||
$("#main-outlet").show();
|
||||
$("header").show();
|
||||
|
||||
fixedElement.style.position = "";
|
||||
fixedElement.style.top = "";
|
||||
$("body").removeClass("ios-safari-composer-hacks");
|
||||
|
||||
if (!iOSWithVisualViewport()) {
|
||||
fixedElement.style.height = oldHeight;
|
||||
|
@ -116,15 +110,17 @@ function positioningWorkaround($fixedElement) {
|
|||
};
|
||||
|
||||
var blurredNow = function(evt) {
|
||||
// we cannot use evt.relatedTarget to get the last focused element in safari iOS
|
||||
// document.activeElement is also unreliable (iOS does not mark buttons as focused)
|
||||
// so instead, we store the last touched element and check against it
|
||||
|
||||
if (
|
||||
!done &&
|
||||
evt.srcElement !== document.activeElement &&
|
||||
$(document.activeElement)
|
||||
.parents()
|
||||
.toArray()
|
||||
.indexOf(fixedElement) > -1
|
||||
lastTouchedElement &&
|
||||
($(lastTouchedElement).hasClass("select-kit-header") ||
|
||||
["span", "svg", "button"].includes(
|
||||
lastTouchedElement.nodeName.toLowerCase()
|
||||
))
|
||||
) {
|
||||
// something in focus so skip
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -134,60 +130,77 @@ function positioningWorkaround($fixedElement) {
|
|||
var blurred = debounce(blurredNow, 250);
|
||||
|
||||
var positioningHack = function(evt) {
|
||||
done = false;
|
||||
|
||||
// we need this, otherwise changing focus means we never clear
|
||||
this.addEventListener("blur", blurred);
|
||||
|
||||
if (fixedElement.style.top === "0px") {
|
||||
if (this !== document.activeElement) {
|
||||
evt.preventDefault();
|
||||
|
||||
// this tricks safari into assuming current input is at top of the viewport
|
||||
// via https://stackoverflow.com/questions/38017771/mobile-safari-prevent-scroll-page-when-focus-on-input
|
||||
this.style.transform = "translateY(-200px)";
|
||||
this.focus();
|
||||
let _this = this;
|
||||
setTimeout(function() {
|
||||
_this.style.transform = "none";
|
||||
}, 50);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// don't trigger keyboard on disabled element (happens when a category is required)
|
||||
if (this.disabled) {
|
||||
return;
|
||||
}
|
||||
// resets focus out of select-kit elements
|
||||
// might become redundant after select-kit refactoring
|
||||
$fixedElement.find(".select-kit.is-expanded > button").trigger("click");
|
||||
$fixedElement
|
||||
.find(".select-kit > button.is-focused")
|
||||
.removeClass("is-focused");
|
||||
|
||||
originalScrollTop = $(window).scrollTop();
|
||||
|
||||
// take care of body
|
||||
|
||||
$("#main-outlet").hide();
|
||||
$("header").hide();
|
||||
|
||||
$(window).scrollTop(0);
|
||||
|
||||
let i = 20;
|
||||
let interval = setInterval(() => {
|
||||
$(window).scrollTop(0);
|
||||
if (i-- === 0) {
|
||||
clearInterval(interval);
|
||||
setTimeout(function() {
|
||||
if (iOSWithVisualViewport()) {
|
||||
// disable hacks when using a hardware keyboard
|
||||
// by default, a hardware keyboard will show the keyboard accessory bar
|
||||
// whose height is currently 55px (using 75 for a bit of a buffer)
|
||||
let heightDiff = window.innerHeight - window.visualViewport.height;
|
||||
if (heightDiff < 75) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}, 10);
|
||||
|
||||
fixedElement.style.top = "0px";
|
||||
if (fixedElement.style.top === "0px") {
|
||||
if (this !== document.activeElement) {
|
||||
evt.preventDefault();
|
||||
|
||||
if (!iOSWithVisualViewport()) {
|
||||
const height = calcHeight();
|
||||
fixedElement.style.height = height + "px";
|
||||
$(fixedElement).addClass("no-transition");
|
||||
// this tricks safari into assuming current input is at top of the viewport
|
||||
// via https://stackoverflow.com/questions/38017771/mobile-safari-prevent-scroll-page-when-focus-on-input
|
||||
this.style.transform = "translateY(-200px)";
|
||||
this.focus();
|
||||
let _this = this;
|
||||
setTimeout(function() {
|
||||
_this.style.transform = "none";
|
||||
}, 30);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// don't trigger keyboard on disabled element (happens when a category is required)
|
||||
if (this.disabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
$("body").addClass("ios-safari-composer-hacks");
|
||||
$(window).scrollTop(0);
|
||||
|
||||
let i = 20;
|
||||
let interval = setInterval(() => {
|
||||
$(window).scrollTop(0);
|
||||
if (i-- === 0) {
|
||||
clearInterval(interval);
|
||||
}
|
||||
}, 10);
|
||||
|
||||
if (!iOSWithVisualViewport()) {
|
||||
const height = calcHeight();
|
||||
fixedElement.style.height = height + "px";
|
||||
$(fixedElement).addClass("no-transition");
|
||||
}
|
||||
|
||||
evt.preventDefault();
|
||||
this.focus();
|
||||
workaroundActive = true;
|
||||
}, 350);
|
||||
};
|
||||
|
||||
var lastTouched = function(evt) {
|
||||
if (evt && evt.target) {
|
||||
lastTouchedElement = evt.target;
|
||||
}
|
||||
|
||||
evt.preventDefault();
|
||||
this.focus();
|
||||
workaroundActive = true;
|
||||
};
|
||||
|
||||
function attachTouchStart(elem, fn) {
|
||||
|
@ -198,30 +211,8 @@ function positioningWorkaround($fixedElement) {
|
|||
}
|
||||
|
||||
const checkForInputs = debounce(function() {
|
||||
$fixedElement
|
||||
.find(
|
||||
"button:not(.hide-preview),a:not(.mobile-file-upload):not(.toggle-toolbar)"
|
||||
)
|
||||
.each(function(idx, elem) {
|
||||
if ($(elem).parents(".emoji-picker").length > 0) {
|
||||
return;
|
||||
}
|
||||
attachTouchStart(fixedElement, lastTouched);
|
||||
|
||||
if ($(elem).parents(".autocomplete").length > 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($(elem).parents(".d-editor-button-bar").length > 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
attachTouchStart(this, function(evt) {
|
||||
done = true;
|
||||
$(document.activeElement).blur();
|
||||
evt.preventDefault();
|
||||
$(this).click();
|
||||
});
|
||||
});
|
||||
$fixedElement.find("input[type=text],textarea").each(function() {
|
||||
attachTouchStart(this, positioningHack);
|
||||
});
|
||||
|
|
|
@ -483,3 +483,19 @@ div.ac-wrap {
|
|||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
body.ios-safari-composer-hacks {
|
||||
#main-outlet,
|
||||
header,
|
||||
.grippie,
|
||||
html:not(.fullscreen-composer) & .toggle-fullscreen {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#reply-control {
|
||||
top: 0px;
|
||||
&.open {
|
||||
height: calc(var(--composer-vh, 1vh) * 100);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -230,16 +230,6 @@ a.toggle-preview {
|
|||
text-align: right;
|
||||
}
|
||||
|
||||
html.keyboard-visible {
|
||||
.grippie,
|
||||
&:not(.fullscreen-composer) .toggle-fullscreen {
|
||||
display: none;
|
||||
}
|
||||
#reply-control.open {
|
||||
height: calc(var(--composer-vh, 1vh) * 100);
|
||||
}
|
||||
}
|
||||
|
||||
// fullscreen composer styles
|
||||
.fullscreen-composer {
|
||||
overflow: hidden;
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
}
|
||||
}
|
||||
|
||||
html.keyboard-visible &.open {
|
||||
body.ios-safari-composer-hacks &.open {
|
||||
height: calc(var(--composer-vh, 1vh) * 100);
|
||||
.reply-area {
|
||||
padding-bottom: 0px;
|
||||
|
|
Loading…
Reference in New Issue
Block a user