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

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 +730 -155
  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,7 +810,7 @@ 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;
@@ -645,7 +832,7 @@ func.runtime.bind.get_source_value = function (_ds, bind_field_id, is_dynamic_fi
645
832
  };
646
833
  func.runtime.bind.format_display_value = function ($elm, field_prop, bind_field_id, expression_value, value, input_field_type) {
647
834
  const field_type = func.runtime.bind.get_field_type(field_prop);
648
- const elm_value = $elm.attr('value');
835
+ const elm_value = func.runtime.ui.get_attr($elm, 'value');
649
836
 
650
837
  if (field_type === 'array' && input_field_type === 'checkbox' && elm_value) {
651
838
  return value.includes(elm_value);
@@ -671,7 +858,7 @@ func.runtime.bind.update_reference_source_array = async function (options) {
671
858
 
672
859
  const arr_idx = Number(options.iterate_info._key);
673
860
  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);
861
+ let new_arr = klona.klona(dataset_arr.ret.value);
675
862
 
676
863
  if (field_type === 'object' && options.val_is_reference_field) {
677
864
  let obj_item = new_arr[arr_idx];
@@ -683,15 +870,15 @@ func.runtime.bind.update_reference_source_array = async function (options) {
683
870
  }
684
871
 
685
872
  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);
873
+ await func.datasource.update(options.SESSION_ID, datasource_changes);
687
874
  return true;
688
875
  };
689
876
  func.runtime.resources.load_cdn = async function (SESSION_ID, resource) {
690
877
  let normalized_resource = resource;
691
- if (!_.isObject(normalized_resource) && _.isString(normalized_resource)) {
878
+ if (!(typeof normalized_resource === 'object' && normalized_resource !== null) && typeof normalized_resource === 'string') {
692
879
  normalized_resource = { src: normalized_resource, type: 'js' };
693
880
  }
694
- if (!_.isObject(normalized_resource)) {
881
+ if (!(typeof normalized_resource === 'object' && normalized_resource !== null)) {
695
882
  throw new Error('cdn resource in wrong format');
696
883
  }
697
884
 
@@ -737,7 +924,7 @@ func.runtime.resources.load_plugin_runtime_css = async function (SESSION_ID, plu
737
924
  return true;
738
925
  };
739
926
  func.runtime.resources.resolve_plugin_properties = async function (SESSION_ID, dsSessionP, attributes, properties) {
740
- let resolved_properties = _.cloneDeep(properties);
927
+ let resolved_properties = klona.klona(properties);
741
928
  for await (let [prop_name, prop_val] of Object.entries(resolved_properties || {})) {
742
929
  prop_val.value = attributes?.[prop_name];
743
930
  if (attributes?.[`xu-exp:${prop_name}`]) {
@@ -763,7 +950,7 @@ func.runtime.resources.run_ui_plugin = async function (SESSION_ID, paramsP, $elm
763
950
  const plugin_runtime_src = await func.runtime.resources.get_plugin_module_url(SESSION_ID, plugin_name, plugin, 'runtime.mjs');
764
951
  const plugin_runtime_resources = await import(plugin_runtime_src);
765
952
 
766
- if (plugin_runtime_resources.cdn && _.isArray(plugin_runtime_resources.cdn)) {
953
+ if (plugin_runtime_resources.cdn && Array.isArray(plugin_runtime_resources.cdn)) {
767
954
  for await (const resource of plugin_runtime_resources.cdn) {
768
955
  await func.runtime.resources.load_cdn(SESSION_ID, resource);
769
956
  }
@@ -895,12 +1082,12 @@ func.runtime.widgets.build_params = function (context, $containerP, plugin_setup
895
1082
  };
896
1083
  };
897
1084
  func.common.find_item_by_key = function (arr, key, val) {
898
- return _.find(arr, function (e) {
1085
+ return arr.find(function (e) {
899
1086
  return e.data[key] === val;
900
1087
  });
901
1088
  };
902
1089
  func.common.find_item_by_key_root = function (arr, key, val) {
903
- return _.find(arr, function (e) {
1090
+ return arr.find(function (e) {
904
1091
  return e[key] === val;
905
1092
  });
906
1093
  };
@@ -1160,7 +1347,7 @@ func.common.db = async function (SESSION_ID, serviceP, dataP, opt = {}, dsSessio
1160
1347
  }
1161
1348
 
1162
1349
  await db.get(row_id);
1163
- let _data = _.cloneDeep(dataP);
1350
+ let _data = klona.klona(dataP);
1164
1351
  _data.ids = [row_id];
1165
1352
  return await func.db.pouch['dbs_delete'](SESSION_ID, _data);
1166
1353
  } catch (err) {
@@ -1249,7 +1436,7 @@ func.common.db = async function (SESSION_ID, serviceP, dataP, opt = {}, dsSessio
1249
1436
 
1250
1437
  const get_white_spaced_data = function (data) {
1251
1438
  var e = {};
1252
- _.forEach(data, function (val, key) {
1439
+ for (const [key, val] of Object.entries(data)) {
1253
1440
  if (!val) {
1254
1441
  if (typeof val === 'boolean') {
1255
1442
  e[key] = 'false';
@@ -1263,7 +1450,7 @@ func.common.db = async function (SESSION_ID, serviceP, dataP, opt = {}, dsSessio
1263
1450
  e[key] = val;
1264
1451
  }
1265
1452
  }
1266
- });
1453
+ }
1267
1454
 
1268
1455
  if (data.fields && !data.fields.length) {
1269
1456
  e.fields = '';
@@ -1512,14 +1699,14 @@ var UI_FRAMEWORK_PLUGIN = {};
1512
1699
  func.common.get_cast_val = async function (SESSION_ID, source, attributeP, typeP, valP, errorP) {
1513
1700
  const report_conversion_error = function (res) {
1514
1701
  if (errorP) {
1515
- return func.utils.debug_report(SESSION_ID, _.capitalize(source), errorP, 'W');
1702
+ return func.utils.debug_report(SESSION_ID, source.charAt(0).toUpperCase() + source.slice(1).toLowerCase(), errorP, 'W');
1516
1703
  }
1517
1704
  var msg = `error converting ${attributeP} from ${valP} to ${typeP}`;
1518
- func.utils.debug_report(SESSION_ID, _.capitalize(source), msg, 'E');
1705
+ func.utils.debug_report(SESSION_ID, source.charAt(0).toUpperCase() + source.slice(1).toLowerCase(), msg, 'E');
1519
1706
  };
1520
1707
  const report_conversion_warn = function (msg) {
1521
1708
  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');
1709
+ func.utils.debug_report(SESSION_ID, source.charAt(0).toUpperCase() + source.slice(1).toLowerCase(), msg, 'W');
1523
1710
  };
1524
1711
  const module = await func.common.get_module(SESSION_ID, `xuda-get-cast-util-module.mjs`);
1525
1712
  return module.cast(typeP, valP, report_conversion_error, report_conversion_warn);
@@ -1537,11 +1724,17 @@ var WEBSOCKET_PROCESS_PID = null;
1537
1724
  glb.worker_queue_num = 0;
1538
1725
  glb.websocket_queue_num = 0;
1539
1726
 
1727
+ func.common._import_cache = func.common._import_cache || {};
1728
+
1540
1729
  func.common.get_module = async function (SESSION_ID, module, paramsP = {}) {
1541
1730
  let ret;
1542
1731
 
1543
1732
  const get_ret = async function (src) {
1544
- const module_ret = await import(src);
1733
+ // Cache the import() result to avoid repeated dynamic imports
1734
+ if (!func.common._import_cache[src]) {
1735
+ func.common._import_cache[src] = await import(src);
1736
+ }
1737
+ const module_ret = func.common._import_cache[src];
1545
1738
  var params = get_params();
1546
1739
 
1547
1740
  const ret = module_ret.XudaModule ? new module_ret.XudaModule(params) : await invoke_init_module(module_ret, params);
@@ -1558,7 +1751,6 @@ func.common.get_module = async function (SESSION_ID, module, paramsP = {}) {
1558
1751
  PROJECT_OBJ,
1559
1752
  DOCS_OBJ,
1560
1753
  SESSION_OBJ,
1561
- _,
1562
1754
  ...paramsP,
1563
1755
  };
1564
1756
  if (typeof IS_PROCESS_SERVER !== 'undefined') params.IS_PROCESS_SERVER = IS_PROCESS_SERVER;
@@ -1592,7 +1784,7 @@ func.common.get_module = async function (SESSION_ID, module, paramsP = {}) {
1592
1784
  }
1593
1785
 
1594
1786
  const rep = function () {
1595
- return _.endsWith(module, '.js') ? module.replace('.js', '.min.js') : module.replace('.mjs', '.min.mjs');
1787
+ return module.endsWith('.js') ? module.replace('.js', '.min.js') : module.replace('.mjs', '.min.mjs');
1596
1788
  };
1597
1789
 
1598
1790
  if (typeof IS_DOCKER !== 'undefined' || typeof IS_PROCESS_SERVER !== 'undefined') {
@@ -1750,7 +1942,7 @@ func.api.watch = function (path, cb, opt = {}) {
1750
1942
  _session.watchers[path] = { ...opt, handler: cb };
1751
1943
 
1752
1944
  if (opt.immediate) {
1753
- const value = _.get(SESSION_OBJ[SESSION_ID].DS_GLB[0], path);
1945
+ const value = xu_get(SESSION_OBJ[SESSION_ID].DS_GLB[0], path);
1754
1946
  cb({ path, newValue: value, oldValue: value, timestamp: Date.now(), opt });
1755
1947
 
1756
1948
  if (opt.once) {
@@ -1902,10 +2094,12 @@ func.common.get_data_from_websocket = async function (SESSION_ID, serviceP, data
1902
2094
  } else {
1903
2095
  if (RUNTIME_SERVER_WEBSOCKET && RUNTIME_SERVER_WEBSOCKET_CONNECTED) {
1904
2096
  RUNTIME_SERVER_WEBSOCKET.emit('message', obj);
1905
- $('body').on('get_ws_data_response_' + glb.websocket_queue_num, (e, data) => {
2097
+ const _ws_event = 'get_ws_data_response_' + glb.websocket_queue_num;
2098
+ const _ws_handler = function (data) {
1906
2099
  resolve(data.data);
1907
- $('body').off('get_ws_data_response_' + data.e.websocket_queue_num);
1908
- });
2100
+ func.runtime.platform.off('get_ws_data_response_' + data.e.websocket_queue_num, _ws_handler);
2101
+ };
2102
+ func.runtime.platform.on(_ws_event, _ws_handler);
1909
2103
  } else {
1910
2104
  throw new Error('fail to fetch from ws websocket inactive');
1911
2105
  }
@@ -1919,10 +2113,11 @@ func.common.get_data_from_websocket = async function (SESSION_ID, serviceP, data
1919
2113
 
1920
2114
  if (RUNTIME_SERVER_WEBSOCKET && RUNTIME_SERVER_WEBSOCKET_CONNECTED) {
1921
2115
  RUNTIME_SERVER_WEBSOCKET.emit('message', obj);
1922
- $('body').on('heartbeat_response', (e, data) => {
2116
+ const _hb_handler = function (data) {
1923
2117
  resolve(data.data);
1924
- $('body').off('heartbeat_response');
1925
- });
2118
+ func.runtime.platform.off('heartbeat_response', _hb_handler);
2119
+ };
2120
+ func.runtime.platform.on('heartbeat_response', _hb_handler);
1926
2121
  } else {
1927
2122
  throw new Error('fail to fetch from ws websocket inactive');
1928
2123
  }
@@ -2157,6 +2352,395 @@ glb.run_xu_before = [
2157
2352
  glb.run_xu_after = ['xu-bind', 'xu-class', 'xu-script', 'xu-ui-plugin', 'xu-ref'];
2158
2353
  glb.attr_abbreviations_arr = ['xu-click', 'xu-dblclick', 'xu-contextmenu', 'xu-focus', 'xu-keyup', 'xu-change', 'xu-blur', 'xu-init'];
2159
2354
  glb.solid_attributes = ['disabled'];
2355
+ // ── Headless/SSR DOM adapter ──
2356
+ // Provides a no-op / in-memory implementation of func.runtime.ui
2357
+ // for environments without a DOM (Node.js, workers, SSR).
2358
+ // Elements are plain objects; metadata lives in _meta_store.
2359
+
2360
+ func.runtime = func.runtime || {};
2361
+ func.runtime.ui = func.runtime.ui || {};
2362
+ func.runtime.render = func.runtime.render || {};
2363
+ func.runtime.widgets = func.runtime.widgets || {};
2364
+ func.runtime.ui.ui_id_hash_cache = func.runtime.ui.ui_id_hash_cache || new Map();
2365
+ func.runtime.ui.node_snapshot_cache = func.runtime.ui.node_snapshot_cache || new WeakMap();
2366
+ func.runtime.ui.node_child_items_cache = func.runtime.ui.node_child_items_cache || new WeakMap();
2367
+ func.runtime.ui.node_children_by_id_cache = func.runtime.ui.node_children_by_id_cache || new WeakMap();
2368
+
2369
+ // ── Metadata store (shared with browser adapter) ──
2370
+ func.runtime.ui._meta_store = func.runtime.ui._meta_store || {};
2371
+ func.runtime.ui._element_id_to_xu_ui_id = func.runtime.ui._element_id_to_xu_ui_id || {};
2372
+
2373
+ func.runtime.ui.set_meta = function (xu_ui_id, key, value) {
2374
+ if (!xu_ui_id) return;
2375
+ if (!func.runtime.ui._meta_store[xu_ui_id]) {
2376
+ func.runtime.ui._meta_store[xu_ui_id] = {};
2377
+ }
2378
+ func.runtime.ui._meta_store[xu_ui_id][key] = value;
2379
+ };
2380
+ func.runtime.ui.get_meta = function (xu_ui_id, key) {
2381
+ const entry = func.runtime.ui._meta_store[xu_ui_id];
2382
+ if (!entry) return undefined;
2383
+ return key ? entry[key] : entry;
2384
+ };
2385
+ func.runtime.ui.delete_meta = function (xu_ui_id) {
2386
+ delete func.runtime.ui._meta_store[xu_ui_id];
2387
+ for (const id in func.runtime.ui._element_id_to_xu_ui_id) {
2388
+ if (func.runtime.ui._element_id_to_xu_ui_id[id] === xu_ui_id) {
2389
+ delete func.runtime.ui._element_id_to_xu_ui_id[id];
2390
+ }
2391
+ }
2392
+ };
2393
+ func.runtime.ui.register_element_id = function (element_id, xu_ui_id) {
2394
+ if (element_id && xu_ui_id) {
2395
+ func.runtime.ui._element_id_to_xu_ui_id[element_id] = xu_ui_id;
2396
+ }
2397
+ };
2398
+ func.runtime.ui.get_meta_by_element_id = function (element_id) {
2399
+ if (!element_id) return undefined;
2400
+ const clean_id = element_id.startsWith('#') ? element_id.substring(1) : element_id;
2401
+ const xu_ui_id = func.runtime.ui._element_id_to_xu_ui_id[clean_id];
2402
+ if (xu_ui_id) {
2403
+ return func.runtime.ui._meta_store[xu_ui_id];
2404
+ }
2405
+ return undefined;
2406
+ };
2407
+ func.runtime.ui.find_element_by_id = function () {
2408
+ return null;
2409
+ };
2410
+ func.runtime.ui.get_session_root = function () {
2411
+ return null;
2412
+ };
2413
+ func.runtime.ui.clear_screen_blockers = function () {
2414
+ // no-op in headless
2415
+ };
2416
+
2417
+ // ── Virtual element representation ──
2418
+ var _next_id = 1;
2419
+ function create_virtual_element(tag, attrs) {
2420
+ return {
2421
+ _v_id: _next_id++,
2422
+ tag: tag || 'div',
2423
+ attrs: attrs || {},
2424
+ children: [],
2425
+ parent: null,
2426
+ style: {},
2427
+ classList: [],
2428
+ textContent: '',
2429
+ innerHTML: '',
2430
+ hidden: false,
2431
+ _data: {},
2432
+ };
2433
+ }
2434
+
2435
+ // ── Core adapter methods ──
2436
+ func.runtime.ui.as_jquery = function (target) {
2437
+ if (!target) return { length: 0, data: function () { return {}; }, toArray: function () { return []; }, attr: function () { return undefined; } };
2438
+ if (target._v_id) return target;
2439
+ return target;
2440
+ };
2441
+ func.runtime.ui.get_first_node = function (target) {
2442
+ if (!target) return null;
2443
+ if (target._v_id) return target;
2444
+ if (Array.isArray(target)) return target[0] || null;
2445
+ return null;
2446
+ };
2447
+ func.runtime.ui.get_data = function (target) {
2448
+ if (!target) return {};
2449
+ if (target._v_id) {
2450
+ const xu_ui_id = target.attrs?.['xu-ui-id'];
2451
+ if (xu_ui_id) {
2452
+ const meta = func.runtime.ui._meta_store[xu_ui_id];
2453
+ if (meta) return meta;
2454
+ }
2455
+ return target._data;
2456
+ }
2457
+ return {};
2458
+ };
2459
+ func.runtime.ui.get_parent = function (target) {
2460
+ if (target?._v_id) return target.parent;
2461
+ return null;
2462
+ };
2463
+ func.runtime.ui.get_children = function (target) {
2464
+ if (target?._v_id) return target.children.slice();
2465
+ return [];
2466
+ };
2467
+ func.runtime.ui.find_by_selector = function () {
2468
+ return { length: 0, toArray: function () { return []; } };
2469
+ };
2470
+ func.runtime.ui.insert_before = function ($element) { return $element; };
2471
+ func.runtime.ui.insert_after = function ($element) { return $element; };
2472
+ func.runtime.ui.has_selector = function () { return false; };
2473
+ func.runtime.ui.append_html = function (target) { return target; };
2474
+ func.runtime.ui.set_style = function (target, prop, value) {
2475
+ if (target?._v_id) target.style[prop] = value;
2476
+ return target;
2477
+ };
2478
+ func.runtime.ui.get_attr = function (target, key) {
2479
+ if (target?._v_id) return target.attrs[key];
2480
+ return undefined;
2481
+ };
2482
+ func.runtime.ui.set_attr = function (target, key, value) {
2483
+ if (target?._v_id) target.attrs[key] = value;
2484
+ return target;
2485
+ };
2486
+ func.runtime.ui.set_data = function (target, key, value) {
2487
+ if (target?._v_id) {
2488
+ target._data[key] = value;
2489
+ const xu_ui_id = target.attrs?.['xu-ui-id'];
2490
+ if (xu_ui_id) {
2491
+ func.runtime.ui.set_meta(xu_ui_id, key, value);
2492
+ }
2493
+ }
2494
+ return target;
2495
+ };
2496
+ func.runtime.ui.clear_data = function (target) {
2497
+ if (target?._v_id) {
2498
+ target._data = {};
2499
+ const xu_ui_id = target.attrs?.['xu-ui-id'];
2500
+ if (xu_ui_id) func.runtime.ui.delete_meta(xu_ui_id);
2501
+ }
2502
+ return target;
2503
+ };
2504
+ func.runtime.ui.add_class = function (target, cls) {
2505
+ if (target?._v_id && cls && !target.classList.includes(cls)) target.classList.push(cls);
2506
+ return target;
2507
+ };
2508
+ func.runtime.ui.remove_class = function (target, cls) {
2509
+ if (target?._v_id) {
2510
+ const idx = target.classList.indexOf(cls);
2511
+ if (idx !== -1) target.classList.splice(idx, 1);
2512
+ }
2513
+ return target;
2514
+ };
2515
+ func.runtime.ui.set_html = function (target, value) {
2516
+ if (target?._v_id) target.innerHTML = value;
2517
+ return target;
2518
+ };
2519
+ func.runtime.ui.set_text = function (target, value) {
2520
+ if (target?._v_id) target.textContent = value;
2521
+ return target;
2522
+ };
2523
+ func.runtime.ui.show = function (target) {
2524
+ if (target?._v_id) target.hidden = false;
2525
+ return target;
2526
+ };
2527
+ func.runtime.ui.hide = function (target) {
2528
+ if (target?._v_id) target.hidden = true;
2529
+ return target;
2530
+ };
2531
+ func.runtime.ui.append = function ($target, $element) {
2532
+ if ($target?._v_id && $element?._v_id) {
2533
+ $target.children.push($element);
2534
+ $element.parent = $target;
2535
+ }
2536
+ return $element;
2537
+ };
2538
+ func.runtime.ui.append_to = function ($element, $target) {
2539
+ return func.runtime.ui.append($target, $element);
2540
+ };
2541
+ func.runtime.ui.empty = function (target) {
2542
+ if (target?._v_id) target.children = [];
2543
+ return target;
2544
+ };
2545
+ func.runtime.ui.remove = function (target) {
2546
+ if (target?._v_id) {
2547
+ const xu_ui_id = target.attrs?.['xu-ui-id'];
2548
+ if (xu_ui_id) func.runtime.ui.delete_meta(xu_ui_id);
2549
+ if (target.parent?._v_id) {
2550
+ const idx = target.parent.children.indexOf(target);
2551
+ if (idx !== -1) target.parent.children.splice(idx, 1);
2552
+ }
2553
+ }
2554
+ return true;
2555
+ };
2556
+ func.runtime.ui.set_display_contents = function ($element) {
2557
+ return func.runtime.ui.set_style($element, 'display', 'contents');
2558
+ };
2559
+ func.runtime.ui.create_xurender = function (xu_ui_id, $target, hidden) {
2560
+ const el = create_virtual_element('xurender', { 'xu-ui-id': xu_ui_id });
2561
+ if (hidden) el.hidden = true;
2562
+ return func.runtime.ui.append_to(el, $target);
2563
+ };
2564
+ func.runtime.ui.replace_with = function ($source, $target) {
2565
+ if ($source?._v_id && $source.parent?._v_id) {
2566
+ const idx = $source.parent.children.indexOf($source);
2567
+ if (idx !== -1 && $target?._v_id) {
2568
+ $source.parent.children[idx] = $target;
2569
+ $target.parent = $source.parent;
2570
+ }
2571
+ }
2572
+ return $target;
2573
+ };
2574
+ func.runtime.ui.remove_xu_ui = function (xu_ui_id) {
2575
+ func.runtime.ui.delete_meta(xu_ui_id);
2576
+ return true;
2577
+ };
2578
+ func.runtime.ui.build_debug_info = function (nodeP, $container, items) {
2579
+ const container_data = func.runtime.ui.get_data($container);
2580
+ return {
2581
+ id: nodeP.id,
2582
+ parent_id: container_data?.xuData?.ui_id,
2583
+ items: items,
2584
+ };
2585
+ };
2586
+ func.runtime.ui.get_node_snapshot = function (nodeP) {
2587
+ if (!nodeP) return nodeP;
2588
+ if (func.runtime.ui.node_snapshot_cache.has(nodeP)) {
2589
+ return func.runtime.ui.node_snapshot_cache.get(nodeP);
2590
+ }
2591
+ const snapshot = klona.klona(nodeP);
2592
+ func.runtime.ui.node_snapshot_cache.set(nodeP, snapshot);
2593
+ return snapshot;
2594
+ };
2595
+ func.runtime.ui.get_node_child_items = function (nodeP) {
2596
+ if (!nodeP?.children?.length) return [];
2597
+ if (func.runtime.ui.node_child_items_cache.has(nodeP)) {
2598
+ return func.runtime.ui.node_child_items_cache.get(nodeP);
2599
+ }
2600
+ const items = nodeP.children.map(function (val) { return val.xu_tree_id || val.id; });
2601
+ func.runtime.ui.node_child_items_cache.set(nodeP, items);
2602
+ return items;
2603
+ };
2604
+ func.runtime.ui.get_node_children_by_id = function (nodeP) {
2605
+ if (!nodeP?.children?.length) return {};
2606
+ if (func.runtime.ui.node_children_by_id_cache.has(nodeP)) {
2607
+ return func.runtime.ui.node_children_by_id_cache.get(nodeP);
2608
+ }
2609
+ const children_by_id = {};
2610
+ for (let i = 0; i < nodeP.children.length; i++) {
2611
+ const child = nodeP.children[i];
2612
+ if (child?.id) children_by_id[child.id] = child;
2613
+ }
2614
+ func.runtime.ui.node_children_by_id_cache.set(nodeP, children_by_id);
2615
+ return children_by_id;
2616
+ };
2617
+ func.runtime.ui.build_container_xu_data = function (options) {
2618
+ const container_data = func.runtime.ui.get_data(options.$container);
2619
+ const containerXuData = container_data?.xuData;
2620
+ return {
2621
+ SESSION_ID: options.SESSION_ID,
2622
+ prog_id: options.paramsP.prog_id,
2623
+ nodeid: options.nodeP.id,
2624
+ ui_type: options.nodeP.tagName,
2625
+ recordid: options.currentRecordId,
2626
+ paramsP: options.paramsP,
2627
+ key: options.keyP,
2628
+ key_path: options.key_path,
2629
+ screenId: options.paramsP.screenId,
2630
+ parent_container: containerXuData?.ui_id,
2631
+ elem_key: options.elem_key,
2632
+ properties: options.prop,
2633
+ node: options.nodeP,
2634
+ node_org: func.runtime.ui.get_node_snapshot(options.nodeP),
2635
+ is_panelP: options.paramsP.is_panelP,
2636
+ ui_id: options.ui_id,
2637
+ elem_prop: options.elem_propP,
2638
+ debug_info: func.runtime.ui.build_debug_info(options.nodeP, options.$container, options.items),
2639
+ parent_node: options.parent_nodeP,
2640
+ currentRecordId: options.currentRecordId,
2641
+ $root_container: options.$root_container,
2642
+ parent_element_ui_id: containerXuData?.ui_id,
2643
+ is_placeholder: !!options.is_placeholder,
2644
+ };
2645
+ };
2646
+ func.runtime.ui.apply_container_meta = function ($div, options) {
2647
+ if ($div?._v_id) $div.attrs['xu-ui-id'] = options.ui_id;
2648
+ const xuData = func.runtime.ui.build_container_xu_data(options);
2649
+ if (options.parent_infoP?.iterate_info) {
2650
+ xuData.iterate_info = options.parent_infoP.iterate_info;
2651
+ }
2652
+ if ($div?._v_id) {
2653
+ $div._data.xuData = xuData;
2654
+ $div._data.xuAttributes = {};
2655
+ }
2656
+ func.runtime.ui.set_meta(options.ui_id, 'xuData', xuData);
2657
+ func.runtime.ui.set_meta(options.ui_id, 'xuAttributes', {});
2658
+ if (options.is_placeholder && $div?._v_id) $div.classList.push('display_none');
2659
+ if (options.classP && $div?._v_id) $div.classList.push(options.classP);
2660
+ return $div;
2661
+ };
2662
+ func.runtime.ui.get_append_target = function ($container, $appendToP) {
2663
+ return $appendToP || $container || null;
2664
+ };
2665
+ func.runtime.ui.create_element = function (tag_name) {
2666
+ return create_virtual_element(tag_name);
2667
+ };
2668
+ func.runtime.ui.create_svg_element = function () {
2669
+ return create_virtual_element('svg');
2670
+ };
2671
+ func.runtime.ui.create_container_element = function (div_typeP) {
2672
+ return create_virtual_element(div_typeP || 'div');
2673
+ };
2674
+ func.runtime.ui.build_xu_ui_id_seed = function (nodeP, dsSessionP, key_path, currentRecordId) {
2675
+ const nodeId = nodeP.xu_tree_id || nodeP.id;
2676
+ const elem_key = `${nodeId}-${key_path}-${currentRecordId}`;
2677
+ return `${nodeP.id}-${elem_key}-${dsSessionP?.toString() || ''}`;
2678
+ };
2679
+ func.runtime.ui.generate_xu_ui_id = async function (SESSION_ID, nodeP, $container, paramsP, keyP, precomputed) {
2680
+ precomputed = precomputed || {};
2681
+ const dsSessionP = paramsP.dsSessionP;
2682
+ const _ds = SESSION_OBJ[SESSION_ID].DS_GLB[dsSessionP];
2683
+ const containerXuData = precomputed.container_xu_data || func.runtime.ui.get_data($container)?.xuData;
2684
+ const currentRecordId = typeof precomputed.currentRecordId !== 'undefined' ? precomputed.currentRecordId : containerXuData?.recordid || _ds?.currentRecordId || '';
2685
+ const key_path = precomputed.key_path || `${containerXuData?.key_path || '0'}-${keyP || '0'}`;
2686
+ const ui_id = func.runtime.ui.build_xu_ui_id_seed(nodeP, dsSessionP, key_path, currentRecordId);
2687
+
2688
+ if (func.runtime.ui.ui_id_hash_cache.has(ui_id)) {
2689
+ return func.runtime.ui.ui_id_hash_cache.get(ui_id);
2690
+ }
2691
+
2692
+ const hashed_ui_id = await func.common.fastHash(ui_id);
2693
+ func.runtime.ui.ui_id_hash_cache.set(ui_id, hashed_ui_id);
2694
+ return hashed_ui_id;
2695
+ };
2696
+ func.runtime.ui.create_container = async function (options) {
2697
+ const _paramsP = klona.klona(options.paramsP);
2698
+ const _ds = SESSION_OBJ[options.SESSION_ID].DS_GLB[_paramsP.dsSessionP];
2699
+ const $appendTo = func.runtime.ui.get_append_target(options.$container, options.$appendToP);
2700
+ if (!$appendTo) return null;
2701
+ const container_data = func.runtime.ui.get_data(options.$container);
2702
+ const container_xu_data = container_data?.xuData;
2703
+ const items = func.runtime.ui.get_node_child_items(options.nodeP);
2704
+ const currentRecordId = container_xu_data?.recordid || (_ds ? _ds.currentRecordId : '');
2705
+
2706
+ try {
2707
+ const key_path = `${container_xu_data?.key_path || '0'}-${options.keyP || '0'}`;
2708
+ const elem_key = `${options.nodeP.xu_tree_id || options.nodeP.id}-${key_path}-${currentRecordId}`;
2709
+ const $div = func.runtime.ui.create_container_element(options.div_typeP);
2710
+ const new_ui_id = await func.runtime.ui.generate_xu_ui_id(options.SESSION_ID, options.nodeP, options.$container, options.paramsP, options.keyP, {
2711
+ container_xu_data,
2712
+ currentRecordId,
2713
+ key_path,
2714
+ });
2715
+
2716
+ func.runtime.ui.apply_container_meta($div, {
2717
+ ui_id: new_ui_id,
2718
+ paramsP: _paramsP,
2719
+ nodeP: options.nodeP,
2720
+ currentRecordId,
2721
+ keyP: options.keyP,
2722
+ key_path,
2723
+ $container: options.$container,
2724
+ prop: options.prop,
2725
+ elem_key,
2726
+ elem_propP: options.elem_propP,
2727
+ items,
2728
+ parent_nodeP: options.parent_nodeP,
2729
+ $root_container: options.$root_container,
2730
+ parent_infoP: options.parent_infoP,
2731
+ is_placeholder: options.is_placeholder,
2732
+ classP: options.classP,
2733
+ SESSION_ID: options.SESSION_ID,
2734
+ });
2735
+
2736
+ func.runtime.ui.append_to($div, $appendTo);
2737
+ return $div;
2738
+ } catch (e) {
2739
+ console.error(e);
2740
+ }
2741
+
2742
+ return null;
2743
+ };
2160
2744
  func.datasource = {};
2161
2745
  func.datasource.create = async function (
2162
2746
  SESSION_ID,
@@ -2351,7 +2935,7 @@ func.datasource.create = async function (
2351
2935
  }
2352
2936
  // vvvv run at worker vvvv
2353
2937
  if (_ds) IS_DATASOURCE_REFRESH = true;
2354
- var data = _.assignIn(
2938
+ var data = Object.assign(
2355
2939
  {
2356
2940
  session_id: SESSION_ID,
2357
2941
  dataSourceSessionGlobal: SESSION_OBJ[SESSION_ID].dataSourceSessionGlobal,
@@ -2406,7 +2990,7 @@ func.datasource.prepare = async function (SESSION_ID, prog_id, dataSourceNoP, pa
2406
2990
  // &&
2407
2991
  // glb.PARAMETER_NODES_ARR.includes(screenInfo.properties.menuType)
2408
2992
  ) {
2409
- if (!_.isEmpty(screenInfo.properties.progParams)) {
2993
+ if (!xu_isEmpty(screenInfo.properties.progParams)) {
2410
2994
  _ds.in_parameters = {};
2411
2995
  _ds.out_parameters = {};
2412
2996
 
@@ -2538,7 +3122,7 @@ func.datasource.prepare = async function (SESSION_ID, prog_id, dataSourceNoP, pa
2538
3122
  _ds.refreshed = true;
2539
3123
 
2540
3124
  if (_ds.watcher) {
2541
- _.set(_ds, _ds.watcher.path, _ds.watcher.newValue);
3125
+ xu_set(_ds, _ds.watcher.path, _ds.watcher.newValue);
2542
3126
  }
2543
3127
  try {
2544
3128
  if (!_ds.v) _ds.v = {};
@@ -3525,7 +4109,7 @@ func.datasource.execute_field_init_events = async function (SESSION_ID, dataSour
3525
4109
  var expression = undefined;
3526
4110
  if (val.eventInfo.props.condition) expression = val.eventInfo.props.condition;
3527
4111
  var expCond = {};
3528
- if (expression && !_.isEmpty(expression)) {
4112
+ if (expression && !xu_isEmpty(expression)) {
3529
4113
  // check if expression exist
3530
4114
  expCond = await func.expression.get(SESSION_ID, expression, dataSourceSession, 'condition', rowIdP, null, null, val.fieldId); // execute expression
3531
4115
  cond = expCond.result;
@@ -3669,7 +4253,7 @@ func.datasource.get_view_events_count = async function (SESSION_ID, dataSourceSe
3669
4253
 
3670
4254
  _ds.viewEventExec_arr[index] = [];
3671
4255
 
3672
- if (!_prog.progEvents || _.isEmpty(_prog.progEvents)) return 0;
4256
+ if (!_prog.progEvents || xu_isEmpty(_prog.progEvents)) return 0;
3673
4257
 
3674
4258
  for (const event_obj of _prog.progEvents) {
3675
4259
  if (event_obj.data.type !== typeP) continue; // was false?? changed to true 020317
@@ -3682,7 +4266,7 @@ func.datasource.get_view_events_count = async function (SESSION_ID, dataSourceSe
3682
4266
  }
3683
4267
  }
3684
4268
 
3685
- if (_.isEmpty(event_obj.workflow)) continue;
4269
+ if (xu_isEmpty(event_obj.workflow)) continue;
3686
4270
  for (const trigger_obj of event_obj.workflow) {
3687
4271
  if (trigger_obj.data.enabled) {
3688
4272
  var expression;
@@ -3735,7 +4319,7 @@ func.datasource.execute_view_events = async function (SESSION_ID, dataSourceSess
3735
4319
  var index = typeP;
3736
4320
  if (eventIdP) index = typeP + '_' + eventIdP;
3737
4321
  var arr = _ds.viewEventExec_arr[index];
3738
- if (_.isEmpty(arr)) return;
4322
+ if (xu_isEmpty(arr)) return;
3739
4323
 
3740
4324
  for await (const val of arr) {
3741
4325
  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 +4332,8 @@ func.datasource.execute_view_events = async function (SESSION_ID, dataSourceSess
3748
4332
  if (cond) {
3749
4333
  var elem_params = undefined;
3750
4334
  if (!glb.IS_WORKER) {
3751
- elem_params = $('#' + _ds.containerId).data('params');
4335
+ const container_meta = func.runtime.ui.get_meta_by_element_id(_ds.containerId);
4336
+ elem_params = container_meta?.params;
3752
4337
  }
3753
4338
  const ret = await func.events.execute(
3754
4339
  SESSION_ID,
@@ -3866,12 +4451,12 @@ func.datasource.clean_all = function (SESSION_ID, dsP) {
3866
4451
 
3867
4452
  var get_child_ds = function (ds) {
3868
4453
  var arr = [];
3869
- _.forEach(SESSION_OBJ[SESSION_ID].DS_GLB, function (val, key) {
4454
+ for (const [key, val] of Object.entries(SESSION_OBJ[SESSION_ID].DS_GLB)) {
3870
4455
  if (val.parentDataSourceNo == ds) {
3871
4456
  arr.push(key);
3872
4457
  arr = arr.concat(get_child_ds(key));
3873
4458
  }
3874
- });
4459
+ }
3875
4460
  return arr;
3876
4461
  };
3877
4462
 
@@ -3884,13 +4469,13 @@ func.datasource.clean = function (SESSION_ID, screenIdP) {
3884
4469
  var arr = [];
3885
4470
  for (const [key, val] of Object.entries(SESSION_OBJ[SESSION_ID].DS_GLB)) {
3886
4471
  try {
4472
+ const _screen_el = val.screenId ? document.getElementById(val.screenId) : null;
4473
+ const screen_parent_id = _screen_el?.parentElement?.id || null;
3887
4474
  if (
3888
4475
  Number(key) > 0 &&
3889
4476
  (val.screenId === screenIdP ||
3890
4477
  val.rootScreenId === screenIdP ||
3891
- $('#' + val.screenId)
3892
- .parent()
3893
- .attr('id') === screenIdP ||
4478
+ screen_parent_id === screenIdP ||
3894
4479
  (val && val.parentDataSourceNo && arr.includes(val.parentDataSourceNo.toString())))
3895
4480
  ) {
3896
4481
  arr.push(key);
@@ -3956,14 +4541,12 @@ func.datasource.del = function (SESSION_ID, dsP) {
3956
4541
 
3957
4542
  var delete_pending_jobs = function () {
3958
4543
  var arr = [];
3959
- _.forEach(SESSION_OBJ[SESSION_ID].WORKER_OBJ.jobs, function (val, key) {
4544
+ for (const [key, val] of Object.entries(SESSION_OBJ[SESSION_ID].WORKER_OBJ.jobs)) {
3960
4545
  if (val && val.dsSessionP == dsP) {
3961
4546
  arr.push(key);
3962
- for (const [key, val] of Object.entries($('.screen_blocker'))) {
3963
- $(val).remove();
3964
- }
4547
+ func.runtime.ui.clear_screen_blockers();
3965
4548
  }
3966
- });
4549
+ }
3967
4550
  for (let val of arr.reverse()) {
3968
4551
  SESSION_OBJ[SESSION_ID].WORKER_OBJ.jobs.splice(val, 1);
3969
4552
  }
@@ -3982,8 +4565,9 @@ func.datasource.del = function (SESSION_ID, dsP) {
3982
4565
  }
3983
4566
  }
3984
4567
  }
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;
4568
+ const _nav_node = func.runtime.ui.get_first_node(SESSION_OBJ[SESSION_ID].root_element)?.querySelector?.('xu-nav');
4569
+ if (_nav_node) {
4570
+ var ds_obj = func.runtime.ui.get_data(_nav_node)?.xuData?.nav_params;
3987
4571
  if (ds_obj) {
3988
4572
  delete ds_obj[dsP];
3989
4573
  }
@@ -4090,7 +4674,7 @@ func.datasource.update = async function (SESSION_ID, datasource_changes, update_
4090
4674
  for (const [field_id, value] of Object.entries(fields_data)) {
4091
4675
  // mechanism to make update directly on the datasource object
4092
4676
  if (record_id === 'datasource_main') {
4093
- _.set(_ds, field_id, value);
4677
+ xu_set(_ds, field_id, value);
4094
4678
  const ret = update_xu_ref(dataSource);
4095
4679
  if (ret) {
4096
4680
  fields_changed.push(field_id);
@@ -4138,7 +4722,7 @@ func.datasource.update = async function (SESSION_ID, datasource_changes, update_
4138
4722
  try {
4139
4723
  const row_idx = func.common.find_ROWID_idx(_ds, record_id);
4140
4724
  // if (_ds.data_feed.rows[row_idx][field_id] !== value) {
4141
- if (!_.isEqual(_ds.data_feed.rows[row_idx][field_id], value)) {
4725
+ if (!xu_isEqual(_ds.data_feed.rows[row_idx][field_id], value)) {
4142
4726
  _ds.data_feed.rows[row_idx][field_id] = value;
4143
4727
  await set_fieldComputed_dependencies(dataSource, field_id, null);
4144
4728
 
@@ -4211,11 +4795,11 @@ func.datasource.update = async function (SESSION_ID, datasource_changes, update_
4211
4795
  }
4212
4796
 
4213
4797
  if (glb.IS_WORKER) {
4214
- if (!update_local_scope_only && !_.isEmpty(client_datasource_changes)) {
4798
+ if (!update_local_scope_only && !xu_isEmpty(client_datasource_changes)) {
4215
4799
  func.utils.post_back_to_client(SESSION_ID, 'update_client_eventChangesResults_from_worker', _session.worker_id, client_datasource_changes);
4216
4800
  }
4217
4801
  } else {
4218
- if (!update_local_scope_only && !_.isEmpty(server_datasource_changes)) {
4802
+ if (!update_local_scope_only && !xu_isEmpty(server_datasource_changes)) {
4219
4803
  const ret = await func.index.call_worker(SESSION_ID, {
4220
4804
  service: 'update_datasource_changes_from_client',
4221
4805
  data: {
@@ -4316,7 +4900,7 @@ func.datasource.callback = async function (SESSION_ID, dsSessionP, rowIdP, jobNo
4316
4900
  dsSession: dsSessionP,
4317
4901
  prop: _ds.log_prop + ' ' + 'adapter',
4318
4902
  });
4319
- if (!glb.IS_WORKER) $(_session.root_element).css('cursor', 'default');
4903
+ if (!glb.IS_WORKER) func.runtime.platform.set_cursor(_session.root_element, 'default');
4320
4904
 
4321
4905
  if (_ds.prog_id) {
4322
4906
  let _ds = _session.DS_GLB[dsSessionP];
@@ -4868,7 +5452,7 @@ func.datasource.get_viewLoops = async function (SESSION_ID, dataSourceSession, d
4868
5452
  // var v = _ds.v;
4869
5453
  var ret = default_limit;
4870
5454
 
4871
- if (batch_source === 'db_data') ret = _.size(data.rows);
5455
+ if (batch_source === 'db_data') ret = data.rows.length;
4872
5456
  if (batch_source === 'array' || batch_source === 'csv') ret = data.length;
4873
5457
  if (batch_source === 'json') ret = Object.keys(data).length;
4874
5458
  if (_ds.progDataSource?.dataSourceLimit) {
@@ -4895,7 +5479,7 @@ func.datasource.set_VIEW_data = async function (SESSION_ID, args, _ds) {
4895
5479
  };
4896
5480
  _ds.viewEventExec_arr = {};
4897
5481
 
4898
- var view = _.cloneDeep(await func.utils.VIEWS_OBJ.get(SESSION_ID, args.prog_id));
5482
+ var view = klona.klona(await func.utils.VIEWS_OBJ.get(SESSION_ID, args.prog_id));
4899
5483
  // var view = klona.klona(await func.utils.VIEWS_OBJ.get(SESSION_ID, args.prog_id));
4900
5484
 
4901
5485
  _ds.v.dataSourceSrcType = view.dataSourceSrcType;
@@ -4941,11 +5525,11 @@ func.datasource.get_cast_val = async function (SESSION_ID, source, dsSession, va
4941
5525
  if (error) {
4942
5526
  return func.utils.debug_report(SESSION_ID, msg, '', 'W');
4943
5527
  }
4944
- func.utils.debug_report(SESSION_ID, msg + ' ' + _.capitalize(source) + prog_info, '', 'E');
5528
+ func.utils.debug_report(SESSION_ID, msg + ' ' + (source.charAt(0).toUpperCase() + source.slice(1).toLowerCase()) + prog_info, '', 'E');
4945
5529
  };
4946
5530
  const report_conversion_warn = function (res) {
4947
5531
  var msg = `type mismatch auto conversion from value ${valP} to ${typeP}`;
4948
- func.utils.debug_report(SESSION_ID, msg + ' ' + _.capitalize(source) + prog_info, '', 'W');
5532
+ func.utils.debug_report(SESSION_ID, msg + ' ' + (source.charAt(0).toUpperCase() + source.slice(1).toLowerCase()) + prog_info, '', 'W');
4949
5533
  };
4950
5534
  // var ret = valP;
4951
5535
  if (error) {
@@ -5014,7 +5598,7 @@ func.datasource.update_changes_for_out_parameter = async function (SESSION_ID, d
5014
5598
  }
5015
5599
  }
5016
5600
  }
5017
- if (!_.isEmpty(data)) {
5601
+ if (!xu_isEmpty(data)) {
5018
5602
  let datasource_changes = {
5019
5603
  [calling_dsP]: { [_calling_ds.currentRecordId]: data },
5020
5604
  };
@@ -5125,7 +5709,7 @@ func.utils.DOCS_OBJ.get = async function (SESSION_ID, idP) {
5125
5709
 
5126
5710
  if (idP !== 'system') {
5127
5711
  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])) {
5712
+ if (DOCS_OBJ[_app_id][idP] && xu_isEmpty(DOCS_OBJ[_app_id][idP])) {
5129
5713
  await func.utils.remove_cached_objects(SESSION_ID);
5130
5714
 
5131
5715
  delete DOCS_OBJ[_app_id][idP];
@@ -5137,7 +5721,7 @@ func.utils.DOCS_OBJ.get = async function (SESSION_ID, idP) {
5137
5721
  if (APP_OBJ[_app_id].app_imported_projects) {
5138
5722
  for await (const imported_app_id of APP_OBJ[_app_id].app_imported_projects) {
5139
5723
  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);
5724
+ DOCS_OBJ[_app_id][idP] = Object.assign(DOCS_OBJ[_app_id][idP], view_ret);
5141
5725
  }
5142
5726
  }
5143
5727
  return DOCS_OBJ[_app_id][idP];
@@ -5219,13 +5803,13 @@ func.utils.get_dateTime = async function (SESSION_ID, typeP, dateP) {
5219
5803
  let ts = await get_server_ts();
5220
5804
  sysDate = new Date(ts);
5221
5805
  }
5222
- var day = _.padStart(sysDate.getDate(), 2, '0');
5223
- var month = _.padStart(sysDate.getMonth() + 1, 2, '0');
5806
+ var day = String(sysDate.getDate()).padStart(2, '0');
5807
+ var month = String(sysDate.getMonth() + 1).padStart(2, '0');
5224
5808
  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');
5809
+ var week = String(getWeekNumber(sysDate)).padStart(2, '0');
5810
+ var hour = String(sysDate.getHours()).padStart(2, '0');
5811
+ var minute = String(sysDate.getMinutes()).padStart(2, '0');
5812
+ var second = String(sysDate.getSeconds()).padStart(2, '0');
5229
5813
  if (typeP === 'SYS_DATE') return year + '-' + month + '-' + day;
5230
5814
  if (typeP === 'SYS_DATE_TIME') return year + '-' + month + '-' + day + 'T' + hour + ':' + minute;
5231
5815
  if (typeP === 'SYS_DATE_VALUE') return sysDate.valueOf();
@@ -5263,7 +5847,7 @@ func.utils.clean_returned_datasource = function (SESSION_ID, DS) {
5263
5847
  var _session = SESSION_OBJ[SESSION_ID];
5264
5848
  if (!_session.DS_GLB[DS]) return;
5265
5849
 
5266
- var obj = _.clone(_session.DS_GLB[DS]);
5850
+ var obj = { ..._session.DS_GLB[DS] };
5267
5851
 
5268
5852
  delete obj.screen_params;
5269
5853
 
@@ -5283,7 +5867,7 @@ func.utils.clean_returned_datasource = function (SESSION_ID, DS) {
5283
5867
 
5284
5868
  const clean_empty_objects = function () {
5285
5869
  for (const [key, val] of Object.entries(obj)) {
5286
- if (typeof val === 'object' && !Array.isArray(val) && _.isEmpty(val)) {
5870
+ if (typeof val === 'object' && !Array.isArray(val) && xu_isEmpty(val)) {
5287
5871
  delete obj[key];
5288
5872
  }
5289
5873
  }
@@ -5386,7 +5970,7 @@ func.utils.job_worker = function (session_id) {
5386
5970
  func.utils.debug_report(SESSION_ID, 'utils.worker.reset', 'worker not responding', 'E', '', _session.WORKER_OBJ.jobs);
5387
5971
  _session.WORKER_OBJ.jobs = [];
5388
5972
  _session.WORKER_OBJ.stat = null;
5389
- $('.screen_blocker').remove();
5973
+ func.runtime.ui.clear_screen_blockers();
5390
5974
  };
5391
5975
  return {
5392
5976
  _interval: null,
@@ -5527,8 +6111,9 @@ func.utils.makeid = function (length) {
5527
6111
  func.utils.get_device = function () {
5528
6112
  var device;
5529
6113
  try {
5530
- if (window.cordova) {
5531
- device = window.cordova.platformId;
6114
+ const win = func.runtime.platform.get_window();
6115
+ if (win?.cordova) {
6116
+ device = win.cordova.platformId;
5532
6117
  }
5533
6118
  } catch (e) {
5534
6119
  console.error('error using ui element in server side request');
@@ -5673,7 +6258,7 @@ func.utils.ws_worker.functions = {
5673
6258
  });
5674
6259
  },
5675
6260
  update_datasource_changes_from_client: async function (params, promise_queue_id) {
5676
- if (_.isEmpty(SESSION_OBJ)) return;
6261
+ if (xu_isEmpty(SESSION_OBJ)) return;
5677
6262
  var SESSION_ID = params.session_id;
5678
6263
  var _session = SESSION_OBJ[SESSION_ID];
5679
6264
  if (!_session) {
@@ -5869,16 +6454,8 @@ func.utils.clean_stringify_null = function (key, value) {
5869
6454
 
5870
6455
  func.utils.load_js_on_demand = async function (js_src, type) {
5871
6456
  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
6457
  if (glb.IS_WORKER) {
5881
- callback(script);
6458
+ callback();
5882
6459
  return;
5883
6460
  }
5884
6461
  function isScriptLoaded(src) {
@@ -5888,8 +6465,7 @@ func.utils.load_js_on_demand = async function (js_src, type) {
5888
6465
  if (isScriptLoaded(js_src)) {
5889
6466
  callback(false);
5890
6467
  } else {
5891
- getScript(js_src, function (response, status) {
5892
- // console.log(response,status)
6468
+ func.runtime.platform.load_script(js_src, type, function () {
5893
6469
  callback(true);
5894
6470
  GLB_JS_SCRIPTS_LOADED.push(js_src);
5895
6471
  });
@@ -5902,33 +6478,11 @@ func.utils.load_js_on_demand = async function (js_src, type) {
5902
6478
  };
5903
6479
 
5904
6480
  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');
6481
+ func.runtime.platform.load_css(css_href);
5922
6482
  };
5923
6483
 
5924
6484
  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
- }
6485
+ func.runtime.platform.remove_js_css(filename, filetype);
5932
6486
  };
5933
6487
 
5934
6488
  func.utils.replace_studio_drive_url = function (SESSION_ID, val) {
@@ -6275,7 +6829,7 @@ func.utils.alerts.popup = function (title, message, alert_type) {
6275
6829
  },
6276
6830
  ];
6277
6831
 
6278
- popup.create(_.upperFirst(alert_type), title, message, buttons);
6832
+ popup.create(alert_type.charAt(0).toUpperCase() + alert_type.slice(1), title, message, buttons);
6279
6833
  };
6280
6834
 
6281
6835
  func.utils.get_system_error_msg = function () {
@@ -6922,7 +7476,7 @@ func.utils.call_plugin_api = function (SESSION_ID, plugin_nameP, dataP) {
6922
7476
  app_token: _session.app_token,
6923
7477
  };
6924
7478
 
6925
- data = _.assignIn(data, dataP);
7479
+ data = Object.assign(data, dataP);
6926
7480
 
6927
7481
  fetch(`https://xuda.ai/ppi/${plugin_nameP}`, {
6928
7482
  method: 'POST',
@@ -7080,7 +7634,7 @@ func.utils.get_resource_filename = function (build, filename) {
7080
7634
  };
7081
7635
 
7082
7636
  func.utils.set_SYS_GLOBAL_OBJ_WIDGET_INFO = async function (SESSION_ID, docP) {
7083
- var obj = _.clone(docP);
7637
+ var obj = { ...docP };
7084
7638
  obj.date = await func.utils.get_dateTime(SESSION_ID, 'SYS_DATE', docP.date);
7085
7639
  obj.time = await func.utils.get_dateTime(SESSION_ID, 'SYS_TIME', docP.date);
7086
7640
 
@@ -7195,7 +7749,7 @@ func.events.validate = async function (SESSION_ID, triggerP, dsSessionP, eventId
7195
7749
 
7196
7750
  let value = await func.common.get_cast_val(SESSION_ID, 'events', fieldId, field_info.props.fieldType, args[fieldId].value);
7197
7751
 
7198
- if (!_.isEmpty(args[fieldId].fx)) {
7752
+ if (!xu_isEmpty(args[fieldId].fx)) {
7199
7753
  const fx_ret = await func.expression.get(SESSION_ID, args[fieldId].fx, dsSessionP, 'update');
7200
7754
  value = fx_ret.result;
7201
7755
  }
@@ -7217,7 +7771,7 @@ func.events.validate = async function (SESSION_ID, triggerP, dsSessionP, eventId
7217
7771
  if (_event.workflow) {
7218
7772
  // check if event property exist
7219
7773
 
7220
- if (!_event.workflow || _.isEmpty(_event.workflow)) return;
7774
+ if (!_event.workflow || xu_isEmpty(_event.workflow)) return;
7221
7775
  // check events has rows
7222
7776
  for (const trigger_obj of _event.workflow) {
7223
7777
  //run events rows
@@ -7237,17 +7791,19 @@ func.events.validate = async function (SESSION_ID, triggerP, dsSessionP, eventId
7237
7791
  if (_ds.panel_div_id) {
7238
7792
  try {
7239
7793
  container = '#' + _ds.panel_div_id;
7240
- if ($(container).data().xuData.panel_info) {
7241
- screen_prop = $(container).data().xuData.panel_info.paramsP;
7794
+ const panel_meta = func.runtime.ui.get_meta_by_element_id(_ds.panel_div_id);
7795
+ if (panel_meta?.xuData?.panel_info) {
7796
+ screen_prop = panel_meta.xuData.panel_info.paramsP;
7242
7797
  } else {
7243
7798
  ///////////////
7244
7799
  container = '#' + _session.DS_GLB[dsSessionP].screenId;
7800
+ const screen_meta = func.runtime.ui.get_meta_by_element_id(_session.DS_GLB[dsSessionP].screenId);
7245
7801
 
7246
- if ($(container) && $(container).data()) {
7247
- screen_prop = $(container).data().xuData.paramsP;
7802
+ if (screen_meta?.xuData) {
7803
+ screen_prop = screen_meta.xuData.paramsP;
7248
7804
  }
7249
7805
 
7250
- if (!$(container) || !$(container).length) {
7806
+ if (!screen_meta) {
7251
7807
  container = '#' + _session.DS_GLB[dsSessionP].containerId;
7252
7808
  }
7253
7809
  //////////////
@@ -7257,12 +7813,13 @@ func.events.validate = async function (SESSION_ID, triggerP, dsSessionP, eventId
7257
7813
  }
7258
7814
  } else {
7259
7815
  container = '#' + _ds.screenId;
7816
+ const screen_meta = func.runtime.ui.get_meta_by_element_id(_ds.screenId);
7260
7817
 
7261
- if ($(container) && $(container).data()) {
7262
- screen_prop = $(container).data().xuData.paramsP;
7818
+ if (screen_meta?.xuData) {
7819
+ screen_prop = screen_meta.xuData.paramsP;
7263
7820
  }
7264
7821
 
7265
- if (!$(container) || !$(container).length) {
7822
+ if (!screen_meta) {
7266
7823
  container = '#' + _ds.containerId;
7267
7824
  }
7268
7825
  }
@@ -7433,12 +7990,12 @@ func.events.find_job_index = function (SESSION_ID, jobNoP) {
7433
7990
  var _session = SESSION_OBJ[SESSION_ID];
7434
7991
  var ret = null;
7435
7992
  if (!_session.WORKER_OBJ) return ret;
7436
- _.forEach(_session.WORKER_OBJ.jobs, function (val, key) {
7993
+ for (const [key, val] of Object.entries(_session.WORKER_OBJ.jobs)) {
7437
7994
  if (val && val.job_num == jobNoP) {
7438
7995
  ret = key;
7439
- return false;
7996
+ break;
7440
7997
  }
7441
- });
7998
+ }
7442
7999
  return ret;
7443
8000
  };
7444
8001
  func.events.execute = async function (
@@ -7500,7 +8057,7 @@ func.events.execute = async function (
7500
8057
  var field_elm = elementP;
7501
8058
 
7502
8059
  var calling_field_id = field_elm;
7503
- if (field_elm && typeof field_elm === 'object') calling_field_id = field_elm.attr('xu-ui-id');
8060
+ if (field_elm && typeof field_elm === 'object') calling_field_id = func.runtime.ui.get_attr(field_elm, 'xu-ui-id');
7504
8061
 
7505
8062
  var log_nodeId;
7506
8063
  var log_prog_id;
@@ -7663,7 +8220,7 @@ func.events.execute = async function (
7663
8220
  var $calling_container;
7664
8221
  if (_session.WORKER_OBJ.jobs[job_index]) {
7665
8222
  if (_session.WORKER_OBJ.jobs[job_index].paramsP) {
7666
- $calling_container = $('#' + _session.WORKER_OBJ.jobs[job_index].paramsP.callingContainerP);
8223
+ $calling_container = func.runtime.ui.find_element_by_id(_session.WORKER_OBJ.jobs[job_index].paramsP.callingContainerP);
7667
8224
  } else {
7668
8225
  $calling_container = ''; // calling from datasource 0
7669
8226
  _session.WORKER_OBJ.jobs[job_index].paramsP = {};
@@ -7679,7 +8236,7 @@ func.events.execute = async function (
7679
8236
  return await func.runtime.ui.init_screen({
7680
8237
  SESSION_ID,
7681
8238
  prog_id: await get_prog_id(),
7682
- sourceScreenP: $(containerP)?.data()?.xuData.screenId,
8239
+ sourceScreenP: func.runtime.ui.get_data(containerP)?.xuData?.screenId,
7683
8240
  callingDataSource_objP: _session.DS_GLB[dsSession],
7684
8241
  $callingContainerP: $calling_container,
7685
8242
  triggerIdP: eventIdP,
@@ -7711,7 +8268,7 @@ func.events.execute = async function (
7711
8268
  var _session = SESSION_OBJ[SESSION_ID];
7712
8269
 
7713
8270
  const set_SYS_GLOBAL_OBJ_WIDGET_INFO = async function (docP) {
7714
- var obj = _.clone(docP);
8271
+ var obj = { ...docP };
7715
8272
  obj.date = await func.utils.get_dateTime(SESSION_ID, 'SYS_DATE', docP.date);
7716
8273
  obj.time = await func.utils.get_dateTime(SESSION_ID, 'SYS_TIME', docP.date);
7717
8274
 
@@ -7926,7 +8483,7 @@ func.events.execute = async function (
7926
8483
  emit_event: async function () {
7927
8484
  if (refIdP.value) {
7928
8485
  // if (descP.value) {
7929
- $(document).trigger(refIdP.value, [_session.DS_GLB[dsSession]]);
8486
+ func.runtime.platform.emit(refIdP.value, [_session.DS_GLB[dsSession]]);
7930
8487
  } else {
7931
8488
  func.utils.debug_report(SESSION_ID, 'func.events.execute', 'Event name missing', 'E');
7932
8489
  }
@@ -7998,7 +8555,7 @@ func.events.execute = async function (
7998
8555
 
7999
8556
  let _ds_new = _session.DS_GLB[ret.dsSessionP];
8000
8557
  let parameters = args?.calling_trigger_prop?.data?.name?.parameters;
8001
- if (parameters && !_.isEmpty(parameters)) {
8558
+ if (parameters && !xu_isEmpty(parameters)) {
8002
8559
  await func.datasource.update_changes_for_out_parameter(SESSION_ID, _ds_new.dsSession, _ds.dsSession);
8003
8560
  }
8004
8561
 
@@ -8017,7 +8574,7 @@ func.events.execute = async function (
8017
8574
  },
8018
8575
  update: async function () {
8019
8576
  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)) {
8577
+ if (!obj_values_to_update || xu_isEmpty(obj_values_to_update)) {
8021
8578
  func.utils.debug_report(SESSION_ID, 'Update values object is empty', '', 'W');
8022
8579
  if (jobNoP) func.events.delete_job(SESSION_ID, jobNoP);
8023
8580
  return;
@@ -8027,12 +8584,14 @@ func.events.execute = async function (
8027
8584
  for await (const [key, val] of Object.entries(obj_values_to_update)) {
8028
8585
  var $element;
8029
8586
 
8587
+ var iterate_info = null;
8030
8588
  if (elementP) {
8031
- $element = $(`[xu-ui-id="${elementP}"]`).clone(true);
8589
+ const element_meta = func.runtime.ui.get_meta(elementP, 'xuData');
8590
+ iterate_info = element_meta?.iterate_info || null;
8032
8591
  }
8033
8592
 
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);
8593
+ let ret_field_id = await func.expression.get(SESSION_ID, val.id.trim(), dsSessionP, 'update', null, null, null, null, null, null, iterate_info);
8594
+ let ret_value = await func.expression.get(SESSION_ID, val.val.trim(), dsSessionP, 'update', null, null, null, null, null, null, iterate_info);
8036
8595
  let _field_id = ret_field_id.result;
8037
8596
  let _value = ret_value.result;
8038
8597
 
@@ -8207,11 +8766,11 @@ func.events.execute = async function (
8207
8766
  if (error) {
8208
8767
  return func.utils.debug_report(SESSION_ID, msg, '', 'W');
8209
8768
  }
8210
- func.utils.debug_report(SESSION_ID, msg + ' ' + _.capitalize(source) + prog_info, '', 'E');
8769
+ func.utils.debug_report(SESSION_ID, msg + ' ' + (source.charAt(0).toUpperCase() + source.slice(1).toLowerCase()) + prog_info, '', 'E');
8211
8770
  };
8212
8771
  const report_conversion_warn = function (res) {
8213
8772
  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');
8773
+ func.utils.debug_report(SESSION_ID, msg + ' ' + (source.charAt(0).toUpperCase() + source.slice(1).toLowerCase()) + prog_info, '', 'W');
8215
8774
  };
8216
8775
  // var ret = valP;
8217
8776
  if (error) {
@@ -8226,8 +8785,7 @@ func.events.execute = async function (
8226
8785
  // report_conversion_warn
8227
8786
  // );
8228
8787
 
8229
- var payload = _.reduce(
8230
- payload_arr,
8788
+ var payload = payload_arr.reduce(
8231
8789
  (ret, val, key) => {
8232
8790
  ret[val.key] = module.cast(val.type, val.val, report_conversion_error, report_conversion_warn);
8233
8791
 
@@ -8344,12 +8902,12 @@ func.events.check_jobs_idle = async function (SESSION_ID, jobsP) {
8344
8902
  var listener = setInterval(function () {
8345
8903
  var found;
8346
8904
  for (const [key, val] of Object.entries(jobsP)) {
8347
- _.forEach(_session.WORKER_OBJ.jobs, function (val2, key2) {
8905
+ for (const [key2, val2] of Object.entries(_session.WORKER_OBJ.jobs)) {
8348
8906
  if (key2 === val) {
8349
8907
  found = true;
8350
- return false;
8908
+ break;
8351
8909
  }
8352
- });
8910
+ }
8353
8911
  }
8354
8912
  if (!found) {
8355
8913
  do_callback();
@@ -8357,7 +8915,7 @@ func.events.check_jobs_idle = async function (SESSION_ID, jobsP) {
8357
8915
  }
8358
8916
  }, 100);
8359
8917
  var do_callback = function () {
8360
- window.clearInterval(listener);
8918
+ clearInterval(listener);
8361
8919
  resolve();
8362
8920
  };
8363
8921
  });
@@ -8369,7 +8927,7 @@ setInterval(function () {
8369
8927
  }, 1000);
8370
8928
 
8371
8929
  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'];
8930
+ if (fieldsChangedP.includes('SYS_GLOBAL_STR_BROWSER_TITLE')) func.runtime.platform.set_title(dsP.dataset_new['SYS_GLOBAL_STR_BROWSER_TITLE']);
8373
8931
  };
8374
8932
 
8375
8933
  func.events.execute_PENDING_OPEN_URL_EVENTS = async function () {
@@ -8392,7 +8950,7 @@ func.events.execute_PENDING_OPEN_URL_EVENTS = async function () {
8392
8950
  prog_id: params_obj.prog,
8393
8951
  sourceScreenP: null,
8394
8952
  callingDataSource_objP: null,
8395
- $callingContainerP: $('#embed_' + SESSION_ID),
8953
+ $callingContainerP: func.runtime.ui.get_session_root(SESSION_ID),
8396
8954
  triggerIdP: null,
8397
8955
  rowIdP: null,
8398
8956
  jobNoP: null,
@@ -8418,7 +8976,7 @@ func.events.invoke = async function (event_id) {
8418
8976
  var ds;
8419
8977
  for await (const [ds_key, val] of Object.entries(_session.DS_GLB)) {
8420
8978
  const _view_obj = await func.utils.VIEWS_OBJ.get(SESSION_ID, val.prog_id);
8421
- if (_.isEmpty(_view_obj.progEvents)) continue;
8979
+ if (xu_isEmpty(_view_obj.progEvents)) continue;
8422
8980
  if (ds) break;
8423
8981
  for await (const [key, val] of Object.entries(_view_obj.progEvents)) {
8424
8982
  if (val?.data?.type === 'user_defined' && val.data.event_name === event_id) {
@@ -8475,7 +9033,7 @@ func.expression.get = async function (SESSION_ID, valP, dsSessionP, sourceP, row
8475
9033
  }
8476
9034
  }
8477
9035
 
8478
- ret = ret.replace(/\&amp;/g, '&');
9036
+ if (ret.includes('&amp;')) ret = ret.replace(/\&amp;/g, '&');
8479
9037
  ret = func.utils.replace_studio_drive_url(SESSION_ID, ret);
8480
9038
 
8481
9039
  const end_results = function () {
@@ -8539,13 +9097,13 @@ func.expression.get = async function (SESSION_ID, valP, dsSessionP, sourceP, row
8539
9097
  const variable_not_exist = async function () {
8540
9098
  try {
8541
9099
  if (sourceP !== 'arguments') {
8542
- if (ret && ret.substr(0, 6) === '_DATE_') {
8543
- ret = ret.substr(6);
9100
+ if (ret && ret.startsWith('_DATE_')) {
9101
+ ret = ret.slice(6);
8544
9102
  } 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
9103
+ ret === 'self' || // bypass eval for 'self'
9104
+ (ret && ret.length === 10 && ret[4] === '-' && ret[7] === '-') // bypass eval for date 2017-03-22
8547
9105
  ) {
8548
- ret = ret;
9106
+ // date or 'self' — skip eval, return as-is
8549
9107
  } else {
8550
9108
  ret = await func.expression.secure_eval(SESSION_ID, sourceP, ret, jobNo, dsSessionP, js_script_callback);
8551
9109
  }
@@ -8579,8 +9137,10 @@ func.expression.get = async function (SESSION_ID, valP, dsSessionP, sourceP, row
8579
9137
  var var_Arr = [];
8580
9138
  const split = func.expression.parse(ret) || [];
8581
9139
  // console.log(valP, split);
8582
- for await (const [arr_key, val] of Object.entries(split)) {
9140
+ const split_entries = Object.entries(split);
9141
+ for (let entry_i = 0; entry_i < split_entries.length; entry_i++) {
8583
9142
  // run each field
9143
+ const [arr_key, val] = split_entries[entry_i];
8584
9144
  const key = Number(arr_key);
8585
9145
  var_Arr[key] = {};
8586
9146
  var_Arr[key].value = val.value;
@@ -8625,14 +9185,16 @@ func.expression.get = async function (SESSION_ID, valP, dsSessionP, sourceP, row
8625
9185
  var prevData = var_Arr[key - 1].value;
8626
9186
  var_Arr[key].value = prevData[data]; // @objB[@var]
8627
9187
  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 .
9188
+ const props_split = await func.expression.get_property(val.value);
9189
+ property2 = props_split.property2;
8629
9190
  if (prevData[data]) set_value(prevData[data][property2]);
8630
9191
  // var_Arr[key].value = prevData[data][property2]; //@objB[@var].property
8631
9192
  }
8632
9193
  delete var_Arr[key - 1];
8633
9194
  } else {
8634
- property1 = await func.expression.get_property(val.value).property1;
8635
- property2 = await func.expression.get_property(val.value).property2;
9195
+ const props = await func.expression.get_property(val.value);
9196
+ property1 = props.property1;
9197
+ property2 = props.property2;
8636
9198
  if (property1) {
8637
9199
  var_Arr[key].value = data[property1]; // @var["value"] or @var.property
8638
9200
  if (property2) {
@@ -8680,7 +9242,7 @@ func.expression.get = async function (SESSION_ID, valP, dsSessionP, sourceP, row
8680
9242
  var exp_exist;
8681
9243
  var var_error_found;
8682
9244
  // merge arr values
8683
- _.forEach(var_Arr, function (val, key) {
9245
+ var_Arr.forEach(function (val, key) {
8684
9246
  if (sourceP === 'UI Property EXP') {
8685
9247
  let ret = func.utils.get_drive_url(SESSION_ID, val.value, true);
8686
9248
  if (ret.changed) {
@@ -8756,7 +9318,7 @@ func.expression.get = async function (SESSION_ID, valP, dsSessionP, sourceP, row
8756
9318
  if (exp.res) res = exp.res;
8757
9319
  // do second pass when exp exist
8758
9320
  else res = [exp.result];
8759
- fields = _.assignIn(exp.fields, fieldsP);
9321
+ fields = Object.assign(exp.fields, fieldsP);
8760
9322
  }
8761
9323
  var result = join(res);
8762
9324
 
@@ -9078,9 +9640,15 @@ func.expression.get = async function (SESSION_ID, valP, dsSessionP, sourceP, row
9078
9640
  // return res;
9079
9641
  // };
9080
9642
 
9643
+ func.expression._parse_cache = new Map();
9644
+
9081
9645
  func.expression.parse = function (input) {
9082
9646
  if (typeof input !== 'string') return [];
9083
9647
 
9648
+ if (func.expression._parse_cache.has(input)) {
9649
+ return func.expression._parse_cache.get(input).map(function (s) { return Object.assign({}, s); });
9650
+ }
9651
+
9084
9652
  const segments = [];
9085
9653
  let pos = 0;
9086
9654
 
@@ -9103,7 +9671,14 @@ func.expression.parse = function (input) {
9103
9671
  pos += part.length;
9104
9672
  }
9105
9673
 
9106
- return segments;
9674
+ // Evict oldest entry if cache exceeds limit
9675
+ if (func.expression._parse_cache.size >= 500) {
9676
+ const firstKey = func.expression._parse_cache.keys().next().value;
9677
+ func.expression._parse_cache.delete(firstKey);
9678
+ }
9679
+ func.expression._parse_cache.set(input, segments);
9680
+
9681
+ return segments.map(function (s) { return Object.assign({}, s); });
9107
9682
  };
9108
9683
 
9109
9684
  func.expression.get_property = async function (valP) {