aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNigel Tao <nigeltao@golang.org>2011-09-03 10:30:05 +1000
committerNigel Tao <nigeltao@golang.org>2011-09-03 10:30:05 +1000
commit2b6d3b498c92371b5e9721d8ca69bc680f4c80f3 (patch)
tree61104f2a1878fe8b3f9ef6f30f9405a6103d6be4
parent9854fd2a0efbeae0a76082a25f46756fe2884b6b (diff)
downloadgo-2b6d3b498c92371b5e9721d8ca69bc680f4c80f3.tar.gz
go-2b6d3b498c92371b5e9721d8ca69bc680f4c80f3.zip
exp/template/html: string replacement refactoring.
R=mikesamuel CC=golang-dev https://golang.org/cl/4968063
-rw-r--r--src/pkg/exp/template/html/js.go200
1 files changed, 74 insertions, 126 deletions
diff --git a/src/pkg/exp/template/html/js.go b/src/pkg/exp/template/html/js.go
index 4480542535..65479bc13e 100644
--- a/src/pkg/exp/template/html/js.go
+++ b/src/pkg/exp/template/html/js.go
@@ -166,66 +166,7 @@ func jsValEscaper(args ...interface{}) string {
// JavaScript source, in JavaScript embedded in an HTML5 <script> element,
// or in an HTML5 event handler attribute such as onclick.
func jsStrEscaper(args ...interface{}) string {
- ok := false
- var s string
- if len(args) == 1 {
- s, ok = args[0].(string)
- }
- if !ok {
- s = fmt.Sprint(args...)
- }
- var b bytes.Buffer
- written := 0
- for i, r := range s {
- var repl string
- switch r {
- case 0:
- repl = `\0`
- case '\t':
- repl = `\t`
- case '\n':
- repl = `\n`
- case '\v':
- // "\v" == "v" on IE 6.
- repl = `\x0b`
- case '\f':
- repl = `\f`
- case '\r':
- repl = `\r`
- // Encode HTML specials as hex so the output can be embedded
- // in HTML attributes without further encoding.
- case '"':
- repl = `\x22`
- case '&':
- repl = `\x26`
- case '\'':
- repl = `\x27`
- case '+':
- repl = `\x2b`
- case '/':
- repl = `\/`
- case '<':
- repl = `\x3c`
- case '>':
- repl = `\x3e`
- case '\\':
- repl = `\\`
- case '\u2028':
- repl = `\u2028`
- case '\u2029':
- repl = `\u2029`
- default:
- continue
- }
- b.WriteString(s[written:i])
- b.WriteString(repl)
- written = i + utf8.RuneLen(r)
- }
- if written == 0 {
- return s
- }
- b.WriteString(s[written:])
- return b.String()
+ return replace(stringify(args...), jsStrReplacementTable)
}
// jsRegexpEscaper behaves like jsStrEscaper but escapes regular expression
@@ -233,79 +174,35 @@ func jsStrEscaper(args ...interface{}) string {
// expression literal. /foo{{.X}}bar/ matches the string "foo" followed by
// the literal text of {{.X}} followed by the string "bar".
func jsRegexpEscaper(args ...interface{}) string {
- ok := false
- var s string
+ return replace(stringify(args...), jsRegexpReplacementTable)
+}
+
+// stringify is an optimized form of fmt.Sprint.
+func stringify(args ...interface{}) string {
if len(args) == 1 {
- s, ok = args[0].(string)
- }
- if !ok {
- s = fmt.Sprint(args...)
+ if s, ok := args[0].(string); ok {
+ return s
+ }
}
+ return fmt.Sprint(args...)
+}
+
+// replace replaces each rune r of s with replacementTable[r], provided that
+// r < len(replacementTable). If replacementTable[r] is the empty string then
+// no replacement is made.
+// It also replaces the runes '\u2028' and '\u2029' with the strings
+// `\u2028` and `\u2029`. Note the different quotes used.
+func replace(s string, replacementTable []string) string {
var b bytes.Buffer
written := 0
for i, r := range s {
var repl string
- switch r {
- case 0:
- repl = `\0`
- case '\t':
- repl = `\t`
- case '\n':
- repl = `\n`
- case '\v':
- // "\v" == "v" on IE 6.
- repl = `\x0b`
- case '\f':
- repl = `\f`
- case '\r':
- repl = `\r`
- // Encode HTML specials as hex so the output can be embedded
- // in HTML attributes without further encoding.
- case '"':
- repl = `\x22`
- case '$':
- repl = `\$`
- case '&':
- repl = `\x26`
- case '\'':
- repl = `\x27`
- case '(':
- repl = `\(`
- case ')':
- repl = `\)`
- case '*':
- repl = `\*`
- case '+':
- repl = `\x2b`
- case '-':
- repl = `\-`
- case '.':
- repl = `\.`
- case '/':
- repl = `\/`
- case '<':
- repl = `\x3c`
- case '>':
- repl = `\x3e`
- case '?':
- repl = `\?`
- case '[':
- repl = `\[`
- case '\\':
- repl = `\\`
- case ']':
- repl = `\]`
- case '^':
- repl = `\^`
- case '{':
- repl = `\{`
- case '|':
- repl = `\|`
- case '}':
- repl = `\}`
- case '\u2028':
+ switch {
+ case r < len(replacementTable) && replacementTable[r] != "":
+ repl = replacementTable[r]
+ case r == '\u2028':
repl = `\u2028`
- case '\u2029':
+ case r == '\u2029':
repl = `\u2029`
default:
continue
@@ -321,6 +218,57 @@ func jsRegexpEscaper(args ...interface{}) string {
return b.String()
}
+var jsStrReplacementTable = []string{
+ 0: `\0`,
+ '\t': `\t`,
+ '\n': `\n`,
+ '\v': `\x0b`, // "\v" == "v" on IE 6.
+ '\f': `\f`,
+ '\r': `\r`,
+ // Encode HTML specials as hex so the output can be embedded
+ // in HTML attributes without further encoding.
+ '"': `\x22`,
+ '&': `\x26`,
+ '\'': `\x27`,
+ '+': `\x2b`,
+ '/': `\/`,
+ '<': `\x3c`,
+ '>': `\x3e`,
+ '\\': `\\`,
+}
+
+var jsRegexpReplacementTable = []string{
+ 0: `\0`,
+ '\t': `\t`,
+ '\n': `\n`,
+ '\v': `\x0b`, // "\v" == "v" on IE 6.
+ '\f': `\f`,
+ '\r': `\r`,
+ // Encode HTML specials as hex so the output can be embedded
+ // in HTML attributes without further encoding.
+ '"': `\x22`,
+ '$': `\$`,
+ '&': `\x26`,
+ '\'': `\x27`,
+ '(': `\(`,
+ ')': `\)`,
+ '*': `\*`,
+ '+': `\x2b`,
+ '-': `\-`,
+ '.': `\.`,
+ '/': `\/`,
+ '<': `\x3c`,
+ '>': `\x3e`,
+ '?': `\?`,
+ '[': `\[`,
+ '\\': `\\`,
+ ']': `\]`,
+ '^': `\^`,
+ '{': `\{`,
+ '|': `\|`,
+ '}': `\}`,
+}
+
// isJSIdentPart is true if the given rune is a JS identifier part.
// It does not handle all the non-Latin letters, joiners, and combining marks,
// but it does handle every codepoint that can occur in a numeric literal or