diff options
author | Nigel Tao <nigeltao@golang.org> | 2011-09-03 10:30:05 +1000 |
---|---|---|
committer | Nigel Tao <nigeltao@golang.org> | 2011-09-03 10:30:05 +1000 |
commit | 2b6d3b498c92371b5e9721d8ca69bc680f4c80f3 (patch) | |
tree | 61104f2a1878fe8b3f9ef6f30f9405a6103d6be4 | |
parent | 9854fd2a0efbeae0a76082a25f46756fe2884b6b (diff) | |
download | go-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.go | 200 |
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 |