` or `I <3 Ponies!`.
+ for len(s) > 0 {
+ if c.delim == delimNone {
+ d, t := transitionFunc[c.state](c, s)
+ if c.state == stateText || c.state == stateRCDATA {
+ i := len(s) - len(t)
+ // Emit text up to the start of the tag or comment.
+ if d.state != c.state {
+ for j := i - 1; j >= 0; j-- {
+ if s[j] == '<' {
+ i = j
+ break
+ }
+ }
+ }
+ b.Write(s[:i])
+ }
+ c, s = d, t
+ continue
+ }
+ i := bytes.IndexAny(s, delimEnds[c.delim])
+ if i == -1 {
+ break
+ }
+ if c.delim != delimSpaceOrTagEnd {
+ // Consume any quote.
+ i++
+ }
+ c, s = context{state: stateTag, element: c.element}, s[i:]
+ }
+ if c.state == stateText {
+ if b.Len() == 0 {
+ return html
+ }
+ b.Write(s)
+ }
+ return b.String()
+}
diff --git a/src/pkg/exp/template/html/html_test.go b/src/pkg/exp/template/html/html_test.go
index 2b118c5bb8..2866fdd0ce 100644
--- a/src/pkg/exp/template/html/html_test.go
+++ b/src/pkg/exp/template/html/html_test.go
@@ -19,9 +19,9 @@ func TestHTMLNospaceEscaper(t *testing.T) {
`PQRSTUVWXYZ[\]^_` +
"`abcdefghijklmno" +
"pqrstuvwxyz{|}~\x7f" +
- "\u00A0\u0100\u2028\u2029\ufeff\U0001D11E")
+ "\u00A0\u0100\u2028\u2029\ufeff\ufdec\U0001D11E")
- want := ("\ufffd\x01\x02\x03\x04\x05\x06\x07" +
+ want := ("�\x01\x02\x03\x04\x05\x06\x07" +
"\x08
\x0E\x0F" +
"\x10\x11\x12\x13\x14\x15\x16\x17" +
"\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" +
@@ -31,7 +31,7 @@ func TestHTMLNospaceEscaper(t *testing.T) {
`PQRSTUVWXYZ[\]^_` +
``abcdefghijklmno` +
`pqrstuvwxyz{|}~` + "\u007f" +
- "\u00A0\u0100\u2028\u2029\ufeff\U0001D11E")
+ "\u00A0\u0100\u2028\u2029\ufeff\U0001D11E")
got := htmlNospaceEscaper(input)
if got != want {
@@ -44,6 +44,30 @@ func TestHTMLNospaceEscaper(t *testing.T) {
}
}
+func TestStripTags(t *testing.T) {
+ tests := []struct {
+ input, want string
+ }{
+ {"", ""},
+ {"Hello, World!", "Hello, World!"},
+ {"foo&bar", "foo&bar"},
+ {`Hello
World!`, "Hello World!"},
+ {"Foo
Baz", "Foo Bar Baz"},
+ {"Foo Baz", "Foo Baz"},
+ {"<", "<"},
+ {"foo < bar", "foo < bar"},
+ {`FooBar`, "FooBar"},
+ {`Foo
Bar`, "FooBar"},
+ {`I <3 Ponies!`, `I <3 Ponies!`},
+ }
+
+ for _, test := range tests {
+ if got := stripTags(test.input); got != test.want {
+ t.Errorf("%q: want %q, got %q", test.input, test.want, got)
+ }
+ }
+}
+
func BenchmarkHTMLNospaceEscaper(b *testing.B) {
for i := 0; i < b.N; i++ {
htmlNospaceEscaper("The quick,\r\nbrown fox jumps\u2028over the dog")
@@ -55,3 +79,15 @@ func BenchmarkHTMLNospaceEscaperNoSpecials(b *testing.B) {
htmlNospaceEscaper("The_quick,_brown_fox_jumps_over_the_lazy_dog.")
}
}
+
+func BenchmarkStripTags(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ stripTags("The quick,\r\nbrown fox jumps\u2028over the dog")
+ }
+}
+
+func BenchmarkStripTagsNoSpecials(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ stripTags("The quick, brown fox jumps over the lazy dog.")
+ }
+}
diff --git a/src/pkg/exp/template/html/js.go b/src/pkg/exp/template/html/js.go
index f9251a053b..4318b00acb 100644
--- a/src/pkg/exp/template/html/js.go
+++ b/src/pkg/exp/template/html/js.go
@@ -123,6 +123,17 @@ func jsValEscaper(args ...interface{}) string {
var a interface{}
if len(args) == 1 {
a = args[0]
+ switch t := a.(type) {
+ case JS:
+ return string(t)
+ case JSStr:
+ // TODO: normalize quotes.
+ return `"` + string(t) + `"`
+ case json.Marshaler:
+ // Do not treat as a Stringer.
+ case fmt.Stringer:
+ a = t.String()
+ }
} else {
a = fmt.Sprint(args...)
}
@@ -166,7 +177,11 @@ func jsValEscaper(args ...interface{}) string {
// JavaScript source, in JavaScript embedded in an HTML5