updates, sort interface

pull/20/head
Henrique Dias 2015-09-18 09:47:02 +01:00
parent d847909da8
commit abb9c4efe1
16 changed files with 434 additions and 52 deletions

View File

@ -38,6 +38,7 @@ module.exports = function(grunt) {
src: ['node_modules/normalize.css/normalize.css',
'node_modules/font-awesome/css/font-awesome.css',
'node_modules/animate.css/animate.min.css',
'node_modules/codemirror/lib/codemirror.css',
'assets/css/src/main.css'
],
dest: 'assets/css/src/main.css',
@ -73,6 +74,7 @@ module.exports = function(grunt) {
'node_modules/noty/js/noty/packaged/jquery.noty.packaged.min.js',
'node_modules/jquery-pjax/jquery.pjax.js',
'node_modules/jquery-serializejson/jquery.serializejson.min.js',
'node_modules/codemirror/lib/codemirror.js',
'assets/js/src/**/*.js'
]
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -41,6 +41,7 @@ func Execute(w http.ResponseWriter, r *http.Request) (int, error) {
Template: tpl,
},
},
IgnoreIndexes: true,
}
return b.ServeHTTP(w, r)

View File

@ -91,7 +91,8 @@ func Execute(w http.ResponseWriter, r *http.Request) (int, error) {
}
page := new(page.Page)
page.Name = "Edit"
page.Name = "Editor"
page.Class = "editor"
page.Body = inf
return page.Render(w, r, "edit", "frontmatter")
}

View File

