Add light file manager to upload/download/delete

files on SPIFFS - need to decrease printer.tpl size to implement have
more space for new settings.tpl for 64K SPIFFS
This commit is contained in:
luc 2015-10-19 14:43:16 +08:00
parent df65c088ed
commit 80742c422a
13 changed files with 201 additions and 8 deletions

BIN
Page1.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 27 KiB

BIN
Page2.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 11 KiB

BIN
Page3.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 16 KiB

BIN
Page4.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 20 KiB

BIN
Page6.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 31 KiB

View File

@ -73,7 +73,7 @@ the template files are stored on SPIFFS:
and uploaded using [IDE](http://arduino.esp8266.com/versions/1.6.5-1160-gef26c5f/doc/reference.html#file-system)
The list of keywords can be find here : https://github.com/luc-github/ESP8266/blob/master/keywords.txt
Any files on SPIFFS can be called on web interface without having the path hard coded - this give more flexibility, favicon.ico is a good example of it.
So UI is kind of separated from FW which allow easier modifications.
So UI is kind of separated from FW which allow easier modifications. For this a light file manager is available in extra settings page, it allows to upload/download/delete files. as SPIFFS is flat filesystem no directory management is necessary so it is very simple.
Additionally 404.tpl (the page not found) and restart.tpl(restart page when applying changes) are not mandatory, a fail safe version is embeded if they are not present.

View File

@ -15,7 +15,7 @@ $INCLUDE[css.inc]$
<td class="$MENU_AP$"><a href="http://$WEB_ADDRESS$/CONFIGAP">AP Configuration</a></td>
<td class="$MENU_STA$"><a href="http://$WEB_ADDRESS$/CONFIGSTA">Station Configuration</a></td>
<td class="$MENU_PRINTER$"><a href="http://$WEB_ADDRESS$/PRINTER">Printer Status</a></td>
<td class="$MENU_SETTINGS$"><a href="http://$WEB_ADDRESS$/SETTINGS">Printer Settings</a></td>
<td class="$MENU_SETTINGS$"><a href="http://$WEB_ADDRESS$/SETTINGS">Extra Settings</a></td>
<td width=100%>&nbsp;</td>
<td>FW: V$FW_VER$</td>
<td><a href="https://github.com/luc-github/ESP8266" >Github</a></td>

View File

@ -1,6 +1,6 @@
$INCLUDE[header.inc]$
<div class="panel">
<div class="panel-heading">Printer Settings</div>
<div class="panel-heading">Extra Settings</div>
<div class="panel-body">
<form method="POST">
<div class="form-group $REFRESH_PAGE_STATUS$"><label class="control-label" for="CONFIG1">Refresh page time: </label><br>
@ -22,6 +22,65 @@ $SUCCESS_MSG$
</div>
</div>
</div>
<div class="panel">
<div class="panel-heading">Filesystem</div>
<div class="panel-body">
<input type="file" id="file-select" name="myfiles[]" multiple />
<input type="button" id="upload-button" onclick="Sendfile();" value="Upload"/><br><br>
<table class="table table-striped" style="border:1px;solid #dddddd;margin-bottom:20px;" ><thead><tr><th>Name</th><th>size</th><th width='0%'></th></tr></thead><tbody id="file_list"><tbody></table>
<label class="text-info" id="status"></label>
</div>
</div>
<script>
function dispatchstatus(jsonresponse)
{
var content ="";
document.getElementById('status').innerHTML=jsonresponse.status;
for (var i=0;i <jsonresponse.files.length;i++){
content +="<TR><TD style=\"cursor:hand;\" onclick=\"window.open('"+jsonresponse.files[i].name+"');\">";
content +=jsonresponse.files[i].name;
content +="</TD><TD>";
content +=jsonresponse.files[i].size;
content +="</TD><TD width='0%'><div style=\"cursor:hand; background:red; color:white;border-radius:12px ;\" onclick=\"Delete('"+jsonresponse.files[i].name+"')\">&nbsp;&#215;&nbsp;";
content +="</div></TD></TR>";
}
document.getElementById('file_list').innerHTML=content;}
function Delete(filename){
if (confirm("Confirm deletion of :" + filename))SendCommand("delete",filename);
}
function SendCommand(action,filename){
var xmlhttp = new XMLHttpRequest();
var url = "/FILES?action="+action;
url += "&filename="+encodeURI(filename);
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
var jsonresponse = JSON.parse(xmlhttp.responseText);
dispatchstatus(jsonresponse);}
}
xmlhttp.open("GET", url, true);
xmlhttp.send();
}
function Sendfile(){
document.getElementById('upload-button').value = "Uploading...";
var files = document.getElementById('file-select').files;
var formData = new FormData();
for (var i = 0; i < files.length; i++) {
var file = files[i];
formData.append('myfiles[]', file, "/"+file.name);}
var xmlhttp = new XMLHttpRequest();
xmlhttp.open('POST', '/FILES', true);
xmlhttp.onload = function () {
if (xmlhttp.status === 200) {
document.getElementById('upload-button').value = 'Upload';
document.getElementById('file-select').value="";
var jsonresponse = JSON.parse(xmlhttp.responseText);
dispatchstatus(jsonresponse);
} else alert('An error occurred!');
}
xmlhttp.send(formData);
}
SendCommand('list','all');
</script>
$INCLUDE[footer.inc]$

