-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #9 from rur/v0.2.0
v0.2.0 improve code docs and further API clarifications
- Loading branch information
Showing
18 changed files
with
494 additions
and
187 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
/* | ||
Package treetop provides tools for handlers to support a HTML template request protocol . | ||
So your webpage does IO; and you need to show updates without clobbering the interface. | ||
The common approach is to expose a data API and dispatch JavaScript to micromanage the client. | ||
That will work, but it is pretty heavy duty for what seems like a simple problem. | ||
Conventional HTTP works very well for navigation and web forms alike, no micromanagement required. | ||
Perhaps it could be extended to solve our dynamic update problem. That is the starting point for Treetop, | ||
to see how far we can get with a simple protocol. | ||
Treetop is unique because it puts the server-side hander in complete control of how the page will be updated | ||
following a request. | ||
For documentation and examples see https://github.com/rur/treetop and https://github.com/rur/treetop-recipes | ||
Introduction | ||
In the spirit of opt-in integration this package supports two use cases. | ||
The first is the handler scoped 'Writer' which is useful for supporting | ||
ad-hoc fragments in an existing application. The view builder abstraction is | ||
the second, it is designed for constructing a UI with many | ||
cooperating endpoints. | ||
Example of ad-hoc partial writer | ||
import ( | ||
"fmt" | ||
"github.com/rur/treetop" | ||
"net/http" | ||
) | ||
... | ||
func MyHandlerFunc(w http.ResponseWriter, req *http.Request) { | ||
if pw, ok := treetop.NewPartialWriter(w, req); ok { | ||
fmt.Fprint(pw, `<p id="greeting">Hello Treetop!</p>`) | ||
return | ||
} | ||
// otherwise render a full page | ||
... | ||
} | ||
For the example, the 'full page' document will include: the Treetop client library, an element | ||
with an ID of "greeting" and an anchor element with a 'treetop' attribute. | ||
Example HTML document | ||
<!DOCTYPE html> | ||
<html> | ||
<head> | ||
<title>My Page</title> | ||
</head> | ||
<body> | ||
<h1>Message</h1> | ||
<p id="greeting">Hello Page!</p> | ||
<div><a treetop href=".">Fetch greeting</a></div> | ||
<script> | ||
// use default config, global variable will signal treetop client to initialize | ||
TREETOP_CONFIG = {} | ||
</script> | ||
<script src="/lib/treetop.js" async></script> | ||
</body> | ||
</html> | ||
When the 'Fetch greeting' anchor is clicked, the client library will issue an XHR fetch | ||
with the appropriate headers. Elements on the DOM will then be replaced with fragments from | ||
the response body based upon their ID attribute. | ||
Views and Templates | ||
Many Go web applications take advantage of the HTML template support | ||
in the Go standard library. Package treetop includes a view builder | ||
that works with the template system to support pages, partials and fragments. | ||
Example | ||
base := treetop.NewView( | ||
treetop.DefaultTemplateExec, | ||
"base.html.tmpl", | ||
baseHandler, | ||
) | ||
greeting := base.NewSubView( | ||
"greeting", | ||
"greeting.html.tmpl", | ||
greetingHandler, | ||
) | ||
mymux.Handle("/", treetop.ViewHandler(greeting)) | ||
See the documentation of the View type for details. | ||
Browser History - Partials vs Fragments | ||
This can cause confussion, but it is a very useful distinction. A partial is a | ||
_part_ of an HTML document, a fragment is a general purpose HTML | ||
snippet. Both have a URL, but only the former should be considered 'navigation' | ||
by the user agent. This allows browser history to be handled correctly so that back, | ||
forward and refresh behavior work as expected. | ||
Note: The client relies upon the HTML 5 history API to support Treetop partials. | ||
*/ | ||
package treetop |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
package main | ||
|
||
import ( | ||
"fmt" | ||
"log" | ||
"net/http" | ||
|
||
"github.com/rur/treetop" | ||
"github.com/rur/treetop/examples/shared" | ||
|
||
"github.com/rur/treetop/examples/view" | ||
"github.com/rur/treetop/examples/writer" | ||
) | ||
|
||
func main() { | ||
mux := http.NewServeMux() | ||
mux.HandleFunc("/favicon.ico", func(_ http.ResponseWriter, _ *http.Request) { /* noop */ }) | ||
mux.HandleFunc("/", func(w http.ResponseWriter, _ *http.Request) { | ||
treetop.StringTemplateExec(w, []string{shared.BaseTemplate}, nil) | ||
}) | ||
view.SetupGreeter(mux) | ||
writer.SetupGreeter(mux) | ||
fmt.Println("serving on http://0.0.0.0:3000/") | ||
log.Fatal(http.ListenAndServe(":3000", mux)) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
package shared | ||
|
||
// BaseTemplate is the document markup shared by all of the example applications | ||
var BaseTemplate = ` | ||
<!DOCTYPE html> | ||
<html lang="en"> | ||
<head> | ||
<meta charset="UTF-8"> | ||
<title>Treetop Examples</title> | ||
</head> | ||
<body> | ||
<nav> | ||
<ul> | ||
<li><a href="/view" title="View Greeter">View Greeter</a></li> | ||
<li><a href="/writer" title="Writer Greeter">Writer Greeter</a></li> | ||
</ul> | ||
</nav> | ||
{{ block "content" . }} | ||
<p id="content">↑ Choose a demo ↑</p> | ||
{{ end }} | ||
<script>TREETOP_CONFIG={/*defaults*/}</script> | ||
<script src="https://rawgit.com/rur/treetop-client/master/treetop.js" async></script> | ||
</body> | ||
</html> | ||
` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
package view | ||
|
||
import ( | ||
"net/http" | ||
|
||
"github.com/rur/treetop" | ||
"github.com/rur/treetop/examples/shared" | ||
) | ||
|
||
var ( | ||
content = ` | ||
{{ block "content" . }} | ||
<div id="content" style="text-align: center;"> | ||
<h1>Treetop View Greeter</h1> | ||
<div> | ||
<form action="/view/greet" treetop> | ||
<span>Greet, </span><input placeholder="Name" type="text" name="name"> | ||
</form> | ||
</div> | ||
{{ template "message" .Message}} | ||
</div> | ||
{{ end }} | ||
` | ||
landing = ` | ||
{{ block "message" . }} | ||
<p id="message"><i>Give me someone to say hello to!</i></p> | ||
{{ end }} | ||
` | ||
greeting = ` | ||
{{ block "message" . }} | ||
<div id="message"> | ||
<h2>Hello, {{ . }}!</h2> | ||
<p><a href="/view" treetop>Clear</a></p> | ||
</div> | ||
{{ end }} | ||
` | ||
) | ||
|
||
// SetupGreeter add routes for /view example endpoint | ||
func SetupGreeter(mux *http.ServeMux) { | ||
page := treetop.NewView( | ||
treetop.StringTemplateExec, | ||
shared.BaseTemplate, | ||
treetop.Delegate("content"), // adopt "content" handler as own template data | ||
) | ||
content := page.SubView("content", content, contentHandler) | ||
|
||
greetForm := content.SubView("message", landing, treetop.Noop) | ||
greetMessage := content.SubView("message", greeting, greetingHandler) | ||
|
||
mux.Handle("/view", treetop.ViewHandler(greetForm)) | ||
mux.Handle("/view/greet", treetop.ViewHandler(greetMessage)) | ||
} | ||
|
||
// contentHandler loads data for the content template | ||
func contentHandler(rsp treetop.Response, req *http.Request) interface{} { | ||
return struct { | ||
// In the content template the .Message field is passed explicitly to the | ||
// "message" template block. | ||
Message interface{} | ||
}{ | ||
// HandleSubView triggers the sub handler call and returns the sub template data. | ||
// `who` in the case of the greetingHandler, or nil in the case of Noop | ||
Message: rsp.HandleSubView("message", req), | ||
} | ||
} | ||
|
||
// greetingHandler obtains the name for the greeting from the request query | ||
func greetingHandler(_ treetop.Response, req *http.Request) interface{} { | ||
who := req.URL.Query().Get("name") | ||
if who == "" { | ||
return "World" | ||
} | ||
// NOTE: relying on Go package html/template for input escaping | ||
return who | ||
} |
Oops, something went wrong.