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('<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>');
+    // 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', `<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
     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; 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(
-				(form[i]!==undefined && form[i]!==null) &&
-				(form[i].type==='checkbox' && form[i].checked) ||
-				(form[i].type==='radio' && form[i].checked) ||
-				(form[i].type==='text' && form[i].value.length>0) ||
-				(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; 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);
+			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 @@
     <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">
     <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>
     {{ if ne .Config.StyleSheet "" }}<style>{{.Config.StyleSheet}}</style>{{ end }}
     </head>
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 @@
 <div id="editor" class="container" data-kind="{{ .Class }}">
     <form method="POST" action="./">
         {{ if or (eq .Class "frontmatter-only") (eq .Class "complete") }}
-        <div class="frontmatter">
+        <div class="frontmatter" data-type="parent">
             {{ template "blocks" .FrontMatter }}
             <button class="add">Add field</button>
         </div>
@@ -18,7 +18,8 @@
         {{ end }}
 
         <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>
     </form>
 </div>
diff --git a/assets/templates/frontmatter.tmpl b/assets/templates/frontmatter.tmpl
index d8af3c50..8d01d6dc 100644
--- a/assets/templates/frontmatter.tmpl
+++ b/assets/templates/frontmatter.tmpl
@@ -28,30 +28,22 @@
     {{ template "fielset" $value }}
     {{ end }}
 
-
-    <template id="arrayItem">
-
-    </template>
-
-    <template id="objectItem">
-
-    </template>
 {{ end }}
 
 {{ define "value" }}
 {{ 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" }}
-<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 }}
-<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 }}
 
 
 {{ define "fielset" }}
 <fieldset id="{{ .Name }}" data-type="{{ .Type }}">
-  <h3>{{ SplitCapitalize .Title }}</h3>
+  {{ if not (eq .Title "") }}<h3>{{ SplitCapitalize .Title }}</h3>{{ end }}
   <div class="action add">
       <i class="material-icons">add</i>
   </div>
diff --git a/assets/templates/listing.tmpl b/assets/templates/listing.tmpl
index c2c3ab0b..e6f20c8a 100644
--- a/assets/templates/listing.tmpl
+++ b/assets/templates/listing.tmpl
@@ -25,6 +25,7 @@
       </p>
      </a>
     </div>
+    <span class="checkbox">
    </div>
    {{- end}}
   </div>
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
+}