View File

@ -15,7 +15,7 @@ $INCLUDE[css.inc]$
<td class="$MENU_AP$"><a href="http://$WEB_ADDRESS$/CONFIGAP">AP Configuration</a></td>
<td class="$MENU_STA$"><a href="http://$WEB_ADDRESS$/CONFIGSTA">Station Configuration</a></td>
<td class="$MENU_PRINTER$"><a href="http://$WEB_ADDRESS$/PRINTER">Printer Status</a></td>
<td class="$MENU_SETTINGS$"><a href="http://$WEB_ADDRESS$/SETTINGS">Printer Settings</a></td>
<td class="$MENU_SETTINGS$"><a href="http://$WEB_ADDRESS$/SETTINGS">Extra Settings</a></td>
<td width=100%>&nbsp;</td>
<td>FW: V$FW_VER$</td>
<td><a href="https://github.com/luc-github/ESP8266" >Github</a></td>

View File

@ -1,6 +1,6 @@
$INCLUDE[header.inc]$
<div class="panel">
<div class="panel-heading">Printer Settings</div>
<div class="panel-heading">Extra Settings</div>
<div class="panel-body">
<form method="POST">
<div class="form-group $REFRESH_PAGE_STATUS$"><label class="control-label" for="CONFIG1">Refresh page time: </label><br>
@ -22,6 +22,65 @@ $SUCCESS_MSG$
</div>
</div>
</div>
<div class="panel">
<div class="panel-heading">Filesystem</div>
<div class="panel-body">
<input type="file" id="file-select" name="myfiles[]" multiple />
<input type="button" id="upload-button" onclick="Sendfile();" value="Upload"/><br><br>
<table class="table table-striped" style="border:1px;solid #dddddd;margin-bottom:20px;" ><thead><tr><th>Name</th><th>size</th><th width='0%'></th></tr></thead><tbody id="file_list"><tbody></table>
<label class="text-info" id="status"></label>
</div>
</div>
<script>
function dispatchstatus(jsonresponse)
{
var content ="";
document.getElementById('status').innerHTML=jsonresponse.status;
for (var i=0;i <jsonresponse.files.length;i++){
content +="<TR><TD style=\"cursor:hand;\" onclick=\"window.open('"+jsonresponse.files[i].name+"');\">";
content +=jsonresponse.files[i].name;
content +="</TD><TD>";
content +=jsonresponse.files[i].size;
content +="</TD><TD width='0%'><div style=\"cursor:hand; background:red; color:white;border-radius:12px ;\" onclick=\"Delete('"+jsonresponse.files[i].name+"')\">&nbsp;&#215;&nbsp;";
content +="</div></TD></TR>";
}
document.getElementById('file_list').innerHTML=content;}
function Delete(filename){
if (confirm("Confirm deletion of :" + filename))SendCommand("delete",filename);
}
function SendCommand(action,filename){
var xmlhttp = new XMLHttpRequest();
var url = "/FILES?action="+action;
url += "&filename="+encodeURI(filename);
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
var jsonresponse = JSON.parse(xmlhttp.responseText);
dispatchstatus(jsonresponse);}
}
xmlhttp.open("GET", url, true);
xmlhttp.send();
}
function Sendfile(){
document.getElementById('upload-button').value = "Uploading...";
var files = document.getElementById('file-select').files;
var formData = new FormData();
for (var i = 0; i < files.length; i++) {
var file = files[i];
formData.append('myfiles[]', file, "/"+file.name);}
var xmlhttp = new XMLHttpRequest();
xmlhttp.open('POST', '/FILES', true);
xmlhttp.onload = function () {
if (xmlhttp.status === 200) {
document.getElementById('upload-button').value = 'Upload';
document.getElementById('file-select').value="";
var jsonresponse = JSON.parse(xmlhttp.responseText);
dispatchstatus(jsonresponse);
} else alert('An error occurred!');
}
xmlhttp.send(formData);
}
SendCommand('list','all');
</script>
$INCLUDE[footer.inc]$

View File

