@xuda.io/runtime-bundle 1.0.1433 → 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.
@@ -1610,6 +1610,23 @@ func.runtime.platform = {
1610
1610
  return false;
1611
1611
  }
1612
1612
  },
1613
+ get_cookie_item: function (key) {
1614
+ if (!key) {
1615
+ return null;
1616
+ }
1617
+ const doc = func.runtime.platform.get_document();
1618
+ const cookie_string = doc?.cookie;
1619
+ if (!cookie_string) {
1620
+ return null;
1621
+ }
1622
+ const cookie_entry = cookie_string.split('; ').find(function (cookie) {
1623
+ return cookie.startsWith(key + '=');
1624
+ });
1625
+ if (!cookie_entry) {
1626
+ return null;
1627
+ }
1628
+ return cookie_entry.split('=').slice(1).join('=') || null;
1629
+ },
1613
1630
  get_url_href: function () {
1614
1631
  return func.runtime.platform.get_location()?.href || '';
1615
1632
  },
@@ -5634,8 +5651,9 @@ func.datasource.clean = function (SESSION_ID, screenIdP) {
5634
5651
  var arr = [];
5635
5652
  for (const [key, val] of Object.entries(SESSION_OBJ[SESSION_ID].DS_GLB)) {
5636
5653
  try {
5637
- const _screen_el = val.screenId ? document.getElementById(val.screenId) : null;
5638
- const screen_parent_id = _screen_el?.parentElement?.id || null;
5654
+ const screen_parent_id = val.screenId && func.runtime?.ui?.get_parent_element_id
5655
+ ? func.runtime.ui.get_parent_element_id(val.screenId)
5656
+ : null;
5639
5657
  if (
5640
5658
  Number(key) > 0 &&
5641
5659
  (val.screenId === screenIdP ||
@@ -5644,7 +5662,7 @@ func.datasource.clean = function (SESSION_ID, screenIdP) {
5644
5662
  (val && val.parentDataSourceNo && arr.includes(val.parentDataSourceNo.toString())))
5645
5663
  ) {
5646
5664
  arr.push(key);
5647
- if (val.screenId) func.UI.utils.screen_blocker(false, val.screenId);
5665
+ if (val.screenId && func.UI?.utils?.screen_blocker) func.UI.utils.screen_blocker(false, val.screenId);
5648
5666
  }
5649
5667
  } catch (err) {
5650
5668
  console.warn('func.datasource.clean failed');
@@ -9191,11 +9209,14 @@ func.runtime.ui.create_screen_host = function (SESSION_ID, screen_type, params,
9191
9209
  };
9192
9210
  };
9193
9211
  func.runtime.ui.find_xu_ui_in_root = function (SESSION_ID, xu_ui_id) {
9212
+ if (!SESSION_ID || !xu_ui_id) {
9213
+ return func.runtime.ui._wrap_matches([]);
9214
+ }
9194
9215
  if (func.runtime.ui.get_refresh_indexed_element_by_ui_id) {
9195
9216
  const elm = func.runtime.ui.get_refresh_indexed_element_by_ui_id(SESSION_ID, xu_ui_id);
9196
9217
  return func.runtime.ui._wrap_matches(elm ? [elm] : []);
9197
9218
  }
9198
- return func.runtime.ui.find_in_root(SESSION_ID, `[xu-ui-id=${xu_ui_id}]`);
9219
+ return func.runtime.ui.find_in_root(SESSION_ID, `[xu-ui-id="${xu_ui_id}"]`);
9199
9220
  };
9200
9221
  func.runtime.ui.find_panel_wrapper_in_root = function (SESSION_ID, xu_ui_id) {
9201
9222
  if (func.runtime.ui.get_refresh_indexed_panel_wrapper_by_id) {
@@ -9316,6 +9337,14 @@ func.runtime.ui.find_element_by_id = function (element_id) {
9316
9337
  }
9317
9338
  return null;
9318
9339
  };
9340
+ func.runtime.ui.get_parent_element_id = function (element_id) {
9341
+ if (!element_id) {
9342
+ return null;
9343
+ }
9344
+ const clean_id = element_id.startsWith('#') ? element_id.substring(1) : element_id;
9345
+ const element = func.runtime.ui.find_element_by_id(clean_id);
9346
+ return element?.parentElement?.id || null;
9347
+ };
9319
9348
  func.runtime.ui.get_session_root = function (SESSION_ID) {
9320
9349
  if (typeof document !== 'undefined') {
9321
9350
  return document.getElementById('embed_' + SESSION_ID) || null;
@@ -9865,12 +9894,23 @@ func.runtime.ui.build_xu_ui_id_seed = function (nodeP, dsSessionP, key_path, cur
9865
9894
  const elem_key = `${nodeId}-${key_path}-${currentRecordId}`;
9866
9895
  return `${nodeP.id}-${elem_key}-${dsSessionP?.toString() || ''}`;
9867
9896
  };
9897
+ func.runtime.ui.build_container_key_path = function (container_xu_data, keyP, parent_infoP, nodeP, parent_nodeP) {
9898
+ const key_segment = typeof keyP === 'undefined' || keyP === null ? '0' : `${keyP}`;
9899
+ let key_path = `${container_xu_data?.key_path || '0'}-${key_segment}`;
9900
+ const parent_identity = parent_nodeP?.xu_tree_id || parent_nodeP?.id;
9901
+ const node_identity = nodeP?.xu_tree_id || nodeP?.id;
9902
+ const is_iterated_clone = !!(parent_infoP?.iterate_info && parent_identity && node_identity && parent_identity === node_identity);
9903
+ if (is_iterated_clone) {
9904
+ key_path += '-iter';
9905
+ }
9906
+ return key_path;
9907
+ };
9868
9908
  func.runtime.ui.generate_xu_ui_id = async function (SESSION_ID, nodeP, $container, paramsP, keyP, precomputed = {}) {
9869
9909
  const dsSessionP = paramsP.dsSessionP;
9870
9910
  const _ds = SESSION_OBJ[SESSION_ID].DS_GLB[dsSessionP];
9871
9911
  const containerXuData = precomputed.container_xu_data || func.runtime.ui.get_data($container)?.xuData;
9872
9912
  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'}`;
9913
+ const key_path = precomputed.key_path || func.runtime.ui.build_container_key_path(containerXuData, keyP, precomputed.parent_infoP, nodeP, precomputed.parent_nodeP);
9874
9914
  const ui_id = func.runtime.ui.build_xu_ui_id_seed(nodeP, dsSessionP, key_path, currentRecordId);
9875
9915
 
9876
9916
  if (func.runtime.ui.ui_id_hash_cache.has(ui_id)) {
@@ -9899,13 +9939,15 @@ func.runtime.ui.create_container = async function (options) {
9899
9939
  const currentRecordId = container_xu_data?.recordid || (_ds ? _ds.currentRecordId : '');
9900
9940
 
9901
9941
  try {
9902
- const key_path = `${container_xu_data?.key_path || '0'}-${options.keyP || '0'}`;
9942
+ const key_path = func.runtime.ui.build_container_key_path(container_xu_data, options.keyP, options.parent_infoP, options.nodeP, options.parent_nodeP);
9903
9943
  const elem_key = `${options.nodeP.xu_tree_id || options.nodeP.id}-${key_path}-${currentRecordId}`;
9904
9944
  const $div = func.runtime.ui.create_container_element(options.div_typeP, options.attr_str, options.prop, options.nodeP, $appendTo);
9905
9945
  const new_ui_id = await func.runtime.ui.generate_xu_ui_id(options.SESSION_ID, options.nodeP, options.$container, options.paramsP, options.keyP, {
9906
9946
  container_xu_data,
9907
9947
  currentRecordId,
9908
9948
  key_path,
9949
+ parent_infoP: options.parent_infoP,
9950
+ parent_nodeP: options.parent_nodeP,
9909
9951
  });
9910
9952
 
9911
9953
  func.runtime.ui.apply_container_meta($div, {
@@ -10237,9 +10279,7 @@ func.UI.utils.get_url_attribute = function (SESSION_ID, key) {
10237
10279
  const root_attribute = func.runtime.ui.get_attr(_session.root_element, key);
10238
10280
  const option_param = _session.opt?.params?.[key];
10239
10281
  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;
10282
+ const cookie_value = platform.get_cookie_item(key);
10243
10283
  const storage_value = platform.get_storage_item(key, 'local');
10244
10284
 
10245
10285
  return url_param || root_attribute || option_param || option_value || cookie_value || storage_value;
@@ -11496,8 +11536,40 @@ func.UI.worker.execute = async function (SESSION_ID, queue_obj) {
11496
11536
  get_live_element_context: function (elem_key, fallback_$elm, context = {}) {
11497
11537
  let raw_$elm = elem_key ? fx.get_element_by_ui_id(elem_key) : fallback_$elm;
11498
11538
  let $elm = func.runtime?.ui?.get_preferred_live_element ? func.runtime.ui.get_preferred_live_element(raw_$elm) : raw_$elm;
11539
+ const matches_context = function (node_xu_data, allow_loose_match = false) {
11540
+ if (!node_xu_data) {
11541
+ return false;
11542
+ }
11543
+ if (context.node_id && node_xu_data.nodeid !== context.node_id) {
11544
+ return false;
11545
+ }
11546
+ if (typeof context.key !== 'undefined' && context.key !== null && node_xu_data.key !== context.key) {
11547
+ return false;
11548
+ }
11549
+ if (context.key_path && node_xu_data.key_path !== context.key_path) {
11550
+ return false;
11551
+ }
11552
+ if (context.recordid && node_xu_data.recordid !== context.recordid) {
11553
+ return false;
11554
+ }
11555
+ if (!allow_loose_match) {
11556
+ if (context.prog_id && node_xu_data.paramsP?.prog_id !== context.prog_id) {
11557
+ return false;
11558
+ }
11559
+ if (context.parent_element_ui_id && node_xu_data.parent_element_ui_id !== context.parent_element_ui_id) {
11560
+ return false;
11561
+ }
11562
+ }
11563
+ if (node_xu_data.pending_to_delete) {
11564
+ return false;
11565
+ }
11566
+ return true;
11567
+ };
11568
+ const resolved_node = func.runtime.ui.get_first_node($elm);
11569
+ const resolved_data = resolved_node ? func.runtime.ui.get_data(resolved_node)?.xuData : null;
11570
+ const has_matching_resolved_node = matches_context(resolved_data);
11499
11571
 
11500
- if (context.node_id) {
11572
+ if (context.node_id && !has_matching_resolved_node) {
11501
11573
  const $root = func.UI.worker.get_session_root(SESSION_ID);
11502
11574
  const runtime_nodes = func.runtime?.ui?.get_refresh_index_elements
11503
11575
  ? func.runtime.ui.get_refresh_index_elements(SESSION_ID, $root).toArray()
@@ -11508,22 +11580,7 @@ func.UI.worker.execute = async function (SESSION_ID, queue_obj) {
11508
11580
  const node = runtime_nodes[index];
11509
11581
  const node_data = func.runtime.ui.get_data(node);
11510
11582
  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) {
11583
+ if (!matches_context(node_xu_data)) {
11527
11584
  continue;
11528
11585
  }
11529
11586
  matching_nodes.push(node);
@@ -11534,16 +11591,7 @@ func.UI.worker.execute = async function (SESSION_ID, queue_obj) {
11534
11591
  const node = runtime_nodes[index];
11535
11592
  const node_data = func.runtime.ui.get_data(node);
11536
11593
  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) {
11594
+ if (!matches_context(node_xu_data, true)) {
11547
11595
  continue;
11548
11596
  }
11549
11597
  matching_nodes.push(node);
@@ -11661,10 +11709,10 @@ func.UI.worker.execute = async function (SESSION_ID, queue_obj) {
11661
11709
  const iterate_info = options.iterate_info;
11662
11710
  const iterate_key = iterate_info
11663
11711
  ? [
11664
- iterate_info.iterator_key || '',
11665
- iterate_info.iterator_val || '',
11666
- iterate_info._key || '',
11667
- iterate_info._val || '',
11712
+ iterate_info.iterator_key ?? '',
11713
+ iterate_info.iterator_val ?? '',
11714
+ iterate_info._key ?? '',
11715
+ iterate_info._val ?? '',
11668
11716
  ].join('::')
11669
11717
  : '';
11670
11718
 
@@ -14614,6 +14662,8 @@ func.runtime.ui.build_refresh_job_obj = function (options, elem_key, elem_val, e
14614
14662
  fields_arr: options.fields_arr,
14615
14663
  elem_key,
14616
14664
  node_id: elm_data?.xuData?.nodeid,
14665
+ key: elm_data?.xuData?.key,
14666
+ key_path: elm_data?.xuData?.key_path,
14617
14667
  recordid: elm_data?.xuData?.recordid,
14618
14668
  parent_element_ui_id: elm_data?.xuData?.parent_element_ui_id,
14619
14669
  prog_id: elm_data?.xuData?.paramsP?.prog_id,
@@ -16120,6 +16170,43 @@ func.runtime.render.scope_css_to_xu_ui = function ($elm, cssText) {
16120
16170
  return parser.getCSSForEditor(parsed);
16121
16171
  };
16122
16172
  func.runtime.render.bind_xu_event = function (options) {
16173
+ const decode_html_entities = function (value) {
16174
+ if (typeof value !== 'string' || value.indexOf('&') === -1) {
16175
+ return value;
16176
+ }
16177
+
16178
+ if (typeof document !== 'undefined') {
16179
+ const textarea = document.createElement('textarea');
16180
+ textarea.innerHTML = value;
16181
+ return textarea.value;
16182
+ }
16183
+
16184
+ return value
16185
+ .replaceAll('"', '"')
16186
+ .replaceAll('"', '"')
16187
+ .replaceAll(''', "'")
16188
+ .replaceAll(''', "'")
16189
+ .replaceAll('&lt;', '<')
16190
+ .replaceAll('&gt;', '>')
16191
+ .replaceAll('&amp;', '&');
16192
+ };
16193
+ const normalize_event_handlers = function (raw_handlers) {
16194
+ if (typeof raw_handlers !== 'string') {
16195
+ return raw_handlers;
16196
+ }
16197
+
16198
+ const decoded_value = decode_html_entities(raw_handlers).trim();
16199
+ if (!decoded_value) {
16200
+ return [];
16201
+ }
16202
+
16203
+ try {
16204
+ return JSON5.parse(decoded_value);
16205
+ } catch (error) {
16206
+ console.error('XUDA RUNTIME', `xu-on has invalid workflow syntax: ${decoded_value}`, error);
16207
+ return [];
16208
+ }
16209
+ };
16123
16210
  CLIENT_ACTIVITY_TS = Date.now();
16124
16211
  const trigger = options.val.key.split('xu-on:')[1].toLowerCase();
16125
16212
  const handler_key = `_xuda_xuOn_${trigger.replace(/[^a-z0-9_]/gi, '_')}`;
@@ -16131,27 +16218,33 @@ func.runtime.render.bind_xu_event = function (options) {
16131
16218
  const _$elm = evt.currentTarget;
16132
16219
  const elm_data = func.runtime.ui.get_data(_$elm);
16133
16220
  const xuAttributes = elm_data?.xuAttributes;
16134
- const event_handlers = xuAttributes?.['xu-on:' + evt.type];
16221
+ const event_attr_key = 'xu-on:' + evt.type;
16222
+ const event_handlers = normalize_event_handlers(xuAttributes?.[event_attr_key]);
16223
+ if (xuAttributes && event_handlers !== xuAttributes?.[event_attr_key]) {
16224
+ xuAttributes[event_attr_key] = event_handlers;
16225
+ }
16135
16226
  if (xu_isEmpty(xuAttributes) || xu_isEmpty(event_handlers)) return;
16136
16227
  const handler_keys = Object.keys(event_handlers);
16137
16228
 
16138
16229
  for (let handler_index = 0; handler_index < handler_keys.length; handler_index++) {
16139
16230
  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);
16231
+ const handler_props = val?.props || {};
16232
+ if (!xu_isEmpty(handler_props.condition)) {
16233
+ const expCond = await func.expression.get(options.SESSION_ID, handler_props.condition, options.paramsP.dsSessionP, 'condition', options.paramsP.recordid);
16142
16234
  if (!expCond.result) continue;
16143
16235
  }
16144
16236
 
16145
- if (val.event_modifiers && evt[val.event_modifiers]) {
16237
+ if (val?.event_modifiers && evt[val.event_modifiers]) {
16146
16238
  evt[val.event_modifiers]();
16147
16239
  }
16148
16240
 
16149
- const workflow = val.workflow || val.event;
16241
+ const workflow = val?.workflow || val?.event;
16150
16242
  if (workflow) {
16151
16243
  const workflow_keys = Object.keys(workflow);
16152
16244
  for (let workflow_index = 0; workflow_index < workflow_keys.length; workflow_index++) {
16153
16245
  const val2 = workflow[workflow_keys[workflow_index]];
16154
- if (!val2.data.enabled) continue;
16246
+ if (!val2?.data?.action) continue;
16247
+ if (val2.data.enabled === false) continue;
16155
16248
 
16156
16249
  func.events.add_to_queue(
16157
16250
  options.SESSION_ID,
@@ -17875,18 +17968,12 @@ func.runtime.render.handle_xu_for = async function (options) {
17875
17968
  }
17876
17969
  }
17877
17970
 
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
17971
  const _live_node = func.runtime.ui.get_first_node($live_elm);
17883
17972
  if (_live_node) {
17884
- _live_node.removeAttribute('xu-ui-id');
17885
17973
  func.runtime.ui.remove($live_elm);
17886
17974
  }
17887
17975
  const _options_node = func.runtime.ui.get_first_node(options.$elm);
17888
17976
  if (_options_node && _options_node !== _live_node) {
17889
- _options_node.removeAttribute('xu-ui-id');
17890
17977
  func.runtime.ui.remove(options.$elm);
17891
17978
  }
17892
17979
  return { abort: true, consume_placeholder: true };
@@ -18482,11 +18569,40 @@ func.runtime.widgets = func.runtime.widgets || {};
18482
18569
  // Browser-only common xu handler factories live here so registry composition can stay small.
18483
18570
 
18484
18571
  func.runtime.render.build_base_xu_handlers = function (options, _ds) {
18572
+ const decode_html_entities = function (value) {
18573
+ if (typeof value !== 'string' || value.indexOf('&') === -1) {
18574
+ return value;
18575
+ }
18576
+
18577
+ if (typeof document !== 'undefined') {
18578
+ const textarea = document.createElement('textarea');
18579
+ textarea.innerHTML = value;
18580
+ return textarea.value;
18581
+ }
18582
+
18583
+ return value
18584
+ .replaceAll('&quot;', '"')
18585
+ .replaceAll('&#34;', '"')
18586
+ .replaceAll('&#39;', "'")
18587
+ .replaceAll('&#039;', "'")
18588
+ .replaceAll('&lt;', '<')
18589
+ .replaceAll('&gt;', '>')
18590
+ .replaceAll('&amp;', '&');
18591
+ };
18485
18592
  const parse_object_value = function (attr_name, val, shape = 'object') {
18486
18593
  let parsed_value = val?.value;
18487
18594
  if (typeof parsed_value === 'string') {
18595
+ const decoded_value = decode_html_entities(parsed_value);
18596
+ const trimmed_value = decoded_value.trim();
18597
+ const wrapped_candidate =
18598
+ trimmed_value.startsWith('(') && trimmed_value.endsWith(')')
18599
+ ? trimmed_value.slice(1, -1).trim()
18600
+ : trimmed_value;
18601
+ const looks_like_wrapped_shape =
18602
+ (shape === 'object' && wrapped_candidate.startsWith('{') && wrapped_candidate.endsWith('}')) ||
18603
+ (shape === 'array' && wrapped_candidate.startsWith('[') && wrapped_candidate.endsWith(']'));
18488
18604
  try {
18489
- parsed_value = JSON5.parse(parsed_value);
18605
+ parsed_value = JSON5.parse(looks_like_wrapped_shape ? wrapped_candidate : trimmed_value);
18490
18606
  } catch (error) {
18491
18607
  throw func.runtime.render.build_xu_runtime_error(
18492
18608
  { ...options, xu_func: attr_name, val: { key: attr_name, value: val?.value } },
@@ -20395,6 +20511,7 @@ func.events.execute = async function (
20395
20511
  },
20396
20512
  execute_native_javascript: async function () {
20397
20513
  const module = await func.common.get_module(SESSION_ID, 'xuda-event-javascript-module.mjs');
20514
+ 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)`;
20398
20515
 
20399
20516
  const result = await module.run_javascript(
20400
20517
  SESSION_ID,
@@ -20402,7 +20519,7 @@ func.events.execute = async function (
20402
20519
  dsSession,
20403
20520
  `(async function(el,evt) {
20404
20521
  ${refIdP.value}
20405
- })(document.querySelector(\`[xu-ui-id="${elementP}"]\`),evt)`,
20522
+ })(${resolved_element_expr},evt)`,
20406
20523
  null,
20407
20524
  null,
20408
20525
  null,
@@ -20415,6 +20532,7 @@ func.events.execute = async function (
20415
20532
  },
20416
20533
  execute_evaluate_javascript: async function () {
20417
20534
  const module = await func.common.get_module(SESSION_ID, 'xuda-event-javascript-module.mjs');
20535
+ 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)`;
20418
20536
 
20419
20537
  const result = await module.run_javascript(
20420
20538
  SESSION_ID,
@@ -20422,7 +20540,7 @@ func.events.execute = async function (
20422
20540
  dsSession,
20423
20541
  `(async function(el,evt) {
20424
20542
  ${refIdP.value}
20425
- })(document.querySelector(\`[xu-ui-id="${elementP}"]\`),evt)`,
20543
+ })(${resolved_element_expr},evt)`,
20426
20544
  true,
20427
20545
  null,
20428
20546
  null,