aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDimitri Sokolyuk <demon@dim13.org>2016-02-16 18:43:22 +0100
committerDimitri Sokolyuk <demon@dim13.org>2016-02-16 18:43:22 +0100
commit8bf5d9d2c82560c81be6809522215bded0cf9911 (patch)
tree82df16f1e2b3d130b63a910df55e22a124d56c5b
Inital import
-rw-r--r--data/.gitkeep0
-rw-r--r--edit.go16
-rw-r--r--index.go27
-rw-r--r--parse.go49
-rw-r--r--root.go11
-rw-r--r--save.go17
-rw-r--r--tmpl/doc23
-rw-r--r--tmpl/edit9
-rw-r--r--tmpl/index8
-rw-r--r--tmpl/root27
-rw-r--r--tmpl/view4
-rw-r--r--view.go22
-rw-r--r--wiki.go39
13 files changed, 252 insertions, 0 deletions
diff --git a/data/.gitkeep b/data/.gitkeep
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/data/.gitkeep
diff --git a/edit.go b/edit.go
new file mode 100644
index 0000000..a425a1a
--- /dev/null
+++ b/edit.go
@@ -0,0 +1,16 @@
+package main
+
+import (
+ "net/http"
+ "text/template"
+)
+
+func init() {
+ http.HandleFunc("/edit/", editHandler)
+}
+
+func editHandler(w http.ResponseWriter, r *http.Request) {
+ title := r.URL.Path[len("/edit/"):]
+ p, _ := loadPage(title)
+ p.render(w, template.Must(template.ParseFiles("tmpl/root", "tmpl/edit")))
+}
diff --git a/index.go b/index.go
new file mode 100644
index 0000000..a9613fd
--- /dev/null
+++ b/index.go
@@ -0,0 +1,27 @@
+package main
+
+import (
+ "io/ioutil"
+ "net/http"
+ "text/template"
+)
+
+func init() {
+ http.HandleFunc("/index", indexHandler)
+}
+
+func indexHandler(w http.ResponseWriter, r *http.Request) {
+ files, err := ioutil.ReadDir("data")
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+ p := new(Page)
+ for _, entry := range files {
+ file := entry.Name()
+ if !entry.IsDir() && file[0] != '.' {
+ p.Pages = append(p.Pages, file)
+ }
+ }
+ p.render(w, template.Must(template.ParseFiles("tmpl/root", "tmpl/index")))
+}
diff --git a/parse.go b/parse.go
new file mode 100644
index 0000000..ccf2a87
--- /dev/null
+++ b/parse.go
@@ -0,0 +1,49 @@
+package main
+
+import (
+ "bytes"
+ "regexp"
+ "strings"
+ "text/template"
+)
+
+var (
+ doc = template.Must(template.ParseFiles("tmpl/doc"))
+ intlink = regexp.MustCompile(`\[[^\]]+\]`)
+ extlink = regexp.MustCompile(`(https?|ftp)://\S+`)
+ imglink = regexp.MustCompile(`\.(jpe?g|png|gif)$`)
+)
+
+func parse(in []byte) string {
+ buf := new(bytes.Buffer)
+ for _, v := range strings.Split(string(in), "\r\n\r\n") {
+ v = intlink.ReplaceAllStringFunc(v, func(s string) string {
+ tmp := new(bytes.Buffer)
+ doc.ExecuteTemplate(tmp, "link", s[1:len(s)-1])
+ return tmp.String()
+ })
+ v = extlink.ReplaceAllStringFunc(v, func(s string) string {
+ tmp := new(bytes.Buffer)
+ if imglink.MatchString(s) {
+ doc.ExecuteTemplate(tmp, "img", s)
+ } else {
+ doc.ExecuteTemplate(tmp, "link", s)
+ }
+ return tmp.String()
+ })
+
+ switch v[0] {
+ case ' ':
+ doc.ExecuteTemplate(buf, "pre", v)
+ case '-':
+ lines := strings.Split(v, "\r\n")
+ for i, l := range lines {
+ lines[i] = l[1:]
+ }
+ doc.ExecuteTemplate(buf, "list", lines)
+ default:
+ doc.ExecuteTemplate(buf, "par", v)
+ }
+ }
+ return buf.String()
+}
diff --git a/root.go b/root.go
new file mode 100644
index 0000000..b9b7e4d
--- /dev/null
+++ b/root.go
@@ -0,0 +1,11 @@
+package main
+
+import "net/http"
+
+func init() {
+ http.HandleFunc("/", rootHandler)
+}
+
+func rootHandler(w http.ResponseWriter, r *http.Request) {
+ http.Redirect(w, r, "/view/Root", http.StatusFound)
+}
diff --git a/save.go b/save.go
new file mode 100644
index 0000000..68ac700
--- /dev/null
+++ b/save.go
@@ -0,0 +1,17 @@
+package main
+
+import "net/http"
+
+func init() {
+ http.HandleFunc("/save/", saveHandler)
+}
+
+func saveHandler(w http.ResponseWriter, r *http.Request) {
+ title := r.URL.Path[len("/save/"):]
+ p := &Page{Title: title, Body: []byte(r.FormValue("body"))}
+ if err := p.save(); err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+ http.Redirect(w, r, "/view/"+title, http.StatusFound)
+}
diff --git a/tmpl/doc b/tmpl/doc
new file mode 100644
index 0000000..f4f1dd3
--- /dev/null
+++ b/tmpl/doc
@@ -0,0 +1,23 @@
+{{define "link"}}
+ <a href="{{.}}">{{.}}</a>
+{{end}}
+
+{{define "img"}}
+ <img src="{{.}}">
+{{end}}
+
+{{define "par"}}
+ <p>{{.}}</p>
+{{end}}
+
+{{define "pre"}}
+ <pre>{{.}}</pre>
+{{end}}
+
+{{define "list"}}
+<ul>
+ {{range .}}
+ <li>{{.}}</li>
+ {{end}}
+</ul>
+{{end}}
diff --git a/tmpl/edit b/tmpl/edit
new file mode 100644
index 0000000..16b7846
--- /dev/null
+++ b/tmpl/edit
@@ -0,0 +1,9 @@
+{{define "title"}}Editing {{.Title}}{{end}}
+{{define "content"}}
+<form action="/save/{{.Title}}" method="POST">
+<textarea name="body" rows="20" cols="80">{{printf "%s" .Body}}</textarea>
+<br>
+<input type="submit" value="Save">
+<input type="reset" value="Reset">
+</form>
+{{end}}
diff --git a/tmpl/index b/tmpl/index
new file mode 100644
index 0000000..d95deca
--- /dev/null
+++ b/tmpl/index
@@ -0,0 +1,8 @@
+{{define "title"}}Index{{end}}
+{{define "content"}}
+<ul>
+{{range .Pages}}
+<li><a href="/view/{{.}}">{{.}}</a></li>
+{{end}}
+</ul>
+{{end}}
diff --git a/tmpl/root b/tmpl/root
new file mode 100644
index 0000000..ae31e36
--- /dev/null
+++ b/tmpl/root
@@ -0,0 +1,27 @@
+{{define "root"}}
+<!DOCTYPE html>
+<html>
+<head>
+ <title>{{template "title" .}}</title>
+ <link href='http://fonts.googleapis.com/css?family=Raleway|Anonymous+Pro' rel='stylesheet' type='text/css'>
+ <style>
+ body {
+ font-family: 'Raleway', sans-serif;
+ margin: 5% 10%;
+ }
+ pre {
+ font-family: 'Anonymous Pro', monospace;
+ }
+ </style>
+</head>
+<body>
+<section>
+<header>
+<h1>{{template "title" .}}</h1>
+<nav><a href="/">root</a> <a href="/index">index</a> {{with .Title}}<a href="/edit/{{.}}">edit</a>{{end}}</nav>
+</header>
+{{template "content" .}}
+</section>
+</body>
+</html>
+{{end}}
diff --git a/tmpl/view b/tmpl/view
new file mode 100644
index 0000000..24d9b55
--- /dev/null
+++ b/tmpl/view
@@ -0,0 +1,4 @@
+{{define "title"}}{{.Title}}{{end}}
+{{define "content"}}
+{{.HTML}}
+{{end}}
diff --git a/view.go b/view.go
new file mode 100644
index 0000000..62f9a4b
--- /dev/null
+++ b/view.go
@@ -0,0 +1,22 @@
+package main
+
+import (
+ "net/http"
+ "text/template"
+)
+
+func init() {
+ http.HandleFunc("/view/", viewHandler)
+}
+
+func viewHandler(w http.ResponseWriter, r *http.Request) {
+ title := r.URL.Path[len("/view/"):]
+ p, err := loadPage(title)
+ if err != nil {
+ http.Redirect(w, r, "/edit/"+title, http.StatusFound)
+ return
+ }
+
+ p.HTML = parse(p.Body)
+ p.render(w, template.Must(template.ParseFiles("tmpl/root", "tmpl/view")))
+}
diff --git a/wiki.go b/wiki.go
new file mode 100644
index 0000000..5f096c1
--- /dev/null
+++ b/wiki.go
@@ -0,0 +1,39 @@
+package main
+
+import (
+ "io/ioutil"
+ "net/http"
+ "text/template"
+)
+
+type Page struct {
+ Title string
+ Body []byte
+ Pages []string
+ HTML string
+}
+
+func (p *Page) fileName() string {
+ return "data/" + p.Title
+}
+
+func (p *Page) save() error {
+ return ioutil.WriteFile(p.fileName(), p.Body, 0600)
+}
+
+func loadPage(title string) (p *Page, err error) {
+ p = &Page{Title: title}
+ p.Body, err = ioutil.ReadFile(p.fileName())
+ return
+}
+
+func (p *Page) render(w http.ResponseWriter, tmpl *template.Template) {
+ err := tmpl.ExecuteTemplate(w, "root", p)
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ }
+}
+
+func main() {
+ http.ListenAndServe(":8080", nil)
+}