@xuda.io/xuda-worker-bundle-min 1.3.2439 → 1.3.2441

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.
Files changed (2) hide show
  1. package/index.js +736 -162
  2. package/package.json +1 -1
package/index.js CHANGED
@@ -5,6 +5,49 @@ if (typeof IS_DOCKER === 'undefined' || typeof IS_PROCESS_SERVER === 'undefined'
5
5
  var DOCS_OBJ = {};
6
6
  }
7
7
 
8
+ // Minimal jQuery shim for plugins that still reference $
9
+ if (typeof $ === 'undefined' && typeof document !== 'undefined') {
10
+ var $ = function (selector) {
11
+ var nodes = typeof selector === 'string'
12
+ ? Array.from(document.querySelectorAll(selector))
13
+ : selector?.nodeType ? [selector] : (selector?.length ? Array.from(selector) : []);
14
+ var obj = {
15
+ 0: nodes[0], length: nodes.length,
16
+ toArray: function () { return nodes.slice(); },
17
+ find: function (s) { var r = []; for (var i = 0; i < nodes.length; i++) { r.push.apply(r, Array.from(nodes[i].querySelectorAll(s))); } return $(r); },
18
+ each: function (fn) { for (var i = 0; i < nodes.length; i++) { fn.call(nodes[i], i, nodes[i]); } return obj; },
19
+ on: function (ev, fn) { for (var i = 0; i < nodes.length; i++) nodes[i].addEventListener(ev, fn); return obj; },
20
+ off: function (ev, fn) { for (var i = 0; i < nodes.length; i++) nodes[i].removeEventListener(ev, fn); return obj; },
21
+ addClass: function (c) { for (var i = 0; i < nodes.length; i++) nodes[i].classList?.add(c); return obj; },
22
+ removeClass: function (c) { for (var i = 0; i < nodes.length; i++) nodes[i].classList?.remove(c); return obj; },
23
+ hasClass: function (c) { return nodes[0]?.classList?.contains(c) || false; },
24
+ attr: function (k, v) { if (typeof v === 'undefined') return nodes[0]?.getAttribute(k); for (var i = 0; i < nodes.length; i++) nodes[i].setAttribute(k, v); return obj; },
25
+ css: function (k, v) { for (var i = 0; i < nodes.length; i++) nodes[i].style[k] = v; return obj; },
26
+ data: function () { return nodes[0]?.__xuData || (nodes[0] ? (nodes[0].__xuData = {}) : {}); },
27
+ val: function (v) { if (typeof v === 'undefined') return nodes[0]?.value; for (var i = 0; i < nodes.length; i++) nodes[i].value = v; return obj; },
28
+ html: function (v) { if (typeof v === 'undefined') return nodes[0]?.innerHTML; for (var i = 0; i < nodes.length; i++) nodes[i].innerHTML = v; return obj; },
29
+ text: function (v) { if (typeof v === 'undefined') return nodes[0]?.textContent; for (var i = 0; i < nodes.length; i++) nodes[i].textContent = v; return obj; },
30
+ show: function () { for (var i = 0; i < nodes.length; i++) nodes[i].style.display = ''; return obj; },
31
+ hide: function () { for (var i = 0; i < nodes.length; i++) nodes[i].style.display = 'none'; return obj; },
32
+ remove: function () { for (var i = 0; i < nodes.length; i++) nodes[i].remove?.(); return obj; },
33
+ empty: function () { for (var i = 0; i < nodes.length; i++) nodes[i].innerHTML = ''; return obj; },
34
+ append: function (c) { var n = c?.nodeType ? c : c?.[0]; if (n && nodes[0]) nodes[0].appendChild(n); return obj; },
35
+ parent: function () { return $(nodes[0]?.parentElement ? [nodes[0].parentElement] : []); },
36
+ children: function () { return $(nodes[0] ? Array.from(nodes[0].children) : []); },
37
+ trigger: function (ev, d) { for (var i = 0; i < nodes.length; i++) nodes[i].dispatchEvent(new CustomEvent(ev, { detail: d })); return obj; },
38
+ is: function (s) { return nodes[0]?.matches?.(s) || false; },
39
+ prop: function (k, v) { if (typeof v === 'undefined') return nodes[0]?.[k]; for (var i = 0; i < nodes.length; i++) nodes[i][k] = v; return obj; },
40
+ unbind: function () { return obj; },
41
+ clone: function () { return $(nodes[0]?.cloneNode(true) ? [nodes[0].cloneNode(true)] : []); },
42
+ };
43
+ obj[Symbol.iterator] = function () { var i = 0; return { next: function () { return i < nodes.length ? { value: nodes[i++], done: false } : { done: true }; } }; };
44
+ return obj;
45
+ };
46
+ $.each = function (o, fn) { if (Array.isArray(o)) { for (var i = 0; i < o.length; i++) fn(i, o[i]); } else { Object.keys(o || {}).forEach(function (k) { fn(k, o[k]); }); } };
47
+ $.cookie = function () { return null; };
48
+ var jQuery = $;
49
+ }
50
+
8
51
  var glb = {};
9
52
  var func = {};
10
53
  func.UI = {};
@@ -21,6 +64,51 @@ func.runtime.ui = {};
21
64
  func.runtime.widgets = {};
22
65
  glb.IS_STUDIO = null;
23
66
 
67
+ // Lodash replacement utilities
68
+ var xu_isEmpty = function (val) {
69
+ if (val == null) return true;
70
+ if (typeof val === 'boolean' || typeof val === 'number') return !val;
71
+ if (typeof val === 'string' || Array.isArray(val)) return val.length === 0;
72
+ if (val instanceof Map || val instanceof Set) return val.size === 0;
73
+ return Object.keys(val).length === 0;
74
+ };
75
+
76
+ var xu_isEqual = function (a, b) {
77
+ if (a === b) return true;
78
+ if (a == null || b == null) return a === b;
79
+ if (typeof a !== typeof b) return false;
80
+ if (a instanceof Date && b instanceof Date) return a.getTime() === b.getTime();
81
+ if (typeof a !== 'object') return false;
82
+ var keysA = Object.keys(a);
83
+ var keysB = Object.keys(b);
84
+ if (keysA.length !== keysB.length) return false;
85
+ for (var i = 0; i < keysA.length; i++) {
86
+ if (!Object.prototype.hasOwnProperty.call(b, keysA[i]) || !xu_isEqual(a[keysA[i]], b[keysA[i]])) return false;
87
+ }
88
+ return true;
89
+ };
90
+
91
+ var xu_get = function (obj, path, defaultVal) {
92
+ var keys = typeof path === 'string' ? path.split('.') : path;
93
+ var result = obj;
94
+ for (var i = 0; i < keys.length; i++) {
95
+ if (result == null) return defaultVal;
96
+ result = result[keys[i]];
97
+ }
98
+ return result === undefined ? defaultVal : result;
99
+ };
100
+
101
+ var xu_set = function (obj, path, value) {
102
+ var keys = typeof path === 'string' ? path.split('.') : path;
103
+ var current = obj;
104
+ for (var i = 0; i < keys.length - 1; i++) {
105
+ if (current[keys[i]] == null) current[keys[i]] = {};
106
+ current = current[keys[i]];
107
+ }
108
+ current[keys[keys.length - 1]] = value;
109
+ return obj;
110
+ };
111
+
24
112
  var PROJECT_OBJ = {};
25
113
 
26
114
  var APP_OBJ = {};
@@ -185,6 +273,105 @@ func.runtime.platform = {
185
273
  return true;
186
274
  },
187
275
  };
