From b453d713644b11176afdff9067f8e49d3ee8082b Mon Sep 17 00:00:00 2001 From: Timur Ismagilov Date: Fri, 31 Dec 2021 00:59:28 +0500 Subject: [PATCH] Backlinks: Make less things exported, better wording --- hyphae/backlinks/backlinks.go | 191 ++++------ hyphae/backlinks/hooks.go | 49 +++ shroom/delete.go | 2 +- shroom/rename.go | 2 +- shroom/upload.go | 2 +- views/stuff.qtpl | 7 +- views/stuff.qtpl.go | 647 +++++++++++++++++----------------- 7 files changed, 452 insertions(+), 448 deletions(-) create mode 100644 hyphae/backlinks/hooks.go diff --git a/hyphae/backlinks/backlinks.go b/hyphae/backlinks/backlinks.go index 444f373..f56dfee 100644 --- a/hyphae/backlinks/backlinks.go +++ b/hyphae/backlinks/backlinks.go @@ -2,16 +2,64 @@ package backlinks import ( - "github.com/bouncepaw/mycorrhiza/hyphae" - "github.com/bouncepaw/mycorrhiza/util" "os" - "github.com/bouncepaw/mycomarkup/v3" - "github.com/bouncepaw/mycomarkup/v3/links" - "github.com/bouncepaw/mycomarkup/v3/mycocontext" - "github.com/bouncepaw/mycomarkup/v3/tools" + "github.com/bouncepaw/mycorrhiza/hyphae" + "github.com/bouncepaw/mycorrhiza/util" ) +// YieldHyphaBacklinks gets backlinks for the desired hypha, sorts and yields them one by one. +func YieldHyphaBacklinks(hyphaName string) <-chan string { + hyphaName = util.CanonicalName(hyphaName) + out := make(chan string) + sorted := hyphae.PathographicSort(out) + go func() { + backlinks, exists := backlinkIndex[hyphaName] + if exists { + for link := range backlinks { + out <- link + } + } + close(out) + }() + return sorted +} + +var backlinkConveyor = make(chan backlinkIndexOperation) // No need to buffer because these operations are rare. + +// RunBacklinksConveyor runs an index operation processing loop. Call it somewhere in main. +func RunBacklinksConveyor() { + // It is supposed to run as a goroutine for all the time. So, don't blame the infinite loop. + defer close(backlinkConveyor) + for { + (<-backlinkConveyor).apply() + } +} + +var backlinkIndex = make(map[string]linkSet) + +// IndexBacklinks traverses all text hyphae, extracts links from them and forms an initial index. Call it when indexing and reindexing hyphae. +func IndexBacklinks() { + // It is safe to ignore the mutex, because there is only one worker. + for h := range hyphae.FilterTextHyphae(hyphae.YieldExistingHyphae()) { + foundLinks := extractHyphaLinksFromContent(h.Name, fetchText(h)) + for _, link := range foundLinks { + if _, exists := backlinkIndex[link]; !exists { + backlinkIndex[link] = make(linkSet) + } + backlinkIndex[link][h.Name] = struct{}{} + } + } +} + +// BacklinksCount returns the amount of backlinks to the hypha. +func BacklinksCount(h *hyphae.Hypha) int { + if _, exists := backlinkIndex[h.Name]; exists { + return len(backlinkIndex[h.Name]) + } + return 0 +} + // Using set here seems like the most appropriate solution type linkSet map[string]struct{} @@ -41,18 +89,18 @@ type backlinkIndexOperation interface { // backlinkIndexEdit contains data for backlink index update after a hypha edit type backlinkIndexEdit struct { - Name string - OldLinks []string - NewLinks []string + name string + oldLinks []string + newLinks []string } -// Apply changes backlink index respective to the operation data +// apply changes backlink index respective to the operation data func (op backlinkIndexEdit) apply() { - oldLinks := toLinkSet(op.OldLinks) - newLinks := toLinkSet(op.NewLinks) + oldLinks := toLinkSet(op.oldLinks) + newLinks := toLinkSet(op.newLinks) for link := range oldLinks { if _, exists := newLinks[link]; !exists { - delete(backlinkIndex[link], op.Name) + delete(backlinkIndex[link], op.name) } } for link := range newLinks { @@ -60,134 +108,39 @@ func (op backlinkIndexEdit) apply() { if _, exists := backlinkIndex[link]; !exists { backlinkIndex[link] = make(linkSet) } - backlinkIndex[link][op.Name] = struct{}{} + backlinkIndex[link][op.name] = struct{}{} } } } // backlinkIndexDeletion contains data for backlink index update after a hypha deletion type backlinkIndexDeletion struct { - Name string - Links []string + name string + links []string } // apply changes backlink index respective to the operation data func (op backlinkIndexDeletion) apply() { - for _, link := range op.Links { + for _, link := range op.links { if lSet, exists := backlinkIndex[link]; exists { - delete(lSet, op.Name) + delete(lSet, op.name) } } } // backlinkIndexRenaming contains data for backlink index update after a hypha renaming type backlinkIndexRenaming struct { - OldName string - NewName string - Links []string + oldName string + newName string + links []string } // Apply changes backlink index respective to the operation data func (op backlinkIndexRenaming) apply() { - for _, link := range op.Links { + for _, link := range op.links { if lSet, exists := backlinkIndex[link]; exists { - delete(lSet, op.OldName) - backlinkIndex[link][op.NewName] = struct{}{} + delete(lSet, op.oldName) + backlinkIndex[link][op.newName] = struct{}{} } } } - -var backlinkIndex = make(map[string]linkSet) -var backlinkConveyor = make(chan backlinkIndexOperation, 64) - -// I hope, the buffer size is enough -- chekoopa -// Do we really need the buffer though? Dunno -- bouncepaw - -// IndexBacklinks traverses all text hyphae, extracts links from them and forms an initial index -func IndexBacklinks() { - // It is safe to ignore the mutex, because there is only one worker. - src := hyphae.FilterTextHyphae(hyphae.YieldExistingHyphae()) - for h := range src { - foundLinks := extractHyphaLinksFromContent(h.Name, fetchText(h)) - for _, link := range foundLinks { - if _, exists := backlinkIndex[link]; !exists { - backlinkIndex[link] = make(linkSet) - } - backlinkIndex[link][h.Name] = struct{}{} - } - } -} - -// RunBacklinksConveyor runs an index operation processing loop -func RunBacklinksConveyor() { - // It is supposed to run as a goroutine for all the time. So, don't blame the infinite loop. - defer close(backlinkConveyor) - for { - (<-backlinkConveyor).apply() - } -} - -// BacklinksCount returns the amount of backlinks to the hypha. -func BacklinksCount(h *hyphae.Hypha) int { - if _, exists := backlinkIndex[h.Name]; exists { - return len(backlinkIndex[h.Name]) - } - return 0 -} - -// BacklinksOnEdit is a creation/editing hook for backlinks index -func BacklinksOnEdit(h *hyphae.Hypha, oldText string) { - oldLinks := extractHyphaLinksFromContent(h.Name, oldText) - newLinks := extractHyphaLinks(h) - backlinkConveyor <- backlinkIndexEdit{h.Name, oldLinks, newLinks} -} - -// BacklinksOnDelete is a deletion hook for backlinks index -func BacklinksOnDelete(h *hyphae.Hypha, oldText string) { - oldLinks := extractHyphaLinksFromContent(h.Name, oldText) - backlinkConveyor <- backlinkIndexDeletion{h.Name, oldLinks} -} - -// BacklinksOnRename is a renaming hook for backlinks index -func BacklinksOnRename(h *hyphae.Hypha, oldName string) { - actualLinks := extractHyphaLinks(h) - backlinkConveyor <- backlinkIndexRenaming{oldName, h.Name, actualLinks} -} - -// YieldHyphaBacklinks gets backlinks for a desired hypha, sorts and iterates over them -func YieldHyphaBacklinks(query string) <-chan string { - hyphaName := util.CanonicalName(query) - out := make(chan string) - sorted := hyphae.PathographicSort(out) - go func() { - backlinks, exists := backlinkIndex[hyphaName] - if exists { - for link := range backlinks { - out <- link - } - } - close(out) - }() - return sorted -} - -// extractHyphaLinks extracts hypha links from a desired hypha -func extractHyphaLinks(h *hyphae.Hypha) []string { - return extractHyphaLinksFromContent(h.Name, fetchText(h)) -} - -// extractHyphaLinksFromContent extracts local hypha links from the provided text. -func extractHyphaLinksFromContent(hyphaName string, contents string) []string { - ctx, _ := mycocontext.ContextFromStringInput(hyphaName, contents) - linkVisitor, getLinks := tools.LinkVisitor(ctx) - // Ignore the result of BlockTree because we call it for linkVisitor. - _ = mycomarkup.BlockTree(ctx, linkVisitor) - foundLinks := getLinks() - var result []string - for _, link := range foundLinks { - if link.OfKind(links.LinkLocalHypha) { - result = append(result, link.TargetHypha()) - } - } - return result -} diff --git a/hyphae/backlinks/hooks.go b/hyphae/backlinks/hooks.go new file mode 100644 index 0000000..eb3fa77 --- /dev/null +++ b/hyphae/backlinks/hooks.go @@ -0,0 +1,49 @@ +package backlinks + +import ( + "github.com/bouncepaw/mycomarkup/v3" + "github.com/bouncepaw/mycomarkup/v3/links" + "github.com/bouncepaw/mycomarkup/v3/mycocontext" + "github.com/bouncepaw/mycomarkup/v3/tools" + "github.com/bouncepaw/mycorrhiza/hyphae" +) + +// UpdateBacklinksAfterEdit is a creation/editing hook for backlinks index +func UpdateBacklinksAfterEdit(h *hyphae.Hypha, oldText string) { + oldLinks := extractHyphaLinksFromContent(h.Name, oldText) + newLinks := extractHyphaLinks(h) + backlinkConveyor <- backlinkIndexEdit{h.Name, oldLinks, newLinks} +} + +// UpdateBacklinksAfterDelete is a deletion hook for backlinks index +func UpdateBacklinksAfterDelete(h *hyphae.Hypha, oldText string) { + oldLinks := extractHyphaLinksFromContent(h.Name, oldText) + backlinkConveyor <- backlinkIndexDeletion{h.Name, oldLinks} +} + +// UpdateBacklinksAfterRename is a renaming hook for backlinks index +func UpdateBacklinksAfterRename(h *hyphae.Hypha, oldName string) { + actualLinks := extractHyphaLinks(h) + backlinkConveyor <- backlinkIndexRenaming{oldName, h.Name, actualLinks} +} + +// extractHyphaLinks extracts hypha links from a desired hypha +func extractHyphaLinks(h *hyphae.Hypha) []string { + return extractHyphaLinksFromContent(h.Name, fetchText(h)) +} + +// extractHyphaLinksFromContent extracts local hypha links from the provided text. +func extractHyphaLinksFromContent(hyphaName string, contents string) []string { + ctx, _ := mycocontext.ContextFromStringInput(hyphaName, contents) + linkVisitor, getLinks := tools.LinkVisitor(ctx) + // Ignore the result of BlockTree because we call it for linkVisitor. + _ = mycomarkup.BlockTree(ctx, linkVisitor) + foundLinks := getLinks() + var result []string + for _, link := range foundLinks { + if link.OfKind(links.LinkLocalHypha) { + result = append(result, link.TargetHypha()) + } + } + return result +} diff --git a/shroom/delete.go b/shroom/delete.go index 017e36f..2f3d5a8 100644 --- a/shroom/delete.go +++ b/shroom/delete.go @@ -26,7 +26,7 @@ func DeleteHypha(u *user.User, h *hyphae.Hypha, lc *l18n.Localizer) (hop *histor WithUser(u). Apply() if !hop.HasErrors() { - backlinks.BacklinksOnDelete(h, originalText) + backlinks.UpdateBacklinksAfterDelete(h, originalText) h.Delete() } return hop, "" diff --git a/shroom/rename.go b/shroom/rename.go index e812937..3c3d11f 100644 --- a/shroom/rename.go +++ b/shroom/rename.go @@ -75,7 +75,7 @@ func RenameHypha(h *hyphae.Hypha, newHypha *hyphae.Hypha, recursive bool, u *use h.TextPath = replaceName(h.TextPath) h.BinaryPath = replaceName(h.BinaryPath) h.Unlock() - backlinks.BacklinksOnRename(h, oldName) + backlinks.UpdateBacklinksAfterRename(h, oldName) } } return hop, "" diff --git a/shroom/upload.go b/shroom/upload.go index d9b3f0e..a61002b 100644 --- a/shroom/upload.go +++ b/shroom/upload.go @@ -106,7 +106,7 @@ func uploadHelp(h *hyphae.Hypha, hop *history.Op, ext string, data []byte, u *us } *originalFullPath = fullPath if hop.Type == history.TypeEditText { - backlinks.BacklinksOnEdit(h, originalText) + backlinks.UpdateBacklinksAfterEdit(h, originalText) } return hop.WithFiles(fullPath).WithUser(u).Apply(), "" } diff --git a/views/stuff.qtpl b/views/stuff.qtpl index b1e2b20..b796711 100644 --- a/views/stuff.qtpl +++ b/views/stuff.qtpl @@ -122,17 +122,18 @@ It outputs a poorly formatted JSON, but it works and is valid. } {% endfunc %} -{% func BacklinksHTML(query string, generator func(string) <-chan string, lc *l18n.Localizer) %} +{% func BacklinksHTML(hyphaName string, generator func(string) <-chan string, lc *l18n.Localizer) %}
-

