mirror of https://github.com/zulip/zulip.git
96 lines
2.8 KiB
TypeScript
96 lines
2.8 KiB
TypeScript
import $ from "jquery";
|
||
import SimpleBar from "simplebar";
|
||
|
||
// This type is helpful for testing, where we may have a dummy object instead of an actual jquery object.
|
||
type JQueryOrZJQuery = {__zjquery?: true} & JQuery;
|
||
|
||
export function get_content_element($element: JQuery): JQuery {
|
||
const element = $element.expectOne()[0];
|
||
const sb = SimpleBar.instances.get(element);
|
||
if (sb) {
|
||
return $(sb.getContentElement());
|
||
}
|
||
return $element;
|
||
}
|
||
|
||
export function get_scroll_element($element: JQueryOrZJQuery): JQuery {
|
||
// For testing we just return the element itself.
|
||
if ($element?.__zjquery) {
|
||
return $element;
|
||
}
|
||
|
||
const element = $element.expectOne()[0];
|
||
const sb = SimpleBar.instances.get(element);
|
||
if (sb) {
|
||
return $(sb.getScrollElement());
|
||
} else if ("simplebar" in element.dataset) {
|
||
// The SimpleBar mutation observer hasn’t processed this element yet.
|
||
// Create the SimpleBar early in case we need to add event listeners.
|
||
return $(new SimpleBar(element).getScrollElement()!);
|
||
}
|
||
return $element;
|
||
}
|
||
|
||
export function reset_scrollbar($element: JQuery): void {
|
||
const element = $element.expectOne()[0];
|
||
const sb = SimpleBar.instances.get(element);
|
||
if (sb) {
|
||
sb.getScrollElement().scrollTop = 0;
|
||
} else {
|
||
element.scrollTop = 0;
|
||
}
|
||
}
|
||
|
||
export function scroll_delta(opts: {
|
||
elem_top: number;
|
||
elem_bottom: number;
|
||
container_height: number;
|
||
}): number {
|
||
const elem_top = opts.elem_top;
|
||
const container_height = opts.container_height;
|
||
const elem_bottom = opts.elem_bottom;
|
||
|
||
let delta = 0;
|
||
|
||
if (elem_top < 0) {
|
||
delta = Math.max(elem_top, elem_bottom - container_height);
|
||
delta = Math.min(0, delta);
|
||
} else {
|
||
if (elem_bottom > container_height) {
|
||
delta = Math.min(elem_top, elem_bottom - container_height);
|
||
delta = Math.max(0, delta);
|
||
}
|
||
}
|
||
|
||
return delta;
|
||
}
|
||
|
||
export function scroll_element_into_container(
|
||
$elem: JQuery,
|
||
$container: JQuery,
|
||
sticky_header_height = 0,
|
||
): void {
|
||
// This does the minimum amount of scrolling that is needed to make
|
||
// the element visible. It doesn't try to center the element, so
|
||
// this will be non-intrusive to users when they already have
|
||
// the element visible.
|
||
$container = get_scroll_element($container);
|
||
const elem_top = $elem.position().top - sticky_header_height;
|
||
const elem_bottom = elem_top + ($elem.innerHeight() ?? 0);
|
||
const container_height = ($container.height() ?? 0) - sticky_header_height;
|
||
|
||
const opts = {
|
||
elem_top,
|
||
elem_bottom,
|
||
container_height,
|
||
};
|
||
|
||
const delta = scroll_delta(opts);
|
||
|
||
if (delta === 0) {
|
||
return;
|
||
}
|
||
|
||
$container.scrollTop(($container.scrollTop() ?? 0) + delta);
|
||
}
|