New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

litespeed.js

Package Overview
Dependencies
Maintainers
1
Versions
29
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

litespeed.js - npm Package Compare versions

Comparing version 0.2.7 to 0.2.8

.DS_Store

91

dist/litespeed.js
let container=function(){let stock=[];let cachePrefix='none';let memory={};let setCachePrefix=function(prefix){cachePrefix=prefix;return this;};let getCachePrefix=function(){return cachePrefix;};let set=function(name,object,singleton,cache){if(typeof name!=='string'){throw new Error('var name must be of type string');}
window.ls=window.ls||{};window.ls.container=function(){let stock={};let cachePrefix='none';let memory={};let setCachePrefix=function(prefix){cachePrefix=prefix;return this;};let getCachePrefix=function(){return cachePrefix;};let set=function(name,object,singleton,cache=false,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');}
if(cache){window.localStorage.setItem(getCachePrefix()+'.'+name,JSON.stringify(object));}
stock[name]={name:name,object:object,singleton:singleton,instance:null};return this;};let get=function(name){let service=(undefined!==stock[name])?stock[name]:null;if(null===service){if(memory[getCachePrefix()+'.'+name]){return memory[getCachePrefix()+'.'+name];}
stock[name]={name:name,object:object,singleton:singleton,instance:null,watch:watch,};return this;};let get=function(name){let service=(undefined!==stock[name])?stock[name]:null;if(null===service){if(memory[getCachePrefix()+'.'+name]){return memory[getCachePrefix()+'.'+name];}
let cached=window.localStorage.getItem(getCachePrefix()+'.'+name);if(cached){cached=JSON.parse(cached);memory[getCachePrefix()+'.'+name]=cached;return cached;}
return null;}
if(service.instance===null){let instance=(typeof service.object==='function')?this.resolve(service.object):service.object;let skip=false;if(name!=='window'&&name!=='document'&&name!=='element'&&typeof instance==='object'&&instance!==null){instance=new Proxy(instance,{name:service.name,watch:function(){},get:function(obj,prop){if(prop==="__name"){return this.name;}
if(prop==="__watch"){return this.watch;}
if(typeof obj[prop]==='object'&&obj[prop]!==null){let handler=Object.assign({},this);handler.name=handler.name+'.'+prop;return new Proxy(obj[prop],handler)}
else{return obj[prop];}},set:function(obj,prop,value,receiver){if(prop==="__name"){return this.name=value;}
if(prop==="__watch"){return this.watch=value;}
obj[prop]=value;let path=receiver.__name+'.'+prop;document.dispatchEvent(new CustomEvent(path+'.changed'));if(skip){return true;}
skip=true;container.set('$prop',prop,true);container.set('$value',value,true);container.resolve(this.watch);container.set('$prop',null,true);container.set('$value',null,true);skip=false;return true;},});}
if(service.instance===null){let instance=(typeof service.object==='function')?this.resolve(service.object):service.object;let skip=false;if(service.watch&&name!=='window'&&name!=='document'&&name!=='element'&&typeof instance==='object'&&instance!==null){let handler={name:service.name,watch:function(){},get:function(target,key){if(key==="__name"){return this.name;}
if(key==="__watch"){return this.watch;}
if(key==="__proxy"){return true;}
if(typeof target[key]==='object'&&target[key]!==null&&!target[key].__proxy){let handler=Object.assign({},this);handler.name=handler.name+'.'+key;return new Proxy(target[key],handler)}
else{return target[key];}},set:function(target,key,value,receiver){if(key==="__name"){return this.name=value;}
if(key==="__watch"){return this.watch=value;}
target[key]=value;let path=receiver.__name+'.'+key;document.dispatchEvent(new CustomEvent(path+'.changed'));if(skip){return true;}
skip=true;container.set('$prop',key,true);container.set('$value',value,true);container.resolve(this.watch);container.set('$key',null,true);container.set('$value',null,true);skip=false;return true;},};instance=new Proxy(instance,handler);}
if(service.singleton){service.instance=instance;}
return instance;}
return service.instance;};let resolve=function(target){if(!target){return function(){};}
let self=this;let FN_ARGS=/^function\s*[^\(]*\(\s*([^\)]*)\)/m;let text=target.toString()||'';let args=text.match(FN_ARGS)[1].split(',');return target.apply(target,args.map(function(value){return self.get(value.trim());}));};let path=function(path,value,as,prefix){as=(as)?as:container.get('$as');prefix=(prefix)?prefix:container.get('$prefix');path=path.replace(as,prefix).split('.');let object=this.get(path.shift());while(path.length>1){if(undefined==object){return null;}
let self=this;let FN_ARGS=/^function\s*[^\(]*\(\s*([^\)]*)\)/m;let text=target.toString()||'';let args=text.match(FN_ARGS)[1].split(',');return target.apply(target,args.map(function(value){return self.get(value.trim());}));};let path=function(path,value,as,prefix){as=(as)?as:container.get('$as');prefix=(prefix)?prefix:container.get('$prefix');path=path.replace(as+'.',prefix+'.').split('.');let name=path.shift();let object=this.get(name);let result=null;while(path.length>1){if(undefined===object){return null;}
object=object[path.shift()];}
if(undefined!=value){return object[path.shift()]=value;}
if(undefined==object){return null;}
let shift=path.shift();if(undefined==shift){return object;}
return object[shift];};let container={set:set,get:get,resolve:resolve,path:path,bind:function(element,path,callback,as,prefix){as=(as)?as:container.get('$as');prefix=(prefix)?prefix:container.get('$prefix');let event=path.replace(as,prefix)+'.changed';let printer=function(){if(!document.body.contains(element)){console.log('cleaned dom');element=null;document.removeEventListener(event,printer,false);return false;}
callback();};document.addEventListener(event,printer);},setCachePrefix:setCachePrefix,getCachePrefix:getCachePrefix};set('container',container,true);return container;}();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(undefined!==value){object[path.shift()]=value;return true;}
if(undefined===object){return null;}
let shift=path.shift();if(undefined===shift){result=object;}
else{return object[shift];}
return result;};let bind=function(element,path,callback,as,prefix){as=(as)?as:container.get('$as');prefix=(prefix)?prefix:container.get('$prefix');let event=path.replace(as+'.',prefix+'.')+'.changed';let printer=function(){if(!document.body.contains(element)){element=null;document.removeEventListener(event,printer,false);return false;}
callback();};document.addEventListener(event,printer);};let container={set:set,get:get,resolve:resolve,path:path,bind:bind,setCachePrefix:setCachePrefix,getCachePrefix:getCachePrefix};set('container',container,true,false,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');}

@@ -33,6 +35,6 @@ if(typeof headers!=='object'){throw new Error('var headers must be of type object');}

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);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();}
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,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);Object.path=function(object,path,value){path=path.split('.');while(path.length>1){if(undefined===object){return null;}
return{'get':get,'set':set}},true,false,false);Object.path=function(object,path,value){path=path.split('.');while(path.length>1){if(undefined===object){return null;}
object=object[path.shift()];}

@@ -47,5 +49,5 @@ if(undefined!==value){return object[path.shift()]=value;}

return false;};}
container.set('view',function(http,container){let stock={};let execute=function(view,node,container){container.set('element',node,true);container.resolve(view.controller);if(true!==view.repeat){node.removeAttribute(view.selector);}};let parse=function(node,skip){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(attrs&&attrsLen){if(1!==node.nodeType){return;}
for(let x=0;x<attrsLen;x++){if(node.$lsSkip===true){break;}
window.ls.container.set('view',function(http,container){let stock={};let execute=function(view,node,container){container.set('element',node,true,false,false);container.resolve(view.controller);if(true!==view.repeat){node.removeAttribute(view.selector);}};let parse=function(node,skip){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;}

@@ -63,7 +65,7 @@ let comp=stock[attr];if(typeof comp.template==="function"){comp.template=container.resolve(comp.template);}

if(!object.selector){throw new Error('View component is missing a selector attribute');}
stock[object.selector]=object;return this;},render:function(element){parse(element);element.dispatchEvent(new window.Event('rendered',{bubbles:false}));}}},true);container.set('state',function(window){let states=[];let current=null;let previous=null;let getPrevious=function(){return previous;};let setPrevious=function(value){previous=value;return this;};let getCurrent=function(){return current;};let setCurrent=function(value){current=value;return this;};let setParam=function(key,value){state.params[key]=value;return this;};let getParam=function(key,def){if(key in state.params){return state.params[key];}
stock[object.selector]=object;return this;},render:function(element){parse(element);element.dispatchEvent(new window.Event('rendered',{bubbles:false}));}}},true,false,false);window.ls.container.set('router',function(window){let states=[];let current=null;let previous=null;let getPrevious=function(){return previous;};let setPrevious=function(value){previous=value;return this;};let getCurrent=function(){return current;};let setCurrent=function(value){current=value;return this;};let setParam=function(key,value){state.params[key]=value;return this;};let getParam=function(key,def){if(key in state.params){return state.params[key];}
return def;};let getParams=function(){return state.params;};let getURL=function(){return window.location.href;};let reset=function(){state.params=getJsonFromUrl(window.location.search);state.hash=window.location.hash;};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+((location.hash)?location.hash:'');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],match=new RegExp("^"+value.path.replace(/:[^\s/]+/g,'([\\w-]+)')+"$");let found=url.match(match);if(found){previous=current;current=value;return value;}}
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);}

@@ -76,14 +78,15 @@ else{window.history.replaceState({},'',URL);}

if(!index){result[key].push(val);}
else{result[key][index]=val;}}});return result;};let state={setParam:setParam,getParam:getParam,getParams:getParams,getURL:getURL,add:add,change:change,reload:reload,reset:reset,match:match,getCurrent:getCurrent,setCurrent:setCurrent,getPrevious:getPrevious,setPrevious:setPrevious,params:getJsonFromUrl(window.location.search),hash:window.location.hash};return state;},true);container.set('expression',function(container,filter,$as,$prefix){let reg=/(\{{.*?\}})/gi;let paths=[];return{parse:function(string,def,as,prefix){def=def||'';paths=[];return string.replace(reg,function(match)
else{result[key][index]=val;}}});return result;};let state={setParam:setParam,getParam:getParam,getParams:getParams,getURL:getURL,add:add,change:change,reload:reload,reset:reset,match:match,getCurrent:getCurrent,setCurrent:setCurrent,getPrevious:getPrevious,setPrevious:setPrevious,params:getJsonFromUrl(window.location.search),hash:window.location.hash};return state;},true,false,false);window.ls.container.set('expression',function(container,filter,$as,$prefix){let reg=/(\{{.*?\}})/gi;let paths=[];return{parse:function(string,def,as,prefix){def=def||'';paths=[];return string.replace(reg,function(match)
{let reference=match.substring(2,match.length-2).replace('[\'','.').replace('\']','').trim();reference=reference.split('|');let path=(reference[0]||'');let result=container.path(path,undefined,as,prefix);if(!paths.includes(path)){paths.push(path);}
result=(null===result||undefined===result)?def:result;result=(typeof result==='object')?JSON.stringify(result):result;if(reference.length>=2){for(let i=1;i<reference.length;i++){result=filter.apply(result,reference[i],{});}}
return result;});},getPaths:function(){return paths;},}},true);container.set('filter',function(container){let filters={};let add=function(name,callback){filters[name]=callback;return this;};let apply=function(value,name){container.set('$value',value,true);return container.resolve(filters[name]);};add('uppercase',function(value){return value.toUpperCase();});add('lowercase',function(value){return value.toLowerCase();});return{add:add,apply:apply}},true);container.get('filter').add('escape',function(value){if(typeof value!=='string'){return value;}
return value.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/\"/g,'&quot;').replace(/\'/g,'&#39;').replace(/\//g,'&#x2F;');});container.set('window',window,true).set('document',window.document,true).set('element',window.document,true);let app=function(version){return{run:function(window){try{container.get('http').addGlobalParam('version',version);this.view.render(window.document);}
catch(error){var handler=container.resolve(this.error);handler(error);}},error:function(){return function(error){console.error('error',error.message,error.stack,error.toString());}},container:container,view:container.get('view')}};container.get('view').add({selector:'data-ls-init',controller:function(element,window,document,view,state){let firstFromServer=(element.getAttribute('data-first-from-server')==='true');let scope={selector:'data-ls-scope',template:false,repeat:true,controller:function(){},state:true},init=function(route){window.scrollTo(0,0);if(window.document.body.scrollTo){window.document.body.scrollTo(0,0);}
state.reset();scope.protected=(undefined!==route.view.protected)?route.view.protected:false;if(scope.protected&&(null===state.getPrevious())){throw new Error('CSRF protection');}
scope.template=(undefined!==route.view.template)?route.view.template:null;scope.controller=(undefined!==route.view.controller)?route.view.controller:function(){};scope.state=(undefined!==route.view.state)?route.view.state:true;document.dispatchEvent(new CustomEvent('state-change'));if(firstFromServer&&null===state.getPrevious()){scope.template='';}
else if(null!==state.getPrevious()){scope.nested=false;view.render(element);}
document.dispatchEvent(new CustomEvent('state-changed'));},findParent=function(tagName,el){if((el.nodeName||el.tagName).toLowerCase()===tagName.toLowerCase()){return el;}
result=(null===result||undefined===result)?def:result;result=(typeof result==='object')?JSON.stringify(result):result;if(reference.length>=2){for(let i=1;i<reference.length;i++){result=filter.apply(reference[i],result);}}
return result;});},getPaths:function(){return paths;},}},true,false,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,false);return container.resolve(filters[name]);};add('uppercase',function($value){return $value.toUpperCase();});add('lowercase',function($value){return $value.toLowerCase();});return{add:add,apply:apply}},true,false,false);window.ls.container.get('filter').add('escape',function(value){if(typeof value!=='string'){return value;}
return value.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/\"/g,'&quot;').replace(/\'/g,'&#39;').replace(/\//g,'&#x2F;');});window.ls=window.ls||{};window.ls.container.set('window',window,true,false,false).set('document',window.document,true,false,false).set('element',window.document,true,false,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=function(){return function(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(){},state:true};let scopeElement=document.createElement('div');let init=function(route){window.scrollTo(0,0);if(window.document.body.scrollTo){window.document.body.scrollTo(0,0);}
router.reset();if(null===route){return;}
scope.protected=(undefined!==route.view.protected)?route.view.protected:false;if(scope.protected&&(null===router.getPrevious())){throw new Error('CSRF protection');}
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='';}
else if(null!==router.getPrevious()){view.render(element);}
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;};view.add(scope);document.addEventListener('click',function(event){let target=findParent('a',event.target);if(!target){return false;}
return null;};scopeElement.setAttribute('data-ls-scope','');element.insertBefore(scopeElement,element.firstChild);view.add(scope);document.addEventListener('click',function(event){let target=findParent('a',event.target);if(!target){return false;}
if(!target.href){return false;}

@@ -93,12 +96,12 @@ if((event.metaKey)){return false;}

if(target.hostname!==window.location.hostname){return false;}
let route=state.match(target);if(null===route){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(state.getPrevious()&&state.getPrevious().view&&(state.getPrevious().view.scope!==route.view.scope)){window.location.href=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(){let route=state.match(window.location);if(state.getPrevious()&&state.getPrevious().view&&(state.getPrevious().view.scope!==route.view.scope)){window.location.reload();return false;}
init(route);});init(state.match(window.location));}});container.get('view').add({selector:'data-ls-attrs',controller:function(element,expression,$as,$prefix){let attrs=element.getAttribute('data-ls-attrs').trim().split(',');let paths=[];let check=function(){for(let i=0;i<attrs.length;i++){let attr=attrs[i].split('=');let key=(attr[0])?expression.parse(attr[0],null,$as,$prefix):null;paths=paths.concat(expression.getPaths());let value=(attr[1])?expression.parse(attr[1],null,$as,$prefix):null;paths=paths.concat(expression.getPaths());if(!key){return null;}
element.setAttribute(key,value);}};check();for(let i=0;i<paths.length;i++){container.bind(element,paths[i],check);}}});container.get('view').add({selector:'data-ls-bind',controller:function(element,expression,container,$prefix,$as){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');}
init(route);return true;});window.addEventListener('popstate',function(){let route=router.match(window.location);if(router.getPrevious()&&router.getPrevious().view&&(router.getPrevious().view.scope!==route.view.scope)){window.location.reload();return false;}
init(route);});init(router.match(window.location));}});window.ls.container.get('view').add({selector:'data-ls-attrs',controller:function(element,expression,container,$as,$prefix){let attrs=element.getAttribute('data-ls-attrs').trim().split(',');let paths=[];let check=function(){for(let i=0;i<attrs.length;i++){let attr=attrs[i].split('=');let key=(attr[0])?expression.parse(attr[0],null,$as,$prefix):null;paths=paths.concat(expression.getPaths());let value=(attr[1])?expression.parse(attr[1],null,$as,$prefix):null;paths=paths.concat(expression.getPaths());if(!key){return null;}
element.setAttribute(key,value);}};check();for(let i=0;i<paths.length;i++){container.bind(element,paths[i],check);}}});window.ls.container.get('view').add({selector:'data-ls-bind',controller:function(element,expression,container,$prefix,$as){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('checkbox'===type){value=JSON.parse(value);if(typeof value==='boolean'){if(value===true){element.setAttribute('checked','checked');element.value=true;}
else{element.removeAttribute('checked');element.value=false;}
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;}
if(bind){element.addEventListener('change',function(){for(let i=0;i<paths.length;i++){container.path(paths[i],element.checked,$as,$prefix);}});}}

@@ -108,15 +111,13 @@ return;}

if(bind){element.addEventListener('input',sync);}}
else{if(element.innerText!==value){element.innerHTML=value;}}};let sync=(function(as,prefix){return function(){for(let i=0;i<paths.length;i++){container.path(paths[i],element.value,as,prefix);}}})($as,$prefix);let syntax=element.getAttribute('data-ls-bind');let result=expression.parse(syntax,null,$as,$prefix);let paths=expression.getPaths();for(let i=0;i<paths.length;i++){container.bind(element,paths[i],function(){echo(expression.parse(syntax,null,$as,$prefix),false);});}
echo(result,true);}});container.get('view').add({selector:'data-ls-if',controller:function(element,expression,$as,$prefix){let result='';let syntax=element.getAttribute('data-ls-if')||'';let debug=element.getAttribute('data-debug')||false;let paths=[];let check=function(){if(debug){console.info('debug-ls-if',expression.parse(syntax,'undefined',$as,$prefix));}
else{if(element.innerText!==value){element.innerHTML=value;}}};let sync=(function(as,prefix){return function(){for(let i=0;i<paths.length;i++){container.path(paths[i],element.value,as,prefix);}}})($as,$prefix);let syntax=element.getAttribute('data-ls-bind');let result=expression.parse(syntax,null,$as,$prefix);let paths=expression.getPaths();echo(result,true);for(let i=0;i<paths.length;i++){container.bind(element,paths[i],function(){echo(expression.parse(syntax,null,$as,$prefix),false);});}}});window.ls.container.get('view').add({selector:'data-ls-if',controller:function(element,expression,container,$as,$prefix){let result='';let syntax=element.getAttribute('data-ls-if')||'';let debug=element.getAttribute('data-debug')||false;let paths=[];let check=function(){if(debug){console.info('debug-ls-if',expression.parse(syntax,'undefined',$as,$prefix));}
try{result=!!(eval(expression.parse(syntax,'undefined',$as,$prefix).replace(/(\r\n|\n|\r)/gm,' ')));}
catch(error){throw new Error('Failed to evaluate expression "'+syntax+'": '+error);}
paths=expression.getPaths();if(!result){element.style.visibility='hidden';element.style.display='none';}
else{element.style.removeProperty('display');element.style.removeProperty('visibility');}};check();for(let i=0;i<paths.length;i++){container.bind(element,paths[i],check);}}});container.get('view').add({selector:'data-ls-loop',template:false,repeat:false,nested:false,controller:function(element,view,container,window){let expr=element.getAttribute('data-ls-loop');let echo=function(){let array=container.path(expr);array=(!array)?[]:array;while(element.hasChildNodes()){element.removeChild(element.lastChild);element.lastChild=null;}
else{element.style.removeProperty('display');element.style.removeProperty('visibility');}};check();for(let i=0;i<paths.length;i++){container.bind(element,paths[i],check);}}});window.ls.container.get('view').add({selector:'data-ls-loop',template:false,repeat:false,nested:false,controller:function(element,view,container,window){let expr=element.getAttribute('data-ls-loop');let as=element.getAttribute('data-ls-as');let echo=function(){let array=container.path(expr);array=(!array)?[]:array;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)?'hidden':'visible';for(let prop in array){if(!array.hasOwnProperty(prop)){continue;}
children[prop]=children[prop]||element.backup.cloneNode(true);element.appendChild(children[prop]);(function(index){let context=expr+'.'+index;container.set(element.getAttribute('data-ls-as'),container.path(context),true);container.set('$index',index,true);container.set('$prefix',context,true);container.set('$as',element.getAttribute('data-ls-as'),true);view.render(children[prop]);})(prop);}
container.set('$index',null,true);container.set('$prefix','',true);container.set('$as','',true);};element.template=(element.template)?element.template:(element.children.length===1)?element.children[0].innerHTML:'';if(!element.backup){element.backup=(element.children.length===1)?element.children[0]:window.document.createElement('li');}
echo();container.bind(element,expr,echo);container.bind(element,expr+'.length',echo);}});container.get('view').add({selector:'data-ls-template',template:false,repeat:true,controller:function(element,view,http,expression,document){let template=expression.parse(element.getAttribute('data-ls-template'));let type=element.getAttribute('data-type')||'url';element.innerHTML='';let parse=function(data,element){element.innerHTML=data;view.render(element);element.dispatchEvent(new CustomEvent('template-loaded',{bubbles:true,cancelable:false}));};if('script'===type){let inlineTemplate=document.getElementById(template);if(inlineTemplate&&inlineTemplate.innerHTML){parse(inlineTemplate.innerHTML,element);}
children[prop]=template.cloneNode(true);element.appendChild(children[prop]);(function(index){let context=expr+'.'+index;container.set(as,container.path(context),true);container.set('$index',index,true,false,false);container.set('$prefix',context,true,false,false);container.set('$as',as,true,false,false);view.render(children[prop]);})(prop);}
container.set('$index',null,true,false,false);container.set('$prefix','',true,false,false);container.set('$as','',true,false,false);};let template=(element.children.length===1)?element.children[0]:window.document.createElement('li');echo();container.bind(element,expr,echo);container.bind(element,expr+'.length',echo);}});window.ls.container.get('view').add({selector:'data-ls-template',template:false,repeat:true,controller:function(element,view,http,expression,document){let template=expression.parse(element.getAttribute('data-ls-template'));let type=element.getAttribute('data-type')||'url';element.innerHTML='';let parse=function(data,element){element.innerHTML=data;view.render(element);element.dispatchEvent(new CustomEvent('template-loaded',{bubbles:true,cancelable:false}));};if('script'===type){let inlineTemplate=document.getElementById(template);if(inlineTemplate&&inlineTemplate.innerHTML){parse(inlineTemplate.innerHTML,element);}
else{element.innerHTML='<span style="color: red">Missing template "'+template+'"</span>';}
return;}
http.get(template).then(function(element){return function(data){parse(data,element);}}(element),function(){throw new Error('Failed loading template');});}});
let container=function(){let stock=[];let cachePrefix='none';let memory={};let setCachePrefix=function(prefix){cachePrefix=prefix;return this;};let getCachePrefix=function(){return cachePrefix;};let set=function(name,object,singleton,cache){if(typeof name!=='string'){throw new Error('var name must be of type string');}
window.ls=window.ls||{};window.ls.container=function(){let stock={};let cachePrefix='none';let memory={};let setCachePrefix=function(prefix){cachePrefix=prefix;return this;};let getCachePrefix=function(){return cachePrefix;};let set=function(name,object,singleton,cache=false,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');}
if(cache){window.localStorage.setItem(getCachePrefix()+'.'+name,JSON.stringify(object));}
stock[name]={name:name,object:object,singleton:singleton,instance:null};return this;};let get=function(name){let service=(undefined!==stock[name])?stock[name]:null;if(null===service){if(memory[getCachePrefix()+'.'+name]){return memory[getCachePrefix()+'.'+name];}
stock[name]={name:name,object:object,singleton:singleton,instance:null,watch:watch,};return this;};let get=function(name){let service=(undefined!==stock[name])?stock[name]:null;if(null===service){if(memory[getCachePrefix()+'.'+name]){return memory[getCachePrefix()+'.'+name];}
let cached=window.localStorage.getItem(getCachePrefix()+'.'+name);if(cached){cached=JSON.parse(cached);memory[getCachePrefix()+'.'+name]=cached;return cached;}
return null;}
if(service.instance===null){let instance=(typeof service.object==='function')?this.resolve(service.object):service.object;let skip=false;if(name!=='window'&&name!=='document'&&name!=='element'&&typeof instance==='object'&&instance!==null){instance=new Proxy(instance,{name:service.name,watch:function(){},get:function(obj,prop){if(prop==="__name"){return this.name;}
if(prop==="__watch"){return this.watch;}
if(typeof obj[prop]==='object'&&obj[prop]!==null){let handler=Object.assign({},this);handler.name=handler.name+'.'+prop;return new Proxy(obj[prop],handler)}
else{return obj[prop];}},set:function(obj,prop,value,receiver){if(prop==="__name"){return this.name=value;}
if(prop==="__watch"){return this.watch=value;}
obj[prop]=value;let path=receiver.__name+'.'+prop;document.dispatchEvent(new CustomEvent(path+'.changed'));if(skip){return true;}
skip=true;container.set('$prop',prop,true);container.set('$value',value,true);container.resolve(this.watch);container.set('$prop',null,true);container.set('$value',null,true);skip=false;return true;},});}
if(service.instance===null){let instance=(typeof service.object==='function')?this.resolve(service.object):service.object;let skip=false;if(service.watch&&name!=='window'&&name!=='document'&&name!=='element'&&typeof instance==='object'&&instance!==null){let handler={name:service.name,watch:function(){},get:function(target,key){if(key==="__name"){return this.name;}
if(key==="__watch"){return this.watch;}
if(key==="__proxy"){return true;}
if(typeof target[key]==='object'&&target[key]!==null&&!target[key].__proxy){let handler=Object.assign({},this);handler.name=handler.name+'.'+key;return new Proxy(target[key],handler)}
else{return target[key];}},set:function(target,key,value,receiver){if(key==="__name"){return this.name=value;}
if(key==="__watch"){return this.watch=value;}
target[key]=value;let path=receiver.__name+'.'+key;document.dispatchEvent(new CustomEvent(path+'.changed'));if(skip){return true;}
skip=true;container.set('$prop',key,true);container.set('$value',value,true);container.resolve(this.watch);container.set('$key',null,true);container.set('$value',null,true);skip=false;return true;},};instance=new Proxy(instance,handler);}
if(service.singleton){service.instance=instance;}
return instance;}
return service.instance;};let resolve=function(target){if(!target){return function(){};}
let self=this;let FN_ARGS=/^function\s*[^\(]*\(\s*([^\)]*)\)/m;let text=target.toString()||'';let args=text.match(FN_ARGS)[1].split(',');return target.apply(target,args.map(function(value){return self.get(value.trim());}));};let path=function(path,value,as,prefix){as=(as)?as:container.get('$as');prefix=(prefix)?prefix:container.get('$prefix');path=path.replace(as,prefix).split('.');let object=this.get(path.shift());while(path.length>1){if(undefined==object){return null;}
let self=this;let FN_ARGS=/^function\s*[^\(]*\(\s*([^\)]*)\)/m;let text=target.toString()||'';let args=text.match(FN_ARGS)[1].split(',');return target.apply(target,args.map(function(value){return self.get(value.trim());}));};let path=function(path,value,as,prefix){as=(as)?as:container.get('$as');prefix=(prefix)?prefix:container.get('$prefix');path=path.replace(as+'.',prefix+'.').split('.');let name=path.shift();let object=this.get(name);let result=null;while(path.length>1){if(undefined===object){return null;}
object=object[path.shift()];}
if(undefined!=value){return object[path.shift()]=value;}
if(undefined==object){return null;}
let shift=path.shift();if(undefined==shift){return object;}
return object[shift];};let container={set:set,get:get,resolve:resolve,path:path,bind:function(element,path,callback,as,prefix){as=(as)?as:container.get('$as');prefix=(prefix)?prefix:container.get('$prefix');let event=path.replace(as,prefix)+'.changed';let printer=function(){if(!document.body.contains(element)){console.log('cleaned dom');element=null;document.removeEventListener(event,printer,false);return false;}
callback();};document.addEventListener(event,printer);},setCachePrefix:setCachePrefix,getCachePrefix:getCachePrefix};set('container',container,true);return container;}();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(undefined!==value){object[path.shift()]=value;return true;}
if(undefined===object){return null;}
let shift=path.shift();if(undefined===shift){result=object;}
else{return object[shift];}
return result;};let bind=function(element,path,callback,as,prefix){as=(as)?as:container.get('$as');prefix=(prefix)?prefix:container.get('$prefix');let event=path.replace(as+'.',prefix+'.')+'.changed';let printer=function(){if(!document.body.contains(element)){element=null;document.removeEventListener(event,printer,false);return false;}
callback();};document.addEventListener(event,printer);};let container={set:set,get:get,resolve:resolve,path:path,bind:bind,setCachePrefix:setCachePrefix,getCachePrefix:getCachePrefix};set('container',container,true,false,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');}

@@ -33,6 +35,6 @@ if(typeof headers!=='object'){throw new Error('var headers must be of type object');}

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);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();}
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,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);Object.path=function(object,path,value){path=path.split('.');while(path.length>1){if(undefined===object){return null;}
return{'get':get,'set':set}},true,false,false);Object.path=function(object,path,value){path=path.split('.');while(path.length>1){if(undefined===object){return null;}
object=object[path.shift()];}

@@ -47,5 +49,5 @@ if(undefined!==value){return object[path.shift()]=value;}

return false;};}
container.set('view',function(http,container){let stock={};let execute=function(view,node,container){container.set('element',node,true);container.resolve(view.controller);if(true!==view.repeat){node.removeAttribute(view.selector);}};let parse=function(node,skip){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(attrs&&attrsLen){if(1!==node.nodeType){return;}
for(let x=0;x<attrsLen;x++){if(node.$lsSkip===true){break;}
window.ls.container.set('view',function(http,container){let stock={};let execute=function(view,node,container){container.set('element',node,true,false,false);container.resolve(view.controller);if(true!==view.repeat){node.removeAttribute(view.selector);}};let parse=function(node,skip){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;}

@@ -63,3 +65,3 @@ let comp=stock[attr];if(typeof comp.template==="function"){comp.template=container.resolve(comp.template);}

if(!object.selector){throw new Error('View component is missing a selector attribute');}
stock[object.selector]=object;return this;},render:function(element){parse(element);element.dispatchEvent(new window.Event('rendered',{bubbles:false}));}}},true);container.set('form',function(){function cast(value,to){switch(to){case'int':case'integer':value=parseInt(value);break;case'string':value=value.toString();break;case'json':value=(value)?JSON.parse(value):[];break;case'array':value=(value.constructor===Array)?value:[value];break;case'array-empty':value=[];break;case'bool':case'boolean':value=(value==='false')?false:value;value=!!value;break;}
stock[object.selector]=object;return this;},render:function(element){parse(element);element.dispatchEvent(new window.Event('rendered',{bubbles:false}));}}},true,false,false);container.set('form',function(){function cast(value,to){switch(to){case'int':case'integer':value=parseInt(value);break;case'string':value=value.toString();break;case'json':value=(value)?JSON.parse(value):[];break;case'array':value=(value.constructor===Array)?value:[value];break;case'array-empty':value=[];break;case'bool':case'boolean':value=(value==='false')?false:value;value=!!value;break;}
return value;}

@@ -81,7 +83,7 @@ function toJson(element,json){json=json||{};let name=element.getAttribute('name');let type=element.getAttribute('type');let castTo=element.getAttribute('data-cast-to');let ref=json;if(name&&'FORM'!==element.tagName){if('FIELDSET'===element.tagName){if(castTo==='object'){if(json[name]===undefined){json[name]={};}

return json;}
return{'toJson':toJson}},true);container.set('state',function(window){let states=[];let current=null;let previous=null;let getPrevious=function(){return previous;};let setPrevious=function(value){previous=value;return this;};let getCurrent=function(){return current;};let setCurrent=function(value){current=value;return this;};let setParam=function(key,value){state.params[key]=value;return this;};let getParam=function(key,def){if(key in state.params){return state.params[key];}
return{'toJson':toJson}},true,false,false);window.ls.container.set('router',function(window){let states=[];let current=null;let previous=null;let getPrevious=function(){return previous;};let setPrevious=function(value){previous=value;return this;};let getCurrent=function(){return current;};let setCurrent=function(value){current=value;return this;};let setParam=function(key,value){state.params[key]=value;return this;};let getParam=function(key,def){if(key in state.params){return state.params[key];}
return def;};let getParams=function(){return state.params;};let getURL=function(){return window.location.href;};let reset=function(){state.params=getJsonFromUrl(window.location.search);state.hash=window.location.hash;};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+((location.hash)?location.hash:'');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],match=new RegExp("^"+value.path.replace(/:[^\s/]+/g,'([\\w-]+)')+"$");let found=url.match(match);if(found){previous=current;current=value;return value;}}
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);}

@@ -94,14 +96,15 @@ else{window.history.replaceState({},'',URL);}

if(!index){result[key].push(val);}
else{result[key][index]=val;}}});return result;};let state={setParam:setParam,getParam:getParam,getParams:getParams,getURL:getURL,add:add,change:change,reload:reload,reset:reset,match:match,getCurrent:getCurrent,setCurrent:setCurrent,getPrevious:getPrevious,setPrevious:setPrevious,params:getJsonFromUrl(window.location.search),hash:window.location.hash};return state;},true);container.set('expression',function(container,filter,$as,$prefix){let reg=/(\{{.*?\}})/gi;let paths=[];return{parse:function(string,def,as,prefix){def=def||'';paths=[];return string.replace(reg,function(match)
else{result[key][index]=val;}}});return result;};let state={setParam:setParam,getParam:getParam,getParams:getParams,getURL:getURL,add:add,change:change,reload:reload,reset:reset,match:match,getCurrent:getCurrent,setCurrent:setCurrent,getPrevious:getPrevious,setPrevious:setPrevious,params:getJsonFromUrl(window.location.search),hash:window.location.hash};return state;},true,false,false);window.ls.container.set('expression',function(container,filter,$as,$prefix){let reg=/(\{{.*?\}})/gi;let paths=[];return{parse:function(string,def,as,prefix){def=def||'';paths=[];return string.replace(reg,function(match)
{let reference=match.substring(2,match.length-2).replace('[\'','.').replace('\']','').trim();reference=reference.split('|');let path=(reference[0]||'');let result=container.path(path,undefined,as,prefix);if(!paths.includes(path)){paths.push(path);}
result=(null===result||undefined===result)?def:result;result=(typeof result==='object')?JSON.stringify(result):result;if(reference.length>=2){for(let i=1;i<reference.length;i++){result=filter.apply(result,reference[i],{});}}
return result;});},getPaths:function(){return paths;},}},true);container.set('filter',function(container){let filters={};let add=function(name,callback){filters[name]=callback;return this;};let apply=function(value,name){container.set('$value',value,true);return container.resolve(filters[name]);};add('uppercase',function(value){return value.toUpperCase();});add('lowercase',function(value){return value.toLowerCase();});return{add:add,apply:apply}},true);container.get('filter').add('escape',function(value){if(typeof value!=='string'){return value;}
return value.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/\"/g,'&quot;').replace(/\'/g,'&#39;').replace(/\//g,'&#x2F;');});container.set('window',window,true).set('document',window.document,true).set('element',window.document,true);let app=function(version){return{run:function(window){try{container.get('http').addGlobalParam('version',version);this.view.render(window.document);}
catch(error){var handler=container.resolve(this.error);handler(error);}},error:function(){return function(error){console.error('error',error.message,error.stack,error.toString());}},container:container,view:container.get('view')}};container.get('view').add({selector:'data-ls-init',controller:function(element,window,document,view,state){let firstFromServer=(element.getAttribute('data-first-from-server')==='true');let scope={selector:'data-ls-scope',template:false,repeat:true,controller:function(){},state:true},init=function(route){window.scrollTo(0,0);if(window.document.body.scrollTo){window.document.body.scrollTo(0,0);}
state.reset();scope.protected=(undefined!==route.view.protected)?route.view.protected:false;if(scope.protected&&(null===state.getPrevious())){throw new Error('CSRF protection');}
scope.template=(undefined!==route.view.template)?route.view.template:null;scope.controller=(undefined!==route.view.controller)?route.view.controller:function(){};scope.state=(undefined!==route.view.state)?route.view.state:true;document.dispatchEvent(new CustomEvent('state-change'));if(firstFromServer&&null===state.getPrevious()){scope.template='';}
else if(null!==state.getPrevious()){scope.nested=false;view.render(element);}
document.dispatchEvent(new CustomEvent('state-changed'));},findParent=function(tagName,el){if((el.nodeName||el.tagName).toLowerCase()===tagName.toLowerCase()){return el;}
result=(null===result||undefined===result)?def:result;result=(typeof result==='object')?JSON.stringify(result):result;if(reference.length>=2){for(let i=1;i<reference.length;i++){result=filter.apply(reference[i],result);}}
return result;});},getPaths:function(){return paths;},}},true,false,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,false);return container.resolve(filters[name]);};add('uppercase',function($value){return $value.toUpperCase();});add('lowercase',function($value){return $value.toLowerCase();});return{add:add,apply:apply}},true,false,false);window.ls.container.get('filter').add('escape',function(value){if(typeof value!=='string'){return value;}
return value.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/\"/g,'&quot;').replace(/\'/g,'&#39;').replace(/\//g,'&#x2F;');});window.ls=window.ls||{};window.ls.container.set('window',window,true,false,false).set('document',window.document,true,false,false).set('element',window.document,true,false,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=function(){return function(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(){},state:true};let scopeElement=document.createElement('div');let init=function(route){window.scrollTo(0,0);if(window.document.body.scrollTo){window.document.body.scrollTo(0,0);}
router.reset();if(null===route){return;}
scope.protected=(undefined!==route.view.protected)?route.view.protected:false;if(scope.protected&&(null===router.getPrevious())){throw new Error('CSRF protection');}
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='';}
else if(null!==router.getPrevious()){view.render(element);}
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;};view.add(scope);document.addEventListener('click',function(event){let target=findParent('a',event.target);if(!target){return false;}
return null;};scopeElement.setAttribute('data-ls-scope','');element.insertBefore(scopeElement,element.firstChild);view.add(scope);document.addEventListener('click',function(event){let target=findParent('a',event.target);if(!target){return false;}
if(!target.href){return false;}

@@ -111,18 +114,20 @@ if((event.metaKey)){return false;}

if(target.hostname!==window.location.hostname){return false;}
let route=state.match(target);if(null===route){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(state.getPrevious()&&state.getPrevious().view&&(state.getPrevious().view.scope!==route.view.scope)){window.location.href=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(){let route=state.match(window.location);if(state.getPrevious()&&state.getPrevious().view&&(state.getPrevious().view.scope!==route.view.scope)){window.location.reload();return false;}
init(route);});init(state.match(window.location));}});container.get('view').add({selector:'data-ls-attrs',controller:function(element,expression,$as,$prefix){let attrs=element.getAttribute('data-ls-attrs').trim().split(',');let paths=[];let check=function(){for(let i=0;i<attrs.length;i++){let attr=attrs[i].split('=');let key=(attr[0])?expression.parse(attr[0],null,$as,$prefix):null;paths=paths.concat(expression.getPaths());let value=(attr[1])?expression.parse(attr[1],null,$as,$prefix):null;paths=paths.concat(expression.getPaths());if(!key){return null;}
element.setAttribute(key,value);}};check();for(let i=0;i<paths.length;i++){container.bind(element,paths[i],check);}}});container.get('view').add({selector:'data-ls-if',controller:function(element,expression,$as,$prefix){let result='';let syntax=element.getAttribute('data-ls-if')||'';let debug=element.getAttribute('data-debug')||false;let paths=[];let check=function(){if(debug){console.info('debug-ls-if',expression.parse(syntax,'undefined',$as,$prefix));}
init(route);return true;});window.addEventListener('popstate',function(){let route=router.match(window.location);if(router.getPrevious()&&router.getPrevious().view&&(router.getPrevious().view.scope!==route.view.scope)){window.location.reload();return false;}
init(route);});init(router.match(window.location));}});window.ls.container.get('view').add({selector:'data-ls-attrs',controller:function(element,expression,container,$as,$prefix){let attrs=element.getAttribute('data-ls-attrs').trim().split(',');let paths=[];let check=function(){for(let i=0;i<attrs.length;i++){let attr=attrs[i].split('=');let key=(attr[0])?expression.parse(attr[0],null,$as,$prefix):null;paths=paths.concat(expression.getPaths());let value=(attr[1])?expression.parse(attr[1],null,$as,$prefix):null;paths=paths.concat(expression.getPaths());if(!key){return null;}
element.setAttribute(key,value);}};check();for(let i=0;i<paths.length;i++){container.bind(element,paths[i],check);}}});window.ls.container.get('view').add({selector:'data-ls-if',controller:function(element,expression,container,$as,$prefix){let result='';let syntax=element.getAttribute('data-ls-if')||'';let debug=element.getAttribute('data-debug')||false;let paths=[];let check=function(){if(debug){console.info('debug-ls-if',expression.parse(syntax,'undefined',$as,$prefix));}
try{result=!!(eval(expression.parse(syntax,'undefined',$as,$prefix).replace(/(\r\n|\n|\r)/gm,' ')));}
catch(error){throw new Error('Failed to evaluate expression "'+syntax+'": '+error);}
paths=expression.getPaths();if(!result){element.style.visibility='hidden';element.style.display='none';}
else{element.style.removeProperty('display');element.style.removeProperty('visibility');}};check();for(let i=0;i<paths.length;i++){container.bind(element,paths[i],check);}}});container.get('view').add({selector:'data-ls-loop',template:false,repeat:false,nested:false,controller:function(element,view,container,window){let expr=element.getAttribute('data-ls-loop');let echo=function(){let array=container.path(expr);array=(!array)?[]:array;while(element.hasChildNodes()){element.removeChild(element.lastChild);element.lastChild=null;}
else{element.style.removeProperty('display');element.style.removeProperty('visibility');}};check();for(let i=0;i<paths.length;i++){container.bind(element,paths[i],check);}}});window.ls.container.get('view').add({selector:'data-ls-loop',template:false,repeat:false,nested:false,controller:function(element,view,container,window){let expr=element.getAttribute('data-ls-loop');let as=element.getAttribute('data-ls-as');let echo=function(){let array=container.path(expr);array=(!array)?[]:array;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)?'hidden':'visible';for(let prop in array){if(!array.hasOwnProperty(prop)){continue;}
children[prop]=children[prop]||element.backup.cloneNode(true);element.appendChild(children[prop]);(function(index){let context=expr+'.'+index;container.set(element.getAttribute('data-ls-as'),container.path(context),true);container.set('$index',index,true);container.set('$prefix',context,true);container.set('$as',element.getAttribute('data-ls-as'),true);view.render(children[prop]);})(prop);}
container.set('$index',null,true);container.set('$prefix','',true);container.set('$as','',true);};element.template=(element.template)?element.template:(element.children.length===1)?element.children[0].innerHTML:'';if(!element.backup){element.backup=(element.children.length===1)?element.children[0]:window.document.createElement('li');}
echo();container.bind(element,expr,echo);container.bind(element,expr+'.length',echo);}});container.get('view').add({selector:'data-ls-alt',template:false,repeat:true,controller:function(element,expression){element.alt=expression.parse(element.dataset['lsAlt']);}});container.get('view').add({selector:'data-ls-class',template:false,repeat:true,controller:function(element,expression){element.className=expression.parse(element.dataset['lsClass']);}});container.get('view').add({selector:'data-ls-echo',template:false,repeat:true,controller:function(element,expression,filter){let def=expression.parse(element.getAttribute('data-default')||'');let filterName=element.getAttribute('data-filter')||'';let filterOptions=JSON.parse(element.getAttribute('data-filter-options')||'{}');let result=expression.parse(element.dataset['lsEcho']);result=result||def;if(filterName){result=filter.apply(result,filterName,filterOptions);}
children[prop]=template.cloneNode(true);element.appendChild(children[prop]);(function(index){let context=expr+'.'+index;container.set(as,container.path(context),true);container.set('$index',index,true,false,false);container.set('$prefix',context,true,false,false);container.set('$as',as,true,false,false);view.render(children[prop]);})(prop);}
container.set('$index',null,true,false,false);container.set('$prefix','',true,false,false);container.set('$as','',true,false,false);};let template=(element.children.length===1)?element.children[0]:window.document.createElement('li');echo();container.bind(element,expr,echo);container.bind(element,expr+'.length',echo);}});window.ls.container.get('view').add({selector:'data-ls-template',template:false,repeat:true,controller:function(element,view,http,expression,document){let template=expression.parse(element.getAttribute('data-ls-template'));let type=element.getAttribute('data-type')||'url';element.innerHTML='';let parse=function(data,element){element.innerHTML=data;view.render(element);element.dispatchEvent(new CustomEvent('template-loaded',{bubbles:true,cancelable:false}));};if('script'===type){let inlineTemplate=document.getElementById(template);if(inlineTemplate&&inlineTemplate.innerHTML){parse(inlineTemplate.innerHTML,element);}
else{element.innerHTML='<span style="color: red">Missing template "'+template+'"</span>';}
return;}
http.get(template).then(function(element){return function(data){parse(data,element);}}(element),function(){throw new Error('Failed loading template');});}});container.get('view').add({selector:'data-ls-alt',template:false,repeat:true,controller:function(element,expression){element.alt=expression.parse(element.dataset['lsAlt']);}});container.get('view').add({selector:'data-ls-class',template:false,repeat:true,controller:function(element,expression){element.className=expression.parse(element.dataset['lsClass']);}});container.get('view').add({selector:'data-ls-echo',template:false,repeat:true,controller:function(element,expression,filter){let def=expression.parse(element.getAttribute('data-default')||'');let filterName=element.getAttribute('data-filter')||'';let filterOptions=JSON.parse(element.getAttribute('data-filter-options')||'{}');let result=expression.parse(element.dataset['lsEcho']);result=result||def;if(filterName){result=filter.apply(filterName,result);}
if(element.tagName==='INPUT'||element.tagName==='OPTION'||element.tagName==='SELECT'||element.tagName==='BUTTON'||element.tagName==='TEXTAREA'){let type=element.getAttribute('type');if('radio'===type){if(result.toString()===def){element.setAttribute('checked','checked');}

@@ -135,3 +140,3 @@ else{element.removeAttribute('checked');}}

else{if(element.innerText!==result){element.innerHTML=result;}}}});container.get('view').add({selector:'data-ls-eval',template:false,controller:function(element,expression){let statement=expression.parse(element.dataset['lsEval']);eval(statement);}});container.get('view').add({selector:'data-ls-for',repeat:true,controller:function(element,expression){let value=expression.parse(element.dataset['lsFor']);if(value!==element.htmlFor&&value!==''){element.htmlFor=value;}}});container.get('view').add({selector:'data-ls-hide',template:false,repeat:true,controller:function(element,expression){if((eval(expression.parse(element.dataset['lsHide'])))){element.style.display='inherit';}
else{element.style.display='none';}}});container.get('view').add({selector:'data-ls-href',template:false,repeat:true,controller:function(element,expression){element.href=expression.parse(element.dataset['lsHref']);}});container.get('view').add({selector:'data-ls-id',repeat:true,controller:function(element,expression){let id=expression.parse(element.dataset['lsId']);if(id!==element.id&&id!==''){element.id=id;}}});container.get('view').add({selector:'data-ls-print',template:false,repeat:true,controller:function(element,expression,filter){console.warn('data-ls-print is deprecated');var def=element.getAttribute('data-default')||'';var filterName=element.getAttribute('data-filter')||'';var filterOptions=JSON.parse(element.getAttribute('data-filter-options')||'{}');var result=expression.parse('{{'+element.dataset['lsPrint']+'}}');result=result||def;if(filterName){result=filter.apply(result,filterName,filterOptions);}
else{element.style.display='none';}}});container.get('view').add({selector:'data-ls-href',template:false,repeat:true,controller:function(element,expression){element.href=expression.parse(element.dataset['lsHref']);}});container.get('view').add({selector:'data-ls-id',repeat:true,controller:function(element,expression){let id=expression.parse(element.dataset['lsId']);if(id!==element.id&&id!==''){element.id=id;}}});container.get('view').add({selector:'data-ls-print',template:false,repeat:true,controller:function(element,expression,filter){console.warn('data-ls-print is deprecated');var def=element.getAttribute('data-default')||'';var filterName=element.getAttribute('data-filter')||'';var filterOptions=JSON.parse(element.getAttribute('data-filter-options')||'{}');var result=expression.parse('{{'+element.dataset['lsPrint']+'}}');result=result||def;if(filterName){result=filter.apply(filterName,result);}
if(element.tagName==='INPUT'||element.tagName==='SELECT'||element.tagName==='BUTTON'||element.tagName==='TEXTAREA'){var type=element.getAttribute('type');if(('radio'===type)||('checkbox'===type)){if(result.toString()===element.value||result.indexOf(element.value)>-1){element.setAttribute('checked','checked');}

@@ -138,0 +143,0 @@ else{element.removeAttribute('checked');}}

@@ -1,5 +0,9 @@

# Get Started
# Documentation
The first step to get started with Litespeed.js is to init the framework in your web project layout.
This documentation should give you knowledge of Litespeed.js framework basic concepts and how to get started building you first app.
## Get Started
The first step to get started with Litespeed.js is to init the framework in your web project HTML layout.
```html

@@ -9,4 +13,4 @@ <!DOCTYPE html>

<head></head>
<body data-ls-init>
<main data-ls-scope="">Loading...</main>
<body>
<main data-ls-router>Loading your router matching state in this element</main>

@@ -20,3 +24,2 @@ <script>

let script = document.createElement('script');
script.type = 'text/javascript';
script.async = true;

@@ -26,19 +29,13 @@ script.src = 'scripts/litespeed.js';

script.onload = function() {
window.Demo = app('v1.0.0'); // Init app and set your own cache buster value
let state = window.Demo.container.get('state');
state // Add some basic routing rules
window.ls.router // Add some basic routing rules
.add('/', {
template: '/pages/index.html'
})
.add('/pages/test-1', {
template: '/pages/test-1.html'
.add('/pages/page-1', {
template: '/pages/page-1.html'
})
.add('/pages/test-2', {
template: '/pages/test-2.html'
})
;
window.Demo.run(window); // Watch the magic happens
window.ls.run(window); // Watch the magic happens
};

@@ -56,5 +53,5 @@

This is a basic example that shows how to init a Litespeed.js app and set 3 different views for our main scope with their respective URL's.
This is a basic example that shows how to init a Litespeed.js JS library asynchronously and set 3 different views for our main router scope with their respective URL paths.
## Register a New Service
## Create a New Service

@@ -80,9 +77,33 @@ Services are where you handle your app logic. A service is any Javascript object, whether a native object, object you create or a 3rd party library, we really don't mind.

```
## Creating a New View Component
### APIs & Examples
Service | Description | API & Examples
--- | --- | ---
**container** | Manage service registration, data binding and dependency injection internally. | [API Refs & Examples](/docs/services/container.md)
**cookie** | Manages user cookie, retrieve and set cookies. | [API Refs & Examples](/docs/services/cookie.md)
**expression** | Parse template syntax expressions and execute them as JS code. | [API Refs & Examples](/docs/services/expression.md)
**filter** | Use predefined string filters or add custom filters. | [API Refs & Examples](/docs/services/filter.md)
**http** | Manage HTTP interactions with server side APIs. | [API Refs & Examples](/docs/services/http.md)
**router** | Manage state registration and routing. | [API Refs & Examples](/docs/services/router.md)
**view** | Handles views registration and rendering | [API Refs & Examples](#/docs/services/view.md)
## Create a New View Component
// TODO
## Creating a New Filter
### APIs & Examples
Service | Description | API & Examples
--- | --- | ---
**ls-router** | Listen for app URL changes and renders the matching route on the DOM. | [API Refs & Examples](/docs/view/router.md)
**ls-bind** | Binds data between your services to the DOM. | [API Refs & Examples](/docs/views/echo.md)
**ls-attrs** | Binds data between your services to your element attributes. | [API Refs & Examples](/docs/views/echo.md)
**ls-if** | Hides element according to given expression evaluation | [API Refs & Examples](/docs/views/if.md)
**ls-loop** | Iterate over a service or array and renders element for each iteration. | [API Refs & Examples](/docs/views/loop.md)
**ls-template** | Render HTTP remote or inline script template to given element. | [API Refs & Examples](/docs/views/template.md)
## Create a New Filter
// TODO

@@ -89,0 +110,0 @@

let container=function(){let stock=[];let cachePrefix='none';let memory={};let setCachePrefix=function(prefix){cachePrefix=prefix;return this;};let getCachePrefix=function(){return cachePrefix;};let set=function(name,object,singleton,cache){if(typeof name!=='string'){throw new Error('var name must be of type string');}
window.ls=window.ls||{};window.ls.container=function(){let stock={};let cachePrefix='none';let memory={};let setCachePrefix=function(prefix){cachePrefix=prefix;return this;};let getCachePrefix=function(){return cachePrefix;};let set=function(name,object,singleton,cache=false,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');}
if(cache){window.localStorage.setItem(getCachePrefix()+'.'+name,JSON.stringify(object));}
stock[name]={name:name,object:object,singleton:singleton,instance:null};return this;};let get=function(name){let service=(undefined!==stock[name])?stock[name]:null;if(null===service){if(memory[getCachePrefix()+'.'+name]){return memory[getCachePrefix()+'.'+name];}
stock[name]={name:name,object:object,singleton:singleton,instance:null,watch:watch,};return this;};let get=function(name){let service=(undefined!==stock[name])?stock[name]:null;if(null===service){if(memory[getCachePrefix()+'.'+name]){return memory[getCachePrefix()+'.'+name];}
let cached=window.localStorage.getItem(getCachePrefix()+'.'+name);if(cached){cached=JSON.parse(cached);memory[getCachePrefix()+'.'+name]=cached;return cached;}
return null;}
if(service.instance===null){let instance=(typeof service.object==='function')?this.resolve(service.object):service.object;let skip=false;if(name!=='window'&&name!=='document'&&name!=='element'&&typeof instance==='object'&&instance!==null){instance=new Proxy(instance,{name:service.name,watch:function(){},get:function(obj,prop){if(prop==="__name"){return this.name;}
if(prop==="__watch"){return this.watch;}
if(typeof obj[prop]==='object'&&obj[prop]!==null){let handler=Object.assign({},this);handler.name=handler.name+'.'+prop;return new Proxy(obj[prop],handler)}
else{return obj[prop];}},set:function(obj,prop,value,receiver){if(prop==="__name"){return this.name=value;}
if(prop==="__watch"){return this.watch=value;}
obj[prop]=value;let path=receiver.__name+'.'+prop;document.dispatchEvent(new CustomEvent(path+'.changed'));if(skip){return true;}
skip=true;container.set('$prop',prop,true);container.set('$value',value,true);container.resolve(this.watch);container.set('$prop',null,true);container.set('$value',null,true);skip=false;return true;},});}
if(service.instance===null){let instance=(typeof service.object==='function')?this.resolve(service.object):service.object;let skip=false;if(service.watch&&name!=='window'&&name!=='document'&&name!=='element'&&typeof instance==='object'&&instance!==null){let handler={name:service.name,watch:function(){},get:function(target,key){if(key==="__name"){return this.name;}
if(key==="__watch"){return this.watch;}
if(key==="__proxy"){return true;}
if(typeof target[key]==='object'&&target[key]!==null&&!target[key].__proxy){let handler=Object.assign({},this);handler.name=handler.name+'.'+key;return new Proxy(target[key],handler)}
else{return target[key];}},set:function(target,key,value,receiver){if(key==="__name"){return this.name=value;}
if(key==="__watch"){return this.watch=value;}
target[key]=value;let path=receiver.__name+'.'+key;document.dispatchEvent(new CustomEvent(path+'.changed'));if(skip){return true;}
skip=true;container.set('$prop',key,true);container.set('$value',value,true);container.resolve(this.watch);container.set('$key',null,true);container.set('$value',null,true);skip=false;return true;},};instance=new Proxy(instance,handler);}
if(service.singleton){service.instance=instance;}
return instance;}
return service.instance;};let resolve=function(target){if(!target){return function(){};}
let self=this;let FN_ARGS=/^function\s*[^\(]*\(\s*([^\)]*)\)/m;let text=target.toString()||'';let args=text.match(FN_ARGS)[1].split(',');return target.apply(target,args.map(function(value){return self.get(value.trim());}));};let path=function(path,value,as,prefix){as=(as)?as:container.get('$as');prefix=(prefix)?prefix:container.get('$prefix');path=path.replace(as,prefix).split('.');let object=this.get(path.shift());while(path.length>1){if(undefined==object){return null;}
let self=this;let FN_ARGS=/^function\s*[^\(]*\(\s*([^\)]*)\)/m;let text=target.toString()||'';let args=text.match(FN_ARGS)[1].split(',');return target.apply(target,args.map(function(value){return self.get(value.trim());}));};let path=function(path,value,as,prefix){as=(as)?as:container.get('$as');prefix=(prefix)?prefix:container.get('$prefix');path=path.replace(as+'.',prefix+'.').split('.');let name=path.shift();let object=this.get(name);let result=null;while(path.length>1){if(undefined===object){return null;}
object=object[path.shift()];}
if(undefined!=value){return object[path.shift()]=value;}
if(undefined==object){return null;}
let shift=path.shift();if(undefined==shift){return object;}
return object[shift];};let container={set:set,get:get,resolve:resolve,path:path,bind:function(element,path,callback,as,prefix){as=(as)?as:container.get('$as');prefix=(prefix)?prefix:container.get('$prefix');let event=path.replace(as,prefix)+'.changed';let printer=function(){if(!document.body.contains(element)){console.log('cleaned dom');element=null;document.removeEventListener(event,printer,false);return false;}
callback();};document.addEventListener(event,printer);},setCachePrefix:setCachePrefix,getCachePrefix:getCachePrefix};set('container',container,true);return container;}();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(undefined!==value){object[path.shift()]=value;return true;}
if(undefined===object){return null;}
let shift=path.shift();if(undefined===shift){result=object;}
else{return object[shift];}
return result;};let bind=function(element,path,callback,as,prefix){as=(as)?as:container.get('$as');prefix=(prefix)?prefix:container.get('$prefix');let event=path.replace(as+'.',prefix+'.')+'.changed';let printer=function(){if(!document.body.contains(element)){element=null;document.removeEventListener(event,printer,false);return false;}
callback();};document.addEventListener(event,printer);};let container={set:set,get:get,resolve:resolve,path:path,bind:bind,setCachePrefix:setCachePrefix,getCachePrefix:getCachePrefix};set('container',container,true,false,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');}

@@ -33,6 +35,6 @@ if(typeof headers!=='object'){throw new Error('var headers must be of type object');}

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);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();}
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,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);Object.path=function(object,path,value){path=path.split('.');while(path.length>1){if(undefined===object){return null;}
return{'get':get,'set':set}},true,false,false);Object.path=function(object,path,value){path=path.split('.');while(path.length>1){if(undefined===object){return null;}
object=object[path.shift()];}

@@ -47,5 +49,5 @@ if(undefined!==value){return object[path.shift()]=value;}

return false;};}
container.set('view',function(http,container){let stock={};let execute=function(view,node,container){container.set('element',node,true);container.resolve(view.controller);if(true!==view.repeat){node.removeAttribute(view.selector);}};let parse=function(node,skip){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(attrs&&attrsLen){if(1!==node.nodeType){return;}
for(let x=0;x<attrsLen;x++){if(node.$lsSkip===true){break;}
window.ls.container.set('view',function(http,container){let stock={};let execute=function(view,node,container){container.set('element',node,true,false,false);container.resolve(view.controller);if(true!==view.repeat){node.removeAttribute(view.selector);}};let parse=function(node,skip){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;}

@@ -63,7 +65,7 @@ let comp=stock[attr];if(typeof comp.template==="function"){comp.template=container.resolve(comp.template);}

if(!object.selector){throw new Error('View component is missing a selector attribute');}
stock[object.selector]=object;return this;},render:function(element){parse(element);element.dispatchEvent(new window.Event('rendered',{bubbles:false}));}}},true);container.set('state',function(window){let states=[];let current=null;let previous=null;let getPrevious=function(){return previous;};let setPrevious=function(value){previous=value;return this;};let getCurrent=function(){return current;};let setCurrent=function(value){current=value;return this;};let setParam=function(key,value){state.params[key]=value;return this;};let getParam=function(key,def){if(key in state.params){return state.params[key];}
stock[object.selector]=object;return this;},render:function(element){parse(element);element.dispatchEvent(new window.Event('rendered',{bubbles:false}));}}},true,false,false);window.ls.container.set('router',function(window){let states=[];let current=null;let previous=null;let getPrevious=function(){return previous;};let setPrevious=function(value){previous=value;return this;};let getCurrent=function(){return current;};let setCurrent=function(value){current=value;return this;};let setParam=function(key,value){state.params[key]=value;return this;};let getParam=function(key,def){if(key in state.params){return state.params[key];}
return def;};let getParams=function(){return state.params;};let getURL=function(){return window.location.href;};let reset=function(){state.params=getJsonFromUrl(window.location.search);state.hash=window.location.hash;};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+((location.hash)?location.hash:'');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],match=new RegExp("^"+value.path.replace(/:[^\s/]+/g,'([\\w-]+)')+"$");let found=url.match(match);if(found){previous=current;current=value;return value;}}
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);}

@@ -76,14 +78,15 @@ else{window.history.replaceState({},'',URL);}

if(!index){result[key].push(val);}
else{result[key][index]=val;}}});return result;};let state={setParam:setParam,getParam:getParam,getParams:getParams,getURL:getURL,add:add,change:change,reload:reload,reset:reset,match:match,getCurrent:getCurrent,setCurrent:setCurrent,getPrevious:getPrevious,setPrevious:setPrevious,params:getJsonFromUrl(window.location.search),hash:window.location.hash};return state;},true);container.set('expression',function(container,filter,$as,$prefix){let reg=/(\{{.*?\}})/gi;let paths=[];return{parse:function(string,def,as,prefix){def=def||'';paths=[];return string.replace(reg,function(match)
else{result[key][index]=val;}}});return result;};let state={setParam:setParam,getParam:getParam,getParams:getParams,getURL:getURL,add:add,change:change,reload:reload,reset:reset,match:match,getCurrent:getCurrent,setCurrent:setCurrent,getPrevious:getPrevious,setPrevious:setPrevious,params:getJsonFromUrl(window.location.search),hash:window.location.hash};return state;},true,false,false);window.ls.container.set('expression',function(container,filter,$as,$prefix){let reg=/(\{{.*?\}})/gi;let paths=[];return{parse:function(string,def,as,prefix){def=def||'';paths=[];return string.replace(reg,function(match)
{let reference=match.substring(2,match.length-2).replace('[\'','.').replace('\']','').trim();reference=reference.split('|');let path=(reference[0]||'');let result=container.path(path,undefined,as,prefix);if(!paths.includes(path)){paths.push(path);}
result=(null===result||undefined===result)?def:result;result=(typeof result==='object')?JSON.stringify(result):result;if(reference.length>=2){for(let i=1;i<reference.length;i++){result=filter.apply(result,reference[i],{});}}
return result;});},getPaths:function(){return paths;},}},true);container.set('filter',function(container){let filters={};let add=function(name,callback){filters[name]=callback;return this;};let apply=function(value,name){container.set('$value',value,true);return container.resolve(filters[name]);};add('uppercase',function(value){return value.toUpperCase();});add('lowercase',function(value){return value.toLowerCase();});return{add:add,apply:apply}},true);container.get('filter').add('escape',function(value){if(typeof value!=='string'){return value;}
return value.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/\"/g,'&quot;').replace(/\'/g,'&#39;').replace(/\//g,'&#x2F;');});container.set('window',window,true).set('document',window.document,true).set('element',window.document,true);let app=function(version){return{run:function(window){try{container.get('http').addGlobalParam('version',version);this.view.render(window.document);}
catch(error){var handler=container.resolve(this.error);handler(error);}},error:function(){return function(error){console.error('error',error.message,error.stack,error.toString());}},container:container,view:container.get('view')}};container.get('view').add({selector:'data-ls-init',controller:function(element,window,document,view,state){let firstFromServer=(element.getAttribute('data-first-from-server')==='true');let scope={selector:'data-ls-scope',template:false,repeat:true,controller:function(){},state:true},init=function(route){window.scrollTo(0,0);if(window.document.body.scrollTo){window.document.body.scrollTo(0,0);}
state.reset();scope.protected=(undefined!==route.view.protected)?route.view.protected:false;if(scope.protected&&(null===state.getPrevious())){throw new Error('CSRF protection');}
scope.template=(undefined!==route.view.template)?route.view.template:null;scope.controller=(undefined!==route.view.controller)?route.view.controller:function(){};scope.state=(undefined!==route.view.state)?route.view.state:true;document.dispatchEvent(new CustomEvent('state-change'));if(firstFromServer&&null===state.getPrevious()){scope.template='';}
else if(null!==state.getPrevious()){scope.nested=false;view.render(element);}
document.dispatchEvent(new CustomEvent('state-changed'));},findParent=function(tagName,el){if((el.nodeName||el.tagName).toLowerCase()===tagName.toLowerCase()){return el;}
result=(null===result||undefined===result)?def:result;result=(typeof result==='object')?JSON.stringify(result):result;if(reference.length>=2){for(let i=1;i<reference.length;i++){result=filter.apply(reference[i],result);}}
return result;});},getPaths:function(){return paths;},}},true,false,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,false);return container.resolve(filters[name]);};add('uppercase',function($value){return $value.toUpperCase();});add('lowercase',function($value){return $value.toLowerCase();});return{add:add,apply:apply}},true,false,false);window.ls.container.get('filter').add('escape',function(value){if(typeof value!=='string'){return value;}
return value.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/\"/g,'&quot;').replace(/\'/g,'&#39;').replace(/\//g,'&#x2F;');});window.ls=window.ls||{};window.ls.container.set('window',window,true,false,false).set('document',window.document,true,false,false).set('element',window.document,true,false,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=function(){return function(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(){},state:true};let scopeElement=document.createElement('div');let init=function(route){window.scrollTo(0,0);if(window.document.body.scrollTo){window.document.body.scrollTo(0,0);}
router.reset();if(null===route){return;}
scope.protected=(undefined!==route.view.protected)?route.view.protected:false;if(scope.protected&&(null===router.getPrevious())){throw new Error('CSRF protection');}
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='';}
else if(null!==router.getPrevious()){view.render(element);}
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;};view.add(scope);document.addEventListener('click',function(event){let target=findParent('a',event.target);if(!target){return false;}
return null;};scopeElement.setAttribute('data-ls-scope','');element.insertBefore(scopeElement,element.firstChild);view.add(scope);document.addEventListener('click',function(event){let target=findParent('a',event.target);if(!target){return false;}
if(!target.href){return false;}

@@ -93,12 +96,12 @@ if((event.metaKey)){return false;}

if(target.hostname!==window.location.hostname){return false;}
let route=state.match(target);if(null===route){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(state.getPrevious()&&state.getPrevious().view&&(state.getPrevious().view.scope!==route.view.scope)){window.location.href=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(){let route=state.match(window.location);if(state.getPrevious()&&state.getPrevious().view&&(state.getPrevious().view.scope!==route.view.scope)){window.location.reload();return false;}
init(route);});init(state.match(window.location));}});container.get('view').add({selector:'data-ls-attrs',controller:function(element,expression,$as,$prefix){let attrs=element.getAttribute('data-ls-attrs').trim().split(',');let paths=[];let check=function(){for(let i=0;i<attrs.length;i++){let attr=attrs[i].split('=');let key=(attr[0])?expression.parse(attr[0],null,$as,$prefix):null;paths=paths.concat(expression.getPaths());let value=(attr[1])?expression.parse(attr[1],null,$as,$prefix):null;paths=paths.concat(expression.getPaths());if(!key){return null;}
element.setAttribute(key,value);}};check();for(let i=0;i<paths.length;i++){container.bind(element,paths[i],check);}}});container.get('view').add({selector:'data-ls-bind',controller:function(element,expression,container,$prefix,$as){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');}
init(route);return true;});window.addEventListener('popstate',function(){let route=router.match(window.location);if(router.getPrevious()&&router.getPrevious().view&&(router.getPrevious().view.scope!==route.view.scope)){window.location.reload();return false;}
init(route);});init(router.match(window.location));}});window.ls.container.get('view').add({selector:'data-ls-attrs',controller:function(element,expression,container,$as,$prefix){let attrs=element.getAttribute('data-ls-attrs').trim().split(',');let paths=[];let check=function(){for(let i=0;i<attrs.length;i++){let attr=attrs[i].split('=');let key=(attr[0])?expression.parse(attr[0],null,$as,$prefix):null;paths=paths.concat(expression.getPaths());let value=(attr[1])?expression.parse(attr[1],null,$as,$prefix):null;paths=paths.concat(expression.getPaths());if(!key){return null;}
element.setAttribute(key,value);}};check();for(let i=0;i<paths.length;i++){container.bind(element,paths[i],check);}}});window.ls.container.get('view').add({selector:'data-ls-bind',controller:function(element,expression,container,$prefix,$as){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('checkbox'===type){value=JSON.parse(value);if(typeof value==='boolean'){if(value===true){element.setAttribute('checked','checked');element.value=true;}
else{element.removeAttribute('checked');element.value=false;}
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;}
if(bind){element.addEventListener('change',function(){for(let i=0;i<paths.length;i++){container.path(paths[i],element.checked,$as,$prefix);}});}}

@@ -108,15 +111,13 @@ return;}

if(bind){element.addEventListener('input',sync);}}
else{if(element.innerText!==value){element.innerHTML=value;}}};let sync=(function(as,prefix){return function(){for(let i=0;i<paths.length;i++){container.path(paths[i],element.value,as,prefix);}}})($as,$prefix);let syntax=element.getAttribute('data-ls-bind');let result=expression.parse(syntax,null,$as,$prefix);let paths=expression.getPaths();for(let i=0;i<paths.length;i++){container.bind(element,paths[i],function(){echo(expression.parse(syntax,null,$as,$prefix),false);});}
echo(result,true);}});container.get('view').add({selector:'data-ls-if',controller:function(element,expression,$as,$prefix){let result='';let syntax=element.getAttribute('data-ls-if')||'';let debug=element.getAttribute('data-debug')||false;let paths=[];let check=function(){if(debug){console.info('debug-ls-if',expression.parse(syntax,'undefined',$as,$prefix));}
else{if(element.innerText!==value){element.innerHTML=value;}}};let sync=(function(as,prefix){return function(){for(let i=0;i<paths.length;i++){container.path(paths[i],element.value,as,prefix);}}})($as,$prefix);let syntax=element.getAttribute('data-ls-bind');let result=expression.parse(syntax,null,$as,$prefix);let paths=expression.getPaths();echo(result,true);for(let i=0;i<paths.length;i++){container.bind(element,paths[i],function(){echo(expression.parse(syntax,null,$as,$prefix),false);});}}});window.ls.container.get('view').add({selector:'data-ls-if',controller:function(element,expression,container,$as,$prefix){let result='';let syntax=element.getAttribute('data-ls-if')||'';let debug=element.getAttribute('data-debug')||false;let paths=[];let check=function(){if(debug){console.info('debug-ls-if',expression.parse(syntax,'undefined',$as,$prefix));}
try{result=!!(eval(expression.parse(syntax,'undefined',$as,$prefix).replace(/(\r\n|\n|\r)/gm,' ')));}
catch(error){throw new Error('Failed to evaluate expression "'+syntax+'": '+error);}
paths=expression.getPaths();if(!result){element.style.visibility='hidden';element.style.display='none';}
else{element.style.removeProperty('display');element.style.removeProperty('visibility');}};check();for(let i=0;i<paths.length;i++){container.bind(element,paths[i],check);}}});container.get('view').add({selector:'data-ls-loop',template:false,repeat:false,nested:false,controller:function(element,view,container,window){let expr=element.getAttribute('data-ls-loop');let echo=function(){let array=container.path(expr);array=(!array)?[]:array;while(element.hasChildNodes()){element.removeChild(element.lastChild);element.lastChild=null;}
else{element.style.removeProperty('display');element.style.removeProperty('visibility');}};check();for(let i=0;i<paths.length;i++){container.bind(element,paths[i],check);}}});window.ls.container.get('view').add({selector:'data-ls-loop',template:false,repeat:false,nested:false,controller:function(element,view,container,window){let expr=element.getAttribute('data-ls-loop');let as=element.getAttribute('data-ls-as');let echo=function(){let array=container.path(expr);array=(!array)?[]:array;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)?'hidden':'visible';for(let prop in array){if(!array.hasOwnProperty(prop)){continue;}
children[prop]=children[prop]||element.backup.cloneNode(true);element.appendChild(children[prop]);(function(index){let context=expr+'.'+index;container.set(element.getAttribute('data-ls-as'),container.path(context),true);container.set('$index',index,true);container.set('$prefix',context,true);container.set('$as',element.getAttribute('data-ls-as'),true);view.render(children[prop]);})(prop);}
container.set('$index',null,true);container.set('$prefix','',true);container.set('$as','',true);};element.template=(element.template)?element.template:(element.children.length===1)?element.children[0].innerHTML:'';if(!element.backup){element.backup=(element.children.length===1)?element.children[0]:window.document.createElement('li');}
echo();container.bind(element,expr,echo);container.bind(element,expr+'.length',echo);}});container.get('view').add({selector:'data-ls-template',template:false,repeat:true,controller:function(element,view,http,expression,document){let template=expression.parse(element.getAttribute('data-ls-template'));let type=element.getAttribute('data-type')||'url';element.innerHTML='';let parse=function(data,element){element.innerHTML=data;view.render(element);element.dispatchEvent(new CustomEvent('template-loaded',{bubbles:true,cancelable:false}));};if('script'===type){let inlineTemplate=document.getElementById(template);if(inlineTemplate&&inlineTemplate.innerHTML){parse(inlineTemplate.innerHTML,element);}
children[prop]=template.cloneNode(true);element.appendChild(children[prop]);(function(index){let context=expr+'.'+index;container.set(as,container.path(context),true);container.set('$index',index,true,false,false);container.set('$prefix',context,true,false,false);container.set('$as',as,true,false,false);view.render(children[prop]);})(prop);}
container.set('$index',null,true,false,false);container.set('$prefix','',true,false,false);container.set('$as','',true,false,false);};let template=(element.children.length===1)?element.children[0]:window.document.createElement('li');echo();container.bind(element,expr,echo);container.bind(element,expr+'.length',echo);}});window.ls.container.get('view').add({selector:'data-ls-template',template:false,repeat:true,controller:function(element,view,http,expression,document){let template=expression.parse(element.getAttribute('data-ls-template'));let type=element.getAttribute('data-type')||'url';element.innerHTML='';let parse=function(data,element){element.innerHTML=data;view.render(element);element.dispatchEvent(new CustomEvent('template-loaded',{bubbles:true,cancelable:false}));};if('script'===type){let inlineTemplate=document.getElementById(template);if(inlineTemplate&&inlineTemplate.innerHTML){parse(inlineTemplate.innerHTML,element);}
else{element.innerHTML='<span style="color: red">Missing template "'+template+'"</span>';}
return;}
http.get(template).then(function(element){return function(data){parse(data,element);}}(element),function(){throw new Error('Failed loading template');});}});
// Include gulp
var gulp = require('gulp'),
const { src, dest, series } = require('gulp');
// Plugins
concat = require('gulp-concat'),
webserver = require('gulp-webserver'),
jsmin = require('gulp-jsmin'),
// Plugins
const gulpConcat = require('gulp-concat');
const gulpWebserver = require('gulp-webserver');
const gulpJsmin = require('gulp-jsmin');
// Config
config = {
mainFile: 'litespeed.js',
src: [
'src/services/container.js',
'src/services/http.js',
'src/services/cookie.js',
'src/services/object.js',
'src/services/view.js',
'src/services/state.js',
'src/services/expression.js',
'src/services/filter.js',
'src/filters/escape.js',
'src/app.js',
'src/views/init.js',
'src/views/attrs.js',
'src/views/bind.js',
'src/views/if.js',
'src/views/loop.js',
'src/views/template.js',
],
dest: './dist'
},
// Config
const config = {
mainFile: 'litespeed.js',
src: [
'src/services/container.js',
'src/services/http.js',
'src/services/cookie.js',
'src/services/object.js',
'src/services/view.js',
'src/services/router.js',
'src/services/expression.js',
'src/services/filter.js',
'src/filters/escape.js',
'src/app.js',
'src/views/router.js',
'src/views/attrs.js',
'src/views/bind.js',
'src/views/if.js',
'src/views/loop.js',
'src/views/template.js',
],
dest: './dist'
};
// Config
configOld = {
mainFile: 'litespeed.old.js',
src: [
'src/services/container.js',
'src/services/http.js',
'src/services/cookie.js',
'src/services/object.js',
'src/services/view.js',
'src/services/deprecated/form.js',
'src/services/state.js',
'src/services/expression.js',
'src/services/filter.js',
'src/filters/escape.js',
'src/app.js',
'src/views/init.js',
'src/views/attrs.js',
'src/views/if.js',
'src/views/loop.js',
'src/views/deprecated/alt.js',
'src/views/deprecated/class.js',
'src/views/deprecated/echo.js',
'src/views/deprecated/eval.js',
'src/views/deprecated/for.js',
'src/views/deprecated/hide.js',
'src/views/deprecated/href.js',
'src/views/deprecated/id.js',
'src/views/deprecated/print.js',
'src/views/deprecated/rerender.js',
'src/views/deprecated/selected.js',
'src/views/deprecated/src.js',
'src/views/deprecated/style.js',
'src/views/deprecated/template.js',
'src/views/deprecated/title.js',
'src/views/deprecated/trigger.js',
'src/views/deprecated/options.js',
'src/views/deprecated/placeholder.js',
],
dest: './dist'
}
;
// Config
const configOld = {
mainFile: 'litespeed.old.js',
src: [
'src/services/container.js',
'src/services/http.js',
'src/services/cookie.js',
'src/services/object.js',
'src/services/view.js',
'src/services/deprecated/form.js',
'src/services/router.js',
'src/services/expression.js',
'src/services/filter.js',
'src/filters/escape.js',
'src/app.js',
'src/views/router.js',
'src/views/attrs.js',
'src/views/if.js',
'src/views/loop.js',
'src/views/template.js',
'src/views/deprecated/alt.js',
'src/views/deprecated/class.js',
'src/views/deprecated/echo.js',
'src/views/deprecated/eval.js',
'src/views/deprecated/for.js',
'src/views/deprecated/hide.js',
'src/views/deprecated/href.js',
'src/views/deprecated/id.js',
'src/views/deprecated/print.js',
'src/views/deprecated/rerender.js',
'src/views/deprecated/selected.js',
'src/views/deprecated/src.js',
'src/views/deprecated/style.js',
'src/views/deprecated/title.js',
'src/views/deprecated/trigger.js',
'src/views/deprecated/options.js',
],
dest: './dist'
};
gulp.task('concat', function() {
return gulp.src(config.src)
.pipe(concat(config.mainFile))
.pipe(jsmin())
.pipe(gulp.dest(config.dest));
});
function concat () {
return src(config.src)
.pipe(gulpConcat(config.mainFile))
.pipe(gulpJsmin())
.pipe(dest(config.dest));
}
gulp.task('concat-old', function() {
return gulp.src(configOld.src)
.pipe(concat(configOld.mainFile))
.pipe(jsmin())
.pipe(gulp.dest(configOld.dest));
});
function concatOld () {
return src(configOld.src)
.pipe(gulpConcat(configOld.mainFile))
.pipe(gulpJsmin())
.pipe(dest(configOld.dest));
}
gulp.task('watch', function() {
gulp.watch(config.src, ['build']);
});
function demo () {
return src(config.dest + '/' + config.mainFile)
.pipe(dest('./example/scripts'));
}
gulp.task('demo', ['concat'], function () {
gulp.src(config.dest + '/' + config.mainFile)
.pipe(gulp.dest('./example/scripts'));
});
gulp.task('webserver', function() {
gulp.src('example')
.pipe(webserver({
function webserver() {
return src('example')
.pipe(gulpWebserver({
fallback: 'index.html'
}));
});
}
// Default Task
gulp.task('build', ['concat', 'concat-old', 'demo']);
exports.concat = concat;
exports.concatOld = concatOld;
exports.demo = demo;
exports.webserver = webserver;
exports.default = series(concat, concatOld, demo);
{
"name": "litespeed.js",
"version": "v0.2.7",
"version": "v0.2.8",
"private": false,

@@ -26,9 +26,13 @@ "main": "gulpfile.js",

"devDependencies": {
"gulp": "^3.0.0",
"gulp-clean-css": "^2.3.2",
"gulp": "^4.0.0",
"gulp-clean-css": "^4.0.0",
"gulp-concat": "2.5.2",
"gulp-jsmin": "^0.1.5",
"gulp-less": "^4.0.1",
"gulp-webserver": "^0.9.1"
"gulp-webserver": "^0.9.1",
"jest": "^24.7.1"
},
"scripts": {
"test": "jest tests"
}
}
}

@@ -6,12 +6,11 @@ <p>

[![npm version](https://badge.fury.io/js/litespeed.js.svg)](https://badge.fury.io/js/litespeed.js)
[![Build Status](https://travis-ci.org/litespeed-js/litespeed.js.svg?branch=master)](https://travis-ci.org/litespeed-js/litespeed.js)
A simple javascript framework to build simple web applications. Litespeed is dependency free, **easy to learn** framework which gives you all tools needed to build a modern, fast and single page web application.
Litespeed.js is a micro Javascript framework for building simple web applications. Litespeed.js is dependency-free and **easy to learn** framework which allows you to extend your DOM functionality in a semantic and declarative way.
Litespeed is build using an [MVVM](https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93viewmodel) architecture design, with dependency injection service to provide easy access and dependency management between views and services.
The litespeed.js framework main features include an **[MVVM](https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93viewmodel)** architecture, built-in single page **routing**, easy to build **view components**, **dependency injection** service, **data binding**, and fully **valid and accessible HTML and DOM**.
Litespeed.js makes very good use of both browser memory management, garbage collection and rendering to maximize application performance.
Litespeed.js makes very good use of both browser memory management, garbage collection and rendering to maximize your web application performance. As of version 0.2.* litespeed.js weights only **4.9kb (minified and compressed)**
- [Getting Started](#getting-started)
- [Services](#services)
- [Views](#views)
- [Documentation](/docs/get-started.md)
- [Contributing](#contributing)

@@ -30,35 +29,9 @@ - [Copyright and license](#copyright-and-license)

```html
<script src="https://cdn.jsdelivr.net/npm/litespeed.js@v0.2.6"></script>
<script src="https://cdn.jsdelivr.net/npm/litespeed.js@v0.2.8"></script>
```
As of version 0.2.* litespeed.js weights only 4.9kb (minified and compressed)
After adding the library to your project, go to our [Documentation](/docs/get-started.md) to learn how to use Litespeed.js APIs, services and view components.
## Docs
You can also check out our demo TODO app which is a good way to understand the framework basic concepts.
* [Getting Started](/docs/get-started.md)
### Services
Service | Description | API & Examples
--- | --- | ---
**container** | Manage service registration, data binding and dependency injection internally. | [API Refs & Examples](/docs/services/container.md)
**cookie** | Manages user cookie, retrieve and set cookies. | [API Refs & Examples](/docs/services/cookie.md)
**expression** | Parse template syntax expressions and execute them as JS code. | [API Refs & Examples](/docs/services/expression.md)
**filter** | Use predefined string filters or add custom filters. | [API Refs & Examples](/docs/services/filter.md)
**http** | Manage HTTP interactions with server side APIs. | [API Refs & Examples](/docs/services/http.md)
**state** | Manage state registration and routing. | [API Refs & Examples](/docs/services/state.md)
**view** | Handles views registration and rendering | [API Refs & Examples](#/docs/services/view.md)
### Views
Service | Description | API & Examples
--- | --- | ---
**ls-init** | Starts DOM rendering and listen for URL changes. | [API Refs & Examples](/docs/view/init.md)
**ls-scope** | Uses to define the routed element scope. | [API Refs & Examples](/docs/view/scope.md)
**ls-bind** | Binds data between your services to the DOM. | [API Refs & Examples](/docs/views/echo.md)
**ls-attrs** | Binds data between your services to your element attributes. | [API Refs & Examples](/docs/views/echo.md)
**ls-if** | Hides element according to given expression evaluation | [API Refs & Examples](/docs/views/if.md)
**ls-loop** | Iterate over a service or array and renders element for each iteration. | [API Refs & Examples](/docs/views/loop.md)
**ls-template** | Render HTTP remote or inline script template to given element. | [API Refs & Examples](/docs/views/template.md)
## Contributing

@@ -65,0 +38,0 @@

@@ -0,26 +1,30 @@

window.ls = window.ls || {};
// Register all core services
container
.set('window', window, true)
.set('document', window.document, true)
.set('element', window.document, true)
window.ls.container
.set('window', window, true, false, false)
.set('document', window.document, true, false, false)
.set('element', window.document, true, false, false)
;
let app = function(version) {
return {
run: function(window) {
try {
container.get('http').addGlobalParam('version', version);
window.ls.run = function (window) {
try {
this.view.render(window.document); // Start DOM rendering
}
catch (error) {
let handler = window.ls.container.resolve(this.error);
handler(error);
}
};
// Trigger reclusive app rendering
this.view.render(window.document);
}
catch (error) {
var handler = container.resolve(this.error);
handler(error);
}
},
error: function() {return function(error) {console.error('error', error.message, error.stack, error.toString());}},
container: container,
view: container.get('view')
window.ls.error = function() {
return function(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');

@@ -1,2 +0,2 @@

container.get('filter').add('escape', function (value) {
window.ls.container.get('filter').add('escape', function (value) {
if(typeof value !== 'string') {

@@ -3,0 +3,0 @@ return value;

@@ -0,1 +1,3 @@

window.ls = window.ls || {};
/**

@@ -6,5 +8,5 @@ * Container

*/
let container = function() {
window.ls.container = function() {
let stock = [];
let stock = {};

@@ -25,3 +27,3 @@ let cachePrefix = 'none';

/**
* Register
* Set Service
*

@@ -33,6 +35,7 @@ * Adds a new service definition to application services stack.

* @param singleton bool
* @param cache bool
* @param cache bool (experimental)
* @param watch bool
* @returns container
*/
let set = function(name, object, singleton, cache) {
let set = function(name, object, singleton, cache = false, watch = true) {
if(typeof name !== 'string') {

@@ -54,3 +57,4 @@ throw new Error('var name must be of type string');

singleton: singleton,
instance: null
instance: null,
watch: watch,
};

@@ -92,6 +96,7 @@

let instance = (typeof service.object === 'function') ? this.resolve(service.object) : service.object;
let skip = false;
let skip = false;
if(name !== 'window' && name !== 'document' && name !== 'element' && typeof instance === 'object' && instance !== null) {
instance = new Proxy(instance, {
if(service.watch && name !== 'window' && name !== 'document' && name !== 'element' && typeof instance === 'object' && instance !== null) {
let handler = {
name: service.name,

@@ -101,38 +106,40 @@

get: function(obj, prop) {
if(prop === "__name") {
get: function(target, key) {
if(key === "__name") {
return this.name;
}
if(prop === "__watch") {
if(key === "__watch") {
return this.watch;
}
if (typeof obj[prop] === 'object' && obj[prop] !== null) {
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 + '.' + prop;
handler.name = handler.name + '.' + key;
return new Proxy(obj[prop], handler)
return new Proxy(target[key], handler)
}
else {
return obj[prop];
return target[key];
}
},
set: function(obj, prop, value, receiver) {
if(prop === "__name") {
set: function(target, key, value, receiver) {
if(key === "__name") {
return this.name = value;
}
if(prop === "__watch") {
if(key === "__watch") {
return this.watch = value;
}
obj[prop] = value;
target[key] = value;
let path = receiver.__name + '.' + prop;
let path = receiver.__name + '.' + key;
//console.log('updated', path + '.changed', value);
//console.log('triggered', path + '.changed', key, value);

@@ -147,3 +154,3 @@ document.dispatchEvent(new CustomEvent(path + '.changed'));

container.set('$prop', prop, true);
container.set('$prop', key, true);
container.set('$value', value, true);

@@ -153,3 +160,3 @@

container.set('$prop', null, true);
container.set('$key', null, true);
container.set('$value', null, true);

@@ -161,5 +168,8 @@

},
});
};
instance = new Proxy(instance, handler);
}
if(service.singleton) {

@@ -175,2 +185,10 @@ service.instance = instance;

/**
* Resolve Callback
*
* Resolves callback dependencies and passes them as arguments to given callback
*
* @returns {*}
* @param target callback
*/
let resolve = function(target) {

@@ -193,2 +211,14 @@ if(!target) {

/**
* Get Path
*
* Return value from a service by a given path, nesting is supported by using the '.' delimiter.
* When passing a value parameter the given path will be set with the new value. Use 'as' and 'prefix' parameters to define the service namespace.
*
* @returns {*}
* @param path string
* @param value mixed
* @param as string
* @param prefix string
*/
let path = function(path, value, as, prefix) {

@@ -199,10 +229,12 @@ as = (as) ? as : container.get('$as');

path = path
.replace(as, prefix)
.replace(as + '.', prefix + '.')
.split('.');
let object = this.get(path.shift());
let name = path.shift();
let object = this.get(name);
let result = null;
// Iterating path
while (path.length > 1) {
if(undefined == object) {
if(undefined === object) {
return null;

@@ -215,8 +247,9 @@ }

// Set new value
if(undefined != value) {
return object[path.shift()] = value;
if(undefined !== value) {
object[path.shift()] = value;
return true;
}
// Return null when missing path
if(undefined == object) {
if(undefined === object) {
return null;

@@ -227,9 +260,46 @@ }

if(undefined == shift) {
return object;
if(undefined === shift) {
result = object;
}
else {
return object[shift];
}
return object[shift];
return result;
};
/**
* Bind
*
* Binds an element to a path change. Every time a new value is set to given path the callback you passes to the function will be executed.
* Use 'as' and 'prefix' parameters to define the service namespace.
*
* @returns {*}
* @param element
* @param path string
* @param callback callback
* @param as string
* @param prefix string
*/
let bind = function(element, path, callback, as, prefix) {
as = (as) ? as : container.get('$as');
prefix = (prefix) ? prefix : container.get('$prefix');
let event = path.replace(as + '.', prefix + '.') + '.changed';
let printer = function () {
if(!document.body.contains(element)) { // Clean DOM
element = null;
document.removeEventListener(event, printer, false);
return false;
}
//console.log('registered', event, element);
callback();
};
document.addEventListener(event, printer);
};
let container = {

@@ -240,21 +310,3 @@ set: set,

path: path,
bind: function(element, path, callback, as, prefix) {
as = (as) ? as : container.get('$as');
prefix = (prefix) ? prefix : container.get('$prefix');
let event = path.replace(as, prefix) + '.changed';
let printer = function () {
if(!document.body.contains(element)) { // Clean DOM
console.log('cleaned dom');
element = null;
document.removeEventListener(event, printer, false);
return false;
}
callback();
};
document.addEventListener(event, printer);
},
bind: bind,
setCachePrefix: setCachePrefix,

@@ -264,5 +316,5 @@ getCachePrefix: getCachePrefix

set('container', container, true);
set('container', container, true, false, false);
return container;
}();

@@ -1,2 +0,2 @@

container.set('cookie', function(document) {
window.ls.container.set('cookie', function(document) {

@@ -30,2 +30,2 @@ function get(name) {

}
}, true);
}, true, false, false);

@@ -110,2 +110,2 @@ container.set('form', function() {

}
}, true);
}, true, false, false);

@@ -1,7 +0,2 @@

/**
* View
*
* Manage application scopes and different views
*/
container.set('expression', function(container, filter, $as, $prefix) {
window.ls.container.set('expression', function(container, filter, $as, $prefix) {
let reg = /(\{{.*?\}})/gi;

@@ -15,2 +10,4 @@ let paths = [];

* @param def string
* @param as
* @param prefix
* @returns {string}

@@ -45,3 +42,3 @@ */

for(let i=1;i<reference.length;i++) {
result = filter.apply(result, reference[i], {});
result = filter.apply(reference[i], result);
}

@@ -58,2 +55,2 @@ }

}
}, true);
}, true, false, false);

@@ -1,7 +0,2 @@

/**
* View
*
* Manage application scopes and different views
*/
container.set('filter', function(container) {
window.ls.container.set('filter', function(container) {
let filters = {};

@@ -14,13 +9,13 @@

let apply = function (value, name) {
container.set('$value', value, true);
let apply = function (name, value) {
container.set('$value', value, true, false, false);
return container.resolve(filters[name]);
};
add('uppercase', function (value) {
return value.toUpperCase();
add('uppercase', function ($value) {
return $value.toUpperCase();
});
add('lowercase', function (value) {
return value.toLowerCase();
add('lowercase', function ($value) {
return $value.toLowerCase();
});

@@ -32,2 +27,2 @@

}
}, true);
}, true, false, false);

@@ -1,2 +0,2 @@

container.set('http', function(document) {
window.ls.container.set('http', function(document) {

@@ -113,2 +113,2 @@ let globalParams = [],

}
}, true);
}, true, false, false);

@@ -6,7 +6,7 @@ /**

*/
container.set('view', function(http, container) {
window.ls.container.set('view', function(http, container) {
let stock = {};
let execute = function(view, node, container) {
container.set('element', node, true);
container.set('element', node, true, false, false);

@@ -21,2 +21,3 @@ container.resolve(view.controller);

let parse = function (node, skip) {
if(node.attributes && skip !== true) {

@@ -30,8 +31,10 @@ let attrs = [];

if(1 !== node.nodeType) { // Skip text nodes
return;
}
//console.log('in DOM?', document.body.contains(node), node, node.nodeType);
if(attrs && attrsLen) { // Loop threw child attributes
if(1 !== node.nodeType) { // Skip text nodes
return;
}
for (let x = 0; x < attrsLen; x++) {

@@ -178,2 +181,2 @@

}
}, true);
}, true, false, false);

@@ -1,4 +0,4 @@

container.get('view').add({
window.ls.container.get('view').add({
selector: 'data-ls-attrs',
controller: function(element, expression, $as, $prefix) {
controller: function(element, expression, container, $as, $prefix) {
let attrs = element.getAttribute('data-ls-attrs').trim().split(',');

@@ -5,0 +5,0 @@ let paths = [];

@@ -1,5 +0,5 @@

container.get('view').add({
window.ls.container.get('view').add({
selector: 'data-ls-bind',
controller: function(element, expression, container, $prefix, $as) {
let echo = function(value, bind = true) {
let echo = function(value, bind = true) {
if(

@@ -23,12 +23,12 @@ element.tagName === 'INPUT' ||

if('checkbox' === type) {
value = JSON.parse(value);
//value = JSON.parse(value);
if(typeof value === 'boolean') {
if(value === true) {
if(typeof value === 'boolean' || value === 'true' || value === 'false') {
if(value === true || value === 'true') {
element.setAttribute('checked', 'checked');
element.value = true;
element.checked = true;
}
else {
element.removeAttribute('checked');
element.value = false;
element.checked = false;
}

@@ -72,6 +72,8 @@

let syntax = element.getAttribute('data-ls-bind');
let result = expression.parse(syntax, null, $as, $prefix);
let paths = expression.getPaths();
let syntax = element.getAttribute('data-ls-bind');
let result = expression.parse(syntax, null, $as, $prefix);
let paths = expression.getPaths();
echo(result, true);
for(let i = 0; i < paths.length; i++) {

@@ -82,5 +84,3 @@ container.bind(element, paths[i], function () {

}
echo(result, true);
}
});
});

@@ -14,3 +14,3 @@ container.get('view').add({

if(filterName) {
result = filter.apply(result, filterName, filterOptions);
result = filter.apply(filterName, result);
}

@@ -17,0 +17,0 @@

@@ -16,3 +16,3 @@ container.get('view').add({

if(filterName) {
result = filter.apply(result, filterName, filterOptions);
result = filter.apply(filterName, result);
}

@@ -19,0 +19,0 @@

@@ -1,4 +0,4 @@

container.get('view').add({
window.ls.container.get('view').add({
selector: 'data-ls-if',
controller: function(element, expression, $as, $prefix) {
controller: function(element, expression, container, $as, $prefix) {
let result = '';

@@ -5,0 +5,0 @@ let syntax = element.getAttribute('data-ls-if') || '';

@@ -1,2 +0,2 @@

container.get('view').add({
window.ls.container.get('view').add({
selector: 'data-ls-loop',

@@ -8,2 +8,3 @@ template: false,

let expr = element.getAttribute('data-ls-loop');
let as = element.getAttribute('data-ls-as');
let echo = function() {

@@ -36,3 +37,3 @@ let array = container.path(expr);

// Create new child element and apply template
children[prop] = children[prop] || element.backup.cloneNode(true);
children[prop] = template.cloneNode(true);

@@ -44,6 +45,6 @@ element.appendChild(children[prop]);

container.set(element.getAttribute('data-ls-as'), container.path(context), true);
container.set('$index', index, true);
container.set('$prefix', context, true);
container.set('$as', element.getAttribute('data-ls-as'), true);
container.set(as, container.path(context), true);
container.set('$index', index, true, false, false);
container.set('$prefix', context, true, false, false);
container.set('$as', as, true, false, false);

@@ -54,13 +55,9 @@ view.render(children[prop]);

container.set('$index', null, true);
container.set('$prefix', '', true);
container.set('$as', '', true);
container.set('$index', null, true, false, false);
container.set('$prefix', '', true, false, false);
container.set('$as', '', true, false, false);
};
element.template = (element.template) ? element.template : (element.children.length === 1) ? element.children[0].innerHTML : ''; // Save template for case we will need to re-render
let template = (element.children.length === 1) ? element.children[0] : window.document.createElement('li');
if(!element.backup) {
element.backup = (element.children.length === 1) ? element.children[0] : window.document.createElement('li');
}
echo();

@@ -70,6 +67,3 @@

container.bind(element, expr + '.length', echo);
//document.addEventListener(expr + '.changed', echo);
//document.addEventListener(expr + '.length.changed', echo);
}
});

@@ -1,2 +0,2 @@

container.get('view').add({
window.ls.container.get('view').add({
selector: 'data-ls-template',

@@ -3,0 +3,0 @@ template: false,

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc