diff --git a/website/src/lib/components/Help.svelte b/website/src/lib/components/Help.svelte
index 3e88a29d..19208656 100644
--- a/website/src/lib/components/Help.svelte
+++ b/website/src/lib/components/Help.svelte
@@ -3,6 +3,6 @@
-
+
diff --git a/website/src/lib/components/layer-control/LayerControlSettings.svelte b/website/src/lib/components/layer-control/LayerControlSettings.svelte
index c9f465c9..d4cb8794 100644
--- a/website/src/lib/components/layer-control/LayerControlSettings.svelte
+++ b/website/src/lib/components/layer-control/LayerControlSettings.svelte
@@ -120,7 +120,7 @@
-
+
diff --git a/website/src/lib/components/toolbar/Toolbar.svelte b/website/src/lib/components/toolbar/Toolbar.svelte
index 694f9848..af76aae1 100644
--- a/website/src/lib/components/toolbar/Toolbar.svelte
+++ b/website/src/lib/components/toolbar/Toolbar.svelte
@@ -40,7 +40,7 @@
- {$_('toolbar.merge_tooltip')}
+ {$_('toolbar.merge.tooltip')}
diff --git a/website/src/lib/components/toolbar/ToolbarItemMenu.svelte b/website/src/lib/components/toolbar/ToolbarItemMenu.svelte
index d4ecd687..09ab54d2 100644
--- a/website/src/lib/components/toolbar/ToolbarItemMenu.svelte
+++ b/website/src/lib/components/toolbar/ToolbarItemMenu.svelte
@@ -5,6 +5,7 @@
import Routing from '$lib/components/toolbar/tools/routing/Routing.svelte';
import Scissors from '$lib/components/toolbar/tools/Scissors.svelte';
import Waypoint from '$lib/components/toolbar/tools/Waypoint.svelte';
+ import Merge from '$lib/components/toolbar/tools/Merge.svelte';
import RoutingControlPopup from '$lib/components/toolbar/tools/routing/RoutingControlPopup.svelte';
import { onMount } from 'svelte';
import mapboxgl from 'mapbox-gl';
@@ -36,6 +37,8 @@
{:else if $currentTool === Tool.WAYPOINT}
+ {:else if $currentTool === Tool.MERGE}
+
{/if}
diff --git a/website/src/lib/components/toolbar/tools/Merge.svelte b/website/src/lib/components/toolbar/tools/Merge.svelte
new file mode 100644
index 00000000..55caa4e7
--- /dev/null
+++ b/website/src/lib/components/toolbar/tools/Merge.svelte
@@ -0,0 +1,100 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {#if mergeType === MergeType.TRACES && canMergeTraces}
+ {$_('toolbar.merge.help_merge_traces')}
+ {:else if mergeType === MergeType.TRACES && !canMergeTraces}
+ {$_('toolbar.merge.help_cannot_merge_traces')}
+ {:else if mergeType === MergeType.CONTENTS && canMergeContents}
+ {$_('toolbar.merge.help_merge_contents')}
+ {:else if mergeType === MergeType.CONTENTS && !canMergeContents}
+ {$_('toolbar.merge.help_cannot_merge_contents')}
+ {/if}
+
+
diff --git a/website/src/lib/db.ts b/website/src/lib/db.ts
index 379d9b9a..a95ea5f6 100644
--- a/website/src/lib/db.ts
+++ b/website/src/lib/db.ts
@@ -1,5 +1,5 @@
import Dexie, { liveQuery } from 'dexie';
-import { GPXFile, GPXStatistics, Track, type AnyGPXTreeElement } from 'gpx';
+import { GPXFile, GPXStatistics, Track, type AnyGPXTreeElement, TrackSegment, Waypoint, TrackPoint } from 'gpx';
import { enableMapSet, enablePatches, applyPatches, type Patch, type WritableDraft, castDraft, freeze, produceWithPatches, original, produce } from 'immer';
import { writable, get, derived, type Readable, type Writable } from 'svelte/store';
import { initTargetMapBounds, updateTargetMapBounds } from './stores';
@@ -187,31 +187,31 @@ function dexieGPXFileStore(id: string): Readable & { dest
};
}
-// Add/update the files to the database
-function updateDbFiles(files: (GPXFile | undefined)[]) {
- let filteredFiles = files.filter(file => file !== undefined) as GPXFile[];
- let fileIds = filteredFiles.map(file => file._data.id);
- return db.transaction('rw', db.fileids, db.files, async () => {
- await db.fileids.bulkPut(fileIds, fileIds);
- await db.files.bulkPut(filteredFiles, fileIds);
- });
-}
-
-// Delete the files with the given ids from the database
-function deleteDbFiles(fileIds: string[]) {
- return db.transaction('rw', db.fileids, db.files, async () => {
- await db.fileids.bulkDelete(fileIds);
- await db.files.bulkDelete(fileIds);
- });
-}
-
// Commit the changes to the file state to the database
function commitFileStateChange(newFileState: ReadonlyMap, patch: Patch[]) {
- if (newFileState.size >= fileState.size) {
- return updateDbFiles(getChangedFileIds(patch).map((fileId) => newFileState.get(fileId)));
- } else {
- return deleteDbFiles(getChangedFileIds(patch));
- }
+ let changedFileIds = getChangedFileIds(patch);
+ let updatedFileIds: string[] = [], deletedFileIds: string[] = [];
+ changedFileIds.forEach(id => {
+ if (newFileState.has(id)) {
+ updatedFileIds.push(id);
+ } else {
+ deletedFileIds.push(id);
+ }
+ });
+
+ let updatedFiles = updatedFileIds.map(id => newFileState.get(id)).filter(file => file !== undefined) as GPXFile[];
+ updatedFileIds = updatedFiles.map(file => file._data.id);
+
+ return db.transaction('rw', db.fileids, db.files, async () => {
+ if (updatedFileIds.length > 0) {
+ await db.fileids.bulkPut(updatedFileIds, updatedFileIds);
+ await db.files.bulkPut(updatedFiles, updatedFileIds);
+ }
+ if (deletedFileIds.length > 0) {
+ await db.fileids.bulkDelete(deletedFileIds);
+ await db.files.bulkDelete(deletedFileIds);
+ }
+ });
}
export const fileObservers: Writable