diff --git a/CHANGES.md b/CHANGES.md
index 81fb6ebcf..0dd92eeff 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -57,6 +57,8 @@
- Fixed incorrect audit worker event names (#1143)
- Increased limit of memberships fetched in `createTeamMembership` to 2000 (#1143)
- Fixed exception thrown when SSL certificate is already stored in the database (#1151)
+- Fixed user delete button in the Appwrite console (#1216)
+- Fixed missing placeholder for user name when empty (#1220)
## Breaking Changes (Read before upgrading!)
diff --git a/app/views/console/users/index.phtml b/app/views/console/users/index.phtml
index 0b5641807..65b611be2 100644
--- a/app/views/console/users/index.phtml
+++ b/app/views/console/users/index.phtml
@@ -77,8 +77,8 @@ $auth = $this->getParam('auth', []);
- -----
- Anonymous User
+ Unknown
+ Anonymous User
|
diff --git a/app/views/console/users/team.phtml b/app/views/console/users/team.phtml
index 912d12306..4b1efcd22 100644
--- a/app/views/console/users/team.phtml
+++ b/app/views/console/users/team.phtml
@@ -12,7 +12,7 @@
- Unknown
+ Unknown
diff --git a/app/views/console/users/user.phtml b/app/views/console/users/user.phtml
index e8b3b04ea..d94982350 100644
--- a/app/views/console/users/user.phtml
+++ b/app/views/console/users/user.phtml
@@ -12,8 +12,8 @@
- Unknown
- Anonymous User
+ Unknown
+ Anonymous User
@@ -97,7 +97,7 @@
Danger Zone
-
+
This is the area where you can delete this user.
By deleting this user you will lose all data associated with this user.
@@ -218,7 +218,7 @@
- ![]()
+
![]()
@@ -228,7 +228,7 @@
on
- ![]()
+
/
@@ -265,11 +265,11 @@
data-param-user-id="{{router.params.id}}"
data-event="load,logs-load">
-
+
No logs available.
-
+
diff --git a/public/dist/scripts/app-all.js b/public/dist/scripts/app-all.js
index 723b390dc..584c3f791 100644
--- a/public/dist/scripts/app-all.js
+++ b/public/dist/scripts/app-all.js
@@ -1960,145 +1960,128 @@ 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(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]);}
+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;}
+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;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-1){value=expression.parse(attr.substring(attr.indexOf('=')+1))||'';paths=paths.concat(expression.getPaths());}
+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-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{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;iscope.max){scope.list.pop();scope.counter--;}
+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;iscope.max){scope.list.pop();scope.counter--;}
if(time>0){window.setTimeout(function(message){return function(){scope.remove(message.id)}}(message),time);}
return message.id;},remove:function(id){let scope=this;for(let index=0;index{};}
-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]);}
+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;}
+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;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-1){value=expression.parse(attr.substring(attr.indexOf('=')+1))||'';paths=paths.concat(expression.getPaths());}
+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-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{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;iscope.max){scope.list.pop();scope.counter--;}
+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;iscope.max){scope.list.pop();scope.counter--;}
if(time>0){window.setTimeout(function(message){return function(){scope.remove(message.id)}}(message),time);}
return message.id;},remove:function(id){let scope=this;for(let index=0;index{};}
-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;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-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{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 {};
+ }
+ 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();
+ }
+ }
+ },
+});
|