@yuneta/gobj-ui 2.3.0 → 2.4.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/dist/gobj-ui.cjs.js +46 -7
- package/dist/gobj-ui.es.js +47 -8
- package/package.json +2 -2
- package/src/c_yui_form.css +50 -0
- package/src/c_yui_form.js +22 -4
- package/src/c_yui_shell.css +10 -2
- package/src/c_yui_treedb_topic_with_form.css +23 -0
- package/src/c_yui_treedb_topic_with_form.js +47 -4
package/dist/gobj-ui.cjs.js
CHANGED
|
@@ -5383,7 +5383,7 @@ function register_c_yui_wizard() {
|
|
|
5383
5383
|
*
|
|
5384
5384
|
* Form (in Window or not)
|
|
5385
5385
|
*
|
|
5386
|
-
* Copyright (c) 2024-
|
|
5386
|
+
* Copyright (c) 2024-2026, ArtGins.
|
|
5387
5387
|
* All Rights Reserved.
|
|
5388
5388
|
***********************************************************************/
|
|
5389
5389
|
/***************************************************************
|
|
@@ -5998,6 +5998,17 @@ function apply_form_mode(gobj, $form) {
|
|
|
5998
5998
|
}
|
|
5999
5999
|
}
|
|
6000
6000
|
/******************************************************************
|
|
6001
|
+
* True when the app renders dark: explicit <html data-theme>, or
|
|
6002
|
+
* the OS scheme when the attribute is absent ("system" theme
|
|
6003
|
+
* removes it — see themes.js). Read at field-build time; the
|
|
6004
|
+
* hosting dialog rebuilds the form on every open.
|
|
6005
|
+
******************************************************************/
|
|
6006
|
+
function form_is_dark_theme() {
|
|
6007
|
+
let attr = document.documentElement.getAttribute("data-theme");
|
|
6008
|
+
if (attr) return attr === "dark";
|
|
6009
|
+
return typeof window !== "undefined" && window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches;
|
|
6010
|
+
}
|
|
6011
|
+
/******************************************************************
|
|
6001
6012
|
* With html field conf builds an html element,
|
|
6002
6013
|
* ready to add to the form
|
|
6003
6014
|
*
|
|
@@ -6438,7 +6449,7 @@ function create_form_field(gobj, $form, prefix, field_desc, { tag, inputType, na
|
|
|
6438
6449
|
break;
|
|
6439
6450
|
case "jsoneditor": {
|
|
6440
6451
|
let attrs = {
|
|
6441
|
-
class: "jsoneditor jse-theme-dark",
|
|
6452
|
+
class: "jsoneditor" + (form_is_dark_theme() ? " jse-theme-dark" : ""),
|
|
6442
6453
|
name,
|
|
6443
6454
|
style: ""
|
|
6444
6455
|
};
|
|
@@ -6447,7 +6458,7 @@ function create_form_field(gobj, $form, prefix, field_desc, { tag, inputType, na
|
|
|
6447
6458
|
else if (required) attrs.required = "";
|
|
6448
6459
|
$extend = (0, _yuneta_gobj_js.createElement2)(["div", attrs]);
|
|
6449
6460
|
$control.appendChild($extend);
|
|
6450
|
-
$extend.jsoneditor =
|
|
6461
|
+
$extend.jsoneditor = (0, vanilla_jsoneditor.createJSONEditor)({
|
|
6451
6462
|
target: $extend,
|
|
6452
6463
|
props: {
|
|
6453
6464
|
readOnly: !!readonly,
|
|
@@ -15402,7 +15413,7 @@ function register_c_yui_treedb_topics() {
|
|
|
15402
15413
|
*
|
|
15403
15414
|
* Table of TreeDB topic with FORM for editing
|
|
15404
15415
|
*
|
|
15405
|
-
* Copyright (c) 2025, ArtGins.
|
|
15416
|
+
* Copyright (c) 2025-2026, ArtGins.
|
|
15406
15417
|
* All Rights Reserved.
|
|
15407
15418
|
***********************************************************************/
|
|
15408
15419
|
/***************************************************************
|
|
@@ -15457,7 +15468,8 @@ var PRIVATE_DATA$2 = {
|
|
|
15457
15468
|
topic_name: "",
|
|
15458
15469
|
tabulator: null,
|
|
15459
15470
|
form: null,
|
|
15460
|
-
$popup: null
|
|
15471
|
+
$popup: null,
|
|
15472
|
+
on_keydown: null
|
|
15461
15473
|
};
|
|
15462
15474
|
var __gclass__$2 = null;
|
|
15463
15475
|
function popup_mount_layer() {
|
|
@@ -16026,6 +16038,14 @@ function create_tabulator(gobj) {
|
|
|
16026
16038
|
n = 0;
|
|
16027
16039
|
}
|
|
16028
16040
|
$rc.textContent = `${n} ${(0, i18next.t)("rows")}`;
|
|
16041
|
+
let single_page = true;
|
|
16042
|
+
try {
|
|
16043
|
+
let max = tabulator.getPageMax();
|
|
16044
|
+
single_page = max === false || max <= 1;
|
|
16045
|
+
} catch (e) {
|
|
16046
|
+
single_page = true;
|
|
16047
|
+
}
|
|
16048
|
+
tabulator.element.classList.toggle("yui-single-page", single_page);
|
|
16029
16049
|
}
|
|
16030
16050
|
tabulator._ready = false;
|
|
16031
16051
|
tabulator.on("tableBuilt", function() {
|
|
@@ -16201,6 +16221,13 @@ function open_form_dialog(gobj, mode, record) {
|
|
|
16201
16221
|
let desc = (0, _yuneta_gobj_js.gobj_read_attr)(gobj, "desc");
|
|
16202
16222
|
let popup_id = (0, _yuneta_gobj_js.gobj_read_str_attr)(gobj, "popup_id");
|
|
16203
16223
|
let topic_name = (0, _yuneta_gobj_js.gobj_read_str_attr)(gobj, "topic_name");
|
|
16224
|
+
let pkey = desc.pkey || "id";
|
|
16225
|
+
let title;
|
|
16226
|
+
if (mode === "create") title = (0, i18next.t)("new") + " " + (0, i18next.t)(topic_name);
|
|
16227
|
+
else {
|
|
16228
|
+
let rid = record ? String(record[pkey] ?? "") : "";
|
|
16229
|
+
title = (0, i18next.t)(topic_name) + ((0, _yuneta_gobj_js.empty_string)(rid) ? "" : " — " + rid);
|
|
16230
|
+
}
|
|
16204
16231
|
let $element = (0, _yuneta_gobj_js.createElement2)([
|
|
16205
16232
|
"div",
|
|
16206
16233
|
{
|
|
@@ -16223,7 +16250,7 @@ function open_form_dialog(gobj, mode, record) {
|
|
|
16223
16250
|
class: "modal-card-title",
|
|
16224
16251
|
style: "text-align:center;"
|
|
16225
16252
|
},
|
|
16226
|
-
|
|
16253
|
+
title
|
|
16227
16254
|
], [
|
|
16228
16255
|
"button",
|
|
16229
16256
|
{
|
|
@@ -16269,8 +16296,16 @@ function open_form_dialog(gobj, mode, record) {
|
|
|
16269
16296
|
}
|
|
16270
16297
|
popup_mount_layer().appendChild($element);
|
|
16271
16298
|
(0, _yuneta_gobj_js.refresh_language)($element, i18next.t);
|
|
16299
|
+
priv.on_keydown = function(evt) {
|
|
16300
|
+
if (evt.key === "Escape") {
|
|
16301
|
+
evt.stopPropagation();
|
|
16302
|
+
request_close_form_dialog(gobj);
|
|
16303
|
+
}
|
|
16304
|
+
};
|
|
16305
|
+
document.addEventListener("keydown", priv.on_keydown);
|
|
16272
16306
|
(0, _yuneta_gobj_js.gobj_start)(form);
|
|
16273
|
-
let $with_focus = $element.querySelector(".with-focus");
|
|
16307
|
+
let $with_focus = $element.querySelector(".with-focus:not([readonly])");
|
|
16308
|
+
if (!$with_focus) $with_focus = $element.querySelector("input.input:not([readonly]), textarea, select");
|
|
16274
16309
|
if ($with_focus) $with_focus.focus();
|
|
16275
16310
|
}
|
|
16276
16311
|
/************************************************************
|
|
@@ -16296,6 +16331,10 @@ function request_close_form_dialog(gobj) {
|
|
|
16296
16331
|
************************************************************/
|
|
16297
16332
|
function close_form_dialog(gobj) {
|
|
16298
16333
|
let priv = gobj.priv;
|
|
16334
|
+
if (priv.on_keydown) {
|
|
16335
|
+
document.removeEventListener("keydown", priv.on_keydown);
|
|
16336
|
+
priv.on_keydown = null;
|
|
16337
|
+
}
|
|
16299
16338
|
if (priv.form) {
|
|
16300
16339
|
if ((0, _yuneta_gobj_js.gobj_is_running)(priv.form)) (0, _yuneta_gobj_js.gobj_stop)(priv.form);
|
|
16301
16340
|
(0, _yuneta_gobj_js.gobj_destroy)(priv.form);
|
package/dist/gobj-ui.es.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { SDATA, SDATA_END, clean_name, createElement2, createOneHtml, create_template_record, data_type_t, debounce, duplicate_objects, empty_string, escapeHtml, event_flag_t, gclass_create, gclass_find_by_name, gclass_flag_t, getPositionRelativeToBody, gobj_command, gobj_create, gobj_create_pure_child, gobj_create_service, gobj_current_state, gobj_default_service, gobj_destroy, gobj_find_child, gobj_find_service, gobj_full_name, gobj_gclass_name, gobj_has_attr, gobj_is_destroying, gobj_is_playing, gobj_is_pure_child, gobj_is_running, gobj_is_service, gobj_is_volatil, gobj_match_children, gobj_name, gobj_parent, gobj_publish_event, gobj_read_attr, gobj_read_bool_attr, gobj_read_integer_attr, gobj_read_pointer_attr, gobj_read_str_attr, gobj_save_persistent_attrs, gobj_send_event, gobj_set_trace_machine_format, gobj_short_name, gobj_start, gobj_stop, gobj_stop_children, gobj_subscribe_event, gobj_unsubscribe_event, gobj_write_attr, gobj_write_bool_attr, gobj_write_integer_attr, gobj_write_str_attr, gobj_yuno, is_array, is_boolean, is_date, is_gobj, is_null, is_number, is_object, is_pure_number, is_string, json_deep_copy, json_object_size, json_object_update, json_object_update_missing, json_size, kw_clone_by_keys, kw_flag_t, kw_get_dict, kw_get_dict_value, kw_get_int, kw_get_local_storage_value, kw_get_str, kw_has_key, kw_set_dict_value, kw_set_local_storage_value, kwid_find_one_record, kwid_get_ids, kwid_new_dict, log_error, log_warning, msg_iev_get_stack, parseBoolean, parseSVG, refresh_language, safeSrc, sdata_flag_t, set_log_callback, sprintf, str_in_list, template_get_field_desc, trace_json, trace_msg, treedb_decoder_fkey, treedb_encoder_fkey, treedb_get_field_desc, treedb_hook_data_size } from "@yuneta/gobj-js";
|
|
2
2
|
import i18next, { t } from "i18next";
|
|
3
3
|
import TomSelect from "tom-select";
|
|
4
|
-
import {
|
|
4
|
+
import { createJSONEditor } from "vanilla-jsoneditor";
|
|
5
5
|
import { TabulatorFull } from "tabulator-tables";
|
|
6
6
|
import maplibregl from "maplibre-gl";
|
|
7
7
|
import uPlot from "uplot";
|
|
@@ -5378,7 +5378,7 @@ function register_c_yui_wizard() {
|
|
|
5378
5378
|
*
|
|
5379
5379
|
* Form (in Window or not)
|
|
5380
5380
|
*
|
|
5381
|
-
* Copyright (c) 2024-
|
|
5381
|
+
* Copyright (c) 2024-2026, ArtGins.
|
|
5382
5382
|
* All Rights Reserved.
|
|
5383
5383
|
***********************************************************************/
|
|
5384
5384
|
/***************************************************************
|
|
@@ -5993,6 +5993,17 @@ function apply_form_mode(gobj, $form) {
|
|
|
5993
5993
|
}
|
|
5994
5994
|
}
|
|
5995
5995
|
/******************************************************************
|
|
5996
|
+
* True when the app renders dark: explicit <html data-theme>, or
|
|
5997
|
+
* the OS scheme when the attribute is absent ("system" theme
|
|
5998
|
+
* removes it — see themes.js). Read at field-build time; the
|
|
5999
|
+
* hosting dialog rebuilds the form on every open.
|
|
6000
|
+
******************************************************************/
|
|
6001
|
+
function form_is_dark_theme() {
|
|
6002
|
+
let attr = document.documentElement.getAttribute("data-theme");
|
|
6003
|
+
if (attr) return attr === "dark";
|
|
6004
|
+
return typeof window !== "undefined" && window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches;
|
|
6005
|
+
}
|
|
6006
|
+
/******************************************************************
|
|
5996
6007
|
* With html field conf builds an html element,
|
|
5997
6008
|
* ready to add to the form
|
|
5998
6009
|
*
|
|
@@ -6433,7 +6444,7 @@ function create_form_field(gobj, $form, prefix, field_desc, { tag, inputType, na
|
|
|
6433
6444
|
break;
|
|
6434
6445
|
case "jsoneditor": {
|
|
6435
6446
|
let attrs = {
|
|
6436
|
-
class: "jsoneditor jse-theme-dark",
|
|
6447
|
+
class: "jsoneditor" + (form_is_dark_theme() ? " jse-theme-dark" : ""),
|
|
6437
6448
|
name,
|
|
6438
6449
|
style: ""
|
|
6439
6450
|
};
|
|
@@ -6442,7 +6453,7 @@ function create_form_field(gobj, $form, prefix, field_desc, { tag, inputType, na
|
|
|
6442
6453
|
else if (required) attrs.required = "";
|
|
6443
6454
|
$extend = createElement2(["div", attrs]);
|
|
6444
6455
|
$control.appendChild($extend);
|
|
6445
|
-
$extend.jsoneditor =
|
|
6456
|
+
$extend.jsoneditor = createJSONEditor({
|
|
6446
6457
|
target: $extend,
|
|
6447
6458
|
props: {
|
|
6448
6459
|
readOnly: !!readonly,
|
|
@@ -15397,7 +15408,7 @@ function register_c_yui_treedb_topics() {
|
|
|
15397
15408
|
*
|
|
15398
15409
|
* Table of TreeDB topic with FORM for editing
|
|
15399
15410
|
*
|
|
15400
|
-
* Copyright (c) 2025, ArtGins.
|
|
15411
|
+
* Copyright (c) 2025-2026, ArtGins.
|
|
15401
15412
|
* All Rights Reserved.
|
|
15402
15413
|
***********************************************************************/
|
|
15403
15414
|
/***************************************************************
|
|
@@ -15452,7 +15463,8 @@ var PRIVATE_DATA$2 = {
|
|
|
15452
15463
|
topic_name: "",
|
|
15453
15464
|
tabulator: null,
|
|
15454
15465
|
form: null,
|
|
15455
|
-
$popup: null
|
|
15466
|
+
$popup: null,
|
|
15467
|
+
on_keydown: null
|
|
15456
15468
|
};
|
|
15457
15469
|
var __gclass__$2 = null;
|
|
15458
15470
|
function popup_mount_layer() {
|
|
@@ -16021,6 +16033,14 @@ function create_tabulator(gobj) {
|
|
|
16021
16033
|
n = 0;
|
|
16022
16034
|
}
|
|
16023
16035
|
$rc.textContent = `${n} ${t("rows")}`;
|
|
16036
|
+
let single_page = true;
|
|
16037
|
+
try {
|
|
16038
|
+
let max = tabulator.getPageMax();
|
|
16039
|
+
single_page = max === false || max <= 1;
|
|
16040
|
+
} catch (e) {
|
|
16041
|
+
single_page = true;
|
|
16042
|
+
}
|
|
16043
|
+
tabulator.element.classList.toggle("yui-single-page", single_page);
|
|
16024
16044
|
}
|
|
16025
16045
|
tabulator._ready = false;
|
|
16026
16046
|
tabulator.on("tableBuilt", function() {
|
|
@@ -16196,6 +16216,13 @@ function open_form_dialog(gobj, mode, record) {
|
|
|
16196
16216
|
let desc = gobj_read_attr(gobj, "desc");
|
|
16197
16217
|
let popup_id = gobj_read_str_attr(gobj, "popup_id");
|
|
16198
16218
|
let topic_name = gobj_read_str_attr(gobj, "topic_name");
|
|
16219
|
+
let pkey = desc.pkey || "id";
|
|
16220
|
+
let title;
|
|
16221
|
+
if (mode === "create") title = t("new") + " " + t(topic_name);
|
|
16222
|
+
else {
|
|
16223
|
+
let rid = record ? String(record[pkey] ?? "") : "";
|
|
16224
|
+
title = t(topic_name) + (empty_string(rid) ? "" : " — " + rid);
|
|
16225
|
+
}
|
|
16199
16226
|
let $element = createElement2([
|
|
16200
16227
|
"div",
|
|
16201
16228
|
{
|
|
@@ -16218,7 +16245,7 @@ function open_form_dialog(gobj, mode, record) {
|
|
|
16218
16245
|
class: "modal-card-title",
|
|
16219
16246
|
style: "text-align:center;"
|
|
16220
16247
|
},
|
|
16221
|
-
|
|
16248
|
+
title
|
|
16222
16249
|
], [
|
|
16223
16250
|
"button",
|
|
16224
16251
|
{
|
|
@@ -16264,8 +16291,16 @@ function open_form_dialog(gobj, mode, record) {
|
|
|
16264
16291
|
}
|
|
16265
16292
|
popup_mount_layer().appendChild($element);
|
|
16266
16293
|
refresh_language($element, t);
|
|
16294
|
+
priv.on_keydown = function(evt) {
|
|
16295
|
+
if (evt.key === "Escape") {
|
|
16296
|
+
evt.stopPropagation();
|
|
16297
|
+
request_close_form_dialog(gobj);
|
|
16298
|
+
}
|
|
16299
|
+
};
|
|
16300
|
+
document.addEventListener("keydown", priv.on_keydown);
|
|
16267
16301
|
gobj_start(form);
|
|
16268
|
-
let $with_focus = $element.querySelector(".with-focus");
|
|
16302
|
+
let $with_focus = $element.querySelector(".with-focus:not([readonly])");
|
|
16303
|
+
if (!$with_focus) $with_focus = $element.querySelector("input.input:not([readonly]), textarea, select");
|
|
16269
16304
|
if ($with_focus) $with_focus.focus();
|
|
16270
16305
|
}
|
|
16271
16306
|
/************************************************************
|
|
@@ -16291,6 +16326,10 @@ function request_close_form_dialog(gobj) {
|
|
|
16291
16326
|
************************************************************/
|
|
16292
16327
|
function close_form_dialog(gobj) {
|
|
16293
16328
|
let priv = gobj.priv;
|
|
16329
|
+
if (priv.on_keydown) {
|
|
16330
|
+
document.removeEventListener("keydown", priv.on_keydown);
|
|
16331
|
+
priv.on_keydown = null;
|
|
16332
|
+
}
|
|
16294
16333
|
if (priv.form) {
|
|
16295
16334
|
if (gobj_is_running(priv.form)) gobj_stop(priv.form);
|
|
16296
16335
|
gobj_destroy(priv.form);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yuneta/gobj-ui",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.4.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "dist/gobj-ui.cjs.js",
|
|
6
6
|
"module": "dist/gobj-ui.es.js",
|
|
@@ -42,6 +42,6 @@
|
|
|
42
42
|
"tabulator-tables": "^6.5.2",
|
|
43
43
|
"tom-select": "^2.6.0",
|
|
44
44
|
"uplot": "^1.6.32",
|
|
45
|
-
"vanilla-jsoneditor": "^
|
|
45
|
+
"vanilla-jsoneditor": "^3.12.0"
|
|
46
46
|
}
|
|
47
47
|
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/***********************************************************************
|
|
2
|
+
* c_yui_form.css
|
|
3
|
+
*
|
|
4
|
+
* Theme integration for the third-party widgets C_YUI_FORM hosts
|
|
5
|
+
* (tom-select, vanilla-jsoneditor) plus form-owned input states.
|
|
6
|
+
*
|
|
7
|
+
* Everything maps to Bulma CSS vars, so a single rule set follows
|
|
8
|
+
* light/dark automatically (explicit data-theme or system theme) —
|
|
9
|
+
* no per-theme selectors needed.
|
|
10
|
+
*
|
|
11
|
+
* Copyright (c) 2026, ArtGins.
|
|
12
|
+
* All Rights Reserved.
|
|
13
|
+
***********************************************************************/
|
|
14
|
+
|
|
15
|
+
/*--- tom-select (fkey fields): ships light-only colors ---*/
|
|
16
|
+
.C_YUI_FORM .ts-wrapper .ts-control {
|
|
17
|
+
background: var(--bulma-scheme-main, #fff);
|
|
18
|
+
color: var(--bulma-text, #4a4a4a);
|
|
19
|
+
border-color: var(--bulma-border, #dbdbdb);
|
|
20
|
+
}
|
|
21
|
+
.C_YUI_FORM .ts-control > input {
|
|
22
|
+
color: var(--bulma-text, #4a4a4a);
|
|
23
|
+
}
|
|
24
|
+
.C_YUI_FORM .ts-wrapper.multi .ts-control > div {
|
|
25
|
+
background: var(--bulma-background, #f2f2f2);
|
|
26
|
+
color: var(--bulma-text, #4a4a4a);
|
|
27
|
+
}
|
|
28
|
+
.C_YUI_FORM .ts-dropdown {
|
|
29
|
+
background: var(--bulma-scheme-main, #fff);
|
|
30
|
+
color: var(--bulma-text, #4a4a4a);
|
|
31
|
+
border-color: var(--bulma-border, #dbdbdb);
|
|
32
|
+
}
|
|
33
|
+
.C_YUI_FORM .ts-dropdown .option.active {
|
|
34
|
+
background: var(--bulma-link, #485fc7);
|
|
35
|
+
color: var(--bulma-link-invert, #fff);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/*--- vanilla-jsoneditor: align its accent with the app palette ---*/
|
|
39
|
+
.C_YUI_FORM .jsoneditor {
|
|
40
|
+
--jse-theme-color: var(--bulma-link, #485fc7);
|
|
41
|
+
--jse-theme-color-highlight: var(--bulma-link, #485fc7);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/*--- readonly fields (e.g. the pkey in update mode) look readonly ---*/
|
|
45
|
+
.C_YUI_FORM input.input[readonly] {
|
|
46
|
+
background-color: var(--bulma-background, #f5f5f5);
|
|
47
|
+
color: var(--bulma-text-weak, #7a7a7a);
|
|
48
|
+
border-color: var(--bulma-border, #dbdbdb);
|
|
49
|
+
cursor: default;
|
|
50
|
+
}
|
package/src/c_yui_form.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Form (in Window or not)
|
|
5
5
|
*
|
|
6
|
-
* Copyright (c) 2024-
|
|
6
|
+
* Copyright (c) 2024-2026, ArtGins.
|
|
7
7
|
* All Rights Reserved.
|
|
8
8
|
***********************************************************************/
|
|
9
9
|
import {
|
|
@@ -53,8 +53,9 @@ import {t} from "i18next";
|
|
|
53
53
|
import "tom-select/dist/css/tom-select.css"; // Import Tom-Select CSS
|
|
54
54
|
import TomSelect from "tom-select"; // Import Tom-Select JS
|
|
55
55
|
|
|
56
|
-
import {
|
|
56
|
+
import { createJSONEditor } from 'vanilla-jsoneditor';
|
|
57
57
|
import "vanilla-jsoneditor/themes/jse-theme-dark.css";
|
|
58
|
+
import "./c_yui_form.css";
|
|
58
59
|
|
|
59
60
|
import "tabulator-tables/dist/css/tabulator.min.css"; // Import Tabulator CSS
|
|
60
61
|
import "tabulator-tables/dist/css/tabulator_bulma.css";
|
|
@@ -835,6 +836,23 @@ function apply_form_mode(gobj, $form)
|
|
|
835
836
|
}
|
|
836
837
|
}
|
|
837
838
|
|
|
839
|
+
/******************************************************************
|
|
840
|
+
* True when the app renders dark: explicit <html data-theme>, or
|
|
841
|
+
* the OS scheme when the attribute is absent ("system" theme
|
|
842
|
+
* removes it — see themes.js). Read at field-build time; the
|
|
843
|
+
* hosting dialog rebuilds the form on every open.
|
|
844
|
+
******************************************************************/
|
|
845
|
+
function form_is_dark_theme()
|
|
846
|
+
{
|
|
847
|
+
let attr = document.documentElement.getAttribute("data-theme");
|
|
848
|
+
if(attr) {
|
|
849
|
+
return attr === "dark";
|
|
850
|
+
}
|
|
851
|
+
return typeof window !== "undefined" &&
|
|
852
|
+
window.matchMedia &&
|
|
853
|
+
window.matchMedia("(prefers-color-scheme: dark)").matches;
|
|
854
|
+
}
|
|
855
|
+
|
|
838
856
|
/******************************************************************
|
|
839
857
|
* With html field conf builds an html element,
|
|
840
858
|
* ready to add to the form
|
|
@@ -1236,7 +1254,7 @@ function create_form_field(
|
|
|
1236
1254
|
case "jsoneditor":
|
|
1237
1255
|
{
|
|
1238
1256
|
let attrs = {
|
|
1239
|
-
class: 'jsoneditor jse-theme-dark',
|
|
1257
|
+
class: 'jsoneditor' + (form_is_dark_theme() ? ' jse-theme-dark' : ''),
|
|
1240
1258
|
name: name,
|
|
1241
1259
|
style: ''
|
|
1242
1260
|
};
|
|
@@ -1250,7 +1268,7 @@ function create_form_field(
|
|
|
1250
1268
|
let extend = ['div', attrs];
|
|
1251
1269
|
$extend = createElement2(extend);
|
|
1252
1270
|
$control.appendChild($extend);
|
|
1253
|
-
$extend.jsoneditor =
|
|
1271
|
+
$extend.jsoneditor = createJSONEditor({
|
|
1254
1272
|
target: $extend,
|
|
1255
1273
|
props: {
|
|
1256
1274
|
readOnly: !!readonly,
|
package/src/c_yui_shell.css
CHANGED
|
@@ -141,16 +141,24 @@
|
|
|
141
141
|
.yui-nav-vertical .yui-nav-label { white-space: nowrap; }
|
|
142
142
|
|
|
143
143
|
/*--- icon-bar (bottom/top icon bar) ---*/
|
|
144
|
+
/* Distribute-or-scroll: items grow to share spare width but never
|
|
145
|
+
* shrink below their content (flex: 1 0 auto); when they don't fit the
|
|
146
|
+
* bar scrolls horizontally. justify-content must stay flex-start —
|
|
147
|
+
* with space-around + overflow the leading items get clipped past the
|
|
148
|
+
* left edge and become unreachable. */
|
|
144
149
|
.yui-nav-iconbar {
|
|
145
150
|
display: flex;
|
|
146
|
-
justify-content:
|
|
151
|
+
justify-content: flex-start;
|
|
147
152
|
align-items: stretch;
|
|
148
153
|
margin: 0;
|
|
149
154
|
padding: 0.25rem 0;
|
|
150
155
|
width: 100%;
|
|
151
156
|
background: var(--bulma-scheme-main, #fff);
|
|
157
|
+
overflow-x: auto;
|
|
158
|
+
scrollbar-width: thin;
|
|
152
159
|
}
|
|
153
|
-
.yui-nav-iconbar .level-item { flex: 1
|
|
160
|
+
.yui-nav-iconbar .level-item { flex: 1 0 auto; justify-content: center; }
|
|
161
|
+
.yui-nav-iconbar .yui-nav-label { white-space: nowrap; }
|
|
154
162
|
.yui-nav-iconbar .yui-nav-item {
|
|
155
163
|
display: flex;
|
|
156
164
|
flex-direction: column;
|
|
@@ -22,3 +22,26 @@
|
|
|
22
22
|
.tabulator .tabulator-footer .yui-tabulator-rowcount {
|
|
23
23
|
line-height: 1.5;
|
|
24
24
|
}
|
|
25
|
+
|
|
26
|
+
/* All rows fit in one page: the page-size selector and the
|
|
27
|
+
* First/Prev/1/Next/Last strip are pure noise (worst on mobile) —
|
|
28
|
+
* update_rowcount() toggles the class on every data change. */
|
|
29
|
+
.tabulator.yui-single-page .tabulator-footer .tabulator-paginator {
|
|
30
|
+
display: none;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/* Toolbar wrapping discipline (mobile): the record-buttons group
|
|
34
|
+
* must never split across lines — Bulma .buttons wraps internally,
|
|
35
|
+
* which stacked the toolbar into 3 rows on narrow phones. Keep the
|
|
36
|
+
* group on one line and scroll it horizontally if it overflows
|
|
37
|
+
* (same distribute-or-scroll pattern as the nav icon-bar); the
|
|
38
|
+
* search+refresh block then wraps as a whole, so the toolbar is
|
|
39
|
+
* 1 row when it fits and exactly 2 when it doesn't. */
|
|
40
|
+
.toolbar_tabulator_table .buttons {
|
|
41
|
+
flex-wrap: nowrap;
|
|
42
|
+
overflow-x: auto;
|
|
43
|
+
scrollbar-width: thin;
|
|
44
|
+
}
|
|
45
|
+
.toolbar_tabulator_table .control.has-icons-left {
|
|
46
|
+
min-width: 0;
|
|
47
|
+
}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Table of TreeDB topic with FORM for editing
|
|
5
5
|
*
|
|
6
|
-
* Copyright (c) 2025, ArtGins.
|
|
6
|
+
* Copyright (c) 2025-2026, ArtGins.
|
|
7
7
|
* All Rights Reserved.
|
|
8
8
|
***********************************************************************/
|
|
9
9
|
|
|
@@ -132,6 +132,7 @@ let PRIVATE_DATA = {
|
|
|
132
132
|
tabulator: null,
|
|
133
133
|
form: null, // hosted C_YUI_FORM child (while dialog open)
|
|
134
134
|
$popup: null, // dialog DOM element
|
|
135
|
+
on_keydown: null, // document Escape handler (while dialog open)
|
|
135
136
|
};
|
|
136
137
|
|
|
137
138
|
let __gclass__ = null;
|
|
@@ -827,7 +828,9 @@ function create_tabulator(gobj)
|
|
|
827
828
|
}
|
|
828
829
|
let tabulator = new Tabulator($table_el, tabulator_settings);
|
|
829
830
|
|
|
830
|
-
/* Keep the footer in sync with the visible (active) row count
|
|
831
|
+
/* Keep the footer in sync with the visible (active) row count,
|
|
832
|
+
* and hide the pagination chrome while everything fits in one
|
|
833
|
+
* page (it comes back as soon as a second page exists). */
|
|
831
834
|
function update_rowcount() {
|
|
832
835
|
let $rc = tabulator.element &&
|
|
833
836
|
tabulator.element.querySelector(".yui-tabulator-rowcount");
|
|
@@ -841,6 +844,15 @@ function create_tabulator(gobj)
|
|
|
841
844
|
n = 0;
|
|
842
845
|
}
|
|
843
846
|
$rc.textContent = `${n} ${t("rows")}`;
|
|
847
|
+
|
|
848
|
+
let single_page = true;
|
|
849
|
+
try {
|
|
850
|
+
let max = tabulator.getPageMax(); // false = pagination off
|
|
851
|
+
single_page = (max === false) || max <= 1;
|
|
852
|
+
} catch(e) {
|
|
853
|
+
single_page = true;
|
|
854
|
+
}
|
|
855
|
+
tabulator.element.classList.toggle("yui-single-page", single_page);
|
|
844
856
|
}
|
|
845
857
|
|
|
846
858
|
tabulator._ready = false;
|
|
@@ -1103,12 +1115,23 @@ function open_form_dialog(gobj, mode, record)
|
|
|
1103
1115
|
let popup_id = gobj_read_str_attr(gobj, "popup_id");
|
|
1104
1116
|
let topic_name = gobj_read_str_attr(gobj, "topic_name");
|
|
1105
1117
|
|
|
1118
|
+
/* Title says what you are doing: "new <topic>" on create,
|
|
1119
|
+
* "<topic> — <pkey>" on update. */
|
|
1120
|
+
let pkey = desc.pkey || "id";
|
|
1121
|
+
let title;
|
|
1122
|
+
if(mode === "create") {
|
|
1123
|
+
title = t("new") + " " + t(topic_name);
|
|
1124
|
+
} else {
|
|
1125
|
+
let rid = record ? String(record[pkey] ?? "") : "";
|
|
1126
|
+
title = t(topic_name) + (empty_string(rid) ? "" : " — " + rid);
|
|
1127
|
+
}
|
|
1128
|
+
|
|
1106
1129
|
let $element = createElement2([
|
|
1107
1130
|
'div', {id: popup_id, class: 'modal is-active'}, [
|
|
1108
1131
|
['div', {class: 'modal-background'}, ''],
|
|
1109
1132
|
['div', {class: 'modal-card modal-is-responsive'}, [
|
|
1110
1133
|
['header', {class: 'modal-card-head p-3'}, [
|
|
1111
|
-
['p', {class: 'modal-card-title', style: 'text-align:center;'},
|
|
1134
|
+
['p', {class: 'modal-card-title', style: 'text-align:center;'}, title],
|
|
1112
1135
|
['button', {class: 'delete is-large', 'aria-label': 'close'}, '', {
|
|
1113
1136
|
click: function(evt) {
|
|
1114
1137
|
evt.stopPropagation();
|
|
@@ -1161,9 +1184,25 @@ function open_form_dialog(gobj, mode, record)
|
|
|
1161
1184
|
popup_mount_layer().appendChild($element);
|
|
1162
1185
|
refresh_language($element, t);
|
|
1163
1186
|
|
|
1187
|
+
/* Escape closes through the same unsaved-changes guard as the X. */
|
|
1188
|
+
priv.on_keydown = function(evt) {
|
|
1189
|
+
if(evt.key === "Escape") {
|
|
1190
|
+
evt.stopPropagation();
|
|
1191
|
+
request_close_form_dialog(gobj);
|
|
1192
|
+
}
|
|
1193
|
+
};
|
|
1194
|
+
document.addEventListener("keydown", priv.on_keydown);
|
|
1195
|
+
|
|
1164
1196
|
gobj_start(form); // mt_start loads `record` into the form
|
|
1165
1197
|
|
|
1166
|
-
|
|
1198
|
+
/* Focus the pkey unless the mode made it readonly (update) —
|
|
1199
|
+
* then the first editable field. */
|
|
1200
|
+
let $with_focus = $element.querySelector('.with-focus:not([readonly])');
|
|
1201
|
+
if(!$with_focus) {
|
|
1202
|
+
$with_focus = $element.querySelector(
|
|
1203
|
+
'input.input:not([readonly]), textarea, select'
|
|
1204
|
+
);
|
|
1205
|
+
}
|
|
1167
1206
|
if($with_focus) {
|
|
1168
1207
|
$with_focus.focus();
|
|
1169
1208
|
}
|
|
@@ -1197,6 +1236,10 @@ function request_close_form_dialog(gobj)
|
|
|
1197
1236
|
function close_form_dialog(gobj)
|
|
1198
1237
|
{
|
|
1199
1238
|
let priv = gobj.priv;
|
|
1239
|
+
if(priv.on_keydown) {
|
|
1240
|
+
document.removeEventListener("keydown", priv.on_keydown);
|
|
1241
|
+
priv.on_keydown = null;
|
|
1242
|
+
}
|
|
1200
1243
|
if(priv.form) {
|
|
1201
1244
|
if(gobj_is_running(priv.form)) {
|
|
1202
1245
|
gobj_stop(priv.form);
|