Allow viewport to be used for constraining popup position

This commit is contained in:
toasted-nutbread 2020-01-11 14:21:10 -05:00
parent 21dbb19565
commit d59f2022b9

View File

@ -258,6 +258,7 @@ class Popup {
Popup._getPositionForVerticalText Popup._getPositionForVerticalText
); );
const viewport = Popup._getViewport(optionsGeneral.popupScaleRelativeToVisualViewport);
const scale = this._contentScale; const scale = this._contentScale;
const scaleRatio = this._containerSizeContentScale === null ? 1.0 : scale / this._containerSizeContentScale; const scaleRatio = this._containerSizeContentScale === null ? 1.0 : scale / this._containerSizeContentScale;
this._containerSizeContentScale = scale; this._containerSizeContentScale = scale;
@ -265,8 +266,7 @@ class Popup {
elementRect, elementRect,
Math.max(containerRect.width * scaleRatio, optionsGeneral.popupWidth * scale), Math.max(containerRect.width * scaleRatio, optionsGeneral.popupWidth * scale),
Math.max(containerRect.height * scaleRatio, optionsGeneral.popupHeight * scale), Math.max(containerRect.height * scaleRatio, optionsGeneral.popupHeight * scale),
document.body.clientWidth, viewport,
window.innerHeight,
scale, scale,
optionsGeneral, optionsGeneral,
writingMode writingMode
@ -353,49 +353,49 @@ class Popup {
} }
} }
static _getPositionForHorizontalText(elementRect, width, height, maxWidth, maxHeight, offsetScale, optionsGeneral) { static _getPositionForHorizontalText(elementRect, width, height, viewport, offsetScale, optionsGeneral) {
let x = elementRect.left + optionsGeneral.popupHorizontalOffset * offsetScale;
const overflowX = Math.max(x + width - maxWidth, 0);
if (overflowX > 0) {
if (x >= overflowX) {
x -= overflowX;
} else {
width = maxWidth;
x = 0;
}
}
const preferBelow = (optionsGeneral.popupHorizontalTextPosition === 'below'); const preferBelow = (optionsGeneral.popupHorizontalTextPosition === 'below');
const horizontalOffset = optionsGeneral.popupHorizontalOffset * offsetScale;
const verticalOffset = optionsGeneral.popupVerticalOffset * offsetScale; const verticalOffset = optionsGeneral.popupVerticalOffset * offsetScale;
const [y, h, below] = Popup._limitGeometry(
const [x, w] = Popup._getConstrainedPosition(
elementRect.right - horizontalOffset,
elementRect.left + horizontalOffset,
width,
viewport.left,
viewport.right,
true
);
const [y, h, below] = Popup._getConstrainedPositionBinary(
elementRect.top - verticalOffset, elementRect.top - verticalOffset,
elementRect.bottom + verticalOffset, elementRect.bottom + verticalOffset,
height, height,
maxHeight, viewport.top,
viewport.bottom,
preferBelow preferBelow
); );
return [x, y, w, h, below];
return [x, y, width, h, below];
} }
static _getPositionForVerticalText(elementRect, width, height, maxWidth, maxHeight, offsetScale, optionsGeneral, writingMode) { static _getPositionForVerticalText(elementRect, width, height, viewport, offsetScale, optionsGeneral, writingMode) {
const preferRight = Popup._isVerticalTextPopupOnRight(optionsGeneral.popupVerticalTextPosition, writingMode); const preferRight = Popup._isVerticalTextPopupOnRight(optionsGeneral.popupVerticalTextPosition, writingMode);
const horizontalOffset = optionsGeneral.popupHorizontalOffset2 * offsetScale; const horizontalOffset = optionsGeneral.popupHorizontalOffset2 * offsetScale;
const verticalOffset = optionsGeneral.popupVerticalOffset2 * offsetScale; const verticalOffset = optionsGeneral.popupVerticalOffset2 * offsetScale;
const [x, w] = Popup._limitGeometry( const [x, w] = Popup._getConstrainedPositionBinary(
elementRect.left - horizontalOffset, elementRect.left - horizontalOffset,
elementRect.right + horizontalOffset, elementRect.right + horizontalOffset,
width, width,
maxWidth, viewport.left,
viewport.right,
preferRight preferRight
); );
const [y, h, below] = Popup._limitGeometry( const [y, h, below] = Popup._getConstrainedPosition(
elementRect.bottom - verticalOffset, elementRect.bottom - verticalOffset,
elementRect.top + verticalOffset, elementRect.top + verticalOffset,
height, height,
maxHeight, viewport.top,
viewport.bottom,
true true
); );
return [x, y, w, h, below]; return [x, y, w, h, below];
@ -424,23 +424,36 @@ class Popup {
} }
} }
static _limitGeometry(positionBefore, positionAfter, size, limit, preferAfter) { static _getConstrainedPosition(positionBefore, positionAfter, size, minLimit, maxLimit, after) {
let after = preferAfter; size = Math.min(size, maxLimit - minLimit);
let position = 0;
const overflowBefore = Math.max(0, size - positionBefore); let position;
const overflowAfter = Math.max(0, positionAfter + size - limit); if (after) {
if (overflowAfter > 0 || overflowBefore > 0) { position = Math.max(minLimit, positionAfter);
if (overflowAfter < overflowBefore) { position = position - Math.max(0, (position + size) - maxLimit);
size = Math.max(0, size - overflowAfter);
position = positionAfter;
after = true;
} else { } else {
size = Math.max(0, size - overflowBefore); position = Math.min(maxLimit, positionBefore) - size;
position = Math.max(0, positionBefore - size); position = position + Math.max(0, minLimit - position);
after = false;
} }
return [position, size, after];
}
static _getConstrainedPositionBinary(positionBefore, positionAfter, size, minLimit, maxLimit, after) {
const overflowBefore = minLimit - (positionBefore - size);
const overflowAfter = (positionAfter + size) - maxLimit;
if (overflowAfter > 0 || overflowBefore > 0) {
after = (overflowAfter < overflowBefore);
}
let position;
if (after) {
size -= Math.max(0, overflowAfter);
position = Math.max(minLimit, positionAfter);
} else { } else {
position = preferAfter ? positionAfter : positionBefore - size; size -= Math.max(0, overflowBefore);
position = Math.min(maxLimit, positionBefore) - size;
} }
return [position, size, after]; return [position, size, after];
@ -479,6 +492,29 @@ class Popup {
// NOP // NOP
} }
} }
static _getViewport(useVisualViewport) {
if (useVisualViewport) {
const visualViewport = window.visualViewport;
if (visualViewport !== null && typeof visualViewport === 'object') {
const left = visualViewport.offsetLeft;
const top = visualViewport.offsetTop;
return {
left,
top,
right: left + visualViewport.width,
bottom: top + visualViewport.height
};
}
}
return {
left: 0,
top: 0,
right: document.body.clientWidth,
bottom: window.innerHeight
};
}
} }
Popup.outerStylesheet = null; Popup.outerStylesheet = null;