{%s lc.Get("ui.backlinks_query", &l18n.Replacements{"query": query})%}

+

{%s lc.Get("ui.backlinks_query", &l18n.Replacements{"query": hyphaName})%}

{%s lc.Get("ui.backlinks_desc")%}

{% endfunc %} diff --git a/views/stuff.qtpl.go b/views/stuff.qtpl.go index 3208475..06cde20 100644 --- a/views/stuff.qtpl.go +++ b/views/stuff.qtpl.go @@ -431,14 +431,14 @@ func TitleSearchJSON(query string, generator func(string) <-chan string) string } //line views/stuff.qtpl:125 -func StreamBacklinksHTML(qw422016 *qt422016.Writer, query string, generator func(string) <-chan string, lc *l18n.Localizer) { +func StreamBacklinksHTML(qw422016 *qt422016.Writer, hyphaName string, generator func(string) <-chan string, lc *l18n.Localizer) { //line views/stuff.qtpl:125 qw422016.N().S(`

`) //line views/stuff.qtpl:128 - qw422016.E().S(lc.Get("ui.backlinks_query", &l18n.Replacements{"query": query})) + qw422016.E().S(lc.Get("ui.backlinks_query", &l18n.Replacements{"query": hyphaName})) //line views/stuff.qtpl:128 qw422016.N().S(`

