@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.
@@ -1493,49 +1493,6 @@ if (typeof IS_DOCKER === 'undefined' || typeof IS_PROCESS_SERVER === 'undefined'
1493
1493
  var DOCS_OBJ = {};
1494
1494
  }
1495
1495
 
1496
- // Minimal jQuery shim for plugins that still reference $
1497
- if (typeof $ === 'undefined' && typeof document !== 'undefined') {
1498
- var $ = function (selector) {
1499
- var nodes = typeof selector === 'string'
1500
- ? Array.from(document.querySelectorAll(selector))
1501
- : selector?.nodeType ? [selector] : (selector?.length ? Array.from(selector) : []);
1502
- var obj = {
1503
- 0: nodes[0], length: nodes.length,
1504
- toArray: function () { return nodes.slice(); },
1505
- 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); },
1506
- each: function (fn) { for (var i = 0; i < nodes.length; i++) { fn.call(nodes[i], i, nodes[i]); } return obj; },
1507
- on: function (ev, fn) { for (var i = 0; i < nodes.length; i++) nodes[i].addEventListener(ev, fn); return obj; },
1508
- off: function (ev, fn) { for (var i = 0; i < nodes.length; i++) nodes[i].removeEventListener(ev, fn); return obj; },
1509
- addClass: function (c) { for (var i = 0; i < nodes.length; i++) nodes[i].classList?.add(c); return obj; },
1510
- removeClass: function (c) { for (var i = 0; i < nodes.length; i++) nodes[i].classList?.remove(c); return obj; },
1511
- hasClass: function (c) { return nodes[0]?.classList?.contains(c) || false; },
1512
- 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; },
1513
- css: function (k, v) { for (var i = 0; i < nodes.length; i++) nodes[i].style[k] = v; return obj; },
1514
- data: function () { return nodes[0]?.__xuData || (nodes[0] ? (nodes[0].__xuData = {}) : {}); },
1515
- 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; },
1516
- 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; },
1517
- 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; },
1518
- show: function () { for (var i = 0; i < nodes.length; i++) nodes[i].style.display = ''; return obj; },
1519
- hide: function () { for (var i = 0; i < nodes.length; i++) nodes[i].style.display = 'none'; return obj; },
1520
- remove: function () { for (var i = 0; i < nodes.length; i++) nodes[i].remove?.(); return obj; },
1521
- empty: function () { for (var i = 0; i < nodes.length; i++) nodes[i].innerHTML = ''; return obj; },
1522
- append: function (c) { var n = c?.nodeType ? c : c?.[0]; if (n && nodes[0]) nodes[0].appendChild(n); return obj; },
1523
- parent: function () { return $(nodes[0]?.parentElement ? [nodes[0].parentElement] : []); },
1524
- children: function () { return $(nodes[0] ? Array.from(nodes[0].children) : []); },
1525
- trigger: function (ev, d) { for (var i = 0; i < nodes.length; i++) nodes[i].dispatchEvent(new CustomEvent(ev, { detail: d })); return obj; },
1526
- is: function (s) { return nodes[0]?.matches?.(s) || false; },
1527
- 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; },
1528
- unbind: function () { return obj; },
1529
- clone: function () { return $(nodes[0]?.cloneNode(true) ? [nodes[0].cloneNode(true)] : []); },
1530
- };
1531
- obj[Symbol.iterator] = function () { var i = 0; return { next: function () { return i < nodes.length ? { value: nodes[i++], done: false } : { done: true }; } }; };
1532
- return obj;
1533
- };
1534
- $.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]); }); } };
1535
- $.cookie = function () { return null; };
1536
- var jQuery = $;
1537
- }
1538
-
1539
1496
  var glb = {};
1540
1497
  var func = {};
1541
1498
  func.UI = {};
@@ -1609,23 +1566,27 @@ glb.PROTECTED_VARS = ['_NULL', '_THIS', '_FOR_KEY', '_FOR_VAL', '_ROWNO', '_ROWI
1609
1566
 
1610
1567
  func.common = {};
1611
1568
  func.runtime.platform = {
1569
+ get_global: function (name) {
1570
+ try {
1571
+ if (typeof globalThis === 'undefined') {
1572
+ return null;
1573
+ }
1574
+ return globalThis?.[name] || null;
1575
+ } catch (error) {
1576
+ return null;
1577
+ }
1578
+ },
1612
1579
  has_window: function () {
1613
- return typeof window !== 'undefined';
1580
+ return !!func.runtime.platform.get_window();
1614
1581
  },
1615
1582
  has_document: function () {
1616
- return typeof document !== 'undefined';
1583
+ return !!func.runtime.platform.get_document();
1617
1584
  },
1618
1585
  get_window: function () {
1619
- if (func.runtime.platform.has_window()) {
1620
- return window;
1621
- }
1622
- return null;
1586
+ return func.runtime.platform.get_global('window');
1623
1587
  },
1624
1588
  get_document: function () {
1625
- if (func.runtime.platform.has_document()) {
1626
- return document;
1627
- }
1628
- return null;
1589
+ return func.runtime.platform.get_global('document');
1629
1590
  },
1630
1591
  get_location: function () {
1631
1592
  const win = func.runtime.platform.get_window();
@@ -1636,27 +1597,23 @@ func.runtime.platform = {
1636
1597
  if (win?.navigator) {
1637
1598
  return win.navigator;
1638
1599
  }
1639
- if (typeof navigator !== 'undefined') {
1640
- return navigator;
1641
- }
1642
- return null;
1600
+ return func.runtime.platform.get_global('navi' + 'gator');
1643
1601
  },
1644
1602
  is_html_element: function (value) {
1645
- if (typeof HTMLElement === 'undefined') {
1603
+ const html_element = func.runtime.platform.get_global('HTML' + 'Element');
1604
+ if (typeof html_element !== 'function') {
1646
1605
  return false;
1647
1606
  }
1648
- return value instanceof HTMLElement;
1607
+ return value instanceof html_element;
1649
1608
  },
1650
1609
  get_storage: function (type) {
1651
1610
  const win = func.runtime.platform.get_window();
1611
+ const storage_key = type === 'session' ? 'session' + 'Storage' : 'local' + 'Storage';
1652
1612
  try {
1653
1613
  if (!win) {
1654
1614
  return null;
1655
1615
  }
1656
- if (type === 'session') {
1657
- return win.sessionStorage || null;
1658
- }
1659
- return win.localStorage || null;
1616
+ return win?.[storage_key] || null;
1660
1617
  } catch (error) {
1661
1618
  return null;
1662
1619
  }
@@ -1684,6 +1641,23 @@ func.runtime.platform = {
1684
1641
  return false;
1685
1642
  }
1686
1643
  },
1644
+ get_cookie_item: function (key) {
1645
+ if (!key) {
1646
+ return null;
1647
+ }
1648
+ const doc = func.runtime.platform.get_document();
1649
+ const cookie_string = doc?.cookie;
1650
+ if (!cookie_string) {
1651
+ return null;
1652
+ }
1653
+ const cookie_entry = cookie_string.split('; ').find(function (cookie) {
1654
+ return cookie.startsWith(key + '=');
1655
+ });
1656
+ if (!cookie_entry) {
1657
+ return null;
1658
+ }
1659
+ return cookie_entry.split('=').slice(1).join('=') || null;
1660
+ },
1687
1661
  get_url_href: function () {
1688
1662
  return func.runtime.platform.get_location()?.href || '';
1689
1663
  },
@@ -1796,9 +1770,8 @@ func.runtime.platform.emit = function (name, data) {
1796
1770
  handlers[i](data);
1797
1771
  }
1798
1772
  }
1799
- // also fire on DOM if in browser (for backward compatibility with custom event listeners)
1800
- if (func.runtime.platform.has_document()) {
1801
- document.dispatchEvent(new CustomEvent(name, { detail: Array.isArray(data) ? data : [data] }));
1773
+ if (typeof func.runtime.platform.dispatch_document_event === 'function') {
1774
+ func.runtime.platform.dispatch_document_event(name, data);
1802
1775
  }
1803
1776
  } finally {
1804
1777
  func.runtime.platform._emitting[name] = false;
@@ -1807,34 +1780,41 @@ func.runtime.platform.emit = function (name, data) {
1807
1780
 
1808
1781
  // ── Platform helpers for DOM-independent resource loading ──
1809
1782
  func.runtime.platform.load_script = function (url, type, callback) {
1810
- if (typeof document !== 'undefined') {
1811
- const script = document.createElement('script');
1812
- script.src = url;
1813
- if (type) script.type = type;
1814
- script.onload = callback;
1815
- document.head.appendChild(script);
1816
- } else if (callback) {
1817
- callback();
1783
+ const doc = func.runtime.platform.get_document();
1784
+ if (!doc?.createElement || !doc?.head?.appendChild) {
1785
+ if (callback) {
1786
+ callback();
1787
+ }
1788
+ return;
1818
1789
  }
1790
+ const script = doc.createElement('script');
1791
+ script.src = url;
1792
+ if (type) script.type = type;
1793
+ script.onload = callback;
1794
+ doc.head.appendChild(script);
1819
1795
  };
1820
1796
  func.runtime.platform.load_css = function (href) {
1821
- if (typeof document === 'undefined') return;
1797
+ const doc = func.runtime.platform.get_document();
1798
+ if (!doc?.createElement || !doc?.head) {
1799
+ return;
1800
+ }
1822
1801
  try {
1823
- if (document.querySelector('link[href="' + href + '"]')) return;
1802
+ if (doc.querySelector('link[href="' + href + '"]')) return;
1824
1803
  } catch (err) {
1825
1804
  return;
1826
1805
  }
1827
- const link = document.createElement('link');
1806
+ const link = doc.createElement('link');
1828
1807
  link.rel = 'stylesheet';
1829
1808
  link.type = 'text/css';
1830
1809
  link.href = href;
1831
- document.head.insertBefore(link, document.head.firstChild);
1810
+ doc.head.insertBefore(link, doc.head.firstChild);
1832
1811
  };
1833
1812
  func.runtime.platform.remove_js_css = function (filename, filetype) {
1834
- if (typeof document === 'undefined') return;
1813
+ const doc = func.runtime.platform.get_document();
1814
+ if (!doc?.getElementsByTagName) return;
1835
1815
  const tagName = filetype === 'js' ? 'script' : filetype === 'css' ? 'link' : 'none';
1836
1816
  const attr = filetype === 'js' ? 'src' : filetype === 'css' ? 'href' : 'none';
1837
- const elements = document.getElementsByTagName(tagName);
1817
+ const elements = doc.getElementsByTagName(tagName);
1838
1818
  for (let i = elements.length - 1; i >= 0; i--) {
1839
1819
  if (elements[i] && elements[i].getAttribute(attr) != null && elements[i].getAttribute(attr).indexOf(filename) !== -1) {
1840
1820
  elements[i].parentNode.removeChild(elements[i]);
@@ -1842,15 +1822,17 @@ func.runtime.platform.remove_js_css = function (filename, filetype) {
1842
1822
  }
1843
1823
  };
1844
1824
  func.runtime.platform.inject_css = function (cssText) {
1845
- if (typeof document === 'undefined' || !cssText) return;
1846
- const style = document.createElement('style');
1825
+ const doc = func.runtime.platform.get_document();
1826
+ if (!doc?.createElement || !doc?.head?.appendChild || !cssText) return;
1827
+ const style = doc.createElement('style');
1847
1828
  style.type = 'text/css';
1848
1829
  style.textContent = cssText;
1849
- document.head.appendChild(style);
1830
+ doc.head.appendChild(style);
1850
1831
  };
1851
1832
  func.runtime.platform.set_title = function (title) {
1852
- if (typeof document !== 'undefined') {
1853
- document.title = title;
1833
+ const doc = func.runtime.platform.get_document();
1834
+ if (doc) {
1835
+ doc.title = title;
1854
1836
  }
1855
1837
  };
1856
1838
  func.runtime.platform.set_cursor = function (element, cursor) {
@@ -2538,12 +2520,36 @@ func.runtime.resources.load_cdn = async function (SESSION_ID, resource) {
2538
2520
  func.runtime.resources.get_plugin_manifest_entry = function (_session, plugin_name) {
2539
2521
  return APP_OBJ[_session.app_id]?.app_plugins_purchased?.[plugin_name] || null;
2540
2522
  };
2541
- func.runtime.resources.get_plugin_module_path = function (plugin, resource) {
2523
+ func.runtime.resources.get_plugin_resource_candidates = function (_session, plugin, resource) {
2542
2524
  const manifest_entry = plugin?.manifest?.[resource];
2543
- return `${manifest_entry?.dist ? 'dist/' : ''}${resource}`;
2525
+ const default_path = `${manifest_entry?.dist ? 'dist/' : ''}${resource}`;
2526
+ const candidates = [];
2527
+ if (_session?.worker_type === 'Dev' && manifest_entry?.dist && /\.mjs$/.test(resource)) {
2528
+ candidates.push(`src/${resource}`);
2529
+ }
2530
+ candidates.push(default_path);
2531
+ return Array.from(new Set(candidates.filter(Boolean)));
2532
+ };
2533
+ func.runtime.resources.get_plugin_module_path = function (plugin, resource, _session) {
2534
+ return func.runtime.resources.get_plugin_resource_candidates(_session, plugin, resource)[0] || resource;
2544
2535
  };
2545
2536
  func.runtime.resources.get_plugin_module_url = async function (SESSION_ID, plugin_name, plugin, resource) {
2546
- return await func.utils.get_plugin_npm_cdn(SESSION_ID, plugin_name, func.runtime.resources.get_plugin_module_path(plugin, resource));
2537
+ const _session = SESSION_OBJ[SESSION_ID];
2538
+ return await func.utils.get_plugin_npm_cdn(SESSION_ID, plugin_name, func.runtime.resources.get_plugin_module_path(plugin, resource, _session));
2539
+ };
2540
+ func.runtime.resources.import_plugin_module = async function (SESSION_ID, plugin_name, plugin, resource) {
2541
+ const _session = SESSION_OBJ[SESSION_ID];
2542
+ const candidates = func.runtime.resources.get_plugin_resource_candidates(_session, plugin, resource);
2543
+ let last_error = null;
2544
+ for (let index = 0; index < candidates.length; index++) {
2545
+ const candidate = candidates[index];
2546
+ try {
2547
+ return await func.utils.get_plugin_resource(SESSION_ID, plugin_name, candidate);
2548
+ } catch (error) {
2549
+ last_error = error;
2550
+ }
2551
+ }
2552
+ throw last_error || new Error(`plugin resource not found: ${plugin_name}/${resource}`);
2547
2553
  };
2548
2554
  func.runtime.resources.load_plugin_runtime_css = async function (SESSION_ID, plugin_name, plugin) {
2549
2555
  if (!plugin?.manifest?.['runtime.mjs']?.dist || !plugin?.manifest?.['runtime.mjs']?.css) {
@@ -2573,12 +2579,10 @@ func.runtime.resources.run_ui_plugin = async function (SESSION_ID, paramsP, $elm
2573
2579
 
2574
2580
  await func.runtime.resources.load_plugin_runtime_css(SESSION_ID, plugin_name, plugin);
2575
2581
 
2576
- const plugin_index_src = await func.runtime.resources.get_plugin_module_url(SESSION_ID, plugin_name, plugin, 'index.mjs');
2577
- const plugin_index_resources = await import(plugin_index_src);
2582
+ const plugin_index_resources = await func.runtime.resources.import_plugin_module(SESSION_ID, plugin_name, plugin, 'index.mjs');
2578
2583
  const properties = await func.runtime.resources.resolve_plugin_properties(SESSION_ID, paramsP.dsSessionP, value?.attributes, plugin_index_resources.properties);
2579
2584
 
2580
- const plugin_runtime_src = await func.runtime.resources.get_plugin_module_url(SESSION_ID, plugin_name, plugin, 'runtime.mjs');
2581
- const plugin_runtime_resources = await import(plugin_runtime_src);
2585
+ const plugin_runtime_resources = await func.runtime.resources.import_plugin_module(SESSION_ID, plugin_name, plugin, 'runtime.mjs');
2582
2586
 
2583
2587
  if (plugin_runtime_resources.cdn && Array.isArray(plugin_runtime_resources.cdn)) {
2584
2588
  for await (const resource of plugin_runtime_resources.cdn) {
@@ -2661,25 +2665,52 @@ func.runtime.widgets.get_fields_data = async function (context, fields, props) {
2661
2665
 
2662
2666
  return { code: return_code, data: data_obj };
2663
2667
  };
2668
+ func.runtime.widgets.get_resource_candidates = function (context, resource) {
2669
+ return func.runtime.resources.get_plugin_resource_candidates(context._session, context.plugin, resource);
2670
+ };
2671
+ func.runtime.widgets.normalize_capabilities = function (definition) {
2672
+ const capabilities = definition?.capabilities || {};
2673
+ return {
2674
+ browser: capabilities.browser !== false,
2675
+ headless: capabilities.headless === true,
2676
+ };
2677
+ };
2678
+ func.runtime.widgets.supports_current_environment = function (definition) {
2679
+ const capabilities = func.runtime.widgets.normalize_capabilities(definition);
2680
+ if (func.runtime.platform.has_document()) {
2681
+ return capabilities.browser !== false;
2682
+ }
2683
+ return !!capabilities.headless;
2684
+ };
2664
2685
  func.runtime.widgets.get_resource_path = function (context, resource) {
2686
+ const relative_path = func.runtime.widgets.get_resource_candidates(context, resource)[0] || resource;
2665
2687
  if (context._session.worker_type === 'Dev') {
2666
- return `../../plugins/${context.plugin_name}/${resource}`;
2688
+ return `../../plugins/${context.plugin_name}/${relative_path}`;
2667
2689
  }
2668
- const manifest_entry = context.plugin?.manifest?.[resource];
2669
- const dist_prefix = manifest_entry?.dist ? 'dist/' : '';
2670
- return `https://${context._session.domain}/plugins/${context.plugin_name}/${dist_prefix}${resource}?gtp_token=${context._session.gtp_token}&app_id=${context._session.app_id}`;
2690
+ return `https://${context._session.domain}/plugins/${context.plugin_name}/${relative_path}?gtp_token=${context._session.gtp_token}&app_id=${context._session.app_id}`;
2671
2691
  };
2672
2692
  func.runtime.widgets.load_css_style = function (context) {
2673
2693
  func.utils.load_css_on_demand(func.runtime.widgets.get_resource_path(context, 'style.css'));
2674
2694
  return true;
2675
2695
  };
2676
2696
  func.runtime.widgets.get_resource = async function (context, resource) {
2677
- const manifest_entry = context.plugin?.manifest?.[resource];
2678
- const path = `${manifest_entry?.dist ? 'dist/' : ''}${resource}`;
2679
- return await func.utils.get_plugin_resource(context.SESSION_ID, context.plugin_name, path);
2697
+ const candidates = func.runtime.widgets.get_resource_candidates(context, resource);
2698
+ let last_error = null;
2699
+ for (let index = 0; index < candidates.length; index++) {
2700
+ const candidate = candidates[index];
2701
+ try {
2702
+ return await func.utils.get_plugin_resource(context.SESSION_ID, context.plugin_name, candidate);
2703
+ } catch (error) {
2704
+ last_error = error;
2705
+ }
2706
+ }
2707
+ throw last_error || new Error(`widget resource not found: ${context.plugin_name}/${resource}`);
2708
+ };
2709
+ func.runtime.widgets.get_definition = async function (context) {
2710
+ return await func.runtime.widgets.get_resource(context, 'index.mjs');
2680
2711
  };
2681
2712
  func.runtime.widgets.get_methods = async function (context) {
2682
- const index = await func.runtime.widgets.get_resource(context, 'index.mjs');
2713
+ const index = await func.runtime.widgets.get_definition(context);
2683
2714
  return index?.methods || {};
2684
2715
  };
2685
2716
  func.runtime.widgets.load_runtime_css = async function (context) {
@@ -2690,7 +2721,7 @@ func.runtime.widgets.load_runtime_css = async function (context) {
2690
2721
  func.utils.load_css_on_demand(plugin_runtime_css_url);
2691
2722
  return true;
2692
2723
  };
2693
- func.runtime.widgets.build_params = function (context, $containerP, plugin_setup, api_utils, extra = {}) {
2724
+ func.runtime.widgets.build_params = function (context, container_node, container_data, plugin_setup, api_utils, extra = {}) {
2694
2725
  return {
2695
2726
  SESSION_ID: context.SESSION_ID,
2696
2727
  method: context.method,
@@ -2699,14 +2730,28 @@ func.runtime.widgets.build_params = function (context, $containerP, plugin_setup
2699
2730
  sourceP: context.sourceP,
2700
2731
  propsP: context.propsP,
2701
2732
  plugin_name: context.plugin_name,
2702
- $containerP,
2733
+ container_node,
2734
+ container_data,
2703
2735
  plugin_setup,
2704
2736
  report_error: function (descP, warn) {
2705
2737
  return func.runtime.widgets.report_error(context, descP, warn);
2706
2738
  },
2739
+ log_error: function (descP, warn) {
2740
+ return func.runtime.widgets.report_error(context, descP, warn);
2741
+ },
2707
2742
  call_plugin_api: async function (plugin_nameP, dataP) {
2708
2743
  return await func.utils.call_plugin_api(context.SESSION_ID, plugin_nameP, dataP);
2709
2744
  },
2745
+ set_SYS_GLOBAL_OBJ_WIDGET_INFO: async function (docP) {
2746
+ return await func.utils.set_SYS_GLOBAL_OBJ_WIDGET_INFO(context.SESSION_ID, docP);
2747
+ },
2748
+ run_widgetCallbackEvent: async function () {
2749
+ const event_id = context.propsP?.widgetCallbackEvent;
2750
+ if (!event_id || !api_utils?.invoke_event) {
2751
+ return false;
2752
+ }
2753
+ return await api_utils.invoke_event(event_id);
2754
+ },
2710
2755
  api_utils,
2711
2756
  ...extra,
2712
2757
  };
@@ -3796,6 +3841,18 @@ func.common.fastHash = function (inputString) {
3796
3841
  };
3797
3842
 
3798
3843
  glb.new_xu_render = false;
3844
+ func.runtime = func.runtime || {};
3845
+ func.runtime.platform = func.runtime.platform || {};
3846
+
3847
+ func.runtime.platform.dispatch_document_event = function (name, data) {
3848
+ if (typeof document === 'undefined' || typeof CustomEvent === 'undefined') {
3849
+ return false;
3850
+ }
3851
+ document.dispatchEvent(new CustomEvent(name, {
3852
+ detail: Array.isArray(data) ? data : [data],
3853
+ }));
3854
+ return true;
3855
+ };
3799
3856
  glb.DEBUG_INFO_OBJ = {};
3800
3857
  // var CONNECTION_ATTEMPTS = 0;
3801
3858
  glb.APP_INFO = {};
@@ -5708,8 +5765,9 @@ func.datasource.clean = function (SESSION_ID, screenIdP) {
5708
5765
  var arr = [];
5709
5766
  for (const [key, val] of Object.entries(SESSION_OBJ[SESSION_ID].DS_GLB)) {
5710
5767
  try {
5711
- const _screen_el = val.screenId ? document.getElementById(val.screenId) : null;
5712
- const screen_parent_id = _screen_el?.parentElement?.id || null;
5768
+ const screen_parent_id = val.screenId && func.runtime?.ui?.get_parent_element_id
5769
+ ? func.runtime.ui.get_parent_element_id(val.screenId)
5770
+ : null;
5713
5771
  if (
5714
5772
  Number(key) > 0 &&
5715
5773
  (val.screenId === screenIdP ||
@@ -5718,7 +5776,7 @@ func.datasource.clean = function (SESSION_ID, screenIdP) {
5718
5776
  (val && val.parentDataSourceNo && arr.includes(val.parentDataSourceNo.toString())))
5719
5777
  ) {
5720
5778
  arr.push(key);
5721
- if (val.screenId) func.UI.utils.screen_blocker(false, val.screenId);
5779
+ if (val.screenId && func.UI?.utils?.screen_blocker) func.UI.utils.screen_blocker(false, val.screenId);
5722
5780
  }
5723
5781
  } catch (err) {
5724
5782
  console.warn('func.datasource.clean failed');
@@ -9265,11 +9323,14 @@ func.runtime.ui.create_screen_host = function (SESSION_ID, screen_type, params,
9265
9323
  };
9266
9324
  };
9267
9325
  func.runtime.ui.find_xu_ui_in_root = function (SESSION_ID, xu_ui_id) {
9326
+ if (!SESSION_ID || !xu_ui_id) {
9327
+ return func.runtime.ui._wrap_matches([]);
9328
+ }
9268
9329
  if (func.runtime.ui.get_refresh_indexed_element_by_ui_id) {
9269
9330
  const elm = func.runtime.ui.get_refresh_indexed_element_by_ui_id(SESSION_ID, xu_ui_id);
9270
9331
  return func.runtime.ui._wrap_matches(elm ? [elm] : []);
9271
9332
  }
9272
- return func.runtime.ui.find_in_root(SESSION_ID, `[xu-ui-id=${xu_ui_id}]`);
9333
+ return func.runtime.ui.find_in_root(SESSION_ID, `[xu-ui-id="${xu_ui_id}"]`);
9273
9334
  };
9274
9335
  func.runtime.ui.find_panel_wrapper_in_root = function (SESSION_ID, xu_ui_id) {
9275
9336
  if (func.runtime.ui.get_refresh_indexed_panel_wrapper_by_id) {
@@ -9292,7 +9353,7 @@ func.runtime.ui.find_element_data_in_root = function (SESSION_ID, dataKey, prope
9292
9353
  }
9293
9354
  return func.runtime.ui.find_in_root(SESSION_ID, '[xu-panel-wrapper-id]');
9294
9355
  }
9295
- return func.UI.utils.find_in_element_data(dataKey, func.runtime.ui.as_jquery(func.runtime.ui.get_root_element(SESSION_ID)), property, value);
9356
+ return func.UI.utils.find_in_element_data(dataKey, func.runtime.ui.get_root_element(SESSION_ID), property, value);
9296
9357
  };
9297
9358
  func.runtime.ui.find_element_data_in_parent = function ($container, dataKey, property, value) {
9298
9359
  const container_node = func.runtime.ui.get_first_node($container);
@@ -9306,7 +9367,7 @@ func.runtime.ui.find_element_data_in_parent = function ($container, dataKey, pro
9306
9367
  }
9307
9368
  return func.runtime.ui.find_by_selector(parent_node, `[xu-ui-id="${value}"]`);
9308
9369
  }
9309
- return func.UI.utils.find_in_element_data(dataKey, func.runtime.ui.as_jquery(parent_node), property, value);
9370
+ return func.UI.utils.find_in_element_data(dataKey, func.runtime.ui._wrap_matches([parent_node]), property, value);
9310
9371
  };
9311
9372
  func.runtime.ui.sync_child_parent_container = function ($div) {
9312
9373
  const div_node = func.runtime.ui.get_first_node($div);
@@ -9390,6 +9451,14 @@ func.runtime.ui.find_element_by_id = function (element_id) {
9390
9451
  }
9391
9452
  return null;
9392
9453
  };
9454
+ func.runtime.ui.get_parent_element_id = function (element_id) {
9455
+ if (!element_id) {
9456
+ return null;
9457
+ }
9458
+ const clean_id = element_id.startsWith('#') ? element_id.substring(1) : element_id;
9459
+ const element = func.runtime.ui.find_element_by_id(clean_id);
9460
+ return element?.parentElement?.id || null;
9461
+ };
9393
9462
  func.runtime.ui.get_session_root = function (SESSION_ID) {
9394
9463
  if (typeof document !== 'undefined') {
9395
9464
  return document.getElementById('embed_' + SESSION_ID) || null;
@@ -9405,40 +9474,14 @@ func.runtime.ui.clear_screen_blockers = function () {
9405
9474
  }
9406
9475
  };
9407
9476
 
9408
- // @deprecated — no-op shim now that jQuery is removed from the bundle.
9409
9477
  func.runtime.ui.as_jquery = function (target) {
9410
- if (target?.jquery) {
9411
- return target;
9412
- }
9413
9478
  const node = func.runtime.ui.get_first_node(target);
9414
- // Return a minimal jQuery-like wrapper so legacy callers don't crash.
9415
- const _node_data = {};
9416
- const _arr = node ? [node] : [];
9417
- return {
9418
- 0: node,
9419
- length: _arr.length,
9420
- toArray: function () { return _arr.slice(); },
9421
- data: function (key, value) {
9422
- if (typeof key === 'undefined') return _node_data;
9423
- if (typeof value !== 'undefined') { _node_data[key] = value; return this; }
9424
- return _node_data[key];
9425
- },
9426
- attr: function (key, value) {
9427
- if (!node) return undefined;
9428
- if (typeof value !== 'undefined') { node.setAttribute(key, value); return this; }
9429
- return node?.getAttribute?.(key);
9430
- },
9431
- removeData: function () { for (const k in _node_data) delete _node_data[k]; return this; },
9432
- children: function () { return { toArray: function () { return node ? Array.from(node.children) : []; } }; },
9433
- };
9479
+ return func.runtime.ui._wrap_matches(node ? [node] : []);
9434
9480
  };
9435
9481
  func.runtime.ui.get_first_node = function (target) {
9436
9482
  if (!target) {
9437
9483
  return null;
9438
9484
  }
9439
- if (target?.jquery) {
9440
- return target[0] || null;
9441
- }
9442
9485
  if (target?.nodeType) {
9443
9486
  return target;
9444
9487
  }
@@ -9456,9 +9499,10 @@ func.runtime.ui.get_data = function (target) {
9456
9499
  if (meta) return meta;
9457
9500
  }
9458
9501
  }
9459
- // fallback: store per-element data on the node itself
9460
9502
  if (target_node) {
9461
- if (!target_node.__xuData) target_node.__xuData = {};
9503
+ if (!target_node.__xuData) {
9504
+ target_node.__xuData = {};
9505
+ }
9462
9506
  return target_node.__xuData;
9463
9507
  }
9464
9508
  return {};
@@ -9939,12 +9983,23 @@ func.runtime.ui.build_xu_ui_id_seed = function (nodeP, dsSessionP, key_path, cur
9939
9983
  const elem_key = `${nodeId}-${key_path}-${currentRecordId}`;
9940
9984
  return `${nodeP.id}-${elem_key}-${dsSessionP?.toString() || ''}`;
9941
9985
  };
9986
+ func.runtime.ui.build_container_key_path = function (container_xu_data, keyP, parent_infoP, nodeP, parent_nodeP) {
9987
+ const key_segment = typeof keyP === 'undefined' || keyP === null ? '0' : `${keyP}`;
9988
+ let key_path = `${container_xu_data?.key_path || '0'}-${key_segment}`;
9989
+ const parent_identity = parent_nodeP?.xu_tree_id || parent_nodeP?.id;
9990
+ const node_identity = nodeP?.xu_tree_id || nodeP?.id;
9991
+ const is_iterated_clone = !!(parent_infoP?.iterate_info && parent_identity && node_identity && parent_identity === node_identity);
9992
+ if (is_iterated_clone) {
9993
+ key_path += '-iter';
9994
+ }
9995
+ return key_path;
9996
+ };
9942
9997
  func.runtime.ui.generate_xu_ui_id = async function (SESSION_ID, nodeP, $container, paramsP, keyP, precomputed = {}) {
9943
9998
  const dsSessionP = paramsP.dsSessionP;
9944
9999
  const _ds = SESSION_OBJ[SESSION_ID].DS_GLB[dsSessionP];
9945
10000
  const containerXuData = precomputed.container_xu_data || func.runtime.ui.get_data($container)?.xuData;
9946
10001
  const currentRecordId = typeof precomputed.currentRecordId !== 'undefined' ? precomputed.currentRecordId : containerXuData?.recordid || _ds?.currentRecordId || '';
9947
- const key_path = precomputed.key_path || `${containerXuData?.key_path || '0'}-${keyP || '0'}`;
10002
+ const key_path = precomputed.key_path || func.runtime.ui.build_container_key_path(containerXuData, keyP, precomputed.parent_infoP, nodeP, precomputed.parent_nodeP);
9948
10003
  const ui_id = func.runtime.ui.build_xu_ui_id_seed(nodeP, dsSessionP, key_path, currentRecordId);
9949
10004
 
9950
10005
  if (func.runtime.ui.ui_id_hash_cache.has(ui_id)) {
@@ -9973,13 +10028,15 @@ func.runtime.ui.create_container = async function (options) {
9973
10028
  const currentRecordId = container_xu_data?.recordid || (_ds ? _ds.currentRecordId : '');
9974
10029
 
9975
10030
  try {
9976
- const key_path = `${container_xu_data?.key_path || '0'}-${options.keyP || '0'}`;
10031
+ const key_path = func.runtime.ui.build_container_key_path(container_xu_data, options.keyP, options.parent_infoP, options.nodeP, options.parent_nodeP);
9977
10032
  const elem_key = `${options.nodeP.xu_tree_id || options.nodeP.id}-${key_path}-${currentRecordId}`;
9978
10033
  const $div = func.runtime.ui.create_container_element(options.div_typeP, options.attr_str, options.prop, options.nodeP, $appendTo);
9979
10034
  const new_ui_id = await func.runtime.ui.generate_xu_ui_id(options.SESSION_ID, options.nodeP, options.$container, options.paramsP, options.keyP, {
9980
10035
  container_xu_data,
9981
10036
  currentRecordId,
9982
10037
  key_path,
10038
+ parent_infoP: options.parent_infoP,
10039
+ parent_nodeP: options.parent_nodeP,
9983
10040
  });
9984
10041
 
9985
10042
  func.runtime.ui.apply_container_meta($div, {
@@ -10311,9 +10368,7 @@ func.UI.utils.get_url_attribute = function (SESSION_ID, key) {
10311
10368
  const root_attribute = func.runtime.ui.get_attr(_session.root_element, key);
10312
10369
  const option_param = _session.opt?.params?.[key];
10313
10370
  const option_value = _session.opt?.[key];
10314
- const cookie_value = (typeof document !== 'undefined' && document.cookie)
10315
- ? (document.cookie.split('; ').find(c => c.startsWith(key + '='))?.split('=').slice(1).join('=') || null)
10316
- : null;
10371
+ const cookie_value = platform.get_cookie_item(key);
10317
10372
  const storage_value = platform.get_storage_item(key, 'local');
10318
10373
 
10319
10374
  return url_param || root_attribute || option_param || option_value || cookie_value || storage_value;
@@ -11570,8 +11625,40 @@ func.UI.worker.execute = async function (SESSION_ID, queue_obj) {
11570
11625
  get_live_element_context: function (elem_key, fallback_$elm, context = {}) {
11571
11626
  let raw_$elm = elem_key ? fx.get_element_by_ui_id(elem_key) : fallback_$elm;
11572
11627
  let $elm = func.runtime?.ui?.get_preferred_live_element ? func.runtime.ui.get_preferred_live_element(raw_$elm) : raw_$elm;
11628
+ const matches_context = function (node_xu_data, allow_loose_match = false) {
11629
+ if (!node_xu_data) {
11630
+ return false;
11631
+ }
11632
+ if (context.node_id && node_xu_data.nodeid !== context.node_id) {
11633
+ return false;
11634
+ }
11635
+ if (typeof context.key !== 'undefined' && context.key !== null && node_xu_data.key !== context.key) {
11636
+ return false;
11637
+ }
11638
+ if (context.key_path && node_xu_data.key_path !== context.key_path) {
11639
+ return false;
11640
+ }
11641
+ if (context.recordid && node_xu_data.recordid !== context.recordid) {
11642
+ return false;
11643
+ }
11644
+ if (!allow_loose_match) {
11645
+ if (context.prog_id && node_xu_data.paramsP?.prog_id !== context.prog_id) {
11646
+ return false;
11647
+ }
11648
+ if (context.parent_element_ui_id && node_xu_data.parent_element_ui_id !== context.parent_element_ui_id) {
11649
+ return false;
11650
+ }
11651
+ }
11652
+ if (node_xu_data.pending_to_delete) {
11653
+ return false;
11654
+ }
11655
+ return true;
11656
+ };
11657
+ const resolved_node = func.runtime.ui.get_first_node($elm);
11658
+ const resolved_data = resolved_node ? func.runtime.ui.get_data(resolved_node)?.xuData : null;
11659
+ const has_matching_resolved_node = matches_context(resolved_data);
11573
11660
 
11574
- if (context.node_id) {
11661
+ if (context.node_id && !has_matching_resolved_node) {
11575
11662
  const $root = func.UI.worker.get_session_root(SESSION_ID);
11576
11663
  const runtime_nodes = func.runtime?.ui?.get_refresh_index_elements
11577
11664
  ? func.runtime.ui.get_refresh_index_elements(SESSION_ID, $root).toArray()
@@ -11582,22 +11669,7 @@ func.UI.worker.execute = async function (SESSION_ID, queue_obj) {
11582
11669
  const node = runtime_nodes[index];
11583
11670
  const node_data = func.runtime.ui.get_data(node);
11584
11671
  const node_xu_data = node_data?.xuData;
11585
- if (!node_xu_data) {
11586
- continue;
11587
- }
11588
- if (node_xu_data.nodeid !== context.node_id) {
11589
- continue;
11590
- }
11591
- if (context.recordid && node_xu_data.recordid !== context.recordid) {
11592
- continue;
11593
- }
11594
- if (context.prog_id && node_xu_data.paramsP?.prog_id !== context.prog_id) {
11595
- continue;
11596
- }
11597
- if (context.parent_element_ui_id && node_xu_data.parent_element_ui_id !== context.parent_element_ui_id) {
11598
- continue;
11599
- }
11600
- if (node_xu_data.pending_to_delete) {
11672
+ if (!matches_context(node_xu_data)) {
11601
11673
  continue;
11602
11674
  }
11603
11675
  matching_nodes.push(node);
@@ -11608,16 +11680,7 @@ func.UI.worker.execute = async function (SESSION_ID, queue_obj) {
11608
11680
  const node = runtime_nodes[index];
11609
11681
  const node_data = func.runtime.ui.get_data(node);
11610
11682
  const node_xu_data = node_data?.xuData;
11611
- if (!node_xu_data) {
11612
- continue;
11613
- }
11614
- if (node_xu_data.nodeid !== context.node_id) {
11615
- continue;
11616
- }
11617
- if (context.recordid && node_xu_data.recordid !== context.recordid) {
11618
- continue;
11619
- }
11620
- if (node_xu_data.pending_to_delete) {
11683
+ if (!matches_context(node_xu_data, true)) {
11621
11684
  continue;
11622
11685
  }
11623
11686
  matching_nodes.push(node);
@@ -11735,10 +11798,10 @@ func.UI.worker.execute = async function (SESSION_ID, queue_obj) {
11735
11798
  const iterate_info = options.iterate_info;
11736
11799
  const iterate_key = iterate_info
11737
11800
  ? [
11738
- iterate_info.iterator_key || '',
11739
- iterate_info.iterator_val || '',
11740
- iterate_info._key || '',
11741
- iterate_info._val || '',
11801
+ iterate_info.iterator_key ?? '',
11802
+ iterate_info.iterator_val ?? '',
11803
+ iterate_info._key ?? '',
11804
+ iterate_info._val ?? '',
11742
11805
  ].join('::')
11743
11806
  : '';
11744
11807
 
@@ -12877,7 +12940,7 @@ func.runtime.ui.ensure_nav = function (SESSION_ID, $container) {
12877
12940
  }
12878
12941
  var nav_el = document.createElement('xu-nav');
12879
12942
  func.runtime.ui.append($container, nav_el);
12880
- var $nav = func.runtime.ui.as_jquery(nav_el);
12943
+ var $nav = func.runtime.ui._wrap_matches([nav_el]);
12881
12944
  func.UI.component.init_xu_nav($container, $nav);
12882
12945
  return $nav;
12883
12946
  };
@@ -13707,7 +13770,7 @@ func.runtime.ui._to_node_array = func.runtime.ui._to_node_array || function (inp
13707
13770
  if (!input) {
13708
13771
  return [];
13709
13772
  }
13710
- if (input.jquery) {
13773
+ if (typeof input?.toArray === 'function' && typeof input?.length === 'number' && !input?.nodeType) {
13711
13774
  return input.toArray();
13712
13775
  }
13713
13776
  if (Array.isArray(input)) {
@@ -14688,6 +14751,8 @@ func.runtime.ui.build_refresh_job_obj = function (options, elem_key, elem_val, e
14688
14751
  fields_arr: options.fields_arr,
14689
14752
  elem_key,
14690
14753
  node_id: elm_data?.xuData?.nodeid,
14754
+ key: elm_data?.xuData?.key,
14755
+ key_path: elm_data?.xuData?.key_path,
14691
14756
  recordid: elm_data?.xuData?.recordid,
14692
14757
  parent_element_ui_id: elm_data?.xuData?.parent_element_ui_id,
14693
14758
  prog_id: elm_data?.xuData?.paramsP?.prog_id,
@@ -16194,6 +16259,43 @@ func.runtime.render.scope_css_to_xu_ui = function ($elm, cssText) {
16194
16259
  return parser.getCSSForEditor(parsed);
16195
16260
  };
16196
16261
  func.runtime.render.bind_xu_event = function (options) {
16262
+ const decode_html_entities = function (value) {
16263
+ if (typeof value !== 'string' || value.indexOf('&') === -1) {
16264
+ return value;
16265
+ }
16266
+
16267
+ if (typeof document !== 'undefined') {
16268
+ const textarea = document.createElement('textarea');
16269
+ textarea.innerHTML = value;
16270
+ return textarea.value;
16271
+ }
16272
+
16273
+ return value
16274
+ .replaceAll('&quot;', '"')
16275
+ .replaceAll('&#34;', '"')
16276
+ .replaceAll('&#39;', "'")
16277
+ .replaceAll('&#039;', "'")
16278
+ .replaceAll('&lt;', '<')
16279
+ .replaceAll('&gt;', '>')
16280
+ .replaceAll('&amp;', '&');
16281
+ };
16282
+ const normalize_event_handlers = function (raw_handlers) {
16283
+ if (typeof raw_handlers !== 'string') {
16284
+ return raw_handlers;
16285
+ }
16286
+
16287
+ const decoded_value = decode_html_entities(raw_handlers).trim();
16288
+ if (!decoded_value) {
16289
+ return [];
16290
+ }
16291
+
16292
+ try {
16293
+ return JSON5.parse(decoded_value);
16294
+ } catch (error) {
16295
+ console.error('XUDA RUNTIME', `xu-on has invalid workflow syntax: ${decoded_value}`, error);
16296
+ return [];
16297
+ }
16298
+ };
16197
16299
  CLIENT_ACTIVITY_TS = Date.now();
16198
16300
  const trigger = options.val.key.split('xu-on:')[1].toLowerCase();
16199
16301
  const handler_key = `_xuda_xuOn_${trigger.replace(/[^a-z0-9_]/gi, '_')}`;
@@ -16205,27 +16307,33 @@ func.runtime.render.bind_xu_event = function (options) {
16205
16307
  const _$elm = evt.currentTarget;
16206
16308
  const elm_data = func.runtime.ui.get_data(_$elm);
16207
16309
  const xuAttributes = elm_data?.xuAttributes;
16208
- const event_handlers = xuAttributes?.['xu-on:' + evt.type];
16310
+ const event_attr_key = 'xu-on:' + evt.type;
16311
+ const event_handlers = normalize_event_handlers(xuAttributes?.[event_attr_key]);
16312
+ if (xuAttributes && event_handlers !== xuAttributes?.[event_attr_key]) {
16313
+ xuAttributes[event_attr_key] = event_handlers;
16314
+ }
16209
16315
  if (xu_isEmpty(xuAttributes) || xu_isEmpty(event_handlers)) return;
16210
16316
  const handler_keys = Object.keys(event_handlers);
16211
16317
 
16212
16318
  for (let handler_index = 0; handler_index < handler_keys.length; handler_index++) {
16213
16319
  const val = event_handlers[handler_keys[handler_index]];
16214
- if (!xu_isEmpty(val.props.condition)) {
16215
- const expCond = await func.expression.get(options.SESSION_ID, val.props.condition, options.paramsP.dsSessionP, 'condition', options.paramsP.recordid);
16320
+ const handler_props = val?.props || {};
16321
+ if (!xu_isEmpty(handler_props.condition)) {
16322
+ const expCond = await func.expression.get(options.SESSION_ID, handler_props.condition, options.paramsP.dsSessionP, 'condition', options.paramsP.recordid);
16216
16323
  if (!expCond.result) continue;
16217
16324
  }
16218
16325
 
16219
- if (val.event_modifiers && evt[val.event_modifiers]) {
16326
+ if (val?.event_modifiers && evt[val.event_modifiers]) {
16220
16327
  evt[val.event_modifiers]();
16221
16328
  }
16222
16329
 
16223
- const workflow = val.workflow || val.event;
16330
+ const workflow = val?.workflow || val?.event;
16224
16331
  if (workflow) {
16225
16332
  const workflow_keys = Object.keys(workflow);
16226
16333
  for (let workflow_index = 0; workflow_index < workflow_keys.length; workflow_index++) {
16227
16334
  const val2 = workflow[workflow_keys[workflow_index]];
16228
- if (!val2.data.enabled) continue;
16335
+ if (!val2?.data?.action) continue;
16336
+ if (val2.data.enabled === false) continue;
16229
16337
 
16230
16338
  func.events.add_to_queue(
16231
16339
  options.SESSION_ID,
@@ -16478,7 +16586,12 @@ func.runtime.widgets.render_node = async function (options) {
16478
16586
  return func.runtime.widgets.report_error(widget_context, descP, warn);
16479
16587
  };
16480
16588
 
16481
- const methods = await func.runtime.widgets.get_methods(widget_context);
16589
+ const definition = await func.runtime.widgets.get_definition(widget_context);
16590
+ if (!func.runtime.widgets.supports_current_environment(definition)) {
16591
+ return report_error(`plugin ${plugin_name} is not available in the current environment`, true);
16592
+ }
16593
+
16594
+ const methods = definition?.methods || {};
16482
16595
  if (methods && !methods[method]) {
16483
16596
  return report_error('method not found');
16484
16597
  }
@@ -16539,7 +16652,13 @@ func.runtime.widgets.render_node = async function (options) {
16539
16652
  job_id: options.jobNoP,
16540
16653
  });
16541
16654
 
16542
- const params = func.runtime.widgets.build_params(widget_context, $div, plugin_setup_ret.data, api_utils);
16655
+ const params = func.runtime.widgets.build_params(
16656
+ widget_context,
16657
+ func.runtime.ui.get_first_node($div),
16658
+ func.runtime.ui.get_data($div),
16659
+ plugin_setup_ret.data,
16660
+ api_utils,
16661
+ );
16543
16662
  const fx = await func.runtime.widgets.get_resource(widget_context, 'runtime.mjs');
16544
16663
 
16545
16664
  await func.runtime.widgets.load_runtime_css(widget_context);
@@ -17569,7 +17688,7 @@ func.runtime.render.handle_xu_ref = async function (options) {
17569
17688
  func.runtime.render.handle_xu_bind = async function (options) {
17570
17689
  if (options.is_skeleton) return {};
17571
17690
 
17572
- 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);
17691
+ const $elm = func.runtime?.ui?.get_preferred_live_element ? func.runtime.ui.get_preferred_live_element(options.$elm) : options.$elm;
17573
17692
  const elm_data = func.runtime.ui.get_data($elm);
17574
17693
  const xuData = elm_data?.xuData;
17575
17694
  const bind_expression =
@@ -17949,18 +18068,12 @@ func.runtime.render.handle_xu_for = async function (options) {
17949
18068
  }
17950
18069
  }
17951
18070
 
17952
- // Strip xu-ui-id from template elements before removal so that
17953
- // delete_meta does not destroy the meta entry shared by iteration-0
17954
- // (the template and first iteration child share the same xu-ui-id
17955
- // because their key_path values collide).
17956
18071
  const _live_node = func.runtime.ui.get_first_node($live_elm);
17957
18072
  if (_live_node) {
17958
- _live_node.removeAttribute('xu-ui-id');
17959
18073
  func.runtime.ui.remove($live_elm);
17960
18074
  }
17961
18075
  const _options_node = func.runtime.ui.get_first_node(options.$elm);
17962
18076
  if (_options_node && _options_node !== _live_node) {
17963
- _options_node.removeAttribute('xu-ui-id');
17964
18077
  func.runtime.ui.remove(options.$elm);
17965
18078
  }
17966
18079
  return { abort: true, consume_placeholder: true };
@@ -18556,10 +18669,31 @@ func.runtime.widgets = func.runtime.widgets || {};
18556
18669
  // Browser-only common xu handler factories live here so registry composition can stay small.
18557
18670
 
18558
18671
  func.runtime.render.build_base_xu_handlers = function (options, _ds) {
18672
+ const decode_html_entities = function (value) {
18673
+ if (typeof value !== 'string' || value.indexOf('&') === -1) {
18674
+ return value;
18675
+ }
18676
+
18677
+ if (typeof document !== 'undefined') {
18678
+ const textarea = document.createElement('textarea');
18679
+ textarea.innerHTML = value;
18680
+ return textarea.value;
18681
+ }
18682
+
18683
+ return value
18684
+ .replaceAll('&quot;', '"')
18685
+ .replaceAll('&#34;', '"')
18686
+ .replaceAll('&#39;', "'")
18687
+ .replaceAll('&#039;', "'")
18688
+ .replaceAll('&lt;', '<')
18689
+ .replaceAll('&gt;', '>')
18690
+ .replaceAll('&amp;', '&');
18691
+ };
18559
18692
  const parse_object_value = function (attr_name, val, shape = 'object') {
18560
18693
  let parsed_value = val?.value;
18561
18694
  if (typeof parsed_value === 'string') {
18562
- const trimmed_value = parsed_value.trim();
18695
+ const decoded_value = decode_html_entities(parsed_value);
18696
+ const trimmed_value = decoded_value.trim();
18563
18697
  const wrapped_candidate =
18564
18698
  trimmed_value.startsWith('(') && trimmed_value.endsWith(')')
18565
18699
  ? trimmed_value.slice(1, -1).trim()
@@ -19712,6 +19846,7 @@ func.events.execute = async function (
19712
19846
  },
19713
19847
  execute_native_javascript: async function () {
19714
19848
  const module = await func.common.get_module(SESSION_ID, 'xuda-event-javascript-module.mjs');
19849
+ 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)`;
19715
19850
 
19716
19851
  const result = await module.run_javascript(
19717
19852
  SESSION_ID,
@@ -19719,7 +19854,7 @@ func.events.execute = async function (
19719
19854
  dsSession,
19720
19855
  `(async function(el,evt) {
19721
19856
  ${refIdP.value}
19722
- })(document.querySelector(\`[xu-ui-id="${elementP}"]\`),evt)`,
19857
+ })(${resolved_element_expr},evt)`,
19723
19858
  null,
19724
19859
  null,
19725
19860
  null,
@@ -19732,6 +19867,7 @@ func.events.execute = async function (
19732
19867
  },
19733
19868
  execute_evaluate_javascript: async function () {
19734
19869
  const module = await func.common.get_module(SESSION_ID, 'xuda-event-javascript-module.mjs');
19870
+ 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)`;
19735
19871
 
19736
19872
  const result = await module.run_javascript(
19737
19873
  SESSION_ID,
@@ -19739,7 +19875,7 @@ func.events.execute = async function (
19739
19875
  dsSession,
19740
19876
  `(async function(el,evt) {
19741
19877
  ${refIdP.value}
19742
- })(document.querySelector(\`[xu-ui-id="${elementP}"]\`),evt)`,
19878
+ })(${resolved_element_expr},evt)`,
19743
19879
  true,
19744
19880
  null,
19745
19881
  null,