@xpell/core 2.0.0-alpha.10 → 2.0.0-alpha.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/XCommand.d.ts +2 -2
- package/dist/XData.d.ts +1 -0
- package/dist/XObject.d.ts +12 -10
- package/dist/Xpell.d.ts +1 -1
- package/dist/xpell-core.cjs.js +2 -2
- package/dist/xpell-core.es.js +227 -102
- package/docs/nano-commands2.md +457 -0
- package/package.json +1 -1
package/dist/XCommand.d.ts
CHANGED
|
@@ -42,7 +42,7 @@ export type XCommandData = {
|
|
|
42
42
|
_object?: string;
|
|
43
43
|
_op: string;
|
|
44
44
|
_params?: {
|
|
45
|
-
[k: string]: string | number |
|
|
45
|
+
[k: string]: string | number | boolean | null | object | any[];
|
|
46
46
|
};
|
|
47
47
|
};
|
|
48
48
|
export declare class XCommand {
|
|
@@ -62,7 +62,7 @@ export declare class XCommand {
|
|
|
62
62
|
* command parameters array
|
|
63
63
|
*/
|
|
64
64
|
_params?: {
|
|
65
|
-
[k: string]: string | number |
|
|
65
|
+
[k: string]: string | number | boolean | null | object | any[];
|
|
66
66
|
};
|
|
67
67
|
/**
|
|
68
68
|
* XCommand create date timestamp
|
package/dist/XData.d.ts
CHANGED
package/dist/XObject.d.ts
CHANGED
|
@@ -29,7 +29,7 @@ import { XNanoCommandPack, XNanoCommand } from "./XNanoCommands";
|
|
|
29
29
|
export type wordsList = {
|
|
30
30
|
[k: string]: string;
|
|
31
31
|
};
|
|
32
|
-
export type XValue = string | number | boolean | null | undefined | Function | XValue[] | {
|
|
32
|
+
export type XValue = string | number | boolean | null | undefined | Function | object | any[] | XValue[] | {
|
|
33
33
|
[k: string]: XValue;
|
|
34
34
|
};
|
|
35
35
|
export interface IXData {
|
|
@@ -52,6 +52,7 @@ export type XObjectOnEventHandler = (xObject: XObject, data?: any) => void;
|
|
|
52
52
|
export interface XObjectOnEventIndex {
|
|
53
53
|
[eventName: string]: XObjectOnEventHandler;
|
|
54
54
|
}
|
|
55
|
+
type XObjectHandler = Function | string | XCommandData | XObjectHandler[];
|
|
55
56
|
export type XObjectData = {
|
|
56
57
|
[k: string]: XValue;
|
|
57
58
|
_id?: string;
|
|
@@ -61,10 +62,10 @@ export type XObjectData = {
|
|
|
61
62
|
_data_source?: string;
|
|
62
63
|
_on?: XObjectOnEventIndex;
|
|
63
64
|
_once?: XObjectOnEventIndex;
|
|
64
|
-
_on_create?:
|
|
65
|
-
_on_mount?:
|
|
66
|
-
_on_frame?:
|
|
67
|
-
_on_data?:
|
|
65
|
+
_on_create?: XObjectHandler;
|
|
66
|
+
_on_mount?: XObjectHandler;
|
|
67
|
+
_on_frame?: XObjectHandler;
|
|
68
|
+
_on_data?: XObjectHandler;
|
|
68
69
|
_process_frame?: boolean;
|
|
69
70
|
_process_data?: boolean;
|
|
70
71
|
_nano_commands?: XNanoCommandPack;
|
|
@@ -85,11 +86,11 @@ export declare class XObject {
|
|
|
85
86
|
_debug?: boolean;
|
|
86
87
|
_on: XObjectOnEventIndex;
|
|
87
88
|
_once: XObjectOnEventIndex;
|
|
88
|
-
_on_create?:
|
|
89
|
-
_on_mount?:
|
|
90
|
-
_on_frame?:
|
|
91
|
-
_on_data?:
|
|
92
|
-
_on_event?:
|
|
89
|
+
_on_create?: XObjectHandler | undefined;
|
|
90
|
+
_on_mount?: XObjectHandler | undefined;
|
|
91
|
+
_on_frame?: XObjectHandler | undefined;
|
|
92
|
+
_on_data?: XObjectHandler | undefined;
|
|
93
|
+
_on_event?: XObjectHandler | undefined;
|
|
93
94
|
_process_frame: boolean;
|
|
94
95
|
_process_data: boolean;
|
|
95
96
|
protected _xem_options: XEventListenerOptions;
|
|
@@ -185,6 +186,7 @@ export declare class XObject {
|
|
|
185
186
|
*
|
|
186
187
|
*/
|
|
187
188
|
onCreate(): Promise<void>;
|
|
189
|
+
private runCmd;
|
|
188
190
|
protected checkAndRunInternalFunction(func: any, ...params: any): Promise<void>;
|
|
189
191
|
/**
|
|
190
192
|
* Triggers when the object is being mounted to other element
|
package/dist/Xpell.d.ts
CHANGED
|
@@ -128,7 +128,7 @@ export declare const Xpell: XpellEngine;
|
|
|
128
128
|
export default Xpell;
|
|
129
129
|
export { Xpell as _x };
|
|
130
130
|
export { XUtils, XUtils as _xu, _XUtils, type XFrameScheduler } from "./XUtils";
|
|
131
|
-
export { XData,
|
|
131
|
+
export { XData, _xd, type XDataStore, _XData } from "./XData";
|
|
132
132
|
export { XParser } from "./XParser";
|
|
133
133
|
export { XCommand, type XCommandData } from "./XCommand";
|
|
134
134
|
export { XLogger, XLogger as _xlog, _XLogger } from "./XLogger";
|
package/dist/xpell-core.cjs.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
"use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});class x{createIgnoreList(t,e){if(!t)return e;const s=t.split(",").map(i=>i.trim()).filter(Boolean);for(const i of s)e[i]="";return e}guid(){const e=globalThis.crypto;if(e&&typeof e.randomUUID=="function")return e.randomUUID();if(e&&typeof e.getRandomValues=="function"){const r=new Uint8Array(16);e.getRandomValues(r),r[6]=r[6]&15|64,r[8]=r[8]&63|128;const a=Array.from(r,_=>_.toString(16).padStart(2,"0"));return a.slice(0,4).join("")+"-"+a.slice(4,6).join("")+"-"+a.slice(6,8).join("")+"-"+a.slice(8,10).join("")+"-"+a.slice(10,16).join("")}const s="0123456789abcdef".split(""),i=[];let n;i[8]=i[13]=i[18]=i[23]="-",i[14]="4";for(let r=0;r<36;r++)i[r]||(n=(0|Math.random()*16)>>>0,i[r]=s[r===19?n&3|8:n&15]);return i.join("")}mergeDefaultsWithData(t,e,s=!1){if(!t)return e;t._id||(t._id=t.id??this.guid());for(const i of Object.keys(e))(!(i in t)||s)&&(t[i]=e[i]);return t}encode(t){const e=globalThis;if(typeof e.btoa=="function"){const s=encodeURIComponent(String(t)).replace(/%([0-9A-F]{2})/g,(i,n)=>String.fromCharCode(parseInt(n,16)));return e.btoa(s)}if(e.Buffer&&typeof e.Buffer.from=="function")return e.Buffer.from(String(t),"utf8").toString("base64");throw new Error("Base64 encode not supported in this environment")}decode(t){const e=globalThis;if(typeof e.atob=="function"){const s=e.atob(String(t)),i=Array.prototype.map.call(s,n=>"%"+n.charCodeAt(0).toString(16).padStart(2,"0")).join("");return decodeURIComponent(i)}if(e.Buffer&&typeof e.Buffer.from=="function")return e.Buffer.from(String(t),"base64").toString("utf8");throw new Error("Base64 decode not supported in this environment")}getRandomInt(t,e){return t=Math.ceil(t),e=Math.floor(e),Math.floor(Math.random()*(e-t+1))+t}getParam(t,e,s=0){return t?._params?.[e]??s}createDefaultScheduler(t){const e=globalThis;if(typeof e.requestAnimationFrame=="function")return n=>e.requestAnimationFrame(n);const s=typeof t=="number"&&isFinite(t)&&t>0?t:60;if(typeof e.setImmediate=="function"&&(!t||t>=60))return n=>e.setImmediate(n);const i=Math.max(1,Math.round(1e3/s));return n=>e.setTimeout(n,i)}}const f=new x;class N{#t=0;#e=0;#s=0;#i;#n;constructor(t=.05,e=1){const s=Number(t);this.#i=Number.isFinite(s)?Math.min(1,Math.max(.001,s)):.05;const i=Number(e);this.#n=Number.isFinite(i)?Math.max(0,Math.floor(i)):1}now(){const t=globalThis.performance;return t&&typeof t.now=="function"?t.now():Date.now()}calc(){const t=this.now();if(this.#s===0)return this.#s=t,this.#t;const e=t-this.#s;if(this.#s=t,!Number.isFinite(e)||e<=0)return this.#t;this.#e===0?this.#e=e:this.#e=(1-this.#i)*this.#e+this.#i*e;const s=1e3/this.#e;if(!Number.isFinite(s)||s<=0)return this.#t;const i=Math.round(s);return this.#t!==0&&this.#n>0&&Math.abs(i-this.#t)<this.#n?this.#t:(this.#t=i,this.#t)}reset(){this.#t=0,this.#e=0,this.#s=0}}class E{constructor(t){this._enabled=!0,this._show_date=!1,this._show_time=!0,this._debug=!1,t&&this.configure(t)}configure(t){typeof t._enabled=="boolean"&&(this._enabled=t._enabled),typeof t._show_date=="boolean"&&(this._show_date=t._show_date),typeof t._show_time=="boolean"&&(this._show_time=t._show_time),typeof t._debug=="boolean"&&(this._debug=t._debug)}_dt(){const t=new Date,e=this._show_date?`${t.getDate()}.${t.getMonth()}.${t.getFullYear()} `:"",s=this._show_time?`${t.getHours()}:${t.getMinutes()}:${t.getSeconds()}.${t.getMilliseconds()}|`:"";return e+s}log(t,...e){this._enabled&&console.log(this._dt(),t,...e)}warn(t,...e){this._enabled&&console.warn(this._dt(),t,...e)}error(t,...e){this._enabled&&console.error(this._dt(),t,...e)}debug(t,...e){!this._enabled||!this._debug||console.debug(this._dt(),t,...e)}}const c=new E,D=typeof process<"u"&&!!process?.env&&process.env.NODE_ENV==="production";D||console.info("[Xpell] _xlog is redirected to console in development mode. Tip: enable 'Show timestamps' in DevTools → Console for timed logs.");const w=D?c:console;class k{constructor(){this._objects={},this._listeners=new Map,this._any_listeners=new Set,this._compat_writes=!0,this._warn_legacy_writes=!0,this._verbose=!1,this._compat_legacy_keys=!0,this._o_proxy=null,this._objects={}}get _o(){return!this._compat_writes&&!this._warn_legacy_writes?this._objects:(this._o_proxy||(this._o_proxy=new Proxy(this._objects,{set:(t,e,s)=>{const i=String(e);return this._warn_legacy_writes&&console.warn(`[XData] Legacy write: _o["${i}"] = ... ; prefer XData.set("${i}", value).`),this._compat_writes?this.set(i,s,{source:"legacy:_o"}):t[i]=s,!0},deleteProperty:(t,e)=>{const s=String(e);return this._warn_legacy_writes&&console.warn(`[XData] Legacy delete: delete _o["${s}"] ; prefer XData.delete("${s}").`),this._compat_writes?this.delete(s,{source:"legacy:_o"}):delete t[s],!0}})),this._o_proxy)}get(t){return this._objects[t]}set(t,e,s){const i=this._objects[t];this._objects[t]=e,this._emit({key:t,value:e,prev:i,ts:Date.now(),op:"set",meta:s})}patch(t,e,s){const i=this._objects[t],r={...i&&typeof i=="object"?i:{},...e};this._objects[t]=r,this._emit({key:t,value:r,prev:i,ts:Date.now(),op:"patch",meta:s})}touch(t,e){const s=this._objects[t];this._emit({key:t,value:s,prev:s,ts:Date.now(),op:"touch",meta:e})}has(t){return Object.prototype.hasOwnProperty.call(this._objects,t)}delete(t,e){const s=this._objects[t];delete this._objects[t],this._emit({key:t,value:void 0,prev:s,ts:Date.now(),op:"delete",meta:e})}pick(t,e){const s=this._objects[t];return this.delete(t,e),s}clean(){this._objects={}}on(t,e){let s=this._listeners.get(t);return s||this._listeners.set(t,s=new Set),s.add(e),()=>this.off(t,e)}off(t,e){const s=this._listeners.get(t);s&&(s.delete(e),s.size===0&&this._listeners.delete(t))}onAny(t){return this._any_listeners.add(t),()=>this._any_listeners.delete(t)}_emit(t){this._verbose&&t.meta?.trace&&(t.stack=new Error().stack);const e=this._listeners.get(t.key);if(e)for(const s of e)s(t);for(const s of this._any_listeners)s(t)}}const u=new k;class F{constructor(t){t&&Object.keys(t).forEach(e=>{this[e]=t[e]}),this.d||(this.d=Date.now())}getParam(t,e,s){return this._params?.hasOwnProperty(e)?this._params[e]:this._params?.hasOwnProperty(t)?this._params[t]:s}}const v={type:"_type",children:"_children"},p=class p{static addHtml2XpellMapItem(t,e){p.html2XMap.elements[t]=e}static parse(t,e){const s=t.split(" ");let i=new F;if(e?(i._module=e,i._op=s[0]):(i._module=s[0],i._op=s[1]),i._params={},s.length>1)for(let n=2;n<s.length;++n){const r=s[n];if(r.indexOf(":")>-1){const _=r.split(":");i._params[_[0]]=_[1]}else i._params[n-1]=s[n]}return i}static replaceSpacesInQuotes(t,e="_%20_"){return t.replace(/(['"])(.*?)\1/g,(s,i,n)=>{const r=String(n).replace(/\s/g,e);return`${i}${r}${i}`})}static parseObjectCommand(t,e){t=p.replaceSpacesInQuotes(t);const s=t.trim().split(/\s+/),i=e||s.shift();if(!i)throw new Error("Missing module name");let n;if(s[0]?.startsWith("#")&&(n=s.shift().slice(1),!n))throw new Error("Invalid object selector '#'. Use '#<id>'");const r=s.shift();if(!r)throw new Error("Missing operation");const a={};let _=null,h=null;if(s.forEach(l=>{if(h){if(h+=` ${l}`,l.endsWith(h[0])){const b=h.slice(1,-1).replace(/_%20_/g," ");a[_]=b,h=null}return}if(l.startsWith('"')||l.startsWith("'")){if(h=l,l.endsWith(l[0])&&l.length>1){const b=l.slice(1,-1).replace(/_%20_/g," ");a[_]=b,h=null}return}if(l.includes(":")){const b=l.split(":"),$=b[0],R=b.slice(1).join(":").replace(/_%20_/g," ");a[$]=R,_=null;return}_=l.replace(/_%20_/g," ")}),h)throw new Error("Unclosed quoted parameter value");return{_module:i,_object:n,_op:r,_params:a}}static xmlString2Xpell(t){const s=new DOMParser().parseFromString(t,"text/xml");return s.childNodes.length>0?p.xml2Xpell(s.childNodes[0]):{}}static xml2Xpell(t,e){const s=p.html2XMap;let i={};i._children=[];const n=t.nodeName,r=t.nodeName;let a=e;if(e?(i[v.type]="xhtml",i._html_ns="http://www.w3.org/2000/svg"):i._type=s.elements[n]?s.elements[n]:n,t.attributes)for(let _=0;_<t.attributes.length;++_){const h=t.attributes[_],l=s.attributes[h.name]?s.attributes[h.name]:h.name;i[l]=h.value}if(t?.firstChild?.nodeValue&&(i.text=t?.firstChild.nodeValue.trim()),i[v.type]=="xhtml"?i._html_tag=r:i[v.type]=="svg"&&(a=!0,i._html_ns="http://www.w3.org/2000/svg"),t?.childNodes.length>0)for(let _=0;_<t.childNodes.length;++_){const h=t.childNodes[_];h.nodeName.startsWith("#")||i[v.children].push(p.xml2Xpell(h,a))}return i}};p.html2XMap={elements:{div:"view",a:"link",b:"xhtml",h1:"xhtml",h2:"xhtml",h3:"xhtml",h4:"xhtml",h5:"xhtml",p:"xhtml",small:"xhtml",aside:"xhtml",span:"xhtml",table:"xhtml",th:"xhtml",td:"xhtml",tr:"xhtml",thead:"xhtml",tbody:"xhtml",ul:"xhtml",li:"xhtml",ol:"xhtml",canvas:"xhtml",img:"image"},attributes:{id:"_id"}};let m=p;class M{constructor(){this._log_rules={register:!1,remove:!1,fire:!1},this._events={},this._listener_index={}}on(t,e,s={},i){this._events[t]||(this._events[t]=[]);const n=s?._owner??i,r=f.guid(),a={_id:r,_callback:e,_options:s,_owner:n,_tag:s?._tag};return this._events[t].push(a),this._listener_index[r]=t,this._log_rules.register&&w.log("XEM Register",t,r),r}once(t,e,s){return this.on(t,e,{_once:!0,_owner:s})}async fire(t,e){const s=this._events[t];if(!s||s.length===0)return;this._log_rules.fire&&w.log("XEM Fire",t,e);const i=s.slice(),n=[];for(const r of i){try{r&&r._callback&&r._callback(e)}catch(a){w.error(a)}r?._options?._once&&n.push(r._id)}for(const r of n)this.remove(r)}remove(t){const e=this._listener_index[t];if(!e)return;const s=this._events[e];if(s&&s.length){const i=s.findIndex(n=>n?._id===t);i>=0&&s.splice(i,1),s.length===0&&delete this._events[e]}delete this._listener_index[t],this._log_rules.remove&&w.log("XEM Remove",e,t)}removeOwner(t){if(!t)return;const e=[];for(const s of Object.values(this._events))for(const i of s)(i?._owner??i?._options?._owner)===t&&e.push(i._id);e.forEach(s=>this.remove(s))}clear(){this._events={},this._listener_index={}}}const g=new M;class S{#t;#e;#s;constructor(){this.#t={},this.#e={},this.#s={}}get _objects(){return this.#e}hasObject(t){return this.#e.hasOwnProperty(t)}registerObjects(t){Object.keys(t).forEach(s=>this.registerObject(s,t[s]))}registerObject(t,e){this.#t[t]=e}hasObjectClass(t){return this.#t.hasOwnProperty(t)}getObjectClass(t){return this.#t[t]}getAllClasses(){return this.#t}get _classes(){return this.#t}addObject(t){t&&t._id?(this.#e[t._id]=t,(!t._name||t._name.length==0)&&(t._name=t._id),this.#s[t._name]=t._id):c.log("unable to add object")}removeObject(t){const e=this.#e[t];e&&(delete this.#s[e?._name],delete this.#e[t])}getObject(t){return this.#e[t]}go(t){return this.getObject(t)}getObjectByName(t){return this.#s[t]?this.getObject(this.#s[t]):null}}const U={info:(o,t)=>{c.log("XObject id "+t?._id)},log:(o,t)=>{o._params&&o._params[1]?c.log(o._params[1]):c.log(t)},fire:(o,t)=>{o._params&&o._params[1]?g.fire(o._params[1],o._params[2]):o._params&&o._params.event&&g.fire(o._params.event,o._params.data)}},j={_children:"child nodes"};class y{constructor(t,e,s){this._children=[],this._parent=null,this._on={},this._once={},this._process_frame=!0,this._process_data=!0,this._nano_commands={},this._event_listeners_ids={},this._event_parsed=!1,this._mounted=!1,this._xporter={_ignore_fields:["_to_xdata_ignore_fields","_xporter","_children","_on","_once","_on_create","_on_mount","_on_frame","_on_data","_process_frame","_process_data","_parent","_event_listeners_ids","_event_parsed","_mounted","_debug"],_instance_xporters:{}},e&&f.mergeDefaultsWithData(t,e),this._id=t&&t._id?t._id:"xo-"+f.guid(),this._type="object",this._children=[],this._nano_commands={},this.addNanoCommandPack(U),t&&t.hasOwnProperty("_nano_commands")&&t._nano_commands&&(this.addNanoCommandPack(t._nano_commands),delete t._nano_commands),this.addXporterDataIgnoreFields(["_nano_commands"]),this.addXporterInstanceXporter(y,i=>i.toXData()),this._xem_options={},!s&&t&&this.parse(t,j)}log(t,...e){this._debug&&t&&c.log(this._type+"->"+this._id+"]",t,...e)}init(t,e){!e&&t&&this.parse(t,j)}parseEvents(t){if(!this._event_parsed){t||(t=this._xem_options),Object.keys(this._on).forEach(s=>{this.addEventListener(s,this._on[s],t)});const e={};Object.assign(e,t),e._once=!0,Object.keys(this._once).forEach(s=>{this.addEventListener(s,this._once[s],e)}),this._event_parsed=!0}}addEventListener(t,e,s){s||(s=this._xem_options);let i;if(typeof e=="function")i=async r=>{e(this,r)};else if(typeof e=="string")i=async r=>{const a=this._id+" "+e+" event-data='"+JSON.stringify(r).replace(/'/g,"\\'")+"'";await this.run(a)};else throw new Error("event handler must be a function");const n=g.on(t,i,s,this);this._event_listeners_ids[t]||(this._event_listeners_ids[t]=[]),this._event_listeners_ids[t].push(n)}removeEventListener(t){const e=this._event_listeners_ids[t];e&&e.length&&(e.forEach(s=>{g.remove(s)}),delete this._event_listeners_ids[t])}removeAllEventListeners(){Object.keys(this._event_listeners_ids).forEach(e=>this.removeEventListener(e))}append(t){this._children?.push(t),t._parent=this}addNanoCommand(t,e){typeof e=="function"&&(this._nano_commands[t]=e)}addNanoCommandPack(t){t&&Object.keys(t).forEach(e=>{this.addNanoCommand(e,t[e])})}addXporterDataIgnoreFields(t){this._xporter._ignore_fields=this._xporter._ignore_fields.concat(t)}addXporterInstanceXporter(t,e){const s=f.guid();this._xporter._instance_xporters[s]={cls:t,handler:e}}parse(t,e=j){Object.keys(t).forEach(i=>{!e.hasOwnProperty(i)&&t.hasOwnProperty(i)&&(this[i]=t[i])})}parseFieldsFromXDataObject(t,e){Object.keys(e).forEach(i=>{t.hasOwnProperty(i)?this[i]=t[i]:this[i]=e[i]})}parseFields(t,e,s){e.forEach(i=>{if(t.hasOwnProperty(i))this[i]=t[i];else if(s&&i.startsWith("_")){const n=i.substring(1);t.hasOwnProperty(n)&&(this[i]=t[n],this[n]=t[n])}})}async onCreate(){this._on_create?this.checkAndRunInternalFunction(this._on_create):this._on&&this._on.create?this.checkAndRunInternalFunction(this._on.create):this._once&&this._once.create&&this.checkAndRunInternalFunction(this._once.create)}async checkAndRunInternalFunction(t,...e){if(typeof t=="function")await t(this,...e);else if(typeof t=="string")if(e.length>0){const s=e[0],i=JSON.stringify(s).replace(/'/g,"\\'");await this.run(`${this._id} ${t} data:'${i}'`)}else await this.run(`${this._id} ${t}`)}async onMount(){if(!this._mounted){this.parseEvents(this._xem_options),this._process_data&&typeof this._data_source=="string"&&this._data_source.length>0&&this.bindDataSource(this._data_source,{initial:!0}),this._on_mount?await this.checkAndRunInternalFunction(this._on_mount):this._on&&this._on.mount?await this.checkAndRunInternalFunction(this._on.mount):this._once&&this._once.mount&&await this.checkAndRunInternalFunction(this._once.mount),this._mounted=!0;for(const t of this._children)t.onMount&&typeof t.onMount=="function"&&t.onMount()}}emptyDataSource(){const t=this._data_source;if(typeof t!="string"||t.length===0)return;const e=this._type??this.constructor.name,s=this._id??"no-id";u.delete(t,{source:`${e}#${s}.emptyDataSource`})}async onData(t){this._process_data&&(this._on_data?this.checkAndRunInternalFunction(this._on_data,t):this._on&&this._on.data?this.checkAndRunInternalFunction(this._on.data,t):this._once&&this._once.data&&this.checkAndRunInternalFunction(this._once.data,t))}async onFrame(t){this._process_frame&&(this._on_frame?this.checkAndRunInternalFunction(this._on_frame,t):this._on&&this._on.frame?this.checkAndRunInternalFunction(this._on.frame,t):this._once&&this._once.frame&&this.checkAndRunInternalFunction(this._once.frame,t));for(const e of this._children)e.onFrame&&typeof e.onFrame=="function"&&e.onFrame(t)}async run(t,e=!0){let s=this._cache_cmd_txt&&this._cache_cmd_txt==t?this._cache_jcmd:m.parseObjectCommand(t);e&&(this._cache_cmd_txt=t,this._cache_jcmd=s),await this.execute(s)}async execute(t){if(t._op&&this._nano_commands[t._op])try{await this._nano_commands[t._op](t,this)}catch(e){c.error(this._id+" has error with command name "+t._op+" "+e)}else c.error(this._id+" has no command name "+t._op)}toXData(){const t={};return Object.keys(this).forEach(e=>{if(!this._xporter._ignore_fields.includes(e)&&this.hasOwnProperty(e)&&this[e]!==void 0){const s=this[e];if(typeof s=="function")return;if(typeof s=="object"){const i=Object.keys(this._xporter._instance_xporters);let n=!0;i.forEach(r=>{this._xporter._instance_xporters[r],s instanceof this._xporter._instance_xporters[r].cls&&(t[e]=this._xporter._instance_xporters[r].handler(s),n=!1)}),n&&(t[e]=s)}else t[e]=s}}),t._children=[],this._children.length>0&&this._children.forEach(e=>{typeof e.toXData=="function"&&t._children?.push(e.toXData())}),t}toString(){return JSON.stringify(this.toXData())}clearAttributes(t){t.forEach(e=>{this.hasOwnProperty(e)&&(this[e]=null,delete this[e])})}bindDataSource(t,e){const s=e?.initial??!0,i=t??this._data_source;typeof i!="string"||i.length===0||this._process_data&&(this._xd_bound_key===i&&this._xd_unsub||(this.unbindDataSource(),this._data_source=i,this._xd_bound_key=i,this._type??this.constructor.name,this._id,this._xd_unsub=u.on(i,async n=>{await this.onData(n.value)}),s&&u.has(i)&&this.onData(u.get(i))))}unbindDataSource(){this._xd_unsub?.(),this._xd_unsub=void 0,this._xd_bound_key=void 0}async dispose(){if(this.unbindDataSource(),this._parent){const t=this._parent._children.indexOf(this);t>-1&&this._parent._children.splice(t,1)}this._process_data=!1,this._process_frame=!1,this.removeAllEventListeners(),this.clearAttributes(["_cache_cmd_txt","_cache_jcmd","_nano_commands","_event_listeners_ids","_parent","_on","_once","_xem_options","_xporter"]),this._children&&this._children.forEach(t=>{typeof t.dispose=="function"&&t.dispose()}),this._children=[]}removeChild(t,e=!1){if(e)t.dispose();else{const s=this._children.indexOf(t);s>-1&&this._children.splice(s,1),t._parent=null}}addChild(t){this.append(t)}}class L{static getObjects(){return{object:y}}}const B="engine:module:num-of-objects:";class C{constructor(t){this._log_rules={createObject:!1,removeObject:!1},this.#t=new S,this._name=t._name,this._id=f.guid()}#t;load(){c.log("Module "+this._name+" loaded")}create(t){let e;if(t.hasOwnProperty("_type"))if(this.#t.hasObjectClass(t._type)){let s=this.#t.getObjectClass(t._type);s.hasOwnProperty("defaults")&&f.mergeDefaultsWithData(t,s.defaults),e=new s(t)}else throw"Xpell object '"+t._type+"' not found";else e=new y(t);return this.#t.addObject(e),t._children&&t._children.forEach(s=>{const i=this.create(s);e.append(i)}),e.onCreate(),e}remove(t){const e=this.#t.getObject(t);if(!e)return;const s=[],i=n=>{n?._id&&(s.push(n._id),(n._children??[]).forEach(r=>i(r)))};i(e),typeof e.dispose=="function"&&e.dispose(),s.reverse().forEach(n=>this.#t.removeObject(n))}_info(t){c.log("module info")}async run(t){if(t){let e=t.trim();e.startsWith(this._name)||(e=this._name+" "+e);let s=m.parse(e);return await this.execute(s)}else throw"Unable to parse Xpell Command"}async execute(t){if(!t||!t._op)throw new Error(`Invalid XCommand: missing _op (module: ${this._name})`);const e=t._object;if(e){const n=this.#t.getObject(e);if(!n)throw new Error(`Module '${this._name}' cant find object id: ${e}`);return await n.execute(t)}const s="_"+t._op.replaceAll("-","_"),i=this[s];if(typeof i=="function")return await i.call(this,t);throw new Error(`Module '${this._name}' cant find op: ${t._op}`)}async onFrame(t){const e=this.#t._objects,s=Object.keys(e);s.forEach(i=>{const n=e[i];n&&n.onFrame&&typeof n.onFrame=="function"&&n?.onFrame(t)}),u.set(B+this._id,s.length,{source:"xmodule"})}get om(){return this.#t}get _object_manager(){return this.#t}getObject(t){return this.#t.getObject(t)}get _o(){return this.#t._objects}importObjectPack(t){this.#t.registerObjects(t.getObjects())}importObjects(t){this.importObjectPack(t)}importObject(t,e){this.#t.registerObject(t,e)}async _help(t){const e=t?._params?._op??t?._params?._command??"";return this.help(e)}help(t){return{module:this._name,usage:`${this._name} help`,ops:["help"],note:"No help() implemented for this module."}}}class T{static get(t,e,s){if(!t?._params)return s;const i=t._params[e];return i!==void 0?i:s}static has(t,e){return t?._params&&t._params[e]!==void 0}static str(t,...e){for(const s of e){const i=t?._params?.[s];if(i!=null)return String(i)}}static bool(t,e,s=!1){const i=this.get(t,e,s);if(typeof i=="boolean")return i;if(typeof i=="number")return i!==0;if(typeof i=="string"){const n=i.toLowerCase();if(["1","true","yes","on"].includes(n))return!0;if(["0","false","no","off"].includes(n))return!1}return!!i}static int(t,e,s=0){const i=this.get(t,e,s),n=parseInt(String(i),10);return Number.isFinite(n)?n:s}static json(t,e,s){const i=this.get(t,e,s);if(i==null)return s;if(typeof i=="object")return i;if(typeof i=="string")try{return JSON.parse(i)}catch{return s}return s}}class O extends Error{constructor(t,e,s){super(e),this.name="XError",this._code=t,this._level=s?._level??"error",this._meta=s?._meta,this._cause=s?._cause}toXData(){return{_code:this._code,_level:this._level,_meta:this._meta,_cause:this._cause,name:this.name,message:this.message}}toJSON(){return{...this.toXData(),stack:this.stack}}}class d{constructor(t){this._ok=!1,this._ts=Date.now(),this._pt=0,t&&this.setXData(t)}static create(t){return new d(t)}static ok(t){return new d({_ok:!0,_result:t})}static error(t){if(t instanceof O)return new d({_ok:!1,_result:t.toXData()});const e=new O("E_INTERNAL",t?.message??String(t),{_cause:t});return new d({_ok:!1,_result:e.toXData()})}stopProcessTimeCounter(){this._pt=Date.now()-this._ts}toXData(){return this.stopProcessTimeCounter(),{_ok:this._ok,_ts:this._ts,_pt:this._pt,_result:this._result}}toString(){return JSON.stringify(this.toXData())}setXData(t){t&&("_ok"in t&&(this._ok=!!t._ok),"_ts"in t&&typeof t._ts=="number"&&(this._ts=t._ts),"_pt"in t&&typeof t._pt=="number"&&(this._pt=t._pt),"_result"in t&&(this._result=t._result))}}class W extends d{constructor(t){super(d.error(t).toXData())}}class J extends d{constructor(t){super({_ok:!0,_result:t})}}const I="engine:frame-number",P="engine:fps";class A{constructor(t){this._log_rules={},this._modules={},this._schedule_frame=t?._schedule_frame??f.createDefaultScheduler(t?._target_fps),this._version="0.0.1",this._engine_id=f.guid(),this._frame_number=0,this._fps_calc=new N,this.parser=m,this._modules={},g.fire("xpell-init"),c._enabled=!1}set verbose(t){c._enabled=t}set _verbose(t){c._enabled=t}log(t,...e){c.log(t,...e)}async delay(t){return new Promise(e=>setTimeout(e,t))}loadModule(t){this._modules.hasOwnProperty(t._name)?c.log("Module "+t._name+" already loaded"):(this._modules[t._name]=t,t.load())}loadModules(...t){t.forEach(e=>this.loadModule(e))}info(){c.log(`Xpell information:
|
|
1
|
+
"use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});class k{createIgnoreList(e,t){if(!e)return t;const s=e.split(",").map(i=>i.trim()).filter(Boolean);for(const i of s)t[i]="";return t}guid(){const t=globalThis.crypto;if(t&&typeof t.randomUUID=="function")return t.randomUUID();if(t&&typeof t.getRandomValues=="function"){const r=new Uint8Array(16);t.getRandomValues(r),r[6]=r[6]&15|64,r[8]=r[8]&63|128;const c=Array.from(r,_=>_.toString(16).padStart(2,"0"));return c.slice(0,4).join("")+"-"+c.slice(4,6).join("")+"-"+c.slice(6,8).join("")+"-"+c.slice(8,10).join("")+"-"+c.slice(10,16).join("")}const s="0123456789abcdef".split(""),i=[];let n;i[8]=i[13]=i[18]=i[23]="-",i[14]="4";for(let r=0;r<36;r++)i[r]||(n=(0|Math.random()*16)>>>0,i[r]=s[r===19?n&3|8:n&15]);return i.join("")}mergeDefaultsWithData(e,t,s=!1){if(!e)return t;e._id||(e._id=e.id??this.guid());for(const i of Object.keys(t))(!(i in e)||s)&&(e[i]=t[i]);return e}encode(e){const t=globalThis;if(typeof t.btoa=="function"){const s=encodeURIComponent(String(e)).replace(/%([0-9A-F]{2})/g,(i,n)=>String.fromCharCode(parseInt(n,16)));return t.btoa(s)}if(t.Buffer&&typeof t.Buffer.from=="function")return t.Buffer.from(String(e),"utf8").toString("base64");throw new Error("Base64 encode not supported in this environment")}decode(e){const t=globalThis;if(typeof t.atob=="function"){const s=t.atob(String(e)),i=Array.prototype.map.call(s,n=>"%"+n.charCodeAt(0).toString(16).padStart(2,"0")).join("");return decodeURIComponent(i)}if(t.Buffer&&typeof t.Buffer.from=="function")return t.Buffer.from(String(e),"base64").toString("utf8");throw new Error("Base64 decode not supported in this environment")}getRandomInt(e,t){return e=Math.ceil(e),t=Math.floor(t),Math.floor(Math.random()*(t-e+1))+e}getParam(e,t,s=0){return e?._params?.[t]??s}createDefaultScheduler(e){const t=globalThis;if(typeof t.requestAnimationFrame=="function")return n=>t.requestAnimationFrame(n);const s=typeof e=="number"&&isFinite(e)&&e>0?e:60;if(typeof t.setImmediate=="function"&&(!e||e>=60))return n=>t.setImmediate(n);const i=Math.max(1,Math.round(1e3/s));return n=>t.setTimeout(n,i)}}const f=new k;class L{#e=0;#t=0;#s=0;#i;#n;constructor(e=.05,t=1){const s=Number(e);this.#i=Number.isFinite(s)?Math.min(1,Math.max(.001,s)):.05;const i=Number(t);this.#n=Number.isFinite(i)?Math.max(0,Math.floor(i)):1}now(){const e=globalThis.performance;return e&&typeof e.now=="function"?e.now():Date.now()}calc(){const e=this.now();if(this.#s===0)return this.#s=e,this.#e;const t=e-this.#s;if(this.#s=e,!Number.isFinite(t)||t<=0)return this.#e;this.#t===0?this.#t=t:this.#t=(1-this.#i)*this.#t+this.#i*t;const s=1e3/this.#t;if(!Number.isFinite(s)||s<=0)return this.#e;const i=Math.round(s);return this.#e!==0&&this.#n>0&&Math.abs(i-this.#e)<this.#n?this.#e:(this.#e=i,this.#e)}reset(){this.#e=0,this.#t=0,this.#s=0}}class F{constructor(e){this._enabled=!0,this._show_date=!1,this._show_time=!0,this._debug=!1,e&&this.configure(e)}configure(e){typeof e._enabled=="boolean"&&(this._enabled=e._enabled),typeof e._show_date=="boolean"&&(this._show_date=e._show_date),typeof e._show_time=="boolean"&&(this._show_time=e._show_time),typeof e._debug=="boolean"&&(this._debug=e._debug)}_dt(){const e=new Date,t=this._show_date?`${e.getDate()}.${e.getMonth()}.${e.getFullYear()} `:"",s=this._show_time?`${e.getHours()}:${e.getMinutes()}:${e.getSeconds()}.${e.getMilliseconds()}|`:"";return t+s}log(e,...t){this._enabled&&console.log(this._dt(),e,...t)}warn(e,...t){this._enabled&&console.warn(this._dt(),e,...t)}error(e,...t){this._enabled&&console.error(this._dt(),e,...t)}debug(e,...t){!this._enabled||!this._debug||console.debug(this._dt(),e,...t)}}const a=new F,S=typeof process<"u"&&!!process?.env&&process.env.NODE_ENV==="production";S||console.info("[Xpell] _xlog is redirected to console in development mode. Tip: enable 'Show timestamps' in DevTools → Console for timed logs.");const w=S?a:console;class M{constructor(){this._objects={},this._listeners=new Map,this._any_listeners=new Set,this._compat_writes=!0,this._warn_legacy_writes=!0,this._verbose=!1,this._compat_legacy_keys=!0,this._o_proxy=null,this._objects={}}get _o(){return!this._compat_writes&&!this._warn_legacy_writes?this._objects:(this._o_proxy||(this._o_proxy=new Proxy(this._objects,{set:(e,t,s)=>{const i=String(t);return this._warn_legacy_writes&&console.warn(`[XData] Legacy write: _o["${i}"] = ... ; prefer XData.set("${i}", value).`),this._compat_writes?this.set(i,s,{source:"legacy:_o"}):e[i]=s,!0},deleteProperty:(e,t)=>{const s=String(t);return this._warn_legacy_writes&&console.warn(`[XData] Legacy delete: delete _o["${s}"] ; prefer XData.delete("${s}").`),this._compat_writes?this.delete(s,{source:"legacy:_o"}):delete e[s],!0}})),this._o_proxy)}get(e){return this._objects[e]}set(e,t,s){const i=this._objects[e];this._objects[e]=t,this._emit({key:e,value:t,prev:i,ts:Date.now(),op:"set",meta:s})}patch(e,t,s){const i=this._objects[e],r={...i&&typeof i=="object"?i:{},...t};this._objects[e]=r,this._emit({key:e,value:r,prev:i,ts:Date.now(),op:"patch",meta:s})}touch(e,t){const s=this._objects[e];this._emit({key:e,value:s,prev:s,ts:Date.now(),op:"touch",meta:t})}has(e){return Object.prototype.hasOwnProperty.call(this._objects,e)}delete(e,t){const s=this._objects[e];delete this._objects[e],this._emit({key:e,value:void 0,prev:s,ts:Date.now(),op:"delete",meta:t})}pick(e,t){const s=this._objects[e];return this.delete(e,t),s}clean(){this._objects={}}on(e,t){let s=this._listeners.get(e);return s||this._listeners.set(e,s=new Set),s.add(t),()=>this.off(e,t)}off(e,t){const s=this._listeners.get(e);s&&(s.delete(t),s.size===0&&this._listeners.delete(e))}onAny(e){return this._any_listeners.add(e),()=>this._any_listeners.delete(e)}_emit(e){this._verbose&&e.meta?.trace&&(e.stack=new Error().stack);const t=this._listeners.get(e.key);if(t)for(const s of t)s(e);for(const s of this._any_listeners)s(e)}}const u=new M,P=u;class X{constructor(e){e&&Object.keys(e).forEach(t=>{this[t]=e[t]}),this.d||(this.d=Date.now())}getParam(e,t,s){return this._params?.hasOwnProperty(t)?this._params[t]:this._params?.hasOwnProperty(e)?this._params[e]:s}}const v={type:"_type",children:"_children"},p=class p{static addHtml2XpellMapItem(e,t){p.html2XMap.elements[e]=t}static parse(e,t){const s=e.split(" ");let i=new X;if(t?(i._module=t,i._op=s[0]):(i._module=s[0],i._op=s[1]),i._params={},s.length>1)for(let n=2;n<s.length;++n){const r=s[n];if(r.indexOf(":")>-1){const _=r.split(":");i._params[_[0]]=_[1]}else i._params[n-1]=s[n]}return i}static replaceSpacesInQuotes(e,t="_%20_"){return e.replace(/(['"])(.*?)\1/g,(s,i,n)=>{const r=String(n).replace(/\s/g,t);return`${i}${r}${i}`})}static parseObjectCommand(e,t){e=p.replaceSpacesInQuotes(e);const s=e.trim().split(/\s+/),i=t||s.shift();if(!i)throw new Error("Missing module name");let n;if(s[0]?.startsWith("#")&&(n=s.shift().slice(1),!n))throw new Error("Invalid object selector '#'. Use '#<id>'");const r=s.shift();if(!r)throw new Error("Missing operation");const c={};let _=null,h=null;if(s.forEach(l=>{if(h){if(h+=` ${l}`,l.endsWith(h[0])){const b=h.slice(1,-1).replace(/_%20_/g," ");c[_]=b,h=null}return}if(l.startsWith('"')||l.startsWith("'")){if(h=l,l.endsWith(l[0])&&l.length>1){const b=l.slice(1,-1).replace(/_%20_/g," ");c[_]=b,h=null}return}if(l.includes(":")){const b=l.split(":"),U=b[0],C=b.slice(1).join(":").replace(/_%20_/g," ");c[U]=C,_=null;return}_=l.replace(/_%20_/g," ")}),h)throw new Error("Unclosed quoted parameter value");return{_module:i,_object:n,_op:r,_params:c}}static xmlString2Xpell(e){const s=new DOMParser().parseFromString(e,"text/xml");return s.childNodes.length>0?p.xml2Xpell(s.childNodes[0]):{}}static xml2Xpell(e,t){const s=p.html2XMap;let i={};i._children=[];const n=e.nodeName,r=e.nodeName;let c=t;if(t?(i[v.type]="xhtml",i._html_ns="http://www.w3.org/2000/svg"):i._type=s.elements[n]?s.elements[n]:n,e.attributes)for(let _=0;_<e.attributes.length;++_){const h=e.attributes[_],l=s.attributes[h.name]?s.attributes[h.name]:h.name;i[l]=h.value}if(e?.firstChild?.nodeValue&&(i.text=e?.firstChild.nodeValue.trim()),i[v.type]=="xhtml"?i._html_tag=r:i[v.type]=="svg"&&(c=!0,i._html_ns="http://www.w3.org/2000/svg"),e?.childNodes.length>0)for(let _=0;_<e.childNodes.length;++_){const h=e.childNodes[_];h.nodeName.startsWith("#")||i[v.children].push(p.xml2Xpell(h,c))}return i}};p.html2XMap={elements:{div:"view",a:"link",b:"xhtml",h1:"xhtml",h2:"xhtml",h3:"xhtml",h4:"xhtml",h5:"xhtml",p:"xhtml",small:"xhtml",aside:"xhtml",span:"xhtml",table:"xhtml",th:"xhtml",td:"xhtml",tr:"xhtml",thead:"xhtml",tbody:"xhtml",ul:"xhtml",li:"xhtml",ol:"xhtml",canvas:"xhtml",img:"image"},attributes:{id:"_id"}};let m=p;class I{constructor(){this._log_rules={register:!1,remove:!1,fire:!1},this._events={},this._listener_index={}}on(e,t,s={},i){this._events[e]||(this._events[e]=[]);const n=s?._owner??i,r=f.guid(),c={_id:r,_callback:t,_options:s,_owner:n,_tag:s?._tag};return this._events[e].push(c),this._listener_index[r]=e,this._log_rules.register&&w.log("XEM Register",e,r),r}once(e,t,s){return this.on(e,t,{_once:!0,_owner:s})}async fire(e,t){const s=this._events[e];if(!s||s.length===0)return;this._log_rules.fire&&w.log("XEM Fire",e,t);const i=s.slice(),n=[];for(const r of i){try{r&&r._callback&&r._callback(t)}catch(c){w.error(c)}r?._options?._once&&n.push(r._id)}for(const r of n)this.remove(r)}remove(e){const t=this._listener_index[e];if(!t)return;const s=this._events[t];if(s&&s.length){const i=s.findIndex(n=>n?._id===e);i>=0&&s.splice(i,1),s.length===0&&delete this._events[t]}delete this._listener_index[e],this._log_rules.remove&&w.log("XEM Remove",t,e)}removeOwner(e){if(!e)return;const t=[];for(const s of Object.values(this._events))for(const i of s)(i?._owner??i?._options?._owner)===e&&t.push(i._id);t.forEach(s=>this.remove(s))}clear(){this._events={},this._listener_index={}}}const g=new I;class A{#e;#t;#s;constructor(){this.#e={},this.#t={},this.#s={}}get _objects(){return this.#t}hasObject(e){return this.#t.hasOwnProperty(e)}registerObjects(e){Object.keys(e).forEach(s=>this.registerObject(s,e[s]))}registerObject(e,t){this.#e[e]=t}hasObjectClass(e){return this.#e.hasOwnProperty(e)}getObjectClass(e){return this.#e[e]}getAllClasses(){return this.#e}get _classes(){return this.#e}addObject(e){e&&e._id?(this.#t[e._id]=e,(!e._name||e._name.length==0)&&(e._name=e._id),this.#s[e._name]=e._id):a.log("unable to add object")}removeObject(e){const t=this.#t[e];t&&(delete this.#s[t?._name],delete this.#t[e])}getObject(e){return this.#t[e]}go(e){return this.getObject(e)}getObjectByName(e){return this.#s[e]?this.getObject(this.#s[e]):null}}const T=["_nano_commands","_cache_cmd_txt","_cache_jcmd","_xporter","_event_listeners_ids","_parent","_children"];function j(o){return T.includes(o)}function x(o){if(!o||typeof o!="object"||Array.isArray(o))return!1;const e=Object.getPrototypeOf(o);return e===Object.prototype||e===null}const B={info:(o,e)=>{a.log("XObject id "+e?._id)},log:(o,e)=>{o._params&&o._params[1]?a.log(o._params[1]):a.log(e)},fire:(o,e)=>{o._params&&o._params[1]?g.fire(o._params[1],o._params[2]):o._params&&o._params.event&&g.fire(o._params.event,o._params.data)},noop:()=>{},"set-field":(o,e)=>{const t=o._params?.name,s=o._params?.value;if(!(!e||typeof t!="string"||t.length===0)){if(j(t)){a.error(`set-field denied for protected field: ${t}`);return}e[t]=s}},"delete-field":(o,e)=>{const t=o._params?.name;if(!(!e||typeof t!="string"||t.length===0)){if(j(t)){a.error(`delete-field denied for protected field: ${t}`);return}delete e[t]}},"toggle-field":(o,e)=>{const t=o._params?.name;if(!e||typeof t!="string"||t.length===0)return;if(j(t)){a.error(`toggle-field denied for protected field: ${t}`);return}const s=e[t];typeof s=="boolean"?e[t]=!s:s==null?e[t]=!0:e[t]=!1},merge:(o,e)=>{const t=o._params?.name,s=o._params?.value;if(!e||typeof t!="string"||t.length===0)return;if(j(t)){a.error(`merge denied for protected field: ${t}`);return}if(!x(s)){a.error("merge expects _params.value as a plain object");return}const i=e[t];x(i)||(e[t]={}),Object.assign(e[t],s)},"run-seq":async(o,e)=>{if(!e)return;const t=o._params?.seq;if(!Array.isArray(t)){a.error("run-seq expects _params.seq as an array");return}for(const s of t){if(typeof s=="string"){await e.run(`${e._id} ${s}`);continue}if(s&&typeof s=="object"&&s._op){const i=s._object;if(!(i==null||i==="this"||i===e._id)){a.error("run-seq rejected non-self _object target");return}const r={_op:s._op,_params:s._params?{...s._params}:void 0};await e.execute(r);continue}a.error("run-seq skipped invalid step; expected string or object with _op")}}},O={_children:"child nodes"};class y{constructor(e,t,s){this._children=[],this._parent=null,this._on={},this._once={},this._process_frame=!0,this._process_data=!0,this._nano_commands={},this._event_listeners_ids={},this._event_parsed=!1,this._mounted=!1,this._xporter={_ignore_fields:["_to_xdata_ignore_fields","_xporter","_children","_on","_once","_on_create","_on_mount","_on_frame","_on_data","_process_frame","_process_data","_parent","_event_listeners_ids","_event_parsed","_mounted","_debug"],_instance_xporters:{}},t&&f.mergeDefaultsWithData(e,t),this._id=e&&e._id?e._id:"xo-"+f.guid(),this._type="object",this._children=[],this._nano_commands={},this.addNanoCommandPack(B),e&&e.hasOwnProperty("_nano_commands")&&e._nano_commands&&(this.addNanoCommandPack(e._nano_commands),delete e._nano_commands),this.addXporterDataIgnoreFields(["_nano_commands"]),this.addXporterInstanceXporter(y,i=>i.toXData()),this._xem_options={},!s&&e&&this.parse(e,O)}log(e,...t){this._debug&&e&&a.log(this._type+"->"+this._id+"]",e,...t)}init(e,t){!t&&e&&this.parse(e,O)}parseEvents(e){if(!this._event_parsed){e||(e=this._xem_options),Object.keys(this._on).forEach(s=>{this.addEventListener(s,this._on[s],e)});const t={};Object.assign(t,e),t._once=!0,Object.keys(this._once).forEach(s=>{this.addEventListener(s,this._once[s],t)}),this._event_parsed=!0}}addEventListener(e,t,s){s||(s=this._xem_options);let i;if(typeof t=="function")i=async r=>{t(this,r)};else if(typeof t=="string")i=async r=>{const c=this._id+" "+t+" event-data='"+JSON.stringify(r).replace(/'/g,"\\'")+"'";await this.run(c)};else throw new Error("event handler must be a function");const n=g.on(e,i,s,this);this._event_listeners_ids[e]||(this._event_listeners_ids[e]=[]),this._event_listeners_ids[e].push(n)}removeEventListener(e){const t=this._event_listeners_ids[e];t&&t.length&&(t.forEach(s=>{g.remove(s)}),delete this._event_listeners_ids[e])}removeAllEventListeners(){Object.keys(this._event_listeners_ids).forEach(t=>this.removeEventListener(t))}append(e){this._children?.push(e),e._parent=this}addNanoCommand(e,t){typeof t=="function"&&(this._nano_commands[e]=t)}addNanoCommandPack(e){e&&Object.keys(e).forEach(t=>{this.addNanoCommand(t,e[t])})}addXporterDataIgnoreFields(e){this._xporter._ignore_fields=this._xporter._ignore_fields.concat(e)}addXporterInstanceXporter(e,t){const s=f.guid();this._xporter._instance_xporters[s]={cls:e,handler:t}}parse(e,t=O){Object.keys(e).forEach(i=>{!t.hasOwnProperty(i)&&e.hasOwnProperty(i)&&(this[i]=e[i])})}parseFieldsFromXDataObject(e,t){Object.keys(t).forEach(i=>{e.hasOwnProperty(i)?this[i]=e[i]:this[i]=t[i]})}parseFields(e,t,s){t.forEach(i=>{if(e.hasOwnProperty(i))this[i]=e[i];else if(s&&i.startsWith("_")){const n=i.substring(1);e.hasOwnProperty(n)&&(this[i]=e[n],this[n]=e[n])}})}async onCreate(){this._on_create?this.checkAndRunInternalFunction(this._on_create):this._on&&this._on.create?this.checkAndRunInternalFunction(this._on.create):this._once&&this._once.create&&this.checkAndRunInternalFunction(this._once.create)}async runCmd(e){const t=e instanceof X?e:new X(e);await this.execute(t)}async checkAndRunInternalFunction(e,...t){if(Array.isArray(e)){for(const s of e)await this.checkAndRunInternalFunction(s,...t);return}if(typeof e=="function"){await e(this,...t);return}if(typeof e=="string"){if(t.length>0){const s=t[0],i=JSON.stringify(s).replace(/'/g,"\\'");await this.run(`${this._id} ${e} data:'${i}'`)}else await this.run(`${this._id} ${e}`);return}if(e&&typeof e=="object"&&e._op){const s=e;if((s._object===void 0||s._object===null||s._object==="this"?this._id:s._object)!==this._id){a.error("XObject JSON handler target not supported in core-only patch; expected _object omitted/'this'/"+this._id);return}const n={_op:s._op,_params:s._params?{...s._params}:void 0};t.length>0&&(n._params||(n._params={}),Object.prototype.hasOwnProperty.call(n._params,"data")||(n._params.data=t[0])),this._debug&&a.log(this._type+"->"+this._id+"]","JSON handler executed locally",n),await this.execute(n);return}}async onMount(){if(!this._mounted){this.parseEvents(this._xem_options),this._process_data&&typeof this._data_source=="string"&&this._data_source.length>0&&this.bindDataSource(this._data_source,{initial:!0}),this._on_mount?await this.checkAndRunInternalFunction(this._on_mount):this._on&&this._on.mount?await this.checkAndRunInternalFunction(this._on.mount):this._once&&this._once.mount&&await this.checkAndRunInternalFunction(this._once.mount),this._mounted=!0;for(const e of this._children)e.onMount&&typeof e.onMount=="function"&&e.onMount()}}emptyDataSource(){const e=this._data_source;if(typeof e!="string"||e.length===0)return;const t=this._type??this.constructor.name,s=this._id??"no-id";u.delete(e,{source:`${t}#${s}.emptyDataSource`})}async onData(e){this._process_data&&(this._on_data?this.checkAndRunInternalFunction(this._on_data,e):this._on&&this._on.data?this.checkAndRunInternalFunction(this._on.data,e):this._once&&this._once.data&&this.checkAndRunInternalFunction(this._once.data,e))}async onFrame(e){this._process_frame&&(this._on_frame?this.checkAndRunInternalFunction(this._on_frame,e):this._on&&this._on.frame?this.checkAndRunInternalFunction(this._on.frame,e):this._once&&this._once.frame&&this.checkAndRunInternalFunction(this._once.frame,e));for(const t of this._children)t.onFrame&&typeof t.onFrame=="function"&&t.onFrame(e)}async run(e,t=!0){let s=this._cache_cmd_txt&&this._cache_cmd_txt==e?this._cache_jcmd:m.parseObjectCommand(e);t&&(this._cache_cmd_txt=e,this._cache_jcmd=s),await this.execute(s)}async execute(e){if(e._op&&this._nano_commands[e._op])try{await this._nano_commands[e._op](e,this)}catch(t){a.error(this._id+" has error with command name "+e._op+" "+t)}else a.error(this._id+" has no command name "+e._op)}toXData(){const e={};return Object.keys(this).forEach(t=>{if(!this._xporter._ignore_fields.includes(t)&&this.hasOwnProperty(t)&&this[t]!==void 0){const s=this[t];if(typeof s=="function")return;if(typeof s=="object"){const i=Object.keys(this._xporter._instance_xporters);let n=!0;i.forEach(r=>{this._xporter._instance_xporters[r],s instanceof this._xporter._instance_xporters[r].cls&&(e[t]=this._xporter._instance_xporters[r].handler(s),n=!1)}),n&&(e[t]=s)}else e[t]=s}}),e._children=[],this._children.length>0&&this._children.forEach(t=>{typeof t.toXData=="function"&&e._children?.push(t.toXData())}),e}toString(){return JSON.stringify(this.toXData())}clearAttributes(e){e.forEach(t=>{this.hasOwnProperty(t)&&(this[t]=null,delete this[t])})}bindDataSource(e,t){const s=t?.initial??!0,i=e??this._data_source;typeof i!="string"||i.length===0||this._process_data&&(this._xd_bound_key===i&&this._xd_unsub||(this.unbindDataSource(),this._data_source=i,this._xd_bound_key=i,this._type??this.constructor.name,this._id,this._xd_unsub=u.on(i,async n=>{await this.onData(n.value)}),s&&u.has(i)&&this.onData(u.get(i))))}unbindDataSource(){this._xd_unsub?.(),this._xd_unsub=void 0,this._xd_bound_key=void 0}async dispose(){if(this.unbindDataSource(),this._parent){const e=this._parent._children.indexOf(this);e>-1&&this._parent._children.splice(e,1)}this._process_data=!1,this._process_frame=!1,this.removeAllEventListeners(),this.clearAttributes(["_cache_cmd_txt","_cache_jcmd","_nano_commands","_event_listeners_ids","_parent","_on","_once","_xem_options","_xporter"]),this._children&&this._children.forEach(e=>{typeof e.dispose=="function"&&e.dispose()}),this._children=[]}removeChild(e,t=!1){if(t)e.dispose();else{const s=this._children.indexOf(e);s>-1&&this._children.splice(s,1),e._parent=null}}addChild(e){this.append(e)}}class W{static getObjects(){return{object:y}}}const q="engine:module:num-of-objects:";class J{constructor(e){this._log_rules={createObject:!1,removeObject:!1},this.#e=new A,this._name=e._name,this._id=f.guid()}#e;load(){a.log("Module "+this._name+" loaded")}create(e){let t;if(e.hasOwnProperty("_type"))if(this.#e.hasObjectClass(e._type)){let s=this.#e.getObjectClass(e._type);s.hasOwnProperty("defaults")&&f.mergeDefaultsWithData(e,s.defaults),t=new s(e)}else throw"Xpell object '"+e._type+"' not found";else t=new y(e);return this.#e.addObject(t),e._children&&e._children.forEach(s=>{const i=this.create(s);t.append(i)}),t.onCreate(),t}remove(e){const t=this.#e.getObject(e);if(!t)return;const s=[],i=n=>{n?._id&&(s.push(n._id),(n._children??[]).forEach(r=>i(r)))};i(t),typeof t.dispose=="function"&&t.dispose(),s.reverse().forEach(n=>this.#e.removeObject(n))}_info(e){a.log("module info")}async run(e){if(e){let t=e.trim();t.startsWith(this._name)||(t=this._name+" "+t);let s=m.parse(t);return await this.execute(s)}else throw"Unable to parse Xpell Command"}async execute(e){if(!e||!e._op)throw new Error(`Invalid XCommand: missing _op (module: ${this._name})`);const t=e._object;if(t){const n=this.#e.getObject(t);if(!n)throw new Error(`Module '${this._name}' cant find object id: ${t}`);return await n.execute(e)}const s="_"+e._op.replaceAll("-","_"),i=this[s];if(typeof i=="function")return await i.call(this,e);throw new Error(`Module '${this._name}' cant find op: ${e._op}`)}async onFrame(e){const t=this.#e._objects,s=Object.keys(t);s.forEach(i=>{const n=t[i];n&&n.onFrame&&typeof n.onFrame=="function"&&n?.onFrame(e)}),P.set(q+this._id,s.length,{source:"xmodule"})}get om(){return this.#e}get _object_manager(){return this.#e}getObject(e){return this.#e.getObject(e)}get _o(){return this.#e._objects}importObjectPack(e){this.#e.registerObjects(e.getObjects())}importObjects(e){this.importObjectPack(e)}importObject(e,t){this.#e.registerObject(e,t)}async _help(e){const t=e?._params?._op??e?._params?._command??"";return this.help(t)}help(e){return{module:this._name,usage:`${this._name} help`,ops:["help"],note:"No help() implemented for this module."}}}class V{static get(e,t,s){if(!e?._params)return s;const i=e._params[t];return i!==void 0?i:s}static has(e,t){return e?._params&&e._params[t]!==void 0}static str(e,...t){for(const s of t){const i=e?._params?.[s];if(i!=null)return String(i)}}static bool(e,t,s=!1){const i=this.get(e,t,s);if(typeof i=="boolean")return i;if(typeof i=="number")return i!==0;if(typeof i=="string"){const n=i.toLowerCase();if(["1","true","yes","on"].includes(n))return!0;if(["0","false","no","off"].includes(n))return!1}return!!i}static int(e,t,s=0){const i=this.get(e,t,s),n=parseInt(String(i),10);return Number.isFinite(n)?n:s}static json(e,t,s){const i=this.get(e,t,s);if(i==null)return s;if(typeof i=="object")return i;if(typeof i=="string")try{return JSON.parse(i)}catch{return s}return s}}class E extends Error{constructor(e,t,s){super(t),this.name="XError",this._code=e,this._level=s?._level??"error",this._meta=s?._meta,this._cause=s?._cause}toXData(){return{_code:this._code,_level:this._level,_meta:this._meta,_cause:this._cause,name:this.name,message:this.message}}toJSON(){return{...this.toXData(),stack:this.stack}}}class d{constructor(e){this._ok=!1,this._ts=Date.now(),this._pt=0,e&&this.setXData(e)}static create(e){return new d(e)}static ok(e){return new d({_ok:!0,_result:e})}static error(e){if(e instanceof E)return new d({_ok:!1,_result:e.toXData()});const t=new E("E_INTERNAL",e?.message??String(e),{_cause:e});return new d({_ok:!1,_result:t.toXData()})}stopProcessTimeCounter(){this._pt=Date.now()-this._ts}toXData(){return this.stopProcessTimeCounter(),{_ok:this._ok,_ts:this._ts,_pt:this._pt,_result:this._result}}toString(){return JSON.stringify(this.toXData())}setXData(e){e&&("_ok"in e&&(this._ok=!!e._ok),"_ts"in e&&typeof e._ts=="number"&&(this._ts=e._ts),"_pt"in e&&typeof e._pt=="number"&&(this._pt=e._pt),"_result"in e&&(this._result=e._result))}}class H extends d{constructor(e){super(d.error(e).toXData())}}class K extends d{constructor(e){super({_ok:!0,_result:e})}}const $="engine:frame-number",R="engine:fps";class N{constructor(e){this._log_rules={},this._modules={},this._schedule_frame=e?._schedule_frame??f.createDefaultScheduler(e?._target_fps),this._version="0.0.1",this._engine_id=f.guid(),this._frame_number=0,this._fps_calc=new L,this.parser=m,this._modules={},g.fire("xpell-init"),a._enabled=!1}set verbose(e){a._enabled=e}set _verbose(e){a._enabled=e}log(e,...t){a.log(e,...t)}async delay(e){return new Promise(t=>setTimeout(t,e))}loadModule(e){this._modules.hasOwnProperty(e._name)?a.log("Module "+e._name+" already loaded"):(this._modules[e._name]=e,e.load())}loadModules(...e){e.forEach(t=>this.loadModule(t))}info(){a.log(`Xpell information:
|
|
2
2
|
- Engine Id: `+this._engine_id+`
|
|
3
|
-
- Version `+this._version)}run(
|
|
3
|
+
- Version `+this._version)}run(e){if(e?.length>2){let t=m.parse(e);return this.execute(t)}else throw"Unable to parse Xpell command"}execute(e){if(e&&e._module&&this._modules[e._module])return this._modules[e._module].execute(e);throw"Xpell module "+e._module+" not loaded"}onFrame(){this._frame_number++;for(const t of Object.keys(this._modules)){const s=this._modules[t];s?.onFrame&&typeof s.onFrame=="function"&&s.onFrame(this._frame_number)}const e=this._fps_calc.calc();u.set($,this._frame_number,{source:"engine"}),u.set(R,e,{source:"engine"}),u._compat_legacy_keys&&(u.set("frame-number",this._frame_number,{source:"engine:legacy"}),u.set("fps",e,{source:"engine:legacy"})),this._schedule_frame(()=>this.onFrame())}getModule(e){return this._modules[e]}start(){a.log("Starting Xpell"),this.onFrame()}getParam(e,t){return e in u._o?u._o[e]:t}}const D=new N;exports.XCommand=X;exports.XD_FPS=R;exports.XD_FRAME_NUMBER=$;exports.XData=u;exports.XError=E;exports.XEventManager=g;exports.XLogger=a;exports.XModule=J;exports.XObject=y;exports.XObjectManager=A;exports.XObjectPack=W;exports.XParams=V;exports.XParser=m;exports.XResponse=d;exports.XResponseError=H;exports.XResponseOK=K;exports.XUtils=f;exports.Xpell=D;exports.XpellEngine=N;exports._XData=M;exports._XEventManager=I;exports._XLogger=F;exports._XUtils=k;exports._x=D;exports._xd=P;exports._xem=g;exports._xlog=a;exports._xu=f;exports.default=D;
|
package/dist/xpell-core.es.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
class
|
|
1
|
+
class S {
|
|
2
2
|
/**
|
|
3
3
|
* Create ignore list for parser to ignore spell words
|
|
4
4
|
* @param list - comma-separated list of words
|
|
@@ -25,8 +25,8 @@ class X {
|
|
|
25
25
|
if (e && typeof e.getRandomValues == "function") {
|
|
26
26
|
const r = new Uint8Array(16);
|
|
27
27
|
e.getRandomValues(r), r[6] = r[6] & 15 | 64, r[8] = r[8] & 63 | 128;
|
|
28
|
-
const
|
|
29
|
-
return
|
|
28
|
+
const c = Array.from(r, (_) => _.toString(16).padStart(2, "0"));
|
|
29
|
+
return c.slice(0, 4).join("") + "-" + c.slice(4, 6).join("") + "-" + c.slice(6, 8).join("") + "-" + c.slice(8, 10).join("") + "-" + c.slice(10, 16).join("");
|
|
30
30
|
}
|
|
31
31
|
const s = "0123456789abcdef".split(""), i = [];
|
|
32
32
|
let n;
|
|
@@ -106,8 +106,8 @@ class X {
|
|
|
106
106
|
return (n) => e.setTimeout(n, i);
|
|
107
107
|
}
|
|
108
108
|
}
|
|
109
|
-
const p = new
|
|
110
|
-
class
|
|
109
|
+
const p = new S();
|
|
110
|
+
class M {
|
|
111
111
|
#t = 0;
|
|
112
112
|
// displayed fps (stable)
|
|
113
113
|
#e = 0;
|
|
@@ -143,7 +143,7 @@ class k {
|
|
|
143
143
|
this.#t = 0, this.#e = 0, this.#s = 0;
|
|
144
144
|
}
|
|
145
145
|
}
|
|
146
|
-
class
|
|
146
|
+
class I {
|
|
147
147
|
constructor(t) {
|
|
148
148
|
this._enabled = !0, this._show_date = !1, this._show_time = !0, this._debug = !1, t && this.configure(t);
|
|
149
149
|
}
|
|
@@ -167,12 +167,12 @@ class F {
|
|
|
167
167
|
!this._enabled || !this._debug || console.debug(this._dt(), t, ...e);
|
|
168
168
|
}
|
|
169
169
|
}
|
|
170
|
-
const
|
|
171
|
-
|
|
170
|
+
const a = new I(), X = typeof process < "u" && !!process?.env && process.env.NODE_ENV === "production";
|
|
171
|
+
X || console.info(
|
|
172
172
|
"[Xpell] _xlog is redirected to console in development mode. Tip: enable 'Show timestamps' in DevTools → Console for timed logs."
|
|
173
173
|
);
|
|
174
|
-
const y =
|
|
175
|
-
class
|
|
174
|
+
const y = X ? a : console;
|
|
175
|
+
class A {
|
|
176
176
|
constructor() {
|
|
177
177
|
this._objects = {}, this._listeners = /* @__PURE__ */ new Map(), this._any_listeners = /* @__PURE__ */ new Set(), this._compat_writes = !0, this._warn_legacy_writes = !0, this._verbose = !1, this._compat_legacy_keys = !0, this._o_proxy = null, this._objects = {};
|
|
178
178
|
}
|
|
@@ -254,8 +254,8 @@ class S {
|
|
|
254
254
|
for (const s of this._any_listeners) s(t);
|
|
255
255
|
}
|
|
256
256
|
}
|
|
257
|
-
const u = new
|
|
258
|
-
class
|
|
257
|
+
const u = new A(), P = u;
|
|
258
|
+
class x {
|
|
259
259
|
constructor(t) {
|
|
260
260
|
t && Object.keys(t).forEach((e) => {
|
|
261
261
|
this[e] = t[e];
|
|
@@ -293,13 +293,13 @@ const w = {
|
|
|
293
293
|
*/
|
|
294
294
|
static parse(t, e) {
|
|
295
295
|
const s = t.split(" ");
|
|
296
|
-
let i = new
|
|
296
|
+
let i = new x();
|
|
297
297
|
if (e ? (i._module = e, i._op = s[0]) : (i._module = s[0], i._op = s[1]), i._params = {}, s.length > 1)
|
|
298
298
|
for (let n = 2; n < s.length; ++n) {
|
|
299
299
|
const r = s[n];
|
|
300
300
|
if (r.indexOf(":") > -1) {
|
|
301
|
-
const
|
|
302
|
-
i._params[
|
|
301
|
+
const _ = r.split(":");
|
|
302
|
+
i._params[_[0]] = _[1];
|
|
303
303
|
} else
|
|
304
304
|
i._params[n - 1] = s[n];
|
|
305
305
|
}
|
|
@@ -320,35 +320,35 @@ const w = {
|
|
|
320
320
|
throw new Error("Invalid object selector '#'. Use '#<id>'");
|
|
321
321
|
const r = s.shift();
|
|
322
322
|
if (!r) throw new Error("Missing operation");
|
|
323
|
-
const
|
|
324
|
-
let
|
|
323
|
+
const c = {};
|
|
324
|
+
let _ = null, h = null;
|
|
325
325
|
if (s.forEach((l) => {
|
|
326
326
|
if (h) {
|
|
327
327
|
if (h += ` ${l}`, l.endsWith(h[0])) {
|
|
328
328
|
const m = h.slice(1, -1).replace(/_%20_/g, " ");
|
|
329
|
-
|
|
329
|
+
c[_] = m, h = null;
|
|
330
330
|
}
|
|
331
331
|
return;
|
|
332
332
|
}
|
|
333
333
|
if (l.startsWith('"') || l.startsWith("'")) {
|
|
334
334
|
if (h = l, l.endsWith(l[0]) && l.length > 1) {
|
|
335
335
|
const m = l.slice(1, -1).replace(/_%20_/g, " ");
|
|
336
|
-
|
|
336
|
+
c[_] = m, h = null;
|
|
337
337
|
}
|
|
338
338
|
return;
|
|
339
339
|
}
|
|
340
340
|
if (l.includes(":")) {
|
|
341
|
-
const m = l.split(":"),
|
|
342
|
-
|
|
341
|
+
const m = l.split(":"), k = m[0], F = m.slice(1).join(":").replace(/_%20_/g, " ");
|
|
342
|
+
c[k] = F, _ = null;
|
|
343
343
|
return;
|
|
344
344
|
}
|
|
345
|
-
|
|
345
|
+
_ = l.replace(/_%20_/g, " ");
|
|
346
346
|
}), h) throw new Error("Unclosed quoted parameter value");
|
|
347
347
|
return {
|
|
348
348
|
_module: i,
|
|
349
349
|
_object: n,
|
|
350
350
|
_op: r,
|
|
351
|
-
_params:
|
|
351
|
+
_params: c
|
|
352
352
|
};
|
|
353
353
|
}
|
|
354
354
|
/**
|
|
@@ -371,16 +371,16 @@ const w = {
|
|
|
371
371
|
let i = {};
|
|
372
372
|
i._children = [];
|
|
373
373
|
const n = t.nodeName, r = t.nodeName;
|
|
374
|
-
let
|
|
374
|
+
let c = e;
|
|
375
375
|
if (e ? (i[w.type] = "xhtml", i._html_ns = "http://www.w3.org/2000/svg") : i._type = s.elements[n] ? s.elements[n] : n, t.attributes)
|
|
376
|
-
for (let
|
|
377
|
-
const h = t.attributes[
|
|
376
|
+
for (let _ = 0; _ < t.attributes.length; ++_) {
|
|
377
|
+
const h = t.attributes[_], l = s.attributes[h.name] ? s.attributes[h.name] : h.name;
|
|
378
378
|
i[l] = h.value;
|
|
379
379
|
}
|
|
380
|
-
if (t?.firstChild?.nodeValue && (i.text = t?.firstChild.nodeValue.trim()), i[w.type] == "xhtml" ? i._html_tag = r : i[w.type] == "svg" && (
|
|
381
|
-
for (let
|
|
382
|
-
const h = t.childNodes[
|
|
383
|
-
h.nodeName.startsWith("#") || i[w.children].push(f.xml2Xpell(h,
|
|
380
|
+
if (t?.firstChild?.nodeValue && (i.text = t?.firstChild.nodeValue.trim()), i[w.type] == "xhtml" ? i._html_tag = r : i[w.type] == "svg" && (c = !0, i._html_ns = "http://www.w3.org/2000/svg"), t?.childNodes.length > 0)
|
|
381
|
+
for (let _ = 0; _ < t.childNodes.length; ++_) {
|
|
382
|
+
const h = t.childNodes[_];
|
|
383
|
+
h.nodeName.startsWith("#") || i[w.children].push(f.xml2Xpell(h, c));
|
|
384
384
|
}
|
|
385
385
|
return i;
|
|
386
386
|
}
|
|
@@ -416,7 +416,7 @@ f.html2XMap = {
|
|
|
416
416
|
}
|
|
417
417
|
};
|
|
418
418
|
let g = f;
|
|
419
|
-
class
|
|
419
|
+
class $ {
|
|
420
420
|
constructor() {
|
|
421
421
|
this._log_rules = {
|
|
422
422
|
register: !1,
|
|
@@ -433,14 +433,14 @@ class I {
|
|
|
433
433
|
*/
|
|
434
434
|
on(t, e, s = {}, i) {
|
|
435
435
|
this._events[t] || (this._events[t] = []);
|
|
436
|
-
const n = s?._owner ?? i, r = p.guid(),
|
|
436
|
+
const n = s?._owner ?? i, r = p.guid(), c = {
|
|
437
437
|
_id: r,
|
|
438
438
|
_callback: e,
|
|
439
439
|
_options: s,
|
|
440
440
|
_owner: n,
|
|
441
441
|
_tag: s?._tag
|
|
442
442
|
};
|
|
443
|
-
return this._events[t].push(
|
|
443
|
+
return this._events[t].push(c), this._listener_index[r] = t, this._log_rules.register && y.log("XEM Register", t, r), r;
|
|
444
444
|
}
|
|
445
445
|
/**
|
|
446
446
|
* Register a listener that will be removed after first fire.
|
|
@@ -459,8 +459,8 @@ class I {
|
|
|
459
459
|
for (const r of i) {
|
|
460
460
|
try {
|
|
461
461
|
r && r._callback && r._callback(e);
|
|
462
|
-
} catch (
|
|
463
|
-
y.error(
|
|
462
|
+
} catch (c) {
|
|
463
|
+
y.error(c);
|
|
464
464
|
}
|
|
465
465
|
r?._options?._once && n.push(r._id);
|
|
466
466
|
}
|
|
@@ -497,8 +497,8 @@ class I {
|
|
|
497
497
|
this._events = {}, this._listener_index = {};
|
|
498
498
|
}
|
|
499
499
|
}
|
|
500
|
-
const b = new
|
|
501
|
-
class
|
|
500
|
+
const b = new $();
|
|
501
|
+
class R {
|
|
502
502
|
#t;
|
|
503
503
|
#e;
|
|
504
504
|
#s;
|
|
@@ -562,7 +562,7 @@ class P {
|
|
|
562
562
|
* @param xObject XObject to maintain
|
|
563
563
|
*/
|
|
564
564
|
addObject(t) {
|
|
565
|
-
t && t._id ? (this.#e[t._id] = t, (!t._name || t._name.length == 0) && (t._name = t._id), this.#s[t._name] = t._id) :
|
|
565
|
+
t && t._id ? (this.#e[t._id] = t, (!t._name || t._name.length == 0) && (t._name = t._id), this.#s[t._name] = t._id) : a.log("unable to add object");
|
|
566
566
|
}
|
|
567
567
|
/**
|
|
568
568
|
* Remove XObject from the manager
|
|
@@ -597,18 +597,115 @@ class P {
|
|
|
597
597
|
return this.#s[t] ? this.getObject(this.#s[t]) : null;
|
|
598
598
|
}
|
|
599
599
|
}
|
|
600
|
-
const
|
|
600
|
+
const N = [
|
|
601
|
+
"_nano_commands",
|
|
602
|
+
"_cache_cmd_txt",
|
|
603
|
+
"_cache_jcmd",
|
|
604
|
+
"_xporter",
|
|
605
|
+
"_event_listeners_ids",
|
|
606
|
+
"_parent",
|
|
607
|
+
"_children"
|
|
608
|
+
];
|
|
609
|
+
function v(o) {
|
|
610
|
+
return N.includes(o);
|
|
611
|
+
}
|
|
612
|
+
function D(o) {
|
|
613
|
+
if (!o || typeof o != "object" || Array.isArray(o)) return !1;
|
|
614
|
+
const t = Object.getPrototypeOf(o);
|
|
615
|
+
return t === Object.prototype || t === null;
|
|
616
|
+
}
|
|
617
|
+
const C = {
|
|
601
618
|
info: (o, t) => {
|
|
602
|
-
|
|
619
|
+
a.log("XObject id " + t?._id);
|
|
603
620
|
},
|
|
604
621
|
log: (o, t) => {
|
|
605
|
-
o._params && o._params[1] ?
|
|
622
|
+
o._params && o._params[1] ? a.log(o._params[1]) : a.log(t);
|
|
606
623
|
},
|
|
607
624
|
fire: (o, t) => {
|
|
608
625
|
o._params && o._params[1] ? b.fire(o._params[1], o._params[2]) : o._params && o._params.event && b.fire(o._params.event, o._params.data);
|
|
626
|
+
},
|
|
627
|
+
// no-op utility command for sequence placeholders and explicit "do nothing" steps.
|
|
628
|
+
noop: () => {
|
|
629
|
+
},
|
|
630
|
+
// set a runtime field directly on the object.
|
|
631
|
+
"set-field": (o, t) => {
|
|
632
|
+
const e = o._params?.name, s = o._params?.value;
|
|
633
|
+
if (!(!t || typeof e != "string" || e.length === 0)) {
|
|
634
|
+
if (v(e)) {
|
|
635
|
+
a.error(`set-field denied for protected field: ${e}`);
|
|
636
|
+
return;
|
|
637
|
+
}
|
|
638
|
+
t[e] = s;
|
|
639
|
+
}
|
|
640
|
+
},
|
|
641
|
+
// delete a runtime field from the object.
|
|
642
|
+
"delete-field": (o, t) => {
|
|
643
|
+
const e = o._params?.name;
|
|
644
|
+
if (!(!t || typeof e != "string" || e.length === 0)) {
|
|
645
|
+
if (v(e)) {
|
|
646
|
+
a.error(`delete-field denied for protected field: ${e}`);
|
|
647
|
+
return;
|
|
648
|
+
}
|
|
649
|
+
delete t[e];
|
|
650
|
+
}
|
|
651
|
+
},
|
|
652
|
+
// toggle a field with boolean-first semantics.
|
|
653
|
+
"toggle-field": (o, t) => {
|
|
654
|
+
const e = o._params?.name;
|
|
655
|
+
if (!t || typeof e != "string" || e.length === 0) return;
|
|
656
|
+
if (v(e)) {
|
|
657
|
+
a.error(`toggle-field denied for protected field: ${e}`);
|
|
658
|
+
return;
|
|
659
|
+
}
|
|
660
|
+
const s = t[e];
|
|
661
|
+
typeof s == "boolean" ? t[e] = !s : s == null ? t[e] = !0 : t[e] = !1;
|
|
662
|
+
},
|
|
663
|
+
// shallow-merge a plain object into a target object field.
|
|
664
|
+
merge: (o, t) => {
|
|
665
|
+
const e = o._params?.name, s = o._params?.value;
|
|
666
|
+
if (!t || typeof e != "string" || e.length === 0) return;
|
|
667
|
+
if (v(e)) {
|
|
668
|
+
a.error(`merge denied for protected field: ${e}`);
|
|
669
|
+
return;
|
|
670
|
+
}
|
|
671
|
+
if (!D(s)) {
|
|
672
|
+
a.error("merge expects _params.value as a plain object");
|
|
673
|
+
return;
|
|
674
|
+
}
|
|
675
|
+
const i = t[e];
|
|
676
|
+
D(i) || (t[e] = {}), Object.assign(t[e], s);
|
|
677
|
+
},
|
|
678
|
+
// run a sequence of steps in strict order (await each).
|
|
679
|
+
"run-seq": async (o, t) => {
|
|
680
|
+
if (!t) return;
|
|
681
|
+
const e = o._params?.seq;
|
|
682
|
+
if (!Array.isArray(e)) {
|
|
683
|
+
a.error("run-seq expects _params.seq as an array");
|
|
684
|
+
return;
|
|
685
|
+
}
|
|
686
|
+
for (const s of e) {
|
|
687
|
+
if (typeof s == "string") {
|
|
688
|
+
await t.run(`${t._id} ${s}`);
|
|
689
|
+
continue;
|
|
690
|
+
}
|
|
691
|
+
if (s && typeof s == "object" && s._op) {
|
|
692
|
+
const i = s._object;
|
|
693
|
+
if (!(i == null || i === "this" || i === t._id)) {
|
|
694
|
+
a.error("run-seq rejected non-self _object target");
|
|
695
|
+
return;
|
|
696
|
+
}
|
|
697
|
+
const r = {
|
|
698
|
+
_op: s._op,
|
|
699
|
+
_params: s._params ? { ...s._params } : void 0
|
|
700
|
+
};
|
|
701
|
+
await t.execute(r);
|
|
702
|
+
continue;
|
|
703
|
+
}
|
|
704
|
+
a.error("run-seq skipped invalid step; expected string or object with _op");
|
|
705
|
+
}
|
|
609
706
|
}
|
|
610
|
-
},
|
|
611
|
-
class
|
|
707
|
+
}, O = { _children: "child nodes" };
|
|
708
|
+
class j {
|
|
612
709
|
/**
|
|
613
710
|
* XObject constructor is creating the object and adding all the data keys to the XObject instance
|
|
614
711
|
* @param data constructor input data (object)
|
|
@@ -637,14 +734,14 @@ class v {
|
|
|
637
734
|
"_debug"
|
|
638
735
|
],
|
|
639
736
|
_instance_xporters: {}
|
|
640
|
-
}, e && p.mergeDefaultsWithData(t, e), this._id = t && t._id ? t._id : "xo-" + p.guid(), this._type = "object", this._children = [], this._nano_commands = {}, this.addNanoCommandPack(
|
|
737
|
+
}, e && p.mergeDefaultsWithData(t, e), this._id = t && t._id ? t._id : "xo-" + p.guid(), this._type = "object", this._children = [], this._nano_commands = {}, this.addNanoCommandPack(C), t && t.hasOwnProperty("_nano_commands") && t._nano_commands && (this.addNanoCommandPack(t._nano_commands), delete t._nano_commands), this.addXporterDataIgnoreFields(["_nano_commands"]), this.addXporterInstanceXporter(j, (i) => i.toXData()), this._xem_options = {
|
|
641
738
|
// _instance:_xem
|
|
642
739
|
// _object: this
|
|
643
740
|
// _support_html: true
|
|
644
|
-
}, !s && t && this.parse(t,
|
|
741
|
+
}, !s && t && this.parse(t, O);
|
|
645
742
|
}
|
|
646
743
|
log(t, ...e) {
|
|
647
|
-
this._debug && t &&
|
|
744
|
+
this._debug && t && a.log(this._type + "->" + this._id + "]", t, ...e);
|
|
648
745
|
}
|
|
649
746
|
/**
|
|
650
747
|
* Initialize the XObject
|
|
@@ -653,7 +750,7 @@ class v {
|
|
|
653
750
|
* @deprecated - use parse method instead
|
|
654
751
|
*/
|
|
655
752
|
init(t, e) {
|
|
656
|
-
!e && t && this.parse(t,
|
|
753
|
+
!e && t && this.parse(t, O);
|
|
657
754
|
}
|
|
658
755
|
parseEvents(t) {
|
|
659
756
|
if (!this._event_parsed) {
|
|
@@ -675,8 +772,8 @@ class v {
|
|
|
675
772
|
};
|
|
676
773
|
else if (typeof e == "string")
|
|
677
774
|
i = async (r) => {
|
|
678
|
-
const
|
|
679
|
-
await this.run(
|
|
775
|
+
const c = this._id + " " + e + " event-data='" + JSON.stringify(r).replace(/'/g, "\\'") + "'";
|
|
776
|
+
await this.run(c);
|
|
680
777
|
};
|
|
681
778
|
else
|
|
682
779
|
throw new Error("event handler must be a function");
|
|
@@ -735,7 +832,7 @@ class v {
|
|
|
735
832
|
* @param data data to parse
|
|
736
833
|
* @param ignore - lis of words to ignore in the parse process
|
|
737
834
|
*/
|
|
738
|
-
parse(t, e =
|
|
835
|
+
parse(t, e = O) {
|
|
739
836
|
Object.keys(t).forEach((i) => {
|
|
740
837
|
!e.hasOwnProperty(i) && t.hasOwnProperty(i) && (this[i] = t[i]);
|
|
741
838
|
});
|
|
@@ -784,15 +881,43 @@ class v {
|
|
|
784
881
|
async onCreate() {
|
|
785
882
|
this._on_create ? this.checkAndRunInternalFunction(this._on_create) : this._on && this._on.create ? this.checkAndRunInternalFunction(this._on.create) : this._once && this._once.create && this.checkAndRunInternalFunction(this._once.create);
|
|
786
883
|
}
|
|
884
|
+
async runCmd(t) {
|
|
885
|
+
const e = t instanceof x ? t : new x(t);
|
|
886
|
+
await this.execute(e);
|
|
887
|
+
}
|
|
787
888
|
async checkAndRunInternalFunction(t, ...e) {
|
|
788
|
-
if (
|
|
889
|
+
if (Array.isArray(t)) {
|
|
890
|
+
for (const s of t)
|
|
891
|
+
await this.checkAndRunInternalFunction(s, ...e);
|
|
892
|
+
return;
|
|
893
|
+
}
|
|
894
|
+
if (typeof t == "function") {
|
|
789
895
|
await t(this, ...e);
|
|
790
|
-
|
|
896
|
+
return;
|
|
897
|
+
}
|
|
898
|
+
if (typeof t == "string") {
|
|
791
899
|
if (e.length > 0) {
|
|
792
900
|
const s = e[0], i = JSON.stringify(s).replace(/'/g, "\\'");
|
|
793
901
|
await this.run(`${this._id} ${t} data:'${i}'`);
|
|
794
902
|
} else
|
|
795
903
|
await this.run(`${this._id} ${t}`);
|
|
904
|
+
return;
|
|
905
|
+
}
|
|
906
|
+
if (t && typeof t == "object" && t._op) {
|
|
907
|
+
const s = t;
|
|
908
|
+
if ((s._object === void 0 || s._object === null || s._object === "this" ? this._id : s._object) !== this._id) {
|
|
909
|
+
a.error(
|
|
910
|
+
"XObject JSON handler target not supported in core-only patch; expected _object omitted/'this'/" + this._id
|
|
911
|
+
);
|
|
912
|
+
return;
|
|
913
|
+
}
|
|
914
|
+
const n = {
|
|
915
|
+
_op: s._op,
|
|
916
|
+
_params: s._params ? { ...s._params } : void 0
|
|
917
|
+
};
|
|
918
|
+
e.length > 0 && (n._params || (n._params = {}), Object.prototype.hasOwnProperty.call(n._params, "data") || (n._params.data = e[0])), this._debug && a.log(this._type + "->" + this._id + "]", "JSON handler executed locally", n), await this.execute(n);
|
|
919
|
+
return;
|
|
920
|
+
}
|
|
796
921
|
}
|
|
797
922
|
/**
|
|
798
923
|
* Triggers when the object is being mounted to other element
|
|
@@ -874,10 +999,10 @@ class v {
|
|
|
874
999
|
try {
|
|
875
1000
|
await this._nano_commands[t._op](t, this);
|
|
876
1001
|
} catch (e) {
|
|
877
|
-
|
|
1002
|
+
a.error(this._id + " has error with command name " + t._op + " " + e);
|
|
878
1003
|
}
|
|
879
1004
|
else
|
|
880
|
-
|
|
1005
|
+
a.error(this._id + " has no command name " + t._op);
|
|
881
1006
|
}
|
|
882
1007
|
/**
|
|
883
1008
|
* Return an IXObjectData JSON representation of the XObject
|
|
@@ -957,29 +1082,29 @@ class v {
|
|
|
957
1082
|
this.append(t);
|
|
958
1083
|
}
|
|
959
1084
|
}
|
|
960
|
-
class
|
|
1085
|
+
class W {
|
|
961
1086
|
/**
|
|
962
1087
|
* Get all registered object in this ObjectPack
|
|
963
1088
|
* @returns XObject dictionary
|
|
964
1089
|
*/
|
|
965
1090
|
static getObjects() {
|
|
966
1091
|
return {
|
|
967
|
-
object:
|
|
1092
|
+
object: j
|
|
968
1093
|
};
|
|
969
1094
|
}
|
|
970
1095
|
}
|
|
971
|
-
const
|
|
972
|
-
class
|
|
1096
|
+
const T = "engine:module:num-of-objects:";
|
|
1097
|
+
class q {
|
|
973
1098
|
//engine: any; //deprecated remove after spell3d
|
|
974
1099
|
constructor(t) {
|
|
975
1100
|
this._log_rules = {
|
|
976
1101
|
createObject: !1,
|
|
977
1102
|
removeObject: !1
|
|
978
|
-
}, this.#t = new
|
|
1103
|
+
}, this.#t = new R(), this._name = t._name, this._id = p.guid();
|
|
979
1104
|
}
|
|
980
1105
|
#t;
|
|
981
1106
|
load() {
|
|
982
|
-
|
|
1107
|
+
a.log("Module " + this._name + " loaded");
|
|
983
1108
|
}
|
|
984
1109
|
/**
|
|
985
1110
|
* Creates new XObject from data object
|
|
@@ -995,7 +1120,7 @@ class C {
|
|
|
995
1120
|
} else
|
|
996
1121
|
throw "Xpell object '" + t._type + "' not found";
|
|
997
1122
|
else
|
|
998
|
-
e = new
|
|
1123
|
+
e = new j(t);
|
|
999
1124
|
return this.#t.addObject(e), t._children && t._children.forEach((s) => {
|
|
1000
1125
|
const i = this.create(s);
|
|
1001
1126
|
e.append(i);
|
|
@@ -1014,7 +1139,7 @@ class C {
|
|
|
1014
1139
|
i(e), typeof e.dispose == "function" && e.dispose(), s.reverse().forEach((n) => this.#t.removeObject(n));
|
|
1015
1140
|
}
|
|
1016
1141
|
_info(t) {
|
|
1017
|
-
|
|
1142
|
+
a.log("module info");
|
|
1018
1143
|
}
|
|
1019
1144
|
//xpell interpreter
|
|
1020
1145
|
/**
|
|
@@ -1063,7 +1188,7 @@ class C {
|
|
|
1063
1188
|
s.forEach((i) => {
|
|
1064
1189
|
const n = e[i];
|
|
1065
1190
|
n && n.onFrame && typeof n.onFrame == "function" && n?.onFrame(t);
|
|
1066
|
-
}),
|
|
1191
|
+
}), P.set(T + this._id, s.length, {
|
|
1067
1192
|
source: "xmodule"
|
|
1068
1193
|
});
|
|
1069
1194
|
}
|
|
@@ -1142,7 +1267,7 @@ class C {
|
|
|
1142
1267
|
};
|
|
1143
1268
|
}
|
|
1144
1269
|
}
|
|
1145
|
-
class
|
|
1270
|
+
class J {
|
|
1146
1271
|
/* -------------------------------------------------- */
|
|
1147
1272
|
/* core helpers */
|
|
1148
1273
|
/* -------------------------------------------------- */
|
|
@@ -1192,7 +1317,7 @@ class L {
|
|
|
1192
1317
|
return s;
|
|
1193
1318
|
}
|
|
1194
1319
|
}
|
|
1195
|
-
class
|
|
1320
|
+
class E extends Error {
|
|
1196
1321
|
constructor(t, e, s) {
|
|
1197
1322
|
super(e), this.name = "XError", this._code = t, this._level = s?._level ?? "error", this._meta = s?._meta, this._cause = s?._cause;
|
|
1198
1323
|
}
|
|
@@ -1229,12 +1354,12 @@ class d {
|
|
|
1229
1354
|
return new d({ _ok: !0, _result: t });
|
|
1230
1355
|
}
|
|
1231
1356
|
static error(t) {
|
|
1232
|
-
if (t instanceof
|
|
1357
|
+
if (t instanceof E)
|
|
1233
1358
|
return new d({
|
|
1234
1359
|
_ok: !1,
|
|
1235
1360
|
_result: t.toXData()
|
|
1236
1361
|
});
|
|
1237
|
-
const e = new
|
|
1362
|
+
const e = new E(
|
|
1238
1363
|
"E_INTERNAL",
|
|
1239
1364
|
t?.message ?? String(t),
|
|
1240
1365
|
{ _cause: t }
|
|
@@ -1272,33 +1397,33 @@ class d {
|
|
|
1272
1397
|
t && ("_ok" in t && (this._ok = !!t._ok), "_ts" in t && typeof t._ts == "number" && (this._ts = t._ts), "_pt" in t && typeof t._pt == "number" && (this._pt = t._pt), "_result" in t && (this._result = t._result));
|
|
1273
1398
|
}
|
|
1274
1399
|
}
|
|
1275
|
-
class
|
|
1400
|
+
class V extends d {
|
|
1276
1401
|
constructor(t) {
|
|
1277
1402
|
super(d.error(t).toXData());
|
|
1278
1403
|
}
|
|
1279
1404
|
}
|
|
1280
|
-
class
|
|
1405
|
+
class H extends d {
|
|
1281
1406
|
constructor(t) {
|
|
1282
1407
|
super({ _ok: !0, _result: t });
|
|
1283
1408
|
}
|
|
1284
1409
|
}
|
|
1285
|
-
const
|
|
1286
|
-
class
|
|
1410
|
+
const U = "engine:frame-number", B = "engine:fps";
|
|
1411
|
+
class L {
|
|
1287
1412
|
constructor(t) {
|
|
1288
|
-
this._log_rules = {}, this._modules = {}, this._schedule_frame = t?._schedule_frame ?? p.createDefaultScheduler(t?._target_fps), this._version = "0.0.1", this._engine_id = p.guid(), this._frame_number = 0, this._fps_calc = new
|
|
1413
|
+
this._log_rules = {}, this._modules = {}, this._schedule_frame = t?._schedule_frame ?? p.createDefaultScheduler(t?._target_fps), this._version = "0.0.1", this._engine_id = p.guid(), this._frame_number = 0, this._fps_calc = new M(), this.parser = g, this._modules = {}, b.fire("xpell-init"), a._enabled = !1;
|
|
1289
1414
|
}
|
|
1290
1415
|
/**
|
|
1291
1416
|
* @deprecated use _verbose instead
|
|
1292
1417
|
* Enable Xpell logs to console
|
|
1293
1418
|
*/
|
|
1294
1419
|
set verbose(t) {
|
|
1295
|
-
|
|
1420
|
+
a._enabled = t;
|
|
1296
1421
|
}
|
|
1297
1422
|
/**
|
|
1298
1423
|
* Enable Xpell logs to console
|
|
1299
1424
|
*/
|
|
1300
1425
|
set _verbose(t) {
|
|
1301
|
-
|
|
1426
|
+
a._enabled = t;
|
|
1302
1427
|
}
|
|
1303
1428
|
/**
|
|
1304
1429
|
* Logs message to console using Xpell logger
|
|
@@ -1308,7 +1433,7 @@ class U {
|
|
|
1308
1433
|
* @param optionalParams
|
|
1309
1434
|
*/
|
|
1310
1435
|
log(t, ...e) {
|
|
1311
|
-
|
|
1436
|
+
a.log(t, ...e);
|
|
1312
1437
|
}
|
|
1313
1438
|
/**
|
|
1314
1439
|
* Delay the execution of the next command
|
|
@@ -1323,7 +1448,7 @@ class U {
|
|
|
1323
1448
|
* @param {XModule} xModule
|
|
1324
1449
|
*/
|
|
1325
1450
|
loadModule(t) {
|
|
1326
|
-
this._modules.hasOwnProperty(t._name) ?
|
|
1451
|
+
this._modules.hasOwnProperty(t._name) ? a.log("Module " + t._name + " already loaded") : (this._modules[t._name] = t, t.load());
|
|
1327
1452
|
}
|
|
1328
1453
|
/**
|
|
1329
1454
|
* Loads multiple module at ones
|
|
@@ -1336,7 +1461,7 @@ class U {
|
|
|
1336
1461
|
* Display information about the Xpell engine to the console
|
|
1337
1462
|
*/
|
|
1338
1463
|
info() {
|
|
1339
|
-
|
|
1464
|
+
a.log(`Xpell information:
|
|
1340
1465
|
- Engine Id: ` + this._engine_id + `
|
|
1341
1466
|
- Version ` + this._version);
|
|
1342
1467
|
}
|
|
@@ -1371,7 +1496,7 @@ class U {
|
|
|
1371
1496
|
s?.onFrame && typeof s.onFrame == "function" && s.onFrame(this._frame_number);
|
|
1372
1497
|
}
|
|
1373
1498
|
const t = this._fps_calc.calc();
|
|
1374
|
-
u.set(
|
|
1499
|
+
u.set(U, this._frame_number, { source: "engine" }), u.set(B, t, { source: "engine" }), u._compat_legacy_keys && (u.set("frame-number", this._frame_number, { source: "engine:legacy" }), u.set("fps", t, { source: "engine:legacy" })), this._schedule_frame(() => this.onFrame());
|
|
1375
1500
|
}
|
|
1376
1501
|
/**
|
|
1377
1502
|
* Gets Xpell module by name
|
|
@@ -1385,7 +1510,7 @@ class U {
|
|
|
1385
1510
|
* Start Xpell engine for web browsers using requestAnimationFrame
|
|
1386
1511
|
*/
|
|
1387
1512
|
start() {
|
|
1388
|
-
|
|
1513
|
+
a.log("Starting Xpell"), this.onFrame();
|
|
1389
1514
|
}
|
|
1390
1515
|
/**
|
|
1391
1516
|
* deprecated - use XData._o directly
|
|
@@ -1394,35 +1519,35 @@ class U {
|
|
|
1394
1519
|
return t in u._o ? u._o[t] : e;
|
|
1395
1520
|
}
|
|
1396
1521
|
}
|
|
1397
|
-
const
|
|
1522
|
+
const Q = new L();
|
|
1398
1523
|
export {
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1524
|
+
x as XCommand,
|
|
1525
|
+
B as XD_FPS,
|
|
1526
|
+
U as XD_FRAME_NUMBER,
|
|
1402
1527
|
u as XData,
|
|
1403
|
-
|
|
1528
|
+
E as XError,
|
|
1404
1529
|
b as XEventManager,
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1530
|
+
a as XLogger,
|
|
1531
|
+
q as XModule,
|
|
1532
|
+
j as XObject,
|
|
1533
|
+
R as XObjectManager,
|
|
1534
|
+
W as XObjectPack,
|
|
1535
|
+
J as XParams,
|
|
1411
1536
|
g as XParser,
|
|
1412
1537
|
d as XResponse,
|
|
1413
|
-
|
|
1414
|
-
|
|
1538
|
+
V as XResponseError,
|
|
1539
|
+
H as XResponseOK,
|
|
1415
1540
|
p as XUtils,
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1541
|
+
Q as Xpell,
|
|
1542
|
+
L as XpellEngine,
|
|
1543
|
+
A as _XData,
|
|
1544
|
+
$ as _XEventManager,
|
|
1545
|
+
I as _XLogger,
|
|
1546
|
+
S as _XUtils,
|
|
1547
|
+
Q as _x,
|
|
1548
|
+
P as _xd,
|
|
1424
1549
|
b as _xem,
|
|
1425
|
-
|
|
1550
|
+
a as _xlog,
|
|
1426
1551
|
p as _xu,
|
|
1427
|
-
|
|
1552
|
+
Q as default
|
|
1428
1553
|
};
|
|
@@ -0,0 +1,457 @@
|
|
|
1
|
+
# Nano-Commands v2 (JSON + Sequences) — Xpell 2 Contract
|
|
2
|
+
|
|
3
|
+
This document is the **canonical contract** for how Xpell 2 executes *nano-commands* from:
|
|
4
|
+
- **DB-stored views**
|
|
5
|
+
- **agent edits**
|
|
6
|
+
- **schema-generated UI**
|
|
7
|
+
- **runtime events** (`_on_click`, `_on_data`, `_on_show`, …)
|
|
8
|
+
|
|
9
|
+
Goal: **data-only intent** instead of JS functions, while keeping execution **small, deterministic, and auditable**.
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## Why this matters
|
|
14
|
+
|
|
15
|
+
Historically, handlers were either:
|
|
16
|
+
- **Functions** (powerful, but not serializable / not DB-safe)
|
|
17
|
+
- **String nano-commands** (simple, but awkward for complex parameters)
|
|
18
|
+
|
|
19
|
+
Xpell 2 upgrades handlers with two capabilities:
|
|
20
|
+
|
|
21
|
+
1) **JSON Command Handlers** — structured `XCommandData` (pure data)
|
|
22
|
+
2) **Sequence Handlers** — arrays of handlers executed **in order** (awaited)
|
|
23
|
+
|
|
24
|
+
This enables **dynamic views** stored in XDB/files and real-time “vibe coding” without embedding code.
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## Handler formats (what you can put in object JSON)
|
|
29
|
+
|
|
30
|
+
A “handler” field (e.g. `_on_click`, `_on_show`, `_on_hide`, `_on_data`, `_on_mount`, `_on_frame`) can be:
|
|
31
|
+
|
|
32
|
+
### A) Function (dev-only)
|
|
33
|
+
Use only in developer-authored object packs.
|
|
34
|
+
|
|
35
|
+
```ts
|
|
36
|
+
_on_click: async (obj, e) => {
|
|
37
|
+
// custom code (NOT DB-safe)
|
|
38
|
+
}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### B) String nano-command (legacy / shorthand)
|
|
42
|
+
For simple actions.
|
|
43
|
+
|
|
44
|
+
```json
|
|
45
|
+
"_on_click": "hide"
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### C) JSON command (canonical)
|
|
49
|
+
For DB-stored, agent-editable views.
|
|
50
|
+
|
|
51
|
+
```json
|
|
52
|
+
"_on_click": { "_op": "hide" }
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Or with parameters:
|
|
56
|
+
|
|
57
|
+
```json
|
|
58
|
+
"_on_click": { "_op": "set-text", "_params": { "text": "ok" } }
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### D) Sequence (canonical composition)
|
|
62
|
+
Multi-step flows as data (no scripting language).
|
|
63
|
+
|
|
64
|
+
```json
|
|
65
|
+
"_on_click": [
|
|
66
|
+
{ "_op": "hide" },
|
|
67
|
+
{ "_op": "set-text", "_params": { "text": "Hidden" } },
|
|
68
|
+
{ "_op": "show" }
|
|
69
|
+
]
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
**Sequence semantics:**
|
|
73
|
+
- Execute **in order**
|
|
74
|
+
- Each item is **awaited**
|
|
75
|
+
- Default: **abort on thrown error** (consistent with your runtime error logging)
|
|
76
|
+
|
|
77
|
+
> If you need shared state between steps, use **XData** keys (recommended).
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
## JSON command format (XCommandData)
|
|
82
|
+
|
|
83
|
+
A JSON command is the canonical runtime intent shape:
|
|
84
|
+
|
|
85
|
+
```json
|
|
86
|
+
{
|
|
87
|
+
"_op": "set-text",
|
|
88
|
+
"_params": { "text": "hello" }
|
|
89
|
+
}
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Optional fields (tooling + future evolution):
|
|
93
|
+
|
|
94
|
+
```json
|
|
95
|
+
{
|
|
96
|
+
"_module": "xui",
|
|
97
|
+
"_object": "this",
|
|
98
|
+
"_op": "hide",
|
|
99
|
+
"_params": {}
|
|
100
|
+
}
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### Important runtime note (today)
|
|
104
|
+
In current Xpell 2 runtime, command resolution is **object-local**:
|
|
105
|
+
- `XObject.execute()` resolves `_op` against nano-command packs registered on the **target object**
|
|
106
|
+
- `_module` is treated as **semantic metadata** (helpful for tools/agents), not required for execution
|
|
107
|
+
|
|
108
|
+
### `_object` target rule
|
|
109
|
+
- If `_object` is omitted or `"this"`, the target is the **current object** (recommended for DB-stored handlers)
|
|
110
|
+
- Cross-object targeting may be constrained by policy; keep DB handlers **local by default**
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
|
|
114
|
+
## Payload injection (passing data/events into JSON handlers)
|
|
115
|
+
|
|
116
|
+
When a handler is invoked with a payload (e.g. `onData(data)` or click event `e`), the runtime may inject:
|
|
117
|
+
|
|
118
|
+
- `cmd._params.data = payload` **only if** `data` is not already provided.
|
|
119
|
+
|
|
120
|
+
This enables structured value passing without JSON-in-string escaping.
|
|
121
|
+
|
|
122
|
+
Example:
|
|
123
|
+
|
|
124
|
+
```json
|
|
125
|
+
"_on_data": { "_op": "set-text-from-data", "_params": { "pattern": "FPS: $data" } }
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
---
|
|
129
|
+
|
|
130
|
+
## Examples
|
|
131
|
+
|
|
132
|
+
### 1) XUIObject — simple click hide (string)
|
|
133
|
+
```json
|
|
134
|
+
{
|
|
135
|
+
"_id": "btn-close",
|
|
136
|
+
"_type": "button",
|
|
137
|
+
"_text": "Close",
|
|
138
|
+
"_on_click": "hide"
|
|
139
|
+
}
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### 2) XUIObject — set text on click (JSON)
|
|
143
|
+
```json
|
|
144
|
+
{
|
|
145
|
+
"_id": "btn-ok",
|
|
146
|
+
"_type": "button",
|
|
147
|
+
"_text": "OK",
|
|
148
|
+
"_on_click": { "_op": "set-text", "_params": { "text": "ok" } }
|
|
149
|
+
}
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
### 3) XUIObject — hide then show (sequence)
|
|
153
|
+
```json
|
|
154
|
+
{
|
|
155
|
+
"_id": "panel",
|
|
156
|
+
"_type": "view",
|
|
157
|
+
"_on_click": [
|
|
158
|
+
{ "_op": "hide" },
|
|
159
|
+
{ "_op": "show" }
|
|
160
|
+
]
|
|
161
|
+
}
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
### 4) XObject — onData drives UI (sequence)
|
|
165
|
+
```json
|
|
166
|
+
{
|
|
167
|
+
"_id": "fps-label",
|
|
168
|
+
"_type": "label",
|
|
169
|
+
"_data_source": "engine:fps",
|
|
170
|
+
"_on_data": [
|
|
171
|
+
{ "_op": "set-text-from-data", "_params": { "pattern": "FPS: $data" } }
|
|
172
|
+
]
|
|
173
|
+
}
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
---
|
|
177
|
+
|
|
178
|
+
## Design rule: no `run-seq` nano command
|
|
179
|
+
|
|
180
|
+
Xpell 2 **does not** introduce a `run-seq` nano command.
|
|
181
|
+
|
|
182
|
+
Sequencing is structural at the handler level:
|
|
183
|
+
- handlers may be arrays
|
|
184
|
+
- each item is executed in order
|
|
185
|
+
|
|
186
|
+
This keeps nano-commands:
|
|
187
|
+
- **atomic**
|
|
188
|
+
- **auditable**
|
|
189
|
+
- **non-scriptable**
|
|
190
|
+
|
|
191
|
+
---
|
|
192
|
+
|
|
193
|
+
## Security notes
|
|
194
|
+
|
|
195
|
+
This upgrade is explicitly designed to avoid “code in DB”:
|
|
196
|
+
|
|
197
|
+
- ✅ JSON commands are **whitelisted ops** (`_op` on a known nano-command pack)
|
|
198
|
+
- ✅ parameters are **data**, not executable code
|
|
199
|
+
- ✅ runtime can enforce:
|
|
200
|
+
- allowed ops
|
|
201
|
+
- allowed targets
|
|
202
|
+
- capability checks
|
|
203
|
+
- rate limits
|
|
204
|
+
- ❌ avoid `eval` / `new Function` / code-in-JSON
|
|
205
|
+
|
|
206
|
+
**Rule:** if a view is stored in DB and editable by an agent, handlers must be **data-only** (no functions).
|
|
207
|
+
|
|
208
|
+
---
|
|
209
|
+
|
|
210
|
+
## Recommended next steps (implementation checklist)
|
|
211
|
+
|
|
212
|
+
1) Ensure `checkAndRunInternalFunction()` supports:
|
|
213
|
+
- `XCommandData` objects (`{ _op, _params }`)
|
|
214
|
+
- sequences (arrays of handlers)
|
|
215
|
+
2) Ensure event dispatch sites call:
|
|
216
|
+
- `checkAndRunInternalFunction(handler, payload)`
|
|
217
|
+
for non-function handlers as well.
|
|
218
|
+
3) Add capability/allowlist enforcement at the command runner boundary.
|
|
219
|
+
|
|
220
|
+
---
|
|
221
|
+
|
|
222
|
+
## Changelog (conceptual)
|
|
223
|
+
|
|
224
|
+
- **v1:** strings + dev-only functions
|
|
225
|
+
- **v2:** JSON commands + sequences for DB-stored realtime views
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
-- Commands:
|
|
229
|
+
```md
|
|
230
|
+
# Codex Prompt — Xpell Nano Commands (Authoritative List)
|
|
231
|
+
|
|
232
|
+
Use **nano commands only** for runtime behavior.
|
|
233
|
+
Do NOT emit JavaScript functions for DB-stored views.
|
|
234
|
+
All actions must map to whitelisted nano commands.
|
|
235
|
+
|
|
236
|
+
---
|
|
237
|
+
|
|
238
|
+
## @xpell/core — XObject (available on ALL objects)
|
|
239
|
+
|
|
240
|
+
### info
|
|
241
|
+
Logs the object id.
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
info
|
|
245
|
+
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
### log
|
|
249
|
+
Logs a value or the object itself.
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
log 'hello'
|
|
253
|
+
log
|
|
254
|
+
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
### fire
|
|
258
|
+
Fires a global event via XEventManager.
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
fire event:'my-event' data:'payload'
|
|
262
|
+
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
### set-attr
|
|
266
|
+
Sets a safe attribute on the object instance.
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
set-attr name:'_name' value:'test'
|
|
270
|
+
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
### delete-attr
|
|
274
|
+
Deletes a safe attribute from the object instance.
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
delete-attr name:'_name'
|
|
278
|
+
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
---
|
|
282
|
+
|
|
283
|
+
## @xpell/ui — XUIObject (UI-only)
|
|
284
|
+
|
|
285
|
+
### hide
|
|
286
|
+
Hides the UI object.
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
hide
|
|
290
|
+
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
### show
|
|
294
|
+
Shows the UI object.
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
show
|
|
298
|
+
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
### toggle
|
|
302
|
+
Toggles visibility.
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
toggle
|
|
306
|
+
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
### set-text
|
|
310
|
+
Sets text content.
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
set-text text:'Hello'
|
|
314
|
+
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
### set (legacy alias)
|
|
318
|
+
Sets text if `text` param exists.
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
set text:'Hello'
|
|
322
|
+
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
### set-text-from-data
|
|
326
|
+
Sets text from incoming data payload.
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
set-text-from-data pattern:'Value: $data'
|
|
330
|
+
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
### set-text-from-frame
|
|
334
|
+
Sets text from frame counter.
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
set-text-from-frame pattern:'Frame $data'
|
|
338
|
+
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
### add-class
|
|
342
|
+
Adds a CSS class.
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
add-class class:'active'
|
|
346
|
+
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
### remove-class
|
|
350
|
+
Removes a CSS class.
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
remove-class class:'active'
|
|
354
|
+
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
### toggle-class
|
|
358
|
+
Toggles a CSS class.
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
toggle-class class:'active'
|
|
362
|
+
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
### set-style
|
|
366
|
+
Sets an inline style.
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
set-style name:'color' value:'red'
|
|
370
|
+
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
### set-attr
|
|
374
|
+
Sets a DOM attribute.
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
set-attr name:'aria-label' value:'Close'
|
|
378
|
+
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
### remove-attr
|
|
382
|
+
Removes a DOM attribute.
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
remove-attr name:'aria-label'
|
|
386
|
+
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
---
|
|
390
|
+
|
|
391
|
+
## @xpell/3d — X3DObject (3D-only)
|
|
392
|
+
|
|
393
|
+
### rotation
|
|
394
|
+
Sets or increments rotation axes.
|
|
395
|
+
```
|
|
396
|
+
|
|
397
|
+
rotation x:0.1 y:++0.02 z:--0.01
|
|
398
|
+
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
### spin
|
|
402
|
+
Applies continuous rotation via on-frame hook.
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
spin y:0.01
|
|
406
|
+
|
|
407
|
+
```
|
|
408
|
+
|
|
409
|
+
### stop
|
|
410
|
+
Stops on-frame behavior.
|
|
411
|
+
```
|
|
412
|
+
|
|
413
|
+
stop
|
|
414
|
+
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
### follow-joystick
|
|
418
|
+
Moves object using joystick data from XData.
|
|
419
|
+
```
|
|
420
|
+
|
|
421
|
+
follow-joystick
|
|
422
|
+
|
|
423
|
+
```
|
|
424
|
+
|
|
425
|
+
### orbit
|
|
426
|
+
Moves object in an orbit.
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
orbit radius:2 speed:0.02
|
|
430
|
+
|
|
431
|
+
````
|
|
432
|
+
|
|
433
|
+
---
|
|
434
|
+
|
|
435
|
+
## Sequences (native, no extra command)
|
|
436
|
+
|
|
437
|
+
Multiple nano commands can be executed in order using arrays:
|
|
438
|
+
|
|
439
|
+
```json
|
|
440
|
+
[
|
|
441
|
+
{ "_op": "hide" },
|
|
442
|
+
{ "_op": "set-text", "_params": { "text": "Hidden" } },
|
|
443
|
+
{ "_op": "show" }
|
|
444
|
+
]
|
|
445
|
+
```
|
|
446
|
+
|
|
447
|
+
---
|
|
448
|
+
|
|
449
|
+
## Rules (MANDATORY)
|
|
450
|
+
|
|
451
|
+
* Prefer **JSON commands** for DB-stored views
|
|
452
|
+
* Use **strings only for trivial actions**
|
|
453
|
+
* Use **arrays instead of `;` or scripting**
|
|
454
|
+
* Never emit `eval`, `new Function`, or inline JS
|
|
455
|
+
* If output is stored → it MUST be data-only
|
|
456
|
+
|
|
457
|
+
This list is the **single source of truth** for Codex and agents.
|