216 lines
7.1 KiB
JavaScript
Vendored
216 lines
7.1 KiB
JavaScript
Vendored
var decodeEntities = (function() {
|
||
// this prevents any overhead from creating the object each time
|
||
var element = document.createElement('div');
|
||
|
||
function decodeHTMLEntities (str) {
|
||
if(str && typeof str === 'string') {
|
||
// strip script/html tags
|
||
str = str.replace(/<script[^>]*>([\S\s]*?)<\/script>/gmi, '');
|
||
str = str.replace(/<\/?\w(?:[^"'>]|"[^"]*"|'[^']*')*>/gmi, '');
|
||
element.innerHTML = str;
|
||
str = element.textContent;
|
||
element.textContent = '';
|
||
}
|
||
|
||
return str;
|
||
}
|
||
|
||
return decodeHTMLEntities;
|
||
})();
|
||
|
||
$(document).ready(function () {
|
||
|
||
// Export content as HTML
|
||
$('#editDownloadHtml').click(function () {
|
||
var htmlContent = $('#editFrameTest');
|
||
downloadFile(htmlContent, 'content.html', 'text/html');
|
||
});
|
||
|
||
// Export content as plain text
|
||
$('#editDownloadText').click(function () {
|
||
//var plainTextContent = $('#editor').trumbowyg('html').replace(/<[^>]*>/g, '');
|
||
var plainTextContent = decodeEntities($('#editFrameTest'));
|
||
downloadFile(plainTextContent, 'content.txt', 'text/plain');
|
||
});
|
||
|
||
// Quit back to Filemanager.
|
||
$('#editQuit').click(function () {
|
||
history.back();
|
||
});
|
||
|
||
// Save buffer and continue editting.
|
||
$('#editSave').click(function () {
|
||
saveFile();
|
||
});
|
||
|
||
// Save buffer and exit.
|
||
$('#editExit').click(function () {
|
||
saveFile();
|
||
history.back();
|
||
});
|
||
|
||
// Save buffer and apply configuration.
|
||
$('#editApply').click(function () {
|
||
const statusDiv = document.getElementById('saveStatus');
|
||
|
||
// Updated changes.
|
||
saveFile();
|
||
|
||
// Reload ESP32, if the config has changed then it will initiate an RP2350 config reload.
|
||
setTimeout(function() {
|
||
const statusDiv = document.getElementById('saveStatus');
|
||
if (statusDiv) {
|
||
statusDiv.style.backgroundColor = "#fff3cd";
|
||
statusDiv.style.color = "#856404";
|
||
statusDiv.innerHTML = "Requesting ESP32 reload configuration,,,)";
|
||
}
|
||
setTimeout(function() {
|
||
window.location.href="/reboot/esp32";
|
||
}, 2000);
|
||
}, 2000);
|
||
});
|
||
|
||
// Method to save the contents of the textarea buffer into a file on the SD card (AJAX style)
|
||
async function saveFile() {
|
||
const editFileInput = document.getElementById('editFile');
|
||
const textarea = document.getElementById('editFrameText');
|
||
const statusDiv = document.getElementById('saveStatus');
|
||
|
||
if (!editFileInput || !textarea) {
|
||
alert("Editor elements not found!");
|
||
return;
|
||
}
|
||
|
||
let fullInput = editFileInput.value.trim();
|
||
if (!fullInput) {
|
||
alert("No file path/filename specified!");
|
||
return;
|
||
}
|
||
|
||
// Clean path (same logic as before)
|
||
let cleanedPath = fullInput
|
||
.replace(/^\/(sdcard|sdpath)\/?/i, '')
|
||
.replace(/^sd(card|path)\/?/i, '')
|
||
.replace(/^[\\/]+/, '');
|
||
|
||
if (!cleanedPath) {
|
||
alert("No valid path after removing SD prefix!");
|
||
return;
|
||
}
|
||
|
||
// Split → dir + filename
|
||
let dirPart = "";
|
||
let filenameOnly = cleanedPath;
|
||
const lastSlash = Math.max(cleanedPath.lastIndexOf('/'), cleanedPath.lastIndexOf('\\'));
|
||
|
||
if (lastSlash >= 0) {
|
||
dirPart = cleanedPath.substring(0, lastSlash).replace(/^[\\/]+|[\\/]+$/g, '');
|
||
filenameOnly = cleanedPath.substring(lastSlash + 1);
|
||
}
|
||
|
||
if (!filenameOnly) {
|
||
alert("No valid filename found!");
|
||
return;
|
||
}
|
||
if (filenameOnly.includes(' ')) {
|
||
alert("Filename cannot contain spaces!");
|
||
return;
|
||
}
|
||
|
||
// Prepare UI for saving
|
||
const saveButton = document.getElementById('editSave');
|
||
if (saveButton) saveButton.disabled = true;
|
||
textarea.disabled = true;
|
||
editFileInput.disabled = true;
|
||
|
||
if (statusDiv) {
|
||
statusDiv.style.backgroundColor = "#fff3cd";
|
||
statusDiv.style.color = "#856404";
|
||
statusDiv.innerHTML = "Saving... (creating backup if needed)";
|
||
}
|
||
|
||
// Attempt backup. Keep same name as server will rename to <filename>;<next unique number>
|
||
let backupDone = false;
|
||
let backupMsg = "";
|
||
|
||
try {
|
||
const renameParams = new URLSearchParams();
|
||
if (dirPart) renameParams.set("dir", dirPart);
|
||
renameParams.set("oldname", filenameOnly);
|
||
renameParams.set("name", filenameOnly);
|
||
|
||
const renameUrl = `/data/rename?${renameParams.toString()}`;
|
||
const renameRes = await fetch(renameUrl, { method: "GET" });
|
||
|
||
backupDone = renameRes.ok;
|
||
backupMsg = backupDone ? "Backup created. " : "No backup created (may already exist). ";
|
||
} catch (err) {
|
||
console.warn("Backup rename failed:", err);
|
||
backupMsg = "Backup attempt failed. ";
|
||
}
|
||
|
||
// Save the current content
|
||
const content = textarea.value;
|
||
|
||
let saveUrl = `/data/upload/${encodeURIComponent(filenameOnly)}`;
|
||
if (dirPart) {
|
||
saveUrl += `?dir=${encodeURIComponent(dirPart)}`;
|
||
}
|
||
|
||
try {
|
||
const saveRes = await fetch(saveUrl, {
|
||
method: "POST",
|
||
headers: {
|
||
"Content-Type": "text/plain; charset=utf-8"
|
||
},
|
||
body: content
|
||
});
|
||
|
||
if (!saveRes.ok) {
|
||
const errorText = await saveRes.text().catch(() => "(no details)");
|
||
throw new Error(`Save failed (${saveRes.status}) – ${errorText}`);
|
||
}
|
||
|
||
// Success path
|
||
if (statusDiv) {
|
||
statusDiv.style.backgroundColor = "#d4edda";
|
||
statusDiv.style.color = "#155724";
|
||
statusDiv.innerHTML = `✓ Saved successfully. ${backupMsg}`;
|
||
}
|
||
|
||
// Optional: small delay then fade or clear status
|
||
setTimeout(() => {
|
||
if (statusDiv) statusDiv.style.opacity = "0.7";
|
||
}, 2000);
|
||
|
||
} catch (err) {
|
||
console.error("Save error:", err);
|
||
if (statusDiv) {
|
||
statusDiv.style.backgroundColor = "#f8d7da";
|
||
statusDiv.style.color = "#721c24";
|
||
statusDiv.innerHTML = `✗ Save failed: ${err.message}`;
|
||
}
|
||
alert("Save failed!\n" + err.message); // keep alert as fallback
|
||
|
||
} finally {
|
||
// Re-enable controls
|
||
if (saveButton) saveButton.disabled = false;
|
||
textarea.disabled = false;
|
||
editFileInput.disabled = false;
|
||
}
|
||
}
|
||
|
||
// Function to download file
|
||
function downloadFile(content, filename, contentType) {
|
||
var blob = new Blob([ content ], { type: contentType });
|
||
var url = window.URL.createObjectURL(blob);
|
||
var a = document.createElement('a');
|
||
a.href = url;
|
||
a.download = filename;
|
||
document.body.appendChild(a);
|
||
a.click();
|
||
document.body.removeChild(a);
|
||
}
|
||
|
||
});
|