mirror of
https://github.com/osmarks/mycorrhiza.git
synced 2024-12-12 13:30:26 +00:00
Render tree
This commit is contained in:
parent
cea18eaa03
commit
6e50ecf6a3
96
genealogy.go
96
genealogy.go
@ -1,9 +1,14 @@
|
|||||||
/* Genealogy is all about relationships between hyphae. For now, the only goal of this file is to help find children of hyphae as they are not marked during the hypha search phase.
|
/* Genealogy is all about relationships between hyphae.*/
|
||||||
|
|
||||||
TODO: make use of family relations.
|
|
||||||
*/
|
|
||||||
package main
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"path/filepath"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
// setRelations fills in all children names based on what hyphae call their parents.
|
// setRelations fills in all children names based on what hyphae call their parents.
|
||||||
func setRelations(hyphae map[string]*Hypha) {
|
func setRelations(hyphae map[string]*Hypha) {
|
||||||
for name, h := range hyphae {
|
for name, h := range hyphae {
|
||||||
@ -17,3 +22,86 @@ func setRelations(hyphae map[string]*Hypha) {
|
|||||||
func (h *Hypha) AddChild(childName string) {
|
func (h *Hypha) AddChild(childName string) {
|
||||||
h.ChildrenNames = append(h.ChildrenNames, childName)
|
h.ChildrenNames = append(h.ChildrenNames, childName)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
// Parameter `limit` is unused now but it is meant to limit how many subhyphae can be shown.
|
||||||
|
func GetTree(name string, root bool, limit ...int) *Tree {
|
||||||
|
t := &Tree{Name: name, Root: root}
|
||||||
|
for hyphaName, _ := range hyphae {
|
||||||
|
t.compareNamesAndAppend(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 (t *Tree) compareNamesAndAppend(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, 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 {
|
||||||
|
html += navitreeEntry(ancestor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
html += navitreeEntry(t.Name)
|
||||||
|
|
||||||
|
if t.Root {
|
||||||
|
for _, siblingName := range t.Siblings {
|
||||||
|
html += navitreeEntry(siblingName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 string) string {
|
||||||
|
return fmt.Sprintf(`<li class="navitree__entry">
|
||||||
|
<a class="navitree__link" href="/%s">%s</a>
|
||||||
|
</li>
|
||||||
|
`, name, filepath.Base(name))
|
||||||
|
}
|
||||||
|
20
handlers.go
20
handlers.go
@ -167,12 +167,21 @@ func HandlerUpdate(w http.ResponseWriter, rq *http.Request) {
|
|||||||
vars := mux.Vars(rq)
|
vars := mux.Vars(rq)
|
||||||
log.Println("Attempt to update hypha", mux.Vars(rq)["hypha"])
|
log.Println("Attempt to update hypha", mux.Vars(rq)["hypha"])
|
||||||
h, isNew := getHypha(vars["hypha"])
|
h, isNew := getHypha(vars["hypha"])
|
||||||
oldRev := h.GetNewestRevision()
|
var oldRev Revision
|
||||||
|
if !isNew {
|
||||||
|
oldRev = h.GetNewestRevision()
|
||||||
|
} else {
|
||||||
|
h = &Hypha{
|
||||||
|
FullName: vars["hypha"],
|
||||||
|
Path: filepath.Join(rootWikiDir, vars["hypha"]),
|
||||||
|
Revisions: make(map[string]*Revision),
|
||||||
|
parentName: filepath.Dir(vars["hypha"]),
|
||||||
|
}
|
||||||
|
h.CreateDir()
|
||||||
|
oldRev = Revision{}
|
||||||
|
}
|
||||||
newRev := revisionFromHttpData(h, rq)
|
newRev := revisionFromHttpData(h, rq)
|
||||||
|
|
||||||
if isNew {
|
|
||||||
h.CreateDir()
|
|
||||||
}
|
|
||||||
err := writeTextFileFromHttpData(newRev, rq)
|
err := writeTextFileFromHttpData(newRev, rq)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
@ -186,6 +195,9 @@ func HandlerUpdate(w http.ResponseWriter, rq *http.Request) {
|
|||||||
|
|
||||||
h.Revisions[newRev.IdAsStr()] = newRev
|
h.Revisions[newRev.IdAsStr()] = newRev
|
||||||
h.SaveJson()
|
h.SaveJson()
|
||||||
|
if isNew {
|
||||||
|
hyphae[h.FullName] = h
|
||||||
|
}
|
||||||
|
|
||||||
log.Println("Current hyphae storage is", hyphae)
|
log.Println("Current hyphae storage is", hyphae)
|
||||||
|
|
||||||
|
2
hypha.go
2
hypha.go
@ -66,7 +66,7 @@ func (h *Hypha) MetaJsonPath() string {
|
|||||||
// CreateDir creates directory where the hypha must reside.
|
// CreateDir creates directory where the hypha must reside.
|
||||||
// It is meant to be used with new hyphae.
|
// It is meant to be used with new hyphae.
|
||||||
func (h *Hypha) CreateDir() error {
|
func (h *Hypha) CreateDir() error {
|
||||||
return os.MkdirAll(h.Path, 0644)
|
return os.MkdirAll(h.Path, os.ModePerm)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SaveJson dumps the hypha's metadata to `meta.json` file.
|
// SaveJson dumps the hypha's metadata to `meta.json` file.
|
||||||
|
@ -3,9 +3,7 @@ package main
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
|
||||||
"path"
|
"path"
|
||||||
"path/filepath"
|
|
||||||
"text/template"
|
"text/template"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -27,9 +25,10 @@ func EditHyphaPage(name, textMime, content, tags string) string {
|
|||||||
// HyphaPage returns HTML page of hypha viewer.
|
// HyphaPage returns HTML page of hypha viewer.
|
||||||
func HyphaPage(rev Revision, content string) string {
|
func HyphaPage(rev Revision, content string) string {
|
||||||
sidebar := DefaultSidebar
|
sidebar := DefaultSidebar
|
||||||
bside, err := ioutil.ReadFile(filepath.Join(templatesDir, "Hypha/view/sidebar.html"))
|
if bside := renderFromMap(map[string]string{
|
||||||
if err == nil {
|
"Tree": GetTree(rev.FullName, true).AsHtml(),
|
||||||
sidebar = string(bside)
|
}, "Hypha/view/sidebar.html"); bside != "" {
|
||||||
|
sidebar = bside
|
||||||
}
|
}
|
||||||
keys := map[string]string{
|
keys := map[string]string{
|
||||||
"Title": fmt.Sprintf(TitleTemplate, rev.FullName),
|
"Title": fmt.Sprintf(TitleTemplate, rev.FullName),
|
||||||
|
Before Width: | Height: | Size: 427 KiB After Width: | Height: | Size: 427 KiB |
@ -39,7 +39,7 @@
|
|||||||
},
|
},
|
||||||
"4": {
|
"4": {
|
||||||
"tags": null,
|
"tags": null,
|
||||||
"name": "",
|
"name": "Apple",
|
||||||
"comment": "copypaste from wikipedia",
|
"comment": "copypaste from wikipedia",
|
||||||
"author": "",
|
"author": "",
|
||||||
"time": 1592663126,
|
"time": 1592663126,
|
||||||
|
3
w/m/Fruit/Pear/1.markdown
Normal file
3
w/m/Fruit/Pear/1.markdown
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
A **pear** is a sweet fruit, usually with a green skin and a lot of juice, that has a round base and is slightly pointed towards the stem.
|
||||||
|
|
||||||
|
Source of info: [cambridge dict](https://dictionary.cambridge.org/ru/словарь/английский/pear)
|
19
w/m/Fruit/Pear/meta.json
Normal file
19
w/m/Fruit/Pear/meta.json
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"views": 0,
|
||||||
|
"deleted": false,
|
||||||
|
"revisions": {
|
||||||
|
"1": {
|
||||||
|
"tags": [
|
||||||
|
""
|
||||||
|
],
|
||||||
|
"name": "Pear",
|
||||||
|
"comment": "Create Fruit/Pear",
|
||||||
|
"author": "",
|
||||||
|
"time": 1592834186,
|
||||||
|
"text_mime": "text/markdown",
|
||||||
|
"binary_mime": "",
|
||||||
|
"text_name": "1.markdown",
|
||||||
|
"binary_name": ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,8 +1,7 @@
|
|||||||
<div class="hypha-actions">
|
<ul class="hypha-actions">
|
||||||
<ul>
|
<li><a href="?action=edit">Edit</a></li>
|
||||||
<li><a href="?action=edit">Edit</a></li>
|
<li><a href="?action=getBinary">Download</a></li>
|
||||||
<li><a href="?action=getBinary">Download</a></li>
|
<li><a href="?action=zen">Zen mode</a></li>
|
||||||
<li><a href="?action=zen">Zen mode</a></li>
|
<li><a href="?action=raw">View raw</a></li>
|
||||||
<li><a href="?action=raw">View raw</a></li>
|
</ul>
|
||||||
</ul>
|
{{ .Tree }}
|
||||||
</div>
|
|
||||||
|
Loading…
Reference in New Issue
Block a user