diff --git a/dist/easycoder-min.js b/dist/easycoder-min.js index 1b6d45f..5a8b3f7 100644 --- a/dist/easycoder-min.js +++ b/dist/easycoder-min.js @@ -152,30 +152,30 @@ variant:"setup",lino:b,variables:c,alignment:d});return!0}a.addCommand({domain:" b.style.display="none";a.tracing=!0}a.stop=!1}return a.pc+1}},UL:{compile:function(a){a.compileVariable("browser","ul",!1,"dom");return!0},run:function(a){return a[a.pc].pc+1}},Upload:{compile:function(a){var b=a.getLino();if(a.nextIsSymbol()){var c=a.getToken();if(a.nextTokenIs("to")){var d=a.getNextValue();if(a.tokenIs("with")&&a.nextIsSymbol()){var e=a.getToken();if(a.nextTokenIs("and")&&a.nextIsSymbol()){var f=a.getToken();a.next();a.addCommand({domain:"browser",keyword:"upload",lino:b,file:c, path:d,progress:e,status:f});return!0}}}}return!1},run:function(a){var b=a[a.pc],c=a.getSymbolRecord(b.file),d=a.getValue(b.path),e=a.getSymbolRecord(b.progress),f=a.getSymbolRecord(b.status),h=e.element[e.index],g=f.element[f.index],k=function(a){g&&(g.innerHTML=a)};if(e=c.element[c.index].files[0])c=new FormData,c.append("source",e),c.append("path",d),e=new XMLHttpRequest,e.upload.addEventListener("progress",function(a){a=Math.round(a.loaded/a.total*100);h&&(h.value=a);k(Math.round(a)+"%...")}, !1),e.addEventListener("load",function(a){a=a.target.responseText;h&&(h.value=0);k("");console.log(a)},!1),e.addEventListener("error",function(){k("Upload failed");console.log("Upload failed")},!1),e.addEventListener("abort",function(){k("Upload aborted");console.log("Upload aborted")},!1),e.onreadystatechange=function(){if(4===this.readyState){var b=a.ajaxCommand,c=this.status;switch(c){case 200:a.run(b.pc+1);break;case 0:break;default:try{a.runtimeError(b.lino,"Error "+c)}catch(p){a.reportError(p, -a)}}}},a.ajaxCommand=b,(f=document.getElementById("easycoder-rest"))||a.runtimeError(b.lino,"No REST server defined"),b=d.startsWith("http")?d:""+window.location.origin+f+"/"+d,e.open("POST",b),e.send(c);return 0}},getHandler:function(a){switch(a){case "a":return EasyCoder_Browser.A;case "alert":return EasyCoder_Browser.Alert;case "attach":return EasyCoder_Browser.Attach;case "audioclip":return EasyCoder_Browser.Audioclip;case "blockquote":return EasyCoder_Browser.BLOCKQUOTE;case "button":return EasyCoder_Browser.BUTTON; -case "canvas":return EasyCoder_Browser.CANVAS;case "clear":return EasyCoder_Browser.Clear;case "click":return EasyCoder_Browser.Click;case "convert":return EasyCoder_Browser.Convert;case "create":return EasyCoder_Browser.Create;case "disable":return EasyCoder_Browser.Disable;case "div":return EasyCoder_Browser.DIV;case "enable":return EasyCoder_Browser.Enable;case "fieldset":return EasyCoder_Browser.FIELDSET;case "file":return EasyCoder_Browser.FILE;case "focus":return EasyCoder_Browser.Focus;case "form":return EasyCoder_Browser.FORM; -case "fullscreen":return EasyCoder_Browser.FullScreen;case "get":return EasyCoder_Browser.Get;case "h1":return EasyCoder_Browser.H1;case "h2":return EasyCoder_Browser.H2;case "h3":return EasyCoder_Browser.H3;case "h4":return EasyCoder_Browser.H4;case "h5":return EasyCoder_Browser.H5;case "h6":return EasyCoder_Browser.H6;case "highlight":return EasyCoder_Browser.Highlight;case "history":return EasyCoder_Browser.History;case "hr":return EasyCoder_Browser.HR;case "image":return EasyCoder_Browser.IMAGE; -case "img":return EasyCoder_Browser.IMG;case "input":return EasyCoder_Browser.INPUT;case "label":return EasyCoder_Browser.LABEL;case "legend":return EasyCoder_Browser.LEGEND;case "li":return EasyCoder_Browser.LI;case "location":return EasyCoder_Browser.Location;case "mail":return EasyCoder_Browser.Mail;case "on":return EasyCoder_Browser.On;case "option":return EasyCoder_Browser.OPTION;case "p":return EasyCoder_Browser.P;case "play":return EasyCoder_Browser.Play;case "pre":return EasyCoder_Browser.PRE; -case "progress":return EasyCoder_Browser.PROGRESS;case "put":return EasyCoder_Browser.Put;case "remove":return EasyCoder_Browser.Remove;case "request":return EasyCoder_Browser.Request;case "select":return EasyCoder_Browser.SELECT;case "scroll":return EasyCoder_Browser.Scroll;case "section":return EasyCoder_Browser.SECTION;case "set":return EasyCoder_Browser.Set;case "span":return EasyCoder_Browser.SPAN;case "table":return EasyCoder_Browser.TABLE;case "tr":return EasyCoder_Browser.TR;case "td":return EasyCoder_Browser.TD; -case "textarea":return EasyCoder_Browser.TEXTAREA;case "trace":return EasyCoder_Browser.Trace;case "ul":return EasyCoder_Browser.UL;case "upload":return EasyCoder_Browser.Upload;default:return null}},run:function(a){var b=a[a.pc],c=EasyCoder_Browser.getHandler(b.keyword);c||a.runtimeError(b.lino,"Unknown keyword '"+b.keyword+"' in 'browser' package");return c.run(a)},value:{compile:function(a){if(a.isSymbol()){var b=a.getSymbolRecord();if(a.nextTokenIs("exists"))return"dom"===b.extra?(a.next(),{domain:"browser", -type:"exists",value:b.name}):null;switch(b.keyword){case "file":case "input":case "select":case "textarea":return{domain:"browser",type:b.keyword,value:b.name}}return null}a.tokenIs("the")&&a.next();var c=!1;a.tokenIs("offset")&&(c=!0,a.next());b=a.getToken();switch(b){case "mobile":case "portrait":case "landscape":case "br":case "location":case "key":case "hostname":return a.next(),{domain:"browser",type:b};case "content":case "text":if(a.nextTokenIs("of")){if(a.nextIsSymbol())return b=a.getSymbolRecord(), -a.next(),{domain:"browser",type:"contentOf",symbol:b.name};throw Error("'"+a.getToken()+"' is not a symbol");}break;case "selected":b=a.nextToken();if(["index","item"].includes(b)&&["in","of"].includes(a.nextToken())&&a.nextIsSymbol()&&(c=a.getSymbolRecord(),["ul","ol","select"].includes(c.keyword)))return a.next(),{domain:"browser",type:"selected",symbol:c.name,arg:b};break;case "color":return a.next(),a=a.getValue(),{domain:"browser",type:b,value:a};case "attribute":c=a.getNextValue();if(a.tokenIs("of")&& -(a.next(),a.isSymbol()&&(b=a.getSymbolRecord(),"dom"===b.extra)))return a.next(),{domain:"browser",type:"attributeOf",attribute:c,symbol:b.name};break;case "style":c=a.getNextValue();if(a.tokenIs("of")&&a.nextIsSymbol()){var d=a.getSymbolRecord();if("dom"===d.extra)return a.next(),{domain:"browser",type:b,style:c,target:d.name}}break;case "confirm":return b=a.getNextValue(),{domain:"browser",type:"confirm",text:b};case "prompt":return b=a.getNextValue(),c=null,a.tokenIs("with")&&(c=a.getNextValue()), -{domain:"browser",type:"prompt",text:b,pre:c};case "screen":c=a.nextToken();if(["width","height"].includes(c))return a.next(),{domain:"browser",type:b,attribute:c};break;case "top":case "bottom":case "left":case "right":case "width":case "height":return EasyCoder_Browser.value.getCoord(a,b,c);case "scroll":if(a.nextTokenIs("position"))return a.next(),{domain:"browser",type:"scrollPosition"};break;case "document":if(a.nextTokenIs("path"))return a.next(),{domain:"browser",type:"docPath"};break;case "storage":if(a.nextTokenIs("keys"))return a.next(), -{domain:"browser",type:"storageKeys"};break;case "parent":switch(a.nextToken()){case "name":return a.next(),{domain:"browser",type:"varName"};case "index":return a.next(),{domain:"browser",type:"varIndex"}}break;case "history":if(a.nextTokenIs("state"))return a.next(),{domain:"browser",type:"historyState"};break;case "pick":case "drag":if(a.nextTokenIs("position"))return a.next(),{domain:"browser",type:b+"Position"};case "click":if(b=a.nextToken(),["left","top"].includes(b))return a.next(),{domain:"browser", -type:"click",which:b}}return null},getCoord:function(a,b,c){if(a.nextTokenIs("of")){a.nextTokenIs("the")&&a.nextToken();var d=a.getToken();if(["window","viewport"].includes(d))return a.next(),{domain:"browser",type:b,symbol:d,offset:c};if(a.isSymbol()&&(d=a.getSymbolRecord(),"dom"===d.extra))return a.next(),{domain:"browser",type:b,symbol:d.name,offset:c}}return null},get:function(a,b){switch(b.type){case "file":case "input":case "select":case "textarea":var c=a.getSymbolRecord(b.value);var d=c.element[c.index]; -return{type:"constant",numeric:!1,content:d.value};case "exists":return c=a.getSymbolRecord(b.value),{domain:"browser",type:"boolean",content:"undefined"!==typeof c.element[c.index]};case "mobile":return{domain:"browser",type:"boolean",content:"undefined"!==typeof window.orientation||-1!==navigator.userAgent.indexOf("IEMobile")};case "portrait":return{domain:"browser",type:"boolean",content:document.documentElement.clientWidth=document.documentElement.clientHeight};case "br":return{type:"constant",numeric:!1,content:decodeURIComponent("%3Cbr%20%2F%3E")};case "attributeOf":return c=a.getSymbolRecord(b.symbol),b=a.getValue(b.attribute),d=c.element[c.index],0===b.indexOf("data-")?a.getSimpleValue(d.dataset[b.substr(5)]):a.getSimpleValue(d[b]);case "style":return c=a.getSymbolRecord(b.target),b=a.getValue(b.style),d=c.element[c.index],a.getSimpleValue(d.style[b]); -case "confirm":return{type:"boolean",content:window.confirm(a.getValue(b.text))};case "prompt":return d=a.getValue(b.text),b=a.getValue(b.pre),{type:"constant",numeric:!1,content:b?window.prompt(d,b):window.prompt(d)};case "contentOf":c=a.getSymbolRecord(b.symbol);d=c.element[c.index];switch(c.keyword){case "input":case "textarea":b=d.value;break;case "pre":b=d.innerHTML;break;default:b=d.innerHTML.split("\n").join("")}return{type:"constant",numeric:!1,content:b};case "selected":return c=a.getSymbolRecord(b.symbol), -d=c.element[c.index],a=d.selectedIndex,d=0<=a?d.options[a].text:"",b="index"===b.arg?a:d,{type:"constant",numeric:!1,content:b};case "top":if("window"==b.symbol)return{type:"constant",numeric:!0,content:window.screenY};c=a.getSymbolRecord(b.symbol);a=c.element[c.index];b=Math.round(b.offset?a.offsetTop:a.getBoundingClientRect().top);return{type:"constant",numeric:!0,content:b};case "bottom":if("window"==b.symbol)return{type:"constant",numeric:!0,content:window.screenY+window.innerHeight};c=a.getSymbolRecord(b.symbol); -b=Math.round(c.element[c.index].getBoundingClientRect().bottom);return{type:"constant",numeric:!0,content:b};case "left":if("window"==b.symbol)return{type:"constant",numeric:!0,content:window.screenLeft};c=a.getSymbolRecord(b.symbol);a=c.element[c.index];b=Math.round(b.offset?a.offsetLeft:a.getBoundingClientRect().left);return{type:"constant",numeric:!0,content:b};case "right":if("window"==b.symbol)return{type:"constant",numeric:!0,content:window.screenX+window.innerWidth};c=a.getSymbolRecord(b.symbol); -b=Math.round(c.element[c.index].getBoundingClientRect().right);return{type:"constant",numeric:!0,content:b};case "width":if("window"==b.symbol)return{type:"constant",numeric:!0,content:window.innerWidth};c=a.getSymbolRecord(b.symbol);b=Math.round(c.element[c.index].getBoundingClientRect().width);return{type:"constant",numeric:!0,content:b};case "height":if("window"==b.symbol)return{type:"constant",numeric:!0,content:window.innerHeight};c=a.getSymbolRecord(b.symbol);b=Math.round(c.element[c.index].getBoundingClientRect().height); -return{type:"constant",numeric:!0,content:b};case "color":return{type:"constant",numeric:!1,content:"#"+a.value.evaluate(a,b.value).content.toString(16).padStart(6,"0")};case "docPath":return{type:"constant",numeric:!1,content:a.docPath};case "storageKeys":return{type:"constant",numeric:!1,content:JSON.stringify(Object.keys(localStorage))};case "location":return{type:"constant",numeric:!1,content:window.location.href};case "historyState":return{type:"constant",numeric:!1,content:window.history.state}; -case "scrollPosition":return{type:"constant",numeric:!0,content:scrollPosition};case "varName":return{type:"constant",numeric:!1,content:a.varName};case "varIndex":return{type:"constant",numeric:!0,content:a.varIndex};case "key":return{type:"constant",numeric:!1,content:a.key};case "hostname":return{type:"constant",numeric:!1,content:location.hostname};case "screen":return{type:"constant",numeric:!0,content:screen[b.attribute]};case "pickPosition":return{type:"constant",numeric:!1,content:JSON.stringify({x:document.pickX, -y:document.pickY})};case "dragPosition":return{type:"constant",numeric:!1,content:JSON.stringify({x:document.dragX,y:document.dragY})};case "click":a=EasyCoder_Browser.clickData;if("undefined"===typeof a)return 0;d=a.target.getBoundingClientRect();return{type:"constant",numeric:!0,content:"left"===b.which?a.clientX-Math.round(d.left):a.clientY-Math.round(d.top)}}}},condition:{compile:function(a){if(a.tokenIs("confirm"))return{domain:"browser",type:"confirm",value:a.getNextValue()};if(a.tokenIs("element")&& -a.nextIsSymbol()){var b=a.getSymbolRecord();if("dom"===b.extra){var c=a.nextToken();if("has"===c){if(a.nextTokenIs("the")&&a.next(),a.tokenIs("focus"))return a.next(),{domain:"browser",type:"focus",element:b.name}}else if("contains"===c)return a=a.getNextValue(),{domain:"browser",type:"contains",element:b.name,position:a}}}return null},test:function(a,b){switch(b.type){case "confirm":return confirm(a.getValue(b.value));case "focus":var c=a.getSymbolRecord(b.element);return c.element[c.index]===document.activeElement; -case "contains":c=a.getSymbolRecord(b.element);var d=c.element[c.index].getBoundingClientRect();c=Math.round(d.left);var e=Math.round(d.right),f=Math.round(d.top);d=Math.round(d.bottom);b=JSON.parse(a.getValue(b.position));a=b.x;b=b.y;return a>=c&&a<=e&&b>=f&&b<=d?!0:!1}}},setStyles:function(a,b){a=document.getElementById(a);b=b.split(";");b=$jscomp.makeIterator(b);for(var c=b.next();!c.done;c=b.next())c=c.value.split(":"),a.setAttribute(c[0],c[1])}},scrollPosition=0; -window.addEventListener("scroll",function(){scrollPosition=this.scrollY});window.onpopstate=function(a){window.EasyCoder.timestamp=Date.now();(a=JSON.parse(a.state))&&a.script&&((a=window.EasyCoder.scripts[a.script])?a.onBrowserBack&&a.run(a.onBrowserBack):console.log("No script property in window state object"))}; +a)}}}},e.onerror=function(c){b.onError?(a.errorMessage=this.responseText,a.run(b.onError)):a.runtimeError(b.lino,this.responseText)},a.ajaxCommand=b,(f=document.getElementById("easycoder-rest"))||a.runtimeError(b.lino,"No REST server defined"),d=d.startsWith("http")?d:window.location.origin+"/"+f.innerText+"/"+d,e.open("POST",d),e.send(c);return 0}},getHandler:function(a){switch(a){case "a":return EasyCoder_Browser.A;case "alert":return EasyCoder_Browser.Alert;case "attach":return EasyCoder_Browser.Attach; +case "audioclip":return EasyCoder_Browser.Audioclip;case "blockquote":return EasyCoder_Browser.BLOCKQUOTE;case "button":return EasyCoder_Browser.BUTTON;case "canvas":return EasyCoder_Browser.CANVAS;case "clear":return EasyCoder_Browser.Clear;case "click":return EasyCoder_Browser.Click;case "convert":return EasyCoder_Browser.Convert;case "create":return EasyCoder_Browser.Create;case "disable":return EasyCoder_Browser.Disable;case "div":return EasyCoder_Browser.DIV;case "enable":return EasyCoder_Browser.Enable; +case "fieldset":return EasyCoder_Browser.FIELDSET;case "file":return EasyCoder_Browser.FILE;case "focus":return EasyCoder_Browser.Focus;case "form":return EasyCoder_Browser.FORM;case "fullscreen":return EasyCoder_Browser.FullScreen;case "get":return EasyCoder_Browser.Get;case "h1":return EasyCoder_Browser.H1;case "h2":return EasyCoder_Browser.H2;case "h3":return EasyCoder_Browser.H3;case "h4":return EasyCoder_Browser.H4;case "h5":return EasyCoder_Browser.H5;case "h6":return EasyCoder_Browser.H6;case "highlight":return EasyCoder_Browser.Highlight; +case "history":return EasyCoder_Browser.History;case "hr":return EasyCoder_Browser.HR;case "image":return EasyCoder_Browser.IMAGE;case "img":return EasyCoder_Browser.IMG;case "input":return EasyCoder_Browser.INPUT;case "label":return EasyCoder_Browser.LABEL;case "legend":return EasyCoder_Browser.LEGEND;case "li":return EasyCoder_Browser.LI;case "location":return EasyCoder_Browser.Location;case "mail":return EasyCoder_Browser.Mail;case "on":return EasyCoder_Browser.On;case "option":return EasyCoder_Browser.OPTION; +case "p":return EasyCoder_Browser.P;case "play":return EasyCoder_Browser.Play;case "pre":return EasyCoder_Browser.PRE;case "progress":return EasyCoder_Browser.PROGRESS;case "put":return EasyCoder_Browser.Put;case "remove":return EasyCoder_Browser.Remove;case "request":return EasyCoder_Browser.Request;case "select":return EasyCoder_Browser.SELECT;case "scroll":return EasyCoder_Browser.Scroll;case "section":return EasyCoder_Browser.SECTION;case "set":return EasyCoder_Browser.Set;case "span":return EasyCoder_Browser.SPAN; +case "table":return EasyCoder_Browser.TABLE;case "tr":return EasyCoder_Browser.TR;case "td":return EasyCoder_Browser.TD;case "textarea":return EasyCoder_Browser.TEXTAREA;case "trace":return EasyCoder_Browser.Trace;case "ul":return EasyCoder_Browser.UL;case "upload":return EasyCoder_Browser.Upload;default:return null}},run:function(a){var b=a[a.pc],c=EasyCoder_Browser.getHandler(b.keyword);c||a.runtimeError(b.lino,"Unknown keyword '"+b.keyword+"' in 'browser' package");return c.run(a)},value:{compile:function(a){if(a.isSymbol()){var b= +a.getSymbolRecord();if(a.nextTokenIs("exists"))return"dom"===b.extra?(a.next(),{domain:"browser",type:"exists",value:b.name}):null;switch(b.keyword){case "file":case "input":case "select":case "textarea":return{domain:"browser",type:b.keyword,value:b.name}}return null}a.tokenIs("the")&&a.next();var c=!1;a.tokenIs("offset")&&(c=!0,a.next());b=a.getToken();switch(b){case "mobile":case "portrait":case "landscape":case "br":case "location":case "key":case "hostname":return a.next(),{domain:"browser", +type:b};case "content":case "text":if(a.nextTokenIs("of")){if(a.nextIsSymbol())return b=a.getSymbolRecord(),a.next(),{domain:"browser",type:"contentOf",symbol:b.name};throw Error("'"+a.getToken()+"' is not a symbol");}break;case "selected":b=a.nextToken();if(["index","item"].includes(b)&&["in","of"].includes(a.nextToken())&&a.nextIsSymbol()&&(c=a.getSymbolRecord(),["ul","ol","select"].includes(c.keyword)))return a.next(),{domain:"browser",type:"selected",symbol:c.name,arg:b};break;case "color":return a.next(), +a=a.getValue(),{domain:"browser",type:b,value:a};case "attribute":c=a.getNextValue();if(a.tokenIs("of")&&(a.next(),a.isSymbol()&&(b=a.getSymbolRecord(),"dom"===b.extra)))return a.next(),{domain:"browser",type:"attributeOf",attribute:c,symbol:b.name};break;case "style":c=a.getNextValue();if(a.tokenIs("of")&&a.nextIsSymbol()){var d=a.getSymbolRecord();if("dom"===d.extra)return a.next(),{domain:"browser",type:b,style:c,target:d.name}}break;case "confirm":return b=a.getNextValue(),{domain:"browser",type:"confirm", +text:b};case "prompt":return b=a.getNextValue(),c=null,a.tokenIs("with")&&(c=a.getNextValue()),{domain:"browser",type:"prompt",text:b,pre:c};case "screen":c=a.nextToken();if(["width","height"].includes(c))return a.next(),{domain:"browser",type:b,attribute:c};break;case "top":case "bottom":case "left":case "right":case "width":case "height":return EasyCoder_Browser.value.getCoord(a,b,c);case "scroll":if(a.nextTokenIs("position"))return a.next(),{domain:"browser",type:"scrollPosition"};break;case "document":if(a.nextTokenIs("path"))return a.next(), +{domain:"browser",type:"docPath"};break;case "storage":if(a.nextTokenIs("keys"))return a.next(),{domain:"browser",type:"storageKeys"};break;case "parent":switch(a.nextToken()){case "name":return a.next(),{domain:"browser",type:"varName"};case "index":return a.next(),{domain:"browser",type:"varIndex"}}break;case "history":if(a.nextTokenIs("state"))return a.next(),{domain:"browser",type:"historyState"};break;case "pick":case "drag":if(a.nextTokenIs("position"))return a.next(),{domain:"browser",type:b+ +"Position"};case "click":if(b=a.nextToken(),["left","top"].includes(b))return a.next(),{domain:"browser",type:"click",which:b}}return null},getCoord:function(a,b,c){if(a.nextTokenIs("of")){a.nextTokenIs("the")&&a.nextToken();var d=a.getToken();if(["window","viewport"].includes(d))return a.next(),{domain:"browser",type:b,symbol:d,offset:c};if(a.isSymbol()&&(d=a.getSymbolRecord(),"dom"===d.extra))return a.next(),{domain:"browser",type:b,symbol:d.name,offset:c}}return null},get:function(a,b){switch(b.type){case "file":case "input":case "select":case "textarea":var c= +a.getSymbolRecord(b.value);var d=c.element[c.index];return{type:"constant",numeric:!1,content:d.value};case "exists":return c=a.getSymbolRecord(b.value),{domain:"browser",type:"boolean",content:"undefined"!==typeof c.element[c.index]};case "mobile":return{domain:"browser",type:"boolean",content:"undefined"!==typeof window.orientation||-1!==navigator.userAgent.indexOf("IEMobile")};case "portrait":return{domain:"browser",type:"boolean",content:document.documentElement.clientWidth=document.documentElement.clientHeight};case "br":return{type:"constant",numeric:!1,content:decodeURIComponent("%3Cbr%20%2F%3E")};case "attributeOf":return c=a.getSymbolRecord(b.symbol),b=a.getValue(b.attribute),d=c.element[c.index],0===b.indexOf("data-")?a.getSimpleValue(d.dataset[b.substr(5)]):a.getSimpleValue(d[b]);case "style":return c=a.getSymbolRecord(b.target),b=a.getValue(b.style),d=c.element[c.index], +a.getSimpleValue(d.style[b]);case "confirm":return{type:"boolean",content:window.confirm(a.getValue(b.text))};case "prompt":return d=a.getValue(b.text),b=a.getValue(b.pre),{type:"constant",numeric:!1,content:b?window.prompt(d,b):window.prompt(d)};case "contentOf":c=a.getSymbolRecord(b.symbol);d=c.element[c.index];switch(c.keyword){case "input":case "textarea":b=d.value;break;case "pre":b=d.innerHTML;break;default:b=d.innerHTML.split("\n").join("")}return{type:"constant",numeric:!1,content:b};case "selected":return c= +a.getSymbolRecord(b.symbol),d=c.element[c.index],a=d.selectedIndex,d=0<=a?d.options[a].text:"",b="index"===b.arg?a:d,{type:"constant",numeric:!1,content:b};case "top":if("window"==b.symbol)return{type:"constant",numeric:!0,content:window.screenY};c=a.getSymbolRecord(b.symbol);a=c.element[c.index];b=Math.round(b.offset?a.offsetTop:a.getBoundingClientRect().top);return{type:"constant",numeric:!0,content:b};case "bottom":if("window"==b.symbol)return{type:"constant",numeric:!0,content:window.screenY+ +window.innerHeight};c=a.getSymbolRecord(b.symbol);b=Math.round(c.element[c.index].getBoundingClientRect().bottom);return{type:"constant",numeric:!0,content:b};case "left":if("window"==b.symbol)return{type:"constant",numeric:!0,content:window.screenLeft};c=a.getSymbolRecord(b.symbol);a=c.element[c.index];b=Math.round(b.offset?a.offsetLeft:a.getBoundingClientRect().left);return{type:"constant",numeric:!0,content:b};case "right":if("window"==b.symbol)return{type:"constant",numeric:!0,content:window.screenX+ +window.innerWidth};c=a.getSymbolRecord(b.symbol);b=Math.round(c.element[c.index].getBoundingClientRect().right);return{type:"constant",numeric:!0,content:b};case "width":if("window"==b.symbol)return{type:"constant",numeric:!0,content:window.innerWidth};c=a.getSymbolRecord(b.symbol);b=Math.round(c.element[c.index].getBoundingClientRect().width);return{type:"constant",numeric:!0,content:b};case "height":if("window"==b.symbol)return{type:"constant",numeric:!0,content:window.innerHeight};c=a.getSymbolRecord(b.symbol); +b=Math.round(c.element[c.index].getBoundingClientRect().height);return{type:"constant",numeric:!0,content:b};case "color":return{type:"constant",numeric:!1,content:"#"+a.value.evaluate(a,b.value).content.toString(16).padStart(6,"0")};case "docPath":return{type:"constant",numeric:!1,content:a.docPath};case "storageKeys":return{type:"constant",numeric:!1,content:JSON.stringify(Object.keys(localStorage))};case "location":return{type:"constant",numeric:!1,content:window.location.href};case "historyState":return{type:"constant", +numeric:!1,content:window.history.state};case "scrollPosition":return{type:"constant",numeric:!0,content:scrollPosition};case "varName":return{type:"constant",numeric:!1,content:a.varName};case "varIndex":return{type:"constant",numeric:!0,content:a.varIndex};case "key":return{type:"constant",numeric:!1,content:a.key};case "hostname":return{type:"constant",numeric:!1,content:location.hostname};case "screen":return{type:"constant",numeric:!0,content:screen[b.attribute]};case "pickPosition":return{type:"constant", +numeric:!1,content:JSON.stringify({x:document.pickX,y:document.pickY})};case "dragPosition":return{type:"constant",numeric:!1,content:JSON.stringify({x:document.dragX,y:document.dragY})};case "click":a=EasyCoder_Browser.clickData;if("undefined"===typeof a)return 0;d=a.target.getBoundingClientRect();return{type:"constant",numeric:!0,content:"left"===b.which?a.clientX-Math.round(d.left):a.clientY-Math.round(d.top)}}}},condition:{compile:function(a){if(a.tokenIs("confirm"))return{domain:"browser",type:"confirm", +value:a.getNextValue()};if(a.tokenIs("element")&&a.nextIsSymbol()){var b=a.getSymbolRecord();if("dom"===b.extra){var c=a.nextToken();if("has"===c){if(a.nextTokenIs("the")&&a.next(),a.tokenIs("focus"))return a.next(),{domain:"browser",type:"focus",element:b.name}}else if("contains"===c)return a=a.getNextValue(),{domain:"browser",type:"contains",element:b.name,position:a}}}return null},test:function(a,b){switch(b.type){case "confirm":return confirm(a.getValue(b.value));case "focus":var c=a.getSymbolRecord(b.element); +return c.element[c.index]===document.activeElement;case "contains":c=a.getSymbolRecord(b.element);var d=c.element[c.index].getBoundingClientRect();c=Math.round(d.left);var e=Math.round(d.right),f=Math.round(d.top);d=Math.round(d.bottom);b=JSON.parse(a.getValue(b.position));a=b.x;b=b.y;return a>=c&&a<=e&&b>=f&&b<=d?!0:!1}}},setStyles:function(a,b){a=document.getElementById(a);b=b.split(";");b=$jscomp.makeIterator(b);for(var c=b.next();!c.done;c=b.next())c=c.value.split(":"),a.setAttribute(c[0],c[1])}}, +scrollPosition=0;window.addEventListener("scroll",function(){scrollPosition=this.scrollY});window.onpopstate=function(a){window.EasyCoder.timestamp=Date.now();(a=JSON.parse(a.state))&&a.script&&((a=window.EasyCoder.scripts[a.script])?a.onBrowserBack&&a.run(a.onBrowserBack):console.log("No script property in window state object"))}; var EasyCoder_Json={name:"EasyCoder_JSON",Json:{compile:function(a){var b=a.getLino(),c=a.nextToken();switch(c){case "set":a.next();if(a.isSymbol())if(c=a.getSymbolRecord(),"variable"===c.keyword){if(a.nextTokenIs("to")){var d=a.nextToken();if('["array","object"]'.includes(d))return a.next(),a.addCommand({domain:"json",keyword:"json",lino:b,request:"setVariable",target:c.name,type:d}),!0}}else if("select"===c.keyword&&a.nextTokenIs("from")&&(a.next(),a.isSymbol()&&(d=a.getSymbolRecord(),"variable"=== d.keyword))){var e=null;a.nextTokenIs("as")&&(e=a.getNextValue());a.addCommand({domain:"json",keyword:"json",lino:b,request:"setList",target:c.name,source:d.name,display:e});return!0}break;case "sort":case "shuffle":case "format":if(a.nextIsSymbol()&&(d=a.getSymbolRecord(),"variable"===d.keyword))return a.next(),a.addCommand({domain:"json",keyword:"json",lino:b,request:c,target:d.name}),!0;break;case "parse":if(a.nextTokenIs("url")&&(d=a.getNextValue(),a.tokenIs("as")&&a.nextIsSymbol()&&(e=a.getSymbolRecord(), "variable"===e.keyword)))return a.next(),a.addCommand({domain:"json",keyword:"json",lino:b,request:c,source:d,target:e.name}),!0;break;case "delete":d=a.nextToken();if(["property","element"].includes(d)&&(e=a.getNextValue(),["from","of"].includes(a.getToken())&&a.nextIsSymbol())){var f=a.getSymbolRecord();if("variable"===f.keyword)return a.next(),a.addCommand({domain:"json",keyword:"json",lino:b,request:c,what:d,value:e,target:f.name}),!0}break;case "rename":d=a.getNextValue();if(a.tokenIs("to")&& diff --git a/dist/easycoder.js b/dist/easycoder.js index 3acf3ec..77f765e 100644 --- a/dist/easycoder.js +++ b/dist/easycoder.js @@ -5659,12 +5659,23 @@ const EasyCoder_Browser = { } } }; + ajax.onerror = function (data) { + if (command.onError) { + program.errorMessage = this.responseText; + program.run(command.onError); + } else { + const error = this.responseText; + program.runtimeError(command.lino, error); + } + }; program.ajaxCommand = command; const rest = document.getElementById(`easycoder-rest`); if (!rest) { program.runtimeError(command.lino, `No REST server defined`); } - const postpath = path.startsWith(`http`) ? path : `${window.location.origin}${rest}/${path}`; + const postpath = path.startsWith(`http`) + ? path + : `${window.location.origin}/${rest.innerText}/${path}`; ajax.open(`POST`, postpath); ajax.send(formData); } diff --git a/iwsy/resources/ecs/fileman.txt b/iwsy/resources/ecs/fileman.txt new file mode 100644 index 0000000..696bc14 --- /dev/null +++ b/iwsy/resources/ecs/fileman.txt @@ -0,0 +1,267 @@ +! File Manager + + script FileManager + + import div Container + + div Tracer + div Panel + div FileListing + div FileRow + div Scroller + div Uploader + div Buttons + div Location + span UploadStatus + progress UploadProgress + input UploadFile + input URL + button CloseButton + button NewFolderButton + button UploadButton + button DeleteButton + a FileName + img Icon + img Image + variable Mobile + variable FileCount + variable File + variable Name + variable Type + variable Source + variable Content + variable Home + variable UserRecord + variable CurrentPath + variable FilePath + variable Path + variable N + variable Even + + if portrait + begin + if mobile set Mobile else clear Mobile + end + + create Panel in Container + if Mobile set the style of Panel to `background:#ffe` + else set the style of Panel to `width:100%;height:100%;background:#ffe` + + create Tracer in Panel + set attribute `id` of Tracer to `easycoder-tracer` + + create Uploader in Panel + set the style of Uploader to `width:100%;padding:0.5em 0;font-size:80%;text-align:center` + create UploadFile in Uploader + set the style of UploadFile to `font-family:serif;color:black` + set attribute `type` of UploadFile to `file` + set attribute `name` of UploadFile to `Source` + create UploadStatus in Uploader + set the style of UploadStatus to `font-family:serif;color:black` + create UploadProgress in Uploader + set style `margin-left` of UploadProgress to `0.5em` + set attribute `value` of UploadProgress to 0 + set attribute `max` of UploadProgress to 100 + + create Buttons in Panel + set the style of Buttons to `display:flex` + create UploadButton in Buttons + set the style of UploadButton to `flex:1;width:150px;height:40px;font-family:sans;color:black` + set the text of UploadButton to `Upload` + on click UploadButton go to Upload + create NewFolderButton in Buttons + set the style of NewFolderButton to `flex:1;width:150px;height:40px;font-family:sans;color:black` + set the text of NewFolderButton to `New Folder` + create DeleteButton in Buttons + set the style of DeleteButton to `flex:1;width:150px;height:40px;font-family:sans;color:black` + set the text of DeleteButton to `Delete` + create CloseButton in Buttons + set the style of CloseButton to `flex:1;width:150px;height:40px;font-family:sans;color:black` + set the text of CloseButton to `Close` + on click CloseButton go to Exit + + create FileListing in Panel + set the style of FileListing to `width:100%;height:80%;text-align:center` + create Location in FileListing + set the style of Location to `width:100%;text-align:left;color:black;padding:0 0.5em` + create URL in FileListing + set the style of URL to `display:none;width:100%;text-align:left;font-family:sans;color:black;padding:0 0.5em` + + create Scroller in FileListing + set the style of Scroller to `width:100%;height:100%;text-align:left;overflow-y:scroll;font-family:mono` + create Image in FileListing + set the style of Image to `margin:0 auto;max-width:100%;max-height:100%` + + on click NewFolderButton + begin + put prompt `Name of folder:` with `new` into Path + if Path is empty stop + replace ` ` with `-` in Path + put CurrentPath cat `/` cat Path into Path + rest post to `mkdir/resources/` cat Path or + begin + alert `Failed to create a directory.` + stop + end + goto Browser + end + + on message go to Show + set ready + stop + +Show: + set style `display` of Container to `block` + + get UserRecord from storage as `.user` + put property `home` of UserRecord into Home + put `users/` cat Home cat `/images` into Home + put Home into CurrentPath + +! Build the list +Browser: + rest get Content from `list/` cat CurrentPath + or begin + alert `Failed to list files.` + stop + end + put CurrentPath into Path + set the content of Location to `Current path: ` cat Path + put the json count of Content into FileCount + set the elements of File to FileCount + set the elements of FileName to FileCount + + ! Add a row for each file + set the content of Scroller to `` + set Even + + if CurrentPath is not Home + begin + create FileRow in Scroller + set the style of FileRow to `width:90%;padding:0.5em 1em;text-align:left` + create Icon in FileRow + set the style of Icon to `float:left;margin-right:0.5em;width:20px` + set attribute `src` of Icon to `/resources/icon/arrow-back.png` + create FileName in FileRow + set the content of FileName to `(back to previous folder)` + on click FileName + begin + put the position of the last `/` in CurrentPath into N + put left N of CurrentPath into CurrentPath + go to Browser + end + end + + set the elements of FileName to FileCount + put 0 into N + while N is less than FileCount + begin + index File to N + put element N of Content into File + put property `name` of File into Name + put property `type` of File into Type + create FileRow in Scroller + set the style of FileRow to `clear:both;padding:0.5em 1em;text-align:left` + if Even set style `background` of FileRow to `#eee` + create Icon in FileRow + set the style of Icon to `float:left;margin-right:0.5em;width:20px` + if Type is `dir` put `folder.png` into Source + else if Type is `img` put `image.png` into Source + else if Type is `txt` put `text.png` into Source + else if Type is `doc` put `document.png` into Source + else put `unknown.png` into Source + set attribute `src` of Icon to `/resources/icon/` cat Source + index FileName to N + create FileName in FileRow + set the content of FileName to Name + on click FileName go to SelectFile + toggle Even + add 1 to N + end + + on click DeleteButton + begin + if FileCount is 0 + begin + put Path into CurrentPath + rest post to `delete/` cat CurrentPath or + begin + alert `Failed to delete a file.` + stop + end + put the position of the last `~` in CurrentPath into N + if N is less than 0 put the position of the last `/` in CurrentPath into N + put left N of CurrentPath into CurrentPath + alert `Returning to ` cat CurrentPath + go to Browser + end + else + begin + alert `Folder is not empty` + end + end + + stop + +SelectFile: + index File to the index of FileName + put property `type` of File into Type + if Type is `dir` + begin + put CurrentPath cat `~` cat the content of FileName into CurrentPath + goto Browser + end + if Type is `img` + begin + set style `display` of Uploader to `none` + set style `display` of UploadButton to `none` + set style `display` of NewFolderButton to `none` + set style `display` of Location to `none` + set style `display` of URL to `block` + + set style `display` of Scroller to `none` + set style `display` of Image to `block` + put CurrentPath cat `/` cat property `name` of File into FilePath + set attribute `src` of Image to `/resources/` cat FilePath + on click CloseButton go to CloseMedia + set the text of URL to `/resources/` cat FilePath +! highlight URL + on click DeleteButton + begin + put `upload` cat FilePath into FilePath + rest post to `delete/` cat FilePath or + begin + alert `Failed to delete the image.` + stop + end + go to CloseMedia + end + end + stop + +CloseMedia: + set style `display` of Image to `none` + set style `display` of Scroller to `block` + set style `display` of Uploader to `inline-block` + set style `display` of UploadButton to `inline-block` + set style `display` of NewFolderButton to `inline-block` + set the content of Location to `Current path: ` cat CurrentPath + set style `display` of Location to `block` + set style `display` of URL to `none` + on click CloseButton go to Exit + go to Browser + +Upload: + if UploadFile is empty alert `Please choose a file to upload` + else + begin + put CurrentPath into Path + put `upload/` cat Path into Path + upload UploadFile to Path with UploadProgress and UploadStatus + goto Browser + end + stop + +Exit: + set style `display` of Container to `none` + stop \ No newline at end of file diff --git a/iwsy/resources/ecs/iwsy.txt b/iwsy/resources/ecs/iwsy.txt index 0266387..97af457 100644 --- a/iwsy/resources/ecs/iwsy.txt +++ b/iwsy/resources/ecs/iwsy.txt @@ -13,12 +13,14 @@ div Buttons div Tabs div Tab - div ScriptName div StepsPanel div BlocksPanel div ContentPanel div Player div UserPanel + div FileManPanel + div Panel + div Div span Status span Span input NameEditor @@ -29,11 +31,13 @@ img RunStop img Delete img User + img FileMan a Link module StepsModule module BlocksModule module ContentModule module UserModule + module FileManModule variable Mobile variable LastSavedState variable Content @@ -43,8 +47,6 @@ variable CurrentName variable ShowRun variable ReadOnly - variable PasswordRequested - variable Password variable CallStack variable Message variable Section @@ -82,7 +84,6 @@ go to L2 end L2: - clear PasswordRequested put empty into CallStack history set on restore @@ -94,6 +95,8 @@ L2: if mobile set Mobile else clear Mobile end + put empty into storage as `.user` + set the title to `IWSY` create Body if Mobile @@ -103,7 +106,8 @@ L2: ! The left-hand panel create Left in Body - set the style of Left to `flex:1;height:100%;border-right:1px solid black;margin-right:0.5em` + set the style of Left to + `flex:1;height:100%;border-right:1px solid black;margin-right:0.5em;display:flex;flex-direction:column` create Masthead in Left set the style of Masthead to @@ -122,14 +126,22 @@ L2: create Buttons in Controls set the style of Buttons to `width:100%;padding:0.5em 0;position:relative` - create ScriptName in Controls - set the style of ScriptName to `display:flex` - if Mobile set style `display` of ScriptName to `none` - create Span in ScriptName + create Panel in Controls + set the style of Panel to `display:flex` + create Div in Panel + set the style of Div to `flex:1;display:flex` + create Span in Div set the style of Span to `flex:15` set the content of Span to `Script name: ` - create NameEditor in ScriptName + create NameEditor in Div set the style of NameEditor to `flex:85;display:inline-block` + + create Div in Panel + set the style of Div to `width:1em` + + create Status in Panel + set the style of Status to + `flex:1;text-align:right;margin-right:0.5em;border:1px solid black;padding-right:0.5em;color:green` create Link in Buttons create New in Link @@ -151,6 +163,11 @@ L2: set attribute `src` of Delete to `resources/icon/trash.png` set attribute `title` of Delete to `Delete` create Link in Buttons + create FileMan in Link + set the style of FileMan to `width:40px;margin-right:1.5em` + set attribute `src` of FileMan to `resources/icon/fileman.png` + set attribute `title` of FileMan to `File Manager` + create Link in Buttons create RunStop in Link set the style of RunStop to `width:40px;margin-right:1.5em` set attribute `src` of RunStop to `resources/icon/run.png` @@ -161,13 +178,12 @@ L2: set attribute `src` of User to `resources/icon/user.png` set attribute `title` of User to `Login` - create Status in Buttons - if Mobile set the style of Status to `height:1em` - else set the style of Status to `float:right;margin:0.5em 70px 0 0;color:green` - create Player in Left set the style of Player to `margin:0.5em` iwsy init + + create FileManPanel in Left + set the style of FileManPanel to `flex:1;display:none` ! The right-hand panel create Right in Body @@ -253,7 +269,7 @@ L2: set the content of Status to `No script name has been given` go to ResetStatus end - if UserRecord rest post Presentation to `save/` cat UserHome cat `/` cat Name + if UserRecord rest post Presentation to `save/` cat `users/` cat UserHome cat `/` cat Name else put Presentation into storage as CurrentName end end @@ -287,7 +303,7 @@ L2: begin put Presentation into Content json format Content - rest post Content to `save/` cat UserHome cat `/` cat Name + rest post Content to `save/` cat `users/` cat `users/` cat UserHome cat `/` cat Name end else put Presentation into storage as Name put Presentation into LastSavedState @@ -315,7 +331,7 @@ L2: end if confirm `Are you sure you want to delete "` cat Name cat `"?` begin - if UserRecord rest post to `delete/` cat UserHome cat `/` cat Name + if UserRecord rest post to `delete/` cat `users/` cat UserHome cat `/` cat Name else remove Name from storage gosub to SetStatusGreen set the content of Status to `Script "` cat Name cat `" deleted` @@ -327,12 +343,28 @@ L2: end end + on click FileMan + begin + if Running stop + if UserRecord is empty stop + if FileManModule is not running + begin + rest get Script from `/resources/ecs/fileman.txt?v=` cat now + run Script with FileManPanel as FileManModule + end + set style `display` of Player to `none` + set style `display` of FileManPanel to `block` + send to FileManModule + end + on click RunStop go to DoRunStop + on click User begin if UserRecord begin put empty into UserRecord + put empty into storage as `.user` set attribute `src` of User to `resources/icon/user.png` set attribute `title` of User to `Login` gosub to SetStatusRed @@ -385,6 +417,8 @@ L2: else if Action is `user` begin put property `user` of Message into UserRecord +print UserRecord + put UserRecord into storage as `.user` put property `home` of UserRecord into UserHome set attribute `src` of User to `resources/icon/user-loggedin.png` set attribute `title` of User to `Logged in as ` cat property `name` of UserRecord @@ -465,13 +499,12 @@ SaveChanges: return DoOpen: - clear FileIsOpen if Presentation is not LastSavedState begin if confirm `Content has changed. Do you want to save it?` begin - if UserRecord rest post Content to `save/` cat UserHome cat `/` cat Name + if UserRecord rest post Content to `save/` cat `users/` cat UserHome cat `/` cat Name else put Content into storage as Name end end @@ -494,7 +527,7 @@ DoOpen: ! Fill the browser with content from the server if UserRecord begin - rest get Files from `list/` cat UserHome + rest get Files from `list/` cat `users/` cat UserHome cat `/scripts` put the json count of Files into FileCount put empty into Content put 0 into N @@ -567,7 +600,8 @@ SelectFile: index File to the index of FileName set the content of NameEditor to File put File into CurrentScriptName - if UserRecord rest get Presentation from `/resources/` cat UserHome cat `/` cat File cat `?v=` cat now + if UserRecord rest get Presentation from + `/resources/users/` cat UserHome cat `/scripts/` cat File cat `?v=` cat now else get Presentation from storage as File put Presentation into LastSavedState gosub to UpdateCurrentSection @@ -606,6 +640,7 @@ DoRunStop: end else begin + set style `display` of Player to `block` put property `steps` of Presentation into Item if the json count of Item is 0 stop put element 0 of Item into Item @@ -646,4 +681,4 @@ ClearStepsButtons: set Message to object set property `action` of Message to `clear` send Message to StepsModule - return + return \ No newline at end of file diff --git a/iwsy/resources/icon/fileman.png b/iwsy/resources/icon/fileman.png new file mode 100644 index 0000000..8bfaa07 Binary files /dev/null and b/iwsy/resources/icon/fileman.png differ diff --git a/iwsy/resources/icon/user-loggedin.png b/iwsy/resources/icon/user-loggedin.png index f008575..3867c0c 100644 Binary files a/iwsy/resources/icon/user-loggedin.png and b/iwsy/resources/icon/user-loggedin.png differ diff --git a/iwsy/resources/icon/user.png b/iwsy/resources/icon/user.png index e79b633..87977a0 100644 Binary files a/iwsy/resources/icon/user.png and b/iwsy/resources/icon/user.png differ diff --git a/js/easycoder/Browser.js b/js/easycoder/Browser.js index 4a911fd..059b256 100644 --- a/js/easycoder/Browser.js +++ b/js/easycoder/Browser.js @@ -2591,12 +2591,23 @@ const EasyCoder_Browser = { } } }; + ajax.onerror = function (data) { + if (command.onError) { + program.errorMessage = this.responseText; + program.run(command.onError); + } else { + const error = this.responseText; + program.runtimeError(command.lino, error); + } + }; program.ajaxCommand = command; const rest = document.getElementById(`easycoder-rest`); if (!rest) { program.runtimeError(command.lino, `No REST server defined`); } - const postpath = path.startsWith(`http`) ? path : `${window.location.origin}${rest}/${path}`; + const postpath = path.startsWith(`http`) + ? path + : `${window.location.origin}/${rest.innerText}/${path}`; ajax.open(`POST`, postpath); ajax.send(formData); }