@xuda.io/runtime-bundle 1.0.1434 → 1.0.1435

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.
@@ -1684,6 +1684,23 @@ func.runtime.platform = {
1684
1684
  return false;
1685
1685
  }
1686
1686
  },
1687
+ get_cookie_item: function (key) {
1688
+ if (!key) {
1689
+ return null;
1690
+ }
1691
+ const doc = func.runtime.platform.get_document();
1692
+ const cookie_string = doc?.cookie;
1693
+ if (!cookie_string) {
1694
+ return null;
1695
+ }
1696
+ const cookie_entry = cookie_string.split('; ').find(function (cookie) {
1697
+ return cookie.startsWith(key + '=');
1698
+ });
1699
+ if (!cookie_entry) {
1700
+ return null;
1701
+ }
1702
+ return cookie_entry.split('=').slice(1).join('=') || null;
1703
+ },
1687
1704
  get_url_href: function () {
1688
1705
  return func.runtime.platform.get_location()?.href || '';
1689
1706
  },
@@ -5708,8 +5725,9 @@ func.datasource.clean = function (SESSION_ID, screenIdP) {
5708
5725
  var arr = [];
5709
5726
  for (const [key, val] of Object.entries(SESSION_OBJ[SESSION_ID].DS_GLB)) {
5710
5727
  try {
5711
- const _screen_el = val.screenId ? document.getElementById(val.screenId) : null;
5712
- const screen_parent_id = _screen_el?.parentElement?.id || null;
5728
+ const screen_parent_id = val.screenId && func.runtime?.ui?.get_parent_element_id
5729
+ ? func.runtime.ui.get_parent_element_id(val.screenId)
5730
+ : null;
5713
5731
  if (
5714
5732
  Number(key) > 0 &&
5715
5733
  (val.screenId === screenIdP ||
@@ -5718,7 +5736,7 @@ func.datasource.clean = function (SESSION_ID, screenIdP) {
5718
5736
  (val && val.parentDataSourceNo && arr.includes(val.parentDataSourceNo.toString())))
5719
5737
  ) {
5720
5738
  arr.push(key);
5721
- if (val.screenId) func.UI.utils.screen_blocker(false, val.screenId);
5739
+ if (val.screenId && func.UI?.utils?.screen_blocker) func.UI.utils.screen_blocker(false, val.screenId);
5722
5740
  }
5723
5741
  } catch (err) {
5724
5742
  console.warn('func.datasource.clean failed');
@@ -9265,11 +9283,14 @@ func.runtime.ui.create_screen_host = function (SESSION_ID, screen_type, params,
9265
9283
  };
9266
9284
  };
9267
9285
  func.runtime.ui.find_xu_ui_in_root = function (SESSION_ID, xu_ui_id) {
9286
+ if (!SESSION_ID || !xu_ui_id) {
9287
+ return func.runtime.ui._wrap_matches([]);
9288
+ }
9268
9289
  if (func.runtime.ui.get_refresh_indexed_element_by_ui_id) {
9269
9290
  const elm = func.runtime.ui.get_refresh_indexed_element_by_ui_id(SESSION_ID, xu_ui_id);
9270
9291
  return func.runtime.ui._wrap_matches(elm ? [elm] : []);
9271
9292
  }
9272
- return func.runtime.ui.find_in_root(SESSION_ID, `[xu-ui-id=${xu_ui_id}]`);
9293
+ return func.runtime.ui.find_in_root(SESSION_ID, `[xu-ui-id="${xu_ui_id}"]`);
9273
9294
  };
9274
9295
  func.runtime.ui.find_panel_wrapper_in_root = function (SESSION_ID, xu_ui_id) {
9275
9296
  if (func.runtime.ui.get_refresh_indexed_panel_wrapper_by_id) {
@@ -9390,6 +9411,14 @@ func.runtime.ui.find_element_by_id = function (element_id) {
9390
9411
  }
9391
9412
  return null;
9392
9413
  };
9414
+ func.runtime.ui.get_parent_element_id = function (element_id) {
9415
+ if (!element_id) {
9416
+ return null;
9417
+ }
9418
+ const clean_id = element_id.startsWith('#') ? element_id.substring(1) : element_id;
9419
+ const element = func.runtime.ui.find_element_by_id(clean_id);
9420
+ return element?.parentElement?.id || null;
9421
+ };
9393
9422
  func.runtime.ui.get_session_root = function (SESSION_ID) {
9394
9423
  if (typeof document !== 'undefined') {
9395
9424
  return document.getElementById('embed_' + SESSION_ID) || null;
@@ -9939,12 +9968,23 @@ func.runtime.ui.build_xu_ui_id_seed = function (nodeP, dsSessionP, key_path, cur
9939
9968
  const elem_key = `${nodeId}-${key_path}-${currentRecordId}`;
9940
9969
  return `${nodeP.id}-${elem_key}-${dsSessionP?.toString() || ''}`;
9941
9970
  };
9971
+ func.runtime.ui.build_container_key_path = function (container_xu_data, keyP, parent_infoP, nodeP, parent_nodeP) {
9972
+ const key_segment = typeof keyP === 'undefined' || keyP === null ? '0' : `${keyP}`;
9973
+ let key_path = `${container_xu_data?.key_path || '0'}-${key_segment}`;
9974
+ const parent_identity = parent_nodeP?.xu_tree_id || parent_nodeP?.id;
9975
+ const node_identity = nodeP?.xu_tree_id || nodeP?.id;
9976
+ const is_iterated_clone = !!(parent_infoP?.iterate_info && parent_identity && node_identity && parent_identity === node_identity);
9977
+ if (is_iterated_clone) {
9978
+ key_path += '-iter';
9979
+ }
9980
+ return key_path;
9981
+ };
9942
9982
  func.runtime.ui.generate_xu_ui_id = async function (SESSION_ID, nodeP, $container, paramsP, keyP, precomputed = {}) {
9943
9983
  const dsSessionP = paramsP.dsSessionP;
9944
9984
  const _ds = SESSION_OBJ[SESSION_ID].DS_GLB[dsSessionP];
9945
9985
  const containerXuData = precomputed.container_xu_data || func.runtime.ui.get_data($container)?.xuData;
9946
9986
  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'}`;
9987
+ const key_path = precomputed.key_path || func.runtime.ui.build_container_key_path(containerXuData, keyP, precomputed.parent_infoP, nodeP, precomputed.parent_nodeP);
9948
9988
  const ui_id = func.runtime.ui.build_xu_ui_id_seed(nodeP, dsSessionP, key_path, currentRecordId);
9949
9989
 
9950
9990
  if (func.runtime.ui.ui_id_hash_cache.has(ui_id)) {
@@ -9973,13 +10013,15 @@ func.runtime.ui.create_container = async function (options) {
9973
10013
  const currentRecordId = container_xu_data?.recordid || (_ds ? _ds.currentRecordId : '');
9974
10014
 
9975
10015
  try {
9976
- const key_path = `${container_xu_data?.key_path || '0'}-${options.keyP || '0'}`;
10016
+ const key_path = func.runtime.ui.build_container_key_path(container_xu_data, options.keyP, options.parent_infoP, options.nodeP, options.parent_nodeP);
9977
10017
  const elem_key = `${options.nodeP.xu_tree_id || options.nodeP.id}-${key_path}-${currentRecordId}`;
9978
10018
  const $div = func.runtime.ui.create_container_element(options.div_typeP, options.attr_str, options.prop, options.nodeP, $appendTo);
9979
10019
  const new_ui_id = await func.runtime.ui.generate_xu_ui_id(options.SESSION_ID, options.nodeP, options.$container, options.paramsP, options.keyP, {
9980
10020
  container_xu_data,
9981
10021
  currentRecordId,
9982
10022
  key_path,
10023
+ parent_infoP: options.parent_infoP,
10024
+ parent_nodeP: options.parent_nodeP,
9983
10025
  });
9984
10026
 
9985
10027
  func.runtime.ui.apply_container_meta($div, {
@@ -10311,9 +10353,7 @@ func.UI.utils.get_url_attribute = function (SESSION_ID, key) {
10311
10353
  const root_attribute = func.runtime.ui.get_attr(_session.root_element, key);
10312
10354
  const option_param = _session.opt?.params?.[key];
10313
10355
  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;
10356
+ const cookie_value = platform.get_cookie_item(key);
10317
10357
  const storage_value = platform.get_storage_item(key, 'local');
10318
10358
 
10319
10359
  return url_param || root_attribute || option_param || option_value || cookie_value || storage_value;
@@ -11570,8 +11610,40 @@ func.UI.worker.execute = async function (SESSION_ID, queue_obj) {
11570
11610
  get_live_element_context: function (elem_key, fallback_$elm, context = {}) {
11571
11611
  let raw_$elm = elem_key ? fx.get_element_by_ui_id(elem_key) : fallback_$elm;
11572
11612
  let $elm = func.runtime?.ui?.get_preferred_live_element ? func.runtime.ui.get_preferred_live_element(raw_$elm) : raw_$elm;
11613
+ const matches_context = function (node_xu_data, allow_loose_match = false) {
11614
+ if (!node_xu_data) {
11615
+ return false;
11616
+ }
11617
+ if (context.node_id && node_xu_data.nodeid !== context.node_id) {
11618
+ return false;
11619
+ }
11620
+ if (typeof context.key !== 'undefined' && context.key !== null && node_xu_data.key !== context.key) {
11621
+ return false;
11622
+ }
11623
+ if (context.key_path && node_xu_data.key_path !== context.key_path) {
11624
+ return false;
11625
+ }
11626
+ if (context.recordid && node_xu_data.recordid !== context.recordid) {
11627
+ return false;
11628
+ }
11629
+ if (!allow_loose_match) {
11630
+ if (context.prog_id && node_xu_data.paramsP?.prog_id !== context.prog_id) {
11631
+ return false;
11632
+ }
11633
+ if (context.parent_element_ui_id && node_xu_data.parent_element_ui_id !== context.parent_element_ui_id) {
11634
+ return false;
11635
+ }
11636
+ }
11637
+ if (node_xu_data.pending_to_delete) {
11638
+ return false;
11639
+ }
11640
+ return true;
11641
+ };
11642
+ const resolved_node = func.runtime.ui.get_first_node($elm);
11643
+ const resolved_data = resolved_node ? func.runtime.ui.get_data(resolved_node)?.xuData : null;
11644
+ const has_matching_resolved_node = matches_context(resolved_data);
11573
11645
 
11574
- if (context.node_id) {
11646
+ if (context.node_id && !has_matching_resolved_node) {
11575
11647
  const $root = func.UI.worker.get_session_root(SESSION_ID);
11576
11648
  const runtime_nodes = func.runtime?.ui?.get_refresh_index_elements
11577
11649
  ? func.runtime.ui.get_refresh_index_elements(SESSION_ID, $root).toArray()
@@ -11582,22 +11654,7 @@ func.UI.worker.execute = async function (SESSION_ID, queue_obj) {
11582
11654
  const node = runtime_nodes[index];
11583
11655
  const node_data = func.runtime.ui.get_data(node);
11584
11656
  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) {
11657
+ if (!matches_context(node_xu_data)) {
11601
11658
  continue;
11602
11659
  }
11603
11660
  matching_nodes.push(node);
@@ -11608,16 +11665,7 @@ func.UI.worker.execute = async function (SESSION_ID, queue_obj) {
11608
11665
  const node = runtime_nodes[index];
11609
11666
  const node_data = func.runtime.ui.get_data(node);
11610
11667
  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) {
11668
+ if (!matches_context(node_xu_data, true)) {
11621
11669
  continue;
11622
11670
  }
11623
11671
  matching_nodes.push(node);
@@ -11735,10 +11783,10 @@ func.UI.worker.execute = async function (SESSION_ID, queue_obj) {
11735
11783
  const iterate_info = options.iterate_info;
11736
11784
  const iterate_key = iterate_info
11737
11785
  ? [
11738
- iterate_info.iterator_key || '',
11739
- iterate_info.iterator_val || '',
11740
- iterate_info._key || '',
11741
- iterate_info._val || '',
11786
+ iterate_info.iterator_key ?? '',
11787
+ iterate_info.iterator_val ?? '',
11788
+ iterate_info._key ?? '',
11789
+ iterate_info._val ?? '',
11742
11790
  ].join('::')
11743
11791
  : '';
11744
11792
 
@@ -14688,6 +14736,8 @@ func.runtime.ui.build_refresh_job_obj = function (options, elem_key, elem_val, e
14688
14736
  fields_arr: options.fields_arr,
14689
14737
  elem_key,
14690
14738
  node_id: elm_data?.xuData?.nodeid,
14739
+ key: elm_data?.xuData?.key,
14740
+ key_path: elm_data?.xuData?.key_path,
14691
14741
  recordid: elm_data?.xuData?.recordid,
14692
14742
  parent_element_ui_id: elm_data?.xuData?.parent_element_ui_id,
14693
14743
  prog_id: elm_data?.xuData?.paramsP?.prog_id,
@@ -16194,6 +16244,43 @@ func.runtime.render.scope_css_to_xu_ui = function ($elm, cssText) {
16194
16244
  return parser.getCSSForEditor(parsed);
16195
16245
  };
16196
16246
  func.runtime.render.bind_xu_event = function (options) {
16247
+ const decode_html_entities = function (value) {
16248
+ if (typeof value !== 'string' || value.indexOf('&') === -1) {
16249
+ return value;
16250
+ }
16251
+
16252
+ if (typeof document !== 'undefined') {
16253
+ const textarea = document.createElement('textarea');
16254
+ textarea.innerHTML = value;
16255
+ return textarea.value;
16256
+ }
16257
+
16258
+ return value
16259
+ .replaceAll('"', '"')
16260
+ .replaceAll('"', '"')
16261
+ .replaceAll(''', "'")
16262
+ .replaceAll(''', "'")
16263
+ .replaceAll('&lt;', '<')
16264
+ .replaceAll('&gt;', '>')
16265
+ .replaceAll('&amp;', '&');
16266
+ };
16267
+ const normalize_event_handlers = function (raw_handlers) {
16268
+ if (typeof raw_handlers !== 'string') {
16269
+ return raw_handlers;
16270
+ }
16271
+
16272
+ const decoded_value = decode_html_entities(raw_handlers).trim();
16273
+ if (!decoded_value) {
16274
+ return [];
16275
+ }
16276
+
16277
+ try {
16278
+ return JSON5.parse(decoded_value);
16279
+ } catch (error) {
16280
+ console.error('XUDA RUNTIME', `xu-on has invalid workflow syntax: ${decoded_value}`, error);
16281
+ return [];
16282
+ }
16283
+ };
16197
16284
  CLIENT_ACTIVITY_TS = Date.now();
16198
16285
  const trigger = options.val.key.split('xu-on:')[1].toLowerCase();
16199
16286
  const handler_key = `_xuda_xuOn_${trigger.replace(/[^a-z0-9_]/gi, '_')}`;
@@ -16205,27 +16292,33 @@ func.runtime.render.bind_xu_event = function (options) {
16205
16292
  const _$elm = evt.currentTarget;
16206
16293
  const elm_data = func.runtime.ui.get_data(_$elm);
16207
16294
  const xuAttributes = elm_data?.xuAttributes;
16208
- const event_handlers = xuAttributes?.['xu-on:' + evt.type];
16295
+ const event_attr_key = 'xu-on:' + evt.type;
16296
+ const event_handlers = normalize_event_handlers(xuAttributes?.[event_attr_key]);
16297
+ if (xuAttributes && event_handlers !== xuAttributes?.[event_attr_key]) {
16298
+ xuAttributes[event_attr_key] = event_handlers;
16299
+ }
16209
16300
  if (xu_isEmpty(xuAttributes) || xu_isEmpty(event_handlers)) return;
16210
16301
  const handler_keys = Object.keys(event_handlers);
16211
16302
 
16212
16303
  for (let handler_index = 0; handler_index < handler_keys.length; handler_index++) {
16213
16304
  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);
16305
+ const handler_props = val?.props || {};
16306
+ if (!xu_isEmpty(handler_props.condition)) {
16307
+ const expCond = await func.expression.get(options.SESSION_ID, handler_props.condition, options.paramsP.dsSessionP, 'condition', options.paramsP.recordid);
16216
16308
  if (!expCond.result) continue;
16217
16309
  }
16218
16310
 
16219
- if (val.event_modifiers && evt[val.event_modifiers]) {
16311
+ if (val?.event_modifiers && evt[val.event_modifiers]) {
16220
16312
  evt[val.event_modifiers]();
16221
16313
  }
16222
16314
 
16223
- const workflow = val.workflow || val.event;
16315
+ const workflow = val?.workflow || val?.event;
16224
16316
  if (workflow) {
16225
16317
  const workflow_keys = Object.keys(workflow);
16226
16318
  for (let workflow_index = 0; workflow_index < workflow_keys.length; workflow_index++) {
16227
16319
  const val2 = workflow[workflow_keys[workflow_index]];
16228
- if (!val2.data.enabled) continue;
16320
+ if (!val2?.data?.action) continue;
16321
+ if (val2.data.enabled === false) continue;
16229
16322
 
16230
16323
  func.events.add_to_queue(
16231
16324
  options.SESSION_ID,
@@ -17949,18 +18042,12 @@ func.runtime.render.handle_xu_for = async function (options) {
17949
18042
  }
17950
18043
  }
17951
18044
 
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
18045
  const _live_node = func.runtime.ui.get_first_node($live_elm);
17957
18046
  if (_live_node) {
17958
- _live_node.removeAttribute('xu-ui-id');
17959
18047
  func.runtime.ui.remove($live_elm);
17960
18048
  }
17961
18049
  const _options_node = func.runtime.ui.get_first_node(options.$elm);
17962
18050
  if (_options_node && _options_node !== _live_node) {
17963
- _options_node.removeAttribute('xu-ui-id');
17964
18051
  func.runtime.ui.remove(options.$elm);
17965
18052
  }
17966
18053
  return { abort: true, consume_placeholder: true };
@@ -18556,10 +18643,31 @@ func.runtime.widgets = func.runtime.widgets || {};
18556
18643
  // Browser-only common xu handler factories live here so registry composition can stay small.
18557
18644
 
18558
18645
  func.runtime.render.build_base_xu_handlers = function (options, _ds) {
18646
+ const decode_html_entities = function (value) {
18647
+ if (typeof value !== 'string' || value.indexOf('&') === -1) {
18648
+ return value;
18649
+ }
18650
+
18651
+ if (typeof document !== 'undefined') {
18652
+ const textarea = document.createElement('textarea');
18653
+ textarea.innerHTML = value;
18654
+ return textarea.value;
18655
+ }
18656
+
18657
+ return value
18658
+ .replaceAll('&quot;', '"')
18659
+ .replaceAll('&#34;', '"')
18660
+ .replaceAll('&#39;', "'")
18661
+ .replaceAll('&#039;', "'")
18662
+ .replaceAll('&lt;', '<')
18663
+ .replaceAll('&gt;', '>')
18664
+ .replaceAll('&amp;', '&');
18665
+ };
18559
18666
  const parse_object_value = function (attr_name, val, shape = 'object') {
18560
18667
  let parsed_value = val?.value;
18561
18668
  if (typeof parsed_value === 'string') {
18562
- const trimmed_value = parsed_value.trim();
18669
+ const decoded_value = decode_html_entities(parsed_value);
18670
+ const trimmed_value = decoded_value.trim();
18563
18671
  const wrapped_candidate =
18564
18672
  trimmed_value.startsWith('(') && trimmed_value.endsWith(')')
18565
18673
  ? trimmed_value.slice(1, -1).trim()
@@ -19712,6 +19820,7 @@ func.events.execute = async function (
19712
19820
  },
19713
19821
  execute_native_javascript: async function () {
19714
19822
  const module = await func.common.get_module(SESSION_ID, 'xuda-event-javascript-module.mjs');
19823
+ 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
19824
 
19716
19825
  const result = await module.run_javascript(
19717
19826
  SESSION_ID,
@@ -19719,7 +19828,7 @@ func.events.execute = async function (
19719
19828
  dsSession,
19720
19829
  `(async function(el,evt) {
19721
19830
  ${refIdP.value}
19722
- })(document.querySelector(\`[xu-ui-id="${elementP}"]\`),evt)`,
19831
+ })(${resolved_element_expr},evt)`,
19723
19832
  null,
19724
19833
  null,
19725
19834
  null,
@@ -19732,6 +19841,7 @@ func.events.execute = async function (
19732
19841
  },
19733
19842
  execute_evaluate_javascript: async function () {
19734
19843
  const module = await func.common.get_module(SESSION_ID, 'xuda-event-javascript-module.mjs');
19844
+ 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
19845
 
19736
19846
  const result = await module.run_javascript(
19737
19847
  SESSION_ID,
@@ -19739,7 +19849,7 @@ func.events.execute = async function (
19739
19849
  dsSession,
19740
19850
  `(async function(el,evt) {
19741
19851
  ${refIdP.value}
19742
- })(document.querySelector(\`[xu-ui-id="${elementP}"]\`),evt)`,
19852
+ })(${resolved_element_expr},evt)`,
19743
19853
  true,
19744
19854
  null,
19745
19855
  null,