Add GPX drag & drop, folder management, delete, and folder-first sort

Uploading is now drag & drop (or click to browse) instead of a form;
folders can be created any time, not just during upload; files can be
dragged onto a folder to move them, or dropped elsewhere in the tree
to move back to the top level; files and folders can be deleted. Both
drag sources (an OS file drag and dragging an existing tree entry)
land on the same drop targets, told apart by a custom drag payload
type versus the browser's own "Files" type.

Also sort folders before files in the tree (previously interleaved
alphabetically).
This commit is contained in:
randy committed 2026-08-25 15:14:09 +02:00
1 parent 4e0d2abbd0
commit d813dd0b20
6 files changed
+440 -66

No files matched your search

+39 -1
View File
@@ -41,6 +41,42 @@ module Maptool
path
end
def create_folder(path)
raise InvalidPath if path.to_s.strip.empty?
FileUtils.mkdir_p(resolve_dir(path.to_s))
end
def delete_file(relative_path)
path = resolve_file(relative_path)
raise Errno::ENOENT, path unless File.file?(path)
File.delete(path)
end
def delete_folder(relative_path)
raise InvalidPath if relative_path.to_s.strip.empty?
dir = resolve_dir(relative_path.to_s)
raise InvalidPath if dir == @root
raise Errno::ENOENT, dir unless File.directory?(dir)
FileUtils.rm_rf(dir)
end
# Moves a file into `to_folder` (created if needed), disambiguating the
# filename on collision. Returns the new store-relative path.
def move(from:, to_folder:)
source = resolve_file(from)
raise Errno::ENOENT, source unless File.file?(source)
dest_dir = resolve_dir(to_folder.to_s)
FileUtils.mkdir_p(dest_dir)
name = unique_filename(dest_dir, File.basename(source))
FileUtils.mv(source, File.join(dest_dir, name))
to_folder.to_s.empty? ? name : "#{to_folder}/#{name}"
end
private
def resolve_dir(folder)
@@ -72,7 +108,9 @@ module Maptool
end
def list_children(dir, relative)
Dir.children(dir).sort.filter_map do |entry|
entries = Dir.children(dir).sort_by { |entry| [File.directory?(File.join(dir, entry)) ? 0 : 1, entry] }
entries.filter_map do |entry|
full = File.join(dir, entry)
rel = relative.empty? ? entry : "#{relative}/#{entry}"