0
0
mirror of https://github.com/go-gitea/gitea.git synced 2026-04-08 04:43:13 +02:00

refactor: unify TOC rendering to use upstream TocHeadingItems for all views

This commit is contained in:
hamki 2026-01-26 17:03:21 +08:00
parent 0497d4fb89
commit 7a5c352d25
No known key found for this signature in database
GPG Key ID: 092D4EC7F4DECB68
7 changed files with 23 additions and 102 deletions

View File

@ -84,11 +84,6 @@ func (g *ASTTransformer) Transform(node *ast.Document, reader text.Reader, pc pa
ctx.TocShowInSection = markup.TocShowInMain
case showTocInSidebar:
ctx.TocShowInSection = markup.TocShowInSidebar
// Also populate SidebarTocHeaders for README/file view (not used by Wiki)
ctx.SidebarTocHeaders = make([]markup.Header, len(tocList))
for i, h := range tocList {
ctx.SidebarTocHeaders[i] = markup.Header{Level: h.Level, Text: h.Text, ID: h.ID}
}
}
}

View File

@ -77,7 +77,10 @@ func Render(ctx *markup.RenderContext, input io.Reader, output io.Writer) error
}
// Extract headers from the document outline for sidebar TOC
ctx.SidebarTocHeaders = extractHeadersFromOutline(doc.Outline)
ctx.TocHeadingItems = extractTocHeadingItems(doc.Outline)
if len(ctx.TocHeadingItems) > 0 {
ctx.TocShowInSection = markup.TocShowInSidebar
}
res, err := doc.Write(w)
if err != nil {
@ -87,15 +90,15 @@ func Render(ctx *markup.RenderContext, input io.Reader, output io.Writer) error
return err
}
// extractHeadersFromOutline recursively extracts headers from org document outline
func extractHeadersFromOutline(outline org.Outline) []markup.Header {
var headers []markup.Header
collectHeaders(outline.Section, &headers)
return headers
// extractTocHeadingItems recursively extracts headers from org document outline
func extractTocHeadingItems(outline org.Outline) []*markup.TocHeadingItem {
var items []*markup.TocHeadingItem
collectTocHeadingItems(outline.Section, &items)
return items
}
// collectHeaders recursively collects headers from sections
func collectHeaders(section *org.Section, headers *[]markup.Header) {
// collectTocHeadingItems recursively collects headers from sections
func collectTocHeadingItems(section *org.Section, items *[]*markup.TocHeadingItem) {
if section == nil {
return
}
@ -105,16 +108,16 @@ func collectHeaders(section *org.Section, headers *[]markup.Header) {
h := section.Headline
// Convert headline title nodes to plain text
titleText := org.String(h.Title...)
*headers = append(*headers, markup.Header{
Level: h.Lvl,
Text: titleText,
ID: h.ID(),
*items = append(*items, &markup.TocHeadingItem{
HeadingLevel: h.Lvl,
InnerText: titleText,
AnchorID: h.ID(),
})
}
// Process child sections
for _, child := range section.Children {
collectHeaders(child, headers)
collectTocHeadingItems(child, items)
}
}

View File

@ -91,8 +91,6 @@ type RenderContext struct {
TocShowInSection TocShowInSectionType
TocHeadingItems []*TocHeadingItem
SidebarTocHeaders []Header // Headers for generating sidebar TOC (used by README/file view)
RenderHelper RenderHelper
RenderOptions RenderOptions
RenderInternal internal.RenderInternal

View File

@ -1,77 +0,0 @@
// Copyright 2026 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package markup
import (
"html"
"html/template"
"net/url"
"strings"
"code.gitea.io/gitea/modules/translation"
)
// RenderSidebarTocHTML renders a list of headers into HTML for sidebar TOC display.
// It generates a <details> element with nested <ul> lists representing the header hierarchy.
func RenderSidebarTocHTML(headers []Header, lang string) template.HTML {
if len(headers) == 0 {
return ""
}
var sb strings.Builder
// Start with <details open>
sb.WriteString(`<details open>`)
sb.WriteString(`<summary>`)
sb.WriteString(html.EscapeString(translation.NewLocale(lang).TrString("toc")))
sb.WriteString(`</summary>`)
// Find the minimum level to start with
minLevel := 6
for _, header := range headers {
if header.Level < minLevel {
minLevel = header.Level
}
}
// Build nested list structure
currentLevel := minLevel
sb.WriteString(`<ul>`)
openLists := 1
for _, header := range headers {
// Close lists if we need to go up levels
for currentLevel > header.Level {
sb.WriteString(`</ul>`)
openLists--
currentLevel--
}
// Open new lists if we need to go down levels
for currentLevel < header.Level {
sb.WriteString(`<ul>`)
openLists++
currentLevel++
}
// Write the list item with link
sb.WriteString(`<li>`)
sb.WriteString(`<a href="#`)
sb.WriteString(url.QueryEscape(header.ID))
sb.WriteString(`">`)
sb.WriteString(html.EscapeString(header.Text))
sb.WriteString(`</a>`)
sb.WriteString(`</li>`)
}
// Close all remaining open lists
for openLists > 0 {
sb.WriteString(`</ul>`)
openLists--
}
sb.WriteString(`</details>`)
return template.HTML(sb.String())
}

View File

@ -174,9 +174,11 @@ func markupRenderToHTML(ctx *context.Context, renderCtx *markup.RenderContext, r
return escaped, output, err
}
func renderSidebarTocHTML(rctx *markup.RenderContext, lang string) template.HTML {
if len(rctx.SidebarTocHeaders) > 0 {
return markup.RenderSidebarTocHTML(rctx.SidebarTocHeaders, lang)
func renderSidebarTocHTML(rctx *markup.RenderContext) template.HTML {
if rctx.TocShowInSection == markup.TocShowInSidebar && len(rctx.TocHeadingItems) > 0 {
sb := strings.Builder{}
markup.RenderTocHeadingItems(rctx, map[string]string{"open": ""}, &sb)
return template.HTML(sb.String())
}
return ""
}

View File

@ -87,7 +87,7 @@ func handleFileViewRenderMarkup(ctx *context.Context, prefetchBuf []byte, utf8Re
return true
}
ctx.Data["FileSidebarHTML"] = renderSidebarTocHTML(rctx, ctx.Locale.Language())
ctx.Data["FileSidebarHTML"] = renderSidebarTocHTML(rctx)
return true
}

View File

@ -203,7 +203,7 @@ func prepareToRenderReadmeFile(ctx *context.Context, subfolder string, readmeFil
delete(ctx.Data, "IsMarkup")
}
ctx.Data["FileSidebarHTML"] = renderSidebarTocHTML(rctx, ctx.Locale.Language())
ctx.Data["FileSidebarHTML"] = renderSidebarTocHTML(rctx)
}
if ctx.Data["IsMarkup"] != true {