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(() => {
|
||||
sortable.destroy();
|
||||
});
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
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 { selection } from '$lib/logic/selection';
|
||||
import { getFileIds, moveItems } from '$lib/logic/file-actions';
|
||||
@@ -41,6 +41,7 @@ export class SortableFileList {
|
||||
private _container: HTMLElement;
|
||||
private _sortable: Sortable | null = null;
|
||||
private _elements: { [id: string]: HTMLElement } = {};
|
||||
private _updatingSelection: boolean = false;
|
||||
private _unsubscribes: (() => void)[] = [];
|
||||
|
||||
constructor(
|
||||
@@ -70,75 +71,13 @@ export class SortableFileList {
|
||||
multiDrag: true,
|
||||
multiDragKey: isMac() ? 'Meta' : 'Ctrl',
|
||||
avoidImplicitDeselect: true,
|
||||
onSelect: (e) => this.updateToSelection(e),
|
||||
onDeselect: (e) => this.updateToSelection(e),
|
||||
onStart: () => {
|
||||
dragging.set(sortableLevel);
|
||||
},
|
||||
onEnd: () => {
|
||||
dragging.set(null);
|
||||
},
|
||||
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);
|
||||
}
|
||||
},
|
||||
onSelect: (e: Sortable.SortableEvent) =>
|
||||
setTimeout(() => this.updateToSelection(e), 50),
|
||||
onDeselect: (e: Sortable.SortableEvent) =>
|
||||
setTimeout(() => this.updateToSelection(e), 50),
|
||||
onStart: () => dragging.set(sortableLevel),
|
||||
onEnd: () => dragging.set(null),
|
||||
onSort: (e: Sortable.SortableEvent) => this.onSort(e),
|
||||
});
|
||||
Object.defineProperty(this._sortable, '_item', {
|
||||
value: item,
|
||||
@@ -154,43 +93,67 @@ export class SortableFileList {
|
||||
this._unsubscribes.push(fileOrder.subscribe(() => this.updateFromFileOrder()));
|
||||
}
|
||||
|
||||
updateToSelection(e: Sortable.SortableEvent) {
|
||||
console.log('updateToSelection', e);
|
||||
onSort(e: Sortable.SortableEvent) {
|
||||
this.updateToFileOrder();
|
||||
|
||||
let changed = this.getChangedIds();
|
||||
if (changed.length > 0) {
|
||||
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')
|
||||
);
|
||||
});
|
||||
const from = Sortable.get(e.from);
|
||||
const to = Sortable.get(e.to);
|
||||
|
||||
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);
|
||||
if (!from || !to) {
|
||||
return;
|
||||
}
|
||||
|
||||
let fromItem = from._item;
|
||||
let toItem = to._item;
|
||||
|
||||
if (this._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');
|
||||
}
|
||||
|
||||
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() {
|
||||
console.log('updateFromSelection');
|
||||
let changed = this.getChangedIds();
|
||||
const changed = this.getChangedIds();
|
||||
if (changed.length === 0) {
|
||||
return;
|
||||
}
|
||||
const selection_ = get(selection);
|
||||
for (let id of changed) {
|
||||
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() {
|
||||
if (!this._sortable || this._sortableLevel !== ListLevel.FILE) {
|
||||
return;
|
||||
}
|
||||
console.log('updateFromFileOrder');
|
||||
|
||||
const fileOrder_ = get(fileOrder);
|
||||
const sortableOrder = this._sortable.toArray();
|
||||
@@ -229,7 +226,6 @@ export class SortableFileList {
|
||||
if (!this._sortable || this._sortableLevel !== ListLevel.FILE) {
|
||||
return;
|
||||
}
|
||||
console.log('updateToFileOrder');
|
||||
|
||||
const fileOrder_ = get(fileOrder);
|
||||
const sortableOrder = this._sortable.toArray();
|
||||
@@ -256,9 +252,6 @@ export class SortableFileList {
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// syncFileOrder();
|
||||
// updateFromSelection();
|
||||
}
|
||||
|
||||
destroy() {
|
||||
|
||||
Reference in New Issue
Block a user