fix MovingUI infinite loop on resize to Y edge

This commit is contained in:
RossAscends 2024-05-21 09:55:56 +09:00
parent 3dc4c8ca39
commit 56d0ffc1fd
2 changed files with 79 additions and 103 deletions

View File

@ -437,7 +437,7 @@ const saveUserInputDebounced = debounce(saveUserInput);
// Make the DIV element draggable:
export function dragElement(elmnt) {
var hasBeenDraggedByUser = false;
var isHeaderBeingDragged = false;
var isMouseDown = false;
var pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0;
@ -448,16 +448,16 @@ export function dragElement(elmnt) {
var elmntName = elmnt.attr('id');
console.debug(`dragElement called for ${elmntName}`);
const elmntNameEscaped = $.escapeSelector(elmntName);
console.debug(`dragElement escaped name: ${elmntNameEscaped}`);
const elmntHeader = $(`#${elmntNameEscaped}header`);
if (elmntHeader.length) {
elmntHeader.off('mousedown').on('mousedown', (e) => {
hasBeenDraggedByUser = true;
elmntHeader.off('mousedown').on('mousedown', (e) => { //listener for drag handle repositioning
isHeaderBeingDragged = true;
isMouseDown = true;
observer.observe(elmnt.get(0), { attributes: true, attributeFilter: ['style'] });
dragMouseDown(e);
});
$(elmnt).off('mousedown').on('mousedown', () => {
$(elmnt).off('mousedown').on('mousedown', () => { //listener for resize
isMouseDown = true;
observer.observe(elmnt.get(0), { attributes: true, attributeFilter: ['style'] });
});
@ -465,20 +465,19 @@ export function dragElement(elmnt) {
const observer = new MutationObserver((mutations) => {
const target = mutations[0].target;
if (!$(target).is(':visible')
|| $(target).hasClass('resizing')
|| Number((String(target.height).replace('px', ''))) < 50
|| Number((String(target.width).replace('px', ''))) < 50
|| power_user.movingUI === false
|| isMobile()
if (!$(target).is(':visible') //abort if element is invisible
|| $(target).hasClass('resizing') //being auto-resized by other JS code
|| Number((String(target.height).replace('px', ''))) < 50 //too short
|| Number((String(target.width).replace('px', ''))) < 50 //too narrow
|| power_user.movingUI === false // if MUI is not turned on
|| isMobile() // if it's a mobile screen
) {
console.debug('aborting mutator');
return;
}
//console.debug(left + width, winWidth, hasBeenDraggedByUser, isMouseDown)
const style = getComputedStyle(target); //use computed values because not all CSS are set by default
height = parseInt(style.height) //target.offsetHeight;
width = parseInt(style.width) //target.offsetWidth;
const style = getComputedStyle(target);
height = parseInt(style.height)
width = parseInt(style.width)
top = parseInt(style.top);
left = parseInt(style.left);
right = parseInt(style.right);
@ -492,20 +491,6 @@ export function dragElement(elmnt) {
const topbarstyle = getComputedStyle(topbar);
topBarFirstX = parseInt(topbarstyle.marginInline);
topBarLastY = parseInt(topbarstyle.height);
/*
console.log(`
Observer
winWidth: ${winWidth}, winHeight: ${winHeight}
sheldWidth: sheldWidth
X: ${$(elmnt).css('left')}
Y: ${$(elmnt).css('top')}
MaxX: ${maxX}, MaxY: ${maxY}
height: ${height}
width: ${width}
Topbar 1st X: ${topBarFirstX}
TopBar lastX: topBarLastX
`);
*/
//prepare an empty poweruser object for the item being altered if we don't have one already
if (!power_user.movingUIState[elmntName]) {
@ -513,48 +498,47 @@ export function dragElement(elmnt) {
power_user.movingUIState[elmntName] = {};
}
//only record position changes if caused by a user click-drag
if (hasBeenDraggedByUser && isMouseDown) {
power_user.movingUIState[elmntName].top = top;
power_user.movingUIState[elmntName].left = left;
power_user.movingUIState[elmntName].right = right;
power_user.movingUIState[elmntName].bottom = bottom;
power_user.movingUIState[elmntName].margin = 'unset';
}
//handle resizing
if (!hasBeenDraggedByUser && isMouseDown) { //if user is dragging the resize handle (not in header)
//console.debug('saw resize, NOT header drag');
if (!isHeaderBeingDragged && isMouseDown) { //if user is dragging the resize handle (not in header)
let imgHeight, imgWidth, imageAspectRatio;
let containerAspectRatio = elmnt.height() / elmnt.width();
let containerAspectRatio = height / width;
//force the zoomed avatar container to always be the same aspect ratio as the inner image
//force aspect ratio for zoomed avatars
if ($(elmnt).attr('id').startsWith('zoomFor_')) {
let zoomedAvatarImage = $(elmnt).find('.zoomed_avatar_img');
imgHeight = zoomedAvatarImage.height();
imgWidth = zoomedAvatarImage.width();
imageAspectRatio = imgHeight / imgWidth;
}
if (containerAspectRatio !== imageAspectRatio) {
elmnt.css('height', imgHeight);
}
// Maintain aspect ratio
if (containerAspectRatio !== imageAspectRatio) {
elmnt.css('width', elmnt.width());
elmnt.css('height', elmnt.width() * imageAspectRatio);
}
//prevent resizing offscreen
if (top + elmnt.height() >= winHeight) {
//console.debug('resizing height to prevent offscreen');
elmnt.css('height', winHeight - top - 1 + 'px');
}
// Prevent resizing offscreen
if (top + elmnt.height() >= winHeight) {
elmnt.css('height', winHeight - top - 1 + 'px');
elmnt.css('width', (winHeight - top - 1) / imageAspectRatio + 'px');
}
if (left + elmnt.width() >= winWidth) {
//console.debug('resizing width to prevent offscreen');
elmnt.css('width', winWidth - left - 1 + 'px');
if (left + elmnt.width() >= winWidth) {
elmnt.css('width', winWidth - left - 1 + 'px');
elmnt.css('height', (winWidth - left - 1) * imageAspectRatio + 'px');
}
} else { //prevent divs that are not zoomedAvatars from resizing offscreen
if (top + elmnt.height() >= winHeight) {
elmnt.css('height', winHeight - top - 1 + 'px');
}
if (left + elmnt.width() >= winWidth) {
elmnt.css('width', winWidth - left - 1 + 'px');
}
}
//prevent resizing from top left into the top bar
if (top < topBarLastY && maxX >= topBarFirstX && left <= topBarFirstX
) {
//console.debug('prevent topbar underlap resize');
if (top < topBarLastY && maxX >= topBarFirstX && left <= topBarFirstX) {
elmnt.css('width', width - 1 + 'px');
}
@ -563,11 +547,11 @@ export function dragElement(elmnt) {
elmnt.css('top', top);
//set a listener for mouseup to save new width/height
elmnt.off('mouseup').on('mouseup', () => {
console.debug(`Saving ${elmntName} Height/Width`);
$(window).off('mouseup').on('mouseup', () => {
console.log(`Saving ${elmntName} Height/Width`);
// check if the height or width actually changed
if (power_user.movingUIState[elmntName].width === width && power_user.movingUIState[elmntName].height === height) {
console.debug('no change detected, aborting save');
if (power_user.movingUIState[elmntName].width === elmnt.width() && power_user.movingUIState[elmntName].height === elmnt.height()) {
console.log('no change detected, aborting save');
return;
}
@ -575,12 +559,26 @@ export function dragElement(elmnt) {
power_user.movingUIState[elmntName].height = height;
eventSource.emit('resizeUI', elmntName);
saveSettingsDebounced();
imgHeight = null;
imgWidth = null;
height = null;
width = null;
containerAspectRatio = null;
imageAspectRatio = null;
});
}
//handle dragging hit detection
if (hasBeenDraggedByUser && isMouseDown) {
//prevent dragging offscreen
//only record position changes if header is being dragged
power_user.movingUIState[elmntName].top = top;
power_user.movingUIState[elmntName].left = left;
power_user.movingUIState[elmntName].right = right;
power_user.movingUIState[elmntName].bottom = bottom;
power_user.movingUIState[elmntName].margin = 'unset';
//handle dragging hit detection to prevent dragging offscreen
if (isHeaderBeingDragged && isMouseDown) {
if (top <= 0) {
elmnt.css('top', '0px');
} else if (maxY >= winHeight) {
@ -592,27 +590,14 @@ export function dragElement(elmnt) {
} else if (maxX >= winWidth) {
elmnt.css('left', winWidth - maxX + left - 1 + 'px');
}
//prevent underlap with topbar div
/*
if (top < topBarLastY
&& (maxX >= topBarFirstX && left <= topBarFirstX //elmnt is hitting topbar from left side
|| left <= topBarLastX && maxX >= topBarLastX //elmnt is hitting topbar from right side
|| left >= topBarFirstX && maxX <= topBarLastX) //elmnt hitting topbar in the middle
) {
console.debug('topbar hit')
elmnt.css('top', top + 1 + "px");
}
*/
}
// Check if the element header exists and set the listener on the grabber
// Check if the element header exists and set the reposition listener on the grabber in the header
if (elmntHeader.length) {
elmntHeader.off('mousedown').on('mousedown', (e) => {
console.debug('listener started from header');
dragMouseDown(e);
});
} else {
} else { //if no header, put the listener on the elmnt itself.
elmnt.off('mousedown').on('mousedown', dragMouseDown);
}
});
@ -620,7 +605,7 @@ export function dragElement(elmnt) {
function dragMouseDown(e) {
if (e) {
hasBeenDraggedByUser = true;
isHeaderBeingDragged = true;
e.preventDefault();
pos3 = e.clientX; //mouse X at click
pos4 = e.clientY; //mouse Y at click
@ -652,35 +637,20 @@ export function dragElement(elmnt) {
elmnt.css('margin', 'unset');
elmnt.css('left', (elmnt.offset().left - pos1) + 'px');
elmnt.css('top', (elmnt.offset().top - pos2) + 'px');
elmnt.css('right', ((winWidth - maxX) + 'px'));
elmnt.css('bottom', ((winHeight - maxY) + 'px'));
/* elmnt.css('right', ((winWidth - maxX) + 'px'));
elmnt.css('bottom', ((winHeight - maxY) + 'px')); */
// Height/Width here are for visuals only, and are not saved to settings
// required because some divs do hot have a set width/height..
// and will defaults to shrink to min value of 100px set in CSS file
// Height/Width here are for visuals only, and are not saved to settings.
// This is required because some divs do hot have a set width/height
// and will default to shrink to min value of 100px set in CSS file
elmnt.css('height', height);
elmnt.css('width', width);
/*console.log(`
elementDrag:
winWidth: ${winWidth}, winHeight: ${winHeight}
sheldWidth: sheldWidth
X: ${$(elmnt).css('left')}
Y: ${$(elmnt).css('top')}
MaxX: ${maxX}, MaxY: ${maxY}
height: ${height}
width: ${width}
Topbar 1st X: ${topBarFirstX}
TopBar lastX: topBarLastX
`);*/
return;
}
function closeDragElement() {
console.debug('drag finished');
hasBeenDraggedByUser = false;
isHeaderBeingDragged = false;
isMouseDown = false;
$(document).off('mouseup', closeDragElement);
$(document).off('mousemove', elementDrag);
@ -690,6 +660,12 @@ TopBar lastX: topBarLastX
observer.disconnect();
console.debug(`Saving ${elmntName} UI position`);
saveSettingsDebounced();
top = null;
left = null;
right = null;
bottom = null;
maxX = null;
maxY = null;
}
}

View File

@ -4904,7 +4904,7 @@ body:not(.movingUI) .drawer-content.maximized {
.zoomed_avatar_container {
width: 100%;
margin-inline: 10px;
/* margin-inline: 10px; */
max-height: 90vh;
max-width: 90svh;
}