-
-
Save logrusorgru/abd846adb521a6fb39c7405f32fec0cf to your computer and use it in GitHub Desktop.
// | |
// Copyright (c) 2018 Konstanin Ivanov <[email protected]>. | |
// All rights reserved. This program is free software. It comes without | |
// any warranty, to the extent permitted by applicable law. You can | |
// redistribute it and/or modify it under the terms of the Do What | |
// The Fuck You Want To Public License, Version 2, as published by | |
// Sam Hocevar. See below for more details. | |
// | |
// | |
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE | |
// Version 2, December 2004 | |
// | |
// Copyright (C) 2004 Sam Hocevar <[email protected]> | |
// | |
// Everyone is permitted to copy and distribute verbatim or modified | |
// copies of this license document, and changing it is allowed as long | |
// as the name is changed. | |
// | |
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE | |
// TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION | |
// | |
// 0. You just DO WHAT THE FUCK YOU WANT TO. | |
// | |
// ************************************************************************** // | |
// // | |
// This gist shows a convenient way to load and use HTML templates in Golang // | |
// web-applications. The way includes: // | |
// // | |
// - recursive loading, unlike (html/template).ParseGlob does it // | |
// - short (Rails-like) template name without shared prefix (dir) // | |
// and without file extension // | |
// // | |
// For example, there is a tree of templates // | |
// views/ // | |
// static/ // | |
// home.html // | |
// about.html // | |
// privacypolicy.html // | |
// help.html // | |
// user/ // | |
// new.html // | |
// edit.html // | |
// show.html // | |
// form.html // | |
// layout/ // | |
// head.html // | |
// foot.html // | |
// // | |
// Thus, the home.html can include head.html and foor.html following way // | |
// // | |
// {{ template "layout/head" . }} // | |
// // | |
// <h1> Home page </h1> // | |
// <!-- other content of the home.html // | |
// // | |
// {{ template "layout/foot" . }} // | |
// // | |
// This is acceptable for user/new and user/edit which can include user/form // | |
// along with the layout/head and layout/foot. // | |
// // | |
// ************************************************************************** // | |
// A Tmpl implements keeper, loader and reloader for HTML templates | |
type Tmpl struct { | |
*template.Template // root template | |
} | |
// NewTmpl creates new Tmpl. | |
func NewTmpl() (tmpl *Tmpl) { | |
tmpl = new(Tmpl) | |
tmpl.Template = template.New("") // unnamed root template | |
return | |
} | |
// SetFuncs sets template functions to underlying templates | |
func (t *Tmpl) SetFuncs(funcMap template.FuncMap) { | |
t.Template = t.Template.Funcs(funcMap) | |
} | |
// Load templates. The dir argument is a directory to load templates from. | |
// The ext argument is extension of tempaltes. | |
func (t *Tmpl) Load(dir, ext string) (err error) { | |
// get absolute path | |
if dir, err = filepath.Abs(dir); err != nil { | |
return fmt.Errorf("getting absolute path: %w", err) | |
} | |
var root = t.Template | |
var walkFunc = func(path string, info os.FileInfo, err error) (_ error) { | |
// handle walking error if any | |
if err != nil { | |
return err | |
} | |
// skip all except regular files | |
// TODO (kostyarin): follow symlinks (?) | |
if !info.Mode().IsRegular() { | |
return | |
} | |
// filter by extension | |
if filepath.Ext(path) != ext { | |
return | |
} | |
// get relative path | |
var rel string | |
if rel, err = filepath.Rel(dir, path); err != nil { | |
return err | |
} | |
// name of a template is its relative path | |
// without extension | |
rel = strings.TrimSuffix(rel, ext) | |
rel = strings.Join(strings.Split(rel, string(os.PathSeparator)), "/") | |
// load or reload | |
var ( | |
nt = root.New(rel) | |
b []byte | |
) | |
if b, err = ioutil.ReadFile(path); err != nil { | |
return err | |
} | |
_, err = nt.Parse(string(b)) | |
return err | |
} | |
if err = filepath.Walk(dir, walkFunc); err != nil { | |
return | |
} | |
t.Template = root // set or replace (does it needed?) | |
return | |
} | |
// Render is equal to ExecuteTemplate. | |
// | |
// DEPRECATED: use Go native ExeuteTempalte instead. | |
func (t *Tmpl) Render(w io.Writer, name string, data interface{}) error { | |
return t.ExecuteTemplate(w, name, data) | |
} |
You forgot t.dir
on line https://gist.github.com/logrusorgru/abd846adb521a6fb39c7405f32fec0cf#file-load-go-L136.
Why did you remove the develop part? Do you find it no longer useful?
Plus I'm having a problem because I'm on Windows I think.
All the templates it finds have the key like: templates\customDir\subdir\file
.
And even if I use path.Join()
everywhere it won't find them unless I point to them using \
instead of /
(example "one\\one-a
" instead of "one/one-a
").
This is very strange. Do you understand why?
This is very strange. Do you understand why?
It uses relative filesystem path as a template name. You can add this line (below), to convert Windows-like paths to UNIX-like for a template name. The line is
rel = strings.TrimSuffix(rel, ext)
rel = strings.Join(strings.Split(rel, os.PathSeparator), "/") // additional line
This way, all template names will be UNIX-like (e.g. /
-separated). I've added this to the load.go
.
Why did you remove the develop part? Do you find it no longer useful?
Yes, I think it useless.
Maybe we should use: string(os.PathSeparator)
.
Yep
@frederikhors , I've updated the
load.go
. And I've not tested it.Use the templates