@yuneta/gobj-ui 2.2.5 → 2.3.0
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/README.md +31 -1
- package/dist/gobj-ui.cjs.js +695 -1023
- package/dist/gobj-ui.es.js +696 -1024
- package/package.json +1 -1
- package/src/c_yui_form.js +322 -51
- package/src/c_yui_map.js +7 -4
- package/src/c_yui_nav.js +90 -1
- package/src/c_yui_shell.css +68 -2
- package/src/c_yui_shell.js +103 -18
- package/src/c_yui_treedb_topic_with_form.js +201 -1170
- package/src/nav_cards_helpers.js +71 -0
- package/src/nav_cards_helpers.test.js +122 -0
- package/src/shell_section_index.js +106 -0
- package/src/shell_section_index.test.js +151 -0
package/dist/gobj-ui.cjs.js
CHANGED
|
@@ -36,13 +36,13 @@ let i18next = require("i18next");
|
|
|
36
36
|
i18next = __toESM(i18next, 1);
|
|
37
37
|
let tom_select = require("tom-select");
|
|
38
38
|
tom_select = __toESM(tom_select, 1);
|
|
39
|
+
let vanilla_jsoneditor = require("vanilla-jsoneditor");
|
|
39
40
|
let tabulator_tables = require("tabulator-tables");
|
|
40
41
|
let maplibre_gl = require("maplibre-gl");
|
|
41
42
|
maplibre_gl = __toESM(maplibre_gl, 1);
|
|
42
43
|
let uplot = require("uplot");
|
|
43
44
|
uplot = __toESM(uplot, 1);
|
|
44
45
|
let _antv_g6 = require("@antv/g6");
|
|
45
|
-
let vanilla_jsoneditor = require("vanilla-jsoneditor");
|
|
46
46
|
//#region src/yui_dev.js
|
|
47
47
|
/***********************************************************************
|
|
48
48
|
* ui_dev.js
|
|
@@ -5399,6 +5399,10 @@ var attrs_table$11 = [
|
|
|
5399
5399
|
(0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_POINTER, "template", 0, "<div>You must supply a template for form</div>", "Template for form, object -> TEMPLATE, array -> DESC"),
|
|
5400
5400
|
(0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_JSON, "record", 0, "{}", "Data to form"),
|
|
5401
5401
|
(0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_JSON, "placeholders", 0, "{}", "Placeholder values for form fields"),
|
|
5402
|
+
(0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_JSON, "fkey_options", 0, "{}", "Options for fkey fields: {topic_name: [ids or {id} records]}, read at build time"),
|
|
5403
|
+
(0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_STRING, "form_mode", 0, "", "'create' (pkey editable+required) or 'update' (pkey readonly); empty = no pkey handling"),
|
|
5404
|
+
(0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_STRING, "pkey", 0, "id", "Primary key field name, used by form_mode"),
|
|
5405
|
+
(0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_STRING, "topic_name", 0, "", "Treedb topic name: labels use the i18n cascade '<topic>.<col>' -> '<col>' -> header (like table headers)"),
|
|
5402
5406
|
(0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_BOOLEAN, "editable", 0, false, "Default is editable, set false to readonly"),
|
|
5403
5407
|
(0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_BOOLEAN, "selectable", 0, true, "Rows selectable with 'click' (BAD with editable=true)"),
|
|
5404
5408
|
(0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_BOOLEAN, "with_checkbox", 0, false, "Show a first column with checkbox to select rows"),
|
|
@@ -5520,34 +5524,35 @@ function build_ui$9(gobj) {
|
|
|
5520
5524
|
let $container = (0, _yuneta_gobj_js.createElement2)([
|
|
5521
5525
|
"div",
|
|
5522
5526
|
{
|
|
5523
|
-
class: "C_YUI_FORM is-flex is-flex-direction-
|
|
5527
|
+
class: "C_YUI_FORM is-flex is-flex-direction-column overscroll-contain",
|
|
5524
5528
|
style: "height:100%; width:100%; box-sizing:border-box;"
|
|
5525
5529
|
},
|
|
5526
5530
|
[[
|
|
5527
5531
|
"div",
|
|
5528
5532
|
{
|
|
5529
5533
|
class: "yui-form is-flex-grow-1 p-2",
|
|
5530
|
-
style: "overflow-y:auto;
|
|
5534
|
+
style: "overflow-y:auto; min-height:0;"
|
|
5531
5535
|
},
|
|
5532
5536
|
build_form(gobj)
|
|
5533
5537
|
], [
|
|
5534
5538
|
"div",
|
|
5535
5539
|
{
|
|
5536
|
-
class: "yui-toolbar-form
|
|
5537
|
-
style: "
|
|
5540
|
+
class: "yui-toolbar-form is-flex-shrink-0 is-flex is-flex-direction-row is-justify-content-space-between is-align-items-center",
|
|
5541
|
+
style: "width:100%; flex-wrap:wrap; row-gap:6px;"
|
|
5538
5542
|
},
|
|
5539
5543
|
[[
|
|
5540
5544
|
"div",
|
|
5541
5545
|
{
|
|
5542
|
-
class: "p-1 is-flex is-flex-direction-
|
|
5543
|
-
style: "
|
|
5546
|
+
class: "p-1 is-flex is-flex-direction-row is-align-items-center",
|
|
5547
|
+
style: "column-gap:6px;"
|
|
5544
5548
|
},
|
|
5545
5549
|
[
|
|
5546
5550
|
[
|
|
5547
5551
|
"button",
|
|
5548
5552
|
{
|
|
5549
|
-
class: "button p-1
|
|
5550
|
-
|
|
5553
|
+
class: "button p-1 button-save",
|
|
5554
|
+
title: "save",
|
|
5555
|
+
"aria-label": "save",
|
|
5551
5556
|
disabled: true
|
|
5552
5557
|
},
|
|
5553
5558
|
[[
|
|
@@ -5557,7 +5562,7 @@ function build_ui$9(gobj) {
|
|
|
5557
5562
|
], [
|
|
5558
5563
|
"span",
|
|
5559
5564
|
{
|
|
5560
|
-
class: "is-hidden-mobile",
|
|
5565
|
+
class: "is-hidden-mobile pl-1 pr-1",
|
|
5561
5566
|
i18n: "save"
|
|
5562
5567
|
},
|
|
5563
5568
|
"save"
|
|
@@ -5570,8 +5575,9 @@ function build_ui$9(gobj) {
|
|
|
5570
5575
|
[
|
|
5571
5576
|
"button",
|
|
5572
5577
|
{
|
|
5573
|
-
class: "button p-1
|
|
5574
|
-
|
|
5578
|
+
class: "button p-1 button-undo",
|
|
5579
|
+
title: "undo",
|
|
5580
|
+
"aria-label": "undo",
|
|
5575
5581
|
disabled: true
|
|
5576
5582
|
},
|
|
5577
5583
|
[[
|
|
@@ -5581,7 +5587,7 @@ function build_ui$9(gobj) {
|
|
|
5581
5587
|
], [
|
|
5582
5588
|
"span",
|
|
5583
5589
|
{
|
|
5584
|
-
class: "is-hidden-mobile",
|
|
5590
|
+
class: "is-hidden-mobile pl-1 pr-1",
|
|
5585
5591
|
i18n: "undo"
|
|
5586
5592
|
},
|
|
5587
5593
|
"undo"
|
|
@@ -5594,8 +5600,9 @@ function build_ui$9(gobj) {
|
|
|
5594
5600
|
[
|
|
5595
5601
|
"button",
|
|
5596
5602
|
{
|
|
5597
|
-
class: "button p-1
|
|
5598
|
-
|
|
5603
|
+
class: "button p-1",
|
|
5604
|
+
title: "clear",
|
|
5605
|
+
"aria-label": "clear"
|
|
5599
5606
|
},
|
|
5600
5607
|
[[
|
|
5601
5608
|
"span",
|
|
@@ -5604,7 +5611,7 @@ function build_ui$9(gobj) {
|
|
|
5604
5611
|
], [
|
|
5605
5612
|
"span",
|
|
5606
5613
|
{
|
|
5607
|
-
class: "is-hidden-mobile",
|
|
5614
|
+
class: "is-hidden-mobile pl-1 pr-1",
|
|
5608
5615
|
i18n: "clear"
|
|
5609
5616
|
},
|
|
5610
5617
|
"clear"
|
|
@@ -5618,14 +5625,15 @@ function build_ui$9(gobj) {
|
|
|
5618
5625
|
], [
|
|
5619
5626
|
"div",
|
|
5620
5627
|
{
|
|
5621
|
-
class: "p-1 is-flex is-flex-direction-
|
|
5622
|
-
style: "
|
|
5628
|
+
class: "p-1 is-flex is-flex-direction-row is-align-items-center",
|
|
5629
|
+
style: "column-gap:6px;"
|
|
5623
5630
|
},
|
|
5624
5631
|
[[
|
|
5625
5632
|
"button",
|
|
5626
5633
|
{
|
|
5627
|
-
class: "button p-1
|
|
5628
|
-
|
|
5634
|
+
class: "button p-1",
|
|
5635
|
+
title: "copy",
|
|
5636
|
+
"aria-label": "copy"
|
|
5629
5637
|
},
|
|
5630
5638
|
[[
|
|
5631
5639
|
"span",
|
|
@@ -5634,7 +5642,7 @@ function build_ui$9(gobj) {
|
|
|
5634
5642
|
], [
|
|
5635
5643
|
"span",
|
|
5636
5644
|
{
|
|
5637
|
-
class: "is-hidden-mobile",
|
|
5645
|
+
class: "is-hidden-mobile pl-1 pr-1",
|
|
5638
5646
|
i18n: "copy"
|
|
5639
5647
|
},
|
|
5640
5648
|
"copy"
|
|
@@ -5646,8 +5654,9 @@ function build_ui$9(gobj) {
|
|
|
5646
5654
|
], [
|
|
5647
5655
|
"button",
|
|
5648
5656
|
{
|
|
5649
|
-
class: "button p-1
|
|
5650
|
-
|
|
5657
|
+
class: "button p-1",
|
|
5658
|
+
title: "paste",
|
|
5659
|
+
"aria-label": "paste"
|
|
5651
5660
|
},
|
|
5652
5661
|
[[
|
|
5653
5662
|
"span",
|
|
@@ -5656,7 +5665,7 @@ function build_ui$9(gobj) {
|
|
|
5656
5665
|
], [
|
|
5657
5666
|
"span",
|
|
5658
5667
|
{
|
|
5659
|
-
class: "is-hidden-mobile",
|
|
5668
|
+
class: "is-hidden-mobile pl-1 pr-1",
|
|
5660
5669
|
i18n: "paste"
|
|
5661
5670
|
},
|
|
5662
5671
|
"paste"
|
|
@@ -5670,6 +5679,7 @@ function build_ui$9(gobj) {
|
|
|
5670
5679
|
]]
|
|
5671
5680
|
]);
|
|
5672
5681
|
(0, _yuneta_gobj_js.gobj_write_attr)(gobj, "$container", $container);
|
|
5682
|
+
apply_form_mode(gobj, $container.querySelector("form"));
|
|
5673
5683
|
(0, _yuneta_gobj_js.refresh_language)($container, i18next.t);
|
|
5674
5684
|
let $parent = (0, _yuneta_gobj_js.gobj_read_attr)(gobj, "$parent");
|
|
5675
5685
|
if ($parent) $parent.appendChild($container);
|
|
@@ -5712,7 +5722,11 @@ function build_html_form(gobj, $form, prefix, template) {
|
|
|
5712
5722
|
const field_desc = (0, _yuneta_gobj_js.template_get_field_desc)(key, value);
|
|
5713
5723
|
let html_field_conf = build_form_field_conf(gobj, field_desc);
|
|
5714
5724
|
html_field_conf.name = field_desc.name;
|
|
5715
|
-
|
|
5725
|
+
let topic_name = (0, _yuneta_gobj_js.gobj_read_str_attr)(gobj, "topic_name");
|
|
5726
|
+
let label_keys = topic_name ? [topic_name + "." + field_desc.name, field_desc.name] : [field_desc.name];
|
|
5727
|
+
const NO_I18N = "\0";
|
|
5728
|
+
html_field_conf.label = (0, i18next.t)(label_keys, { defaultValue: field_desc.header });
|
|
5729
|
+
html_field_conf.label_i18n = (0, i18next.t)(field_desc.name, { defaultValue: NO_I18N }) !== NO_I18N ? field_desc.name : null;
|
|
5716
5730
|
html_field_conf.placeholder = field_desc.placeholder ? (0, i18next.t)(field_desc.placeholder) : "";
|
|
5717
5731
|
let placeholders = (0, _yuneta_gobj_js.gobj_read_attr)(gobj, "placeholders");
|
|
5718
5732
|
if (placeholders[key]) html_field_conf.placeholder = placeholders[key];
|
|
@@ -5756,7 +5770,7 @@ function build_form_field_conf(gobj, field_desc) {
|
|
|
5756
5770
|
switch (field_desc.type) {
|
|
5757
5771
|
case "object":
|
|
5758
5772
|
case "dict":
|
|
5759
|
-
field_conf.tag = "
|
|
5773
|
+
field_conf.tag = "jsoneditor";
|
|
5760
5774
|
break;
|
|
5761
5775
|
case "template":
|
|
5762
5776
|
field_conf.tag = "fieldset";
|
|
@@ -5771,7 +5785,7 @@ function build_form_field_conf(gobj, field_desc) {
|
|
|
5771
5785
|
break;
|
|
5772
5786
|
case "array":
|
|
5773
5787
|
case "list":
|
|
5774
|
-
field_conf.tag = "
|
|
5788
|
+
field_conf.tag = "jsoneditor";
|
|
5775
5789
|
break;
|
|
5776
5790
|
case "enum":
|
|
5777
5791
|
switch (field_desc.real_type) {
|
|
@@ -5789,7 +5803,10 @@ function build_form_field_conf(gobj, field_desc) {
|
|
|
5789
5803
|
}
|
|
5790
5804
|
break;
|
|
5791
5805
|
case "hook": break;
|
|
5792
|
-
case "fkey":
|
|
5806
|
+
case "fkey":
|
|
5807
|
+
field_conf.tag = "select2";
|
|
5808
|
+
field_conf.options = get_fkey_select_options(gobj, field_desc);
|
|
5809
|
+
break;
|
|
5793
5810
|
case "image":
|
|
5794
5811
|
case "string":
|
|
5795
5812
|
field_conf.tag = "input";
|
|
@@ -5874,6 +5891,112 @@ function build_form_field_conf(gobj, field_desc) {
|
|
|
5874
5891
|
}
|
|
5875
5892
|
return field_conf;
|
|
5876
5893
|
}
|
|
5894
|
+
/************************************************************
|
|
5895
|
+
* Options for a fkey field: the ids of the parent topic's
|
|
5896
|
+
* rows, taken from the `fkey_options` attr
|
|
5897
|
+
* ({topic_name: [ids or {id} records]}, supplied by the host —
|
|
5898
|
+
* the form never queries the backend or its parent itself).
|
|
5899
|
+
* Read at build time.
|
|
5900
|
+
************************************************************/
|
|
5901
|
+
function get_fkey_select_options(gobj, field_desc) {
|
|
5902
|
+
let fkey_desc = field_desc.fkey;
|
|
5903
|
+
if (!(0, _yuneta_gobj_js.is_object)(fkey_desc) || Object.keys(fkey_desc).length === 0) {
|
|
5904
|
+
(0, _yuneta_gobj_js.log_error)((0, _yuneta_gobj_js.sprintf)("%s: fkey field '%s' without fkey mapping", (0, _yuneta_gobj_js.gobj_short_name)(gobj), field_desc.name));
|
|
5905
|
+
return [];
|
|
5906
|
+
}
|
|
5907
|
+
let topic_name = Object.keys(fkey_desc)[0];
|
|
5908
|
+
let fkey_options = (0, _yuneta_gobj_js.gobj_read_attr)(gobj, "fkey_options");
|
|
5909
|
+
let list = (0, _yuneta_gobj_js.is_object)(fkey_options) ? fkey_options[topic_name] : null;
|
|
5910
|
+
if (!(0, _yuneta_gobj_js.is_array)(list)) {
|
|
5911
|
+
(0, _yuneta_gobj_js.log_warning)((0, _yuneta_gobj_js.sprintf)("%s: no fkey_options for topic '%s' (field '%s')", (0, _yuneta_gobj_js.gobj_short_name)(gobj), topic_name, field_desc.name));
|
|
5912
|
+
return [];
|
|
5913
|
+
}
|
|
5914
|
+
let options = [];
|
|
5915
|
+
for (let item of list) {
|
|
5916
|
+
let id = (0, _yuneta_gobj_js.is_object)(item) ? item.id : item;
|
|
5917
|
+
if ((0, _yuneta_gobj_js.is_string)(id) && !(0, _yuneta_gobj_js.empty_string)(id)) options.push(id);
|
|
5918
|
+
}
|
|
5919
|
+
return options;
|
|
5920
|
+
}
|
|
5921
|
+
/************************************************************
|
|
5922
|
+
* Encode the select2 value (array of ids) into fkey ref(s)
|
|
5923
|
+
* "topic_name^id^hook_name", shaped by the column real type:
|
|
5924
|
+
* string -> single ref (or null if no selection)
|
|
5925
|
+
* object/dict -> {ref: true, ...}
|
|
5926
|
+
* array/list -> [ref, ...]
|
|
5927
|
+
************************************************************/
|
|
5928
|
+
function build_fkey_ref$1(gobj, field_desc, value) {
|
|
5929
|
+
let fkey_desc = field_desc.fkey;
|
|
5930
|
+
if (!(0, _yuneta_gobj_js.is_object)(fkey_desc) || Object.keys(fkey_desc).length === 0) {
|
|
5931
|
+
(0, _yuneta_gobj_js.log_error)((0, _yuneta_gobj_js.sprintf)("%s: fkey field '%s' without fkey mapping", (0, _yuneta_gobj_js.gobj_short_name)(gobj), field_desc.name));
|
|
5932
|
+
return null;
|
|
5933
|
+
}
|
|
5934
|
+
let topic_name = Object.keys(fkey_desc)[0];
|
|
5935
|
+
let hook_name = fkey_desc[topic_name];
|
|
5936
|
+
let refs;
|
|
5937
|
+
switch (field_desc.real_type) {
|
|
5938
|
+
case "string":
|
|
5939
|
+
refs = null;
|
|
5940
|
+
break;
|
|
5941
|
+
case "object":
|
|
5942
|
+
case "dict":
|
|
5943
|
+
refs = {};
|
|
5944
|
+
break;
|
|
5945
|
+
case "array":
|
|
5946
|
+
case "list":
|
|
5947
|
+
refs = [];
|
|
5948
|
+
break;
|
|
5949
|
+
default:
|
|
5950
|
+
(0, _yuneta_gobj_js.log_error)((0, _yuneta_gobj_js.sprintf)("%s: fkey field '%s' with bad real_type '%s'", (0, _yuneta_gobj_js.gobj_short_name)(gobj), field_desc.name, field_desc.real_type));
|
|
5951
|
+
return null;
|
|
5952
|
+
}
|
|
5953
|
+
if (!(0, _yuneta_gobj_js.is_array)(value)) value = value ? [value] : [];
|
|
5954
|
+
for (let v of value) {
|
|
5955
|
+
let id = (0, _yuneta_gobj_js.is_object)(v) ? v.id : v;
|
|
5956
|
+
if (!(0, _yuneta_gobj_js.is_string)(id) || (0, _yuneta_gobj_js.empty_string)(id)) {
|
|
5957
|
+
(0, _yuneta_gobj_js.log_error)((0, _yuneta_gobj_js.sprintf)("%s: fkey field '%s' with bad value: %s", (0, _yuneta_gobj_js.gobj_short_name)(gobj), field_desc.name, JSON.stringify(v)));
|
|
5958
|
+
continue;
|
|
5959
|
+
}
|
|
5960
|
+
let ref = topic_name + "^" + id + "^" + hook_name;
|
|
5961
|
+
switch (field_desc.real_type) {
|
|
5962
|
+
case "string": return ref;
|
|
5963
|
+
case "object":
|
|
5964
|
+
case "dict":
|
|
5965
|
+
refs[ref] = true;
|
|
5966
|
+
break;
|
|
5967
|
+
case "array":
|
|
5968
|
+
case "list":
|
|
5969
|
+
refs.push(ref);
|
|
5970
|
+
break;
|
|
5971
|
+
}
|
|
5972
|
+
}
|
|
5973
|
+
return refs;
|
|
5974
|
+
}
|
|
5975
|
+
/************************************************************
|
|
5976
|
+
* Apply the form mode to the pkey field:
|
|
5977
|
+
* "update" -> pkey readonly, not required
|
|
5978
|
+
* "create" -> pkey writable and required (readonly if rowid)
|
|
5979
|
+
* Empty form_mode keeps the template-declared behaviour
|
|
5980
|
+
* (backward compatible).
|
|
5981
|
+
************************************************************/
|
|
5982
|
+
function apply_form_mode(gobj, $form) {
|
|
5983
|
+
let mode = (0, _yuneta_gobj_js.gobj_read_str_attr)(gobj, "form_mode");
|
|
5984
|
+
if ((0, _yuneta_gobj_js.empty_string)(mode)) return;
|
|
5985
|
+
let pkey = (0, _yuneta_gobj_js.gobj_read_str_attr)(gobj, "pkey");
|
|
5986
|
+
let $input = $form.querySelector(`[name="${pkey}"]`);
|
|
5987
|
+
if (!$input) {
|
|
5988
|
+
(0, _yuneta_gobj_js.log_error)((0, _yuneta_gobj_js.sprintf)("%s: form_mode '%s' but form has no pkey field '%s'", (0, _yuneta_gobj_js.gobj_short_name)(gobj), mode, pkey));
|
|
5989
|
+
return;
|
|
5990
|
+
}
|
|
5991
|
+
let is_rowid = $input.field_desc && $input.field_desc.type === "rowid";
|
|
5992
|
+
if (mode === "create" && !is_rowid) {
|
|
5993
|
+
$input.removeAttribute("readonly");
|
|
5994
|
+
$input.setAttribute("required", "");
|
|
5995
|
+
} else {
|
|
5996
|
+
$input.setAttribute("readonly", "readonly");
|
|
5997
|
+
$input.removeAttribute("required");
|
|
5998
|
+
}
|
|
5999
|
+
}
|
|
5877
6000
|
/******************************************************************
|
|
5878
6001
|
* With html field conf builds an html element,
|
|
5879
6002
|
* ready to add to the form
|
|
@@ -5904,7 +6027,7 @@ function build_form_field_conf(gobj, field_desc) {
|
|
|
5904
6027
|
* default_value:
|
|
5905
6028
|
* }
|
|
5906
6029
|
******************************************************************/
|
|
5907
|
-
function create_form_field(gobj, $form, prefix, field_desc, { tag, inputType, name, label, placeholder, options, extras, readonly, required, hidden, default_value }) {
|
|
6030
|
+
function create_form_field(gobj, $form, prefix, field_desc, { tag, inputType, name, label, label_i18n, placeholder, options, extras, readonly, required, hidden, default_value }) {
|
|
5908
6031
|
let $element;
|
|
5909
6032
|
let kw_add_table_row = {
|
|
5910
6033
|
$row: null,
|
|
@@ -5926,7 +6049,7 @@ function create_form_field(gobj, $form, prefix, field_desc, { tag, inputType, na
|
|
|
5926
6049
|
"label",
|
|
5927
6050
|
{
|
|
5928
6051
|
class: "label ",
|
|
5929
|
-
i18n: label,
|
|
6052
|
+
i18n: label_i18n || label,
|
|
5930
6053
|
for: name
|
|
5931
6054
|
},
|
|
5932
6055
|
label
|
|
@@ -5960,7 +6083,7 @@ function create_form_field(gobj, $form, prefix, field_desc, { tag, inputType, na
|
|
|
5960
6083
|
"label",
|
|
5961
6084
|
{
|
|
5962
6085
|
class: "label ",
|
|
5963
|
-
i18n: label,
|
|
6086
|
+
i18n: label_i18n || label,
|
|
5964
6087
|
for: name
|
|
5965
6088
|
},
|
|
5966
6089
|
label
|
|
@@ -6002,7 +6125,7 @@ function create_form_field(gobj, $form, prefix, field_desc, { tag, inputType, na
|
|
|
6002
6125
|
"label",
|
|
6003
6126
|
{
|
|
6004
6127
|
class: "label ",
|
|
6005
|
-
i18n: label,
|
|
6128
|
+
i18n: label_i18n || label,
|
|
6006
6129
|
for: name
|
|
6007
6130
|
},
|
|
6008
6131
|
label
|
|
@@ -6033,7 +6156,7 @@ function create_form_field(gobj, $form, prefix, field_desc, { tag, inputType, na
|
|
|
6033
6156
|
"label",
|
|
6034
6157
|
{
|
|
6035
6158
|
class: "label ",
|
|
6036
|
-
i18n: label,
|
|
6159
|
+
i18n: label_i18n || label,
|
|
6037
6160
|
for: name
|
|
6038
6161
|
},
|
|
6039
6162
|
label
|
|
@@ -6064,7 +6187,7 @@ function create_form_field(gobj, $form, prefix, field_desc, { tag, inputType, na
|
|
|
6064
6187
|
"label",
|
|
6065
6188
|
{
|
|
6066
6189
|
class: "label",
|
|
6067
|
-
i18n: label
|
|
6190
|
+
i18n: label_i18n || label
|
|
6068
6191
|
},
|
|
6069
6192
|
label
|
|
6070
6193
|
]]
|
|
@@ -6148,7 +6271,7 @@ function create_form_field(gobj, $form, prefix, field_desc, { tag, inputType, na
|
|
|
6148
6271
|
"label",
|
|
6149
6272
|
{
|
|
6150
6273
|
class: "label ",
|
|
6151
|
-
i18n: label,
|
|
6274
|
+
i18n: label_i18n || label,
|
|
6152
6275
|
for: name
|
|
6153
6276
|
},
|
|
6154
6277
|
label
|
|
@@ -6174,7 +6297,7 @@ function create_form_field(gobj, $form, prefix, field_desc, { tag, inputType, na
|
|
|
6174
6297
|
switch (tag) {
|
|
6175
6298
|
case "input": {
|
|
6176
6299
|
let attrs = {
|
|
6177
|
-
class: `input ${name === "
|
|
6300
|
+
class: `input ${name === (0, _yuneta_gobj_js.gobj_read_str_attr)(gobj, "pkey") ? "with-focus" : ""}`,
|
|
6178
6301
|
name,
|
|
6179
6302
|
type: inputType,
|
|
6180
6303
|
placeholder
|
|
@@ -6227,8 +6350,8 @@ function create_form_field(gobj, $form, prefix, field_desc, { tag, inputType, na
|
|
|
6227
6350
|
$control.appendChild($extend);
|
|
6228
6351
|
break;
|
|
6229
6352
|
}
|
|
6230
|
-
case "select":
|
|
6231
|
-
$
|
|
6353
|
+
case "select": {
|
|
6354
|
+
let $wrapper = (0, _yuneta_gobj_js.createElement2)([
|
|
6232
6355
|
"div",
|
|
6233
6356
|
{ class: "select" },
|
|
6234
6357
|
[
|
|
@@ -6241,11 +6364,16 @@ function create_form_field(gobj, $form, prefix, field_desc, { tag, inputType, na
|
|
|
6241
6364
|
i18n: option
|
|
6242
6365
|
},
|
|
6243
6366
|
option
|
|
6244
|
-
])
|
|
6367
|
+
]),
|
|
6368
|
+
{ "change": function(evt) {
|
|
6369
|
+
(0, _yuneta_gobj_js.gobj_send_event)(gobj, "EV_RECORD_CHANGED", {}, gobj);
|
|
6370
|
+
} }
|
|
6245
6371
|
]
|
|
6246
6372
|
]);
|
|
6247
|
-
$control.appendChild($
|
|
6373
|
+
$control.appendChild($wrapper);
|
|
6374
|
+
$extend = $wrapper.querySelector("select");
|
|
6248
6375
|
break;
|
|
6376
|
+
}
|
|
6249
6377
|
case "select2":
|
|
6250
6378
|
$extend = (0, _yuneta_gobj_js.createElement2)([
|
|
6251
6379
|
"select",
|
|
@@ -6267,6 +6395,7 @@ function create_form_field(gobj, $form, prefix, field_desc, { tag, inputType, na
|
|
|
6267
6395
|
$extend.tom_select = new tom_select.default($extend, {
|
|
6268
6396
|
allowEmptyOption: true,
|
|
6269
6397
|
placeholder,
|
|
6398
|
+
maxItems: field_desc.type === "fkey" && field_desc.real_type === "string" ? 1 : null,
|
|
6270
6399
|
plugins: {
|
|
6271
6400
|
"clear_button": { "title": (0, i18next.t)("Remove all selected options") },
|
|
6272
6401
|
"no_active_items": {},
|
|
@@ -6278,17 +6407,26 @@ function create_form_field(gobj, $form, prefix, field_desc, { tag, inputType, na
|
|
|
6278
6407
|
(0, _yuneta_gobj_js.gobj_send_event)(gobj, "EV_RECORD_CHANGED", {}, gobj);
|
|
6279
6408
|
});
|
|
6280
6409
|
break;
|
|
6281
|
-
case "checkbox":
|
|
6282
|
-
$
|
|
6410
|
+
case "checkbox": {
|
|
6411
|
+
let $wrapper = (0, _yuneta_gobj_js.createElement2)([
|
|
6283
6412
|
"label",
|
|
6284
6413
|
{ class: "checkbox" },
|
|
6285
|
-
[
|
|
6286
|
-
|
|
6287
|
-
|
|
6288
|
-
|
|
6414
|
+
[
|
|
6415
|
+
"input",
|
|
6416
|
+
{
|
|
6417
|
+
type: "checkbox",
|
|
6418
|
+
name
|
|
6419
|
+
},
|
|
6420
|
+
"",
|
|
6421
|
+
{ "change": function(evt) {
|
|
6422
|
+
(0, _yuneta_gobj_js.gobj_send_event)(gobj, "EV_RECORD_CHANGED", {}, gobj);
|
|
6423
|
+
} }
|
|
6424
|
+
]
|
|
6289
6425
|
]);
|
|
6290
|
-
$control.appendChild($
|
|
6426
|
+
$control.appendChild($wrapper);
|
|
6427
|
+
$extend = $wrapper.querySelector("input");
|
|
6291
6428
|
break;
|
|
6429
|
+
}
|
|
6292
6430
|
case "radio":
|
|
6293
6431
|
$extend = (0, _yuneta_gobj_js.createOneHtml)(`
|
|
6294
6432
|
<label class="radio">
|
|
@@ -6301,6 +6439,7 @@ function create_form_field(gobj, $form, prefix, field_desc, { tag, inputType, na
|
|
|
6301
6439
|
case "jsoneditor": {
|
|
6302
6440
|
let attrs = {
|
|
6303
6441
|
class: "jsoneditor jse-theme-dark",
|
|
6442
|
+
name,
|
|
6304
6443
|
style: ""
|
|
6305
6444
|
};
|
|
6306
6445
|
Object.assign(attrs, extras);
|
|
@@ -6308,6 +6447,18 @@ function create_form_field(gobj, $form, prefix, field_desc, { tag, inputType, na
|
|
|
6308
6447
|
else if (required) attrs.required = "";
|
|
6309
6448
|
$extend = (0, _yuneta_gobj_js.createElement2)(["div", attrs]);
|
|
6310
6449
|
$control.appendChild($extend);
|
|
6450
|
+
$extend.jsoneditor = new vanilla_jsoneditor.JSONEditor({
|
|
6451
|
+
target: $extend,
|
|
6452
|
+
props: {
|
|
6453
|
+
readOnly: !!readonly,
|
|
6454
|
+
onChange: function() {
|
|
6455
|
+
(0, _yuneta_gobj_js.gobj_send_event)(gobj, "EV_RECORD_CHANGED", {}, gobj);
|
|
6456
|
+
},
|
|
6457
|
+
timestampTag: function({ field, value, path }) {
|
|
6458
|
+
return field === "__t__" || field === "__tm__" || field === "tm" || field === "t" || field === "time" || field === "from_t" || field === "to_t" || field === "t_input" || field === "t_output" || field === "from_tm" || field === "to_tm";
|
|
6459
|
+
}
|
|
6460
|
+
}
|
|
6461
|
+
});
|
|
6311
6462
|
break;
|
|
6312
6463
|
}
|
|
6313
6464
|
case "fieldset": {
|
|
@@ -6703,7 +6854,7 @@ function template2columns(gobj, columns, template, sub_elements) {
|
|
|
6703
6854
|
/************************************************************
|
|
6704
6855
|
*
|
|
6705
6856
|
************************************************************/
|
|
6706
|
-
function validate_form
|
|
6857
|
+
function validate_form(gobj, $form) {
|
|
6707
6858
|
let validated = true;
|
|
6708
6859
|
if (!$form.checkValidity()) validated = false;
|
|
6709
6860
|
$form.querySelectorAll(".yui-tabulator-table").forEach(($table) => {
|
|
@@ -6724,7 +6875,7 @@ function getInputValue($input) {
|
|
|
6724
6875
|
/************************************************************
|
|
6725
6876
|
* Function to get input value based on its type
|
|
6726
6877
|
************************************************************/
|
|
6727
|
-
function get_form_values
|
|
6878
|
+
function get_form_values(gobj, $form) {
|
|
6728
6879
|
const record = {};
|
|
6729
6880
|
$form.querySelectorAll(".yui-form-data-input").forEach(($input) => {
|
|
6730
6881
|
$input.closest(".xfield");
|
|
@@ -6805,9 +6956,10 @@ function get_form_values$1(gobj, $form) {
|
|
|
6805
6956
|
/************************************************************
|
|
6806
6957
|
*
|
|
6807
6958
|
************************************************************/
|
|
6808
|
-
function clear_data
|
|
6959
|
+
function clear_data(gobj, $form) {
|
|
6960
|
+
let pkey = (0, _yuneta_gobj_js.gobj_read_str_attr)(gobj, "pkey");
|
|
6809
6961
|
$form.querySelectorAll("input, select, textarea, .jsoneditor").forEach(($input) => {
|
|
6810
|
-
if ($input.name !==
|
|
6962
|
+
if ($input.name !== pkey) if ($input.classList.contains("jsoneditor")) {
|
|
6811
6963
|
let jsoneditor = $input.jsoneditor;
|
|
6812
6964
|
if (jsoneditor) jsoneditor.set({ text: "" });
|
|
6813
6965
|
} else if ($input.type === "checkbox") $input.checked = false;
|
|
@@ -6826,7 +6978,7 @@ function clear_data$1(gobj, $form) {
|
|
|
6826
6978
|
/************************************************************
|
|
6827
6979
|
*
|
|
6828
6980
|
************************************************************/
|
|
6829
|
-
function clear_validation
|
|
6981
|
+
function clear_validation(gobj, $form) {
|
|
6830
6982
|
$form.querySelectorAll("input").forEach(($input) => {
|
|
6831
6983
|
$input.classList.remove("is-danger");
|
|
6832
6984
|
});
|
|
@@ -6864,10 +7016,10 @@ function convertColor(color) {
|
|
|
6864
7016
|
/************************************************************
|
|
6865
7017
|
*
|
|
6866
7018
|
************************************************************/
|
|
6867
|
-
function set_form_values
|
|
7019
|
+
function set_form_values(gobj, template, $form, record) {
|
|
6868
7020
|
let modified = false;
|
|
6869
|
-
clear_data
|
|
6870
|
-
if (!record || record.length === 0) record = (0, _yuneta_gobj_js.create_template_record)(template);
|
|
7021
|
+
clear_data(gobj, $form);
|
|
7022
|
+
if (!record || Object.keys(record).length === 0) record = (0, _yuneta_gobj_js.create_template_record)(template);
|
|
6871
7023
|
$form.querySelectorAll(".yui-form-data-input").forEach(($input) => {
|
|
6872
7024
|
let field_desc = $input.field_desc;
|
|
6873
7025
|
let name = $input.dataset.treedb_name;
|
|
@@ -6883,10 +7035,16 @@ function set_form_values$1(gobj, template, $form, record) {
|
|
|
6883
7035
|
modified = true;
|
|
6884
7036
|
}
|
|
6885
7037
|
value = treedb_value_2_form_value(gobj, field_desc, value);
|
|
7038
|
+
if (value === void 0) value = null;
|
|
6886
7039
|
switch (tag) {
|
|
6887
7040
|
case "input":
|
|
6888
7041
|
switch (input_type) {
|
|
6889
|
-
case "datetime-local":
|
|
7042
|
+
case "datetime-local":
|
|
7043
|
+
if (value instanceof Date && !isNaN(value.getTime())) {
|
|
7044
|
+
let pad = (n) => String(n).padStart(2, "0");
|
|
7045
|
+
$input.value = `${value.getFullYear()}-${pad(value.getMonth() + 1)}-${pad(value.getDate())}T${pad(value.getHours())}:${pad(value.getMinutes())}`;
|
|
7046
|
+
} else $input.value = "";
|
|
7047
|
+
break;
|
|
6890
7048
|
case "color":
|
|
6891
7049
|
$input.value = convertColor(value);
|
|
6892
7050
|
break;
|
|
@@ -6913,11 +7071,11 @@ function set_form_values$1(gobj, template, $form, record) {
|
|
|
6913
7071
|
break;
|
|
6914
7072
|
case "jsoneditor":
|
|
6915
7073
|
let jsoneditor = $input.jsoneditor;
|
|
6916
|
-
if (jsoneditor) jsoneditor.set(value);
|
|
7074
|
+
if (jsoneditor) jsoneditor.set(value ? value : { text: "" });
|
|
6917
7075
|
break;
|
|
6918
7076
|
case "fieldset": break;
|
|
6919
7077
|
case "table":
|
|
6920
|
-
load_tabulator_data(gobj, $input, value);
|
|
7078
|
+
load_tabulator_data(gobj, $input, value ? value : []);
|
|
6921
7079
|
break;
|
|
6922
7080
|
case "coordinates":
|
|
6923
7081
|
if ($input.tagName !== "INPUT") $input = $input.querySelector("input");
|
|
@@ -6963,7 +7121,22 @@ function treedb_value_2_form_value(gobj, field_desc, value) {
|
|
|
6963
7121
|
let type = field_desc.type;
|
|
6964
7122
|
field_desc.real_type;
|
|
6965
7123
|
switch (type) {
|
|
6966
|
-
case "fkey":
|
|
7124
|
+
case "fkey": {
|
|
7125
|
+
let new_value = [];
|
|
7126
|
+
if ((0, _yuneta_gobj_js.is_string)(value) && !(0, _yuneta_gobj_js.empty_string)(value)) {
|
|
7127
|
+
let fkey = (0, _yuneta_gobj_js.treedb_decoder_fkey)(field_desc, value);
|
|
7128
|
+
if (fkey) new_value.push(fkey.id);
|
|
7129
|
+
} else if ((0, _yuneta_gobj_js.is_array)(value)) for (let v of value) {
|
|
7130
|
+
let fkey = (0, _yuneta_gobj_js.treedb_decoder_fkey)(field_desc, v);
|
|
7131
|
+
if (fkey) new_value.push(fkey.id);
|
|
7132
|
+
}
|
|
7133
|
+
else if ((0, _yuneta_gobj_js.is_object)(value)) for (let v of Object.keys(value)) {
|
|
7134
|
+
let fkey = (0, _yuneta_gobj_js.treedb_decoder_fkey)(field_desc, v);
|
|
7135
|
+
if (fkey) new_value.push(fkey.id);
|
|
7136
|
+
}
|
|
7137
|
+
value = new_value;
|
|
7138
|
+
break;
|
|
7139
|
+
}
|
|
6967
7140
|
case "hook":
|
|
6968
7141
|
case "enum":
|
|
6969
7142
|
case "uuid":
|
|
@@ -6973,8 +7146,7 @@ function treedb_value_2_form_value(gobj, field_desc, value) {
|
|
|
6973
7146
|
case "url": break;
|
|
6974
7147
|
case "now":
|
|
6975
7148
|
case "time":
|
|
6976
|
-
value = parseInt(value) || 0;
|
|
6977
|
-
value = new Date(value);
|
|
7149
|
+
value = /* @__PURE__ */ new Date((parseInt(value) || 0) * 1e3);
|
|
6978
7150
|
break;
|
|
6979
7151
|
case "date":
|
|
6980
7152
|
case "color":
|
|
@@ -6990,13 +7162,19 @@ function treedb_value_2_form_value(gobj, field_desc, value) {
|
|
|
6990
7162
|
case "base64": break;
|
|
6991
7163
|
case "string":
|
|
6992
7164
|
case "integer":
|
|
7165
|
+
case "real":
|
|
7166
|
+
case "boolean": break;
|
|
6993
7167
|
case "object":
|
|
6994
7168
|
case "dict":
|
|
7169
|
+
value = { json: (0, _yuneta_gobj_js.is_object)(value) ? value : {} };
|
|
7170
|
+
break;
|
|
7171
|
+
case "blob":
|
|
7172
|
+
value = { json: (0, _yuneta_gobj_js.is_object)(value) || (0, _yuneta_gobj_js.is_array)(value) ? value : {} };
|
|
7173
|
+
break;
|
|
6995
7174
|
case "array":
|
|
6996
7175
|
case "list":
|
|
6997
|
-
|
|
6998
|
-
|
|
6999
|
-
case "blob": break;
|
|
7176
|
+
value = { json: (0, _yuneta_gobj_js.is_array)(value) ? value : [] };
|
|
7177
|
+
break;
|
|
7000
7178
|
case "number": break;
|
|
7001
7179
|
case "coordinates":
|
|
7002
7180
|
let longitude = 0;
|
|
@@ -7028,7 +7206,9 @@ function form_value_2_treedb_value(gobj, field_desc, value) {
|
|
|
7028
7206
|
let type = field_desc.type;
|
|
7029
7207
|
let real_type = field_desc.real_type;
|
|
7030
7208
|
switch (type) {
|
|
7031
|
-
case "fkey":
|
|
7209
|
+
case "fkey":
|
|
7210
|
+
value = build_fkey_ref$1(gobj, field_desc, value);
|
|
7211
|
+
break;
|
|
7032
7212
|
case "hook":
|
|
7033
7213
|
value = null;
|
|
7034
7214
|
break;
|
|
@@ -7136,7 +7316,9 @@ function ac_load_record(gobj, event, kw, src) {
|
|
|
7136
7316
|
(0, _yuneta_gobj_js.gobj_write_attr)(gobj, "record", kw);
|
|
7137
7317
|
let $form = (0, _yuneta_gobj_js.gobj_read_attr)(gobj, "$container").querySelector("form");
|
|
7138
7318
|
(0, _yuneta_gobj_js.gobj_write_bool_attr)(gobj, "initialized", false);
|
|
7139
|
-
|
|
7319
|
+
let modified = set_form_values(gobj, (0, _yuneta_gobj_js.gobj_read_attr)(gobj, "template"), $form, kw);
|
|
7320
|
+
apply_form_mode(gobj, $form);
|
|
7321
|
+
set_changed_stated(gobj, modified);
|
|
7140
7322
|
(0, _yuneta_gobj_js.gobj_write_bool_attr)(gobj, "initialized", true);
|
|
7141
7323
|
return 0;
|
|
7142
7324
|
}
|
|
@@ -7146,8 +7328,8 @@ function ac_load_record(gobj, event, kw, src) {
|
|
|
7146
7328
|
************************************************************/
|
|
7147
7329
|
function ac_save_record(gobj, event, kw, src) {
|
|
7148
7330
|
let $form = (0, _yuneta_gobj_js.gobj_read_attr)(gobj, "$container").querySelector("form");
|
|
7149
|
-
if (validate_form
|
|
7150
|
-
(0, _yuneta_gobj_js.gobj_publish_event)(gobj, "EV_SAVE_RECORD", get_form_values
|
|
7331
|
+
if (validate_form(gobj, $form)) {
|
|
7332
|
+
(0, _yuneta_gobj_js.gobj_publish_event)(gobj, "EV_SAVE_RECORD", get_form_values(gobj, $form));
|
|
7151
7333
|
set_changed_stated(gobj, false);
|
|
7152
7334
|
} else {
|
|
7153
7335
|
kw.abort_close = true;
|
|
@@ -7161,7 +7343,7 @@ function ac_save_record(gobj, event, kw, src) {
|
|
|
7161
7343
|
function ac_undo_record(gobj, event, kw, src) {
|
|
7162
7344
|
let $form = (0, _yuneta_gobj_js.gobj_read_attr)(gobj, "$container").querySelector("form");
|
|
7163
7345
|
(0, _yuneta_gobj_js.gobj_write_bool_attr)(gobj, "initialized", false);
|
|
7164
|
-
set_form_values
|
|
7346
|
+
set_form_values(gobj, (0, _yuneta_gobj_js.gobj_read_attr)(gobj, "template"), $form, (0, _yuneta_gobj_js.gobj_read_attr)(gobj, "record"));
|
|
7165
7347
|
set_changed_stated(gobj, false);
|
|
7166
7348
|
(0, _yuneta_gobj_js.gobj_write_bool_attr)(gobj, "initialized", true);
|
|
7167
7349
|
return 0;
|
|
@@ -7171,8 +7353,8 @@ function ac_undo_record(gobj, event, kw, src) {
|
|
|
7171
7353
|
************************************************************/
|
|
7172
7354
|
function ac_clear_record(gobj, event, kw, src) {
|
|
7173
7355
|
let $form = (0, _yuneta_gobj_js.gobj_read_attr)(gobj, "$container").querySelector("form");
|
|
7174
|
-
clear_validation
|
|
7175
|
-
clear_data
|
|
7356
|
+
clear_validation(gobj, $form);
|
|
7357
|
+
clear_data(gobj, $form);
|
|
7176
7358
|
return 0;
|
|
7177
7359
|
}
|
|
7178
7360
|
/************************************************************
|
|
@@ -7217,8 +7399,8 @@ function ac_record_changed(gobj, event, kw, src) {
|
|
|
7217
7399
|
************************************************************/
|
|
7218
7400
|
function ac_copy_record(gobj, event, kw, src) {
|
|
7219
7401
|
let $form = (0, _yuneta_gobj_js.gobj_read_attr)(gobj, "$container").querySelector("form");
|
|
7220
|
-
if (validate_form
|
|
7221
|
-
let data = { record: get_form_values
|
|
7402
|
+
if (validate_form(gobj, $form)) {
|
|
7403
|
+
let data = { record: get_form_values(gobj, $form) };
|
|
7222
7404
|
navigator.clipboard.writeText(JSON.stringify(data));
|
|
7223
7405
|
}
|
|
7224
7406
|
return 0;
|
|
@@ -7231,7 +7413,7 @@ function ac_paste_record(gobj, event, kw, src) {
|
|
|
7231
7413
|
let record = kw.record;
|
|
7232
7414
|
if ((0, _yuneta_gobj_js.is_object)(record)) {
|
|
7233
7415
|
(0, _yuneta_gobj_js.gobj_write_bool_attr)(gobj, "initialized", true);
|
|
7234
|
-
set_form_values
|
|
7416
|
+
set_form_values(gobj, (0, _yuneta_gobj_js.gobj_read_attr)(gobj, "template"), $form, record);
|
|
7235
7417
|
}
|
|
7236
7418
|
return 0;
|
|
7237
7419
|
}
|
|
@@ -7377,6 +7559,7 @@ function create_gclass$11(gclass_name) {
|
|
|
7377
7559
|
* Register GClass
|
|
7378
7560
|
***************************************************************/
|
|
7379
7561
|
function register_c_yui_form() {
|
|
7562
|
+
if ((0, _yuneta_gobj_js.gclass_find_by_name)(GCLASS_NAME$11, false)) return 0;
|
|
7380
7563
|
return create_gclass$11(GCLASS_NAME$11);
|
|
7381
7564
|
}
|
|
7382
7565
|
//#endregion
|
|
@@ -8454,7 +8637,7 @@ function onClick(gobj, e) {
|
|
|
8454
8637
|
const map = gobj.priv.xmap;
|
|
8455
8638
|
const coordinates = e.features[0].geometry.coordinates.slice();
|
|
8456
8639
|
const properties = e.features[0].properties;
|
|
8457
|
-
const gobj_service = (0, _yuneta_gobj_js.gobj_find_service)(properties.gobj_service_name,
|
|
8640
|
+
const gobj_service = properties.gobj_service_name ? (0, _yuneta_gobj_js.gobj_find_service)(properties.gobj_service_name, false) : null;
|
|
8458
8641
|
if (gobj_service) {
|
|
8459
8642
|
let window_service_name = `window-map-${(0, _yuneta_gobj_js.clean_name)((0, _yuneta_gobj_js.gobj_name)(gobj_service))}`;
|
|
8460
8643
|
let popupContent = (0, _yuneta_gobj_js.createElement2)([
|
|
@@ -11748,6 +11931,93 @@ function resolve_route(item_index, route) {
|
|
|
11748
11931
|
};
|
|
11749
11932
|
}
|
|
11750
11933
|
//#endregion
|
|
11934
|
+
//#region src/shell_section_index.js
|
|
11935
|
+
/***********************************************************************
|
|
11936
|
+
* shell_section_index.js
|
|
11937
|
+
*
|
|
11938
|
+
* Pure helper for C_YUI_SHELL: synthesize the stage target of a
|
|
11939
|
+
* section-index landing route.
|
|
11940
|
+
*
|
|
11941
|
+
* A level-1 menu item that declares `submenu.index` opts out of
|
|
11942
|
+
* the redirect-to-default-child behaviour: its own route becomes
|
|
11943
|
+
* a real resting, deep-linkable route whose view is the submenu
|
|
11944
|
+
* itself rendered as a "cards" C_YUI_NAV (the shell's view
|
|
11945
|
+
* contract only requires a $container by the end of mt_create,
|
|
11946
|
+
* which C_YUI_NAV already satisfies). Config:
|
|
11947
|
+
*
|
|
11948
|
+
* "submenu": {
|
|
11949
|
+
* "render": { "top-sub": "tabs" },
|
|
11950
|
+
* "index": true — landing in stage "main"
|
|
11951
|
+
* "index": {"stage": "x"} — landing in stage "x"
|
|
11952
|
+
* }
|
|
11953
|
+
*
|
|
11954
|
+
* Precedence: an explicit inline `target` on the item wins (this
|
|
11955
|
+
* helper returns null then). When the target is synthesized,
|
|
11956
|
+
* `submenu.default` becomes inert for the section: navigate_to()
|
|
11957
|
+
* only redirects to the default child while the entry has NO
|
|
11958
|
+
* target.
|
|
11959
|
+
*
|
|
11960
|
+
* Tabs and cards never coexist (DRY of navigation): while the
|
|
11961
|
+
* index is on stage the shell collapses the secondary zone, and
|
|
11962
|
+
* for index sections the tab strip defaults to desktop/tablet
|
|
11963
|
+
* only — on mobile a "backbar" nav (← <section>) takes its place
|
|
11964
|
+
* inside a child view. See secondary_nav_renders().
|
|
11965
|
+
*
|
|
11966
|
+
* Split out of c_yui_shell.js so it can be unit-tested without
|
|
11967
|
+
* a DOM.
|
|
11968
|
+
*
|
|
11969
|
+
* Copyright (c) 2026, ArtGins.
|
|
11970
|
+
* All Rights Reserved.
|
|
11971
|
+
***********************************************************************/
|
|
11972
|
+
/************************************************************
|
|
11973
|
+
* Return the synthesized target for `item`'s section route,
|
|
11974
|
+
* or null when the item doesn't opt in.
|
|
11975
|
+
************************************************************/
|
|
11976
|
+
function section_index_target(menu_id, item) {
|
|
11977
|
+
if (!item || !item.route || item.target) return null;
|
|
11978
|
+
let sub = item.submenu;
|
|
11979
|
+
if (!sub || !Array.isArray(sub.items) || !sub.index) return null;
|
|
11980
|
+
return {
|
|
11981
|
+
stage: (typeof sub.index === "object" ? sub.index : {}).stage || "main",
|
|
11982
|
+
gclass: "C_YUI_NAV",
|
|
11983
|
+
kw: {
|
|
11984
|
+
menu_id: `index.${menu_id}.${item.id}`,
|
|
11985
|
+
nav_label: item.name || item.id || "",
|
|
11986
|
+
menu_items: sub.items,
|
|
11987
|
+
layout: "cards",
|
|
11988
|
+
level: "secondary"
|
|
11989
|
+
}
|
|
11990
|
+
};
|
|
11991
|
+
}
|
|
11992
|
+
/************************************************************
|
|
11993
|
+
* Return the list of render configs for one (submenu, zone)
|
|
11994
|
+
* pair. `layout` is the raw submenu.render[zone] value
|
|
11995
|
+
* (string or object).
|
|
11996
|
+
*
|
|
11997
|
+
* Without submenu.index: the declared render, unchanged.
|
|
11998
|
+
* With submenu.index (list → detail):
|
|
11999
|
+
* - the declared nav defaults to show_on ">=tablet" (an
|
|
12000
|
+
* explicit show_on in the render object wins);
|
|
12001
|
+
* - a "backbar" nav (show_on "<tablet") is appended so a
|
|
12002
|
+
* child view offers "← <section>" on mobile instead of
|
|
12003
|
+
* the duplicated tab strip. Disable with
|
|
12004
|
+
* index: {backbar: false}; tune its breakpoints with
|
|
12005
|
+
* index: {backbar: {show_on: "..."}}.
|
|
12006
|
+
************************************************************/
|
|
12007
|
+
function secondary_nav_renders(item, layout) {
|
|
12008
|
+
let cfg = layout && typeof layout === "object" ? Object.assign({}, layout) : { layout: String(layout || "vertical") };
|
|
12009
|
+
let sub = item && item.submenu || {};
|
|
12010
|
+
if (!sub.index) return [cfg];
|
|
12011
|
+
let index_cfg = typeof sub.index === "object" ? sub.index : {};
|
|
12012
|
+
if (!cfg.show_on) cfg.show_on = ">=tablet";
|
|
12013
|
+
if (index_cfg.backbar === false) return [cfg];
|
|
12014
|
+
return [cfg, {
|
|
12015
|
+
layout: "backbar",
|
|
12016
|
+
show_on: (typeof index_cfg.backbar === "object" && index_cfg.backbar ? index_cfg.backbar : {}).show_on || "<tablet",
|
|
12017
|
+
back_route: item && item.route || ""
|
|
12018
|
+
}];
|
|
12019
|
+
}
|
|
12020
|
+
//#endregion
|
|
11751
12021
|
//#region src/c_yui_shell.js
|
|
11752
12022
|
/***********************************************************************
|
|
11753
12023
|
* c_yui_shell.js
|
|
@@ -11767,6 +12037,11 @@ function resolve_route(item_index, route) {
|
|
|
11767
12037
|
* $container in its stage, hide the previous one. Lifecycle per item
|
|
11768
12038
|
* decides when the gobj is created/destroyed.
|
|
11769
12039
|
*
|
|
12040
|
+
* A primary item with `submenu.index` gets a section-index landing:
|
|
12041
|
+
* its own route mounts the submenu as a "cards" C_YUI_NAV in the
|
|
12042
|
+
* stage instead of redirecting to the default child (see
|
|
12043
|
+
* shell_section_index.js for the contract).
|
|
12044
|
+
*
|
|
11770
12045
|
* Hash-based 2-level routing (#/primary/secondary). No dependency on
|
|
11771
12046
|
* C_YUI_ROUTING.
|
|
11772
12047
|
*
|
|
@@ -12142,12 +12417,13 @@ function build_item_index(gobj, config) {
|
|
|
12142
12417
|
let items = menu && menu.items || [];
|
|
12143
12418
|
for (let item of items) {
|
|
12144
12419
|
if (item.route) {
|
|
12420
|
+
let target = item.target || section_index_target(menu_id, item);
|
|
12145
12421
|
let prev = priv.item_index[item.route];
|
|
12146
|
-
if (!prev || !prev.target &&
|
|
12422
|
+
if (!prev || !prev.target && target) priv.item_index[item.route] = {
|
|
12147
12423
|
item,
|
|
12148
12424
|
parent_item: null,
|
|
12149
|
-
stage:
|
|
12150
|
-
target
|
|
12425
|
+
stage: target && target.stage || null,
|
|
12426
|
+
target,
|
|
12151
12427
|
menu_id
|
|
12152
12428
|
};
|
|
12153
12429
|
}
|
|
@@ -12225,11 +12501,15 @@ function instantiate_menus(gobj, config) {
|
|
|
12225
12501
|
(0, _yuneta_gobj_js.log_warning)(`C_YUI_SHELL: submenu of '${menu_id}.${item.id}' renders in unknown zone '${zone_id}'`);
|
|
12226
12502
|
continue;
|
|
12227
12503
|
}
|
|
12228
|
-
let
|
|
12229
|
-
|
|
12230
|
-
|
|
12231
|
-
|
|
12232
|
-
|
|
12504
|
+
let renders = secondary_nav_renders(item, render_to_obj(layout));
|
|
12505
|
+
let sub_menu_id = `secondary.${menu_id}.${item.id}`;
|
|
12506
|
+
for (let render_cfg of renders) {
|
|
12507
|
+
let $c = (0, _yuneta_gobj_js.gobj_read_attr)(instantiate_nav_in_zone(gobj, {
|
|
12508
|
+
items: sub.items,
|
|
12509
|
+
render: { [zone_id]: render_cfg }
|
|
12510
|
+
}, sub_menu_id, zone_id, "secondary", item.name || ""), "$container");
|
|
12511
|
+
if ($c) $c.classList.add("is-hidden");
|
|
12512
|
+
}
|
|
12233
12513
|
}
|
|
12234
12514
|
}
|
|
12235
12515
|
}
|
|
@@ -12243,9 +12523,8 @@ function instantiate_nav_in_zone(gobj, menu, menu_id, zone_id, level, nav_label)
|
|
|
12243
12523
|
let priv = (0, _yuneta_gobj_js.gobj_read_attr)(gobj, "priv");
|
|
12244
12524
|
let render_cfg = menu.render && (menu.render[zone_id] || menu.render["*"]) || { layout: "vertical" };
|
|
12245
12525
|
if ((0, _yuneta_gobj_js.is_string)(render_cfg)) render_cfg = { layout: render_cfg };
|
|
12246
|
-
let nav_name = `nav_${menu_id.replace(/\./g, "_")}_${zone_id}`;
|
|
12247
12526
|
let layout = render_cfg.layout || "vertical";
|
|
12248
|
-
let nav = (0, _yuneta_gobj_js.gobj_create)(
|
|
12527
|
+
let nav = (0, _yuneta_gobj_js.gobj_create)(`nav_${menu_id.replace(/\./g, "_")}_${zone_id}` + (layout === "backbar" ? "_backbar" : ""), "C_YUI_NAV", {
|
|
12249
12528
|
menu_id,
|
|
12250
12529
|
nav_label: nav_label || "",
|
|
12251
12530
|
menu_items: menu.items || [],
|
|
@@ -12254,6 +12533,8 @@ function instantiate_nav_in_zone(gobj, menu, menu_id, zone_id, level, nav_label)
|
|
|
12254
12533
|
icon_pos: render_cfg.icon_pos || default_icon_pos(zone_id),
|
|
12255
12534
|
show_label: render_cfg.show_label !== false,
|
|
12256
12535
|
level,
|
|
12536
|
+
show_on: render_cfg.show_on || "",
|
|
12537
|
+
back_route: render_cfg.back_route || "",
|
|
12257
12538
|
shell: gobj
|
|
12258
12539
|
}, gobj);
|
|
12259
12540
|
let $c = (0, _yuneta_gobj_js.gobj_read_attr)(nav, "$container");
|
|
@@ -12438,6 +12719,8 @@ function build_view_gobj(gobj, entry, route, stage) {
|
|
|
12438
12719
|
}
|
|
12439
12720
|
stage.el.appendChild($view);
|
|
12440
12721
|
(0, _yuneta_gobj_js.gobj_start)(view);
|
|
12722
|
+
let priv = (0, _yuneta_gobj_js.gobj_read_attr)(gobj, "priv");
|
|
12723
|
+
if (priv && typeof priv.translator === "function" && target.gclass === "C_YUI_NAV") (0, _yuneta_gobj_js.refresh_language)($view, priv.translator);
|
|
12441
12724
|
return view;
|
|
12442
12725
|
}
|
|
12443
12726
|
function safe_id(s) {
|
|
@@ -13022,7 +13305,7 @@ function update_secondary_nav_visibility(gobj, entry) {
|
|
|
13022
13305
|
let active_primary_id = entry.parent_item && entry.parent_item.id || entry.item && entry.item.id || "";
|
|
13023
13306
|
let target_secondary_id = `secondary.${entry.menu_id || ""}.${active_primary_id}`;
|
|
13024
13307
|
let active_primary = entry.parent_item || entry.item || null;
|
|
13025
|
-
let has_secondary = !!(active_primary && active_primary.submenu && Array.isArray(active_primary.submenu.items) && active_primary.submenu.items.some((it) => it && it.route));
|
|
13308
|
+
let has_secondary = !!!(!entry.parent_item && active_primary && active_primary.submenu && active_primary.submenu.index) && !!(active_primary && active_primary.submenu && Array.isArray(active_primary.submenu.items) && active_primary.submenu.items.some((it) => it && it.route));
|
|
13026
13309
|
let config = (0, _yuneta_gobj_js.gobj_read_attr)(gobj, "config") || {};
|
|
13027
13310
|
let zones_cfg = config.shell && config.shell.zones || {};
|
|
13028
13311
|
for (let z in zones_cfg) if (zones_cfg[z] && zones_cfg[z].host === "menu.secondary") {
|
|
@@ -13035,7 +13318,7 @@ function update_secondary_nav_visibility(gobj, entry) {
|
|
|
13035
13318
|
if (!nav_menu_id.startsWith("secondary.")) continue;
|
|
13036
13319
|
let $c = (0, _yuneta_gobj_js.gobj_read_attr)(nav, "$container");
|
|
13037
13320
|
if (!$c) continue;
|
|
13038
|
-
if (nav_menu_id === target_secondary_id) $c.classList.remove("is-hidden");
|
|
13321
|
+
if (nav_menu_id === target_secondary_id && has_secondary) $c.classList.remove("is-hidden");
|
|
13039
13322
|
else $c.classList.add("is-hidden");
|
|
13040
13323
|
}
|
|
13041
13324
|
}
|
|
@@ -13220,6 +13503,86 @@ function yui_shell_close_dropdown(shell_gobj) {
|
|
|
13220
13503
|
close_toolbar_dropdown(shell_gobj);
|
|
13221
13504
|
}
|
|
13222
13505
|
//#endregion
|
|
13506
|
+
//#region src/nav_cards_helpers.js
|
|
13507
|
+
/***********************************************************************
|
|
13508
|
+
* nav_cards_helpers.js
|
|
13509
|
+
*
|
|
13510
|
+
* Pure descriptor builders for C_YUI_NAV's "cards" layout — a
|
|
13511
|
+
* grid of tappable cards, one per item, used as the section-index
|
|
13512
|
+
* landing of a submenu (list → detail pattern). Split out of
|
|
13513
|
+
* c_yui_nav.js so it can be unit-tested without a DOM: the
|
|
13514
|
+
* functions return createElement2 node descriptors, never
|
|
13515
|
+
* HTMLElements.
|
|
13516
|
+
*
|
|
13517
|
+
* Copyright (c) 2026, ArtGins.
|
|
13518
|
+
* All Rights Reserved.
|
|
13519
|
+
***********************************************************************/
|
|
13520
|
+
/************************************************************
|
|
13521
|
+
* Descriptor of one card: an <a> carrying the same data-*
|
|
13522
|
+
* contract as every other nav item (data-route/data-item-id/
|
|
13523
|
+
* data-disabled), so C_YUI_NAV's delegated click handler and
|
|
13524
|
+
* active-route highlight work unchanged.
|
|
13525
|
+
************************************************************/
|
|
13526
|
+
function card_descriptor(it, show_label) {
|
|
13527
|
+
let children = [];
|
|
13528
|
+
let label = it.name || "";
|
|
13529
|
+
if (it.icon) children.push([
|
|
13530
|
+
"span",
|
|
13531
|
+
{ class: "icon is-medium" },
|
|
13532
|
+
["i", {
|
|
13533
|
+
class: it.icon,
|
|
13534
|
+
"aria-hidden": "true"
|
|
13535
|
+
}]
|
|
13536
|
+
]);
|
|
13537
|
+
if (show_label && label) children.push([
|
|
13538
|
+
"span",
|
|
13539
|
+
{
|
|
13540
|
+
class: "yui-nav-label",
|
|
13541
|
+
i18n: label
|
|
13542
|
+
},
|
|
13543
|
+
label
|
|
13544
|
+
]);
|
|
13545
|
+
let a_attrs = {
|
|
13546
|
+
class: "yui-nav-item yui-nav-card",
|
|
13547
|
+
href: it.route ? "#" + it.route : "#",
|
|
13548
|
+
"data-item-id": it.id,
|
|
13549
|
+
"data-route": it.route || "",
|
|
13550
|
+
"data-disabled": it.disabled ? "1" : "0",
|
|
13551
|
+
"aria-label": label || it.id
|
|
13552
|
+
};
|
|
13553
|
+
if (label) a_attrs["data-i18n-aria-label"] = label;
|
|
13554
|
+
let tip = it.tooltip || it.aria_label;
|
|
13555
|
+
if (tip) {
|
|
13556
|
+
a_attrs.title = tip;
|
|
13557
|
+
a_attrs["data-i18n-title"] = tip;
|
|
13558
|
+
}
|
|
13559
|
+
if (it.disabled) {
|
|
13560
|
+
a_attrs["aria-disabled"] = "true";
|
|
13561
|
+
a_attrs["tabindex"] = "-1";
|
|
13562
|
+
}
|
|
13563
|
+
return [
|
|
13564
|
+
"a",
|
|
13565
|
+
a_attrs,
|
|
13566
|
+
children
|
|
13567
|
+
];
|
|
13568
|
+
}
|
|
13569
|
+
/************************************************************
|
|
13570
|
+
* Descriptor of the whole grid. Decorative items (`header`/
|
|
13571
|
+
* `divider`) are dropped, same policy as the tabs layout.
|
|
13572
|
+
************************************************************/
|
|
13573
|
+
function cards_grid_descriptor(items, show_label) {
|
|
13574
|
+
let cards = [];
|
|
13575
|
+
for (let it of items || []) {
|
|
13576
|
+
if (!it || it.type === "header" || it.type === "divider") continue;
|
|
13577
|
+
cards.push(card_descriptor(it, show_label));
|
|
13578
|
+
}
|
|
13579
|
+
return [
|
|
13580
|
+
"div",
|
|
13581
|
+
{},
|
|
13582
|
+
cards
|
|
13583
|
+
];
|
|
13584
|
+
}
|
|
13585
|
+
//#endregion
|
|
13223
13586
|
//#region src/c_yui_nav.js
|
|
13224
13587
|
/***********************************************************************
|
|
13225
13588
|
* c_yui_nav.js
|
|
@@ -13235,6 +13598,17 @@ function yui_shell_close_dropdown(shell_gobj) {
|
|
|
13235
13598
|
* "drawer" — off-canvas vertical (toggled by hamburger)
|
|
13236
13599
|
* "submenu" — Bulma .menu nested under a heading
|
|
13237
13600
|
* "accordion" — Bulma .menu list with collapsible group
|
|
13601
|
+
* "cards" — grid of tappable cards (section-index landing;
|
|
13602
|
+
* mounted as a stage view by C_YUI_SHELL when a
|
|
13603
|
+
* primary item declares submenu.index)
|
|
13604
|
+
* "backbar" — single "← <section>" link back to the section
|
|
13605
|
+
* index; the mobile replacement of the tab strip
|
|
13606
|
+
* for submenu.index sections (the shell collapses
|
|
13607
|
+
* the secondary zone while the index is on stage)
|
|
13608
|
+
*
|
|
13609
|
+
* The `show_on` attr (same expressions as the shell's zone
|
|
13610
|
+
* `show_on`) applies breakpoint visibility classes to the nav
|
|
13611
|
+
* container; build_ui re-applies them on every rebuild.
|
|
13238
13612
|
*
|
|
13239
13613
|
* Each item supports:
|
|
13240
13614
|
* id, name, icon (CSS class or svg id), route, badge, disabled
|
|
@@ -13272,7 +13646,9 @@ var SUPPORTED_LAYOUTS = [
|
|
|
13272
13646
|
"tabs",
|
|
13273
13647
|
"drawer",
|
|
13274
13648
|
"submenu",
|
|
13275
|
-
"accordion"
|
|
13649
|
+
"accordion",
|
|
13650
|
+
"cards",
|
|
13651
|
+
"backbar"
|
|
13276
13652
|
];
|
|
13277
13653
|
function is_decorative(it) {
|
|
13278
13654
|
return !!(it && (it.type === "header" || it.type === "divider"));
|
|
@@ -13290,6 +13666,8 @@ var attrs_table$4 = [
|
|
|
13290
13666
|
(0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_STRING, "icon_pos", 0, "left", "left|right|top|bottom"),
|
|
13291
13667
|
(0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_BOOLEAN, "show_label", 0, true, "Show item label next to/under the icon"),
|
|
13292
13668
|
(0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_STRING, "level", 0, "primary", "primary|secondary"),
|
|
13669
|
+
(0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_STRING, "show_on", 0, "", "Breakpoint visibility expr (shell show_on syntax); empty = always"),
|
|
13670
|
+
(0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_STRING, "back_route", 0, "", "backbar layout: route of the section index the ← returns to"),
|
|
13293
13671
|
(0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_POINTER, "shell", 0, null, "C_YUI_SHELL gobj (for navigation calls)"),
|
|
13294
13672
|
(0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_POINTER, "$container", 0, null, "Root HTMLElement of this nav"),
|
|
13295
13673
|
(0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_STRING, "active_route", 0, "", "Currently active route"),
|
|
@@ -13373,11 +13751,23 @@ function build_ui$4(gobj) {
|
|
|
13373
13751
|
case "accordion":
|
|
13374
13752
|
$container = render_accordion(gobj, items);
|
|
13375
13753
|
break;
|
|
13754
|
+
case "cards":
|
|
13755
|
+
$container = render_cards(gobj, items);
|
|
13756
|
+
break;
|
|
13757
|
+
case "backbar":
|
|
13758
|
+
$container = render_backbar(gobj);
|
|
13759
|
+
break;
|
|
13376
13760
|
default: $container = render_vertical(gobj, items);
|
|
13377
13761
|
}
|
|
13378
13762
|
$container.setAttribute("data-nav-zone", zone);
|
|
13379
13763
|
$container.setAttribute("data-nav-layout", layout);
|
|
13380
13764
|
$container.classList.add("C_YUI_NAV", "yui-nav", `yui-nav-${layout}`);
|
|
13765
|
+
let show_on = (0, _yuneta_gobj_js.gobj_read_attr)(gobj, "show_on") || "";
|
|
13766
|
+
if (!(0, _yuneta_gobj_js.empty_string)(show_on) && show_on !== "*") {
|
|
13767
|
+
let visible = breakpoints_from_expr(show_on);
|
|
13768
|
+
for (let bp of BULMA_BP_ORDER) if (!visible[bp]) $container.classList.add(bulma_hidden_class(bp));
|
|
13769
|
+
$container.setAttribute("data-show-on", show_on);
|
|
13770
|
+
}
|
|
13381
13771
|
if (layout !== "drawer") {
|
|
13382
13772
|
$container.setAttribute("role", "navigation");
|
|
13383
13773
|
if (!$container.hasAttribute("aria-label")) {
|
|
@@ -13548,6 +13938,51 @@ function render_tabs(gobj, items) {
|
|
|
13548
13938
|
]
|
|
13549
13939
|
]);
|
|
13550
13940
|
}
|
|
13941
|
+
function render_cards(gobj, items) {
|
|
13942
|
+
return (0, _yuneta_gobj_js.createElement2)(cards_grid_descriptor(items, (0, _yuneta_gobj_js.gobj_read_attr)(gobj, "show_label")));
|
|
13943
|
+
}
|
|
13944
|
+
/************************************************************
|
|
13945
|
+
* "backbar": a single "← <section>" link back to the section
|
|
13946
|
+
* index route. Static DOM — the active child view names itself
|
|
13947
|
+
* in its own content, so the bar only carries the way back plus
|
|
13948
|
+
* section context. While the index itself is on stage the shell
|
|
13949
|
+
* collapses the whole secondary zone (tabs and cards never
|
|
13950
|
+
* coexist), so the bar needs no self-hiding logic.
|
|
13951
|
+
************************************************************/
|
|
13952
|
+
function render_backbar(gobj) {
|
|
13953
|
+
let back_route = (0, _yuneta_gobj_js.gobj_read_attr)(gobj, "back_route") || "";
|
|
13954
|
+
let label = (0, _yuneta_gobj_js.gobj_read_attr)(gobj, "nav_label") || "";
|
|
13955
|
+
let label_attrs = { class: "yui-nav-label" };
|
|
13956
|
+
if (label) label_attrs.i18n = label;
|
|
13957
|
+
let a_attrs = {
|
|
13958
|
+
class: "yui-nav-item yui-nav-back",
|
|
13959
|
+
href: back_route ? "#" + back_route : "#",
|
|
13960
|
+
"data-item-id": "__index__",
|
|
13961
|
+
"data-route": back_route,
|
|
13962
|
+
"aria-label": label || "back"
|
|
13963
|
+
};
|
|
13964
|
+
if (label) a_attrs["data-i18n-aria-label"] = label;
|
|
13965
|
+
return (0, _yuneta_gobj_js.createElement2)([
|
|
13966
|
+
"div",
|
|
13967
|
+
{},
|
|
13968
|
+
[
|
|
13969
|
+
"a",
|
|
13970
|
+
a_attrs,
|
|
13971
|
+
[[
|
|
13972
|
+
"span",
|
|
13973
|
+
{ class: "icon is-small" },
|
|
13974
|
+
["i", {
|
|
13975
|
+
class: "yi-arrow-left",
|
|
13976
|
+
"aria-hidden": "true"
|
|
13977
|
+
}]
|
|
13978
|
+
], [
|
|
13979
|
+
"span",
|
|
13980
|
+
label_attrs,
|
|
13981
|
+
label
|
|
13982
|
+
]]
|
|
13983
|
+
]
|
|
13984
|
+
]);
|
|
13985
|
+
}
|
|
13551
13986
|
function render_drawer(gobj, items) {
|
|
13552
13987
|
let menu_id = (0, _yuneta_gobj_js.gobj_read_attr)(gobj, "menu_id") || "drawer";
|
|
13553
13988
|
let wrap = document.createElement("div");
|
|
@@ -13849,6 +14284,7 @@ function ac_route_changed(gobj, event, kw, src) {
|
|
|
13849
14284
|
(0, _yuneta_gobj_js.gobj_write_attr)(gobj, "active_route", route);
|
|
13850
14285
|
let $c = (0, _yuneta_gobj_js.gobj_read_attr)(gobj, "$container");
|
|
13851
14286
|
if (!$c) return 0;
|
|
14287
|
+
if ((0, _yuneta_gobj_js.gobj_read_attr)(gobj, "layout") === "backbar") return 0;
|
|
13852
14288
|
$c.querySelectorAll(".is-active").forEach((n) => n.classList.remove("is-active"));
|
|
13853
14289
|
let id_to_mark = null;
|
|
13854
14290
|
if (level === "primary") {
|
|
@@ -14818,7 +15254,7 @@ function ac_treedb_node_deleted$1(gobj, event, kw, src) {
|
|
|
14818
15254
|
* record
|
|
14819
15255
|
* }
|
|
14820
15256
|
********************************************/
|
|
14821
|
-
function ac_create_record
|
|
15257
|
+
function ac_create_record(gobj, event, kw, src) {
|
|
14822
15258
|
let treedb_name = (0, _yuneta_gobj_js.gobj_read_str_attr)(gobj, "treedb_name");
|
|
14823
15259
|
let topic_name = (0, _yuneta_gobj_js.gobj_read_attr)(src, "topic_name");
|
|
14824
15260
|
let record = kw.record;
|
|
@@ -14835,7 +15271,7 @@ function ac_create_record$1(gobj, event, kw, src) {
|
|
|
14835
15271
|
* record
|
|
14836
15272
|
* }
|
|
14837
15273
|
********************************************/
|
|
14838
|
-
function ac_update_record
|
|
15274
|
+
function ac_update_record(gobj, event, kw, src) {
|
|
14839
15275
|
let treedb_name = (0, _yuneta_gobj_js.gobj_read_str_attr)(gobj, "treedb_name");
|
|
14840
15276
|
let topic_name = (0, _yuneta_gobj_js.gobj_read_attr)(src, "topic_name");
|
|
14841
15277
|
let record = kw.record;
|
|
@@ -14908,12 +15344,12 @@ function create_gclass$3(gclass_name) {
|
|
|
14908
15344
|
],
|
|
14909
15345
|
[
|
|
14910
15346
|
"EV_CREATE_RECORD",
|
|
14911
|
-
ac_create_record
|
|
15347
|
+
ac_create_record,
|
|
14912
15348
|
null
|
|
14913
15349
|
],
|
|
14914
15350
|
[
|
|
14915
15351
|
"EV_UPDATE_RECORD",
|
|
14916
|
-
ac_update_record
|
|
15352
|
+
ac_update_record,
|
|
14917
15353
|
null
|
|
14918
15354
|
],
|
|
14919
15355
|
[
|
|
@@ -15012,7 +15448,6 @@ var attrs_table$2 = [
|
|
|
15012
15448
|
(0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_POINTER, "tabulator", 0, null, "Tabulator instance"),
|
|
15013
15449
|
(0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_STRING, "table_id", 0, null, "Table div ID"),
|
|
15014
15450
|
(0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_STRING, "toolbar_id", 0, null, "Toolbar ID"),
|
|
15015
|
-
(0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_STRING, "form_id", 0, null, "Edit form ID"),
|
|
15016
15451
|
(0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_STRING, "popup_id", 0, null, "Edit form popup ID"),
|
|
15017
15452
|
(0, _yuneta_gobj_js.SDATA_END)()
|
|
15018
15453
|
];
|
|
@@ -15020,7 +15455,9 @@ var PRIVATE_DATA$2 = {
|
|
|
15020
15455
|
$container: null,
|
|
15021
15456
|
treedb_name: "",
|
|
15022
15457
|
topic_name: "",
|
|
15023
|
-
tabulator: null
|
|
15458
|
+
tabulator: null,
|
|
15459
|
+
form: null,
|
|
15460
|
+
$popup: null
|
|
15024
15461
|
};
|
|
15025
15462
|
var __gclass__$2 = null;
|
|
15026
15463
|
function popup_mount_layer() {
|
|
@@ -15036,7 +15473,6 @@ function mt_create$2(gobj) {
|
|
|
15036
15473
|
let name = (0, _yuneta_gobj_js.clean_name)((0, _yuneta_gobj_js.gobj_name)(gobj));
|
|
15037
15474
|
(0, _yuneta_gobj_js.gobj_write_attr)(gobj, "table_id", "table" + name);
|
|
15038
15475
|
(0, _yuneta_gobj_js.gobj_write_attr)(gobj, "toolbar_id", "toolbar" + name);
|
|
15039
|
-
(0, _yuneta_gobj_js.gobj_write_attr)(gobj, "form_id", "form" + name);
|
|
15040
15476
|
(0, _yuneta_gobj_js.gobj_write_attr)(gobj, "popup_id", "popup" + name);
|
|
15041
15477
|
build_ui$2(gobj);
|
|
15042
15478
|
let subscriber = (0, _yuneta_gobj_js.gobj_read_pointer_attr)(gobj, "subscriber");
|
|
@@ -15053,6 +15489,7 @@ function mt_start$2(gobj) {
|
|
|
15053
15489
|
* Framework Method: Stop
|
|
15054
15490
|
***************************************************************/
|
|
15055
15491
|
function mt_stop$2(gobj) {
|
|
15492
|
+
close_form_dialog(gobj);
|
|
15056
15493
|
table__destroy(gobj);
|
|
15057
15494
|
}
|
|
15058
15495
|
/***************************************************************
|
|
@@ -15392,6 +15829,29 @@ function col_label(col, topic_name) {
|
|
|
15392
15829
|
return (0, i18next.t)(topic_name ? [topic_name + "." + col.id, col.id] : [col.id], { defaultValue: col.header || col.id });
|
|
15393
15830
|
}
|
|
15394
15831
|
/******************************************************************
|
|
15832
|
+
* Column-title formatter: render the header as a span carrying
|
|
15833
|
+
* `data-i18n` (the shared col id) so a live language switch —
|
|
15834
|
+
* which calls refresh_language(document.body) — retranslates the
|
|
15835
|
+
* Tabulator headers in place, without rebuilding the table. Only
|
|
15836
|
+
* tag translatable columns; otherwise keep the schema header
|
|
15837
|
+
* (refresh_language would otherwise overwrite it with the raw id).
|
|
15838
|
+
* Tabulator re-runs this on redraw, so the full cascade re-applies.
|
|
15839
|
+
******************************************************************/
|
|
15840
|
+
function col_title_formatter(gobj, col) {
|
|
15841
|
+
let topic_name = (0, _yuneta_gobj_js.gobj_read_str_attr)(gobj, "topic_name");
|
|
15842
|
+
return function(cell, formatterParams, onRendered) {
|
|
15843
|
+
let text = col_label(col, topic_name);
|
|
15844
|
+
let attrs = {};
|
|
15845
|
+
const NO_I18N = "\0";
|
|
15846
|
+
if ((0, i18next.t)(col.id, { defaultValue: NO_I18N }) !== NO_I18N) attrs.i18n = col.id;
|
|
15847
|
+
return (0, _yuneta_gobj_js.createElement2)([
|
|
15848
|
+
"span",
|
|
15849
|
+
attrs,
|
|
15850
|
+
text
|
|
15851
|
+
]);
|
|
15852
|
+
};
|
|
15853
|
+
}
|
|
15854
|
+
/******************************************************************
|
|
15395
15855
|
* Build table with Tabulator
|
|
15396
15856
|
* This fn is called on start and when desc attribute is set.
|
|
15397
15857
|
* desc contains the description (columns) of table to create
|
|
@@ -15496,6 +15956,7 @@ function create_tabulator(gobj) {
|
|
|
15496
15956
|
}
|
|
15497
15957
|
let colDef = {
|
|
15498
15958
|
title: col_label(col, (0, _yuneta_gobj_js.gobj_read_str_attr)(gobj, "topic_name")),
|
|
15959
|
+
titleFormatter: col_title_formatter(gobj, col),
|
|
15499
15960
|
field: col.id,
|
|
15500
15961
|
sorter,
|
|
15501
15962
|
hozAlign,
|
|
@@ -15689,436 +16150,62 @@ function transform__treedb_value_2_table_value(gobj, col, value, row, field) {
|
|
|
15689
16150
|
}
|
|
15690
16151
|
return value;
|
|
15691
16152
|
}
|
|
15692
|
-
|
|
15693
|
-
*
|
|
15694
|
-
|
|
15695
|
-
|
|
16153
|
+
/************************************************************
|
|
16154
|
+
* Build the form template from desc.cols: only user-editable
|
|
16155
|
+
* fields reach the form — writable cols, fkeys (linkable) and
|
|
16156
|
+
* the pkey (the hosted C_YUI_FORM's form_mode drives the
|
|
16157
|
+
* pkey's readonly/required state).
|
|
16158
|
+
************************************************************/
|
|
16159
|
+
function build_form_template(gobj) {
|
|
15696
16160
|
let desc = (0, _yuneta_gobj_js.gobj_read_attr)(gobj, "desc");
|
|
15697
|
-
let
|
|
15698
|
-
|
|
15699
|
-
|
|
15700
|
-
|
|
15701
|
-
|
|
15702
|
-
|
|
15703
|
-
|
|
15704
|
-
|
|
15705
|
-
let [tag, form_input_type, options, extras] = transform__treedb_type_2_form_type(gobj, col);
|
|
15706
|
-
if (!tag) continue;
|
|
15707
|
-
let id = col.id;
|
|
15708
|
-
let flag = col.flag;
|
|
15709
|
-
let is_writable = (0, _yuneta_gobj_js.str_in_list)(flag, "writable");
|
|
15710
|
-
let is_notnull = (0, _yuneta_gobj_js.str_in_list)(flag, "notnull");
|
|
15711
|
-
let is_rowid = (0, _yuneta_gobj_js.str_in_list)(flag, "rowid");
|
|
15712
|
-
let is_required = (0, _yuneta_gobj_js.str_in_list)(flag, "required");
|
|
15713
|
-
let is_hidden = (0, _yuneta_gobj_js.str_in_list)(flag, "hidden");
|
|
15714
|
-
(0, _yuneta_gobj_js.str_in_list)(flag, "persistent");
|
|
15715
|
-
(0, _yuneta_gobj_js.str_in_list)(flag, "hook");
|
|
15716
|
-
let is_fkey = (0, _yuneta_gobj_js.str_in_list)(flag, "fkey");
|
|
15717
|
-
if (id === desc.pkey) is_writable = false;
|
|
15718
|
-
if (is_fkey) is_writable = true;
|
|
15719
|
-
if (!is_writable) {
|
|
15720
|
-
if (id !== desc.pkey) continue;
|
|
15721
|
-
}
|
|
15722
|
-
if (is_hidden) continue;
|
|
15723
|
-
if (is_rowid) {
|
|
15724
|
-
is_writable = false;
|
|
15725
|
-
is_required = false;
|
|
15726
|
-
is_notnull = false;
|
|
15727
|
-
}
|
|
15728
|
-
let field_conf = {
|
|
15729
|
-
tag,
|
|
15730
|
-
inputType: form_input_type,
|
|
15731
|
-
name: col.id,
|
|
15732
|
-
label: col_label(col, (0, _yuneta_gobj_js.gobj_read_str_attr)(gobj, "topic_name")),
|
|
15733
|
-
placeholder: "",
|
|
15734
|
-
options,
|
|
15735
|
-
extras,
|
|
15736
|
-
readonly: !is_writable,
|
|
15737
|
-
required: is_required,
|
|
15738
|
-
hidden: is_hidden,
|
|
15739
|
-
not_null: is_notnull,
|
|
15740
|
-
is_pkey: id === desc.pkey,
|
|
15741
|
-
is_rowid
|
|
15742
|
-
};
|
|
15743
|
-
let $field = create_html_field(field_conf);
|
|
15744
|
-
$field.field_conf = field_conf;
|
|
15745
|
-
$form.appendChild($field);
|
|
16161
|
+
let template = [];
|
|
16162
|
+
for (let col of desc.cols) {
|
|
16163
|
+
if (!col.id || col.id.charAt(0) === "_") continue;
|
|
16164
|
+
const field_desc = (0, _yuneta_gobj_js.treedb_get_field_desc)(col);
|
|
16165
|
+
if (field_desc.is_hidden) continue;
|
|
16166
|
+
if (field_desc.type === "hook") continue;
|
|
16167
|
+
if (!field_desc.is_writable && field_desc.type !== "fkey" && col.id !== desc.pkey) continue;
|
|
16168
|
+
template.push(col);
|
|
15746
16169
|
}
|
|
15747
|
-
return
|
|
16170
|
+
return template;
|
|
15748
16171
|
}
|
|
15749
16172
|
/************************************************************
|
|
15750
|
-
*
|
|
15751
|
-
*
|
|
15752
|
-
*
|
|
15753
|
-
*
|
|
15754
|
-
*
|
|
16173
|
+
* Collect the linkable parent rows for every fkey col:
|
|
16174
|
+
* {topic_name: rows}, asked to the topics manager (parent)
|
|
16175
|
+
* with the same command the old embedded form used. Collected
|
|
16176
|
+
* fresh on every dialog open, so new parent rows are always
|
|
16177
|
+
* offered.
|
|
15755
16178
|
************************************************************/
|
|
15756
|
-
function
|
|
15757
|
-
|
|
15758
|
-
let
|
|
15759
|
-
let
|
|
15760
|
-
|
|
15761
|
-
|
|
15762
|
-
|
|
15763
|
-
|
|
15764
|
-
|
|
15765
|
-
tag = "input";
|
|
15766
|
-
inputType = "text";
|
|
15767
|
-
break;
|
|
15768
|
-
case "integer":
|
|
15769
|
-
tag = "input";
|
|
15770
|
-
extras.inputmode = "numeric";
|
|
15771
|
-
break;
|
|
15772
|
-
case "real":
|
|
15773
|
-
tag = "input";
|
|
15774
|
-
extras.inputmode = "decimal";
|
|
15775
|
-
break;
|
|
15776
|
-
case "rowid":
|
|
15777
|
-
tag = "input";
|
|
15778
|
-
inputType = "text";
|
|
15779
|
-
break;
|
|
15780
|
-
case "boolean":
|
|
15781
|
-
tag = "checkbox";
|
|
15782
|
-
break;
|
|
15783
|
-
case "now":
|
|
15784
|
-
case "time":
|
|
15785
|
-
tag = "input";
|
|
15786
|
-
inputType = "datetime-local";
|
|
15787
|
-
switch (field_desc.real_type) {
|
|
15788
|
-
case "string": break;
|
|
15789
|
-
case "integer": break;
|
|
15790
|
-
}
|
|
15791
|
-
break;
|
|
15792
|
-
case "color":
|
|
15793
|
-
tag = "input";
|
|
15794
|
-
inputType = "color";
|
|
15795
|
-
switch (field_desc.real_type) {
|
|
15796
|
-
case "string": break;
|
|
15797
|
-
case "integer": break;
|
|
15798
|
-
}
|
|
15799
|
-
break;
|
|
15800
|
-
case "email":
|
|
15801
|
-
tag = "input";
|
|
15802
|
-
inputType = "email";
|
|
15803
|
-
extras.inputmode = "email";
|
|
15804
|
-
break;
|
|
15805
|
-
case "password":
|
|
15806
|
-
tag = "input";
|
|
15807
|
-
inputType = "password";
|
|
15808
|
-
break;
|
|
15809
|
-
case "url":
|
|
15810
|
-
tag = "input";
|
|
15811
|
-
inputType = "url";
|
|
15812
|
-
extras.inputmode = "url";
|
|
15813
|
-
break;
|
|
15814
|
-
case "tel":
|
|
15815
|
-
tag = "input";
|
|
15816
|
-
inputType = "tel";
|
|
15817
|
-
extras.inputmode = "tel";
|
|
15818
|
-
break;
|
|
15819
|
-
case "object":
|
|
15820
|
-
case "dict":
|
|
15821
|
-
case "template":
|
|
15822
|
-
case "array":
|
|
15823
|
-
case "list":
|
|
15824
|
-
case "coordinates":
|
|
15825
|
-
case "blob":
|
|
15826
|
-
tag = "jsoneditor";
|
|
15827
|
-
break;
|
|
15828
|
-
case "enum":
|
|
15829
|
-
tag = "select2";
|
|
15830
|
-
switch (field_desc.real_type) {
|
|
15831
|
-
case "string":
|
|
15832
|
-
case "object":
|
|
15833
|
-
case "dict":
|
|
15834
|
-
case "array":
|
|
15835
|
-
case "list":
|
|
15836
|
-
options = (0, _yuneta_gobj_js.list2options)(field_desc.enum_list, "id", "id");
|
|
15837
|
-
break;
|
|
15838
|
-
}
|
|
15839
|
-
break;
|
|
15840
|
-
case "hook": break;
|
|
15841
|
-
case "fkey":
|
|
15842
|
-
tag = "select2";
|
|
15843
|
-
switch (field_desc.real_type) {
|
|
15844
|
-
case "string":
|
|
15845
|
-
case "object":
|
|
15846
|
-
case "dict":
|
|
15847
|
-
case "array":
|
|
15848
|
-
case "list":
|
|
15849
|
-
options = get_fkey_options(gobj, col);
|
|
15850
|
-
break;
|
|
15851
|
-
}
|
|
15852
|
-
break;
|
|
15853
|
-
}
|
|
15854
|
-
return [
|
|
15855
|
-
tag,
|
|
15856
|
-
inputType,
|
|
15857
|
-
options,
|
|
15858
|
-
extras
|
|
15859
|
-
];
|
|
15860
|
-
}
|
|
15861
|
-
/******************************************************************
|
|
15862
|
-
* Helper function to create different form elements
|
|
15863
|
-
* Available types:
|
|
15864
|
-
* - input
|
|
15865
|
-
* - textarea
|
|
15866
|
-
* - select
|
|
15867
|
-
* - select2
|
|
15868
|
-
* - checkbox
|
|
15869
|
-
* - radio
|
|
15870
|
-
* - jsoneditor
|
|
15871
|
-
*
|
|
15872
|
-
* {
|
|
15873
|
-
* tag: field tag,
|
|
15874
|
-
* inputType: input type,
|
|
15875
|
-
* name: id
|
|
15876
|
-
* label: ""
|
|
15877
|
-
* placeholder: "",
|
|
15878
|
-
* options: [{id:"", value:""}]]
|
|
15879
|
-
* extras: {}
|
|
15880
|
-
* readonly: bool
|
|
15881
|
-
* required: bool
|
|
15882
|
-
* hidden: bool
|
|
15883
|
-
* not_null: bool
|
|
15884
|
-
* _col: col
|
|
15885
|
-
* }
|
|
15886
|
-
******************************************************************/
|
|
15887
|
-
function create_html_field({ tag, inputType, name, label, placeholder, options, extras, readonly, required, hidden, not_null }) {
|
|
15888
|
-
let base;
|
|
15889
|
-
switch (tag) {
|
|
15890
|
-
case "input":
|
|
15891
|
-
case "textarea":
|
|
15892
|
-
case "select":
|
|
15893
|
-
case "select2":
|
|
15894
|
-
case "checkbox":
|
|
15895
|
-
case "radio":
|
|
15896
|
-
case "jsoneditor":
|
|
15897
|
-
base = [
|
|
15898
|
-
"div",
|
|
15899
|
-
{ class: "xfield field is-horizontal" },
|
|
15900
|
-
[[
|
|
15901
|
-
"div",
|
|
15902
|
-
{ class: "field-label is-normal" },
|
|
15903
|
-
[[
|
|
15904
|
-
"label",
|
|
15905
|
-
{
|
|
15906
|
-
class: "label ",
|
|
15907
|
-
i18n: label,
|
|
15908
|
-
for: name
|
|
15909
|
-
},
|
|
15910
|
-
label
|
|
15911
|
-
]]
|
|
15912
|
-
], [
|
|
15913
|
-
"div",
|
|
15914
|
-
{ class: "field-body" },
|
|
15915
|
-
[[
|
|
15916
|
-
"div",
|
|
15917
|
-
{ class: "field" },
|
|
15918
|
-
[[
|
|
15919
|
-
"div",
|
|
15920
|
-
{ class: "control" },
|
|
15921
|
-
[]
|
|
15922
|
-
]]
|
|
15923
|
-
]]
|
|
15924
|
-
]]
|
|
15925
|
-
];
|
|
15926
|
-
break;
|
|
15927
|
-
default: base = [
|
|
15928
|
-
"div",
|
|
15929
|
-
{ class: "control" },
|
|
15930
|
-
"Unsupported element type"
|
|
15931
|
-
];
|
|
15932
|
-
}
|
|
15933
|
-
let $element = (0, _yuneta_gobj_js.createElement2)(base);
|
|
15934
|
-
let $control = $element.querySelector(".control");
|
|
15935
|
-
switch (tag) {
|
|
15936
|
-
case "input": {
|
|
15937
|
-
let attrs = {
|
|
15938
|
-
class: `input ${name === "id" ? "with-focus" : ""}`,
|
|
15939
|
-
name,
|
|
15940
|
-
type: inputType,
|
|
15941
|
-
placeholder
|
|
15942
|
-
};
|
|
15943
|
-
Object.assign(attrs, extras);
|
|
15944
|
-
if (readonly) attrs.readonly = "";
|
|
15945
|
-
let $extend = (0, _yuneta_gobj_js.createElement2)([
|
|
15946
|
-
"input",
|
|
15947
|
-
attrs,
|
|
15948
|
-
"",
|
|
15949
|
-
{ "blur": function(evt) {
|
|
15950
|
-
validate_field_on_blur(this);
|
|
15951
|
-
} }
|
|
15952
|
-
]);
|
|
15953
|
-
$control.appendChild($extend);
|
|
15954
|
-
$control.appendChild((0, _yuneta_gobj_js.createElement2)([
|
|
15955
|
-
"p",
|
|
15956
|
-
{
|
|
15957
|
-
class: "help is-danger",
|
|
15958
|
-
style: "display:none"
|
|
15959
|
-
},
|
|
15960
|
-
""
|
|
15961
|
-
]));
|
|
15962
|
-
break;
|
|
15963
|
-
}
|
|
15964
|
-
case "jsoneditor": {
|
|
15965
|
-
let attrs = {
|
|
15966
|
-
class: "jsoneditor jse-theme-dark",
|
|
15967
|
-
style: ""
|
|
15968
|
-
};
|
|
15969
|
-
Object.assign(attrs, extras);
|
|
15970
|
-
if (readonly) attrs.readonly = "";
|
|
15971
|
-
let $extend = (0, _yuneta_gobj_js.createElement2)(["div", attrs]);
|
|
15972
|
-
$extend.setAttribute("name", name);
|
|
15973
|
-
$control.appendChild($extend);
|
|
15974
|
-
$control.appendChild((0, _yuneta_gobj_js.createElement2)([
|
|
15975
|
-
"p",
|
|
15976
|
-
{
|
|
15977
|
-
class: "help is-danger",
|
|
15978
|
-
style: "display:none"
|
|
15979
|
-
},
|
|
15980
|
-
""
|
|
15981
|
-
]));
|
|
15982
|
-
break;
|
|
15983
|
-
}
|
|
15984
|
-
case "textarea": {
|
|
15985
|
-
let attrs = {
|
|
15986
|
-
class: "textarea",
|
|
15987
|
-
name,
|
|
15988
|
-
placeholder
|
|
15989
|
-
};
|
|
15990
|
-
Object.assign(attrs, extras);
|
|
15991
|
-
if (readonly) attrs.readonly = "";
|
|
15992
|
-
let $extend = (0, _yuneta_gobj_js.createElement2)([
|
|
15993
|
-
"textarea",
|
|
15994
|
-
attrs,
|
|
15995
|
-
"",
|
|
15996
|
-
{ "blur": function(evt) {
|
|
15997
|
-
validate_field_on_blur(this);
|
|
15998
|
-
} }
|
|
15999
|
-
]);
|
|
16000
|
-
$control.appendChild($extend);
|
|
16001
|
-
$control.appendChild((0, _yuneta_gobj_js.createElement2)([
|
|
16002
|
-
"p",
|
|
16003
|
-
{
|
|
16004
|
-
class: "help is-danger",
|
|
16005
|
-
style: "display:none"
|
|
16006
|
-
},
|
|
16007
|
-
""
|
|
16008
|
-
]));
|
|
16009
|
-
break;
|
|
16010
|
-
}
|
|
16011
|
-
case "select": {
|
|
16012
|
-
let $extend = (0, _yuneta_gobj_js.createElement2)([
|
|
16013
|
-
"div",
|
|
16014
|
-
{ class: "select" },
|
|
16015
|
-
[
|
|
16016
|
-
"select",
|
|
16017
|
-
{ name },
|
|
16018
|
-
options.map((option) => [
|
|
16019
|
-
"option",
|
|
16020
|
-
{
|
|
16021
|
-
value: option.id,
|
|
16022
|
-
i18n: option.value
|
|
16023
|
-
},
|
|
16024
|
-
option.value
|
|
16025
|
-
])
|
|
16026
|
-
]
|
|
16027
|
-
]);
|
|
16028
|
-
$control.appendChild($extend);
|
|
16029
|
-
$control.appendChild((0, _yuneta_gobj_js.createElement2)([
|
|
16030
|
-
"p",
|
|
16031
|
-
{
|
|
16032
|
-
class: "help is-danger",
|
|
16033
|
-
style: "display:none"
|
|
16034
|
-
},
|
|
16035
|
-
""
|
|
16036
|
-
]));
|
|
16037
|
-
break;
|
|
16038
|
-
}
|
|
16039
|
-
case "select2": {
|
|
16040
|
-
let $extend = (0, _yuneta_gobj_js.createElement2)([
|
|
16041
|
-
"select",
|
|
16042
|
-
{
|
|
16043
|
-
name,
|
|
16044
|
-
class: "select2-multiple",
|
|
16045
|
-
multiple: "multiple",
|
|
16046
|
-
style: "width: 100% !important;"
|
|
16047
|
-
},
|
|
16048
|
-
options.map((option) => [
|
|
16049
|
-
"option",
|
|
16050
|
-
{
|
|
16051
|
-
value: option.id,
|
|
16052
|
-
i18n: option.value
|
|
16053
|
-
},
|
|
16054
|
-
option.value
|
|
16055
|
-
])
|
|
16056
|
-
]);
|
|
16057
|
-
$control.appendChild($extend);
|
|
16058
|
-
$control.appendChild((0, _yuneta_gobj_js.createElement2)([
|
|
16059
|
-
"p",
|
|
16060
|
-
{
|
|
16061
|
-
class: "help is-danger",
|
|
16062
|
-
style: "display:none"
|
|
16063
|
-
},
|
|
16064
|
-
""
|
|
16065
|
-
]));
|
|
16066
|
-
break;
|
|
16067
|
-
}
|
|
16068
|
-
case "checkbox": {
|
|
16069
|
-
let $extend = (0, _yuneta_gobj_js.createElement2)([
|
|
16070
|
-
"label",
|
|
16071
|
-
{ class: "checkbox" },
|
|
16072
|
-
["input", {
|
|
16073
|
-
type: "checkbox",
|
|
16074
|
-
name
|
|
16075
|
-
}]
|
|
16076
|
-
]);
|
|
16077
|
-
$control.appendChild($extend);
|
|
16078
|
-
$control.appendChild((0, _yuneta_gobj_js.createElement2)([
|
|
16079
|
-
"p",
|
|
16080
|
-
{
|
|
16081
|
-
class: "help is-danger",
|
|
16082
|
-
style: "display:none"
|
|
16083
|
-
},
|
|
16084
|
-
""
|
|
16085
|
-
]));
|
|
16086
|
-
break;
|
|
16087
|
-
}
|
|
16088
|
-
case "radio":
|
|
16089
|
-
for (const option of options) {
|
|
16090
|
-
let $extend = (0, _yuneta_gobj_js.createOneHtml)(`
|
|
16091
|
-
<label class="radio">
|
|
16092
|
-
<input type="radio" name="${name}">
|
|
16093
|
-
${(0, i18next.t)(option)}
|
|
16094
|
-
</label>
|
|
16095
|
-
`);
|
|
16096
|
-
$control.appendChild($extend);
|
|
16097
|
-
}
|
|
16098
|
-
$control.appendChild((0, _yuneta_gobj_js.createElement2)([
|
|
16099
|
-
"p",
|
|
16100
|
-
{
|
|
16101
|
-
class: "help is-danger",
|
|
16102
|
-
style: "display:none"
|
|
16103
|
-
},
|
|
16104
|
-
""
|
|
16105
|
-
]));
|
|
16106
|
-
break;
|
|
16107
|
-
default: (0, _yuneta_gobj_js.log_error)(`Unsupported element type, tag ${tag}`);
|
|
16179
|
+
function build_fkey_options(gobj) {
|
|
16180
|
+
let desc = (0, _yuneta_gobj_js.gobj_read_attr)(gobj, "desc");
|
|
16181
|
+
let fkey_options = {};
|
|
16182
|
+
for (let col of desc.cols) {
|
|
16183
|
+
if ((0, _yuneta_gobj_js.treedb_get_field_desc)(col).type !== "fkey" || !(0, _yuneta_gobj_js.is_object)(col.fkey)) continue;
|
|
16184
|
+
let topic_name = Object.keys(col.fkey)[0];
|
|
16185
|
+
if (!topic_name || fkey_options[topic_name] !== void 0) continue;
|
|
16186
|
+
let webix = (0, _yuneta_gobj_js.gobj_command)((0, _yuneta_gobj_js.gobj_parent)(gobj), "get_topic_data", { topic_name }, gobj);
|
|
16187
|
+
fkey_options[topic_name] = webix && (0, _yuneta_gobj_js.is_array)(webix.data) ? webix.data : [];
|
|
16108
16188
|
}
|
|
16109
|
-
return
|
|
16189
|
+
return fkey_options;
|
|
16110
16190
|
}
|
|
16111
|
-
|
|
16112
|
-
*
|
|
16113
|
-
|
|
16114
|
-
|
|
16115
|
-
|
|
16116
|
-
|
|
16191
|
+
/************************************************************
|
|
16192
|
+
* Open the edit/create dialog hosting a C_YUI_FORM child.
|
|
16193
|
+
* The child is created fresh on every open (schema and fkey
|
|
16194
|
+
* options are read at its build time) and destroyed on close.
|
|
16195
|
+
* Its EV_SAVE_RECORD (CHILD model) arrives already in treedb
|
|
16196
|
+
* shape — see ac_form_save_record().
|
|
16197
|
+
************************************************************/
|
|
16198
|
+
function open_form_dialog(gobj, mode, record) {
|
|
16199
|
+
close_form_dialog(gobj);
|
|
16200
|
+
let priv = gobj.priv;
|
|
16201
|
+
let desc = (0, _yuneta_gobj_js.gobj_read_attr)(gobj, "desc");
|
|
16202
|
+
let popup_id = (0, _yuneta_gobj_js.gobj_read_str_attr)(gobj, "popup_id");
|
|
16203
|
+
let topic_name = (0, _yuneta_gobj_js.gobj_read_str_attr)(gobj, "topic_name");
|
|
16117
16204
|
let $element = (0, _yuneta_gobj_js.createElement2)([
|
|
16118
16205
|
"div",
|
|
16119
16206
|
{
|
|
16120
|
-
id:
|
|
16121
|
-
class: "modal"
|
|
16207
|
+
id: popup_id,
|
|
16208
|
+
class: "modal is-active"
|
|
16122
16209
|
},
|
|
16123
16210
|
[[
|
|
16124
16211
|
"div",
|
|
@@ -16127,333 +16214,120 @@ function build_topic_modal(gobj) {
|
|
|
16127
16214
|
], [
|
|
16128
16215
|
"div",
|
|
16129
16216
|
{ class: "modal-card modal-is-responsive" },
|
|
16130
|
-
[
|
|
16131
|
-
|
|
16132
|
-
|
|
16133
|
-
|
|
16134
|
-
|
|
16135
|
-
|
|
16136
|
-
|
|
16137
|
-
|
|
16138
|
-
|
|
16139
|
-
|
|
16140
|
-
|
|
16141
|
-
|
|
16217
|
+
[[
|
|
16218
|
+
"header",
|
|
16219
|
+
{ class: "modal-card-head p-3" },
|
|
16220
|
+
[[
|
|
16221
|
+
"p",
|
|
16222
|
+
{
|
|
16223
|
+
class: "modal-card-title",
|
|
16224
|
+
style: "text-align:center;"
|
|
16225
|
+
},
|
|
16226
|
+
(0, i18next.t)(topic_name)
|
|
16227
|
+
], [
|
|
16228
|
+
"button",
|
|
16229
|
+
{
|
|
16142
16230
|
class: "delete is-large",
|
|
16143
16231
|
"aria-label": "close"
|
|
16144
|
-
}
|
|
16145
|
-
|
|
16146
|
-
|
|
16147
|
-
|
|
16148
|
-
|
|
16149
|
-
|
|
16150
|
-
]
|
|
16151
|
-
|
|
16152
|
-
|
|
16153
|
-
|
|
16154
|
-
|
|
16155
|
-
|
|
16156
|
-
|
|
16157
|
-
|
|
16158
|
-
|
|
16159
|
-
},
|
|
16160
|
-
[
|
|
16161
|
-
[
|
|
16162
|
-
"button",
|
|
16163
|
-
{
|
|
16164
|
-
class: "button is-success px-4",
|
|
16165
|
-
type: "submit"
|
|
16166
|
-
},
|
|
16167
|
-
[[
|
|
16168
|
-
"span",
|
|
16169
|
-
{ class: "icon" },
|
|
16170
|
-
[["i", { class: "yi-floppy-disk" }]]
|
|
16171
|
-
], [
|
|
16172
|
-
"span",
|
|
16173
|
-
{ i18n: "save" },
|
|
16174
|
-
"save"
|
|
16175
|
-
]],
|
|
16176
|
-
{ click: function(evt) {
|
|
16177
|
-
evt.stopPropagation();
|
|
16178
|
-
evt.preventDefault();
|
|
16179
|
-
let $form = $element.querySelector("form");
|
|
16180
|
-
if (validate_form(gobj, $form)) {
|
|
16181
|
-
let values = get_form_values($form);
|
|
16182
|
-
let ret;
|
|
16183
|
-
if ($form.__mode__ === "create") ret = (0, _yuneta_gobj_js.gobj_send_event)(gobj, "EV_CREATE_RECORD", values, gobj);
|
|
16184
|
-
else ret = (0, _yuneta_gobj_js.gobj_send_event)(gobj, "EV_UPDATE_RECORD", values, gobj);
|
|
16185
|
-
if (ret === 0) $element.classList.remove("is-active");
|
|
16186
|
-
}
|
|
16187
|
-
} }
|
|
16188
|
-
],
|
|
16189
|
-
[
|
|
16190
|
-
"button",
|
|
16191
|
-
{ class: "button px-4 form-close" },
|
|
16192
|
-
[[
|
|
16193
|
-
"span",
|
|
16194
|
-
{ class: "icon" },
|
|
16195
|
-
[["i", { class: "yi-xmark" }]]
|
|
16196
|
-
], [
|
|
16197
|
-
"span",
|
|
16198
|
-
{ i18n: "cancel" },
|
|
16199
|
-
"cancel"
|
|
16200
|
-
]]
|
|
16201
|
-
],
|
|
16202
|
-
[
|
|
16203
|
-
"button",
|
|
16204
|
-
{ class: "button px-4" },
|
|
16205
|
-
[[
|
|
16206
|
-
"span",
|
|
16207
|
-
{ class: "icon" },
|
|
16208
|
-
[["i", { class: "yi-broom" }]]
|
|
16209
|
-
], [
|
|
16210
|
-
"span",
|
|
16211
|
-
{ i18n: "clear" },
|
|
16212
|
-
"clear"
|
|
16213
|
-
]],
|
|
16214
|
-
{ click: function(evt) {
|
|
16215
|
-
evt.stopPropagation();
|
|
16216
|
-
clear_validation(gobj, $form);
|
|
16217
|
-
clear_data(gobj, $form);
|
|
16218
|
-
} }
|
|
16219
|
-
]
|
|
16220
|
-
]
|
|
16221
|
-
]]
|
|
16222
|
-
]
|
|
16223
|
-
]
|
|
16232
|
+
},
|
|
16233
|
+
"",
|
|
16234
|
+
{ click: function(evt) {
|
|
16235
|
+
evt.stopPropagation();
|
|
16236
|
+
request_close_form_dialog(gobj);
|
|
16237
|
+
} }
|
|
16238
|
+
]]
|
|
16239
|
+
], [
|
|
16240
|
+
"section",
|
|
16241
|
+
{
|
|
16242
|
+
class: "modal-card-body p-2",
|
|
16243
|
+
style: "display:flex; flex-direction:column;"
|
|
16244
|
+
},
|
|
16245
|
+
[]
|
|
16246
|
+
]]
|
|
16224
16247
|
]],
|
|
16225
16248
|
{ click: function(evt) {
|
|
16226
16249
|
evt.stopPropagation();
|
|
16227
16250
|
} }
|
|
16228
16251
|
]);
|
|
16229
|
-
$element.
|
|
16230
|
-
|
|
16231
|
-
|
|
16232
|
-
|
|
16233
|
-
|
|
16234
|
-
|
|
16235
|
-
|
|
16236
|
-
|
|
16237
|
-
|
|
16238
|
-
|
|
16239
|
-
|
|
16240
|
-
|
|
16241
|
-
|
|
16242
|
-
|
|
16243
|
-
|
|
16244
|
-
|
|
16245
|
-
|
|
16246
|
-
});
|
|
16247
|
-
});
|
|
16248
|
-
$element.querySelectorAll(".select2-multiple").forEach((el) => {
|
|
16249
|
-
if (el.tomselect) return;
|
|
16250
|
-
new tom_select.default(el, {
|
|
16251
|
-
plugins: ["remove_button"],
|
|
16252
|
-
create: false,
|
|
16253
|
-
hideSelected: true,
|
|
16254
|
-
closeAfterSelect: false
|
|
16255
|
-
});
|
|
16256
|
-
});
|
|
16257
|
-
return $element;
|
|
16258
|
-
}
|
|
16259
|
-
/************************************************************
|
|
16260
|
-
* Show a validation error on a field
|
|
16261
|
-
************************************************************/
|
|
16262
|
-
function show_field_error($field, message) {
|
|
16263
|
-
$field.querySelectorAll("input, textarea, select").forEach((el) => {
|
|
16264
|
-
el.classList.add("is-danger");
|
|
16265
|
-
});
|
|
16266
|
-
let $help = $field.querySelector(".help");
|
|
16267
|
-
if ($help) {
|
|
16268
|
-
$help.textContent = message;
|
|
16269
|
-
$help.style.display = "block";
|
|
16270
|
-
}
|
|
16271
|
-
}
|
|
16272
|
-
/************************************************************
|
|
16273
|
-
* Clear a validation error from a field
|
|
16274
|
-
************************************************************/
|
|
16275
|
-
function clear_field_error($field) {
|
|
16276
|
-
$field.querySelectorAll("input, textarea, select").forEach((el) => {
|
|
16277
|
-
el.classList.remove("is-danger");
|
|
16278
|
-
});
|
|
16279
|
-
let $help = $field.querySelector(".help");
|
|
16280
|
-
if ($help) {
|
|
16281
|
-
$help.textContent = "";
|
|
16282
|
-
$help.style.display = "none";
|
|
16252
|
+
let $body = $element.querySelector(".modal-card-body");
|
|
16253
|
+
let form = (0, _yuneta_gobj_js.gobj_create_pure_child)("form_" + (0, _yuneta_gobj_js.clean_name)((0, _yuneta_gobj_js.gobj_name)(gobj)), "C_YUI_FORM", {
|
|
16254
|
+
template: build_form_template(gobj),
|
|
16255
|
+
record,
|
|
16256
|
+
fkey_options: build_fkey_options(gobj),
|
|
16257
|
+
form_mode: mode,
|
|
16258
|
+
pkey: desc.pkey || "id",
|
|
16259
|
+
topic_name,
|
|
16260
|
+
editable: true,
|
|
16261
|
+
$parent: $body
|
|
16262
|
+
}, gobj);
|
|
16263
|
+
priv.form = form;
|
|
16264
|
+
priv.$popup = $element;
|
|
16265
|
+
let $form_container = (0, _yuneta_gobj_js.gobj_read_attr)(form, "$container");
|
|
16266
|
+
if ($form_container) {
|
|
16267
|
+
$form_container.style.flex = "1 1 auto";
|
|
16268
|
+
$form_container.style.minHeight = "0";
|
|
16283
16269
|
}
|
|
16270
|
+
popup_mount_layer().appendChild($element);
|
|
16271
|
+
(0, _yuneta_gobj_js.refresh_language)($element, i18next.t);
|
|
16272
|
+
(0, _yuneta_gobj_js.gobj_start)(form);
|
|
16273
|
+
let $with_focus = $element.querySelector(".with-focus");
|
|
16274
|
+
if ($with_focus) $with_focus.focus();
|
|
16284
16275
|
}
|
|
16285
16276
|
/************************************************************
|
|
16286
|
-
*
|
|
16277
|
+
* Close request from the dialog X: if the form carries
|
|
16278
|
+
* unsaved changes ask first (EV_WINDOW_TO_CLOSE contract).
|
|
16287
16279
|
************************************************************/
|
|
16288
|
-
function
|
|
16289
|
-
|
|
16290
|
-
|
|
16291
|
-
|
|
16292
|
-
|
|
16293
|
-
|
|
16294
|
-
|
|
16295
|
-
|
|
16296
|
-
|
|
16297
|
-
|
|
16298
|
-
if (!$input) return false;
|
|
16299
|
-
return $input.checked;
|
|
16300
|
-
}
|
|
16301
|
-
case "textarea": {
|
|
16302
|
-
let $el = $field.querySelector("textarea");
|
|
16303
|
-
if (!$el) return "";
|
|
16304
|
-
return $el.value;
|
|
16305
|
-
}
|
|
16306
|
-
case "select":
|
|
16307
|
-
case "select2": {
|
|
16308
|
-
let $el = $field.querySelector("select");
|
|
16309
|
-
if (!$el) return "";
|
|
16310
|
-
if ($el.tomselect) return $el.tomselect.getValue();
|
|
16311
|
-
return $el.value;
|
|
16312
|
-
}
|
|
16313
|
-
case "jsoneditor": {
|
|
16314
|
-
let $el = $field.querySelector(".jsoneditor");
|
|
16315
|
-
if (!$el || !$el.jsoneditor) return "";
|
|
16316
|
-
let val = $el.jsoneditor.get();
|
|
16317
|
-
if (val.text !== void 0) return val.text;
|
|
16318
|
-
return JSON.stringify(val.json);
|
|
16319
|
-
}
|
|
16320
|
-
case "radio": {
|
|
16321
|
-
let $checked = $field.querySelector("input[type=\"radio\"]:checked");
|
|
16322
|
-
if (!$checked) return "";
|
|
16323
|
-
return $checked.value;
|
|
16280
|
+
function request_close_form_dialog(gobj) {
|
|
16281
|
+
let priv = gobj.priv;
|
|
16282
|
+
if (priv.form) {
|
|
16283
|
+
let kw = {};
|
|
16284
|
+
(0, _yuneta_gobj_js.gobj_send_event)(priv.form, "EV_WINDOW_TO_CLOSE", kw, gobj);
|
|
16285
|
+
if (kw.abort_close) {
|
|
16286
|
+
get_yesnocancel((0, i18next.t)("All changes will be lost. Are you sure?"), function(evt) {
|
|
16287
|
+
if (evt === "yes") close_form_dialog(gobj);
|
|
16288
|
+
});
|
|
16289
|
+
return;
|
|
16324
16290
|
}
|
|
16325
16291
|
}
|
|
16326
|
-
|
|
16292
|
+
close_form_dialog(gobj);
|
|
16327
16293
|
}
|
|
16328
16294
|
/************************************************************
|
|
16329
|
-
*
|
|
16295
|
+
* Destroy the hosted form and remove the dialog DOM.
|
|
16330
16296
|
************************************************************/
|
|
16331
|
-
function
|
|
16332
|
-
|
|
16333
|
-
if (
|
|
16334
|
-
|
|
16335
|
-
|
|
16336
|
-
|
|
16337
|
-
* Determine if a field requires validation in the current mode
|
|
16338
|
-
************************************************************/
|
|
16339
|
-
function is_field_required(conf, mode) {
|
|
16340
|
-
if (conf.is_pkey) return mode === "create" && !conf.is_rowid;
|
|
16341
|
-
if (conf.readonly) return false;
|
|
16342
|
-
return conf.required || conf.not_null;
|
|
16343
|
-
}
|
|
16344
|
-
/************************************************************
|
|
16345
|
-
* Validate a single field on blur
|
|
16346
|
-
* Called from input/textarea blur event handlers
|
|
16347
|
-
************************************************************/
|
|
16348
|
-
function validate_field_on_blur(element) {
|
|
16349
|
-
let $field = element.closest(".xfield");
|
|
16350
|
-
if (!$field || !$field.field_conf) return;
|
|
16351
|
-
let conf = $field.field_conf;
|
|
16352
|
-
let $form = element.closest("form");
|
|
16353
|
-
if (!is_field_required(conf, $form ? $form.__mode__ : "update")) {
|
|
16354
|
-
clear_field_error($field);
|
|
16355
|
-
return;
|
|
16297
|
+
function close_form_dialog(gobj) {
|
|
16298
|
+
let priv = gobj.priv;
|
|
16299
|
+
if (priv.form) {
|
|
16300
|
+
if ((0, _yuneta_gobj_js.gobj_is_running)(priv.form)) (0, _yuneta_gobj_js.gobj_stop)(priv.form);
|
|
16301
|
+
(0, _yuneta_gobj_js.gobj_destroy)(priv.form);
|
|
16302
|
+
priv.form = null;
|
|
16356
16303
|
}
|
|
16357
|
-
if (
|
|
16358
|
-
|
|
16359
|
-
|
|
16360
|
-
/************************************************************
|
|
16361
|
-
* Validate all required fields in the form
|
|
16362
|
-
* Returns true if valid, false otherwise
|
|
16363
|
-
************************************************************/
|
|
16364
|
-
function validate_form(gobj, $form) {
|
|
16365
|
-
let is_valid = true;
|
|
16366
|
-
let first_invalid = null;
|
|
16367
|
-
let mode = $form.__mode__ || "update";
|
|
16368
|
-
$form.querySelectorAll(".xfield").forEach(($field) => {
|
|
16369
|
-
let conf = $field.field_conf;
|
|
16370
|
-
if (!conf) return;
|
|
16371
|
-
if (!is_field_required(conf, mode)) {
|
|
16372
|
-
clear_field_error($field);
|
|
16373
|
-
return;
|
|
16374
|
-
}
|
|
16375
|
-
if (is_field_value_empty(get_field_value_for_validation($field, conf))) {
|
|
16376
|
-
show_field_error($field, (0, i18next.t)("this field is required"));
|
|
16377
|
-
is_valid = false;
|
|
16378
|
-
if (!first_invalid) first_invalid = $field;
|
|
16379
|
-
} else clear_field_error($field);
|
|
16380
|
-
});
|
|
16381
|
-
if (first_invalid) {
|
|
16382
|
-
let $focusable = first_invalid.querySelector("input, select, textarea");
|
|
16383
|
-
if ($focusable && $focusable.focus) $focusable.focus();
|
|
16304
|
+
if (priv.$popup) {
|
|
16305
|
+
if (priv.$popup.parentNode) priv.$popup.parentNode.removeChild(priv.$popup);
|
|
16306
|
+
priv.$popup = null;
|
|
16384
16307
|
}
|
|
16385
|
-
return is_valid;
|
|
16386
|
-
}
|
|
16387
|
-
/************************************************************
|
|
16388
|
-
* Clear all validation errors from the form
|
|
16389
|
-
************************************************************/
|
|
16390
|
-
function clear_validation(gobj, $form) {
|
|
16391
|
-
$form.querySelectorAll(".xfield").forEach(($field) => {
|
|
16392
|
-
clear_field_error($field);
|
|
16393
|
-
});
|
|
16394
16308
|
}
|
|
16395
16309
|
/************************************************************
|
|
16396
|
-
*
|
|
16397
|
-
* set form state "update" or "create"
|
|
16398
|
-
* Only the "id" field is modified,
|
|
16399
|
-
* in "update" is readonly
|
|
16400
|
-
* in "create" is writable
|
|
16401
|
-
* Although by default the pkey (primary key) is "id",
|
|
16402
|
-
* use always desc.pkey value, who knows all cases!
|
|
16310
|
+
* True if the topic's pkey col carries the "rowid" flag.
|
|
16403
16311
|
************************************************************/
|
|
16404
|
-
function
|
|
16312
|
+
function pkey_is_rowid(gobj) {
|
|
16405
16313
|
let desc = (0, _yuneta_gobj_js.gobj_read_attr)(gobj, "desc");
|
|
16406
|
-
let
|
|
16407
|
-
|
|
16408
|
-
|
|
16409
|
-
$id.setAttribute("readonly", "readonly");
|
|
16410
|
-
$id.removeAttribute("required");
|
|
16411
|
-
} else if (is_rowid) {
|
|
16412
|
-
$id.setAttribute("readonly", "readonly");
|
|
16413
|
-
$id.removeAttribute("required");
|
|
16414
|
-
} else {
|
|
16415
|
-
$id.removeAttribute("readonly");
|
|
16416
|
-
$id.setAttribute("required", "");
|
|
16417
|
-
}
|
|
16418
|
-
else (0, _yuneta_gobj_js.log_error)((0, _yuneta_gobj_js.sprintf)("%s: form without id field ('%s')", (0, _yuneta_gobj_js.gobj_short_name)(gobj), desc.pkey));
|
|
16419
|
-
if (is_rowid) mode = "create";
|
|
16420
|
-
$form.__mode__ = mode;
|
|
16421
|
-
$form.__index__ = index;
|
|
16314
|
+
let col_pkey = (0, _yuneta_gobj_js.kwid_find_one_record)(gobj, desc.cols, null, { "id": desc.pkey });
|
|
16315
|
+
if (!col_pkey) return false;
|
|
16316
|
+
return (0, _yuneta_gobj_js.str_in_list)(col_pkey.flag, "rowid");
|
|
16422
16317
|
}
|
|
16423
16318
|
/************************************************************
|
|
16424
16319
|
* Show the edit "update" form of a row (record)
|
|
16425
16320
|
* internally called from the icon edit at Op column
|
|
16426
16321
|
************************************************************/
|
|
16427
16322
|
function show_edit_form(gobj, row, index) {
|
|
16428
|
-
|
|
16429
|
-
let form_id = (0, _yuneta_gobj_js.gobj_read_str_attr)(gobj, "form_id");
|
|
16430
|
-
let $element = document.getElementById(popup_id);
|
|
16431
|
-
if (!$element) $element = build_topic_modal(gobj);
|
|
16432
|
-
let $form = document.getElementById(form_id);
|
|
16433
|
-
clear_validation(gobj, $form);
|
|
16434
|
-
if ((0, _yuneta_gobj_js.json_size)(row) === 0 || (0, _yuneta_gobj_js.json_size)(row) === 1 && "_check_box_state_" in row) set_form_mode(gobj, $form, "create", index);
|
|
16435
|
-
else set_form_mode(gobj, $form, "update", index);
|
|
16436
|
-
set_form_values(gobj, $form, row);
|
|
16437
|
-
$element.classList.add("is-active");
|
|
16438
|
-
let $with_focus = $element.querySelector(".with-focus");
|
|
16439
|
-
if ($with_focus) $with_focus.focus();
|
|
16323
|
+
open_form_dialog(gobj, pkey_is_rowid(gobj) ? "create" : "update", row);
|
|
16440
16324
|
}
|
|
16441
16325
|
/************************************************************
|
|
16442
16326
|
* Show the edit "create" form to a new record
|
|
16443
16327
|
* internally called from the top toolbar +New button
|
|
16444
16328
|
************************************************************/
|
|
16445
16329
|
function show_create_form(gobj, row) {
|
|
16446
|
-
|
|
16447
|
-
let form_id = (0, _yuneta_gobj_js.gobj_read_str_attr)(gobj, "form_id");
|
|
16448
|
-
let $element = document.getElementById(popup_id);
|
|
16449
|
-
if (!$element) $element = build_topic_modal(gobj);
|
|
16450
|
-
let $form = document.getElementById(form_id);
|
|
16451
|
-
clear_validation(gobj, $form);
|
|
16452
|
-
set_form_mode(gobj, $form, "create", -1);
|
|
16453
|
-
set_form_values(gobj, $form, row);
|
|
16454
|
-
$element.classList.add("is-active");
|
|
16455
|
-
let $with_focus = $element.querySelector(".with-focus");
|
|
16456
|
-
if ($with_focus) $with_focus.focus();
|
|
16330
|
+
open_form_dialog(gobj, "create", row);
|
|
16457
16331
|
}
|
|
16458
16332
|
/************************************************************
|
|
16459
16333
|
* Return column schema of field id
|
|
@@ -16467,174 +16341,6 @@ function get_schema_col(gobj, id) {
|
|
|
16467
16341
|
return null;
|
|
16468
16342
|
}
|
|
16469
16343
|
/************************************************************
|
|
16470
|
-
*
|
|
16471
|
-
************************************************************/
|
|
16472
|
-
function clear_data(gobj, $form) {
|
|
16473
|
-
$form.querySelectorAll("input, select, textarea, .jsoneditor").forEach((input) => {
|
|
16474
|
-
if (input.name !== "id") if (input.classList.contains("jsoneditor")) {
|
|
16475
|
-
let jsoneditor = input.jsoneditor;
|
|
16476
|
-
if (jsoneditor) jsoneditor.set({ text: "" });
|
|
16477
|
-
} else if (input.type === "checkbox") input.checked = false;
|
|
16478
|
-
else if (input.type === "radio") input.checked = false;
|
|
16479
|
-
else if (input.type === "datetime-local") input.value = null;
|
|
16480
|
-
else if (input.multiple) {
|
|
16481
|
-
if (input.tomselect) input.tomselect.clear();
|
|
16482
|
-
} else input.value = null;
|
|
16483
|
-
});
|
|
16484
|
-
}
|
|
16485
|
-
/************************************************************
|
|
16486
|
-
*
|
|
16487
|
-
************************************************************/
|
|
16488
|
-
function get_form_values($form) {
|
|
16489
|
-
const values = {};
|
|
16490
|
-
$form.querySelectorAll("input, select, textarea, .jsoneditor").forEach((input) => {
|
|
16491
|
-
if (input.classList.contains("jsoneditor")) {
|
|
16492
|
-
let jsoneditor = input.jsoneditor;
|
|
16493
|
-
if (jsoneditor) {
|
|
16494
|
-
let name = input.getAttribute("name");
|
|
16495
|
-
let value = jsoneditor.get();
|
|
16496
|
-
if (value.text === void 0) values[name] = JSON.stringify(value.json, null, null);
|
|
16497
|
-
else values[name] = value.text;
|
|
16498
|
-
}
|
|
16499
|
-
} else if (input.type === "checkbox") values[input.name] = input.checked;
|
|
16500
|
-
else if (input.type === "radio") {
|
|
16501
|
-
if (input.checked) values[input.name] = input.value;
|
|
16502
|
-
} else if (input.type === "datetime-local") {
|
|
16503
|
-
const date = new Date(input.value);
|
|
16504
|
-
const epochTime = Math.floor(date.getTime() / 1e3);
|
|
16505
|
-
values[input.name] = epochTime;
|
|
16506
|
-
} else if (input.multiple) {
|
|
16507
|
-
if (input.tomselect) values[input.name] = input.tomselect.getValue();
|
|
16508
|
-
} else values[input.name] = input.value;
|
|
16509
|
-
});
|
|
16510
|
-
return values;
|
|
16511
|
-
}
|
|
16512
|
-
/************************************************************
|
|
16513
|
-
* Convert a record column value from backend to frontend
|
|
16514
|
-
************************************************************/
|
|
16515
|
-
function epochToDateTimeLocal(epochTime) {
|
|
16516
|
-
const date = /* @__PURE__ */ new Date(epochTime * 1e3);
|
|
16517
|
-
const year = date.getFullYear();
|
|
16518
|
-
const month = String(date.getMonth() + 1).padStart(2, "0");
|
|
16519
|
-
const day = String(date.getDate()).padStart(2, "0");
|
|
16520
|
-
const hours = String(date.getHours()).padStart(2, "0");
|
|
16521
|
-
const minutes = String(date.getMinutes()).padStart(2, "0");
|
|
16522
|
-
String(date.getSeconds()).padStart(2, "0");
|
|
16523
|
-
return `${year}-${month}-${day}T${hours}:${minutes}`;
|
|
16524
|
-
}
|
|
16525
|
-
/************************************************************
|
|
16526
|
-
*
|
|
16527
|
-
************************************************************/
|
|
16528
|
-
function set_form_values(gobj, form, values) {
|
|
16529
|
-
Object.keys(values).forEach((key) => {
|
|
16530
|
-
let element = form.querySelector(`[name="${key}"]`);
|
|
16531
|
-
if (element) {
|
|
16532
|
-
let value = values[key];
|
|
16533
|
-
let col = get_schema_col(gobj, key);
|
|
16534
|
-
if (col) value = transform__treedb_value_2_form_value(gobj, col, value);
|
|
16535
|
-
switch (element.type) {
|
|
16536
|
-
case "select":
|
|
16537
|
-
element.value = value;
|
|
16538
|
-
break;
|
|
16539
|
-
case "select-one":
|
|
16540
|
-
element.value = value;
|
|
16541
|
-
break;
|
|
16542
|
-
case "select-multiple":
|
|
16543
|
-
if (element.tomselect) element.tomselect.setValue(value);
|
|
16544
|
-
break;
|
|
16545
|
-
case "radio":
|
|
16546
|
-
let radio = form.querySelector(`input[name="${key}"][value="${values[key]}"]`);
|
|
16547
|
-
if (radio) radio.checked = true;
|
|
16548
|
-
break;
|
|
16549
|
-
case "checkbox":
|
|
16550
|
-
element.checked = value;
|
|
16551
|
-
break;
|
|
16552
|
-
case "text":
|
|
16553
|
-
case "textarea":
|
|
16554
|
-
case "email":
|
|
16555
|
-
element.value = value;
|
|
16556
|
-
break;
|
|
16557
|
-
case "datetime-local":
|
|
16558
|
-
element.value = epochToDateTimeLocal(value);
|
|
16559
|
-
break;
|
|
16560
|
-
default:
|
|
16561
|
-
if (element.classList.contains("jsoneditor")) {
|
|
16562
|
-
let jsoneditor = element.jsoneditor;
|
|
16563
|
-
if (jsoneditor) jsoneditor.set(value);
|
|
16564
|
-
break;
|
|
16565
|
-
}
|
|
16566
|
-
element.value = value;
|
|
16567
|
-
(0, _yuneta_gobj_js.log_error)((0, _yuneta_gobj_js.sprintf)("%s: form type unknown: '%s'", (0, _yuneta_gobj_js.gobj_short_name)(gobj), element.type));
|
|
16568
|
-
break;
|
|
16569
|
-
}
|
|
16570
|
-
}
|
|
16571
|
-
});
|
|
16572
|
-
}
|
|
16573
|
-
/************************************************************
|
|
16574
|
-
* Convert a record column value from backend
|
|
16575
|
-
* to frontend form field
|
|
16576
|
-
************************************************************/
|
|
16577
|
-
function transform__treedb_value_2_form_value(gobj, col, value) {
|
|
16578
|
-
const field_desc = (0, _yuneta_gobj_js.treedb_get_field_desc)(col);
|
|
16579
|
-
switch (field_desc.type) {
|
|
16580
|
-
case "string":
|
|
16581
|
-
case "email":
|
|
16582
|
-
case "tel":
|
|
16583
|
-
case "url": break;
|
|
16584
|
-
case "integer": break;
|
|
16585
|
-
case "real": break;
|
|
16586
|
-
case "boolean": break;
|
|
16587
|
-
case "object":
|
|
16588
|
-
case "dict":
|
|
16589
|
-
case "template":
|
|
16590
|
-
case "array":
|
|
16591
|
-
case "list":
|
|
16592
|
-
case "coordinates":
|
|
16593
|
-
case "blob":
|
|
16594
|
-
value = { json: value };
|
|
16595
|
-
break;
|
|
16596
|
-
case "enum":
|
|
16597
|
-
switch (field_desc.real_type) {
|
|
16598
|
-
case "string": break;
|
|
16599
|
-
case "object":
|
|
16600
|
-
case "dict":
|
|
16601
|
-
case "array":
|
|
16602
|
-
case "list": break;
|
|
16603
|
-
}
|
|
16604
|
-
break;
|
|
16605
|
-
case "now":
|
|
16606
|
-
case "time":
|
|
16607
|
-
switch (field_desc.real_type) {
|
|
16608
|
-
case "string":
|
|
16609
|
-
case "integer":
|
|
16610
|
-
value = parseInt(value) || 0;
|
|
16611
|
-
value = new Date(value);
|
|
16612
|
-
break;
|
|
16613
|
-
}
|
|
16614
|
-
break;
|
|
16615
|
-
case "color":
|
|
16616
|
-
switch (field_desc.real_type) {
|
|
16617
|
-
case "string": break;
|
|
16618
|
-
case "integer": break;
|
|
16619
|
-
}
|
|
16620
|
-
break;
|
|
16621
|
-
case "hook": break;
|
|
16622
|
-
case "fkey":
|
|
16623
|
-
let new_value = [];
|
|
16624
|
-
if (value) if ((0, _yuneta_gobj_js.is_string)(value)) {
|
|
16625
|
-
let fkey = (0, _yuneta_gobj_js.treedb_decoder_fkey)(col, value);
|
|
16626
|
-
if (fkey) new_value.push(fkey.id);
|
|
16627
|
-
} else if ((0, _yuneta_gobj_js.is_array)(value)) for (let i = 0; i < value.length; i++) {
|
|
16628
|
-
let fkey = (0, _yuneta_gobj_js.treedb_decoder_fkey)(col, value[i]);
|
|
16629
|
-
if (fkey) new_value.push(fkey.id);
|
|
16630
|
-
}
|
|
16631
|
-
else (0, _yuneta_gobj_js.log_error)("fkey type unsupported: " + JSON.stringify(value));
|
|
16632
|
-
value = new_value;
|
|
16633
|
-
break;
|
|
16634
|
-
}
|
|
16635
|
-
return value;
|
|
16636
|
-
}
|
|
16637
|
-
/************************************************************
|
|
16638
16344
|
* Convert from frontend to backend
|
|
16639
16345
|
* operation: "create" "update"
|
|
16640
16346
|
************************************************************/
|
|
@@ -16758,18 +16464,6 @@ function transform__form_value_2_treedb_value(gobj, col, value, operation) {
|
|
|
16758
16464
|
/************************************************************
|
|
16759
16465
|
*
|
|
16760
16466
|
************************************************************/
|
|
16761
|
-
function get_fkey_options(gobj, col) {
|
|
16762
|
-
for (let topic_name of Object.keys(col.fkey)) {
|
|
16763
|
-
let kw = { topic_name };
|
|
16764
|
-
let current_list = (0, _yuneta_gobj_js.gobj_command)((0, _yuneta_gobj_js.gobj_parent)(gobj), "get_topic_data", kw, gobj).data;
|
|
16765
|
-
return (0, _yuneta_gobj_js.list2options)(current_list, "id", "id");
|
|
16766
|
-
}
|
|
16767
|
-
(0, _yuneta_gobj_js.log_error)("No fkey options found" + JSON.stringify(col));
|
|
16768
|
-
return null;
|
|
16769
|
-
}
|
|
16770
|
-
/************************************************************
|
|
16771
|
-
*
|
|
16772
|
-
************************************************************/
|
|
16773
16467
|
function fkey_in_col(col, topic_name, hook_name) {
|
|
16774
16468
|
if (hook_name === col.fkey[topic_name]) return true;
|
|
16775
16469
|
return false;
|
|
@@ -17099,37 +16793,18 @@ function ac_paste_rows(gobj, event, kw, src) {
|
|
|
17099
16793
|
return 0;
|
|
17100
16794
|
}
|
|
17101
16795
|
/************************************************************
|
|
17102
|
-
*
|
|
17103
|
-
|
|
17104
|
-
|
|
17105
|
-
let new_kw = null;
|
|
17106
|
-
try {
|
|
17107
|
-
new_kw = transform__form_record_2_treedb_record(gobj, kw, "create");
|
|
17108
|
-
} catch (e) {
|
|
17109
|
-
(0, _yuneta_gobj_js.log_warning)(e);
|
|
17110
|
-
throw e;
|
|
17111
|
-
}
|
|
17112
|
-
(0, _yuneta_gobj_js.gobj_publish_event)(gobj, "EV_CREATE_RECORD", {
|
|
17113
|
-
topic_name: (0, _yuneta_gobj_js.gobj_read_str_attr)(gobj, "topic_name"),
|
|
17114
|
-
record: new_kw
|
|
17115
|
-
});
|
|
17116
|
-
return 0;
|
|
17117
|
-
}
|
|
17118
|
-
/************************************************************
|
|
17119
|
-
* From internal Save button of "update" modal form
|
|
16796
|
+
* EV_SAVE_RECORD from the hosted C_YUI_FORM: kw is the
|
|
16797
|
+
* record already in treedb shape (the form itself encodes
|
|
16798
|
+
* fkeys, times and numbers). Route by the form's mode.
|
|
17120
16799
|
************************************************************/
|
|
17121
|
-
function
|
|
17122
|
-
|
|
17123
|
-
try {
|
|
17124
|
-
new_kw = transform__form_record_2_treedb_record(gobj, kw, "update");
|
|
17125
|
-
} catch (e) {
|
|
17126
|
-
(0, _yuneta_gobj_js.log_warning)(e);
|
|
17127
|
-
throw e;
|
|
17128
|
-
}
|
|
17129
|
-
(0, _yuneta_gobj_js.gobj_publish_event)(gobj, "EV_UPDATE_RECORD", {
|
|
16800
|
+
function ac_form_save_record(gobj, event, kw, src) {
|
|
16801
|
+
(0, _yuneta_gobj_js.gobj_publish_event)(gobj, (0, _yuneta_gobj_js.gobj_read_str_attr)(src, "form_mode") === "create" ? "EV_CREATE_RECORD" : "EV_UPDATE_RECORD", {
|
|
17130
16802
|
topic_name: (0, _yuneta_gobj_js.gobj_read_str_attr)(gobj, "topic_name"),
|
|
17131
|
-
record:
|
|
16803
|
+
record: kw
|
|
17132
16804
|
});
|
|
16805
|
+
setTimeout(function() {
|
|
16806
|
+
close_form_dialog(gobj);
|
|
16807
|
+
}, 0);
|
|
17133
16808
|
return 0;
|
|
17134
16809
|
}
|
|
17135
16810
|
/************************************************************
|
|
@@ -17259,13 +16934,8 @@ function create_gclass$2(gclass_name) {
|
|
|
17259
16934
|
null
|
|
17260
16935
|
],
|
|
17261
16936
|
[
|
|
17262
|
-
"
|
|
17263
|
-
|
|
17264
|
-
null
|
|
17265
|
-
],
|
|
17266
|
-
[
|
|
17267
|
-
"EV_UPDATE_RECORD",
|
|
17268
|
-
ac_update_record,
|
|
16937
|
+
"EV_SAVE_RECORD",
|
|
16938
|
+
ac_form_save_record,
|
|
17269
16939
|
null
|
|
17270
16940
|
],
|
|
17271
16941
|
[
|
|
@@ -17330,6 +17000,7 @@ function create_gclass$2(gclass_name) {
|
|
|
17330
17000
|
["EV_LOAD_NODE_UPDATED", 0],
|
|
17331
17001
|
["EV_NODE_DELETED", 0],
|
|
17332
17002
|
["EV_EDITION_MODE", 0],
|
|
17003
|
+
["EV_SAVE_RECORD", 0],
|
|
17333
17004
|
["EV_NEW_ROW", 0],
|
|
17334
17005
|
["EV_DELETE_ROWS", 0],
|
|
17335
17006
|
["EV_COPY_ROWS", 0],
|
|
@@ -17353,6 +17024,7 @@ function create_gclass$2(gclass_name) {
|
|
|
17353
17024
|
* Register GClass
|
|
17354
17025
|
***************************************************************/
|
|
17355
17026
|
function register_c_yui_treedb_topic_with_form() {
|
|
17027
|
+
if (!(0, _yuneta_gobj_js.gclass_find_by_name)("C_YUI_FORM", false)) register_c_yui_form();
|
|
17356
17028
|
return create_gclass$2(GCLASS_NAME$2);
|
|
17357
17029
|
}
|
|
17358
17030
|
//#endregion
|