Initial commit
This commit is contained in:
95
examples/board/main.go
Normal file
95
examples/board/main.go
Normal file
@@ -0,0 +1,95 @@
|
||||
package main
|
||||
|
||||
import "log"
|
||||
import "sync"
|
||||
import "path"
|
||||
import "net/http"
|
||||
import "crypto/tls"
|
||||
import "html/template"
|
||||
import "hnakra/service"
|
||||
|
||||
type Post struct {
|
||||
Author, Content string
|
||||
Next *Post
|
||||
}
|
||||
|
||||
type Board struct {
|
||||
root string
|
||||
mount *service.HTTP
|
||||
mux *http.ServeMux
|
||||
template *template.Template
|
||||
|
||||
postsMutex sync.RWMutex
|
||||
posts *Post
|
||||
}
|
||||
|
||||
func main () {
|
||||
board := Board { root: "/board/" }
|
||||
board.mux = http.NewServeMux()
|
||||
board.mount = &service.HTTP {
|
||||
Mount: service.Mount {
|
||||
Path: board.root,
|
||||
Name: "Board",
|
||||
Description: "A board where you can post things.",
|
||||
TLSConfig: &tls.Config { InsecureSkipVerify: true },
|
||||
},
|
||||
Handler: board.mux,
|
||||
}
|
||||
handle := func (pattern string, handler func (http.ResponseWriter, *http.Request)) {
|
||||
board.mux.HandleFunc(pattern, handler)
|
||||
}
|
||||
handle(board.root, board.serveHome)
|
||||
handle(path.Join(board.root, "actionPost"), board.serveActionPost)
|
||||
board.template = template.Must(template.New("board").Parse(tem))
|
||||
|
||||
err := board.mount.Run()
|
||||
if err != nil {
|
||||
log.Println("XXX", err)
|
||||
}
|
||||
}
|
||||
|
||||
func (board *Board) getPosts (max int) []*Post {
|
||||
board.postsMutex.RLock()
|
||||
defer board.postsMutex.RUnlock()
|
||||
|
||||
posts := make([]*Post, max)
|
||||
count := 0
|
||||
current := board.posts
|
||||
for current != nil && count < max {
|
||||
posts[count] = current
|
||||
count ++
|
||||
current = current.Next
|
||||
}
|
||||
return posts[:count]
|
||||
}
|
||||
|
||||
func (board *Board) serveHome (res http.ResponseWriter, req *http.Request) {
|
||||
if req.URL.Path != board.root {
|
||||
http.NotFoundHandler().ServeHTTP(res, req)
|
||||
return
|
||||
}
|
||||
res.Header().Add("content-type", "text/html")
|
||||
res.WriteHeader(http.StatusOK)
|
||||
board.template.ExecuteTemplate(res, "pageHome", board.getPosts(16))
|
||||
}
|
||||
|
||||
func (board *Board) serveActionPost (res http.ResponseWriter, req *http.Request) {
|
||||
if req.Method != "POST" {
|
||||
res.Header().Add("content-type", "text/plain")
|
||||
res.WriteHeader(http.StatusMethodNotAllowed)
|
||||
res.Write([]byte("Method not allowed"))
|
||||
return
|
||||
}
|
||||
|
||||
defer http.Redirect(res, req, board.root, http.StatusSeeOther)
|
||||
|
||||
req.ParseForm()
|
||||
author := req.PostFormValue("author")
|
||||
content := req.PostFormValue("content")
|
||||
|
||||
board.posts = &Post {
|
||||
Author: author,
|
||||
Content: content,
|
||||
Next: board.posts,
|
||||
}
|
||||
}
|
||||
150
examples/board/template.go
Normal file
150
examples/board/template.go
Normal file
@@ -0,0 +1,150 @@
|
||||
package main
|
||||
|
||||
const tem = `
|
||||
{{define "top"}}
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>{{.}}</title>
|
||||
<style>
|
||||
* {
|
||||
appearance: none;
|
||||
--webkit-appearance: none;
|
||||
font-family: monospace;
|
||||
box-sizing: border-box;
|
||||
color: inherit;
|
||||
font-size: 12pt;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: #b3b5b1;
|
||||
color: #272825;
|
||||
margin: 1em;
|
||||
}
|
||||
|
||||
body > * {
|
||||
margin: auto;
|
||||
max-width: 40em;
|
||||
padding: 1em;
|
||||
}
|
||||
|
||||
header {
|
||||
background-color: #a2a89d;
|
||||
border: 1px solid #8f938c;
|
||||
border-bottom-color: #7f847b;
|
||||
border-radius: 4px 4px 0 0;
|
||||
text-shadow: 1px 1px 1px #b8bfb0;
|
||||
color: #4c4f49;
|
||||
}
|
||||
|
||||
main {
|
||||
background-color: #abaea8;
|
||||
border: 1px solid #959b91;
|
||||
border-top-color: #a1a59e;
|
||||
border-radius: 0 0 4px 4px;
|
||||
}
|
||||
|
||||
h1 { font-size: 1.5em }
|
||||
|
||||
hr {
|
||||
margin: 1em 0;
|
||||
border: none;
|
||||
border-top: 1px solid #7f847b9e;
|
||||
border-bottom: 1px solid #56604f1c;
|
||||
}
|
||||
|
||||
.formRow {
|
||||
margin: 1em 0;
|
||||
}
|
||||
|
||||
button, input, textarea {
|
||||
margin: 0;
|
||||
border: 1px solid #7f847b;
|
||||
background-color: #b3b5b1;
|
||||
padding: 0.25em 0.5em;
|
||||
box-shadow: 1px 1px 0 inset #56604f38;
|
||||
border-radius: 2px;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
textarea {
|
||||
height: 4em;
|
||||
}
|
||||
|
||||
button:not(:active), input[type=submit]:not(:active) {
|
||||
box-shadow: -1px -1px 0 inset #56604f38;
|
||||
}
|
||||
|
||||
button:active, input[type=submit]:active {
|
||||
border-color: #757a71;
|
||||
padding-top: calc(0.25em + 1px);
|
||||
padding-right: calc(0.5em - 1px);
|
||||
padding-bottom: calc(0.25em - 1px);
|
||||
padding-left: calc(0.5em + 1px);
|
||||
}
|
||||
|
||||
.post {
|
||||
padding: 0.4em 0.5em;
|
||||
background-color: #a2a69f;
|
||||
border-radius: 2px;
|
||||
border: 1px solid #8f938c;
|
||||
margin: 1em 0;
|
||||
}
|
||||
|
||||
.post .author {
|
||||
font-size: 0.7em;
|
||||
color: #5e625a;
|
||||
text-shadow: 1px 1px 0 #b3b5b1;
|
||||
margin-bottom: 0.3em;
|
||||
}
|
||||
|
||||
*:last-child { margin-bottom: 0 }
|
||||
*:first-child { margin-top: 0 }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1>{{.}}</h1>
|
||||
</header>
|
||||
<main>
|
||||
{{end}}
|
||||
|
||||
{{define "bottom"}}</main></body></html>{{end}}
|
||||
|
||||
{{define "post"}}
|
||||
<div class=post>
|
||||
<div class=author>{{.Author}}</div>
|
||||
<div class=content>{{.Content}}</div>
|
||||
</div>
|
||||
{{end}}
|
||||
|
||||
{{define "postForm"}}
|
||||
<form method=POST action=actionPost>
|
||||
<div class=formRow>
|
||||
<input type=text name=author id=author placeholder="Name" required>
|
||||
</div>
|
||||
<div class=formRow>
|
||||
<textarea name=content id=content placeholder="Post content" required></textarea>
|
||||
</div>
|
||||
<div class=formRow>
|
||||
<input type=submit value="Post">
|
||||
</div>
|
||||
</form>
|
||||
{{end}}
|
||||
|
||||
{{define "pageGeneric"}}
|
||||
{{template "top" .Title}}
|
||||
<p>{{.Content}}</p>
|
||||
{{template "bottom"}}
|
||||
{{end}}
|
||||
|
||||
{{define "pageHome"}}
|
||||
{{template "top" "Home"}}
|
||||
{{template "postForm"}}
|
||||
<hr>
|
||||
{{range .}}
|
||||
{{template "post" .}}
|
||||
{{end}}
|
||||
{{template "bottom"}}
|
||||
{{end}}
|
||||
`
|
||||
Reference in New Issue
Block a user