mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2025-03-02 01:30:51 +03:00
224 lines
7.0 KiB
HTML
224 lines
7.0 KiB
HTML
{{define "component/sortableTableTrigger"}}
|
|
<a-icon type="drag"
|
|
class="sortable-icon"
|
|
style="cursor: move;"
|
|
@mouseup="mouseUpHandler"
|
|
@mousedown="mouseDownHandler"
|
|
@click="clickHandler" />
|
|
{{end}}
|
|
|
|
{{define "component/sortableTable"}}
|
|
<script>
|
|
const DRAGGABLE_ROW_CLASS = 'draggable-row';
|
|
|
|
const findParentRowElement = (el) => {
|
|
if (!el || !el.tagName) {
|
|
return null;
|
|
} else if (el.classList.contains(DRAGGABLE_ROW_CLASS)) {
|
|
return el;
|
|
} else if (el.parentNode) {
|
|
return findParentRowElement(el.parentNode);
|
|
} else {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
Vue.component('a-table-sortable', {
|
|
data() {
|
|
return {
|
|
sortingElementIndex: null,
|
|
newElementIndex: null,
|
|
};
|
|
},
|
|
props: ['data-source', 'customRow'],
|
|
inheritAttrs: false,
|
|
provide() {
|
|
const sortable = {}
|
|
|
|
Object.defineProperty(sortable, "setSortableIndex", {
|
|
enumerable: true,
|
|
get: () => this.setCurrentSortableIndex,
|
|
});
|
|
|
|
Object.defineProperty(sortable, "resetSortableIndex", {
|
|
enumerable: true,
|
|
get: () => this.resetSortableIndex,
|
|
});
|
|
|
|
return {
|
|
sortable,
|
|
}
|
|
},
|
|
render: function (createElement) {
|
|
return createElement(
|
|
'a-table',
|
|
{
|
|
class: {
|
|
'ant-table-is-sorting': this.isDragging(),
|
|
},
|
|
props: {
|
|
...this.$attrs,
|
|
'data-source': this.records,
|
|
customRow: (record, index) => this.customRowRender(record, index),
|
|
},
|
|
on: this.$listeners,
|
|
nativeOn: {
|
|
drop: (e) => this.dropHandler(e),
|
|
},
|
|
scopedSlots: this.$scopedSlots,
|
|
},
|
|
this.$slots.default,
|
|
)
|
|
},
|
|
created() {
|
|
this.$memoSort = {};
|
|
},
|
|
methods: {
|
|
isDragging() {
|
|
const currentIndex = this.sortingElementIndex;
|
|
return currentIndex !== null && currentIndex !== undefined;
|
|
},
|
|
resetSortableIndex(e, index) {
|
|
this.sortingElementIndex = null;
|
|
this.newElementIndex = null;
|
|
this.$memoSort = {};
|
|
},
|
|
setCurrentSortableIndex(e, index) {
|
|
this.sortingElementIndex = index;
|
|
},
|
|
dragStartHandler(e, index) {
|
|
if (!this.isDragging()) {
|
|
e.preventDefault();
|
|
return;
|
|
}
|
|
},
|
|
dragStopHandler(e, index) {
|
|
this.resetSortableIndex(e, index);
|
|
},
|
|
dragOverHandler(e, index) {
|
|
if (!this.isDragging()) {
|
|
return;
|
|
}
|
|
|
|
e.preventDefault();
|
|
|
|
const currentIndex = this.sortingElementIndex;
|
|
if (index === currentIndex) {
|
|
this.newElementIndex = null;
|
|
return;
|
|
}
|
|
|
|
const row = findParentRowElement(e.target);
|
|
if (!row) {
|
|
return;
|
|
}
|
|
|
|
const rect = row.getBoundingClientRect();
|
|
const offsetTop = e.pageY - rect.top;
|
|
|
|
if (offsetTop < rect.height / 2) {
|
|
this.newElementIndex = Math.max(index - 1, 0);
|
|
} else {
|
|
this.newElementIndex = index;
|
|
}
|
|
},
|
|
dropHandler(e) {
|
|
if (this.isDragging()) {
|
|
this.$emit('onsort', this.sortingElementIndex, this.newElementIndex);
|
|
}
|
|
},
|
|
customRowRender(record, index) {
|
|
const parentMethodResult = this.customRow?.(record, index) || {};
|
|
const newIndex = this.newElementIndex;
|
|
const currentIndex = this.sortingElementIndex;
|
|
|
|
return {
|
|
...parentMethodResult,
|
|
attrs: {
|
|
...(parentMethodResult?.attrs || {}),
|
|
draggable: true,
|
|
},
|
|
on: {
|
|
...(parentMethodResult?.on || {}),
|
|
dragstart: (e) => this.dragStartHandler(e, index),
|
|
dragend: (e) => this.dragStopHandler(e, index),
|
|
dragover: (e) => this.dragOverHandler(e, index),
|
|
},
|
|
class: {
|
|
...(parentMethodResult?.class || {}),
|
|
[DRAGGABLE_ROW_CLASS]: true,
|
|
['dragging']: this.isDragging()
|
|
? (newIndex === null ? index === currentIndex : index === newIndex)
|
|
: false,
|
|
},
|
|
};
|
|
}
|
|
},
|
|
computed: {
|
|
records() {
|
|
const newIndex = this.newElementIndex;
|
|
const currentIndex = this.sortingElementIndex;
|
|
|
|
if (!this.isDragging() || newIndex === null || currentIndex === newIndex) {
|
|
return this.dataSource;
|
|
}
|
|
|
|
if (this.$memoSort.newIndex === newIndex) {
|
|
return this.$memoSort.list;
|
|
}
|
|
|
|
let list = [...this.dataSource];
|
|
list.splice(newIndex, 0, list.splice(currentIndex, 1)[0]);
|
|
|
|
this.$memoSort = {
|
|
newIndex,
|
|
list,
|
|
};
|
|
|
|
return list;
|
|
}
|
|
}
|
|
});
|
|
|
|
Vue.component('table-sort-trigger', {
|
|
template: `{{template "component/sortableTableTrigger"}}`,
|
|
props: ['item-index'],
|
|
inject: ['sortable'],
|
|
methods: {
|
|
mouseDownHandler(e) {
|
|
if (this.sortable) {
|
|
this.sortable.setSortableIndex(e, this.itemIndex);
|
|
}
|
|
},
|
|
mouseUpHandler(e) {
|
|
if (this.sortable) {
|
|
this.sortable.resetSortableIndex(e, this.itemIndex);
|
|
}
|
|
},
|
|
clickHandler(e) {
|
|
e.preventDefault();
|
|
},
|
|
}
|
|
})
|
|
</script>
|
|
|
|
<style>
|
|
@media only screen and (max-width: 767px) {
|
|
.sortable-icon {
|
|
display: none;
|
|
}
|
|
}
|
|
.ant-table-is-sorting .draggable-row td {
|
|
background-color: white !important;
|
|
}
|
|
.dark .ant-table-is-sorting .draggable-row td {
|
|
background-color: var(--dark-color-surface-100) !important;
|
|
}
|
|
.ant-table-is-sorting .dragging {
|
|
opacity: 0.5;
|
|
}
|
|
.ant-table-is-sorting .dragging .ant-table-row-index {
|
|
opacity: 0;
|
|
}
|
|
</style>
|
|
{{end}} |