| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293 |
- import { debounce } from 'lodash'
- export const OFFSET_FOR_ENTRIES_ABOVE = 70
- const GAP_BETWEEN_ENTRIES = 4
- export const positionItems = debounce(
- (
- element: HTMLDivElement,
- previousFocusedItemIndex: number | undefined,
- docId: string
- ) => {
- const items = Array.from(
- element.querySelectorAll<HTMLDivElement>('.review-panel-entry')
- )
- items.sort((a, b) => Number(a.dataset.pos) - Number(b.dataset.pos))
- if (!items.length) {
- return
- }
- let activeItemIndex = items.findIndex(item =>
- item.classList.contains('review-panel-entry-selected')
- )
- if (activeItemIndex === -1) {
- // if entry was not selected manually
- // check if there is an entry in selection and use that as the focused item
- activeItemIndex = items.findIndex(item =>
- item.classList.contains('review-panel-entry-highlighted')
- )
- }
- if (activeItemIndex === -1) {
- activeItemIndex = previousFocusedItemIndex || 0
- }
- const activeItem = items[activeItemIndex]
- if (!activeItem) {
- return
- }
- const activeItemTop = getTopPosition(activeItem, activeItemIndex === 0)
- const positions: [HTMLElement, number][] = []
- positions.push([activeItem, activeItemTop])
- // above the active item
- let topLimit = activeItemTop
- for (let i = activeItemIndex - 1; i >= 0; i--) {
- const item = items[i]
- const height = item.offsetHeight
- let top = getTopPosition(item, i === 0)
- const bottom = top + height
- if (bottom > topLimit) {
- top = topLimit - height - GAP_BETWEEN_ENTRIES
- }
- positions.push([item, top])
- topLimit = top
- }
- // below the active item
- let bottomLimit = activeItemTop + activeItem.offsetHeight
- for (let i = activeItemIndex + 1; i < items.length; i++) {
- const item = items[i]
- const height = item.offsetHeight
- let top = getTopPosition(item, false)
- if (top < bottomLimit) {
- top = bottomLimit + GAP_BETWEEN_ENTRIES
- }
- positions.push([item, top])
- bottomLimit = top + height
- }
- for (const [item, top] of positions) {
- item.style.top = `${top}px`
- item.style.visibility = 'visible'
- }
- return {
- docId,
- activeItemIndex,
- }
- },
- 100,
- { leading: false, trailing: true, maxWait: 1000 }
- )
- function getTopPosition(item: HTMLDivElement, isFirstEntry: boolean) {
- const offset = isFirstEntry ? 0 : OFFSET_FOR_ENTRIES_ABOVE
- return Math.max(offset, Number(item.dataset.top))
- }
|