This commit is contained in:
Henrique Dias 2015-09-20 09:15:21 +01:00
parent 3c0383d500
commit 0ac1f84f60
9 changed files with 98 additions and 43 deletions

View File

@ -2,6 +2,16 @@
This is an add-on for Caddy which wants to deliver a good UI to edit the content of the website.
## Add-on configuration
You can define, or not, the admin UI styles. It will **not** replace the default ones, it will be included after it. The path must be relative to ```public``` folder.
```
hugo {
styles [file]
}
```
## Try it
### Prepare your machine

View File

@ -6,27 +6,25 @@ import (
"strings"
"text/template"
"github.com/hacdias/caddy-hugo/editor"
"github.com/hacdias/caddy-hugo/config"
"github.com/hacdias/caddy-hugo/utils"
"github.com/mholt/caddy/middleware"
"github.com/mholt/caddy/middleware/browse"
)
// ServeHTTP is...
func ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error) {
if r.URL.Path[len(r.URL.Path)-1] != '/' {
http.Redirect(w, r, r.URL.Path+"/", http.StatusTemporaryRedirect)
return 0, nil
}
// ServeHTTP is used to serve the content of Browse page
// using Browse middleware from Caddy
func ServeHTTP(w http.ResponseWriter, r *http.Request, c *config.Config) (int, error) {
// Removes the page main path from the URL
r.URL.Path = strings.Replace(r.URL.Path, "/admin/browse", "", 1)
// If the URL is blank now, replace it with a trailing slash
if r.URL.Path == "" {
r.URL.Path = "/"
}
functions := template.FuncMap{
"canBeEdited": editor.CanBeEdited,
"CanBeEdited": utils.CanBeEdited,
"Defined": utils.Defined,
}
@ -45,6 +43,7 @@ func ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error) {
Configs: []browse.Config{
browse.Config{
PathScope: "/",
Variables: c,
Template: tpl,
},
},

35
config/config.go Normal file
View File

@ -0,0 +1,35 @@
package config
import (
"strings"
"github.com/mholt/caddy/config/setup"
)
// Config is the add-on configuration set on Caddyfile
type Config struct {
Styles string
}
// ParseHugo parses the configuration file
func ParseHugo(c *setup.Controller) (*Config, error) {
conf := &Config{}
for c.Next() {
for c.NextBlock() {
switch c.Val() {
case "styles":
if !c.NextArg() {
return nil, c.ArgErr()
}
conf.Styles = c.Val()
// Remove the beginning slash if it exists or not
conf.Styles = strings.TrimPrefix(conf.Styles, "/")
// Add a beginning slash to make a
conf.Styles = "/" + conf.Styles
}
}
}
return conf, nil
}

View File

@ -12,6 +12,7 @@ import (
"strings"
"text/template"
"github.com/hacdias/caddy-hugo/config"
"github.com/hacdias/caddy-hugo/frontmatter"
"github.com/hacdias/caddy-hugo/utils"
"github.com/spf13/hugo/parser"
@ -23,38 +24,21 @@ type editor struct {
Mode string
Content string
FrontMatter interface{}
Config *config.Config
}
// ServeHTTP is...
func ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error) {
// ServeHTTP serves the editor page
func ServeHTTP(w http.ResponseWriter, r *http.Request, c *config.Config) (int, error) {
filename := strings.Replace(r.URL.Path, "/admin/edit/", "", 1)
if r.Method == "POST" {
return post(w, r, filename)
return servePost(w, r, filename)
}
return get(w, r, filename)
return serveGet(w, r, c, filename)
}
// CanBeEdited checks if a file has a supported extension
func CanBeEdited(filename string) bool {
extensions := [...]string{".markdown", ".md",
".json", ".toml", ".yaml",
".css", ".sass", ".scss",
".js",
".html",
}
for _, extension := range extensions {
if strings.HasSuffix(filename, extension) {
return true
}
}
return false
}
func post(w http.ResponseWriter, r *http.Request, filename string) (int, error) {
func servePost(w http.ResponseWriter, r *http.Request, filename string) (int, error) {
// Get the JSON information sent using a buffer
rawBuffer := new(bytes.Buffer)
rawBuffer.ReadFrom(r.Body)
@ -152,10 +136,10 @@ func post(w http.ResponseWriter, r *http.Request, filename string) (int, error)
return 200, nil
}
func get(w http.ResponseWriter, r *http.Request, filename string) (int, error) {
func serveGet(w http.ResponseWriter, r *http.Request, c *config.Config, filename string) (int, error) {
// Check if the file format is supported. If not, send a "Not Acceptable"
// header and an error
if !CanBeEdited(filename) {
if !utils.CanBeEdited(filename) {
return 406, errors.New("File format not supported.")
}
@ -176,6 +160,7 @@ func get(w http.ResponseWriter, r *http.Request, filename string) (int, error) {
page := new(editor)
page.Mode = strings.TrimPrefix(filepath.Ext(filename), ".")
page.Name = filename
page.Config = c
// Sanitize the extension
page.Mode = sanitizeMode(page.Mode)
@ -227,7 +212,7 @@ func get(w http.ResponseWriter, r *http.Request, filename string) (int, error) {
// Create the functions map, then the template, check for erros and
// execute the template if there aren't errors
functions := template.FuncMap{
"splitCapitalize": utils.SplitCapitalize,
"SplitCapitalize": utils.SplitCapitalize,
"Defined": utils.Defined,
}

16
hugo.go
View File

@ -11,6 +11,7 @@ import (
"github.com/hacdias/caddy-hugo/assets"
"github.com/hacdias/caddy-hugo/browse"
"github.com/hacdias/caddy-hugo/config"
"github.com/hacdias/caddy-hugo/editor"
"github.com/hacdias/caddy-hugo/utils"
"github.com/mholt/caddy/config/setup"
@ -20,16 +21,21 @@ import (
// Setup configures the middleware
func Setup(c *setup.Controller) (middleware.Middleware, error) {
config, _ := config.ParseHugo(c)
commands.Execute()
return func(next middleware.Handler) middleware.Handler {
return &handler{Next: next}
return &CaddyHugo{Next: next, Config: config}
}, nil
}
type handler struct{ Next middleware.Handler }
// CaddyHugo main type
type CaddyHugo struct {
Next middleware.Handler
Config *config.Config
}
func (h handler) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error) {
func (h CaddyHugo) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error) {
// Only handle /admin path
if middleware.Path(r.URL.Path).Matches("/admin") {
var err error
@ -103,12 +109,12 @@ func (h handler) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error)
// Browse page
if page == "browse" {
code, err = browse.ServeHTTP(w, r)
code, err = browse.ServeHTTP(w, r, h.Config)
}
// Edit page
if page == "edit" {
code, err = editor.ServeHTTP(w, r)
code, err = editor.ServeHTTP(w, r, h.Config)
}
// Whenever the header "X-Refenerate" is true, the website should be

View File

@ -10,6 +10,8 @@
<link href='https://fonts.googleapis.com/css?family=Roboto:400,700,400italic,700italic' rel='stylesheet' type='text/css'>
<link rel="stylesheet" href="/admin/assets/css/main.min.css">
{{ if and (Defined . "Config")}}{{ if not (eq .Config.Styles "") }}<link rel="stylesheet" href="{{ .Config.Styles }}">{{ end }}{{ end }}
{{ if and (Defined . "User") }}{{ if not (eq .User.Styles "") }}<link rel="stylesheet" href="{{ .User.Styles }}">{{ end }}{{ end }}
<script src="/admin/assets/js/plugins.min.js"></script>
<script src="/admin/assets/js/app.min.js"></script>
</head>

View File

@ -46,7 +46,7 @@
<tr>
<td>
{{if .IsDir}}
<i class="fa fa-folder"></i> <a href="{{.URL}}">{{.Name}}</a> {{else}} {{ if canBeEdited .URL }}
<i class="fa fa-folder"></i> <a href="{{.URL}}">{{.Name}}</a> {{else}} {{ if CanBeEdited .URL }}
<i class="fa fa-file"></i> <a class="file" href="/admin/edit{{ $path }}{{.URL}}">{{.Name}}</a> {{ else }}
<i class="fa fa-file"></i> {{.Name}} {{ end }} {{ end }}
</td>

View File

@ -1,6 +1,6 @@
{{ define "frontmatter" }} {{ range $key, $value := . }} {{ if or (eq $value.Type "object") (eq $value.Type "array") }}
<fieldset id="{{ $value.Name }}" data-name="{{ $value.Name }}" data-type="{{ $value.Type }}">
<h3>{{ splitCapitalize $value.Title }}
<h3>{{ SplitCapitalize $value.Title }}
<span class="actions">
<button class="delete"><i class="fa fa-minus"></i></button>
<button class="add"><i class="fa fa-plus"></i></button>
@ -9,7 +9,7 @@
{{ template "frontmatter" $value.Content }}
</fieldset>
{{ else }} {{ if not (eq $value.Parent.Type "array") }}
<label for="{{ $value.Name }}">{{ splitCapitalize $value.Title }}
<label for="{{ $value.Name }}">{{ SplitCapitalize $value.Title }}
<span class="actions">
<button class="delete"><i class="fa fa-minus"></i></button>
</span>

View File

@ -12,6 +12,24 @@ import (
"github.com/hacdias/caddy-hugo/assets"
)
// CanBeEdited checks if a filename has a supported extension
func CanBeEdited(filename string) bool {
extensions := [...]string{".markdown", ".md",
".json", ".toml", ".yaml",
".css", ".sass", ".scss",
".js",
".html",
}
for _, extension := range extensions {
if strings.HasSuffix(filename, extension) {
return true
}
}
return false
}
// GetTemplate is used to get a ready to use template based on the url and on
// other sent templates
func GetTemplate(r *http.Request, functions template.FuncMap, templates ...string) (*template.Template, error) {