From ade7ec818798c0e5507d4fb6cc5b4396262a85d6 Mon Sep 17 00:00:00 2001 From: Bjørn Erik Pedersen Date: Tue, 1 Aug 2023 18:12:36 +0200 Subject: Add Page.RenderShortcodes A layouts/shortcodes/include.html shortcode may look like this: ```html {{ $p := site.GetPage (.Get 0) }} {{ $p.RenderShortcodes }} ``` Fixes #7297 --- hugolib/page__per_output.go | 81 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) (limited to 'hugolib/page__per_output.go') diff --git a/hugolib/page__per_output.go b/hugolib/page__per_output.go index 89dc5ac77..e806ca339 100644 --- a/hugolib/page__per_output.go +++ b/hugolib/page__per_output.go @@ -103,6 +103,30 @@ func newPageContentOutput(p *pageState, po *pageOutput) (*pageContentOutput, err return err } + ctxCallback := func(cp2 *pageContentOutput) { + cp.p.cmap.hasNonMarkdownShortcode = cp.p.cmap.hasNonMarkdownShortcode || cp2.p.cmap.hasNonMarkdownShortcode + // Merge content placeholders + for k, v := range cp2.contentPlaceholders { + cp.contentPlaceholders[k] = v + } + + if p.s.watching() { + for _, s := range cp2.p.shortcodeState.shortcodes { + for _, templ := range s.templs { + dependencyTracker.Add(templ.(identity.Manager)) + } + } + } + + // Transfer shortcode names so HasShortcode works for shortcodes from included pages. + cp.p.shortcodeState.transferNames(cp2.p.shortcodeState) + if cp2.p.pageOutputTemplateVariationsState.Load() == 2 { + cp.p.pageOutputTemplateVariationsState.Store(2) + } + } + + ctx = tpl.SetCallbackFunctionInContext(ctx, ctxCallback) + var hasVariants bool cp.workContent, hasVariants, err = p.contentToRender(ctx, p.source.parsed, p.cmap, cp.contentPlaceholders) if err != nil { @@ -350,6 +374,63 @@ func (p *pageContentOutput) Fragments(ctx context.Context) *tableofcontents.Frag return p.tableOfContents } +func (p *pageContentOutput) RenderShortcodes(ctx context.Context) (template.HTML, error) { + p.p.s.initInit(ctx, p.initToC, p.p) + source := p.p.source.parsed.Input() + renderedShortcodes := p.contentPlaceholders + var insertPlaceholders bool + var hasVariants bool + var cb func(*pageContentOutput) + if v := tpl.GetCallbackFunctionFromContext(ctx); v != nil { + if fn, ok := v.(func(*pageContentOutput)); ok { + insertPlaceholders = true + cb = fn + } + } + c := make([]byte, 0, len(source)+(len(source)/10)) + for _, it := range p.p.cmap.items { + switch v := it.(type) { + case pageparser.Item: + c = append(c, source[v.Pos():v.Pos()+len(v.Val(source))]...) + case pageContentReplacement: + // Ignore. + case *shortcode: + if !insertPlaceholders || !v.insertPlaceholder() { + // Insert the rendered shortcode. + renderedShortcode, found := renderedShortcodes[v.placeholder] + if !found { + // This should never happen. + panic(fmt.Sprintf("rendered shortcode %q not found", v.placeholder)) + } + + b, more, err := renderedShortcode.renderShortcode(ctx) + if err != nil { + return "", fmt.Errorf("failed to render shortcode: %w", err) + } + hasVariants = hasVariants || more + c = append(c, []byte(b)...) + + } else { + // Insert the placeholder so we can insert the content after + // markdown processing. + c = append(c, []byte(v.placeholder)...) + } + default: + panic(fmt.Sprintf("unknown item type %T", it)) + } + } + + if hasVariants { + p.p.pageOutputTemplateVariationsState.Store(2) + } + + if cb != nil { + cb(p) + } + + return helpers.BytesToHTML(c), nil +} + func (p *pageContentOutput) TableOfContents(ctx context.Context) template.HTML { p.p.s.initInit(ctx, p.initToC, p.p) return p.tableOfContentsHTML -- cgit v1.2.3