updates on editor
Former-commit-id: 2928727a06a94c0ea87ed821a472ae662df803d1 [formerly 098bc4234803078aba013f6312d179158194fffb] [formerly d2bb681fe62ba87a29b9866e291fb975489cd3fc [formerly 3d25185a55]]
Former-commit-id: 288ccb95466fbd234d278886800e1d27c54fa8dd [formerly 78c473865b085e97cf435cb230e2afa85559aba0]
Former-commit-id: c5dc56f4d6198c9c306c01573e1a1af5f1827c3a
			
			
				pull/726/head
			
			
		
							parent
							
								
									90ba8e18da
								
							
						
					
					
						commit
						cc462c8bca
					
				| 
						 | 
				
			
			@ -9,7 +9,7 @@ install:
 | 
			
		|||
  - go get github.com/gordonklaus/ineffassign
 | 
			
		||||
 | 
			
		||||
script:
 | 
			
		||||
  - sed -i 's/\_ \"github.com\/mholt\/caddy\/caddyhttp\"/\_ \"github.com\/mholt\/caddy\/caddyhttp\"\n\_ \"github.com\/hacdias\/filemanager\/caddy\"/g' $GOPATH/src/github.com/mholt/caddy/caddy/caddymain/run.go
 | 
			
		||||
  - sed -i 's/\_ \"github.com\/mholt\/caddy\/caddyhttp\"/\_ \"github.com\/mholt\/caddy\/caddyhttp\"\n\_ \"github.com\/hacdias\/filemanager\/caddy\/filemanager\"/g' $GOPATH/src/github.com/mholt/caddy/caddy/caddymain/run.go
 | 
			
		||||
  - go build -o binary github.com/mholt/caddy/caddy
 | 
			
		||||
  - go build github.com/hacdias/filemanager
 | 
			
		||||
  - ineffassign .
 | 
			
		||||
| 
						 | 
				
			
			@ -30,27 +30,3 @@
 | 
			
		|||
 | 
			
		||||
{{ end }}
 | 
			
		||||
 | 
			
		||||
{{ define "value" }}
 | 
			
		||||
{{- if eq .HTMLType "textarea" }}
 | 
			
		||||
    <textarea class="scroll" name="{{ .Name }}" id="{{.Name }}" data-parent-type="{{ .Parent.Type }}">{{ .Content.Other }}</textarea>
 | 
			
		||||
{{- else if eq .HTMLType "datetime" }}
 | 
			
		||||
    <input name="{{ .Name }}" id="{{ .Name }}" value="{{ .Content.Other.Format "2006-01-02T15:04" }}" type="datetime-local" data-parent-type="{{ .Parent.Type }}"></input>
 | 
			
		||||
{{- else }}
 | 
			
		||||
    <input name="{{ .Name }}" id="{{ .Name }}" value="{{ .Content.Other }}" type="{{ .HTMLType }}" data-parent-type="{{ .Parent.Type }}"></input>
 | 
			
		||||
{{- end }}
 | 
			
		||||
{{ end }}
 | 
			
		||||
 | 
			
		||||
{{ define "fielset" }}
 | 
			
		||||
<fieldset id="{{ .Name }}" data-type="{{ .Type }}">
 | 
			
		||||
    {{- if not (eq .Title "") }}
 | 
			
		||||
        <h3>{{ .Name }}</h3>
 | 
			
		||||
    {{- end }}
 | 
			
		||||
    <div class="action add">
 | 
			
		||||
        <i class="material-icons" title="Add">add</i>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="action delete" data-delete="{{ .Name }}">
 | 
			
		||||
        <i class="material-icons" title="Close">close</i>
 | 
			
		||||
    </div>
 | 
			
		||||
    {{- template "blocks" .Content }}
 | 
			
		||||
</fieldset>
 | 
			
		||||
{{ end }}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,14 +0,0 @@
 | 
			
		|||
{{ define "sidebar-addon" }}
 | 
			
		||||
<a class="action" href="{{ .BaseURL }}/content/">
 | 
			
		||||
    <i class="material-icons">subject</i>
 | 
			
		||||
    <span>Posts and Pages</span>
 | 
			
		||||
</a>
 | 
			
		||||
