function getRefsRoot() { return app } function element(id_, findParent = false) { function findref(obj) { if (!obj?.$refs) return for (let id in obj.$refs) { let inner = obj.$refs[id] if (Array.isArray(inner)) { inner = inner[0] } if (!inner) continue if (id_ == id) return findParent ? obj : inner let res = findref(inner) if (res) return res } return null } return findref(getRefsRoot()) } function getAllID() { let all = [] function flatten(obj) { if (!obj?.$refs) return for (let id in obj.$refs) { let inner = obj.$refs[id] if (Array.isArray(inner)) { inner = inner[0] } if (!inner) continue all.push(id) flatten(inner) } } flatten(getRefsRoot()) return all } function getAllItems() { let all = {} function flatten(obj) { if (!obj?.$refs) return for (let id in obj.$refs) { let inner = obj.$refs[id] if (Array.isArray(inner)) { inner = inner[0] } if (!inner) continue if (inner?.getValue) { let firstCopy = inner.getValue() if (firstCopy) { all[id] = new Proxy({}, { set(obj, prop, value) { if (!firstCopy) return firstCopy[prop] = value inner.setValue({ [prop]: value }) }, get(obj, prop) { if (!firstCopy) return if (prop == 'toJSON') return () => firstCopy return firstCopy[prop]; }, }) } } flatten(inner) } } flatten(getRefsRoot()) return all } async function waitElements(list) { if (!list || list.length == 0) return let waitCounter = 1 let all let ok = false let hits = [] while (data.pageLoading) { console.log("waitElements waitPageLoading ######", waitCounter++) await sleep(150) } while (waitCounter < 20) { all = getAllItems() hits = [] for (let l of list) { if (all[l]) hits.push(l) } if (hits.length == list.length) { ok = true break; } console.log("waitElements", list.join(','), waitCounter++)//, hits, Object.keys(all)) await sleep(150) } if (!ok) { let missing = list.filter(x => !hits.includes(x)) await alert("waitElements ERROR, missing elements: " + missing.join(', ')) } } async function exec(logic, options = {}) { if (!logic) return if (!logic.steps?.length) return console.log("exec-logic", logic.id) let hasCapture = logic.steps?.filter(x => x.type == 'capture').length > 0 if (!hasCapture && false) { console.log("no capture warning", new Error()?.stack) toast("warning: deprecated logic without capture found! ID=" + logic.id, true) } let context = hasCapture ? {} : getAllItems() //wait app and app.$route to be ready let waitRouteCounter = 0 while (!app || (app.$route?.name != app.page.id)) { console.log("wait route ready...", waitRouteCounter) await sleep(150) if (++waitRouteCounter > 50) { return alert("wait route ready timeout") } } //merge route params context.route = { ...(app.$route.params || {}), ...(app.$route.query || {}), } context.visibility = {} context.user = data.user context.token = getToken() Object.assign(context, app.$route?.params) //@depracted, to be removed Object.assign(context, options.clientOnlyProps) try { let stop = false context.stop = (params) => { //TODO: manage params? stop = true } for (let i = 0; i < logic.steps?.length && !stop; i++) { let step = logic.steps[i] switch (step.type) { case 'empty': break case 'capture': if (step.inputs) { await waitElements(step.inputs) let all = getAllItems() for (let key of step.inputs) { context[key] = all[key] } } break case 'js-code': let code = 'with (context) {\n' + step.code + '\n}\n//# sourceURL=logic-' + step.id + '.js'; let f = new AsyncFunction('context', code) await f(context) break case 'sql-table-select': //@deprecated case 'sql-code': //@deprecated case 'nodejs-code': loaderShow("Processing...", true) let ncontext = { ...context } delete ncontext.user delete ncontext.token for (let cprop in options.clientOnlyProps) { delete ncontext[cprop] } let res = await tkpost(`exec/${options.pageOverride || data.page.id}/${logic.id}?si=${i}`, ncontext, step.id.includes('$njson')) if (typeof res !== 'string') { //for each value in response for (let key in res) { let item = res[key] //check if item has changed before-after API call if (JSON.stringify(context[key]) != JSON.stringify(item)) { let el = element(key) if (el && el.setValue) { el.setValue(item) /*TODO: test for concurrency problems... //DOES NOT WORK when multiple EXEC are running on the same APM ELEMENT for (let ikey in item) context[key][ikey] = item[ikey] */ } else { context[key] = item } } } if (res.nextIndex) { i = res.nextIndex -1 } if (res.stopReason) { if (!options.skipAlerts) alert(translate(res.stopReason)) stop = true } } loaderHide() //@deprecated Object.assign(context, res) break default: console.error('unknown step type', step) break } } } catch (ex) { console.error("exec error", ex) let emsg = ex.responseJSON?.error || ex.toString() if (emsg == "[object Object]" && ex.statusText) { if (ex.status == 0) emsg = 'E_CONNECTION_ERROR' else emsg = ex.status + ' ' + ex.statusText } if (!options.skipAlerts) alert(emsg) } loaderHide() //apply visibility for (let vkey in context.visibility) { Vue.set(data.visibility, vkey, context.visibility[vkey]) } return context } /*@deprecated function component(id) { return element(id, false, true) } */