`) @@ -449,7 +449,7 @@ func StreamBacklinksHTML(qw422016 *qt422016.Writer, query string, generator func

`) -//line views/stuff.qtpl:138 +//line views/stuff.qtpl:139 } -//line views/stuff.qtpl:138 -func WriteBacklinksHTML(qq422016 qtio422016.Writer, query string, generator func(string) <-chan string, lc *l18n.Localizer) { -//line views/stuff.qtpl:138 +//line views/stuff.qtpl:139 +func WriteBacklinksHTML(qq422016 qtio422016.Writer, hyphaName string, generator func(string) <-chan string, lc *l18n.Localizer) { +//line views/stuff.qtpl:139 qw422016 := qt422016.AcquireWriter(qq422016) -//line views/stuff.qtpl:138 - StreamBacklinksHTML(qw422016, query, generator, lc) -//line views/stuff.qtpl:138 +//line views/stuff.qtpl:139 + StreamBacklinksHTML(qw422016, hyphaName, generator, lc) +//line views/stuff.qtpl:139 qt422016.ReleaseWriter(qw422016) -//line views/stuff.qtpl:138 +//line views/stuff.qtpl:139 } -//line views/stuff.qtpl:138 -func BacklinksHTML(query string, generator func(string) <-chan string, lc *l18n.Localizer) string { -//line views/stuff.qtpl:138 +//line views/stuff.qtpl:139 +func BacklinksHTML(hyphaName string, generator func(string) <-chan string, lc *l18n.Localizer) string { +//line views/stuff.qtpl:139 qb422016 := qt422016.AcquireByteBuffer() -//line views/stuff.qtpl:138 - WriteBacklinksHTML(qb422016, query, generator, lc) -//line views/stuff.qtpl:138 +//line views/stuff.qtpl:139 + WriteBacklinksHTML(qb422016, hyphaName, generator, lc) +//line views/stuff.qtpl:139 qs422016 := string(qb422016.B) -//line views/stuff.qtpl:138 +//line views/stuff.qtpl:139 qt422016.ReleaseByteBuffer(qb422016) -//line views/stuff.qtpl:138 +//line views/stuff.qtpl:139 return qs422016 -//line views/stuff.qtpl:138 +//line views/stuff.qtpl:139 } -//line views/stuff.qtpl:140 +//line views/stuff.qtpl:141 func StreamHelpHTML(qw422016 *qt422016.Writer, content, lang string, lc *l18n.Localizer) { -//line views/stuff.qtpl:140 +//line views/stuff.qtpl:141 qw422016.N().S(`
`) -//line views/stuff.qtpl:144 +//line views/stuff.qtpl:145 qw422016.N().S(content) -//line views/stuff.qtpl:144 +//line views/stuff.qtpl:145 qw422016.N().S(`
`) -//line views/stuff.qtpl:147 +//line views/stuff.qtpl:148 qw422016.N().S(helpTopicsHTML(lang, lc)) -//line views/stuff.qtpl:147 +//line views/stuff.qtpl:148 qw422016.N().S(`
`) -//line views/stuff.qtpl:149 +//line views/stuff.qtpl:150 } -//line views/stuff.qtpl:149 +//line views/stuff.qtpl:150 func WriteHelpHTML(qq422016 qtio422016.Writer, content, lang string, lc *l18n.Localizer) { -//line views/stuff.qtpl:149 +//line views/stuff.qtpl:150 qw422016 := qt422016.AcquireWriter(qq422016) -//line views/stuff.qtpl:149 +//line views/stuff.qtpl:150 StreamHelpHTML(qw422016, content, lang, lc) -//line views/stuff.qtpl:149 +//line views/stuff.qtpl:150 qt422016.ReleaseWriter(qw422016) -//line views/stuff.qtpl:149 +//line views/stuff.qtpl:150 } -//line views/stuff.qtpl:149 +//line views/stuff.qtpl:150 func HelpHTML(content, lang string, lc *l18n.Localizer) string { -//line views/stuff.qtpl:149 +//line views/stuff.qtpl:150 qb422016 := qt422016.AcquireByteBuffer() -//line views/stuff.qtpl:149 +//line views/stuff.qtpl:150 WriteHelpHTML(qb422016, content, lang, lc) -//line views/stuff.qtpl:149 +//line views/stuff.qtpl:150 qs422016 := string(qb422016.B) -//line views/stuff.qtpl:149 +//line views/stuff.qtpl:150 qt422016.ReleaseByteBuffer(qb422016) -//line views/stuff.qtpl:149 +//line views/stuff.qtpl:150 return qs422016 -//line views/stuff.qtpl:149 +//line views/stuff.qtpl:150 } -//line views/stuff.qtpl:151 +//line views/stuff.qtpl:152 func StreamHelpEmptyErrorHTML(qw422016 *qt422016.Writer, lc *l18n.Localizer) { -//line views/stuff.qtpl:151 +//line views/stuff.qtpl:152 qw422016.N().S(`