276
+
277
+ // ── Platform-agnostic event bus ──
278
+ // Works in browser, worker, and Node environments.
279
+ // In browser, bridge DOM events into this bus so core code never touches $(document) directly.
280
+ func.runtime.platform._event_bus = {};
281
+ func.runtime.platform.on = function (name, handler) {
282
+ if (!func.runtime.platform._event_bus[name]) {
283
+ func.runtime.platform._event_bus[name] = [];
284
+ }
285
+ func.runtime.platform._event_bus[name].push(handler);
286
+ };
287
+ func.runtime.platform.off = function (name, handler) {
288
+ const handlers = func.runtime.platform._event_bus[name];
289
+ if (!handlers) return;
290
+ if (!handler) {
291
+ delete func.runtime.platform._event_bus[name];
292
+ return;
293
+ }
294
+ const index = handlers.indexOf(handler);
295
+ if (index !== -1) {
296
+ handlers.splice(index, 1);
297
+ }
298
+ };
299
+ func.runtime.platform._emitting = {};
300
+ func.runtime.platform.emit = function (name, data) {
301
+ // re-entrancy guard: prevent infinite loops when DOM bridge triggers the same event
302
+ if (func.runtime.platform._emitting[name]) return;
303
+ func.runtime.platform._emitting[name] = true;
304
+ try {
305
+ const handlers = func.runtime.platform._event_bus[name];
306
+ if (handlers) {
307
+ for (let i = 0; i < handlers.length; i++) {
308
+ handlers[i](data);
309
+ }
310
+ }
311
+ // also fire on DOM if in browser (for backward compatibility with custom event listeners)
312
+ if (func.runtime.platform.has_document()) {
313
+ document.dispatchEvent(new CustomEvent(name, { detail: Array.isArray(data) ? data : [data] }));
314
+ }
315
+ } finally {
316
+ func.runtime.platform._emitting[name] = false;
317
+ }
318
+ };
319
+
320
+ // ── Platform helpers for DOM-independent resource loading ──
321
+ func.runtime.platform.load_script = function (url, type, callback) {
322
+ if (typeof document !== 'undefined') {
323
+ const script = document.createElement('script');
324
+ script.src = url;
325
+ if (type) script.type = type;
326
+ script.onload = callback;
327
+ document.head.appendChild(script);
328
+ } else if (callback) {
329
+ callback();
330
+ }
331
+ };
332
+ func.runtime.platform.load_css = function (href) {
333
+ if (typeof document === 'undefined') return;
334
+ try {
335
+ if (document.querySelector('link[href="' + href + '"]')) return;
336
+ } catch (err) {
337
+ return;
338
+ }
339
+ const link = document.createElement('link');
340
+ link.rel = 'stylesheet';
341
+ link.type = 'text/css';
342
+ link.href = href;
343
+ document.head.insertBefore(link, document.head.firstChild);
344
+ };
345
+ func.runtime.platform.remove_js_css = function (filename, filetype) {
346
+ if (typeof document === 'undefined') return;
347
+ const tagName = filetype === 'js' ? 'script' : filetype === 'css' ? 'link' : 'none';
348
+ const attr = filetype === 'js' ? 'src' : filetype === 'css' ? 'href' : 'none';
349
+ const elements = document.getElementsByTagName(tagName);
350
+ for (let i = elements.length - 1; i >= 0; i--) {
351
+ if (elements[i] && elements[i].getAttribute(attr) != null && elements[i].getAttribute(attr).indexOf(filename) !== -1) {
352
+ elements[i].parentNode.removeChild(elements[i]);
353
+ }
354
+ }
355
+ };
356
+ func.runtime.platform.inject_css = function (cssText) {
357
+ if (typeof document === 'undefined' || !cssText) return;
358
+ const style = document.createElement('style');
359
+ style.type = 'text/css';
360
+ style.textContent = cssText;
361
+ document.head.appendChild(style);
362
+ };
363
+ func.runtime.platform.set_title = function (title) {
364
+ if (typeof document !== 'undefined') {
365
+ document.title = title;
366
+ }
367
+ };
368
+ func.runtime.platform.set_cursor = function (element, cursor) {
369
+ const node = func.runtime.ui?.get_first_node ? func.runtime.ui.get_first_node(element) : element;
370
+ if (node?.style) {
371
+ node.style.cursor = cursor;
372
+ }
373
+ };
374
+
188
375
  func.runtime.env = {
189
376
  get_url_params: function () {
190
377
  const search = func.runtime.platform.get_url_search();
@@ -623,18 +810,17 @@ func.runtime.bind.get_field_type = function (field_prop) {
623
810
  };
624
811
  func.runtime.bind.toggle_array_value = function (arr_value_before_cast, value_from_getter) {
625
812
  if (arr_value_before_cast.includes(value_from_getter)) {
626
- return arr_value_before_cast.filter((item) => !_.isEqual(item, value_from_getter));
813
+ return arr_value_before_cast.filter((item) => !xu_isEqual(item, value_from_getter));
627
814
  }
628
815
  arr_value_before_cast.push(value_from_getter);
629
816
  return arr_value_before_cast;
630
817
  };
631
818
  func.runtime.bind.get_cast_value = async function (SESSION_ID, field_prop, input_field_type, raw_value) {
632
819
  const field_type = func.runtime.bind.get_field_type(field_prop);
633
- var value = await func.common.get_cast_val(SESSION_ID, 'xu-bind', 'value', field_type, raw_value);
634
820
  if (field_type === 'object') {
635
- value = await func.common.get_cast_val(SESSION_ID, 'xu-bind', 'value', input_field_type, raw_value);
821
+ return await func.common.get_cast_val(SESSION_ID, 'xu-bind', 'value', input_field_type, raw_value);
636
822
  }
637
- return value;
823
+ return await func.common.get_cast_val(SESSION_ID, 'xu-bind', 'value', field_type, raw_value);
638
824
  };
639
825
  func.runtime.bind.get_source_value = function (_ds, bind_field_id, is_dynamic_field) {
640
826
  if (is_dynamic_field) {
@@ -645,7 +831,7 @@ func.runtime.bind.get_source_value = function (_ds, bind_field_id, is_dynamic_fi
645
831
  };
646
832
  func.runtime.bind.format_display_value = function ($elm, field_prop, bind_field_id, expression_value, value, input_field_type) {
647
833
  const field_type = func.runtime.bind.get_field_type(field_prop);
648
- const elm_value = $elm.attr('value');
834
+ const elm_value = func.runtime.ui.get_attr($elm, 'value');
649
835
 
650
836
  if (field_type === 'array' && input_field_type === 'checkbox' && elm_value) {
651
837
  return value.includes(elm_value);
@@ -671,7 +857,7 @@ func.runtime.bind.update_reference_source_array = async function (options) {
671
857
 
672
858
  const arr_idx = Number(options.iterate_info._key);
673
859
  const dataset_arr = await func.datasource.get_value(options.SESSION_ID, reference_source_obj.fieldIdP, options.dsSessionP, reference_source_obj.currentRecordId);
674
- let new_arr = _.cloneDeep(dataset_arr.ret.value);
860
+ let new_arr = structuredClone(dataset_arr.ret.value);
675
861
 
676
862
  if (field_type === 'object' && options.val_is_reference_field) {
677
863
  let obj_item = new_arr[arr_idx];
@@ -683,15 +869,15 @@ func.runtime.bind.update_reference_source_array = async function (options) {
683
869
  }
684
870
 
685
871
  let datasource_changes = func.runtime.bind.build_datasource_changes(options.dsSessionP, options.currentRecordId, reference_source_obj.fieldIdP, new_arr);
686
- await func.datasource.update(options.SESSION_ID, datasource_changes, null, true);
872
+ await func.datasource.update(options.SESSION_ID, datasource_changes);
687
873
  return true;
688
874
  };
689
875
  func.runtime.resources.load_cdn = async function (SESSION_ID, resource) {
690
876
  let normalized_resource = resource;
691
- if (!_.isObject(normalized_resource) && _.isString(normalized_resource)) {
877
+ if (!(typeof normalized_resource === 'object' && normalized_resource !== null) && typeof normalized_resource === 'string') {
692
878
  normalized_resource = { src: normalized_resource, type: 'js' };
693
879
  }
694
- if (!_.isObject(normalized_resource)) {
880
+ if (!(typeof normalized_resource === 'object' && normalized_resource !== null)) {
695
881
  throw new Error('cdn resource in wrong format');
696
882
  }
697
883
 
@@ -737,7 +923,7 @@ func.runtime.resources.load_plugin_runtime_css = async function (SESSION_ID, plu
737
923
  return true;
738
924
  };
739
925
  func.runtime.resources.resolve_plugin_properties = async function (SESSION_ID, dsSessionP, attributes, properties) {
740
- let resolved_properties = _.cloneDeep(properties);
926
+ let resolved_properties = structuredClone(properties);
741
927
  for await (let [prop_name, prop_val] of Object.entries(resolved_properties || {})) {
742
928
  prop_val.value = attributes?.[prop_name];
743
929
  if (attributes?.[`xu-exp:${prop_name}`]) {
@@ -763,7 +949,7 @@ func.runtime.resources.run_ui_plugin = async function (SESSION_ID, paramsP, $elm
763
949
  const plugin_runtime_src = await func.runtime.resources.get_plugin_module_url(SESSION_ID, plugin_name, plugin, 'runtime.mjs');
764
950
  const plugin_runtime_resources = await import(plugin_runtime_src);
765
951
 
766
- if (plugin_runtime_resources.cdn && _.isArray(plugin_runtime_resources.cdn)) {
952
+ if (plugin_runtime_resources.cdn && Array.isArray(plugin_runtime_resources.cdn)) {
767
953
  for await (const resource of plugin_runtime_resources.cdn) {
768
954
  await func.runtime.resources.load_cdn(SESSION_ID, resource);
769
955
  }
@@ -895,12 +1081,12 @@ func.runtime.widgets.build_params = function (context, $containerP, plugin_setup
895
1081
  };
896
1082
  };
897
1083
  func.common.find_item_by_key = function (arr, key, val) {
898
- return _.find(arr, function (e) {
1084
+ return arr.find(function (e) {
899
1085
  return e.data[key] === val;
900
1086
  });
901
1087
  };
902
1088
  func.common.find_item_by_key_root = function (arr, key, val) {
903
- return _.find(arr, function (e) {
1089
+ return arr.find(function (e) {
904
1090
  return e[key] === val;
905
1091
  });
906
1092
  };
@@ -1160,7 +1346,7 @@ func.common.db = async function (SESSION_ID, serviceP, dataP, opt = {}, dsSessio
1160
1346
  }
1161
1347
 
1162
1348
  await db.get(row_id);
1163
- let _data = _.cloneDeep(dataP);
1349
+ let _data = structuredClone(dataP);
1164
1350
  _data.ids = [row_id];
1165
1351
  return await func.db.pouch['dbs_delete'](SESSION_ID, _data);
1166
1352
  } catch (err) {
@@ -1249,7 +1435,7 @@ func.common.db = async function (SESSION_ID, serviceP, dataP, opt = {}, dsSessio
1249
1435
 
1250
1436
  const get_white_spaced_data = function (data) {
1251
1437
  var e = {};
1252
- _.forEach(data, function (val, key) {
1438
+ for (const [key, val] of Object.entries(data)) {
1253
1439
  if (!val) {
1254
1440
  if (typeof val === 'boolean') {
1255
1441
  e[key] = 'false';
@@ -1263,7 +1449,7 @@ func.common.db = async function (SESSION_ID, serviceP, dataP, opt = {}, dsSessio
1263
1449
  e[key] = val;
1264
1450
  }
1265
1451
  }
1266
- });
1452
+ }
1267
1453
 
1268
1454
  if (data.fields && !data.fields.length) {
1269
1455
  e.fields = '';
@@ -1512,14 +1698,14 @@ var UI_FRAMEWORK_PLUGIN = {};
1512
1698
  func.common.get_cast_val = async function (SESSION_ID, source, attributeP, typeP, valP, errorP) {
1513
1699
  const report_conversion_error = function (res) {
1514
1700
  if (errorP) {
1515
- return func.utils.debug_report(SESSION_ID, _.capitalize(source), errorP, 'W');
1701
+ return func.utils.debug_report(SESSION_ID, source.charAt(0).toUpperCase() + source.slice(1).toLowerCase(), errorP, 'W');
1516
1702
  }
1517
1703
  var msg = `error converting ${attributeP} from ${valP} to ${typeP}`;
1518
- func.utils.debug_report(SESSION_ID, _.capitalize(source), msg, 'E');
1704
+ func.utils.debug_report(SESSION_ID, source.charAt(0).toUpperCase() + source.slice(1).toLowerCase(), msg, 'E');
1519
1705
  };
1520
1706
  const report_conversion_warn = function (msg) {
1521
1707
  var msg = `type mismatch auto conversion made to ${attributeP} from value ${valP} to ${typeP}`;
1522
- func.utils.debug_report(SESSION_ID, _.capitalize(source), msg, 'W');
1708
+ func.utils.debug_report(SESSION_ID, source.charAt(0).toUpperCase() + source.slice(1).toLowerCase(), msg, 'W');
1523
1709
  };
1524
1710
  const module = await func.common.get_module(SESSION_ID, `xuda-get-cast-util-module.mjs`);
1525
1711
  return module.cast(typeP, valP, report_conversion_error, report_conversion_warn);
@@ -1537,11 +1723,17 @@ var WEBSOCKET_PROCESS_PID = null;
1537
1723
  glb.worker_queue_num = 0;
1538
1724
  glb.websocket_queue_num = 0;
1539
1725
 
1726
+ func.common._import_cache = func.common._import_cache || {};
1727
+
1540
1728
  func.common.get_module = async function (SESSION_ID, module, paramsP = {}) {
1541
1729
  let ret;
1542
1730
 
1543
1731
  const get_ret = async function (src) {
1544
- const module_ret = await import(src);
1732
+ // Cache the import() result to avoid repeated dynamic imports
1733
+ if (!func.common._import_cache[src]) {
1734
+ func.common._import_cache[src] = await import(src);
1735
+ }
1736
+ const module_ret = func.common._import_cache[src];
1545
1737
  var params = get_params();
1546
1738
 
1547
1739
  const ret = module_ret.XudaModule ? new module_ret.XudaModule(params) : await invoke_init_module(module_ret, params);
@@ -1558,7 +1750,6 @@ func.common.get_module = async function (SESSION_ID, module, paramsP = {}) {
1558
1750
  PROJECT_OBJ,
1559
1751
  DOCS_OBJ,
1560
1752
  SESSION_OBJ,
1561
- _,
1562
1753
  ...paramsP,
1563
1754
  };
1564
1755
  if (typeof IS_PROCESS_SERVER !== 'undefined') params.IS_PROCESS_SERVER = IS_PROCESS_SERVER;
@@ -1592,7 +1783,7 @@ func.common.get_module = async function (SESSION_ID, module, paramsP = {}) {
1592
1783
  }
1593
1784
 
1594
1785
  const rep = function () {
1595
- return _.endsWith(module, '.js') ? module.replace('.js', '.min.js') : module.replace('.mjs', '.min.mjs');
1786
+ return module.endsWith('.js') ? module.replace('.js', '.min.js') : module.replace('.mjs', '.min.mjs');
1596
1787
  };
1597
1788
 
1598
1789
  if (typeof IS_DOCKER !== 'undefined' || typeof IS_PROCESS_SERVER !== 'undefined') {
@@ -1750,7 +1941,7 @@ func.api.watch = function (path, cb, opt = {}) {
1750
1941
  _session.watchers[path] = { ...opt, handler: cb };
1751
1942
 
1752
1943
  if (opt.immediate) {
1753
- const value = _.get(SESSION_OBJ[SESSION_ID].DS_GLB[0], path);
1944
+ const value = xu_get(SESSION_OBJ[SESSION_ID].DS_GLB[0], path);
1754
1945
  cb({ path, newValue: value, oldValue: value, timestamp: Date.now(), opt });
1755
1946
 
1756
1947
  if (opt.once) {
@@ -1902,10 +2093,12 @@ func.common.get_data_from_websocket = async function (SESSION_ID, serviceP, data
1902
2093
  } else {
1903
2094
  if (RUNTIME_SERVER_WEBSOCKET && RUNTIME_SERVER_WEBSOCKET_CONNECTED) {
1904
2095
  RUNTIME_SERVER_WEBSOCKET.emit('message', obj);
1905
- $('body').on('get_ws_data_response_' + glb.websocket_queue_num, (e, data) => {
2096
+ const _ws_event = 'get_ws_data_response_' + glb.websocket_queue_num;
2097
+ const _ws_handler = function (data) {
1906
2098
  resolve(data.data);
1907
- $('body').off('get_ws_data_response_' + data.e.websocket_queue_num);
1908
- });
2099
+ func.runtime.platform.off('get_ws_data_response_' + data.e.websocket_queue_num, _ws_handler);
2100
+ };
2101
+ func.runtime.platform.on(_ws_event, _ws_handler);
1909
2102
  } else {
1910
2103
  throw new Error('fail to fetch from ws websocket inactive');
1911
2104
  }
@@ -1919,10 +2112,11 @@ func.common.get_data_from_websocket = async function (SESSION_ID, serviceP, data
1919
2112
 
1920
2113
  if (RUNTIME_SERVER_WEBSOCKET && RUNTIME_SERVER_WEBSOCKET_CONNECTED) {
1921
2114
  RUNTIME_SERVER_WEBSOCKET.emit('message', obj);
1922
- $('body').on('heartbeat_response', (e, data) => {
2115
+ const _hb_handler = function (data) {
1923
2116
  resolve(data.data);
1924
- $('body').off('heartbeat_response');
1925
- });
2117
+ func.runtime.platform.off('heartbeat_response', _hb_handler);
2118
+ };
2119
+ func.runtime.platform.on('heartbeat_response', _hb_handler);
1926
2120
  } else {
1927
2121
  throw new Error('fail to fetch from ws websocket inactive');
1928
2122
  }
@@ -2157,6 +2351,395 @@ glb.run_xu_before = [
2157
2351
  glb.run_xu_after = ['xu-bind', 'xu-class', 'xu-script', 'xu-ui-plugin', 'xu-ref'];
2158
2352
  glb.attr_abbreviations_arr = ['xu-click', 'xu-dblclick', 'xu-contextmenu', 'xu-focus', 'xu-keyup', 'xu-change', 'xu-blur', 'xu-init'];
2159
2353
  glb.solid_attributes = ['disabled'];
2354
+ // ── Headless/SSR DOM adapter ──
2355
+ // Provides a no-op / in-memory implementation of func.runtime.ui
2356
+ // for environments without a DOM (Node.js, workers, SSR).
2357
+ // Elements are plain objects; metadata lives in _meta_store.
2358
+
2359
+ func.runtime = func.runtime || {};
2360
+ func.runtime.ui = func.runtime.ui || {};
2361
+ func.runtime.render = func.runtime.render || {};
2362
+ func.runtime.widgets = func.runtime.widgets || {};
2363
+ func.runtime.ui.ui_id_hash_cache = func.runtime.ui.ui_id_hash_cache || new Map();
2364
+ func.runtime.ui.node_snapshot_cache = func.runtime.ui.node_snapshot_cache || new WeakMap();
2365
+ func.runtime.ui.node_child_items_cache = func.runtime.ui.node_child_items_cache || new WeakMap();
2366
+ func.runtime.ui.node_children_by_id_cache = func.runtime.ui.node_children_by_id_cache || new WeakMap();
2367
+
2368
+ // ── Metadata store (shared with browser adapter) ──
2369
+ func.runtime.ui._meta_store = func.runtime.ui._meta_store || {};
2370
+ func.runtime.ui._element_id_to_xu_ui_id = func.runtime.ui._element_id_to_xu_ui_id || {};
2371
+
2372
+ func.runtime.ui.set_meta = function (xu_ui_id, key, value) {
2373
+ if (!xu_ui_id) return;
2374
+ if (!func.runtime.ui._meta_store[xu_ui_id]) {
2375
+ func.runtime.ui._meta_store[xu_ui_id] = {};
2376
+ }
2377
+ func.runtime.ui._meta_store[xu_ui_id][key] = value;
2378
+ };
2379
+ func.runtime.ui.get_meta = function (xu_ui_id, key) {
2380
+ const entry = func.runtime.ui._meta_store[xu_ui_id];
2381
+ if (!entry) return undefined;
2382
+ return key ? entry[key] : entry;
2383
+ };
2384
+ func.runtime.ui.delete_meta = function (xu_ui_id) {
2385
+ delete func.runtime.ui._meta_store[xu_ui_id];
2386
+ for (const id in func.runtime.ui._element_id_to_xu_ui_id) {
2387
+ if (func.runtime.ui._element_id_to_xu_ui_id[id] === xu_ui_id) {
2388
+ delete func.runtime.ui._element_id_to_xu_ui_id[id];
2389
+ }
2390
+ }
2391
+ };
2392
+ func.runtime.ui.register_element_id = function (element_id, xu_ui_id) {
2393
+ if (element_id && xu_ui_id) {
2394
+ func.runtime.ui._element_id_to_xu_ui_id[element_id] = xu_ui_id;
2395
+ }
2396
+ };
2397
+ func.runtime.ui.get_meta_by_element_id = function (element_id) {
2398
+ if (!element_id) return undefined;
2399
+ const clean_id = element_id.startsWith('#') ? element_id.substring(1) : element_id;
2400
+ const xu_ui_id = func.runtime.ui._element_id_to_xu_ui_id[clean_id];
2401
+ if (xu_ui_id) {
2402
+ return func.runtime.ui._meta_store[xu_ui_id];
2403
+ }
2404
+ return undefined;
2405
+ };
2406
+ func.runtime.ui.find_element_by_id = function () {
2407
+ return null;
2408
+ };
2409
+ func.runtime.ui.get_session_root = function () {
2410
+ return null;
2411
+ };
2412
+ func.runtime.ui.clear_screen_blockers = function () {
2413
+ // no-op in headless
2414
+ };
2415
+
2416
+ // ── Virtual element representation ──
2417
+ var _next_id = 1;
2418
+ function create_virtual_element(tag, attrs) {
2419
+ return {
2420
+ _v_id: _next_id++,
2421
+ tag: tag || 'div',
2422
+ attrs: attrs || {},
2423
+ children: [],
2424
+ parent: null,
2425
+ style: {},
2426
+ classList: [],
2427
+ textContent: '',
2428
+ innerHTML: '',
2429
+ hidden: false,
2430
+ _data: {},
2431
+ };
2432
+ }
2433
+
2434
+ // ── Core adapter methods ──
2435
+ func.runtime.ui.as_jquery = function (target) {
2436
+ if (!target) return { length: 0, data: function () { return {}; }, toArray: function () { return []; }, attr: function () { return undefined; } };
2437
+ if (target._v_id) return target;
2438
+ return target;
2439
+ };
2440
+ func.runtime.ui.get_first_node = function (target) {
2441
+ if (!target) return null;
2442
+ if (target._v_id) return target;
2443
+ if (Array.isArray(target)) return target[0] || null;
2444
+ return null;
2445
+ };
2446
+ func.runtime.ui.get_data = function (target) {
2447
+ if (!target) return {};
2448
+ if (target._v_id) {
2449
+ const xu_ui_id = target.attrs?.['xu-ui-id'];
2450
+ if (xu_ui_id) {
2451
+ const meta = func.runtime.ui._meta_store[xu_ui_id];
2452
+ if (meta) return meta;
2453
+ }
2454
+ return target._data;
2455
+ }
2456
+ return {};
2457
+ };
2458
+ func.runtime.ui.get_parent = function (target) {
2459
+ if (target?._v_id) return target.parent;
2460
+ return null;
2461
+ };
2462
+ func.runtime.ui.get_children = function (target) {
2463
+ if (target?._v_id) return target.children.slice();
2464
+ return [];
2465
+ };
2466
+ func.runtime.ui.find_by_selector = function () {
2467
+ return { length: 0, toArray: function () { return []; } };
2468
+ };
2469
+ func.runtime.ui.insert_before = function ($element) { return $element; };
2470
+ func.runtime.ui.insert_after = function ($element) { return $element; };
2471
+ func.runtime.ui.has_selector = function () { return false; };
2472
+ func.runtime.ui.append_html = function (target) { return target; };
2473
+ func.runtime.ui.set_style = function (target, prop, value) {
2474
+ if (target?._v_id) target.style[prop] = value;
2475
+ return target;
2476
+ };
2477
+ func.runtime.ui.get_attr = function (target, key) {
2478
+ if (target?._v_id) return target.attrs[key];
2479
+ return undefined;
2480
+ };
2481
+ func.runtime.ui.set_attr = function (target, key, value) {
2482
+ if (target?._v_id) target.attrs[key] = value;
2483
+ return target;
2484
+ };
2485
+ func.runtime.ui.set_data = function (target, key, value) {
2486
+ if (target?._v_id) {
2487
+ target._data[key] = value;
2488
+ const xu_ui_id = target.attrs?.['xu-ui-id'];
2489
+ if (xu_ui_id) {
2490
+ func.runtime.ui.set_meta(xu_ui_id, key, value);
2491
+ }
2492
+ }
2493
+ return target;
2494
+ };
2495
+ func.runtime.ui.clear_data = function (target) {
2496
+ if (target?._v_id) {
2497
+ target._data = {};
2498
+ const xu_ui_id = target.attrs?.['xu-ui-id'];
2499
+ if (xu_ui_id) func.runtime.ui.delete_meta(xu_ui_id);
2500
+ }
2501
+ return target;
2502
+ };
2503
+ func.runtime.ui.add_class = function (target, cls) {
2504
+ if (target?._v_id && cls && !target.classList.includes(cls)) target.classList.push(cls);
2505
+ return target;
2506
+ };
2507
+ func.runtime.ui.remove_class = function (target, cls) {
2508
+ if (target?._v_id) {
2509
+ const idx = target.classList.indexOf(cls);
2510
+ if (idx !== -1) target.classList.splice(idx, 1);
2511
+ }
2512
+ return target;
2513
+ };
2514
+ func.runtime.ui.set_html = function (target, value) {
2515
+ if (target?._v_id) target.innerHTML = value;
2516
+ return target;
2517
+ };
2518
+ func.runtime.ui.set_text = function (target, value) {
2519
+ if (target?._v_id) target.textContent = value;
2520
+ return target;
2521
+ };
2522
+ func.runtime.ui.show = function (target) {
2523
+ if (target?._v_id) target.hidden = false;
2524
+ return target;
2525
+ };
2526
+ func.runtime.ui.hide = function (target) {
2527
+ if (target?._v_id) target.hidden = true;
2528
+ return target;
2529
+ };
2530
+ func.runtime.ui.append = function ($target, $element) {
2531
+ if ($target?._v_id && $element?._v_id) {
2532
+ $target.children.push($element);
2533
+ $element.parent = $target;
2534
+ }
2535
+ return $element;
2536
+ };
2537
+ func.runtime.ui.append_to = function ($element, $target) {
2538
+ return func.runtime.ui.append($target, $element);
2539
+ };
2540
+ func.runtime.ui.empty = function (target) {
2541
+ if (target?._v_id) target.children = [];
2542
+ return target;
2543
+ };
2544
+ func.runtime.ui.remove = function (target) {
2545
+ if (target?._v_id) {
2546
+ const xu_ui_id = target.attrs?.['xu-ui-id'];
2547
+ if (xu_ui_id) func.runtime.ui.delete_meta(xu_ui_id);
2548
+ if (target.parent?._v_id) {
2549
+ const idx = target.parent.children.indexOf(target);
2550
+ if (idx !== -1) target.parent.children.splice(idx, 1);
2551
+ }
2552
+ }
2553
+ return true;
2554
+ };
2555
+ func.runtime.ui.set_display_contents = function ($element) {
2556
+ return func.runtime.ui.set_style($element, 'display', 'contents');
2557
+ };
2558
+ func.runtime.ui.create_xurender = function (xu_ui_id, $target, hidden) {
2559
+ const el = create_virtual_element('xurender', { 'xu-ui-id': xu_ui_id });
2560
+ if (hidden) el.hidden = true;
2561
+ return func.runtime.ui.append_to(el, $target);
2562
+ };
2563
+ func.runtime.ui.replace_with = function ($source, $target) {
2564
+ if ($source?._v_id && $source.parent?._v_id) {
2565
+ const idx = $source.parent.children.indexOf($source);
2566
+ if (idx !== -1 && $target?._v_id) {
2567
+ $source.parent.children[idx] = $target;
2568
+ $target.parent = $source.parent;
2569
+ }
2570
+ }
2571
+ return $target;
2572
+ };
2573
+ func.runtime.ui.remove_xu_ui = function (xu_ui_id) {
2574
+ func.runtime.ui.delete_meta(xu_ui_id);
2575
+ return true;
2576
+ };
2577
+ func.runtime.ui.build_debug_info = function (nodeP, $container, items) {
2578
+ const container_data = func.runtime.ui.get_data($container);
2579
+ return {
2580
+ id: nodeP.id,
2581
+ parent_id: container_data?.xuData?.ui_id,
2582
+ items: items,
2583
+ };
2584
+ };
2585
+ func.runtime.ui.get_node_snapshot = function (nodeP) {
2586
+ if (!nodeP) return nodeP;
2587
+ if (func.runtime.ui.node_snapshot_cache.has(nodeP)) {
2588
+ return func.runtime.ui.node_snapshot_cache.get(nodeP);
2589
+ }
2590
+ const snapshot = structuredClone(nodeP);
2591
+ func.runtime.ui.node_snapshot_cache.set(nodeP, snapshot);
2592
+ return snapshot;
2593
+ };
2594
+ func.runtime.ui.get_node_child_items = function (nodeP) {
2595
+ if (!nodeP?.children?.length) return [];
2596
+ if (func.runtime.ui.node_child_items_cache.has(nodeP)) {
2597
+ return func.runtime.ui.node_child_items_cache.get(nodeP);
2598
+ }
2599
+ const items = nodeP.children.map(function (val) { return val.xu_tree_id || val.id; });
2600
+ func.runtime.ui.node_child_items_cache.set(nodeP, items);
2601
+ return items;
2602
+ };
2603
+ func.runtime.ui.get_node_children_by_id = function (nodeP) {
2604
+ if (!nodeP?.children?.length) return {};
2605
+ if (func.runtime.ui.node_children_by_id_cache.has(nodeP)) {
2606
+ return func.runtime.ui.node_children_by_id_cache.get(nodeP);
2607
+ }
2608
+ const children_by_id = {};
2609
+ for (let i = 0; i < nodeP.children.length; i++) {
2610
+ const child = nodeP.children[i];
2611
+ if (child?.id) children_by_id[child.id] = child;
2612
+ }
2613
+ func.runtime.ui.node_children_by_id_cache.set(nodeP, children_by_id);
2614
+ return children_by_id;
2615
+ };
2616
+ func.runtime.ui.build_container_xu_data = function (options) {
2617
+ const container_data = func.runtime.ui.get_data(options.$container);
2618
+ const containerXuData = container_data?.xuData;
2619
+ return {
2620
+ SESSION_ID: options.SESSION_ID,
2621
+ prog_id: options.paramsP.prog_id,
2622
+ nodeid: options.nodeP.id,
2623
+ ui_type: options.nodeP.tagName,
2624
+ recordid: options.currentRecordId,
2625
+ paramsP: options.paramsP,
2626
+ key: options.keyP,
2627
+ key_path: options.key_path,
2628
+ screenId: options.paramsP.screenId,
2629
+ parent_container: containerXuData?.ui_id,
2630
+ elem_key: options.elem_key,
2631
+ properties: options.prop,
2632
+ node: options.nodeP,
2633
+ node_org: func.runtime.ui.get_node_snapshot(options.nodeP),
2634
+ is_panelP: options.paramsP.is_panelP,
2635
+ ui_id: options.ui_id,
2636
+ elem_prop: options.elem_propP,
2637
+ debug_info: func.runtime.ui.build_debug_info(options.nodeP, options.$container, options.items),
2638
+ parent_node: options.parent_nodeP,
2639
+ currentRecordId: options.currentRecordId,
2640
+ $root_container: options.$root_container,
2641
+ parent_element_ui_id: containerXuData?.ui_id,
2642
+ is_placeholder: !!options.is_placeholder,
2643
+ };
2644
+ };
2645
+ func.runtime.ui.apply_container_meta = function ($div, options) {
2646
+ if ($div?._v_id) $div.attrs['xu-ui-id'] = options.ui_id;
2647
+ const xuData = func.runtime.ui.build_container_xu_data(options);
2648
+ if (options.parent_infoP?.iterate_info) {
2649
+ xuData.iterate_info = options.parent_infoP.iterate_info;
2650
+ }
2651
+ if ($div?._v_id) {
2652
+ $div._data.xuData = xuData;
2653
+ $div._data.xuAttributes = {};
2654
+ }
2655
+ func.runtime.ui.set_meta(options.ui_id, 'xuData', xuData);
2656
+ func.runtime.ui.set_meta(options.ui_id, 'xuAttributes', {});
2657
+ if (options.is_placeholder && $div?._v_id) $div.classList.push('display_none');
2658
+ if (options.classP && $div?._v_id) $div.classList.push(options.classP);
2659
+ return $div;
2660
+ };
2661
+ func.runtime.ui.get_append_target = function ($container, $appendToP) {
2662
+ return $appendToP || $container || null;
2663
+ };
2664
+ func.runtime.ui.create_element = function (tag_name) {
2665
+ return create_virtual_element(tag_name);
2666
+ };
2667
+ func.runtime.ui.create_svg_element = function () {
2668
+ return create_virtual_element('svg');
2669
+ };
2670
+ func.runtime.ui.create_container_element = function (div_typeP) {
2671
+ return create_virtual_element(div_typeP || 'div');
2672
+ };
2673
+ func.runtime.ui.build_xu_ui_id_seed = function (nodeP, dsSessionP, key_path, currentRecordId) {
2674
+ const nodeId = nodeP.xu_tree_id || nodeP.id;
2675
+ const elem_key = `${nodeId}-${key_path}-${currentRecordId}`;
2676
+ return `${nodeP.id}-${elem_key}-${dsSessionP?.toString() || ''}`;
2677
+ };
2678
+ func.runtime.ui.generate_xu_ui_id = async function (SESSION_ID, nodeP, $container, paramsP, keyP, precomputed) {
2679
+ precomputed = precomputed || {};
2680
+ const dsSessionP = paramsP.dsSessionP;
2681
+ const _ds = SESSION_OBJ[SESSION_ID].DS_GLB[dsSessionP];
2682
+ const containerXuData = precomputed.container_xu_data || func.runtime.ui.get_data($container)?.xuData;
2683
+ const currentRecordId = typeof precomputed.currentRecordId !== 'undefined' ? precomputed.currentRecordId : containerXuData?.recordid || _ds?.currentRecordId || '';
2684
+ const key_path = precomputed.key_path || `${containerXuData?.key_path || '0'}-${keyP || '0'}`;
2685
+ const ui_id = func.runtime.ui.build_xu_ui_id_seed(nodeP, dsSessionP, key_path, currentRecordId);
2686
+
2687
+ if (func.runtime.ui.ui_id_hash_cache.has(ui_id)) {
2688
+ return func.runtime.ui.ui_id_hash_cache.get(ui_id);
2689
+ }
2690
+
2691
+ const hashed_ui_id = await func.common.fastHash(ui_id);
2692
+ func.runtime.ui.ui_id_hash_cache.set(ui_id, hashed_ui_id);
2693
+ return hashed_ui_id;
2694
+ };
2695
+ func.runtime.ui.create_container = async function (options) {
2696
+ const _paramsP = structuredClone(options.paramsP);
2697
+ const _ds = SESSION_OBJ[options.SESSION_ID].DS_GLB[_paramsP.dsSessionP];
2698
+ const $appendTo = func.runtime.ui.get_append_target(options.$container, options.$appendToP);
2699
+ if (!$appendTo) return null;
2700
+ const container_data = func.runtime.ui.get_data(options.$container);
2701
+ const container_xu_data = container_data?.xuData;
2702
+ const items = func.runtime.ui.get_node_child_items(options.nodeP);
2703
+ const currentRecordId = container_xu_data?.recordid || (_ds ? _ds.currentRecordId : '');
2704
+
2705
+ try {
2706
+ const key_path = `${container_xu_data?.key_path || '0'}-${options.keyP || '0'}`;
2707
+ const elem_key = `${options.nodeP.xu_tree_id || options.nodeP.id}-${key_path}-${currentRecordId}`;
2708
+ const $div = func.runtime.ui.create_container_element(options.div_typeP);
2709
+ const new_ui_id = await func.runtime.ui.generate_xu_ui_id(options.SESSION_ID, options.nodeP, options.$container, options.paramsP, options.keyP, {
2710
+ container_xu_data,
2711
+ currentRecordId,
2712
+ key_path,
2713
+ });
2714
+
2715
+ func.runtime.ui.apply_container_meta($div, {
2716
+ ui_id: new_ui_id,
2717
+ paramsP: _paramsP,
2718
+ nodeP: options.nodeP,
2719
+ currentRecordId,
2720
+ keyP: options.keyP,
2721
+ key_path,
2722
+ $container: options.$container,
2723
+ prop: options.prop,
2724
+ elem_key,
2725
+ elem_propP: options.elem_propP,
2726
+ items,
2727
+ parent_nodeP: options.parent_nodeP,
2728
+ $root_container: options.$root_container,
2729
+ parent_infoP: options.parent_infoP,
2730
+ is_placeholder: options.is_placeholder,
2731
+ classP: options.classP,
2732
+ SESSION_ID: options.SESSION_ID,
2733
+ });
2734
+
2735
+ func.runtime.ui.append_to($div, $appendTo);
2736
+ return $div;
2737
+ } catch (e) {
2738
+ console.error(e);
2739
+ }
2740
+
2741
+ return null;
2742
+ };
2160
2743
  func.datasource = {};
2161
2744
  func.datasource.create = async function (
2162
2745
  SESSION_ID,
@@ -2351,7 +2934,7 @@ func.datasource.create = async function (
2351
2934
  }
2352
2935
  // vvvv run at worker vvvv
2353
2936
  if (_ds) IS_DATASOURCE_REFRESH = true;
2354
- var data = _.assignIn(
2937
+ var data = Object.assign(
2355
2938
  {
2356
2939
  session_id: SESSION_ID,
2357
2940
  dataSourceSessionGlobal: SESSION_OBJ[SESSION_ID].dataSourceSessionGlobal,
@@ -2406,7 +2989,7 @@ func.datasource.prepare = async function (SESSION_ID, prog_id, dataSourceNoP, pa
2406
2989
  // &&
2407
2990
  // glb.PARAMETER_NODES_ARR.includes(screenInfo.properties.menuType)
2408
2991
  ) {
2409
- if (!_.isEmpty(screenInfo.properties.progParams)) {
2992
+ if (!xu_isEmpty(screenInfo.properties.progParams)) {
2410
2993
  _ds.in_parameters = {};
2411
2994
  _ds.out_parameters = {};
2412
2995
 
@@ -2538,7 +3121,7 @@ func.datasource.prepare = async function (SESSION_ID, prog_id, dataSourceNoP, pa
2538
3121
  _ds.refreshed = true;
2539
3122
 
2540
3123
  if (_ds.watcher) {
2541
- _.set(_ds, _ds.watcher.path, _ds.watcher.newValue);
3124
+ xu_set(_ds, _ds.watcher.path, _ds.watcher.newValue);
2542
3125
  }
2543
3126
  try {
2544
3127
  if (!_ds.v) _ds.v = {};
@@ -2548,7 +3131,7 @@ func.datasource.prepare = async function (SESSION_ID, prog_id, dataSourceNoP, pa
2548
3131
  _ds.data_feed = {};
2549
3132
 
2550
3133
  // _ds.v.old_dataSource = _.cloneDeep(_ds);
2551
- _ds.v.old_dataSource = klona.klona(_ds);
3134
+ _ds.v.old_dataSource = structuredClone(_ds);
2552
3135
  } catch (err) {
2553
3136
  console.error('function: init_existing_dataSource - error');
2554
3137
  return;
@@ -3525,7 +4108,7 @@ func.datasource.execute_field_init_events = async function (SESSION_ID, dataSour
3525
4108
  var expression = undefined;
3526
4109
  if (val.eventInfo.props.condition) expression = val.eventInfo.props.condition;
3527
4110
  var expCond = {};
3528
- if (expression && !_.isEmpty(expression)) {
4111
+ if (expression && !xu_isEmpty(expression)) {
3529
4112
  // check if expression exist
3530
4113
  expCond = await func.expression.get(SESSION_ID, expression, dataSourceSession, 'condition', rowIdP, null, null, val.fieldId); // execute expression
3531
4114
  cond = expCond.result;
@@ -3669,7 +4252,7 @@ func.datasource.get_view_events_count = async function (SESSION_ID, dataSourceSe
3669
4252
 
3670
4253
  _ds.viewEventExec_arr[index] = [];
3671
4254
 
3672
- if (!_prog.progEvents || _.isEmpty(_prog.progEvents)) return 0;
4255
+ if (!_prog.progEvents || xu_isEmpty(_prog.progEvents)) return 0;
3673
4256
 
3674
4257
  for (const event_obj of _prog.progEvents) {
3675
4258
  if (event_obj.data.type !== typeP) continue; // was false?? changed to true 020317
@@ -3682,7 +4265,7 @@ func.datasource.get_view_events_count = async function (SESSION_ID, dataSourceSe
3682
4265
  }
3683
4266
  }
3684
4267
 
3685
- if (_.isEmpty(event_obj.workflow)) continue;
4268
+ if (xu_isEmpty(event_obj.workflow)) continue;
3686
4269
  for (const trigger_obj of event_obj.workflow) {
3687
4270
  if (trigger_obj.data.enabled) {
3688
4271
  var expression;
@@ -3735,7 +4318,7 @@ func.datasource.execute_view_events = async function (SESSION_ID, dataSourceSess
3735
4318
  var index = typeP;
3736
4319
  if (eventIdP) index = typeP + '_' + eventIdP;
3737
4320
  var arr = _ds.viewEventExec_arr[index];
3738
- if (_.isEmpty(arr)) return;
4321
+ if (xu_isEmpty(arr)) return;
3739
4322
 
3740
4323
  for await (const val of arr) {
3741
4324
  if (!glb.IS_WORKER || !func.utils.is_onscreen_event(val.eventInfo.data.action) || (glb.IS_WORKER && _ds.v.run_at === 'server' && !func.utils.is_onscreen_event(val.eventInfo.data.action))) {
@@ -3748,7 +4331,8 @@ func.datasource.execute_view_events = async function (SESSION_ID, dataSourceSess
3748
4331
  if (cond) {
3749
4332
  var elem_params = undefined;
3750
4333
  if (!glb.IS_WORKER) {
3751
- elem_params = $('#' + _ds.containerId).data('params');
4334
+ const container_meta = func.runtime.ui.get_meta_by_element_id(_ds.containerId);
4335
+ elem_params = container_meta?.params;
3752
4336
  }
3753
4337
  const ret = await func.events.execute(
3754
4338
  SESSION_ID,
@@ -3866,12 +4450,12 @@ func.datasource.clean_all = function (SESSION_ID, dsP) {
3866
4450
 
3867
4451
  var get_child_ds = function (ds) {
3868
4452
  var arr = [];
3869
- _.forEach(SESSION_OBJ[SESSION_ID].DS_GLB, function (val, key) {
4453
+ for (const [key, val] of Object.entries(SESSION_OBJ[SESSION_ID].DS_GLB)) {
3870
4454
  if (val.parentDataSourceNo == ds) {
3871
4455
  arr.push(key);
3872
4456
  arr = arr.concat(get_child_ds(key));
3873
4457
  }
3874
- });
4458
+ }
3875
4459
  return arr;
3876
4460
  };
3877
4461
 
@@ -3884,13 +4468,13 @@ func.datasource.clean = function (SESSION_ID, screenIdP) {
3884
4468
  var arr = [];
3885
4469
  for (const [key, val] of Object.entries(SESSION_OBJ[SESSION_ID].DS_GLB)) {
3886
4470
  try {
4471
+ const _screen_el = val.screenId ? document.getElementById(val.screenId) : null;
4472
+ const screen_parent_id = _screen_el?.parentElement?.id || null;
3887
4473
  if (
3888
4474
  Number(key) > 0 &&
3889
4475
  (val.screenId === screenIdP ||
3890
4476
  val.rootScreenId === screenIdP ||
3891
- $('#' + val.screenId)
3892
- .parent()
3893
- .attr('id') === screenIdP ||
4477
+ screen_parent_id === screenIdP ||
3894
4478
  (val && val.parentDataSourceNo && arr.includes(val.parentDataSourceNo.toString())))
3895
4479
  ) {
3896
4480
  arr.push(key);
@@ -3956,14 +4540,12 @@ func.datasource.del = function (SESSION_ID, dsP) {
3956
4540
 
3957
4541
  var delete_pending_jobs = function () {
3958
4542
  var arr = [];
3959
- _.forEach(SESSION_OBJ[SESSION_ID].WORKER_OBJ.jobs, function (val, key) {
4543
+ for (const [key, val] of Object.entries(SESSION_OBJ[SESSION_ID].WORKER_OBJ.jobs)) {
3960
4544
  if (val && val.dsSessionP == dsP) {
3961
4545
  arr.push(key);
3962
- for (const [key, val] of Object.entries($('.screen_blocker'))) {
3963
- $(val).remove();
3964
- }
4546
+ func.runtime.ui.clear_screen_blockers();
3965
4547
  }
3966
- });
4548
+ }
3967
4549
  for (let val of arr.reverse()) {
3968
4550
  SESSION_OBJ[SESSION_ID].WORKER_OBJ.jobs.splice(val, 1);
3969
4551
  }
@@ -3982,8 +4564,9 @@ func.datasource.del = function (SESSION_ID, dsP) {
3982
4564
  }
3983
4565
  }
3984
4566
  }
3985
- if ($(SESSION_OBJ[SESSION_ID].root_element).find('xu-nav').length) {
3986
- var ds_obj = $(SESSION_OBJ[SESSION_ID].root_element).find('xu-nav')?.data()?.xuData.nav_params;
4567
+ const _nav_node = func.runtime.ui.get_first_node(SESSION_OBJ[SESSION_ID].root_element)?.querySelector?.('xu-nav');
4568
+ if (_nav_node) {
4569
+ var ds_obj = func.runtime.ui.get_data(_nav_node)?.xuData?.nav_params;
3987
4570
  if (ds_obj) {
3988
4571
  delete ds_obj[dsP];
3989
4572
  }
@@ -4090,7 +4673,7 @@ func.datasource.update = async function (SESSION_ID, datasource_changes, update_
4090
4673
  for (const [field_id, value] of Object.entries(fields_data)) {
4091
4674
  // mechanism to make update directly on the datasource object
4092
4675
  if (record_id === 'datasource_main') {
4093
- _.set(_ds, field_id, value);
4676
+ xu_set(_ds, field_id, value);
4094
4677
  const ret = update_xu_ref(dataSource);
4095
4678
  if (ret) {
4096
4679
  fields_changed.push(field_id);
@@ -4119,7 +4702,7 @@ func.datasource.update = async function (SESSION_ID, datasource_changes, update_
4119
4702
 
4120
4703
  await func.runtime.ui.refresh_screen({
4121
4704
  SESSION_ID,
4122
- fields_changed_arr: klona.klona(fields_changed),
4705
+ fields_changed_arr: structuredClone(fields_changed),
4123
4706
  datasource_changed: datasource_changed[0],
4124
4707
  fields_changed_datasource: datasource_changed[0],
4125
4708
  watcher: value,
@@ -4138,7 +4721,7 @@ func.datasource.update = async function (SESSION_ID, datasource_changes, update_
4138
4721
  try {
4139
4722
  const row_idx = func.common.find_ROWID_idx(_ds, record_id);
4140
4723
  // if (_ds.data_feed.rows[row_idx][field_id] !== value) {
4141
- if (!_.isEqual(_ds.data_feed.rows[row_idx][field_id], value)) {
4724
+ if (!xu_isEqual(_ds.data_feed.rows[row_idx][field_id], value)) {
4142
4725
  _ds.data_feed.rows[row_idx][field_id] = value;
4143
4726
  await set_fieldComputed_dependencies(dataSource, field_id, null);
4144
4727
 
@@ -4211,11 +4794,11 @@ func.datasource.update = async function (SESSION_ID, datasource_changes, update_
4211
4794
  }
4212
4795
 
4213
4796
  if (glb.IS_WORKER) {
4214
- if (!update_local_scope_only && !_.isEmpty(client_datasource_changes)) {
4797
+ if (!update_local_scope_only && !xu_isEmpty(client_datasource_changes)) {
4215
4798
  func.utils.post_back_to_client(SESSION_ID, 'update_client_eventChangesResults_from_worker', _session.worker_id, client_datasource_changes);
4216
4799
  }
4217
4800
  } else {
4218
- if (!update_local_scope_only && !_.isEmpty(server_datasource_changes)) {
4801
+ if (!update_local_scope_only && !xu_isEmpty(server_datasource_changes)) {
4219
4802
  const ret = await func.index.call_worker(SESSION_ID, {
4220
4803
  service: 'update_datasource_changes_from_client',
4221
4804
  data: {
@@ -4234,7 +4817,7 @@ func.datasource.update = async function (SESSION_ID, datasource_changes, update_
4234
4817
  // await func.UI.screen.refresh_xu_attributes(SESSION_ID, _.cloneDeep(fields_changed), null, null, findMin(datasource_changed), avoid_xu_for_refresh, trigger);
4235
4818
  await func.runtime.ui.refresh_xu_attributes({
4236
4819
  SESSION_ID,
4237
- fields_arr: klona.klona(fields_changed),
4820
+ fields_arr: structuredClone(fields_changed),
4238
4821
  jobNoP: null,
4239
4822
  $elm_to_search: null,
4240
4823
  dsSession_changed: findMin(datasource_changed),
@@ -4245,7 +4828,7 @@ func.datasource.update = async function (SESSION_ID, datasource_changes, update_
4245
4828
  // await removed from the below function cause to dead lock Mar 3 25
4246
4829
  await func.runtime.ui.refresh_screen({
4247
4830
  SESSION_ID,
4248
- fields_changed_arr: klona.klona(fields_changed),
4831
+ fields_changed_arr: structuredClone(fields_changed),
4249
4832
  datasource_changed: null,
4250
4833
  fields_changed_datasource: datasource_changed[0],
4251
4834
  });
@@ -4316,7 +4899,7 @@ func.datasource.callback = async function (SESSION_ID, dsSessionP, rowIdP, jobNo
4316
4899
  dsSession: dsSessionP,
4317
4900
  prop: _ds.log_prop + ' ' + 'adapter',
4318
4901
  });
4319
- if (!glb.IS_WORKER) $(_session.root_element).css('cursor', 'default');
4902
+ if (!glb.IS_WORKER) func.runtime.platform.set_cursor(_session.root_element, 'default');
4320
4903
 
4321
4904
  if (_ds.prog_id) {
4322
4905
  let _ds = _session.DS_GLB[dsSessionP];
@@ -4868,7 +5451,7 @@ func.datasource.get_viewLoops = async function (SESSION_ID, dataSourceSession, d
4868
5451
  // var v = _ds.v;
4869
5452
  var ret = default_limit;
4870
5453
 
4871
- if (batch_source === 'db_data') ret = _.size(data.rows);
5454
+ if (batch_source === 'db_data') ret = data.rows.length;
4872
5455
  if (batch_source === 'array' || batch_source === 'csv') ret = data.length;
4873
5456
  if (batch_source === 'json') ret = Object.keys(data).length;
4874
5457
  if (_ds.progDataSource?.dataSourceLimit) {
@@ -4895,7 +5478,7 @@ func.datasource.set_VIEW_data = async function (SESSION_ID, args, _ds) {
4895
5478
  };
4896
5479
  _ds.viewEventExec_arr = {};
4897
5480
 
4898
- var view = _.cloneDeep(await func.utils.VIEWS_OBJ.get(SESSION_ID, args.prog_id));
5481
+ var view = structuredClone(await func.utils.VIEWS_OBJ.get(SESSION_ID, args.prog_id));
4899
5482
  // var view = klona.klona(await func.utils.VIEWS_OBJ.get(SESSION_ID, args.prog_id));
4900
5483
 
4901
5484
  _ds.v.dataSourceSrcType = view.dataSourceSrcType;
@@ -4941,11 +5524,11 @@ func.datasource.get_cast_val = async function (SESSION_ID, source, dsSession, va
4941
5524
  if (error) {
4942
5525
  return func.utils.debug_report(SESSION_ID, msg, '', 'W');
4943
5526
  }
4944
- func.utils.debug_report(SESSION_ID, msg + ' ' + _.capitalize(source) + prog_info, '', 'E');
5527
+ func.utils.debug_report(SESSION_ID, msg + ' ' + (source.charAt(0).toUpperCase() + source.slice(1).toLowerCase()) + prog_info, '', 'E');
4945
5528
  };
4946
5529
  const report_conversion_warn = function (res) {
4947
5530
  var msg = `type mismatch auto conversion from value ${valP} to ${typeP}`;
4948
- func.utils.debug_report(SESSION_ID, msg + ' ' + _.capitalize(source) + prog_info, '', 'W');
5531
+ func.utils.debug_report(SESSION_ID, msg + ' ' + (source.charAt(0).toUpperCase() + source.slice(1).toLowerCase()) + prog_info, '', 'W');
4949
5532
  };
4950
5533
  // var ret = valP;
4951
5534
  if (error) {
@@ -5014,7 +5597,7 @@ func.datasource.update_changes_for_out_parameter = async function (SESSION_ID, d
5014
5597
  }
5015
5598
  }
5016
5599
  }
5017
- if (!_.isEmpty(data)) {
5600
+ if (!xu_isEmpty(data)) {
5018
5601
  let datasource_changes = {
5019
5602
  [calling_dsP]: { [_calling_ds.currentRecordId]: data },
5020
5603
  };
@@ -5125,7 +5708,7 @@ func.utils.DOCS_OBJ.get = async function (SESSION_ID, idP) {
5125
5708
 
5126
5709
  if (idP !== 'system') {
5127
5710
  DOCS_OBJ[_app_id][idP] = await module.DOCS_OBJ_get(SESSION_ID, idP);
5128
- if (DOCS_OBJ[_app_id][idP] && _.isEmpty(DOCS_OBJ[_app_id][idP])) {
5711
+ if (DOCS_OBJ[_app_id][idP] && xu_isEmpty(DOCS_OBJ[_app_id][idP])) {
5129
5712
  await func.utils.remove_cached_objects(SESSION_ID);
5130
5713
 
5131
5714
  delete DOCS_OBJ[_app_id][idP];
@@ -5137,7 +5720,7 @@ func.utils.DOCS_OBJ.get = async function (SESSION_ID, idP) {
5137
5720
  if (APP_OBJ[_app_id].app_imported_projects) {
5138
5721
  for await (const imported_app_id of APP_OBJ[_app_id].app_imported_projects) {
5139
5722
  var view_ret = await module.DOCS_OBJ_get(SESSION_ID, 'global_' + imported_app_id);
5140
- DOCS_OBJ[_app_id][idP] = _.merge(DOCS_OBJ[_app_id][idP], view_ret);
5723
+ DOCS_OBJ[_app_id][idP] = Object.assign(DOCS_OBJ[_app_id][idP], view_ret);
5141
5724
  }
5142
5725
  }
5143
5726
  return DOCS_OBJ[_app_id][idP];
@@ -5219,13 +5802,13 @@ func.utils.get_dateTime = async function (SESSION_ID, typeP, dateP) {
5219
5802
  let ts = await get_server_ts();
5220
5803
  sysDate = new Date(ts);
5221
5804
  }
5222
- var day = _.padStart(sysDate.getDate(), 2, '0');
5223
- var month = _.padStart(sysDate.getMonth() + 1, 2, '0');
5805
+ var day = String(sysDate.getDate()).padStart(2, '0');
5806
+ var month = String(sysDate.getMonth() + 1).padStart(2, '0');
5224
5807
  var year = sysDate.getFullYear();
5225
- var week = _.padStart(getWeekNumber(sysDate), 2, '0');
5226
- var hour = _.padStart(sysDate.getHours(), 2, '0');
5227
- var minute = _.padStart(sysDate.getMinutes(), 2, '0');
5228
- var second = _.padStart(sysDate.getSeconds(), 2, '0');
5808
+ var week = String(getWeekNumber(sysDate)).padStart(2, '0');
5809
+ var hour = String(sysDate.getHours()).padStart(2, '0');
5810
+ var minute = String(sysDate.getMinutes()).padStart(2, '0');
5811
+ var second = String(sysDate.getSeconds()).padStart(2, '0');
5229
5812
  if (typeP === 'SYS_DATE') return year + '-' + month + '-' + day;
5230
5813
  if (typeP === 'SYS_DATE_TIME') return year + '-' + month + '-' + day + 'T' + hour + ':' + minute;
5231
5814
  if (typeP === 'SYS_DATE_VALUE') return sysDate.valueOf();
@@ -5263,7 +5846,7 @@ func.utils.clean_returned_datasource = function (SESSION_ID, DS) {
5263
5846
  var _session = SESSION_OBJ[SESSION_ID];
5264
5847
  if (!_session.DS_GLB[DS]) return;
5265
5848
 
5266
- var obj = _.clone(_session.DS_GLB[DS]);
5849
+ var obj = { ..._session.DS_GLB[DS] };
5267
5850
 
5268
5851
  delete obj.screen_params;
5269
5852
 
@@ -5283,7 +5866,7 @@ func.utils.clean_returned_datasource = function (SESSION_ID, DS) {
5283
5866
 
5284
5867
  const clean_empty_objects = function () {
5285
5868
  for (const [key, val] of Object.entries(obj)) {
5286
- if (typeof val === 'object' && !Array.isArray(val) && _.isEmpty(val)) {
5869
+ if (typeof val === 'object' && !Array.isArray(val) && xu_isEmpty(val)) {
5287
5870
  delete obj[key];
5288
5871
  }
5289
5872
  }
@@ -5386,7 +5969,7 @@ func.utils.job_worker = function (session_id) {
5386
5969
  func.utils.debug_report(SESSION_ID, 'utils.worker.reset', 'worker not responding', 'E', '', _session.WORKER_OBJ.jobs);
5387
5970
  _session.WORKER_OBJ.jobs = [];
5388
5971
  _session.WORKER_OBJ.stat = null;
5389
- $('.screen_blocker').remove();
5972
+ func.runtime.ui.clear_screen_blockers();
5390
5973
  };
5391
5974
  return {
5392
5975
  _interval: null,
@@ -5527,8 +6110,9 @@ func.utils.makeid = function (length) {
5527
6110
  func.utils.get_device = function () {
5528
6111
  var device;
5529
6112
  try {
5530
- if (window.cordova) {
5531
- device = window.cordova.platformId;
6113
+ const win = func.runtime.platform.get_window();
6114
+ if (win?.cordova) {
6115
+ device = win.cordova.platformId;
5532
6116
  }
5533
6117
  } catch (e) {
5534
6118
  console.error('error using ui element in server side request');
@@ -5673,7 +6257,7 @@ func.utils.ws_worker.functions = {
5673
6257
  });
5674
6258
  },
5675
6259
  update_datasource_changes_from_client: async function (params, promise_queue_id) {
5676
- if (_.isEmpty(SESSION_OBJ)) return;
6260
+ if (xu_isEmpty(SESSION_OBJ)) return;
5677
6261
  var SESSION_ID = params.session_id;
5678
6262
  var _session = SESSION_OBJ[SESSION_ID];
5679
6263
  if (!_session) {
@@ -5869,16 +6453,8 @@ func.utils.clean_stringify_null = function (key, value) {
5869
6453
 
5870
6454
  func.utils.load_js_on_demand = async function (js_src, type) {
5871
6455
  const get_script = function (callback) {
5872
- function getScript(scriptUrl, callback) {
5873
- const script = document.createElement('script');
5874
- script.src = scriptUrl;
5875
- if (type) script.type = type;
5876
- script.onload = callback;
5877
-
5878
- document.head.appendChild(script);
5879
- }
5880
6456
  if (glb.IS_WORKER) {
5881
- callback(script);
6457
+ callback();
5882
6458
  return;
5883
6459
  }
5884
6460
  function isScriptLoaded(src) {
@@ -5888,8 +6464,7 @@ func.utils.load_js_on_demand = async function (js_src, type) {
5888
6464
  if (isScriptLoaded(js_src)) {
5889
6465
  callback(false);
5890
6466
  } else {
5891
- getScript(js_src, function (response, status) {
5892
- // console.log(response,status)
6467
+ func.runtime.platform.load_script(js_src, type, function () {
5893
6468
  callback(true);
5894
6469
  GLB_JS_SCRIPTS_LOADED.push(js_src);
5895
6470
  });
@@ -5902,33 +6477,11 @@ func.utils.load_js_on_demand = async function (js_src, type) {
5902
6477
  };
5903
6478
 
5904
6479
  func.utils.load_css_on_demand = function (css_href) {
5905
- function isCssLoaded(src) {
5906
- try {
5907
- return document.querySelector('link[href="' + src + '"]') ? true : false;
5908
- } catch (err) {
5909
- console.warn(`load css ${css_href} failed`);
5910
- return true;
5911
- }
5912
- }
5913
-
5914
- if (isCssLoaded(css_href)) {
5915
- return;
5916
- }
5917
- return $('<link/>', {
5918
- rel: 'stylesheet',
5919
- type: 'text/css',
5920
- href: css_href,
5921
- }).prependTo('head');
6480
+ func.runtime.platform.load_css(css_href);
5922
6481
  };
5923
6482
 
5924
6483
  func.utils.remove_js_css_file = function (filename, filetype) {
5925
- var targetelement = filetype == 'js' ? 'script' : filetype == 'css' ? 'link' : 'none'; //determine element type to create nodelist from
5926
- var targetattr = filetype == 'js' ? 'src' : filetype == 'css' ? 'href' : 'none'; //determine corresponding attribute to test for
5927
- var allsuspects = document.getElementsByTagName(targetelement);
5928
- for (var i = allsuspects.length; i >= 0; i--) {
5929
- //search backwards within node list for matching elements to remove
5930
- if (allsuspects[i] && allsuspects[i].getAttribute(targetattr) != null && allsuspects[i].getAttribute(targetattr).indexOf(filename) != -1) allsuspects[i].parentNode.removeChild(allsuspects[i]); //remove element by calling parentNode.removeChild()
5931
- }
6484
+ func.runtime.platform.remove_js_css(filename, filetype);
5932
6485
  };
5933
6486
 
5934
6487
  func.utils.replace_studio_drive_url = function (SESSION_ID, val) {
@@ -6275,7 +6828,7 @@ func.utils.alerts.popup = function (title, message, alert_type) {
6275
6828
  },
6276
6829
  ];
6277
6830
 
6278
- popup.create(_.upperFirst(alert_type), title, message, buttons);
6831
+ popup.create(alert_type.charAt(0).toUpperCase() + alert_type.slice(1), title, message, buttons);
6279
6832
  };
6280
6833
 
6281
6834
  func.utils.get_system_error_msg = function () {
@@ -6922,7 +7475,7 @@ func.utils.call_plugin_api = function (SESSION_ID, plugin_nameP, dataP) {
6922
7475
  app_token: _session.app_token,
6923
7476
  };
6924
7477
 
6925
- data = _.assignIn(data, dataP);
7478
+ data = Object.assign(data, dataP);
6926
7479
 
6927
7480
  fetch(`https://xuda.ai/ppi/${plugin_nameP}`, {
6928
7481
  method: 'POST',
@@ -7080,7 +7633,7 @@ func.utils.get_resource_filename = function (build, filename) {
7080
7633
  };
7081
7634
 
7082
7635
  func.utils.set_SYS_GLOBAL_OBJ_WIDGET_INFO = async function (SESSION_ID, docP) {
7083
- var obj = _.clone(docP);
7636
+ var obj = { ...docP };
7084
7637
  obj.date = await func.utils.get_dateTime(SESSION_ID, 'SYS_DATE', docP.date);
7085
7638
  obj.time = await func.utils.get_dateTime(SESSION_ID, 'SYS_TIME', docP.date);
7086
7639
 
@@ -7195,7 +7748,7 @@ func.events.validate = async function (SESSION_ID, triggerP, dsSessionP, eventId
7195
7748
 
7196
7749
  let value = await func.common.get_cast_val(SESSION_ID, 'events', fieldId, field_info.props.fieldType, args[fieldId].value);
7197
7750
 
7198
- if (!_.isEmpty(args[fieldId].fx)) {
7751
+ if (!xu_isEmpty(args[fieldId].fx)) {
7199
7752
  const fx_ret = await func.expression.get(SESSION_ID, args[fieldId].fx, dsSessionP, 'update');
7200
7753
  value = fx_ret.result;
7201
7754
  }
@@ -7217,7 +7770,7 @@ func.events.validate = async function (SESSION_ID, triggerP, dsSessionP, eventId
7217
7770
  if (_event.workflow) {
7218
7771
  // check if event property exist
7219
7772
 
7220
- if (!_event.workflow || _.isEmpty(_event.workflow)) return;
7773
+ if (!_event.workflow || xu_isEmpty(_event.workflow)) return;
7221
7774
  // check events has rows
7222
7775
  for (const trigger_obj of _event.workflow) {
7223
7776
  //run events rows
@@ -7237,17 +7790,19 @@ func.events.validate = async function (SESSION_ID, triggerP, dsSessionP, eventId
7237
7790
  if (_ds.panel_div_id) {
7238
7791
  try {
7239
7792
  container = '#' + _ds.panel_div_id;
7240
- if ($(container).data().xuData.panel_info) {
7241
- screen_prop = $(container).data().xuData.panel_info.paramsP;
7793
+ const panel_meta = func.runtime.ui.get_meta_by_element_id(_ds.panel_div_id);
7794
+ if (panel_meta?.xuData?.panel_info) {
7795
+ screen_prop = panel_meta.xuData.panel_info.paramsP;
7242
7796
  } else {
7243
7797
  ///////////////
7244
7798
  container = '#' + _session.DS_GLB[dsSessionP].screenId;
7799
+ const screen_meta = func.runtime.ui.get_meta_by_element_id(_session.DS_GLB[dsSessionP].screenId);
7245
7800
 
7246
- if ($(container) && $(container).data()) {
7247
- screen_prop = $(container).data().xuData.paramsP;
7801
+ if (screen_meta?.xuData) {
7802
+ screen_prop = screen_meta.xuData.paramsP;
7248
7803
  }
7249
7804
 
7250
- if (!$(container) || !$(container).length) {
7805
+ if (!screen_meta) {
7251
7806
  container = '#' + _session.DS_GLB[dsSessionP].containerId;
7252
7807
  }
7253
7808
  //////////////
@@ -7257,12 +7812,13 @@ func.events.validate = async function (SESSION_ID, triggerP, dsSessionP, eventId
7257
7812
  }
7258
7813
  } else {
7259
7814
  container = '#' + _ds.screenId;
7815
+ const screen_meta = func.runtime.ui.get_meta_by_element_id(_ds.screenId);
7260
7816
 
7261
- if ($(container) && $(container).data()) {
7262
- screen_prop = $(container).data().xuData.paramsP;
7817
+ if (screen_meta?.xuData) {
7818
+ screen_prop = screen_meta.xuData.paramsP;
7263
7819
  }
7264
7820
 
7265
- if (!$(container) || !$(container).length) {
7821
+ if (!screen_meta) {
7266
7822
  container = '#' + _ds.containerId;
7267
7823
  }
7268
7824
  }
@@ -7433,12 +7989,12 @@ func.events.find_job_index = function (SESSION_ID, jobNoP) {
7433
7989
  var _session = SESSION_OBJ[SESSION_ID];
7434
7990
  var ret = null;
7435
7991
  if (!_session.WORKER_OBJ) return ret;
7436
- _.forEach(_session.WORKER_OBJ.jobs, function (val, key) {
7992
+ for (const [key, val] of Object.entries(_session.WORKER_OBJ.jobs)) {
7437
7993
  if (val && val.job_num == jobNoP) {
7438
7994
  ret = key;
7439
- return false;
7995
+ break;
7440
7996
  }
7441
- });
7997
+ }
7442
7998
  return ret;
7443
7999
  };
7444
8000
  func.events.execute = async function (
@@ -7500,7 +8056,7 @@ func.events.execute = async function (
7500
8056
  var field_elm = elementP;
7501
8057
 
7502
8058
  var calling_field_id = field_elm;
7503
- if (field_elm && typeof field_elm === 'object') calling_field_id = field_elm.attr('xu-ui-id');
8059
+ if (field_elm && typeof field_elm === 'object') calling_field_id = func.runtime.ui.get_attr(field_elm, 'xu-ui-id');
7504
8060
 
7505
8061
  var log_nodeId;
7506
8062
  var log_prog_id;
@@ -7663,7 +8219,7 @@ func.events.execute = async function (
7663
8219
  var $calling_container;
7664
8220
  if (_session.WORKER_OBJ.jobs[job_index]) {
7665
8221
  if (_session.WORKER_OBJ.jobs[job_index].paramsP) {
7666
- $calling_container = $('#' + _session.WORKER_OBJ.jobs[job_index].paramsP.callingContainerP);
8222
+ $calling_container = func.runtime.ui.find_element_by_id(_session.WORKER_OBJ.jobs[job_index].paramsP.callingContainerP);
7667
8223
  } else {
7668
8224
  $calling_container = ''; // calling from datasource 0
7669
8225
  _session.WORKER_OBJ.jobs[job_index].paramsP = {};
@@ -7679,7 +8235,7 @@ func.events.execute = async function (
7679
8235
  return await func.runtime.ui.init_screen({
7680
8236
  SESSION_ID,
7681
8237
  prog_id: await get_prog_id(),
7682
- sourceScreenP: $(containerP)?.data()?.xuData.screenId,
8238
+ sourceScreenP: func.runtime.ui.get_data(containerP)?.xuData?.screenId,
7683
8239
  callingDataSource_objP: _session.DS_GLB[dsSession],
7684
8240
  $callingContainerP: $calling_container,
7685
8241
  triggerIdP: eventIdP,
@@ -7711,7 +8267,7 @@ func.events.execute = async function (
7711
8267
  var _session = SESSION_OBJ[SESSION_ID];
7712
8268
 
7713
8269
  const set_SYS_GLOBAL_OBJ_WIDGET_INFO = async function (docP) {
7714
- var obj = _.clone(docP);
8270
+ var obj = { ...docP };
7715
8271
  obj.date = await func.utils.get_dateTime(SESSION_ID, 'SYS_DATE', docP.date);
7716
8272
  obj.time = await func.utils.get_dateTime(SESSION_ID, 'SYS_TIME', docP.date);
7717
8273
 
@@ -7926,7 +8482,7 @@ func.events.execute = async function (
7926
8482
  emit_event: async function () {
7927
8483
  if (refIdP.value) {
7928
8484
  // if (descP.value) {
7929
- $(document).trigger(refIdP.value, [_session.DS_GLB[dsSession]]);
8485
+ func.runtime.platform.emit(refIdP.value, [_session.DS_GLB[dsSession]]);
7930
8486
  } else {
7931
8487
  func.utils.debug_report(SESSION_ID, 'func.events.execute', 'Event name missing', 'E');
7932
8488
  }
@@ -7998,7 +8554,7 @@ func.events.execute = async function (
7998
8554
 
7999
8555
  let _ds_new = _session.DS_GLB[ret.dsSessionP];
8000
8556
  let parameters = args?.calling_trigger_prop?.data?.name?.parameters;
8001
- if (parameters && !_.isEmpty(parameters)) {
8557
+ if (parameters && !xu_isEmpty(parameters)) {
8002
8558
  await func.datasource.update_changes_for_out_parameter(SESSION_ID, _ds_new.dsSession, _ds.dsSession);
8003
8559
  }
8004
8560
 
@@ -8017,7 +8573,7 @@ func.events.execute = async function (
8017
8573
  },
8018
8574
  update: async function () {
8019
8575
  const obj_values_to_update = func.datasource.get_viewFields_for_update_function(SESSION_ID, calling_trigger_prop, null, dsSessionP);
8020
- if (!obj_values_to_update || _.isEmpty(obj_values_to_update)) {
8576
+ if (!obj_values_to_update || xu_isEmpty(obj_values_to_update)) {
8021
8577
  func.utils.debug_report(SESSION_ID, 'Update values object is empty', '', 'W');
8022
8578
  if (jobNoP) func.events.delete_job(SESSION_ID, jobNoP);
8023
8579
  return;
@@ -8027,12 +8583,14 @@ func.events.execute = async function (
8027
8583
  for await (const [key, val] of Object.entries(obj_values_to_update)) {
8028
8584
  var $element;
8029
8585
 
8586
+ var iterate_info = null;
8030
8587
  if (elementP) {
8031
- $element = $(`[xu-ui-id="${elementP}"]`).clone(true);
8588
+ const element_meta = func.runtime.ui.get_meta(elementP, 'xuData');
8589
+ iterate_info = element_meta?.iterate_info || null;
8032
8590
  }
8033
8591
 
8034
- let ret_field_id = await func.expression.get(SESSION_ID, val.id.trim(), dsSessionP, 'update', null, null, null, null, null, null, $element?.length ? $element?.data()?.xuData?.iterate_info : null);
8035
- let ret_value = await func.expression.get(SESSION_ID, val.val.trim(), dsSessionP, 'update', null, null, null, null, null, null, $element?.length ? $element?.data()?.xuData?.iterate_info : null);
8592
+ let ret_field_id = await func.expression.get(SESSION_ID, val.id.trim(), dsSessionP, 'update', null, null, null, null, null, null, iterate_info);
8593
+ let ret_value = await func.expression.get(SESSION_ID, val.val.trim(), dsSessionP, 'update', null, null, null, null, null, null, iterate_info);
8036
8594
  let _field_id = ret_field_id.result;
8037
8595
  let _value = ret_value.result;
8038
8596
 
@@ -8207,11 +8765,11 @@ func.events.execute = async function (
8207
8765
  if (error) {
8208
8766
  return func.utils.debug_report(SESSION_ID, msg, '', 'W');
8209
8767
  }
8210
- func.utils.debug_report(SESSION_ID, msg + ' ' + _.capitalize(source) + prog_info, '', 'E');
8768
+ func.utils.debug_report(SESSION_ID, msg + ' ' + (source.charAt(0).toUpperCase() + source.slice(1).toLowerCase()) + prog_info, '', 'E');
8211
8769
  };
8212
8770
  const report_conversion_warn = function (res) {
8213
8771
  var msg = `${elementP} >${triggerP} >${functionP} > type mismatch auto conversion from value ${valP} to ${typeP}`;
8214
- func.utils.debug_report(SESSION_ID, msg + ' ' + _.capitalize(source) + prog_info, '', 'W');
8772
+ func.utils.debug_report(SESSION_ID, msg + ' ' + (source.charAt(0).toUpperCase() + source.slice(1).toLowerCase()) + prog_info, '', 'W');
8215
8773
  };
8216
8774
  // var ret = valP;
8217
8775
  if (error) {
@@ -8226,8 +8784,7 @@ func.events.execute = async function (
8226
8784
  // report_conversion_warn
8227
8785
  // );
8228
8786
 
8229
- var payload = _.reduce(
8230
- payload_arr,
8787
+ var payload = payload_arr.reduce(
8231
8788
  (ret, val, key) => {
8232
8789
  ret[val.key] = module.cast(val.type, val.val, report_conversion_error, report_conversion_warn);
8233
8790
 
@@ -8344,12 +8901,12 @@ func.events.check_jobs_idle = async function (SESSION_ID, jobsP) {
8344
8901
  var listener = setInterval(function () {
8345
8902
  var found;
8346
8903
  for (const [key, val] of Object.entries(jobsP)) {
8347
- _.forEach(_session.WORKER_OBJ.jobs, function (val2, key2) {
8904
+ for (const [key2, val2] of Object.entries(_session.WORKER_OBJ.jobs)) {
8348
8905
  if (key2 === val) {
8349
8906
  found = true;
8350
- return false;
8907
+ break;
8351
8908
  }
8352
- });
8909
+ }
8353
8910
  }
8354
8911
  if (!found) {
8355
8912
  do_callback();
@@ -8357,7 +8914,7 @@ func.events.check_jobs_idle = async function (SESSION_ID, jobsP) {
8357
8914
  }
8358
8915
  }, 100);
8359
8916
  var do_callback = function () {
8360
- window.clearInterval(listener);
8917
+ clearInterval(listener);
8361
8918
  resolve();
8362
8919
  };
8363
8920
  });
@@ -8369,7 +8926,7 @@ setInterval(function () {
8369
8926
  }, 1000);
8370
8927
 
8371
8928
  func.events.set_browser_changes = function (dsP, fieldsChangedP) {
8372
- if (fieldsChangedP.includes('SYS_GLOBAL_STR_BROWSER_TITLE')) document.title = dsP.dataset_new['SYS_GLOBAL_STR_BROWSER_TITLE'];
8929
+ if (fieldsChangedP.includes('SYS_GLOBAL_STR_BROWSER_TITLE')) func.runtime.platform.set_title(dsP.dataset_new['SYS_GLOBAL_STR_BROWSER_TITLE']);
8373
8930
  };
8374
8931
 
8375
8932
  func.events.execute_PENDING_OPEN_URL_EVENTS = async function () {
@@ -8392,7 +8949,7 @@ func.events.execute_PENDING_OPEN_URL_EVENTS = async function () {
8392
8949
  prog_id: params_obj.prog,
8393
8950
  sourceScreenP: null,
8394
8951
  callingDataSource_objP: null,
8395
- $callingContainerP: $('#embed_' + SESSION_ID),
8952
+ $callingContainerP: func.runtime.ui.get_session_root(SESSION_ID),
8396
8953
  triggerIdP: null,
8397
8954
  rowIdP: null,
8398
8955
  jobNoP: null,
@@ -8418,7 +8975,7 @@ func.events.invoke = async function (event_id) {
8418
8975
  var ds;
8419
8976
  for await (const [ds_key, val] of Object.entries(_session.DS_GLB)) {
8420
8977
  const _view_obj = await func.utils.VIEWS_OBJ.get(SESSION_ID, val.prog_id);
8421
- if (_.isEmpty(_view_obj.progEvents)) continue;
8978
+ if (xu_isEmpty(_view_obj.progEvents)) continue;
8422
8979
  if (ds) break;
8423
8980
  for await (const [key, val] of Object.entries(_view_obj.progEvents)) {
8424
8981
  if (val?.data?.type === 'user_defined' && val.data.event_name === event_id) {
@@ -8475,7 +9032,7 @@ func.expression.get = async function (SESSION_ID, valP, dsSessionP, sourceP, row
8475
9032
  }
8476
9033
  }
8477
9034
 
8478
- ret = ret.replace(/\&amp;/g, '&');
9035
+ if (ret.includes('&amp;')) ret = ret.replace(/\&amp;/g, '&');
8479
9036
  ret = func.utils.replace_studio_drive_url(SESSION_ID, ret);
8480
9037
 
8481
9038
  const end_results = function () {
@@ -8539,13 +9096,13 @@ func.expression.get = async function (SESSION_ID, valP, dsSessionP, sourceP, row
8539
9096
  const variable_not_exist = async function () {
8540
9097
  try {
8541
9098
  if (sourceP !== 'arguments') {
8542
- if (ret && ret.substr(0, 6) === '_DATE_') {
8543
- ret = ret.substr(6);
9099
+ if (ret && ret.startsWith('_DATE_')) {
9100
+ ret = ret.slice(6);
8544
9101
  } else if (
8545
- (ret && ret.length === 10 && ret.substr(4, 1) === '-' && ret.substr(7, 1) === '-') ||
8546
- ret === 'self' // bypass eval for date 2017-03-22
9102
+ ret === 'self' || // bypass eval for 'self'
9103
+ (ret && ret.length === 10 && ret[4] === '-' && ret[7] === '-') // bypass eval for date 2017-03-22
8547
9104
  ) {
8548
- ret = ret;
9105
+ // date or 'self' — skip eval, return as-is
8549
9106
  } else {
8550
9107
  ret = await func.expression.secure_eval(SESSION_ID, sourceP, ret, jobNo, dsSessionP, js_script_callback);
8551
9108
  }
@@ -8579,8 +9136,10 @@ func.expression.get = async function (SESSION_ID, valP, dsSessionP, sourceP, row
8579
9136
  var var_Arr = [];
8580
9137
  const split = func.expression.parse(ret) || [];
8581
9138
  // console.log(valP, split);
8582
- for await (const [arr_key, val] of Object.entries(split)) {
9139
+ const split_entries = Object.entries(split);
9140
+ for (let entry_i = 0; entry_i < split_entries.length; entry_i++) {
8583
9141
  // run each field
9142
+ const [arr_key, val] = split_entries[entry_i];
8584
9143
  const key = Number(arr_key);
8585
9144
  var_Arr[key] = {};
8586
9145
  var_Arr[key].value = val.value;
@@ -8625,14 +9184,16 @@ func.expression.get = async function (SESSION_ID, valP, dsSessionP, sourceP, row
8625
9184
  var prevData = var_Arr[key - 1].value;
8626
9185
  var_Arr[key].value = prevData[data]; // @objB[@var]
8627
9186
  if (val.value.indexOf('.') > -1) {
8628
- property2 = await func.expression.get_property(val.value).property2; //val.value.substr(val.value.indexOf(".") + 1, val.value.length); // get .
9187
+ const props_split = await func.expression.get_property(val.value);
9188
+ property2 = props_split.property2;
8629
9189
  if (prevData[data]) set_value(prevData[data][property2]);
8630
9190
  // var_Arr[key].value = prevData[data][property2]; //@objB[@var].property
8631
9191
  }
8632
9192
  delete var_Arr[key - 1];
8633
9193
  } else {
8634
- property1 = await func.expression.get_property(val.value).property1;
8635
- property2 = await func.expression.get_property(val.value).property2;
9194
+ const props = await func.expression.get_property(val.value);
9195
+ property1 = props.property1;
9196
+ property2 = props.property2;
8636
9197
  if (property1) {
8637
9198
  var_Arr[key].value = data[property1]; // @var["value"] or @var.property
8638
9199
  if (property2) {
@@ -8680,7 +9241,7 @@ func.expression.get = async function (SESSION_ID, valP, dsSessionP, sourceP, row
8680
9241
  var exp_exist;
8681
9242
  var var_error_found;
8682
9243
  // merge arr values
8683
- _.forEach(var_Arr, function (val, key) {
9244
+ var_Arr.forEach(function (val, key) {
8684
9245
  if (sourceP === 'UI Property EXP') {
8685
9246
  let ret = func.utils.get_drive_url(SESSION_ID, val.value, true);
8686
9247
  if (ret.changed) {
@@ -8756,7 +9317,7 @@ func.expression.get = async function (SESSION_ID, valP, dsSessionP, sourceP, row
8756
9317
  if (exp.res) res = exp.res;
8757
9318
  // do second pass when exp exist
8758
9319
  else res = [exp.result];
8759
- fields = _.assignIn(exp.fields, fieldsP);
9320
+ fields = Object.assign(exp.fields, fieldsP);
8760
9321
  }
8761
9322
  var result = join(res);
8762
9323
 
@@ -9078,9 +9639,15 @@ func.expression.get = async function (SESSION_ID, valP, dsSessionP, sourceP, row
9078
9639
  // return res;
9079
9640
  // };
9080
9641
 
9642
+ func.expression._parse_cache = new Map();
9643
+
9081
9644
  func.expression.parse = function (input) {
9082
9645
  if (typeof input !== 'string') return [];
9083
9646
 
9647
+ if (func.expression._parse_cache.has(input)) {
9648
+ return func.expression._parse_cache.get(input).map(function (s) { return Object.assign({}, s); });
9649
+ }
9650
+
9084
9651
  const segments = [];
9085
9652
  let pos = 0;
9086
9653
 
@@ -9103,7 +9670,14 @@ func.expression.parse = function (input) {
9103
9670
  pos += part.length;
9104
9671
  }
9105
9672
 
9106
- return segments;
9673
+ // Evict oldest entry if cache exceeds limit
9674
+ if (func.expression._parse_cache.size >= 500) {
9675
+ const firstKey = func.expression._parse_cache.keys().next().value;
9676
+ func.expression._parse_cache.delete(firstKey);
9677
+ }
9678
+ func.expression._parse_cache.set(input, segments);
9679
+
9680
+ return segments.map(function (s) { return Object.assign({}, s); });
9107
9681
  };
9108
9682
 
9109
9683
  func.expression.get_property = async function (valP) {