This commit is contained in:
Henrique Dias 2016-06-27 18:57:54 +01:00
parent 1c55147faa
commit 429b67f661
13 changed files with 568 additions and 215 deletions

View File

@ -113,8 +113,8 @@ button, html [type="button"], [type="reset"], [type="submit"] {
border: none; border: none;
border-radius: 2px; border-radius: 2px;
display: inline-block; display: inline-block;
height: 36px; height: 2.25em;
line-height: 36px; line-height: 2.25em;
outline: 0; outline: 0;
padding: 0 2rem; padding: 0 2rem;
text-transform: uppercase; text-transform: uppercase;
@ -504,6 +504,23 @@ header form input {
-webkit-box-flex: 1; -webkit-box-flex: 1;
-ms-flex-positive: 1; -ms-flex-positive: 1;
flex-grow: 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 { .item:hover {
box-shadow: 0 1px 3px rgba(0, 0, 0, .12), 0 1px 2px rgba(0, 0, 0, .24) !important; 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 { #editor fieldset fieldset {
margin-left: 1em; 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;
}

View File

@ -455,6 +455,7 @@ var textareaAutoGrow = function() {
var handleEditorPage = function () { var handleEditorPage = function () {
let container = document.getElementById('editor'); let container = document.getElementById('editor');
let button = document.querySelector('#submit span:first-child');
let kind = container.dataset.kind; let kind = container.dataset.kind;
if (kind != 'frontmatter-only') { if (kind != 'frontmatter-only') {
@ -482,9 +483,28 @@ var handleEditorPage = function () {
button.addEventListener('click', deleteFrontMatterItem); 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) { var deleteFrontMatterItem = function(event) {
@ -492,30 +512,42 @@ var deleteFrontMatterItem = function(event) {
document.getElementById(this.dataset.delete).remove(); document.getElementById(this.dataset.delete).remove();
} }
const tempID = "_fm_internal_temporary_id"
var addFrontMatterItem = function(event) { var addFrontMatterItem = function(event) {
/*
event.preventDefault(); event.preventDefault();
defaultID = "lorem-ipsum-sin-dolor-amet";
// Remove if there is an incomplete new item let newItem = document.getElementById(tempID)
newItem = $("#" + defaultID); if (newItem) {
if (newItem.length) { newItem.remove();
newItem.remove();
} }
block = $(this).parent().parent(); let block = this.parentNode;
blockType = block.data("type"); let type = block.dataset.type;
blockID = block.attr("id"); let id = block.id;
// If the Block Type is an array // If the block is an array
if (blockType == "array") { if (type === "array") {
newID = blockID + "[]"; let fieldID = id + "[]"
input = blockID; let input = fieldID
input = input.replace(/\[/, '\\['); let count = block.querySelectorAll('.group > div').length
input = input.replace(/\]/, '\\]'); input = input.replace(/\[/, '\\[');
block.append('<div id="' + newID + '-' + $('#' + input + ' > div').length + '" data-type="array-item"><input name="' + newID + ':auto" id="' + newID + '"></input><span class="actions"> <button class="delete">&#8722;</button></span></div></div>'); input = input.replace(/\]/, '\\]');
block.querySelector('.group').insertAdjacentHTML('beforeend', `<div id="${fieldID}-${count}" data-type="array-item">
<input name="${fieldID}" id="${fieldID}" type="text" data-parent-type="array"></input>
<div class="action delete" data-delete="none">
<i class="material-icons">close</i>
</div>
</div>`);
} }
/*
// Main add button, after all blocks // Main add button, after all blocks
if (block.is('div') && block.hasClass("frontmatter")) { if (block.is('div') && block.hasClass("frontmatter")) {
block = $('.blocks'); block = $('.blocks');
@ -608,4 +640,6 @@ var addFrontMatterItem = function(event) {
return false; return false;
*/ */
return false;
} }

View File

@ -1,141 +1,349 @@
/** /**
Author: Jhan Mateo * Copyright (c) 2010 Maxim Vasiliev
Date Started: 7/29/2015 *
Date Ended: 7/30/2015 * Permission is hereby granted, free of charge, to any person obtaining a copy
Description: Using native javascript (no js framework), this application will serializes from form data to Json format. * of this software and associated documentation files (the "Software"), to deal
The MIT License (MIT) * 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 (function (root, factory)
a copy of this software and associated documentation files (the "Software"), {
to deal in the Software without restriction, including without limitation if (typeof exports !== 'undefined' && typeof module !== 'undefined' && module.exports) {
the rights to use, copy, modify, merge, publish, distribute, sublicense, // NodeJS
and/or sell copies of the Software, and to permit persons to whom the Software module.exports = factory();
is furnished to do so, subject to the following conditions: }
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){ /* If rootNode is array - combine values */
console.log('Form error'); if (rootNode.constructor == Array || (typeof NodeList != "undefined" && rootNode.constructor == NodeList))
return false; {
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; i<n; i++){ for (i = 0; i < nameValues.length; i++)
{
value = nameValues[i].value;
if(form[i].type!=='submit' || form[i].nodeName.toLowerCase()!=='fieldset' || form[i].nodeName.toLowerCase()!=='reset'){ if (skipEmpty && (value === '' || value === null)) continue;
if( name = nameValues[i].name;
(form[i]!==undefined && form[i]!==null) && _nameParts = name.split(delimiter);
(form[i].type==='checkbox' && form[i].checked) || nameParts = [];
(form[i].type==='radio' && form[i].checked) || currResult = result;
(form[i].type==='text' && form[i].value.length>0) || arrNameFull = '';
(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)
){
/*get the name of the current input*/ for(j = 0; j < _nameParts.length; j++)
input_name = form[i].name; {
namePart = _nameParts[j].split('][');
/*array/object*/ if (namePart.length > 1)
if(input_name.match(/\[.*\]/g)){ {
for(k = 0; k < namePart.length; k++)
if(input_name.match(/\[.+\]/g)){ {
if (k == 0)
/*array object, Object[][name]*/ {
if(input_name.match(/\[.+\]/g)[0].match(/\[[0-9]\]/)!==null){ namePart[k] = namePart[k] + ']';
}
new_arr_obj = input_name.replace(/\[.+\]/g,''); //get object name else if (k == namePart.length - 1)
index = input_name.match(/[0-9]/g)[0]; //get index group {
key = input_name.match(/\[.+\]/g)[0].replace(/(\[|\]|[0-9])/g,''); namePart[k] = '[' + namePart[k];
}
/*create an array in an object*/ else
if(typeof json_data[new_arr_obj]==='undefined'){ {
json_data[new_arr_obj] = []; namePart[k] = '[' + namePart[k] + ']';
}
/*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; j<m; j++){
if(form[i].selectedOptions[j].value.length>0){
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);
} }
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*/ else
key = form[i].name.replace(/\[.*\]/g, ''); nameParts = nameParts.concat(namePart);
json_data[key] = form[i].value; }
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); return result;
console.log("Result: ",json_data); }
return false;
}//endfunc 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;
}));

View File

@ -7,6 +7,7 @@
<link href='https://fonts.googleapis.com/css?family=Roboto:400,500' rel='stylesheet' type='text/css'> <link href='https://fonts.googleapis.com/css?family=Roboto:400,500' rel='stylesheet' type='text/css'>
<link rel="stylesheet" href="{{ .Config.BaseURL }}/_filemanagerinternal/css/styles.css"> <link rel="stylesheet" href="{{ .Config.BaseURL }}/_filemanagerinternal/css/styles.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.2.3/ace.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.2.3/ace.js"></script>
<script src="{{ .Config.BaseURL }}/_filemanagerinternal/js/form-to-json.js"></script>
<script src="{{ .Config.BaseURL }}/_filemanagerinternal/js/application.js"></script> <script src="{{ .Config.BaseURL }}/_filemanagerinternal/js/application.js"></script>
{{ if ne .Config.StyleSheet "" }}<style>{{.Config.StyleSheet}}</style>{{ end }} {{ if ne .Config.StyleSheet "" }}<style>{{.Config.StyleSheet}}</style>{{ end }}
</head> </head>

View File

@ -2,7 +2,7 @@
<div id="editor" class="container" data-kind="{{ .Class }}"> <div id="editor" class="container" data-kind="{{ .Class }}">
<form method="POST" action="./"> <form method="POST" action="./">
{{ if or (eq .Class "frontmatter-only") (eq .Class "complete") }} {{ if or (eq .Class "frontmatter-only") (eq .Class "complete") }}
<div class="frontmatter"> <div class="frontmatter" data-type="parent">
{{ template "blocks" .FrontMatter }} {{ template "blocks" .FrontMatter }}
<button class="add">Add field</button> <button class="add">Add field</button>
</div> </div>
@ -18,7 +18,8 @@
{{ end }} {{ end }}
<div> <div>
<input type="submit" data-type="{{ .Class }}" value="Save"> <button id="submit" type="submit" data-type="{{ .Class }}"><span><i class="material-icons">save</i></span> <span>save</span>
</button>
</div> </div>
</form> </form>
</div> </div>

View File

@ -28,30 +28,22 @@
{{ template "fielset" $value }} {{ template "fielset" $value }}
{{ end }} {{ end }}
<template id="arrayItem">
</template>
<template id="objectItem">
</template>
{{ end }} {{ end }}
{{ define "value" }} {{ define "value" }}
{{ if eq .HTMLType "textarea" }} {{ if eq .HTMLType "textarea" }}
<textarea class="scroll" name="{{ .Name }}:{{ .Type }}" id="{{.Name }}" data-parent-type="{{ .Parent.Type }}">{{ .Content.Other }}</textarea> <textarea class="scroll" name="{{ .Name }}" id="{{.Name }}" data-parent-type="{{ .Parent.Type }}">{{ .Content.Other }}</textarea>
{{ else if eq .HTMLType "datetime" }} {{ else if eq .HTMLType "datetime" }}
<input name="{{ .Name }}:{{ .Type }}" id="{{ .Name }}" value="{{ .Content.Other.Format "2006-01-02T15:04" }}" type="datetime-local" data-parent-type="{{ .Parent.Type }}"></input> <input name="{{ .Name }}" id="{{ .Name }}" value="{{ .Content.Other.Format "2006-01-02T15:04" }}" type="datetime-local" data-parent-type="{{ .Parent.Type }}"></input>
{{ else }} {{ else }}
<input name="{{ .Name }}:{{ .Type }}" id="{{ .Name }}" value="{{ .Content.Other }}" type="{{ .HTMLType }}" data-parent-type="{{ .Parent.Type }}"></input> <input name="{{ .Name }}" id="{{ .Name }}" value="{{ .Content.Other }}" type="{{ .HTMLType }}" data-parent-type="{{ .Parent.Type }}"></input>
{{ end }} {{ end }}
{{ end }} {{ end }}
{{ define "fielset" }} {{ define "fielset" }}
<fieldset id="{{ .Name }}" data-type="{{ .Type }}"> <fieldset id="{{ .Name }}" data-type="{{ .Type }}">
<h3>{{ SplitCapitalize .Title }}</h3> {{ if not (eq .Title "") }}<h3>{{ SplitCapitalize .Title }}</h3>{{ end }}
<div class="action add"> <div class="action add">
<i class="material-icons">add</i> <i class="material-icons">add</i>
</div> </div>

View File

@ -25,6 +25,7 @@
</p> </p>
</a> </a>
</div> </div>
<span class="checkbox">
</div> </div>
{{- end}} {{- end}}
</div> </div>

View File

@ -2,6 +2,7 @@
// sources: // sources:
// assets/public/css/styles.css // assets/public/css/styles.css
// assets/public/js/application.js // assets/public/js/application.js
// assets/public/js/form-to-json.js
// assets/templates/actions.tmpl // assets/templates/actions.tmpl
// assets/templates/base.tmpl // assets/templates/base.tmpl
// assets/templates/editor.tmpl // assets/templates/editor.tmpl
@ -70,6 +71,24 @@ func publicJsApplicationJs() (*asset, error) {
return a, err 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. // templatesActionsTmpl reads file data from disk. It returns an error on failure.
func templatesActionsTmpl() (*asset, error) { func templatesActionsTmpl() (*asset, error) {
path := "D:\\Code\\Go\\src\\github.com\\hacdias\\caddy-filemanager\\assets\\templates\\actions.tmpl" 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){ var _bindata = map[string]func() (*asset, error){
"public/css/styles.css": publicCssStylesCss, "public/css/styles.css": publicCssStylesCss,
"public/js/application.js": publicJsApplicationJs, "public/js/application.js": publicJsApplicationJs,
"public/js/form-to-json.js": publicJsFormToJsonJs,
"templates/actions.tmpl": templatesActionsTmpl, "templates/actions.tmpl": templatesActionsTmpl,
"templates/base.tmpl": templatesBaseTmpl, "templates/base.tmpl": templatesBaseTmpl,
"templates/editor.tmpl": templatesEditorTmpl, "templates/editor.tmpl": templatesEditorTmpl,
@ -286,6 +306,7 @@ var _bintree = &bintree{nil, map[string]*bintree{
}}, }},
"js": &bintree{nil, map[string]*bintree{ "js": &bintree{nil, map[string]*bintree{
"application.js": &bintree{publicJsApplicationJs, 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{ "templates": &bintree{nil, map[string]*bintree{

View File

@ -78,7 +78,6 @@ func (i *Info) GetEditor() (*Editor, error) {
editor.Class = "content-only" editor.Class = "content-only"
editor.Content = i.Content editor.Content = i.Content
} }
return editor, nil return editor, nil
} }

View File

@ -146,7 +146,7 @@ func handleObjects(content interface{}, parent *Block, name string) *Block {
} else if parent.Type == arrayType { } else if parent.Type == arrayType {
c.Name = parent.Name + "[]" c.Name = parent.Name + "[]"
} else { } else {
c.Name = parent.Name + "[" + c.Title + "]" c.Name = parent.Name + "." + c.Title
} }
c.Content = rawToPretty(content, c) c.Content = rawToPretty(content, c)
@ -162,7 +162,7 @@ func handleArrays(content interface{}, parent *Block, name string) *Block {
if parent.Name == mainName { if parent.Name == mainName {
c.Name = name c.Name = name
} else { } else {
c.Name = parent.Name + "[" + name + "]" c.Name = parent.Name + "." + name
} }
c.Content = rawToPretty(content, c) c.Content = rawToPretty(content, c)
@ -199,7 +199,7 @@ func handleFlatValues(content interface{}, parent *Block, name string) *Block {
c.Title = content.(string) c.Title = content.(string)
} else if parent.Type == objectType { } else if parent.Type == objectType {
c.Title = name c.Title = name
c.Name = parent.Name + "[" + name + "]" c.Name = parent.Name + "." + name
if parent.Name == mainName { if parent.Name == mainName {
c.Name = name c.Name = name

View File

@ -1,68 +1,134 @@
package file package file
import ( import (
"bytes"
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"net/http" "net/http"
"path/filepath"
"strings"
"github.com/hacdias/caddy-filemanager/internal/config" "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) { 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")
/* // TODO: remove
// POST handles the POST method on editor page fmt.Println(i.Name)
func POST(w http.ResponseWriter, r *http.Request, c *config.Config, filename string) (int, error) {
var data info
// Get the JSON information sent using a buffer if kind == "" {
rawBuffer := new(bytes.Buffer) return http.StatusBadRequest, nil
rawBuffer.ReadFrom(r.Body) }
err := json.Unmarshal(rawBuffer.Bytes(), &data)
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 { if err != nil {
return server.RespondJSON(w, &response{"Error decrypting json."}, http.StatusInternalServerError, err) return http.StatusInternalServerError, err
} }
// Initializes the file content to write var file []byte
var file []byte var code int
var code int
switch data.ContentType { switch kind {
case "frontmatter-only": case "frontmatter-only":
file, code, err = parseFrontMatterOnlyFile(data, filename) if file, code, err = parseFrontMatterOnlyFile(data, i.Name); err != nil {
if err != nil { return http.StatusInternalServerError, err
return server.RespondJSON(w, &response{err.Error()}, code, err) }
} case "content-only":
case "content-only": mainContent := data["content"].(string)
// The main content of the file mainContent = strings.TrimSpace(mainContent)
mainContent := data.Content["content"].(string) file = []byte(mainContent)
mainContent = strings.TrimSpace(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) // Write the file
case "complete": err = ioutil.WriteFile(i.Path, file, 0666)
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 if err != nil {
err = ioutil.WriteFile(filename, file, 0666) return http.StatusInternalServerError, err
}
if err != nil { return code, nil
return server.RespondJSON(w, &response{err.Error()}, http.StatusInternalServerError, err) }
}
func parseFrontMatterOnlyFile(data interface{}, filename string) ([]byte, int, error) {
if data.Regenerate { frontmatter := strings.TrimPrefix(filepath.Ext(filename), ".")
go hugo.Run(c, false) var mark rune
}
switch frontmatter {
return server.RespondJSON(w, nil, http.StatusOK, nil) case "toml":
} mark = rune('+')
*/ case "json":
return 0, nil 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
} }

View File

@ -27,12 +27,3 @@ func Run(c *config.Config.Config, force bool) {
log.Panic(err) 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
}

View File

@ -35,3 +35,13 @@ func Dict(values ...interface{}) (map[string]interface{}, error) {
return dict, nil 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
}