Add Tree Selector
This commit is contained in:
@@ -0,0 +1,85 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"os"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type treeEntry struct {
|
||||
Name string `json:"name"`
|
||||
Kind string `json:"kind"`
|
||||
}
|
||||
|
||||
type treeResponse struct {
|
||||
Path string `json:"path"`
|
||||
Entries []treeEntry `json:"entries"`
|
||||
}
|
||||
|
||||
// handleTree responds with a JSON listing of the immediate children of the
|
||||
// folder at fsPath. Hidden entries and `index.md` are filtered. Files are not
|
||||
// descended — the client lazy-loads children on expand.
|
||||
func (h *handler) handleTree(w http.ResponseWriter, r *http.Request, urlPath, fsPath string) {
|
||||
info, err := os.Stat(fsPath)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
http.NotFound(w, r)
|
||||
return
|
||||
}
|
||||
http.Error(w, "stat failed", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
if !info.IsDir() {
|
||||
http.Error(w, "not a folder", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
entries, err := listTreeEntries(fsPath)
|
||||
if err != nil {
|
||||
http.Error(w, "read failed", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
resp := treeResponse{Path: canonicalTreePath(urlPath), Entries: entries}
|
||||
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
||||
_ = json.NewEncoder(w).Encode(resp)
|
||||
}
|
||||
|
||||
// canonicalTreePath returns the URL path in the form used by the picker:
|
||||
// "/" for root, otherwise stripped of any trailing slash.
|
||||
func canonicalTreePath(urlPath string) string {
|
||||
if urlPath == "" || urlPath == "/" {
|
||||
return "/"
|
||||
}
|
||||
return "/" + strings.Trim(urlPath, "/")
|
||||
}
|
||||
|
||||
// listTreeEntries returns the immediate children of fsPath, filtering hidden
|
||||
// entries and index.md. Folders are listed before files; both groups are
|
||||
// sorted alphabetically.
|
||||
func listTreeEntries(fsPath string) ([]treeEntry, error) {
|
||||
raw, err := os.ReadDir(fsPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var folders, files []treeEntry
|
||||
for _, e := range raw {
|
||||
name := e.Name()
|
||||
if strings.HasPrefix(name, ".") {
|
||||
continue
|
||||
}
|
||||
if e.IsDir() {
|
||||
folders = append(folders, treeEntry{Name: name, Kind: "folder"})
|
||||
} else {
|
||||
if name == "index.md" {
|
||||
continue
|
||||
}
|
||||
files = append(files, treeEntry{Name: name, Kind: "file"})
|
||||
}
|
||||
}
|
||||
sort.Slice(folders, func(i, j int) bool { return folders[i].Name < folders[j].Name })
|
||||
sort.Slice(files, func(i, j int) bool { return files[i].Name < files[j].Name })
|
||||
return append(folders, files...), nil
|
||||
}
|
||||
Reference in New Issue
Block a user