hugolib: Add zero-based Ordinal to shortcode

The count starts at 0 relative to the shortcode's parent: Either the page or the surrounding shortcode.

Access it in a shortcode like this:

```bash
Ordinal is {{ .Ordinal }}
```

Note that this is a shared ordinal for all shortcodes in the relevant context, so, as an example, you have this in a content page:

```markdown
This is a shortcode:

{{< hello >}}

This is another shortcode:

{{< hugo >}}

The `.Ordinal` you get in the two shortcodes above is 0 and 1.
```

See #3359
This commit is contained in:
Bjørn Erik Pedersen 2018-04-23 08:09:56 +02:00
parent 24c662ce6b
commit 3decf4a327
No known key found for this signature in database
GPG key ID: 330E6E2BD4859D8F
2 changed files with 38 additions and 10 deletions

View file

@ -40,7 +40,11 @@ type ShortcodeWithPage struct {
Page *PageWithoutContent Page *PageWithoutContent
Parent *ShortcodeWithPage Parent *ShortcodeWithPage
IsNamedParams bool IsNamedParams bool
scratch *Scratch
// Zero-based oridinal in relation to its parent.
Ordinal int
scratch *Scratch
} }
// Site returns information about the current site. // Site returns information about the current site.
@ -122,6 +126,7 @@ type shortcode struct {
name string name string
inner []interface{} // string or nested shortcode inner []interface{} // string or nested shortcode
params interface{} // map or array params interface{} // map or array
ordinal int
err error err error
doMarkup bool doMarkup bool
} }
@ -287,7 +292,7 @@ func renderShortcode(
return "" return ""
} }
data := &ShortcodeWithPage{Params: sc.params, Page: p, Parent: parent} data := &ShortcodeWithPage{Ordinal: sc.ordinal, Params: sc.params, Page: p, Parent: parent}
if sc.params != nil { if sc.params != nil {
data.IsNamedParams = reflect.TypeOf(sc.params).Kind() == reflect.Map data.IsNamedParams = reflect.TypeOf(sc.params).Kind() == reflect.Map
} }
@ -449,12 +454,13 @@ var errShortCodeIllegalState = errors.New("Illegal shortcode state")
// pageTokens state: // pageTokens state:
// - before: positioned just before the shortcode start // - before: positioned just before the shortcode start
// - after: shortcode(s) consumed (plural when they are nested) // - after: shortcode(s) consumed (plural when they are nested)
func (s *shortcodeHandler) extractShortcode(pt *pageTokens, p *PageWithoutContent) (*shortcode, error) { func (s *shortcodeHandler) extractShortcode(ordinal int, pt *pageTokens, p *PageWithoutContent) (*shortcode, error) {
sc := &shortcode{} sc := &shortcode{ordinal: ordinal}
var isInner = false var isInner = false
var currItem item var currItem item
var cnt = 0 var cnt = 0
var nestedOrdinal = 0
Loop: Loop:
for { for {
@ -470,7 +476,8 @@ Loop:
if cnt > 0 { if cnt > 0 {
// nested shortcode; append it to inner content // nested shortcode; append it to inner content
pt.backup3(currItem, next) pt.backup3(currItem, next)
nested, err := s.extractShortcode(pt, p) nested, err := s.extractShortcode(nestedOrdinal, pt, p)
nestedOrdinal++
if nested.name != "" { if nested.name != "" {
s.nameSet[nested.name] = true s.nameSet[nested.name] = true
} }
@ -593,6 +600,7 @@ func (s *shortcodeHandler) extractShortcodes(stringToParse string, p *PageWithou
// … it's safe to keep some "global" state // … it's safe to keep some "global" state
var currItem item var currItem item
var currShortcode shortcode var currShortcode shortcode
var ordinal int
Loop: Loop:
for { for {
@ -605,7 +613,7 @@ Loop:
// let extractShortcode handle left delim (will do so recursively) // let extractShortcode handle left delim (will do so recursively)
pt.backup() pt.backup()
currShortcode, err := s.extractShortcode(pt, p) currShortcode, err := s.extractShortcode(ordinal, pt, p)
if currShortcode.name != "" { if currShortcode.name != "" {
s.nameSet[currShortcode.name] = true s.nameSet[currShortcode.name] = true
@ -621,6 +629,7 @@ Loop:
placeHolder := s.createShortcodePlaceholder() placeHolder := s.createShortcodePlaceholder()
result.WriteString(placeHolder) result.WriteString(placeHolder)
ordinal++
s.shortcodes.Add(placeHolder, currShortcode) s.shortcodes.Add(placeHolder, currShortcode)
case tEOF: case tEOF:
break Loop break Loop

View file

@ -894,17 +894,28 @@ weight: %d
--- ---
# doc # doc
{{< increment >}}{{< s1 >}}{{< increment >}}{{< s2 >}}{{< increment >}}{{< s3 >}}{{< increment >}}{{< s4 >}}{{< increment >}}{{< s5 >}} {{< s1 >}}{{< s2 >}}{{< s3 >}}{{< s4 >}}{{< s5 >}}
{{< nested >}}
{{< ordinal >}}
{{< ordinal >}}
{{< ordinal >}}
{{< /nested >}}
` `
shortCodeTemplate := `v%d: {{ .Page.Scratch.Get "v" }}|` ordinalShortcodeTemplate := `ordinal: {{ .Ordinal }}`
nestedShortcode := `outer ordinal: {{ .Ordinal }} inner: {{ .Inner }}`
shortCodeTemplate := `v%d: {{ .Ordinal }}|`
var shortcodes []string var shortcodes []string
var content []string var content []string
shortcodes = append(shortcodes, []string{"shortcodes/increment.html", `{{ .Page.Scratch.Add "v" 1}}`}...) shortcodes = append(shortcodes, []string{"shortcodes/nested.html", nestedShortcode}...)
shortcodes = append(shortcodes, []string{"shortcodes/ordinal.html", ordinalShortcodeTemplate}...)
for i := 1; i <= 5; i++ { for i := 1; i <= 5; i++ {
shortcodes = append(shortcodes, []string{fmt.Sprintf("shortcodes/s%d.html", i), fmt.Sprintf(shortCodeTemplate, i)}...) shortcodes = append(shortcodes, []string{fmt.Sprintf("shortcodes/s%d.html", i), fmt.Sprintf(shortCodeTemplate, i)}...)
@ -923,7 +934,15 @@ weight: %d
p1 := s.RegularPages[0] p1 := s.RegularPages[0]
if !strings.Contains(string(p1.content()), `v1: 1|v2: 2|v3: 3|v4: 4|v5: 5`) { if !strings.Contains(string(p1.content()), `v1: 0|v2: 1|v3: 2|v4: 3|v5: 4|`) {
t.Fatal(p1.content())
}
// Check nested behaviour
if !strings.Contains(string(p1.content()), `outer ordinal: 5 inner:
ordinal: 0
ordinal: 1
ordinal: 2`) {
t.Fatal(p1.content()) t.Fatal(p1.content())
} }