`) -//line views/stuff.qtpl:152 +//line views/stuff.qtpl:153 qw422016.E().S(lc.Get("help.empty_error_title")) -//line views/stuff.qtpl:152 +//line views/stuff.qtpl:153 qw422016.N().S(`

`) -//line views/stuff.qtpl:153 +//line views/stuff.qtpl:154 qw422016.E().S(lc.Get("help.empty_error_line_1")) -//line views/stuff.qtpl:153 +//line views/stuff.qtpl:154 qw422016.N().S(`

`) -//line views/stuff.qtpl:154 +//line views/stuff.qtpl:155 qw422016.E().S(lc.Get("help.empty_error_line_2a")) -//line views/stuff.qtpl:154 +//line views/stuff.qtpl:155 qw422016.N().S(` `) -//line views/stuff.qtpl:154 +//line views/stuff.qtpl:155 qw422016.E().S(lc.Get("help.empty_error_link")) -//line views/stuff.qtpl:154 +//line views/stuff.qtpl:155 qw422016.N().S(` `) -//line views/stuff.qtpl:154 +//line views/stuff.qtpl:155 qw422016.E().S(lc.Get("help.empty_error_line_2b")) -//line views/stuff.qtpl:154 +//line views/stuff.qtpl:155 qw422016.N().S(`

`) -//line views/stuff.qtpl:155 +//line views/stuff.qtpl:156 } -//line views/stuff.qtpl:155 +//line views/stuff.qtpl:156 func WriteHelpEmptyErrorHTML(qq422016 qtio422016.Writer, lc *l18n.Localizer) { -//line views/stuff.qtpl:155 +//line views/stuff.qtpl:156 qw422016 := qt422016.AcquireWriter(qq422016) -//line views/stuff.qtpl:155 +//line views/stuff.qtpl:156 StreamHelpEmptyErrorHTML(qw422016, lc) -//line views/stuff.qtpl:155 +//line views/stuff.qtpl:156 qt422016.ReleaseWriter(qw422016) -//line views/stuff.qtpl:155 +//line views/stuff.qtpl:156 } -//line views/stuff.qtpl:155 +//line views/stuff.qtpl:156 func HelpEmptyErrorHTML(lc *l18n.Localizer) string { -//line views/stuff.qtpl:155 +//line views/stuff.qtpl:156 qb422016 := qt422016.AcquireByteBuffer() -//line views/stuff.qtpl:155 +//line views/stuff.qtpl:156 WriteHelpEmptyErrorHTML(qb422016, lc) -//line views/stuff.qtpl:155 +//line views/stuff.qtpl:156 qs422016 := string(qb422016.B) -//line views/stuff.qtpl:155 +//line views/stuff.qtpl:156 qt422016.ReleaseByteBuffer(qb422016) -//line views/stuff.qtpl:155 +//line views/stuff.qtpl:156 return qs422016 -//line views/stuff.qtpl:155 +//line views/stuff.qtpl:156 } -//line views/stuff.qtpl:157 +//line views/stuff.qtpl:158 func streamhelpTopicsHTML(qw422016 *qt422016.Writer, lang string, lc *l18n.Localizer) { -//line views/stuff.qtpl:157 +//line views/stuff.qtpl:158 qw422016.N().S(` `) -//line views/stuff.qtpl:193 +//line views/stuff.qtpl:194 } -//line views/stuff.qtpl:193 +//line views/stuff.qtpl:194 func writehelpTopicsHTML(qq422016 qtio422016.Writer, lang string, lc *l18n.Localizer) { -//line views/stuff.qtpl:193 +//line views/stuff.qtpl:194 qw422016 := qt422016.AcquireWriter(qq422016) -//line views/stuff.qtpl:193 +//line views/stuff.qtpl:194 streamhelpTopicsHTML(qw422016, lang, lc) -//line views/stuff.qtpl:193 +//line views/stuff.qtpl:194 qt422016.ReleaseWriter(qw422016) -//line views/stuff.qtpl:193 +//line views/stuff.qtpl:194 } -//line views/stuff.qtpl:193 +//line views/stuff.qtpl:194 func helpTopicsHTML(lang string, lc *l18n.Localizer) string { -//line views/stuff.qtpl:193 +//line views/stuff.qtpl:194 qb422016 := qt422016.AcquireByteBuffer() -//line views/stuff.qtpl:193 +//line views/stuff.qtpl:194 writehelpTopicsHTML(qb422016, lang, lc) -//line views/stuff.qtpl:193 +//line views/stuff.qtpl:194 qs422016 := string(qb422016.B) -//line views/stuff.qtpl:193 +//line views/stuff.qtpl:194 qt422016.ReleaseByteBuffer(qb422016) -//line views/stuff.qtpl:193 +//line views/stuff.qtpl:194 return qs422016 -//line views/stuff.qtpl:193 +//line views/stuff.qtpl:194 } -//line views/stuff.qtpl:195 +//line views/stuff.qtpl:196 func streamhelpTopicBadgeHTML(qw422016 *qt422016.Writer, lang, topic string) { -//line views/stuff.qtpl:195 +//line views/stuff.qtpl:196 qw422016.N().S(` ? `) -//line views/stuff.qtpl:197 +//line views/stuff.qtpl:198 } -//line views/stuff.qtpl:197 +//line views/stuff.qtpl:198 func writehelpTopicBadgeHTML(qq422016 qtio422016.Writer, lang, topic string) { -//line views/stuff.qtpl:197 +//line views/stuff.qtpl:198 qw422016 := qt422016.AcquireWriter(qq422016) -//line views/stuff.qtpl:197 +//line views/stuff.qtpl:198 streamhelpTopicBadgeHTML(qw422016, lang, topic) -//line views/stuff.qtpl:197 +//line views/stuff.qtpl:198 qt422016.ReleaseWriter(qw422016) -//line views/stuff.qtpl:197 +//line views/stuff.qtpl:198 } -//line views/stuff.qtpl:197 +//line views/stuff.qtpl:198 func helpTopicBadgeHTML(lang, topic string) string { -//line views/stuff.qtpl:197 +//line views/stuff.qtpl:198 qb422016 := qt422016.AcquireByteBuffer() -//line views/stuff.qtpl:197 +//line views/stuff.qtpl:198 writehelpTopicBadgeHTML(qb422016, lang, topic) -//line views/stuff.qtpl:197 +//line views/stuff.qtpl:198 qs422016 := string(qb422016.B) -//line views/stuff.qtpl:197 +//line views/stuff.qtpl:198 qt422016.ReleaseByteBuffer(qb422016) -//line views/stuff.qtpl:197 +//line views/stuff.qtpl:198 return qs422016 -//line views/stuff.qtpl:197 +//line views/stuff.qtpl:198 } -//line views/stuff.qtpl:199 +//line views/stuff.qtpl:200 func StreamUserListHTML(qw422016 *qt422016.Writer, lc *l18n.Localizer) { -//line views/stuff.qtpl:199 +//line views/stuff.qtpl:200 qw422016.N().S(`

`) -//line views/stuff.qtpl:202 +//line views/stuff.qtpl:203 qw422016.E().S(lc.Get("ui.users_heading")) -//line views/stuff.qtpl:202 +//line views/stuff.qtpl:203 qw422016.N().S(`

`) -//line views/stuff.qtpl:204 +//line views/stuff.qtpl:205 var ( admins = make([]string, 0) moderators = make([]string, 0) @@ -871,149 +872,149 @@ func StreamUserListHTML(qw422016 *qt422016.Writer, lc *l18n.Localizer) { sort.Strings(moderators) sort.Strings(editors) -//line views/stuff.qtpl:222 +//line views/stuff.qtpl:223 qw422016.N().S(`

