diff --git a/static/js/recent_topics_ui.js b/static/js/recent_topics_ui.js index 40e670486e..e140ed9496 100644 --- a/static/js/recent_topics_ui.js +++ b/static/js/recent_topics_ui.js @@ -104,7 +104,7 @@ function is_table_focused() { return current_focus_elem === "table"; } -function set_table_focus(row, col) { +function set_table_focus(row, col, using_keyboard) { const topic_rows = $("#recent_topics_table table tbody tr"); if (topic_rows.length === 0 || row < 0 || row >= topic_rows.length) { row_focus = 0; @@ -114,39 +114,32 @@ function set_table_focus(row, col) { } const topic_row = topic_rows.eq(row); - topic_row.find(".recent_topics_focusable").eq(col).children().trigger("focus"); - - // Bring the focused element in view in the smoothest - // possible way. Using `block: center` is not a - // smooth scrolling experience. - // Using {block: "nearest"}, the element: - // * is aligned at the top of its ancestor if you're currently below it. - // * is aligned at the bottom of its ancestor if you're currently above it. - // * stays put, if it's already in view - // NOTE: Although, according to - // https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView#browser_compatibility - // `scrollIntoView` is not fully supported on Safari, - // it works as intended on Safari v14.0.3 on macOS Big Sur. - topic_row.get()[0].scrollIntoView({ - block: "nearest", - }); - + // We need to allow table to render first before setting focus. + setTimeout( + () => topic_row.find(".recent_topics_focusable").eq(col).children().trigger("focus"), + 0, + ); current_focus_elem = "table"; + if (using_keyboard) { + const scroll_element = document.querySelector( + "#recent_topics_table .table_fix_head .simplebar-content-wrapper", + ); + const half_height_of_visible_area = scroll_element.offsetHeight / 2; + const topic_offset = topic_offset_to_visible_area(topic_row); + + if (topic_offset === "above") { + scroll_element.scrollBy({top: -1 * half_height_of_visible_area}); + } else if (topic_offset === "below") { + scroll_element.scrollBy({top: half_height_of_visible_area}); + } + } + const message = { stream: topic_row.find(".recent_topic_stream a").text(), topic: topic_row.find(".recent_topic_name a").text(), }; compose_closed_ui.update_reply_recipient_label(message); - - // focused topic can be under table `thead` - // or under compose, so, to avoid that - // from happening, we bring the element to center. - if (!is_topic_visible_to_user(topic_row)) { - topic_row.get()[0].scrollIntoView({ - block: "center", - }); - } return true; } @@ -483,7 +476,7 @@ function topic_sort(a, b) { return -1; } -function is_topic_visible_to_user(topic_row) { +function topic_offset_to_visible_area(topic_row) { const scroll_container = $("#recent_topics_table .table_fix_head"); const thead_height = 30; const under_closed_compose_region_height = 50; @@ -495,23 +488,32 @@ function is_topic_visible_to_user(topic_row) { const topic_row_top = $(topic_row).offset().top; const topic_row_bottom = topic_row_top + $(topic_row).height(); - // check if topic_row is inside the visible part of scroll container. - return topic_row_bottom <= scroll_container_bottom && topic_row_top >= scroll_container_top; + // Topic is above the visible scroll region. + if (topic_row_top < scroll_container_top) { + return "above"; + // Topic is below the visible scroll region. + } else if (topic_row_bottom > scroll_container_bottom) { + return "below"; + } + + // Topic is visible + return "visible"; } function set_focus_to_element_in_center() { + const table_wrapper_element = document.querySelector("#recent_topics_table .table_fix_head"); const topic_rows = $("#recent_topics_table table tbody tr"); + if (row_focus > topic_rows.length) { // User used a filter which reduced // the number of visible rows. return; } let topic_row = topic_rows.eq(row_focus); - if (!is_topic_visible_to_user(topic_row)) { + const topic_offset = topic_offset_to_visible_area(topic_row); + if (topic_offset !== "visible") { // Get the element at the center of the table. - const position = document - .querySelector("#recent_topics_table .table_fix_head") - .getBoundingClientRect(); + const position = table_wrapper_element.getBoundingClientRect(); const topic_center_x = (position.left + position.right) / 2; const topic_center_y = (position.top + position.bottom) / 2; @@ -817,7 +819,7 @@ export function change_focused_element($elt, input_key) { case "up_arrow": row_focus -= 1; } - set_table_focus(row_focus, col_focus); + set_table_focus(row_focus, col_focus, true); return true; } if (current_focus_elem && input_key !== "escape") {