diff --git a/dist/js/ext/websocket.min.js.gz b/dist/js/ext/websocket.min.js.gz index fdeb063..b3d6914 100644 Binary files a/dist/js/ext/websocket.min.js.gz and b/dist/js/ext/websocket.min.js.gz differ diff --git a/dist/js/secutio.js b/dist/js/secutio.js index d0bff64..fb5bec1 100644 --- a/dist/js/secutio.js +++ b/dist/js/secutio.js @@ -1,7 +1,7 @@ /* secutio.js Author: Henrique Dias - Last Modification: 2024-03-25 19:10:51 + Last Modification: 2024-04-01 18:20:24 Attention: This is work in progress References: @@ -769,7 +769,7 @@ if (!this.callbacks.hasOwnProperty(properties.callback)) { throw new Error(`The registered callback "${properties.callback}" not exist!`); } - const result = this.callbacks[properties.callback](event, properties); + const result = this.callbacks[properties.callback](event); if (result === false) { if (properties.hasOwnProperty('next')) { delete properties.next; diff --git a/dist/js/secutio.min.js b/dist/js/secutio.min.js index b39aa50..359b46a 100644 --- a/dist/js/secutio.min.js +++ b/dist/js/secutio.min.js @@ -1,2 +1,2 @@ (function(t,e){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=e()}else if(typeof define==="function"&&define.amd){define(e)}else{t.Secutio=e()}})(this,function(){"use strict";class t{constructor(t={tasks_attribute:"data-tasks",start_element:"body"}){this.triggers=new Set(["change","click","focus","init","input","keydown","mouseenter","mouseover","mouseup","mouseleave","mousemove","reset","scroll","scrollend","submit"]);this.methods=new Set(["get","post","put","patch","delete"]);this.tasksAttribute=t["tasks_attribute"];this.startElement=t["start_element"];this.tasks={};this.callbacks={};this.extensions={}}fetchOptions(t,e){let r={method:t.method,cache:"no-cache",signal:AbortSignal.timeout(1e3*(t.hasOwnProperty("timeout")?parseInt(t.timeout,10):300))};if(t.method==="post"&&Object.prototype.toString.call(e)==="[object FormData]"){r["body"]=e;return r}if(["post","put","patch"].includes(t.method)){r["headers"]={"Content-Type":"application/json"};r["body"]=JSON.stringify(e);return r}return r}async makeRequest(e,r){try{const s=await fetch(e.action,this.fetchOptions(e,r));let t={transformation:{},data:undefined,ok:s.ok,status:s.status};if(s.headers.has("Secutio-Transformation")){console.log("Secutio-Transformation:",s.headers.get("Secutio-Transformation"));const n=s.headers.get("Secutio-Transformation");if(n!==""){t.transformation=this.attrsStr2Obj(n)}}if(s.headers.has("Content-Type")){if(s.headers.get("Content-Type").includes("application/json")){const o=await s.json();t.data=o;return t}}const a=await s.text();t.data=a;return t}catch(t){return{transformation:{},data:undefined,ok:false,status:0}}}attrsStr2Obj(t){if(t===""){return{}}const e=t.replace(/[\r\n] */gm,"").replace(/\;$/,"").split(/\; */);let r={};for(const s of e){const a=s.split(/\: */);if(a.length!=2){throw new Error(`Wrong data atribute: ${s}`)}r[a[0]]=a[1]}return r}async getResource(t){if(t.length<=".json".length||!t.endsWith(".json")){throw new Error(`The ${t} file is not a valid JSON file!`)}const e=await fetch(t,{cache:"no-cache"});if(!e.ok){throw new Error(`When fetching the file ${t} \ - happen an HTTP error! status: ${e.status} ${e.statusText}`)}return await e.json()}swapContent(t,e,r){if(e===null){console.warn("no target to swap");return}if(t===null){if(r==="delete"){e.remove();return}if(r==="clean"){while(e.firstChild){e.removeChild(e.firstChild)}return}if(r==="none"){return}return}if(r==="inner"){e.replaceChildren(...t.childNodes);return}if(r==="outer"){e.replaceWith(...t.childNodes);return}if(r==="before"){e.before(...t.childNodes);return}if(r==="after"){e.after(...t.childNodes);return}if(r==="prepend"){e.prepend(...t.childNodes);return}if(r==="append"){e.append(...t.childNodes);return}throw new Error(`swap "${r}" attribute not supported`)}async runNextTask(t,e){const r=e.split(/ +/);for(const s of r){if(!this.tasks.hasOwnProperty(s)){throw new Error(`The next task "${s}" not exist in tasks file!`)}const a=this.tasks[s];if(!a.hasOwnProperty("disabled")){a["disabled"]=false}if(a.hasOwnProperty("trigger")){throw new Error(`The trigger property from "${s}" is not allowed in next task!`)}if(a.disabled===false){if(!a.hasOwnProperty("wait")){a.wait=0}setTimeout(async()=>{await this.findResourcePath(t,a);if(a.hasOwnProperty("next")){await this.runNextTask(t,a.next)}},a.wait)}}}runSubtasks(t,e){const r=e.split(/ +/);for(const s of r){if(!this.tasks.hasOwnProperty(s)){throw new Error(`The subtask "${s}" not exist in tasks file!`)}const a=this.tasks[s];if(!a.hasOwnProperty("selector")){a["traverse"]="target"}for(const o in a){if(!["traverse","selector","remove","add"].includes(o)){throw new Error(`The property "${o}" in subtask "${s}" is not allowed with property "selector"!`)}}if(Object.prototype.toString.call(a)!=="[object Object]"){throw new Error(`The properties of subtask "${s}" is not a object!`)}const n=(()=>{if(a.hasOwnProperty("traverse")){if(a.traverse==="target"){return[t]}if(a.traverse==="closest"&&a["selector"]!==""){return t.closest(a["selector"])}}if(a["selector"]!==""){return document.querySelectorAll(a["selector"])}throw new Error(`The properties of subtask "${s}" has a empty selector!`)})();if(a.hasOwnProperty("remove")&&Object.keys(a["remove"]).length===0){for(const i of n){i.remove()}continue}for(const i of n){if(a.hasOwnProperty("remove")){if(a["remove"].hasOwnProperty("attributes")){if(!Array.isArray(a["remove"]["attributes"])){throw new Error(`The property "remove/attributes" of subtask "${s}" is not an array!`)}for(const c of a["remove"]["attributes"]){if(i.hasAttribute(c)){i.removeAttribute(c);if(c==="class"||c==="style"){return true}}}}if(i.hasAttribute("class")&&a["remove"].hasOwnProperty("class")){const l=a["remove"]["class"].split(/ +/);for(const h of l){if(i.classList.contains(h)){i.classList.remove(h)}}if(i.getAttribute("class")===""){i.removeAttribute("class")}}if(i.hasAttribute("style")&&a["remove"].hasOwnProperty("style")){let t=i.style;const f=a["remove"]["style"].split(/ +/);for(const u of f){if(i.style.hasOwnProperty(u)){delete t[u]}}i.style=t;if(i.getAttribute("style")===""){i.removeAttribute("style")}}}if(a.hasOwnProperty("add")){if(a["add"].hasOwnProperty("attributes")){if(Object.prototype.toString.call(a["add"]["attributes"])!=="[object Object]"){throw new Error(`The properties "add/attributes" of subtask "${s}" is not a object!`)}for(const[c,p]of Object.entries(a["add"]["attributes"])){if(!i.hasAttribute(c)){i.setAttribute(c,p)}}}if(a["add"].hasOwnProperty("class")){const l=a["add"]["class"].split(/ +/);for(const h of l){i.classList.add(h)}}if(a["add"].hasOwnProperty("style")){if(i.hasAttribute("style")){const f=this.attrsStr2Obj(a["add"]["style"]);for(const[d,p]of Object.entries(f)){i.style[d]=p}}else{i.setAttribute("style",a["add"]["style"])}}}}}}async findElemWithTasks(t){if(t.hasChildNodes()){for(const e of t.childNodes){if(e.nodeName!=="TEMPLATE"&&e.nodeName!=="SCRIPT"&&e.nodeType!==e.TEXT_NODE&&e.nodeType!==e.COMMENT_NODE&&e.nodeType!==e.DOCUMENT_FRAGMENT_NODE){if(e.hasChildNodes()){await this.findElemWithTasks(e)}if(e.hasAttribute(this.tasksAttribute)){await this.setTask(e)}}}}}minifyJavaScript(t){return t.replace(/\/\/.*|\/\*[\s\S]*?\*\//g,"").replace(/\s+/g," ").trim()}reScript(t){for(const e of t.childNodes){if(e.hasChildNodes()){this.reScript(e)}if(e.nodeName==="SCRIPT"){const r=document.createElement("script");r.type="text/javascript";r.textContent=this.minifyJavaScript(e.textContent);e.replaceWith(r)}}}buildFragment(s){const t=document.createElement("div");try{if(!s.hasOwnProperty("template")){throw new Error(`The template not exist`)}t.insertAdjacentHTML("afterbegin",(()=>{const t=document.createElement("script");t.type="text/javascript";t.id="temporary-helper";t.innerHTML="function populateTemplate(event) {const data = event.result; return `"+s.template+"`;}";let e=0;let r=setInterval(()=>{if(e>5||document.getElementById("temporary-helper")===null){clearInterval(r);if(e>5){throw new Error(`The temporary helper already exist after 500ms!`)}}e++},100);document.body.appendChild(t);return populateTemplate(s)})());delete s.template;const e=document.getElementById("temporary-helper");if(e!==null){e.remove()}}catch(t){console.error(t)}this.reScript(t);return t}async fetchTemplate(t){try{const e=await fetch(t);if(!e.ok){throw new Error(`HTTP error! status: ${e.status} ${e.statusText}`)}return e.text()}catch(t){console.error(t)}return undefined}setTransformation(t,e){for(const[r,s]of Object.entries({target:"this",template:"",swap:"inner",after:"",before:"","is-template":false})){if(e.hasOwnProperty(r)){t[r]=e[r]}else if(s!==""&&!t.hasOwnProperty(r)){t[r]=s}}}async sequenceTasks(t,e,r){if(r.hasOwnProperty("before")&&r.before!==""){this.runSubtasks(e.currentTarget,r.before)}await this.findElemWithTasks(t);const s=r.target==="this"?e.currentTarget:document.querySelector(r.target);this.swapContent(t,s,r.hasOwnProperty("swap")?r.swap:"inner");if(r.hasOwnProperty("after")&&r.after!==""){this.runSubtasks(e.currentTarget,r.after)}}async templateManager(s,t){if(s.template.length<3){throw new Error(`Short template name "${s.template}"`)}t.template=await(async t=>{switch(Array.from(s.template)[0]){case"@":return await t.fetchTemplate(s.template.substring(1));case"#":const e=document.getElementById(s.template.substring(1));if(e===null){throw new Error(`Template "${s.template}" not exist!`)}if(e.content.hasChildNodes()&&e.content.nodeType===Node.DOCUMENT_FRAGMENT_NODE&&e.content.hasChildNodes){const r=document.createElement("textarea");r.insertAdjacentHTML("afterbegin",e.innerHTML);return r.value}throw new Error(`Invalid "${s.template}" embedded template`);default:throw new Error(`Invalid "${s.template}" fetched template`)}})(this);const e=this.buildFragment(t);if(e===null){throw new Error(`An error happened while processing the "${s.template}" template`)}return e}async setTemplateData(t,e){t.result=await(async t=>{if(e.hasOwnProperty("src-file")){return await t.getResource(e["src-file"])}return{}})(this);if(e.hasOwnProperty("callback")){if(!this.callbacks.hasOwnProperty(e.callback)){throw new Error(`The registered calback "${e.callback}" not exist!`)}this.callbacks[e.callback](t)}if(e.hasOwnProperty("template")&&e.hasOwnProperty("target")&&e.target!=""){const s=await this.templateManager(e,t);await this.sequenceTasks(s,t,e)}const r=e.target==="this"?t.currentTarget:document.querySelector(e.target);if(r!==null){this.swapContent(null,r,e.hasOwnProperty("swap")?e.swap:"inner")}}async processReqData(r,t){if("template"in r){const e=this.buildFragment(r);if(e===null){throw new Error('An error happened while processing the "remote" template from server')}return e}if(!("result"in r)){throw new Error("There is no any data for the transformation")}if(typeof r.result==="object"){if(t.hasOwnProperty("template")){const e=await this.templateManager(t,r);return e}throw new Error("There is no json data for the transformation")}if(typeof r.result==="string"){if(t.hasOwnProperty("template")){const e=await this.templateManager(t,r);return e}const e=(t=>{const e=document.createElement("div");e.innerHTML=r.result;t.reScript(e);return e})(this);return e}throw new Error("There is no data for the transformation")}serialize(t){let e={};for(const[r,s]of t){if(e[r]!==undefined){if(!Array.isArray(e[r])){e[r]=[e[r]]}e[r].push(s)}else{e[r]=s}}return e}async prepareRequest(t,e){let r=undefined;if(e.hasOwnProperty("callback")){if(!this.callbacks.hasOwnProperty(e.callback)){throw new Error(`The registered callback "${e.callback}" not exist!`)}const n=this.callbacks[e.callback](t,e);if(n===false){if(e.hasOwnProperty("next")){delete e.next}return}r=t.data}else if(e.hasOwnProperty("trigger")&&e.trigger==="submit"){const o=t.currentTarget.closest("form");if(o!==null){const i=new FormData(o);r=e.method==="post"?i:this.serialize(i)}}const s=await this.makeRequest(e,r);console.log("Make Request Result:",s.ok,s.status);t.ok=s.ok;t.status=s.status;if(e.hasOwnProperty("error")&&!s.ok){e=this.tasks[e["error"]];if(e.hasOwnProperty("message")){s.data=e["message"]}}this.setTransformation(e,s.transformation);if(e["is-template"]==true){t.template=s.data}else{t.result=s.data}const a=await this.processReqData(t,e);await this.sequenceTasks(a,t,e)}async findResourcePath(t,e){if(e.hasOwnProperty("then")&&e.then!==""){this.runSubtasks(t.currentTarget,e.then)}if(e.hasOwnProperty("extension")){if(!e["extension"].hasOwnProperty("name")){throw new Error('The registered extension has no "name" property!')}if(this.extensions.hasOwnProperty(e["extension"]["name"])){if(!this.extensions.hasOwnProperty(e["extension"]["name"])){throw new Error(`The registered extension "${e["extension"]["name"]}" not exist!`)}this.extensions[e["extension"]["name"]](t,e);return}}if(e.hasOwnProperty("action")){if(e.action===""){throw new Error("Empty action")}if(e.hasOwnProperty("method")){e.method=e.method.toLowerCase();if(!this.methods.has(e.method)){throw new Error(`Unknown HTTP method: ${e.method}`)}}else{e["method"]="get"}await this.prepareRequest(t,e);return}await this.setTemplateData(t,e)}async processEvent(t,e){for(const r of Object.keys(e)){if(!r.startsWith("attribute-")){continue}const s=r.substring("attribute-".length);if(s.length>1&&t.currentTarget.hasAttribute(e[r])){e[s]=t.currentTarget.getAttribute(e[r])}}await this.findResourcePath(t,e);if(e.hasOwnProperty("next")&&e.next!==""){await this.runNextTask(t,e.next)}}setDefaultTrigger(t){if(t.nodeName==="FORM"){return"submit"}if(t.nodeName==="BUTTON"){return t.type==="submit"?"submit":"click"}if(t.nodeName==="INPUT"&&t.type==="button"){return"click"}return null}async setTask(t){const e=t.dataset.tasks.split(/ +/);for(const r of e){if(!this.tasks.hasOwnProperty(r)){throw new Error(`The task "${r}" not exist in tasks file!`)}const s=structuredClone(this.tasks[r]);if(s.hasOwnProperty("attribute-trigger")&&t.hasAttribute(s["attribute-trigger"])&&t.getAttribute(s["attribute-trigger"])!==""){s["trigger"]=t.getAttribute(s["attribute-trigger"])}if(!s.hasOwnProperty("disabled")){s["disabled"]=false}if(!s.hasOwnProperty("prevent")){s["prevent"]=true}if(s.trigger==="init"){if(s.disabled===false){t.addEventListener("init",async t=>{if(s.prevent){t.preventDefault()}if(s.disabled===false){try{await this.processEvent(t,s)}catch(t){console.log(`Error for "${r}": ${t}`)}}});const a=new CustomEvent("init",{bubbles:true,cancelable:true});t.dispatchEvent(a)}continue}if(s.hasOwnProperty("trigger")){if(!this.triggers.has(s.trigger)){throw new Error(`The "${s.trigger}" trigger is not allowed yet!`)}}else{s.trigger=this.setDefaultTrigger(t);if(s.trigger===null){throw new Error(`No trigger defined for "${r}"!`)}}t.addEventListener(s.trigger,async t=>{if(s.prevent){t.preventDefault()}if(s.disabled===false){try{await this.processEvent(t,s)}catch(t){console.log(`Error for "${r}": ${t}`)}}})}}async getDataTasks(){const t=document.querySelectorAll("script[data-tasktable]");for(const e of t){if(e.type.toLowerCase()!=="application/json"){throw new Error(`Wrong mime-type "${e.type}" for element tasks!`)}if(e.hasAttribute("src")&&e.src!==""){const r=await(async t=>{return await t.getResource(e.src)})(this);Object.assign(this.tasks,r);continue}const r=JSON.parse(e.text);Object.assign(this.tasks,r)}}callback_register(t,e){this.callbacks[t]=e}extension_register(t,e){this.extensions[t]=e}init(){const t=document.getElementsByTagName(this.startElement);this.getDataTasks().then(async()=>{if(Object.keys(this.tasks).length>=0){await this.findElemWithTasks(t[0])}})}}return t}); \ No newline at end of file + happen an HTTP error! status: ${e.status} ${e.statusText}`)}return await e.json()}swapContent(t,e,r){if(e===null){console.warn("no target to swap");return}if(t===null){if(r==="delete"){e.remove();return}if(r==="clean"){while(e.firstChild){e.removeChild(e.firstChild)}return}if(r==="none"){return}return}if(r==="inner"){e.replaceChildren(...t.childNodes);return}if(r==="outer"){e.replaceWith(...t.childNodes);return}if(r==="before"){e.before(...t.childNodes);return}if(r==="after"){e.after(...t.childNodes);return}if(r==="prepend"){e.prepend(...t.childNodes);return}if(r==="append"){e.append(...t.childNodes);return}throw new Error(`swap "${r}" attribute not supported`)}async runNextTask(t,e){const r=e.split(/ +/);for(const s of r){if(!this.tasks.hasOwnProperty(s)){throw new Error(`The next task "${s}" not exist in tasks file!`)}const a=this.tasks[s];if(!a.hasOwnProperty("disabled")){a["disabled"]=false}if(a.hasOwnProperty("trigger")){throw new Error(`The trigger property from "${s}" is not allowed in next task!`)}if(a.disabled===false){if(!a.hasOwnProperty("wait")){a.wait=0}setTimeout(async()=>{await this.findResourcePath(t,a);if(a.hasOwnProperty("next")){await this.runNextTask(t,a.next)}},a.wait)}}}runSubtasks(t,e){const r=e.split(/ +/);for(const s of r){if(!this.tasks.hasOwnProperty(s)){throw new Error(`The subtask "${s}" not exist in tasks file!`)}const a=this.tasks[s];if(!a.hasOwnProperty("selector")){a["traverse"]="target"}for(const o in a){if(!["traverse","selector","remove","add"].includes(o)){throw new Error(`The property "${o}" in subtask "${s}" is not allowed with property "selector"!`)}}if(Object.prototype.toString.call(a)!=="[object Object]"){throw new Error(`The properties of subtask "${s}" is not a object!`)}const n=(()=>{if(a.hasOwnProperty("traverse")){if(a.traverse==="target"){return[t]}if(a.traverse==="closest"&&a["selector"]!==""){return t.closest(a["selector"])}}if(a["selector"]!==""){return document.querySelectorAll(a["selector"])}throw new Error(`The properties of subtask "${s}" has a empty selector!`)})();if(a.hasOwnProperty("remove")&&Object.keys(a["remove"]).length===0){for(const i of n){i.remove()}continue}for(const i of n){if(a.hasOwnProperty("remove")){if(a["remove"].hasOwnProperty("attributes")){if(!Array.isArray(a["remove"]["attributes"])){throw new Error(`The property "remove/attributes" of subtask "${s}" is not an array!`)}for(const c of a["remove"]["attributes"]){if(i.hasAttribute(c)){i.removeAttribute(c);if(c==="class"||c==="style"){return true}}}}if(i.hasAttribute("class")&&a["remove"].hasOwnProperty("class")){const l=a["remove"]["class"].split(/ +/);for(const h of l){if(i.classList.contains(h)){i.classList.remove(h)}}if(i.getAttribute("class")===""){i.removeAttribute("class")}}if(i.hasAttribute("style")&&a["remove"].hasOwnProperty("style")){let t=i.style;const f=a["remove"]["style"].split(/ +/);for(const u of f){if(i.style.hasOwnProperty(u)){delete t[u]}}i.style=t;if(i.getAttribute("style")===""){i.removeAttribute("style")}}}if(a.hasOwnProperty("add")){if(a["add"].hasOwnProperty("attributes")){if(Object.prototype.toString.call(a["add"]["attributes"])!=="[object Object]"){throw new Error(`The properties "add/attributes" of subtask "${s}" is not a object!`)}for(const[c,p]of Object.entries(a["add"]["attributes"])){if(!i.hasAttribute(c)){i.setAttribute(c,p)}}}if(a["add"].hasOwnProperty("class")){const l=a["add"]["class"].split(/ +/);for(const h of l){i.classList.add(h)}}if(a["add"].hasOwnProperty("style")){if(i.hasAttribute("style")){const f=this.attrsStr2Obj(a["add"]["style"]);for(const[d,p]of Object.entries(f)){i.style[d]=p}}else{i.setAttribute("style",a["add"]["style"])}}}}}}async findElemWithTasks(t){if(t.hasChildNodes()){for(const e of t.childNodes){if(e.nodeName!=="TEMPLATE"&&e.nodeName!=="SCRIPT"&&e.nodeType!==e.TEXT_NODE&&e.nodeType!==e.COMMENT_NODE&&e.nodeType!==e.DOCUMENT_FRAGMENT_NODE){if(e.hasChildNodes()){await this.findElemWithTasks(e)}if(e.hasAttribute(this.tasksAttribute)){await this.setTask(e)}}}}}minifyJavaScript(t){return t.replace(/\/\/.*|\/\*[\s\S]*?\*\//g,"").replace(/\s+/g," ").trim()}reScript(t){for(const e of t.childNodes){if(e.hasChildNodes()){this.reScript(e)}if(e.nodeName==="SCRIPT"){const r=document.createElement("script");r.type="text/javascript";r.textContent=this.minifyJavaScript(e.textContent);e.replaceWith(r)}}}buildFragment(s){const t=document.createElement("div");try{if(!s.hasOwnProperty("template")){throw new Error(`The template not exist`)}t.insertAdjacentHTML("afterbegin",(()=>{const t=document.createElement("script");t.type="text/javascript";t.id="temporary-helper";t.innerHTML="function populateTemplate(event) {const data = event.result; return `"+s.template+"`;}";let e=0;let r=setInterval(()=>{if(e>5||document.getElementById("temporary-helper")===null){clearInterval(r);if(e>5){throw new Error(`The temporary helper already exist after 500ms!`)}}e++},100);document.body.appendChild(t);return populateTemplate(s)})());delete s.template;const e=document.getElementById("temporary-helper");if(e!==null){e.remove()}}catch(t){console.error(t)}this.reScript(t);return t}async fetchTemplate(t){try{const e=await fetch(t);if(!e.ok){throw new Error(`HTTP error! status: ${e.status} ${e.statusText}`)}return e.text()}catch(t){console.error(t)}return undefined}setTransformation(t,e){for(const[r,s]of Object.entries({target:"this",template:"",swap:"inner",after:"",before:"","is-template":false})){if(e.hasOwnProperty(r)){t[r]=e[r]}else if(s!==""&&!t.hasOwnProperty(r)){t[r]=s}}}async sequenceTasks(t,e,r){if(r.hasOwnProperty("before")&&r.before!==""){this.runSubtasks(e.currentTarget,r.before)}await this.findElemWithTasks(t);const s=r.target==="this"?e.currentTarget:document.querySelector(r.target);this.swapContent(t,s,r.hasOwnProperty("swap")?r.swap:"inner");if(r.hasOwnProperty("after")&&r.after!==""){this.runSubtasks(e.currentTarget,r.after)}}async templateManager(s,t){if(s.template.length<3){throw new Error(`Short template name "${s.template}"`)}t.template=await(async t=>{switch(Array.from(s.template)[0]){case"@":return await t.fetchTemplate(s.template.substring(1));case"#":const e=document.getElementById(s.template.substring(1));if(e===null){throw new Error(`Template "${s.template}" not exist!`)}if(e.content.hasChildNodes()&&e.content.nodeType===Node.DOCUMENT_FRAGMENT_NODE&&e.content.hasChildNodes){const r=document.createElement("textarea");r.insertAdjacentHTML("afterbegin",e.innerHTML);return r.value}throw new Error(`Invalid "${s.template}" embedded template`);default:throw new Error(`Invalid "${s.template}" fetched template`)}})(this);const e=this.buildFragment(t);if(e===null){throw new Error(`An error happened while processing the "${s.template}" template`)}return e}async setTemplateData(t,e){t.result=await(async t=>{if(e.hasOwnProperty("src-file")){return await t.getResource(e["src-file"])}return{}})(this);if(e.hasOwnProperty("callback")){if(!this.callbacks.hasOwnProperty(e.callback)){throw new Error(`The registered calback "${e.callback}" not exist!`)}this.callbacks[e.callback](t)}if(e.hasOwnProperty("template")&&e.hasOwnProperty("target")&&e.target!=""){const s=await this.templateManager(e,t);await this.sequenceTasks(s,t,e)}const r=e.target==="this"?t.currentTarget:document.querySelector(e.target);if(r!==null){this.swapContent(null,r,e.hasOwnProperty("swap")?e.swap:"inner")}}async processReqData(r,t){if("template"in r){const e=this.buildFragment(r);if(e===null){throw new Error('An error happened while processing the "remote" template from server')}return e}if(!("result"in r)){throw new Error("There is no any data for the transformation")}if(typeof r.result==="object"){if(t.hasOwnProperty("template")){const e=await this.templateManager(t,r);return e}throw new Error("There is no json data for the transformation")}if(typeof r.result==="string"){if(t.hasOwnProperty("template")){const e=await this.templateManager(t,r);return e}const e=(t=>{const e=document.createElement("div");e.innerHTML=r.result;t.reScript(e);return e})(this);return e}throw new Error("There is no data for the transformation")}serialize(t){let e={};for(const[r,s]of t){if(e[r]!==undefined){if(!Array.isArray(e[r])){e[r]=[e[r]]}e[r].push(s)}else{e[r]=s}}return e}async prepareRequest(t,e){let r=undefined;if(e.hasOwnProperty("callback")){if(!this.callbacks.hasOwnProperty(e.callback)){throw new Error(`The registered callback "${e.callback}" not exist!`)}const n=this.callbacks[e.callback](t);if(n===false){if(e.hasOwnProperty("next")){delete e.next}return}r=t.data}else if(e.hasOwnProperty("trigger")&&e.trigger==="submit"){const o=t.currentTarget.closest("form");if(o!==null){const i=new FormData(o);r=e.method==="post"?i:this.serialize(i)}}const s=await this.makeRequest(e,r);console.log("Make Request Result:",s.ok,s.status);t.ok=s.ok;t.status=s.status;if(e.hasOwnProperty("error")&&!s.ok){e=this.tasks[e["error"]];if(e.hasOwnProperty("message")){s.data=e["message"]}}this.setTransformation(e,s.transformation);if(e["is-template"]==true){t.template=s.data}else{t.result=s.data}const a=await this.processReqData(t,e);await this.sequenceTasks(a,t,e)}async findResourcePath(t,e){if(e.hasOwnProperty("then")&&e.then!==""){this.runSubtasks(t.currentTarget,e.then)}if(e.hasOwnProperty("extension")){if(!e["extension"].hasOwnProperty("name")){throw new Error('The registered extension has no "name" property!')}if(this.extensions.hasOwnProperty(e["extension"]["name"])){if(!this.extensions.hasOwnProperty(e["extension"]["name"])){throw new Error(`The registered extension "${e["extension"]["name"]}" not exist!`)}this.extensions[e["extension"]["name"]](t,e);return}}if(e.hasOwnProperty("action")){if(e.action===""){throw new Error("Empty action")}if(e.hasOwnProperty("method")){e.method=e.method.toLowerCase();if(!this.methods.has(e.method)){throw new Error(`Unknown HTTP method: ${e.method}`)}}else{e["method"]="get"}await this.prepareRequest(t,e);return}await this.setTemplateData(t,e)}async processEvent(t,e){for(const r of Object.keys(e)){if(!r.startsWith("attribute-")){continue}const s=r.substring("attribute-".length);if(s.length>1&&t.currentTarget.hasAttribute(e[r])){e[s]=t.currentTarget.getAttribute(e[r])}}await this.findResourcePath(t,e);if(e.hasOwnProperty("next")&&e.next!==""){await this.runNextTask(t,e.next)}}setDefaultTrigger(t){if(t.nodeName==="FORM"){return"submit"}if(t.nodeName==="BUTTON"){return t.type==="submit"?"submit":"click"}if(t.nodeName==="INPUT"&&t.type==="button"){return"click"}return null}async setTask(t){const e=t.dataset.tasks.split(/ +/);for(const r of e){if(!this.tasks.hasOwnProperty(r)){throw new Error(`The task "${r}" not exist in tasks file!`)}const s=structuredClone(this.tasks[r]);if(s.hasOwnProperty("attribute-trigger")&&t.hasAttribute(s["attribute-trigger"])&&t.getAttribute(s["attribute-trigger"])!==""){s["trigger"]=t.getAttribute(s["attribute-trigger"])}if(!s.hasOwnProperty("disabled")){s["disabled"]=false}if(!s.hasOwnProperty("prevent")){s["prevent"]=true}if(s.trigger==="init"){if(s.disabled===false){t.addEventListener("init",async t=>{if(s.prevent){t.preventDefault()}if(s.disabled===false){try{await this.processEvent(t,s)}catch(t){console.log(`Error for "${r}": ${t}`)}}});const a=new CustomEvent("init",{bubbles:true,cancelable:true});t.dispatchEvent(a)}continue}if(s.hasOwnProperty("trigger")){if(!this.triggers.has(s.trigger)){throw new Error(`The "${s.trigger}" trigger is not allowed yet!`)}}else{s.trigger=this.setDefaultTrigger(t);if(s.trigger===null){throw new Error(`No trigger defined for "${r}"!`)}}t.addEventListener(s.trigger,async t=>{if(s.prevent){t.preventDefault()}if(s.disabled===false){try{await this.processEvent(t,s)}catch(t){console.log(`Error for "${r}": ${t}`)}}})}}async getDataTasks(){const t=document.querySelectorAll("script[data-tasktable]");for(const e of t){if(e.type.toLowerCase()!=="application/json"){throw new Error(`Wrong mime-type "${e.type}" for element tasks!`)}if(e.hasAttribute("src")&&e.src!==""){const r=await(async t=>{return await t.getResource(e.src)})(this);Object.assign(this.tasks,r);continue}const r=JSON.parse(e.text);Object.assign(this.tasks,r)}}callback_register(t,e){this.callbacks[t]=e}extension_register(t,e){this.extensions[t]=e}init(){const t=document.getElementsByTagName(this.startElement);this.getDataTasks().then(async()=>{if(Object.keys(this.tasks).length>=0){await this.findElemWithTasks(t[0])}})}}return t}); \ No newline at end of file diff --git a/dist/js/secutio.min.js.gz b/dist/js/secutio.min.js.gz index acb30b2..80303a9 100644 Binary files a/dist/js/secutio.min.js.gz and b/dist/js/secutio.min.js.gz differ diff --git a/examples/chat/public/index.html b/examples/chat/public/index.html index a6dae67..20fe1f4 100644 --- a/examples/chat/public/index.html +++ b/examples/chat/public/index.html @@ -95,13 +95,7 @@ if (newUserElem.value.length > 2) { event.data = { 'user': newUserElem.value }; document.getElementById("myself").value = newUserElem.value; - } - })); - - app.callback_register('logout', ((event, properties) => { - const user = document.getElementById("myself").value; - if (user.length > 2) { - properties["action"] = `logout/${user}`; + document.getElementById("logout").setAttribute('data-action', `logout/${newUserElem.value}`); } })); diff --git a/examples/chat/public/tasks.json b/examples/chat/public/tasks.json index 9eefe64..eb221c1 100644 --- a/examples/chat/public/tasks.json +++ b/examples/chat/public/tasks.json @@ -21,8 +21,8 @@ }, "logout": { "action": "logout", + "attribute-action": "data-action", "method": "delete", - "callback": "logout", "trigger": "click", "target": "#main", "template": "#login-dialog-tpl", diff --git a/src/js/secutio.js b/src/js/secutio.js index d0bff64..fb5bec1 100644 --- a/src/js/secutio.js +++ b/src/js/secutio.js @@ -1,7 +1,7 @@ /* secutio.js Author: Henrique Dias - Last Modification: 2024-03-25 19:10:51 + Last Modification: 2024-04-01 18:20:24 Attention: This is work in progress References: @@ -769,7 +769,7 @@ if (!this.callbacks.hasOwnProperty(properties.callback)) { throw new Error(`The registered callback "${properties.callback}" not exist!`); } - const result = this.callbacks[properties.callback](event, properties); + const result = this.callbacks[properties.callback](event); if (result === false) { if (properties.hasOwnProperty('next')) { delete properties.next;