`) -//line views/stuff.qtpl:224 +//line views/stuff.qtpl:225 qw422016.E().S(lc.Get("ui.users_admins")) -//line views/stuff.qtpl:224 +//line views/stuff.qtpl:225 qw422016.N().S(`

    `) -//line views/stuff.qtpl:225 +//line views/stuff.qtpl:226 for _, name := range admins { -//line views/stuff.qtpl:225 +//line views/stuff.qtpl:226 qw422016.N().S(`
  1. `) -//line views/stuff.qtpl:226 +//line views/stuff.qtpl:227 qw422016.E().S(name) -//line views/stuff.qtpl:226 +//line views/stuff.qtpl:227 qw422016.N().S(`
  2. `) -//line views/stuff.qtpl:227 +//line views/stuff.qtpl:228 } -//line views/stuff.qtpl:227 +//line views/stuff.qtpl:228 qw422016.N().S(`

`) -//line views/stuff.qtpl:230 +//line views/stuff.qtpl:231 qw422016.E().S(lc.Get("ui.users_moderators")) -//line views/stuff.qtpl:230 +//line views/stuff.qtpl:231 qw422016.N().S(`

    `) -//line views/stuff.qtpl:231 +//line views/stuff.qtpl:232 for _, name := range moderators { -//line views/stuff.qtpl:231 +//line views/stuff.qtpl:232 qw422016.N().S(`
  1. `) -//line views/stuff.qtpl:232 +//line views/stuff.qtpl:233 qw422016.E().S(name) -//line views/stuff.qtpl:232 +//line views/stuff.qtpl:233 qw422016.N().S(`
  2. `) -//line views/stuff.qtpl:233 +//line views/stuff.qtpl:234 } -//line views/stuff.qtpl:233 +//line views/stuff.qtpl:234 qw422016.N().S(`

`) -//line views/stuff.qtpl:236 +//line views/stuff.qtpl:237 qw422016.E().S(lc.Get("ui.users_editors")) -//line views/stuff.qtpl:236 +//line views/stuff.qtpl:237 qw422016.N().S(`

    `) -//line views/stuff.qtpl:237 +//line views/stuff.qtpl:238 for _, name := range editors { -//line views/stuff.qtpl:237 +//line views/stuff.qtpl:238 qw422016.N().S(`
  1. `) -//line views/stuff.qtpl:238 +//line views/stuff.qtpl:239 qw422016.E().S(name) -//line views/stuff.qtpl:238 +//line views/stuff.qtpl:239 qw422016.N().S(`
  2. `) -//line views/stuff.qtpl:239 +//line views/stuff.qtpl:240 } -//line views/stuff.qtpl:239 +//line views/stuff.qtpl:240 qw422016.N().S(`
`) -//line views/stuff.qtpl:243 +//line views/stuff.qtpl:244 } -//line views/stuff.qtpl:243 +//line views/stuff.qtpl:244 func WriteUserListHTML(qq422016 qtio422016.Writer, lc *l18n.Localizer) { -//line views/stuff.qtpl:243 +//line views/stuff.qtpl:244 qw422016 := qt422016.AcquireWriter(qq422016) -//line views/stuff.qtpl:243 +//line views/stuff.qtpl:244 StreamUserListHTML(qw422016, lc) -//line views/stuff.qtpl:243 +//line views/stuff.qtpl:244 qt422016.ReleaseWriter(qw422016) -//line views/stuff.qtpl:243 +//line views/stuff.qtpl:244 } -//line views/stuff.qtpl:243 +//line views/stuff.qtpl:244 func UserListHTML(lc *l18n.Localizer) string { -//line views/stuff.qtpl:243 +//line views/stuff.qtpl:244 qb422016 := qt422016.AcquireByteBuffer() -//line views/stuff.qtpl:243 +//line views/stuff.qtpl:244 WriteUserListHTML(qb422016, lc) -//line views/stuff.qtpl:243 +//line views/stuff.qtpl:244 qs422016 := string(qb422016.B) -//line views/stuff.qtpl:243 +//line views/stuff.qtpl:244 qt422016.ReleaseByteBuffer(qb422016) -//line views/stuff.qtpl:243 +//line views/stuff.qtpl:244 return qs422016 -//line views/stuff.qtpl:243 +//line views/stuff.qtpl:244 } -//line views/stuff.qtpl:245 +//line views/stuff.qtpl:246 func StreamHyphaListHTML(qw422016 *qt422016.Writer, lc *l18n.Localizer) { -//line views/stuff.qtpl:245 +//line views/stuff.qtpl:246 qw422016.N().S(`

`) -//line views/stuff.qtpl:248 +//line views/stuff.qtpl:249 qw422016.E().S(lc.Get("ui.list_heading")) -//line views/stuff.qtpl:248 +//line views/stuff.qtpl:249 qw422016.N().S(`

