mirror of https://github.com/zulip/zulip.git
message_scroll: Show scroll to bottom button.
Show/hide scroll to bottom button when the last message is not visible in the current scroll position. We adjust the bottom offset of the button based on compose box height. Fixes #19862
This commit is contained in:
parent
ea07b6440c
commit
0eafa6039b
|
@ -13,8 +13,16 @@ const {page_params, user_settings} = require("../zjsunit/zpage_params");
|
|||
|
||||
const noop = () => {};
|
||||
|
||||
set_global("document", {});
|
||||
set_global("document", {
|
||||
querySelector: () => {},
|
||||
});
|
||||
set_global("navigator", {});
|
||||
// eslint-disable-next-line prefer-arrow-callback
|
||||
set_global("ResizeObserver", function () {
|
||||
return {
|
||||
observe: () => {},
|
||||
};
|
||||
});
|
||||
|
||||
const fake_now = 555;
|
||||
|
||||
|
|
|
@ -14,7 +14,16 @@ const upload = mock_esm("../../static/js/upload");
|
|||
mock_esm("../../static/js/resize", {
|
||||
watch_manual_resize() {},
|
||||
});
|
||||
set_global("document", {
|
||||
querySelector: () => {},
|
||||
});
|
||||
set_global("navigator", {});
|
||||
// eslint-disable-next-line prefer-arrow-callback
|
||||
set_global("ResizeObserver", function () {
|
||||
return {
|
||||
observe: () => {},
|
||||
};
|
||||
});
|
||||
|
||||
const server_events_dispatch = zrequire("server_events_dispatch");
|
||||
const compose_ui = zrequire("compose_ui");
|
||||
|
|
|
@ -27,6 +27,7 @@ import * as message_lists from "./message_lists";
|
|||
import * as message_store from "./message_store";
|
||||
import * as muted_topics_ui from "./muted_topics_ui";
|
||||
import * as narrow from "./narrow";
|
||||
import * as navigate from "./navigate";
|
||||
import * as notifications from "./notifications";
|
||||
import * as overlays from "./overlays";
|
||||
import {page_params} from "./page_params";
|
||||
|
@ -249,6 +250,13 @@ export function initialize() {
|
|||
window.location.href = $(this).attr("href");
|
||||
});
|
||||
|
||||
$("body").on("click", "#scroll-to-bottom-button-clickable-area", (e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
navigate.to_end();
|
||||
});
|
||||
|
||||
// MESSAGE EDITING
|
||||
|
||||
$("body").on("click", ".edit_content_button", function (e) {
|
||||
|
|
|
@ -413,6 +413,13 @@ export function initialize() {
|
|||
|
||||
resize.watch_manual_resize("#compose-textarea");
|
||||
|
||||
// Update position of scroll to bottom button based on
|
||||
// height of the compose box.
|
||||
const update_scroll_to_bottom_position = new ResizeObserver(() => {
|
||||
$("#scroll-to-bottom-button-container").css("bottom", $("#compose").outerHeight());
|
||||
});
|
||||
update_scroll_to_bottom_position.observe(document.querySelector("#compose"));
|
||||
|
||||
upload.feature_check($("#compose .compose_upload_file"));
|
||||
|
||||
$("#compose-all-everyone").on("click", ".compose-all-everyone-confirm", (event) => {
|
||||
|
|
|
@ -172,6 +172,7 @@ export function make_compose_box_full_size() {
|
|||
|
||||
$(".collapse_composebox_button").show();
|
||||
$(".expand_composebox_button").hide();
|
||||
$("#scroll-to-bottom-button-container").hide();
|
||||
$("#compose-textarea").trigger("focus");
|
||||
}
|
||||
|
||||
|
|
|
@ -129,12 +129,57 @@ export function hide_top_of_narrow_notices() {
|
|||
hide_history_limit_notice();
|
||||
}
|
||||
|
||||
let hide_scroll_to_bottom_timer;
|
||||
export function hide_scroll_to_bottom() {
|
||||
const $show_scroll_to_bottom_button = $("#scroll-to-bottom-button-container");
|
||||
if (message_viewport.bottom_message_visible() || message_lists.current.empty()) {
|
||||
// If last message is visible, just hide the
|
||||
// scroll to bottom button.
|
||||
$show_scroll_to_bottom_button.hide();
|
||||
return;
|
||||
}
|
||||
|
||||
// Wait before hiding to allow user time to click on the button.
|
||||
hide_scroll_to_bottom_timer = setTimeout(() => {
|
||||
// Don't hide if user is hovered on it.
|
||||
if (
|
||||
!narrow_state.narrowed_by_topic_reply() &&
|
||||
!$show_scroll_to_bottom_button.get(0).matches(":hover")
|
||||
) {
|
||||
$show_scroll_to_bottom_button.fadeOut(500);
|
||||
}
|
||||
}, 3000);
|
||||
}
|
||||
|
||||
export function show_scroll_to_bottom_button() {
|
||||
if (message_viewport.bottom_message_visible()) {
|
||||
// Only show scroll to bottom button when
|
||||
// last message is not visible in the
|
||||
// current scroll position.
|
||||
return;
|
||||
}
|
||||
|
||||
clearTimeout(hide_scroll_to_bottom_timer);
|
||||
$("#scroll-to-bottom-button-container").fadeIn(500);
|
||||
}
|
||||
|
||||
$(document).on("keydown", (e) => {
|
||||
if (e.shiftKey || e.ctrlKey || e.metaKey) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Instantly hide scroll to bottom button on any keypress.
|
||||
// Keyboard users are very less likely to use this button.
|
||||
$("#scroll-to-bottom-button-container").hide();
|
||||
});
|
||||
|
||||
export function is_actively_scrolling() {
|
||||
return actively_scrolling;
|
||||
}
|
||||
|
||||
export function scroll_finished() {
|
||||
actively_scrolling = false;
|
||||
hide_scroll_to_bottom();
|
||||
|
||||
if (!$("#message_feed_container").hasClass("active")) {
|
||||
return;
|
||||
|
@ -170,6 +215,7 @@ export function scroll_finished() {
|
|||
let scroll_timer;
|
||||
function scroll_finish() {
|
||||
actively_scrolling = true;
|
||||
show_scroll_to_bottom_button();
|
||||
clearTimeout(scroll_timer);
|
||||
scroll_timer = setTimeout(scroll_finished, 100);
|
||||
}
|
||||
|
|
|
@ -185,7 +185,12 @@ export function initialize() {
|
|||
// ensures that tooltip doesn't hide behind the message
|
||||
// box or it is not limited by the parent container.
|
||||
delegate("body", {
|
||||
target: [".recipient_bar_icon", ".sidebar-title", "#user_filter_icon"],
|
||||
target: [
|
||||
".recipient_bar_icon",
|
||||
".sidebar-title",
|
||||
"#user_filter_icon",
|
||||
"#scroll-to-bottom-button-clickable-area",
|
||||
],
|
||||
appendTo: () => document.body,
|
||||
});
|
||||
|
||||
|
|
|
@ -203,6 +203,7 @@ function initialize_compose_box() {
|
|||
embedded: $("#compose").attr("data-embedded") === "",
|
||||
file_upload_enabled: page_params.max_file_upload_size_mib > 0,
|
||||
giphy_enabled: giphy.is_giphy_enabled(),
|
||||
scroll_to_bottom_key: common.has_mac_keyboard() ? "Fn + Right arrow" : "End",
|
||||
}),
|
||||
);
|
||||
$(`.enter_sends_${user_settings.enter_sends}`).show();
|
||||
|
|
|
@ -215,6 +215,8 @@
|
|||
}
|
||||
|
||||
#compose-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
/* This should match the value for .app-main */
|
||||
max-width: 1400px;
|
||||
|
|
|
@ -148,6 +148,14 @@ body.dark-theme {
|
|||
background-color: hsl(212, 28%, 18%);
|
||||
}
|
||||
|
||||
#scroll-to-bottom-button-container {
|
||||
background: transparent;
|
||||
|
||||
span {
|
||||
color: hsl(0, 0%, 27%);
|
||||
}
|
||||
}
|
||||
|
||||
#compose_buttons
|
||||
.reply_button_container
|
||||
.compose_reply_button
|
||||
|
|
|
@ -3095,3 +3095,40 @@ select.inline_select_topic_edit {
|
|||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
#scroll-to-bottom-button-container {
|
||||
display: none;
|
||||
z-index: 3;
|
||||
position: absolute;
|
||||
bottom: 41px;
|
||||
right: 0;
|
||||
|
||||
#scroll-to-bottom-button-clickable-area {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover #scroll-to-bottom-button {
|
||||
background: hsl(240, 96%, 68%);
|
||||
}
|
||||
|
||||
#scroll-to-bottom-button {
|
||||
text-align: center;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
background: hsl(240, 96%, 68%, 0.5);
|
||||
border-radius: 50%;
|
||||
|
||||
i {
|
||||
color: hsl(0, 0%, 100%);
|
||||
margin: 0 auto;
|
||||
font-size: 21px;
|
||||
position: relative;
|
||||
top: 8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,15 @@
|
|||
<div id="compose-content">
|
||||
{{!-- scroll to bottom button is not part of compose but
|
||||
helps us align it at various screens sizes with
|
||||
minimal css and no JS. We keep it `position: absolute` to prevent
|
||||
it changing compose box layout in any way. --}}
|
||||
<div id="scroll-to-bottom-button-container">
|
||||
<div id="scroll-to-bottom-button-clickable-area" data-tippy-content="{{t 'Scroll to bottom' }} <span class='hotkey-hint'>({{scroll_to_bottom_key}})</span>" data-tippy-allowHtml="true">
|
||||
<div id="scroll-to-bottom-button">
|
||||
<i class="fa fa-chevron-down"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="compose_controls" class="new-style">
|
||||
<div id="compose_buttons">
|
||||
<span class="new_message_button reply_button_container">
|
||||
|
|
Loading…
Reference in New Issue