Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/MHSanaei/3x-ui.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'web/html/component/aTableSortable.html')
-rw-r--r--web/html/component/aTableSortable.html232
1 files changed, 232 insertions, 0 deletions
diff --git a/web/html/component/aTableSortable.html b/web/html/component/aTableSortable.html
new file mode 100644
index 00000000..443ac50c
--- /dev/null
+++ b/web/html/component/aTableSortable.html
@@ -0,0 +1,232 @@
+{{define "component/sortableTableTrigger"}}
+<a-icon type="drag" class="sortable-icon" :style="{ cursor: 'move' }" @mouseup="mouseUpHandler" @mousedown="mouseDownHandler"
+ @click="clickHandler" />
+{{end}}
+
+{{define "component/aTableSortable"}}
+<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': {
+ type: undefined,
+ required: false,
+ },
+ 'customRow': {
+ type: undefined,
+ required: false,
+ }
+ },
+ 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;
+ }
+ const hideDragImage = this.$el.cloneNode(true);
+ hideDragImage.id = "hideDragImage-hide";
+ hideDragImage.style.opacity = 0;
+ e.dataTransfer.setDragImage(hideDragImage, 0, 0);
+ },
+ dragStopHandler(e, index) {
+ const hideDragImage = document.getElementById('hideDragImage-hide');
+ if (hideDragImage) hideDragImage.remove();
+ 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('a-table-sort-trigger', {
+ template: `{{template "component/sortableTableTrigger"}}`,
+ props: {
+ 'item-index': {
+ type: undefined,
+ required: false
+ }
+ },
+ 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: #ffffff !important;
+ }
+
+ .dark .ant-table-is-sorting .draggable-row td {
+ background-color: var(--dark-color-surface-100) !important;
+ }
+
+ .ant-table-is-sorting .dragging td {
+ background-color: rgb(232 244 242) !important;
+ color: rgba(0, 0, 0, 0.3);
+ }
+
+ .dark .ant-table-is-sorting .dragging td {
+ background-color: var(--dark-color-table-hover) !important;
+ color: rgba(255, 255, 255, 0.3);
+ }
+
+ .ant-table-is-sorting .dragging {
+ opacity: 1;
+ box-shadow: 1px -2px 2px #008771;
+ transition: all 0.2s;
+ }
+
+ .ant-table-is-sorting .dragging .ant-table-row-index {
+ opacity: 0.3;
+ }
+</style>
+{{end}} \ No newline at end of file