`) -//line views/stuff.qtpl:249 +//line views/stuff.qtpl:250 qw422016.E().S(lc.GetPlural("ui.list_desc", hyphae.Count())) -//line views/stuff.qtpl:249 +//line views/stuff.qtpl:250 qw422016.N().S(`

    `) -//line views/stuff.qtpl:252 +//line views/stuff.qtpl:253 hyphaNames := make(chan string) sortedHypha := hyphae.PathographicSort(hyphaNames) for hypha := range hyphae.YieldExistingHyphae() { @@ -1021,252 +1022,252 @@ func StreamHyphaListHTML(qw422016 *qt422016.Writer, lc *l18n.Localizer) { } close(hyphaNames) -//line views/stuff.qtpl:258 +//line views/stuff.qtpl:259 qw422016.N().S(` `) -//line views/stuff.qtpl:259 +//line views/stuff.qtpl:260 for hyphaName := range sortedHypha { -//line views/stuff.qtpl:259 +//line views/stuff.qtpl:260 qw422016.N().S(` `) -//line views/stuff.qtpl:260 +//line views/stuff.qtpl:261 hypha := hyphae.ByName(hyphaName) -//line views/stuff.qtpl:260 +//line views/stuff.qtpl:261 qw422016.N().S(`
  • `) -//line views/stuff.qtpl:262 +//line views/stuff.qtpl:263 qw422016.E().S(util.BeautifulName(hypha.Name)) -//line views/stuff.qtpl:262 +//line views/stuff.qtpl:263 qw422016.N().S(` `) -//line views/stuff.qtpl:263 +//line views/stuff.qtpl:264 if hypha.BinaryPath != "" { -//line views/stuff.qtpl:263 +//line views/stuff.qtpl:264 qw422016.N().S(` `) -//line views/stuff.qtpl:264 +//line views/stuff.qtpl:265 qw422016.E().S(filepath.Ext(hypha.BinaryPath)[1:]) -//line views/stuff.qtpl:264 +//line views/stuff.qtpl:265 qw422016.N().S(` `) -//line views/stuff.qtpl:265 +//line views/stuff.qtpl:266 } -//line views/stuff.qtpl:265 +//line views/stuff.qtpl:266 qw422016.N().S(`
  • `) -//line views/stuff.qtpl:267 +//line views/stuff.qtpl:268 } -//line views/stuff.qtpl:267 +//line views/stuff.qtpl:268 qw422016.N().S(`
`) -//line views/stuff.qtpl:271 +//line views/stuff.qtpl:272 } -//line views/stuff.qtpl:271 +//line views/stuff.qtpl:272 func WriteHyphaListHTML(qq422016 qtio422016.Writer, lc *l18n.Localizer) { -//line views/stuff.qtpl:271 +//line views/stuff.qtpl:272 qw422016 := qt422016.AcquireWriter(qq422016) -//line views/stuff.qtpl:271 +//line views/stuff.qtpl:272 StreamHyphaListHTML(qw422016, lc) -//line views/stuff.qtpl:271 +//line views/stuff.qtpl:272 qt422016.ReleaseWriter(qw422016) -//line views/stuff.qtpl:271 +//line views/stuff.qtpl:272 } -//line views/stuff.qtpl:271 +//line views/stuff.qtpl:272 func HyphaListHTML(lc *l18n.Localizer) string { -//line views/stuff.qtpl:271 +//line views/stuff.qtpl:272 qb422016 := qt422016.AcquireByteBuffer() -//line views/stuff.qtpl:271 +//line views/stuff.qtpl:272 WriteHyphaListHTML(qb422016, lc) -//line views/stuff.qtpl:271 +//line views/stuff.qtpl:272 qs422016 := string(qb422016.B) -//line views/stuff.qtpl:271 +//line views/stuff.qtpl:272 qt422016.ReleaseByteBuffer(qb422016) -//line views/stuff.qtpl:271 +//line views/stuff.qtpl:272 return qs422016 -//line views/stuff.qtpl:271 +//line views/stuff.qtpl:272 } -//line views/stuff.qtpl:273 +//line views/stuff.qtpl:274 func StreamAboutHTML(qw422016 *qt422016.Writer, lc *l18n.Localizer) { -//line views/stuff.qtpl:273 +//line views/stuff.qtpl:274 qw422016.N().S(`

`) -//line views/stuff.qtpl:277 +//line views/stuff.qtpl:278 qw422016.E().S(lc.Get("ui.about_title", &l18n.Replacements{"name": cfg.WikiName})) -//line views/stuff.qtpl:277 +//line views/stuff.qtpl:278 qw422016.N().S(`

  • `) -//line views/stuff.qtpl:279 +//line views/stuff.qtpl:280 qw422016.N().S(lc.Get("ui.about_version", &l18n.Replacements{"pre": "", "post": ""})) -//line views/stuff.qtpl:279 +//line views/stuff.qtpl:280 qw422016.N().S(` 1.7.0
  • `) -//line views/stuff.qtpl:280 +//line views/stuff.qtpl:281 if cfg.UseAuth { -//line views/stuff.qtpl:280 +//line views/stuff.qtpl:281 qw422016.N().S(`
  • `) -//line views/stuff.qtpl:281 +//line views/stuff.qtpl:282 qw422016.E().S(lc.Get("ui.about_usercount")) -//line views/stuff.qtpl:281 +//line views/stuff.qtpl:282 qw422016.N().S(` `) -//line views/stuff.qtpl:281 +//line views/stuff.qtpl:282 qw422016.N().DUL(user.Count()) -//line views/stuff.qtpl:281 +//line views/stuff.qtpl:282 qw422016.N().S(`
  • `) -//line views/stuff.qtpl:282 +//line views/stuff.qtpl:283 qw422016.E().S(lc.Get("ui.about_homepage")) -//line views/stuff.qtpl:282 +//line views/stuff.qtpl:283 qw422016.N().S(` `) -//line views/stuff.qtpl:282 +//line views/stuff.qtpl:283 qw422016.E().S(cfg.HomeHypha) -//line views/stuff.qtpl:282 +//line views/stuff.qtpl:283 qw422016.N().S(`
  • `) -//line views/stuff.qtpl:283 +//line views/stuff.qtpl:284 qw422016.E().S(lc.Get("ui.about_admins")) -//line views/stuff.qtpl:283 +//line views/stuff.qtpl:284 qw422016.N().S(``) -//line views/stuff.qtpl:283 +//line views/stuff.qtpl:284 for i, username := range user.ListUsersWithGroup("admin") { -//line views/stuff.qtpl:284 +//line views/stuff.qtpl:285 if i > 0 { -//line views/stuff.qtpl:284 +//line views/stuff.qtpl:285 qw422016.N().S(` `) -//line views/stuff.qtpl:285 +//line views/stuff.qtpl:286 } -//line views/stuff.qtpl:285 +//line views/stuff.qtpl:286 qw422016.N().S(` `) -//line views/stuff.qtpl:286 +//line views/stuff.qtpl:287 qw422016.E().S(username) -//line views/stuff.qtpl:286 +//line views/stuff.qtpl:287 qw422016.N().S(``) -//line views/stuff.qtpl:286 +//line views/stuff.qtpl:287 } -//line views/stuff.qtpl:286 +//line views/stuff.qtpl:287 qw422016.N().S(`
  • `) -//line views/stuff.qtpl:287 +//line views/stuff.qtpl:288 } else { -//line views/stuff.qtpl:287 +//line views/stuff.qtpl:288 qw422016.N().S(`
  • `) -//line views/stuff.qtpl:288 +//line views/stuff.qtpl:289 qw422016.E().S(lc.Get("ui.about_noauth")) -//line views/stuff.qtpl:288 +//line views/stuff.qtpl:289 qw422016.N().S(`
  • `) -//line views/stuff.qtpl:289 +//line views/stuff.qtpl:290 } -//line views/stuff.qtpl:289 +//line views/stuff.qtpl:290 qw422016.N().S(`

