From c87bafa9d51cc8573f08b473a03ebfab3f27635c Mon Sep 17 00:00:00 2001 From: Oleksandr Povar Date: Mon, 15 Jun 2026 14:18:02 +0200 Subject: [PATCH 1/2] Show duplicates in search --- apps/map/src/editor/editor.ts | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/apps/map/src/editor/editor.ts b/apps/map/src/editor/editor.ts index a86e1f7e..10f91746 100644 --- a/apps/map/src/editor/editor.ts +++ b/apps/map/src/editor/editor.ts @@ -669,16 +669,36 @@ export class Editor { this.keyEscapeListener(evt); }; - // Add search control + // Add search control. We feed the entities through sourceData/formatData + // (instead of `layer`) so we can control the result keys: the plugin keys + // results by name and silently drops duplicates, so same-named camps after + // the first are suffixed with [1] [2] [3]... to keep them distinct. if (!this._isCleanAndQuietMode) { + const revisions = this._currentRevisions; //@ts-ignore - map.addControl(new L.Control.Search({ - layer: this._placementLayers, - propertyName: 'name', + const search = new L.Control.Search({ + sourceData: (_text, cb) => (cb(Object.values(revisions)), { abort() {} }), + formatData: (entities) => { + const seen: Record = {}; + const result: Record = {}; + for (const e of entities) { + const n = (seen[e.name] = (seen[e.name] || 0) + 1); + const key = n > 1 ? `${e.name} [${n - 1}]` : e.name; + const latlng: any = e.layer.getBounds().getCenter(); + latlng.layer = e.layer; + latlng.name = e.name; + result[key] = latlng; + } + return result; + }, marker: false, zoom: SHOW_NAME_TOOLTIP_ZOOM_LEVEL, initial: false, - })); + }); + search.on('search:locationfound', (e: any) => { + search.searchText(e.latlng.name); + }); + map.addControl(search); } } From e39390c9963d6047e45c668e3aff8216d707e81d Mon Sep 17 00:00:00 2001 From: Oleksandr Povar Date: Mon, 15 Jun 2026 16:06:02 +0200 Subject: [PATCH 2/2] Render same name --- apps/map/src/editor/editor.ts | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/apps/map/src/editor/editor.ts b/apps/map/src/editor/editor.ts index 10f91746..4a68cb20 100644 --- a/apps/map/src/editor/editor.ts +++ b/apps/map/src/editor/editor.ts @@ -671,8 +671,9 @@ export class Editor { // Add search control. We feed the entities through sourceData/formatData // (instead of `layer`) so we can control the result keys: the plugin keys - // results by name and silently drops duplicates, so same-named camps after - // the first are suffixed with [1] [2] [3]... to keep them distinct. + // results by name and silently drops duplicates. We give same-named camps a + // unique internal key (a [n] suffix) so all of them survive, but buildTip + // renders the clean name, so the dropdown shows the duplicates unaltered. if (!this._isCleanAndQuietMode) { const revisions = this._currentRevisions; //@ts-ignore @@ -683,7 +684,7 @@ export class Editor { const result: Record = {}; for (const e of entities) { const n = (seen[e.name] = (seen[e.name] || 0) + 1); - const key = n > 1 ? `${e.name} [${n - 1}]` : e.name; + const key = `${e.name} [${n}]`; const latlng: any = e.layer.getBounds().getCenter(); latlng.layer = e.layer; latlng.name = e.name; @@ -691,9 +692,13 @@ export class Editor { } return result; }, + // Show the clean name (not the internal [n] key) for each result. + buildTip: (_key, latlng) => `
  • ${latlng.name}
  • `, marker: false, zoom: SHOW_NAME_TOOLTIP_ZOOM_LEVEL, initial: false, + // Internal keys carry the [n] suffix; don't let autotype pull it into the box. + autoType: false, }); search.on('search:locationfound', (e: any) => { search.searchText(e.latlng.name);