Skip to content

5. Advanced Customization

Matt Mc edited this page Jul 13, 2018 · 3 revisions

There are a few primitives in Jet that you can use to improve performance or handle certain objects a little differently when it comes to rendering them into a template or iterating over them:

  • fast functions by implementing a function with the signature func(jet.Arguments) reflect.Value
  • custom iterator by implementing the interface jet.Ranger
  • custom renderer by implementing the interface jet.Renderer
  • custom escape handling by implementing a SafeWriter function with the signature func(io.Writer, []byte)

Each of these will now be explained with an example.

Fast functions

var views = jet.NewHTMLSet("./views")

views.AddGlobalFunc("base64", func(a jet.Arguments) reflect.Value {
  a.RequireNumOfArguments("base64", 1, 1)

  buffer := bytes.NewBuffer(nil)
  fmt.Fprint(buffer, a.Get(0))

  return reflect.ValueOf(base64.URLEncoding.EncodeToString(buffer.Bytes()))
})

Tell Jet how many arguments your function is supposed to take (pass -1 for min/max if they are 0 or unlimited) – it will panic with a descriptive error message if used incorrectly in a template. Via a.Get(index) you may request an argument by its index.

Custom renderer with jet.Renderer

An example of this is in the example project, see the main.go.

type tTODO struct {
  Text string
  Done bool
}

// Render implements jet.Renderer interface
func (t *tTODO) Render(r *jet.Runtime) {
  done := "yes"
  if !t.Done {
    done = "no"
  }
  r.Write([]byte(fmt.Sprintf("TODO: %s (done: %s)", t.Text, done)))
}

Custom ranger with jet.Ranger

An example of this is in the example project, see the main.go.

Custom escape handling using SafeWriter

When you're taking advantage of Jet's auto-escaping a SafeWriter function is passed upon instantiation of the jet.Set, the default created with jet.NewHTMLSet("your/views/directory") is Go's template.HTMLEscape function. Escape functions get the writer and the bytes to be written as parameters. If you want to disable auto-escaping or handle it in a special way you may provide a custom escape function like this:

func RawWriter(w io.Writer, b []byte) {
  w.Write(b)
}

var views = jet.NewSet(jet.SafeWriter(RawWriter), "./views")

The other way to use custom escape functions is to use them as filters in your templates. The core library does this in the same way because both the raw and the unsafe filters are custom escape functions (take a look into the default.go file). Adding your own is easy:

var views = jet.NewHTMLSet("./views")
views.AddGlobal("specialEscape", jet.SafeWriter(func(w io.Writer, b []byte) {
  // special escape handling
  // then write your bytes into the writer:
  w.Write(b)
}))

Use it in your templates as filters:

{{ "funky user-generated content in need of escaping"|specialEscape }}
{{ specialEscape: "funky user-generated content in need of escaping" }}

As explained in the pipelines section escape functions need to be the last statement when chaining or there cannot be any more filters when using the prefix version.