@@ -12,7 +12,9 @@ import (
1212 "strings"
1313 "sync"
1414
15+ "code.gitea.io/gitea/modules/htmlutil"
1516 "code.gitea.io/gitea/modules/markup/common"
17+ "code.gitea.io/gitea/modules/translation"
1618
1719 "golang.org/x/net/html"
1820 "golang.org/x/net/html/atom"
@@ -234,6 +236,49 @@ func postProcessString(ctx *RenderContext, procs []processor, content string) (s
234236 return buf .String (), nil
235237}
236238
239+ func RenderTocHeadingItems (ctx * RenderContext , nodeDetailsAttrs map [string ]string , out io.Writer ) {
240+ locale , ok := ctx .Value (translation .ContextKey ).(translation.Locale )
241+ if ! ok {
242+ locale = translation .NewLocale ("" )
243+ }
244+ _ , _ = htmlutil .HTMLPrintTag (out , "details" , nodeDetailsAttrs )
245+ _ , _ = htmlutil .HTMLPrintf (out , "<summary>%s</summary>\n " , locale .TrString ("toc" ))
246+
247+ baseLevel := 6
248+ for _ , header := range ctx .TocHeadingItems {
249+ if header .HeadingLevel < baseLevel {
250+ baseLevel = header .HeadingLevel
251+ }
252+ }
253+
254+ currentLevel := baseLevel
255+ indent := []byte {' ' , ' ' }
256+ _ , _ = htmlutil .HTMLPrint (out , "<ul>\n " )
257+ for _ , header := range ctx .TocHeadingItems {
258+ for currentLevel < header .HeadingLevel {
259+ _ , _ = out .Write (indent )
260+ _ , _ = htmlutil .HTMLPrint (out , "<ul>\n " )
261+ indent = append (indent , ' ' , ' ' )
262+ currentLevel ++
263+ }
264+ for currentLevel > header .HeadingLevel {
265+ indent = indent [:len (indent )- 2 ]
266+ _ , _ = out .Write (indent )
267+ _ , _ = htmlutil .HTMLPrint (out , "</ul>\n " )
268+ currentLevel --
269+ }
270+ _ , _ = out .Write (indent )
271+ _ , _ = htmlutil .HTMLPrintf (out , "<li><a href=\" #%s\" >%s</a></li>\n " , header .AnchorID , header .InnerText )
272+ }
273+ for currentLevel > baseLevel {
274+ indent = indent [:len (indent )- 2 ]
275+ _ , _ = out .Write (indent )
276+ _ , _ = htmlutil .HTMLPrint (out , "</ul>\n " )
277+ currentLevel --
278+ }
279+ _ , _ = htmlutil .HTMLPrint (out , "</ul>\n </details>\n " )
280+ }
281+
237282func postProcess (ctx * RenderContext , procs []processor , input io.Reader , output io.Writer ) error {
238283 if ! ctx .usedByRender && ctx .RenderHelper != nil {
239284 defer ctx .RenderHelper .CleanUp ()
@@ -284,6 +329,9 @@ func postProcess(ctx *RenderContext, procs []processor, input io.Reader, output
284329 }
285330
286331 // Render everything to buf.
332+ if ctx .TocShowInSection == TocShowInMain && len (ctx .TocHeadingItems ) > 0 {
333+ RenderTocHeadingItems (ctx , nil , output )
334+ }
287335 for _ , node := range newNodes {
288336 if err := html .Render (output , node ); err != nil {
289337 return fmt .Errorf ("markup.postProcess: html.Render: %w" , err )
@@ -314,7 +362,7 @@ func visitNode(ctx *RenderContext, procs []processor, node *html.Node) *html.Nod
314362 return node .NextSibling
315363 }
316364
317- processNodeAttrID (ctx , node )
365+ processNodeHeadingAndID (ctx , node )
318366 processFootnoteNode (ctx , node ) // FIXME: the footnote processing should be done in the "footnote.go" renderer directly
319367
320368 if isEmojiNode (node ) {
0 commit comments