|
|
|
@ -88,6 +88,8 @@ const expandedFormDlg = ref(false)
|
|
|
|
|
const expandedFormRow = ref<Row>() |
|
|
|
|
const expandedFormRowState = ref<Record<string, any>>() |
|
|
|
|
const tbodyEl = ref<HTMLElement>() |
|
|
|
|
const gridWrapper = ref<HTMLElement>() |
|
|
|
|
const tableHead = ref<HTMLElement>() |
|
|
|
|
|
|
|
|
|
const { |
|
|
|
|
isLoading, |
|
|
|
@ -107,6 +109,55 @@ const { getMeta } = useMetas()
|
|
|
|
|
|
|
|
|
|
const { loadGridViewColumns, updateWidth, resizingColWidth, resizingCol } = useGridViewColumnWidth(view) |
|
|
|
|
|
|
|
|
|
const getContainerScrollForElement = ( |
|
|
|
|
el: HTMLElement, |
|
|
|
|
container: HTMLElement, |
|
|
|
|
offset?: { |
|
|
|
|
top?: number |
|
|
|
|
bottom?: number |
|
|
|
|
left?: number |
|
|
|
|
right?: number |
|
|
|
|
}, |
|
|
|
|
) => { |
|
|
|
|
const childPos = el.getBoundingClientRect() |
|
|
|
|
const parentPos = container.getBoundingClientRect() |
|
|
|
|
const relativePos = { |
|
|
|
|
top: childPos.top - parentPos.top, |
|
|
|
|
right: childPos.right - parentPos.right, |
|
|
|
|
bottom: childPos.bottom - parentPos.bottom, |
|
|
|
|
left: childPos.left - parentPos.left, |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
const scroll = { |
|
|
|
|
top: 0, |
|
|
|
|
left: 0, |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* |
|
|
|
|
* If the element is to the right of the container, scroll right (positive) |
|
|
|
|
* If the element is to the left of the container, scroll left (negative) |
|
|
|
|
*/ |
|
|
|
|
scroll.left = |
|
|
|
|
relativePos.right + (offset?.right || 0) > 0 |
|
|
|
|
? container.scrollLeft + relativePos.right + (offset?.right || 0) |
|
|
|
|
: relativePos.left - (offset?.left || 0) < 0 |
|
|
|
|
? container.scrollLeft + relativePos.left - (offset?.left || 0) |
|
|
|
|
: container.scrollLeft |
|
|
|
|
|
|
|
|
|
/* |
|
|
|
|
* If the element is below the container, scroll down (positive) |
|
|
|
|
* If the element is above the container, scroll up (negative) |
|
|
|
|
*/ |
|
|
|
|
scroll.top = |
|
|
|
|
relativePos.bottom + (offset?.bottom || 0) > 0 |
|
|
|
|
? container.scrollTop + relativePos.bottom + (offset?.bottom || 0) |
|
|
|
|
: relativePos.top - (offset?.top || 0) < 0 |
|
|
|
|
? container.scrollTop + relativePos.top - (offset?.top || 0) |
|
|
|
|
: container.scrollTop |
|
|
|
|
|
|
|
|
|
return scroll |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
const { selectCell, selectBlock, selectedRange, clearRangeRows, startSelectRange, selected } = useMultiSelect( |
|
|
|
|
fields, |
|
|
|
|
data, |
|
|
|
@ -114,16 +165,48 @@ const { selectCell, selectBlock, selectedRange, clearRangeRows, startSelectRange
|
|
|
|
|
isPkAvail, |
|
|
|
|
clearCell, |
|
|
|
|
makeEditable, |
|
|
|
|
() => { |
|
|
|
|
if (selected.row !== null && selected.col !== null) { |
|
|
|
|
(row?: number | null, col?: number | null) => { |
|
|
|
|
row = row ?? selected.row |
|
|
|
|
col = col ?? selected.col |
|
|
|
|
if (row !== undefined && col !== undefined && row !== null && col !== null) { |
|
|
|
|
// get active cell |
|
|
|
|
const td = tbodyEl.value?.querySelectorAll('tr')[selected.row]?.querySelectorAll('td')[selected.col + 1] |
|
|
|
|
if (!td) return |
|
|
|
|
const rows = tbodyEl.value?.querySelectorAll('tr') |
|
|
|
|
const cols = rows?.[row].querySelectorAll('td') |
|
|
|
|
const td = cols?.[col === 0 ? 0 : col + 1] |
|
|
|
|
|
|
|
|
|
if (!td || !gridWrapper.value) return |
|
|
|
|
|
|
|
|
|
const { height: headerHeight } = tableHead.value!.getBoundingClientRect() |
|
|
|
|
const tdScroll = getContainerScrollForElement(td, gridWrapper.value, { top: headerHeight, bottom: 9, right: 9 }) |
|
|
|
|
|
|
|
|
|
if (rows && row === rows.length - 2) { |
|
|
|
|
// if last row make 'Add New Row' visible |
|
|
|
|
gridWrapper.value.scrollTo({ |
|
|
|
|
top: gridWrapper.value.scrollHeight, |
|
|
|
|
left: |
|
|
|
|
cols && col === cols.length - 2 // if corner cell |
|
|
|
|
? gridWrapper.value.scrollWidth |
|
|
|
|
: tdScroll.left, |
|
|
|
|
behavior: 'smooth', |
|
|
|
|
}) |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (cols && col === cols.length - 2) { |
|
|
|
|
// if last column make 'Add New Column' visible |
|
|
|
|
gridWrapper.value.scrollTo({ |
|
|
|
|
top: tdScroll.top, |
|
|
|
|
left: gridWrapper.value.scrollWidth, |
|
|
|
|
behavior: 'smooth', |
|
|
|
|
}) |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// scroll into the active cell |
|
|
|
|
td.scrollIntoView({ |
|
|
|
|
gridWrapper.value.scrollTo({ |
|
|
|
|
top: tdScroll.top, |
|
|
|
|
left: tdScroll.left, |
|
|
|
|
behavior: 'smooth', |
|
|
|
|
block: 'nearest', |
|
|
|
|
inline: 'nearest', |
|
|
|
|
}) |
|
|
|
|
} |
|
|
|
|
}, |
|
|
|
@ -381,7 +464,7 @@ watch(
|
|
|
|
|
</div> |
|
|
|
|
</general-overlay> |
|
|
|
|
|
|
|
|
|
<div class="nc-grid-wrapper min-h-0 flex-1 scrollbar-thin-dull"> |
|
|
|
|
<div ref="gridWrapper" class="nc-grid-wrapper min-h-0 flex-1 scrollbar-thin-dull"> |
|
|
|
|
<a-dropdown |
|
|
|
|
v-model:visible="contextMenu" |
|
|
|
|
:trigger="isSqlView ? [] : ['contextmenu']" |
|
|
|
@ -392,7 +475,7 @@ watch(
|
|
|
|
|
class="xc-row-table nc-grid backgroundColorDefault !h-auto bg-white" |
|
|
|
|
@contextmenu="showContextMenu" |
|
|
|
|
> |
|
|
|
|
<thead> |
|
|
|
|
<thead ref="tableHead"> |
|
|
|
|
<tr class="nc-grid-header border-1 bg-gray-100 sticky top[-1px]"> |
|
|
|
|
<th> |
|
|
|
|
<div class="w-full h-full bg-gray-100 flex min-w-[70px] pl-5 pr-1 items-center"> |
|
|
|
|