// ApplyTemplate is internal. Gets a the template, clones and executes. // getter is called after l.Init so it can rely on l.Template presence. func (l *LazyTemplate) ApplyTemplate(getter func() (*template.Template, string), data interface{}) (*bytes.Buffer, error) { var clone *template.Template if err := func() error { l.MU.Lock() defer l.MU.Unlock() if err := l.Init(); err != nil { return err } var t *template.Template if getter == nil { t = l.Template } else { var name string t, name = getter() if t == nil { return fmt.Errorf("template: %q is undefined", name) } } var err error clone, err = t.Clone() return err }(); err != nil { return nil, err } buf := new(bytes.Buffer) err := clone.Execute(buf, data) return buf, err }
func (tl *TemplateLoader) loadTemplates(searchPath string, includeTmpl *template.Template) error { tmplFiles, err := filepath.Glob(filepath.Join(tl.basePath, searchPath, "*.tmpl")) if err != nil { return err } for _, tf := range tmplFiles { tfBytes, err := ioutil.ReadFile(tf) if err != nil { return err } tfStr := string(tfBytes) tn, err := filepath.Rel(tl.basePath, tf) if err != nil { return err } tn = strings.TrimSuffix(tn, ".tmpl") // We clone the included templates here to keep each namespace fresh. it, err := includeTmpl.Clone() if err != nil { return err } t, err := it.New(tn).Parse(tfStr) if err != nil { return err } tl.templates[tn] = t } return nil }
func getLayoutTemplates() *template.Template { var templLayouts *template.Template = template.Must( template.ParseGlob("templates/layouts/*.html")) temp, _ := templLayouts.Clone() return temp }
func readtemplates(dir string, titles map[Language]string) (err error) { var templates *template.Template templates, err = template.New("base").Funcs(tmplFuncs).ParseGlob(dir + "/*.tmpl") if err != nil { return } var d *os.File d, err = os.Open(dir) if err != nil { return } var v []os.FileInfo v, err = d.Readdir(0) if err != nil { return } for _, fi := range v { if fi.IsDir() { var t *template.Template t, err = templates.Clone() if err != nil { return } subdir := dir + "/" + fi.Name() _, err = t.ParseGlob(subdir + "/*.tmpl") if err != nil { return } th := t.Lookup("home") ti := t.Lookup("info") if th == nil { return fmt.Errorf(`Template "home" is missing in %s`, subdir) } if ti == nil { return fmt.Errorf(`Template "info" is missing in %s`, subdir) } title, ok := "", false if title, ok = titles[Language(fi.Name())]; !ok { if title, ok = titles[defaultlang]; !ok { title = "Uploader" } } langtmpl[Language(fi.Name())] = &tmpl{title, th, ti} } } defaulttmpl = langtmpl[defaultlang] if defaulttmpl == nil { fmt.Errorf("missing " + string(defaultlang) + " template") } languages = make([]Language, 0, len(langtmpl)) languages = append(languages, defaultlang) for k := range langtmpl { if k != defaultlang { languages = append(languages, k) } } return }
// LoadTemplates parses all specified files located in fpath. Each template is wrapped // in a unique clone of layout. All templates are expecting {{authboss}} handlebars // for parsing. It will check the override directory specified in the config, replacing any // templates as necessary. func LoadTemplates(ab *authboss.Authboss, layout *template.Template, fpath string, files ...string) (Templates, error) { m := make(Templates) funcMap := template.FuncMap{ "title": strings.Title, "mountpathed": func(location string) string { if ab.MountPath == "/" { return location } return path.Join(ab.MountPath, location) }, } for _, file := range files { b, err := ioutil.ReadFile(filepath.Join(fpath, file)) if exists := !os.IsNotExist(err); err != nil && exists { return nil, err } else if !exists { b, err = Asset(file) if err != nil { return nil, err } } clone, err := layout.Clone() if err != nil { return nil, err } _, err = clone.New("authboss").Funcs(funcMap).Parse(string(b)) if err != nil { return nil, err } m[file] = clone } return m, nil }
func (h *HtmlRender) getTemplate(root *template.Template, args ...string) (*template.Template, error) { var name, file string if len(args) == 1 { name = args[0] file = args[0] } else { name = args[1] file = args[1] } if !h.saveTemp { //for debug log.Println("get template of ", name, file) } file = filepath.FromSlash(file) t := h.models[name] if t == nil { cloned_rest_model, err := root.Clone() if err == nil { err = parseFileWithName(cloned_rest_model, name, filepath.Join(h.dir, file)) if err == nil { t = cloned_rest_model.Lookup(name) if h.saveTemp { h.models[name] = t } } else { if os.IsNotExist(err) { log.Printf("template for (%s) is missing", file) return nil, ge.NOSUCHROUTER } else { return nil, err } } } } return t, nil }
func templatesCompileDemo(w http.ResponseWriter, r *http.Request, m map[string]interface{}) { w.Header().Set("Content-Type", "text/html") funcMap := tt.FuncMap{ "unescape": html.UnescapeString, "escape": html.EscapeString, } var t_base *tt.Template var err error = nil // creating T0 - naming it - adding func map t_base = tt.Must(tt.New("str_T0_outmost").Funcs(funcMap).Parse(T0)) loghttp.E(w, r, err, false) // adding the definition of T1 - introducing reference to T2 - undefined yet t_base, err = t_base.Parse(T1) // definitions must appear at top level - but not at the start loghttp.E(w, r, err, false) // create two clones // now both containing T0 and T1 tc_1, err := t_base.Clone() loghttp.E(w, r, err, false) tc_2, err := t_base.Clone() loghttp.E(w, r, err, false) // adding different T2 definitions s_if := "{{if .}}{{.}}{{else}}no dyn data{{end}}" tc_1, err = tc_1.Parse("{{define `T2`}}T2-A <br>--" + s_if + "-- {{end}}") loghttp.E(w, r, err, false) tc_2, err = tc_2.Parse("{{define `T2`}}T2-B <br>--" + s_if + "-- {{end}}") loghttp.E(w, r, err, false) // writing both clones to the response writer err = tc_1.ExecuteTemplate(w, "str_T0_outmost", nil) loghttp.E(w, r, err, false) // second clone is written with dynamic data on two levels dyndata := map[string]string{"key1": "dyn val 1", "key2": "dyn val 2"} err = tc_2.ExecuteTemplate(w, "str_T0_outmost", dyndata) loghttp.E(w, r, err, false) // Note: it is important to pass the DOT // {{template "T1" .}} // {{template "T2" .key2 }} // ^ // otherwise "dyndata" can not be accessed by the inner templates... // leaving T2 undefined => error tc_3, err := t_base.Clone() loghttp.E(w, r, err, false) err = tc_3.ExecuteTemplate(w, "str_T0_outmost", dyndata) // NOT logging the error: // loghttp.E(w, r, err, false) }
// Renderer is a Middleware that maps a render.Render service into the Martini handler chain. An single variadic render.Options // struct can be optionally provided to configure HTML rendering. The default directory for templates is "templates" and the default // file extension is ".tmpl". // // If MARTINI_ENV is set to "" or "development" then templates will be recompiled on every request. For more performance, set the // MARTINI_ENV environment variable to "production" func Renderer(options ...Options) martini.Handler { opt := prepareOptions(options) cs := prepareCharset(opt.Charset) var t *template.Template if opt.Template == nil { t = compile(opt) } return func(res http.ResponseWriter, req *http.Request, c martini.Context) { var tc *template.Template if opt.Template == nil { if martini.Env == martini.Dev { // recompile for easy development tc = compile(opt) } else { // use a clone of the initial template tc, _ = t.Clone() } } else { tc = opt.Template } c.MapTo(&renderer{res, req, tc, opt, cs}, (*Render)(nil)) } }
// evalTemplate evaluates a single template (path) and saves it to output. func evalTemplate(path string, output string, t *template.Template, context interface{}) error { newT, err := t.Clone() if err != nil { return err } tData, err := ioutil.ReadFile(path) if err != nil { return err } // Pull out front matter tData, context, err = processFrontmatter(tData, context) if err != nil { return err } _, err = newT.Parse(string(tData)) if err != nil { return err } err = os.MkdirAll(filepath.Dir(output), os.ModePerm) if err != nil { return err } of, err := os.Create(output) if err != nil { return err } defer of.Close() // Ideally we wouldn't have to name the template here, but // https://github.com/golang/go/issues/12996 return newT.ExecuteTemplate(of, "<root>", context) }
// Use Act in order to create an http.Handler that fills a template with the data from an executed Action // or executes the ErrorHandler in case of an error. func (l *Layout) Act(respond Action, eh ErrorHandler, volatility Volatility, templates ...string) http.Handler { var loadTemplates func() (*template.Template, error) var ttl time.Duration if eh == nil { eh = func(w http.ResponseWriter, r *http.Request, e error) {} } switch volatility { case NoVolatility: // Load templates so that we can clone instead of loading every time var storedTemplates *template.Template lock := sync.Mutex{} loadTemplates = func() (*template.Template, error) { var err error lock.Lock() defer lock.Unlock() if storedTemplates == nil { storedTemplates, err = l.load(templates...) if err != nil { return nil, err } } return storedTemplates.Clone() } respond = respond.cache(-1) // cache permanently ttl = 7 * 24 * time.Hour case LowVolatility: ttl = 24 * time.Hour fallthrough case MediumVolatility: if ttl == 0 { ttl = 1 * time.Hour } fallthrough case HighVolatility: if ttl == 0 { ttl = 5 * time.Minute } var storedTemplates *template.Template lock := sync.Mutex{} loadTemplates = func() (*template.Template, error) { var err error // lock to ensure we don't have multiple requests attempting to reload the // templates at the same time lock.Lock() defer lock.Unlock() if storedTemplates == nil { storedTemplates, err = l.load(templates...) if err != nil { return nil, err } time.AfterFunc(ttl, func() { lock.Lock() defer lock.Unlock() storedTemplates = nil }) } return storedTemplates.Clone() } respond = respond.cache(ttl) case ExtremeVolatility: fallthrough // make this the default value default: loadTemplates = func() (*template.Template, error) { return l.load(templates...) } } // ensure that template loading will work template.Must(loadTemplates()) return http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) { t, err := loadTemplates() if err != nil { eh(res, req, err) return } var data map[string]interface{} data, err = respond(req) if err != nil { eh(res, req, err) return } b := new(bytes.Buffer) if err = t.ExecuteTemplate(b, l.baseTemplate, data); err != nil { eh(res, req, err) return } // Add Client-Side caching if volatility < ExtremeVolatility { res.Header().Set("Cache-Control", "public, max-age="+strconv.FormatFloat(ttl.Seconds(), 'f', 0, 64)) res.Header().Set("Expires", time.Now().Add(ttl).Format(time.RFC1123)) } if _, err = b.WriteTo(res); err != nil { eh(res, req, err) } }) }