<a class="action" href="{{ .BaseURL }}/themes/">
 | 
			
		||||
    <i class="material-icons">format_paint</i>
 | 
			
		||||
    <span>Themes</span>
 | 
			
		||||
</a>
 | 
			
		||||
<a class="action" href="{{ .BaseURL }}/settings/">
 | 
			
		||||
    <i class="material-icons">settings</i>
 | 
			
		||||
    <span>Settings</span>
 | 
			
		||||
</a>
 | 
			
		||||
{{ end }}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,23 +0,0 @@
 | 
			
		|||
{{ define "templates" }}
 | 
			
		||||
<template id="question-template">
 | 
			
		||||
    <form class="prompt">
 | 
			
		||||
        <h3></h3>
 | 
			
		||||
        <p></p>
 | 
			
		||||
        <input autofocus type="text">
 | 
			
		||||
        <div>
 | 
			
		||||
            <button type="submit" autofocus class="ok">OK</button>
 | 
			
		||||
            <button class="cancel" onclick="closePrompt(event);">Cancel</button>
 | 
			
		||||
        </div>
 | 
			
		||||
    </form>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<template id="message-template">
 | 
			
		||||
    <div class="prompt">
 | 
			
		||||
        <h3></h3>
 | 
			
		||||
        <p></p>
 | 
			
		||||
        <div>
 | 
			
		||||
            <button type="submit" onclick="closePrompt(event);" class="ok">OK</button>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
</template>
 | 
			
		||||
{{ end }}
 | 
			
		||||
