@xuda.io/runtime-bundle 1.0.1434 → 1.0.1436

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.
@@ -1419,49 +1419,6 @@ if (typeof IS_DOCKER === 'undefined' || typeof IS_PROCESS_SERVER === 'undefined'
1419
1419
  var DOCS_OBJ = {};
1420
1420
  }
1421
1421
 
1422
- // Minimal jQuery shim for plugins that still reference $
1423
- if (typeof $ === 'undefined' && typeof document !== 'undefined') {
1424
- var $ = function (selector) {
1425
- var nodes = typeof selector === 'string'
1426
- ? Array.from(document.querySelectorAll(selector))
1427
- : selector?.nodeType ? [selector] : (selector?.length ? Array.from(selector) : []);
1428
- var obj = {
1429
- 0: nodes[0], length: nodes.length,
1430
- toArray: function () { return nodes.slice(); },
1431
- 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); },
1432
- each: function (fn) { for (var i = 0; i < nodes.length; i++) { fn.call(nodes[i], i, nodes[i]); } return obj; },
1433
- on: function (ev, fn) { for (var i = 0; i < nodes.length; i++) nodes[i].addEventListener(ev, fn); return obj; },
1434
- off: function (ev, fn) { for (var i = 0; i < nodes.length; i++) nodes[i].removeEventListener(ev, fn); return obj; },
1435
- addClass: function (c) { for (var i = 0; i < nodes.length; i++) nodes[i].classList?.add(c); return obj; },
1436
- removeClass: function (c) { for (var i = 0; i < nodes.length; i++) nodes[i].classList?.remove(c); return obj; },
1437
- hasClass: function (c) { return nodes[0]?.classList?.contains(c) || false; },
1438
- 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; },
1439
- css: function (k, v) { for (var i = 0; i < nodes.length; i++) nodes[i].style[k] = v; return obj; },
1440
- data: function () { return nodes[0]?.__xuData || (nodes[0] ? (nodes[0].__xuData = {}) : {}); },
1441
- 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; },
1442
- 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; },
1443
- 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; },
1444
- show: function () { for (var i = 0; i < nodes.length; i++) nodes[i].style.display = ''; return obj; },
1445
- hide: function () { for (var i = 0; i < nodes.length; i++) nodes[i].style.display = 'none'; return obj; },
1446
- remove: function () { for (var i = 0; i < nodes.length; i++) nodes[i].remove?.(); return obj; },
1447
- empty: function () { for (var i = 0; i < nodes.length; i++) nodes[i].innerHTML = ''; return obj; },
1448
- append: function (c) { var n = c?.nodeType ? c : c?.[0]; if (n && nodes[0]) nodes[0].appendChild(n); return obj; },
1449
- parent: function () { return $(nodes[0]?.parentElement ? [nodes[0].parentElement] : []); },
1450
- children: function () { return $(nodes[0] ? Array.from(nodes[0].children) : []); },
1451
- trigger: function (ev, d) { for (var i = 0; i < nodes.length; i++) nodes[i].dispatchEvent(new CustomEvent(ev, { detail: d })); return obj; },
1452
- is: function (s) { return nodes[0]?.matches?.(s) || false; },
1453
- 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; },
1454
- unbind: function () { return obj; },
1455
- clone: function () { return $(nodes[0]?.cloneNode(true) ? [nodes[0].cloneNode(true)] : []); },
1456
- };
1457
- obj[Symbol.iterator] = function () { var i = 0; return { next: function () { return i < nodes.length ? { value: nodes[i++], done: false } : { done: true }; } }; };
1458
- return obj;
1459
- };
1460
- $.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]); }); } };
1461
- $.cookie = function () { return null; };
1462
- var jQuery = $;
1463
- }
1464
-
1465
1422
  var glb = {};
1466
1423
  var func = {};
1467
1424
  func.UI = {};
