@yuneta/gobj-ui 2.6.0 → 4.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 +331 -11
- package/dist/gobj-ui.cjs.js +21386 -17919
- package/dist/gobj-ui.es.js +26059 -22613
- package/index.js +45 -9
- package/package.json +4 -4
- package/src/c_g6_nodes_tree.js +128 -40
- package/src/c_yui_form.css +9 -0
- package/src/c_yui_form.js +113 -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 +18 -36
- 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 +120 -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 +18 -0
- package/src/c_yui_treedb_topic_with_form.js +153 -103
- package/src/c_yui_treedb_topics.css +73 -0
- package/src/c_yui_treedb_topics.js +1070 -29
- package/src/c_yui_window.css +22 -0
- package/src/c_yui_window.js +182 -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 +162 -52
- package/src/shell_route_map.css +225 -0
- package/src/shell_route_map.js +363 -0
- package/src/tabulator.css +245 -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.css +28 -0
- package/src/yui_toolbar.js +86 -43
- package/src/c_yui_main.css +0 -501
- package/src/c_yui_main.js +0 -1623
- package/src/c_yui_routing.css +0 -18
- package/src/c_yui_routing.js +0 -837
- package/src/c_yui_tabs.js +0 -487
- package/src/themes.js +0 -215
- package/src/ytable.css +0 -63
- package/src/ytable.js +0 -505
|
@@ -0,0 +1,928 @@
|
|
|
1
|
+
/***********************************************************************
|
|
2
|
+
* c_yui_json.js
|
|
3
|
+
*
|
|
4
|
+
* Lazy JSON tree viewer.
|
|
5
|
+
*
|
|
6
|
+
* Container-agnostic (like C_YUI_PAGER): the gclass owns ONLY the
|
|
7
|
+
* viewer chrome (a toolbar + a scrollable tree body). The parent
|
|
8
|
+
* mounts `gobj_read_attr(json_view, "$container")` wherever it wants
|
|
9
|
+
* (a C_YUI_WINDOW body, a Bulma modal-card, or inline) and feeds it
|
|
10
|
+
* JSON with EV_SET_JSON.
|
|
11
|
+
*
|
|
12
|
+
* Built for ARBITRARILY LARGE JSON via server-driven lazy expansion.
|
|
13
|
+
* The kernel's `kw_collapse()` (kwid.c) truncates over-limit dicts and
|
|
14
|
+
* arrays into sentinels:
|
|
15
|
+
* { "__collapsed__": { "path": ..., "size": N } }
|
|
16
|
+
* The viewer renders those as an expandable stub; opening one does NOT
|
|
17
|
+
* fetch anything itself — it PUBLISHES EV_EXPAND_PATH {path, size} to
|
|
18
|
+
* its subscriber, which is the ONLY party that knows the backend (e.g.
|
|
19
|
+
* it re-issues `print-tranger path=<path>`), then hands the subtree
|
|
20
|
+
* back with EV_SUBTREE_LOADED {path, json}. This keeps the component
|
|
21
|
+
* decoupled from any command / transport. With no sentinels present
|
|
22
|
+
* it degrades to a plain client-side collapsible tree.
|
|
23
|
+
*
|
|
24
|
+
* Only expanded containers are materialised in the DOM, so the tree
|
|
25
|
+
* stays bounded no matter how large the source document is.
|
|
26
|
+
*
|
|
27
|
+
* DOM is self-describing (UPPER_SNAKE logical classes): JSON_VIEWER /
|
|
28
|
+
* JSON_TOOLBAR / JSON_SEARCH / JSON_TREE / JSON_ROW / JSON_KEY /
|
|
29
|
+
* JSON_VALUE / JSON_SUMMARY / JSON_COLLAPSED / JSON_TIME.
|
|
30
|
+
*
|
|
31
|
+
* Copyright (c) 2026, ArtGins.
|
|
32
|
+
* All Rights Reserved.
|
|
33
|
+
***********************************************************************/
|
|
34
|
+
import {
|
|
35
|
+
SDATA,
|
|
36
|
+
SDATA_END,
|
|
37
|
+
data_type_t,
|
|
38
|
+
event_flag_t,
|
|
39
|
+
gclass_create,
|
|
40
|
+
log_error,
|
|
41
|
+
gobj_read_pointer_attr,
|
|
42
|
+
gobj_parent,
|
|
43
|
+
gobj_subscribe_event,
|
|
44
|
+
gobj_read_attr,
|
|
45
|
+
gobj_write_attr,
|
|
46
|
+
gobj_read_str_attr,
|
|
47
|
+
gobj_send_event,
|
|
48
|
+
gobj_publish_event,
|
|
49
|
+
createElement2,
|
|
50
|
+
json_deep_copy,
|
|
51
|
+
json_object_size,
|
|
52
|
+
refresh_language,
|
|
53
|
+
} from "@yuneta/gobj-js";
|
|
54
|
+
|
|
55
|
+
import {
|
|
56
|
+
json_type,
|
|
57
|
+
is_collapsed,
|
|
58
|
+
seg_join,
|
|
59
|
+
seg_split,
|
|
60
|
+
set_by_segments,
|
|
61
|
+
subtree_matches,
|
|
62
|
+
is_time_field,
|
|
63
|
+
format_epoch,
|
|
64
|
+
} from "./json_view_helpers.js";
|
|
65
|
+
|
|
66
|
+
import {yui_toolbar} from "./yui_toolbar.js";
|
|
67
|
+
import {attach_clear} from "./yui_inputs.js";
|
|
68
|
+
|
|
69
|
+
import {t} from "i18next";
|
|
70
|
+
|
|
71
|
+
import "./c_yui_json.css";
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
/***************************************************************
|
|
75
|
+
* Constants
|
|
76
|
+
***************************************************************/
|
|
77
|
+
const GCLASS_NAME = "C_YUI_JSON";
|
|
78
|
+
|
|
79
|
+
/*
|
|
80
|
+
* Hard cap on rows painted in one render pass. A guard against an
|
|
81
|
+
* accidental "expand all" over a giant already-loaded document; the
|
|
82
|
+
* cap is announced in the tree (never silently truncated).
|
|
83
|
+
*/
|
|
84
|
+
const MAX_RENDER_ROWS = 5000;
|
|
85
|
+
|
|
86
|
+
/***************************************************************
|
|
87
|
+
* Data
|
|
88
|
+
***************************************************************/
|
|
89
|
+
const attrs_table = [
|
|
90
|
+
/*---------------- Public Attributes ----------------*/
|
|
91
|
+
SDATA(data_type_t.DTP_POINTER, "subscriber", 0, null, "Subscriber of output events"),
|
|
92
|
+
|
|
93
|
+
/*---------------- Config ----------------*/
|
|
94
|
+
SDATA(data_type_t.DTP_STRING, "title", 0, "", "Optional header title (i18n key)"),
|
|
95
|
+
SDATA(data_type_t.DTP_JSON, "json_data", 0, null, "Initial JSON to render (usually already collapsed)"),
|
|
96
|
+
|
|
97
|
+
/*---------------- UI ----------------*/
|
|
98
|
+
SDATA(data_type_t.DTP_POINTER, "$container", 0, null, "HTMLElement root, mounted by the parent"),
|
|
99
|
+
SDATA_END()
|
|
100
|
+
];
|
|
101
|
+
|
|
102
|
+
let PRIVATE_DATA = {
|
|
103
|
+
root: null, // working JSON tree (deep-copied, mutated on splice)
|
|
104
|
+
expanded: null, // Set<string> of expanded absolute paths
|
|
105
|
+
pending: null, // Set<string> of paths whose subtree is being fetched
|
|
106
|
+
errors: null, // Map<string,string> of per-path expand errors
|
|
107
|
+
search: "", // current search term (lower-cased)
|
|
108
|
+
$tree: null, // the scrollable tree body element
|
|
109
|
+
$search: null, // the search input element
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
let __gclass__ = null;
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
/******************************
|
|
118
|
+
* Framework Methods
|
|
119
|
+
******************************/
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
/***************************************************************
|
|
125
|
+
* Framework Method: Create
|
|
126
|
+
***************************************************************/
|
|
127
|
+
function mt_create(gobj)
|
|
128
|
+
{
|
|
129
|
+
let priv = gobj.priv;
|
|
130
|
+
|
|
131
|
+
priv.expanded = new Set();
|
|
132
|
+
priv.pending = new Set();
|
|
133
|
+
priv.errors = new Map();
|
|
134
|
+
priv.search = "";
|
|
135
|
+
|
|
136
|
+
let json_data = gobj_read_attr(gobj, "json_data");
|
|
137
|
+
if(json_data !== null && json_data !== undefined) {
|
|
138
|
+
priv.root = json_deep_copy(json_data);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
build_ui(gobj);
|
|
142
|
+
|
|
143
|
+
/*
|
|
144
|
+
* CHILD subscription model
|
|
145
|
+
*/
|
|
146
|
+
let subscriber = gobj_read_pointer_attr(gobj, "subscriber");
|
|
147
|
+
if(!subscriber) {
|
|
148
|
+
subscriber = gobj_parent(gobj);
|
|
149
|
+
}
|
|
150
|
+
gobj_subscribe_event(gobj, null, {}, subscriber);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/***************************************************************
|
|
154
|
+
* Framework Method: Start
|
|
155
|
+
***************************************************************/
|
|
156
|
+
function mt_start(gobj)
|
|
157
|
+
{
|
|
158
|
+
render_tree(gobj);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/***************************************************************
|
|
162
|
+
* Framework Method: Stop
|
|
163
|
+
***************************************************************/
|
|
164
|
+
function mt_stop(gobj)
|
|
165
|
+
{
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/***************************************************************
|
|
169
|
+
* Framework Method: Destroy
|
|
170
|
+
***************************************************************/
|
|
171
|
+
function mt_destroy(gobj)
|
|
172
|
+
{
|
|
173
|
+
destroy_ui(gobj);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
/***************************
|
|
180
|
+
* Local Methods
|
|
181
|
+
***************************/
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
/************************************************************
|
|
187
|
+
* Build UI
|
|
188
|
+
************************************************************/
|
|
189
|
+
function build_ui(gobj)
|
|
190
|
+
{
|
|
191
|
+
let priv = gobj.priv;
|
|
192
|
+
|
|
193
|
+
let $toolbar = make_toolbar(gobj);
|
|
194
|
+
|
|
195
|
+
let $container = createElement2(
|
|
196
|
+
['div', {class: 'C_YUI_JSON JSON_VIEWER view-card',
|
|
197
|
+
style: 'height:100%; display:flex; flex-direction:column;'}, [
|
|
198
|
+
['div', {class: 'JSON_TOOLBAR is-flex-grow-0'}, [$toolbar]],
|
|
199
|
+
['div', {class: 'JSON_TREE is-flex-grow-1',
|
|
200
|
+
style: 'flex:1 1 auto; min-height:0; overflow:auto;'}, []]
|
|
201
|
+
]]
|
|
202
|
+
);
|
|
203
|
+
|
|
204
|
+
gobj_write_attr(gobj, "$container", $container);
|
|
205
|
+
priv.$tree = $container.querySelector('.JSON_TREE');
|
|
206
|
+
priv.$search = $container.querySelector('.JSON_SEARCH');
|
|
207
|
+
|
|
208
|
+
refresh_language($container, t);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/************************************************************
|
|
212
|
+
* Destroy UI
|
|
213
|
+
************************************************************/
|
|
214
|
+
function destroy_ui(gobj)
|
|
215
|
+
{
|
|
216
|
+
let priv = gobj.priv;
|
|
217
|
+
let $container = gobj_read_attr(gobj, "$container");
|
|
218
|
+
if($container) {
|
|
219
|
+
if($container.parentNode) {
|
|
220
|
+
$container.parentNode.removeChild($container);
|
|
221
|
+
}
|
|
222
|
+
gobj_write_attr(gobj, "$container", null);
|
|
223
|
+
}
|
|
224
|
+
priv.$tree = null;
|
|
225
|
+
priv.$search = null;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/************************************************************
|
|
229
|
+
* Toolbar: search + expand-all / collapse-all / copy
|
|
230
|
+
************************************************************/
|
|
231
|
+
function make_toolbar(gobj)
|
|
232
|
+
{
|
|
233
|
+
let title = gobj_read_str_attr(gobj, "title");
|
|
234
|
+
|
|
235
|
+
let left_items = [];
|
|
236
|
+
if(title) {
|
|
237
|
+
left_items.push(
|
|
238
|
+
['span', {class: 'JSON_TITLE is-flex is-align-items-center px-2',
|
|
239
|
+
style: 'font-weight:600;', 'data-i18n': title}, title]
|
|
240
|
+
);
|
|
241
|
+
}
|
|
242
|
+
/* Search box: a magnifier on the left and the NORM clear (✕) via
|
|
243
|
+
* attach_clear on the right. Clearing dispatches a synthetic `input`,
|
|
244
|
+
* which re-fires EV_SEARCH with an empty term through the FSM. */
|
|
245
|
+
let $search_input = createElement2(
|
|
246
|
+
['input', {class: 'JSON_SEARCH input', type: 'text',
|
|
247
|
+
placeholder: t("search")}, [], {
|
|
248
|
+
input: function(evt) {
|
|
249
|
+
gobj_send_event(gobj, "EV_SEARCH", {text: evt.target.value}, gobj);
|
|
250
|
+
}
|
|
251
|
+
}]);
|
|
252
|
+
let $search_control = createElement2(
|
|
253
|
+
['div', {class: 'control has-icons-left', style: 'max-width:22em;'}, [
|
|
254
|
+
$search_input,
|
|
255
|
+
['span', {class: 'icon is-left'}, [['i', {class: 'yi-magnifying-glass'}]]]
|
|
256
|
+
]]);
|
|
257
|
+
attach_clear($search_control, $search_input);
|
|
258
|
+
left_items.push($search_control);
|
|
259
|
+
|
|
260
|
+
let right_items = [
|
|
261
|
+
icon_button(gobj, "yi-chevron-right", "EV_EXPAND_ALL", "expand loaded"),
|
|
262
|
+
icon_button(gobj, "yi-chevron-right", "EV_COLLAPSE_ALL", "collapse all"),
|
|
263
|
+
icon_button(gobj, "yi-copy", "EV_COPY_ALL", "copy json"),
|
|
264
|
+
];
|
|
265
|
+
|
|
266
|
+
const $toolbar = yui_toolbar({}, [
|
|
267
|
+
['div', {class: 'yui-horizontal-toolbar-section left is-flex is-align-items-center',
|
|
268
|
+
style: 'gap:.25rem;'}, left_items],
|
|
269
|
+
['div', {class: 'yui-horizontal-toolbar-section center'}, []],
|
|
270
|
+
['div', {class: 'yui-horizontal-toolbar-section right is-flex is-align-items-center',
|
|
271
|
+
style: 'gap:.25rem;'}, right_items],
|
|
272
|
+
]);
|
|
273
|
+
|
|
274
|
+
refresh_language($toolbar, t);
|
|
275
|
+
return $toolbar;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
/************************************************************
|
|
279
|
+
* A single icon toolbar button that fires `event_name`
|
|
280
|
+
************************************************************/
|
|
281
|
+
function icon_button(gobj, icon, event_name, label_key)
|
|
282
|
+
{
|
|
283
|
+
return ['button', {class: `button ${event_name}`, style: 'width:2.5em;',
|
|
284
|
+
title: t(label_key), 'data-i18n-title': label_key,
|
|
285
|
+
'aria-label': t(label_key), 'data-i18n-aria-label': label_key}, [
|
|
286
|
+
['span', {class: 'icon'}, [['i', {class: icon}]]]
|
|
287
|
+
], {
|
|
288
|
+
click: function(evt) {
|
|
289
|
+
evt.stopPropagation();
|
|
290
|
+
gobj_send_event(gobj, event_name, {}, gobj);
|
|
291
|
+
}
|
|
292
|
+
}];
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
/************************************************************
|
|
296
|
+
* Re-render the whole tree from priv.root + priv.expanded.
|
|
297
|
+
*
|
|
298
|
+
* Only expanded containers are walked, so the DOM size is
|
|
299
|
+
* bounded by what the user opened, not by the document size.
|
|
300
|
+
************************************************************/
|
|
301
|
+
function render_tree(gobj)
|
|
302
|
+
{
|
|
303
|
+
let priv = gobj.priv;
|
|
304
|
+
let $tree = priv.$tree;
|
|
305
|
+
if(!$tree) {
|
|
306
|
+
return;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
let scroll_top = $tree.scrollTop;
|
|
310
|
+
$tree.textContent = "";
|
|
311
|
+
|
|
312
|
+
if(priv.root === null || priv.root === undefined) {
|
|
313
|
+
$tree.appendChild(createElement2(
|
|
314
|
+
['div', {class: 'JSON_EMPTY has-text-grey p-3', 'data-i18n': 'no data'}, 'no data']
|
|
315
|
+
));
|
|
316
|
+
return;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
let ctx = {gobj: gobj, term: priv.search, count: 0, capped: false};
|
|
320
|
+
let rows = [];
|
|
321
|
+
|
|
322
|
+
let type = json_type(priv.root);
|
|
323
|
+
if(is_collapsed(priv.root)) {
|
|
324
|
+
push_collapsed_row(ctx, priv.root, [], 0, "", rows);
|
|
325
|
+
} else if(type === "object") {
|
|
326
|
+
for(let [k, v] of Object.entries(priv.root)) {
|
|
327
|
+
push_entry_rows(ctx, k, v, [k], 0, rows);
|
|
328
|
+
}
|
|
329
|
+
} else if(type === "array") {
|
|
330
|
+
priv.root.forEach(function(v, i) {
|
|
331
|
+
push_entry_rows(ctx, i, v, [String(i)], 0, rows);
|
|
332
|
+
});
|
|
333
|
+
} else {
|
|
334
|
+
push_entry_rows(ctx, null, priv.root, [], 0, rows);
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
if(ctx.capped) {
|
|
338
|
+
rows.push(['div', {class: 'JSON_CAPPED has-text-warning p-2',
|
|
339
|
+
'data-i18n': 'too many rows; collapse some branches'},
|
|
340
|
+
'too many rows; collapse some branches']);
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
$tree.appendChild(createElement2(['div', {class: 'JSON_ROWS'}, rows]));
|
|
344
|
+
refresh_language($tree, t);
|
|
345
|
+
$tree.scrollTop = scroll_top;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
/************************************************************
|
|
349
|
+
* Render one entry (key -> value) into `rows`.
|
|
350
|
+
* Dispatches to collapsed-stub / container / leaf.
|
|
351
|
+
************************************************************/
|
|
352
|
+
function push_entry_rows(ctx, key, value, segments, depth, rows)
|
|
353
|
+
{
|
|
354
|
+
if(ctx.count >= MAX_RENDER_ROWS) {
|
|
355
|
+
ctx.capped = true;
|
|
356
|
+
return;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
let term = ctx.term;
|
|
360
|
+
let key_match = term && key !== null && String(key).toLowerCase().includes(term);
|
|
361
|
+
|
|
362
|
+
if(is_collapsed(value)) {
|
|
363
|
+
/*
|
|
364
|
+
* A not-yet-loaded subtree: searchable only by its key.
|
|
365
|
+
*/
|
|
366
|
+
if(term && !key_match) {
|
|
367
|
+
return;
|
|
368
|
+
}
|
|
369
|
+
push_collapsed_row(ctx, value, segments, depth, key, rows);
|
|
370
|
+
return;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
let type = json_type(value);
|
|
374
|
+
if(type === "object" || type === "array") {
|
|
375
|
+
if(term && !key_match && !subtree_matches(value, term)) {
|
|
376
|
+
return;
|
|
377
|
+
}
|
|
378
|
+
push_container_rows(ctx, key, value, segments, depth, rows, key_match);
|
|
379
|
+
return;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
/*
|
|
383
|
+
* Leaf (primitive)
|
|
384
|
+
*/
|
|
385
|
+
if(term && !key_match && !String_of(value).toLowerCase().includes(term)) {
|
|
386
|
+
return;
|
|
387
|
+
}
|
|
388
|
+
ctx.count++;
|
|
389
|
+
rows.push(leaf_row(key, value, depth));
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
/************************************************************
|
|
393
|
+
* Container (object/array) row + its expanded children
|
|
394
|
+
************************************************************/
|
|
395
|
+
function push_container_rows(ctx, key, value, segments, depth, rows, key_match)
|
|
396
|
+
{
|
|
397
|
+
let priv = ctx.gobj.priv;
|
|
398
|
+
let path = seg_join(segments);
|
|
399
|
+
let is_object = json_type(value) === "object";
|
|
400
|
+
let size = is_object ? json_object_size(value) : value.length;
|
|
401
|
+
|
|
402
|
+
/*
|
|
403
|
+
* Auto-expand while searching so matches are visible; otherwise
|
|
404
|
+
* honour the user's expand/collapse state.
|
|
405
|
+
*/
|
|
406
|
+
let searching_match = ctx.term && !key_match && subtree_matches(value, ctx.term);
|
|
407
|
+
let open = priv.expanded.has(path) || searching_match;
|
|
408
|
+
|
|
409
|
+
ctx.count++;
|
|
410
|
+
rows.push(toggle_row(ctx.gobj, key, size, is_object, depth, path, open));
|
|
411
|
+
|
|
412
|
+
if(!open) {
|
|
413
|
+
return;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
if(is_object) {
|
|
417
|
+
for(let [k, v] of Object.entries(value)) {
|
|
418
|
+
push_entry_rows(ctx, k, v, segments.concat(k), depth + 1, rows);
|
|
419
|
+
}
|
|
420
|
+
} else {
|
|
421
|
+
value.forEach(function(v, i) {
|
|
422
|
+
push_entry_rows(ctx, i, v, segments.concat(String(i)), depth + 1, rows);
|
|
423
|
+
});
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
/************************************************************
|
|
428
|
+
* Collapsed-sentinel stub row (fetch-on-open)
|
|
429
|
+
************************************************************/
|
|
430
|
+
function push_collapsed_row(ctx, value, segments, depth, key, rows)
|
|
431
|
+
{
|
|
432
|
+
let priv = ctx.gobj.priv;
|
|
433
|
+
let path = seg_join(segments);
|
|
434
|
+
let info = is_collapsed(value) || {};
|
|
435
|
+
let size = info.size;
|
|
436
|
+
let is_pending = priv.pending.has(path);
|
|
437
|
+
let err = priv.errors.get(path);
|
|
438
|
+
|
|
439
|
+
ctx.count++;
|
|
440
|
+
|
|
441
|
+
let key_spec = (key === null || key === "")
|
|
442
|
+
? null
|
|
443
|
+
: ['span', {class: 'JSON_KEY'}, String(key)];
|
|
444
|
+
|
|
445
|
+
let stub_text = (info.is_array ? "[" : "{") +
|
|
446
|
+
(size !== undefined ? String(size) : "?") +
|
|
447
|
+
(info.is_array ? "]" : "}");
|
|
448
|
+
|
|
449
|
+
let children = [];
|
|
450
|
+
if(key_spec) {
|
|
451
|
+
children.push(key_spec);
|
|
452
|
+
children.push(['span', {class: 'JSON_PUNCT'}, ': ']);
|
|
453
|
+
}
|
|
454
|
+
children.push(['span', {class: 'JSON_STUB'}, stub_text]);
|
|
455
|
+
children.push(['span', {class: 'JSON_STUB_HINT is-size-7 ml-2',
|
|
456
|
+
'data-i18n': is_pending ? 'loading' : 'click to load'},
|
|
457
|
+
is_pending ? 'loading' : 'click to load']);
|
|
458
|
+
if(err) {
|
|
459
|
+
children.push(['span', {class: 'JSON_STUB_ERR has-text-danger is-size-7 ml-2'}, String(err)]);
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
let attrs = {
|
|
463
|
+
class: 'JSON_ROW JSON_COLLAPSED' + (is_pending ? ' is-pending' : ''),
|
|
464
|
+
style: row_indent(depth),
|
|
465
|
+
};
|
|
466
|
+
let events = is_pending ? undefined : {
|
|
467
|
+
click: function(evt) {
|
|
468
|
+
evt.stopPropagation();
|
|
469
|
+
gobj_send_event(ctx.gobj, "EV_EXPAND_COLLAPSED",
|
|
470
|
+
{path: path, size: size}, ctx.gobj);
|
|
471
|
+
}
|
|
472
|
+
};
|
|
473
|
+
|
|
474
|
+
let content = [
|
|
475
|
+
['span', {class: 'JSON_TOGGLE JSON_TOGGLE_REMOTE'}, [['i', {class: 'yi-plus'}]]],
|
|
476
|
+
['span', {class: 'JSON_ROW_BODY'}, children],
|
|
477
|
+
];
|
|
478
|
+
rows.push(events ? ['div', attrs, content, events] : ['div', attrs, content]);
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
/************************************************************
|
|
482
|
+
* Expandable container header row
|
|
483
|
+
************************************************************/
|
|
484
|
+
function toggle_row(gobj, key, size, is_object, depth, path, open)
|
|
485
|
+
{
|
|
486
|
+
let summary = (is_object ? "{" : "[") + String(size) + (is_object ? "}" : "]");
|
|
487
|
+
|
|
488
|
+
let body = [];
|
|
489
|
+
if(key !== null && key !== "") {
|
|
490
|
+
body.push(['span', {class: 'JSON_KEY'}, String(key)]);
|
|
491
|
+
body.push(['span', {class: 'JSON_PUNCT'}, ': ']);
|
|
492
|
+
}
|
|
493
|
+
body.push(['span', {class: 'JSON_SUMMARY has-text-grey'}, summary]);
|
|
494
|
+
|
|
495
|
+
return ['div', {class: 'JSON_ROW JSON_CONTAINER', style: row_indent(depth)}, [
|
|
496
|
+
['span', {class: 'JSON_TOGGLE' + (open ? ' is-open' : '')}, [
|
|
497
|
+
['i', {class: 'yi-chevron-right'}]
|
|
498
|
+
]],
|
|
499
|
+
['span', {class: 'JSON_ROW_BODY'}, body],
|
|
500
|
+
], {
|
|
501
|
+
click: function(evt) {
|
|
502
|
+
evt.stopPropagation();
|
|
503
|
+
gobj_send_event(gobj, "EV_TOGGLE_NODE", {path: path}, gobj);
|
|
504
|
+
}
|
|
505
|
+
}];
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
/************************************************************
|
|
509
|
+
* Leaf (primitive) row, type-coloured, timestamp-tagged
|
|
510
|
+
************************************************************/
|
|
511
|
+
function leaf_row(key, value, depth)
|
|
512
|
+
{
|
|
513
|
+
let type = json_type(value);
|
|
514
|
+
let text;
|
|
515
|
+
switch(type) {
|
|
516
|
+
case "string":
|
|
517
|
+
text = '"' + value + '"';
|
|
518
|
+
break;
|
|
519
|
+
case "null":
|
|
520
|
+
text = "null";
|
|
521
|
+
break;
|
|
522
|
+
case "boolean":
|
|
523
|
+
text = value ? "true" : "false";
|
|
524
|
+
break;
|
|
525
|
+
default:
|
|
526
|
+
text = String(value);
|
|
527
|
+
break;
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
let body = [];
|
|
531
|
+
if(key !== null && key !== "") {
|
|
532
|
+
body.push(['span', {class: 'JSON_KEY'}, String(key)]);
|
|
533
|
+
body.push(['span', {class: 'JSON_PUNCT'}, ': ']);
|
|
534
|
+
}
|
|
535
|
+
body.push(['span', {class: 'JSON_VALUE JSON_TYPE_' + type.toUpperCase()}, text]);
|
|
536
|
+
|
|
537
|
+
if(key !== null && is_time_field(String(key))) {
|
|
538
|
+
let wall = format_epoch(value);
|
|
539
|
+
if(wall) {
|
|
540
|
+
body.push(['span', {class: 'JSON_TIME is-size-7 has-text-grey ml-2'}, wall]);
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
return ['div', {class: 'JSON_ROW JSON_LEAF', style: row_indent(depth)}, [
|
|
545
|
+
['span', {class: 'JSON_TOGGLE JSON_TOGGLE_SPACER'}, []],
|
|
546
|
+
['span', {class: 'JSON_ROW_BODY'}, body],
|
|
547
|
+
]];
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
/************************************************************
|
|
551
|
+
* Depth indentation (inline style keeps it CSS-framework free)
|
|
552
|
+
************************************************************/
|
|
553
|
+
function row_indent(depth)
|
|
554
|
+
{
|
|
555
|
+
return 'padding-left:' + (0.4 + depth * 1.1) + 'em;';
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
/************************************************************
|
|
559
|
+
* String() that never throws on a non-primitive
|
|
560
|
+
************************************************************/
|
|
561
|
+
function String_of(value)
|
|
562
|
+
{
|
|
563
|
+
try {
|
|
564
|
+
return String(value);
|
|
565
|
+
} catch(e) {
|
|
566
|
+
return "";
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
/************************************************************
|
|
571
|
+
* Recursively collect every loaded container path (for
|
|
572
|
+
* "expand loaded"). Collapsed sentinels are NOT expanded.
|
|
573
|
+
************************************************************/
|
|
574
|
+
function collect_loaded_paths(value, segments, out)
|
|
575
|
+
{
|
|
576
|
+
if(is_collapsed(value)) {
|
|
577
|
+
return;
|
|
578
|
+
}
|
|
579
|
+
let type = json_type(value);
|
|
580
|
+
if(type === "object") {
|
|
581
|
+
out.push(seg_join(segments));
|
|
582
|
+
for(let [k, v] of Object.entries(value)) {
|
|
583
|
+
collect_loaded_paths(v, segments.concat(k), out);
|
|
584
|
+
}
|
|
585
|
+
} else if(type === "array") {
|
|
586
|
+
out.push(seg_join(segments));
|
|
587
|
+
value.forEach(function(v, i) {
|
|
588
|
+
collect_loaded_paths(v, segments.concat(String(i)), out);
|
|
589
|
+
});
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
|
|
594
|
+
|
|
595
|
+
|
|
596
|
+
/***************************
|
|
597
|
+
* Actions
|
|
598
|
+
***************************/
|
|
599
|
+
|
|
600
|
+
|
|
601
|
+
|
|
602
|
+
|
|
603
|
+
/************************************************************
|
|
604
|
+
* EV_SET_JSON { json } — replace the whole document
|
|
605
|
+
************************************************************/
|
|
606
|
+
function ac_set_json(gobj, event, kw, src)
|
|
607
|
+
{
|
|
608
|
+
let priv = gobj.priv;
|
|
609
|
+
|
|
610
|
+
priv.root = (kw.json === undefined || kw.json === null)
|
|
611
|
+
? null
|
|
612
|
+
: json_deep_copy(kw.json);
|
|
613
|
+
priv.expanded.clear();
|
|
614
|
+
priv.pending.clear();
|
|
615
|
+
priv.errors.clear();
|
|
616
|
+
|
|
617
|
+
render_tree(gobj);
|
|
618
|
+
return 0;
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
/************************************************************
|
|
622
|
+
* EV_SUBTREE_LOADED { path, json } — splice a fetched subtree
|
|
623
|
+
************************************************************/
|
|
624
|
+
function ac_subtree_loaded(gobj, event, kw, src)
|
|
625
|
+
{
|
|
626
|
+
let priv = gobj.priv;
|
|
627
|
+
|
|
628
|
+
let path = kw.path || "";
|
|
629
|
+
let segments = seg_split(path);
|
|
630
|
+
|
|
631
|
+
if(segments.length === 0) {
|
|
632
|
+
priv.root = (kw.json === undefined) ? null : json_deep_copy(kw.json);
|
|
633
|
+
} else {
|
|
634
|
+
priv.root = set_by_segments(priv.root, segments, json_deep_copy(kw.json));
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
priv.pending.delete(path);
|
|
638
|
+
priv.errors.delete(path);
|
|
639
|
+
if(path) {
|
|
640
|
+
priv.expanded.add(path); // reveal what we just loaded
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
render_tree(gobj);
|
|
644
|
+
return 0;
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
/************************************************************
|
|
648
|
+
* EV_SUBTREE_ERROR { path, error } — mark the failed branch
|
|
649
|
+
************************************************************/
|
|
650
|
+
function ac_subtree_error(gobj, event, kw, src)
|
|
651
|
+
{
|
|
652
|
+
let priv = gobj.priv;
|
|
653
|
+
|
|
654
|
+
let path = kw.path || "";
|
|
655
|
+
priv.pending.delete(path);
|
|
656
|
+
priv.errors.set(path, kw.error || "error");
|
|
657
|
+
|
|
658
|
+
log_error(`${GCLASS_NAME}: subtree load failed at '${path}': ${kw.error || ""}`);
|
|
659
|
+
|
|
660
|
+
render_tree(gobj);
|
|
661
|
+
return 0;
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
/************************************************************
|
|
665
|
+
* EV_TOGGLE_NODE { path } — expand/collapse a loaded container
|
|
666
|
+
************************************************************/
|
|
667
|
+
function ac_toggle_node(gobj, event, kw, src)
|
|
668
|
+
{
|
|
669
|
+
let priv = gobj.priv;
|
|
670
|
+
let path = kw.path || "";
|
|
671
|
+
|
|
672
|
+
if(priv.expanded.has(path)) {
|
|
673
|
+
priv.expanded.delete(path);
|
|
674
|
+
} else {
|
|
675
|
+
priv.expanded.add(path);
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
render_tree(gobj);
|
|
679
|
+
return 0;
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
/************************************************************
|
|
683
|
+
* EV_EXPAND_COLLAPSED { path, size } — ask the subscriber to
|
|
684
|
+
* load a truncated subtree, then republish EV_EXPAND_PATH.
|
|
685
|
+
************************************************************/
|
|
686
|
+
function ac_expand_collapsed(gobj, event, kw, src)
|
|
687
|
+
{
|
|
688
|
+
let priv = gobj.priv;
|
|
689
|
+
let path = kw.path || "";
|
|
690
|
+
|
|
691
|
+
if(priv.pending.has(path)) {
|
|
692
|
+
return 0;
|
|
693
|
+
}
|
|
694
|
+
priv.pending.add(path);
|
|
695
|
+
priv.errors.delete(path);
|
|
696
|
+
|
|
697
|
+
render_tree(gobj); // show the "loading…" state
|
|
698
|
+
|
|
699
|
+
gobj_publish_event(gobj, "EV_EXPAND_PATH", {path: path, size: kw.size});
|
|
700
|
+
return 0;
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
/************************************************************
|
|
704
|
+
* EV_SEARCH { text }
|
|
705
|
+
************************************************************/
|
|
706
|
+
function ac_search(gobj, event, kw, src)
|
|
707
|
+
{
|
|
708
|
+
let priv = gobj.priv;
|
|
709
|
+
priv.search = (kw.text || "").trim().toLowerCase();
|
|
710
|
+
render_tree(gobj);
|
|
711
|
+
return 0;
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
/************************************************************
|
|
715
|
+
* EV_EXPAND_ALL — expand every already-loaded container
|
|
716
|
+
************************************************************/
|
|
717
|
+
function ac_expand_all(gobj, event, kw, src)
|
|
718
|
+
{
|
|
719
|
+
let priv = gobj.priv;
|
|
720
|
+
if(priv.root === null || priv.root === undefined) {
|
|
721
|
+
return 0;
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
let paths = [];
|
|
725
|
+
let type = json_type(priv.root);
|
|
726
|
+
if(type === "object") {
|
|
727
|
+
for(let [k, v] of Object.entries(priv.root)) {
|
|
728
|
+
collect_loaded_paths(v, [k], paths);
|
|
729
|
+
}
|
|
730
|
+
} else if(type === "array") {
|
|
731
|
+
priv.root.forEach(function(v, i) {
|
|
732
|
+
collect_loaded_paths(v, [String(i)], paths);
|
|
733
|
+
});
|
|
734
|
+
}
|
|
735
|
+
paths.forEach(function(p) {
|
|
736
|
+
priv.expanded.add(p);
|
|
737
|
+
});
|
|
738
|
+
|
|
739
|
+
render_tree(gobj);
|
|
740
|
+
return 0;
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
/************************************************************
|
|
744
|
+
* EV_COLLAPSE_ALL
|
|
745
|
+
************************************************************/
|
|
746
|
+
function ac_collapse_all(gobj, event, kw, src)
|
|
747
|
+
{
|
|
748
|
+
let priv = gobj.priv;
|
|
749
|
+
priv.expanded.clear();
|
|
750
|
+
render_tree(gobj);
|
|
751
|
+
return 0;
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
/************************************************************
|
|
755
|
+
* EV_COPY_ALL — copy the working document to the clipboard
|
|
756
|
+
************************************************************/
|
|
757
|
+
function ac_copy_all(gobj, event, kw, src)
|
|
758
|
+
{
|
|
759
|
+
let priv = gobj.priv;
|
|
760
|
+
if(priv.root === null || priv.root === undefined) {
|
|
761
|
+
return 0;
|
|
762
|
+
}
|
|
763
|
+
let text = JSON.stringify(priv.root, null, 2);
|
|
764
|
+
if(navigator.clipboard && navigator.clipboard.writeText) {
|
|
765
|
+
navigator.clipboard.writeText(text).catch(function(e) {
|
|
766
|
+
log_error(`${GCLASS_NAME}: clipboard write failed: ${e}`);
|
|
767
|
+
});
|
|
768
|
+
} else {
|
|
769
|
+
log_error(`${GCLASS_NAME}: clipboard API unavailable`);
|
|
770
|
+
}
|
|
771
|
+
return 0;
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
/************************************************************
|
|
775
|
+
* EV_LANGUAGE_CHANGED — re-translate chrome + re-render
|
|
776
|
+
************************************************************/
|
|
777
|
+
function ac_language_changed(gobj, event, kw, src)
|
|
778
|
+
{
|
|
779
|
+
let priv = gobj.priv;
|
|
780
|
+
let $container = gobj_read_attr(gobj, "$container");
|
|
781
|
+
if($container) {
|
|
782
|
+
refresh_language($container, t);
|
|
783
|
+
if(priv.$search) {
|
|
784
|
+
priv.$search.setAttribute("placeholder", t("search"));
|
|
785
|
+
}
|
|
786
|
+
}
|
|
787
|
+
render_tree(gobj);
|
|
788
|
+
return 0;
|
|
789
|
+
}
|
|
790
|
+
|
|
791
|
+
/************************************************************
|
|
792
|
+
* EV_SHOW / EV_HIDE — host visibility
|
|
793
|
+
************************************************************/
|
|
794
|
+
function ac_show(gobj, event, kw, src)
|
|
795
|
+
{
|
|
796
|
+
let $container = gobj_read_attr(gobj, "$container");
|
|
797
|
+
if($container) {
|
|
798
|
+
$container.classList.remove('is-hidden');
|
|
799
|
+
}
|
|
800
|
+
return 0;
|
|
801
|
+
}
|
|
802
|
+
|
|
803
|
+
function ac_hide(gobj, event, kw, src)
|
|
804
|
+
{
|
|
805
|
+
let $container = gobj_read_attr(gobj, "$container");
|
|
806
|
+
if($container) {
|
|
807
|
+
$container.classList.add('is-hidden');
|
|
808
|
+
}
|
|
809
|
+
return 0;
|
|
810
|
+
}
|
|
811
|
+
|
|
812
|
+
/************************************************************
|
|
813
|
+
* EV_REFRESH
|
|
814
|
+
************************************************************/
|
|
815
|
+
function ac_refresh(gobj, event, kw, src)
|
|
816
|
+
{
|
|
817
|
+
render_tree(gobj);
|
|
818
|
+
return 0;
|
|
819
|
+
}
|
|
820
|
+
|
|
821
|
+
|
|
822
|
+
|
|
823
|
+
|
|
824
|
+
/***************************
|
|
825
|
+
* FSM
|
|
826
|
+
***************************/
|
|
827
|
+
|
|
828
|
+
|
|
829
|
+
|
|
830
|
+
|
|
831
|
+
/*---------------------------------------------*
|
|
832
|
+
* Global methods table
|
|
833
|
+
*---------------------------------------------*/
|
|
834
|
+
const gmt = {
|
|
835
|
+
mt_create: mt_create,
|
|
836
|
+
mt_start: mt_start,
|
|
837
|
+
mt_stop: mt_stop,
|
|
838
|
+
mt_destroy: mt_destroy,
|
|
839
|
+
};
|
|
840
|
+
|
|
841
|
+
/***************************************************************
|
|
842
|
+
* Create the GClass
|
|
843
|
+
***************************************************************/
|
|
844
|
+
function create_gclass(gclass_name)
|
|
845
|
+
{
|
|
846
|
+
if(__gclass__) {
|
|
847
|
+
log_error(`GClass ALREADY created: ${gclass_name}`);
|
|
848
|
+
return -1;
|
|
849
|
+
}
|
|
850
|
+
|
|
851
|
+
/*---------------------------------------------*
|
|
852
|
+
* States
|
|
853
|
+
*---------------------------------------------*/
|
|
854
|
+
const states = [
|
|
855
|
+
["ST_EMPTY", [
|
|
856
|
+
["EV_SET_JSON", ac_set_json, "ST_READY"],
|
|
857
|
+
["EV_LANGUAGE_CHANGED", ac_language_changed, null],
|
|
858
|
+
["EV_REFRESH", ac_refresh, null],
|
|
859
|
+
["EV_SHOW", ac_show, null],
|
|
860
|
+
["EV_HIDE", ac_hide, null]
|
|
861
|
+
]],
|
|
862
|
+
["ST_READY", [
|
|
863
|
+
["EV_SET_JSON", ac_set_json, null],
|
|
864
|
+
["EV_SUBTREE_LOADED", ac_subtree_loaded, null],
|
|
865
|
+
["EV_SUBTREE_ERROR", ac_subtree_error, null],
|
|
866
|
+
["EV_TOGGLE_NODE", ac_toggle_node, null],
|
|
867
|
+
["EV_EXPAND_COLLAPSED", ac_expand_collapsed, null],
|
|
868
|
+
["EV_SEARCH", ac_search, null],
|
|
869
|
+
["EV_EXPAND_ALL", ac_expand_all, null],
|
|
870
|
+
["EV_COLLAPSE_ALL", ac_collapse_all, null],
|
|
871
|
+
["EV_COPY_ALL", ac_copy_all, null],
|
|
872
|
+
["EV_LANGUAGE_CHANGED", ac_language_changed, null],
|
|
873
|
+
["EV_REFRESH", ac_refresh, null],
|
|
874
|
+
["EV_SHOW", ac_show, null],
|
|
875
|
+
["EV_HIDE", ac_hide, null]
|
|
876
|
+
]]
|
|
877
|
+
];
|
|
878
|
+
|
|
879
|
+
/*---------------------------------------------*
|
|
880
|
+
* Events
|
|
881
|
+
*---------------------------------------------*/
|
|
882
|
+
const event_types = [
|
|
883
|
+
["EV_SET_JSON", 0],
|
|
884
|
+
["EV_SUBTREE_LOADED", 0],
|
|
885
|
+
["EV_SUBTREE_ERROR", 0],
|
|
886
|
+
["EV_TOGGLE_NODE", 0],
|
|
887
|
+
["EV_EXPAND_COLLAPSED", 0],
|
|
888
|
+
["EV_SEARCH", 0],
|
|
889
|
+
["EV_EXPAND_ALL", 0],
|
|
890
|
+
["EV_COLLAPSE_ALL", 0],
|
|
891
|
+
["EV_COPY_ALL", 0],
|
|
892
|
+
["EV_LANGUAGE_CHANGED", 0],
|
|
893
|
+
["EV_REFRESH", 0],
|
|
894
|
+
["EV_SHOW", 0],
|
|
895
|
+
["EV_HIDE", 0],
|
|
896
|
+
["EV_EXPAND_PATH", event_flag_t.EVF_OUTPUT_EVENT|event_flag_t.EVF_NO_WARN_SUBS]
|
|
897
|
+
];
|
|
898
|
+
|
|
899
|
+
__gclass__ = gclass_create(
|
|
900
|
+
gclass_name,
|
|
901
|
+
event_types,
|
|
902
|
+
states,
|
|
903
|
+
gmt,
|
|
904
|
+
0, // lmt,
|
|
905
|
+
attrs_table,
|
|
906
|
+
PRIVATE_DATA,
|
|
907
|
+
0, // authz_table,
|
|
908
|
+
0, // command_table,
|
|
909
|
+
0, // s_user_trace_level
|
|
910
|
+
0 // gclass_flag
|
|
911
|
+
);
|
|
912
|
+
|
|
913
|
+
if(!__gclass__) {
|
|
914
|
+
return -1;
|
|
915
|
+
}
|
|
916
|
+
|
|
917
|
+
return 0;
|
|
918
|
+
}
|
|
919
|
+
|
|
920
|
+
/***************************************************************
|
|
921
|
+
* Register GClass
|
|
922
|
+
***************************************************************/
|
|
923
|
+
function register_c_yui_json()
|
|
924
|
+
{
|
|
925
|
+
return create_gclass(GCLASS_NAME);
|
|
926
|
+
}
|
|
927
|
+
|
|
928
|
+
export { register_c_yui_json };
|