diff --git a/public/dist/scripts/app-all.js b/public/dist/scripts/app-all.js index bacf1159a..adb894c8e 100644 --- a/public/dist/scripts/app-all.js +++ b/public/dist/scripts/app-all.js @@ -1990,128 +1990,147 @@ function join(string1,string2){var separator=separatingNewlines(string1,string2) function canConvert(input){return(input!=null&&(typeof input==='string'||(input.nodeType&&(input.nodeType===1||input.nodeType===9||input.nodeType===11))))} return TurndownService;}()); -window.ls=window.ls||{};window.ls.container=(function(){let stock={};let listeners={};let namespaces={};let set=function(name,object,singleton,watch=true){if(typeof name!=="string"){throw new Error("var name must be of type string");} -if(typeof singleton!=="boolean"){throw new Error('var singleton "'+ -singleton+'" of service "'+ -name+'" must be of type boolean');} +window.ls=window.ls||{};window.ls.container=function(){let stock={};let listeners={};let namespaces={};let set=function(name,object,singleton,watch=true){if(typeof name!=='string'){throw new Error('var name must be of type string');} +if(typeof singleton!=='boolean'){throw new Error('var singleton "'+singleton+'" of service "'+name+'" must be of type boolean');} stock[name]={name:name,object:object,singleton:singleton,instance:null,watch:watch,};if(!watch){return this;} let binds=listeners[name]||{};for(let key in binds){if(binds.hasOwnProperty(key)){document.dispatchEvent(new CustomEvent(key));}} -return this;};let get=function(name){let service=undefined!==stock[name]?stock[name]:null;if(null==service){return null;} +return this;};let get=function(name){let service=(undefined!==stock[name])?stock[name]:null;if(null==service){return null;} if(service.instance){return service.instance;} -let instance=typeof service.object==="function"?this.resolve(service.object):service.object;let skip=false;if(service.watch&&name!=="window"&&name!=="document"&&name!=="element"&&typeof instance==="object"&&instance!==null){let handler={name:service.name,watch:function(){},get:function(target,key){if(key==="__name"){return this.name;} +let instance=(typeof service.object==='function')?this.resolve(service.object):service.object;let skip=false;if(service.watch&&name!=='window'&&name!=='document'&&name!=='element'&&typeof instance==='object'&&instance!==null){let handler={name:service.name,watch:function(){},get:function(target,key){if(key==="__name"){return this.name;} if(key==="__watch"){return this.watch;} if(key==="__proxy"){return true;} -if(typeof target[key]==="object"&&target[key]!==null&&!target[key].__proxy){let handler=Object.assign({},this);handler.name=handler.name+"."+key;return new Proxy(target[key],handler);}else{return target[key];}},set:function(target,key,value,receiver){if(key==="__name"){return(this.name=value);} -if(key==="__watch"){return(this.watch=value);} -target[key]=value;let path=receiver.__name+"."+key;document.dispatchEvent(new CustomEvent(path+".changed"));if(skip){return true;} -skip=true;container.set("$prop",key,true);container.set("$value",value,true);container.resolve(this.watch);container.set("$key",null,true);container.set("$value",null,true);skip=false;return true;},};instance=new Proxy(instance,handler);} +if(key!=='constructor'&&typeof target[key]==='function'&&([Map,Set,WeakMap,WeakSet].includes(target.constructor))){return target[key].bind(target);} +if(typeof target[key]==='object'&&target[key]!==null&&!target[key].__proxy){let handler=Object.assign({},this);handler.name=handler.name+'.'+key;return new Proxy(target[key],handler)} +else{return target[key];}},set:function(target,key,value,receiver){if(key==="__name"){return this.name=value;} +if(key==="__watch"){return this.watch=value;} +target[key]=value;let path=receiver.__name+'.'+key;document.dispatchEvent(new CustomEvent(path+'.changed'));if(skip){return true;} +skip=true;container.set('$prop',key,true);container.set('$value',value,true);container.resolve(this.watch);container.set('$key',null,true);container.set('$value',null,true);skip=false;return true;},};instance=new Proxy(instance,handler);} if(service.singleton){service.instance=instance;} return instance;};let resolve=function(target){if(!target){return()=>{};} -let self=this;const REGEX_COMMENTS=/((\/\/.*$)|(\/\*[\s\S]*?\*\/))/gm;const REGEX_FUNCTION_PARAMS=/(?:\s*(?:function\s*[^(]*)?\s*)((?:[^'"]|(?:(?:(['"])(?:(?:.*?[^\\]\2)|\2))))*?)\s*(?=(?:=>)|{)/m;const REGEX_PARAMETERS_VALUES=/\s*([\w\\$]+)\s*(?:=\s*((?:(?:(['"])(?:\3|(?:.*?[^\\]\3)))((\s*\+\s*)(?:(?:(['"])(?:\6|(?:.*?[^\\]\6)))|(?:[\w$]*)))*)|.*?))?\s*(?:,|$)/gm;function getParams(func){let functionAsString=func.toString();let params=[];let match;functionAsString=functionAsString.replace(REGEX_COMMENTS,"");functionAsString=functionAsString.match(REGEX_FUNCTION_PARAMS)[1];if(functionAsString.charAt(0)==="("){functionAsString=functionAsString.slice(1,-1);} -while((match=REGEX_PARAMETERS_VALUES.exec(functionAsString))){params.push(match[1]);} +let self=this;const REGEX_COMMENTS=/((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;const REGEX_FUNCTION_PARAMS=/(?:\s*(?:function\s*[^(]*)?\s*)((?:[^'"]|(?:(?:(['"])(?:(?:.*?[^\\]\2)|\2))))*?)\s*(?=(?:=>)|{)/m;const REGEX_PARAMETERS_VALUES=/\s*([\w\\$]+)\s*(?:=\s*((?:(?:(['"])(?:\3|(?:.*?[^\\]\3)))((\s*\+\s*)(?:(?:(['"])(?:\6|(?:.*?[^\\]\6)))|(?:[\w$]*)))*)|.*?))?\s*(?:,|$)/gm;function getParams(func){let functionAsString=func.toString();let params=[];let match;functionAsString=functionAsString.replace(REGEX_COMMENTS,'');functionAsString=functionAsString.match(REGEX_FUNCTION_PARAMS)[1];if(functionAsString.charAt(0)==='('){functionAsString=functionAsString.slice(1,-1);} +while(match=REGEX_PARAMETERS_VALUES.exec(functionAsString)){params.push(match[1]);} return params;} -let args=getParams(target);return target.apply(target,args.map(function(value){return self.get(value.trim());}));};let path=function(path,value,type){type=type?type:"assign";path=container.scope(path).split(".");let name=path.shift();let object=container.get(name);let result=null;while(path.length>1){if(!object){return null;} +let args=getParams(target);return target.apply(target,args.map(function(value){return self.get(value.trim());}));};let path=function(path,value,type){type=(type)?type:'assign';path=container.scope(path).split('.');let name=path.shift();let object=container.get(name);let result=null;while(path.length>1){if(!object){return null;} object=object[path.shift()];} -let shift=path.shift();if(value!==null&&value!==undefined&&object&&shift&&(object[shift]!==undefined||object[shift]!==null)){switch(type){case"append":if(!Array.isArray(object[shift])){object[shift]=[];} -object[shift].push(value);break;case"prepend":if(!Array.isArray(object[shift])){object[shift]=[];} -object[shift].unshift(value);break;case"splice":if(!Array.isArray(object[shift])){object[shift]=[];} +let shift=path.shift();if(value!==null&&value!==undefined&&object&&shift&&(object[shift]!==undefined||object[shift]!==null)){switch(type){case'append':if(!Array.isArray(object[shift])){object[shift]=[];} +object[shift].push(value);break;case'prepend':if(!Array.isArray(object[shift])){object[shift]=[];} +object[shift].unshift(value);break;case'splice':if(!Array.isArray(object[shift])){object[shift]=[];} object[shift].splice(value,1);break;default:object[shift]=value;} return true;} if(!object){return null;} -if(!shift){result=object;}else{return object[shift];} -return result;};let bind=function(element,path,callback){let event=container.scope(path)+".changed";let service=event.split(".").slice(0,1).pop();let debug=element.getAttribute("data-debug")||false;listeners[service]=listeners[service]||{};listeners[service][event]=true;let printer=(function(x){return function(){if(!document.body.contains(element)){element=null;document.removeEventListener(event,printer,false);return false;} -let oldNamespaces=namespaces;namespaces=x;callback();namespaces=oldNamespaces;};})(Object.assign({},namespaces));document.addEventListener(event,printer);};let addNamespace=function(key,scope){namespaces[key]=scope;return this;};let removeNamespace=function(key){delete namespaces[key];return this;};let scope=function(path){for(let[key,value]of Object.entries(namespaces)){path=path.indexOf(".")>-1?path.replace(key+".",value+"."):path.replace(key,value);} -return path;};let container={set:set,get:get,resolve:resolve,path:path,bind:bind,scope:scope,addNamespace:addNamespace,removeNamespace:removeNamespace,stock:stock,listeners:listeners,namespaces:namespaces,};set("container",container,true,false);return container;})();window.ls.container.set("http",function(document){let globalParams=[],globalHeaders=[];let addParam=function(url,param,value){param=encodeURIComponent(param);let a=document.createElement("a");param+=value?"="+encodeURIComponent(value):"";a.href=url;a.search+=(a.search?"&":"")+param;return a.href;};let request=function(method,url,headers,payload,progress){let i;if(-1===["GET","POST","PUT","DELETE","TRACE","HEAD","OPTIONS","CONNECT","PATCH",].indexOf(method)){throw new Error("var method must contain a valid HTTP method name");} -if(typeof url!=="string"){throw new Error("var url must be of type string");} -if(typeof headers!=="object"){throw new Error("var headers must be of type object");} -if(typeof url!=="string"){throw new Error("var url must be of type string");} +if(!shift){result=object;} +else{return object[shift];} +return result;};let bind=function(element,path,callback){let event=container.scope(path)+'.changed';let service=event.split('.').slice(0,1).pop();let debug=element.getAttribute('data-debug')||false;listeners[service]=listeners[service]||{};listeners[service][event]=true;let printer=(function(x){return function(){if(!document.body.contains(element)){element=null;document.removeEventListener(event,printer,false);return false;} +let oldNamespaces=namespaces;namespaces=x;callback();namespaces=oldNamespaces;}}(Object.assign({},namespaces)));document.addEventListener(event,printer);};let addNamespace=function(key,scope){namespaces[key]=scope;return this;} +let removeNamespace=function(key){delete namespaces[key];return this;} +let scope=function(path){for(let[key,value]of Object.entries(namespaces)){path=(path.indexOf('.')>-1)?path.replace(key+'.',value+'.'):path.replace(key,value);} +return path;} +let container={set:set,get:get,resolve:resolve,path:path,bind:bind,scope:scope,addNamespace:addNamespace,removeNamespace:removeNamespace,stock:stock,listeners:listeners,namespaces:namespaces,};set('container',container,true,false);return container;}();window.ls.container.set('http',function(document){let globalParams=[],globalHeaders=[];let addParam=function(url,param,value){param=encodeURIComponent(param);let a=document.createElement('a');param+=(value?"="+encodeURIComponent(value):"");a.href=url;a.search+=(a.search?"&":"")+param;return a.href;};let request=function(method,url,headers,payload,progress){let i;if(-1===['GET','POST','PUT','DELETE','TRACE','HEAD','OPTIONS','CONNECT','PATCH'].indexOf(method)){throw new Error('var method must contain a valid HTTP method name');} +if(typeof url!=='string'){throw new Error('var url must be of type string');} +if(typeof headers!=='object'){throw new Error('var headers must be of type object');} +if(typeof url!=='string'){throw new Error('var url must be of type string');} for(i=0;i-1?part.substr(0,eq):part;let val=eq>-1?decodeURIComponent(part.substr(eq+1)):"";let from=key.indexOf("[");if(from===-1){result[decodeURIComponent(key)]=val;}else{let to=key.indexOf("]");let index=decodeURIComponent(key.substring(from+1,to));key=decodeURIComponent(key.substring(0,from));if(!result[key]){result[key]=[];} -if(!index){result[key].push(val);}else{result[key][index]=val;}}});return result;};let states=[];let params=getJsonFromUrl(window.location.search);let hash=window.location.hash;let current=null;let previous=null;let getPrevious=()=>previous;let getCurrent=()=>current;let setPrevious=(value)=>{previous=value;return this;};let setCurrent=(value)=>{current=value;return this;};let setParam=function(key,value){params[key]=value;return this;};let getParam=function(key,def){if(key in params){return params[key];} -return def;};let getParams=function(){return params;};let getURL=function(){return window.location.href;};let add=function(path,view){if(typeof path!=="string"){throw new Error("path must be of type string");} -if(typeof view!=="object"){throw new Error("view must be of type object");} -states[states.length++]={path:path,view:view};return this;};let match=function(location){let url=location.pathname;states.sort(function(a,b){return b.path.length-a.path.length;});states.sort(function(a,b){let n=b.path.split("/").length-a.path.split("/").length;if(n!==0){return n;} -return b.path.length-a.path.length;});for(let i=0;i{let reference=match.substring(2,match.length-2).replace("['",".").replace("']","").trim();reference=reference.split("|");let path=container.scope(reference[0]||"");let result=container.path(path);path=container.scope(path);if(!paths.includes(path)){paths.push(path);} +if(!object.selector){throw new Error('View component is missing a selector attribute');} +stock[object.selector]=object;return this;},render:function(element,callback){parse(element,false,callback);element.dispatchEvent(new window.Event('rendered',{bubbles:false}));}}},true,false);window.ls.container.set('router',function(window){let getJsonFromUrl=function(URL){let query;if(URL){let pos=location.search.indexOf('?');if(pos===-1)return[];query=location.search.substr(pos+1);}else{query=location.search.substr(1);} +let result={};query.split('&').forEach(function(part){if(!part){return;} +part=part.split('+').join(' ');let eq=part.indexOf('=');let key=eq>-1?part.substr(0,eq):part;let val=eq>-1?decodeURIComponent(part.substr(eq+1)):'';let from=key.indexOf('[');if(from===-1){result[decodeURIComponent(key)]=val;} +else{let to=key.indexOf(']');let index=decodeURIComponent(key.substring(from+1,to));key=decodeURIComponent(key.substring(0,from));if(!result[key]){result[key]=[];} +if(!index){result[key].push(val);} +else{result[key][index]=val;}}});return result;};let states=[];let params=getJsonFromUrl(window.location.search);let hash=window.location.hash;let current=null;let previous=null;let getPrevious=()=>previous;let getCurrent=()=>current;let setPrevious=(value)=>{previous=value;return this;};let setCurrent=(value)=>{current=value;return this;};let setParam=function(key,value){params[key]=value;return this;};let getParam=function(key,def){if(key in params){return params[key];} +return def;};let getParams=function(){return params;};let getURL=function(){return window.location.href;};let add=function(path,view){if(typeof path!=='string'){throw new Error('path must be of type string');} +if(typeof view!=='object'){throw new Error('view must be of type object');} +states[states.length++]={path:path,view:view};return this;};let match=function(location){let url=location.pathname;if(url.endsWith('/')){url=url.slice(0,-1);} +states.sort(function(a,b){return b.path.length-a.path.length;});states.sort(function(a,b){let n=b.path.split('/').length-a.path.split('/').length;if(n!==0){return n;} +return b.path.length-a.path.length;});for(let i=0;i{let reference=match.substring(2,match.length-2).replace('[\'','.').replace('\']','').trim();reference=reference.split('|');let path=container.scope((reference[0]||''));let result=container.path(path);path=container.scope(path);if(!paths.includes(path)){paths.push(path);} if(reference.length>=2){for(let i=1;ipaths,};},true,false);window.ls.container.set("filter",function(container){let filters={};let add=function(name,callback){filters[name]=callback;return this;};let apply=function(name,value){container.set("$value",value,true,false);return container.resolve(filters[name]);};add("uppercase",($value)=>{if(typeof $value!=="string"){return $value;} -return $value.toUpperCase();});add("lowercase",($value)=>{if(typeof $value!=="string"){return $value;} -return $value.toLowerCase();});return{add:add,apply:apply};},true,false);window.ls.container.get("filter").add("escape",($value)=>{if(typeof $value!=="string"){return $value;} -return $value.replace(/&/g,"&").replace(//g,">").replace(/\"/g,""").replace(/\'/g,"'").replace(/\//g,"/");});window.ls=window.ls||{};window.ls.container.set("window",window,true,false).set("document",window.document,true,false).set("element",window.document,true,false);window.ls.run=function(window){try{this.view.render(window.document);}catch(error){let handler=window.ls.container.resolve(this.error);handler(error);}};window.ls.error=()=>{return(error)=>{console.error("ls-error",error.message,error.stack,error.toString());};};window.ls.router=window.ls.container.get("router");window.ls.view=window.ls.container.get("view");window.ls.filter=window.ls.container.get("filter");window.ls.container.get("view").add({selector:"data-ls-router",controller:function(element,window,document,view,router){let firstFromServer=element.getAttribute("data-first-from-server")==="true";let scope={selector:"data-ls-scope",template:false,repeat:true,controller:function(){},};let init=function(route){let count=parseInt(element.getAttribute("data-ls-scope-count")||0);element.setAttribute("data-ls-scope-count",count+1);window.scrollTo(0,0);if(window.document.body.scrollTo){window.document.body.scrollTo(0,0);} +if(null===result||undefined===result){result=def;} +else if(typeof result==='object'){result=JSON.stringify(result,null,4);} +else if(((typeof result==='object')||(typeof result==='string'))&&cast){result='\''+result+'\'';} +return result;}).replace(/\\{/g,"{").replace(/\\}/g,"}");},getPaths:()=>paths,}},true,false);window.ls.container.set('filter',function(container){let filters={};let add=function(name,callback){filters[name]=callback;return this;};let apply=function(name,value){container.set('$value',value,true,false);return container.resolve(filters[name]);};add('uppercase',($value)=>{if(typeof $value!=='string'){return $value;} +return $value.toUpperCase();});add('lowercase',($value)=>{if(typeof $value!=='string'){return $value;} +return $value.toLowerCase();});return{add:add,apply:apply}},true,false);window.ls.container.get('filter').add('escape',$value=>{if(typeof $value!=='string'){return $value;} +return $value.replace(/&/g,'&').replace(//g,'>').replace(/\"/g,'"').replace(/\'/g,''').replace(/\//g,'/');});window.ls=window.ls||{};window.ls.container.set('window',window,true,false).set('document',window.document,true,false).set('element',window.document,true,false);window.ls.run=function(window){try{this.view.render(window.document);} +catch(error){let handler=window.ls.container.resolve(this.error);handler(error);}};window.ls.error=()=>{return error=>{console.error('ls-error',error.message,error.stack,error.toString());}};window.ls.router=window.ls.container.get('router');window.ls.view=window.ls.container.get('view');window.ls.filter=window.ls.container.get('filter');window.ls.container.get('view').add({selector:'data-ls-router',controller:function(element,window,document,view,router){let firstFromServer=(element.getAttribute('data-first-from-server')==='true');let scope={selector:'data-ls-scope',template:false,repeat:true,controller:function(){},};let init=function(route){let count=parseInt(element.getAttribute('data-ls-scope-count')||0);element.setAttribute('data-ls-scope-count',count+1);window.scrollTo(0,0);if(window.document.body.scrollTo){window.document.body.scrollTo(0,0);} router.reset();if(null===route){return;} -scope.template=undefined!==route.view.template?route.view.template:null;scope.controller=undefined!==route.view.controller?route.view.controller:function(){};document.dispatchEvent(new CustomEvent("state-change"));if(firstFromServer&&null===router.getPrevious()){scope.template="";document.dispatchEvent(new CustomEvent("state-changed"));}else if(count===1){view.render(element,function(){document.dispatchEvent(new CustomEvent("state-changed"));});}else if(null!==router.getPrevious()){view.render(element,function(){document.dispatchEvent(new CustomEvent("state-changed"));});}};let findParent=function(tagName,el){if((el.nodeName||el.tagName).toLowerCase()===tagName.toLowerCase()){return el;} -while((el=el.parentNode)){if((el.nodeName||el.tagName).toLowerCase()===tagName.toLowerCase()){return el;}} -return null;};element.removeAttribute("data-ls-router");element.setAttribute("data-ls-scope","");element.setAttribute("data-ls-scope-count",1);view.add(scope);document.addEventListener("click",function(event){let target=findParent("a",event.target);if(!target){return false;} +scope.template=(undefined!==route.view.template)?route.view.template:null;scope.controller=(undefined!==route.view.controller)?route.view.controller:function(){};document.dispatchEvent(new CustomEvent('state-change'));if(firstFromServer&&null===router.getPrevious()){scope.template='';document.dispatchEvent(new CustomEvent('state-changed'));} +else if(count===1){view.render(element,function(){document.dispatchEvent(new CustomEvent('state-changed'));});} +else if(null!==router.getPrevious()){view.render(element,function(){document.dispatchEvent(new CustomEvent('state-changed'));});}};let findParent=function(tagName,el){if((el.nodeName||el.tagName).toLowerCase()===tagName.toLowerCase()){return el;} +while(el=el.parentNode){if((el.nodeName||el.tagName).toLowerCase()===tagName.toLowerCase()){return el;}} +return null;};element.removeAttribute('data-ls-router');element.setAttribute('data-ls-scope','');element.setAttribute('data-ls-scope-count',1);view.add(scope);document.addEventListener('click',function(event){let target=findParent('a',event.target);if(!target){return false;} if(!target.href){return false;} -if(event.metaKey){return false;} -if(target.hasAttribute("target")&&"_blank"===target.getAttribute("target")){return false;} +if((event.metaKey)){return false;} +if((target.hasAttribute('target'))&&('_blank'===target.getAttribute('target'))){return false;} if(target.hostname!==window.location.hostname){return false;} let route=router.match(target);if(null===route){return false;} event.preventDefault();if(window.location===target.href){return false;} -route.view.state=undefined===route.view.state?true:route.view.state;if(true===route.view.state){if(router.getPrevious()&&router.getPrevious().view&&router.getPrevious().view.scope!==route.view.scope){window.location.href=target.href;return false;} -window.history.pushState({},"Unknown",target.href);} -init(route);return true;});window.addEventListener("popstate",function(){init(router.match(window.location));});window.addEventListener("hashchange",function(){init(router.match(window.location));});init(router.match(window.location));},});window.ls.container.get("view").add({selector:"data-ls-attrs",controller:function(element,expression,container){let attrs=element.getAttribute("data-ls-attrs").trim().split(",");let paths=[];let debug=element.getAttribute("data-debug")||false;let check=()=>{container.set("element",element,true,false);if(debug){console.info("debug-ls-attrs attributes:",attrs);} -for(let i=0;i{container.set('element',element,true,false);if(debug){console.info('debug-ls-attrs attributes:',attrs);} +for(let i=0;i{for(let i=0;i{for(let i=0;i-1;value=element.value;}catch{return null;}} -if(bind){element.addEventListener("change",()=>{for(let i=0;i-1));value=element.value;} +catch{return null;}} +if(bind){element.addEventListener('change',()=>{for(let i=0;i-1){value.splice(index,1);} container.path(paths[i],value);}});} return;} -if(element.value!==value){element.value=value;element.dispatchEvent(new Event("change"));} -if(bind){element.addEventListener("input",sync);element.addEventListener("change",sync);}}else{if(element.textContent!=value){element.textContent=value;}}};let sync=(()=>{return()=>{if(debug){console.info("debug-ls-bind","sync-path",paths);console.info("debug-ls-bind","sync-syntax",syntax);console.info("debug-ls-bind","sync-syntax-parsed",parsedSyntax);console.info("debug-ls-bind","sync-value",element.value);} -for(let i=0;i{return()=>{if(debug){console.info('debug-ls-bind','sync-path',paths);console.info('debug-ls-bind','sync-syntax',syntax);console.info('debug-ls-bind','sync-syntax-parsed',parsedSyntax);console.info('debug-ls-bind','sync-value',element.value);} +for(let i=0;i{echo(expression.parse(parsedSyntax),false);});path.pop();}}},});window.ls.container.get("view").add({selector:"data-ls-if",controller:function(element,expression,container,view){let result="";let syntax=element.getAttribute("data-ls-if")||"";let debug=element.getAttribute("data-debug")||false;let paths=[];let check=()=>{if(debug){console.info("debug-ls-if",expression.parse(syntax.replace(/(\r\n|\n|\r)/gm," "),"undefined",true));} -try{result=eval(expression.parse(syntax.replace(/(\r\n|\n|\r)/gm," "),"undefined",true));}catch(error){throw new Error('Failed to evaluate expression "'+ -syntax+' (resulted with: "'+ -result+'")": '+ -error);} -if(debug){console.info("debug-ls-if result:",result);} -paths=expression.getPaths();let prv=element.$lsSkip;element.$lsSkip=!result;if(!result){element.style.visibility="hidden";element.style.display="none";}else{element.style.removeProperty("display");element.style.removeProperty("visibility");} -if(prv===true&&element.$lsSkip===false){view.render(element);}};check();for(let i=0;i{echo(expression.parse(parsedSyntax),false);});path.pop();}}}});window.ls.container.get('view').add({selector:'data-ls-if',controller:function(element,expression,container,view){let result='';let syntax=element.getAttribute('data-ls-if')||'';let debug=element.getAttribute('data-debug')||false;let paths=[];let check=()=>{if(debug){console.info('debug-ls-if',expression.parse(syntax.replace(/(\r\n|\n|\r)/gm,' '),'undefined',true));} +try{result=(eval(expression.parse(syntax.replace(/(\r\n|\n|\r)/gm,' '),'undefined',true)));} +catch(error){throw new Error('Failed to evaluate expression "'+syntax+' (resulted with: "'+result+'")": '+error);} +if(debug){console.info('debug-ls-if result:',result);} +paths=expression.getPaths();let prv=element.$lsSkip;element.$lsSkip=!result;if(!result){element.style.visibility='hidden';element.style.display='none';} +else{element.style.removeProperty('display');element.style.removeProperty('visibility');} +if(prv===true&&element.$lsSkip===false){view.render(element)}};check();for(let i=0;i{let context=expr+"."+index;container.addNamespace(as,context);if(debug){console.info("debug-ls-loop","index",index);console.info("debug-ls-loop","context",context);console.info("debug-ls-loop","context-path",container.path(context).name);console.info("debug-ls-loop","namespaces",container.namespaces);} +children[prop]=template.cloneNode(true);element.appendChild(children[prop]);(index=>{let context=expr+'.'+index;container.addNamespace(as,context);if(debug){console.info('debug-ls-loop','index',index);console.info('debug-ls-loop','context',context);console.info('debug-ls-loop','context-path',container.path(context).name);console.info('debug-ls-loop','namespaces',container.namespaces);} container.set(as,container.path(context),true,watch);container.set(key,index,true,false);view.render(children[prop]);container.removeNamespace(as);})(prop);} -element.dispatchEvent(new Event("looped"));};let template=element.children.length===1?element.children[0]:window.document.createElement("li");echo();container.bind(element,expr+".length",echo);let path=(expr+".length").split(".");while(path.length){container.bind(element,path.join("."),echo);path.pop();}},});window.ls.container.get("view").add({selector:"data-ls-template",template:false,controller:function(element,view,http,expression,document,container){let template=element.getAttribute("data-ls-template")||"";let type=element.getAttribute("data-type")||"url";let debug=element.getAttribute("data-debug")||false;let paths=[];let check=function(init=false){let source=expression.parse(template);paths=expression.getPaths();element.innerHTML="";if("script"===type){let inlineTemplate=document.getElementById(source);if(inlineTemplate&&inlineTemplate.innerHTML){element.innerHTML=inlineTemplate.innerHTML;element.dispatchEvent(new CustomEvent("template-loaded",{bubbles:true,cancelable:false,}));}else{if(debug){console.error('Missing template "'+source+'"');}} +element.dispatchEvent(new Event('looped'));};let template=(element.children.length===1)?element.children[0]:window.document.createElement('li');echo();container.bind(element,expr+'.length',echo);let path=(expr+'.length').split('.');while(path.length){container.bind(element,path.join('.'),echo);path.pop();}}});window.ls.container.get('view').add({selector:'data-ls-template',template:false,controller:function(element,view,http,expression,document,container){let template=element.getAttribute('data-ls-template')||'';let type=element.getAttribute('data-type')||'url';let debug=element.getAttribute('data-debug')||false;let paths=[];let check=function(init=false){let source=expression.parse(template);paths=expression.getPaths();element.innerHTML='';if('script'===type){let inlineTemplate=document.getElementById(source);if(inlineTemplate&&inlineTemplate.innerHTML){element.innerHTML=inlineTemplate.innerHTML;element.dispatchEvent(new CustomEvent('template-loaded',{bubbles:true,cancelable:false}));} +else{if(debug){console.error('Missing template "'+source+'"');}} if(!init){view.render(element);} return;} -http.get(source).then((function(element){return function(data){element.innerHTML=data;view.render(element);element.dispatchEvent(new CustomEvent("template-loaded",{bubbles:true,cancelable:false,}));};})(element),function(){throw new Error("Failed loading template");});};check(true);for(let i=0;i{const bars=12;const realtime=window.ls.container.get('realtime');const sleep=ms=>new Promise(resolve=>setTimeout(resolve,ms));let current={};window.ls.container.get('console').subscribe('project',event=>{for(let project in event.payload){current[project]=event.payload[project]??0;}});while(true){let newHistory={};let createdHistory=false;for(const project in current){let history=realtime?.history??{};if(!(project in history)){history[project]=new Array(bars).fill({percentage:0,value:0});} +http.get(source).then(function(element){return function(data){element.innerHTML=data;view.render(element);element.dispatchEvent(new CustomEvent('template-loaded',{bubbles:true,cancelable:false}));}}(element),function(){throw new Error('Failed loading template');});};check(true);for(let i=0;i{const bars=12;const realtime=window.ls.container.get('realtime');const sleep=ms=>new Promise(resolve=>setTimeout(resolve,ms));let current={};window.ls.container.get('console').subscribe('project',event=>{for(let project in event.payload){current[project]=event.payload[project]??0;}});while(true){let newHistory={};let createdHistory=false;for(const project in current){let history=realtime?.history??{};if(!(project in history)){history[project]=new Array(bars).fill({percentage:0,value:0});} history=history[project];history.push({percentage:0,value:current[project]});if(history.length>=bars){history.shift();} const highest=history.reduce((prev,curr)=>{return(curr.value>prev)?curr.value:prev;},0);history=history.map(({percentage,value})=>{createdHistory=true;percentage=value===0?0:((Math.round((value/highest)*10)/10)*100);if(percentage>100)percentage=100;else if(percentage==0&&value!=0)percentage=5;return{percentage:percentage,value:value};}) newHistory[project]=history;} diff --git a/public/dist/scripts/app.js b/public/dist/scripts/app.js index eb5836fcc..10dc12fc0 100644 --- a/public/dist/scripts/app.js +++ b/public/dist/scripts/app.js @@ -1,126 +1,145 @@ -window.ls=window.ls||{};window.ls.container=(function(){let stock={};let listeners={};let namespaces={};let set=function(name,object,singleton,watch=true){if(typeof name!=="string"){throw new Error("var name must be of type string");} -if(typeof singleton!=="boolean"){throw new Error('var singleton "'+ -singleton+'" of service "'+ -name+'" must be of type boolean');} +window.ls=window.ls||{};window.ls.container=function(){let stock={};let listeners={};let namespaces={};let set=function(name,object,singleton,watch=true){if(typeof name!=='string'){throw new Error('var name must be of type string');} +if(typeof singleton!=='boolean'){throw new Error('var singleton "'+singleton+'" of service "'+name+'" must be of type boolean');} stock[name]={name:name,object:object,singleton:singleton,instance:null,watch:watch,};if(!watch){return this;} let binds=listeners[name]||{};for(let key in binds){if(binds.hasOwnProperty(key)){document.dispatchEvent(new CustomEvent(key));}} -return this;};let get=function(name){let service=undefined!==stock[name]?stock[name]:null;if(null==service){return null;} +return this;};let get=function(name){let service=(undefined!==stock[name])?stock[name]:null;if(null==service){return null;} if(service.instance){return service.instance;} -let instance=typeof service.object==="function"?this.resolve(service.object):service.object;let skip=false;if(service.watch&&name!=="window"&&name!=="document"&&name!=="element"&&typeof instance==="object"&&instance!==null){let handler={name:service.name,watch:function(){},get:function(target,key){if(key==="__name"){return this.name;} +let instance=(typeof service.object==='function')?this.resolve(service.object):service.object;let skip=false;if(service.watch&&name!=='window'&&name!=='document'&&name!=='element'&&typeof instance==='object'&&instance!==null){let handler={name:service.name,watch:function(){},get:function(target,key){if(key==="__name"){return this.name;} if(key==="__watch"){return this.watch;} if(key==="__proxy"){return true;} -if(typeof target[key]==="object"&&target[key]!==null&&!target[key].__proxy){let handler=Object.assign({},this);handler.name=handler.name+"."+key;return new Proxy(target[key],handler);}else{return target[key];}},set:function(target,key,value,receiver){if(key==="__name"){return(this.name=value);} -if(key==="__watch"){return(this.watch=value);} -target[key]=value;let path=receiver.__name+"."+key;document.dispatchEvent(new CustomEvent(path+".changed"));if(skip){return true;} -skip=true;container.set("$prop",key,true);container.set("$value",value,true);container.resolve(this.watch);container.set("$key",null,true);container.set("$value",null,true);skip=false;return true;},};instance=new Proxy(instance,handler);} +if(key!=='constructor'&&typeof target[key]==='function'&&([Map,Set,WeakMap,WeakSet].includes(target.constructor))){return target[key].bind(target);} +if(typeof target[key]==='object'&&target[key]!==null&&!target[key].__proxy){let handler=Object.assign({},this);handler.name=handler.name+'.'+key;return new Proxy(target[key],handler)} +else{return target[key];}},set:function(target,key,value,receiver){if(key==="__name"){return this.name=value;} +if(key==="__watch"){return this.watch=value;} +target[key]=value;let path=receiver.__name+'.'+key;document.dispatchEvent(new CustomEvent(path+'.changed'));if(skip){return true;} +skip=true;container.set('$prop',key,true);container.set('$value',value,true);container.resolve(this.watch);container.set('$key',null,true);container.set('$value',null,true);skip=false;return true;},};instance=new Proxy(instance,handler);} if(service.singleton){service.instance=instance;} return instance;};let resolve=function(target){if(!target){return()=>{};} -let self=this;const REGEX_COMMENTS=/((\/\/.*$)|(\/\*[\s\S]*?\*\/))/gm;const REGEX_FUNCTION_PARAMS=/(?:\s*(?:function\s*[^(]*)?\s*)((?:[^'"]|(?:(?:(['"])(?:(?:.*?[^\\]\2)|\2))))*?)\s*(?=(?:=>)|{)/m;const REGEX_PARAMETERS_VALUES=/\s*([\w\\$]+)\s*(?:=\s*((?:(?:(['"])(?:\3|(?:.*?[^\\]\3)))((\s*\+\s*)(?:(?:(['"])(?:\6|(?:.*?[^\\]\6)))|(?:[\w$]*)))*)|.*?))?\s*(?:,|$)/gm;function getParams(func){let functionAsString=func.toString();let params=[];let match;functionAsString=functionAsString.replace(REGEX_COMMENTS,"");functionAsString=functionAsString.match(REGEX_FUNCTION_PARAMS)[1];if(functionAsString.charAt(0)==="("){functionAsString=functionAsString.slice(1,-1);} -while((match=REGEX_PARAMETERS_VALUES.exec(functionAsString))){params.push(match[1]);} +let self=this;const REGEX_COMMENTS=/((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;const REGEX_FUNCTION_PARAMS=/(?:\s*(?:function\s*[^(]*)?\s*)((?:[^'"]|(?:(?:(['"])(?:(?:.*?[^\\]\2)|\2))))*?)\s*(?=(?:=>)|{)/m;const REGEX_PARAMETERS_VALUES=/\s*([\w\\$]+)\s*(?:=\s*((?:(?:(['"])(?:\3|(?:.*?[^\\]\3)))((\s*\+\s*)(?:(?:(['"])(?:\6|(?:.*?[^\\]\6)))|(?:[\w$]*)))*)|.*?))?\s*(?:,|$)/gm;function getParams(func){let functionAsString=func.toString();let params=[];let match;functionAsString=functionAsString.replace(REGEX_COMMENTS,'');functionAsString=functionAsString.match(REGEX_FUNCTION_PARAMS)[1];if(functionAsString.charAt(0)==='('){functionAsString=functionAsString.slice(1,-1);} +while(match=REGEX_PARAMETERS_VALUES.exec(functionAsString)){params.push(match[1]);} return params;} -let args=getParams(target);return target.apply(target,args.map(function(value){return self.get(value.trim());}));};let path=function(path,value,type){type=type?type:"assign";path=container.scope(path).split(".");let name=path.shift();let object=container.get(name);let result=null;while(path.length>1){if(!object){return null;} +let args=getParams(target);return target.apply(target,args.map(function(value){return self.get(value.trim());}));};let path=function(path,value,type){type=(type)?type:'assign';path=container.scope(path).split('.');let name=path.shift();let object=container.get(name);let result=null;while(path.length>1){if(!object){return null;} object=object[path.shift()];} -let shift=path.shift();if(value!==null&&value!==undefined&&object&&shift&&(object[shift]!==undefined||object[shift]!==null)){switch(type){case"append":if(!Array.isArray(object[shift])){object[shift]=[];} -object[shift].push(value);break;case"prepend":if(!Array.isArray(object[shift])){object[shift]=[];} -object[shift].unshift(value);break;case"splice":if(!Array.isArray(object[shift])){object[shift]=[];} +let shift=path.shift();if(value!==null&&value!==undefined&&object&&shift&&(object[shift]!==undefined||object[shift]!==null)){switch(type){case'append':if(!Array.isArray(object[shift])){object[shift]=[];} +object[shift].push(value);break;case'prepend':if(!Array.isArray(object[shift])){object[shift]=[];} +object[shift].unshift(value);break;case'splice':if(!Array.isArray(object[shift])){object[shift]=[];} object[shift].splice(value,1);break;default:object[shift]=value;} return true;} if(!object){return null;} -if(!shift){result=object;}else{return object[shift];} -return result;};let bind=function(element,path,callback){let event=container.scope(path)+".changed";let service=event.split(".").slice(0,1).pop();let debug=element.getAttribute("data-debug")||false;listeners[service]=listeners[service]||{};listeners[service][event]=true;let printer=(function(x){return function(){if(!document.body.contains(element)){element=null;document.removeEventListener(event,printer,false);return false;} -let oldNamespaces=namespaces;namespaces=x;callback();namespaces=oldNamespaces;};})(Object.assign({},namespaces));document.addEventListener(event,printer);};let addNamespace=function(key,scope){namespaces[key]=scope;return this;};let removeNamespace=function(key){delete namespaces[key];return this;};let scope=function(path){for(let[key,value]of Object.entries(namespaces)){path=path.indexOf(".")>-1?path.replace(key+".",value+"."):path.replace(key,value);} -return path;};let container={set:set,get:get,resolve:resolve,path:path,bind:bind,scope:scope,addNamespace:addNamespace,removeNamespace:removeNamespace,stock:stock,listeners:listeners,namespaces:namespaces,};set("container",container,true,false);return container;})();window.ls.container.set("http",function(document){let globalParams=[],globalHeaders=[];let addParam=function(url,param,value){param=encodeURIComponent(param);let a=document.createElement("a");param+=value?"="+encodeURIComponent(value):"";a.href=url;a.search+=(a.search?"&":"")+param;return a.href;};let request=function(method,url,headers,payload,progress){let i;if(-1===["GET","POST","PUT","DELETE","TRACE","HEAD","OPTIONS","CONNECT","PATCH",].indexOf(method)){throw new Error("var method must contain a valid HTTP method name");} -if(typeof url!=="string"){throw new Error("var url must be of type string");} -if(typeof headers!=="object"){throw new Error("var headers must be of type object");} -if(typeof url!=="string"){throw new Error("var url must be of type string");} +if(!shift){result=object;} +else{return object[shift];} +return result;};let bind=function(element,path,callback){let event=container.scope(path)+'.changed';let service=event.split('.').slice(0,1).pop();let debug=element.getAttribute('data-debug')||false;listeners[service]=listeners[service]||{};listeners[service][event]=true;let printer=(function(x){return function(){if(!document.body.contains(element)){element=null;document.removeEventListener(event,printer,false);return false;} +let oldNamespaces=namespaces;namespaces=x;callback();namespaces=oldNamespaces;}}(Object.assign({},namespaces)));document.addEventListener(event,printer);};let addNamespace=function(key,scope){namespaces[key]=scope;return this;} +let removeNamespace=function(key){delete namespaces[key];return this;} +let scope=function(path){for(let[key,value]of Object.entries(namespaces)){path=(path.indexOf('.')>-1)?path.replace(key+'.',value+'.'):path.replace(key,value);} +return path;} +let container={set:set,get:get,resolve:resolve,path:path,bind:bind,scope:scope,addNamespace:addNamespace,removeNamespace:removeNamespace,stock:stock,listeners:listeners,namespaces:namespaces,};set('container',container,true,false);return container;}();window.ls.container.set('http',function(document){let globalParams=[],globalHeaders=[];let addParam=function(url,param,value){param=encodeURIComponent(param);let a=document.createElement('a');param+=(value?"="+encodeURIComponent(value):"");a.href=url;a.search+=(a.search?"&":"")+param;return a.href;};let request=function(method,url,headers,payload,progress){let i;if(-1===['GET','POST','PUT','DELETE','TRACE','HEAD','OPTIONS','CONNECT','PATCH'].indexOf(method)){throw new Error('var method must contain a valid HTTP method name');} +if(typeof url!=='string'){throw new Error('var url must be of type string');} +if(typeof headers!=='object'){throw new Error('var headers must be of type object');} +if(typeof url!=='string'){throw new Error('var url must be of type string');} for(i=0;i-1?part.substr(0,eq):part;let val=eq>-1?decodeURIComponent(part.substr(eq+1)):"";let from=key.indexOf("[");if(from===-1){result[decodeURIComponent(key)]=val;}else{let to=key.indexOf("]");let index=decodeURIComponent(key.substring(from+1,to));key=decodeURIComponent(key.substring(0,from));if(!result[key]){result[key]=[];} -if(!index){result[key].push(val);}else{result[key][index]=val;}}});return result;};let states=[];let params=getJsonFromUrl(window.location.search);let hash=window.location.hash;let current=null;let previous=null;let getPrevious=()=>previous;let getCurrent=()=>current;let setPrevious=(value)=>{previous=value;return this;};let setCurrent=(value)=>{current=value;return this;};let setParam=function(key,value){params[key]=value;return this;};let getParam=function(key,def){if(key in params){return params[key];} -return def;};let getParams=function(){return params;};let getURL=function(){return window.location.href;};let add=function(path,view){if(typeof path!=="string"){throw new Error("path must be of type string");} -if(typeof view!=="object"){throw new Error("view must be of type object");} -states[states.length++]={path:path,view:view};return this;};let match=function(location){let url=location.pathname;states.sort(function(a,b){return b.path.length-a.path.length;});states.sort(function(a,b){let n=b.path.split("/").length-a.path.split("/").length;if(n!==0){return n;} -return b.path.length-a.path.length;});for(let i=0;i{let reference=match.substring(2,match.length-2).replace("['",".").replace("']","").trim();reference=reference.split("|");let path=container.scope(reference[0]||"");let result=container.path(path);path=container.scope(path);if(!paths.includes(path)){paths.push(path);} +if(!object.selector){throw new Error('View component is missing a selector attribute');} +stock[object.selector]=object;return this;},render:function(element,callback){parse(element,false,callback);element.dispatchEvent(new window.Event('rendered',{bubbles:false}));}}},true,false);window.ls.container.set('router',function(window){let getJsonFromUrl=function(URL){let query;if(URL){let pos=location.search.indexOf('?');if(pos===-1)return[];query=location.search.substr(pos+1);}else{query=location.search.substr(1);} +let result={};query.split('&').forEach(function(part){if(!part){return;} +part=part.split('+').join(' ');let eq=part.indexOf('=');let key=eq>-1?part.substr(0,eq):part;let val=eq>-1?decodeURIComponent(part.substr(eq+1)):'';let from=key.indexOf('[');if(from===-1){result[decodeURIComponent(key)]=val;} +else{let to=key.indexOf(']');let index=decodeURIComponent(key.substring(from+1,to));key=decodeURIComponent(key.substring(0,from));if(!result[key]){result[key]=[];} +if(!index){result[key].push(val);} +else{result[key][index]=val;}}});return result;};let states=[];let params=getJsonFromUrl(window.location.search);let hash=window.location.hash;let current=null;let previous=null;let getPrevious=()=>previous;let getCurrent=()=>current;let setPrevious=(value)=>{previous=value;return this;};let setCurrent=(value)=>{current=value;return this;};let setParam=function(key,value){params[key]=value;return this;};let getParam=function(key,def){if(key in params){return params[key];} +return def;};let getParams=function(){return params;};let getURL=function(){return window.location.href;};let add=function(path,view){if(typeof path!=='string'){throw new Error('path must be of type string');} +if(typeof view!=='object'){throw new Error('view must be of type object');} +states[states.length++]={path:path,view:view};return this;};let match=function(location){let url=location.pathname;if(url.endsWith('/')){url=url.slice(0,-1);} +states.sort(function(a,b){return b.path.length-a.path.length;});states.sort(function(a,b){let n=b.path.split('/').length-a.path.split('/').length;if(n!==0){return n;} +return b.path.length-a.path.length;});for(let i=0;i{let reference=match.substring(2,match.length-2).replace('[\'','.').replace('\']','').trim();reference=reference.split('|');let path=container.scope((reference[0]||''));let result=container.path(path);path=container.scope(path);if(!paths.includes(path)){paths.push(path);} if(reference.length>=2){for(let i=1;ipaths,};},true,false);window.ls.container.set("filter",function(container){let filters={};let add=function(name,callback){filters[name]=callback;return this;};let apply=function(name,value){container.set("$value",value,true,false);return container.resolve(filters[name]);};add("uppercase",($value)=>{if(typeof $value!=="string"){return $value;} -return $value.toUpperCase();});add("lowercase",($value)=>{if(typeof $value!=="string"){return $value;} -return $value.toLowerCase();});return{add:add,apply:apply};},true,false);window.ls.container.get("filter").add("escape",($value)=>{if(typeof $value!=="string"){return $value;} -return $value.replace(/&/g,"&").replace(//g,">").replace(/\"/g,""").replace(/\'/g,"'").replace(/\//g,"/");});window.ls=window.ls||{};window.ls.container.set("window",window,true,false).set("document",window.document,true,false).set("element",window.document,true,false);window.ls.run=function(window){try{this.view.render(window.document);}catch(error){let handler=window.ls.container.resolve(this.error);handler(error);}};window.ls.error=()=>{return(error)=>{console.error("ls-error",error.message,error.stack,error.toString());};};window.ls.router=window.ls.container.get("router");window.ls.view=window.ls.container.get("view");window.ls.filter=window.ls.container.get("filter");window.ls.container.get("view").add({selector:"data-ls-router",controller:function(element,window,document,view,router){let firstFromServer=element.getAttribute("data-first-from-server")==="true";let scope={selector:"data-ls-scope",template:false,repeat:true,controller:function(){},};let init=function(route){let count=parseInt(element.getAttribute("data-ls-scope-count")||0);element.setAttribute("data-ls-scope-count",count+1);window.scrollTo(0,0);if(window.document.body.scrollTo){window.document.body.scrollTo(0,0);} +if(null===result||undefined===result){result=def;} +else if(typeof result==='object'){result=JSON.stringify(result,null,4);} +else if(((typeof result==='object')||(typeof result==='string'))&&cast){result='\''+result+'\'';} +return result;}).replace(/\\{/g,"{").replace(/\\}/g,"}");},getPaths:()=>paths,}},true,false);window.ls.container.set('filter',function(container){let filters={};let add=function(name,callback){filters[name]=callback;return this;};let apply=function(name,value){container.set('$value',value,true,false);return container.resolve(filters[name]);};add('uppercase',($value)=>{if(typeof $value!=='string'){return $value;} +return $value.toUpperCase();});add('lowercase',($value)=>{if(typeof $value!=='string'){return $value;} +return $value.toLowerCase();});return{add:add,apply:apply}},true,false);window.ls.container.get('filter').add('escape',$value=>{if(typeof $value!=='string'){return $value;} +return $value.replace(/&/g,'&').replace(//g,'>').replace(/\"/g,'"').replace(/\'/g,''').replace(/\//g,'/');});window.ls=window.ls||{};window.ls.container.set('window',window,true,false).set('document',window.document,true,false).set('element',window.document,true,false);window.ls.run=function(window){try{this.view.render(window.document);} +catch(error){let handler=window.ls.container.resolve(this.error);handler(error);}};window.ls.error=()=>{return error=>{console.error('ls-error',error.message,error.stack,error.toString());}};window.ls.router=window.ls.container.get('router');window.ls.view=window.ls.container.get('view');window.ls.filter=window.ls.container.get('filter');window.ls.container.get('view').add({selector:'data-ls-router',controller:function(element,window,document,view,router){let firstFromServer=(element.getAttribute('data-first-from-server')==='true');let scope={selector:'data-ls-scope',template:false,repeat:true,controller:function(){},};let init=function(route){let count=parseInt(element.getAttribute('data-ls-scope-count')||0);element.setAttribute('data-ls-scope-count',count+1);window.scrollTo(0,0);if(window.document.body.scrollTo){window.document.body.scrollTo(0,0);} router.reset();if(null===route){return;} -scope.template=undefined!==route.view.template?route.view.template:null;scope.controller=undefined!==route.view.controller?route.view.controller:function(){};document.dispatchEvent(new CustomEvent("state-change"));if(firstFromServer&&null===router.getPrevious()){scope.template="";document.dispatchEvent(new CustomEvent("state-changed"));}else if(count===1){view.render(element,function(){document.dispatchEvent(new CustomEvent("state-changed"));});}else if(null!==router.getPrevious()){view.render(element,function(){document.dispatchEvent(new CustomEvent("state-changed"));});}};let findParent=function(tagName,el){if((el.nodeName||el.tagName).toLowerCase()===tagName.toLowerCase()){return el;} -while((el=el.parentNode)){if((el.nodeName||el.tagName).toLowerCase()===tagName.toLowerCase()){return el;}} -return null;};element.removeAttribute("data-ls-router");element.setAttribute("data-ls-scope","");element.setAttribute("data-ls-scope-count",1);view.add(scope);document.addEventListener("click",function(event){let target=findParent("a",event.target);if(!target){return false;} +scope.template=(undefined!==route.view.template)?route.view.template:null;scope.controller=(undefined!==route.view.controller)?route.view.controller:function(){};document.dispatchEvent(new CustomEvent('state-change'));if(firstFromServer&&null===router.getPrevious()){scope.template='';document.dispatchEvent(new CustomEvent('state-changed'));} +else if(count===1){view.render(element,function(){document.dispatchEvent(new CustomEvent('state-changed'));});} +else if(null!==router.getPrevious()){view.render(element,function(){document.dispatchEvent(new CustomEvent('state-changed'));});}};let findParent=function(tagName,el){if((el.nodeName||el.tagName).toLowerCase()===tagName.toLowerCase()){return el;} +while(el=el.parentNode){if((el.nodeName||el.tagName).toLowerCase()===tagName.toLowerCase()){return el;}} +return null;};element.removeAttribute('data-ls-router');element.setAttribute('data-ls-scope','');element.setAttribute('data-ls-scope-count',1);view.add(scope);document.addEventListener('click',function(event){let target=findParent('a',event.target);if(!target){return false;} if(!target.href){return false;} -if(event.metaKey){return false;} -if(target.hasAttribute("target")&&"_blank"===target.getAttribute("target")){return false;} +if((event.metaKey)){return false;} +if((target.hasAttribute('target'))&&('_blank'===target.getAttribute('target'))){return false;} if(target.hostname!==window.location.hostname){return false;} let route=router.match(target);if(null===route){return false;} event.preventDefault();if(window.location===target.href){return false;} -route.view.state=undefined===route.view.state?true:route.view.state;if(true===route.view.state){if(router.getPrevious()&&router.getPrevious().view&&router.getPrevious().view.scope!==route.view.scope){window.location.href=target.href;return false;} -window.history.pushState({},"Unknown",target.href);} -init(route);return true;});window.addEventListener("popstate",function(){init(router.match(window.location));});window.addEventListener("hashchange",function(){init(router.match(window.location));});init(router.match(window.location));},});window.ls.container.get("view").add({selector:"data-ls-attrs",controller:function(element,expression,container){let attrs=element.getAttribute("data-ls-attrs").trim().split(",");let paths=[];let debug=element.getAttribute("data-debug")||false;let check=()=>{container.set("element",element,true,false);if(debug){console.info("debug-ls-attrs attributes:",attrs);} -for(let i=0;i{container.set('element',element,true,false);if(debug){console.info('debug-ls-attrs attributes:',attrs);} +for(let i=0;i{for(let i=0;i{for(let i=0;i-1;value=element.value;}catch{return null;}} -if(bind){element.addEventListener("change",()=>{for(let i=0;i-1));value=element.value;} +catch{return null;}} +if(bind){element.addEventListener('change',()=>{for(let i=0;i-1){value.splice(index,1);} container.path(paths[i],value);}});} return;} -if(element.value!==value){element.value=value;element.dispatchEvent(new Event("change"));} -if(bind){element.addEventListener("input",sync);element.addEventListener("change",sync);}}else{if(element.textContent!=value){element.textContent=value;}}};let sync=(()=>{return()=>{if(debug){console.info("debug-ls-bind","sync-path",paths);console.info("debug-ls-bind","sync-syntax",syntax);console.info("debug-ls-bind","sync-syntax-parsed",parsedSyntax);console.info("debug-ls-bind","sync-value",element.value);} -for(let i=0;i{return()=>{if(debug){console.info('debug-ls-bind','sync-path',paths);console.info('debug-ls-bind','sync-syntax',syntax);console.info('debug-ls-bind','sync-syntax-parsed',parsedSyntax);console.info('debug-ls-bind','sync-value',element.value);} +for(let i=0;i{echo(expression.parse(parsedSyntax),false);});path.pop();}}},});window.ls.container.get("view").add({selector:"data-ls-if",controller:function(element,expression,container,view){let result="";let syntax=element.getAttribute("data-ls-if")||"";let debug=element.getAttribute("data-debug")||false;let paths=[];let check=()=>{if(debug){console.info("debug-ls-if",expression.parse(syntax.replace(/(\r\n|\n|\r)/gm," "),"undefined",true));} -try{result=eval(expression.parse(syntax.replace(/(\r\n|\n|\r)/gm," "),"undefined",true));}catch(error){throw new Error('Failed to evaluate expression "'+ -syntax+' (resulted with: "'+ -result+'")": '+ -error);} -if(debug){console.info("debug-ls-if result:",result);} -paths=expression.getPaths();let prv=element.$lsSkip;element.$lsSkip=!result;if(!result){element.style.visibility="hidden";element.style.display="none";}else{element.style.removeProperty("display");element.style.removeProperty("visibility");} -if(prv===true&&element.$lsSkip===false){view.render(element);}};check();for(let i=0;i{echo(expression.parse(parsedSyntax),false);});path.pop();}}}});window.ls.container.get('view').add({selector:'data-ls-if',controller:function(element,expression,container,view){let result='';let syntax=element.getAttribute('data-ls-if')||'';let debug=element.getAttribute('data-debug')||false;let paths=[];let check=()=>{if(debug){console.info('debug-ls-if',expression.parse(syntax.replace(/(\r\n|\n|\r)/gm,' '),'undefined',true));} +try{result=(eval(expression.parse(syntax.replace(/(\r\n|\n|\r)/gm,' '),'undefined',true)));} +catch(error){throw new Error('Failed to evaluate expression "'+syntax+' (resulted with: "'+result+'")": '+error);} +if(debug){console.info('debug-ls-if result:',result);} +paths=expression.getPaths();let prv=element.$lsSkip;element.$lsSkip=!result;if(!result){element.style.visibility='hidden';element.style.display='none';} +else{element.style.removeProperty('display');element.style.removeProperty('visibility');} +if(prv===true&&element.$lsSkip===false){view.render(element)}};check();for(let i=0;i{let context=expr+"."+index;container.addNamespace(as,context);if(debug){console.info("debug-ls-loop","index",index);console.info("debug-ls-loop","context",context);console.info("debug-ls-loop","context-path",container.path(context).name);console.info("debug-ls-loop","namespaces",container.namespaces);} +children[prop]=template.cloneNode(true);element.appendChild(children[prop]);(index=>{let context=expr+'.'+index;container.addNamespace(as,context);if(debug){console.info('debug-ls-loop','index',index);console.info('debug-ls-loop','context',context);console.info('debug-ls-loop','context-path',container.path(context).name);console.info('debug-ls-loop','namespaces',container.namespaces);} container.set(as,container.path(context),true,watch);container.set(key,index,true,false);view.render(children[prop]);container.removeNamespace(as);})(prop);} -element.dispatchEvent(new Event("looped"));};let template=element.children.length===1?element.children[0]:window.document.createElement("li");echo();container.bind(element,expr+".length",echo);let path=(expr+".length").split(".");while(path.length){container.bind(element,path.join("."),echo);path.pop();}},});window.ls.container.get("view").add({selector:"data-ls-template",template:false,controller:function(element,view,http,expression,document,container){let template=element.getAttribute("data-ls-template")||"";let type=element.getAttribute("data-type")||"url";let debug=element.getAttribute("data-debug")||false;let paths=[];let check=function(init=false){let source=expression.parse(template);paths=expression.getPaths();element.innerHTML="";if("script"===type){let inlineTemplate=document.getElementById(source);if(inlineTemplate&&inlineTemplate.innerHTML){element.innerHTML=inlineTemplate.innerHTML;element.dispatchEvent(new CustomEvent("template-loaded",{bubbles:true,cancelable:false,}));}else{if(debug){console.error('Missing template "'+source+'"');}} +element.dispatchEvent(new Event('looped'));};let template=(element.children.length===1)?element.children[0]:window.document.createElement('li');echo();container.bind(element,expr+'.length',echo);let path=(expr+'.length').split('.');while(path.length){container.bind(element,path.join('.'),echo);path.pop();}}});window.ls.container.get('view').add({selector:'data-ls-template',template:false,controller:function(element,view,http,expression,document,container){let template=element.getAttribute('data-ls-template')||'';let type=element.getAttribute('data-type')||'url';let debug=element.getAttribute('data-debug')||false;let paths=[];let check=function(init=false){let source=expression.parse(template);paths=expression.getPaths();element.innerHTML='';if('script'===type){let inlineTemplate=document.getElementById(source);if(inlineTemplate&&inlineTemplate.innerHTML){element.innerHTML=inlineTemplate.innerHTML;element.dispatchEvent(new CustomEvent('template-loaded',{bubbles:true,cancelable:false}));} +else{if(debug){console.error('Missing template "'+source+'"');}} if(!init){view.render(element);} return;} -http.get(source).then((function(element){return function(data){element.innerHTML=data;view.render(element);element.dispatchEvent(new CustomEvent("template-loaded",{bubbles:true,cancelable:false,}));};})(element),function(){throw new Error("Failed loading template");});};check(true);for(let i=0;i{const bars=12;const realtime=window.ls.container.get('realtime');const sleep=ms=>new Promise(resolve=>setTimeout(resolve,ms));let current={};window.ls.container.get('console').subscribe('project',event=>{for(let project in event.payload){current[project]=event.payload[project]??0;}});while(true){let newHistory={};let createdHistory=false;for(const project in current){let history=realtime?.history??{};if(!(project in history)){history[project]=new Array(bars).fill({percentage:0,value:0});} +http.get(source).then(function(element){return function(data){element.innerHTML=data;view.render(element);element.dispatchEvent(new CustomEvent('template-loaded',{bubbles:true,cancelable:false}));}}(element),function(){throw new Error('Failed loading template');});};check(true);for(let i=0;i{const bars=12;const realtime=window.ls.container.get('realtime');const sleep=ms=>new Promise(resolve=>setTimeout(resolve,ms));let current={};window.ls.container.get('console').subscribe('project',event=>{for(let project in event.payload){current[project]=event.payload[project]??0;}});while(true){let newHistory={};let createdHistory=false;for(const project in current){let history=realtime?.history??{};if(!(project in history)){history[project]=new Array(bars).fill({percentage:0,value:0});} history=history[project];history.push({percentage:0,value:current[project]});if(history.length>=bars){history.shift();} const highest=history.reduce((prev,curr)=>{return(curr.value>prev)?curr.value:prev;},0);history=history.map(({percentage,value})=>{createdHistory=true;percentage=value===0?0:((Math.round((value/highest)*10)/10)*100);if(percentage>100)percentage=100;else if(percentage==0&&value!=0)percentage=5;return{percentage:percentage,value:value};}) newHistory[project]=history;} diff --git a/public/scripts/dependencies/litespeed.js b/public/scripts/dependencies/litespeed.js index e5b97068c..3343dbd2e 100644 --- a/public/scripts/dependencies/litespeed.js +++ b/public/scripts/dependencies/litespeed.js @@ -1,1255 +1,142 @@ -window.ls = window.ls || {}; -window.ls.container = (function () { - let stock = {}; - let listeners = {}; - let namespaces = {}; - let set = function (name, object, singleton, watch = true) { - if (typeof name !== "string") { - throw new Error("var name must be of type string"); - } - if (typeof singleton !== "boolean") { - throw new Error( - 'var singleton "' + - singleton + - '" of service "' + - name + - '" must be of type boolean' - ); - } - stock[name] = { - name: name, - object: object, - singleton: singleton, - instance: null, - watch: watch, - }; - if (!watch) { - return this; - } - let binds = listeners[name] || {}; - for (let key in binds) { - if (binds.hasOwnProperty(key)) { - document.dispatchEvent(new CustomEvent(key)); - } - } - return this; - }; - let get = function (name) { - let service = undefined !== stock[name] ? stock[name] : null; - if (null == service) { - return null; - } - if (service.instance) { - return service.instance; - } - let instance = - typeof service.object === "function" - ? this.resolve(service.object) - : service.object; - let skip = false; - if ( - service.watch && - name !== "window" && - name !== "document" && - name !== "element" && - typeof instance === "object" && - instance !== null - ) { - let handler = { - name: service.name, - watch: function () {}, - get: function (target, key) { - if (key === "__name") { - return this.name; - } - if (key === "__watch") { - return this.watch; - } - if (key === "__proxy") { - return true; - } - if ( - typeof target[key] === "object" && - target[key] !== null && - !target[key].__proxy - ) { - let handler = Object.assign({}, this); - handler.name = handler.name + "." + key; - return new Proxy(target[key], handler); - } else { - return target[key]; - } - }, - set: function (target, key, value, receiver) { - if (key === "__name") { - return (this.name = value); - } - if (key === "__watch") { - return (this.watch = value); - } - target[key] = value; - let path = receiver.__name + "." + key; - document.dispatchEvent(new CustomEvent(path + ".changed")); - if (skip) { - return true; - } - skip = true; - container.set("$prop", key, true); - container.set("$value", value, true); - container.resolve(this.watch); - container.set("$key", null, true); - container.set("$value", null, true); - skip = false; - return true; - }, - }; - instance = new Proxy(instance, handler); - } - if (service.singleton) { - service.instance = instance; - } - return instance; - }; - let resolve = function (target) { - if (!target) { - return () => {}; - } - let self = this; - const REGEX_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/gm; - const REGEX_FUNCTION_PARAMS = - /(?:\s*(?:function\s*[^(]*)?\s*)((?:[^'"]|(?:(?:(['"])(?:(?:.*?[^\\]\2)|\2))))*?)\s*(?=(?:=>)|{)/m; - const REGEX_PARAMETERS_VALUES = - /\s*([\w\\$]+)\s*(?:=\s*((?:(?:(['"])(?:\3|(?:.*?[^\\]\3)))((\s*\+\s*)(?:(?:(['"])(?:\6|(?:.*?[^\\]\6)))|(?:[\w$]*)))*)|.*?))?\s*(?:,|$)/gm; - function getParams(func) { - let functionAsString = func.toString(); - let params = []; - let match; - functionAsString = functionAsString.replace(REGEX_COMMENTS, ""); - functionAsString = functionAsString.match(REGEX_FUNCTION_PARAMS)[1]; - if (functionAsString.charAt(0) === "(") { - functionAsString = functionAsString.slice(1, -1); - } - while ((match = REGEX_PARAMETERS_VALUES.exec(functionAsString))) { - params.push(match[1]); - } - return params; - } - let args = getParams(target); - return target.apply( - target, - args.map(function (value) { - return self.get(value.trim()); - }) - ); - }; - let path = function (path, value, type) { - type = type ? type : "assign"; - path = container.scope(path).split("."); - let name = path.shift(); - let object = container.get(name); - let result = null; - while (path.length > 1) { - if (!object) { - return null; - } - object = object[path.shift()]; - } - let shift = path.shift(); - if ( - value !== null && - value !== undefined && - object && - shift && - (object[shift] !== undefined || object[shift] !== null) - ) { - switch (type) { - case "append": - if (!Array.isArray(object[shift])) { - object[shift] = []; - } - object[shift].push(value); - break; - case "prepend": - if (!Array.isArray(object[shift])) { - object[shift] = []; - } - object[shift].unshift(value); - break; - case "splice": - if (!Array.isArray(object[shift])) { - object[shift] = []; - } - object[shift].splice(value, 1); - break; - default: - object[shift] = value; - } - return true; - } - if (!object) { - return null; - } - if (!shift) { - result = object; - } else { - return object[shift]; - } - return result; - }; - let bind = function (element, path, callback) { - let event = container.scope(path) + ".changed"; - let service = event.split(".").slice(0, 1).pop(); - let debug = element.getAttribute("data-debug") || false; - listeners[service] = listeners[service] || {}; - listeners[service][event] = true; - let printer = (function (x) { - return function () { - if (!document.body.contains(element)) { - element = null; - document.removeEventListener(event, printer, false); - return false; - } - let oldNamespaces = namespaces; - namespaces = x; - callback(); - namespaces = oldNamespaces; - }; - })(Object.assign({}, namespaces)); - document.addEventListener(event, printer); - }; - let addNamespace = function (key, scope) { - namespaces[key] = scope; - return this; - }; - let removeNamespace = function (key) { - delete namespaces[key]; - return this; - }; - let scope = function (path) { - for (let [key, value] of Object.entries(namespaces)) { - path = - path.indexOf(".") > -1 - ? path.replace(key + ".", value + ".") - : path.replace(key, value); - } - return path; - }; - let container = { - set: set, - get: get, - resolve: resolve, - path: path, - bind: bind, - scope: scope, - addNamespace: addNamespace, - removeNamespace: removeNamespace, - stock: stock, - listeners: listeners, - namespaces: namespaces, - }; - set("container", container, true, false); - return container; -})(); -window.ls.container.set( - "http", - function (document) { - let globalParams = [], - globalHeaders = []; - let addParam = function (url, param, value) { - param = encodeURIComponent(param); - let a = document.createElement("a"); - param += value ? "=" + encodeURIComponent(value) : ""; - a.href = url; - a.search += (a.search ? "&" : "") + param; - return a.href; - }; - let request = function (method, url, headers, payload, progress) { - let i; - if ( - -1 === - [ - "GET", - "POST", - "PUT", - "DELETE", - "TRACE", - "HEAD", - "OPTIONS", - "CONNECT", - "PATCH", - ].indexOf(method) - ) { - throw new Error("var method must contain a valid HTTP method name"); - } - if (typeof url !== "string") { - throw new Error("var url must be of type string"); - } - if (typeof headers !== "object") { - throw new Error("var headers must be of type object"); - } - if (typeof url !== "string") { - throw new Error("var url must be of type string"); - } - for (i = 0; i < globalParams.length; i++) { - url = addParam(url, globalParams[i].key, globalParams[i].value); - } - return new Promise(function (resolve, reject) { - let xmlhttp = new XMLHttpRequest(); - xmlhttp.open(method, url, true); - for (i = 0; i < globalHeaders.length; i++) { - xmlhttp.setRequestHeader( - globalHeaders[i].key, - globalHeaders[i].value - ); - } - for (let key in headers) { - if (headers.hasOwnProperty(key)) { - xmlhttp.setRequestHeader(key, headers[key]); - } - } - xmlhttp.onload = function () { - if (4 === xmlhttp.readyState && 200 === xmlhttp.status) { - resolve(xmlhttp.response); - } else { - document.dispatchEvent( - new CustomEvent( - "http-" + method.toLowerCase() + "-" + xmlhttp.status - ) - ); - reject(new Error(xmlhttp.statusText)); - } - }; - if (progress) { - xmlhttp.addEventListener("progress", progress); - xmlhttp.upload.addEventListener("progress", progress, false); - } - xmlhttp.onerror = function () { - reject(new Error("Network Error")); - }; - xmlhttp.send(payload); - }); - }; - return { - get: function (url) { - return request("GET", url, {}, ""); - }, - post: function (url, headers, payload) { - return request("POST", url, headers, payload); - }, - put: function (url, headers, payload) { - return request("PUT", url, headers, payload); - }, - patch: function (url, headers, payload) { - return request("PATCH", url, headers, payload); - }, - delete: function (url) { - return request("DELETE", url, {}, ""); - }, - addGlobalParam: function (key, value) { - globalParams.push({ key: key, value: value }); - }, - addGlobalHeader: function (key, value) { - globalHeaders.push({ key: key, value: value }); - }, - }; - }, - true, - false -); -window.ls.container.set( - "cookie", - function (document) { - function get(name) { - let value = "; " + document.cookie, - parts = value.split("; " + name + "="); - if (parts.length === 2) { - return parts.pop().split(";").shift(); - } - return null; - } - function set(name, value, days) { - let date = new Date(); - date.setTime(date.getTime() + days * 24 * 60 * 60 * 1000); - let expires = 0 < days ? "expires=" + date.toUTCString() : "expires=0"; - document.cookie = name + "=" + value + ";" + expires + ";path=/"; - return this; - } - return { get: get, set: set }; - }, - true, - false -); -window.ls.container.set( - "view", - function (http, container) { - let stock = {}; - let execute = function (view, node, container) { - container.set("element", node, true, false); - container.resolve(view.controller); - if (true !== view.repeat) { - node.removeAttribute(view.selector); - } - }; - let parse = function (node, skip, callback) { - if (node.tagName === "SCRIPT") { - return; - } - if (node.attributes && skip !== true) { - let attrs = []; - let attrsLen = node.attributes.length; - for (let x = 0; x < attrsLen; x++) { - attrs.push(node.attributes[x].nodeName); - } - if (1 !== node.nodeType) { - return; - } - if (attrs && attrsLen) { - for (let x = 0; x < attrsLen; x++) { - if (node.$lsSkip === true) { - break; - } - let pointer = !/Edge/.test(navigator.userAgent) - ? x - : attrsLen - 1 - x; - let length = attrsLen; - let attr = attrs[pointer]; - if (!stock[attr]) { - continue; - } - let comp = stock[attr]; - if (typeof comp.template === "function") { - comp.template = container.resolve(comp.template); - } - if (!comp.template) { - (function (comp, node, container) { - execute(comp, node, container); - })(comp, node, container); - if (length !== attrsLen) { - x--; - } - if (callback) { - callback(); - } - continue; - } - node.classList.remove("load-end"); - node.classList.add("load-start"); - node.$lsSkip = true; - http.get(comp.template).then( - (function (node, comp) { - return function (data) { - node.$lsSkip = false; - node.innerHTML = data; - node.classList.remove("load-start"); - node.classList.add("load-end"); - (function (comp, node, container) { - execute(comp, node, container); - })(comp, node, container); - parse(node, true); - if (callback) { - callback(); - } - }; - })(node, comp), - function (error) { - throw new Error( - "Failed to load comp template: " + error.message - ); - } - ); - } - } - } - if (true === node.$lsSkip) { - return; - } - let list = node ? node.childNodes : []; - if (node.$lsSkip === true) { - list = []; - } - for (let i = 0; i < list.length; i++) { - let child = list[i]; - parse(child); - } - }; - return { - stock: stock, - add: function (object) { - if (typeof object !== "object") { - throw new Error("object must be of type object"); - } - let defaults = { - selector: "", - controller: function () {}, - template: "", - repeat: false, - protected: false, - }; - for (let prop in defaults) { - if (!defaults.hasOwnProperty(prop)) { - continue; - } - if (prop in object) { - continue; - } - object[prop] = defaults[prop]; - } - if (!object.selector) { - throw new Error("View component is missing a selector attribute"); - } - stock[object.selector] = object; - return this; - }, - render: function (element, callback) { - parse(element, false, callback); - element.dispatchEvent(new window.Event("rendered", { bubbles: false })); - }, - }; - }, - true, - false -); -window.ls.container.set( - "router", - function (window) { - let getJsonFromUrl = function (URL) { - let query; - if (URL) { - let pos = location.search.indexOf("?"); - if (pos === -1) return []; - query = location.search.substr(pos + 1); - } else { - query = location.search.substr(1); - } - let result = {}; - query.split("&").forEach(function (part) { - if (!part) { - return; - } - part = part.split("+").join(" "); - let eq = part.indexOf("="); - let key = eq > -1 ? part.substr(0, eq) : part; - let val = eq > -1 ? decodeURIComponent(part.substr(eq + 1)) : ""; - let from = key.indexOf("["); - if (from === -1) { - result[decodeURIComponent(key)] = val; - } else { - let to = key.indexOf("]"); - let index = decodeURIComponent(key.substring(from + 1, to)); - key = decodeURIComponent(key.substring(0, from)); - if (!result[key]) { - result[key] = []; - } - if (!index) { - result[key].push(val); - } else { - result[key][index] = val; - } - } - }); - return result; - }; - let states = []; - let params = getJsonFromUrl(window.location.search); - let hash = window.location.hash; - let current = null; - let previous = null; - let getPrevious = () => previous; - let getCurrent = () => current; - let setPrevious = (value) => { - previous = value; - return this; - }; - let setCurrent = (value) => { - current = value; - return this; - }; - let setParam = function (key, value) { - params[key] = value; - return this; - }; - let getParam = function (key, def) { - if (key in params) { - return params[key]; - } - return def; - }; - let getParams = function () { - return params; - }; - let getURL = function () { - return window.location.href; - }; - let add = function (path, view) { - if (typeof path !== "string") { - throw new Error("path must be of type string"); - } - if (typeof view !== "object") { - throw new Error("view must be of type object"); - } - states[states.length++] = { path: path, view: view }; - return this; - }; - let match = function (location) { - let url = location.pathname; - states.sort(function (a, b) { - return b.path.length - a.path.length; - }); - states.sort(function (a, b) { - let n = b.path.split("/").length - a.path.split("/").length; - if (n !== 0) { - return n; - } - return b.path.length - a.path.length; - }); - for (let i = 0; i < states.length; i++) { - let value = states[i]; - value.path = - value.path.substring(0, 1) !== "/" - ? location.pathname + value.path - : value.path; - let match = new RegExp( - "^" + value.path.replace(/:[^\s/]+/g, "([\\w-]+)") + "$" - ); - let found = url.match(match); - if (found) { - previous = current; - current = value; - return value; - } - } - return null; - }; - let change = function (URL, replace) { - if (!replace) { - window.history.pushState({}, "", URL); - } else { - window.history.replaceState({}, "", URL); - } - window.dispatchEvent(new PopStateEvent("popstate", {})); - return this; - }; - let reload = function () { - return change(window.location.href); - }; - return { - setParam: setParam, - getParam: getParam, - getParams: getParams, - getURL: getURL, - add: add, - change: change, - reload: reload, - match: match, - getCurrent: getCurrent, - setCurrent: setCurrent, - getPrevious: getPrevious, - setPrevious: setPrevious, - params: params, - hash: hash, - reset: function () { - this.params = getJsonFromUrl(window.location.search); - this.hash = window.location.hash; - }, - }; - }, - true, - true -); -window.ls.container.set( - "expression", - function (container, filter) { - let paths = []; - return { - regex: /(\{{.*?\}})/gi, - parse: function (string, def, cast = false) { - def = def || ""; - paths = []; - return string - .replace(this.regex, (match) => { - let reference = match - .substring(2, match.length - 2) - .replace("['", ".") - .replace("']", "") - .trim(); - reference = reference.split("|"); - let path = container.scope(reference[0] || ""); - let result = container.path(path); - path = container.scope(path); - if (!paths.includes(path)) { - paths.push(path); - } - if (reference.length >= 2) { - for (let i = 1; i < reference.length; i++) { - result = filter.apply(reference[i], result); - } - } - if (null === result || undefined === result) { - result = def; - } else if (typeof result === "object") { - result = JSON.stringify(result, null, 4); - } else if ( - (typeof result === "object" || typeof result === "string") && - cast - ) { - result = "'" + result + "'"; - } - return result; - }) - .replace(/\\{/g, "{") - .replace(/\\}/g, "}"); - }, - getPaths: () => paths, - }; - }, - true, - false -); -window.ls.container.set( - "filter", - function (container) { - let filters = {}; - let add = function (name, callback) { - filters[name] = callback; - return this; - }; - let apply = function (name, value) { - container.set("$value", value, true, false); - return container.resolve(filters[name]); - }; - add("uppercase", ($value) => { - if (typeof $value !== "string") { - return $value; - } - return $value.toUpperCase(); - }); - add("lowercase", ($value) => { - if (typeof $value !== "string") { - return $value; - } - return $value.toLowerCase(); - }); - return { add: add, apply: apply }; - }, - true, - false -); -window.ls.container.get("filter").add("escape", ($value) => { - if (typeof $value !== "string") { - return $value; - } - return $value - .replace(/&/g, "&") - .replace(//g, ">") - .replace(/\"/g, """) - .replace(/\'/g, "'") - .replace(/\//g, "/"); -}); -window.ls = window.ls || {}; -window.ls.container - .set("window", window, true, false) - .set("document", window.document, true, false) - .set("element", window.document, true, false); -window.ls.run = function (window) { - try { - this.view.render(window.document); - } catch (error) { - let handler = window.ls.container.resolve(this.error); - handler(error); - } -}; -window.ls.error = () => { - return (error) => { - console.error("ls-error", error.message, error.stack, error.toString()); - }; -}; -window.ls.router = window.ls.container.get("router"); -window.ls.view = window.ls.container.get("view"); -window.ls.filter = window.ls.container.get("filter"); -window.ls.container.get("view").add({ - selector: "data-ls-router", - controller: function (element, window, document, view, router) { - let firstFromServer = - element.getAttribute("data-first-from-server") === "true"; - let scope = { - selector: "data-ls-scope", - template: false, - repeat: true, - controller: function () {}, - }; - let init = function (route) { - let count = parseInt(element.getAttribute("data-ls-scope-count") || 0); - element.setAttribute("data-ls-scope-count", count + 1); - window.scrollTo(0, 0); - if (window.document.body.scrollTo) { - window.document.body.scrollTo(0, 0); - } - router.reset(); - if (null === route) { - return; - } - scope.template = - undefined !== route.view.template ? route.view.template : null; - scope.controller = - undefined !== route.view.controller - ? route.view.controller - : function () {}; - document.dispatchEvent(new CustomEvent("state-change")); - if (firstFromServer && null === router.getPrevious()) { - scope.template = ""; - document.dispatchEvent(new CustomEvent("state-changed")); - } else if (count === 1) { - view.render(element, function () { - document.dispatchEvent(new CustomEvent("state-changed")); - }); - } else if (null !== router.getPrevious()) { - view.render(element, function () { - document.dispatchEvent(new CustomEvent("state-changed")); - }); - } - }; - let findParent = function (tagName, el) { - if ((el.nodeName || el.tagName).toLowerCase() === tagName.toLowerCase()) { - return el; - } - while ((el = el.parentNode)) { - if ( - (el.nodeName || el.tagName).toLowerCase() === tagName.toLowerCase() - ) { - return el; - } - } - return null; - }; - element.removeAttribute("data-ls-router"); - element.setAttribute("data-ls-scope", ""); - element.setAttribute("data-ls-scope-count", 1); - view.add(scope); - document.addEventListener("click", function (event) { - let target = findParent("a", event.target); - if (!target) { - return false; - } - if (!target.href) { - return false; - } - if (event.metaKey) { - return false; - } - if ( - target.hasAttribute("target") && - "_blank" === target.getAttribute("target") - ) { - return false; - } - if (target.hostname !== window.location.hostname) { - return false; - } - let route = router.match(target); - if (null === route) { - return false; - } - event.preventDefault(); - if (window.location === target.href) { - return false; - } - route.view.state = - undefined === route.view.state ? true : route.view.state; - if (true === route.view.state) { - if ( - router.getPrevious() && - router.getPrevious().view && - router.getPrevious().view.scope !== route.view.scope - ) { - window.location.href = target.href; - return false; - } - window.history.pushState({}, "Unknown", target.href); - } - init(route); - return true; - }); - window.addEventListener("popstate", function () { - init(router.match(window.location)); - }); - window.addEventListener("hashchange", function () { - init(router.match(window.location)); - }); - init(router.match(window.location)); - }, -}); -window.ls.container.get("view").add({ - selector: "data-ls-attrs", - controller: function (element, expression, container) { - let attrs = element.getAttribute("data-ls-attrs").trim().split(","); - let paths = []; - let debug = element.getAttribute("data-debug") || false; - let check = () => { - container.set("element", element, true, false); - if (debug) { - console.info("debug-ls-attrs attributes:", attrs); - } - for (let i = 0; i < attrs.length; i++) { - let attr = attrs[i]; - let key = expression.parse( - attr.substring(0, attr.indexOf("=")) || attr - ); - paths = paths.concat(expression.getPaths()); - let value = ""; - if (attr.indexOf("=") > -1) { - value = expression.parse(attr.substring(attr.indexOf("=") + 1)) || ""; - paths = paths.concat(expression.getPaths()); - } - if (!key) { - return null; - } - element.setAttribute(key, value); - } - }; - check(); - for (let i = 0; i < paths.length; i++) { - let path = paths[i].split("."); - while (path.length) { - container.bind(element, path.join("."), check); - path.pop(); - } - } - }, -}); -window.ls.container.get("view").add({ - selector: "data-ls-bind", - controller: function (element, expression, container) { - let debug = element.getAttribute("data-debug") || false; - let echo = function (value, bind = true) { - if ( - element.tagName === "INPUT" || - element.tagName === "SELECT" || - element.tagName === "BUTTON" || - element.tagName === "TEXTAREA" - ) { - let type = element.getAttribute("type"); - if ("radio" === type) { - if (value.toString() === element.value) { - element.setAttribute("checked", "checked"); - } else { - element.removeAttribute("checked"); - } - if (bind) { - element.addEventListener("change", () => { - for (let i = 0; i < paths.length; i++) { - if (element.checked) { - value = element.value; - } - container.path(paths[i], value); - } - }); - } - return; - } - if ("checkbox" === type) { - if ( - typeof value === "boolean" || - value === "true" || - value === "false" - ) { - if (value === true || value === "true") { - element.setAttribute("checked", "checked"); - element.checked = true; - } else { - element.removeAttribute("checked"); - element.checked = false; - } - } else { - try { - value = JSON.parse(value); - element.checked = - Array.isArray(value) && value.indexOf(element.value) > -1; - value = element.value; - } catch { - return null; - } - } - if (bind) { - element.addEventListener("change", () => { - for (let i = 0; i < paths.length; i++) { - let value = container.path(paths[i]); - let index = value.indexOf(element.value); - if (element.checked && index < 0) { - value.push(element.value); - } - if (!element.checked && index > -1) { - value.splice(index, 1); - } - container.path(paths[i], value); - } - }); - } - return; - } - if (element.value !== value) { - element.value = value; - element.dispatchEvent(new Event("change")); - } - if (bind) { - element.addEventListener("input", sync); - element.addEventListener("change", sync); - } - } else { - if (element.textContent != value) { - element.textContent = value; - } - } - }; - let sync = (() => { - return () => { - if (debug) { - console.info("debug-ls-bind", "sync-path", paths); - console.info("debug-ls-bind", "sync-syntax", syntax); - console.info("debug-ls-bind", "sync-syntax-parsed", parsedSyntax); - console.info("debug-ls-bind", "sync-value", element.value); - } - for (let i = 0; i < paths.length; i++) { - if ("{{" + paths[i] + "}}" !== parsedSyntax) { - if (debug) { - console.info("debug-ls-bind", "sync-skipped-path", paths[i]); - console.info("debug-ls-bind", "sync-skipped-syntax", syntax); - console.info( - "debug-ls-bind", - "sync-skipped-syntax-parsed", - parsedSyntax - ); - } - continue; - } - if (debug) { - console.info("debug-ls-bind", "sync-loop-path", paths[i]); - console.info("debug-ls-bind", "sync-loop-syntax", parsedSyntax); - } - container.path(paths[i], element.value); - } - }; - })(); - let syntax = element.getAttribute("data-ls-bind"); - let parsedSyntax = container.scope(syntax); - let unsync = !!element.getAttribute("data-unsync") || false; - let result = expression.parse(syntax); - let paths = expression.getPaths(); - echo(result, !unsync); - element.addEventListener("looped", function () { - echo(expression.parse(parsedSyntax), false); - }); - for (let i = 0; i < paths.length; i++) { - let path = paths[i].split("."); - if (debug) { - console.info("debug-ls-bind", "bind-path", path); - console.info("debug-ls-bind", "bind-syntax", syntax); - } - while (path.length) { - container.bind(element, path.join("."), () => { - echo(expression.parse(parsedSyntax), false); - }); - path.pop(); - } - } - }, -}); -window.ls.container.get("view").add({ - selector: "data-ls-if", - controller: function (element, expression, container, view) { - let result = ""; - let syntax = element.getAttribute("data-ls-if") || ""; - let debug = element.getAttribute("data-debug") || false; - let paths = []; - let check = () => { - if (debug) { - console.info( - "debug-ls-if", - expression.parse( - syntax.replace(/(\r\n|\n|\r)/gm, " "), - "undefined", - true - ) - ); - } - try { - result = eval( - expression.parse( - syntax.replace(/(\r\n|\n|\r)/gm, " "), - "undefined", - true - ) - ); - } catch (error) { - throw new Error( - 'Failed to evaluate expression "' + - syntax + - ' (resulted with: "' + - result + - '")": ' + - error - ); - } - if (debug) { - console.info("debug-ls-if result:", result); - } - paths = expression.getPaths(); - let prv = element.$lsSkip; - element.$lsSkip = !result; - if (!result) { - element.style.visibility = "hidden"; - element.style.display = "none"; - } else { - element.style.removeProperty("display"); - element.style.removeProperty("visibility"); - } - if (prv === true && element.$lsSkip === false) { - view.render(element); - } - }; - check(); - for (let i = 0; i < paths.length; i++) { - let path = paths[i].split("."); - while (path.length) { - container.bind(element, path.join("."), check); - path.pop(); - } - } - }, -}); -window.ls.container.get("view").add({ - selector: "data-ls-loop", - template: false, - nested: false, - controller: function (element, view, container, window, expression) { - let expr = expression.parse(element.getAttribute("data-ls-loop")); - let as = element.getAttribute("data-ls-as"); - let key = element.getAttribute("data-ls-key") || "$index"; - let limit = parseInt( - expression.parse(element.getAttribute("data-limit") || "") || -1 - ); - let debug = element.getAttribute("data-debug") || false; - let echo = function () { - let array = container.path(expr); - let counter = 0; - array = !array ? [] : array; - let watch = !!(array && array.__proxy); - while (element.hasChildNodes()) { - element.removeChild(element.lastChild); - element.lastChild = null; - } - if (array instanceof Array && typeof array !== "object") { - throw new Error( - "Reference value must be array or object. " + typeof array + " given" - ); - } - let children = []; - element.$lsSkip = true; - element.style.visibility = - 0 === array.length && element.style.visibility == "" - ? "hidden" - : "visible"; - for (let prop in array) { - if (counter == limit) { - break; - } - counter++; - if (!array.hasOwnProperty(prop)) { - continue; - } - children[prop] = template.cloneNode(true); - element.appendChild(children[prop]); - ((index) => { - let context = expr + "." + index; - container.addNamespace(as, context); - if (debug) { - console.info("debug-ls-loop", "index", index); - console.info("debug-ls-loop", "context", context); - console.info( - "debug-ls-loop", - "context-path", - container.path(context).name - ); - console.info("debug-ls-loop", "namespaces", container.namespaces); - } - container.set(as, container.path(context), true, watch); - container.set(key, index, true, false); - view.render(children[prop]); - container.removeNamespace(as); - })(prop); - } - element.dispatchEvent(new Event("looped")); - }; - let template = - element.children.length === 1 - ? element.children[0] - : window.document.createElement("li"); - echo(); - container.bind(element, expr + ".length", echo); - let path = (expr + ".length").split("."); - while (path.length) { - container.bind(element, path.join("."), echo); - path.pop(); - } - }, -}); -window.ls.container.get("view").add({ - selector: "data-ls-template", - template: false, - controller: function (element, view, http, expression, document, container) { - let template = element.getAttribute("data-ls-template") || ""; - let type = element.getAttribute("data-type") || "url"; - let debug = element.getAttribute("data-debug") || false; - let paths = []; - let check = function (init = false) { - let source = expression.parse(template); - paths = expression.getPaths(); - element.innerHTML = ""; - if ("script" === type) { - let inlineTemplate = document.getElementById(source); - if (inlineTemplate && inlineTemplate.innerHTML) { - element.innerHTML = inlineTemplate.innerHTML; - element.dispatchEvent( - new CustomEvent("template-loaded", { - bubbles: true, - cancelable: false, - }) - ); - } else { - if (debug) { - console.error('Missing template "' + source + '"'); - } - } - if (!init) { - view.render(element); - } - return; - } - http.get(source).then( - (function (element) { - return function (data) { - element.innerHTML = data; - view.render(element); - element.dispatchEvent( - new CustomEvent("template-loaded", { - bubbles: true, - cancelable: false, - }) - ); - }; - })(element), - function () { - throw new Error("Failed loading template"); - } - ); - }; - check(true); - for (let i = 0; i < paths.length; i++) { - let path = paths[i].split("."); - while (path.length) { - container.bind(element, path.join("."), check); - path.pop(); - } - } - }, -}); + +window.ls=window.ls||{};window.ls.container=function(){let stock={};let listeners={};let namespaces={};let set=function(name,object,singleton,watch=true){if(typeof name!=='string'){throw new Error('var name must be of type string');} +if(typeof singleton!=='boolean'){throw new Error('var singleton "'+singleton+'" of service "'+name+'" must be of type boolean');} +stock[name]={name:name,object:object,singleton:singleton,instance:null,watch:watch,};if(!watch){return this;} +let binds=listeners[name]||{};for(let key in binds){if(binds.hasOwnProperty(key)){document.dispatchEvent(new CustomEvent(key));}} +return this;};let get=function(name){let service=(undefined!==stock[name])?stock[name]:null;if(null==service){return null;} +if(service.instance){return service.instance;} +let instance=(typeof service.object==='function')?this.resolve(service.object):service.object;let skip=false;if(service.watch&&name!=='window'&&name!=='document'&&name!=='element'&&typeof instance==='object'&&instance!==null){let handler={name:service.name,watch:function(){},get:function(target,key){if(key==="__name"){return this.name;} +if(key==="__watch"){return this.watch;} +if(key==="__proxy"){return true;} +if(key!=='constructor'&&typeof target[key]==='function'&&([Map,Set,WeakMap,WeakSet].includes(target.constructor))){return target[key].bind(target);} +if(typeof target[key]==='object'&&target[key]!==null&&!target[key].__proxy){let handler=Object.assign({},this);handler.name=handler.name+'.'+key;return new Proxy(target[key],handler)} +else{return target[key];}},set:function(target,key,value,receiver){if(key==="__name"){return this.name=value;} +if(key==="__watch"){return this.watch=value;} +target[key]=value;let path=receiver.__name+'.'+key;document.dispatchEvent(new CustomEvent(path+'.changed'));if(skip){return true;} +skip=true;container.set('$prop',key,true);container.set('$value',value,true);container.resolve(this.watch);container.set('$key',null,true);container.set('$value',null,true);skip=false;return true;},};instance=new Proxy(instance,handler);} +if(service.singleton){service.instance=instance;} +return instance;};let resolve=function(target){if(!target){return()=>{};} +let self=this;const REGEX_COMMENTS=/((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;const REGEX_FUNCTION_PARAMS=/(?:\s*(?:function\s*[^(]*)?\s*)((?:[^'"]|(?:(?:(['"])(?:(?:.*?[^\\]\2)|\2))))*?)\s*(?=(?:=>)|{)/m;const REGEX_PARAMETERS_VALUES=/\s*([\w\\$]+)\s*(?:=\s*((?:(?:(['"])(?:\3|(?:.*?[^\\]\3)))((\s*\+\s*)(?:(?:(['"])(?:\6|(?:.*?[^\\]\6)))|(?:[\w$]*)))*)|.*?))?\s*(?:,|$)/gm;function getParams(func){let functionAsString=func.toString();let params=[];let match;functionAsString=functionAsString.replace(REGEX_COMMENTS,'');functionAsString=functionAsString.match(REGEX_FUNCTION_PARAMS)[1];if(functionAsString.charAt(0)==='('){functionAsString=functionAsString.slice(1,-1);} +while(match=REGEX_PARAMETERS_VALUES.exec(functionAsString)){params.push(match[1]);} +return params;} +let args=getParams(target);return target.apply(target,args.map(function(value){return self.get(value.trim());}));};let path=function(path,value,type){type=(type)?type:'assign';path=container.scope(path).split('.');let name=path.shift();let object=container.get(name);let result=null;while(path.length>1){if(!object){return null;} +object=object[path.shift()];} +let shift=path.shift();if(value!==null&&value!==undefined&&object&&shift&&(object[shift]!==undefined||object[shift]!==null)){switch(type){case'append':if(!Array.isArray(object[shift])){object[shift]=[];} +object[shift].push(value);break;case'prepend':if(!Array.isArray(object[shift])){object[shift]=[];} +object[shift].unshift(value);break;case'splice':if(!Array.isArray(object[shift])){object[shift]=[];} +object[shift].splice(value,1);break;default:object[shift]=value;} +return true;} +if(!object){return null;} +if(!shift){result=object;} +else{return object[shift];} +return result;};let bind=function(element,path,callback){let event=container.scope(path)+'.changed';let service=event.split('.').slice(0,1).pop();let debug=element.getAttribute('data-debug')||false;listeners[service]=listeners[service]||{};listeners[service][event]=true;let printer=(function(x){return function(){if(!document.body.contains(element)){element=null;document.removeEventListener(event,printer,false);return false;} +let oldNamespaces=namespaces;namespaces=x;callback();namespaces=oldNamespaces;}}(Object.assign({},namespaces)));document.addEventListener(event,printer);};let addNamespace=function(key,scope){namespaces[key]=scope;return this;} +let removeNamespace=function(key){delete namespaces[key];return this;} +let scope=function(path){for(let[key,value]of Object.entries(namespaces)){path=(path.indexOf('.')>-1)?path.replace(key+'.',value+'.'):path.replace(key,value);} +return path;} +let container={set:set,get:get,resolve:resolve,path:path,bind:bind,scope:scope,addNamespace:addNamespace,removeNamespace:removeNamespace,stock:stock,listeners:listeners,namespaces:namespaces,};set('container',container,true,false);return container;}();window.ls.container.set('http',function(document){let globalParams=[],globalHeaders=[];let addParam=function(url,param,value){param=encodeURIComponent(param);let a=document.createElement('a');param+=(value?"="+encodeURIComponent(value):"");a.href=url;a.search+=(a.search?"&":"")+param;return a.href;};let request=function(method,url,headers,payload,progress){let i;if(-1===['GET','POST','PUT','DELETE','TRACE','HEAD','OPTIONS','CONNECT','PATCH'].indexOf(method)){throw new Error('var method must contain a valid HTTP method name');} +if(typeof url!=='string'){throw new Error('var url must be of type string');} +if(typeof headers!=='object'){throw new Error('var headers must be of type object');} +if(typeof url!=='string'){throw new Error('var url must be of type string');} +for(i=0;i-1?part.substr(0,eq):part;let val=eq>-1?decodeURIComponent(part.substr(eq+1)):'';let from=key.indexOf('[');if(from===-1){result[decodeURIComponent(key)]=val;} +else{let to=key.indexOf(']');let index=decodeURIComponent(key.substring(from+1,to));key=decodeURIComponent(key.substring(0,from));if(!result[key]){result[key]=[];} +if(!index){result[key].push(val);} +else{result[key][index]=val;}}});return result;};let states=[];let params=getJsonFromUrl(window.location.search);let hash=window.location.hash;let current=null;let previous=null;let getPrevious=()=>previous;let getCurrent=()=>current;let setPrevious=(value)=>{previous=value;return this;};let setCurrent=(value)=>{current=value;return this;};let setParam=function(key,value){params[key]=value;return this;};let getParam=function(key,def){if(key in params){return params[key];} +return def;};let getParams=function(){return params;};let getURL=function(){return window.location.href;};let add=function(path,view){if(typeof path!=='string'){throw new Error('path must be of type string');} +if(typeof view!=='object'){throw new Error('view must be of type object');} +states[states.length++]={path:path,view:view};return this;};let match=function(location){let url=location.pathname;if(url.endsWith('/')){url=url.slice(0,-1);} +states.sort(function(a,b){return b.path.length-a.path.length;});states.sort(function(a,b){let n=b.path.split('/').length-a.path.split('/').length;if(n!==0){return n;} +return b.path.length-a.path.length;});for(let i=0;i{let reference=match.substring(2,match.length-2).replace('[\'','.').replace('\']','').trim();reference=reference.split('|');let path=container.scope((reference[0]||''));let result=container.path(path);path=container.scope(path);if(!paths.includes(path)){paths.push(path);} +if(reference.length>=2){for(let i=1;ipaths,}},true,false);window.ls.container.set('filter',function(container){let filters={};let add=function(name,callback){filters[name]=callback;return this;};let apply=function(name,value){container.set('$value',value,true,false);return container.resolve(filters[name]);};add('uppercase',($value)=>{if(typeof $value!=='string'){return $value;} +return $value.toUpperCase();});add('lowercase',($value)=>{if(typeof $value!=='string'){return $value;} +return $value.toLowerCase();});return{add:add,apply:apply}},true,false);window.ls.container.get('filter').add('escape',$value=>{if(typeof $value!=='string'){return $value;} +return $value.replace(/&/g,'&').replace(//g,'>').replace(/\"/g,'"').replace(/\'/g,''').replace(/\//g,'/');});window.ls=window.ls||{};window.ls.container.set('window',window,true,false).set('document',window.document,true,false).set('element',window.document,true,false);window.ls.run=function(window){try{this.view.render(window.document);} +catch(error){let handler=window.ls.container.resolve(this.error);handler(error);}};window.ls.error=()=>{return error=>{console.error('ls-error',error.message,error.stack,error.toString());}};window.ls.router=window.ls.container.get('router');window.ls.view=window.ls.container.get('view');window.ls.filter=window.ls.container.get('filter');window.ls.container.get('view').add({selector:'data-ls-router',controller:function(element,window,document,view,router){let firstFromServer=(element.getAttribute('data-first-from-server')==='true');let scope={selector:'data-ls-scope',template:false,repeat:true,controller:function(){},};let init=function(route){let count=parseInt(element.getAttribute('data-ls-scope-count')||0);element.setAttribute('data-ls-scope-count',count+1);window.scrollTo(0,0);if(window.document.body.scrollTo){window.document.body.scrollTo(0,0);} +router.reset();if(null===route){return;} +scope.template=(undefined!==route.view.template)?route.view.template:null;scope.controller=(undefined!==route.view.controller)?route.view.controller:function(){};document.dispatchEvent(new CustomEvent('state-change'));if(firstFromServer&&null===router.getPrevious()){scope.template='';document.dispatchEvent(new CustomEvent('state-changed'));} +else if(count===1){view.render(element,function(){document.dispatchEvent(new CustomEvent('state-changed'));});} +else if(null!==router.getPrevious()){view.render(element,function(){document.dispatchEvent(new CustomEvent('state-changed'));});}};let findParent=function(tagName,el){if((el.nodeName||el.tagName).toLowerCase()===tagName.toLowerCase()){return el;} +while(el=el.parentNode){if((el.nodeName||el.tagName).toLowerCase()===tagName.toLowerCase()){return el;}} +return null;};element.removeAttribute('data-ls-router');element.setAttribute('data-ls-scope','');element.setAttribute('data-ls-scope-count',1);view.add(scope);document.addEventListener('click',function(event){let target=findParent('a',event.target);if(!target){return false;} +if(!target.href){return false;} +if((event.metaKey)){return false;} +if((target.hasAttribute('target'))&&('_blank'===target.getAttribute('target'))){return false;} +if(target.hostname!==window.location.hostname){return false;} +let route=router.match(target);if(null===route){return false;} +event.preventDefault();if(window.location===target.href){return false;} +route.view.state=(undefined===route.view.state)?true:route.view.state;if(true===route.view.state){if(router.getPrevious()&&router.getPrevious().view&&(router.getPrevious().view.scope!==route.view.scope)){window.location.href=target.href;return false;} +window.history.pushState({},'Unknown',target.href);} +init(route);return true;});window.addEventListener('popstate',function(){init(router.match(window.location));});window.addEventListener('hashchange',function(){init(router.match(window.location));});init(router.match(window.location));}});window.ls.container.get('view').add({selector:'data-ls-attrs',controller:function(element,expression,container){let attrs=element.getAttribute('data-ls-attrs').trim().split(',');let paths=[];let debug=element.getAttribute('data-debug')||false;let check=()=>{container.set('element',element,true,false);if(debug){console.info('debug-ls-attrs attributes:',attrs);} +for(let i=0;i{for(let i=0;i-1));value=element.value;} +catch{return null;}} +if(bind){element.addEventListener('change',()=>{for(let i=0;i-1){value.splice(index,1);} +container.path(paths[i],value);}});} +return;} +if(element.value!==value){element.value=value;element.dispatchEvent(new Event('change'));} +if(bind){element.addEventListener('input',sync);element.addEventListener('change',sync);}} +else{if(element.textContent!=value){element.textContent=value;}}};let sync=(()=>{return()=>{if(debug){console.info('debug-ls-bind','sync-path',paths);console.info('debug-ls-bind','sync-syntax',syntax);console.info('debug-ls-bind','sync-syntax-parsed',parsedSyntax);console.info('debug-ls-bind','sync-value',element.value);} +for(let i=0;i{echo(expression.parse(parsedSyntax),false);});path.pop();}}}});window.ls.container.get('view').add({selector:'data-ls-if',controller:function(element,expression,container,view){let result='';let syntax=element.getAttribute('data-ls-if')||'';let debug=element.getAttribute('data-debug')||false;let paths=[];let check=()=>{if(debug){console.info('debug-ls-if',expression.parse(syntax.replace(/(\r\n|\n|\r)/gm,' '),'undefined',true));} +try{result=(eval(expression.parse(syntax.replace(/(\r\n|\n|\r)/gm,' '),'undefined',true)));} +catch(error){throw new Error('Failed to evaluate expression "'+syntax+' (resulted with: "'+result+'")": '+error);} +if(debug){console.info('debug-ls-if result:',result);} +paths=expression.getPaths();let prv=element.$lsSkip;element.$lsSkip=!result;if(!result){element.style.visibility='hidden';element.style.display='none';} +else{element.style.removeProperty('display');element.style.removeProperty('visibility');} +if(prv===true&&element.$lsSkip===false){view.render(element)}};check();for(let i=0;i{let context=expr+'.'+index;container.addNamespace(as,context);if(debug){console.info('debug-ls-loop','index',index);console.info('debug-ls-loop','context',context);console.info('debug-ls-loop','context-path',container.path(context).name);console.info('debug-ls-loop','namespaces',container.namespaces);} +container.set(as,container.path(context),true,watch);container.set(key,index,true,false);view.render(children[prop]);container.removeNamespace(as);})(prop);} +element.dispatchEvent(new Event('looped'));};let template=(element.children.length===1)?element.children[0]:window.document.createElement('li');echo();container.bind(element,expr+'.length',echo);let path=(expr+'.length').split('.');while(path.length){container.bind(element,path.join('.'),echo);path.pop();}}});window.ls.container.get('view').add({selector:'data-ls-template',template:false,controller:function(element,view,http,expression,document,container){let template=element.getAttribute('data-ls-template')||'';let type=element.getAttribute('data-type')||'url';let debug=element.getAttribute('data-debug')||false;let paths=[];let check=function(init=false){let source=expression.parse(template);paths=expression.getPaths();element.innerHTML='';if('script'===type){let inlineTemplate=document.getElementById(source);if(inlineTemplate&&inlineTemplate.innerHTML){element.innerHTML=inlineTemplate.innerHTML;element.dispatchEvent(new CustomEvent('template-loaded',{bubbles:true,cancelable:false}));} +else{if(debug){console.error('Missing template "'+source+'"');}} +if(!init){view.render(element);} +return;} +http.get(source).then(function(element){return function(data){element.innerHTML=data;view.render(element);element.dispatchEvent(new CustomEvent('template-loaded',{bubbles:true,cancelable:false}));}}(element),function(){throw new Error('Failed loading template');});};check(true);for(let i=0;i