diff --git a/config/tree.go b/config/tree.go index d5c6c63..ef21787 100644 --- a/config/tree.go +++ b/config/tree.go @@ -1,11 +1,56 @@ package config import ( + "fmt" "reflect" "github.com/imdario/mergo" ) +// MapString is a map[string]interface{} which always unmarsahls yaml to map[string]interface{} +type MapString map[string]interface{} + +// UnmarshalYAML handles all maps as map[string]interface{} for later JSON +// see https://github.com/elastic/beats/blob/6435194af9f42cbf778ca0a1a92276caf41a0da8/libbeat/common/mapstr.go +func (ms *MapString) UnmarshalYAML(unmarshal func(interface{}) error) error { + var result map[interface{}]interface{} + err := unmarshal(&result) + if err != nil { + return err + } + *ms = cleanUpInterfaceMap(result) + return nil +} + +func cleanUpInterfaceArray(in []interface{}) []interface{} { + result := make([]interface{}, len(in)) + for i, v := range in { + result[i] = cleanUpMapValue(v) + } + return result +} + +func cleanUpInterfaceMap(in map[interface{}]interface{}) MapString { + result := make(MapString) + for k, v := range in { + result[fmt.Sprintf("%v", k)] = cleanUpMapValue(v) + } + return result +} + +func cleanUpMapValue(v interface{}) interface{} { + switch v := v.(type) { + case []interface{}: + return cleanUpInterfaceArray(v) + case map[interface{}]interface{}: + return cleanUpInterfaceMap(v) + case string: + return v + default: + return fmt.Sprintf("%v", v) + } +} + // CollectionConfig describes a collection type CollectionConfig struct { Name *string `yaml:"Name"` @@ -26,7 +71,7 @@ type ThisPathConfig struct { Navname *string `yaml:"Navname"` GoTo *string `yaml:"GoTo"` Collections []*CollectionConfig `yaml:"Collections"` - Data interface{} `yaml:"Data"` + Data MapString `yaml:"Data"` } // IndexConfig describes index input and output file @@ -85,7 +130,7 @@ type PathConfig struct { Markdown *MarkdownConfig `yaml:"Markdown"` Imaging *ImagingConfig `yaml:"Imaging"` - Data map[string]interface{} `yaml:"Data"` + Data MapString `yaml:"Data"` } // PathConfigTree is complete config tree of content dir @@ -94,7 +139,7 @@ type PathConfigTree struct { OutputPath string Hidden bool // for collections which are not part of the navigation - ColMap map[string]interface{} + ColMap MapString InputFiles []string OtherFiles []string diff --git a/helper/content.go b/helper/content.go index 032bfa5..61423f9 100644 --- a/helper/content.go +++ b/helper/content.go @@ -19,8 +19,8 @@ import ( "gopkg.in/yaml.v2" ) -func newContext() map[string]interface{} { - return map[string]interface{}{ +func newContext() pongo2.Context { + return pongo2.Context{ "fnRequest": RequestFn, "fnRender": RenderFn, @@ -106,7 +106,7 @@ func fillNodeConfig(node *config.PathConfigTree, inBase, outBase, dir string, co } if node.ColMap == nil { - node.ColMap = make(map[string]interface{}) + node.ColMap = make(config.MapString) } ctx := newContext() jsonStr, err := pongo2.RenderTemplateString(*colConfig.EntriesJSON, ctx) @@ -114,7 +114,7 @@ func fillNodeConfig(node *config.PathConfigTree, inBase, outBase, dir string, co Log.Panicf("invalid template string in '%s': %s", inPath, err) } - var colSlice []map[string]interface{} + var colSlice []config.MapString err = json.Unmarshal([]byte(jsonStr), &colSlice) if err != nil { Log.Panicf("invalid JSON in EntriesJSON in '%s': %s", inPath, err) @@ -130,12 +130,12 @@ func fillNodeConfig(node *config.PathConfigTree, inBase, outBase, dir string, co // build navigation with detail sites for _, colEl := range colSlice { - ctxE := make(map[string]interface{}) + ctxE := make(pongo2.Context) err := config.Merge(&ctxE, ctx) if err != nil { Log.Panicf("could not merge context in '%s': %s", inPath, err) } - err = config.Merge(&ctxE, colEl) + err = config.Merge(&ctxE, pongo2.Context(colEl)) if err != nil { Log.Panicf("could not merge context in '%s': %s", inPath, err) } diff --git a/helper/navigation.go b/helper/navigation.go index 4c77445..950480b 100644 --- a/helper/navigation.go +++ b/helper/navigation.go @@ -14,7 +14,7 @@ type NavElement struct { GoTo string Active bool - ColMap map[string]interface{} + ColMap config.MapString Data interface{} @@ -93,7 +93,7 @@ func BuildNavigation(conf *config.PathConfigTree, curNavMap *map[string]*NavElem navEl.GoTo = path.Clean(navEl.GoTo) } - (*curNavMap)[navEl.Navname] = &navEl + (*curNavMap)[path.Base(el.OutputPath)] = &navEl if curNavSlice != nil { *curNavSlice = append(*curNavSlice, &navEl) } diff --git a/helper/render.go b/helper/render.go index 791400a..68fcfa4 100644 --- a/helper/render.go +++ b/helper/render.go @@ -11,7 +11,7 @@ import ( ) var templateCache = make(map[string]*pongo2.Template) -var currentContext *map[string]interface{} +var currentContext *pongo2.Context var currentTreeNodeConfig *config.PathConfigTree var currentPathConfig *config.PathConfig var templateDir string @@ -63,7 +63,7 @@ func SetTemplateDir(dir string) { } // RenderTemplate renders a pongo2 template with context -func RenderTemplate(filename string, treeNodeConfig *config.PathConfigTree, pathConfig *config.PathConfig, ctx *map[string]interface{}) (string, error) { +func RenderTemplate(filename string, treeNodeConfig *config.PathConfigTree, pathConfig *config.PathConfig, ctx *pongo2.Context) (string, error) { currentContext = ctx currentTreeNodeConfig = treeNodeConfig currentPathConfig = pathConfig diff --git a/helper/template_filters.go b/helper/template_filters.go index a14b437..14bfbbb 100644 --- a/helper/template_filters.go +++ b/helper/template_filters.go @@ -15,6 +15,7 @@ import ( "strings" "gitbase.de/apairon/mark2web/config" + "github.com/davecgh/go-spew/spew" "github.com/ddliu/motto" "github.com/disintegration/imaging" "github.com/flosch/pongo2" @@ -32,6 +33,7 @@ func init() { "image_process": ImageProcessFilter, "relative_path": RelativePathFilter, "json": JSONFilter, + "dump": DumpFilter, } for name, fn := range newFilters { err := pongo2.RegisterFilter(name, fn) @@ -41,9 +43,29 @@ func init() { } } +// DumpFilter is a pongo2 filter, which returns a spew.Dump of the input +func DumpFilter(in *pongo2.Value, param *pongo2.Value) (*pongo2.Value, *pongo2.Error) { + dumpString := spew.Sdump(in.Interface()) + return pongo2.AsValue(string(dumpString)), nil +} + // 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()) + pretty := false + for _, s := range strings.Split(param.String(), ",") { + switch s { + case "pretty": + pretty = true + } + } + var err error + var jsonBytes []byte + if pretty { + jsonBytes, err = json.MarshalIndent(in.Interface(), "", " ") + + } else { + jsonBytes, err = json.Marshal(in.Interface()) + } if err != nil { return nil, &pongo2.Error{ Sender: "filter:json", @@ -51,7 +73,7 @@ func JSONFilter(in *pongo2.Value, param *pongo2.Value) (*pongo2.Value, *pongo2.E } } - return pongo2.AsSafeValue(string(jsonString)), nil + return pongo2.AsSafeValue(string(jsonBytes)), nil } // MarkdownFilter is a pongo2 filter, which converts markdown to html diff --git a/helper/template_functions.go b/helper/template_functions.go index 25bf295..cf4e844 100644 --- a/helper/template_functions.go +++ b/helper/template_functions.go @@ -10,7 +10,7 @@ import ( "github.com/flosch/pongo2" ) -func jsonWebRequest(url string) map[string]interface{} { +func jsonWebRequest(url string) config.MapString { Log.Noticef("requesting url via GET %s", url) resp, err := http.Get(url) @@ -38,7 +38,7 @@ func jsonWebRequest(url string) map[string]interface{} { Log.Panicf("is not json '%s' from url '%s'", contentType, url) } - jsonMap := make(map[string]interface{}) + jsonMap := make(config.MapString) err = json.Unmarshal(body, &jsonMap) if err != nil { Log.Panicf("could not read json from '%s': %s", url, err) @@ -69,7 +69,7 @@ func add2Nav(currentNode *config.PathConfigTree, pathConfig *config.PathConfig, } if dataMapKey != "" { if newNodeConfig.Config.Data == nil { - newNodeConfig.Config.Data = make(map[string]interface{}) + newNodeConfig.Config.Data = make(config.MapString) } // as submap in Data newNodeConfig.Config.Data[dataMapKey] = ctx diff --git a/website/content/config.yml b/website/content/config.yml index bc9fc43..5a994f7 100644 --- a/website/content/config.yml +++ b/website/content/config.yml @@ -11,5 +11,6 @@ Markdown: ChromaStyle: monokai Data: + debug: True matomoSiteId: 89 token: 89ff216524093123bf7a0a10f7b273 # cockpit api token \ No newline at end of file diff --git a/website/templates/base.html b/website/templates/base.html index 231b833..64eb001 100755 --- a/website/templates/base.html +++ b/website/templates/base.html @@ -100,15 +100,34 @@ <!-- ========== Main Content ========== --> <div class="maincontent"> {% if Data.background %} - <img src="{{ Data.background|relative_path }}" alt="{{ Meta.Title }}" class="img2bg"> + <img + src="{{ Data.background|image_process:"p=fill,w=1440,h=810,q=30" }}" + srcset="{{ Data.background|image_process:"p=fill,w=768,h=768,q=30" }} 768w, + {{ Data.background|image_process:"p=fill,w=1440,h=810,q=30" }} 1440w, + {{ Data.background|image_process:"p=fill,w=1920,h=1020,q=30" }} 1920w" + alt="{{ Meta.Title }}" class="img2bg"> {% endif %} <div class="white_section section_padding"> <div class="container"> {% block part1 %} {{ BodyParts.1 }} {% endblock part1 %} - {% if This.Data.img %} + + {% if Data.debug %} + <hr> + <h2>DEBUG</h2> + + <h3>This</h3> + <pre>{{ This|json:"pretty" }}</pre> + + <h3>Data</h3> + <pre>{{ Data|json:"pretty" }}</pre> + + <h3>NavMap</h3> + <pre>{{ NavMap|json: "pretty" }}</pre> + {% endif %} + </div> </div>