+
@@ -32,10 +42,6 @@ export default {
required: false,
default: 0,
},
- containerWidth: {
- type: Number,
- required: true,
- },
readOnly: {
type: Boolean,
required: true,
@@ -44,6 +50,16 @@ export default {
type: Function,
required: true,
},
+ getScrollableElement: {
+ type: Function,
+ required: false,
+ default: null,
+ },
+ frozenSectionWidth: {
+ type: Number,
+ required: false,
+ default: 0,
+ },
},
emits: ['scroll'],
data() {
@@ -62,12 +78,17 @@ export default {
mouseStartY: 0,
// The horizontal scrollbar offset starting position.
scrollStart: 0,
+ // The visual left position of the field at drag start (in grid coords).
+ initialVisualLeft: 0,
// The width of the dragging animation, this is equal to the width of the field.
draggingWidth: 0,
// The position of the dragging animation.
draggingLeft: 0,
// The position of the target indicator where the field is going to be moved to.
targetLeft: 0,
+ // The left offset of the clipping container. When scrolled, clips the frozen
+ // area so scrolled-out positions aren't visible behind frozen fields.
+ clipOffset: 0,
// The mouse move event.
lastMoveEvent: null,
// Indicates if the user is auto scrolling at the moment.
@@ -83,6 +104,20 @@ export default {
this.cancel()
},
methods: {
+ _getScrollableElement() {
+ return this.getScrollableElement
+ ? this.getScrollableElement()
+ : this.getScrollElement()
+ },
+ _contentToVisual(contentPos) {
+ if (
+ this.frozenSectionWidth > 0 &&
+ contentPos >= this.frozenSectionWidth
+ ) {
+ return contentPos - this._getScrollableElement().scrollLeft
+ }
+ return contentPos
+ },
getFieldLeft(id) {
let left = 0
for (let i = 0; i < this.fields.length; i++) {
@@ -105,7 +140,10 @@ export default {
this.moved = false
this.mouseStartX = event.clientX
this.mouseStartY = event.clientY
- this.scrollStart = this.getScrollElement().scrollLeft
+ const scrollable = this._getScrollableElement()
+ this.scrollStart = scrollable.scrollLeft
+ const contentLeft = this.offset + this.getFieldLeft(field.id)
+ this.initialVisualLeft = this._contentToVisual(contentLeft)
this.draggingLeft = 0
this.targetLeft = 0
@@ -151,31 +189,32 @@ export default {
}
}
- // This is the horizontally scrollable element.
+ // The positioning element for coordinate calculations (getBoundingClientRect).
const element = this.getScrollElement()
+ // The element that actually scrolls horizontally.
+ const scrollable = this._getScrollableElement()
this.draggingWidth = this.getFieldWidth(this.field)
+ this.clipOffset = scrollable.scrollLeft > 0 ? this.frozenSectionWidth : 0
- // Calculate the left position of the dragging animation. This is the transparent
- // overlay that has the same width as the field.
- this.draggingLeft =
- this.offset +
- Math.min(
- this.getFieldLeft(this.field.id) +
- event.clientX -
- this.mouseStartX +
- this.getScrollElement().scrollLeft -
- this.scrollStart,
- this.containerWidth - this.draggingWidth
- )
+ // The overlay is in the non-scrolling gridView container, so draggingLeft is
+ // the visual position directly. We anchor to the field's visual position at
+ // drag start and track mouse movement from there.
+ const unclampedLeft =
+ this.initialVisualLeft + event.clientX - this.mouseStartX
+ const visibleWidth = this.frozenSectionWidth + scrollable.clientWidth
+ this.draggingLeft = Math.min(
+ unclampedLeft,
+ visibleWidth - this.draggingWidth
+ )
- // Calculate which after which field we want to place the field that is currently
- // being dragged. This is named the target. We also calculate what position the
- // field would have for visualisation purposes.
+ // Calculate which field we want to place the dragged field after. mouseLeft is
+ // in content-space (accounts for scroll) so it can be compared against the
+ // cumulative field widths in the loop.
const mouseLeft =
event.clientX -
element.getBoundingClientRect().left +
- element.scrollLeft
+ scrollable.scrollLeft
let left = this.offset
for (let i = 0; i < this.fields.length; i++) {
const width = this.getFieldWidth(this.fields[i])
@@ -189,12 +228,12 @@ export default {
this.targetFieldId = 0
// The value 1 makes sure it is visible instead of falling outside of the
// view port.
- this.targetLeft = Math.max(this.offset, 1)
+ this.targetLeft = Math.max(this._contentToVisual(this.offset), 1)
break
}
if (mouseLeft > leftHalf && mouseLeft < rightHalf) {
this.targetFieldId = this.fields[i].id
- this.targetLeft = left + width
+ this.targetLeft = this._contentToVisual(left + width)
break
}
left += width
@@ -204,23 +243,27 @@ export default {
// moving the element outside of the view port at the left or right side, we
// might need to initiate that process.
if (!this.autoScrolling || !startAutoScroll) {
- const relativeLeft = this.draggingLeft - element.scrollLeft
- const relativeRight = relativeLeft + this.getFieldWidth(this.field)
- const maxScrollLeft = element.scrollWidth - element.clientWidth
+ const maxScrollLeft = scrollable.scrollWidth - scrollable.clientWidth
let speed = 0
- if (relativeLeft < 0 && element.scrollLeft > 0) {
- // If the dragging animation falls out of the left side of the viewport we
- // need to auto scroll to the left.
- speed = -Math.ceil(Math.min(Math.abs(relativeLeft), 100) / 20)
+ if (
+ unclampedLeft < this.frozenSectionWidth &&
+ scrollable.scrollLeft > 0
+ ) {
+ // If the dragging animation enters the frozen area, auto scroll left.
+ speed = -Math.ceil(
+ Math.min(Math.abs(unclampedLeft - this.frozenSectionWidth), 100) /
+ 20
+ )
} else if (
- relativeRight > element.clientWidth &&
- element.scrollLeft < maxScrollLeft
+ unclampedLeft + this.draggingWidth > visibleWidth &&
+ scrollable.scrollLeft < maxScrollLeft
) {
// If the dragging animation falls out of the right side of the viewport we
// need to auto scroll to the right.
speed = Math.ceil(
- Math.min(relativeRight - element.clientWidth, 100) / 20
+ Math.min(unclampedLeft + this.draggingWidth - visibleWidth, 100) /
+ 20
)
}
diff --git a/web-frontend/modules/database/components/view/grid/GridViewFieldType.vue b/web-frontend/modules/database/components/view/grid/GridViewFieldType.vue
index 1d6afd8cbe..664e5cf73f 100644
--- a/web-frontend/modules/database/components/view/grid/GridViewFieldType.vue
+++ b/web-frontend/modules/database/components/view/grid/GridViewFieldType.vue
@@ -282,7 +282,6 @@
+
+
+
+
+ {{ dragging ? tooltipText : $t('gridViewFreezeHandle.hoverHint') }}
+
+
+
+
+
diff --git a/web-frontend/modules/database/components/view/grid/GridViewHead.vue b/web-frontend/modules/database/components/view/grid/GridViewHead.vue
index dd97c04ee2..3d41701812 100644
--- a/web-frontend/modules/database/components/view/grid/GridViewHead.vue
+++ b/web-frontend/modules/database/components/view/grid/GridViewHead.vue
@@ -40,7 +40,6 @@
:field="field"
:all-fields-in-table="allFieldsInTable"
:filters="view.filters"
- :include-field-width-handles="includeFieldWidthHandles"
:read-only="readOnly"
:store-prefix="storePrefix"
@refresh="$emit('refresh', $event)"
@@ -120,11 +119,6 @@ export default {
type: Array,
required: true,
},
- includeFieldWidthHandles: {
- type: Boolean,
- required: false,
- default: () => false,
- },
includeRowDetails: {
type: Boolean,
required: false,
diff --git a/web-frontend/modules/database/components/view/grid/GridViewRow.vue b/web-frontend/modules/database/components/view/grid/GridViewRow.vue
index 12aa3d8c73..e2c32f4144 100644
--- a/web-frontend/modules/database/components/view/grid/GridViewRow.vue
+++ b/web-frontend/modules/database/components/view/grid/GridViewRow.vue
@@ -194,6 +194,10 @@ export default {
type: Array,
required: true,
},
+ allVisibleFields: {
+ type: Array,
+ required: true,
+ },
allFieldsInTable: {
type: Array,
required: true,
@@ -229,11 +233,6 @@ export default {
type: Number,
required: true,
},
- primaryFieldIsSticky: {
- type: Boolean,
- required: false,
- default: () => true,
- },
},
emits: [
'update',
@@ -392,9 +391,9 @@ export default {
rowId
)
- const allFieldIds = this.visibleFields.map((field) => field.id)
- let fieldIndex = allFieldIds.findIndex((id) => field.id === id)
- fieldIndex += !field.primary && this.primaryFieldIsSticky ? 1 : 0
+ const fieldIndex = this.allVisibleFields.findIndex(
+ (f) => f.id === field.id
+ )
const [minRow, maxRow] =
this.$store.getters[
diff --git a/web-frontend/modules/database/components/view/grid/GridViewRows.vue b/web-frontend/modules/database/components/view/grid/GridViewRows.vue
index 11cd07ef8e..7c043b6e27 100644
--- a/web-frontend/modules/database/components/view/grid/GridViewRows.vue
+++ b/web-frontend/modules/database/components/view/grid/GridViewRows.vue
@@ -15,8 +15,8 @@
:row="row"
:rendered-fields="renderedFields"
:visible-fields="visibleFields"
+ :all-visible-fields="allVisibleFields"
:all-fields-in-table="allFieldsInTable"
- :primary-field-is-sticky="primaryFieldIsSticky"
:field-widths="fieldWidths"
:include-row-details="includeRowDetails"
:include-group-by="includeGroupBy"
@@ -77,6 +77,10 @@ export default {
type: Array,
required: true,
},
+ allVisibleFields: {
+ type: Array,
+ required: true,
+ },
/**
* All the fields in the table, regardless of the visibility, or whether they
* should be rendered.
@@ -116,11 +120,6 @@ export default {
type: Number,
required: true,
},
- primaryFieldIsSticky: {
- type: Boolean,
- required: false,
- default: () => true,
- },
rowsAtEndOfGroups: {
type: Set,
required: true,
diff --git a/web-frontend/modules/database/components/view/grid/GridViewSection.vue b/web-frontend/modules/database/components/view/grid/GridViewSection.vue
index 3ee6d8a7bb..fcdc8e08e6 100644
--- a/web-frontend/modules/database/components/view/grid/GridViewSection.vue
+++ b/web-frontend/modules/database/components/view/grid/GridViewSection.vue
@@ -35,7 +35,6 @@
:view="view"
:all-fields-in-table="allFieldsInTable"
:visible-fields="visibleFields"
- :include-field-width-handles="includeFieldWidthHandles"
:include-row-details="includeRowDetails"
:include-add-field="includeAddField"
:include-grid-view-identifier-dropdown="
@@ -46,11 +45,7 @@
:store-prefix="storePrefix"
@field-created="$emit('field-created', $event)"
@refresh="$emit('refresh', $event)"
- @dragging="
- canOrderFields &&
- !$event.field.primary &&
- $refs.fieldDragging.start($event.field, $event.event)
- "
+ @dragging="handleFieldDragging($event)"
>
-