Search code examples
javascripthtmlcsstauri

Scrolling on one axis blocks the other


I'm making a simple file viewer in Tauri framework (Just simple HTML and CSS). Because of long files I can't just put the content of the file to the <pre> element that I use to display the visible lines. So I call the rust backend with parameters of what lines are visible inside of a viewport to render just those. To simulate the scrolling i use <div> scaled to math the size that will the text have if will be displayed normally in one piece. While the <pre> is fixed to the viewport and can't be moved with.

Now when i scroll on one axis I'm unable to scroll on the other unless i wait a couple of seconds. This bug gives me no errors in the debugging console.

Code in charge of updating the lines:

addEventListener("scroll", () => {
    if (last_number_of_lines_above_viewport !== get_lines_above_viewport()) {
        lazy_redraw();
        last_number_of_lines_above_viewport = get_lines_above_viewport();
    }
});

function lazy_redraw() {
    if (loaded_file) { //Catches no file was loaded
        invoke('lazy_read_lines', {file_path: loaded_file.file_path, filter: filtered_tab_lines.slice(get_lines_above_viewport(), get_lines_above_viewport() + get_lines_inside_viewport())})
            .then((message) => { //Just returns string of lines inside a specified viewport
                document.getElementsByClassName("file")[0].innerText = message;
            }
        );
    }   
}

<pre> element css style:

.file {
    margin: 0px;
    position: fixed;
    top: 25px;
    left: 0;
    height: 100%;
    width: 100%;
    overflow-x: auto;
    overflow-y: hidden; /* Sometimes one line is slightly below the viewport, causing an extra scrollbar */

}

I thought the problem is caused by different lines length but after putting spaces at the end of the shorter ones to make their length equal i don't get any difference.

I have also tried updateing the viewport using the requestAnimationFrame():

let animationFrameId = null;

addEventListener("scroll", () => {
    if (animationFrameId === null) {
        animationFrameId = requestAnimationFrame(scrollHandler);
    }
});

function scrollHandler() {
    if (last_number_of_lines_above_viewport !== get_lines_above_viewport()) {
        lazy_redraw();
        last_number_of_lines_above_viewport = get_lines_above_viewport();
    }
    animationFrameId = requestAnimationFrame(scrollHandler);
}

Solution

  • As it turned out, the problem was that the <pre> element that displays the text lost focus when user clicked outside, than the browser didn't listen to scrolling on that element until I click back in it.

    I fixed it by returning focus to that element when lost, I know that this solution isn't optimal but it works fine in my case.

    <pre onfocusout="document.getElementById('file').focus();" id="file" autofocus></pre>