Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

scrollWindow: fix view scrolling #9869

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 18 additions & 2 deletions browser/css/jsdialogs.css
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,12 @@ td.jsdialog > [id^='table-box']:not(.sidebar) {
grid-gap: 4px;
width: fit-content;
}
#SpecialCharactersDialog .jsdialog.ui-scrollwindow.has-ui-drawing-area {
height: 279px;
}
#SpecialCharactersDialog .jsdialog.ui-scrollwindow.has-ui-drawing-area #showcharset.ui-drawing-area-container {
height: 279px;
}

/* Find and replace dialog */
#search_grid, #replace_grid {
Expand Down Expand Up @@ -2036,6 +2042,15 @@ input[type='number']:hover::-webkit-outer-spin-button {
flex-direction: column;
}

#FormulaDialog #ParameterPage > #paramgrid .ui-scrollwindow {
width: 400px;
max-height: 200px;
}

#FormulaDialog #ParameterPage > #paramgrid .ui-scrollwindow .ui-edit-container {
display: flex;
}

#FormulaDialog > [id^='dialog-vbox'] > [id^='box'] > [id^='box'] {
grid-auto-columns: max-content;
grid-column-gap: 8px;
Expand Down Expand Up @@ -2205,8 +2220,9 @@ kbd,
margin: 0;
}

#DocumentPropertiesDialog #customprops .jsdialog.ui-scrollwindow {
max-height: min-content;
#DocumentPropertiesDialog #customprops #CustomInfoPage > .jsdialog.ui-scrollwindow:not(.formulabar) {
height: 540px;
max-height: none;
}

#ServerAuditDialog #ServerAuditDialog-mainbox {
Expand Down
121 changes: 95 additions & 26 deletions browser/src/control/jsdialog/Widget.ScrolledWindow.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,8 @@ function _scrolledWindowControl(parentContainer, data, builder) {
scrollwindow.id = data.id;

// drawing areas inside scrollwindows should be not cropped so we add special class
if (_hasDrawingAreaInside(data.children))
let drawingArea = _hasDrawingAreaInside(data.children);
if (drawingArea)
L.DomUtil.addClass(scrollwindow, 'has-ui-drawing-area');

var content = L.DomUtil.create('div', builder.options.cssClass + ' ui-scrollwindow-content', scrollwindow);
Expand All @@ -70,7 +71,7 @@ function _scrolledWindowControl(parentContainer, data, builder) {
if (data.vertical.policy === 'always')
scrollwindow.style.overflowY = 'scroll';

var noHorizontal = data.horizontal.policy === 'never';
var noHorizontal = data.horizontal.policy === 'never' || data.horizontal.page_size == 0;
if (noHorizontal)
scrollwindow.style.overflowX = 'hidden';
if (data.horizontal.policy === 'always')
Expand All @@ -89,7 +90,9 @@ function _scrolledWindowControl(parentContainer, data, builder) {
if (horizontalSteps < 0 || noHorizontal)
horizontalSteps = 0;

var rowHeight = 0;
var timeoutLimit = 2;

var updateSize = function () {
realContentHeight = scrollwindow.scrollHeight;
realContentWidth = scrollwindow.scrollwidth;
Expand All @@ -99,43 +102,109 @@ function _scrolledWindowControl(parentContainer, data, builder) {
return;
}

if (!noVertical) {
content.style.height = (realContentHeight + verticalSteps) + 'px';
scrollwindow.style.height = (realContentHeight + margin) + 'px';
if (!noVertical && data.vertical.upper > 0) {
if (rowHeight == 0) {
// determine the height a row
let height = drawingArea ? scrollwindow.scrollHeight : realContentHeight;
if (data.vertical.upper >= data.vertical.page_size) {
rowHeight = height / data.vertical.page_size;
} else {
rowHeight = height / data.vertical.upper;
}
}
var totalContentHeight = data.vertical.upper * rowHeight;
let marginTop = data.vertical.value * rowHeight;

if (totalContentHeight != scrollwindow.scrollHeight) {
// only if view has changed
content.style.marginBlockStart = marginTop + 'px';
content.style.marginBlockEnd = (totalContentHeight - marginTop - realContentHeight) + 'px';
}
scrollwindow.scrollTop = marginTop;
}
if (!noHorizontal) {
content.style.width = (realContentWidth + horizontalSteps) + 'px';
scrollwindow.style.width = (realContentWidth + margin) + 'px';
content.scrollLeft = data.horizontal.value * 10;
content.style.marginInlineEnd = margin + 'px';
content.style.marginInlineStart = content.scrollLeft + 'px';
}

content.scrollTop = data.vertical.value * 10;
content.scrollLeft = data.horizontal.value * 10;

content.style.margin = content.scrollTop + 'px ' + margin + 'px ' + margin + 'px ' + content.scrollLeft + 'px';
};

if (data.user_managed_scrolling !== false)
if (data.user_managed_scrolling !== false) {
setTimeout(updateSize, 0);

var sendTimer = null;
}

if ((!noVertical && verticalSteps) || (!noHorizontal && horizontalSteps)) {
scrollwindow.addEventListener('scroll', function () {
// keep content at the same place on the screen
var scrollTop = scrollwindow.scrollTop;
var scrollLeft = scrollwindow.scrollLeft;

if (data.user_managed_scrolling !== false) {
content.style.margin = scrollTop + 'px ' + margin + 'px ' + margin + 'px ' + scrollLeft + 'px';
content.style.height = (realContentHeight - scrollTop + verticalSteps) + 'px';
content.style.width = (realContentWidth - scrollLeft + horizontalSteps) + 'px';
}

var mutating = false;
var restoreScrollV = null;
var lastScrollV = null;

if (drawingArea) {
// With drawing area after each scroll event the content is removed
// this creates spurrious events to the top of the list
// this detect those and allows to ignore them
var noMutation = function (mutationsList) {
for (var mutation of mutationsList) {
if (mutation.type == "childList") {
if (mutation.removedNodes.length != 0) {
// some nodes were removed, consider we are mutating
// and next scroll event will be spurrious
mutating = true;
restoreScrollV = lastScrollV;
}
}
}
};

var observer = new MutationObserver(noMutation);
observer.observe(content, {childList: true });
}

var lastScrollH = null;
var sendTimer = null;

scrollwindow.addEventListener('scroll', function() {
if (sendTimer)
clearTimeout(sendTimer);
sendTimer = setTimeout(function () {
builder.callback('scrolledwindow', 'scrollv', scrollwindow, Math.round(scrollTop / 10), builder);
builder.callback('scrolledwindow', 'scrollh', scrollwindow, Math.round(scrollLeft / 10), builder); }, 50);

if (mutating) {
// ignore spurious event
mutating = false;
scrollwindow.scrollTop = restoreScrollV * rowHeight;
return;
}

if (data.user_managed_scrolling !== false) {

if (!noVertical) {
let newScrollV = Math.round(scrollwindow.scrollTop / rowHeight);
let totalContentHeight = scrollwindow.scrollHeight;
let offset = newScrollV * rowHeight;
let marginTop = offset;
content.style.marginBlockStart = marginTop + 'px';
content.style.marginBlockEnd = (totalContentHeight - marginTop - scrollwindow.clientHeight) + 'px';
}
if (!noHorizontal) {
realContentWidth = scrollwindow.scrollWidth;
content.style.width = (realContentWidth - scrollwindow.scrollLeft + horizontalSteps) + 'px';
content.style.marginInlineStart = scrollwindow.scrollLeft + 'px';
}
}

var newScrollV = Math.round(scrollwindow.scrollTop / rowHeight);
if (lastScrollV !== newScrollV) {
lastScrollV = newScrollV;
builder.callback('scrolledwindow', 'scrollv', scrollwindow, newScrollV, builder);
}

var newScrollH = Math.round(scrollwindow.scrollLeft / 10);
if (lastScrollH !== newScrollH) {
lastScrollH = newScrollH;
builder.callback('scrolledwindow', 'scrollh', scrollwindow, newScrollH, builder);
}
}, 50);
});
}

Expand Down
Loading