@yuneta/gobj-ui 3.0.0 → 5.0.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 +335 -6
- package/dist/gobj-ui.cjs.js +10930 -5027
- package/dist/gobj-ui.es.js +10948 -5080
- package/index.js +45 -1
- package/package.json +11 -11
- package/src/c_g6_nodes_tree.js +128 -40
- package/src/c_yui_form.js +112 -53
- package/src/c_yui_gobj_tree_js.js +58 -36
- package/src/c_yui_json.css +139 -0
- package/src/c_yui_json.js +928 -0
- package/src/c_yui_json_graph.js +110 -20
- package/src/c_yui_map.js +19 -37
- package/src/c_yui_nav.js +6 -9
- package/src/c_yui_period.css +184 -0
- package/src/c_yui_period.js +1441 -0
- package/src/c_yui_shell.css +33 -0
- package/src/c_yui_shell.js +672 -111
- package/src/c_yui_treedb_graph.js +639 -37
- package/src/c_yui_treedb_schema.js +478 -0
- package/src/c_yui_treedb_topic_with_form.css +7 -42
- package/src/c_yui_treedb_topic_with_form.js +152 -103
- package/src/c_yui_treedb_topics.css +73 -0
- package/src/c_yui_treedb_topics.js +1070 -29
- package/src/c_yui_window.js +180 -97
- package/src/c_yui_window_manager.js +38 -4
- package/src/json_view_helpers.js +214 -0
- package/src/json_view_helpers.test.js +135 -0
- package/src/route_map_model.js +317 -0
- package/src/route_map_model.test.js +209 -0
- package/src/route_resolver.js +24 -1
- package/src/route_resolver.test.js +40 -1
- package/src/shell_modals.js +117 -39
- package/src/shell_route_map.css +225 -0
- package/src/shell_route_map.js +363 -0
- package/src/tabulator.css +67 -0
- package/src/yui_dev.js +130 -8
- package/src/yui_frontend_view.js +106 -0
- package/src/yui_icons.css +62 -0
- package/src/yui_inputs.css +8 -3
- package/src/yui_inputs.js +51 -8
- package/src/yui_tabulator_i18n.js +128 -0
- package/src/yui_theme.js +147 -0
- package/src/yui_time.js +666 -0
- package/src/yui_time.test.js +330 -0
- package/src/yui_toolbar.js +86 -43
|
@@ -0,0 +1,478 @@
|
|
|
1
|
+
/***********************************************************************
|
|
2
|
+
* c_yui_treedb_schema.js
|
|
3
|
+
*
|
|
4
|
+
* Schema-graph landing (prototype): the treedb drawn as a GRAPH OF
|
|
5
|
+
* TOPICS — one node per topic, one edge per hook/fkey relationship
|
|
6
|
+
* — from the schema `descs` alone (no data, no backend calls). A
|
|
7
|
+
* node click opens that topic's table (a real hash navigation via
|
|
8
|
+
* the host-supplied `node_route`). An alternate landing to the
|
|
9
|
+
* topic cards, in the spirit of "every treedb is a graph".
|
|
10
|
+
*
|
|
11
|
+
* Copyright (c) 2026, ArtGins.
|
|
12
|
+
* All Rights Reserved.
|
|
13
|
+
***********************************************************************/
|
|
14
|
+
|
|
15
|
+
import {
|
|
16
|
+
SDATA,
|
|
17
|
+
SDATA_END,
|
|
18
|
+
data_type_t,
|
|
19
|
+
gclass_create,
|
|
20
|
+
log_error,
|
|
21
|
+
gobj_read_pointer_attr,
|
|
22
|
+
gobj_subscribe_event,
|
|
23
|
+
gobj_parent,
|
|
24
|
+
gobj_read_attr,
|
|
25
|
+
createElement2,
|
|
26
|
+
gobj_write_attr,
|
|
27
|
+
gobj_short_name,
|
|
28
|
+
gobj_read_bool_attr,
|
|
29
|
+
gobj_read_str_attr,
|
|
30
|
+
is_object,
|
|
31
|
+
} from "@yuneta/gobj-js";
|
|
32
|
+
|
|
33
|
+
import {Graph, NodeEvent} from "@antv/g6";
|
|
34
|
+
|
|
35
|
+
import {yui_is_dark, yui_watch_theme} from "./yui_theme.js";
|
|
36
|
+
|
|
37
|
+
import {t} from "i18next";
|
|
38
|
+
|
|
39
|
+
/***************************************************************
|
|
40
|
+
* Constants
|
|
41
|
+
***************************************************************/
|
|
42
|
+
const GCLASS_NAME = "C_YUI_TREEDB_SCHEMA";
|
|
43
|
+
|
|
44
|
+
/***************************************************************
|
|
45
|
+
* Data
|
|
46
|
+
***************************************************************/
|
|
47
|
+
const attrs_table = [
|
|
48
|
+
SDATA(data_type_t.DTP_POINTER, "subscriber", 0, null, "Subscriber of output events"),
|
|
49
|
+
SDATA(data_type_t.DTP_JSON, "descs", 0, null, "Treedb schema: {topic_name: desc}"),
|
|
50
|
+
SDATA(data_type_t.DTP_STRING, "node_route", 0, "", "Hash-route template with a {topic} placeholder: a node click opens that topic (e.g. '#/topics/db/<sel>/{topic}')"),
|
|
51
|
+
SDATA(data_type_t.DTP_BOOLEAN, "system", 0, false, "Include system topics (__*__) too"),
|
|
52
|
+
SDATA(data_type_t.DTP_POINTER, "$container", 0, null, "Root HTML element"),
|
|
53
|
+
SDATA_END()
|
|
54
|
+
];
|
|
55
|
+
|
|
56
|
+
let PRIVATE_DATA = {
|
|
57
|
+
$container: null,
|
|
58
|
+
graph: null,
|
|
59
|
+
theme_observer: null, // MutationObserver on <html data-theme>
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
let __gclass__ = null;
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
/******************************
|
|
68
|
+
* Framework Methods
|
|
69
|
+
******************************/
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
function mt_create(gobj)
|
|
75
|
+
{
|
|
76
|
+
build_ui(gobj);
|
|
77
|
+
|
|
78
|
+
/*
|
|
79
|
+
* CHILD subscription model
|
|
80
|
+
*/
|
|
81
|
+
let subscriber = gobj_read_pointer_attr(gobj, "subscriber");
|
|
82
|
+
if(!subscriber) {
|
|
83
|
+
subscriber = gobj_parent(gobj);
|
|
84
|
+
}
|
|
85
|
+
gobj_subscribe_event(gobj, null, {}, subscriber);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function mt_start(gobj)
|
|
89
|
+
{
|
|
90
|
+
/* The graph picks its colours from the theme. Translate the DOM
|
|
91
|
+
* mutation into EV_THEME and let the action restyle the live graph
|
|
92
|
+
* (ac_theme) — a rebuild would reset the camera. */
|
|
93
|
+
gobj.priv.theme_observer = yui_watch_theme(gobj);
|
|
94
|
+
|
|
95
|
+
build_graph(gobj);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function mt_stop(gobj)
|
|
99
|
+
{
|
|
100
|
+
let priv = gobj.priv;
|
|
101
|
+
|
|
102
|
+
if(priv.theme_observer) {
|
|
103
|
+
priv.theme_observer.disconnect();
|
|
104
|
+
priv.theme_observer = null;
|
|
105
|
+
}
|
|
106
|
+
destroy_graph(gobj);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function mt_destroy(gobj)
|
|
110
|
+
{
|
|
111
|
+
let $container = gobj_read_attr(gobj, "$container");
|
|
112
|
+
if($container && $container.parentNode) {
|
|
113
|
+
$container.parentNode.removeChild($container);
|
|
114
|
+
}
|
|
115
|
+
gobj_write_attr(gobj, "$container", null);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
/***************************
|
|
122
|
+
* Local Methods
|
|
123
|
+
***************************/
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
/************************************************************
|
|
129
|
+
* Build UI
|
|
130
|
+
************************************************************/
|
|
131
|
+
function build_ui(gobj)
|
|
132
|
+
{
|
|
133
|
+
let $container = createElement2(
|
|
134
|
+
['div', {class: 'C_YUI_TREEDB_SCHEMA TREEDB_SCHEMA_VIEW',
|
|
135
|
+
style: 'position:relative; height:100%; min-height:0;'}, []]
|
|
136
|
+
);
|
|
137
|
+
gobj_write_attr(gobj, "$container", $container);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/************************************************************
|
|
141
|
+
* Derive {nodes, edges} from the schema.
|
|
142
|
+
* Node = a topic. Edge = a hook (parent -> child) or an
|
|
143
|
+
* fkey (child -> parent, reversed to parent -> child), deduped.
|
|
144
|
+
* Left-to-right dagre follows the parent -> child data flow.
|
|
145
|
+
************************************************************/
|
|
146
|
+
function schema_to_graph(gobj)
|
|
147
|
+
{
|
|
148
|
+
let descs = gobj_read_attr(gobj, "descs");
|
|
149
|
+
let system = gobj_read_bool_attr(gobj, "system");
|
|
150
|
+
let nodes = [];
|
|
151
|
+
let topic_set = {};
|
|
152
|
+
|
|
153
|
+
if(!is_object(descs)) {
|
|
154
|
+
return {nodes: nodes, edges: []};
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
for(let topic of Object.keys(descs)) {
|
|
158
|
+
if(!system && topic.substring(0, 2) === "__") {
|
|
159
|
+
continue;
|
|
160
|
+
}
|
|
161
|
+
topic_set[topic] = true;
|
|
162
|
+
nodes.push({id: topic, data: {topic_name: topic}});
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
let edge_seen = {};
|
|
166
|
+
let edges = [];
|
|
167
|
+
let add_edge = (source, target) => {
|
|
168
|
+
if(!topic_set[source] || !topic_set[target] || source === target) {
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
let key = source + "" + target;
|
|
172
|
+
if(edge_seen[key]) {
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
edge_seen[key] = true;
|
|
176
|
+
edges.push({id: key, source: source, target: target});
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
for(let topic of Object.keys(descs)) {
|
|
180
|
+
let desc = descs[topic];
|
|
181
|
+
if(!is_object(desc) || !Array.isArray(desc.cols)) {
|
|
182
|
+
continue;
|
|
183
|
+
}
|
|
184
|
+
for(let col of desc.cols) {
|
|
185
|
+
if(!col) {
|
|
186
|
+
continue;
|
|
187
|
+
}
|
|
188
|
+
if(is_object(col.hook)) {
|
|
189
|
+
for(let child of Object.keys(col.hook)) {
|
|
190
|
+
add_edge(topic, child); /* parent -> child */
|
|
191
|
+
}
|
|
192
|
+
} else if(is_object(col.fkey)) {
|
|
193
|
+
for(let parent of Object.keys(col.fkey)) {
|
|
194
|
+
add_edge(parent, topic); /* parent -> child */
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
return {nodes: nodes, edges: edges};
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/************************************************************
|
|
204
|
+
* The theme-dependent styles, in ONE place: they are applied
|
|
205
|
+
* as the graph is built and re-applied on a theme switch
|
|
206
|
+
* (ac_theme), which restyles the LIVE graph — rebuilding it
|
|
207
|
+
* would drop the user's zoom/pan and any dragged node.
|
|
208
|
+
************************************************************/
|
|
209
|
+
function node_style(dark)
|
|
210
|
+
{
|
|
211
|
+
return {
|
|
212
|
+
size: 40,
|
|
213
|
+
fill: "#5B8FF9",
|
|
214
|
+
labelText: (d) => d.id,
|
|
215
|
+
labelPlacement: "bottom",
|
|
216
|
+
labelFill: dark ? "#e6e6e6" : "#333333",
|
|
217
|
+
labelBackground: true,
|
|
218
|
+
labelBackgroundFill: dark ? "rgba(0,0,0,0.5)" : "rgba(255,255,255,0.7)",
|
|
219
|
+
cursor: "pointer",
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
function edge_style(dark)
|
|
224
|
+
{
|
|
225
|
+
return {
|
|
226
|
+
stroke: dark ? "#666666" : "#bbbbbb",
|
|
227
|
+
endArrow: true,
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/************************************************************
|
|
232
|
+
* Build the G6 schema graph.
|
|
233
|
+
************************************************************/
|
|
234
|
+
function build_graph(gobj)
|
|
235
|
+
{
|
|
236
|
+
let priv = gobj.priv;
|
|
237
|
+
let $container = gobj_read_attr(gobj, "$container");
|
|
238
|
+
if(!$container) {
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
241
|
+
destroy_graph(gobj);
|
|
242
|
+
|
|
243
|
+
let data = schema_to_graph(gobj);
|
|
244
|
+
if(data.nodes.length === 0) {
|
|
245
|
+
let $empty = createElement2(
|
|
246
|
+
['div', {class: 'TREEDB_SCHEMA_EMPTY p-4 has-text-grey',
|
|
247
|
+
i18n: 'no topics'}, t('no topics', {defaultValue: 'No topics'})]
|
|
248
|
+
);
|
|
249
|
+
$container.appendChild($empty);
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
let dark = yui_is_dark();
|
|
254
|
+
let graph;
|
|
255
|
+
try {
|
|
256
|
+
graph = new Graph({
|
|
257
|
+
container: $container,
|
|
258
|
+
autoResize: true,
|
|
259
|
+
data: data,
|
|
260
|
+
node: {
|
|
261
|
+
style: node_style(dark),
|
|
262
|
+
},
|
|
263
|
+
edge: {
|
|
264
|
+
style: edge_style(dark),
|
|
265
|
+
},
|
|
266
|
+
layout: {
|
|
267
|
+
type: "antv-dagre",
|
|
268
|
+
rankdir: "LR",
|
|
269
|
+
nodesep: 24,
|
|
270
|
+
ranksep: 60,
|
|
271
|
+
},
|
|
272
|
+
behaviors: ["zoom-canvas", "drag-canvas", "drag-element"],
|
|
273
|
+
});
|
|
274
|
+
} catch(e) {
|
|
275
|
+
log_error(`${gobj_short_name(gobj)}: schema graph create failed: ${e}`);
|
|
276
|
+
return;
|
|
277
|
+
}
|
|
278
|
+
priv.graph = graph;
|
|
279
|
+
|
|
280
|
+
graph.setTheme(dark ? "dark" : "light");
|
|
281
|
+
|
|
282
|
+
/* A node click opens that topic — a real hash navigation, so it is
|
|
283
|
+
* deep-linkable and Back-friendly like the cards. Crosses the FSM. */
|
|
284
|
+
graph.on(NodeEvent.CLICK, (evt) => {
|
|
285
|
+
let node_id = evt && evt.target && evt.target.id;
|
|
286
|
+
gobj_send_event(gobj, "EV_NODE_CLICK", {node_id: node_id}, gobj);
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
graph.render().then(() => {
|
|
290
|
+
try {
|
|
291
|
+
graph.fitView();
|
|
292
|
+
} catch(e) {
|
|
293
|
+
// best-effort centring
|
|
294
|
+
}
|
|
295
|
+
}).catch((e) => {
|
|
296
|
+
log_error(`${gobj_short_name(gobj)}: schema graph render failed: ${e}`);
|
|
297
|
+
});
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/************************************************************
|
|
301
|
+
* Destroy the G6 graph.
|
|
302
|
+
************************************************************/
|
|
303
|
+
function destroy_graph(gobj)
|
|
304
|
+
{
|
|
305
|
+
let priv = gobj.priv;
|
|
306
|
+
if(priv.graph) {
|
|
307
|
+
try {
|
|
308
|
+
priv.graph.destroy();
|
|
309
|
+
} catch(e) {
|
|
310
|
+
// already gone
|
|
311
|
+
}
|
|
312
|
+
priv.graph = null;
|
|
313
|
+
}
|
|
314
|
+
let $container = gobj_read_attr(gobj, "$container");
|
|
315
|
+
if($container) {
|
|
316
|
+
while($container.firstChild) {
|
|
317
|
+
$container.removeChild($container.firstChild);
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
|
|
323
|
+
|
|
324
|
+
|
|
325
|
+
/***************************
|
|
326
|
+
* Actions
|
|
327
|
+
***************************/
|
|
328
|
+
|
|
329
|
+
|
|
330
|
+
|
|
331
|
+
|
|
332
|
+
/************************************************************
|
|
333
|
+
* A topic node was clicked: open its table via the host route.
|
|
334
|
+
************************************************************/
|
|
335
|
+
function ac_node_click(gobj, event, kw, src)
|
|
336
|
+
{
|
|
337
|
+
let topic = kw && kw.node_id;
|
|
338
|
+
let route = gobj_read_str_attr(gobj, "node_route");
|
|
339
|
+
if(!topic || !route) {
|
|
340
|
+
return 0;
|
|
341
|
+
}
|
|
342
|
+
let href = route.replace("{topic}", topic);
|
|
343
|
+
if(typeof window !== "undefined") {
|
|
344
|
+
window.location.hash = href;
|
|
345
|
+
}
|
|
346
|
+
return 0;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
/************************************************************
|
|
350
|
+
* Shown by the host: (re)fit the view now the container is
|
|
351
|
+
* visible and sized (G6 renders at 0×0 while display:none).
|
|
352
|
+
************************************************************/
|
|
353
|
+
function ac_show(gobj, event, kw, src)
|
|
354
|
+
{
|
|
355
|
+
let priv = gobj.priv;
|
|
356
|
+
if(!priv.graph) {
|
|
357
|
+
build_graph(gobj);
|
|
358
|
+
return 0;
|
|
359
|
+
}
|
|
360
|
+
try {
|
|
361
|
+
priv.graph.fitView();
|
|
362
|
+
} catch(e) {
|
|
363
|
+
// best-effort
|
|
364
|
+
}
|
|
365
|
+
return 0;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
/************************************************************
|
|
369
|
+
* {theme: "dark"|"light"} — the app switched theme.
|
|
370
|
+
* A restyle, not new data: repaint the LIVE graph and redraw,
|
|
371
|
+
* so the user's zoom/pan and dragged nodes survive. A rebuild
|
|
372
|
+
* is only right when there is no graph to restyle — the "no
|
|
373
|
+
* topics" empty state, whose message is built, not drawn.
|
|
374
|
+
************************************************************/
|
|
375
|
+
function ac_theme(gobj, event, kw, src)
|
|
376
|
+
{
|
|
377
|
+
let priv = gobj.priv;
|
|
378
|
+
let graph = priv.graph;
|
|
379
|
+
|
|
380
|
+
if(!graph) {
|
|
381
|
+
build_graph(gobj);
|
|
382
|
+
return 0;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
let dark = (kw && kw.theme) ? (kw.theme === "dark") : yui_is_dark();
|
|
386
|
+
try {
|
|
387
|
+
graph.setTheme(dark ? "dark" : "light");
|
|
388
|
+
graph.setNode({style: node_style(dark)});
|
|
389
|
+
graph.setEdge({style: edge_style(dark)});
|
|
390
|
+
graph.draw().catch((e) => {
|
|
391
|
+
log_error(`${gobj_short_name(gobj)}: schema graph redraw failed: ${e}`);
|
|
392
|
+
});
|
|
393
|
+
} catch(e) {
|
|
394
|
+
log_error(`${gobj_short_name(gobj)}: schema graph restyle failed: ${e}`);
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
return 0;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
/************************************************************
|
|
401
|
+
* Rebuild from a fresh schema (descs arrived / changed).
|
|
402
|
+
************************************************************/
|
|
403
|
+
function ac_rebuild(gobj, event, kw, src)
|
|
404
|
+
{
|
|
405
|
+
if(kw && is_object(kw.descs)) {
|
|
406
|
+
gobj_write_attr(gobj, "descs", kw.descs);
|
|
407
|
+
}
|
|
408
|
+
build_graph(gobj);
|
|
409
|
+
return 0;
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
|
|
413
|
+
|
|
414
|
+
|
|
415
|
+
/***************************
|
|
416
|
+
* FSM
|
|
417
|
+
***************************/
|
|
418
|
+
|
|
419
|
+
|
|
420
|
+
|
|
421
|
+
|
|
422
|
+
const gmt = {
|
|
423
|
+
mt_create: mt_create,
|
|
424
|
+
mt_start: mt_start,
|
|
425
|
+
mt_stop: mt_stop,
|
|
426
|
+
mt_destroy: mt_destroy,
|
|
427
|
+
};
|
|
428
|
+
|
|
429
|
+
function create_gclass(gclass_name)
|
|
430
|
+
{
|
|
431
|
+
if(__gclass__) {
|
|
432
|
+
log_error(`GClass ALREADY created: ${gclass_name}`);
|
|
433
|
+
return -1;
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
const states = [
|
|
437
|
+
["ST_IDLE", [
|
|
438
|
+
["EV_NODE_CLICK", ac_node_click, null],
|
|
439
|
+
["EV_SHOW", ac_show, null],
|
|
440
|
+
["EV_THEME", ac_theme, null],
|
|
441
|
+
["EV_REBUILD", ac_rebuild, null],
|
|
442
|
+
]]
|
|
443
|
+
];
|
|
444
|
+
|
|
445
|
+
const event_types = [
|
|
446
|
+
["EV_NODE_CLICK", 0],
|
|
447
|
+
["EV_SHOW", 0],
|
|
448
|
+
["EV_THEME", 0],
|
|
449
|
+
["EV_REBUILD", 0],
|
|
450
|
+
];
|
|
451
|
+
|
|
452
|
+
__gclass__ = gclass_create(
|
|
453
|
+
gclass_name,
|
|
454
|
+
event_types,
|
|
455
|
+
states,
|
|
456
|
+
gmt,
|
|
457
|
+
0, // lmt
|
|
458
|
+
attrs_table,
|
|
459
|
+
PRIVATE_DATA,
|
|
460
|
+
0, // authz_table
|
|
461
|
+
0, // command_table
|
|
462
|
+
0, // s_user_trace_level
|
|
463
|
+
0 // gclass_flag
|
|
464
|
+
);
|
|
465
|
+
|
|
466
|
+
if(!__gclass__) {
|
|
467
|
+
return -1;
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
return 0;
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
function register_c_yui_treedb_schema()
|
|
474
|
+
{
|
|
475
|
+
return create_gclass(GCLASS_NAME);
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
export {register_c_yui_treedb_schema};
|
|
@@ -46,52 +46,17 @@
|
|
|
46
46
|
min-width: 0;
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
-
/*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
.
|
|
56
|
-
width: 100%;
|
|
57
|
-
max-width: 100%;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
@media screen and (min-width: 768px) {
|
|
61
|
-
.modal-card.modal-is-responsive {
|
|
62
|
-
width: 50rem;
|
|
49
|
+
/* The edit/create form runs in the shell's standardized adaptive dialog
|
|
50
|
+
* (yui_shell_show_modal dialog:true, logical_class TREEDB_FORM_SHEET). The
|
|
51
|
+
* shell CSS already gives it the centred card / full-screen-mobile sheet;
|
|
52
|
+
* here we only widen it on desktop — a label+field record form wants more
|
|
53
|
+
* room than the default 640px. Mobile stays edge-to-edge (shell rule). */
|
|
54
|
+
@media screen and (min-width: 769px) {
|
|
55
|
+
.TREEDB_FORM_SHEET .yui-dialog-content {
|
|
63
56
|
max-width: 50rem;
|
|
64
57
|
}
|
|
65
58
|
}
|
|
66
59
|
|
|
67
|
-
/*
|
|
68
|
-
* Mobile (< 768px, dovetails with the desktop rule above): a
|
|
69
|
-
* `modal-is-responsive` card (the C_YUI_TREEDB edit/delete form
|
|
70
|
-
* popup, and any other consumer of this opt-in class) takes the
|
|
71
|
-
* WHOLE screen instead of a centred sheet — more room to edit on a
|
|
72
|
-
* phone. Confirm dialogs do not carry `modal-is-responsive`, so
|
|
73
|
-
* they stay compact. Edge-to-edge: full size, no margin, flat
|
|
74
|
-
* corners; the body keeps Bulma's own scroll.
|
|
75
|
-
*/
|
|
76
|
-
@media screen and (max-width: 767px) {
|
|
77
|
-
.modal-card.modal-is-responsive {
|
|
78
|
-
width: 100%;
|
|
79
|
-
max-width: 100%;
|
|
80
|
-
height: 100%;
|
|
81
|
-
max-height: 100%;
|
|
82
|
-
margin: 0;
|
|
83
|
-
border-radius: 0;
|
|
84
|
-
}
|
|
85
|
-
.modal-card.modal-is-responsive .modal-card-head,
|
|
86
|
-
.modal-card.modal-is-responsive .modal-card-foot {
|
|
87
|
-
border-radius: 0;
|
|
88
|
-
}
|
|
89
|
-
.modal-card.modal-is-responsive .modal-card-body {
|
|
90
|
-
flex: 1 1 auto;
|
|
91
|
-
overflow-y: auto;
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
|
|
95
60
|
.without-border {
|
|
96
61
|
border: none !important;
|
|
97
62
|
box-shadow: none !important;
|