mirror of
https://github.com/gpxstudio/gpx.studio.git
synced 2025-12-02 10:02:12 +00:00
sortable file list, to be fixed
This commit is contained in:
@@ -53,6 +53,12 @@
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$effect(() => {
|
||||||
|
if (sortable) {
|
||||||
|
sortable.updateElements();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
onDestroy(() => {
|
onDestroy(() => {
|
||||||
sortable.destroy();
|
sortable.destroy();
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { isMac } from '$lib/utils';
|
import { isMac } from '$lib/utils';
|
||||||
import Sortable, { type Direction } from 'sortablejs';
|
import Sortable, { type Direction } from 'sortablejs/Sortable';
|
||||||
import { ListItem, ListLevel, ListRootItem } from './file-list';
|
import { ListItem, ListLevel, ListRootItem } from './file-list';
|
||||||
import { selection } from '$lib/logic/selection';
|
import { selection } from '$lib/logic/selection';
|
||||||
import { getFileIds, moveItems } from '$lib/logic/file-actions';
|
import { getFileIds, moveItems } from '$lib/logic/file-actions';
|
||||||
@@ -41,6 +41,7 @@ export class SortableFileList {
|
|||||||
private _container: HTMLElement;
|
private _container: HTMLElement;
|
||||||
private _sortable: Sortable | null = null;
|
private _sortable: Sortable | null = null;
|
||||||
private _elements: { [id: string]: HTMLElement } = {};
|
private _elements: { [id: string]: HTMLElement } = {};
|
||||||
|
private _updatingSelection: boolean = false;
|
||||||
private _unsubscribes: (() => void)[] = [];
|
private _unsubscribes: (() => void)[] = [];
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@@ -70,75 +71,13 @@ export class SortableFileList {
|
|||||||
multiDrag: true,
|
multiDrag: true,
|
||||||
multiDragKey: isMac() ? 'Meta' : 'Ctrl',
|
multiDragKey: isMac() ? 'Meta' : 'Ctrl',
|
||||||
avoidImplicitDeselect: true,
|
avoidImplicitDeselect: true,
|
||||||
onSelect: (e) => this.updateToSelection(e),
|
onSelect: (e: Sortable.SortableEvent) =>
|
||||||
onDeselect: (e) => this.updateToSelection(e),
|
setTimeout(() => this.updateToSelection(e), 50),
|
||||||
onStart: () => {
|
onDeselect: (e: Sortable.SortableEvent) =>
|
||||||
dragging.set(sortableLevel);
|
setTimeout(() => this.updateToSelection(e), 50),
|
||||||
},
|
onStart: () => dragging.set(sortableLevel),
|
||||||
onEnd: () => {
|
onEnd: () => dragging.set(null),
|
||||||
dragging.set(null);
|
onSort: (e: Sortable.SortableEvent) => this.onSort(e),
|
||||||
},
|
|
||||||
onSort: (e: Sortable.SortableEvent) => {
|
|
||||||
this.updateToFileOrder();
|
|
||||||
|
|
||||||
const from = Sortable.get(e.from);
|
|
||||||
const to = Sortable.get(e.to);
|
|
||||||
|
|
||||||
if (!from || !to) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let fromItem = from._item;
|
|
||||||
let toItem = to._item;
|
|
||||||
|
|
||||||
console.log('onSort', e);
|
|
||||||
|
|
||||||
if (item === toItem && !(fromItem instanceof ListRootItem)) {
|
|
||||||
// Event is triggered on source and destination list, only handle it once
|
|
||||||
let fromItems = [];
|
|
||||||
let toItems = [];
|
|
||||||
|
|
||||||
if (from._waypointRoot) {
|
|
||||||
fromItems = [fromItem.extend('waypoints')];
|
|
||||||
} else {
|
|
||||||
let oldIndices: number[] =
|
|
||||||
e.oldIndicies.length > 0
|
|
||||||
? e.oldIndicies.map((i) => i.index)
|
|
||||||
: [e.oldIndex];
|
|
||||||
oldIndices = oldIndices.filter((i) => i >= 0);
|
|
||||||
oldIndices.sort((a, b) => a - b);
|
|
||||||
|
|
||||||
fromItems = oldIndices.map((i) => fromItem.extend(i));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (from._waypointRoot && to._waypointRoot) {
|
|
||||||
toItems = [toItem.extend('waypoints')];
|
|
||||||
} else {
|
|
||||||
if (to._waypointRoot) {
|
|
||||||
toItem = toItem.extend('waypoints');
|
|
||||||
}
|
|
||||||
|
|
||||||
let newIndices: number[] =
|
|
||||||
e.newIndicies.length > 0
|
|
||||||
? e.newIndicies.map((i) => i.index)
|
|
||||||
: [e.newIndex];
|
|
||||||
newIndices = newIndices.filter((i) => i >= 0);
|
|
||||||
newIndices.sort((a, b) => a - b);
|
|
||||||
|
|
||||||
if (toItem instanceof ListRootItem) {
|
|
||||||
let newFileIds = getFileIds(newIndices.length);
|
|
||||||
toItems = newIndices.map((i, index) => {
|
|
||||||
get(fileOrder).splice(i, 0, newFileIds[index]);
|
|
||||||
return item.extend(newFileIds[index]);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
toItems = newIndices.map((i) => toItem.extend(i));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
moveItems(fromItem, toItem, fromItems, toItems);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
Object.defineProperty(this._sortable, '_item', {
|
Object.defineProperty(this._sortable, '_item', {
|
||||||
value: item,
|
value: item,
|
||||||
@@ -154,43 +93,67 @@ export class SortableFileList {
|
|||||||
this._unsubscribes.push(fileOrder.subscribe(() => this.updateFromFileOrder()));
|
this._unsubscribes.push(fileOrder.subscribe(() => this.updateFromFileOrder()));
|
||||||
}
|
}
|
||||||
|
|
||||||
updateToSelection(e: Sortable.SortableEvent) {
|
onSort(e: Sortable.SortableEvent) {
|
||||||
console.log('updateToSelection', e);
|
this.updateToFileOrder();
|
||||||
|
|
||||||
let changed = this.getChangedIds();
|
const from = Sortable.get(e.from);
|
||||||
if (changed.length > 0) {
|
const to = Sortable.get(e.to);
|
||||||
selection.update(($selection) => {
|
|
||||||
$selection.clear();
|
|
||||||
Object.entries(this._elements).forEach(([id, element]) => {
|
|
||||||
$selection.set(
|
|
||||||
this._item.extend(this.getRealId(id)),
|
|
||||||
element.classList.contains('sortable-selected')
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
if (
|
if (!from || !to) {
|
||||||
e.originalEvent &&
|
return;
|
||||||
!(
|
}
|
||||||
e.originalEvent.ctrlKey ||
|
|
||||||
e.originalEvent.metaKey ||
|
let fromItem = from._item;
|
||||||
e.originalEvent.shiftKey
|
let toItem = to._item;
|
||||||
) &&
|
|
||||||
($selection.size > 1 ||
|
if (this._item === toItem && !(fromItem instanceof ListRootItem)) {
|
||||||
!$selection.has(this._item.extend(this.getRealId(changed[0]))))
|
// Event is triggered on source and destination list, only handle it once
|
||||||
) {
|
let fromItems = [];
|
||||||
// Fix bug that sometimes causes a single select to be treated as a multi-select
|
let toItems = [];
|
||||||
$selection.clear();
|
|
||||||
$selection.set(this._item.extend(this.getRealId(changed[0])), true);
|
if (from._waypointRoot) {
|
||||||
|
fromItems = [fromItem.extend('waypoints')];
|
||||||
|
} else {
|
||||||
|
let oldIndices: number[] =
|
||||||
|
e.oldIndicies.length > 0 ? e.oldIndicies.map((i) => i.index) : [e.oldIndex];
|
||||||
|
oldIndices = oldIndices.filter((i) => i >= 0);
|
||||||
|
oldIndices.sort((a, b) => a - b);
|
||||||
|
|
||||||
|
fromItems = oldIndices.map((i) => fromItem.extend(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (from._waypointRoot && to._waypointRoot) {
|
||||||
|
toItems = [toItem.extend('waypoints')];
|
||||||
|
} else {
|
||||||
|
if (to._waypointRoot) {
|
||||||
|
toItem = toItem.extend('waypoints');
|
||||||
}
|
}
|
||||||
|
|
||||||
return $selection;
|
let newIndices: number[] =
|
||||||
});
|
e.newIndicies.length > 0 ? e.newIndicies.map((i) => i.index) : [e.newIndex];
|
||||||
|
newIndices = newIndices.filter((i) => i >= 0);
|
||||||
|
newIndices.sort((a, b) => a - b);
|
||||||
|
|
||||||
|
if (toItem instanceof ListRootItem) {
|
||||||
|
let newFileIds = getFileIds(newIndices.length);
|
||||||
|
toItems = newIndices.map((i, index) => {
|
||||||
|
get(fileOrder).splice(i, 0, newFileIds[index]);
|
||||||
|
return this._item.extend(newFileIds[index]);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
toItems = newIndices.map((i) => toItem.extend(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
moveItems(fromItem, toItem, fromItems, toItems);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
updateFromSelection() {
|
updateFromSelection() {
|
||||||
console.log('updateFromSelection');
|
const changed = this.getChangedIds();
|
||||||
let changed = this.getChangedIds();
|
if (changed.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
const selection_ = get(selection);
|
const selection_ = get(selection);
|
||||||
for (let id of changed) {
|
for (let id of changed) {
|
||||||
let element = this._elements[id];
|
let element = this._elements[id];
|
||||||
@@ -208,11 +171,45 @@ export class SortableFileList {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updateToSelection(e: Sortable.SortableEvent) {
|
||||||
|
if (this._updatingSelection) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this._updatingSelection = true;
|
||||||
|
const changed = this.getChangedIds();
|
||||||
|
if (changed.length == 0) {
|
||||||
|
this._updatingSelection = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
selection.update(($selection) => {
|
||||||
|
$selection.clear();
|
||||||
|
Object.entries(this._elements).forEach(([id, element]) => {
|
||||||
|
$selection.set(
|
||||||
|
this._item.extend(this.getRealId(id)),
|
||||||
|
element.classList.contains('sortable-selected')
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (
|
||||||
|
e.originalEvent &&
|
||||||
|
!(e.originalEvent.ctrlKey || e.originalEvent.metaKey || e.originalEvent.shiftKey) &&
|
||||||
|
($selection.size > 1 ||
|
||||||
|
!$selection.has(this._item.extend(this.getRealId(changed[0]))))
|
||||||
|
) {
|
||||||
|
// Fix bug that sometimes causes a single select to be treated as a multi-select
|
||||||
|
$selection.clear();
|
||||||
|
$selection.set(this._item.extend(this.getRealId(changed[0])), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $selection;
|
||||||
|
});
|
||||||
|
this._updatingSelection = false;
|
||||||
|
}
|
||||||
|
|
||||||
updateFromFileOrder() {
|
updateFromFileOrder() {
|
||||||
if (!this._sortable || this._sortableLevel !== ListLevel.FILE) {
|
if (!this._sortable || this._sortableLevel !== ListLevel.FILE) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
console.log('updateFromFileOrder');
|
|
||||||
|
|
||||||
const fileOrder_ = get(fileOrder);
|
const fileOrder_ = get(fileOrder);
|
||||||
const sortableOrder = this._sortable.toArray();
|
const sortableOrder = this._sortable.toArray();
|
||||||
@@ -229,7 +226,6 @@ export class SortableFileList {
|
|||||||
if (!this._sortable || this._sortableLevel !== ListLevel.FILE) {
|
if (!this._sortable || this._sortableLevel !== ListLevel.FILE) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
console.log('updateToFileOrder');
|
|
||||||
|
|
||||||
const fileOrder_ = get(fileOrder);
|
const fileOrder_ = get(fileOrder);
|
||||||
const sortableOrder = this._sortable.toArray();
|
const sortableOrder = this._sortable.toArray();
|
||||||
@@ -256,9 +252,6 @@ export class SortableFileList {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// syncFileOrder();
|
|
||||||
// updateFromSelection();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
destroy() {
|
destroy() {
|
||||||
|
|||||||
Reference in New Issue
Block a user