add json validation to file inputs in UI and minify before upload (#5248)

* also updated edit.htm to do the same
This commit is contained in:
Damian Schneider
2026-01-30 08:18:17 +01:00
committed by GitHub
parent 1031e70d70
commit f19d29cd64
2 changed files with 28 additions and 22 deletions

View File

@@ -137,16 +137,26 @@ function showToast(text, error = false) {
x.style.animation = 'none';
timeout = setTimeout(function(){ x.className = x.className.replace("show", ""); }, 2900);
}
function uploadFile(fileObj, name) {
async function uploadFile(fileObj, name, callback) {
let file = fileObj.files?.[0]; // get first file, "?"" = optional chaining in case no file is selected
if (!file) { callback?.(false); return; }
if (/\.json$/i.test(name)) { // same as name.toLowerCase().endsWith('.json')
try {
const minified = JSON.stringify(JSON.parse(await file.text())); // validate and minify JSON
file = new Blob([minified], { type: file.type || "application/json" });
} catch (err) {
if (!confirm("JSON invalid. Continue?")) { callback?.(false); return; }
// proceed with original file if invalid but user confirms
}
}
var req = new XMLHttpRequest();
req.addEventListener('load', function(){showToast(this.responseText,this.status >= 400)});
req.addEventListener('error', function(e){showToast(e.stack,true);});
req.addEventListener('load', function(){showToast(this.responseText,this.status >= 400); if(callback) callback(this.status < 400);});
req.addEventListener('error', function(e){showToast("Upload failed",true); if(callback) callback(false);});
req.open("POST", "/upload");
var formData = new FormData();
formData.append("data", fileObj.files[0], name);
formData.append("data", file, name);
req.send(formData);
fileObj.value = '';
return false;
}
// connect to WebSocket, use parent WS or open new, callback function gets passed the new WS object
function connectWs(onOpen) {

View File

@@ -134,6 +134,7 @@ loadFiles('common.js', -1, () => {
});
});
});
var QueuedRequester = function(){ this.q=[]; this.r=false; this.x=null; }
QueuedRequester.prototype = {
_request: function(req){
@@ -432,7 +433,7 @@ function createEditor(element,file){
// Check filename from text field or current file
var pathField = gId("filepath");
var filename = (pathField && pathField.value) ? pathField.value : currentFile;
aceEditor.session.setMode(filename && filename.toLowerCase().endsWith('.json') ? "ace/mode/json" : "ace/mode/text");
aceEditor.session.setMode(filename && (/\.json$/i.test(filename)) ? "ace/mode/json" : "ace/mode/text"); // same as filename.toLowerCase().endsWith('.json')
}
// Try to initialize Ace editor if available
@@ -488,7 +489,7 @@ function createEditor(element,file){
var filename = pathField ? pathField.value : currentFile;
var border = "2px solid #333";
if (filename && filename.toLowerCase().endsWith('.json')) {
if (filename && (/\.json$/i.test(filename))) { // same as filename.toLowerCase().endsWith('.json')
try {
JSON.parse(ta.value);
} catch(e) {
@@ -499,23 +500,19 @@ function createEditor(element,file){
};
function saveFile(filename,data){
var finalData = data;
// Minify JSON files before upload
if (filename.toLowerCase().endsWith('.json')) {
var outdata = data;
if (/\.json$/i.test(filename)) { // same as filename.toLowerCase().endsWith('.json')
try {
finalData = JSON.stringify(JSON.parse(data));
outdata = JSON.stringify(JSON.parse(data)); // validate and minify
} catch(e) {
alert("Invalid JSON! Please fix syntax.");
alert("Invalid JSON! Please fix.");
return;
}
}
var fd=new FormData();
fd.append("file",new Blob([finalData],{type:"text/plain"}),filename);
req.add("POST","/upload",fd,function(st,resp){
if (st!=200) alert("ERROR "+st+": "+resp);
else {
showToast("File saved");
uploadFile({files: [new Blob([outdata], {type:"text/plain"})]}, filename, function(s) {
if(s) {
refreshTree();
loadFile(filename); // (re)load if saved successfully to update formating or show file content
}
});
}
@@ -526,9 +523,9 @@ function createEditor(element,file){
gId("preview").style.display="none";
gId("editor").style.display="flex";
if (st==200) {
if (filename.toLowerCase().endsWith('.json')) {
if ((/\.json$/i.test(filename))) { // same as filename.toLowerCase().endsWith('.json')
try {
setContent(filename.toLowerCase().includes('ledmap') ? prettyLedmap(resp) : JSON.stringify(JSON.parse(resp), null, 2));
setContent(/ledmap/i.test(filename) ? prettyLedmap(resp) : JSON.stringify(JSON.parse(resp), null, 2)); // pretty-print ledmap files (i.e. if file name includes "ledmap" case-insensitive)
} catch(e) {
setContent(resp);
}
@@ -555,8 +552,7 @@ function createEditor(element,file){
}
if (!fn.startsWith("/")) fn = "/" + fn;
currentFile = fn; // Update current file
saveFile(fn, getContent());
loadFile(fn);
saveFile(fn, getContent())
},
loadText:function(fn){
currentFile=fn;