github.com/linchen2chris/hugo@v0.0.0-20230307053224-cec209389705/hugolib/shortcode_page.go (about) 1 // Copyright 2019 The Hugo Authors. All rights reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // http://www.apache.org/licenses/LICENSE-2.0 7 // 8 // Unless required by applicable law or agreed to in writing, software 9 // distributed under the License is distributed on an "AS IS" BASIS, 10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 package hugolib 15 16 import ( 17 "context" 18 "html/template" 19 20 "github.com/gohugoio/hugo/resources/page" 21 ) 22 23 // A placeholder for the TableOfContents markup. This is what we pass to the Goldmark etc. renderers. 24 var tocShortcodePlaceholder = createShortcodePlaceholder("TOC", 0) 25 26 // shortcodeRenderer is typically used to delay rendering of inner shortcodes 27 // marked with placeholders in the content. 28 type shortcodeRenderer interface { 29 renderShortcode(context.Context) ([]byte, bool, error) 30 renderShortcodeString(context.Context) (string, bool, error) 31 } 32 33 type shortcodeRenderFunc func(context.Context) ([]byte, bool, error) 34 35 func (f shortcodeRenderFunc) renderShortcode(ctx context.Context) ([]byte, bool, error) { 36 return f(ctx) 37 } 38 39 func (f shortcodeRenderFunc) renderShortcodeString(ctx context.Context) (string, bool, error) { 40 b, has, err := f(ctx) 41 return string(b), has, err 42 } 43 44 type prerenderedShortcode struct { 45 s string 46 hasVariants bool 47 } 48 49 func (p prerenderedShortcode) renderShortcode(context.Context) ([]byte, bool, error) { 50 return []byte(p.s), p.hasVariants, nil 51 } 52 53 func (p prerenderedShortcode) renderShortcodeString(context.Context) (string, bool, error) { 54 return p.s, p.hasVariants, nil 55 } 56 57 var zeroShortcode = prerenderedShortcode{} 58 59 // This is sent to the shortcodes. They cannot access the content 60 // they're a part of. It would cause an infinite regress. 61 // 62 // Go doesn't support virtual methods, so this careful dance is currently (I think) 63 // the best we can do. 64 type pageForShortcode struct { 65 page.PageWithoutContent 66 page.TableOfContentsProvider 67 page.ContentProvider 68 69 // We need to replace it after we have rendered it, so provide a 70 // temporary placeholder. 71 toc template.HTML 72 73 p *pageState 74 } 75 76 func newPageForShortcode(p *pageState) page.Page { 77 return &pageForShortcode{ 78 PageWithoutContent: p, 79 TableOfContentsProvider: p, 80 ContentProvider: page.NopPage, 81 toc: template.HTML(tocShortcodePlaceholder), 82 p: p, 83 } 84 } 85 86 func (p *pageForShortcode) page() page.Page { 87 return p.PageWithoutContent.(page.Page) 88 } 89 90 func (p *pageForShortcode) String() string { 91 return p.p.String() 92 } 93 94 func (p *pageForShortcode) TableOfContents(context.Context) template.HTML { 95 p.p.enablePlaceholders() 96 return p.toc 97 } 98 99 // This is what is sent into the content render hooks (link, image). 100 type pageForRenderHooks struct { 101 page.PageWithoutContent 102 page.TableOfContentsProvider 103 page.ContentProvider 104 } 105 106 func newPageForRenderHook(p *pageState) page.Page { 107 return &pageForRenderHooks{ 108 PageWithoutContent: p, 109 ContentProvider: page.NopPage, 110 TableOfContentsProvider: p, 111 } 112 } 113 114 func (p *pageForRenderHooks) page() page.Page { 115 return p.PageWithoutContent.(page.Page) 116 }