CloudyKit / jet

Jet template engine
Apache License 2.0
1.26k stars 106 forks source link

Global variable with raw html #193

Closed wsantos closed 3 years ago

wsantos commented 3 years ago

I've been playing around with jet and couldn't find a way to render a var with HTML it always escape, how is the correct way to implement it ? for my canse I want to implement the csrf_input

vars.Set("csrf_token", fmt.Sprintf(`<input type="hidden" name="csrf" value="%v" />`, c.Get("csrf"))

Thanks in advance.

sauerbraten commented 3 years ago

That's what https://github.com/CloudyKit/jet/blob/master/docs/builtins.md#rawunsafe is for.

It's a function, so you can use it with any function call syntax: https://github.com/CloudyKit/jet/blob/master/docs/syntax.md#function-calls, with the following exception:

Please note that the raw, unsafe, safeHtml or safeJs built-in escapers (or custom safe writers) need to be the last command evaluated in an action node. This means they have to come last when used in a pipeline.

{{ "hello" | upper | raw }} <!-- valid -->
{{ raw: "hello" }}          <!-- valid -->
{{ raw: "hello" | upper }}  <!-- invalid (upper would be evaluated after raw) -->
wsantos commented 3 years ago

Just to be sure I got it, I'll always need to add | raw there is no way to mark a string safe inside go code, this needs to happen inside template scope ?

Would you be open to a PR for this?

Thanks in advance.

sauerbraten commented 3 years ago

I mean, for implementing your example, it actually seems to be an advantage to have most of the input tag as part of the template (maybe as a block you can include?), and only render the return value of c.Get("csrf") in there? Something like this:

// in Go:
vars.Set("csrf_token", c.Get("csrf")

// in csrf.jet:
{{ block csrf_token() }}
    <input type="hidden" name="csrf" value="{{ csrf_token | raw }}" />
{{ end }}

Apart from that, there is a Renderer interface, that lets you render directly to the output buffer without any escaping. You could define a type like this:

type SafeString string

func (s SafeString) Render(rt *jet.Runtime) {
    rt.Write([]byte(s)) // todo: error handling
}

and then return your string like this from any custom function:

return reflect.ValueOf(SafeString(fmt.Sprintf(`<input type="hidden" name="csrf" value="%v" />`, c.Get("csrf"))))

This should make Jet not touch the string and call its Render() function instead. But to answer your question: no, jet doesn't offer this SafeString type out of the box.

wsantos commented 3 years ago

Perfect, thank you @sauerbraten that solves my problem.