Consolidate note-drawing into Measure; add edit/delete
Measure already draws distance lines and area polygons by hand — a second click-to-draw UI in the notes tool (Point/Area mode, from the previous commit) duplicated that. Replaced it with a "Save as note" button on the Measure panel that saves whatever shape is currently drawn there; NotesControl goes back to being just a one-click point pin. Both share a single NoteSaveForm (notes.js) for the note-text + target-layer-file UI instead of two copies of it. gpx.js: the "lines" source now also renders a note-flagged LineString (dashed, popup-on-click) alongside the Polygon fill/outline from before — the plain track-line layer excludes category:"Note" features so a saved distance note doesn't also get the track hover-summary/ profile-panel treatment. Notes are now individually editable/deletable from their own popup (logged-in only): Edit swaps the popup content for an inline textarea, Delete confirms and removes. Both target the feature by a new client-generated properties.id rather than array position (new GpxStore#update_feature/#delete_feature, PUT/DELETE /api/gpx/notes), since neither array index nor the note's own text (the thing being edited) is a stable identifier. Verified live: Measure's Save button (disabled/enabled state, saves the exact on-screen shape), the popup's Edit/Delete buttons and inline edit form. Full test suite: 115 runs, 0 failures (new coverage for update_feature/delete_feature and the PUT/DELETE routes).
This commit is contained in:
1 parent
db58468187
commit
aafb4cb4a0
9 files changed
+499
-239
No files matched your search
@@ -154,6 +154,38 @@ module Maptool
|
||||
path
|
||||
end
|
||||
|
||||
# Replaces the feature whose properties["id"] matches `id` (see
|
||||
# append_feature/notes.js — every hand-drawn note gets a client-
|
||||
# generated id specifically so it can be found again later, since nothing
|
||||
# else here is a stable identifier: array position shifts as other
|
||||
# features are added/removed, and a note's own text is exactly the thing
|
||||
# being edited). Raises Errno::ENOENT for a missing file *or* a missing
|
||||
# feature — same "nothing to act on" story either way.
|
||||
def update_feature(path:, id:, feature:)
|
||||
file = resolve_file(path)
|
||||
raise Errno::ENOENT, file unless File.file?(file)
|
||||
|
||||
collection = JSON.parse(File.read(file))
|
||||
index = (collection["features"] || []).find_index { |f| f.dig("properties", "id") == id }
|
||||
raise Errno::ENOENT, "#{path}##{id}" unless index
|
||||
|
||||
collection["features"][index] = feature
|
||||
File.write(file, JSON.generate(collection))
|
||||
end
|
||||
|
||||
# Same id-matching story as update_feature above.
|
||||
def delete_feature(path:, id:)
|
||||
file = resolve_file(path)
|
||||
raise Errno::ENOENT, file unless File.file?(file)
|
||||
|
||||
collection = JSON.parse(File.read(file))
|
||||
before = (collection["features"] || []).length
|
||||
collection["features"] = (collection["features"] || []).reject { |f| f.dig("properties", "id") == id }
|
||||
raise Errno::ENOENT, "#{path}##{id}" if collection["features"].length == before
|
||||
|
||||
File.write(file, JSON.generate(collection))
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def resolve_dir(folder)
|
||||
|
||||
Reference in new issue
Block a user