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:
parent
0497d4fb89
commit
7a5c352d25
@ -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}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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())
|
||||
}
|
||||
@ -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 ""
|
||||
}
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
|
||||
@ -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 {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user