diff --git a/assets/js/app.min.js b/assets/js/app.min.js
index 71c62b2e..eb316a47 100644
--- a/assets/js/app.min.js
+++ b/assets/js/app.min.js
@@ -1 +1 @@
-$(document).ready(function(){$("#logout").click(function(a){return a.preventDefault(),$.ajax({type:"GET",url:"/admin",async:!1,username:"username",password:"password",headers:{Authorization:"Basic xxx"}}).fail(function(){window.location="/"}),!1}),$(document).pjax("a[data-pjax]","#content")}),$(document).on("ready pjax:end",function(){function a(){this.style.height="5px",this.style.height=this.scrollHeight+"px"}return $("#content").off(),document.title=document.getElementById("site-title").innerHTML,$("textarea").each(a),$("textarea").keyup(a),$(window).resize(function(){$("textarea").each(a)}),$("main").hasClass("browse")&&$(document).trigger("page:browse"),$(".editor")[0]&&$(document).trigger("page:editor"),!1}),$(document).on("page:browse",function(){var a="#foreground",b=new Object;b.selector="form#delete",b.form=$(b.selector),b.row="",b.button="",b.url="",$("#content").on("click",".delete",function(c){return c.preventDefault(),b.button=$(this),b.row=$(this).parent().parent(),$(a).fadeIn(200),b.url=b.row.find(".filename").text(),b.form.find("span").text(b.url),b.form.fadeIn(200),!1}),$("#content").on("submit",b.selector,function(c){c.preventDefault();var d=new XMLHttpRequest;return d.open("DELETE",b.button.data("file")),d.send(),d.onreadystatechange=function(){4==d.readyState&&(200==d.status?($(a).fadeOut(200),b.form.fadeOut(200),b.row.fadeOut(200),notification({text:b.button.data("message"),type:"success",timeout:5e3})):(notification({text:"Something went wrong.",type:"error"}),console.log(d.responseText)))},!1}),$("#content").on("change",'input[type="file"]',function(a){a.preventDefault(),files=a.target.files;var b=new FormData;return $.each(files,function(a,c){b.append(a,c)}),$.ajax({url:window.location.pathname,type:"POST",data:b,cache:!1,dataType:"json",headers:{"X-Upload":"true"},processData:!1,contentType:!1}).done(function(a){notification({text:"File(s) uploaded successfully.",type:"success",timeout:5e3}),$.pjax({url:window.location.pathname,container:"#content"})}).fail(function(a){notification({text:"Something went wrong.",type:"error"}),console.log(a)}),!1}),$("#content").on("click","#upload",function(a){return a.preventDefault(),$('.actions input[type="file"]').click(),!1});var c=new Object;c.selector="form#new",c.form=$(c.selector),c.input=c.selector+' input[type="text"]',c.button="",c.url="",$("#content").on("click",".new",function(b){return b.preventDefault(),c.button=$(this),$(a).fadeIn(200),c.form.fadeIn(200),!1}),$("#content").on("keypress",c.input,function(a){return 13==a.keyCode?(a.preventDefault(),$(c.form).submit(),!1):void 0}),$("#content").on("submit",c.selector,function(a){a.preventDefault();var b=c.form.find('input[type="text"]').val(),d=b.split(":"),e="",f="";if(""==b)return notification({text:"You have to write something. If you want to close the box, click the button again.",type:"warning",timeout:5e3}),!1;if(1==d.length)e=b;else{if(2!=d.length)return notification({text:"Hmm... I don't understand you. Try writing something like 'name[:archetype]'.",type:"error"}),!1;e=d[0],f=d[1]}var g={filename:e,archetype:f},h=new XMLHttpRequest;return h.open("POST",window.location.pathname),h.setRequestHeader("Content-Type","application/json;charset=UTF-8"),h.send(JSON.stringify(g)),h.onreadystatechange=function(){if(4==h.readyState)if(200==h.status){var a=JSON.parse(h.responseText);notification({text:"File created successfully.",type:"success",timeout:5e3}),$.pjax({url:a.Location,container:"#content"})}else notification({text:"Something went wrong.",type:"error"}),console.log(h.responseText)},!1});var d=new Object;d.selector="form#rename",d.form=$(d.selector),d.input=d.selector+' input[type="text"]',d.button="",d.url="",$("#content").on("click",".rename",function(b){return b.preventDefault(),d.button=$(this),$(a).fadeIn(200),d.url=$(this).parent().parent().find(".filename").text(),d.form.fadeIn(200),d.form.find("span").text(d.url),d.form.find('input[type="text"]').val(d.url),!1}),$("#content").on("keypress",d.input,function(a){return 13==a.keyCode?(a.preventDefault(),$(d.form).submit(),!1):void 0}),$("#content").on("submit",d.selector,function(a){a.preventDefault();var b=d.form.find('input[type="text"]').val();if(""===b)return!1;"/"!=b.substring(0,1)&&(b=window.location.pathname.replace("/admin/browse/","")+"/"+b);var c={filename:b},e=new XMLHttpRequest;return e.open("PUT",d.url),e.setRequestHeader("Content-Type","application/json;charset=UTF-8"),e.send(JSON.stringify(c)),e.onreadystatechange=function(){4==e.readyState&&(200==e.status?($.pjax({url:window.location.pathname,container:"#content"}),notification({text:d.button.data("message"),type:"success",timeout:5e3})):(notification({text:"Something went wrong.",type:"error"}),console.log(e.responseText)))},!1});var e=new Object;e.selector="form#git",e.form=$(e.selector),e.input=e.selector+' input[type="text"]',$("#content").on("click","button.git",function(b){return b.preventDefault(),$(a).fadeIn(200),e.form.fadeIn(200),!1}),$("#content").on("keypress",e.input,function(a){return 13==a.keyCode?(a.preventDefault(),$(e.form).submit(),!1):void 0}),$("#content").on("submit",e.selector,function(a){a.preventDefault();var b=e.form.find('input[type="text"]').val();if(""==b)return notification({text:"You have to write something. If you want to close the box, click outside of the box.",type:"warning",timeout:5e3}),!1;var c=new XMLHttpRequest;return c.open("POST","/admin/git"),c.setRequestHeader("Content-Type","application/json;charset=UTF-8"),c.send(JSON.stringify({command:b})),c.onreadystatechange=function(){if(4==c.readyState){var a=JSON.parse(c.responseText),b="success",d=5e3;200==c.status?("false"==a.success&&(b="error",d=!1),notification({text:a.message,type:b,timeout:d})):console.log(c.responseText)}},!1}),$("#content").on("click",".close",function(b){return b.preventDefault(),$(this).parent().parent().fadeOut(200),$(a).click(),!1}),$("#content").on("click",a,function(f){return f.preventDefault(),$(a).fadeOut(200),c.form.fadeOut(200),d.form.fadeOut(200),b.form.fadeOut(200),e.form.fadeOut(200),!1})}),$(document).on("page:editor",function(){var a=$(".editor"),b=$("#editor-preview"),c=$("#editor-source");if(a.hasClass("complete")&&$("#content").on("keyup","#site-title",function(){$(".frontmatter #title").val($(this).val())}),!a.hasClass("frontmatter-only")){var d=$("#editor-source").data("mode"),e=$('textarea[name="content"]').hide(),f=ace.edit("editor-source");f.getSession().setMode("ace/mode/"+d),f.getSession().setValue(e.val()),f.getSession().on("change",function(){e.val(f.getSession().getValue())}),f.setOptions({wrap:!0,maxLines:1/0,theme:"ace/theme/github",showPrintMargin:!1,fontSize:"1em",minLines:20}),$("#content").on("click","#see-source",function(a){a.preventDefault(),b.hide(),c.fadeIn(),$(this).addClass("active"),$("#see-preview").removeClass("active"),$("#see-preview").data("previewing","false")}),$("#content").on("click","#see-preview",function(a){if(a.preventDefault(),"true"==$(this).data("previewing"))b.hide(),c.fadeIn(),$(this).removeClass("active"),$("#see-source").addClass("active"),$(this).data("previewing","false");else{var d=new showdown.Converter,e=f.getValue(),g=d.makeHtml(e);c.hide(),b.html(g).fadeIn(),$(this).addClass("active"),$("#see-source").removeClass("active"),$(this).data("previewing","true")}return!1})}$("#content").on("keypress","input",function(a){return 13==a.keyCode?(a.preventDefault(),$('input[value="Save"]').focus().click(),!1):void 0}),$("#content").on("submit","form",function(d){d.preventDefault(),a.hasClass("frontmatter-only")||(b.html("").fadeOut(),$("#see-preview").data("previewing","false"),c.fadeIn());var e=JSON.stringify($(this).serializeJSON()),f=$(this).find("input[type=submit]:focus"),g=new XMLHttpRequest;return g.open("POST",window.location),g.setRequestHeader("Content-Type","application/json;charset=UTF-8"),g.setRequestHeader("X-Regenerate",f.data("regenerate")),g.setRequestHeader("X-Schedule",f.data("schedule")),g.setRequestHeader("X-Content-Type",f.data("type")),g.send(e),g.onreadystatechange=function(){4==g.readyState&&(200==g.status?notification({text:f.data("message"),type:"success",timeout:5e3}):(notification({text:"Something went wrong.",type:"error"}),console.log(g.responseText)))},!1}),$("#content").on("click",".add",function(a){if(a.preventDefault(),defaultID="lorem-ipsum-sin-dolor-amet",newItem=$("#"+defaultID),newItem.length&&newItem.remove(),block=$(this).parent().parent(),blockType=block.data("type"),blockID=block.attr("id"),"array"==blockType&&(newID=blockID+"[]",input=blockID,input=input.replace(/\[/,"\\["),input=input.replace(/\]/,"\\]"),block.append('
div").length+'" data-type="array-item">
'),console.log("New array item added.")),block.is("div")&&block.hasClass("frontmatter")&&(block=$(".blocks"),blockType="object"),"object"==blockType){if(block.append(''),newItem=$("#"+defaultID),newItem.html(''),field=$("#name-"+defaultID),!document.cookie.replace(/(?:(?:^|.*;\s*)placeholdertip\s*\=\s*([^;]*).*$)|^.*$/,"$1")){var b=new Date;b.setDate(b.getDate()+365),document.cookie="placeholdertip=true; expires="+b.toUTCString+"; path=/",notification({text:'Write the field name and then press enter. If you want to create an array or an object, end the name with ":array" or ":object".',type:"information"})}$(field).keypress(function(a){return 13==a.which?(a.preventDefault(),value=field.val(),""==value?(newItem.remove(),!1):(elements=value.split(":"),elements.length>2?(notification({text:"Invalid syntax. It must be 'name[:type]'.",type:"error"}),!1):2==elements.length&&"array"!=elements[1]&&"object"!=elements[1]?(notification({text:"Only arrays and objects are allowed.",type:"error"}),!1):(field.remove(),"undefined"==typeof blockID?blockID=elements[0]:blockID=blockID+"["+elements[0]+"]",1==elements.length?(newItem.attr("id","block-"+blockID),newItem.append(' '),newItem.prepend(' ')):(type="","array"==elements[1]?type="array":type="object",template='',template=template.replace("${blockID}",blockID),template=template.replace("${elements[0]}",elements[0]),template=template.replace("${type}",type),newItem.after(template),newItem.remove(),console.log('"'+blockID+'" block of type "'+type+'" added.')),!1))):void 0})}return!1}),$("#content").on("click",".delete",function(a){return a.preventDefault(),button=$(this),name=button.parent().parent().attr("for")||button.parent().parent().attr("id")||button.parent().parent().parent().attr("id"),name=name.replace(/\[/,"\\["),name=name.replace(/\]/,"\\]"),console.log(name),$('label[for="'+name+'"]').fadeOut().remove(),$("#"+name).fadeOut().remove(),!1})}),$.noty.themes.admin={name:"admin",helpers:{},modal:{css:{position:"fixed",width:"100%",height:"100%",backgroundColor:"#000",zIndex:1e4,opacity:.6,display:"none",left:0,top:0}}},$.noty.defaults={layout:"topRight",theme:"admin",dismissQueue:!0,animation:{open:"animated bounceInRight",close:"animated fadeOut",easing:"swing",speed:500},timeout:!1,force:!1,modal:!1,maxVisible:5,killer:!1,closeWith:["click"],callback:{onShow:function(){},afterShow:function(){},onClose:function(){},afterClose:function(){},onCloseClick:function(){}},buttons:!1},notification=function(a){var b;switch(a.type){case"success":b='';break;case"error":b='';break;case"warning":b='';break;case"information":b='';break;default:b=''}var c={template:'
'+b+'
'};if(a=$.extend({},c,a),noty(a),!document.cookie.replace(/(?:(?:^|.*;\s*)stickynoties\s*\=\s*([^;]*).*$)|^.*$/,"$1")&&!a.timeout){var d=new Date;d.setDate(d.getDate()+365),document.cookie="stickynoties=true; expires="+d.toUTCString+"; path=/",notification({text:"Some notifications are sticky. If it doesn't go away, click to dismiss it.",type:"information"})}};
\ No newline at end of file
+$(document).ready(function(){$("#logout").click(function(a){return a.preventDefault(),$.ajax({type:"GET",url:"/admin",async:!1,username:"username",password:"password",headers:{Authorization:"Basic xxx"}}).fail(function(){window.location="/"}),!1}),$(document).pjax("a[data-pjax]","#content")}),$(document).on("ready pjax:end",function(){function a(){this.style.height="5px",this.style.height=this.scrollHeight+"px"}return $("#content").off(),document.title=document.getElementById("site-title").innerHTML,$("textarea").each(a),$("textarea").keyup(a),$(window).resize(function(){$("textarea").each(a)}),$("main").hasClass("browse")&&$(document).trigger("page:browse"),$(".editor")[0]&&$(document).trigger("page:editor"),!1}),$(document).on("page:browse",function(){var a="#foreground",b=new Object;b.selector="form#delete",b.form=$(b.selector),b.row="",b.button="",b.url="",$("#content").on("click",".delete",function(c){return c.preventDefault(),b.button=$(this),b.row=$(this).parent().parent(),$(a).fadeIn(200),b.url=b.row.find(".filename").text(),b.form.find("span").text(b.url),b.form.fadeIn(200),!1}),$("#content").on("submit",b.selector,function(c){c.preventDefault();var d=new XMLHttpRequest;return d.open("DELETE",b.button.data("file")),d.send(),d.onreadystatechange=function(){if(4==d.readyState){var c=JSON.parse(d.responseText),e="success",f=5e3;$(a).fadeOut(200),b.form.fadeOut(200),b.row.fadeOut(200),200!=d.status&&(e="error",f=!1),notification({text:c.message,type:e,timeout:f})}},!1}),$("#content").on("change",'input[type="file"]',function(a){a.preventDefault(),files=a.target.files;var b=new FormData;return $.each(files,function(a,c){b.append(a,c)}),$.ajax({url:window.location.pathname,type:"POST",data:b,cache:!1,dataType:"json",headers:{"X-Upload":"true"},processData:!1,contentType:!1}).done(function(a){notification({text:"File(s) uploaded successfully.",type:"success",timeout:5e3}),$.pjax({url:window.location.pathname,container:"#content"})}).fail(function(a){notification({text:"Something went wrong.",type:"error"}),console.log(a)}),!1}),$("#content").on("click","#upload",function(a){return a.preventDefault(),$('.actions input[type="file"]').click(),!1});var c=new Object;c.selector="form#new",c.form=$(c.selector),c.input=c.selector+' input[type="text"]',c.button="",c.url="",$("#content").on("click",".new",function(b){return b.preventDefault(),c.button=$(this),$(a).fadeIn(200),c.form.fadeIn(200),!1}),$("#content").on("keypress",c.input,function(a){return 13==a.keyCode?(a.preventDefault(),$(c.form).submit(),!1):void 0}),$("#content").on("submit",c.selector,function(a){a.preventDefault();var b=c.form.find('input[type="text"]').val(),d=b.split(":"),e="",f="";if(""==b)return notification({text:"You have to write something. If you want to close the box, click the button again.",type:"warning",timeout:5e3}),!1;if(1==d.length)e=b;else{if(2!=d.length)return notification({text:"Hmm... I don't understand you. Try writing something like 'name[:archetype]'.",type:"error"}),!1;e=d[0],f=d[1]}var g={filename:e,archetype:f},h=new XMLHttpRequest;return h.open("POST",window.location.pathname),h.setRequestHeader("Content-Type","application/json;charset=UTF-8"),h.send(JSON.stringify(g)),h.onreadystatechange=function(){if(4==h.readyState)if(200==h.status){var a=JSON.parse(h.responseText);notification({text:"File created successfully.",type:"success",timeout:5e3}),$.pjax({url:a.Location,container:"#content"})}else notification({text:"Something went wrong.",type:"error"}),console.log(h.responseText)},!1});var d=new Object;d.selector="form#rename",d.form=$(d.selector),d.input=d.selector+' input[type="text"]',d.button="",d.url="",$("#content").on("click",".rename",function(b){return b.preventDefault(),d.button=$(this),$(a).fadeIn(200),d.url=$(this).parent().parent().find(".filename").text(),d.form.fadeIn(200),d.form.find("span").text(d.url),d.form.find('input[type="text"]').val(d.url),!1}),$("#content").on("keypress",d.input,function(a){return 13==a.keyCode?(a.preventDefault(),$(d.form).submit(),!1):void 0}),$("#content").on("submit",d.selector,function(a){a.preventDefault();var b=d.form.find('input[type="text"]').val();if(""===b)return!1;"/"!=b.substring(0,1)&&(b=window.location.pathname.replace("/admin/browse/","")+"/"+b);var c={filename:b},e=new XMLHttpRequest;return e.open("PUT",d.url),e.setRequestHeader("Content-Type","application/json;charset=UTF-8"),e.send(JSON.stringify(c)),e.onreadystatechange=function(){if(4==e.readyState){var a=JSON.parse(e.responseText),b="success",c=5e3;200!=e.status&&(b="error",c=!1),$.pjax({url:window.location.pathname,container:"#content"}),notification({text:a.message,type:b,timeout:c})}},!1});var e=new Object;e.selector="form#git",e.form=$(e.selector),e.input=e.selector+' input[type="text"]',$("#content").on("click","button.git",function(b){return b.preventDefault(),$(a).fadeIn(200),e.form.fadeIn(200),!1}),$("#content").on("keypress",e.input,function(a){return 13==a.keyCode?(a.preventDefault(),$(e.form).submit(),!1):void 0}),$("#content").on("submit",e.selector,function(a){a.preventDefault();var b=e.form.find('input[type="text"]').val();if(""==b)return notification({text:"You have to write something. If you want to close the box, click outside of the box.",type:"warning",timeout:5e3}),!1;var c=new XMLHttpRequest;return c.open("POST","/admin/git"),c.setRequestHeader("Content-Type","application/json;charset=UTF-8"),c.send(JSON.stringify({command:b})),c.onreadystatechange=function(){if(4==c.readyState){var a=JSON.parse(c.responseText);200==c.status?notification({text:a.message,type:"success"}):notification({text:a.message,type:"error"})}},!1}),$("#content").on("click",".close",function(b){return b.preventDefault(),$(this).parent().parent().fadeOut(200),$(a).click(),!1}),$("#content").on("click",a,function(f){return f.preventDefault(),$(a).fadeOut(200),c.form.fadeOut(200),d.form.fadeOut(200),b.form.fadeOut(200),e.form.fadeOut(200),!1})}),$(document).on("page:editor",function(){var a=$(".editor"),b=$("#editor-preview"),c=$("#editor-source");if(a.hasClass("complete")&&$("#content").on("keyup","#site-title",function(){$(".frontmatter #title").val($(this).val())}),!a.hasClass("frontmatter-only")){var d=$("#editor-source").data("mode"),e=$('textarea[name="content"]').hide(),f=ace.edit("editor-source");f.getSession().setMode("ace/mode/"+d),f.getSession().setValue(e.val()),f.getSession().on("change",function(){e.val(f.getSession().getValue())}),f.setOptions({wrap:!0,maxLines:1/0,theme:"ace/theme/github",showPrintMargin:!1,fontSize:"1em",minLines:20}),$("#content").on("click","#see-source",function(a){a.preventDefault(),b.hide(),c.fadeIn(),$(this).addClass("active"),$("#see-preview").removeClass("active"),$("#see-preview").data("previewing","false")}),$("#content").on("click","#see-preview",function(a){if(a.preventDefault(),"true"==$(this).data("previewing"))b.hide(),c.fadeIn(),$(this).removeClass("active"),$("#see-source").addClass("active"),$(this).data("previewing","false");else{var d=new showdown.Converter,e=f.getValue(),g=d.makeHtml(e);c.hide(),b.html(g).fadeIn(),$(this).addClass("active"),$("#see-source").removeClass("active"),$(this).data("previewing","true")}return!1})}$("#content").on("keypress","input",function(a){return 13==a.keyCode?(a.preventDefault(),$('input[value="Save"]').focus().click(),!1):void 0}),$("#content").on("submit","form",function(d){d.preventDefault(),a.hasClass("frontmatter-only")||(b.html("").fadeOut(),$("#see-preview").data("previewing","false"),c.fadeIn());var e=JSON.stringify($(this).serializeJSON()),f=$(this).find("input[type=submit]:focus"),g=new XMLHttpRequest;return g.open("POST",window.location),g.setRequestHeader("Content-Type","application/json;charset=UTF-8"),g.setRequestHeader("X-Regenerate",f.data("regenerate")),g.setRequestHeader("X-Schedule",f.data("schedule")),g.setRequestHeader("X-Content-Type",f.data("type")),g.send(e),g.onreadystatechange=function(){4==g.readyState&&(200==g.status?notification({text:f.data("message"),type:"success",timeout:5e3}):(notification({text:"Something went wrong.",type:"error"}),console.log(g.responseText)))},!1}),$("#content").on("click",".add",function(a){if(a.preventDefault(),defaultID="lorem-ipsum-sin-dolor-amet",newItem=$("#"+defaultID),newItem.length&&newItem.remove(),block=$(this).parent().parent(),blockType=block.data("type"),blockID=block.attr("id"),"array"==blockType&&(newID=blockID+"[]",input=blockID,input=input.replace(/\[/,"\\["),input=input.replace(/\]/,"\\]"),block.append('
div").length+'" data-type="array-item">
'),console.log("New array item added.")),block.is("div")&&block.hasClass("frontmatter")&&(block=$(".blocks"),blockType="object"),"object"==blockType){if(block.append(''),newItem=$("#"+defaultID),newItem.html(''),field=$("#name-"+defaultID),!document.cookie.replace(/(?:(?:^|.*;\s*)placeholdertip\s*\=\s*([^;]*).*$)|^.*$/,"$1")){var b=new Date;b.setDate(b.getDate()+365),document.cookie="placeholdertip=true; expires="+b.toUTCString+"; path=/",notification({text:'Write the field name and then press enter. If you want to create an array or an object, end the name with ":array" or ":object".',type:"information"})}$(field).keypress(function(a){return 13==a.which?(a.preventDefault(),value=field.val(),""==value?(newItem.remove(),!1):(elements=value.split(":"),elements.length>2?(notification({text:"Invalid syntax. It must be 'name[:type]'.",type:"error"}),!1):2==elements.length&&"array"!=elements[1]&&"object"!=elements[1]?(notification({text:"Only arrays and objects are allowed.",type:"error"}),!1):(field.remove(),"undefined"==typeof blockID?blockID=elements[0]:blockID=blockID+"["+elements[0]+"]",1==elements.length?(newItem.attr("id","block-"+blockID),newItem.append(' '),newItem.prepend(' ')):(type="","array"==elements[1]?type="array":type="object",template='',template=template.replace("${blockID}",blockID),template=template.replace("${elements[0]}",elements[0]),template=template.replace("${type}",type),newItem.after(template),newItem.remove(),console.log('"'+blockID+'" block of type "'+type+'" added.')),!1))):void 0})}return!1}),$("#content").on("click",".delete",function(a){return a.preventDefault(),button=$(this),name=button.parent().parent().attr("for")||button.parent().parent().attr("id")||button.parent().parent().parent().attr("id"),name=name.replace(/\[/,"\\["),name=name.replace(/\]/,"\\]"),console.log(name),$('label[for="'+name+'"]').fadeOut().remove(),$("#"+name).fadeOut().remove(),!1})}),$.noty.themes.admin={name:"admin",helpers:{},modal:{css:{position:"fixed",width:"100%",height:"100%",backgroundColor:"#000",zIndex:1e4,opacity:.6,display:"none",left:0,top:0}}},$.noty.defaults={layout:"topRight",theme:"admin",dismissQueue:!0,animation:{open:"animated bounceInRight",close:"animated fadeOut",easing:"swing",speed:500},timeout:!1,force:!1,modal:!1,maxVisible:5,killer:!1,closeWith:["click"],callback:{onShow:function(){},afterShow:function(){},onClose:function(){},afterClose:function(){},onCloseClick:function(){}},buttons:!1},notification=function(a){var b;switch(a.type){case"success":b='';break;case"error":b='';break;case"warning":b='';break;case"information":b='';break;default:b=''}var c={template:'
'+b+'
'};if(a=$.extend({},c,a),noty(a),!document.cookie.replace(/(?:(?:^|.*;\s*)stickynoties\s*\=\s*([^;]*).*$)|^.*$/,"$1")&&!a.timeout){var d=new Date;d.setDate(d.getDate()+365),document.cookie="stickynoties=true; expires="+d.toUTCString+"; path=/",notification({text:"Some notifications are sticky. If it doesn't go away, click to dismiss it.",type:"information"})}};
\ No newline at end of file
diff --git a/assets/src/js/browse.js b/assets/src/js/browse.js
index 9b6300bd..5c12d8ed 100644
--- a/assets/src/js/browse.js
+++ b/assets/src/js/browse.js
@@ -29,22 +29,24 @@ $(document).on('page:browse', function() {
request.send();
request.onreadystatechange = function() {
if (request.readyState == 4) {
- if (request.status == 200) {
- $(foreground).fadeOut(200);
- remove.form.fadeOut(200);
- remove.row.fadeOut(200);
- notification({
- text: remove.button.data("message"),
- type: 'success',
- timeout: 5000
- });
- } else {
- notification({
- text: 'Something went wrong.',
- type: 'error'
- });
- console.log(request.responseText);
+ var response = JSON.parse(request.responseText),
+ type = "success",
+ timeout = 5000;
+
+ $(foreground).fadeOut(200);
+ remove.form.fadeOut(200);
+ remove.row.fadeOut(200);
+
+ if (request.status != 200) {
+ type = "error";
+ timeout = false;
}
+
+ notification({
+ text: response.message,
+ type: type,
+ timeout: timeout
+ });
}
}
@@ -244,23 +246,25 @@ $(document).on('page:browse', function() {
request.send(JSON.stringify(content));
request.onreadystatechange = function() {
if (request.readyState == 4) {
- if (request.status == 200) {
- $.pjax({
- url: window.location.pathname,
- container: '#content'
- });
- notification({
- text: rename.button.data("message"),
- type: 'success',
- timeout: 5000
- });
- } else {
- notification({
- text: 'Something went wrong.',
- type: 'error'
- });
- console.log(request.responseText);
+ var response = JSON.parse(request.responseText),
+ type = "success",
+ timeout = 5000;
+
+ if (request.status != 200) {
+ type = "error";
+ timeout = false;
}
+
+ $.pjax({
+ url: window.location.pathname,
+ container: '#content'
+ });
+
+ notification({
+ text: response.message,
+ type: type,
+ timeout: timeout
+ });
}
}
@@ -313,22 +317,17 @@ $(document).on('page:browse', function() {
request.onreadystatechange = function() {
if (request.readyState == 4) {
var data = JSON.parse(request.responseText);
- var type = "success"
- var timeout = 5000
if (request.status == 200) {
- if (data.success == "false") {
- type = "error"
- timeout = false
- }
-
notification({
text: data.message,
- type: type,
- timeout: timeout
+ type: "success"
});
} else {
- console.log(request.responseText)
+ notification({
+ text: data.message,
+ type: "error"
+ });
}
}
}
@@ -354,4 +353,4 @@ $(document).on('page:browse', function() {
git.form.fadeOut(200);
return false;
});
-});
+});
\ No newline at end of file
diff --git a/browse/delete.go b/browse/delete.go
index 6e008ce3..54eafb1e 100644
--- a/browse/delete.go
+++ b/browse/delete.go
@@ -6,6 +6,7 @@ import (
"strings"
"github.com/hacdias/caddy-hugo/config"
+ "github.com/hacdias/caddy-hugo/utils"
)
// DELETE handles the delete requests on browse pages
@@ -16,25 +17,26 @@ func DELETE(w http.ResponseWriter, r *http.Request, c *config.Config) (int, erro
path = strings.TrimSuffix(path, "/")
path = c.Path + path
+ message := "File deleted."
+
// Check if the file or directory exists
if stat, err := os.Stat(path); err == nil {
var err error
// If it's dir, remove all of the content inside
if stat.IsDir() {
err = os.RemoveAll(path)
+ message = "Folder deleted."
} else {
err = os.Remove(path)
}
// Check for errors
if err != nil {
- return 500, err
+ return utils.RespondJSON(w, "Something went wrong.", 500, nil)
}
} else {
- return 404, nil
+ return utils.RespondJSON(w, "File not found.", 404, nil)
}
- w.Header().Set("Content-Type", "application/json")
- w.Write([]byte("{}"))
- return 200, nil
+ return utils.RespondJSON(w, message, 200, nil)
}
diff --git a/browse/post.go b/browse/post.go
index cce760c1..a16863f9 100644
--- a/browse/post.go
+++ b/browse/post.go
@@ -3,8 +3,6 @@ package browse
import (
"bytes"
"encoding/json"
- "errors"
- "fmt"
"io"
"mime/multipart"
"net/http"
@@ -38,11 +36,11 @@ func POST(w http.ResponseWriter, r *http.Request, c *config.Config) (int, error)
// Check if filename and archetype are specified in
// the request
if _, ok := info["filename"]; !ok {
- return http.StatusBadRequest, errors.New("Filename not specified.")
+ return utils.RespondJSON(w, "Filename not specified.", 500, nil)
}
if _, ok := info["archetype"]; !ok {
- return http.StatusBadRequest, errors.New("Archtype not specified.")
+ return utils.RespondJSON(w, "Archtype not specified.", 500, nil)
}
// Sanitize the file name path
@@ -64,7 +62,7 @@ func POST(w http.ResponseWriter, r *http.Request, c *config.Config) (int, error)
}
if err := utils.RunCommand(c.Hugo, args, c.Path); err != nil {
- return http.StatusInternalServerError, err
+ return utils.RespondJSON(w, "Something went wrong.", 500, err)
}
} else {
var err error
@@ -79,23 +77,22 @@ func POST(w http.ResponseWriter, r *http.Request, c *config.Config) (int, error)
}
if err != nil {
- return http.StatusInternalServerError, err
+ return utils.RespondJSON(w, "Something went wrong.", 500, err)
}
}
- fmt.Println(url)
-
w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(200)
w.Write([]byte("{\"Location\": \"" + url + "\"}"))
- return http.StatusOK, nil
+ return 0, nil
}
func upload(w http.ResponseWriter, r *http.Request, c *config.Config) (int, error) {
// Parse the multipart form in the request
err := r.ParseMultipartForm(100000)
if err != nil {
- return http.StatusInternalServerError, err
+ return utils.RespondJSON(w, "Something went wrong.", 500, err)
}
// For each file header in the multipart form
@@ -105,25 +102,24 @@ func upload(w http.ResponseWriter, r *http.Request, c *config.Config) (int, erro
// Open the first file
var infile multipart.File
if infile, err = hdr.Open(); nil != err {
- return http.StatusInternalServerError, err
+ return utils.RespondJSON(w, "Something went wrong.", 500, err)
}
// Create the file
var outfile *os.File
if outfile, err = os.Create(c.Path + r.URL.Path + hdr.Filename); nil != err {
- return http.StatusInternalServerError, err
+ return utils.RespondJSON(w, "Something went wrong.", 500, err)
}
// Copy the file content
if _, err = io.Copy(outfile, infile); nil != err {
- return http.StatusInternalServerError, err
+ return utils.RespondJSON(w, "Something went wrong.", 500, err)
}
defer outfile.Close()
}
}
- w.Header().Set("Content-Type", "application/json")
- w.Write([]byte("{}"))
- return http.StatusOK, nil
+ return utils.RespondJSON(w, "", 200, nil)
+ return 0, nil
}
diff --git a/browse/put.go b/browse/put.go
index ad7e9de5..28441d31 100644
--- a/browse/put.go
+++ b/browse/put.go
@@ -3,12 +3,12 @@ package browse
import (
"bytes"
"encoding/json"
- "errors"
"net/http"
"os"
"strings"
"github.com/hacdias/caddy-hugo/config"
+ "github.com/hacdias/caddy-hugo/utils"
)
// PUT handles the HTTP PUT request for all /admin/browse related requests.
@@ -31,7 +31,7 @@ func PUT(w http.ResponseWriter, r *http.Request, c *config.Config) (int, error)
// Check if filename and archetype are specified in
// the request
if _, ok := info["filename"]; !ok {
- return 400, errors.New("Filename not specified.")
+ return utils.RespondJSON(w, "Filename not specified.", 400, nil)
}
// Sanitize the file name path
@@ -42,10 +42,8 @@ func PUT(w http.ResponseWriter, r *http.Request, c *config.Config) (int, error)
// Renames the file/folder
if err := os.Rename(old, new); err != nil {
- return 500, err
+ return utils.RespondJSON(w, "Something went wrong.", 500, err)
}
- w.Header().Set("Content-Type", "application/json")
- w.Write([]byte("{}"))
- return 200, nil
+ return utils.RespondJSON(w, "File renamed.", 200, nil)
}
diff --git a/git/post.go b/git/post.go
index 21a5bfec..2b787d71 100644
--- a/git/post.go
+++ b/git/post.go
@@ -12,9 +12,10 @@ import (
// POST handles the POST method on GIT page which is only an API.
func POST(w http.ResponseWriter, r *http.Request, c *config.Config) (int, error) {
+ // Check if git is installed on the computer
if _, err := exec.LookPath("git"); err != nil {
- jsonMessage(w, "Git is not installed on your computer.", false)
- return 200, nil
+ jsonMessage(w, "Git is not installed on your computer.", 500)
+ return 0, nil
}
// Get the JSON information sent using a buffer
@@ -25,9 +26,10 @@ func POST(w http.ResponseWriter, r *http.Request, c *config.Config) (int, error)
var info map[string]interface{}
json.Unmarshal(buff.Bytes(), &info)
+ // Check if command was sent
if _, ok := info["command"]; !ok {
- jsonMessage(w, "Command not specified.", false)
- return 200, nil
+ jsonMessage(w, "Command not specified.", 500)
+ return 0, nil
}
command := info["command"].(string)
@@ -38,8 +40,8 @@ func POST(w http.ResponseWriter, r *http.Request, c *config.Config) (int, error)
}
if len(args) == 0 {
- jsonMessage(w, "Command not specified.", false)
- return 200, nil
+ jsonMessage(w, "Command not specified.", 500)
+ return 0, nil
}
cmd := exec.Command("git", args...)
@@ -47,26 +49,25 @@ func POST(w http.ResponseWriter, r *http.Request, c *config.Config) (int, error)
output, err := cmd.CombinedOutput()
if err != nil {
- jsonMessage(w, err.Error(), false)
- return 200, nil
+ jsonMessage(w, err.Error(), 500)
+ return 0, nil
}
- jsonMessage(w, string(output), true)
- return http.StatusOK, nil
+ jsonMessage(w, string(output), 200)
+ return 0, nil
}
type jsonMSG struct {
Message string `json:"message"`
- Success bool `json:"success"`
}
-func jsonMessage(w http.ResponseWriter, message string, success bool) {
+func jsonMessage(w http.ResponseWriter, message string, code int) {
msg := &jsonMSG{
Message: message,
- Success: success,
}
m, _ := json.Marshal(msg)
w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(code)
w.Write(m)
}
diff --git a/hugo.go b/hugo.go
index de035093..97767518 100644
--- a/hugo.go
+++ b/hugo.go
@@ -123,7 +123,7 @@ func (h CaddyHugo) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error
// Serve the static assets
if page == "assets" {
- return serveAssets(w, r)
+ code, err = serveAssets(w, r)
}
// Browse page
@@ -151,6 +151,22 @@ func (h CaddyHugo) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error
log.Panic(err)
}
+ /*
+
+ // Create the functions map, then the template, check for erros and
+ // execute the template if there aren't errors
+ functions := template.FuncMap{
+ "Defined": utils.Defined,
+ }
+
+ switch code {
+ case 404:
+ tpl, _ := utils.GetTemplate(r, functions, "404")
+ tpl.Execute(w, nil)
+ code = 200
+ err = nil
+ } */
+
return code, err
}
diff --git a/templates/404.tmpl b/templates/404.tmpl
new file mode 100644
index 00000000..4de316a2
--- /dev/null
+++ b/templates/404.tmpl
@@ -0,0 +1,5 @@
+{{ define "content" }}
+
+