示例#1
0
// 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
}
示例#2
0
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
}
示例#3
0
func getLayoutTemplates() *template.Template {
	var templLayouts *template.Template = template.Must(
		template.ParseGlob("templates/layouts/*.html"))

	temp, _ := templLayouts.Clone()

	return temp
}
示例#4
0
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
}
示例#5
0
// 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
}
示例#6
0
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
}
示例#7
0
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)

}
示例#8
0
// 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))
	}
}
示例#9
0
// 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)
}
示例#10
0
// 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)
		}
	})
}