mirror of
https://github.com/gpxstudio/gpx.studio.git
synced 2025-09-02 16:52:31 +00:00
delete any selection
This commit is contained in:
@@ -80,6 +80,10 @@ export class SelectionTreeType {
|
|||||||
return this.children[id];
|
return this.children[id];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
deleteChild(id: string | number) {
|
||||||
|
delete this.children[id];
|
||||||
|
}
|
||||||
|
|
||||||
get size(): number {
|
get size(): number {
|
||||||
let size = this.selected ? 1 : 0;
|
let size = this.selected ? 1 : 0;
|
||||||
for (let key in this.children) {
|
for (let key in this.children) {
|
||||||
|
@@ -127,13 +127,25 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
afterUpdate(() => {
|
afterUpdate(() => {
|
||||||
|
syncFileOrder();
|
||||||
if (sortableLevel === 'file') {
|
if (sortableLevel === 'file') {
|
||||||
syncFileOrder();
|
|
||||||
Object.keys(elements).forEach((fileId) => {
|
Object.keys(elements).forEach((fileId) => {
|
||||||
if (!get(fileObservers).has(fileId)) {
|
if (!get(fileObservers).has(fileId)) {
|
||||||
delete elements[fileId];
|
delete elements[fileId];
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
} else if (sortableLevel === 'waypoints') {
|
||||||
|
if (node.wpt.length === 0) {
|
||||||
|
delete elements['waypoints'];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Object.keys(elements).forEach((index) => {
|
||||||
|
if ((node instanceof GPXFile || node instanceof Track) && node.children.length <= index) {
|
||||||
|
delete elements[index];
|
||||||
|
} else if (Array.isArray(node) && node.length <= index) {
|
||||||
|
delete elements[index];
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
import { get, writable } from "svelte/store";
|
import { get, writable } from "svelte/store";
|
||||||
import { ListFileItem, ListItem, ListRootItem, ListTrackItem, ListTrackSegmentItem, ListWaypointItem, SelectionTreeType } from "./FileList";
|
import { ListFileItem, ListItem, ListRootItem, ListTrackItem, ListTrackSegmentItem, ListWaypointItem, SelectionTreeType, type ListLevel } from "./FileList";
|
||||||
import { fileObservers } from "$lib/db";
|
import { fileObservers, settings } from "$lib/db";
|
||||||
|
|
||||||
export const selection = writable<SelectionTreeType>(new SelectionTreeType(new ListRootItem()));
|
export const selection = writable<SelectionTreeType>(new SelectionTreeType(new ListRootItem()));
|
||||||
|
|
||||||
@@ -60,4 +60,32 @@ export function selectAll() {
|
|||||||
|
|
||||||
return $selection;
|
return $selection;
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function applyToOrderedSelectedItemsFromFile(callback: (fileId: string, level: ListLevel | undefined, items: ListItem[]) => void) {
|
||||||
|
get(settings.fileOrder).forEach((fileId) => {
|
||||||
|
let level: ListLevel | undefined = undefined;
|
||||||
|
let items: ListItem[] = [];
|
||||||
|
get(selection).forEach((item) => {
|
||||||
|
if (item.getFileId() === fileId) {
|
||||||
|
level = item.level;
|
||||||
|
if (item instanceof ListTrackItem || item instanceof ListTrackSegmentItem || item instanceof ListWaypointItem) {
|
||||||
|
items.push(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
items.sort((a, b) => { // Process the items in reverse order to avoid index conflicts
|
||||||
|
if (a instanceof ListTrackItem && b instanceof ListTrackItem) {
|
||||||
|
return b.getTrackIndex() - a.getTrackIndex();
|
||||||
|
} else if (a instanceof ListTrackSegmentItem && b instanceof ListTrackSegmentItem) {
|
||||||
|
return b.getSegmentIndex() - a.getSegmentIndex();
|
||||||
|
} else if (a instanceof ListWaypointItem && b instanceof ListWaypointItem) {
|
||||||
|
return b.getWaypointIndex() - a.getWaypointIndex();
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
});
|
||||||
|
|
||||||
|
callback(fileId, level, items);
|
||||||
|
});
|
||||||
}
|
}
|
@@ -5,7 +5,7 @@ import { writable, get, derived, type Readable, type Writable } from 'svelte/sto
|
|||||||
import { initTargetMapBounds, updateTargetMapBounds } from './stores';
|
import { initTargetMapBounds, updateTargetMapBounds } from './stores';
|
||||||
import { mode } from 'mode-watcher';
|
import { mode } from 'mode-watcher';
|
||||||
import { defaultBasemap, defaultBasemapTree, defaultOverlayTree, defaultOverlays } from './assets/layers';
|
import { defaultBasemap, defaultBasemapTree, defaultOverlayTree, defaultOverlays } from './assets/layers';
|
||||||
import { selection } from '$lib/components/file-list/Selection';
|
import { applyToOrderedSelectedItemsFromFile, selection } from '$lib/components/file-list/Selection';
|
||||||
import { ListFileItem, ListItem, ListTrackItem, type ListLevel, ListTrackSegmentItem, ListWaypointItem } from '$lib/components/file-list/FileList';
|
import { ListFileItem, ListItem, ListTrackItem, type ListLevel, ListTrackSegmentItem, ListWaypointItem } from '$lib/components/file-list/FileList';
|
||||||
import { updateAnchorPoints } from '$lib/components/toolbar/tools/routing/Simplify';
|
import { updateAnchorPoints } from '$lib/components/toolbar/tools/routing/Simplify';
|
||||||
|
|
||||||
@@ -229,13 +229,12 @@ liveQuery(() => db.fileids.toArray()).subscribe(dbFileIds => {
|
|||||||
// Find deleted files to stop observing
|
// Find deleted files to stop observing
|
||||||
let deletedFiles = Array.from(get(fileObservers).keys()).filter(id => !dbFileIds.find(fileId => fileId === id));
|
let deletedFiles = Array.from(get(fileObservers).keys()).filter(id => !dbFileIds.find(fileId => fileId === id));
|
||||||
|
|
||||||
if (newFiles.length > 0) { // Reset the target map bounds when new files are added
|
|
||||||
initTargetMapBounds(fileState.size === 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update the store
|
// Update the store
|
||||||
if (newFiles.length > 0 || deletedFiles.length > 0) {
|
if (newFiles.length > 0 || deletedFiles.length > 0) {
|
||||||
fileObservers.update($files => {
|
fileObservers.update($files => {
|
||||||
|
if (newFiles.length > 0) { // Reset the target map bounds when new files are added
|
||||||
|
initTargetMapBounds($files.size === 0);
|
||||||
|
}
|
||||||
newFiles.forEach(id => {
|
newFiles.forEach(id => {
|
||||||
$files.set(id, dexieGPXFileStore(id));
|
$files.set(id, dexieGPXFileStore(id));
|
||||||
});
|
});
|
||||||
@@ -245,6 +244,14 @@ liveQuery(() => db.fileids.toArray()).subscribe(dbFileIds => {
|
|||||||
});
|
});
|
||||||
return $files;
|
return $files;
|
||||||
});
|
});
|
||||||
|
if (deletedFiles.length > 0) {
|
||||||
|
selection.update(($selection) => {
|
||||||
|
deletedFiles.forEach((fileId) => {
|
||||||
|
$selection.deleteChild(fileId);
|
||||||
|
});
|
||||||
|
return $selection;
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -357,45 +364,19 @@ export const dbUtils = {
|
|||||||
applyToFiles(get(selection).forEach(fileId), callback);
|
applyToFiles(get(selection).forEach(fileId), callback);
|
||||||
},
|
},
|
||||||
duplicateSelection: () => {
|
duplicateSelection: () => {
|
||||||
|
if (get(selection).size === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
applyGlobal((draft) => {
|
applyGlobal((draft) => {
|
||||||
let ids = getFileIds(get(settings.fileOrder).length);
|
let ids = getFileIds(get(settings.fileOrder).length);
|
||||||
get(settings.fileOrder).forEach((fileId, index) => {
|
let index = 0;
|
||||||
|
applyToOrderedSelectedItemsFromFile((fileId, level, items) => {
|
||||||
let file = original(draft)?.get(fileId);
|
let file = original(draft)?.get(fileId);
|
||||||
if (file) {
|
if (file) {
|
||||||
let level: ListLevel | undefined = undefined;
|
|
||||||
let items: ListItem[] = [];
|
|
||||||
get(selection).forEach((item) => {
|
|
||||||
if (item.getFileId() === fileId) {
|
|
||||||
if (item instanceof ListFileItem) {
|
|
||||||
level = 'file';
|
|
||||||
} else if (item instanceof ListTrackItem) {
|
|
||||||
level = 'track';
|
|
||||||
items.push(item);
|
|
||||||
} else if (item instanceof ListTrackSegmentItem) {
|
|
||||||
level = 'segment';
|
|
||||||
items.push(item);
|
|
||||||
} else if (item instanceof ListWaypointItem) {
|
|
||||||
level = 'waypoint';
|
|
||||||
items.push(item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
items.sort((a, b) => { // Process the items in reverse order to avoid index conflicts
|
|
||||||
if (a instanceof ListTrackItem && b instanceof ListTrackItem) {
|
|
||||||
return b.getTrackIndex() - a.getTrackIndex();
|
|
||||||
} else if (a instanceof ListTrackSegmentItem && b instanceof ListTrackSegmentItem) {
|
|
||||||
return b.getSegmentIndex() - a.getSegmentIndex();
|
|
||||||
} else if (a instanceof ListWaypointItem && b instanceof ListWaypointItem) {
|
|
||||||
return b.getWaypointIndex() - a.getWaypointIndex();
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
});
|
|
||||||
|
|
||||||
let newFile = file;
|
let newFile = file;
|
||||||
if (level === 'file') {
|
if (level === 'file') {
|
||||||
newFile = file.clone();
|
newFile = file.clone();
|
||||||
newFile._data.id = ids[index];
|
newFile._data.id = ids[index++];
|
||||||
} else if (level === 'track') {
|
} else if (level === 'track') {
|
||||||
for (let item of items) {
|
for (let item of items) {
|
||||||
let trackIndex = (item as ListTrackItem).getTrackIndex();
|
let trackIndex = (item as ListTrackItem).getTrackIndex();
|
||||||
@@ -413,22 +394,45 @@ export const dbUtils = {
|
|||||||
newFile = newFile.replaceWaypoints(waypointIndex + 1, waypointIndex, [file.wpt[waypointIndex].clone()]);
|
newFile = newFile.replaceWaypoints(waypointIndex + 1, waypointIndex, [file.wpt[waypointIndex].clone()]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
draft.set(fileId, freeze(newFile));
|
draft.set(newFile._data.id, freeze(newFile));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
deleteSelection: () => {
|
deleteSelection: () => {
|
||||||
|
if (get(selection).size === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
applyGlobal((draft) => {
|
applyGlobal((draft) => {
|
||||||
selection.update(($selection) => {
|
applyToOrderedSelectedItemsFromFile((fileId, level, items) => {
|
||||||
$selection.forEach((item) => {
|
if (level === 'file') {
|
||||||
if (item instanceof ListFileItem) {
|
draft.delete(fileId);
|
||||||
draft.delete(item.getId());
|
} else {
|
||||||
|
let file = original(draft)?.get(fileId);
|
||||||
|
if (file) {
|
||||||
|
let newFile = file;
|
||||||
|
if (level === 'track') {
|
||||||
|
for (let item of items) {
|
||||||
|
let trackIndex = (item as ListTrackItem).getTrackIndex();
|
||||||
|
newFile = newFile.replaceTracks(trackIndex, trackIndex, []);
|
||||||
|
}
|
||||||
|
} else if (level === 'segment') {
|
||||||
|
for (let item of items) {
|
||||||
|
let trackIndex = (item as ListTrackSegmentItem).getTrackIndex();
|
||||||
|
let segmentIndex = (item as ListTrackSegmentItem).getSegmentIndex();
|
||||||
|
newFile = newFile.replaceTrackSegments(trackIndex, segmentIndex, segmentIndex, []);
|
||||||
|
}
|
||||||
|
} else if (level === 'waypoints') {
|
||||||
|
newFile = newFile.replaceWaypoints(0, newFile.wpt.length - 1, []);
|
||||||
|
} else if (level === 'waypoint') {
|
||||||
|
for (let item of items) {
|
||||||
|
let waypointIndex = (item as ListWaypointItem).getWaypointIndex();
|
||||||
|
newFile = newFile.replaceWaypoints(waypointIndex, waypointIndex, []);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
draft.set(newFile._data.id, freeze(newFile));
|
||||||
}
|
}
|
||||||
// TODO: Implement deletion of tracks, segments, waypoints
|
}
|
||||||
});
|
|
||||||
$selection.clear();
|
|
||||||
return $selection;
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
Reference in New Issue
Block a user