@xuda.io/runtime-bundle 1.0.1412 → 1.0.1414
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.
- package/js/xuda-runtime-bundle.js +12465 -7105
- package/js/xuda-runtime-bundle.min.js +2 -2
- package/js/xuda-runtime-slim.js +9673 -4313
- package/js/xuda-runtime-slim.min.es.js +446 -103
- package/js/xuda-runtime-slim.min.js +2 -2
- package/js/xuda-server-bundle.min.mjs +1 -1
- package/js/xuda-server-bundle.mjs +40 -6
- package/js/xuda-worker-bundle.js +40 -6
- package/js/xuda-worker-bundle.min.js +1 -1
- package/js/xuda_common-bundle.js +16 -3
- package/js/xuda_common-bundle.min.js +1 -1
- package/package.json +1 -1
|
@@ -2188,7 +2188,7 @@ func.runtime.bind.build_datasource_changes = function (dsSessionP, currentRecord
|
|
|
2188
2188
|
},
|
|
2189
2189
|
};
|
|
2190
2190
|
};
|
|
2191
|
-
func.runtime.bind.resolve_field = async function (SESSION_ID, prog_id, dsSessionP, field_id) {
|
|
2191
|
+
func.runtime.bind.resolve_field = async function (SESSION_ID, prog_id, dsSessionP, field_id, iterate_info) {
|
|
2192
2192
|
let _prog_id = prog_id;
|
|
2193
2193
|
let _dsP = dsSessionP;
|
|
2194
2194
|
let is_dynamic_field = false;
|
|
@@ -2204,7 +2204,20 @@ func.runtime.bind.resolve_field = async function (SESSION_ID, prog_id, dsSession
|
|
|
2204
2204
|
|
|
2205
2205
|
if (['_FOR_VAL', '_FOR_KEY'].includes(field_id)) {
|
|
2206
2206
|
is_dynamic_field = true;
|
|
2207
|
-
|
|
2207
|
+
if (iterate_info && (iterate_info.iterator_val === field_id || iterate_info.iterator_key === field_id)) {
|
|
2208
|
+
const iter_value = iterate_info.iterator_val === field_id ? iterate_info._val : iterate_info._key;
|
|
2209
|
+
const toType = function (obj) {
|
|
2210
|
+
return {}.toString.call(obj).match(/\s([a-zA-Z]+)/)[1].toLowerCase();
|
|
2211
|
+
};
|
|
2212
|
+
field_prop = {
|
|
2213
|
+
id: field_id,
|
|
2214
|
+
data: { type: 'virtual', field_id },
|
|
2215
|
+
props: { fieldType: typeof iter_value !== 'undefined' ? toType(iter_value) : 'string' },
|
|
2216
|
+
value: iter_value,
|
|
2217
|
+
};
|
|
2218
|
+
} else {
|
|
2219
|
+
field_prop = SESSION_OBJ[SESSION_ID]?.DS_GLB?.[_dsP]?.dynamic_fields?.[field_id];
|
|
2220
|
+
}
|
|
2208
2221
|
} else {
|
|
2209
2222
|
field_prop = await find_in_view(field_id, _prog_id);
|
|
2210
2223
|
if (!field_prop) {
|
|
@@ -2288,7 +2301,7 @@ func.runtime.bind.update_reference_source_array = async function (options) {
|
|
|
2288
2301
|
if (field_type === 'object' && options.val_is_reference_field) {
|
|
2289
2302
|
let obj_item = new_arr[arr_idx];
|
|
2290
2303
|
let e_exp = options.expression_value.replace(options.bind_field_id, 'obj_item');
|
|
2291
|
-
eval(e_exp +
|
|
2304
|
+
eval(e_exp + `=${JSON.stringify(options.value)}`);
|
|
2292
2305
|
new_arr[arr_idx] = obj_item;
|
|
2293
2306
|
} else {
|
|
2294
2307
|
new_arr[arr_idx] = options.value;
|
|
@@ -4282,6 +4295,23 @@ func.datasource.execute = async function (SESSION_ID, dataSourceSession, IS_DATA
|
|
|
4282
4295
|
let prog_obj = await func.utils.VIEWS_OBJ.get(SESSION_ID, _ds.prog_id);
|
|
4283
4296
|
|
|
4284
4297
|
const callback_datasource = async function () {
|
|
4298
|
+
const run_on_load_events = async function () {
|
|
4299
|
+
if (!(await func.datasource.get_view_events_count(SESSION_ID, dataSourceSession, 'on_load'))) {
|
|
4300
|
+
return false;
|
|
4301
|
+
}
|
|
4302
|
+
await func.datasource.execute_view_events(SESSION_ID, dataSourceSession, 'on_load');
|
|
4303
|
+
return true;
|
|
4304
|
+
};
|
|
4305
|
+
const schedule_panel_on_load_events = function () {
|
|
4306
|
+
setTimeout(async function () {
|
|
4307
|
+
try {
|
|
4308
|
+
await run_on_load_events();
|
|
4309
|
+
} catch (error) {
|
|
4310
|
+
console.error(error);
|
|
4311
|
+
}
|
|
4312
|
+
}, 0);
|
|
4313
|
+
};
|
|
4314
|
+
|
|
4285
4315
|
if (typeof IS_WORKER === 'undefined' && typeof IS_DOCKER === 'undefined' && typeof IS_PROCESS_SERVER === 'undefined' && _ds.viewSourceProp === 'globals') {
|
|
4286
4316
|
if (!['main'].includes(_session.opt.app_computing_mode)) {
|
|
4287
4317
|
await func.index.call_worker(SESSION_ID, {
|
|
@@ -4291,10 +4321,13 @@ func.datasource.execute = async function (SESSION_ID, dataSourceSession, IS_DATA
|
|
|
4291
4321
|
}
|
|
4292
4322
|
}
|
|
4293
4323
|
|
|
4294
|
-
if (
|
|
4295
|
-
await func.datasource.
|
|
4324
|
+
if (args.is_panelP) {
|
|
4325
|
+
const callback_ret = await func.datasource.callback(SESSION_ID, dataSourceSession, args.rowIdP, args.jobNoP, _ds.prog_id);
|
|
4326
|
+
schedule_panel_on_load_events();
|
|
4327
|
+
return callback_ret;
|
|
4296
4328
|
}
|
|
4297
|
-
|
|
4329
|
+
|
|
4330
|
+
await run_on_load_events();
|
|
4298
4331
|
return await func.datasource.callback(SESSION_ID, dataSourceSession, args.rowIdP, args.jobNoP, _ds.prog_id);
|
|
4299
4332
|
};
|
|
4300
4333
|
|
|
@@ -5832,6 +5865,7 @@ func.datasource.update = async function (SESSION_ID, datasource_changes, update_
|
|
|
5832
5865
|
dsSession_changed: findMin(datasource_changed),
|
|
5833
5866
|
avoid_xu_for_refresh,
|
|
5834
5867
|
trigger,
|
|
5868
|
+
ignore_screen_blocker: true,
|
|
5835
5869
|
});
|
|
5836
5870
|
// await removed from the below function cause to dead lock Mar 3 25
|
|
5837
5871
|
await func.runtime.ui.refresh_screen({
|
|
@@ -10131,7 +10165,7 @@ func.UI.utils.get_panels_wrapper_from_dom = async function (SESSION_ID, $xu_embe
|
|
|
10131
10165
|
const panel_keys = Object.keys(refresh_state?.panel_wrappers_cache || {});
|
|
10132
10166
|
for (let index = 0; index < panel_keys.length; index++) {
|
|
10133
10167
|
const panel_entry = refresh_state.panel_wrappers_cache[panel_keys[index]];
|
|
10134
|
-
if (
|
|
10168
|
+
if (!panel_entry?.$panel_div?.length || !panel_entry.$panel_div[0]?.isConnected) {
|
|
10135
10169
|
requires_rebuild = true;
|
|
10136
10170
|
break;
|
|
10137
10171
|
}
|
|
@@ -10584,15 +10618,52 @@ func.UI.worker.init = async function (SESSION_ID) {
|
|
|
10584
10618
|
return elementBottom > viewportTop && elementTop < viewportBottom;
|
|
10585
10619
|
};
|
|
10586
10620
|
|
|
10587
|
-
|
|
10588
|
-
|
|
10589
|
-
|
|
10590
|
-
|
|
10591
|
-
|
|
10592
|
-
|
|
10621
|
+
if (!UI_WORKER_OBJ.in_flight_job_elements) {
|
|
10622
|
+
UI_WORKER_OBJ.in_flight_job_elements = [];
|
|
10623
|
+
}
|
|
10624
|
+
|
|
10625
|
+
const contains_job_element = function ($parent, $child) {
|
|
10626
|
+
const parent_node = $parent?.[0];
|
|
10627
|
+
const child_node = $child?.[0];
|
|
10628
|
+
if (!parent_node || !child_node) {
|
|
10629
|
+
return false;
|
|
10630
|
+
}
|
|
10631
|
+
return parent_node.contains(child_node);
|
|
10632
|
+
};
|
|
10633
|
+
|
|
10634
|
+
// Cancel in-flight child jobs when a parent element is being removed/hidden.
|
|
10635
|
+
// This prevents orphaned jobs whose DOM elements no longer exist.
|
|
10636
|
+
func.UI.worker.cancel_child_in_flight_jobs = function ($parent_element) {
|
|
10637
|
+
if (!$parent_element?.length || !UI_WORKER_OBJ.in_flight_job_elements.length) return;
|
|
10638
|
+
const parent_node = $parent_element[0];
|
|
10639
|
+
if (!parent_node) return;
|
|
10640
|
+
for (let i = UI_WORKER_OBJ.in_flight_job_elements.length - 1; i >= 0; i--) {
|
|
10641
|
+
const child_el = UI_WORKER_OBJ.in_flight_job_elements[i];
|
|
10642
|
+
const child_node = child_el?.[0];
|
|
10643
|
+
if (child_node && parent_node.contains(child_node)) {
|
|
10644
|
+
UI_WORKER_OBJ.in_flight_job_elements.splice(i, 1);
|
|
10593
10645
|
}
|
|
10594
|
-
|
|
10595
|
-
|
|
10646
|
+
}
|
|
10647
|
+
};
|
|
10648
|
+
|
|
10649
|
+
const overlaps_any_in_flight = function (job) {
|
|
10650
|
+
if (!job?.elementP) {
|
|
10651
|
+
return false;
|
|
10652
|
+
}
|
|
10653
|
+
for (let index = 0; index < UI_WORKER_OBJ.in_flight_job_elements.length; index++) {
|
|
10654
|
+
const active_el = UI_WORKER_OBJ.in_flight_job_elements[index];
|
|
10655
|
+
if (!active_el) continue;
|
|
10656
|
+
// Block only when the new job is a CHILD of an in-flight element.
|
|
10657
|
+
// If the new job is a PARENT of an in-flight element, allow it to run
|
|
10658
|
+
// (e.g. xu-render hiding a container while a child panel's on_load is still running).
|
|
10659
|
+
if (contains_job_element(active_el, job.elementP)) {
|
|
10660
|
+
return true;
|
|
10661
|
+
}
|
|
10662
|
+
}
|
|
10663
|
+
return false;
|
|
10664
|
+
};
|
|
10665
|
+
|
|
10666
|
+
const job_iterator = async function (run_mode = 'data') {
|
|
10596
10667
|
const mark_pending_delete_on_descendants = function ($element) {
|
|
10597
10668
|
if (!$element?.length) {
|
|
10598
10669
|
return;
|
|
@@ -10611,6 +10682,7 @@ func.UI.worker.init = async function (SESSION_ID) {
|
|
|
10611
10682
|
};
|
|
10612
10683
|
const dom_job_budget = run_mode === 'dom' ? UI_WORKER_OBJ.dom_jobs_per_frame : Number.POSITIVE_INFINITY;
|
|
10613
10684
|
let dom_jobs_processed = 0;
|
|
10685
|
+
const dispatched_jobs = [];
|
|
10614
10686
|
|
|
10615
10687
|
if (UI_WORKER_OBJ.active_jobs_count) {
|
|
10616
10688
|
func.UI.worker.idle = 0;
|
|
@@ -10624,9 +10696,15 @@ func.UI.worker.init = async function (SESSION_ID) {
|
|
|
10624
10696
|
|
|
10625
10697
|
if (run_mode === 'data' && job_lane !== 'data') continue;
|
|
10626
10698
|
if (job_lane === 'dom' && dom_jobs_processed >= dom_job_budget) continue;
|
|
10699
|
+
// skip jobs whose element overlaps with any currently in-flight job (parent/child)
|
|
10700
|
+
// sibling containers can run in parallel
|
|
10701
|
+
if (overlaps_any_in_flight(val)) continue;
|
|
10627
10702
|
|
|
10628
10703
|
if (!val.elementP) {
|
|
10629
|
-
|
|
10704
|
+
const job_promise = func.UI.worker.execute(val.SESSION_ID, val).catch(function (err) {
|
|
10705
|
+
console.error(err);
|
|
10706
|
+
});
|
|
10707
|
+
dispatched_jobs.push(job_promise);
|
|
10630
10708
|
if (job_lane === 'dom') {
|
|
10631
10709
|
dom_jobs_processed++;
|
|
10632
10710
|
}
|
|
@@ -10646,67 +10724,48 @@ func.UI.worker.init = async function (SESSION_ID) {
|
|
|
10646
10724
|
continue;
|
|
10647
10725
|
}
|
|
10648
10726
|
|
|
10649
|
-
//
|
|
10727
|
+
// keep overlapping parent/child jobs serialized; siblings can run in-flight together
|
|
10650
10728
|
if (contains_job_element(val.elementP, running_job_obj.elementP)) {
|
|
10651
|
-
|
|
10652
|
-
mark_pending_delete_on_descendants(val.elementP);
|
|
10653
|
-
func.UI.worker.mark_pending_delete_session(SESSION_ID);
|
|
10654
|
-
await func.UI.worker.delete_job(SESSION_ID, running_job_obj.job_num);
|
|
10655
|
-
break;
|
|
10656
|
-
}
|
|
10729
|
+
continue;
|
|
10657
10730
|
}
|
|
10658
10731
|
}
|
|
10659
10732
|
|
|
10660
|
-
//
|
|
10661
|
-
|
|
10733
|
+
// Track this element as in-flight so future schedule_run passes skip overlapping jobs
|
|
10734
|
+
const in_flight_entry = val.elementP;
|
|
10735
|
+
UI_WORKER_OBJ.in_flight_job_elements.push(in_flight_entry);
|
|
10736
|
+
|
|
10737
|
+
// execute siblings/non-overlapping jobs — fire and forget, re-trigger scheduler on completion
|
|
10738
|
+
const job_promise = func.UI.worker.execute(val.SESSION_ID, val).catch(function (err) {
|
|
10739
|
+
console.error(err);
|
|
10740
|
+
}).finally(function () {
|
|
10741
|
+
// remove this element from in-flight tracking
|
|
10742
|
+
const idx = UI_WORKER_OBJ.in_flight_job_elements.indexOf(in_flight_entry);
|
|
10743
|
+
if (idx !== -1) {
|
|
10744
|
+
UI_WORKER_OBJ.in_flight_job_elements.splice(idx, 1);
|
|
10745
|
+
}
|
|
10746
|
+
// re-trigger scheduler so blocked sibling jobs can now run
|
|
10747
|
+
func.UI.worker.schedule_run(0);
|
|
10748
|
+
});
|
|
10749
|
+
dispatched_jobs.push(job_promise);
|
|
10662
10750
|
if (job_lane === 'dom') {
|
|
10663
10751
|
dom_jobs_processed++;
|
|
10664
10752
|
}
|
|
10665
10753
|
continue;
|
|
10666
|
-
|
|
10667
|
-
// active_job_children_elements = [];
|
|
10668
|
-
// if (val.elementP) {
|
|
10669
|
-
// // get active_job children elements only if job handle ui job (not update)
|
|
10670
|
-
// $.each(val.elementP.find('*'), function (key, val) {
|
|
10671
|
-
// const xu_ui_id = val.elementP.attr('xu-ui-id');
|
|
10672
|
-
// if (!xu_ui_id) return true;
|
|
10673
|
-
// active_job_children_elements.push(xu_ui_id);
|
|
10674
|
-
// });
|
|
10675
|
-
// func.UI.worker.execute(val.SESSION_ID, val);
|
|
10676
|
-
// continue;
|
|
10677
|
-
// } else {
|
|
10678
|
-
// // non ui job
|
|
10679
|
-
// await func.UI.worker.execute(val.SESSION_ID, val);
|
|
10680
|
-
// break;
|
|
10681
|
-
// }
|
|
10682
|
-
|
|
10683
|
-
// if (UI_WORKER_OBJ.jobs.length > 1 && val.elementP) {
|
|
10684
|
-
// const xu_ui_id = val.elementP.attr('xu-ui-id');
|
|
10685
|
-
// if (!xu_ui_id) continue;
|
|
10686
|
-
// // skip - if job element exist in the active job ui as child element
|
|
10687
|
-
// if (active_job_children_elements.includes(xu_ui_id)) {
|
|
10688
|
-
// continue;
|
|
10689
|
-
// }
|
|
10690
|
-
// // abort - if active job element exist in the current job ui (parent element changed)
|
|
10691
|
-
// $.each(val.elementP.find('*'), function (key, val) {
|
|
10692
|
-
// const xu_ui_id = val.elementP.attr('xu-ui-id');
|
|
10693
|
-
// if (!xu_ui_id) return true;
|
|
10694
|
-
// active_job_children_elements.push(xu_ui_id);
|
|
10695
|
-
// });
|
|
10696
|
-
// // execute - if active job element not exist the current job ui and not detected as parent element
|
|
10697
|
-
// const active_job = UI_WORKER_OBJ.jobs[0];
|
|
10698
|
-
// }
|
|
10699
|
-
|
|
10700
|
-
// break;
|
|
10701
10754
|
} catch (err) {
|
|
10702
10755
|
console.error(err);
|
|
10703
10756
|
}
|
|
10704
10757
|
}
|
|
10758
|
+
|
|
10759
|
+
// Only await jobs that have no element (data jobs) — don't block on long-running UI jobs
|
|
10760
|
+
// UI jobs with elements will re-trigger schedule_run when they complete
|
|
10705
10761
|
}
|
|
10706
10762
|
};
|
|
10707
10763
|
func.UI.worker.schedule_run = function (delay = 0, preferred_mode) {
|
|
10708
10764
|
func.UI.worker.ensure_runtime_indexes();
|
|
10709
10765
|
if (UI_WORKER_OBJ.run_in_progress) {
|
|
10766
|
+
// Allow re-entry: even though a scan is in progress, mark run_again
|
|
10767
|
+
// so the scheduler re-scans after the current pass. This lets sibling
|
|
10768
|
+
// jobs that were queued after the scan started get picked up quickly.
|
|
10710
10769
|
UI_WORKER_OBJ.run_again = true;
|
|
10711
10770
|
return;
|
|
10712
10771
|
}
|
|
@@ -10952,8 +11011,69 @@ func.UI.worker.execute = async function (SESSION_ID, queue_obj) {
|
|
|
10952
11011
|
}
|
|
10953
11012
|
return $root.find(`[xu-ui-id="${xu_ui_id}"]`);
|
|
10954
11013
|
},
|
|
10955
|
-
get_live_element_context: function (elem_key, fallback_$elm) {
|
|
10956
|
-
|
|
11014
|
+
get_live_element_context: function (elem_key, fallback_$elm, context = {}) {
|
|
11015
|
+
let raw_$elm = elem_key ? fx.get_element_by_ui_id(elem_key) : fallback_$elm;
|
|
11016
|
+
let $elm = func.runtime?.ui?.get_preferred_live_element ? func.runtime.ui.get_preferred_live_element(raw_$elm) : raw_$elm;
|
|
11017
|
+
|
|
11018
|
+
if (context.node_id) {
|
|
11019
|
+
const $root = func.UI.worker.get_session_root(SESSION_ID);
|
|
11020
|
+
const runtime_nodes = func.runtime?.ui?.get_refresh_index_elements
|
|
11021
|
+
? func.runtime.ui.get_refresh_index_elements(SESSION_ID, $root).toArray()
|
|
11022
|
+
: $root.find('[xu-ui-id]').toArray();
|
|
11023
|
+
let matching_nodes = [];
|
|
11024
|
+
|
|
11025
|
+
for (let index = 0; index < runtime_nodes.length; index++) {
|
|
11026
|
+
const node = runtime_nodes[index];
|
|
11027
|
+
const node_data = func.runtime.ui.get_data(node);
|
|
11028
|
+
const node_xu_data = node_data?.xuData;
|
|
11029
|
+
if (!node_xu_data) {
|
|
11030
|
+
continue;
|
|
11031
|
+
}
|
|
11032
|
+
if (node_xu_data.nodeid !== context.node_id) {
|
|
11033
|
+
continue;
|
|
11034
|
+
}
|
|
11035
|
+
if (context.recordid && node_xu_data.recordid !== context.recordid) {
|
|
11036
|
+
continue;
|
|
11037
|
+
}
|
|
11038
|
+
if (context.prog_id && node_xu_data.paramsP?.prog_id !== context.prog_id) {
|
|
11039
|
+
continue;
|
|
11040
|
+
}
|
|
11041
|
+
if (context.parent_element_ui_id && node_xu_data.parent_element_ui_id !== context.parent_element_ui_id) {
|
|
11042
|
+
continue;
|
|
11043
|
+
}
|
|
11044
|
+
if (node_xu_data.pending_to_delete) {
|
|
11045
|
+
continue;
|
|
11046
|
+
}
|
|
11047
|
+
matching_nodes.push(node);
|
|
11048
|
+
}
|
|
11049
|
+
|
|
11050
|
+
if (!matching_nodes.length) {
|
|
11051
|
+
for (let index = 0; index < runtime_nodes.length; index++) {
|
|
11052
|
+
const node = runtime_nodes[index];
|
|
11053
|
+
const node_data = func.runtime.ui.get_data(node);
|
|
11054
|
+
const node_xu_data = node_data?.xuData;
|
|
11055
|
+
if (!node_xu_data) {
|
|
11056
|
+
continue;
|
|
11057
|
+
}
|
|
11058
|
+
if (node_xu_data.nodeid !== context.node_id) {
|
|
11059
|
+
continue;
|
|
11060
|
+
}
|
|
11061
|
+
if (context.recordid && node_xu_data.recordid !== context.recordid) {
|
|
11062
|
+
continue;
|
|
11063
|
+
}
|
|
11064
|
+
if (node_xu_data.pending_to_delete) {
|
|
11065
|
+
continue;
|
|
11066
|
+
}
|
|
11067
|
+
matching_nodes.push(node);
|
|
11068
|
+
}
|
|
11069
|
+
}
|
|
11070
|
+
|
|
11071
|
+
if (matching_nodes.length) {
|
|
11072
|
+
raw_$elm = $(matching_nodes);
|
|
11073
|
+
$elm = func.runtime?.ui?.get_preferred_live_element ? func.runtime.ui.get_preferred_live_element(raw_$elm) : raw_$elm;
|
|
11074
|
+
}
|
|
11075
|
+
}
|
|
11076
|
+
|
|
10957
11077
|
if (!$elm?.length) {
|
|
10958
11078
|
return {
|
|
10959
11079
|
$elm: $(),
|
|
@@ -11008,6 +11128,13 @@ func.UI.worker.execute = async function (SESSION_ID, queue_obj) {
|
|
|
11008
11128
|
'xu-for': true,
|
|
11009
11129
|
'xu-exp:xu-bind': true,
|
|
11010
11130
|
};
|
|
11131
|
+
const raw_value_attributes = {
|
|
11132
|
+
'xu-bind': true,
|
|
11133
|
+
'xu-ref': true,
|
|
11134
|
+
'xu-on': true,
|
|
11135
|
+
'xu-for-key': true,
|
|
11136
|
+
'xu-for-val': true,
|
|
11137
|
+
};
|
|
11011
11138
|
|
|
11012
11139
|
const execution_plan = [];
|
|
11013
11140
|
for (let index = 0; index < (refresh_attributes || []).length; index++) {
|
|
@@ -11023,7 +11150,7 @@ func.UI.worker.execute = async function (SESSION_ID, queue_obj) {
|
|
|
11023
11150
|
attr_new,
|
|
11024
11151
|
xu_func,
|
|
11025
11152
|
is_regular_attribute: !!(attr_new && attr_new.substr(0, 2) !== 'xu'),
|
|
11026
|
-
requires_expression: attr !== 'xu-class' && attr !== 'xu-ui-plugin',
|
|
11153
|
+
requires_expression: !raw_value_attributes[attr] && attr !== 'xu-class' && attr !== 'xu-ui-plugin',
|
|
11027
11154
|
regular_attr_name: attr_new ? (attr_new !== 'viewBox' ? attr_new.toLowerCase() : attr_new) : null,
|
|
11028
11155
|
});
|
|
11029
11156
|
}
|
|
@@ -11099,23 +11226,25 @@ func.UI.worker.execute = async function (SESSION_ID, queue_obj) {
|
|
|
11099
11226
|
},
|
|
11100
11227
|
execute_xu_render_attributes: async function () {
|
|
11101
11228
|
const perf_end = func.runtime?.perf?.start?.(SESSION_ID, 'execute_xu_render_attributes');
|
|
11102
|
-
const live_context = fx.get_live_element_context(queue_obj.paramsP?.elem_key, queue_obj.elementP || queue_obj.paramsP?.elem_val?.$elm);
|
|
11229
|
+
const live_context = fx.get_live_element_context(queue_obj.paramsP?.elem_key, queue_obj.elementP || queue_obj.paramsP?.elem_val?.$elm, queue_obj.paramsP);
|
|
11103
11230
|
const _data = live_context.data;
|
|
11104
11231
|
try {
|
|
11105
11232
|
if (_data?.xuData?.paramsP) {
|
|
11233
|
+
const live_xu_data = _data.xuData;
|
|
11106
11234
|
await func.runtime.render.execute_xu_function({
|
|
11107
11235
|
SESSION_ID,
|
|
11108
11236
|
is_skeleton: null,
|
|
11109
|
-
$root_container:
|
|
11110
|
-
nodeP:
|
|
11111
|
-
$container: fx.get_element_by_ui_id(
|
|
11112
|
-
paramsP:
|
|
11113
|
-
parent_infoP: {},
|
|
11237
|
+
$root_container: live_xu_data.$root_container,
|
|
11238
|
+
nodeP: live_xu_data.node,
|
|
11239
|
+
$container: fx.get_element_by_ui_id(live_xu_data.parent_element_ui_id) || live_xu_data.$container,
|
|
11240
|
+
paramsP: live_xu_data.paramsP,
|
|
11241
|
+
parent_infoP: live_xu_data.iterate_info ? { iterate_info: live_xu_data.iterate_info } : {},
|
|
11114
11242
|
jobNoP: queue_obj.jobNoP,
|
|
11115
|
-
keyP:
|
|
11116
|
-
parent_nodeP:
|
|
11243
|
+
keyP: live_xu_data.key,
|
|
11244
|
+
parent_nodeP: live_xu_data.parent_node,
|
|
11117
11245
|
xu_func: 'xu-render',
|
|
11118
11246
|
$elm: live_context.$elm,
|
|
11247
|
+
$live_elm: live_context.$elm,
|
|
11119
11248
|
val: {
|
|
11120
11249
|
key: 'xu-render',
|
|
11121
11250
|
value: queue_obj.paramsP.attr_value,
|
|
@@ -11138,7 +11267,7 @@ func.UI.worker.execute = async function (SESSION_ID, queue_obj) {
|
|
|
11138
11267
|
};
|
|
11139
11268
|
|
|
11140
11269
|
try {
|
|
11141
|
-
const live_context = fx.get_live_element_context(queue_obj.paramsP?.elem_key, queue_obj.elementP || queue_obj.paramsP?.elem_val?.$elm);
|
|
11270
|
+
const live_context = fx.get_live_element_context(queue_obj.paramsP?.elem_key, queue_obj.elementP || queue_obj.paramsP?.elem_val?.$elm, queue_obj.paramsP);
|
|
11142
11271
|
const $elm = live_context.$elm;
|
|
11143
11272
|
const live_data = live_context.data;
|
|
11144
11273
|
const elm_node = $elm?.[0];
|
|
@@ -11151,18 +11280,20 @@ func.UI.worker.execute = async function (SESSION_ID, queue_obj) {
|
|
|
11151
11280
|
const refresh_attributes = queue_obj.paramsP?.elem_val?.attributes || [];
|
|
11152
11281
|
const execution_plan = fx.get_refresh_execution_plan(live_data, refresh_attributes);
|
|
11153
11282
|
const expression_results_cache = {};
|
|
11283
|
+
const live_parent_container = fx.get_element_by_ui_id(live_xu_data.parent_element_ui_id);
|
|
11154
11284
|
const xu_execution_context = {
|
|
11155
11285
|
SESSION_ID,
|
|
11156
11286
|
is_skeleton: null,
|
|
11157
11287
|
$root_container: live_xu_data.$root_container,
|
|
11158
11288
|
nodeP: live_xu_data.node,
|
|
11159
|
-
$container: live_xu_data.$container,
|
|
11289
|
+
$container: live_parent_container?.length ? live_parent_container : live_xu_data.$container,
|
|
11160
11290
|
paramsP: live_xu_data.paramsP,
|
|
11161
|
-
parent_infoP: {},
|
|
11291
|
+
parent_infoP: live_xu_data.iterate_info ? { iterate_info: live_xu_data.iterate_info } : {},
|
|
11162
11292
|
jobNoP: queue_obj.jobNoP,
|
|
11163
|
-
keyP:
|
|
11164
|
-
parent_nodeP:
|
|
11293
|
+
keyP: live_xu_data.key,
|
|
11294
|
+
parent_nodeP: live_xu_data.parent_node,
|
|
11165
11295
|
$elm,
|
|
11296
|
+
$live_elm: $elm,
|
|
11166
11297
|
get_params_obj_new: func.runtime.program.get_params_obj,
|
|
11167
11298
|
};
|
|
11168
11299
|
const handler_bundle = func.runtime.render.build_xu_handlers(xu_execution_context, SESSION_OBJ[SESSION_ID].DS_GLB[live_xu_data.paramsP.dsSessionP]);
|
|
@@ -11217,7 +11348,7 @@ func.UI.worker.execute = async function (SESSION_ID, queue_obj) {
|
|
|
11217
11348
|
execute_xu_for: async function () {
|
|
11218
11349
|
const perf_end = func.runtime?.perf?.start?.(SESSION_ID, 'execute_xu_for');
|
|
11219
11350
|
try {
|
|
11220
|
-
const live_context = fx.get_live_element_context(queue_obj.paramsP?.elem_key, queue_obj.elementP || queue_obj?.paramsP?.elem_val?.$elm);
|
|
11351
|
+
const live_context = fx.get_live_element_context(queue_obj.paramsP?.elem_key, queue_obj.elementP || queue_obj?.paramsP?.elem_val?.$elm, queue_obj.paramsP);
|
|
11221
11352
|
var $elm = live_context.$elm; // $(SESSION_OBJ[SESSION_ID].root_element).find(`[xu-ui-id=${queue_obj.paramsP.elem_key}]`)
|
|
11222
11353
|
|
|
11223
11354
|
if (!$elm?.length) {
|
|
@@ -11294,7 +11425,7 @@ func.UI.worker.execute = async function (SESSION_ID, queue_obj) {
|
|
|
11294
11425
|
},
|
|
11295
11426
|
execute_xu_widget: async function () {
|
|
11296
11427
|
try {
|
|
11297
|
-
const live_context = fx.get_live_element_context(queue_obj.paramsP?.elem_key, queue_obj.elementP || queue_obj?.paramsP?.elem_val?.$elm);
|
|
11428
|
+
const live_context = fx.get_live_element_context(queue_obj.paramsP?.elem_key, queue_obj.elementP || queue_obj?.paramsP?.elem_val?.$elm, queue_obj.paramsP);
|
|
11298
11429
|
var $elm = live_context.$elm; // $(SESSION_OBJ[SESSION_ID].root_element).find(`[xu-ui-id=${queue_obj.paramsP.elem_key}]`)
|
|
11299
11430
|
|
|
11300
11431
|
if (!$elm?.length) {
|
|
@@ -11323,7 +11454,16 @@ func.UI.worker.execute = async function (SESSION_ID, queue_obj) {
|
|
|
11323
11454
|
},
|
|
11324
11455
|
};
|
|
11325
11456
|
|
|
11326
|
-
|
|
11457
|
+
try {
|
|
11458
|
+
return await fx[queue_obj.functionP]();
|
|
11459
|
+
} catch (error) {
|
|
11460
|
+
console.error(error);
|
|
11461
|
+
const failed_job_index = func.UI.worker.find_job_index(SESSION_ID, queue_obj.job_num);
|
|
11462
|
+
if (failed_job_index !== null && typeof failed_job_index !== 'undefined' && UI_WORKER_OBJ.jobs[failed_job_index]) {
|
|
11463
|
+
await func.UI.worker.delete_job(SESSION_ID, queue_obj.job_num);
|
|
11464
|
+
}
|
|
11465
|
+
return null;
|
|
11466
|
+
}
|
|
11327
11467
|
};
|
|
11328
11468
|
func.UI.worker.find_job_index = function (SESSION_ID, jobNoP) {
|
|
11329
11469
|
var ret = null;
|
|
@@ -12027,7 +12167,7 @@ func.runtime.ui.init_screen = async function (options) {
|
|
|
12027
12167
|
$rootFrame.css('display', 'contents');
|
|
12028
12168
|
}
|
|
12029
12169
|
|
|
12030
|
-
func.UI.utils.indicator.screen.busy();
|
|
12170
|
+
if (!is_panelP) func.UI.utils.indicator.screen.busy();
|
|
12031
12171
|
|
|
12032
12172
|
const ret = await func.datasource.create(
|
|
12033
12173
|
SESSION_ID,
|
|
@@ -12043,7 +12183,7 @@ func.runtime.ui.init_screen = async function (options) {
|
|
|
12043
12183
|
null,
|
|
12044
12184
|
null,
|
|
12045
12185
|
null,
|
|
12046
|
-
|
|
12186
|
+
is_panelP,
|
|
12047
12187
|
parameters_obj_inP,
|
|
12048
12188
|
);
|
|
12049
12189
|
|
|
@@ -12070,7 +12210,7 @@ func.runtime.ui.init_screen = async function (options) {
|
|
|
12070
12210
|
if (!node.length) return console.warn('ui node empty');
|
|
12071
12211
|
const ret_render_$container = await func.runtime.render.render_ui_tree(SESSION_ID, $rootFrame, node[0], null, params, jobNoP, null, null, null, null, null, $rootFrame);
|
|
12072
12212
|
|
|
12073
|
-
func.UI.utils.indicator.screen.normal();
|
|
12213
|
+
if (!is_panelP) func.UI.utils.indicator.screen.normal();
|
|
12074
12214
|
|
|
12075
12215
|
return await func.runtime.ui.screen_loading_done({
|
|
12076
12216
|
SESSION_ID,
|
|
@@ -12595,6 +12735,7 @@ func.runtime.render = func.runtime.render || {};
|
|
|
12595
12735
|
// Browser-only panel rendering helpers live here so generic view rendering can stay focused.
|
|
12596
12736
|
|
|
12597
12737
|
func.runtime.ui.render_panel_node = async function (options) {
|
|
12738
|
+
|
|
12598
12739
|
const $wrapper = $('<div>');
|
|
12599
12740
|
const $div = await func.runtime.ui.create_container({
|
|
12600
12741
|
SESSION_ID: options.SESSION_ID,
|
|
@@ -13168,7 +13309,7 @@ func.runtime.ui.normalize_refresh_field_reference = function (field_ref) {
|
|
|
13168
13309
|
|
|
13169
13310
|
return [...normalized].filter(Boolean);
|
|
13170
13311
|
};
|
|
13171
|
-
func.runtime.ui.extract_expression_refresh_fields = function (elm_data, expression_text, without_var) {
|
|
13312
|
+
func.runtime.ui.extract_expression_refresh_fields = function (elm_data, expression_text, without_var, _visited) {
|
|
13172
13313
|
const fields = new Set();
|
|
13173
13314
|
if (!expression_text) {
|
|
13174
13315
|
return fields;
|
|
@@ -13199,8 +13340,12 @@ func.runtime.ui.extract_expression_refresh_fields = function (elm_data, expressi
|
|
|
13199
13340
|
|
|
13200
13341
|
const parameters_raw_obj = elm_data?.xuData?.paramsP?.parameters_raw_obj || {};
|
|
13201
13342
|
const parameter_keys = Object.keys(parameters_raw_obj);
|
|
13343
|
+
const visited = _visited || new Set();
|
|
13202
13344
|
for (let index = 0; index < parameter_keys.length; index++) {
|
|
13203
13345
|
const param_key = parameter_keys[index];
|
|
13346
|
+
if (visited.has(param_key)) {
|
|
13347
|
+
continue;
|
|
13348
|
+
}
|
|
13204
13349
|
const param_val = parameters_raw_obj[param_key];
|
|
13205
13350
|
if (!param_val?.includes?.('@')) {
|
|
13206
13351
|
continue;
|
|
@@ -13209,7 +13354,8 @@ func.runtime.ui.extract_expression_refresh_fields = function (elm_data, expressi
|
|
|
13209
13354
|
if (!text.includes(param_token)) {
|
|
13210
13355
|
continue;
|
|
13211
13356
|
}
|
|
13212
|
-
|
|
13357
|
+
visited.add(param_key);
|
|
13358
|
+
const nested_fields = func.runtime.ui.extract_expression_refresh_fields(elm_data, param_val, false, visited);
|
|
13213
13359
|
nested_fields.forEach(function (field_id) {
|
|
13214
13360
|
add_field(field_id);
|
|
13215
13361
|
});
|
|
@@ -13509,6 +13655,41 @@ func.runtime.ui.find_refresh_elements_by_attr = function ($root, attr_name, attr
|
|
|
13509
13655
|
|
|
13510
13656
|
return $(elements);
|
|
13511
13657
|
};
|
|
13658
|
+
func.runtime.ui.get_preferred_live_element = function (target) {
|
|
13659
|
+
const elements = func.runtime.ui.as_jquery(target).toArray();
|
|
13660
|
+
if (!elements.length) {
|
|
13661
|
+
return $();
|
|
13662
|
+
}
|
|
13663
|
+
|
|
13664
|
+
let best_node = null;
|
|
13665
|
+
let best_score = -Infinity;
|
|
13666
|
+
for (let index = 0; index < elements.length; index++) {
|
|
13667
|
+
const node = elements[index];
|
|
13668
|
+
if (!node) {
|
|
13669
|
+
continue;
|
|
13670
|
+
}
|
|
13671
|
+
const node_data = func.runtime.ui.get_data(node);
|
|
13672
|
+
let score = 0;
|
|
13673
|
+
if (node.isConnected) {
|
|
13674
|
+
score += 100;
|
|
13675
|
+
}
|
|
13676
|
+
if (!node_data?.xuData?.pending_to_delete) {
|
|
13677
|
+
score += 50;
|
|
13678
|
+
}
|
|
13679
|
+
if (node.getClientRects?.().length) {
|
|
13680
|
+
score += 25;
|
|
13681
|
+
}
|
|
13682
|
+
if (!node.hidden) {
|
|
13683
|
+
score += 10;
|
|
13684
|
+
}
|
|
13685
|
+
if (score >= best_score) {
|
|
13686
|
+
best_score = score;
|
|
13687
|
+
best_node = node;
|
|
13688
|
+
}
|
|
13689
|
+
}
|
|
13690
|
+
|
|
13691
|
+
return best_node ? $(best_node) : $(elements[elements.length - 1]);
|
|
13692
|
+
};
|
|
13512
13693
|
func.runtime.ui.get_refresh_indexed_element_by_ui_id = function (SESSION_ID, selector_id) {
|
|
13513
13694
|
const state = func.runtime.ui.ensure_refresh_dependency_state(SESSION_ID);
|
|
13514
13695
|
if (!state) {
|
|
@@ -13519,12 +13700,14 @@ func.runtime.ui.get_refresh_indexed_element_by_ui_id = function (SESSION_ID, sel
|
|
|
13519
13700
|
}
|
|
13520
13701
|
|
|
13521
13702
|
let $elm = state.elements_by_ui_id?.[selector_id];
|
|
13703
|
+
$elm = func.runtime.ui.get_preferred_live_element($elm);
|
|
13522
13704
|
if ($elm?.length && $elm[0]?.isConnected) {
|
|
13705
|
+
state.elements_by_ui_id[selector_id] = $elm;
|
|
13523
13706
|
return $elm;
|
|
13524
13707
|
}
|
|
13525
13708
|
|
|
13526
13709
|
const $root = func.runtime.ui.get_refresh_index_root(SESSION_ID);
|
|
13527
|
-
$elm = func.runtime.ui.find_refresh_elements_by_attr($root, 'xu-ui-id', selector_id
|
|
13710
|
+
$elm = func.runtime.ui.get_preferred_live_element(func.runtime.ui.find_refresh_elements_by_attr($root, 'xu-ui-id', selector_id));
|
|
13528
13711
|
if ($elm?.length) {
|
|
13529
13712
|
state.elements_by_ui_id[selector_id] = $elm;
|
|
13530
13713
|
state.runtime_elements_cache = null;
|
|
@@ -13628,12 +13811,14 @@ func.runtime.ui.get_refresh_indexed_panel_wrapper_by_id = function (SESSION_ID,
|
|
|
13628
13811
|
}
|
|
13629
13812
|
|
|
13630
13813
|
let $elm = state.panel_wrappers_by_id?.[wrapper_id];
|
|
13814
|
+
$elm = func.runtime.ui.get_preferred_live_element($elm);
|
|
13631
13815
|
if ($elm?.length && $elm[0]?.isConnected) {
|
|
13816
|
+
state.panel_wrappers_by_id[wrapper_id] = $elm;
|
|
13632
13817
|
return $elm;
|
|
13633
13818
|
}
|
|
13634
13819
|
|
|
13635
13820
|
const $root = func.runtime.ui.get_refresh_index_root(SESSION_ID);
|
|
13636
|
-
$elm = func.runtime.ui.find_refresh_elements_by_attr($root, 'xu-panel-wrapper-id', wrapper_id
|
|
13821
|
+
$elm = func.runtime.ui.get_preferred_live_element(func.runtime.ui.find_refresh_elements_by_attr($root, 'xu-panel-wrapper-id', wrapper_id));
|
|
13637
13822
|
if ($elm?.length) {
|
|
13638
13823
|
state.panel_wrappers_by_id[wrapper_id] = $elm;
|
|
13639
13824
|
state.panel_wrapper_elements_cache = null;
|
|
@@ -13865,6 +14050,10 @@ func.runtime.ui.build_refresh_job_obj = function (options, elem_key, elem_val, e
|
|
|
13865
14050
|
SESSION_ID: options.SESSION_ID,
|
|
13866
14051
|
fields_arr: options.fields_arr,
|
|
13867
14052
|
elem_key,
|
|
14053
|
+
node_id: elm_data?.xuData?.nodeid,
|
|
14054
|
+
recordid: elm_data?.xuData?.recordid,
|
|
14055
|
+
parent_element_ui_id: elm_data?.xuData?.parent_element_ui_id,
|
|
14056
|
+
prog_id: elm_data?.xuData?.paramsP?.prog_id,
|
|
13868
14057
|
elem_val: {
|
|
13869
14058
|
attributes: [...(elem_val.attributes || [])],
|
|
13870
14059
|
},
|
|
@@ -14189,7 +14378,7 @@ func.runtime.render = func.runtime.render || {};
|
|
|
14189
14378
|
// Browser-only xu-attribute refresh helpers live here so screen refresh orchestration can stay focused.
|
|
14190
14379
|
|
|
14191
14380
|
func.runtime.ui.refresh_xu_attributes = async function (options) {
|
|
14192
|
-
if (options.trigger !== 'click' && !_.isEmpty(SCREEN_BLOCKER_OBJ)) {
|
|
14381
|
+
if (!options.ignore_screen_blocker && options.trigger !== 'click' && !_.isEmpty(SCREEN_BLOCKER_OBJ)) {
|
|
14193
14382
|
setTimeout(() => {
|
|
14194
14383
|
func.runtime.ui.refresh_xu_attributes(options);
|
|
14195
14384
|
}, 100);
|
|
@@ -16710,11 +16899,19 @@ func.runtime.render.handle_xu_ref = async function (options) {
|
|
|
16710
16899
|
func.runtime.render.handle_xu_bind = async function (options) {
|
|
16711
16900
|
if (options.is_skeleton) return {};
|
|
16712
16901
|
|
|
16713
|
-
const
|
|
16902
|
+
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);
|
|
16903
|
+
const elm_data = func.runtime.ui.get_data($elm);
|
|
16714
16904
|
const xuData = elm_data?.xuData;
|
|
16905
|
+
const bind_expression =
|
|
16906
|
+
typeof options?.val?.value === 'string'
|
|
16907
|
+
? options.val.value
|
|
16908
|
+
: elm_data?.xuAttributes?.['xu-bind'] || func.runtime.ui.get_attr($elm, 'xu-bind');
|
|
16715
16909
|
if (!xuData?.paramsP) {
|
|
16716
16910
|
return {};
|
|
16717
16911
|
}
|
|
16912
|
+
if (!bind_expression) {
|
|
16913
|
+
return {};
|
|
16914
|
+
}
|
|
16718
16915
|
|
|
16719
16916
|
let val_is_reference_field = false;
|
|
16720
16917
|
let _prog_id = xuData.paramsP.prog_id;
|
|
@@ -16722,10 +16919,94 @@ func.runtime.render.handle_xu_bind = async function (options) {
|
|
|
16722
16919
|
let is_dynamic_field = false;
|
|
16723
16920
|
let field_prop;
|
|
16724
16921
|
let bind_field_id;
|
|
16725
|
-
const input_field_type =
|
|
16922
|
+
const input_field_type = $elm?.[0]?.type || func.runtime.ui.get_attr($elm, 'type');
|
|
16923
|
+
const bind_ui_id = xuData.ui_id || func.runtime.ui.get_attr($elm, 'xu-ui-id');
|
|
16924
|
+
const get_bind_targets = function () {
|
|
16925
|
+
const $root = func.runtime.ui.get_refresh_index_root?.(options.SESSION_ID) || func.runtime.ui.get_root_element?.(options.SESSION_ID) || $('body');
|
|
16926
|
+
const live_targets = [];
|
|
16927
|
+
const seen_nodes = new Set();
|
|
16928
|
+
const add_candidate = function (node) {
|
|
16929
|
+
if (!node || seen_nodes.has(node)) {
|
|
16930
|
+
return;
|
|
16931
|
+
}
|
|
16932
|
+
const target_data = func.runtime.ui.get_data(node);
|
|
16933
|
+
if (!node.isConnected || target_data?.xuData?.pending_to_delete) {
|
|
16934
|
+
return;
|
|
16935
|
+
}
|
|
16936
|
+
seen_nodes.add(node);
|
|
16937
|
+
live_targets.push(node);
|
|
16938
|
+
};
|
|
16939
|
+
|
|
16940
|
+
if (bind_ui_id && options.SESSION_ID && func.runtime?.ui?.find_refresh_elements_by_attr) {
|
|
16941
|
+
const ui_id_targets = func.runtime.ui.find_refresh_elements_by_attr($root, 'xu-ui-id', bind_ui_id).toArray();
|
|
16942
|
+
for (let index = 0; index < ui_id_targets.length; index++) {
|
|
16943
|
+
add_candidate(ui_id_targets[index]);
|
|
16944
|
+
}
|
|
16945
|
+
}
|
|
16946
|
+
|
|
16947
|
+
const runtime_nodes = func.runtime?.ui?.get_refresh_index_elements
|
|
16948
|
+
? func.runtime.ui.get_refresh_index_elements(options.SESSION_ID, $root).toArray()
|
|
16949
|
+
: $root.find('[xu-ui-id]').toArray();
|
|
16950
|
+
const target_parent_ui_id = xuData.parent_element_ui_id;
|
|
16951
|
+
const target_node_id = xuData.nodeid;
|
|
16952
|
+
const target_recordid = xuData.recordid;
|
|
16953
|
+
const target_prog_id = xuData.paramsP?.prog_id;
|
|
16954
|
+
for (let index = 0; index < runtime_nodes.length; index++) {
|
|
16955
|
+
const node = runtime_nodes[index];
|
|
16956
|
+
const node_data = func.runtime.ui.get_data(node);
|
|
16957
|
+
const node_xu_data = node_data?.xuData;
|
|
16958
|
+
if (!node_xu_data) {
|
|
16959
|
+
continue;
|
|
16960
|
+
}
|
|
16961
|
+
if (target_node_id && node_xu_data.nodeid !== target_node_id) {
|
|
16962
|
+
continue;
|
|
16963
|
+
}
|
|
16964
|
+
if (target_parent_ui_id && node_xu_data.parent_element_ui_id !== target_parent_ui_id) {
|
|
16965
|
+
continue;
|
|
16966
|
+
}
|
|
16967
|
+
if (target_prog_id && node_xu_data.paramsP?.prog_id !== target_prog_id) {
|
|
16968
|
+
continue;
|
|
16969
|
+
}
|
|
16970
|
+
if (typeof target_recordid !== 'undefined' && target_recordid !== null && node_xu_data.recordid !== target_recordid) {
|
|
16971
|
+
continue;
|
|
16972
|
+
}
|
|
16973
|
+
const node_bind_expression = node_data?.xuAttributes?.['xu-bind'] || func.runtime.ui.get_attr(node, 'xu-bind');
|
|
16974
|
+
if (node_bind_expression !== bind_expression) {
|
|
16975
|
+
continue;
|
|
16976
|
+
}
|
|
16977
|
+
add_candidate(node);
|
|
16978
|
+
}
|
|
16979
|
+
|
|
16980
|
+
if (!live_targets.length) {
|
|
16981
|
+
return $elm;
|
|
16982
|
+
}
|
|
16983
|
+
|
|
16984
|
+
for (let index = 0; index < live_targets.length; index++) {
|
|
16985
|
+
const node = live_targets[index];
|
|
16986
|
+
const target_data = func.runtime.ui.get_data(node);
|
|
16987
|
+
if (!node?.isConnected || target_data?.xuData?.pending_to_delete) {
|
|
16988
|
+
continue;
|
|
16989
|
+
}
|
|
16990
|
+
add_candidate(node);
|
|
16991
|
+
}
|
|
16992
|
+
|
|
16993
|
+
if (!live_targets.length) {
|
|
16994
|
+
return $elm;
|
|
16995
|
+
}
|
|
16996
|
+
|
|
16997
|
+
const target_nodes = live_targets;
|
|
16998
|
+
const visible_targets = [];
|
|
16999
|
+
for (let index = 0; index < target_nodes.length; index++) {
|
|
17000
|
+
const node = target_nodes[index];
|
|
17001
|
+
if (node.getClientRects?.().length && !node.hidden) {
|
|
17002
|
+
visible_targets.push(node);
|
|
17003
|
+
}
|
|
17004
|
+
}
|
|
17005
|
+
return $(visible_targets.length ? visible_targets : live_targets);
|
|
17006
|
+
};
|
|
16726
17007
|
|
|
16727
17008
|
try {
|
|
16728
|
-
const bind_field = await func.runtime.bind.resolve_field(options.SESSION_ID, _prog_id, _dsP,
|
|
17009
|
+
const bind_field = await func.runtime.bind.resolve_field(options.SESSION_ID, _prog_id, _dsP, bind_expression.split('.')[0], xuData.iterate_info);
|
|
16729
17010
|
bind_field_id = bind_field.bind_field_id;
|
|
16730
17011
|
field_prop = bind_field.field_prop;
|
|
16731
17012
|
is_dynamic_field = bind_field.is_dynamic_field;
|
|
@@ -16774,38 +17055,85 @@ func.runtime.render.handle_xu_bind = async function (options) {
|
|
|
16774
17055
|
field_prop,
|
|
16775
17056
|
val_is_reference_field,
|
|
16776
17057
|
input_field_type,
|
|
16777
|
-
expression_value:
|
|
17058
|
+
expression_value: bind_expression,
|
|
16778
17059
|
value,
|
|
16779
17060
|
});
|
|
16780
17061
|
|
|
16781
17062
|
await func.datasource.update_changes_for_out_parameter(options.SESSION_ID, _dsP, _ds.parentDataSourceNo);
|
|
16782
17063
|
};
|
|
16783
17064
|
|
|
16784
|
-
|
|
17065
|
+
const bind_targets = get_bind_targets();
|
|
17066
|
+
const target_nodes = bind_targets.toArray();
|
|
17067
|
+
for (let index = 0; index < target_nodes.length; index++) {
|
|
17068
|
+
const target = target_nodes[index];
|
|
17069
|
+
const target_data = func.runtime.ui.get_data(target);
|
|
17070
|
+
if (!target_data?.xuData || target_data.xuData.bind_listener_attached) {
|
|
17071
|
+
continue;
|
|
17072
|
+
}
|
|
17073
|
+
bind.listener(target, field_changed);
|
|
17074
|
+
target_data.xuData.bind_listener_attached = true;
|
|
17075
|
+
}
|
|
16785
17076
|
|
|
16786
|
-
const set_value = function () {
|
|
16787
|
-
const _ds = SESSION_OBJ[options.SESSION_ID].DS_GLB[
|
|
16788
|
-
if (!_ds
|
|
17077
|
+
const set_value = async function () {
|
|
17078
|
+
const _ds = SESSION_OBJ[options.SESSION_ID].DS_GLB[_dsP];
|
|
17079
|
+
if (!_ds) return;
|
|
17080
|
+
const target_record_id = xuData.recordid || _ds.currentRecordId;
|
|
17081
|
+
if (!target_record_id) return;
|
|
16789
17082
|
let value;
|
|
16790
17083
|
try {
|
|
16791
17084
|
if (val_is_reference_field) {
|
|
16792
|
-
|
|
16793
|
-
|
|
17085
|
+
const iter = xuData.iterate_info;
|
|
17086
|
+
if (iter && is_dynamic_field && (iter.iterator_val === bind_field_id || iter.iterator_key === bind_field_id)) {
|
|
17087
|
+
value = iter.iterator_val === bind_field_id ? iter._val : iter._key;
|
|
17088
|
+
} else {
|
|
17089
|
+
const resolved_value = await func.datasource.get_value(options.SESSION_ID, bind_field_id, _dsP, target_record_id);
|
|
17090
|
+
if (resolved_value?.found) {
|
|
17091
|
+
value = resolved_value.ret.value;
|
|
17092
|
+
} else {
|
|
17093
|
+
value = func.runtime.bind.get_source_value(_ds, bind_field_id, is_dynamic_field);
|
|
17094
|
+
}
|
|
17095
|
+
}
|
|
17096
|
+
value = func.runtime.bind.format_display_value($elm, field_prop, bind_field_id, bind_expression, value, input_field_type);
|
|
16794
17097
|
} else {
|
|
16795
|
-
value =
|
|
17098
|
+
value = bind_expression;
|
|
16796
17099
|
}
|
|
16797
17100
|
if (typeof value === 'undefined') return;
|
|
16798
|
-
|
|
17101
|
+
|
|
17102
|
+
const live_bind_targets = get_bind_targets().toArray();
|
|
17103
|
+
for (let index = 0; index < live_bind_targets.length; index++) {
|
|
17104
|
+
const elm = live_bind_targets[index];
|
|
17105
|
+
if (!elm) {
|
|
17106
|
+
continue;
|
|
17107
|
+
}
|
|
17108
|
+
|
|
17109
|
+
bind.setter(elm, value);
|
|
17110
|
+
const target_input_type = elm.type || input_field_type;
|
|
17111
|
+
switch (target_input_type) {
|
|
17112
|
+
case 'radio':
|
|
17113
|
+
elm.checked = elm.value === _.toString(value);
|
|
17114
|
+
break;
|
|
17115
|
+
case 'checkbox':
|
|
17116
|
+
elm.checked = !!value;
|
|
17117
|
+
break;
|
|
17118
|
+
default:
|
|
17119
|
+
if (typeof elm.value !== 'undefined') {
|
|
17120
|
+
elm.value = value === null ? '' : _.toString(value);
|
|
17121
|
+
}
|
|
17122
|
+
break;
|
|
17123
|
+
}
|
|
17124
|
+
}
|
|
16799
17125
|
} catch (err) {
|
|
16800
17126
|
console.error(err);
|
|
16801
17127
|
}
|
|
16802
17128
|
};
|
|
16803
17129
|
|
|
16804
|
-
|
|
16805
|
-
|
|
17130
|
+
const bind_refresh_event = 'xu-bind-refresh.' + _dsP.toString();
|
|
17131
|
+
const bind_refresh_namespace = `.ui${bind_ui_id || bind_field_id || 'bind'}`;
|
|
17132
|
+
$('body').off(bind_refresh_namespace).on(bind_refresh_event + bind_refresh_namespace, async () => {
|
|
17133
|
+
await set_value();
|
|
16806
17134
|
});
|
|
16807
17135
|
|
|
16808
|
-
set_value();
|
|
17136
|
+
await set_value();
|
|
16809
17137
|
return {};
|
|
16810
17138
|
};
|
|
16811
17139
|
func.runtime.render.apply_xu_class = async function (options) {
|
|
@@ -17117,7 +17445,11 @@ func.runtime.render.handle_modern_xu_render = async function (options) {
|
|
|
17117
17445
|
};
|
|
17118
17446
|
|
|
17119
17447
|
const post_render = async function () {
|
|
17120
|
-
const
|
|
17448
|
+
const container_data = func.runtime.ui.get_data(options.$container);
|
|
17449
|
+
if (!container_data?.xuData?.node?.children?.[options.keyP]) {
|
|
17450
|
+
return;
|
|
17451
|
+
}
|
|
17452
|
+
const nodeP = container_data.xuData.node.children[options.keyP];
|
|
17121
17453
|
nodeP.xu_render_made = value;
|
|
17122
17454
|
if (value) {
|
|
17123
17455
|
try {
|
|
@@ -17163,12 +17495,23 @@ func.runtime.render.handle_modern_xu_render = async function (options) {
|
|
|
17163
17495
|
}
|
|
17164
17496
|
|
|
17165
17497
|
func.runtime.render.insert_ordered_child(options.$container, new_$div, options.keyP);
|
|
17498
|
+
// Remove the XURENDER placeholder now that the real content has been inserted.
|
|
17499
|
+
if (options.$elm?.[0]?.tagName === 'XURENDER') {
|
|
17500
|
+
func.runtime.ui.remove(options.$elm);
|
|
17501
|
+
}
|
|
17166
17502
|
} catch (error) {
|
|
17167
17503
|
func.events.delete_job(options.SESSION_ID, options.jobNoP);
|
|
17168
17504
|
}
|
|
17169
17505
|
return;
|
|
17170
17506
|
}
|
|
17171
17507
|
|
|
17508
|
+
// Cancel any in-flight child jobs before removing the element.
|
|
17509
|
+
// This prevents orphaned jobs (e.g. a child panel's long-running on_load delay)
|
|
17510
|
+
// from blocking future scheduler passes after the parent element is gone.
|
|
17511
|
+
if (func.UI?.worker?.cancel_child_in_flight_jobs) {
|
|
17512
|
+
func.UI.worker.cancel_child_in_flight_jobs(options.$elm);
|
|
17513
|
+
}
|
|
17514
|
+
|
|
17172
17515
|
const xu_ui_id = func.runtime.ui.get_attr(options.$elm, 'xu-ui-id');
|
|
17173
17516
|
const exclude_fields = func.runtime.render.get_xu_render_exclude_fields(options.$elm);
|
|
17174
17517
|
const cache_str = await func.runtime.render.get_xu_render_cache_str(
|