@ -180,7 +180,7 @@ const char KEY_E_FEEDRATE [] PROGMEM = "$E_FEEDRATE$";
const char KEY_XY_FEEDRATE_STATUS [] PROGMEM = "$XY_FEEDRATE_STATUS$";
const char KEY_Z_FEEDRATE_STATUS [] PROGMEM = "$Z_FEEDRATE_STATUS$";
const char KEY_E_FEEDRATE_STATUS [] PROGMEM = "$E_FEEDRATE_STATUS$";
const char VALUE_SETTINGS [] PROGMEM = "Printer Settings";
const char VALUE_SETTINGS [] PROGMEM = "Extra Settings";
const char KEY_REFRESH_PAGE_STATUS [] PROGMEM = "$REFRESH_PAGE_STATUS$";
bool WEBINTERFACE_CLASS::isHostnameValid(const char * hostname)
@ -2306,13 +2306,24 @@ void handle_web_interface_status()
buffer2send+="\"}";
}
buffer2send+="]";
// buffer2send+="\"end\":\"end\"";
buffer2send+="}";
web_interface->WebServer.send(200, "text/plain",buffer2send);
web_interface->WebServer.send(200, "application/json",buffer2send);
Serial.println(system_get_free_heap_size());
}
String formatBytes(size_t bytes){
if (bytes < 1024){
return String(bytes)+"oct";
} else if(bytes < (1024 * 1024)){
return String(bytes/1024.0)+"Ko";
} else if(bytes < (1024 * 1024 * 1024)){
return String(bytes/1024.0/1024.0)+"Mo";
} else {
return String(bytes/1024.0/1024.0/1024.0)+"Go";
}
}
String getContentType(String filename){
if(filename.endsWith(".htm")) return "text/html";
else if(filename.endsWith(".html")) return "text/html";
@ -2331,6 +2342,65 @@ String getContentType(String filename){
else if(filename.endsWith(".txt")) return "text/plain";
return "application/octet-stream";
}
void handleFileUpload(){
if(web_interface->WebServer.uri() != "/FILES") return;
HTTPUpload& upload = (web_interface->WebServer).upload();
if(upload.status == UPLOAD_FILE_START){
String filename = upload.filename;
web_interface->fsUploadFile = SPIFFS.open(filename, "w");
filename = String();
} else if(upload.status == UPLOAD_FILE_WRITE){
if(web_interface->fsUploadFile)
{
web_interface->fsUploadFile.write(upload.buf, upload.currentSize);
}
} else if(upload.status == UPLOAD_FILE_END){
if(web_interface->fsUploadFile)
web_interface->fsUploadFile.close();
}
else Serial.println("Cannot open file");
}
void handleFileList() {
String path = "/";
String status="Ok";
if(web_interface->WebServer.hasArg("action")) {
if(web_interface->WebServer.arg("action")=="delete" && web_interface->WebServer.hasArg("filename"))
{
String filename;
web_interface->urldecode(filename,web_interface->WebServer.arg("filename").c_str());
if(!SPIFFS.exists(filename)){
status="Cannot delete, file not found!";
}
else
{
SPIFFS.remove(filename);
}
}
}
String jsonfile = "{\"path\":\"" + path + "\",";
Dir dir = SPIFFS.openDir(path);
jsonfile+="\"files\":[";
bool firstentry=true;
while (dir.next()) {
if (!firstentry) jsonfile+=",";
else firstentry=false;
jsonfile+="{";
jsonfile+="\"name\":\"";
jsonfile+=dir.fileName();
jsonfile+="\",\"size\":\"";
File f = dir.openFile("r");
jsonfile+=formatBytes(f.size());
jsonfile+="\"";
jsonfile+="}";
f.close();
}
jsonfile+="],";
jsonfile+="\"status\":\"" + status + "\"";
jsonfile+="}";
path = "";
web_interface->WebServer.send(200, "application/json", jsonfile);
}
//do a redirect to avoid to many query
//and handle not registred path
@ -2558,6 +2628,8 @@ WEBINTERFACE_CLASS::WEBINTERFACE_CLASS (int port):WebServer(port)
WebServer.on("/PRINTER",HTTP_ANY, handle_web_interface_printer);
WebServer.on("/CMD",HTTP_ANY, handle_web_command);
WebServer.on("/RESTART",HTTP_GET, handle_restart);
WebServer.on("/FILES", HTTP_ANY, handleFileList);
WebServer.onFileUpload(handleFileUpload);
//Captive portal Feature
#ifdef CAPTIVE_PORTAL_FEATURE
WebServer.on("/generate_204",HTTP_ANY, handle_web_interface_root);
@ -2580,6 +2652,7 @@ WEBINTERFACE_CLASS::WEBINTERFACE_CLASS (int port):WebServer(port)
info_msg.setlenght(50);
status_msg.setsize(4);
status_msg.setlenght(50);
fsUploadFile=(fs::File)0;
}
//Destructor
WEBINTERFACE_CLASS::~WEBINTERFACE_CLASS()

View File

@ -24,6 +24,7 @@
#include <WiFiClient.h>
#include <WiFiServer.h>
#include <ESP8266WebServer.h>
#include <FS.h>
#include "storestrings.h"
#define MAX_EXTRUDERS 4
@ -34,6 +35,7 @@ class WEBINTERFACE_CLASS
WEBINTERFACE_CLASS (int port = 80);
~WEBINTERFACE_CLASS();
ESP8266WebServer WebServer;
File fsUploadFile;
void urldecode( String & dst, const char *src);
bool isSSIDValid(const char * ssid);
bool isPasswordValid(const char * password);

BIN
page5.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

After

Width:  |  Height:  |  Size: 41 KiB