@ -4,6 +4,7 @@ import (
"log"
"reflect"
"sort"
"strings"
"github.com/hacdias/caddy-hugo/utils"
"github.com/spf13/hugo/parser"
@ -64,9 +65,9 @@ func rawToPretty(config interface{}, parent *frontmatter) interface{} {
log.Panic("Parent type not allowed.")
}
sortByTitle(objects)
sortByTitle(arrays)
sortByTitle(fields)
sort.Sort(sortByTitle(objects))
sort.Sort(sortByTitle(arrays))
sort.Sort(sortByTitle(fields))
settings := []*frontmatter{}
settings = append(settings, fields...)
@ -75,26 +76,12 @@ func rawToPretty(config interface{}, parent *frontmatter) interface{} {
return settings
}
func sortByTitle(config []*frontmatter) {
keys := make([]string, len(config))
positionByTitle := make(map[string]int)
type sortByTitle []*frontmatter
for index, element := range config {
keys[index] = element.Title
positionByTitle[element.Title] = index
}
sort.Strings(keys)
// TODO: http://golang.org/pkg/sort/#Interface
cnf := make([]*frontmatter, len(config))
for index, title := range keys {
cnf[index] = config[positionByTitle[title]]
}
for index := range config {
config[index] = cnf[index]
}
func (f sortByTitle) Len() int { return len(f) }
func (f sortByTitle) Swap(i, j int) { f[i], f[j] = f[j], f[i] }
func (f sortByTitle) Less(i, j int) bool {
return strings.ToLower(f[i].Name) < strings.ToLower(f[j].Name)
}
func handleObjects(content interface{}, parent *frontmatter, name string) *frontmatter {
@ -133,6 +120,7 @@ func handleFlatValues(content interface{}, parent *frontmatter, name string) *fr
c := new(frontmatter)
c.Parent = parent
// TODO: see why isn't this working
switch reflect.ValueOf(content).Kind() {
case reflect.Bool:
c.Type = "boolean"

53
hugo.go
View File

@ -18,7 +18,6 @@ import (
"github.com/spf13/hugo/commands"
)
// Setup function
func Setup(c *setup.Controller) (middleware.Middleware, error) {
commands.Execute()
@ -30,11 +29,22 @@ func Setup(c *setup.Controller) (middleware.Middleware, error) {
type handler struct{ Next middleware.Handler }
func (h handler) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error) {
// Only handle /admin path
if middleware.Path(r.URL.Path).Matches("/admin") {
page := utils.ParseComponents(r)[1]
code := 404
var err error
var page string
code := 404
// If the length of the components string is less than one, the variable
// page will always be "admin"
if len(utils.ParseComponents(r)) > 1 {
page = utils.ParseComponents(r)[1]
} else {
page = utils.ParseComponents(r)[0]
}
// If the page isn't "assets" neither "edit", it should always put a
// trailing slash in the path
if page != "assets" && page != "edit" {
if r.URL.Path[len(r.URL.Path)-1] != '/' {
http.Redirect(w, r, r.URL.Path+"/", http.StatusTemporaryRedirect)
@ -42,6 +52,13 @@ func (h handler) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error)
}
}
// If the current page is only "/admin/", redirect to "/admin/browse/contents"
if r.URL.Path == "/admin/" {
http.Redirect(w, r, "/admin/browse/content/", http.StatusTemporaryRedirect)
return 0, nil
}
// Serve the static assets
if page == "assets" {
filename := strings.Replace(r.URL.Path, "/admin/", "", 1)
file, err := assets.Asset(filename)
@ -50,28 +67,36 @@ func (h handler) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error)
return 404, nil
}
// Get the file extension ant its mime type
extension := filepath.Ext(filename)
mime := mime.TypeByExtension(extension)
header := w.Header()
header.Set("Content-Type", mime)
// Write the header with the Content-Type and write the file
// content to the buffer
w.Header().Set("Content-Type", mime)
w.Write(file)
return 200, nil
}
if page == "browse" {
code, err = browse.Execute(w, r)
}
if page == "edit" {
code, err = edit.Execute(w, r)
}
// If the url matches exactly with /admin/settings/ serve that page
// page variable isn't used here to avoid people using URLs like
// "/admin/settings/something".
if r.URL.Path == "/admin/settings/" {
code, err = settings.Execute(w, r)
}
// Browse page
if page == "browse" {
code, err = browse.Execute(w, r)
}
// Edit page
if page == "edit" {
code, err = edit.Execute(w, r)
}
// Whenever the header "X-Refenerate" is true, the website should be
// regenerated. Used in edit and settings, for example.
if r.Header.Get("X-Regenerate") == "true" {
commands.Execute()
}

View File

@ -18,6 +18,7 @@
},
"dependencies": {
"animate.css": "^3.4.0",
"codemirror": "^5.6.0",
"font-awesome": "^4.4.0",
"jquery": "^2.1.4",
"jquery-serializejson": "^2.5.0",

View File

@ -20,8 +20,9 @@ var funcMap = template.FuncMap{
// Page type
type Page struct {
Name string
Body interface{}
Name string
Class string
Body interface{}
}
// Render the page
@ -37,7 +38,11 @@ func (p *Page) Render(w http.ResponseWriter, r *http.Request, templates ...strin
return 200, nil
}
// GetTemplate is used to get a ready to use template based on the url and on
// other sent templates
func GetTemplate(r *http.Request, templates ...string) (*template.Template, error) {
// If this is a pjax request, use the minimal template to send only
// the main content
if r.Header.Get("X-PJAX") == "true" {
templates = append(templates, "base_minimal")
} else {
@ -46,14 +51,19 @@ func GetTemplate(r *http.Request, templates ...string) (*template.Template, erro
var tpl *template.Template
// For each template, add it to the the tpl variable
for i, t := range templates {
// Get the template from the assets
page, err := assets.Asset("templates/" + t + templateExtension)
// Check if there is some error. If so, the template doesn't exist
if err != nil {
log.Print(err)
return new(template.Template), err
}
// If it's the first iteration, creates a new template and add the
// functions map
if i == 0 {
tpl, err = template.New(t).Funcs(funcMap).Parse(string(page))
} else {

View File

@ -62,6 +62,7 @@ func Execute(w http.ResponseWriter, r *http.Request) (int, error) {
page := new(page.Page)
page.Name = "Settings"
page.Class = "settings"
page.Body = f
return page.Render(w, r, "settings", "frontmatter")
}

View File

@ -1,6 +1,5 @@
<!DOCTYPE html>
<html class="no-js" lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
@ -17,16 +16,14 @@
<nav>
<ul>
<li><a href="/"><i class="fa fa-home fa-lg"></i> Home</a></li>
<li><a href="/admin/browse/content"><i class="fa fa-newspaper-o"></i> Content</a></li>
<li><a href="/admin/browse"><i class="fa fa-folder-o"></i> Browse</a></li>
<li><a href="/admin/settings"><i class="fa fa-cog"></i> Settings</a></li>
<li><a href="/admin/browse/content/"><i class="fa fa-newspaper-o"></i> Content</a></li>
<li><a href="/admin/browse/"><i class="fa fa-folder-o"></i> Browse</a></li>
<li><a href="/admin/settings/"><i class="fa fa-cog"></i> Settings</a></li>
<li><a id="logout" href="#logout"><i class="fa fa-sign-out"></i> Logout</a></li>
</ul>
</nav>
<div class="main" id="container">
{{ template "content" . }}
</div>
</body>
</html>

View File

@ -8,7 +8,7 @@
</div>
<div class="container data">
<textarea name="content" class="scroll">{{ .Content }}</textarea>
<textarea id="content-area" name="content" class="scroll">{{ .Content }}</textarea>
<div id="preview-area" class="scroll hidden"></div>
</div>

View File

@ -9,7 +9,7 @@
{{ if not (eq $value.Parent.Type "array") }}
<label for="{{ $value.Name }}">{{ splitCapitalize $value.Title }}</label>
{{ end }}
<input name="{{ $value.Name }}" id="{{ $value.Name }}" value="{{ $value.Content }}"></input><br>
<input name="{{ $value.Name }}:auto" id="{{ $value.Name }}" value="{{ $value.Content }}"></input><br>
{{ end }}
{{ end }}
{{ end }}

View File

@ -1,8 +1,13 @@
{{ define "content" }}
<header>
<div class="content">
<h1>Settings</h1>
</div>
</header>
<main>
{{ with .Body }}
<div class="content">
<h1>Settings</h1>
<form method="POST" action="/admin/settings">
{{ template "frontmatter" . }}
<input type="submit" data-message="Settings updated." data-regenerate="true" value="Save">

View File

@ -24,38 +24,48 @@ func Dict(values ...interface{}) (map[string]interface{}, error) {
return dict, nil
}
// IsMap checks if some variable is a map
func IsMap(sth interface{}) bool {
return reflect.ValueOf(sth).Kind() == reflect.Map
}
// IsSlice checks if some variable is a slice
func IsSlice(sth interface{}) bool {
return reflect.ValueOf(sth).Kind() == reflect.Slice
}
// IsArray checks if some variable is an array
func IsArray(sth interface{}) bool {
return reflect.ValueOf(sth).Kind() == reflect.Array
}
// IsString checks if some variable is a string
func IsString(sth interface{}) bool {
return reflect.ValueOf(sth).Kind() == reflect.String
}
// IsInt checks if some variable is an integer
func IsInt(sth interface{}) bool {
return reflect.ValueOf(sth).Kind() == reflect.Int
}
// IsBool checks if some variable is a boolean
func IsBool(sth interface{}) bool {
return reflect.ValueOf(sth).Kind() == reflect.Bool
}
// IsInterface checks if some variable is an interface
func IsInterface(sth interface{}) bool {
return reflect.ValueOf(sth).Kind() == reflect.Interface
}
// IsMarkdownFile checks if a filename belongs to a markdown file
func IsMarkdownFile(filename string) bool {
return strings.HasSuffix(filename, ".markdown") || strings.HasSuffix(filename, ".md")
}
// SplitCapitalize splits a string by its uppercase letters and capitalize the
// first letter of the string
func SplitCapitalize(name string) string {
var words []string
l := 0
@ -79,6 +89,7 @@ func SplitCapitalize(name string) string {
return name
}
// ParseComponents parses the components of an URL creating an array
func ParseComponents(r *http.Request) []string {
//The URL that the user queried.
path := r.URL.Path