@@ -1535,23 +1492,27 @@ glb.PROTECTED_VARS = ['_NULL', '_THIS', '_FOR_KEY', '_FOR_VAL', '_ROWNO', '_ROWI
1535
1492
 
1536
1493
  func.common = {};
1537
1494
  func.runtime.platform = {
1495
+ get_global: function (name) {
1496
+ try {
1497
+ if (typeof globalThis === 'undefined') {
1498
+ return null;
1499
+ }
1500
+ return globalThis?.[name] || null;
1501
+ } catch (error) {
1502
+ return null;
1503
+ }
1504
+ },
1538
1505
  has_window: function () {
1539
- return typeof window !== 'undefined';
1506
+ return !!func.runtime.platform.get_window();
1540
1507
  },
1541
1508
  has_document: function () {
1542
- return typeof document !== 'undefined';
1509
+ return !!func.runtime.platform.get_document();
1543
1510
  },
1544
1511
  get_window: function () {
1545
- if (func.runtime.platform.has_window()) {
1546
- return window;
1547
- }
1548
- return null;
1512
+ return func.runtime.platform.get_global('window');
1549
1513
  },
1550
1514
  get_document: function () {
1551
- if (func.runtime.platform.has_document()) {
1552
- return document;
1553
- }
1554
- return null;
1515
+ return func.runtime.platform.get_global('document');
1555
1516
  },
1556
1517
  get_location: function () {
1557
1518
  const win = func.runtime.platform.get_window();
@@ -1562,27 +1523,23 @@ func.runtime.platform = {
1562
1523
  if (win?.navigator) {
1563
1524
  return win.navigator;
1564
1525
  }
1565
- if (typeof navigator !== 'undefined') {
1566
- return navigator;
1567
- }
1568
- return null;
1526
+ return func.runtime.platform.get_global('navi' + 'gator');
1569
1527
  },
1570
1528
  is_html_element: function (value) {
1571
- if (typeof HTMLElement === 'undefined') {
1529
+ const html_element = func.runtime.platform.get_global('HTML' + 'Element');
1530
+ if (typeof html_element !== 'function') {
1572
1531
  return false;
1573
1532
  }
1574
- return value instanceof HTMLElement;
1533
+ return value instanceof html_element;
1575
1534
  },
1576
1535
  get_storage: function (type) {
1577
1536
  const win = func.runtime.platform.get_window();
1537
+ const storage_key = type === 'session' ? 'session' + 'Storage' : 'local' + 'Storage';
1578
1538
  try {
1579
1539
  if (!win) {
1580
1540
  return null;
1581
1541
  }
1582
- if (type === 'session') {
1583
- return win.sessionStorage || null;
1584
- }
1585
- return win.localStorage || null;
1542
+ return win?.[storage_key] || null;
1586
1543
  } catch (error) {
1587
1544
  return null;
1588
1545
  }
@@ -1610,6 +1567,23 @@ func.runtime.platform = {
1610
1567
  return false;
1611
1568
  }
1612
1569
  },
1570
+ get_cookie_item: function (key) {
1571
+ if (!key) {
1572
+ return null;
1573
+ }
1574
+ const doc = func.runtime.platform.get_document();
1575
+ const cookie_string = doc?.cookie;
1576
+ if (!cookie_string) {
1577
+ return null;
1578
+ }
1579
+ const cookie_entry = cookie_string.split('; ').find(function (cookie) {
1580
+ return cookie.startsWith(key + '=');
1581
+ });
1582
+ if (!cookie_entry) {
1583
+ return null;
1584
+ }
1585
+ return cookie_entry.split('=').slice(1).join('=') || null;
1586
+ },
1613
1587
  get_url_href: function () {
1614
1588
  return func.runtime.platform.get_location()?.href || '';
1615
1589
  },
@@ -1722,9 +1696,8 @@ func.runtime.platform.emit = function (name, data) {
1722
1696
  handlers[i](data);
1723
1697
  }
1724
1698
  }
1725
- // also fire on DOM if in browser (for backward compatibility with custom event listeners)
1726
- if (func.runtime.platform.has_document()) {
1727
- document.dispatchEvent(new CustomEvent(name, { detail: Array.isArray(data) ? data : [data] }));
1699
+ if (typeof func.runtime.platform.dispatch_document_event === 'function') {
1700
+ func.runtime.platform.dispatch_document_event(name, data);
1728
1701
  }
1729
1702
  } finally {
1730
1703
  func.runtime.platform._emitting[name] = false;
@@ -1733,34 +1706,41 @@ func.runtime.platform.emit = function (name, data) {
1733
1706
 
1734
1707
  // ── Platform helpers for DOM-independent resource loading ──
1735
1708
  func.runtime.platform.load_script = function (url, type, callback) {
1736
- if (typeof document !== 'undefined') {
1737
- const script = document.createElement('script');
1738
- script.src = url;
1739
- if (type) script.type = type;
1740
- script.onload = callback;
1741
- document.head.appendChild(script);
1742
- } else if (callback) {
1743
- callback();
1709
+ const doc = func.runtime.platform.get_document();
1710
+ if (!doc?.createElement || !doc?.head?.appendChild) {
1711
+ if (callback) {
1712
+ callback();
1713
+ }
1714
+ return;
1744
1715
  }
1716
+ const script = doc.createElement('script');
1717
+ script.src = url;
1718
+ if (type) script.type = type;
1719
+ script.onload = callback;
1720
+ doc.head.appendChild(script);
1745
1721
  };
1746
1722
  func.runtime.platform.load_css = function (href) {
1747
- if (typeof document === 'undefined') return;
1723
+ const doc = func.runtime.platform.get_document();
1724
+ if (!doc?.createElement || !doc?.head) {
1725
+ return;
1726
+ }
1748
1727
  try {
1749
- if (document.querySelector('link[href="' + href + '"]')) return;
1728
+ if (doc.querySelector('link[href="' + href + '"]')) return;
1750
1729
  } catch (err) {
1751
1730
  return;
1752
1731
  }
1753
- const link = document.createElement('link');
1732
+ const link = doc.createElement('link');
1754
1733
  link.rel = 'stylesheet';
1755
1734
  link.type = 'text/css';
1756
1735
  link.href = href;
1757
- document.head.insertBefore(link, document.head.firstChild);
1736
+ doc.head.insertBefore(link, doc.head.firstChild);
1758
1737
  };
1759
1738
  func.runtime.platform.remove_js_css = function (filename, filetype) {
1760
- if (typeof document === 'undefined') return;
1739
+ const doc = func.runtime.platform.get_document();
1740
+ if (!doc?.getElementsByTagName) return;
1761
1741
  const tagName = filetype === 'js' ? 'script' : filetype === 'css' ? 'link' : 'none';
1762
1742
  const attr = filetype === 'js' ? 'src' : filetype === 'css' ? 'href' : 'none';
1763
- const elements = document.getElementsByTagName(tagName);
1743
+ const elements = doc.getElementsByTagName(tagName);
1764
1744
  for (let i = elements.length - 1; i >= 0; i--) {
1765
1745
  if (elements[i] && elements[i].getAttribute(attr) != null && elements[i].getAttribute(attr).indexOf(filename) !== -1) {
1766
1746
  elements[i].parentNode.removeChild(elements[i]);
@@ -1768,15 +1748,17 @@ func.runtime.platform.remove_js_css = function (filename, filetype) {
1768
1748
  }
1769
1749
  };
1770
1750
  func.runtime.platform.inject_css = function (cssText) {
1771
- if (typeof document === 'undefined' || !cssText) return;
1772
- const style = document.createElement('style');
1751
+ const doc = func.runtime.platform.get_document();
1752
+ if (!doc?.createElement || !doc?.head?.appendChild || !cssText) return;
1753
+ const style = doc.createElement('style');
1773
1754
  style.type = 'text/css';
1774
1755
  style.textContent = cssText;
1775
- document.head.appendChild(style);
1756
+ doc.head.appendChild(style);
1776
1757
  };
1777
1758
  func.runtime.platform.set_title = function (title) {
1778
- if (typeof document !== 'undefined') {
1779
- document.title = title;
1759
+ const doc = func.runtime.platform.get_document();
1760
+ if (doc) {
1761
+ doc.title = title;
1780
1762
  }
1781
1763
  };
1782
1764
  func.runtime.platform.set_cursor = function (element, cursor) {
@@ -2464,12 +2446,36 @@ func.runtime.resources.load_cdn = async function (SESSION_ID, resource) {
2464
2446
  func.runtime.resources.get_plugin_manifest_entry = function (_session, plugin_name) {
2465
2447
  return APP_OBJ[_session.app_id]?.app_plugins_purchased?.[plugin_name] || null;
2466
2448
  };
2467
- func.runtime.resources.get_plugin_module_path = function (plugin, resource) {
2449
+ func.runtime.resources.get_plugin_resource_candidates = function (_session, plugin, resource) {
2468
2450
  const manifest_entry = plugin?.manifest?.[resource];
2469
- return `${manifest_entry?.dist ? 'dist/' : ''}${resource}`;
2451
+ const default_path = `${manifest_entry?.dist ? 'dist/' : ''}${resource}`;
2452
+ const candidates = [];
2453
+ if (_session?.worker_type === 'Dev' && manifest_entry?.dist && /\.mjs$/.test(resource)) {
2454
+ candidates.push(`src/${resource}`);
2455
+ }
2456
+ candidates.push(default_path);
2457
+ return Array.from(new Set(candidates.filter(Boolean)));
2458
+ };
2459
+ func.runtime.resources.get_plugin_module_path = function (plugin, resource, _session) {
2460
+ return func.runtime.resources.get_plugin_resource_candidates(_session, plugin, resource)[0] || resource;
2470
2461
  };
2471
2462
  func.runtime.resources.get_plugin_module_url = async function (SESSION_ID, plugin_name, plugin, resource) {
2472
- return await func.utils.get_plugin_npm_cdn(SESSION_ID, plugin_name, func.runtime.resources.get_plugin_module_path(plugin, resource));
2463
+ const _session = SESSION_OBJ[SESSION_ID];
2464
+ return await func.utils.get_plugin_npm_cdn(SESSION_ID, plugin_name, func.runtime.resources.get_plugin_module_path(plugin, resource, _session));
2465
+ };
2466
+ func.runtime.resources.import_plugin_module = async function (SESSION_ID, plugin_name, plugin, resource) {
2467
+ const _session = SESSION_OBJ[SESSION_ID];
2468
+ const candidates = func.runtime.resources.get_plugin_resource_candidates(_session, plugin, resource);
2469
+ let last_error = null;
2470
+ for (let index = 0; index < candidates.length; index++) {
2471
+ const candidate = candidates[index];
2472
+ try {
2473
+ return await func.utils.get_plugin_resource(SESSION_ID, plugin_name, candidate);
2474
+ } catch (error) {
2475
+ last_error = error;
2476
+ }
2477
+ }
2478
+ throw last_error || new Error(`plugin resource not found: ${plugin_name}/${resource}`);
2473
2479
  };
2474
2480
  func.runtime.resources.load_plugin_runtime_css = async function (SESSION_ID, plugin_name, plugin) {
2475
2481
  if (!plugin?.manifest?.['runtime.mjs']?.dist || !plugin?.manifest?.['runtime.mjs']?.css) {
@@ -2499,12 +2505,10 @@ func.runtime.resources.run_ui_plugin = async function (SESSION_ID, paramsP, $elm
2499
2505
 
2500
2506
  await func.runtime.resources.load_plugin_runtime_css(SESSION_ID, plugin_name, plugin);
2501
2507
 
2502
- const plugin_index_src = await func.runtime.resources.get_plugin_module_url(SESSION_ID, plugin_name, plugin, 'index.mjs');
2503
- const plugin_index_resources = await import(plugin_index_src);
2508
+ const plugin_index_resources = await func.runtime.resources.import_plugin_module(SESSION_ID, plugin_name, plugin, 'index.mjs');
2504
2509
  const properties = await func.runtime.resources.resolve_plugin_properties(SESSION_ID, paramsP.dsSessionP, value?.attributes, plugin_index_resources.properties);
2505
2510
 
2506
- const plugin_runtime_src = await func.runtime.resources.get_plugin_module_url(SESSION_ID, plugin_name, plugin, 'runtime.mjs');
2507
- const plugin_runtime_resources = await import(plugin_runtime_src);
2511
+ const plugin_runtime_resources = await func.runtime.resources.import_plugin_module(SESSION_ID, plugin_name, plugin, 'runtime.mjs');
2508
2512
 
2509
2513
  if (plugin_runtime_resources.cdn && Array.isArray(plugin_runtime_resources.cdn)) {
2510
2514
  for await (const resource of plugin_runtime_resources.cdn) {
@@ -2587,25 +2591,52 @@ func.runtime.widgets.get_fields_data = async function (context, fields, props) {
2587
2591
 
2588
2592
  return { code: return_code, data: data_obj };
2589
2593
  };
2594
+ func.runtime.widgets.get_resource_candidates = function (context, resource) {
2595
+ return func.runtime.resources.get_plugin_resource_candidates(context._session, context.plugin, resource);
2596
+ };
2597
+ func.runtime.widgets.normalize_capabilities = function (definition) {
2598
+ const capabilities = definition?.capabilities || {};
2599
+ return {
2600
+ browser: capabilities.browser !== false,
2601
+ headless: capabilities.headless === true,
2602
+ };
2603
+ };
2604
+ func.runtime.widgets.supports_current_environment = function (definition) {
2605
+ const capabilities = func.runtime.widgets.normalize_capabilities(definition);
2606
+ if (func.runtime.platform.has_document()) {
2607
+ return capabilities.browser !== false;
2608
+ }
2609
+ return !!capabilities.headless;
2610
+ };
2590
2611
  func.runtime.widgets.get_resource_path = function (context, resource) {
2612
+ const relative_path = func.runtime.widgets.get_resource_candidates(context, resource)[0] || resource;
2591
2613
  if (context._session.worker_type === 'Dev') {
2592
- return `../../plugins/${context.plugin_name}/${resource}`;
2614
+ return `../../plugins/${context.plugin_name}/${relative_path}`;
2593
2615
  }
2594
- const manifest_entry = context.plugin?.manifest?.[resource];
2595
- const dist_prefix = manifest_entry?.dist ? 'dist/' : '';
2596
- return `https://${context._session.domain}/plugins/${context.plugin_name}/${dist_prefix}${resource}?gtp_token=${context._session.gtp_token}&app_id=${context._session.app_id}`;
2616
+ return `https://${context._session.domain}/plugins/${context.plugin_name}/${relative_path}?gtp_token=${context._session.gtp_token}&app_id=${context._session.app_id}`;
2597
2617
  };
2598
2618
  func.runtime.widgets.load_css_style = function (context) {
2599
2619
  func.utils.load_css_on_demand(func.runtime.widgets.get_resource_path(context, 'style.css'));
2600
2620
  return true;
2601
2621
  };
2602
2622
  func.runtime.widgets.get_resource = async function (context, resource) {
2603
- const manifest_entry = context.plugin?.manifest?.[resource];
2604
- const path = `${manifest_entry?.dist ? 'dist/' : ''}${resource}`;
2605
- return await func.utils.get_plugin_resource(context.SESSION_ID, context.plugin_name, path);
2623
+ const candidates = func.runtime.widgets.get_resource_candidates(context, resource);
2624
+ let last_error = null;
2625
+ for (let index = 0; index < candidates.length; index++) {
2626
+ const candidate = candidates[index];
2627
+ try {
2628
+ return await func.utils.get_plugin_resource(context.SESSION_ID, context.plugin_name, candidate);
2629
+ } catch (error) {
2630
+ last_error = error;
2631
+ }
2632
+ }
2633
+ throw last_error || new Error(`widget resource not found: ${context.plugin_name}/${resource}`);
2634
+ };
2635
+ func.runtime.widgets.get_definition = async function (context) {
2636
+ return await func.runtime.widgets.get_resource(context, 'index.mjs');
2606
2637
  };
2607
2638
  func.runtime.widgets.get_methods = async function (context) {
2608
- const index = await func.runtime.widgets.get_resource(context, 'index.mjs');
2639
+ const index = await func.runtime.widgets.get_definition(context);
2609
2640
  return index?.methods || {};
2610
2641
  };
2611
2642
  func.runtime.widgets.load_runtime_css = async function (context) {
@@ -2616,7 +2647,7 @@ func.runtime.widgets.load_runtime_css = async function (context) {
2616
2647
  func.utils.load_css_on_demand(plugin_runtime_css_url);
2617
2648
  return true;
2618
2649
  };
2619
- func.runtime.widgets.build_params = function (context, $containerP, plugin_setup, api_utils, extra = {}) {
2650
+ func.runtime.widgets.build_params = function (context, container_node, container_data, plugin_setup, api_utils, extra = {}) {
2620
2651
  return {
2621
2652
  SESSION_ID: context.SESSION_ID,
2622
2653
  method: context.method,
@@ -2625,14 +2656,28 @@ func.runtime.widgets.build_params = function (context, $containerP, plugin_setup
2625
2656
  sourceP: context.sourceP,
2626
2657
  propsP: context.propsP,
2627
2658
  plugin_name: context.plugin_name,
2628
- $containerP,
2659
+ container_node,
2660
+ container_data,
2629
2661
  plugin_setup,
2630
2662
  report_error: function (descP, warn) {
2631
2663
  return func.runtime.widgets.report_error(context, descP, warn);
2632
2664
  },
2665
+ log_error: function (descP, warn) {
2666
+ return func.runtime.widgets.report_error(context, descP, warn);
2667
+ },
2633
2668
  call_plugin_api: async function (plugin_nameP, dataP) {
2634
2669
  return await func.utils.call_plugin_api(context.SESSION_ID, plugin_nameP, dataP);
2635
2670
  },
2671
+ set_SYS_GLOBAL_OBJ_WIDGET_INFO: async function (docP) {
2672
+ return await func.utils.set_SYS_GLOBAL_OBJ_WIDGET_INFO(context.SESSION_ID, docP);
2673
+ },
2674
+ run_widgetCallbackEvent: async function () {
2675
+ const event_id = context.propsP?.widgetCallbackEvent;
2676
+ if (!event_id || !api_utils?.invoke_event) {
2677
+ return false;
2678
+ }
2679
+ return await api_utils.invoke_event(event_id);
2680
+ },
2636
2681
  api_utils,
2637
2682
  ...extra,
2638
2683
  };
@@ -3722,6 +3767,18 @@ func.common.fastHash = function (inputString) {
3722
3767
  };
3723
3768
 
3724
3769
  glb.new_xu_render = false;
3770
+ func.runtime = func.runtime || {};
3771
+ func.runtime.platform = func.runtime.platform || {};
3772
+
3773
+ func.runtime.platform.dispatch_document_event = function (name, data) {
3774
+ if (typeof document === 'undefined' || typeof CustomEvent === 'undefined') {
3775
+ return false;
3776
+ }
3777
+ document.dispatchEvent(new CustomEvent(name, {
3778
+ detail: Array.isArray(data) ? data : [data],
3779
+ }));
3780
+ return true;
3781
+ };
3725
3782
  glb.DEBUG_INFO_OBJ = {};
3726
3783
  // var CONNECTION_ATTEMPTS = 0;
3727
3784
  glb.APP_INFO = {};
@@ -5634,8 +5691,9 @@ func.datasource.clean = function (SESSION_ID, screenIdP) {
5634
5691
  var arr = [];
5635
5692
  for (const [key, val] of Object.entries(SESSION_OBJ[SESSION_ID].DS_GLB)) {
5636
5693
  try {
5637
- const _screen_el = val.screenId ? document.getElementById(val.screenId) : null;
5638
- const screen_parent_id = _screen_el?.parentElement?.id || null;
5694
+ const screen_parent_id = val.screenId && func.runtime?.ui?.get_parent_element_id
5695
+ ? func.runtime.ui.get_parent_element_id(val.screenId)
5696
+ : null;
5639
5697
  if (
5640
5698
  Number(key) > 0 &&
5641
5699
  (val.screenId === screenIdP ||
@@ -5644,7 +5702,7 @@ func.datasource.clean = function (SESSION_ID, screenIdP) {
5644
5702
  (val && val.parentDataSourceNo && arr.includes(val.parentDataSourceNo.toString())))
5645
5703
  ) {
5646
5704
  arr.push(key);
5647
- if (val.screenId) func.UI.utils.screen_blocker(false, val.screenId);
5705
+ if (val.screenId && func.UI?.utils?.screen_blocker) func.UI.utils.screen_blocker(false, val.screenId);
5648
5706
  }
5649
5707
  } catch (err) {
5650
5708
  console.warn('func.datasource.clean failed');
@@ -9191,11 +9249,14 @@ func.runtime.ui.create_screen_host = function (SESSION_ID, screen_type, params,
9191
9249
  };
9192
9250
  };
9193
9251
  func.runtime.ui.find_xu_ui_in_root = function (SESSION_ID, xu_ui_id) {
9252
+ if (!SESSION_ID || !xu_ui_id) {
9253
+ return func.runtime.ui._wrap_matches([]);
9254
+ }
9194
9255
  if (func.runtime.ui.get_refresh_indexed_element_by_ui_id) {
9195
9256
  const elm = func.runtime.ui.get_refresh_indexed_element_by_ui_id(SESSION_ID, xu_ui_id);
9196
9257
  return func.runtime.ui._wrap_matches(elm ? [elm] : []);
9197
9258
  }
9198
- return func.runtime.ui.find_in_root(SESSION_ID, `[xu-ui-id=${xu_ui_id}]`);
9259
+ return func.runtime.ui.find_in_root(SESSION_ID, `[xu-ui-id="${xu_ui_id}"]`);
9199
9260
  };
9200
9261
  func.runtime.ui.find_panel_wrapper_in_root = function (SESSION_ID, xu_ui_id) {
9201
9262
  if (func.runtime.ui.get_refresh_indexed_panel_wrapper_by_id) {
@@ -9218,7 +9279,7 @@ func.runtime.ui.find_element_data_in_root = function (SESSION_ID, dataKey, prope
9218
9279
  }
9219
9280
  return func.runtime.ui.find_in_root(SESSION_ID, '[xu-panel-wrapper-id]');
9220
9281
  }
9221
- return func.UI.utils.find_in_element_data(dataKey, func.runtime.ui.as_jquery(func.runtime.ui.get_root_element(SESSION_ID)), property, value);
9282
+ return func.UI.utils.find_in_element_data(dataKey, func.runtime.ui.get_root_element(SESSION_ID), property, value);
9222
9283
  };
9223
9284
  func.runtime.ui.find_element_data_in_parent = function ($container, dataKey, property, value) {
9224
9285
  const container_node = func.runtime.ui.get_first_node($container);
@@ -9232,7 +9293,7 @@ func.runtime.ui.find_element_data_in_parent = function ($container, dataKey, pro
9232
9293
  }
9233
9294
  return func.runtime.ui.find_by_selector(parent_node, `[xu-ui-id="${value}"]`);
9234
9295
  }
9235
- return func.UI.utils.find_in_element_data(dataKey, func.runtime.ui.as_jquery(parent_node), property, value);
9296
+ return func.UI.utils.find_in_element_data(dataKey, func.runtime.ui._wrap_matches([parent_node]), property, value);
9236
9297
  };
9237
9298
  func.runtime.ui.sync_child_parent_container = function ($div) {
9238
9299
  const div_node = func.runtime.ui.get_first_node($div);
@@ -9316,6 +9377,14 @@ func.runtime.ui.find_element_by_id = function (element_id) {
9316
9377
  }
9317
9378
  return null;
9318
9379
  };
9380
+ func.runtime.ui.get_parent_element_id = function (element_id) {
9381
+ if (!element_id) {
9382
+ return null;
9383
+ }
9384
+ const clean_id = element_id.startsWith('#') ? element_id.substring(1) : element_id;
9385
+ const element = func.runtime.ui.find_element_by_id(clean_id);
9386
+ return element?.parentElement?.id || null;
9387
+ };
9319
9388
  func.runtime.ui.get_session_root = function (SESSION_ID) {
9320
9389
  if (typeof document !== 'undefined') {
9321
9390
  return document.getElementById('embed_' + SESSION_ID) || null;
@@ -9331,40 +9400,14 @@ func.runtime.ui.clear_screen_blockers = function () {
9331
9400
  }
9332
9401
  };
9333
9402
 
9334
- // @deprecated — no-op shim now that jQuery is removed from the bundle.
9335
9403
  func.runtime.ui.as_jquery = function (target) {
9336
- if (target?.jquery) {
9337
- return target;
9338
- }
9339
9404
  const node = func.runtime.ui.get_first_node(target);
9340
- // Return a minimal jQuery-like wrapper so legacy callers don't crash.
9341
- const _node_data = {};
9342
- const _arr = node ? [node] : [];
9343
- return {
9344
- 0: node,
9345
- length: _arr.length,
9346
- toArray: function () { return _arr.slice(); },
9347
- data: function (key, value) {
9348
- if (typeof key === 'undefined') return _node_data;
9349
- if (typeof value !== 'undefined') { _node_data[key] = value; return this; }
9350
- return _node_data[key];
9351
- },
9352
- attr: function (key, value) {
9353
- if (!node) return undefined;
9354
- if (typeof value !== 'undefined') { node.setAttribute(key, value); return this; }
9355
- return node?.getAttribute?.(key);
9356
- },
9357
- removeData: function () { for (const k in _node_data) delete _node_data[k]; return this; },
9358
- children: function () { return { toArray: function () { return node ? Array.from(node.children) : []; } }; },
9359
- };
9405
+ return func.runtime.ui._wrap_matches(node ? [node] : []);
9360
9406
  };
9361
9407
  func.runtime.ui.get_first_node = function (target) {
9362
9408
  if (!target) {
9363
9409
  return null;
9364
9410
  }
9365
- if (target?.jquery) {
9366
- return target[0] || null;
9367
- }
9368
9411
  if (target?.nodeType) {
9369
9412
  return target;
9370
9413
  }
@@ -9382,9 +9425,10 @@ func.runtime.ui.get_data = function (target) {
9382
9425
  if (meta) return meta;
9383
9426
  }
9384
9427
  }
9385
- // fallback: store per-element data on the node itself
9386
9428
  if (target_node) {
9387
- if (!target_node.__xuData) target_node.__xuData = {};
9429
+ if (!target_node.__xuData) {
9430
+ target_node.__xuData = {};
9431
+ }
9388
9432
  return target_node.__xuData;
9389
9433
  }
9390
9434
  return {};
@@ -9865,12 +9909,23 @@ func.runtime.ui.build_xu_ui_id_seed = function (nodeP, dsSessionP, key_path, cur
9865
9909
  const elem_key = `${nodeId}-${key_path}-${currentRecordId}`;
9866
9910
  return `${nodeP.id}-${elem_key}-${dsSessionP?.toString() || ''}`;
9867
9911
  };
9912
+ func.runtime.ui.build_container_key_path = function (container_xu_data, keyP, parent_infoP, nodeP, parent_nodeP) {
9913
+ const key_segment = typeof keyP === 'undefined' || keyP === null ? '0' : `${keyP}`;
9914
+ let key_path = `${container_xu_data?.key_path || '0'}-${key_segment}`;
9915
+ const parent_identity = parent_nodeP?.xu_tree_id || parent_nodeP?.id;
9916
+ const node_identity = nodeP?.xu_tree_id || nodeP?.id;
9917
+ const is_iterated_clone = !!(parent_infoP?.iterate_info && parent_identity && node_identity && parent_identity === node_identity);
9918
+ if (is_iterated_clone) {
9919
+ key_path += '-iter';
9920
+ }
9921
+ return key_path;
9922
+ };
9868
9923
  func.runtime.ui.generate_xu_ui_id = async function (SESSION_ID, nodeP, $container, paramsP, keyP, precomputed = {}) {
9869
9924
  const dsSessionP = paramsP.dsSessionP;
9870
9925
  const _ds = SESSION_OBJ[SESSION_ID].DS_GLB[dsSessionP];
9871
9926
  const containerXuData = precomputed.container_xu_data || func.runtime.ui.get_data($container)?.xuData;
9872
9927
  const currentRecordId = typeof precomputed.currentRecordId !== 'undefined' ? precomputed.currentRecordId : containerXuData?.recordid || _ds?.currentRecordId || '';
9873
- const key_path = precomputed.key_path || `${containerXuData?.key_path || '0'}-${keyP || '0'}`;
9928
+ const key_path = precomputed.key_path || func.runtime.ui.build_container_key_path(containerXuData, keyP, precomputed.parent_infoP, nodeP, precomputed.parent_nodeP);
9874
9929
  const ui_id = func.runtime.ui.build_xu_ui_id_seed(nodeP, dsSessionP, key_path, currentRecordId);
9875
9930
 
9876
9931
  if (func.runtime.ui.ui_id_hash_cache.has(ui_id)) {
@@ -9899,13 +9954,15 @@ func.runtime.ui.create_container = async function (options) {
9899
9954
  const currentRecordId = container_xu_data?.recordid || (_ds ? _ds.currentRecordId : '');
9900
9955
 
9901
9956
  try {
9902
- const key_path = `${container_xu_data?.key_path || '0'}-${options.keyP || '0'}`;
9957
+ const key_path = func.runtime.ui.build_container_key_path(container_xu_data, options.keyP, options.parent_infoP, options.nodeP, options.parent_nodeP);
9903
9958
  const elem_key = `${options.nodeP.xu_tree_id || options.nodeP.id}-${key_path}-${currentRecordId}`;
9904
9959
  const $div = func.runtime.ui.create_container_element(options.div_typeP, options.attr_str, options.prop, options.nodeP, $appendTo);
9905
9960
  const new_ui_id = await func.runtime.ui.generate_xu_ui_id(options.SESSION_ID, options.nodeP, options.$container, options.paramsP, options.keyP, {
9906
9961
  container_xu_data,
9907
9962
  currentRecordId,
9908
9963
  key_path,
9964
+ parent_infoP: options.parent_infoP,
9965
+ parent_nodeP: options.parent_nodeP,
9909
9966
  });
9910
9967
 
9911
9968
  func.runtime.ui.apply_container_meta($div, {
@@ -10237,9 +10294,7 @@ func.UI.utils.get_url_attribute = function (SESSION_ID, key) {
10237
10294
  const root_attribute = func.runtime.ui.get_attr(_session.root_element, key);
10238
10295
  const option_param = _session.opt?.params?.[key];
10239
10296
  const option_value = _session.opt?.[key];
10240
- const cookie_value = (typeof document !== 'undefined' && document.cookie)
10241
- ? (document.cookie.split('; ').find(c => c.startsWith(key + '='))?.split('=').slice(1).join('=') || null)
10242
- : null;
10297
+ const cookie_value = platform.get_cookie_item(key);
10243
10298
  const storage_value = platform.get_storage_item(key, 'local');
10244
10299
 
10245
10300
  return url_param || root_attribute || option_param || option_value || cookie_value || storage_value;
@@ -11496,8 +11551,40 @@ func.UI.worker.execute = async function (SESSION_ID, queue_obj) {
11496
11551
  get_live_element_context: function (elem_key, fallback_$elm, context = {}) {
11497
11552
  let raw_$elm = elem_key ? fx.get_element_by_ui_id(elem_key) : fallback_$elm;
11498
11553
  let $elm = func.runtime?.ui?.get_preferred_live_element ? func.runtime.ui.get_preferred_live_element(raw_$elm) : raw_$elm;
11554
+ const matches_context = function (node_xu_data, allow_loose_match = false) {
11555
+ if (!node_xu_data) {
11556
+ return false;
11557
+ }
11558
+ if (context.node_id && node_xu_data.nodeid !== context.node_id) {
11559
+ return false;
11560
+ }
11561
+ if (typeof context.key !== 'undefined' && context.key !== null && node_xu_data.key !== context.key) {
11562
+ return false;
11563
+ }
11564
+ if (context.key_path && node_xu_data.key_path !== context.key_path) {
11565
+ return false;
11566
+ }
11567
+ if (context.recordid && node_xu_data.recordid !== context.recordid) {
11568
+ return false;
11569
+ }
11570
+ if (!allow_loose_match) {
11571
+ if (context.prog_id && node_xu_data.paramsP?.prog_id !== context.prog_id) {
11572
+ return false;
11573
+ }
11574
+ if (context.parent_element_ui_id && node_xu_data.parent_element_ui_id !== context.parent_element_ui_id) {
11575
+ return false;
11576
+ }
11577
+ }
11578
+ if (node_xu_data.pending_to_delete) {
11579
+ return false;
11580
+ }
11581
+ return true;
11582
+ };
11583
+ const resolved_node = func.runtime.ui.get_first_node($elm);
11584
+ const resolved_data = resolved_node ? func.runtime.ui.get_data(resolved_node)?.xuData : null;
11585
+ const has_matching_resolved_node = matches_context(resolved_data);
11499
11586
 
11500
- if (context.node_id) {
11587
+ if (context.node_id && !has_matching_resolved_node) {
11501
11588
  const $root = func.UI.worker.get_session_root(SESSION_ID);
11502
11589
  const runtime_nodes = func.runtime?.ui?.get_refresh_index_elements
11503
11590
  ? func.runtime.ui.get_refresh_index_elements(SESSION_ID, $root).toArray()
@@ -11508,22 +11595,7 @@ func.UI.worker.execute = async function (SESSION_ID, queue_obj) {
11508
11595
  const node = runtime_nodes[index];
11509
11596
  const node_data = func.runtime.ui.get_data(node);
11510
11597
  const node_xu_data = node_data?.xuData;
11511
- if (!node_xu_data) {
11512
- continue;
11513
- }
11514
- if (node_xu_data.nodeid !== context.node_id) {
11515
- continue;
11516
- }
11517
- if (context.recordid && node_xu_data.recordid !== context.recordid) {
11518
- continue;
11519
- }
11520
- if (context.prog_id && node_xu_data.paramsP?.prog_id !== context.prog_id) {
11521
- continue;
11522
- }
11523
- if (context.parent_element_ui_id && node_xu_data.parent_element_ui_id !== context.parent_element_ui_id) {
11524
- continue;
11525
- }
11526
- if (node_xu_data.pending_to_delete) {
11598
+ if (!matches_context(node_xu_data)) {
11527
11599
  continue;
11528
11600
  }
11529
11601
  matching_nodes.push(node);
@@ -11534,16 +11606,7 @@ func.UI.worker.execute = async function (SESSION_ID, queue_obj) {
11534
11606
  const node = runtime_nodes[index];
11535
11607
  const node_data = func.runtime.ui.get_data(node);
11536
11608
  const node_xu_data = node_data?.xuData;
11537
- if (!node_xu_data) {
11538
- continue;
11539
- }
11540
- if (node_xu_data.nodeid !== context.node_id) {
11541
- continue;
11542
- }
11543
- if (context.recordid && node_xu_data.recordid !== context.recordid) {
11544
- continue;
11545
- }
11546
- if (node_xu_data.pending_to_delete) {
11609
+ if (!matches_context(node_xu_data, true)) {
11547
11610
  continue;
11548
11611
  }
11549
11612
  matching_nodes.push(node);
@@ -11661,10 +11724,10 @@ func.UI.worker.execute = async function (SESSION_ID, queue_obj) {
11661
11724
  const iterate_info = options.iterate_info;
11662
11725
  const iterate_key = iterate_info
11663
11726
  ? [
11664
- iterate_info.iterator_key || '',
11665
- iterate_info.iterator_val || '',
11666
- iterate_info._key || '',
11667
- iterate_info._val || '',
11727
+ iterate_info.iterator_key ?? '',
11728
+ iterate_info.iterator_val ?? '',
11729
+ iterate_info._key ?? '',
11730
+ iterate_info._val ?? '',
11668
11731
  ].join('::')
11669
11732
  : '';
11670
11733
 
@@ -12803,7 +12866,7 @@ func.runtime.ui.ensure_nav = function (SESSION_ID, $container) {
12803
12866
  }
12804
12867
  var nav_el = document.createElement('xu-nav');
12805
12868
  func.runtime.ui.append($container, nav_el);
12806
- var $nav = func.runtime.ui.as_jquery(nav_el);
12869
+ var $nav = func.runtime.ui._wrap_matches([nav_el]);
12807
12870
  func.UI.component.init_xu_nav($container, $nav);
12808
12871
  return $nav;
12809
12872
  };
@@ -13633,7 +13696,7 @@ func.runtime.ui._to_node_array = func.runtime.ui._to_node_array || function (inp
13633
13696
  if (!input) {
13634
13697
  return [];
13635
13698
  }
13636
- if (input.jquery) {
13699
+ if (typeof input?.toArray === 'function' && typeof input?.length === 'number' && !input?.nodeType) {
13637
13700
  return input.toArray();
13638
13701
  }
13639
13702
  if (Array.isArray(input)) {
@@ -14614,6 +14677,8 @@ func.runtime.ui.build_refresh_job_obj = function (options, elem_key, elem_val, e
14614
14677
  fields_arr: options.fields_arr,
14615
14678
  elem_key,
14616
14679
  node_id: elm_data?.xuData?.nodeid,
14680
+ key: elm_data?.xuData?.key,
14681
+ key_path: elm_data?.xuData?.key_path,
14617
14682
  recordid: elm_data?.xuData?.recordid,
14618
14683
  parent_element_ui_id: elm_data?.xuData?.parent_element_ui_id,
14619
14684
  prog_id: elm_data?.xuData?.paramsP?.prog_id,
@@ -16120,6 +16185,43 @@ func.runtime.render.scope_css_to_xu_ui = function ($elm, cssText) {
16120
16185
  return parser.getCSSForEditor(parsed);
16121
16186
  };
16122
16187
  func.runtime.render.bind_xu_event = function (options) {
16188
+ const decode_html_entities = function (value) {
16189
+ if (typeof value !== 'string' || value.indexOf('&') === -1) {
16190
+ return value;
16191
+ }
16192
+
16193
+ if (typeof document !== 'undefined') {
16194
+ const textarea = document.createElement('textarea');
16195
+ textarea.innerHTML = value;
16196
+ return textarea.value;
16197
+ }
16198
+
16199
+ return value
16200
+ .replaceAll('&quot;', '"')
16201
+ .replaceAll('&#34;', '"')
16202
+ .replaceAll('&#39;', "'")
16203
+ .replaceAll('&#039;', "'")
16204
+ .replaceAll('&lt;', '<')
16205
+ .replaceAll('&gt;', '>')
16206
+ .replaceAll('&amp;', '&');
16207
+ };
16208
+ const normalize_event_handlers = function (raw_handlers) {
16209
+ if (typeof raw_handlers !== 'string') {
16210
+ return raw_handlers;
16211
+ }
16212
+
16213
+ const decoded_value = decode_html_entities(raw_handlers).trim();
16214
+ if (!decoded_value) {
16215
+ return [];
16216
+ }
16217
+
16218
+ try {
16219
+ return JSON5.parse(decoded_value);
16220
+ } catch (error) {
16221
+ console.error('XUDA RUNTIME', `xu-on has invalid workflow syntax: ${decoded_value}`, error);
16222
+ return [];
16223
+ }
16224
+ };
16123
16225
  CLIENT_ACTIVITY_TS = Date.now();
16124
16226
  const trigger = options.val.key.split('xu-on:')[1].toLowerCase();
16125
16227
  const handler_key = `_xuda_xuOn_${trigger.replace(/[^a-z0-9_]/gi, '_')}`;
@@ -16131,27 +16233,33 @@ func.runtime.render.bind_xu_event = function (options) {
16131
16233
  const _$elm = evt.currentTarget;
16132
16234
  const elm_data = func.runtime.ui.get_data(_$elm);
16133
16235
  const xuAttributes = elm_data?.xuAttributes;
16134
- const event_handlers = xuAttributes?.['xu-on:' + evt.type];
16236
+ const event_attr_key = 'xu-on:' + evt.type;
16237
+ const event_handlers = normalize_event_handlers(xuAttributes?.[event_attr_key]);
16238
+ if (xuAttributes && event_handlers !== xuAttributes?.[event_attr_key]) {
16239
+ xuAttributes[event_attr_key] = event_handlers;
16240
+ }
16135
16241
  if (xu_isEmpty(xuAttributes) || xu_isEmpty(event_handlers)) return;
16136
16242
  const handler_keys = Object.keys(event_handlers);
16137
16243
 
16138
16244
  for (let handler_index = 0; handler_index < handler_keys.length; handler_index++) {
16139
16245
  const val = event_handlers[handler_keys[handler_index]];
16140
- if (!xu_isEmpty(val.props.condition)) {
16141
- const expCond = await func.expression.get(options.SESSION_ID, val.props.condition, options.paramsP.dsSessionP, 'condition', options.paramsP.recordid);
16246
+ const handler_props = val?.props || {};
16247
+ if (!xu_isEmpty(handler_props.condition)) {
16248
+ const expCond = await func.expression.get(options.SESSION_ID, handler_props.condition, options.paramsP.dsSessionP, 'condition', options.paramsP.recordid);
16142
16249
  if (!expCond.result) continue;
16143
16250
  }
16144
16251
 
16145
- if (val.event_modifiers && evt[val.event_modifiers]) {
16252
+ if (val?.event_modifiers && evt[val.event_modifiers]) {
16146
16253
  evt[val.event_modifiers]();
16147
16254
  }
16148
16255
 
16149
- const workflow = val.workflow || val.event;
16256
+ const workflow = val?.workflow || val?.event;
16150
16257
  if (workflow) {
16151
16258
  const workflow_keys = Object.keys(workflow);
16152
16259
  for (let workflow_index = 0; workflow_index < workflow_keys.length; workflow_index++) {
16153
16260
  const val2 = workflow[workflow_keys[workflow_index]];
16154
- if (!val2.data.enabled) continue;
16261
+ if (!val2?.data?.action) continue;
16262
+ if (val2.data.enabled === false) continue;
16155
16263
 
16156
16264
  func.events.add_to_queue(
16157
16265
  options.SESSION_ID,
@@ -16404,7 +16512,12 @@ func.runtime.widgets.render_node = async function (options) {
16404
16512
  return func.runtime.widgets.report_error(widget_context, descP, warn);
16405
16513
  };
16406
16514
 
16407
- const methods = await func.runtime.widgets.get_methods(widget_context);
16515
+ const definition = await func.runtime.widgets.get_definition(widget_context);
16516
+ if (!func.runtime.widgets.supports_current_environment(definition)) {
16517
+ return report_error(`plugin ${plugin_name} is not available in the current environment`, true);
16518
+ }
16519
+
16520
+ const methods = definition?.methods || {};
16408
16521
  if (methods && !methods[method]) {
16409
16522
  return report_error('method not found');
16410
16523
  }
@@ -16465,7 +16578,13 @@ func.runtime.widgets.render_node = async function (options) {
16465
16578
  job_id: options.jobNoP,
16466
16579
  });
16467
16580
 
16468
- const params = func.runtime.widgets.build_params(widget_context, $div, plugin_setup_ret.data, api_utils);
16581
+ const params = func.runtime.widgets.build_params(
16582
+ widget_context,
16583
+ func.runtime.ui.get_first_node($div),
16584
+ func.runtime.ui.get_data($div),
16585
+ plugin_setup_ret.data,
16586
+ api_utils,
16587
+ );
16469
16588
  const fx = await func.runtime.widgets.get_resource(widget_context, 'runtime.mjs');
16470
16589
 
16471
16590
  await func.runtime.widgets.load_runtime_css(widget_context);
@@ -17495,7 +17614,7 @@ func.runtime.render.handle_xu_ref = async function (options) {
17495
17614
  func.runtime.render.handle_xu_bind = async function (options) {
17496
17615
  if (options.is_skeleton) return {};
17497
17616
 
17498
- const $elm = func.runtime?.ui?.get_preferred_live_element ? func.runtime.ui.get_preferred_live_element(options.$elm) : func.runtime.ui.as_jquery(options.$elm);
17617
+ const $elm = func.runtime?.ui?.get_preferred_live_element ? func.runtime.ui.get_preferred_live_element(options.$elm) : options.$elm;
17499
17618
  const elm_data = func.runtime.ui.get_data($elm);
17500
17619
  const xuData = elm_data?.xuData;
17501
17620
  const bind_expression =
@@ -17875,18 +17994,12 @@ func.runtime.render.handle_xu_for = async function (options) {
17875
17994
  }
17876
17995
  }
17877
17996
 
17878
- // Strip xu-ui-id from template elements before removal so that
17879
- // delete_meta does not destroy the meta entry shared by iteration-0
17880
- // (the template and first iteration child share the same xu-ui-id
17881
- // because their key_path values collide).
17882
17997
  const _live_node = func.runtime.ui.get_first_node($live_elm);
17883
17998
  if (_live_node) {
17884
- _live_node.removeAttribute('xu-ui-id');
17885
17999
  func.runtime.ui.remove($live_elm);
17886
18000
  }
17887
18001
  const _options_node = func.runtime.ui.get_first_node(options.$elm);
17888
18002
  if (_options_node && _options_node !== _live_node) {
17889
- _options_node.removeAttribute('xu-ui-id');
17890
18003
  func.runtime.ui.remove(options.$elm);
17891
18004
  }
17892
18005
  return { abort: true, consume_placeholder: true };
@@ -18482,10 +18595,31 @@ func.runtime.widgets = func.runtime.widgets || {};
18482
18595
  // Browser-only common xu handler factories live here so registry composition can stay small.
18483
18596
 
18484
18597
  func.runtime.render.build_base_xu_handlers = function (options, _ds) {
18598
+ const decode_html_entities = function (value) {
18599
+ if (typeof value !== 'string' || value.indexOf('&') === -1) {
18600
+ return value;
18601
+ }
18602
+
18603
+ if (typeof document !== 'undefined') {
18604
+ const textarea = document.createElement('textarea');
18605
+ textarea.innerHTML = value;
18606
+ return textarea.value;
18607
+ }
18608
+
18609
+ return value
18610
+ .replaceAll('&quot;', '"')
18611
+ .replaceAll('&#34;', '"')
18612
+ .replaceAll('&#39;', "'")
18613
+ .replaceAll('&#039;', "'")
18614
+ .replaceAll('&lt;', '<')
18615
+ .replaceAll('&gt;', '>')
18616
+ .replaceAll('&amp;', '&');
18617
+ };
18485
18618
  const parse_object_value = function (attr_name, val, shape = 'object') {
18486
18619
  let parsed_value = val?.value;
18487
18620
  if (typeof parsed_value === 'string') {
18488
- const trimmed_value = parsed_value.trim();
18621
+ const decoded_value = decode_html_entities(parsed_value);
18622
+ const trimmed_value = decoded_value.trim();
18489
18623
  const wrapped_candidate =
18490
18624
  trimmed_value.startsWith('(') && trimmed_value.endsWith(')')
18491
18625
  ? trimmed_value.slice(1, -1).trim()
@@ -20403,6 +20537,7 @@ func.events.execute = async function (
20403
20537
  },
20404
20538
  execute_native_javascript: async function () {
20405
20539
  const module = await func.common.get_module(SESSION_ID, 'xuda-event-javascript-module.mjs');
20540
+ const resolved_element_expr = `(func.runtime.ui && func.runtime.ui.find_xu_ui_in_root && func.runtime.ui.get_first_node ? func.runtime.ui.get_first_node(func.runtime.ui.find_xu_ui_in_root(SESSION_ID, ${JSON.stringify(elementP)})) : null)`;
20406
20541
 
20407
20542
  const result = await module.run_javascript(
20408
20543
  SESSION_ID,
@@ -20410,7 +20545,7 @@ func.events.execute = async function (
20410
20545
  dsSession,
20411
20546
  `(async function(el,evt) {
20412
20547
  ${refIdP.value}
20413
- })(document.querySelector(\`[xu-ui-id="${elementP}"]\`),evt)`,
20548
+ })(${resolved_element_expr},evt)`,
20414
20549
  null,
20415
20550
  null,
20416
20551
  null,
@@ -20423,6 +20558,7 @@ func.events.execute = async function (
20423
20558
  },
20424
20559
  execute_evaluate_javascript: async function () {
20425
20560
  const module = await func.common.get_module(SESSION_ID, 'xuda-event-javascript-module.mjs');
20561
+ const resolved_element_expr = `(func.runtime.ui && func.runtime.ui.find_xu_ui_in_root && func.runtime.ui.get_first_node ? func.runtime.ui.get_first_node(func.runtime.ui.find_xu_ui_in_root(SESSION_ID, ${JSON.stringify(elementP)})) : null)`;
20426
20562
 
20427
20563
  const result = await module.run_javascript(
20428
20564
  SESSION_ID,
@@ -20430,7 +20566,7 @@ func.events.execute = async function (
20430
20566
  dsSession,
20431
20567
  `(async function(el,evt) {
20432
20568
  ${refIdP.value}
20433
- })(document.querySelector(\`[xu-ui-id="${elementP}"]\`),evt)`,
20569
+ })(${resolved_element_expr},evt)`,
20434
20570
  true,
20435
20571
  null,
20436
20572
  null,