mirror of
https://github.com/SillyTavern/SillyTavern.git
synced 2025-03-13 18:40:11 +01:00
fix MovingUI infinite loop on resize to Y edge
This commit is contained in:
parent
3dc4c8ca39
commit
56d0ffc1fd
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user