2020-06-25 17:18:50 +00:00
|
|
|
package fs
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"log"
|
|
|
|
"path/filepath"
|
|
|
|
"sort"
|
|
|
|
"strings"
|
2020-06-30 18:13:46 +00:00
|
|
|
|
|
|
|
"github.com/bouncepaw/mycorrhiza/util"
|
2020-06-25 17:18:50 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
func (s *Storage) RenderHypha(h *Hypha) {
|
|
|
|
}
|
|
|
|
|
|
|
|
// If Name == "", the tree is empty.
|
|
|
|
type Tree struct {
|
|
|
|
Name string
|
|
|
|
Ancestors []string
|
|
|
|
Siblings []string
|
|
|
|
Descendants []*Tree
|
|
|
|
Root bool
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetTree generates a Tree for the given hypha name.
|
|
|
|
// It can also generate trees for non-existent hyphae, that's why we use `name string` instead of making it a method on `Hypha`.
|
|
|
|
// In `root` is `false`, siblings will not be fetched.
|
|
|
|
func (s *Storage) GetTree(name string, root bool) *Tree {
|
2020-06-30 18:13:46 +00:00
|
|
|
name = util.UrlToCanonical(name)
|
2020-06-25 17:18:50 +00:00
|
|
|
t := &Tree{Name: name, Root: root}
|
|
|
|
for hyphaName, _ := range s.paths {
|
|
|
|
s.compareNamesAndAppend(t, hyphaName)
|
|
|
|
}
|
|
|
|
sort.Slice(t.Ancestors, func(i, j int) bool {
|
|
|
|
return strings.Count(t.Ancestors[i], "/") < strings.Count(t.Ancestors[j], "/")
|
|
|
|
})
|
|
|
|
sort.Strings(t.Siblings)
|
|
|
|
sort.Slice(t.Descendants, func(i, j int) bool {
|
|
|
|
a := t.Descendants[i].Name
|
|
|
|
b := t.Descendants[j].Name
|
|
|
|
return len(a) < len(b)
|
|
|
|
})
|
|
|
|
log.Printf("Generate tree for %v: %v %v\n", t.Name, t.Ancestors, t.Siblings)
|
|
|
|
return t
|
|
|
|
}
|
|
|
|
|
|
|
|
// Compares names appends name2 to an array of `t`:
|
|
|
|
func (s *Storage) compareNamesAndAppend(t *Tree, name2 string) {
|
|
|
|
switch {
|
|
|
|
case t.Name == name2:
|
|
|
|
case strings.HasPrefix(t.Name, name2):
|
|
|
|
t.Ancestors = append(t.Ancestors, name2)
|
|
|
|
case t.Root && (strings.Count(t.Name, "/") == strings.Count(name2, "/") &&
|
|
|
|
(filepath.Dir(t.Name) == filepath.Dir(name2))):
|
|
|
|
t.Siblings = append(t.Siblings, name2)
|
|
|
|
case strings.HasPrefix(name2, t.Name):
|
|
|
|
t.Descendants = append(t.Descendants, s.GetTree(name2, false))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// asHtml returns HTML representation of a tree.
|
|
|
|
// It recursively itself on the tree's children.
|
|
|
|
// TODO: redo with templates. I'm not in mood for it now.
|
|
|
|
func (t *Tree) AsHtml() (html string) {
|
|
|
|
if t.Name == "" {
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
html += `<ul class="navitree__node">`
|
|
|
|
if t.Root {
|
|
|
|
for _, ancestor := range t.Ancestors {
|
2020-06-30 18:13:46 +00:00
|
|
|
html += navitreeEntry(util.CanonicalToDisplay(ancestor), "navitree__ancestor")
|
2020-06-25 17:18:50 +00:00
|
|
|
}
|
|
|
|
for _, siblingName := range t.Siblings {
|
2020-06-30 18:13:46 +00:00
|
|
|
html += navitreeEntry(util.CanonicalToDisplay(siblingName), "navitree__sibling")
|
2020-06-25 17:18:50 +00:00
|
|
|
}
|
2020-06-30 18:13:46 +00:00
|
|
|
html += navitreeEntry(util.CanonicalToDisplay(t.Name), "navitree__pagename")
|
2020-06-28 18:04:26 +00:00
|
|
|
} else {
|
2020-06-30 18:13:46 +00:00
|
|
|
html += navitreeEntry(util.CanonicalToDisplay(t.Name), "navitree__name")
|
2020-06-25 17:18:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for _, subtree := range t.Descendants {
|
|
|
|
html += subtree.AsHtml()
|
|
|
|
}
|
|
|
|
|
|
|
|
html += `</ul>`
|
|
|
|
return html
|
|
|
|
}
|
|
|
|
|
|
|
|
// navitreeEntry is a small utility function that makes generating html easier.
|
|
|
|
// Someone please redo it in templates.
|
|
|
|
func navitreeEntry(name, class string) string {
|
2020-06-28 18:04:26 +00:00
|
|
|
return fmt.Sprintf(`<li class="navitree__entry %s">
|
|
|
|
<a class="navitree__link" href="/%s">%s</a>
|
2020-06-25 17:18:50 +00:00
|
|
|
</li>
|
2020-07-03 19:20:56 +00:00
|
|
|
`, class, ":"+util.DisplayToCanonical(name), filepath.Base(name))
|
2020-06-25 17:18:50 +00:00
|
|
|
}
|