mirror of
https://github.com/golang/go
synced 2024-11-21 20:54:45 -07:00
doc/codelab: use new template package
R=golang-dev, r CC=golang-dev https://golang.org/cl/4897048
This commit is contained in:
parent
0f801ff81e
commit
b67b72da43
@ -1,6 +1,6 @@
|
|||||||
<h1>Editing {Title}</h1>
|
<h1>Editing {{.Title |html}}</h1>
|
||||||
|
|
||||||
<form action="/save/{Title}" method="POST">
|
<form action="/save/{{.Title |html}}" method="POST">
|
||||||
<div><textarea name="body" rows="20" cols="80">{Body|html}</textarea></div>
|
<div><textarea name="body" rows="20" cols="80">{{printf "%s" .Body |html}}</textarea></div>
|
||||||
<div><input type="submit" value="Save"></div>
|
<div><input type="submit" value="Save"></div>
|
||||||
</form>
|
</form>
|
||||||
|
@ -3,9 +3,9 @@ package main
|
|||||||
import (
|
import (
|
||||||
"http"
|
"http"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"old/template"
|
|
||||||
"os"
|
"os"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
"template"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Page struct {
|
type Page struct {
|
||||||
@ -68,7 +68,7 @@ func saveHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func renderTemplate(w http.ResponseWriter, tmpl string, p *Page) {
|
func renderTemplate(w http.ResponseWriter, tmpl string, p *Page) {
|
||||||
t, err := template.ParseFile(tmpl+".html", nil)
|
t, err := template.ParseFile(tmpl+".html")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, err.String(), http.StatusInternalServerError)
|
http.Error(w, err.String(), http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
|
@ -3,8 +3,8 @@ package main
|
|||||||
import (
|
import (
|
||||||
"http"
|
"http"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"old/template"
|
|
||||||
"os"
|
"os"
|
||||||
|
"template"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Page struct {
|
type Page struct {
|
||||||
@ -34,14 +34,14 @@ func editHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
p = &Page{Title: title}
|
p = &Page{Title: title}
|
||||||
}
|
}
|
||||||
t, _ := template.ParseFile("edit.html", nil)
|
t, _ := template.ParseFile("edit.html")
|
||||||
t.Execute(w, p)
|
t.Execute(w, p)
|
||||||
}
|
}
|
||||||
|
|
||||||
func viewHandler(w http.ResponseWriter, r *http.Request) {
|
func viewHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
title := r.URL.Path[lenPath:]
|
title := r.URL.Path[lenPath:]
|
||||||
p, _ := loadPage(title)
|
p, _ := loadPage(title)
|
||||||
t, _ := template.ParseFile("view.html", nil)
|
t, _ := template.ParseFile("view.html")
|
||||||
t.Execute(w, p)
|
t.Execute(w, p)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,9 +3,9 @@ package main
|
|||||||
import (
|
import (
|
||||||
"http"
|
"http"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"old/template"
|
|
||||||
"os"
|
"os"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
"template"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Page struct {
|
type Page struct {
|
||||||
@ -59,7 +59,8 @@ var templates = make(map[string]*template.Template)
|
|||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
for _, tmpl := range []string{"edit", "view"} {
|
for _, tmpl := range []string{"edit", "view"} {
|
||||||
templates[tmpl] = template.MustParseFile(tmpl+".html", nil)
|
t := template.Must(template.ParseFile(tmpl+".html"))
|
||||||
|
templates[tmpl] = t
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"old/template"
|
"template"
|
||||||
"os"
|
"os"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
b, _ := ioutil.ReadAll(os.Stdin)
|
b, _ := ioutil.ReadAll(os.Stdin)
|
||||||
template.HTMLFormatter(os.Stdout, "", b)
|
template.HTMLEscape(os.Stdout, b)
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@ Covered in this codelab:
|
|||||||
<ul>
|
<ul>
|
||||||
<li>Creating a data structure with load and save methods</li>
|
<li>Creating a data structure with load and save methods</li>
|
||||||
<li>Using the <code>http</code> package to build web applications
|
<li>Using the <code>http</code> package to build web applications
|
||||||
<li>Using the <code>old/template</code> package to process HTML templates</li>
|
<li>Using the <code>template</code> package to process HTML templates</li>
|
||||||
<li>Using the <code>regexp</code> package to validate user input</li>
|
<li>Using the <code>regexp</code> package to validate user input</li>
|
||||||
<li>Using closures</li>
|
<li>Using closures</li>
|
||||||
</ul>
|
</ul>
|
||||||
@ -426,27 +426,27 @@ This function will work fine, but all that hard-coded HTML is ugly.
|
|||||||
Of course, there is a better way.
|
Of course, there is a better way.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<h2>The <code>old/template</code> package</h2>
|
<h2>The <code>template</code> package</h2>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
The <code>old/template</code> package is part of the Go standard library.
|
The <code>template</code> package is part of the Go standard library.
|
||||||
(A new template package is coming; this code lab will be updated soon.)
|
(A new template package is coming; this code lab will be updated soon.)
|
||||||
We can
|
We can
|
||||||
use <code>old/template</code> to keep the HTML in a separate file, allowing
|
use <code>template</code> to keep the HTML in a separate file, allowing
|
||||||
us to change the layout of our edit page without modifying the underlying Go
|
us to change the layout of our edit page without modifying the underlying Go
|
||||||
code.
|
code.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
First, we must add <code>old/template</code> to the list of imports:
|
First, we must add <code>template</code> to the list of imports:
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
import (
|
import (
|
||||||
"http"
|
"http"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
<b>"old/template"</b>
|
|
||||||
"os"
|
"os"
|
||||||
|
<b>"template"</b>
|
||||||
)
|
)
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
@ -456,10 +456,10 @@ Open a new file named <code>edit.html</code>, and add the following lines:
|
|||||||
</p>
|
</p>
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
<h1>Editing {Title}</h1>
|
<h1>Editing {{.Title |html}}</h1>
|
||||||
|
|
||||||
<form action="/save/{Title}" method="POST">
|
<form action="/save/{{.Title |html}}" method="POST">
|
||||||
<div><textarea name="body" rows="20" cols="80">{Body|html}</textarea></div>
|
<div><textarea name="body" rows="20" cols="80">{{printf "%s" .Body |html}}</textarea></div>
|
||||||
<div><input type="submit" value="Save"></div>
|
<div><input type="submit" value="Save"></div>
|
||||||
</form>
|
</form>
|
||||||
</pre>
|
</pre>
|
||||||
@ -476,7 +476,7 @@ func editHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
p = &Page{Title: title}
|
p = &Page{Title: title}
|
||||||
}
|
}
|
||||||
t, _ := template.ParseFile("edit.html", nil)
|
t, _ := template.ParseFile("edit.html")
|
||||||
t.Execute(w, p)
|
t.Execute(w, p)
|
||||||
}
|
}
|
||||||
</pre>
|
</pre>
|
||||||
@ -487,19 +487,21 @@ The function <code>template.ParseFile</code> will read the contents of
|
|||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
The method <code>t.Execute</code> replaces all occurrences of
|
The method <code>t.Execute</code> executes the template, writing the
|
||||||
<code>{Title}</code> and <code>{Body}</code> with the values of
|
generated HTML to the <code>http.ResponseWriter</code>.
|
||||||
<code>p.Title</code> and <code>p.Body</code>, and writes the resultant
|
The <code>.Title</code> and <code>.Body</code> dotted identifiers refer to
|
||||||
HTML to the <code>http.ResponseWriter</code>.
|
<code>p.Title</code> and <code>p.Body</code>.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
Note that we've used <code>{Body|html}</code> in the above template.
|
Template directives are enclosed in double curly braces.
|
||||||
The <code>|html</code> part asks the template engine to pass the value
|
The <code>printf "%s" .Body</code> instruction is a function call
|
||||||
<code>Body</code> through the <code>html</code> formatter before outputting it,
|
that outputs <code>.Body</code> as a string instead of a stream of bytes,
|
||||||
which escapes HTML characters (such as replacing <code>></code> with
|
the same as a call to <code>fmt.Printf</code>.
|
||||||
<code>&gt;</code>).
|
The <code>|html</code> part of each directive pipes the value through the
|
||||||
This will prevent user data from corrupting the form HTML.
|
<code>html</code> formatter before outputting it, which escapes HTML
|
||||||
|
characters (such as replacing <code>></code> with <code>&gt;</code>),
|
||||||
|
preventing user data from corrupting the form HTML.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
@ -513,11 +515,11 @@ While we're working with templates, let's create a template for our
|
|||||||
</p>
|
</p>
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
<h1>{Title}</h1>
|
<h1>{{.Title |html}}</h1>
|
||||||
|
|
||||||
<p>[<a href="/edit/{Title}">edit</a>]</p>
|
<p>[<a href="/edit/{{.Title |html}}">edit</a>]</p>
|
||||||
|
|
||||||
<div>{Body}</div>
|
<div>{{printf "%s" .Body |html}}</div>
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
@ -528,7 +530,7 @@ Modify <code>viewHandler</code> accordingly:
|
|||||||
func viewHandler(w http.ResponseWriter, r *http.Request) {
|
func viewHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
title := r.URL.Path[lenPath:]
|
title := r.URL.Path[lenPath:]
|
||||||
p, _ := loadPage(title)
|
p, _ := loadPage(title)
|
||||||
t, _ := template.ParseFile("view.html", nil)
|
t, _ := template.ParseFile("view.html")
|
||||||
t.Execute(w, p)
|
t.Execute(w, p)
|
||||||
}
|
}
|
||||||
</pre>
|
</pre>
|
||||||
@ -708,16 +710,17 @@ var templates = make(map[string]*template.Template)
|
|||||||
<p>
|
<p>
|
||||||
Then we create an <code>init</code> function, which will be called before
|
Then we create an <code>init</code> function, which will be called before
|
||||||
<code>main</code> at program initialization. The function
|
<code>main</code> at program initialization. The function
|
||||||
<code>template.MustParseFile</code> is a convenience wrapper around
|
<code>template.Must</code> is a convenience wrapper that panics when passed a
|
||||||
<code>ParseFile</code> that does not return an error code; instead, it panics
|
non-nil <code>os.Error</code> value, and otherwise returns the
|
||||||
if an error is encountered. A panic is appropriate here; if the templates can't
|
<code>*Template</code> unaltered. A panic is appropriate here; if the templates
|
||||||
be loaded the only sensible thing to do is exit the program.
|
can't be loaded the only sensible thing to do is exit the program.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
func init() {
|
func init() {
|
||||||
for _, tmpl := range []string{"edit", "view"} {
|
for _, tmpl := range []string{"edit", "view"} {
|
||||||
templates[tmpl] = template.MustParseFile(tmpl+".html", nil)
|
t := template.Must(template.ParseFile(tmpl + ".html"))
|
||||||
|
templates[tmpl] = t
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</pre>
|
</pre>
|
||||||
@ -763,10 +766,9 @@ var titleValidator = regexp.MustCompile("^[a-zA-Z0-9]+$")
|
|||||||
<p>
|
<p>
|
||||||
The function <code>regexp.MustCompile</code> will parse and compile the
|
The function <code>regexp.MustCompile</code> will parse and compile the
|
||||||
regular expression, and return a <code>regexp.Regexp</code>.
|
regular expression, and return a <code>regexp.Regexp</code>.
|
||||||
<code>MustCompile</code>, like <code>template.MustParseFile</code>,
|
<code>MustCompile</code> is distinct from <code>Compile</code> in that it will
|
||||||
is distinct from <code>Compile</code> in that it will panic if
|
panic if the expression compilation fails, while <code>Compile</code> returns
|
||||||
the expression compilation fails, while <code>Compile</code> returns an
|
an <code>os.Error</code> as a second parameter.
|
||||||
<code>os.Error</code> as a second parameter.
|
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
|
@ -8,7 +8,7 @@ import (
|
|||||||
"go/ast"
|
"go/ast"
|
||||||
"go/token"
|
"go/token"
|
||||||
"log"
|
"log"
|
||||||
"old/template"
|
"template"
|
||||||
"os"
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<h1>{Title}</h1>
|
<h1>{{.Title |html}}</h1>
|
||||||
|
|
||||||
<p>[<a href="/edit/{Title}">edit</a>]</p>
|
<p>[<a href="/edit/{{.Title |html}}">edit</a>]</p>
|
||||||
|
|
||||||
<div>{Body}</div>
|
<div>{{printf "%s" .Body |html}}</div>
|
||||||
|
@ -7,7 +7,7 @@ Covered in this codelab:
|
|||||||
<ul>
|
<ul>
|
||||||
<li>Creating a data structure with load and save methods</li>
|
<li>Creating a data structure with load and save methods</li>
|
||||||
<li>Using the <code>http</code> package to build web applications
|
<li>Using the <code>http</code> package to build web applications
|
||||||
<li>Using the <code>old/template</code> package to process HTML templates</li>
|
<li>Using the <code>template</code> package to process HTML templates</li>
|
||||||
<li>Using the <code>regexp</code> package to validate user input</li>
|
<li>Using the <code>regexp</code> package to validate user input</li>
|
||||||
<li>Using closures</li>
|
<li>Using closures</li>
|
||||||
</ul>
|
</ul>
|
||||||
@ -366,27 +366,27 @@ This function will work fine, but all that hard-coded HTML is ugly.
|
|||||||
Of course, there is a better way.
|
Of course, there is a better way.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<h2>The <code>old/template</code> package</h2>
|
<h2>The <code>template</code> package</h2>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
The <code>old/template</code> package is part of the Go standard library.
|
The <code>template</code> package is part of the Go standard library.
|
||||||
(A new template package is coming; this code lab will be updated soon.)
|
(A new template package is coming; this code lab will be updated soon.)
|
||||||
We can
|
We can
|
||||||
use <code>old/template</code> to keep the HTML in a separate file, allowing
|
use <code>template</code> to keep the HTML in a separate file, allowing
|
||||||
us to change the layout of our edit page without modifying the underlying Go
|
us to change the layout of our edit page without modifying the underlying Go
|
||||||
code.
|
code.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
First, we must add <code>old/template</code> to the list of imports:
|
First, we must add <code>template</code> to the list of imports:
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
import (
|
import (
|
||||||
"http"
|
"http"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
<b>"old/template"</b>
|
|
||||||
"os"
|
"os"
|
||||||
|
<b>"template"</b>
|
||||||
)
|
)
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
@ -414,19 +414,21 @@ The function <code>template.ParseFile</code> will read the contents of
|
|||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
The method <code>t.Execute</code> replaces all occurrences of
|
The method <code>t.Execute</code> executes the template, writing the
|
||||||
<code>{Title}</code> and <code>{Body}</code> with the values of
|
generated HTML to the <code>http.ResponseWriter</code>.
|
||||||
<code>p.Title</code> and <code>p.Body</code>, and writes the resultant
|
The <code>.Title</code> and <code>.Body</code> dotted identifiers refer to
|
||||||
HTML to the <code>http.ResponseWriter</code>.
|
<code>p.Title</code> and <code>p.Body</code>.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
Note that we've used <code>{Body|html}</code> in the above template.
|
Template directives are enclosed in double curly braces.
|
||||||
The <code>|html</code> part asks the template engine to pass the value
|
The <code>printf "%s" .Body</code> instruction is a function call
|
||||||
<code>Body</code> through the <code>html</code> formatter before outputting it,
|
that outputs <code>.Body</code> as a string instead of a stream of bytes,
|
||||||
which escapes HTML characters (such as replacing <code>></code> with
|
the same as a call to <code>fmt.Printf</code>.
|
||||||
<code>&gt;</code>).
|
The <code>|html</code> part of each directive pipes the value through the
|
||||||
This will prevent user data from corrupting the form HTML.
|
<code>html</code> formatter before outputting it, which escapes HTML
|
||||||
|
characters (such as replacing <code>></code> with <code>&gt;</code>),
|
||||||
|
preventing user data from corrupting the form HTML.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
@ -572,10 +574,10 @@ our <code>*Template</code> values, keyed by <code>string</code>
|
|||||||
<p>
|
<p>
|
||||||
Then we create an <code>init</code> function, which will be called before
|
Then we create an <code>init</code> function, which will be called before
|
||||||
<code>main</code> at program initialization. The function
|
<code>main</code> at program initialization. The function
|
||||||
<code>template.MustParseFile</code> is a convenience wrapper around
|
<code>template.Must</code> is a convenience wrapper that panics when passed a
|
||||||
<code>ParseFile</code> that does not return an error code; instead, it panics
|
non-nil <code>os.Error</code> value, and otherwise returns the
|
||||||
if an error is encountered. A panic is appropriate here; if the templates can't
|
<code>*Template</code> unaltered. A panic is appropriate here; if the templates
|
||||||
be loaded the only sensible thing to do is exit the program.
|
can't be loaded the only sensible thing to do is exit the program.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
@ -618,10 +620,9 @@ Then we can create a global variable to store our validation regexp:
|
|||||||
<p>
|
<p>
|
||||||
The function <code>regexp.MustCompile</code> will parse and compile the
|
The function <code>regexp.MustCompile</code> will parse and compile the
|
||||||
regular expression, and return a <code>regexp.Regexp</code>.
|
regular expression, and return a <code>regexp.Regexp</code>.
|
||||||
<code>MustCompile</code>, like <code>template.MustParseFile</code>,
|
<code>MustCompile</code> is distinct from <code>Compile</code> in that it will
|
||||||
is distinct from <code>Compile</code> in that it will panic if
|
panic if the expression compilation fails, while <code>Compile</code> returns
|
||||||
the expression compilation fails, while <code>Compile</code> returns an
|
an <code>os.Error</code> as a second parameter.
|
||||||
<code>os.Error</code> as a second parameter.
|
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
|
Loading…
Reference in New Issue
Block a user