UNPKG

@cocreate/api

Version:

A simple api helper component in vanilla javascript used by JavaScript developers to create thirdparty api intergrations. CoCreate-api includes the client component and server side for api processing. Thirdparty apis can be accessible using HTML5 attribut

277 lines (248 loc) 7.45 kB
/*globals CustomEvent, config*/ import { getValueFromObject, dotNotationToObject } from "@cocreate/utils"; import Observer from "@cocreate/observer"; import Socket from "@cocreate/socket-client"; import Actions from "@cocreate/actions"; import { render } from "@cocreate/render"; import "@cocreate/element-prototype"; const CoCreateApi = { modules: {}, init: function (moduleConfig) { if (!moduleConfig) { let elements = document.querySelectorAll("[api], [module]"); for (let i = 0; i < elements.length; i++) { let name = elements[i].getAttribute("api") || elements[i].getAttribute("module"); this.register({ name, endPoints: {} }); } } else { let { name, endPoints, options } = moduleConfig; this.register({ name, endPoints, options }); if (options && options.socket !== false && !Socket.sockets.size) Socket.create({ prefix: "api" }); } }, register: function ({ name, endPoints, options }) { const self = this; if (typeof this.modules[name] === "undefined") { this.modules[name] = { name, endPoints, options }; Actions.init({ name, callback: (action) => { action.form = action.form || document; self.request({ ...action, type: "action" }); } }); const inputEvent = (element) => { element.addEventListener("input", (e) => { if (!e.detail || (e.detail && e.detail.skip != true)) { self.request({ name, element, type: "input" }); } }); }; let elements = document.querySelectorAll(`[${name}]`); for (let i = 0; i < elements.length; i++) { inputEvent(elements[i]); this.request({ name, element: elements[i], type: "onload" }); } Observer.init({ name: `${name}NodeObserver`, types: ["addedNodes"], selector: `[${name}]`, callback: function (mutation) { inputEvent(mutation.target); self.request({ name, element: mutation.target, type: "nodeObserver" }); } }); Observer.init({ name: `${name}AttributeObserver`, types: ["attributes"], attributeFilter: [name], callback: function (mutation) { self.request({ name, element: mutation.target, type: "attributeObserver" }); } }); } }, request: async function (object) { if (object.element) { if (!object.method) object.method = object.element.getAttribute(object.name); if (!object.key) object.key = object.element.getAttribute(`${object.name}-key`); if (!object.event) object.event = object.element.getAttribute( `${object.name}-event` ); } if ( this.modules[object.name][object.method] && this.modules[object.name][object.method].request ) this.modules[object.name][object.method].request(object); else if ( (!object.event && object.type === "action") || (object.event && object.event.includes(object.type)) ) { object.data = await CoCreateApi.getData(object); if (Object.keys(object.data).length) CoCreateApi.send(object); } }, response: function (object) { const name = object.name; const method = object.method; const data = object.data; if (this.modules[name][method] && this.modules[name][method].response) this.modules[name][method].response(data[name]); else if (data.error) { render({ selector: `[template*='${name}']`, data: [ { type: name, method, status: "failed", message: data.error } ] }); } else { CoCreateApi.setData(object); object.element.dispatchEvent( new CustomEvent(object.endEvent, { detail: { data: object } }) ); } }, send: async function (object) { object.data = await Socket.send({ method: object.name + "." + object.method, [object.name]: object.data, broadcast: false, broadcastBrowser: false, status: "await" }); this.response(object); }, getData: async function ({ name, method, element, form }) { let data = {}; if (!form && element) form = element.closest("form"); if (!form) form = document; let elements; if (form) elements = form.querySelectorAll( `[${name}="${method}"]:not([${name}-request="false"])` ); if (!elements || elements.length == 0) elements = [element]; for (let i = 0; i < elements.length; i++) { if (!elements[i] || elements[i].closest("[template]")) continue; let key = elements[i].getAttribute(`${name}-key`); if (key) { let value = elements[i].stripeElement || (await elements[i].getValue()); if (key.endsWith("[]")) { if (!data[key]) data[key] = []; if (Array.isArray(value)) data[key].push(...value); else data[key].push(value); } else data[key] = value; } let endpoint = elements[i].getAttribute("endpoint"); if (endpoint) { data.endpoint = endpoint; } if ( elements[i].getAttribute("query") && elements[i].getAttribute("query") !== "false" ) { data.query = true; } } let params = {}, hasParams = false; for (let i = 0; true; i++) { if (`$param[${i}]` in data) { params[`$param[${i}]`] = data[`$param[${i}]`]; delete data[`$param[${i}]`]; hasParams = true; } else { break; } } data = dotNotationToObject(data); if (hasParams) data = { ...params, ...data }; return data; }, setData: function (object) { const name = object.name; const data = object.data; let form = object.form; if (!form) form = document; let elements = form.querySelectorAll( `[${name}="${object.method}"]:not([${name}-response="false"])` ); if (!elements || elements.length == 0) return; for (let i = 0; i < elements.length; i++) { let attribute = elements[i].getAttribute(name); if (attribute) { if (elements[i].hasAttribute("actions")) continue; let templateid = elements[i].getAttribute("template_id"); if (templateid) { let items = document.querySelectorAll( `[templateid="${templateid}"]` ); for (let item of items) item.remove(); render({ selector: `[template="${templateid}"]`, data }); } else if (elements[i].renderValue) { let key = elements[i].getAttribute(`${name}-key`); if (key === "{}") { elements[i].renderValue(data[name]); } else { let value = getValueFromObject(data[name], key); if (typeof value === "function") { value = value(); // Call the function and assign its return value. } elements[i].renderValue(value); } } else { let key = elements[i].getAttribute(`${name}-key`); if (key === "{}") elements[i].setValue(data[name]); else { let value = getValueFromObject(data[name], key); if (typeof value === "function") { value = value(); // Call the function and assign its return value. } elements[i].setValue(value); } } } } } }; Observer.init({ name: `apiNodeObserver`, types: ["addedNodes"], selector: "[module], [api]", callback: function (mutation) { let name = mutation.target.getAttribute("api") || mutation.target.getAttribute("module"); CoCreateApi.register({ name, endPoints: {} }); } }); CoCreateApi.init(); export default CoCreateApi;