2015-05-04 12:49:49 -05:00
|
|
|
package setup
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"html/template"
|
|
|
|
"io/ioutil"
|
|
|
|
|
|
|
|
"github.com/mholt/caddy/middleware"
|
|
|
|
"github.com/mholt/caddy/middleware/browse"
|
|
|
|
)
|
|
|
|
|
|
|
|
// Browse configures a new Browse middleware instance.
|
|
|
|
func Browse(c *Controller) (middleware.Middleware, error) {
|
|
|
|
configs, err := browseParse(c)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
browse := browse.Browse{
|
|
|
|
Root: c.Root,
|
|
|
|
Configs: configs,
|
|
|
|
}
|
|
|
|
|
|
|
|
return func(next middleware.Handler) middleware.Handler {
|
|
|
|
browse.Next = next
|
|
|
|
return browse
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func browseParse(c *Controller) ([]browse.Config, error) {
|
|
|
|
var configs []browse.Config
|
|
|
|
|
|
|
|
appendCfg := func(bc browse.Config) error {
|
|
|
|
for _, c := range configs {
|
|
|
|
if c.PathScope == bc.PathScope {
|
|
|
|
return fmt.Errorf("Duplicate browsing config for %s", c.PathScope)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
configs = append(configs, bc)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
for c.Next() {
|
|
|
|
var bc browse.Config
|
|
|
|
|
|
|
|
// First argument is directory to allow browsing; default is site root
|
|
|
|
if c.NextArg() {
|
|
|
|
bc.PathScope = c.Val()
|
|
|
|
} else {
|
|
|
|
bc.PathScope = "/"
|
|
|
|
}
|
|
|
|
|
|
|
|
// Second argument would be the template file to use
|
|
|
|
var tplText string
|
|
|
|
if c.NextArg() {
|
|
|
|
tplBytes, err := ioutil.ReadFile(c.Val())
|
|
|
|
if err != nil {
|
|
|
|
return configs, err
|
|
|
|
}
|
|
|
|
tplText = string(tplBytes)
|
|
|
|
} else {
|
|
|
|
tplText = defaultTemplate
|
|
|
|
}
|
|
|
|
|
|
|
|
// Build the template
|
|
|
|
tpl, err := template.New("listing").Parse(tplText)
|
|
|
|
if err != nil {
|
|
|
|
return configs, err
|
|
|
|
}
|
|
|
|
bc.Template = tpl
|
|
|
|
|
|
|
|
// Save configuration
|
|
|
|
err = appendCfg(bc)
|
|
|
|
if err != nil {
|
|
|
|
return configs, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return configs, nil
|
|
|
|
}
|
2015-03-25 00:05:42 -05:00
|
|
|
|
|
|
|
// The default template to use when serving up directory listings
|
|
|
|
const defaultTemplate = `<!DOCTYPE html>
|
|
|
|
<html>
|
|
|
|
<head>
|
|
|
|
<title>{{.Name}}</title>
|
|
|
|
<meta charset="utf-8">
|
|
|
|
<style>
|
|
|
|
* { padding: 0; margin: 0; }
|
|
|
|
|
|
|
|
body {
|
|
|
|
padding: 1% 2%;
|
2015-04-21 22:36:43 -05:00
|
|
|
font: 16px Arial;
|
2015-03-25 00:05:42 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
header {
|
|
|
|
font-size: 45px;
|
|
|
|
padding: 25px;
|
|
|
|
}
|
|
|
|
|
|
|
|
header a {
|
|
|
|
text-decoration: none;
|
|
|
|
color: inherit;
|
|
|
|
}
|
|
|
|
|
|
|
|
header .up {
|
|
|
|
display: inline-block;
|
|
|
|
height: 50px;
|
|
|
|
width: 50px;
|
|
|
|
text-align: center;
|
|
|
|
margin-right: 20px;
|
|
|
|
}
|
|
|
|
|
|
|
|
header a.up:hover {
|
|
|
|
background: #000;
|
|
|
|
color: #FFF;
|
|
|
|
}
|
|
|
|
|
|
|
|
h1 {
|
|
|
|
font-size: 30px;
|
|
|
|
display: inline;
|
|
|
|
}
|
|
|
|
|
|
|
|
table {
|
|
|
|
border: 0;
|
|
|
|
border-collapse: collapse;
|
|
|
|
max-width: 750px;
|
|
|
|
margin: 0 auto;
|
|
|
|
}
|
|
|
|
|
|
|
|
th,
|
|
|
|
td {
|
|
|
|
padding: 4px 20px;
|
|
|
|
vertical-align: middle;
|
|
|
|
line-height: 1.5em; /* emoji are kind of odd heights */
|
|
|
|
}
|
|
|
|
|
|
|
|
th {
|
|
|
|
text-align: left;
|
|
|
|
}
|
|
|
|
|
2015-04-21 22:36:43 -05:00
|
|
|
@media (max-width: 700px) {
|
2015-03-25 00:05:42 -05:00
|
|
|
.hideable {
|
|
|
|
display: none;
|
|
|
|
}
|
|
|
|
|
|
|
|
body {
|
|
|
|
padding: 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
header,
|
|
|
|
header h1 {
|
2015-04-21 22:36:43 -05:00
|
|
|
font-size: 16px;
|
2015-03-25 00:05:42 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
header {
|
|
|
|
position: fixed;
|
|
|
|
top: 0;
|
|
|
|
width: 100%;
|
|
|
|
background: #333;
|
|
|
|
color: #FFF;
|
2015-04-21 22:36:43 -05:00
|
|
|
padding: 15px;
|
2015-03-25 00:05:42 -05:00
|
|
|
text-align: center;
|
|
|
|
}
|
|
|
|
|
|
|
|
header .up {
|
|
|
|
height: auto;
|
|
|
|
width: auto;
|
|
|
|
display: none;
|
|
|
|
}
|
|
|
|
|
|
|
|
header a.up {
|
|
|
|
display: inline-block;
|
|
|
|
position: absolute;
|
|
|
|
left: 0;
|
|
|
|
top: 0;
|
2015-04-21 22:36:43 -05:00
|
|
|
width: 40px;
|
|
|
|
height: 48px;
|
2015-03-25 00:05:42 -05:00
|
|
|
font-size: 35px;
|
|
|
|
}
|
|
|
|
|
|
|
|
header h1 {
|
|
|
|
font-weight: normal;
|
|
|
|
}
|
|
|
|
|
|
|
|
main {
|
2015-04-21 22:36:43 -05:00
|
|
|
margin-top: 70px;
|
2015-03-25 00:05:42 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
</style>
|
|
|
|
</head>
|
|
|
|
<body>
|
|
|
|
<header>
|
|
|
|
{{if .CanGoUp}}
|
|
|
|
<a href=".." class="up" title="Up one level">⬑</a>
|
|
|
|
{{else}}
|
|
|
|
<div class="up"> </div>
|
|
|
|
{{end}}
|
|
|
|
|
|
|
|
<h1>{{.Path}}</h1>
|
|
|
|
</header>
|
|
|
|
<main>
|
|
|
|
<table>
|
|
|
|
<tr>
|
|
|
|
<th>Name</th>
|
|
|
|
<th>Size</th>
|
|
|
|
<th class="hideable">Modified</th>
|
|
|
|
</tr>
|
|
|
|
{{range .Items}}
|
|
|
|
<tr>
|
|
|
|
<td>
|
|
|
|
{{if .IsDir}}📂{{else}}📄{{end}}
|
|
|
|
<a href="{{.URL}}">{{.Name}}</a>
|
|
|
|
</td>
|
|
|
|
<td>{{.HumanSize}}</td>
|
|
|
|
<td class="hideable">{{.HumanModTime "01/02/2006 3:04:05 PM -0700"}}</td>
|
|
|
|
</tr>
|
|
|
|
{{end}}
|
|
|
|
</table>
|
|
|
|
</main>
|
|
|
|
</body>
|
|
|
|
</html>`
|