Compare commits
2
Commits
c0b7ebf0c2
...
b14941b3e0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b14941b3e0 | ||
|
|
adf1540cf9 |
+4
-12
@@ -72,10 +72,10 @@ body {
|
|||||||
* { box-sizing: border-box; margin: 0; padding: 0; }
|
* { box-sizing: border-box; margin: 0; padding: 0; }
|
||||||
|
|
||||||
a { color: var(--text); text-decoration: none; }
|
a { color: var(--text); text-decoration: none; }
|
||||||
a:hover { color: var(--primary-hover); }
|
a:hover { color: var(--link-hover); }
|
||||||
.content a { color: var(--link); }
|
.content a { color: var(--link); }
|
||||||
.content a:hover { color: var(--link-hover); }
|
.content a:hover { color: var(--link-hover); }
|
||||||
.content a.broken { color: var(--primary-hover); text-decoration: line-through; }
|
.content a.broken { color: var(--link-hover); text-decoration: line-through; }
|
||||||
.content a.broken:hover { color: var(--link-hover); }
|
.content a.broken:hover { color: var(--link-hover); }
|
||||||
|
|
||||||
hr { border: none; border-top: var(--border-dashed); margin: var(--space-4) 0; }
|
hr { border: none; border-top: var(--border-dashed); margin: var(--space-4) 0; }
|
||||||
@@ -714,14 +714,13 @@ aside.sidebar:empty { display: none; }
|
|||||||
border-left: 3px solid var(--primary);
|
border-left: 3px solid var(--primary);
|
||||||
padding-left: calc(var(--space-2) - 3px);
|
padding-left: calc(var(--space-2) - 3px);
|
||||||
}
|
}
|
||||||
|
.tree-row.is-active > .tree-name { color: var(--secondary); }
|
||||||
.tree-row.is-disabled { color: var(--text-muted); cursor: default; }
|
.tree-row.is-disabled { color: var(--text-muted); cursor: default; }
|
||||||
.tree-row.is-disabled:hover { background: none; }
|
.tree-row.is-disabled:hover { background: none; }
|
||||||
.tree-chevron { text-align: center; flex-shrink: 0; }
|
.tree-chevron { text-align: center; flex-shrink: 0; }
|
||||||
.tree-chevron { width: 1.25rem; color: var(--secondary); }
|
.tree-chevron { width: 1.25rem; color: var(--secondary); }
|
||||||
.tree-chevron.is-leaf { visibility: hidden; }
|
.tree-chevron.is-leaf { visibility: hidden; }
|
||||||
.tree-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
.tree-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||||
/* Each nesting level gets a vertical guide rail down its left edge so depth
|
|
||||||
stays scannable in the compact view (cf. VS Code / file-explorer trees). */
|
|
||||||
.tree-children {
|
.tree-children {
|
||||||
margin-left: var(--space-2);
|
margin-left: var(--space-2);
|
||||||
padding-left: var(--space-2);
|
padding-left: var(--space-2);
|
||||||
@@ -732,14 +731,7 @@ aside.sidebar:empty { display: none; }
|
|||||||
padding: var(--space-1) 0;
|
padding: var(--space-1) 0;
|
||||||
word-break: break-all;
|
word-break: break-all;
|
||||||
}
|
}
|
||||||
/* Current-page row in the navigation rail. Mirrors .tree-row.is-selected so the
|
|
||||||
two tree surfaces stay visually consistent. */
|
|
||||||
.tree-row.is-active {
|
|
||||||
background: var(--bg-panel-hover);
|
|
||||||
border-left: 3px solid var(--primary);
|
|
||||||
padding-left: calc(var(--space-2) - 3px);
|
|
||||||
}
|
|
||||||
.tree-row.is-active > .tree-name { color: var(--primary-hover); }
|
|
||||||
|
|
||||||
/* Tree sidebar (persistent navigation) */
|
/* Tree sidebar (persistent navigation) */
|
||||||
.tree-sidebar {
|
.tree-sidebar {
|
||||||
|
|||||||
+197
-182
@@ -1,200 +1,215 @@
|
|||||||
(function () {
|
;(function () {
|
||||||
// This script owns the .tree-scroll child of the aside, not the aside itself.
|
// This script owns the .tree-scroll child of the aside, not the aside itself.
|
||||||
var container = document.querySelector('aside.tree-sidebar .tree-scroll');
|
var container = document.querySelector("aside.tree-sidebar .tree-scroll")
|
||||||
if (!container) return;
|
if (!container) return
|
||||||
|
|
||||||
function joinPath(parent, name) {
|
function joinPath(parent, name) {
|
||||||
if (parent === '/' || parent === '') return '/' + name;
|
if (parent === "/" || parent === "") return "/" + name
|
||||||
return parent.replace(/\/+$/, '') + '/' + name;
|
return parent.replace(/\/+$/, "") + "/" + name
|
||||||
|
}
|
||||||
|
|
||||||
|
function encodeSegments(p) {
|
||||||
|
return p.replace(/^\/+/, "").split("/").map(encodeURIComponent).join("/")
|
||||||
|
}
|
||||||
|
|
||||||
|
function folderHref(p) {
|
||||||
|
if (p === "/" || p === "") return "/"
|
||||||
|
return "/" + encodeSegments(p) + "/"
|
||||||
|
}
|
||||||
|
|
||||||
|
function fetchFolder(path, expandTo) {
|
||||||
|
var url = folderHref(path) + "?tree=1&foldersOnly=1"
|
||||||
|
if (expandTo) url += "&expandTo=" + encodeURIComponent(expandTo)
|
||||||
|
return fetch(url, { credentials: "same-origin" }).then(function (r) {
|
||||||
|
if (!r.ok) throw new Error("HTTP " + r.status)
|
||||||
|
return r.json()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Current page as a canonical, DECODED wiki path ("/" for root, no trailing
|
||||||
|
// slash otherwise). pathname is percent-encoded; the tree's entry names (and
|
||||||
|
// thus fullPath) are decoded, so we must decode here too or paths containing
|
||||||
|
// spaces / non-ASCII never match a row and the chain never expands.
|
||||||
|
var activePath = (function () {
|
||||||
|
var p = window.location.pathname.replace(/\/+$/, "")
|
||||||
|
if (p === "") return "/"
|
||||||
|
try {
|
||||||
|
return decodeURIComponent(p)
|
||||||
|
} catch (e) {
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
})()
|
||||||
|
var activeRow = null
|
||||||
|
|
||||||
|
function disabledRow(text) {
|
||||||
|
var row = document.createElement("div")
|
||||||
|
row.className = "tree-row is-disabled"
|
||||||
|
row.textContent = text
|
||||||
|
return row
|
||||||
|
}
|
||||||
|
|
||||||
|
// renderInto fills containerEl with rows for `entries` (children of
|
||||||
|
// parentPath). Folders carrying a `children` array (the pre-expanded
|
||||||
|
// ancestor chain from ?expandTo) are opened immediately and recurse.
|
||||||
|
function renderInto(containerEl, parentPath, entries) {
|
||||||
|
entries.forEach(function (entry) {
|
||||||
|
var built = buildRow(parentPath, entry)
|
||||||
|
containerEl.appendChild(built.row)
|
||||||
|
if (built.preExpand) built.open()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildRow(parentPath, entry) {
|
||||||
|
var fullPath = joinPath(parentPath, entry.name)
|
||||||
|
var row = document.createElement("div")
|
||||||
|
row.className = "tree-row"
|
||||||
|
|
||||||
|
var chevron = document.createElement("span")
|
||||||
|
chevron.className = "tree-chevron"
|
||||||
|
chevron.textContent = "▸"
|
||||||
|
row.appendChild(chevron)
|
||||||
|
|
||||||
|
var link = document.createElement("a")
|
||||||
|
link.className = "tree-name tree-folder"
|
||||||
|
link.textContent = entry.name
|
||||||
|
link.href = folderHref(fullPath)
|
||||||
|
row.appendChild(link)
|
||||||
|
|
||||||
|
if (fullPath === activePath) {
|
||||||
|
row.classList.add("is-active")
|
||||||
|
activeRow = row
|
||||||
}
|
}
|
||||||
|
|
||||||
function encodeSegments(p) {
|
var preChildren = entry.children ? entry.children : null
|
||||||
return p.replace(/^\/+/, '').split('/').map(encodeURIComponent).join('/');
|
var childrenEl = null
|
||||||
|
var loaded = false
|
||||||
|
var isOpen = false
|
||||||
|
var isLeaf = false
|
||||||
|
|
||||||
|
function ensureChildrenEl() {
|
||||||
|
if (!childrenEl) {
|
||||||
|
childrenEl = document.createElement("div")
|
||||||
|
childrenEl.className = "tree-children"
|
||||||
|
}
|
||||||
|
return childrenEl
|
||||||
}
|
}
|
||||||
|
|
||||||
function folderHref(p) {
|
function markLeaf() {
|
||||||
if (p === '/' || p === '') return '/';
|
isLeaf = true
|
||||||
return '/' + encodeSegments(p) + '/';
|
isOpen = false
|
||||||
|
chevron.textContent = "▸"
|
||||||
|
chevron.classList.add("is-leaf")
|
||||||
|
if (childrenEl && childrenEl.parentNode) {
|
||||||
|
childrenEl.parentNode.removeChild(childrenEl)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function fileHref(p) {
|
function loadChildren() {
|
||||||
return '/' + encodeSegments(p);
|
var el = ensureChildrenEl()
|
||||||
|
el.textContent = ""
|
||||||
|
el.appendChild(disabledRow("…"))
|
||||||
|
fetchFolder(fullPath)
|
||||||
|
.then(function (resp) {
|
||||||
|
el.textContent = ""
|
||||||
|
loaded = true
|
||||||
|
if (!resp.entries || resp.entries.length === 0) {
|
||||||
|
markLeaf()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
renderInto(el, fullPath, resp.entries)
|
||||||
|
})
|
||||||
|
.catch(function () {
|
||||||
|
el.textContent = ""
|
||||||
|
var err = document.createElement("div")
|
||||||
|
err.className = "tree-row"
|
||||||
|
err.textContent = "(failed — tap to retry)"
|
||||||
|
err.addEventListener("click", function (e) {
|
||||||
|
e.stopPropagation()
|
||||||
|
loadChildren()
|
||||||
|
})
|
||||||
|
el.appendChild(err)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function fetchFolder(path, expandTo) {
|
function open() {
|
||||||
var url = folderHref(path) + '?tree=1';
|
if (isOpen || isLeaf) return
|
||||||
if (expandTo) url += '&expandTo=' + encodeURIComponent(expandTo);
|
var el = ensureChildrenEl()
|
||||||
return fetch(url, { credentials: 'same-origin' }).then(function (r) {
|
row.parentNode.insertBefore(el, row.nextSibling)
|
||||||
if (!r.ok) throw new Error('HTTP ' + r.status);
|
chevron.textContent = "▾" // ▾
|
||||||
return r.json();
|
isOpen = true
|
||||||
});
|
if (!loaded) {
|
||||||
}
|
if (preChildren) {
|
||||||
|
renderInto(el, fullPath, preChildren)
|
||||||
// Current page as a canonical, DECODED wiki path ("/" for root, no trailing
|
loaded = true
|
||||||
// slash otherwise). pathname is percent-encoded; the tree's entry names (and
|
} else {
|
||||||
// thus fullPath) are decoded, so we must decode here too or paths containing
|
loadChildren()
|
||||||
// spaces / non-ASCII never match a row and the chain never expands.
|
|
||||||
var activePath = (function () {
|
|
||||||
var p = window.location.pathname.replace(/\/+$/, '');
|
|
||||||
if (p === '') return '/';
|
|
||||||
try { return decodeURIComponent(p); } catch (e) { return p; }
|
|
||||||
})();
|
|
||||||
var activeRow = null;
|
|
||||||
|
|
||||||
function disabledRow(text) {
|
|
||||||
var row = document.createElement('div');
|
|
||||||
row.className = 'tree-row is-disabled';
|
|
||||||
row.textContent = text;
|
|
||||||
return row;
|
|
||||||
}
|
|
||||||
|
|
||||||
// renderInto fills containerEl with rows for `entries` (children of
|
|
||||||
// parentPath). Folders carrying a `children` array (the pre-expanded
|
|
||||||
// ancestor chain from ?expandTo) are opened immediately and recurse.
|
|
||||||
function renderInto(containerEl, parentPath, entries) {
|
|
||||||
if (!entries || entries.length === 0) {
|
|
||||||
containerEl.appendChild(disabledRow('(empty)'));
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
entries.forEach(function (entry) {
|
}
|
||||||
var built = buildRow(parentPath, entry);
|
|
||||||
containerEl.appendChild(built.row);
|
|
||||||
if (built.preExpand) built.open();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildRow(parentPath, entry) {
|
function close() {
|
||||||
var fullPath = joinPath(parentPath, entry.name);
|
if (!isOpen) return
|
||||||
var isFolder = entry.kind === 'folder';
|
if (childrenEl && childrenEl.parentNode) {
|
||||||
|
childrenEl.parentNode.removeChild(childrenEl)
|
||||||
var row = document.createElement('div');
|
}
|
||||||
row.className = 'tree-row';
|
chevron.textContent = "▸"
|
||||||
|
isOpen = false
|
||||||
var chevron = document.createElement('span');
|
|
||||||
chevron.className = 'tree-chevron';
|
|
||||||
if (isFolder) chevron.textContent = '▸'; // ▸
|
|
||||||
else chevron.classList.add('is-leaf');
|
|
||||||
row.appendChild(chevron);
|
|
||||||
|
|
||||||
|
|
||||||
var link = document.createElement('a');
|
|
||||||
link.className = 'tree-name ' + (isFolder ? 'tree-folder' : 'tree-file');
|
|
||||||
link.textContent = entry.name;
|
|
||||||
link.href = isFolder ? folderHref(fullPath) : fileHref(fullPath);
|
|
||||||
row.appendChild(link);
|
|
||||||
|
|
||||||
if (isFolder && fullPath === activePath) {
|
|
||||||
row.classList.add('is-active');
|
|
||||||
activeRow = row;
|
|
||||||
}
|
|
||||||
|
|
||||||
var preChildren = (isFolder && entry.children) ? entry.children : null;
|
|
||||||
var childrenEl = null;
|
|
||||||
var loaded = false;
|
|
||||||
var isOpen = false;
|
|
||||||
|
|
||||||
function ensureChildrenEl() {
|
|
||||||
if (!childrenEl) {
|
|
||||||
childrenEl = document.createElement('div');
|
|
||||||
childrenEl.className = 'tree-children';
|
|
||||||
}
|
|
||||||
return childrenEl;
|
|
||||||
}
|
|
||||||
|
|
||||||
function loadChildren() {
|
|
||||||
var el = ensureChildrenEl();
|
|
||||||
el.textContent = '';
|
|
||||||
el.appendChild(disabledRow('…'));
|
|
||||||
fetchFolder(fullPath).then(function (resp) {
|
|
||||||
el.textContent = '';
|
|
||||||
renderInto(el, fullPath, resp.entries);
|
|
||||||
loaded = true;
|
|
||||||
}).catch(function () {
|
|
||||||
el.textContent = '';
|
|
||||||
var err = document.createElement('div');
|
|
||||||
err.className = 'tree-row';
|
|
||||||
err.textContent = '(failed — tap to retry)';
|
|
||||||
err.addEventListener('click', function (e) {
|
|
||||||
e.stopPropagation();
|
|
||||||
loadChildren();
|
|
||||||
});
|
|
||||||
el.appendChild(err);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function open() {
|
|
||||||
if (!isFolder || isOpen) return;
|
|
||||||
var el = ensureChildrenEl();
|
|
||||||
row.parentNode.insertBefore(el, row.nextSibling);
|
|
||||||
chevron.textContent = '▾'; // ▾
|
|
||||||
isOpen = true;
|
|
||||||
if (!loaded) {
|
|
||||||
if (preChildren) {
|
|
||||||
renderInto(el, fullPath, preChildren);
|
|
||||||
loaded = true;
|
|
||||||
} else {
|
|
||||||
loadChildren();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function close() {
|
|
||||||
if (!isFolder || !isOpen) return;
|
|
||||||
if (childrenEl && childrenEl.parentNode) {
|
|
||||||
childrenEl.parentNode.removeChild(childrenEl);
|
|
||||||
}
|
|
||||||
chevron.textContent = '▸';
|
|
||||||
isOpen = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clicking the name link navigates (folder) or opens the file; clicking
|
|
||||||
// anywhere else on the row toggles expansion for folders.
|
|
||||||
row.addEventListener('click', function (e) {
|
|
||||||
if (e.target.closest('a.tree-name')) return;
|
|
||||||
if (!isFolder) return;
|
|
||||||
if (isOpen) close(); else open();
|
|
||||||
});
|
|
||||||
|
|
||||||
return { row: row, open: open, preExpand: !!preChildren };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function render() {
|
// Clicking the name link navigates (folder) or opens the file; clicking
|
||||||
container.textContent = '';
|
// anywhere else on the row toggles expansion for folders.
|
||||||
var listing = document.createElement('div');
|
row.addEventListener("click", function (e) {
|
||||||
container.appendChild(listing);
|
if (e.target.closest("a.tree-name")) return
|
||||||
listing.appendChild(disabledRow('…'));
|
if (isOpen) close()
|
||||||
|
else open()
|
||||||
|
})
|
||||||
|
|
||||||
fetchFolder('/', activePath === '/' ? '' : activePath).then(function (resp) {
|
return { row: row, open: open, preExpand: !!preChildren }
|
||||||
listing.textContent = '';
|
}
|
||||||
renderInto(listing, '/', resp.entries);
|
|
||||||
if (activeRow) {
|
|
||||||
try { activeRow.scrollIntoView({ block: 'nearest' }); } catch (e) {}
|
|
||||||
}
|
|
||||||
}).catch(function () {
|
|
||||||
listing.textContent = '';
|
|
||||||
var err = document.createElement('div');
|
|
||||||
err.className = 'tree-row';
|
|
||||||
err.textContent = '(failed — tap to retry)';
|
|
||||||
err.addEventListener('click', function () { render(); });
|
|
||||||
listing.appendChild(err);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function setupMenuItem() {
|
function render() {
|
||||||
var specials = document.querySelector('.actions-special');
|
container.textContent = ""
|
||||||
if (!specials) return;
|
var listing = document.createElement("div")
|
||||||
|
container.appendChild(listing)
|
||||||
|
listing.appendChild(disabledRow("…"))
|
||||||
|
|
||||||
var item = document.createElement("button");
|
fetchFolder("/", activePath === "/" ? "" : activePath)
|
||||||
item.type = "button";
|
.then(function (resp) {
|
||||||
item.className = "btn btn-block";
|
listing.textContent = ""
|
||||||
item.title = "Folders";
|
renderInto(listing, "/", resp.entries)
|
||||||
item.textContent = "FOLDERS";
|
if (activeRow) {
|
||||||
item.addEventListener("click", function () {
|
try {
|
||||||
if (typeof openOverlay === "function") openOverlay(container);
|
activeRow.scrollIntoView({ block: "nearest" })
|
||||||
});
|
} catch (e) {}
|
||||||
specials.appendChild(item);
|
}
|
||||||
}
|
})
|
||||||
|
.catch(function () {
|
||||||
|
listing.textContent = ""
|
||||||
|
var err = document.createElement("div")
|
||||||
|
err.className = "tree-row"
|
||||||
|
err.textContent = "(failed — tap to retry)"
|
||||||
|
err.addEventListener("click", function () {
|
||||||
|
render()
|
||||||
|
})
|
||||||
|
listing.appendChild(err)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
render();
|
function setupMenuItem() {
|
||||||
setupMenuItem();
|
var specials = document.querySelector(".actions-special")
|
||||||
})();
|
if (!specials) return
|
||||||
|
|
||||||
|
var item = document.createElement("button")
|
||||||
|
item.type = "button"
|
||||||
|
item.className = "btn btn-block"
|
||||||
|
item.title = "Folders"
|
||||||
|
item.textContent = "FOLDERS"
|
||||||
|
item.addEventListener("click", function () {
|
||||||
|
if (typeof openOverlay === "function") openOverlay(container)
|
||||||
|
})
|
||||||
|
specials.appendChild(item)
|
||||||
|
}
|
||||||
|
|
||||||
|
render()
|
||||||
|
setupMenuItem()
|
||||||
|
})()
|
||||||
|
|||||||
@@ -40,18 +40,16 @@ func (h *handler) handleTree(w http.ResponseWriter, r *http.Request, urlPath, fs
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
entries, err := listTreeEntries(fsPath)
|
foldersOnly := r.URL.Query().Has("foldersOnly")
|
||||||
|
|
||||||
|
entries, err := listTreeEntries(fsPath, foldersOnly)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, "read failed", http.StatusInternalServerError)
|
http.Error(w, "read failed", http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// expandTo asks for a nested listing: each folder along the ancestor chain
|
|
||||||
// carries its own children, recursively, down to the target. Used by the
|
|
||||||
// tree sidebar to render the current page's chain in one request. The flat
|
|
||||||
// picker omits expandTo and is unaffected.
|
|
||||||
if expandTo := r.URL.Query().Get("expandTo"); expandTo != "" {
|
if expandTo := r.URL.Query().Get("expandTo"); expandTo != "" {
|
||||||
expandTreeChain(fsPath, entries, treePathSegments(expandTo))
|
expandTreeChain(fsPath, entries, treePathSegments(expandTo), foldersOnly)
|
||||||
}
|
}
|
||||||
|
|
||||||
resp := treeResponse{Path: canonicalTreePath(urlPath), Entries: entries}
|
resp := treeResponse{Path: canonicalTreePath(urlPath), Entries: entries}
|
||||||
@@ -70,8 +68,8 @@ func canonicalTreePath(urlPath string) string {
|
|||||||
|
|
||||||
// listTreeEntries returns the immediate children of fsPath, filtering hidden
|
// listTreeEntries returns the immediate children of fsPath, filtering hidden
|
||||||
// entries and index.md. Folders are listed before files; both groups are
|
// entries and index.md. Folders are listed before files; both groups are
|
||||||
// sorted alphabetically.
|
// sorted alphabetically. foldersOnly will not list any individual files at all.
|
||||||
func listTreeEntries(fsPath string) ([]treeEntry, error) {
|
func listTreeEntries(fsPath string, foldersOnly bool) ([]treeEntry, error) {
|
||||||
raw, err := os.ReadDir(fsPath)
|
raw, err := os.ReadDir(fsPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -85,7 +83,7 @@ func listTreeEntries(fsPath string) ([]treeEntry, error) {
|
|||||||
if e.IsDir() {
|
if e.IsDir() {
|
||||||
folders = append(folders, treeEntry{Name: name, Kind: "folder"})
|
folders = append(folders, treeEntry{Name: name, Kind: "folder"})
|
||||||
} else {
|
} else {
|
||||||
if name == "index.md" {
|
if foldersOnly || name == "index.md" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
files = append(files, treeEntry{Name: name, Kind: "file"})
|
files = append(files, treeEntry{Name: name, Kind: "file"})
|
||||||
@@ -113,7 +111,7 @@ func treePathSegments(p string) []string {
|
|||||||
// far as it still exists. Segments only ever match real directory names from
|
// far as it still exists. Segments only ever match real directory names from
|
||||||
// listTreeEntries (no "." or ".." entries), so this cannot traverse outside the
|
// listTreeEntries (no "." or ".." entries), so this cannot traverse outside the
|
||||||
// listed tree.
|
// listed tree.
|
||||||
func expandTreeChain(fsPath string, entries []treeEntry, segs []string) {
|
func expandTreeChain(fsPath string, entries []treeEntry, segs []string, foldersOnly bool) {
|
||||||
if len(segs) == 0 {
|
if len(segs) == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -122,12 +120,12 @@ func expandTreeChain(fsPath string, entries []treeEntry, segs []string) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
childFs := filepath.Join(fsPath, segs[0])
|
childFs := filepath.Join(fsPath, segs[0])
|
||||||
kids, err := listTreeEntries(childFs)
|
kids, err := listTreeEntries(childFs, foldersOnly)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
entries[i].Children = kids
|
entries[i].Children = kids
|
||||||
expandTreeChain(childFs, entries[i].Children, segs[1:])
|
expandTreeChain(childFs, entries[i].Children, segs[1:], foldersOnly)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user