`) -//line views/stuff.qtpl:291 +//line views/stuff.qtpl:292 qw422016.N().S(lc.Get("ui.about_hyphae", &l18n.Replacements{"link": "/list"})) -//line views/stuff.qtpl:291 +//line views/stuff.qtpl:292 qw422016.N().S(`

`) -//line views/stuff.qtpl:295 +//line views/stuff.qtpl:296 } -//line views/stuff.qtpl:295 +//line views/stuff.qtpl:296 func WriteAboutHTML(qq422016 qtio422016.Writer, lc *l18n.Localizer) { -//line views/stuff.qtpl:295 +//line views/stuff.qtpl:296 qw422016 := qt422016.AcquireWriter(qq422016) -//line views/stuff.qtpl:295 +//line views/stuff.qtpl:296 StreamAboutHTML(qw422016, lc) -//line views/stuff.qtpl:295 +//line views/stuff.qtpl:296 qt422016.ReleaseWriter(qw422016) -//line views/stuff.qtpl:295 +//line views/stuff.qtpl:296 } -//line views/stuff.qtpl:295 +//line views/stuff.qtpl:296 func AboutHTML(lc *l18n.Localizer) string { -//line views/stuff.qtpl:295 +//line views/stuff.qtpl:296 qb422016 := qt422016.AcquireByteBuffer() -//line views/stuff.qtpl:295 +//line views/stuff.qtpl:296 WriteAboutHTML(qb422016, lc) -//line views/stuff.qtpl:295 +//line views/stuff.qtpl:296 qs422016 := string(qb422016.B) -//line views/stuff.qtpl:295 +//line views/stuff.qtpl:296 qt422016.ReleaseByteBuffer(qb422016) -//line views/stuff.qtpl:295 +//line views/stuff.qtpl:296 return qs422016 -//line views/stuff.qtpl:295 +//line views/stuff.qtpl:296 } -//line views/stuff.qtpl:297 +//line views/stuff.qtpl:298 func StreamCommonScripts(qw422016 *qt422016.Writer) { -//line views/stuff.qtpl:297 +//line views/stuff.qtpl:298 qw422016.N().S(` `) -//line views/stuff.qtpl:298 +//line views/stuff.qtpl:299 for _, scriptPath := range cfg.CommonScripts { -//line views/stuff.qtpl:298 +//line views/stuff.qtpl:299 qw422016.N().S(` `) -//line views/stuff.qtpl:300 +//line views/stuff.qtpl:301 } -//line views/stuff.qtpl:300 +//line views/stuff.qtpl:301 qw422016.N().S(` `) -//line views/stuff.qtpl:301 +//line views/stuff.qtpl:302 } -//line views/stuff.qtpl:301 +//line views/stuff.qtpl:302 func WriteCommonScripts(qq422016 qtio422016.Writer) { -//line views/stuff.qtpl:301 +//line views/stuff.qtpl:302 qw422016 := qt422016.AcquireWriter(qq422016) -//line views/stuff.qtpl:301 +//line views/stuff.qtpl:302 StreamCommonScripts(qw422016) -//line views/stuff.qtpl:301 +//line views/stuff.qtpl:302 qt422016.ReleaseWriter(qw422016) -//line views/stuff.qtpl:301 +//line views/stuff.qtpl:302 } -//line views/stuff.qtpl:301 +//line views/stuff.qtpl:302 func CommonScripts() string { -//line views/stuff.qtpl:301 +//line views/stuff.qtpl:302 qb422016 := qt422016.AcquireByteBuffer() -//line views/stuff.qtpl:301 +//line views/stuff.qtpl:302 WriteCommonScripts(qb422016) -//line views/stuff.qtpl:301 +//line views/stuff.qtpl:302 qs422016 := string(qb422016.B) -//line views/stuff.qtpl:301 +//line views/stuff.qtpl:302 qt422016.ReleaseByteBuffer(qb422016) -//line views/stuff.qtpl:301 +//line views/stuff.qtpl:302 return qs422016 -//line views/stuff.qtpl:301 +//line views/stuff.qtpl:302 }