1 line
18 KiB
JavaScript
1 line
18 KiB
JavaScript
class VUtils{static makePublic(){VUtils.isUsed||(this.initHandlers(),VUtils.isUsed=!0,console.log("[VUtils] is now available in the Global Space! no VUtils. anymore needed"))}static initHandlers(){window.$=this.$,window.$$=this.$$,window.tryCatch=this.tryCatch,VUtils.nodePrototypes()}static $(e,t){return(t=t||document).querySelector(e)}static $$(e,t){return(t=t||document).querySelectorAll(e)}static tryCatch(e,t,i){e=VUtils.wrap(e,[]),i=i||console.error,t=t||console.log;try{t(...e)}catch(e){i(e)}}static forEach(e,t,i){for(let s=0;s<e.length;s++)VUtils.tryCatch([e[s],s],t,i)}static get(e,t){return this.wrap(e,t)}static mergeKeys(e,t){e=e||{};let i=Object.keys(e);for(let s of i)t[s]=e[s];return t}static mergeOptions(e,t){t=t||{};let i=Object.keys(t);for(let s of i)e[s]=VUtils.get(t[s],e[s]);return e}static wrap(e,t){return!(e instanceof Array)&&t instanceof Array?[e]:"string"===typeof t&&e instanceof Array?e.join("."):void 0===e?t:e}static tempId(){return"temp_"+Math.random().toString(36).substr(2,16)}static nodePrototypes(){Node.prototype.find=function(e){return this.closest(e)},Node.prototype.createNew=function(e,t){let i=document.createElement(e);return t.classes&&i.classList.add(...VUtils.get(t.classes,[])),i.id=VUtils.get(t.id,""),i.innerHTML=VUtils.get(t.content,""),VUtils.mergeKeys(t.dataset,i.dataset),!0===VUtils.get(t.append,!0)&&this.appendChild(i),i},Node.prototype.addDelegatedEventListener=function(e,t,i,s){i&&e&&t&&this.addMultiListener(e,e=>{let n=e.target;if(e.detail instanceof HTMLElement&&(n=e.detail),n instanceof HTMLElement)if(n.matches(t))VUtils.tryCatch([e,n],i,s);else{const r=n.find(t);r&&VUtils.tryCatch([e,r],i,s)}})},Node.prototype.addMultiListener=function(e,t,i={}){let s=e.split(" ");for(let e of s)this.addEventListener(e,t,i)}}}VUtils.makePublic();class VRipple{constructor(e={}){if(!VUtils.isUsed)throw"VRipply is only with Public VUtils usable!";let t=this;if(t.options=JSON.parse('{"classes":["btn-ripple__effect"],"target":"body","selector":".btn-ripple"}'),VUtils.mergeOptions(t.options,e),t.options.selector.indexOf("#")>-1)throw"ID's are not allowed as selector!";this.instanceCheck(),this.ripples=[],requestAnimationFrame(this.initHandler.bind(this))}instanceCheck(){let e=this.options;const t=[e.target,e.selector,e.classes.join(".")].join(" ");VRipple.instances=VRipple.instances||{},VRipple.instances[t]=this}initHandler(){let e=this,t=e.options.selector;$(e.options.target).addDelegatedEventListener("mousedown touchstart",t,(t,i)=>{let s=t.touches?t.touches[0]:t,n=i.parentNode,r=i.createNew("span",e.options),a=n.getBoundingClientRect(),o=s.clientX-a.left,l=s.clientY-a.top;r.style.top=l+"px",r.style.left=o+"px",r._mouseDown=!0,r._animationEnded=!1,e.ripples.push(r)}),document.body.addDelegatedEventListener("animationend","."+VUtils.get(e.options.classes,""),e.rippleEnd.bind(e)),document.body._vRippleInit||(document.body.addMultiListener("mouseup touchend mouseleave rippleClose",t=>{let i=Object.keys(VRipple.instances);for(let s of i)for(let i of VRipple.instances[s].ripples)e.rippleEnd.bind(VRipple.instances[s])(t,i)}),document.body._vRippleInit=!0)}rippleEnd(e,t){t.parentNode&&("animationend"===e.type?t._animationEnded=!0:t._mouseDown=!1,!t._mouseDown&&t._animationEnded&&(t.classList.contains("to-remove")?(t.parentNode.removeChild(t),this.ripples.splice(this.ripples.indexOf(t),1)):t.classList.add("to-remove")))}}const rippler=new VRipple;!function(){window._openVSelect=null,requestAnimationFrame(e=>{document.body.addEventListener("click",e=>{window._openVSelect&&e.target.closest("v-select")!==window._openVSelect&&window._openVSelect.toggle(!1)})});class e extends HTMLElement{constructor(){super();let e=this;e._in=this.attachInternals(),e._in.role="select",e.setAttribute("tabindex",0),e.update()}static get formAssociated(){return!0}static get observedAttributes(){return["required","validity"]}get required(){return this.hasAttribute("required")}set required(e){this.toggleAttribute("required",Boolean(e))}get name(){return this.getAttribute("name")}set name(e){this.toggleAttribute("name",e)}get form(){return this._in.form}get options(){return $$("v-options v-option",this)}get selected(){return $$("v-options v-option[selected]",this)}update(){let e=[],t=$("v-label",this),i=new FormData;this.selected.forEach(t=>{e.push(t.innerText),i.append(this.name,t.value)}),t.attributeChangedCallback("value","",e.join(", ")),this.required&&0===e.length?this._in.setValidity({customError:!0},"Option is needed"):this._in.setValidity({}),this._in.setFormValue(i)}checkValidity(){return this._in.checkValidity()}reportValidity(){return this._in.reportValidity()}toggle(e){window._openVSelect&&e&&window._openVSelect.toggleSelect(!1);const t=$("v-options",this);if(!e||this.isOpen)t.style.maxHeight="0",window._openVSelect=!1,this.isOpen=!1,this.update();else{t.focus();let e=0,i=t.children;for(let t=0;t<i.length;t++)e+=i[t].offsetHeight;t.style.maxHeight=e+"px",window._openVSelect=this,this.isOpen=!0}let i=$("v-label",this).classList;this.isOpen?i.add("open"):i.remove("open")}}class t extends HTMLElement{constructor(){super(),this._in=this.attachInternals(),this._in.role="option",this.addEventListener("click",e=>{let t=this.parentNode.parentNode,i=!this.selected;if(!t.hasAttribute("multiple")){t.toggle(!1);for(let e of t.selected)e!==this&&e.removeAttribute("selected")}this.disabled||(this.attributeChangedCallback("selected",!1,i,!0),this.parentNode.parentNode.update())})}static get observedAttributes(){return["selected","disabled","value"]}attributeChangedCallback(e,t,i,s){"selected"===e&&this.hasAttribute("disabled")?this.removeAttribute(e):("disabled"===e&&!0===i&&this.hasAttribute("selected")&&this.attributeChangedCallback("selected",!1,!1),s&&(i?this.setAttribute(e,i):this.removeAttribute(e)),this[e]=i)}}class i extends HTMLElement{constructor(){super(),this.empty=this.getAttribute("empty")||"",this.innerHTML=this.getAttribute("value")||this.empty,this.addEventListener("click",this.openPopUp.bind(this))}static get observedAttributes(){return["empty","value"]}openPopUp(){this.parentNode.toggle(!0)}attributeChangedCallback(e,t,i){"value"===e&&(this.innerHTML=i||this.empty),this[e]=i}}customElements.define("v-label",i),customElements.define("v-option",t),customElements.define("v-select",e)}();class FormHandler{constructor(e,t,i,s){this.cb=i||console.log,this.err=s||console.err,$(t).addDelegatedEventListener("submit",e,this.handleEvent.bind(this))}handleEvent(e,t){if(e.preventDefault(),t.checkValidity()){if(""===(t.action??""))return void console.error("No URL Found on Form",t);fetch(t.action,{method:t.method.toUpperCase(),credentials:"same-origin",body:new FormData(t),redirect:"manual"}).then(e=>{if(!e.ok)throw new Error("Network response errored");return e.json()}).then(e=>this.cb(e,t)).catch(e=>this.err(e,t))}else VUtils.forEach($$("input",t),e=>{if(!e.checkValidity()){let t=e.parentNode;t.classList.remove("valid"),t.classList.add("invalid")}})}}!function(){class e extends HTMLElement{constructor(){super();let e=this;e.id=e.id||VUtils.tempId();let t=e.innerHTML;e.innerHTML="";let i=e.input=e.createNew("input",{id:e.id}),s=e.createNew("label",{content:e.dataset.label});e.createNew("span",{classes:"error",content:e.dataset.error}),s.setAttribute("for",e.id),i.type=e.getAttribute("type")||"text",i.value=t.trim(),i.required=e.hasAttribute("required"),i.name=e.getAttribute("name"),i.addMultiListener("change input",e.cb.bind(e))}connectedCallback(){this.cb({currentTarget:this.input},!0)}cb(e,t){let i=e.currentTarget,s=$(".error-message",i.find("form"));s&&s.classList.add("hide");let n=this.classList;""===i.value?n.remove("focus"):n.add("focus"),i.checkValidity()?(n.add("valid"),n.remove("invalid")):t||(n.remove("valid"),n.add("invalid"))}}class t extends HTMLElement{constructor(){super();const e=this.dataset.id||VUtils.tempId();$("input",this).id=e,$("label",this).setAttribute("for",e)}}customElements.define("v-input",e),customElements.define("v-switch",t),$("#login")&&new FormHandler("form#login","body",()=>{location.reload()},(e,t)=>{$(".error-message",t).classList.remove("hide")})}(),(()=>{class e{constructor(e){let t=this;t.editor=e instanceof HTMLElement?e:$(e),t.todoOnKey={},t.keys=[],t.backup=[],t.taberr=[">"," ","\n","<"],t.name="veditor-"+t.editor.id,t.init(),t.selfClosing=["img","area","base","br","col","embed","hr","img","input","link","menuitem","meta","param","source","track"],t.restore()}init(){let e=this;e.editor.addEventListener("keydown",e.handleKey.bind(e)),e.addKey("Tab",e.pressTab.bind(e)),e.addKey("<",e.addEmptyTags.bind(e)),e.addKey("ctrl-z",e.undo.bind(e)),e.addKey("ctrl-s",e.store.bind(e)),e.addKey("ctrl-shift-S",e.delete.bind(e)),e.editor.classList.add(e.name,"veditor")}registerSelfClosing(e){this.selfClosing.push(e)}restore(){let e=localStorage.getItem(this.name);e&&(this.editor.value=e)}delete(){localStorage.removeItem(this.name),console.log(`[VEdit] Editor: ${this.name} removed`)}store(){localStorage.setItem(this.name,this.editor.value),console.log(`[VEdit] Editor: ${this.name} saved`)}handleKey(e){let t,i=this;if(e.ctrlKey&&"Control"===e.key||e.shiftKey&&"Shift"===e.key)return;if(e.ctrlKey&&e.shiftKey?t="ctrl-shift-"+e.key:e.ctrlKey&&(t="ctrl-"+e.key),t&&-1!==this.keys.indexOf(t))return e.preventDefault(),void this.todoOnKey[t]();let s=i.editor.value;const n=i.editor.selectionStart;if(i.backup.length>50&&i.backup.shift(),i.backup.push([s,n]),i.keys.indexOf(e.key)>-1){e.preventDefault();let t=i.todoOnKey[e.key](n,s,this.editor);t[0].push(s.substr(n)),i.afterWork(t)}}undo(){let e=this.backup.pop()||[this.editor.value,this.editor.selectionStart];this.editor.value=e[0],this.editor.setSelectionRange(e[1],e[1])}afterWork(e){this.setText(e[0].join("")),this.editor.setSelectionRange(e[1],e[1])}setText(e){this.editor.value=e}addKey(e,t){this.todoOnKey[e]=t,this.keys.push(e)}addEmptyTags(e,t,i){return[[t.substr(0,e),"<>"],e+1]}pressTab(e,t,i){let s,n,r=this,a=e;if(0===e||-1!==r.taberr.indexOf(t[e-1]))s=" ",a+=4,n=t.substr(0,e);else if(-1===r.taberr.indexOf(t[e-1])){let i=2;for(;-1===r.taberr.indexOf(t[e-i])&&e-i>0;)i++;e-i>0&&(i-=1);let o=r.generateTag(t.substr(e-i,i).trim());s=o[0],a=e-i+o[1],n=t.substr(0,e-i)}return[[n,s],a]}generateTag(e){let t,i={".":[],"#":[]},s=Object.keys(i),n="cl",r=e.split(/([#.])/g);t=r.shift();for(let e of r)s.indexOf(e)>-1?n=e:i[n].push(e);let a="";i["."].length>0&&(a+=` class="${i["."].join(" ")}"`),i["#"].length>0&&(a+=` id="${i["#"].join("-")}"`);let o="";-1===this.selfClosing.indexOf(t.trim())&&(o=`</${t}>`);let l=`<${t}${a}>`;return[`${l}${o}`,l.length]}}class t extends HTMLElement{constructor(){super(),this.editor=document.createElement("textarea"),this.editor.innerHTML=this.innerHTML,this.editor.id=this.getAttribute("name");for(let e of this.attributes)this.editor.setAttribute(e.name,e.value);this.innerHTML="",this.appendChild(this.editor),this.edit=new e(this.editor)}connectedCallback(){this.edit.restore()}disconnectedCallback(){this.edit.save()}}customElements.define("v-editor",t)})(),(()=>{const e=$("main");function t(){return window.matchMedia("(max-width: 1023px)").matches}window.isMobileDevice=t,$("body").addDelegatedEventListener("click",".nav-toggle",(i,s)=>{t()&&e.classList.toggle("nav-open")})})(),window.router=new class{constructor(e){this.options=e,document.body.addDelegatedEventListener("click","[data-link]",(e,t)=>{e.preventDefault(),$$("[data-link].active").forEach(e=>e.classList.remove("active"));let i=$(".loader").classList;i.remove("hide"),this.handleRouting(t.dataset).then(e=>{i.add("hide"),t.classList.add("active")})}),document.body.addEventListener("triggerRouter",e=>{let t=sessionStorage.getItem("url")||JSON.stringify({data:{link:$("[data-link].active").dataset.link}});this.handle(t)}),window.addEventListener("popstate",e=>{this.handle(e.state)}),this.components={},window.dispatchEvent(new CustomEvent("routerReady")),window.routerIsReady=!0}handle(e){e&&(e=JSON.parse(e),this.handleRouting(e.data).then(t=>{let i=$('[data-link="'+e.data.link+'"]');i&&i.classList.add("active")}))}async handleRouting(e){try{let t=e.link,i=this.components[t];if(""===t)return null;i&&(t=i.getUrl(e));let s=await this.handleRequest(t,!0);return s.reload?location.reload():(i=i||this.components[s.component]||null,i?(sessionStorage.setItem("url",JSON.stringify({data:e})),i.handle(s,e).then(t=>{$(this.options.toReplace).innerHTML=t,history.pushState(JSON.stringify({data:e}),document.title)})):await alert("Error"),null)}catch(e){return e}}async handleRequest(e,t){if(""!==(e=e.trim()))return await fetch(e,{credentials:"same-origin"}).then(e=>{if(!e.ok)throw"URL is Status: "+e.status;let i=e.headers.get("Content-Type");return-1!==i.indexOf("json")||t?e.json():-1!==i.indexOf("text")?e.text():e.blob()}).catch(e=>(console.error(e),null))}addComponent(e,t){this.components[e]=t}}({toReplace:".content-area"});class VTpeLCore{constructor(e={}){this.templates={},this.dir=e.path||"/tpl/",this.suffix=e.suffix||"tpl",this.path=e.template||`${this.dir}%s.${this.suffix}`,this.cache=void 0===e.cache||e.cache}async loadTemplate(e){if(this.templates[e])return null;let t=this.path.replace("%s",e),i=await fetch(t,{cache:"force-cache"});if(i.ok){let t=await i.text();this.addTpl(e,t)}return null}async loadArray(e){for(let t of e)await this.loadTemplate(t)}addTpl(e,t){(this.templates[e]=new VTpeLTemplate(e,t,this)).parseContent(this.cache)}async renderOn(e,t){return this.templates[e]?await this.templates[e].render(t):""}}const VParserTypes={content:0,variable:1,for:2,forEach:3,forContent:4,forEnd:5,if:6,ifContent:7,ifEnd:8,assign:9,include:10,none:-1};class VTpeLParser{constructor(e,t){let i=this;i.name=e,i.legex=t.trim(),i.index=0,i.content="",i.parsed=[],i.contexts=[0]}tokenize(){let e=this;for(e.index=0;e.index<e.legex.length;e.index++){let t=e.index,i=e.legex.charAt(t);e.nextContains("/*",t,!0)?e.extract("*/",VParserTypes.none):e.nextContains("// ",t,!0)?e.extract("\n",VParserTypes.none):e.nextContains("\x3c!--",t,!0)?e.extract("--\x3e",VParserTypes.none):e.nextContains("{for(",t,!0)?(e.extract(")}",VParserTypes.for),e.contexts.push(VParserTypes.for)):e.nextContains("{include(",t,!0)?(e.extract(")}",VParserTypes.include),e.contexts.push(VParserTypes.include)):e.nextContains("{foreach(",t,!0)?(e.extract(")}",VParserTypes.forEach),e.contexts.push(VParserTypes.forEach)):e.nextContains("{/for}",t,!0)?(e.addType(VParserTypes.forEnd),e.contexts.pop()):e.nextContains("{if(",t,!0)?(e.extract(")}",VParserTypes.if),e.contexts.push(VParserTypes.if)):e.nextContains("{/if}",t,!0)?(e.addType(VParserTypes.ifEnd),e.contexts.pop()):e.nextContains("$${",t,!0)?e.extract("}",VParserTypes.assign):e.nextContains("${",t,!0)?e.extract("}",VParserTypes.variable):e.content+=i}return e.addType(VParserTypes.content),e.parsed}addType(e){let t=this,i=t.content.replace(/^\n+|\n+$/g,""),s=t.findInstructions(e);return t.content="",e!==VParserTypes.none?e===VParserTypes.content&&""===i?null:t.parsed.push({content:i,type:e,context:t.contexts[t.contexts.length-1],instructions:s}):null}nextContains(e,t,i=!1){let s=this.nextContainsRaw(this.legex,e,t);return i&&s>0&&(this.index+=s),s>0||-1===s}nextContainsRaw(e,t,i){"string"==typeof t&&(t=t.split(""));let s=t.length;if(s<1)return-1;for(let n=0;n<s;n++){let r=e.charAt(i+n);if("\n"===t[n]&&void 0===r)return s;if(t[n]!==r)return 0}return s}extract(e="}",t=1){let i=this;i.addType(0),e=e.split("");let s="",n=i.index,r=i.legex,a=e.shift();for(let o=i.index;o<r.length;o++){let l=r.charAt(o);if(l===a&&i.nextContains(e,o+1))return console.debug(`[Parser][${n} > ${o}] >> ${s}`),i.index=o+e.length,i.content=s.trim(),void i.addType(t);s+=l}if("\n"===a)return i.index=r.length,i.content=s.trim(),void i.addType(t);throw"Template variable at Position: "+n+" not closed!"}getOperator(e){let t=[];for(let i=0;i<e.length;i++)if(this.nextContainsRaw(e,"(",i)){let s="";for(let t=0;t<e.length;t++){let n=e.charAt(i+t);if(")"===n)break;s+=n}t=[...t,this.getOperator(s)]}return t}findInstructions(e){return e===VParserTypes.if?this.getOperator(this.content):[]}}class VTepLInterpreter{constructor(e,t){this.parser=e,this.data=[],this.content="",this.core=t}async render(e){let t=this;t.data=e;let i=await t.interpreter(t.parser.parsed);return t.data=[],i[0]}async interpreter(e,t=0){let i=this,s=VParserTypes,n="";for(let r=t;r<e.length;r++){let t=e[r],a=t.content;switch(t.type){case s.content:n+=a;break;case s.variable:n+=i.getVariable(a);break;case s.assign:let o=a.split("="),l=o.shift();i.setVariable(o.join("=").trim(),l.trim());break;case s.forEach:let d=await this.handleForEach(t,e,r);r=d[0],n+=d[1];break;case s.for:let c=await this.handleFor(t,e,r);r=c[0],n+=c[1];break;case s.if:let h=await this.handleIf(t,e,r);r=h[0],n+=h[1];break;case s.include:n+=await this.handleInclude(t);break;case s.ifEnd:case s.forEnd:return n+=a,[n,r];default:console.warn("Invalid Type found")}}return[n,e.length]}getVariable(e){if(e=e.toString(),this.data[e])return this.data[e];let t=e.split("."),i=this.data;for(let e=0;e<t.length;e++)i=i[t[e]]||i;return"string"==typeof i?i:"number"==typeof i?i.toString():""}setVariable(e,t){let i=this.getVariable(e);""!==i&&(e=i),this.data[t]=e}async handleForEach(e,t,i){let s=e.content.split(" as "),n=this.getVariable(s[0].trim()),r=0,a=!1;""===n&&(a=!0,n={invalid:"true"});let o=Object.keys(n),l="",d=s[1].trim().split(",");for(let e of o){2===d.length&&this.setVariable(e,d[1]),this.setVariable(n[e],d[0]);let s=await this.interpreter(t,i+1);r=s[1],l+=s[0]}return a&&(l=""),[r,l]}async handleInclude(e){let t=e.content.split(";"),i=t.shift(),s={};await this.core.loadTemplate(i);for(let e of t){let t=e.split("="),i=t.shift(),n=t.join("=");n.startsWith("$")&&(n=this.getVariable(n.substr(1,n.length))),s[i]=n}return await this.core.renderOn(i,s)}async handleFor(e,t,i){let s=e.content.split(" as "),n=0,r=s[0].trim().split(".."),a=parseInt(r[1]),o="";for(let e=parseInt(r[0]);e<a;e++){this.setVariable(e.toString(),s[1]);let r=await this.interpreter(t,i+1);n=r[1],o+=r[0]}return[n,o]}async handleIf(e,t,i){let s=await this.interpreter(t,i+1);return[s[1],s[0]]}}class VTpeLTemplate{constructor(e,t,i){this.name=e,this.tpl=t,this.parser=new VTpeLParser(e,t),this.core=i}async render(e={}){return await new VTepLInterpreter(this.parser,this.core).render(e)}parseContent(e){if(e){let e=localStorage.getItem("vtepl-"+this.name);if(e)return void(this.parser.parsed=JSON.parse(e))}this.parser.tokenize(),e&&localStorage.setItem("vtepl-"+this.name,JSON.stringify(this.parser.parsed))}}window.tpl=new VTpeLCore({template:"/admin/api/templateLoader?tpl=%s",cache:!document.body.hasAttribute("debug")}),window.tpl.loadArray(["includes/btn","includes/input","includes/select","includes/svg","includes/switch"]); |