mirror of
https://github.com/gpxstudio/gpx.studio.git
synced 2025-09-02 16:52:31 +00:00
functional dnd
This commit is contained in:
@@ -1,8 +1,9 @@
|
|||||||
import { dbUtils, fileObservers } from "$lib/db";
|
import { dbUtils, fileObservers } from "$lib/db";
|
||||||
import { castDraft } from "immer";
|
import { castDraft, freeze } from "immer";
|
||||||
import { Track, TrackSegment, Waypoint } from "gpx";
|
import { Track, TrackSegment, Waypoint } from "gpx";
|
||||||
import { selection } from "./Selection";
|
import { selection } from "./Selection";
|
||||||
import { get } from "svelte/store";
|
import { get } from "svelte/store";
|
||||||
|
import { newGPXFile } from "$lib/stores";
|
||||||
|
|
||||||
export enum ListLevel {
|
export enum ListLevel {
|
||||||
ROOT,
|
ROOT,
|
||||||
@@ -273,7 +274,7 @@ export function moveItems(fromParent: ListItem, toParent: ListItem, fromItems: L
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
dbUtils.applyEachToFiles([fromParent.getFileId(), toParent.getFileId()], [
|
dbUtils.applyEachToFilesAndGlobal([fromParent.getFileId(), toParent.getFileId()], [
|
||||||
(file, context: (Track | TrackSegment | Waypoint[] | Waypoint)[]) => {
|
(file, context: (Track | TrackSegment | Waypoint[] | Waypoint)[]) => {
|
||||||
let newFile = file;
|
let newFile = file;
|
||||||
fromItems.forEach((item) => {
|
fromItems.forEach((item) => {
|
||||||
@@ -301,15 +302,27 @@ export function moveItems(fromParent: ListItem, toParent: ListItem, fromItems: L
|
|||||||
(file, context: (Track | TrackSegment | Waypoint[] | Waypoint)[]) => {
|
(file, context: (Track | TrackSegment | Waypoint[] | Waypoint)[]) => {
|
||||||
let newFile = file;
|
let newFile = file;
|
||||||
toItems.forEach((item, i) => {
|
toItems.forEach((item, i) => {
|
||||||
if (item instanceof ListTrackItem && context[i] instanceof Track) {
|
if (item instanceof ListTrackItem) {
|
||||||
let [result, _removed] = newFile.replaceTracks(item.getTrackIndex(), item.getTrackIndex() - 1, [context[i]]);
|
if (context[i] instanceof Track) {
|
||||||
newFile = castDraft(result);
|
let [result, _removed] = newFile.replaceTracks(item.getTrackIndex(), item.getTrackIndex() - 1, [context[i]]);
|
||||||
|
newFile = castDraft(result);
|
||||||
|
} else if (context[i] instanceof TrackSegment) {
|
||||||
|
let [result, _removed] = newFile.replaceTracks(item.getTrackIndex(), item.getTrackIndex() - 1, [new Track({
|
||||||
|
trkseg: [context[i]]
|
||||||
|
})]);
|
||||||
|
newFile = castDraft(result);
|
||||||
|
}
|
||||||
} else if (item instanceof ListTrackSegmentItem && context[i] instanceof TrackSegment) {
|
} else if (item instanceof ListTrackSegmentItem && context[i] instanceof TrackSegment) {
|
||||||
let [result, _removed] = newFile.replaceTrackSegments(item.getTrackIndex(), item.getSegmentIndex(), item.getSegmentIndex() - 1, [context[i]]);
|
let [result, _removed] = newFile.replaceTrackSegments(item.getTrackIndex(), item.getSegmentIndex(), item.getSegmentIndex() - 1, [context[i]]);
|
||||||
newFile = castDraft(result);
|
newFile = castDraft(result);
|
||||||
} else if (item instanceof ListWaypointsItem && Array.isArray(context[i]) && context[i].length > 0 && context[i][0] instanceof Waypoint) {
|
} else if (item instanceof ListWaypointsItem) {
|
||||||
let [result, _removed] = newFile.replaceWaypoints(newFile.wpt.length, newFile.wpt.length - 1, context[i]);
|
if (Array.isArray(context[i]) && context[i].length > 0 && context[i][0] instanceof Waypoint) {
|
||||||
newFile = castDraft(result);
|
let [result, _removed] = newFile.replaceWaypoints(newFile.wpt.length, newFile.wpt.length - 1, context[i]);
|
||||||
|
newFile = castDraft(result);
|
||||||
|
} else if (context[i] instanceof Waypoint) {
|
||||||
|
let [result, _removed] = newFile.replaceWaypoints(newFile.wpt.length, newFile.wpt.length - 1, [context[i]]);
|
||||||
|
newFile = castDraft(result);
|
||||||
|
}
|
||||||
} else if (item instanceof ListWaypointItem && context[i] instanceof Waypoint) {
|
} else if (item instanceof ListWaypointItem && context[i] instanceof Waypoint) {
|
||||||
let [result, _removed] = newFile.replaceWaypoints(item.getWaypointIndex(), item.getWaypointIndex() - 1, [context[i]]);
|
let [result, _removed] = newFile.replaceWaypoints(item.getWaypointIndex(), item.getWaypointIndex() - 1, [context[i]]);
|
||||||
newFile = castDraft(result);
|
newFile = castDraft(result);
|
||||||
@@ -317,13 +330,26 @@ export function moveItems(fromParent: ListItem, toParent: ListItem, fromItems: L
|
|||||||
});
|
});
|
||||||
return newFile;
|
return newFile;
|
||||||
}
|
}
|
||||||
], []);
|
], (files, context: (Track | TrackSegment | Waypoint[] | Waypoint)[]) => {
|
||||||
|
toItems.forEach((item, i) => {
|
||||||
selection.update(($selection) => {
|
if (item instanceof ListFileItem) {
|
||||||
$selection.clear();
|
if (context[i] instanceof Track) {
|
||||||
toItems.forEach((item) => {
|
let newFile = newGPXFile();
|
||||||
$selection.set(item, true);
|
newFile._data.id = item.getFileId();
|
||||||
|
if (context[i].name) {
|
||||||
|
newFile.metadata.name = context[i].name;
|
||||||
|
}
|
||||||
|
newFile = newFile.replaceTracks(0, 0, [context[i]])[0];
|
||||||
|
files.set(item.getFileId(), freeze(newFile));
|
||||||
|
} else if (context[i] instanceof TrackSegment) {
|
||||||
|
let newFile = newGPXFile();
|
||||||
|
newFile._data.id = item.getFileId();
|
||||||
|
newFile = newFile.replaceTracks(0, 0, [new Track({
|
||||||
|
trkseg: [context[i]]
|
||||||
|
})])[0];
|
||||||
|
files.set(item.getFileId(), freeze(newFile));
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
return $selection;
|
}, []);
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
@@ -1,12 +1,25 @@
|
|||||||
|
<script lang="ts" context="module">
|
||||||
|
let pull: Record<ListLevel, ListLevel[]> = {
|
||||||
|
[ListLevel.ROOT]: [],
|
||||||
|
[ListLevel.FILE]: [ListLevel.FILE],
|
||||||
|
[ListLevel.TRACK]: [ListLevel.FILE, ListLevel.TRACK],
|
||||||
|
[ListLevel.SEGMENT]: [ListLevel.FILE, ListLevel.TRACK, ListLevel.SEGMENT],
|
||||||
|
[ListLevel.WAYPOINTS]: [ListLevel.WAYPOINTS],
|
||||||
|
[ListLevel.WAYPOINT]: [ListLevel.WAYPOINTS, ListLevel.WAYPOINT]
|
||||||
|
};
|
||||||
|
|
||||||
|
let dragging: Writable<ListLevel | null> = writable(null);
|
||||||
|
</script>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { GPXFile, Track, Waypoint, type AnyGPXTreeElement, type GPXTreeElement } from 'gpx';
|
import { GPXFile, Track, Waypoint, type AnyGPXTreeElement, type GPXTreeElement } from 'gpx';
|
||||||
import { afterUpdate, getContext, onMount } from 'svelte';
|
import { afterUpdate, getContext, onMount } from 'svelte';
|
||||||
import Sortable from 'sortablejs/Sortable';
|
import Sortable from 'sortablejs/Sortable';
|
||||||
import { fileObservers, settings, type GPXFileWithStatistics } from '$lib/db';
|
import { fileObservers, getFileIds, settings, type GPXFileWithStatistics } from '$lib/db';
|
||||||
import { get, type Readable } from 'svelte/store';
|
import { get, writable, type Readable, type Writable } from 'svelte/store';
|
||||||
import FileListNodeStore from './FileListNodeStore.svelte';
|
import FileListNodeStore from './FileListNodeStore.svelte';
|
||||||
import FileListNode from './FileListNode.svelte';
|
import FileListNode from './FileListNode.svelte';
|
||||||
import { ListLevel, moveItems, type ListItem } from './FileList';
|
import { ListLevel, ListRootItem, moveItems, type ListItem } from './FileList';
|
||||||
import { selection } from './Selection';
|
import { selection } from './Selection';
|
||||||
import { _ } from 'svelte-i18n';
|
import { _ } from 'svelte-i18n';
|
||||||
|
|
||||||
@@ -29,12 +42,6 @@
|
|||||||
: node instanceof Track
|
: node instanceof Track
|
||||||
? ListLevel.SEGMENT
|
? ListLevel.SEGMENT
|
||||||
: ListLevel.WAYPOINT;
|
: ListLevel.WAYPOINT;
|
||||||
let pull: Record<string, string[]> = {
|
|
||||||
file: ['file', 'track'],
|
|
||||||
track: ['file', 'track'],
|
|
||||||
segment: ['file', 'track', 'segment'],
|
|
||||||
waypoint: ['waypoint']
|
|
||||||
};
|
|
||||||
let sortable: Sortable;
|
let sortable: Sortable;
|
||||||
let orientation = getContext<'vertical' | 'horizontal'>('orientation');
|
let orientation = getContext<'vertical' | 'horizontal'>('orientation');
|
||||||
|
|
||||||
@@ -84,26 +91,6 @@
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($fileOrder.length !== $fileObservers.size) {
|
|
||||||
// Files were added or removed
|
|
||||||
fileOrder.update((order) => {
|
|
||||||
for (let i = 0; i < order.length; ) {
|
|
||||||
if (!$fileObservers.has(order[i])) {
|
|
||||||
order.splice(i, 1);
|
|
||||||
} else {
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (let id of $fileObservers.keys()) {
|
|
||||||
if (!order.includes(id)) {
|
|
||||||
order.push(id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return order;
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const currentOrder = sortable.toArray();
|
const currentOrder = sortable.toArray();
|
||||||
if (currentOrder.length !== $fileOrder.length) {
|
if (currentOrder.length !== $fileOrder.length) {
|
||||||
sortable.sort($fileOrder);
|
sortable.sort($fileOrder);
|
||||||
@@ -124,7 +111,9 @@
|
|||||||
function createSortable() {
|
function createSortable() {
|
||||||
sortable = Sortable.create(container, {
|
sortable = Sortable.create(container, {
|
||||||
group: {
|
group: {
|
||||||
name: sortableLevel
|
name: sortableLevel,
|
||||||
|
pull: pull[sortableLevel],
|
||||||
|
put: true
|
||||||
},
|
},
|
||||||
direction: orientation,
|
direction: orientation,
|
||||||
forceAutoScrollFallback: true,
|
forceAutoScrollFallback: true,
|
||||||
@@ -133,46 +122,65 @@
|
|||||||
avoidImplicitDeselect: true,
|
avoidImplicitDeselect: true,
|
||||||
onSelect: updateToSelection,
|
onSelect: updateToSelection,
|
||||||
onDeselect: updateToSelection,
|
onDeselect: updateToSelection,
|
||||||
|
onStart: () => {
|
||||||
|
dragging.set(sortableLevel);
|
||||||
|
},
|
||||||
|
onEnd: () => {
|
||||||
|
dragging.set(null);
|
||||||
|
},
|
||||||
onSort: (e) => {
|
onSort: (e) => {
|
||||||
if (sortableLevel === ListLevel.FILE) {
|
if (sortableLevel === ListLevel.FILE) {
|
||||||
let newFileOrder = sortable.toArray();
|
let newFileOrder = sortable.toArray();
|
||||||
if (newFileOrder.length !== get(fileOrder).length) {
|
if (newFileOrder.length !== get(fileOrder).length) {
|
||||||
fileOrder.set(newFileOrder);
|
fileOrder.set(newFileOrder);
|
||||||
return;
|
} else {
|
||||||
}
|
for (let i = 0; i < newFileOrder.length; i++) {
|
||||||
|
if (newFileOrder[i] !== get(fileOrder)[i]) {
|
||||||
for (let i = 0; i < newFileOrder.length; i++) {
|
fileOrder.set(newFileOrder);
|
||||||
if (newFileOrder[i] !== get(fileOrder)[i]) {
|
break;
|
||||||
fileOrder.set(newFileOrder);
|
}
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
let fromItem = Sortable.get(e.from)._item;
|
|
||||||
let toItem = Sortable.get(e.to)._item;
|
|
||||||
|
|
||||||
if (item === toItem) {
|
let fromItem = Sortable.get(e.from)._item;
|
||||||
// Event is triggered on source and destination list, only handle it once
|
let toItem = Sortable.get(e.to)._item;
|
||||||
let fromItems = [];
|
|
||||||
let toItems = [];
|
|
||||||
|
|
||||||
if (waypointRoot) {
|
if (item === toItem && !(fromItem instanceof ListRootItem)) {
|
||||||
fromItems = [fromItem.extend('waypoints')];
|
// Event is triggered on source and destination list, only handle it once
|
||||||
toItems = [toItem.extend('waypoints')];
|
let fromItems = [];
|
||||||
|
let toItems = [];
|
||||||
|
|
||||||
|
if (Sortable.get(e.from)._waypointRoot) {
|
||||||
|
fromItems = [fromItem.extend('waypoints')];
|
||||||
|
} else {
|
||||||
|
let oldIndices =
|
||||||
|
e.oldIndicies.length > 0 ? e.oldIndicies.map((i) => i.index) : [e.oldIndex];
|
||||||
|
oldIndices.sort((a, b) => a - b);
|
||||||
|
|
||||||
|
fromItems = oldIndices.map((i) => fromItem.extend(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Sortable.get(e.from)._waypointRoot && Sortable.get(e.to)._waypointRoot) {
|
||||||
|
toItems = [toItem.extend('waypoints')];
|
||||||
|
} else {
|
||||||
|
if (Sortable.get(e.to)._waypointRoot) {
|
||||||
|
toItem = toItem.extend('waypoints');
|
||||||
|
}
|
||||||
|
|
||||||
|
let newIndices =
|
||||||
|
e.newIndicies.length > 0 ? e.newIndicies.map((i) => i.index) : [e.newIndex];
|
||||||
|
newIndices.sort((a, b) => a - b);
|
||||||
|
|
||||||
|
if (toItem instanceof ListRootItem) {
|
||||||
|
let newFileIds = getFileIds(newIndices.length);
|
||||||
|
toItems = newIndices.map((_i, index) => item.extend(newFileIds[index]));
|
||||||
} else {
|
} else {
|
||||||
let oldIndices =
|
|
||||||
e.oldIndicies.length > 0 ? e.oldIndicies.map((i) => i.index) : [e.oldIndex];
|
|
||||||
let newIndices =
|
|
||||||
e.newIndicies.length > 0 ? e.newIndicies.map((i) => i.index) : [e.newIndex];
|
|
||||||
oldIndices.sort((a, b) => a - b);
|
|
||||||
newIndices.sort((a, b) => a - b);
|
|
||||||
|
|
||||||
fromItems = oldIndices.map((i) => fromItem.extend(i));
|
|
||||||
toItems = newIndices.map((i) => toItem.extend(i));
|
toItems = newIndices.map((i) => toItem.extend(i));
|
||||||
}
|
}
|
||||||
|
|
||||||
moveItems(fromItem, toItem, fromItems, toItems);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
moveItems(fromItem, toItem, fromItems, toItems);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -180,6 +188,11 @@
|
|||||||
value: item,
|
value: item,
|
||||||
writable: true
|
writable: true
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Object.defineProperty(sortable, '_waypointRoot', {
|
||||||
|
value: waypointRoot,
|
||||||
|
writable: true
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
@@ -220,11 +233,15 @@
|
|||||||
? id
|
? id
|
||||||
: parseInt(id);
|
: parseInt(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$: canDrop = $dragging !== null && pull[$dragging].includes(sortableLevel);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
bind:this={container}
|
bind:this={container}
|
||||||
class="sortable {orientation} flex {orientation === 'vertical' ? 'flex-col' : 'flex-row gap-1'}"
|
class="sortable {orientation} flex {orientation === 'vertical'
|
||||||
|
? 'flex-col'
|
||||||
|
: 'flex-row gap-1'} {canDrop ? 'p-b-5' : ''}"
|
||||||
>
|
>
|
||||||
{#if node instanceof Map}
|
{#if node instanceof Map}
|
||||||
{#each node as [fileId, file] (fileId)}
|
{#each node as [fileId, file] (fileId)}
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
import { get, writable } from "svelte/store";
|
import { get, writable } from "svelte/store";
|
||||||
import { ListFileItem, ListItem, ListRootItem, ListTrackItem, ListTrackSegmentItem, ListWaypointItem, type ListLevel, sortItems } from "./FileList";
|
import { ListFileItem, ListItem, ListRootItem, ListTrackItem, ListTrackSegmentItem, ListWaypointItem, type ListLevel, sortItems, ListWaypointsItem } from "./FileList";
|
||||||
import { fileObservers, settings } from "$lib/db";
|
import { fileObservers, settings } from "$lib/db";
|
||||||
|
|
||||||
export class SelectionTreeType {
|
export class SelectionTreeType {
|
||||||
@@ -205,7 +205,7 @@ export function applyToOrderedSelectedItemsFromFile(callback: (fileId: string, l
|
|||||||
get(selection).forEach((item) => {
|
get(selection).forEach((item) => {
|
||||||
if (item.getFileId() === fileId) {
|
if (item.getFileId() === fileId) {
|
||||||
level = item.level;
|
level = item.level;
|
||||||
if (item instanceof ListFileItem || item instanceof ListTrackItem || item instanceof ListTrackSegmentItem || item instanceof ListWaypointItem) {
|
if (item instanceof ListFileItem || item instanceof ListTrackItem || item instanceof ListTrackSegmentItem || item instanceof ListWaypointsItem || item instanceof ListWaypointItem) {
|
||||||
items.push(item);
|
items.push(item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -187,17 +187,13 @@ function dexieGPXFileStore(id: string): Readable<GPXFileWithStatistics> & { dest
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Add/update the files to the database
|
// Add/update the files to the database
|
||||||
function updateDbFiles(files: (GPXFile | undefined)[], add: boolean = false) {
|
function updateDbFiles(files: (GPXFile | undefined)[]) {
|
||||||
let filteredFiles = files.filter(file => file !== undefined) as GPXFile[];
|
let filteredFiles = files.filter(file => file !== undefined) as GPXFile[];
|
||||||
let fileIds = filteredFiles.map(file => file._data.id);
|
let fileIds = filteredFiles.map(file => file._data.id);
|
||||||
if (add) {
|
return db.transaction('rw', db.fileids, db.files, async () => {
|
||||||
return db.transaction('rw', db.fileids, db.files, async () => {
|
await db.fileids.bulkPut(fileIds, fileIds);
|
||||||
await db.fileids.bulkAdd(fileIds, fileIds);
|
await db.files.bulkPut(filteredFiles, fileIds);
|
||||||
await db.files.bulkAdd(filteredFiles, fileIds);
|
});
|
||||||
});
|
|
||||||
} else {
|
|
||||||
return db.files.bulkPut(filteredFiles, fileIds);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete the files with the given ids from the database
|
// Delete the files with the given ids from the database
|
||||||
@@ -210,9 +206,7 @@ function deleteDbFiles(fileIds: string[]) {
|
|||||||
|
|
||||||
// Commit the changes to the file state to the database
|
// Commit the changes to the file state to the database
|
||||||
function commitFileStateChange(newFileState: ReadonlyMap<string, GPXFile>, patch: Patch[]) {
|
function commitFileStateChange(newFileState: ReadonlyMap<string, GPXFile>, patch: Patch[]) {
|
||||||
if (newFileState.size > fileState.size) {
|
if (newFileState.size >= fileState.size) {
|
||||||
return updateDbFiles(getChangedFileIds(patch).map((fileId) => newFileState.get(fileId)), true);
|
|
||||||
} else if (newFileState.size === fileState.size) {
|
|
||||||
return updateDbFiles(getChangedFileIds(patch).map((fileId) => newFileState.get(fileId)));
|
return updateDbFiles(getChangedFileIds(patch).map((fileId) => newFileState.get(fileId)));
|
||||||
} else {
|
} else {
|
||||||
return deleteDbFiles(getChangedFileIds(patch));
|
return deleteDbFiles(getChangedFileIds(patch));
|
||||||
@@ -252,6 +246,20 @@ liveQuery(() => db.fileids.toArray()).subscribe(dbFileIds => {
|
|||||||
return $selection;
|
return $selection;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
settings.fileOrder.update((order) => {
|
||||||
|
newFiles.forEach((fileId) => {
|
||||||
|
if (!order.includes(fileId)) {
|
||||||
|
order.push(fileId);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
deletedFiles.forEach((fileId) => {
|
||||||
|
let index = order.indexOf(fileId);
|
||||||
|
if (index !== -1) {
|
||||||
|
order.splice(index, 1);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return order;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -292,7 +300,7 @@ function applyToFiles(fileIds: string[], callback: (file: WritableDraft<GPXFile>
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Helper function to apply different callbacks to multiple files
|
// Helper function to apply different callbacks to multiple files
|
||||||
function applyEachToFiles(fileIds: string[], callbacks: ((file: WritableDraft<GPXFile>, context?: any) => GPXFile)[], context?: any) {
|
function applyEachToFilesAndGlobal(fileIds: string[], callbacks: ((file: WritableDraft<GPXFile>, context?: any) => GPXFile)[], globalCallback: (files: Map<string, GPXFile>, context?: any) => void, context?: any) {
|
||||||
const [newFileState, patch, inversePatch] = produceWithPatches(fileState, (draft) => {
|
const [newFileState, patch, inversePatch] = produceWithPatches(fileState, (draft) => {
|
||||||
fileIds.forEach((fileId, index) => {
|
fileIds.forEach((fileId, index) => {
|
||||||
let file = draft.get(fileId);
|
let file = draft.get(fileId);
|
||||||
@@ -300,6 +308,7 @@ function applyEachToFiles(fileIds: string[], callbacks: ((file: WritableDraft<GP
|
|||||||
draft.set(fileId, castDraft(callbacks[index](file, context)));
|
draft.set(fileId, castDraft(callbacks[index](file, context)));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
globalCallback(draft, context);
|
||||||
});
|
});
|
||||||
|
|
||||||
storePatches(patch, inversePatch);
|
storePatches(patch, inversePatch);
|
||||||
@@ -344,7 +353,7 @@ function getChangedFileIds(patch: Patch[]): string[] {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Generate unique file ids, different from the ones in the database
|
// Generate unique file ids, different from the ones in the database
|
||||||
function getFileIds(n: number) {
|
export function getFileIds(n: number) {
|
||||||
let ids = [];
|
let ids = [];
|
||||||
for (let index = 0; ids.length < n; index++) {
|
for (let index = 0; ids.length < n; index++) {
|
||||||
let id = `gpx-${index}`;
|
let id = `gpx-${index}`;
|
||||||
@@ -378,8 +387,8 @@ export const dbUtils = {
|
|||||||
applyToFiles: (ids: string[], callback: (file: WritableDraft<GPXFile>) => GPXFile) => {
|
applyToFiles: (ids: string[], callback: (file: WritableDraft<GPXFile>) => GPXFile) => {
|
||||||
applyToFiles(ids, callback);
|
applyToFiles(ids, callback);
|
||||||
},
|
},
|
||||||
applyEachToFiles: (ids: string[], callbacks: ((file: WritableDraft<GPXFile>, context?: any) => GPXFile)[], context?: any) => {
|
applyEachToFilesAndGlobal: (ids: string[], callbacks: ((file: WritableDraft<GPXFile>, context?: any) => GPXFile)[], globalCallback: (files: Map<string, GPXFile>, context?: any) => void, context?: any) => {
|
||||||
applyEachToFiles(ids, callbacks, context);
|
applyEachToFilesAndGlobal(ids, callbacks, globalCallback, context);
|
||||||
},
|
},
|
||||||
applyToSelection: (callback: (file: WritableDraft<AnyGPXTreeElement>) => AnyGPXTreeElement) => {
|
applyToSelection: (callback: (file: WritableDraft<AnyGPXTreeElement>) => AnyGPXTreeElement) => {
|
||||||
if (get(selection).size === 0) {
|
if (get(selection).size === 0) {
|
||||||
|
@@ -127,9 +127,14 @@ export enum Tool {
|
|||||||
}
|
}
|
||||||
export const currentTool = writable<Tool | null>(null);
|
export const currentTool = writable<Tool | null>(null);
|
||||||
|
|
||||||
export function createFile() {
|
export function newGPXFile() {
|
||||||
let file = new GPXFile();
|
let file = new GPXFile();
|
||||||
file.metadata.name = get(_)("menu.new_filename");
|
file.metadata.name = get(_)("menu.new_filename");
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createFile() {
|
||||||
|
let file = newGPXFile();
|
||||||
|
|
||||||
dbUtils.add(file);
|
dbUtils.add(file);
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user