mirror of
https://github.com/osmarks/mycorrhiza.git
synced 2024-10-30 19:56:16 +00:00
141 lines
3.9 KiB
Go
141 lines
3.9 KiB
Go
package tree
|
|
|
|
import (
|
|
"fmt"
|
|
"path"
|
|
"sort"
|
|
"strings"
|
|
|
|
"github.com/bouncepaw/mycorrhiza/hyphae"
|
|
"github.com/bouncepaw/mycorrhiza/util"
|
|
)
|
|
|
|
type sibling struct {
|
|
name string
|
|
hasChildren bool
|
|
}
|
|
|
|
func (s *sibling) checkThisChild(hyphaName string) {
|
|
if !s.hasChildren && path.Dir(hyphaName) == s.name {
|
|
s.hasChildren = true
|
|
}
|
|
}
|
|
|
|
func (s *sibling) asHTML() string {
|
|
class := "navitree__entry navitree__sibling"
|
|
if s.hasChildren {
|
|
class += " navitree__sibling_fertile navitree__entry_fertile"
|
|
} else {
|
|
class += " navitree__sibling_infertile navitree__entry_infertile"
|
|
}
|
|
return fmt.Sprintf(
|
|
`<li class="%s"><a class="navitree__link" href="/hypha/%s">%s</a></li>`,
|
|
class,
|
|
s.name,
|
|
util.BeautifulName(path.Base(s.name)),
|
|
)
|
|
}
|
|
|
|
type mainFamilyMember struct {
|
|
name string
|
|
children []*mainFamilyMember
|
|
}
|
|
|
|
func (m *mainFamilyMember) checkThisChild(hyphaName string) (adopted bool) {
|
|
if path.Dir(hyphaName) == m.name {
|
|
m.children = append(m.children, &mainFamilyMember{
|
|
name: hyphaName,
|
|
children: make([]*mainFamilyMember, 0),
|
|
})
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
func (m *mainFamilyMember) asHTML() string {
|
|
if len(m.children) == 0 {
|
|
return fmt.Sprintf(`<li class="subhyphae__entry"><a class="subhyphae__link" href="/hypha/%s">%s</a></li>`, m.name, util.BeautifulName(path.Base(m.name)))
|
|
}
|
|
sort.Slice(m.children, func(i, j int) bool {
|
|
return m.children[i].name < m.children[j].name
|
|
})
|
|
html := fmt.Sprintf(`<li class="subhyphae__entry"><a class="subhyphae__link" href="/hypha/%s">%s</a><ul>`, m.name, util.BeautifulName(path.Base(m.name)))
|
|
for _, child := range m.children {
|
|
html += child.asHTML()
|
|
}
|
|
return html + `</li></ul></li>`
|
|
}
|
|
|
|
func mainFamilyFromPool(hyphaName string, subhyphaePool map[string]bool) *mainFamilyMember {
|
|
var (
|
|
nestLevel = strings.Count(hyphaName, "/")
|
|
adopted = make([]*mainFamilyMember, 0)
|
|
)
|
|
for subhyphaName, _ := range subhyphaePool {
|
|
subnestLevel := strings.Count(subhyphaName, "/")
|
|
if subnestLevel-1 == nestLevel && path.Dir(subhyphaName) == hyphaName {
|
|
delete(subhyphaePool, subhyphaName)
|
|
adopted = append(adopted, mainFamilyFromPool(subhyphaName, subhyphaePool))
|
|
}
|
|
}
|
|
return &mainFamilyMember{name: hyphaName, children: adopted}
|
|
}
|
|
|
|
func subhyphaeMatrix(hyphaName string, subhyphaePool map[string]bool) string {
|
|
var html string
|
|
children := mainFamilyFromPool(hyphaName, subhyphaePool).children
|
|
sort.Slice(children, func(i, j int) bool {
|
|
return children[i].name < children[j].name
|
|
})
|
|
for _, child := range children {
|
|
html += child.asHTML()
|
|
}
|
|
return html
|
|
}
|
|
|
|
// Tree generates a tree for `hyphaName` as html and returns next and previous hyphae if any.
|
|
func Tree(hyphaName string) (relatives, subhyphae, prev, next string) {
|
|
var (
|
|
// One of the siblings is the hypha with name `hyphaName`
|
|
siblings = findSiblings(hyphaName)
|
|
subhyphaePool = make(map[string]bool)
|
|
I int
|
|
)
|
|
for h := range hyphae.YieldExistingHyphae() {
|
|
for _, s := range siblings {
|
|
s.checkThisChild(h.Name)
|
|
}
|
|
if strings.HasPrefix(h.Name, hyphaName+"/") {
|
|
subhyphaePool[h.Name] = true
|
|
}
|
|
}
|
|
for i, s := range siblings {
|
|
if s.name == hyphaName {
|
|
I = i
|
|
relatives += fmt.Sprintf(`<li class="navitree__entry navitree__entry_this"><span>%s</span></li>`, util.BeautifulName(path.Base(hyphaName)))
|
|
} else {
|
|
relatives += s.asHTML()
|
|
}
|
|
}
|
|
if I != 0 {
|
|
prev = siblings[I-1].name
|
|
}
|
|
if I != len(siblings)-1 {
|
|
next = siblings[I+1].name
|
|
}
|
|
return fmt.Sprintf(`<ul class="navitree">%s</ul>`, relatives), subhyphaeMatrix(hyphaName, subhyphaePool), prev, next
|
|
}
|
|
|
|
func findSiblings(hyphaName string) []*sibling {
|
|
siblings := []*sibling{&sibling{name: hyphaName, hasChildren: true}}
|
|
for h := range hyphae.YieldExistingHyphae() {
|
|
if path.Dir(hyphaName) == path.Dir(h.Name) && hyphaName != h.Name {
|
|
siblings = append(siblings, &sibling{name: h.Name, hasChildren: false})
|
|
}
|
|
}
|
|
sort.Slice(siblings, func(i, j int) bool {
|
|
return siblings[i].name < siblings[j].name
|
|
})
|
|
return siblings
|
|
}
|