mirror of
https://github.com/gohugoio/hugo.git
synced 2025-04-29 07:00:31 +03:00
hugolib: Process and render shortcodes in their order of appearance
Fixes #3359
This commit is contained in:
parent
19084eaf74
commit
85535084de
5 changed files with 261 additions and 40 deletions
|
@ -180,11 +180,11 @@ type shortcodeHandler struct {
|
|||
p *PageWithoutContent
|
||||
|
||||
// This is all shortcode rendering funcs for all potential output formats.
|
||||
contentShortcodes map[scKey]func() (string, error)
|
||||
contentShortcodes *orderedMap
|
||||
|
||||
// This map contains the new or changed set of shortcodes that need
|
||||
// to be rendered for the current output format.
|
||||
contentShortcodesDelta map[scKey]func() (string, error)
|
||||
contentShortcodesDelta *orderedMap
|
||||
|
||||
// This maps the shorcode placeholders with the rendered content.
|
||||
// We will do (potential) partial re-rendering per output format,
|
||||
|
@ -192,7 +192,7 @@ type shortcodeHandler struct {
|
|||
renderedShortcodes map[string]string
|
||||
|
||||
// Maps the shortcodeplaceholder with the actual shortcode.
|
||||
shortcodes map[string]shortcode
|
||||
shortcodes *orderedMap
|
||||
|
||||
// All the shortcode names in this set.
|
||||
nameSet map[string]bool
|
||||
|
@ -216,8 +216,8 @@ func (s *shortcodeHandler) createShortcodePlaceholder() string {
|
|||
func newShortcodeHandler(p *Page) *shortcodeHandler {
|
||||
return &shortcodeHandler{
|
||||
p: p.withoutContent(),
|
||||
contentShortcodes: make(map[scKey]func() (string, error)),
|
||||
shortcodes: make(map[string]shortcode),
|
||||
contentShortcodes: newOrderedMap(),
|
||||
shortcodes: newOrderedMap(),
|
||||
nameSet: make(map[string]bool),
|
||||
renderedShortcodes: make(map[string]string),
|
||||
}
|
||||
|
@ -259,7 +259,7 @@ const innerNewlineRegexp = "\n"
|
|||
const innerCleanupRegexp = `\A<p>(.*)</p>\n\z`
|
||||
const innerCleanupExpand = "$1"
|
||||
|
||||
func prepareShortcodeForPage(placeholder string, sc shortcode, parent *ShortcodeWithPage, p *PageWithoutContent) map[scKey]func() (string, error) {
|
||||
func prepareShortcodeForPage(placeholder string, sc *shortcode, parent *ShortcodeWithPage, p *PageWithoutContent) map[scKey]func() (string, error) {
|
||||
|
||||
m := make(map[scKey]func() (string, error))
|
||||
lang := p.Lang()
|
||||
|
@ -277,7 +277,7 @@ func prepareShortcodeForPage(placeholder string, sc shortcode, parent *Shortcode
|
|||
|
||||
func renderShortcode(
|
||||
tmplKey scKey,
|
||||
sc shortcode,
|
||||
sc *shortcode,
|
||||
parent *ShortcodeWithPage,
|
||||
p *PageWithoutContent) string {
|
||||
|
||||
|
@ -298,8 +298,8 @@ func renderShortcode(
|
|||
switch innerData.(type) {
|
||||
case string:
|
||||
inner += innerData.(string)
|
||||
case shortcode:
|
||||
inner += renderShortcode(tmplKey, innerData.(shortcode), data, p)
|
||||
case *shortcode:
|
||||
inner += renderShortcode(tmplKey, innerData.(*shortcode), data, p)
|
||||
default:
|
||||
p.s.Log.ERROR.Printf("Illegal state on shortcode rendering of %q in page %q. Illegal type in inner data: %s ",
|
||||
sc.name, p.Path(), reflect.TypeOf(innerData))
|
||||
|
@ -363,48 +363,51 @@ func (s *shortcodeHandler) updateDelta() bool {
|
|||
|
||||
contentShortcodes := s.contentShortcodesForOutputFormat(s.p.s.rc.Format)
|
||||
|
||||
if s.contentShortcodesDelta == nil || len(s.contentShortcodesDelta) == 0 {
|
||||
if s.contentShortcodesDelta == nil || s.contentShortcodesDelta.Len() == 0 {
|
||||
s.contentShortcodesDelta = contentShortcodes
|
||||
return true
|
||||
}
|
||||
|
||||
delta := make(map[scKey]func() (string, error))
|
||||
delta := newOrderedMap()
|
||||
|
||||
for k, v := range contentShortcodes {
|
||||
if _, found := s.contentShortcodesDelta[k]; !found {
|
||||
delta[k] = v
|
||||
for _, k := range contentShortcodes.Keys() {
|
||||
if !s.contentShortcodesDelta.Contains(k) {
|
||||
v, _ := contentShortcodes.Get(k)
|
||||
delta.Add(k, v)
|
||||
}
|
||||
}
|
||||
|
||||
s.contentShortcodesDelta = delta
|
||||
|
||||
return len(delta) > 0
|
||||
return delta.Len() > 0
|
||||
}
|
||||
|
||||
func (s *shortcodeHandler) contentShortcodesForOutputFormat(f output.Format) map[scKey]func() (string, error) {
|
||||
contentShortcodesForOuputFormat := make(map[scKey]func() (string, error))
|
||||
func (s *shortcodeHandler) contentShortcodesForOutputFormat(f output.Format) *orderedMap {
|
||||
contentShortcodesForOuputFormat := newOrderedMap()
|
||||
lang := s.p.Lang()
|
||||
|
||||
for shortcodePlaceholder := range s.shortcodes {
|
||||
for _, key := range s.shortcodes.Keys() {
|
||||
shortcodePlaceholder := key.(string)
|
||||
// shortcodePlaceholder := s.shortcodes.getShortcode(key)
|
||||
|
||||
key := newScKeyFromLangAndOutputFormat(lang, f, shortcodePlaceholder)
|
||||
renderFn, found := s.contentShortcodes[key]
|
||||
renderFn, found := s.contentShortcodes.Get(key)
|
||||
|
||||
if !found {
|
||||
key.OutputFormat = ""
|
||||
renderFn, found = s.contentShortcodes[key]
|
||||
renderFn, found = s.contentShortcodes.Get(key)
|
||||
}
|
||||
|
||||
// Fall back to HTML
|
||||
if !found && key.Suffix != "html" {
|
||||
key.Suffix = "html"
|
||||
renderFn, found = s.contentShortcodes[key]
|
||||
renderFn, found = s.contentShortcodes.Get(key)
|
||||
}
|
||||
|
||||
if !found {
|
||||
panic(fmt.Sprintf("Shortcode %q could not be found", shortcodePlaceholder))
|
||||
}
|
||||
contentShortcodesForOuputFormat[newScKeyFromLangAndOutputFormat(lang, f, shortcodePlaceholder)] = renderFn
|
||||
contentShortcodesForOuputFormat.Add(newScKeyFromLangAndOutputFormat(lang, f, shortcodePlaceholder), renderFn)
|
||||
}
|
||||
|
||||
return contentShortcodesForOuputFormat
|
||||
|
@ -412,27 +415,29 @@ func (s *shortcodeHandler) contentShortcodesForOutputFormat(f output.Format) map
|
|||
|
||||
func (s *shortcodeHandler) executeShortcodesForDelta(p *PageWithoutContent) error {
|
||||
|
||||
for k, render := range s.contentShortcodesDelta {
|
||||
for _, k := range s.contentShortcodesDelta.Keys() {
|
||||
render := s.contentShortcodesDelta.getShortcodeRenderer(k)
|
||||
renderedShortcode, err := render()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to execute shortcode in page %q: %s", p.Path(), err)
|
||||
}
|
||||
|
||||
s.renderedShortcodes[k.ShortcodePlaceholder] = renderedShortcode
|
||||
s.renderedShortcodes[k.(scKey).ShortcodePlaceholder] = renderedShortcode
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
}
|
||||
|
||||
func createShortcodeRenderers(shortcodes map[string]shortcode, p *PageWithoutContent) map[scKey]func() (string, error) {
|
||||
func createShortcodeRenderers(shortcodes *orderedMap, p *PageWithoutContent) *orderedMap {
|
||||
|
||||
shortcodeRenderers := make(map[scKey]func() (string, error))
|
||||
shortcodeRenderers := newOrderedMap()
|
||||
|
||||
for k, v := range shortcodes {
|
||||
prepared := prepareShortcodeForPage(k, v, nil, p)
|
||||
for _, k := range shortcodes.Keys() {
|
||||
v := shortcodes.getShortcode(k)
|
||||
prepared := prepareShortcodeForPage(k.(string), v, nil, p)
|
||||
for kk, vv := range prepared {
|
||||
shortcodeRenderers[kk] = vv
|
||||
shortcodeRenderers.Add(kk, vv)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -444,8 +449,8 @@ var errShortCodeIllegalState = errors.New("Illegal shortcode state")
|
|||
// pageTokens state:
|
||||
// - before: positioned just before the shortcode start
|
||||
// - after: shortcode(s) consumed (plural when they are nested)
|
||||
func (s *shortcodeHandler) extractShortcode(pt *pageTokens, p *PageWithoutContent) (shortcode, error) {
|
||||
sc := shortcode{}
|
||||
func (s *shortcodeHandler) extractShortcode(pt *pageTokens, p *PageWithoutContent) (*shortcode, error) {
|
||||
sc := &shortcode{}
|
||||
var isInner = false
|
||||
|
||||
var currItem item
|
||||
|
@ -616,7 +621,7 @@ Loop:
|
|||
|
||||
placeHolder := s.createShortcodePlaceholder()
|
||||
result.WriteString(placeHolder)
|
||||
s.shortcodes[placeHolder] = currShortcode
|
||||
s.shortcodes.Add(placeHolder, currShortcode)
|
||||
case tEOF:
|
||||
break Loop
|
||||
case tError:
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue