collections as one navigation level

This commit is contained in:
Sebastian Frank 2019-03-10 16:02:53 +01:00
parent e3dfbcb591
commit 38820e6baf
Signed by: apairon
GPG Key ID: 7270D06DDA7FE8C3
6 changed files with 157 additions and 47 deletions

View File

@ -8,10 +8,16 @@ import (
// CollectionConfig describes a collection
type CollectionConfig struct {
Name *string `yaml:"Name"`
URL *string `yaml:"URL"`
GoToTemplate *string `yaml:"GoToTemplate"`
RegisterNav *bool `yaml:"RegisterNav"`
Name *string `yaml:"Name"`
EntriesJSON *string `yaml:"EntriesJSON"`
NavTemplate *struct {
GoTo string `yaml:"GoTo"`
Navname string `yaml:"Navname"`
Body string `yaml:"Body"`
DataKey string `yaml:"DataKey"`
Hidden bool `yaml:"Hidden"`
Template string `yaml:"Template"`
} `yaml:"NavTemplate"`
}
// ThisPathConfig is struct for This in paths yaml

View File

@ -2,6 +2,7 @@ package helper
import (
"bytes"
"encoding/json"
"io/ioutil"
"os"
"path"
@ -18,6 +19,15 @@ import (
"gopkg.in/yaml.v2"
)
func newContext() map[string]interface{} {
return map[string]interface{}{
"fnRequest": RequestFn,
"fnRender": RenderFn,
"AssetsPath": config.Config.Assets.ToPath,
}
}
func fillNodeConfig(node *config.PathConfigTree, inBase, outBase, dir string, conf *config.PathConfig) {
inPath := inBase
if dir != "" {
@ -90,15 +100,81 @@ func fillNodeConfig(node *config.PathConfigTree, inBase, outBase, dir string, co
if colConfig.Name == nil || *colConfig.Name == "" {
Log.Panicf("missing Name in collection config in '%s'", inPath)
}
if colConfig.URL == nil || *colConfig.URL == "" {
Log.Panicf("missing URL in collection config in '%s'", inPath)
if colConfig.EntriesJSON == nil || *colConfig.EntriesJSON == "" {
Log.Panicf("missing EntriesJSON in collection config in '%s'", inPath)
}
}
if node.ColMap == nil {
node.ColMap = make(map[string]interface{})
}
node.ColMap[*colConfig.Name] = jsonWebRequest(*colConfig.URL)
ctx := newContext()
jsonStr, err := pongo2.RenderTemplateString(*colConfig.EntriesJSON, ctx)
if err != nil {
Log.Panicf("invalid template string in '%s': %s", inPath, err)
}
var colSlice []map[string]interface{}
err = json.Unmarshal([]byte(jsonStr), &colSlice)
if err != nil {
Log.Panicf("invalid JSON in EntriesJSON in '%s': %s", inPath, err)
}
node.ColMap[*colConfig.Name] = colSlice
//node.ColMap[*colConfig.Name] = jsonWebRequest(*colConfig.URL)
if navT := colConfig.NavTemplate; navT != nil {
tpl := navT.Template
if tpl == "" {
tpl = *newConfig.Template
}
// build navigation with detail sites
for _, colEl := range colSlice {
ctxE := make(map[string]interface{})
err := config.Merge(&ctxE, ctx)
if err != nil {
Log.Panicf("could not merge context in '%s': %s", inPath, err)
}
err = config.Merge(&ctxE, colEl)
if err != nil {
Log.Panicf("could not merge context in '%s': %s", inPath, err)
}
goTo, err := pongo2.RenderTemplateString(navT.GoTo, ctxE)
if err != nil {
Log.Panicf("invalid template string for NavTemplate.GoTo in '%s': %s", inPath, err)
}
goTo = strings.Trim(goTo, "/")
goTo = path.Clean(goTo)
if strings.Contains(goTo, "..") {
Log.Panicf("going back via .. in NavTemplate.GoTo forbidden in collection config in '%s': %s", inPath, goTo)
}
if goTo == "." {
Log.Panicf("invalid config '.' for NavTemplate.GoTo in collection config in '%s'", inPath)
}
if goTo == "" {
Log.Panicf("missing NavTemplate.GoTo in collection config in '%s'", inPath)
}
navname := ""
if navT.Navname != "" {
navname, err = pongo2.RenderTemplateString(navT.Navname, ctxE)
if err != nil {
Log.Panicf("invalid template string for NavTemplate.Navname in '%s': %s", inPath, err)
}
}
body := ""
if navT.Body != "" {
body, err = pongo2.RenderTemplateString(navT.Body, ctxE)
if err != nil {
Log.Panicf("invalid template string for NavTemplate.Body in '%s': %s", inPath, err)
}
}
add2Nav(node, node.Config, tpl, goTo, navname, colEl, navT.DataKey, body, navT.Hidden)
}
}
}
}
@ -304,7 +380,7 @@ RewriteRule ^$ %{REQUEST_URI}`+goToFixed+`/ [R,L]
BuildNavigation(rootConf, &navMap, &navSlice, &navActive, curNavPath)
// read yaml header as data for template
ctx := make(map[string]interface{})
ctx := newContext()
ctx["This"] = newConfig.This
ctx["Meta"] = newConfig.Meta
ctx["Data"] = newConfig.Data
@ -314,7 +390,6 @@ RewriteRule ^$ %{REQUEST_URI}`+goToFixed+`/ [R,L]
ctx["NavActive"] = navActive
ctx["Body"] = pongo2.AsSafeValue(string(renderMarkdown(input, newConfig.Markdown)))
ctx["BodyParts"] = htmlParts
ctx["AssetsPath"] = config.Config.Assets.ToPath
ctx["CurrentPath"] = curNavPath
// set active nav element
if len(navActive) > 0 {
@ -332,10 +407,6 @@ RewriteRule ^$ %{REQUEST_URI}`+goToFixed+`/ [R,L]
}
}
// register functions
ctx["fnRequest"] = RequestFn
ctx["fnRender"] = RenderFn
Log.Debugf("rendering template '%s' for '%s'", *newConfig.Template, outFile)
templateFilename := *newConfig.Template
result, err := RenderTemplate(*newConfig.Template, conf, newConfig, &ctx)

View File

@ -2,6 +2,7 @@ package helper
import (
"crypto/md5"
"encoding/json"
"errors"
"fmt"
"image"
@ -30,6 +31,7 @@ func init() {
newFilters := map[string]pongo2.FilterFunction{
"image_process": ImageProcessFilter,
"relative_path": RelativePathFilter,
"json": JSONFilter,
}
for name, fn := range newFilters {
err := pongo2.RegisterFilter(name, fn)
@ -39,6 +41,19 @@ func init() {
}
}
// JSONFilter is a pongo2 filter, which returns a json string of the input
func JSONFilter(in *pongo2.Value, param *pongo2.Value) (*pongo2.Value, *pongo2.Error) {
jsonString, err := json.Marshal(in.Interface())
if err != nil {
return nil, &pongo2.Error{
Sender: "filter:json",
OrigError: err,
}
}
return pongo2.AsSafeValue(string(jsonString)), nil
}
// MarkdownFilter is a pongo2 filter, which converts markdown to html
func MarkdownFilter(in *pongo2.Value, param *pongo2.Value) (*pongo2.Value, *pongo2.Error) {
return pongo2.AsSafeValue(

View File

@ -53,39 +53,30 @@ func RequestFn(url *pongo2.Value, args ...*pongo2.Value) *pongo2.Value {
return pongo2.AsValue(jsonWebRequest(u))
}
// RenderFn renders a pongo2 template with additional context
func RenderFn(templateFilename, outDir, ctx *pongo2.Value, param ...*pongo2.Value) *pongo2.Value {
ctxMapKey := ""
body := ""
for i, p := range param {
switch i {
case 0:
ctxMapKey = p.String()
case 1:
body = p.String()
}
}
func add2Nav(currentNode *config.PathConfigTree, pathConfig *config.PathConfig, tplFilename, outDir string, navname string, ctx interface{}, dataMapKey string, body string, hidden bool) {
newNodeConfig := new(config.PathConfigTree)
fillNodeConfig(
newNodeConfig,
currentTreeNodeConfig.InputPath,
currentTreeNodeConfig.OutputPath,
outDir.String(),
currentPathConfig,
currentNode.InputPath,
currentNode.OutputPath,
outDir,
pathConfig,
)
if newNodeConfig.Config.Data == nil {
newNodeConfig.Config.Data = make(map[string]interface{})
if navname != "" {
newNodeConfig.Config.This = config.ThisPathConfig{
Navname: &navname,
}
}
if ctxMapKey != "" {
if dataMapKey != "" {
if newNodeConfig.Config.Data == nil {
newNodeConfig.Config.Data = make(map[string]interface{})
}
// as submap in Data
newNodeConfig.Config.Data[ctxMapKey] = ctx.Interface()
} else if m, ok := ctx.Interface().(map[string]interface{}); ok {
newNodeConfig.Config.Data[dataMapKey] = ctx
} else if m, ok := ctx.(map[string]interface{}); ok {
// direct set data
newNodeConfig.Config.Data = m
}
tplFilename := templateFilename.String()
// fake via normal file behavior
newNodeConfig.Config.Template = &tplFilename
@ -102,9 +93,26 @@ func RenderFn(templateFilename, outDir, ctx *pongo2.Value, param ...*pongo2.Valu
OutputFile: &indexOutFile,
InputString: &body,
}
newNodeConfig.Hidden = true
newNodeConfig.Hidden = hidden
currentTreeNodeConfig.Sub = append(currentTreeNodeConfig.Sub, newNodeConfig)
currentNode.Sub = append(currentNode.Sub, newNodeConfig)
}
// RenderFn renders a pongo2 template with additional context
func RenderFn(templateFilename, outDir, ctx *pongo2.Value, param ...*pongo2.Value) *pongo2.Value {
dataMapKey := ""
body := ""
for i, p := range param {
switch i {
case 0:
dataMapKey = p.String()
case 1:
body = p.String()
}
}
add2Nav(currentTreeNodeConfig, currentPathConfig, templateFilename.String(), outDir.String(), "", ctx.Interface(), dataMapKey, body, true)
return pongo2.AsValue(nil)
}

View File

@ -1,9 +1,21 @@
This:
Collections:
- Name: blog1st
URL: https://mark2web.basiscms.de/api/collections/get/mark2webBlog?token=89ff216524093123bf7a0a10f7b273&filter[published]=true&sort[date]=-1&skip=0&limit=1
GoToTemplate: '{{ date|add:"-"|add:title|slugify }}'
EntriesJSON: '{{ fnRequest("https://mark2web.basiscms.de/api/collections/get/mark2webBlog?token=89ff216524093123bf7a0a10f7b273&filter[published]=true&sort[date]=-1&skip=0&limit=1").entries|json }}'
NavTemplate:
GoTo: '{{ date|add:"-"|add:title|slugify }}'
Navname: '{{ title }}'
Body: '{{ body }}'
Template: base_blog_details.html
DataKey: details
Hidden: true # hide from nav, but use this feature for rendering detail sites
- Name: blog1skip
URL: https://mark2web.basiscms.de/api/collections/get/mark2webBlog?token=89ff216524093123bf7a0a10f7b273&filter[published]=true&sort[date]=-1&skip=1&limit=100
GoToTemplate: '{{ date|add:"-"|add:title|slugify }}'
EntriesJSON: '{{ fnRequest("https://mark2web.basiscms.de/api/collections/get/mark2webBlog?token=89ff216524093123bf7a0a10f7b273&filter[published]=true&sort[date]=-1&skip=1&limit=100").entries|json }}'
NavTemplate:
GoTo: '{{ date|add:"-"|add:title|slugify }}'
Navname: '{{ title }}'
Body: '{{ body }}'
Template: base_blog_details.html
DataKey: details
Hidden: true

View File

@ -2,7 +2,7 @@
{% block part0 %}
{{ Body }}
{% for e in NavElement.ColMap.blog1st.entries %}
{% for e in NavElement.ColMap.blog1st %}
<h2>
{{ e.title }}
<div class="datum">{{ e.date|datum }}</div>
@ -10,7 +10,6 @@
{{ e.teaser|markdown }}
{% if e.body %}
<a href="{{ e.date|add:"-"|add:e.title|slugify }}" class="btn">mehr lesen &raquo;</a>
{{ fnRender("base_blog_details.html", e.date|add:"-"|add:e.title, e, "details", e.body) }}
{% endif %}
{% endfor %}
{% endblock part0 %}
@ -19,7 +18,7 @@
{% comment %}
limit wird für skip in Query gebraucht
{% endcomment %}
{% for e in NavElement.ColMap.blog1skip.entries %}
{% for e in NavElement.ColMap.blog1skip %}
<h2>
{{ e.title }}
<div class="datum">{{ e.date|datum }}</div>
@ -27,7 +26,6 @@
{{ e.teaser|markdown }}
{% if e.body %}
<a href="{{ e.date|add:"-"|add:e.title|slugify }}" class="btn">mehr lesen &raquo;</a>
{{ fnRender("base_blog_details.html", e.date|add:"-"|add:e.title, e, "details", e.body) }}
{% endif %}
{% endfor %}
{% endblock part1 %}