| 
						 | 
				
			
			@ -41,6 +41,11 @@ module.exports = {
 | 
			
		|||
        loader: 'vue-loader',
 | 
			
		||||
        options: vueLoaderConfig
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        test: /\.css$/,
 | 
			
		||||
        include: /node_modules/,
 | 
			
		||||
        loader: 'style!css'
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        test: /\.js$/,
 | 
			
		||||
        loader: 'babel-loader',
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -26,6 +26,7 @@
 | 
			
		|||
        <i class="material-icons">folder</i>
 | 
			
		||||
        <span>My Files</span>
 | 
			
		||||
      </a>
 | 
			
		||||
 | 
			
		||||
      <div v-if="user.allowNew">
 | 
			
		||||
        <button @click="$store.commit('showNewDir', true)" aria-label="New directory" title="New directory" class="action">
 | 
			
		||||
          <i class="material-icons">create_new_folder</i>
 | 
			
		||||
| 
						 | 
				
			
			@ -36,6 +37,14 @@
 | 
			
		|||
          <span>New file</span>
 | 
			
		||||
        </button>
 | 
			
		||||
      </div>
 | 
			
		||||
 | 
			
		||||
      <div v-for="plugin in plugins">
 | 
			
		||||
        <button v-for="action in plugin.sidebar" @click="action.click" :aria-label="action.name" :title="action.name" class="action">
 | 
			
		||||
          <i class="material-icons">{{ action.icon }}</i>
 | 
			
		||||
          <span>{{ action.name }}</span>
 | 
			
		||||
        </button>
 | 
			
		||||
      </div>
 | 
			
		||||
 | 
			
		||||
      <button class="action" id="logout" tabindex="0" role="button" aria-label="Log out">
 | 
			
		||||
        <i class="material-icons" title="Logout">exit_to_app</i>
 | 
			
		||||
        <span>Logout</span>
 | 
			
		||||
| 
						 | 
				
			
			@ -134,10 +143,19 @@ export default {
 | 
			
		|||
      'showDownload'
 | 
			
		||||
    ])
 | 
			
		||||
  },
 | 
			
		||||
  data: function () {
 | 
			
		||||
    return {
 | 
			
		||||
      plugins: []
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  mounted: function () {
 | 
			
		||||
    updateColumnSizes()
 | 
			
		||||
    window.addEventListener('resize', updateColumnSizes)
 | 
			
		||||
 | 
			
		||||
    if (window.plugins !== undefined || window.plugins !== null) {
 | 
			
		||||
      this.plugins = window.plugins
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    document.title = this.req.data.name
 | 
			
		||||
    window.history.replaceState({
 | 
			
		||||
      url: window.location.pathname,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,16 +1,30 @@
 | 
			
		|||
<template>
 | 
			
		||||
    <form id="editor">
 | 
			
		||||
        <h2 v-if="editor.type == 'complete'">Metadata</h2>
 | 
			
		||||
        <h2 v-if="req.data.editor.type == 'complete'">Metadata</h2>
 | 
			
		||||
 | 
			
		||||
        <h2 v-if="editor.type == 'complete'">Body</h2>
 | 
			
		||||
        <h2 v-if="req.data.editor.type == 'complete'">Body</h2>
 | 
			
		||||
 | 
			
		||||
        <div v-if="req.data.editor.type !== 'frontmatter-only'" class="content">
 | 
			
		||||
            <div id="ace"></div>
 | 
			
		||||
            <textarea id="source" name="content">{{ req.data.content }}</textarea>
 | 
			
		||||
        </div>
 | 
			
		||||
    </form>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import { mapState } from 'vuex'
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  name: 'editor',
 | 
			
		||||
  computed: mapState(['req']),
 | 
			
		||||
  data: function () {
 | 
			
		||||
    return window.info.req.data
 | 
			
		||||
    return {
 | 
			
		||||
      codemirror: null,
 | 
			
		||||
      simplemde: null
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  mounted: function () {
 | 
			
		||||
 | 
			
		||||
  },
 | 
			
		||||
  methods: {
 | 
			
		||||
  }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,19 @@
 | 
			
		|||
<template>
 | 
			
		||||
  <fieldset :id="name" :data-type="type">
 | 
			
		||||
    <h3 v-if="title !== ''">{{ name }}</h3>
 | 
			
		||||
    <div class="action add">
 | 
			
		||||
      <i class="material-icons" title="Add">add</i>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="action delete" :data-delete="name">
 | 
			
		||||
      <i class="material-icons" title="Close">close</i>
 | 
			
		||||
    </div>
 | 
			
		||||
    <!-- template blocks w/ content -->
 | 
			
		||||
  </fieldset>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
export default {
 | 
			
		||||
  name: 'array-object',
 | 
			
		||||
  props: ['name', 'type', 'title', 'content']
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,28 @@
 | 
			
		|||
<template>
 | 
			
		||||
  <textarea v-if="htmlType === 'textarea'"
 | 
			
		||||
    class="scroll"
 | 
			
		||||
    :name="name"
 | 
			
		||||
    :id="name"
 | 
			
		||||
    :data-parent-type="parentType">
 | 
			
		||||
    {{ content.other }}
 | 
			
		||||
  </textarea>
 | 
			
		||||
  <input v-else-if="htmlType ==='datatime'"
 | 
			
		||||
    :name="name"
 | 
			
		||||
    :id="name"
 | 
			
		||||
    :value="content.other"
 | 
			
		||||
    type="datetime-local"
 | 
			
		||||
    :data-parent-type="parentType"></input>
 | 
			
		||||
  <input v-else
 | 
			
		||||
    :name="name"
 | 
			
		||||
    :id="name"
 | 
			
		||||
    :value="content.other"
 | 
			
		||||
    :type="htmlType"
 | 
			
		||||
    :data-parent-type="parentType"></input>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
export default {
 | 
			
		||||
  name: 'value',
 | 
			
		||||
  props: ['htmlType', 'name', 'parentType', 'content']
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
| 
						 | 
				
			
			@ -26,7 +26,12 @@ export default {
 | 
			
		|||
      event.preventDefault()
 | 
			
		||||
      if (this.new === '') return
 | 
			
		||||
 | 
			
		||||
      let url = window.location.pathname + this.name + '/'
 | 
			
		||||
      let url = window.location.pathname
 | 
			
		||||
      if (this.$store.state.req.kind !== 'listing') {
 | 
			
		||||
        url = page.removeLastDir(url) + '/'
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      url += this.name + '/'
 | 
			
		||||
      url = url.replace('//', '/')
 | 
			
		||||
 | 
			
		||||
      // buttons.setLoading('newDir')
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -26,11 +26,19 @@ export default {
 | 
			
		|||
      event.preventDefault()
 | 
			
		||||
      if (this.new === '') return
 | 
			
		||||
 | 
			
		||||
      let url = window.location.pathname
 | 
			
		||||
      if (this.$store.state.req.kind !== 'listing') {
 | 
			
		||||
        url = page.removeLastDir(url) + '/'
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      url += this.name
 | 
			
		||||
      url = url.replace('//', '/')
 | 
			
		||||
 | 
			
		||||
      // buttons.setLoading('newFile')
 | 
			
		||||
      webdav.create(window.location.pathname + this.name)
 | 
			
		||||
      webdav.create(url)
 | 
			
		||||
        .then(() => {
 | 
			
		||||
          // buttons.setDone('newFile')
 | 
			
		||||
          page.open(window.location.pathname + this.name)
 | 
			
		||||
          page.open(url)
 | 
			
		||||
        })
 | 
			
		||||
        .catch(e => {
 | 
			
		||||
          // buttons.setDone('newFile', false)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -51,6 +51,7 @@ export default {
 | 
			
		|||
    },
 | 
			
		||||
    back: function (event) {
 | 
			
		||||
      let url = page.removeLastDir(window.location.pathname)
 | 
			
		||||
      if (url === '') url = '/'
 | 
			
		||||
      page.open(url)
 | 
			
		||||
    },
 | 
			
		||||
    allowEdit: function (event) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -94,9 +94,9 @@ nav .action {
 | 
			
		|||
    padding: .5em;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
nav > .action:last-child,
 | 
			
		||||
nav > div {
 | 
			
		||||
    border-top: 1px solid rgba(0, 0, 0, 0.05);
 | 
			
		||||
    border-bottom: 1px solid rgba(0, 0, 0, 0.05);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
nav .action>* {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -15,7 +15,7 @@ import (
 | 
			
		|||
	"strconv"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	"github.com/hacdias/filemanager"
 | 
			
		||||
	. "github.com/hacdias/filemanager"
 | 
			
		||||
	"github.com/mholt/caddy"
 | 
			
		||||
	"github.com/mholt/caddy/caddyhttp/httpserver"
 | 
			
		||||
)
 | 
			
		||||
| 
						 | 
				
			
			@ -27,18 +27,22 @@ func init() {
 | 
			
		|||
	})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// FileManager is an http.Handler that can show a file listing when
 | 
			
		||||
// directories in the given paths are specified.
 | 
			
		||||
type FileManager struct {
 | 
			
		||||
type plugin struct {
 | 
			
		||||
	Next    httpserver.Handler
 | 
			
		||||
	Configs []*filemanager.FileManager
 | 
			
		||||
	Configs []*config
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type config struct {
 | 
			
		||||
	*FileManager
 | 
			
		||||
	baseURL   string
 | 
			
		||||
	webDavURL string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ServeHTTP determines if the request is for this plugin, and if all prerequisites are met.
 | 
			
		||||
func (f FileManager) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error) {
 | 
			
		||||
func (f plugin) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error) {
 | 
			
		||||
	for i := range f.Configs {
 | 
			
		||||
		// Checks if this Path should be handled by File Manager.
 | 
			
		||||
		if !httpserver.Path(r.URL.Path).Matches(f.Configs[i].BaseURL) {
 | 
			
		||||
		if !httpserver.Path(r.URL.Path).Matches(f.Configs[i].baseURL) {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -56,21 +60,21 @@ func setup(c *caddy.Controller) error {
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	httpserver.GetConfig(c).AddMiddleware(func(next httpserver.Handler) httpserver.Handler {
 | 
			
		||||
		return FileManager{Configs: configs, Next: next}
 | 
			
		||||
		return plugin{Configs: configs, Next: next}
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func parse(c *caddy.Controller) ([]*filemanager.FileManager, error) {
 | 
			
		||||
func parse(c *caddy.Controller) ([]*config, error) {
 | 
			
		||||
	var (
 | 
			
		||||
		configs []*filemanager.FileManager
 | 
			
		||||
		configs []*config
 | 
			
		||||
		err     error
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	for c.Next() {
 | 
			
		||||
		var (
 | 
			
		||||
			m    = filemanager.New(".")
 | 
			
		||||
			m    = &config{FileManager: New(".")}
 | 
			
		||||
			u    = m.User
 | 
			
		||||
			name = ""
 | 
			
		||||
		)
 | 
			
		||||
| 
						 | 
				
			
			@ -79,7 +83,7 @@ func parse(c *caddy.Controller) ([]*filemanager.FileManager, error) {
 | 
			
		|||
 | 
			
		||||
		m.SetPrefixURL(strings.TrimSuffix(caddyConf.Addr.Path, "/"))
 | 
			
		||||
		m.Commands = []string{"git", "svn", "hg"}
 | 
			
		||||
		m.Rules = append(m.Rules, &filemanager.Rule{
 | 
			
		||||
		m.Rules = append(m.Rules, &Rule{
 | 
			
		||||
			Regex:  true,
 | 
			
		||||
			Allow:  false,
 | 
			
		||||
			Regexp: regexp.MustCompile("\\/\\..+"),
 | 
			
		||||
| 
						 | 
				
			
			@ -89,18 +93,19 @@ func parse(c *caddy.Controller) ([]*filemanager.FileManager, error) {
 | 
			
		|||
		args := c.RemainingArgs()
 | 
			
		||||
 | 
			
		||||
		if len(args) > 0 {
 | 
			
		||||
			m.baseURL = args[0]
 | 
			
		||||
			m.webDavURL = "/webdav"
 | 
			
		||||
			m.SetBaseURL(args[0])
 | 
			
		||||
			m.SetWebDavURL("/webdav")
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		for c.NextBlock() {
 | 
			
		||||
			switch c.Val() {
 | 
			
		||||
			case "before_save":
 | 
			
		||||
				if m.BeforeSave, err = makeCommand(c); err != nil {
 | 
			
		||||
				if m.BeforeSave, err = makeCommand(c, m); err != nil {
 | 
			
		||||
					return configs, err
 | 
			
		||||
				}
 | 
			
		||||
			case "after_save":
 | 
			
		||||
				if m.AfterSave, err = makeCommand(c); err != nil {
 | 
			
		||||
				if m.AfterSave, err = makeCommand(c, m); err != nil {
 | 
			
		||||
					return configs, err
 | 
			
		||||
				}
 | 
			
		||||
			case "webdav":
 | 
			
		||||
| 
						 | 
				
			
			@ -108,6 +113,7 @@ func parse(c *caddy.Controller) ([]*filemanager.FileManager, error) {
 | 
			
		|||
					return configs, c.ArgErr()
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				m.webDavURL = "c.Val()"
 | 
			
		||||
				m.SetWebDavURL(c.Val())
 | 
			
		||||
			case "show":
 | 
			
		||||
				if !c.NextArg() {
 | 
			
		||||
| 
						 | 
				
			
			@ -185,7 +191,7 @@ func parse(c *caddy.Controller) ([]*filemanager.FileManager, error) {
 | 
			
		|||
					ruleType += "_r"
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				rule := &filemanager.Rule{
 | 
			
		||||
				rule := &Rule{
 | 
			
		||||
					Allow: ruleType == "allow" || ruleType == "allow_r",
 | 
			
		||||
					Regex: ruleType == "allow_r" || ruleType == "block_r",
 | 
			
		||||
				}
 | 
			
		||||
| 
						 | 
				
			
			@ -215,14 +221,16 @@ func parse(c *caddy.Controller) ([]*filemanager.FileManager, error) {
 | 
			
		|||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		m.baseURL = strings.TrimSuffix(m.baseURL, "/")
 | 
			
		||||
		m.webDavURL = strings.TrimSuffix(m.webDavURL, "/")
 | 
			
		||||
		configs = append(configs, m)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return configs, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func makeCommand(c *caddy.Controller) (filemanager.Command, error) {
 | 
			
		||||
	fn := func(r *http.Request, c *filemanager.FileManager, u *filemanager.User) error { return nil }
 | 
			
		||||
func makeCommand(c *caddy.Controller, m *config) (Command, error) {
 | 
			
		||||
	fn := func(r *http.Request, c *FileManager, u *User) error { return nil }
 | 
			
		||||
 | 
			
		||||
	args := c.RemainingArgs()
 | 
			
		||||
	if len(args) == 0 {
 | 
			
		||||
| 
						 | 
				
			
			@ -241,8 +249,8 @@ func makeCommand(c *caddy.Controller) (filemanager.Command, error) {
 | 
			
		|||
		return fn, c.Err(err.Error())
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fn = func(r *http.Request, c *filemanager.FileManager, u *filemanager.User) error {
 | 
			
		||||
		path := strings.Replace(r.URL.Path, c.WebDavURL, "", 1)
 | 
			
		||||
	fn = func(r *http.Request, c *FileManager, u *User) error {
 | 
			
		||||
		path := strings.Replace(r.URL.Path, m.baseURL+m.webDavURL, "", 1)
 | 
			
		||||
		path = u.Scope() + "/" + path
 | 
			
		||||
		path = filepath.Clean(path)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,52 @@
 | 
			
		|||
# hugo - a caddy plugin
 | 
			
		||||
 | 
			
		||||
[](https://caddy.community)
 | 
			
		||||
 | 
			
		||||
hugo fills the gap between Hugo and the browser. [Hugo](http://gohugo.io/) is an easy and fast static website generator. This plugin fills the gap between Hugo and the end-user, providing you a web interface to manage the whole website.
 | 
			
		||||
 | 
			
		||||
Using this plugin, you won't need to have your own computer to edit posts, neither regenerate your static website, because you can do all of that just through your browser.
 | 
			
		||||
 | 
			
		||||
**Requirements:** you need to have the hugo executable in your PATH. You can download it from its [official page](http://gohugo.io).
 | 
			
		||||
 | 
			
		||||
### Syntax
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
hugo [directory] [admin] {
 | 
			
		||||
    clean_public    [true|false]
 | 
			
		||||
    before_publish  command
 | 
			
		||||
    after_publish   command
 | 
			
		||||
    flag            name  [value]
 | 
			
		||||
    # other file manager compatible options
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
All of the options above are optional.
 | 
			
		||||
 | 
			
		||||
* **directory** is the folder where the commands are going to be executed. By default, it is the current working directory. Default: `./`.
 | 
			
		||||
* **admin** is the path where you will find your administration interface. Default: `/admin`.
 | 
			
		||||
* **clean_public** sets if the `public` folder should be removed before generating the website again. Default: `true`.
 | 
			
		||||
* **before_publish** and **after_publish** allow you to set a custom command to be executed before publishing and after publishing a post/page. The placeholder `{path}` can be used and it will be replaced by the file path.
 | 
			
		||||
* **name** refers to the Hugo available flags. Please use their long form without `--` in the beginning. If no **value** is set, it will be evaluated as `true`.
 | 
			
		||||
 | 
			
		||||
In spite of these options, you can also use the [filemanager](https://caddyserver.com/docs/http.filemanager) so you can have more control about what can be acceded, the permissions of each user, and so on.
 | 
			
		||||
 | 
			
		||||
This directive should be used with [root](https://caddyserver.com/docs/root), [basicauth](https://caddyserver.com/docs/basicauth) and [errors](https://caddyserver.com/docs/errors) middleware to have the best experience. See the examples to know more.
 | 
			
		||||
 | 
			
		||||
### Examples
 | 
			
		||||
 | 
			
		||||
If you don't already have an Hugo website, don't worry. This plugin will auto-generate it for you. But that's not everything. It is recommended that you take a look at Hugo [documentation](http://gohugo.io/themes/overview/) to learn more about themes, content types, and so on.
 | 
			
		||||
 | 
			
		||||
A simple Caddyfile to use with Hugo static website generator:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
root      public           # the folder where Hugo generates the website
 | 
			
		||||
basicauth /admin user pass # protect the admin area using HTTP basic auth
 | 
			
		||||
hugo                       # enable the admin panel
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Screenshots
 | 
			
		||||
 | 
			
		||||

 | 
			
		||||

 | 
			
		||||

 | 
			
		||||

 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1 @@
 | 
			
		|||
package hugo
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,42 @@
 | 
			
		|||
'use strict'
 | 
			
		||||
 | 
			
		||||
if (window.plugins === undefined || window.plugins === null) {
 | 
			
		||||
  window.plugins = []
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
window.plugins.append({
 | 
			
		||||
  sidebar: [
 | 
			
		||||
    {
 | 
			
		||||
      click: function (event) {
 | 
			
		||||
        console.log('evt')
 | 
			
		||||
      },
 | 
			
		||||
      icon: 'settings_applications',
 | 
			
		||||
      name: 'Settings'
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      click: function (event) {
 | 
			
		||||
        console.log('evt')
 | 
			
		||||
      },
 | 
			
		||||
      icon: 'remove_red_eye',
 | 
			
		||||
      name: 'Preview'
 | 
			
		||||
    }
 | 
			
		||||
  ]
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
{{ define "sidebar-addon" }}
 | 
			
		||||
<a class="action" href="{{ .BaseURL }}/content/">
 | 
			
		||||
    <i class="material-icons">subject</i>
 | 
			
		||||
    <span>Posts and Pages</span>
 | 
			
		||||
</a>
 | 
			
		||||
<a class="action" href="{{ .BaseURL }}/themes/">
 | 
			
		||||
    <i class="material-icons">format_paint</i>
 | 
			
		||||
    <span>Themes</span>
 | 
			
		||||
</a>
 | 
			
		||||
<a class="action" href="{{ .BaseURL }}/settings/">
 | 
			
		||||
    <i class="material-icons">settings</i>
 | 
			
		||||
    <span>Settings</span>
 | 
			
		||||
</a>
 | 
			
		||||
{{ end }}
 | 
			
		||||
*/
 | 
			
		||||
| 
						 | 
				
			
			@ -1,31 +0,0 @@
 | 
			
		|||
package main
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"log"
 | 
			
		||||
	"net/http"
 | 
			
		||||
 | 
			
		||||
	"github.com/hacdias/filemanager"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var m *filemanager.FileManager
 | 
			
		||||
 | 
			
		||||
func handler(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
	// TODO: review return codes and return 0 when everything works.
 | 
			
		||||
 | 
			
		||||
	code, err := m.ServeHTTP(w, r)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Print(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if code != 0 {
 | 
			
		||||
		w.WriteHeader(code)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func main() {
 | 
			
		||||
	m = filemanager.New("D:\\TEST")
 | 
			
		||||
	m.SetBaseURL("/vaca")
 | 
			
		||||
	m.Commands = []string{"git"}
 | 
			
		||||
	http.HandleFunc("/", handler)
 | 
			
		||||
	http.ListenAndServe(":80", nil)
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -123,19 +123,19 @@ func Marshal(data interface{}, mark rune) ([]byte, error) {
 | 
			
		|||
 | 
			
		||||
// Content is the block content
 | 
			
		||||
type Content struct {
 | 
			
		||||
	Other   interface{}
 | 
			
		||||
	Fields  []*Block
 | 
			
		||||
	Arrays  []*Block
 | 
			
		||||
	Objects []*Block
 | 
			
		||||
	Other   interface{} `json:"other"`
 | 
			
		||||
	Fields  []*Block    `json:"fields"`
 | 
			
		||||
	Arrays  []*Block    `json:"arrays"`
 | 
			
		||||
	Objects []*Block    `json:"objects"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Block is a block
 | 
			
		||||
type Block struct {
 | 
			
		||||
	Name     string
 | 
			
		||||
	Title    string
 | 
			
		||||
	Type     string
 | 
			
		||||
	HTMLType string
 | 
			
		||||
	Content  *Content
 | 
			
		||||
	Name     string   `json:"name"`
 | 
			
		||||
	Title    string   `json:"title"`
 | 
			
		||||
	Type     string   `json:"type"`
 | 
			
		||||
	HTMLType string   `json:"htmlType"`
 | 
			
		||||
	Content  *Content `json:"content"`
 | 
			
		||||
	Parent   *Block   `json:"-"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										2
									
								
								http.go
								
								
								
								
							
							
						
						
									
										2
									
								
								http.go
								
								
								
								
							| 
						 | 
				
			
			@ -27,7 +27,7 @@ func serveHTTP(c *requestContext, w http.ResponseWriter, r *http.Request) (int,
 | 
			
		|||
 | 
			
		||||
	// Checks if the URL contains the baseURL. If so, it strips it. Otherwise,
 | 
			
		||||
	// it throws an error.
 | 
			
		||||
	if p := strings.TrimPrefix(r.URL.Path, c.fm.baseURL); len(p) < len(r.URL.Path) {
 | 
			
		||||
	if p := strings.TrimPrefix(r.URL.Path, c.fm.baseURL); len(p) < len(r.URL.Path) || len(c.fm.baseURL) == 0 {
 | 
			
		||||
		r.URL.Path = p
 | 
			
		||||
	} else {
 | 
			
		||||
		return http.StatusNotFound, nil
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue