diff --git a/assets/public/css/styles.css b/assets/public/css/styles.css
index 7fcd44e8..8a609465 100644
--- a/assets/public/css/styles.css
+++ b/assets/public/css/styles.css
@@ -113,8 +113,8 @@ button, html [type="button"], [type="reset"], [type="submit"] {
border: none;
border-radius: 2px;
display: inline-block;
- height: 36px;
- line-height: 36px;
+ height: 2.25em;
+ line-height: 2.25em;
outline: 0;
padding: 0 2rem;
text-transform: uppercase;
@@ -504,6 +504,23 @@ header form input {
-webkit-box-flex: 1;
-ms-flex-positive: 1;
flex-grow: 1;
+ position: relative;
+}
+#listing .item .checkbox {
+
+position: absolute;
+
+top: 0;
+
+right: 0;
+
+border-radius: 50%;
+
+background: #000;
+
+border: 0;
+
+-webkit-appearance: initial;
}
.item:hover {
box-shadow: 0 1px 3px rgba(0, 0, 0, .12), 0 1px 2px rgba(0, 0, 0, .24) !important;
@@ -640,3 +657,15 @@ i.spin {
#editor fieldset fieldset {
margin-left: 1em;
}
+#editor #submit span {
+ vertical-align: middle;
+ transition: 0.2s ease-in-out all;
+}
+#editor #submit span i {
+
+vertical-align: sub;
+
+font-size: 1.3rem;
+
+margin-right: .2em;
+}
diff --git a/assets/public/js/application.js b/assets/public/js/application.js
index 555dba61..9e0a2d78 100644
--- a/assets/public/js/application.js
+++ b/assets/public/js/application.js
@@ -455,6 +455,7 @@ var textareaAutoGrow = function() {
var handleEditorPage = function () {
let container = document.getElementById('editor');
+ let button = document.querySelector('#submit span:first-child');
let kind = container.dataset.kind;
if (kind != 'frontmatter-only') {
@@ -482,9 +483,28 @@ var handleEditorPage = function () {
button.addEventListener('click', deleteFrontMatterItem);
});
+ let addFrontMatterItemButtons = document.getElementsByClassName('add');
+ Array.from(addFrontMatterItemButtons).forEach(button => {
+ button.addEventListener('click', addFrontMatterItem);
+ });
+ document.querySelector('form').addEventListener('submit', (event) => {
+ event.preventDefault();
- return false;
+ let data = form2js(document.querySelector('form'));
+ let html = button.changeToLoading();
+ let request = new XMLHttpRequest();
+ request.open("PUT", window.location);
+ request.setRequestHeader('Kind', kind);
+ request.send(JSON.stringify(data));
+ request.onreadystatechange = function() {
+ if (request.readyState == 4) {
+ button.changeToDone((request.status != 200), html);
+ }
+ }
+ });
+
+ return false;
}
var deleteFrontMatterItem = function(event) {
@@ -492,30 +512,42 @@ var deleteFrontMatterItem = function(event) {
document.getElementById(this.dataset.delete).remove();
}
+const tempID = "_fm_internal_temporary_id"
+
var addFrontMatterItem = function(event) {
- /*
event.preventDefault();
- defaultID = "lorem-ipsum-sin-dolor-amet";
- // Remove if there is an incomplete new item
- newItem = $("#" + defaultID);
- if (newItem.length) {
- newItem.remove();
+ let newItem = document.getElementById(tempID)
+ if (newItem) {
+ newItem.remove();
}
- block = $(this).parent().parent();
- blockType = block.data("type");
- blockID = block.attr("id");
+ let block = this.parentNode;
+ let type = block.dataset.type;
+ let id = block.id;
- // If the Block Type is an array
- if (blockType == "array") {
- newID = blockID + "[]";
- input = blockID;
- input = input.replace(/\[/, '\\[');
- input = input.replace(/\]/, '\\]');
- block.append('
');
+ // If the block is an array
+ if (type === "array") {
+ let fieldID = id + "[]"
+ let input = fieldID
+ let count = block.querySelectorAll('.group > div').length
+ input = input.replace(/\[/, '\\[');
+ input = input.replace(/\]/, '\\]');
+
+ block.querySelector('.group').insertAdjacentHTML('beforeend', ``);
}
+
+
+
+ /*
+
+
// Main add button, after all blocks
if (block.is('div') && block.hasClass("frontmatter")) {
block = $('.blocks');
@@ -608,4 +640,6 @@ var addFrontMatterItem = function(event) {
return false;
*/
+
+ return false;
}
diff --git a/assets/public/js/form-to-json.js b/assets/public/js/form-to-json.js
index 778cf848..4968ad94 100644
--- a/assets/public/js/form-to-json.js
+++ b/assets/public/js/form-to-json.js
@@ -1,141 +1,349 @@
/**
-Author: Jhan Mateo
-Date Started: 7/29/2015
-Date Ended: 7/30/2015
-Description: Using native javascript (no js framework), this application will serializes from form data to Json format.
-The MIT License (MIT)
+ * Copyright (c) 2010 Maxim Vasiliev
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @author Maxim Vasiliev
+ * Date: 09.09.2010
+ * Time: 19:02:33
+ */
-Copyright (c) 2015 Jhan Mateo
-Permission is hereby granted, free of charge, to any person obtaining
-a copy of this software and associated documentation files (the "Software"),
-to deal in the Software without restriction, including without limitation
-the rights to use, copy, modify, merge, publish, distribute, sublicense,
-and/or sell copies of the Software, and to permit persons to whom the Software
-is furnished to do so, subject to the following conditions:
+(function (root, factory)
+{
+ if (typeof exports !== 'undefined' && typeof module !== 'undefined' && module.exports) {
+ // NodeJS
+ module.exports = factory();
+ }
+ else if (typeof define === 'function' && define.amd)
+ {
+ // AMD. Register as an anonymous module.
+ define(factory);
+ }
+ else
+ {
+ // Browser globals
+ root.form2js = factory();
+ }
+}(this, function ()
+{
+ "use strict";
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-**/
+ /**
+ * Returns form values represented as Javascript object
+ * "name" attribute defines structure of resulting object
+ *
+ * @param rootNode {Element|String} root form element (or it's id) or array of root elements
+ * @param delimiter {String} structure parts delimiter defaults to '.'
+ * @param skipEmpty {Boolean} should skip empty text values, defaults to true
+ * @param nodeCallback {Function} custom function to get node value
+ * @param useIdIfEmptyName {Boolean} if true value of id attribute of field will be used if name of field is empty
+ */
+ function form2js(rootNode, delimiter, skipEmpty, nodeCallback, useIdIfEmptyName, getDisabled)
+ {
+ getDisabled = getDisabled ? true : false;
+ if (typeof skipEmpty == 'undefined' || skipEmpty == null) skipEmpty = true;
+ if (typeof delimiter == 'undefined' || delimiter == null) delimiter = '.';
+ if (arguments.length < 5) useIdIfEmptyName = false;
-'use strict';
+ rootNode = typeof rootNode == 'string' ? document.getElementById(rootNode) : rootNode;
-function formToJson(form){
+ var formValues = [],
+ currNode,
+ i = 0;
- if('form'!==form.nodeName.toLowerCase() && 1!==form.nodeType){
- console.log('Form error');
- return false;
+ /* If rootNode is array - combine values */
+ if (rootNode.constructor == Array || (typeof NodeList != "undefined" && rootNode.constructor == NodeList))
+ {
+ while(currNode = rootNode[i++])
+ {
+ formValues = formValues.concat(getFormValues(currNode, nodeCallback, useIdIfEmptyName, getDisabled));
+ }
+ }
+ else
+ {
+ formValues = getFormValues(rootNode, nodeCallback, useIdIfEmptyName, getDisabled);
+ }
+
+ return processNameValues(formValues, skipEmpty, delimiter);
}
- var json_data = {}, new_arr_obj=null, index=null, key=null, input_name=null, new_obj=null;
+ /**
+ * Processes collection of { name: 'name', value: 'value' } objects.
+ * @param nameValues
+ * @param skipEmpty if true skips elements with value == '' or value == null
+ * @param delimiter
+ */
+ function processNameValues(nameValues, skipEmpty, delimiter)
+ {
+ var result = {},
+ arrays = {},
+ i, j, k, l,
+ value,
+ nameParts,
+ currResult,
+ arrNameFull,
+ arrName,
+ arrIdx,
+ namePart,
+ name,
+ _nameParts;
- for(var i=0,n=form.length; i0) ||
- (form[i].type==='range' && form[i].value.length>0) ||
- (form[i].type==='select-one' && form[i].options[form[i].selectedIndex].value.length>0) ||
- (form[i].type==='select-multiple' && form[i].selectedOptions.length>0) ||
- (form[i].type==='textarea' && form[i].value.length>0) ||
- (form[i].type==='number' && form[i].value.length>0) ||
- (form[i].type==='date' && form[i].value.length>0) ||
- (form[i].type==='color' && form[i].value.length>0) ||
- (form[i].type==='month' && form[i].value.length>0) ||
- (form[i].type==='week' && form[i].value.length>0) ||
- (form[i].type==='time' && form[i].value.length>0) ||
- (form[i].type==='datetime' && form[i].value.length>0) ||
- (form[i].type==='datetime-local' && form[i].value.length>0) ||
- (form[i].type==='email' && form[i].value.length>0) ||
- (form[i].type==='search' && form[i].value.length>0) ||
- (form[i].type==='tel' && form[i].value.length>0) ||
- (form[i].type==='url' && form[i].value.length>0) ||
- (form[i].type==='image' && form[i].value.length>0) ||
- (form[i].type==='file' && form[i].value.length>0)
- ){
+ name = nameValues[i].name;
+ _nameParts = name.split(delimiter);
+ nameParts = [];
+ currResult = result;
+ arrNameFull = '';
- /*get the name of the current input*/
- input_name = form[i].name;
-
- /*array/object*/
- if(input_name.match(/\[.*\]/g)){
-
- if(input_name.match(/\[.+\]/g)){
-
- /*array object, Object[][name]*/
- if(input_name.match(/\[.+\]/g)[0].match(/\[[0-9]\]/)!==null){
-
- new_arr_obj = input_name.replace(/\[.+\]/g,''); //get object name
- index = input_name.match(/[0-9]/g)[0]; //get index group
- key = input_name.match(/\[.+\]/g)[0].replace(/(\[|\]|[0-9])/g,'');
-
- /*create an array in an object*/
- if(typeof json_data[new_arr_obj]==='undefined'){
- json_data[new_arr_obj] = [];
- }
-
- /*create an object inside array*/
- if(typeof json_data[new_arr_obj][index]==='undefined'){
- json_data[new_arr_obj][index] = {};
- }
-
- json_data[new_arr_obj][index][key] = form[i].value;
-
- }else if(input_name.match(/\[.+\]/g)!==null){
- //to object
- //Object[name]
-
- /*get object name*/
- new_obj = input_name.replace(/\[.+\]/g,'');
-
- /*set new object*/
- if(typeof json_data[new_obj]==='undefined'){
- json_data[new_obj] = {};
- }
- /*assign a key name*/
- key = input_name.match(/\[.+\]/g)[0].replace(/(\[|\])/g,'');
-
- /*set key and form value*/
- json_data[new_obj][key] = form[i].value;
- }else{}
- }else{
-
- /*to array, Object[]*/
- key = input_name.replace(/\[.*\]/g, '');
-
- if(form[i].type==='select-multiple'){
- for(var j=0, m=form[i].selectedOptions.length; j0){
- if(typeof json_data[key]==='undefined'){
- json_data[key] = [];
- }
- json_data[key].push(form[i].selectedOptions[j].value);
- }
- }
-
- }else{
- if(typeof json_data[key]==='undefined'){
- json_data[key] = [];
- }
- json_data[key].push(form[i].value);
+ for(j = 0; j < _nameParts.length; j++)
+ {
+ namePart = _nameParts[j].split('][');
+ if (namePart.length > 1)
+ {
+ for(k = 0; k < namePart.length; k++)
+ {
+ if (k == 0)
+ {
+ namePart[k] = namePart[k] + ']';
+ }
+ else if (k == namePart.length - 1)
+ {
+ namePart[k] = '[' + namePart[k];
+ }
+ else
+ {
+ namePart[k] = '[' + namePart[k] + ']';
}
+ arrIdx = namePart[k].match(/([a-z_]+)?\[([a-z_][a-z0-9_]+?)\]/i);
+ if (arrIdx)
+ {
+ for(l = 1; l < arrIdx.length; l++)
+ {
+ if (arrIdx[l]) nameParts.push(arrIdx[l]);
+ }
+ }
+ else{
+ nameParts.push(namePart[k]);
+ }
}
- }else{
- /*basic info*/
- key = form[i].name.replace(/\[.*\]/g, '');
- json_data[key] = form[i].value;
+ }
+ else
+ nameParts = nameParts.concat(namePart);
+ }
+ for (j = 0; j < nameParts.length; j++)
+ {
+ namePart = nameParts[j];
+
+ if (namePart.indexOf('[]') > -1 && j == nameParts.length - 1)
+ {
+ arrName = namePart.substr(0, namePart.indexOf('['));
+ arrNameFull += arrName;
+
+ if (!currResult[arrName]) currResult[arrName] = [];
+ currResult[arrName].push(value);
+ }
+ else if (namePart.indexOf('[') > -1)
+ {
+ arrName = namePart.substr(0, namePart.indexOf('['));
+ arrIdx = namePart.replace(/(^([a-z_]+)?\[)|(\]$)/gi, '');
+
+ /* Unique array name */
+ arrNameFull += '_' + arrName + '_' + arrIdx;
+
+ /*
+ * Because arrIdx in field name can be not zero-based and step can be
+ * other than 1, we can't use them in target array directly.
+ * Instead we're making a hash where key is arrIdx and value is a reference to
+ * added array element
+ */
+
+ if (!arrays[arrNameFull]) arrays[arrNameFull] = {};
+ if (arrName != '' && !currResult[arrName]) currResult[arrName] = [];
+
+ if (j == nameParts.length - 1)
+ {
+ if (arrName == '')
+ {
+ currResult.push(value);
+ arrays[arrNameFull][arrIdx] = currResult[currResult.length - 1];
+ }
+ else
+ {
+ currResult[arrName].push(value);
+ arrays[arrNameFull][arrIdx] = currResult[arrName][currResult[arrName].length - 1];
+ }
+ }
+ else
+ {
+ if (!arrays[arrNameFull][arrIdx])
+ {
+ if ((/^[0-9a-z_]+\[?/i).test(nameParts[j+1])) currResult[arrName].push({});
+ else currResult[arrName].push([]);
+
+ arrays[arrNameFull][arrIdx] = currResult[arrName][currResult[arrName].length - 1];
+ }
+ }
+
+ currResult = arrays[arrNameFull][arrIdx];
+ }
+ else
+ {
+ arrNameFull += namePart;
+
+ if (j < nameParts.length - 1) /* Not the last part of name - means object */
+ {
+ if (!currResult[namePart]) currResult[namePart] = {};
+ currResult = currResult[namePart];
+ }
+ else
+ {
+ currResult[namePart] = value;
+ }
}
}
}
- }//endfor
- document.getElementById('json_result').innerHTML = JSON.stringify(json_data);
- console.log("Result: ",json_data);
- return false;
-}//endfunc
+ return result;
+ }
+
+ function getFormValues(rootNode, nodeCallback, useIdIfEmptyName, getDisabled)
+ {
+ var result = extractNodeValues(rootNode, nodeCallback, useIdIfEmptyName, getDisabled);
+ return result.length > 0 ? result : getSubFormValues(rootNode, nodeCallback, useIdIfEmptyName, getDisabled);
+ }
+
+ function getSubFormValues(rootNode, nodeCallback, useIdIfEmptyName, getDisabled)
+ {
+ var result = [],
+ currentNode = rootNode.firstChild;
+
+ while (currentNode)
+ {
+ result = result.concat(extractNodeValues(currentNode, nodeCallback, useIdIfEmptyName, getDisabled));
+ currentNode = currentNode.nextSibling;
+ }
+
+ return result;
+ }
+
+ function extractNodeValues(node, nodeCallback, useIdIfEmptyName, getDisabled) {
+ if (node.disabled && !getDisabled) return [];
+
+ var callbackResult, fieldValue, result, fieldName = getFieldName(node, useIdIfEmptyName);
+
+ callbackResult = nodeCallback && nodeCallback(node);
+
+ if (callbackResult && callbackResult.name) {
+ result = [callbackResult];
+ }
+ else if (fieldName != '' && node.nodeName.match(/INPUT|TEXTAREA/i)) {
+ fieldValue = getFieldValue(node, getDisabled);
+ if (null === fieldValue) {
+ result = [];
+ } else {
+ result = [ { name: fieldName, value: fieldValue} ];
+ }
+ }
+ else if (fieldName != '' && node.nodeName.match(/SELECT/i)) {
+ fieldValue = getFieldValue(node, getDisabled);
+ result = [ { name: fieldName.replace(/\[\]$/, ''), value: fieldValue } ];
+ }
+ else {
+ result = getSubFormValues(node, nodeCallback, useIdIfEmptyName, getDisabled);
+ }
+
+ return result;
+ }
+
+ function getFieldName(node, useIdIfEmptyName)
+ {
+ if (node.name && node.name != '') return node.name;
+ else if (useIdIfEmptyName && node.id && node.id != '') return node.id;
+ else return '';
+ }
+
+
+ function getFieldValue(fieldNode, getDisabled)
+ {
+ if (fieldNode.disabled && !getDisabled) return null;
+
+ switch (fieldNode.nodeName) {
+ case 'INPUT':
+ case 'TEXTAREA':
+ switch (fieldNode.type.toLowerCase()) {
+ case 'radio':
+ if (fieldNode.checked && fieldNode.value === "false") return false;
+ case 'checkbox':
+ if (fieldNode.checked && fieldNode.value === "true") return true;
+ if (!fieldNode.checked && fieldNode.value === "true") return false;
+ if (fieldNode.checked) return fieldNode.value;
+ break;
+
+ case 'button':
+ case 'reset':
+ case 'submit':
+ case 'image':
+ return '';
+ break;
+
+ default:
+ return fieldNode.value;
+ break;
+ }
+ break;
+
+ case 'SELECT':
+ return getSelectedOptionValue(fieldNode);
+ break;
+
+ default:
+ break;
+ }
+
+ return null;
+ }
+
+ function getSelectedOptionValue(selectNode)
+ {
+ var multiple = selectNode.multiple,
+ result = [],
+ options,
+ i, l;
+
+ if (!multiple) return selectNode.value;
+
+ for (options = selectNode.getElementsByTagName("option"), i = 0, l = options.length; i < l; i++)
+ {
+ if (options[i].selected) result.push(options[i].value);
+ }
+
+ return result;
+ }
+
+ return form2js;
+
+}));
diff --git a/assets/templates/base.tmpl b/assets/templates/base.tmpl
index a428f6fc..f2f3656c 100644
--- a/assets/templates/base.tmpl
+++ b/assets/templates/base.tmpl
@@ -7,6 +7,7 @@
+
{{ if ne .Config.StyleSheet "" }}{{ end }}
diff --git a/assets/templates/editor.tmpl b/assets/templates/editor.tmpl
index dc3fdaf6..512f6767 100644
--- a/assets/templates/editor.tmpl
+++ b/assets/templates/editor.tmpl
@@ -2,7 +2,7 @@
+
{{- end}}
diff --git a/internal/assets/binary.go b/internal/assets/binary.go
index 0d330776..9f7714d0 100644
--- a/internal/assets/binary.go
+++ b/internal/assets/binary.go
@@ -2,6 +2,7 @@
// sources:
// assets/public/css/styles.css
// assets/public/js/application.js
+// assets/public/js/form-to-json.js
// assets/templates/actions.tmpl
// assets/templates/base.tmpl
// assets/templates/editor.tmpl
@@ -70,6 +71,24 @@ func publicJsApplicationJs() (*asset, error) {
return a, err
}
+// publicJsFormToJsonJs reads file data from disk. It returns an error on failure.
+func publicJsFormToJsonJs() (*asset, error) {
+ path := "D:\\Code\\Go\\src\\github.com\\hacdias\\caddy-filemanager\\assets\\public\\js\\form-to-json.js"
+ name := "public/js/form-to-json.js"
+ bytes, err := bindataRead(path, name)
+ if err != nil {
+ return nil, err
+ }
+
+ fi, err := os.Stat(path)
+ if err != nil {
+ err = fmt.Errorf("Error reading asset info %s at %s: %v", name, path, err)
+ }
+
+ a := &asset{bytes: bytes, info: fi}
+ return a, err
+}
+
// templatesActionsTmpl reads file data from disk. It returns an error on failure.
func templatesActionsTmpl() (*asset, error) {
path := "D:\\Code\\Go\\src\\github.com\\hacdias\\caddy-filemanager\\assets\\templates\\actions.tmpl"
@@ -232,6 +251,7 @@ func AssetNames() []string {
var _bindata = map[string]func() (*asset, error){
"public/css/styles.css": publicCssStylesCss,
"public/js/application.js": publicJsApplicationJs,
+ "public/js/form-to-json.js": publicJsFormToJsonJs,
"templates/actions.tmpl": templatesActionsTmpl,
"templates/base.tmpl": templatesBaseTmpl,
"templates/editor.tmpl": templatesEditorTmpl,
@@ -286,6 +306,7 @@ var _bintree = &bintree{nil, map[string]*bintree{
}},
"js": &bintree{nil, map[string]*bintree{
"application.js": &bintree{publicJsApplicationJs, map[string]*bintree{}},
+ "form-to-json.js": &bintree{publicJsFormToJsonJs, map[string]*bintree{}},
}},
}},
"templates": &bintree{nil, map[string]*bintree{
diff --git a/internal/file/editor.go b/internal/file/editor.go
index 8ddb3c9b..89150d20 100644
--- a/internal/file/editor.go
+++ b/internal/file/editor.go
@@ -78,7 +78,6 @@ func (i *Info) GetEditor() (*Editor, error) {
editor.Class = "content-only"
editor.Content = i.Content
}
-
return editor, nil
}
diff --git a/internal/file/frontmatter.go b/internal/file/frontmatter.go
index aeedeba4..77f24248 100644
--- a/internal/file/frontmatter.go
+++ b/internal/file/frontmatter.go
@@ -146,7 +146,7 @@ func handleObjects(content interface{}, parent *Block, name string) *Block {
} else if parent.Type == arrayType {
c.Name = parent.Name + "[]"
} else {
- c.Name = parent.Name + "[" + c.Title + "]"
+ c.Name = parent.Name + "." + c.Title
}
c.Content = rawToPretty(content, c)
@@ -162,7 +162,7 @@ func handleArrays(content interface{}, parent *Block, name string) *Block {
if parent.Name == mainName {
c.Name = name
} else {
- c.Name = parent.Name + "[" + name + "]"
+ c.Name = parent.Name + "." + name
}
c.Content = rawToPretty(content, c)
@@ -199,7 +199,7 @@ func handleFlatValues(content interface{}, parent *Block, name string) *Block {
c.Title = content.(string)
} else if parent.Type == objectType {
c.Title = name
- c.Name = parent.Name + "[" + name + "]"
+ c.Name = parent.Name + "." + name
if parent.Name == mainName {
c.Name = name
diff --git a/internal/file/update.go b/internal/file/update.go
index e30e548b..fe473488 100644
--- a/internal/file/update.go
+++ b/internal/file/update.go
@@ -1,68 +1,134 @@
package file
import (
+ "bytes"
+ "encoding/json"
+ "errors"
+ "fmt"
+ "io/ioutil"
"net/http"
+ "path/filepath"
+ "strings"
"github.com/hacdias/caddy-filemanager/internal/config"
+ "github.com/spf13/hugo/parser"
)
-// Update is
+// Update is used to update a file that was edited
func (i *Info) Update(w http.ResponseWriter, r *http.Request, c *config.Config) (int, error) {
+ var data map[string]interface{}
+ kind := r.Header.Get("kind")
- /*
- // POST handles the POST method on editor page
- func POST(w http.ResponseWriter, r *http.Request, c *config.Config, filename string) (int, error) {
- var data info
+ // TODO: remove
+ fmt.Println(i.Name)
- // Get the JSON information sent using a buffer
- rawBuffer := new(bytes.Buffer)
- rawBuffer.ReadFrom(r.Body)
- err := json.Unmarshal(rawBuffer.Bytes(), &data)
+ if kind == "" {
+ return http.StatusBadRequest, nil
+ }
- fmt.Println(string(rawBuffer.Bytes()))
+ // Get the JSON information
+ rawBuffer := new(bytes.Buffer)
+ rawBuffer.ReadFrom(r.Body)
+ err := json.Unmarshal(rawBuffer.Bytes(), &data)
- if err != nil {
- return server.RespondJSON(w, &response{"Error decrypting json."}, http.StatusInternalServerError, err)
- }
+ if err != nil {
+ return http.StatusInternalServerError, err
+ }
- // Initializes the file content to write
- var file []byte
- var code int
+ var file []byte
+ var code int
- switch data.ContentType {
- case "frontmatter-only":
- file, code, err = parseFrontMatterOnlyFile(data, filename)
- if err != nil {
- return server.RespondJSON(w, &response{err.Error()}, code, err)
- }
- case "content-only":
- // The main content of the file
- mainContent := data.Content["content"].(string)
- mainContent = strings.TrimSpace(mainContent)
+ switch kind {
+ case "frontmatter-only":
+ if file, code, err = parseFrontMatterOnlyFile(data, i.Name); err != nil {
+ return http.StatusInternalServerError, err
+ }
+ case "content-only":
+ mainContent := data["content"].(string)
+ mainContent = strings.TrimSpace(mainContent)
+ file = []byte(mainContent)
+ case "complete":
+ if file, code, err = parseCompleteFile(data, i.Name); err != nil {
+ return http.StatusInternalServerError, err
+ }
+ default:
+ return http.StatusBadRequest, nil
+ }
- file = []byte(mainContent)
- case "complete":
- file, code, err = parseCompleteFile(data, filename, c)
- if err != nil {
- return server.RespondJSON(w, &response{err.Error()}, code, err)
- }
- default:
- return server.RespondJSON(w, &response{"Invalid content type."}, http.StatusBadRequest, nil)
- }
+ // Write the file
+ err = ioutil.WriteFile(i.Path, file, 0666)
- // Write the file
- err = ioutil.WriteFile(filename, file, 0666)
+ if err != nil {
+ return http.StatusInternalServerError, err
+ }
- if err != nil {
- return server.RespondJSON(w, &response{err.Error()}, http.StatusInternalServerError, err)
- }
-
- if data.Regenerate {
- go hugo.Run(c, false)
- }
-
- return server.RespondJSON(w, nil, http.StatusOK, nil)
- }
- */
- return 0, nil
+ return code, nil
+}
+
+func parseFrontMatterOnlyFile(data interface{}, filename string) ([]byte, int, error) {
+ frontmatter := strings.TrimPrefix(filepath.Ext(filename), ".")
+ var mark rune
+
+ switch frontmatter {
+ case "toml":
+ mark = rune('+')
+ case "json":
+ mark = rune('{')
+ case "yaml":
+ mark = rune('-')
+ default:
+ return []byte{}, http.StatusBadRequest, errors.New("Can't define the frontmatter.")
+ }
+
+ f, err := parser.InterfaceToFrontMatter(data, mark)
+ fString := string(f)
+
+ // If it's toml or yaml, strip frontmatter identifier
+ if frontmatter == "toml" {
+ fString = strings.TrimSuffix(fString, "+++\n")
+ fString = strings.TrimPrefix(fString, "+++\n")
+ }
+
+ if frontmatter == "yaml" {
+ fString = strings.TrimSuffix(fString, "---\n")
+ fString = strings.TrimPrefix(fString, "---\n")
+ }
+
+ f = []byte(fString)
+
+ if err != nil {
+ return []byte{}, http.StatusInternalServerError, err
+ }
+
+ return f, http.StatusOK, nil
+}
+
+func parseCompleteFile(data map[string]interface{}, filename string) ([]byte, int, error) {
+ // The main content of the file
+ mainContent := data["content"].(string)
+ mainContent = "\n\n" + strings.TrimSpace(mainContent) + "\n"
+
+ // Removes the main content from the rest of the frontmatter
+ delete(data, "content")
+
+ if _, ok := data["date"]; ok {
+ data["date"] = data["date"].(string) + ":00"
+ }
+
+ // Converts the frontmatter in JSON
+ jsonFrontmatter, err := json.Marshal(data)
+
+ if err != nil {
+ return []byte{}, http.StatusInternalServerError, err
+ }
+
+ // Indents the json
+ frontMatterBuffer := new(bytes.Buffer)
+ json.Indent(frontMatterBuffer, jsonFrontmatter, "", " ")
+
+ // Generates the final file
+ f := new(bytes.Buffer)
+ f.Write(frontMatterBuffer.Bytes())
+ f.Write([]byte(mainContent))
+ return f.Bytes(), http.StatusOK, nil
}
diff --git a/utils/_unused/hugo/hugo.go b/utils/_unused/hugo/hugo.go
index 69d210e9..acd2978c 100644
--- a/utils/_unused/hugo/hugo.go
+++ b/utils/_unused/hugo/hugo.go
@@ -27,12 +27,3 @@ func Run(c *config.Config.Config, force bool) {
log.Panic(err)
}
}
-
-func stringInSlice(a string, list []string) (bool, int) {
- for i, b := range list {
- if b == a {
- return true, i
- }
- }
- return false, 0
-}
diff --git a/utils/variables/variables.go b/utils/variables/variables.go
index 9d60dabf..7a0168b4 100644
--- a/utils/variables/variables.go
+++ b/utils/variables/variables.go
@@ -35,3 +35,13 @@ func Dict(values ...interface{}) (map[string]interface{}, error) {
return dict, nil
}
+
+// StringInSlice checks if a slice contains a string
+func StringInSlice(a string, list []string) (bool, int) {
+ for i, b := range list {
+ if b == a {
+ return true, i
+ }
+ }
+ return false, 0
+}