mirror of
https://github.com/gohugoio/hugo.git
synced 2025-08-22 21:42:50 +02:00
Make Page an interface
The main motivation of this commit is to add a `page.Page` interface to replace the very file-oriented `hugolib.Page` struct. This is all a preparation step for issue #5074, "pages from other data sources". But this also fixes a set of annoying limitations, especially related to custom output formats, and shortcodes. Most notable changes: * The inner content of shortcodes using the `{{%` as the outer-most delimiter will now be sent to the content renderer, e.g. Blackfriday. This means that any markdown will partake in the global ToC and footnote context etc. * The Custom Output formats are now "fully virtualized". This removes many of the current limitations. * The taxonomy list type now has a reference to the `Page` object. This improves the taxonomy template `.Title` situation and make common template constructs much simpler. See #5074 Fixes #5763 Fixes #5758 Fixes #5090 Fixes #5204 Fixes #4695 Fixes #5607 Fixes #5707 Fixes #5719 Fixes #3113 Fixes #5706 Fixes #5767 Fixes #5723 Fixes #5769 Fixes #5770 Fixes #5771 Fixes #5759 Fixes #5776 Fixes #5777 Fixes #5778
This commit is contained in:
148
tpl/tplimpl/shortcodes.go
Normal file
148
tpl/tplimpl/shortcodes.go
Normal file
@@ -0,0 +1,148 @@
|
||||
// Copyright 2019 The Hugo Authors. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package tplimpl
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/gohugoio/hugo/tpl"
|
||||
)
|
||||
|
||||
// Currently lang, outFormat, suffix
|
||||
const numTemplateVariants = 3
|
||||
|
||||
type shortcodeVariant struct {
|
||||
|
||||
// The possible variants: lang, outFormat, suffix
|
||||
// gtag
|
||||
// gtag.html
|
||||
// gtag.no.html
|
||||
// gtag.no.amp.html
|
||||
// A slice of length numTemplateVariants.
|
||||
variants []string
|
||||
|
||||
info tpl.Info
|
||||
templ tpl.Template
|
||||
}
|
||||
|
||||
type shortcodeTemplates struct {
|
||||
variants []shortcodeVariant
|
||||
}
|
||||
|
||||
func (s *shortcodeTemplates) indexOf(variants []string) int {
|
||||
L:
|
||||
for i, v1 := range s.variants {
|
||||
for i, v2 := range v1.variants {
|
||||
if v2 != variants[i] {
|
||||
continue L
|
||||
}
|
||||
}
|
||||
return i
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
func (s *shortcodeTemplates) fromVariants(variants tpl.TemplateVariants) (shortcodeVariant, bool) {
|
||||
return s.fromVariantsSlice([]string{
|
||||
variants.Language,
|
||||
strings.ToLower(variants.OutputFormat.Name),
|
||||
variants.OutputFormat.MediaType.Suffix(),
|
||||
})
|
||||
}
|
||||
|
||||
// Get the most specific template given a full name, e.g gtag.no.amp.html.
|
||||
func (s *shortcodeTemplates) fromName(name string) (shortcodeVariant, bool) {
|
||||
return s.fromVariantsSlice(templateVariants(name))
|
||||
}
|
||||
|
||||
func (s *shortcodeTemplates) fromVariantsSlice(variants []string) (shortcodeVariant, bool) {
|
||||
var (
|
||||
bestMatch shortcodeVariant
|
||||
bestMatchWeight int
|
||||
)
|
||||
|
||||
for _, variant := range s.variants {
|
||||
w := s.compareVariants(variants, variant.variants)
|
||||
if bestMatchWeight == 0 || w > bestMatchWeight {
|
||||
bestMatch = variant
|
||||
bestMatchWeight = w
|
||||
}
|
||||
}
|
||||
|
||||
return bestMatch, true
|
||||
}
|
||||
|
||||
// calculate a weight for two string slices of same lenght.
|
||||
// higher value means "better match".
|
||||
func (s *shortcodeTemplates) compareVariants(a, b []string) int {
|
||||
|
||||
weight := 0
|
||||
for i, av := range a {
|
||||
bv := b[i]
|
||||
if av == bv {
|
||||
weight++
|
||||
} else {
|
||||
weight--
|
||||
}
|
||||
}
|
||||
return weight
|
||||
}
|
||||
|
||||
func templateVariants(name string) []string {
|
||||
_, variants := templateNameAndVariants(name)
|
||||
return variants
|
||||
}
|
||||
|
||||
func templateNameAndVariants(name string) (string, []string) {
|
||||
|
||||
variants := make([]string, numTemplateVariants)
|
||||
|
||||
parts := strings.Split(name, ".")
|
||||
|
||||
if len(parts) <= 1 {
|
||||
// No variants.
|
||||
return name, variants
|
||||
}
|
||||
|
||||
name = parts[0]
|
||||
parts = parts[1:]
|
||||
lp := len(parts)
|
||||
start := len(variants) - lp
|
||||
|
||||
for i, j := start, 0; i < len(variants); i, j = i+1, j+1 {
|
||||
variants[i] = parts[j]
|
||||
}
|
||||
|
||||
if lp > 1 && lp < len(variants) {
|
||||
for i := lp - 1; i > 0; i-- {
|
||||
variants[i-1] = variants[i]
|
||||
}
|
||||
}
|
||||
|
||||
if lp == 1 {
|
||||
// Suffix only. Duplicate it into the output format field to
|
||||
// make HTML win over AMP.
|
||||
variants[len(variants)-2] = variants[len(variants)-1]
|
||||
}
|
||||
|
||||
return name, variants
|
||||
}
|
||||
|
||||
func isShortcode(name string) bool {
|
||||
return strings.Contains(name, "shortcodes/")
|
||||
}
|
||||
|
||||
func isInternal(name string) bool {
|
||||
return strings.HasPrefix(name, "_internal/")
|
||||
}
|
Reference in New Issue
Block a user