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

storage: Scroll dialog fields into view as needed #20060

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

mvollmer
Copy link
Member

@mvollmer mvollmer commented Feb 19, 2024

When fields fail validation, the first of them is scrolled into view. Additionally, when the encryption fields of the Format dialog are revealed, they are scrolled into view.

https://bugzilla.redhat.com/show_bug.cgi?id=2264540

Demo: https://www.youtube.com/watch?v=POn3lDoPJOc

Copy link
Member

@garrett garrett left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think any of this is needed, and could probably be replaced with 1 line of JavaScript in a render event or perhaps a line and a setTimeout() on a change event.

Rely on the CSS selector to conditionally select the element, use optional chaining (in case it doesn't match anything — which it won't in some cases), and then the scrollIntoView() to scroll (which is a no-operation if not necessary).

Details inline in the part that it would replace... but I think we can probably drop everything else in the PR too using this method, as we wouldn't need to check its state or position or anything like that.

WDYT?

Comment on lines 486 to 505
function scroll() {
const dialog_element = document.querySelector('#dialog .pf-v5-c-modal-box__body');
const field_element = document.querySelector('#dialog [data-tag="' + tag + '"]');

if (field_element) {
if (dialog_element) {
// check if we need to scroll
if (field_element.getBoundingClientRect().bottom <=
dialog_element.getBoundingClientRect().bottom)
return;
}

field_element.scrollIntoView({ behavior: "smooth", block: "end" });
}
}
// By the time show_field is called from the "update"
// callback, newly visible fields don't exist yet in the
// DOM, so delay the scrolling a bit.
window.setTimeout(scroll, 10);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need to check if we need to scroll? Just ask for it to be in the view. If it's already in the view, then it's a NOOP (no operation).

It should also be block as start (which is default when passing options), not end, as we want people to be able to read the error and everything after. If scoll-behavior is set in CSS, we wouldn't need to specify an animation. (I'm not sure if that's set by default though. It's something to consider, probably. Then we could have it conditionally set across all of Cockpit provided reduce animations isn't turned on in as an OS pref. But this is outside the scope of this PR, likely.)

window.setTimeout(() => {
    document.querySelector(`#dialog .pf-v5-c-form__group:has([data-tag="${tag}"])`)?.scrollIntoView({behavior: "smooth"});
}, 10);

But that data-tag is probably not even needed? You can probably select it on the change event of the element and as long as it has a value, then scroll to top of all the encryption group? You can even do all that logic in the CSS selector like this:

// Scroll to encryption area into view when encryption details are required.
document.querySelector('[data-field="crypto"]:not([data-value="none"])')?.scrollIntoView({behavior: "smooth"});

The ?. makes it not scrollIntoView when there are no matches (which would happen when none is selected in the selector). If there's a render call after changing the element, that's the place to put this line... and you probably wouldn't even need the setTimeout(), checking a scroll state, or any separate function either.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need to check if we need to scroll?

As far as I can tell, scrollIntoView will always scroll the element to the requested position, even if it is already fully visible. The scrollIntoViewIfNeeded method would do what we want, but it is not widely enough available.

It should also be block as start (which is default when passing options), not end,

Ok.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From the scrollIntoViewIfNeeded page:

This method is a proprietary variation of the standard Element.scrollIntoView() method.

We should not use a proprietary version of something that became standard.

If the scroll only happens when it can and when someone changes the dropdown to a value that isn't nothing, then it's very limited to scrolling to content. If we use block: nearest, then it won't scroll at all unless needed (which duplicates the proprietary behavior, but in a standards way).

We'd use this: {block: 'nearest', behavior: 'smooth'}

nearest details: It scrolls to show the content only when needed. When all the content is on screen, it doesn't scroll at all. When the content is larger than the screen, it also doesn't scroll. When the top or bottom is not shown and there's room, it scrolls to view it (unless it doesn't need to).

(I just double-checked nearest in a codepen example from https://matthiasott.com/notes/scrolling-elements-into-view and tried modifying it under various conditions.)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about always centering the field that the user is interacting with? Like this: https://www.youtube.com/watch?v=S4YdDXljuX8

When fields fail validation, the first of them is scrolled into view
at the top of the dialog. Additionally, when the encryption fields of
the Format dialog are revealed, they are scrolled into view.

https://bugzilla.redhat.com/show_bug.cgi?id=2264540
return;
}

field_element.scrollIntoView({ behavior: "smooth", block: align || "start" });
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This added line is not executed by any test. Details

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants