@yuneta/gobj-ui 7.19.4 → 7.20.1
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 +26 -3
- package/dist/gobj-ui.cjs.js +256 -29
- package/dist/gobj-ui.es.js +256 -29
- package/package.json +1 -1
- package/src/c_yui_json.css +38 -1
- package/src/c_yui_json.js +233 -16
- package/src/json_view_helpers.js +32 -2
- package/src/json_view_helpers.test.js +42 -0
- package/src/yui_icons.css +13 -0
package/dist/gobj-ui.es.js
CHANGED
|
@@ -10411,6 +10411,39 @@ function format_epoch(value) {
|
|
|
10411
10411
|
if (isNaN(d.getTime())) return null;
|
|
10412
10412
|
return d.toLocaleString();
|
|
10413
10413
|
}
|
|
10414
|
+
/************************************************************
|
|
10415
|
+
* The text view's payload: the document as text, indented
|
|
10416
|
+
* four characters, cut at `max_chars`.
|
|
10417
|
+
*
|
|
10418
|
+
* Returns {text, capped}. `capped` is what the caller
|
|
10419
|
+
* announces under the dump — a cut that is not announced
|
|
10420
|
+
* reads as a document that ends there.
|
|
10421
|
+
************************************************************/
|
|
10422
|
+
function json_text_dump(root, max_chars) {
|
|
10423
|
+
let text;
|
|
10424
|
+
try {
|
|
10425
|
+
text = JSON.stringify(root, null, 4);
|
|
10426
|
+
} catch (e) {
|
|
10427
|
+
return {
|
|
10428
|
+
text: "",
|
|
10429
|
+
capped: false,
|
|
10430
|
+
error: String(e)
|
|
10431
|
+
};
|
|
10432
|
+
}
|
|
10433
|
+
if (text === void 0) return {
|
|
10434
|
+
text: "",
|
|
10435
|
+
capped: false,
|
|
10436
|
+
error: "not representable as JSON"
|
|
10437
|
+
};
|
|
10438
|
+
if (typeof max_chars === "number" && max_chars > 0 && text.length > max_chars) return {
|
|
10439
|
+
text: text.slice(0, max_chars),
|
|
10440
|
+
capped: true
|
|
10441
|
+
};
|
|
10442
|
+
return {
|
|
10443
|
+
text,
|
|
10444
|
+
capped: false
|
|
10445
|
+
};
|
|
10446
|
+
}
|
|
10414
10447
|
//#endregion
|
|
10415
10448
|
//#region src/c_yui_json.js
|
|
10416
10449
|
/***********************************************************************
|
|
@@ -10439,9 +10472,19 @@ function format_epoch(value) {
|
|
|
10439
10472
|
* Only expanded containers are materialised in the DOM, so the tree
|
|
10440
10473
|
* stays bounded no matter how large the source document is.
|
|
10441
10474
|
*
|
|
10475
|
+
* TWO VIEWS over the same working document, chosen by the `view_mode`
|
|
10476
|
+
* attr ("tree" | "text") and switched from the toolbar: the lazy tree
|
|
10477
|
+
* above, and the raw `JSON.stringify(…, 4)` dump of what is currently
|
|
10478
|
+
* loaded. The text view is what you reach for to read a document as
|
|
10479
|
+
* it is written, to select a slab of it, or to search it with the
|
|
10480
|
+
* browser's own Ctrl+F; it shows the `__collapsed__` sentinels
|
|
10481
|
+
* verbatim, because that is honestly what the client holds. The
|
|
10482
|
+
* tree-only controls (search, expand/collapse) hide with the tree.
|
|
10483
|
+
*
|
|
10442
10484
|
* DOM is self-describing (UPPER_SNAKE logical classes): JSON_VIEWER /
|
|
10443
|
-
* JSON_TOOLBAR / JSON_SEARCH /
|
|
10444
|
-
*
|
|
10485
|
+
* JSON_TOOLBAR / JSON_SEARCH / JSON_VIEW_MODE / JSON_TREE / JSON_TEXT /
|
|
10486
|
+
* JSON_TEXT_BODY / JSON_ROW / JSON_KEY / JSON_VALUE / JSON_SUMMARY /
|
|
10487
|
+
* JSON_COLLAPSED / JSON_TIME.
|
|
10445
10488
|
*
|
|
10446
10489
|
* Copyright (c) 2026, ArtGins.
|
|
10447
10490
|
* All Rights Reserved.
|
|
@@ -10451,6 +10494,7 @@ function format_epoch(value) {
|
|
|
10451
10494
|
***************************************************************/
|
|
10452
10495
|
var GCLASS_NAME$10 = "C_YUI_JSON";
|
|
10453
10496
|
var MAX_RENDER_ROWS = 5e3;
|
|
10497
|
+
var MAX_TEXT_CHARS = 2e6;
|
|
10454
10498
|
/***************************************************************
|
|
10455
10499
|
* Data
|
|
10456
10500
|
***************************************************************/
|
|
@@ -10458,6 +10502,7 @@ var attrs_table$10 = [
|
|
|
10458
10502
|
SDATA(data_type_t.DTP_POINTER, "subscriber", 0, null, "Subscriber of output events"),
|
|
10459
10503
|
SDATA(data_type_t.DTP_STRING, "title", 0, "", "Optional header title (i18n key)"),
|
|
10460
10504
|
SDATA(data_type_t.DTP_JSON, "json_data", 0, null, "Initial JSON to render (usually already collapsed)"),
|
|
10505
|
+
SDATA(data_type_t.DTP_STRING, "view_mode", 0, "tree", "View: 'tree' (lazy tree) or 'text' (raw JSON dump)"),
|
|
10461
10506
|
SDATA(data_type_t.DTP_POINTER, "$container", 0, null, "HTMLElement root, mounted by the parent"),
|
|
10462
10507
|
SDATA_END()
|
|
10463
10508
|
];
|
|
@@ -10468,7 +10513,13 @@ var PRIVATE_DATA$10 = {
|
|
|
10468
10513
|
errors: null,
|
|
10469
10514
|
search: "",
|
|
10470
10515
|
$tree: null,
|
|
10471
|
-
$
|
|
10516
|
+
$text: null,
|
|
10517
|
+
$text_body: null,
|
|
10518
|
+
$search: null,
|
|
10519
|
+
$search_ctl: null,
|
|
10520
|
+
$expand_btn: null,
|
|
10521
|
+
$collapse_btn: null,
|
|
10522
|
+
$mode_btn: null
|
|
10472
10523
|
};
|
|
10473
10524
|
var __gclass__$10 = null;
|
|
10474
10525
|
/******************************
|
|
@@ -10486,6 +10537,7 @@ function mt_create$10(gobj) {
|
|
|
10486
10537
|
let json_data = gobj_read_attr(gobj, "json_data");
|
|
10487
10538
|
if (json_data !== null && json_data !== void 0) priv.root = json_deep_copy(json_data);
|
|
10488
10539
|
build_ui$9(gobj);
|
|
10540
|
+
apply_view_mode(gobj);
|
|
10489
10541
|
let subscriber = gobj_read_pointer_attr(gobj, "subscriber");
|
|
10490
10542
|
if (!subscriber) subscriber = gobj_parent(gobj);
|
|
10491
10543
|
gobj_subscribe_event(gobj, null, {}, subscriber);
|
|
@@ -10494,7 +10546,7 @@ function mt_create$10(gobj) {
|
|
|
10494
10546
|
* Framework Method: Start
|
|
10495
10547
|
***************************************************************/
|
|
10496
10548
|
function mt_start$10(gobj) {
|
|
10497
|
-
|
|
10549
|
+
render_view(gobj);
|
|
10498
10550
|
}
|
|
10499
10551
|
/***************************************************************
|
|
10500
10552
|
* Framework Method: Stop
|
|
@@ -10521,22 +10573,38 @@ function build_ui$9(gobj) {
|
|
|
10521
10573
|
class: "C_YUI_JSON JSON_VIEWER view-card",
|
|
10522
10574
|
style: "height:100%; display:flex; flex-direction:column;"
|
|
10523
10575
|
},
|
|
10524
|
-
[
|
|
10525
|
-
|
|
10526
|
-
|
|
10527
|
-
|
|
10528
|
-
|
|
10529
|
-
|
|
10530
|
-
|
|
10531
|
-
|
|
10532
|
-
|
|
10533
|
-
|
|
10534
|
-
|
|
10535
|
-
|
|
10576
|
+
[
|
|
10577
|
+
[
|
|
10578
|
+
"div",
|
|
10579
|
+
{ class: "JSON_TOOLBAR is-flex-grow-0" },
|
|
10580
|
+
[$toolbar]
|
|
10581
|
+
],
|
|
10582
|
+
[
|
|
10583
|
+
"div",
|
|
10584
|
+
{
|
|
10585
|
+
class: "JSON_TREE is-flex-grow-1",
|
|
10586
|
+
style: "flex:1 1 auto; min-height:0; overflow:auto;"
|
|
10587
|
+
},
|
|
10588
|
+
[]
|
|
10589
|
+
],
|
|
10590
|
+
[
|
|
10591
|
+
"div",
|
|
10592
|
+
{
|
|
10593
|
+
class: "JSON_TEXT is-flex-grow-1 is-hidden",
|
|
10594
|
+
style: "flex:1 1 auto; min-height:0; overflow:auto;"
|
|
10595
|
+
},
|
|
10596
|
+
[]
|
|
10597
|
+
]
|
|
10598
|
+
]
|
|
10536
10599
|
]);
|
|
10537
10600
|
gobj_write_attr(gobj, "$container", $container);
|
|
10538
10601
|
priv.$tree = $container.querySelector(".JSON_TREE");
|
|
10602
|
+
priv.$text = $container.querySelector(".JSON_TEXT");
|
|
10539
10603
|
priv.$search = $container.querySelector(".JSON_SEARCH");
|
|
10604
|
+
priv.$search_ctl = $container.querySelector(".JSON_SEARCH_CONTROL");
|
|
10605
|
+
priv.$expand_btn = $container.querySelector(".EV_EXPAND_ALL");
|
|
10606
|
+
priv.$collapse_btn = $container.querySelector(".EV_COLLAPSE_ALL");
|
|
10607
|
+
priv.$mode_btn = $container.querySelector(".JSON_VIEW_MODE");
|
|
10540
10608
|
refresh_language($container, t);
|
|
10541
10609
|
}
|
|
10542
10610
|
/************************************************************
|
|
@@ -10550,10 +10618,17 @@ function destroy_ui$5(gobj) {
|
|
|
10550
10618
|
gobj_write_attr(gobj, "$container", null);
|
|
10551
10619
|
}
|
|
10552
10620
|
priv.$tree = null;
|
|
10621
|
+
priv.$text = null;
|
|
10622
|
+
priv.$text_body = null;
|
|
10553
10623
|
priv.$search = null;
|
|
10624
|
+
priv.$search_ctl = null;
|
|
10625
|
+
priv.$expand_btn = null;
|
|
10626
|
+
priv.$collapse_btn = null;
|
|
10627
|
+
priv.$mode_btn = null;
|
|
10554
10628
|
}
|
|
10555
10629
|
/************************************************************
|
|
10556
|
-
* Toolbar: search +
|
|
10630
|
+
* Toolbar: search + tree/text switch + expand-all /
|
|
10631
|
+
* collapse-all / copy
|
|
10557
10632
|
************************************************************/
|
|
10558
10633
|
function make_toolbar$2(gobj) {
|
|
10559
10634
|
let title = gobj_read_str_attr(gobj, "title");
|
|
@@ -10582,7 +10657,7 @@ function make_toolbar$2(gobj) {
|
|
|
10582
10657
|
let $search_control = createElement2([
|
|
10583
10658
|
"div",
|
|
10584
10659
|
{
|
|
10585
|
-
class: "control has-icons-left",
|
|
10660
|
+
class: "control has-icons-left JSON_SEARCH_CONTROL",
|
|
10586
10661
|
style: "max-width:22em;"
|
|
10587
10662
|
},
|
|
10588
10663
|
[$search_input, [
|
|
@@ -10594,6 +10669,7 @@ function make_toolbar$2(gobj) {
|
|
|
10594
10669
|
attach_clear($search_control, $search_input);
|
|
10595
10670
|
left_items.push($search_control);
|
|
10596
10671
|
let right_items = [
|
|
10672
|
+
view_mode_button(gobj),
|
|
10597
10673
|
icon_button(gobj, "yi-chevron-right", "EV_EXPAND_ALL", "expand loaded"),
|
|
10598
10674
|
icon_button(gobj, "yi-chevron-right", "EV_COLLAPSE_ALL", "collapse all"),
|
|
10599
10675
|
icon_button(gobj, "yi-copy", "EV_COPY_ALL", "copy json")
|
|
@@ -10650,6 +10726,123 @@ function icon_button(gobj, icon, event_name, label_key) {
|
|
|
10650
10726
|
];
|
|
10651
10727
|
}
|
|
10652
10728
|
/************************************************************
|
|
10729
|
+
* The tree/text switch.
|
|
10730
|
+
*
|
|
10731
|
+
* It shows the view it takes you TO — the `code` glyph while the
|
|
10732
|
+
* tree is on screen, the `sitemap` glyph while the text is — and
|
|
10733
|
+
* sends EV_SET_VIEW_MODE with no mode, which the action reads as
|
|
10734
|
+
* "toggle". apply_view_mode() keeps the icon and its i18n keys in
|
|
10735
|
+
* step with the attr.
|
|
10736
|
+
************************************************************/
|
|
10737
|
+
function view_mode_button(gobj) {
|
|
10738
|
+
return [
|
|
10739
|
+
"button",
|
|
10740
|
+
{
|
|
10741
|
+
class: "button JSON_VIEW_MODE",
|
|
10742
|
+
style: "width:2.5em;",
|
|
10743
|
+
title: t("text view"),
|
|
10744
|
+
"data-i18n-title": "text view",
|
|
10745
|
+
"aria-label": t("text view"),
|
|
10746
|
+
"data-i18n-aria-label": "text view"
|
|
10747
|
+
},
|
|
10748
|
+
[[
|
|
10749
|
+
"span",
|
|
10750
|
+
{ class: "icon" },
|
|
10751
|
+
[["i", { class: "yi-code" }]]
|
|
10752
|
+
]],
|
|
10753
|
+
{ click: function(evt) {
|
|
10754
|
+
evt.stopPropagation();
|
|
10755
|
+
gobj_send_event(gobj, "EV_SET_VIEW_MODE", {}, gobj);
|
|
10756
|
+
} }
|
|
10757
|
+
];
|
|
10758
|
+
}
|
|
10759
|
+
/************************************************************
|
|
10760
|
+
* The current view, normalised. Anything but "text" is the tree.
|
|
10761
|
+
************************************************************/
|
|
10762
|
+
function current_view_mode(gobj) {
|
|
10763
|
+
return gobj_read_str_attr(gobj, "view_mode") === "text" ? "text" : "tree";
|
|
10764
|
+
}
|
|
10765
|
+
/************************************************************
|
|
10766
|
+
* Show the chrome of the current view and hide the other's.
|
|
10767
|
+
************************************************************/
|
|
10768
|
+
function apply_view_mode(gobj) {
|
|
10769
|
+
let priv = gobj.priv;
|
|
10770
|
+
let text_mode = current_view_mode(gobj) === "text";
|
|
10771
|
+
if (priv.$tree) priv.$tree.classList.toggle("is-hidden", text_mode);
|
|
10772
|
+
if (priv.$text) priv.$text.classList.toggle("is-hidden", !text_mode);
|
|
10773
|
+
[
|
|
10774
|
+
priv.$search_ctl,
|
|
10775
|
+
priv.$expand_btn,
|
|
10776
|
+
priv.$collapse_btn
|
|
10777
|
+
].forEach(function($el) {
|
|
10778
|
+
if ($el) $el.classList.toggle("is-hidden", text_mode);
|
|
10779
|
+
});
|
|
10780
|
+
if (priv.$mode_btn) {
|
|
10781
|
+
let icon = text_mode ? "yi-sitemap" : "yi-code";
|
|
10782
|
+
let key = text_mode ? "tree view" : "text view";
|
|
10783
|
+
let label = text_mode ? t("tree view") : t("text view");
|
|
10784
|
+
let $i = priv.$mode_btn.querySelector("i");
|
|
10785
|
+
if ($i) $i.className = icon;
|
|
10786
|
+
priv.$mode_btn.setAttribute("data-i18n-title", key);
|
|
10787
|
+
priv.$mode_btn.setAttribute("data-i18n-aria-label", key);
|
|
10788
|
+
priv.$mode_btn.setAttribute("title", label);
|
|
10789
|
+
priv.$mode_btn.setAttribute("aria-label", label);
|
|
10790
|
+
}
|
|
10791
|
+
}
|
|
10792
|
+
/************************************************************
|
|
10793
|
+
* Render whichever view is current.
|
|
10794
|
+
************************************************************/
|
|
10795
|
+
function render_view(gobj) {
|
|
10796
|
+
if (current_view_mode(gobj) === "text") render_text(gobj);
|
|
10797
|
+
else render_tree(gobj);
|
|
10798
|
+
}
|
|
10799
|
+
/************************************************************
|
|
10800
|
+
* Render the text view: the whole loaded document, verbatim.
|
|
10801
|
+
*
|
|
10802
|
+
* Unlike the tree, nothing here is lazy — what the client holds is
|
|
10803
|
+
* what it prints, `__collapsed__` sentinels included. Over
|
|
10804
|
+
* MAX_TEXT_CHARS the dump is cut and the cut is announced.
|
|
10805
|
+
************************************************************/
|
|
10806
|
+
function render_text(gobj) {
|
|
10807
|
+
let priv = gobj.priv;
|
|
10808
|
+
let $text = priv.$text;
|
|
10809
|
+
if (!$text) return;
|
|
10810
|
+
let scroll_top = $text.scrollTop;
|
|
10811
|
+
$text.textContent = "";
|
|
10812
|
+
priv.$text_body = null;
|
|
10813
|
+
if (priv.root === null || priv.root === void 0) {
|
|
10814
|
+
$text.appendChild(createElement2([
|
|
10815
|
+
"div",
|
|
10816
|
+
{
|
|
10817
|
+
class: "JSON_EMPTY has-text-grey p-3",
|
|
10818
|
+
"data-i18n": "no data"
|
|
10819
|
+
},
|
|
10820
|
+
"no data"
|
|
10821
|
+
]));
|
|
10822
|
+
return;
|
|
10823
|
+
}
|
|
10824
|
+
let dump = json_text_dump(priv.root, MAX_TEXT_CHARS);
|
|
10825
|
+
if (dump.error) log_error(`${GCLASS_NAME$10}: cannot dump the document as text: ${dump.error}`);
|
|
10826
|
+
let $pre = createElement2([
|
|
10827
|
+
"pre",
|
|
10828
|
+
{ class: "JSON_TEXT_BODY" },
|
|
10829
|
+
[]
|
|
10830
|
+
]);
|
|
10831
|
+
$pre.textContent = dump.text;
|
|
10832
|
+
$text.appendChild($pre);
|
|
10833
|
+
priv.$text_body = $pre;
|
|
10834
|
+
if (dump.capped) $text.appendChild(createElement2([
|
|
10835
|
+
"div",
|
|
10836
|
+
{
|
|
10837
|
+
class: "JSON_CAPPED has-text-warning p-2",
|
|
10838
|
+
"data-i18n": "text truncated; collapse some branches"
|
|
10839
|
+
},
|
|
10840
|
+
"text truncated; collapse some branches"
|
|
10841
|
+
]));
|
|
10842
|
+
refresh_language($text, t);
|
|
10843
|
+
$text.scrollTop = scroll_top;
|
|
10844
|
+
}
|
|
10845
|
+
/************************************************************
|
|
10653
10846
|
* Re-render the whole tree from priv.root + priv.expanded.
|
|
10654
10847
|
*
|
|
10655
10848
|
* Only expanded containers are walked, so the DOM size is
|
|
@@ -10980,7 +11173,7 @@ function ac_set_json(gobj, event, kw, src) {
|
|
|
10980
11173
|
priv.expanded.clear();
|
|
10981
11174
|
priv.pending.clear();
|
|
10982
11175
|
priv.errors.clear();
|
|
10983
|
-
|
|
11176
|
+
render_view(gobj);
|
|
10984
11177
|
return 0;
|
|
10985
11178
|
}
|
|
10986
11179
|
/************************************************************
|
|
@@ -10995,7 +11188,7 @@ function ac_subtree_loaded(gobj, event, kw, src) {
|
|
|
10995
11188
|
priv.pending.delete(path);
|
|
10996
11189
|
priv.errors.delete(path);
|
|
10997
11190
|
if (path) priv.expanded.add(path);
|
|
10998
|
-
|
|
11191
|
+
render_view(gobj);
|
|
10999
11192
|
return 0;
|
|
11000
11193
|
}
|
|
11001
11194
|
/************************************************************
|
|
@@ -11007,7 +11200,7 @@ function ac_subtree_error(gobj, event, kw, src) {
|
|
|
11007
11200
|
priv.pending.delete(path);
|
|
11008
11201
|
priv.errors.set(path, kw.error || "error");
|
|
11009
11202
|
log_error(`${GCLASS_NAME$10}: subtree load failed at '${path}': ${kw.error || ""}`);
|
|
11010
|
-
|
|
11203
|
+
render_view(gobj);
|
|
11011
11204
|
return 0;
|
|
11012
11205
|
}
|
|
11013
11206
|
/************************************************************
|
|
@@ -11018,7 +11211,7 @@ function ac_toggle_node(gobj, event, kw, src) {
|
|
|
11018
11211
|
let path = kw.path || "";
|
|
11019
11212
|
if (priv.expanded.has(path)) priv.expanded.delete(path);
|
|
11020
11213
|
else priv.expanded.add(path);
|
|
11021
|
-
|
|
11214
|
+
render_view(gobj);
|
|
11022
11215
|
return 0;
|
|
11023
11216
|
}
|
|
11024
11217
|
/************************************************************
|
|
@@ -11031,7 +11224,7 @@ function ac_expand_collapsed(gobj, event, kw, src) {
|
|
|
11031
11224
|
if (priv.pending.has(path)) return 0;
|
|
11032
11225
|
priv.pending.add(path);
|
|
11033
11226
|
priv.errors.delete(path);
|
|
11034
|
-
|
|
11227
|
+
render_view(gobj);
|
|
11035
11228
|
gobj_publish_event(gobj, "EV_EXPAND_PATH", {
|
|
11036
11229
|
path,
|
|
11037
11230
|
size: kw.size
|
|
@@ -11044,7 +11237,7 @@ function ac_expand_collapsed(gobj, event, kw, src) {
|
|
|
11044
11237
|
function ac_search$1(gobj, event, kw, src) {
|
|
11045
11238
|
let priv = gobj.priv;
|
|
11046
11239
|
priv.search = (kw.text || "").trim().toLowerCase();
|
|
11047
|
-
|
|
11240
|
+
render_view(gobj);
|
|
11048
11241
|
return 0;
|
|
11049
11242
|
}
|
|
11050
11243
|
/************************************************************
|
|
@@ -11062,7 +11255,7 @@ function ac_expand_all$1(gobj, event, kw, src) {
|
|
|
11062
11255
|
paths.forEach(function(p) {
|
|
11063
11256
|
priv.expanded.add(p);
|
|
11064
11257
|
});
|
|
11065
|
-
|
|
11258
|
+
render_view(gobj);
|
|
11066
11259
|
return 0;
|
|
11067
11260
|
}
|
|
11068
11261
|
/************************************************************
|
|
@@ -11070,7 +11263,7 @@ function ac_expand_all$1(gobj, event, kw, src) {
|
|
|
11070
11263
|
************************************************************/
|
|
11071
11264
|
function ac_collapse_all$1(gobj, event, kw, src) {
|
|
11072
11265
|
gobj.priv.expanded.clear();
|
|
11073
|
-
|
|
11266
|
+
render_view(gobj);
|
|
11074
11267
|
return 0;
|
|
11075
11268
|
}
|
|
11076
11269
|
/************************************************************
|
|
@@ -11079,7 +11272,12 @@ function ac_collapse_all$1(gobj, event, kw, src) {
|
|
|
11079
11272
|
function ac_copy_all(gobj, event, kw, src) {
|
|
11080
11273
|
let priv = gobj.priv;
|
|
11081
11274
|
if (priv.root === null || priv.root === void 0) return 0;
|
|
11082
|
-
let
|
|
11275
|
+
let dump = json_text_dump(priv.root, 0);
|
|
11276
|
+
if (dump.error) {
|
|
11277
|
+
log_error(`${GCLASS_NAME$10}: cannot copy the document: ${dump.error}`);
|
|
11278
|
+
return -1;
|
|
11279
|
+
}
|
|
11280
|
+
let text = dump.text;
|
|
11083
11281
|
if (navigator.clipboard && navigator.clipboard.writeText) navigator.clipboard.writeText(text).catch(function(e) {
|
|
11084
11282
|
log_error(`${GCLASS_NAME$10}: clipboard write failed: ${e}`);
|
|
11085
11283
|
});
|
|
@@ -11087,6 +11285,23 @@ function ac_copy_all(gobj, event, kw, src) {
|
|
|
11087
11285
|
return 0;
|
|
11088
11286
|
}
|
|
11089
11287
|
/************************************************************
|
|
11288
|
+
* EV_SET_VIEW_MODE { mode } — "tree" | "text".
|
|
11289
|
+
*
|
|
11290
|
+
* With no mode it toggles, which is what the toolbar button sends.
|
|
11291
|
+
************************************************************/
|
|
11292
|
+
function ac_set_view_mode(gobj, event, kw, src) {
|
|
11293
|
+
let mode = kw.mode;
|
|
11294
|
+
if (mode === void 0 || mode === null || mode === "") mode = current_view_mode(gobj) === "text" ? "tree" : "text";
|
|
11295
|
+
else if (mode !== "tree" && mode !== "text") {
|
|
11296
|
+
log_error(`${GCLASS_NAME$10}: unknown view_mode '${mode}'`);
|
|
11297
|
+
return -1;
|
|
11298
|
+
}
|
|
11299
|
+
gobj_write_attr(gobj, "view_mode", mode);
|
|
11300
|
+
apply_view_mode(gobj);
|
|
11301
|
+
render_view(gobj);
|
|
11302
|
+
return 0;
|
|
11303
|
+
}
|
|
11304
|
+
/************************************************************
|
|
11090
11305
|
* EV_LANGUAGE_CHANGED — re-translate chrome + re-render
|
|
11091
11306
|
************************************************************/
|
|
11092
11307
|
function ac_language_changed$3(gobj, event, kw, src) {
|
|
@@ -11095,8 +11310,9 @@ function ac_language_changed$3(gobj, event, kw, src) {
|
|
|
11095
11310
|
if ($container) {
|
|
11096
11311
|
refresh_language($container, t);
|
|
11097
11312
|
if (priv.$search) priv.$search.setAttribute("placeholder", t("search"));
|
|
11313
|
+
apply_view_mode(gobj);
|
|
11098
11314
|
}
|
|
11099
|
-
|
|
11315
|
+
render_view(gobj);
|
|
11100
11316
|
return 0;
|
|
11101
11317
|
}
|
|
11102
11318
|
/************************************************************
|
|
@@ -11116,7 +11332,7 @@ function ac_hide$6(gobj, event, kw, src) {
|
|
|
11116
11332
|
* EV_REFRESH
|
|
11117
11333
|
************************************************************/
|
|
11118
11334
|
function ac_refresh$4(gobj, event, kw, src) {
|
|
11119
|
-
|
|
11335
|
+
render_view(gobj);
|
|
11120
11336
|
return 0;
|
|
11121
11337
|
}
|
|
11122
11338
|
/***************************
|
|
@@ -11142,6 +11358,11 @@ function create_gclass$10(gclass_name) {
|
|
|
11142
11358
|
ac_set_json,
|
|
11143
11359
|
"ST_READY"
|
|
11144
11360
|
],
|
|
11361
|
+
[
|
|
11362
|
+
"EV_SET_VIEW_MODE",
|
|
11363
|
+
ac_set_view_mode,
|
|
11364
|
+
null
|
|
11365
|
+
],
|
|
11145
11366
|
[
|
|
11146
11367
|
"EV_LANGUAGE_CHANGED",
|
|
11147
11368
|
ac_language_changed$3,
|
|
@@ -11208,6 +11429,11 @@ function create_gclass$10(gclass_name) {
|
|
|
11208
11429
|
ac_copy_all,
|
|
11209
11430
|
null
|
|
11210
11431
|
],
|
|
11432
|
+
[
|
|
11433
|
+
"EV_SET_VIEW_MODE",
|
|
11434
|
+
ac_set_view_mode,
|
|
11435
|
+
null
|
|
11436
|
+
],
|
|
11211
11437
|
[
|
|
11212
11438
|
"EV_LANGUAGE_CHANGED",
|
|
11213
11439
|
ac_language_changed$3,
|
|
@@ -11239,6 +11465,7 @@ function create_gclass$10(gclass_name) {
|
|
|
11239
11465
|
["EV_EXPAND_ALL", 0],
|
|
11240
11466
|
["EV_COLLAPSE_ALL", 0],
|
|
11241
11467
|
["EV_COPY_ALL", 0],
|
|
11468
|
+
["EV_SET_VIEW_MODE", 0],
|
|
11242
11469
|
["EV_LANGUAGE_CHANGED", 0],
|
|
11243
11470
|
["EV_REFRESH", 0],
|
|
11244
11471
|
["EV_SHOW", 0],
|
package/package.json
CHANGED
package/src/c_yui_json.css
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/***********************************************************************
|
|
2
2
|
* c_yui_json.css
|
|
3
3
|
*
|
|
4
|
-
* Styling for C_YUI_JSON (lazy JSON tree viewer).
|
|
4
|
+
* Styling for C_YUI_JSON (lazy JSON tree viewer + raw text view).
|
|
5
5
|
* Monospace tree, type-coloured leaves, dark-aware.
|
|
6
6
|
* No transitions/animations by design (lib-yui convention).
|
|
7
7
|
*
|
|
@@ -151,6 +151,43 @@
|
|
|
151
151
|
opacity: 0.7;
|
|
152
152
|
}
|
|
153
153
|
|
|
154
|
+
/*
|
|
155
|
+
* Text view: the same document as a raw dump, monospace like the tree.
|
|
156
|
+
*/
|
|
157
|
+
.C_YUI_JSON .JSON_TEXT {
|
|
158
|
+
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
|
|
159
|
+
font-size: 1em;
|
|
160
|
+
line-height: 1.5;
|
|
161
|
+
padding: 0.25rem 0.5rem;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
.C_YUI_JSON .JSON_TEXT_BODY {
|
|
165
|
+
margin: 0;
|
|
166
|
+
padding: 0;
|
|
167
|
+
background: none;
|
|
168
|
+
color: inherit;
|
|
169
|
+
font-family: inherit;
|
|
170
|
+
font-size: inherit;
|
|
171
|
+
line-height: inherit;
|
|
172
|
+
/* `pre`, NOT `pre-wrap`: the indentation IS the structure here, and
|
|
173
|
+
* a wrapped continuation line restarts at column 0 and lies about
|
|
174
|
+
* the depth of everything under it — on a phone that is most of the
|
|
175
|
+
* document. Long lines scroll sideways inside .JSON_TEXT (which
|
|
176
|
+
* owns the overflow), never on the page body. */
|
|
177
|
+
white-space: pre;
|
|
178
|
+
/* And the <pre> must GROW to its longest line: as a plain block it
|
|
179
|
+
* takes the container's width, its text spills out of a box that
|
|
180
|
+
* reports no overflow, and .JSON_TEXT gets no scroll range to
|
|
181
|
+
* offer — the tail of every long line is simply unreachable.
|
|
182
|
+
* `min-width: 100%` keeps it filling the container when the
|
|
183
|
+
* document is narrower. */
|
|
184
|
+
width: max-content;
|
|
185
|
+
min-width: 100%;
|
|
186
|
+
/* The dump is there to be read AND taken: a plain <pre> in some
|
|
187
|
+
* host stylesheets is unselectable chrome. */
|
|
188
|
+
user-select: text;
|
|
189
|
+
}
|
|
190
|
+
|
|
154
191
|
/*
|
|
155
192
|
* Disable any transition a host stylesheet might inject.
|
|
156
193
|
*/
|