| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627 |
- <!--This is the plain html source of the hex encoded Editor-Page embedded in SPIFFSEditor.cpp -->
- <!DOCTYPE html>
- <html lang="en">
- <head>
- <title>ESP Editor</title>
- <style type="text/css" media="screen">
- .cm {
- z-index: 300;
- position: absolute;
- left: 5px;
- border: 1px solid #444;
- background-color: #F5F5F5;
- display: none;
- box-shadow: 0 0 10px rgba( 0, 0, 0, .4 );
- font-size: 12px;
- font-family: sans-serif;
- font-weight:bold;
- }
- .cm ul {
- list-style: none;
- top: 0;
- left: 0;
- margin: 0;
- padding: 0;
- }
- .cm li {
- position: relative;
- min-width: 60px;
- cursor: pointer;
- }
- .cm span {
- color: #444;
- display: inline-block;
- padding: 6px;
- }
- .cm li:hover { background: #444; }
- .cm li:hover span { color: #EEE; }
- .tvu ul, .tvu li {
- padding: 0;
- margin: 0;
- list-style: none;
- }
- .tvu input {
- position: absolute;
- opacity: 0;
- }
- .tvu {
- font: normal 12px Verdana, Arial, Sans-serif;
- -moz-user-select: none;
- -webkit-user-select: none;
- user-select: none;
- color: #444;
- line-height: 16px;
- }
- .tvu span {
- margin-bottom:5px;
- padding: 0 0 0 18px;
- cursor: pointer;
- display: inline-block;
- height: 16px;
- vertical-align: middle;
- background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAQAAAC1+jfqAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAADoSURBVBgZBcExblNBGAbA2ceegTRBuIKOgiihSZNTcC5LUHAihNJR0kGKCDcYJY6D3/77MdOinTvzAgCw8ysThIvn/VojIyMjIyPP+bS1sUQIV2s95pBDDvmbP/mdkft83tpYguZq5Jh/OeaYh+yzy8hTHvNlaxNNczm+la9OTlar1UdA/+C2A4trRCnD3jS8BB1obq2Gk6GU6QbQAS4BUaYSQAf4bhhKKTFdAzrAOwAxEUAH+KEM01SY3gM6wBsEAQB0gJ+maZoC3gI6iPYaAIBJsiRmHU0AALOeFC3aK2cWAACUXe7+AwO0lc9eTHYTAAAAAElFTkSuQmCC') no-repeat;
- background-position: 0px 0px;
- }
- .tvu span:hover {
- text-decoration: underline;
- }
- @media screen and (-webkit-min-device-pixel-ratio:0){
- .tvu{
- -webkit-animation: webkit-adjacent-element-selector-bugfix infinite 1s;
- }
- @-webkit-keyframes webkit-adjacent-element-selector-bugfix {
- from {
- padding: 0;
- }
- to {
- padding: 0;
- }
- }
- }
- #uploader {
- position: absolute;
- top: 0;
- right: 0;
- left: 0;
- height:28px;
- line-height: 24px;
- padding-left: 10px;
- background-color: #444;
- color:#EEE;
- }
- #tree {
- position: absolute;
- top: 28px;
- bottom: 0;
- left: 0;
- width:160px;
- padding: 8px;
- }
- #editor, #preview {
- position: absolute;
- top: 28px;
- right: 0;
- bottom: 0;
- left: 160px;
- border-left:1px solid #EEE;
- }
- #preview {
- background-color: #EEE;
- padding:5px;
- }
- #loader {
- position: absolute;
- top: 36%;
- right: 40%;
- }
- .loader {
- z-index: 10000;
- border: 8px solid #b5b5b5; /* Grey */
- border-top: 8px solid #3498db; /* Blue */
- border-bottom: 8px solid #3498db; /* Blue */
- border-radius: 50%;
- width: 240px;
- height: 240px;
- animation: spin 2s linear infinite;
- display:none;
- }
- @keyframes spin {
- 0% { transform: rotate(0deg); }
- 100% { transform: rotate(360deg); }
- }
- </style>
- <script>
- if (typeof XMLHttpRequest === "undefined") {
- XMLHttpRequest = function () {
- try { return new ActiveXObject("Msxml2.XMLHTTP.6.0"); } catch (e) {}
- try { return new ActiveXObject("Msxml2.XMLHTTP.3.0"); } catch (e) {}
- try { return new ActiveXObject("Microsoft.XMLHTTP"); } catch (e) {}
- throw new Error("This browser does not support XMLHttpRequest.");
- };
- }
- function ge(a){
- return document.getElementById(a);
- }
- function ce(a){
- return document.createElement(a);
- }
- function sortByKey(array, key) {
- return array.sort(function(a, b) {
- var x = a[key]; var y = b[key];
- return ((x < y) ? -1 : ((x > y) ? 1 : 0));
- });
- }
- var QueuedRequester = function () {
- this.queue = [];
- this.running = false;
- this.xmlhttp = null;
- }
- QueuedRequester.prototype = {
- _request: function(req){
- this.running = true;
- if(!req instanceof Object) return;
- var that = this;
-
- function ajaxCb(x,d){ return function(){
- if (x.readyState == 4){
- ge("loader").style.display = "none";
- d.callback(x.status, x.responseText);
- if(that.queue.length === 0) that.running = false;
- if(that.running) that._request(that.queue.shift());
- }
- }}
-
- ge("loader").style.display = "block";
-
- var p = "";
- if(req.params instanceof FormData){
- p = req.params;
- } else if(req.params instanceof Object){
- for (var key in req.params) {
- if(p === "")
- p += (req.method === "GET")?"?":"";
- else
- p += "&";
- p += encodeURIComponent(key)+"="+encodeURIComponent(req.params[key]);
- };
- }
-
- this.xmlhttp = new XMLHttpRequest();
- this.xmlhttp.onreadystatechange = ajaxCb(this.xmlhttp, req);
- if(req.method === "GET"){
- this.xmlhttp.open(req.method, req.url+p, true);
- this.xmlhttp.send();
- } else {
- this.xmlhttp.open(req.method, req.url, true);
- if(p instanceof String)
- this.xmlhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
- this.xmlhttp.send(p);
- }
- },
- stop: function(){
- if(this.running) this.running = false;
- if(this.xmlhttp && this.xmlhttp.readyState < 4){
- this.xmlhttp.abort();
- }
- },
- add: function(method, url, params, callback){
- this.queue.push({url:url,method:method,params:params,callback:callback});
- if(!this.running){
- this._request(this.queue.shift());
- }
- }
- }
- var requests = new QueuedRequester();
- function createFileUploader(element, tree, editor){
- var xmlHttp;
-
- var refresh = ce("button");
- refresh.innerHTML = 'Refresh List';
- ge(element).appendChild(refresh);
- var input = ce("input");
- input.type = "file";
- input.multiple = false;
- input.name = "data";
- input.id="upload-select";
- ge(element).appendChild(input);
-
- var path = ce("input");
- path.id = "upload-path";
- path.type = "text";
- path.name = "path";
- path.defaultValue = "/";
- ge(element).appendChild(path);
-
- var button = ce("button");
- button.innerHTML = 'Upload';
- ge(element).appendChild(button);
-
- var mkfile = ce("button");
- mkfile.innerHTML = 'Create';
- ge(element).appendChild(mkfile);
- var filename = ce("input");
- filename.id = "editor-filename";
- filename.type = "text";
- filename.disabled= true;
- filename.size = 20;
- ge(element).appendChild(filename);
- var savefile = ce("button");
- savefile.innerHTML = ' Save ' ;
- ge(element).appendChild(savefile);
- function httpPostProcessRequest(status, responseText){
- if(status != 200)
- alert("ERROR["+status+"]: "+responseText);
- else
- tree.refreshPath(path.value);
- }
- function createPath(p){
- var formData = new FormData();
- formData.append("path", p);
- requests.add("PUT", "/edit", formData, httpPostProcessRequest);
- }
-
- mkfile.onclick = function(e){
- createPath(path.value);
- editor.loadUrl(path.value);
- path.value="/";
- };
- savefile.onclick = function(e){
- editor.execCommand('saveCommand');
- };
-
- refresh.onclick = function(e){
- tree.refreshPath(path.value);
- };
-
- button.onclick = function(e){
- if(input.files.length === 0){
- return;
- }
- var formData = new FormData();
- formData.append("data", input.files[0], path.value);
- requests.add("POST", "/edit", formData, httpPostProcessRequest);
- var uploadPath= ge("upload-path");
- uploadPath.value="/";
- var uploadSelect= ge("upload-select");
- uploadSelect.value="";
- };
- input.onchange = function(e){
- if(input.files.length === 0) return;
- var filename = input.files[0].name;
- var ext = /(?:\.([^.]+))?$/.exec(filename)[1];
- var name = /(.*)\.[^.]+$/.exec(filename)[1];
- if(typeof name !== undefined){
- filename = name;
- }
- path.value = "/"+filename+"."+ext;
- };
- }
- function createTree(element, editor){
- var preview = ge("preview");
- var treeRoot = ce("div");
- treeRoot.className = "tvu";
- ge(element).appendChild(treeRoot);
- function loadDownload(path){
- ge('download-frame').src = "/edit?download="+path;
- }
- function loadPreview(path){
- var edfname = ge("editor-filename");
- edfname.value=path;
- ge("editor").style.display = "none";
- preview.style.display = "block";
- preview.innerHTML = '<img src="/edit?edit='+path+'&_cb='+Date.now()+'" style="max-width:100%; max-height:100%; margin:auto; display:block;" />';
- }
- function fillFileMenu(el, path){
- var list = ce("ul");
- el.appendChild(list);
- var action = ce("li");
- list.appendChild(action);
- if(isImageFile(path)){
- action.innerHTML = "<span>Preview</span>";
- action.onclick = function(e){
- loadPreview(path);
- if(document.body.getElementsByClassName('cm').length > 0) document.body.removeChild(el);
- };
- } else if(isTextFile(path)){
- action.innerHTML = "<span>Edit</span>";
- action.onclick = function(e){
- editor.loadUrl(path);
- if(document.body.getElementsByClassName('cm').length > 0) document.body.removeChild(el);
- };
- }
- var download = ce("li");
- list.appendChild(download);
- download.innerHTML = "<span>Download</span>";
- download.onclick = function(e){
- loadDownload(path);
- if(document.body.getElementsByClassName('cm').length > 0) document.body.removeChild(el);
- };
- var delFile = ce("li");
- list.appendChild(delFile);
- delFile.innerHTML = "<span>Delete</span>";
- delFile.onclick = function(e){
- httpDelete(path);
- if(document.body.getElementsByClassName('cm').length > 0) document.body.removeChild(el);
- };
- }
- function showContextMenu(event, path, isfile){
- var divContext = ce("div");
- var scrollTop = document.body.scrollTop ? document.body.scrollTop : document.documentElement.scrollTop;
- var scrollLeft = document.body.scrollLeft ? document.body.scrollLeft : document.documentElement.scrollLeft;
- var left = event.clientX + scrollLeft;
- var top = event.clientY + scrollTop;
- divContext.className = 'cm';
- divContext.style.display = 'block';
- divContext.style.left = left + 'px';
- divContext.style.top = top + 'px';
- fillFileMenu(divContext, path);
- document.body.appendChild(divContext);
- var width = divContext.offsetWidth;
- var height = divContext.offsetHeight;
- divContext.onmouseout = function(e){
- if(e.clientX < left || e.clientX > (left + width) || e.clientY < top || e.clientY > (top + height)){
- if(document.body.getElementsByClassName('cm').length > 0) document.body.removeChild(divContext);
- }
- };
- }
- function createTreeLeaf(path, name, size){
- var leaf = ce("li");
- leaf.id = name;
- var label = ce("span");
- label.innerHTML = name;
- leaf.appendChild(label);
- leaf.onclick = function(e){
- if(isTextFile(leaf.id.toLowerCase())){
- editor.loadUrl(leaf.id);
- } else if(isImageFile(leaf.id.toLowerCase())){
- loadPreview(leaf.id);
- }
- };
- leaf.oncontextmenu = function(e){
- e.preventDefault();
- e.stopPropagation();
- showContextMenu(e, leaf.id, true);
- };
- return leaf;
- }
- function addList(parent, path, items){
- sortByKey(items, 'name');
- var list = ce("ul");
- parent.appendChild(list);
- var ll = items.length;
- for(var i = 0; i < ll; i++){
- if(items[i].type === "file")
- list.appendChild(createTreeLeaf(path, items[i].name, items[i].size));
- }
- }
- function isTextFile(path){
- var ext = /(?:\.([^.]+))?$/.exec(path)[1];
- if(typeof ext !== undefined){
- switch(ext){
- case "txt":
- case "htm":
- case "html":
- case "js":
- case "css":
- case "xml":
- case "json":
- case "conf":
- case "ini":
- case "h":
- case "c":
- case "cpp":
- case "php":
- case "hex":
- case "ino":
- case "pde":
- return true;
- }
- }
- return false;
- }
- function isImageFile(path){
- var ext = /(?:\.([^.]+))?$/.exec(path)[1];
- if(typeof ext !== undefined){
- switch(ext){
- case "png":
- case "jpg":
- case "gif":
- case "bmp":
- return true;
- }
- }
- return false;
- }
- this.refreshPath = function(path){
- treeRoot.removeChild(treeRoot.childNodes[0]);
- httpGet(treeRoot, "/");
- };
- function delCb(path){
- return function(status, responseText){
- if(status != 200){
- alert("ERROR["+status+"]: "+responseText);
- } else {
- treeRoot.removeChild(treeRoot.childNodes[0]);
- httpGet(treeRoot, "/");
- }
- }
- }
- function httpDelete(filename){
- var formData = new FormData();
- formData.append("path", filename);
- requests.add("DELETE", "/edit", formData, delCb(filename));
- }
- function getCb(parent, path){
- return function(status, responseText){
- if(status == 200)
- addList(parent, path, JSON.parse(responseText));
- }
- }
- function httpGet(parent, path){
- requests.add("GET", "/edit", { list: path }, getCb(parent, path));
- }
- httpGet(treeRoot, "/");
- return this;
- }
- function createEditor(element, file, lang, theme, type){
- function getLangFromFilename(filename){
- var lang = "plain";
- var ext = /(?:\.([^.]+))?$/.exec(filename)[1];
- if(typeof ext !== undefined){
- switch(ext){
- case "txt": lang = "plain"; break;
- case "hex": lang = "plain"; break;
- case "conf": lang = "plain"; break;
- case "htm": lang = "html"; break;
- case "js": lang = "javascript"; break;
- case "h": lang = "c_cpp"; break;
- case "c": lang = "c_cpp"; break;
- case "cpp": lang = "c_cpp"; break;
- case "css":
- case "scss":
- case "php":
- case "html":
- case "json":
- case "xml":
- case "ini": lang = ext;
- }
- }
- return lang;
- }
- if(typeof file === "undefined") file = "/index.html";
- if(typeof lang === "undefined"){
- lang = getLangFromFilename(file);
- }
- if(typeof theme === "undefined") theme = "textmate";
- if(typeof type === "undefined"){
- type = "text/"+lang;
- if(lang === "c_cpp") type = "text/plain";
- }
- var editor = ace.edit(element);
- function httpPostProcessRequest(status, responseText){
- if(status != 200) alert("ERROR["+status+"]: "+responseText);
- }
- function httpPost(filename, data, type){
- var formData = new FormData();
- formData.append("data", new Blob([data], { type: type }), filename);
- requests.add("POST", "/edit", formData, httpPostProcessRequest);
- }
- function httpGetProcessRequest(status, responseText){
- ge("preview").style.display = "none";
- ge("editor").style.display = "block";
- if(status == 200)
- editor.setValue(responseText);
- else
- editor.setValue("");
- editor.clearSelection();
- }
- function httpGet(theUrl){
- requests.add("GET", "/edit", { edit: theUrl }, httpGetProcessRequest);
- }
- if(lang !== "plain") editor.getSession().setMode("ace/mode/"+lang);
- editor.setTheme("ace/theme/"+theme);
- editor.$blockScrolling = Infinity;
- editor.getSession().setUseSoftTabs(true);
- editor.getSession().setTabSize(2);
- editor.setHighlightActiveLine(true);
- editor.setShowPrintMargin(false);
- editor.commands.addCommand({
- name: 'saveCommand',
- bindKey: {win: 'Ctrl-S', mac: 'Command-S'},
- exec: function(editor) {
- httpPost(file, editor.getValue()+"", type);
- },
- readOnly: false
- });
- editor.commands.addCommand({
- name: 'undoCommand',
- bindKey: {win: 'Ctrl-Z', mac: 'Command-Z'},
- exec: function(editor) {
- editor.getSession().getUndoManager().undo(false);
- },
- readOnly: false
- });
- editor.commands.addCommand({
- name: 'redoCommand',
- bindKey: {win: 'Ctrl-Shift-Z', mac: 'Command-Shift-Z'},
- exec: function(editor) {
- editor.getSession().getUndoManager().redo(false);
- },
- readOnly: false
- });
- editor.loadUrl = function(filename){
- var edfname = ge("editor-filename");
- edfname.value=filename;
- file = filename;
- lang = getLangFromFilename(file);
- type = "text/"+lang;
- if(lang !== "plain") editor.getSession().setMode("ace/mode/"+lang);
- httpGet(file);
- };
- return editor;
- }
- function onBodyLoad(){
- var vars = {};
- var parts = window.location.href.replace(/[?&]+([^=&]+)=([^&]*)/gi, function(m,key,value) { vars[key] = value; });
- var editor = createEditor("editor", vars.file, vars.lang, vars.theme);
- var tree = createTree("tree", editor);
- createFileUploader("uploader", tree, editor);
- if(typeof vars.file === "undefined") vars.file = "/index.htm";
- editor.loadUrl(vars.file);
- };
- </script>
- <script id='ace' src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.2.6/ace.js" type="text/javascript" charset="utf-8"></script>
- <script>
- if (typeof ace.edit == "undefined") {
- var script = document.createElement('script');
- script.src = "/ace.js";
- script.async = false;
- document.head.appendChild(script);
- }
- </script>
- </head>
- <body onload="onBodyLoad();">
- <div id="loader" class="loader"></div>
- <div id="uploader"></div>
- <div id="tree"></div>
- <div id="editor"></div>
- <div id="preview" style="display:none;"></div>
- <iframe id=download-frame style='display:none;'></iframe>
- </body>
- </html>
|