diff --git a/docs/content/templates/functions.md b/docs/content/templates/functions.md
index fc6c361e6..503702290 100644
--- a/docs/content/templates/functions.md
+++ b/docs/content/templates/functions.md
@@ -456,6 +456,21 @@ Example: Given `style = "color: red;"` defined in the front matter of your `.md`
Note: "ZgotmplZ" is a special value that indicates that unsafe content reached a
CSS or URL context.
+### safeJS
+
+Declares the provided string as a known "safe" Javascript string so Go
+html/templates will not escape it. "Safe" means the string encapsulates a known
+safe EcmaScript5 Expression, for example, `(x + y * z())`. Template authors
+are responsible for ensuring that typed expressions do not break the intended
+precedence and that there is no statement/expression ambiguity as when passing
+an expression like `{ foo:bar() }\n['foo']()`, which is both a valid Expression
+and a valid Program with a very different meaning.
+
+Example: Given `hash = "619c16f"` defined in the front matter of your `.md` file:
+
+* `` ⇒ `` (Good!)
+* `` ⇒ `` (Bad!)
+
### singularize
Singularize the given word with a set of common English singularization rules.
diff --git a/tpl/template_funcs.go b/tpl/template_funcs.go
index 8b5b71a2c..283bcc829 100644
--- a/tpl/template_funcs.go
+++ b/tpl/template_funcs.go
@@ -14,7 +14,6 @@
package tpl
import (
- "bitbucket.org/pkg/inflect"
"bytes"
"encoding/base64"
"errors"
@@ -28,6 +27,8 @@ import (
"strings"
"time"
+ "bitbucket.org/pkg/inflect"
+
"github.com/spf13/cast"
"github.com/spf13/hugo/helpers"
jww "github.com/spf13/jwalterweatherman"
@@ -1192,6 +1193,9 @@ func SafeURL(text string) template.URL {
func SafeHTML(a string) template.HTML { return template.HTML(a) }
+// SafeJS returns the given string as a template.JS type from html/template.
+func SafeJS(a string) template.JS { return template.JS(a) }
+
func doArithmetic(a, b interface{}, op rune) (interface{}, error) {
av := reflect.ValueOf(a)
bv := reflect.ValueOf(b)
@@ -1393,6 +1397,7 @@ func init() {
"echoParam": ReturnWhenSet,
"safeHTML": SafeHTML,
"safeCSS": SafeCSS,
+ "safeJS": SafeJS,
"safeURL": SafeURL,
"absURL": func(a string) template.HTML { return template.HTML(helpers.AbsURL(a)) },
"relURL": func(a string) template.HTML { return template.HTML(helpers.RelURL(a)) },
diff --git a/tpl/template_funcs_test.go b/tpl/template_funcs_test.go
index 9683e4595..99acfa475 100644
--- a/tpl/template_funcs_test.go
+++ b/tpl/template_funcs_test.go
@@ -1580,6 +1580,41 @@ func TestSafeCSS(t *testing.T) {
}
}
+func TestSafeJS(t *testing.T) {
+ for i, this := range []struct {
+ str string
+ tmplStr string
+ expectWithoutEscape string
+ expectWithEscape string
+ }{
+ {`619c16f`, ``, ``, ``},
+ } {
+ tmpl, err := template.New("test").Parse(this.tmplStr)
+ if err != nil {
+ t.Errorf("[%d] unable to create new html template %q: %s", i, this.tmplStr, err)
+ continue
+ }
+
+ buf := new(bytes.Buffer)
+ err = tmpl.Execute(buf, this.str)
+ if err != nil {
+ t.Errorf("[%d] execute template with a raw string value returns unexpected error: %s", i, err)
+ }
+ if buf.String() != this.expectWithoutEscape {
+ t.Errorf("[%d] execute template with a raw string value, got %v but expected %v", i, buf.String(), this.expectWithoutEscape)
+ }
+
+ buf.Reset()
+ err = tmpl.Execute(buf, SafeJS(this.str))
+ if err != nil {
+ t.Errorf("[%d] execute template with an escaped string value by SafeJS returns unexpected error: %s", i, err)
+ }
+ if buf.String() != this.expectWithEscape {
+ t.Errorf("[%d] execute template with an escaped string value by SafeJS, got %v but expected %v", i, buf.String(), this.expectWithEscape)
+ }
+ }
+}
+
func TestSafeURL(t *testing.T) {
for i, this := range []struct {
str string