JSON viewer
A foldable tree drawn from a textarea that holds the JSON. Without the script the textarea is all there is.
A foldable tree of the JSON
<div class="json-viewer" id="jv-main">
<textarea class="input" readonly aria-label="Raw post params">{"transaction": {"amount": 12900, "currency_code": "USD", "email": "emma.wilson@example.com", "billing_address": {"name": "Emma Wilson", "address1": "48 Harbor Street", "address2": "", "city": "Portland", "state": "ME", "zip": "04101", "country": "US", "phone": null}, "retain_on_success": true, "gateway_specific_fields": {"shopper_reference": "CUS_100482", "splits": [{"type": "BalanceAccount", "amount": {"currency": "USD", "value": 12513}}, {"type": "Commission", "amount": {"currency": "USD", "value": 387}, "description": "Fixed Fee"}]}}}</textarea>
</div>
The markup is a textarea holding the JSON
The page writes the box and the textarea. The script adds the buttons and draws the tree.
<div class="json-viewer">
<textarea class="input" readonly>{"amount": 12900, "currency_code": "USD"}</textarea>
</div>
data-collapsed starts the tree folded to its top
level
<div class="json-viewer" id="jv-collapsed" data-collapsed>
<textarea class="input" readonly aria-label="Order">{"number": "110963", "status": "open", "total": "259.96", "lines": [{"sku": "LAMP-BLK", "quantity": 2}, {"sku": "SHEET-TWIN", "quantity": 1}], "shipping": {"method": "Standard", "tracking": null}}</textarea>
</div>
data-view="raw" starts on the textarea
<div class="json-viewer" id="jv-raw" data-view="raw">
<textarea class="input" readonly aria-label="Order">{"number": "110963", "status": "open", "total": "259.96", "lines": [{"sku": "LAMP-BLK", "quantity": 2}, {"sku": "SHEET-TWIN", "quantity": 1}], "shipping": {"method": "Standard", "tracking": null}}</textarea>
</div>
Without readonly the raw view can be edited, and text
that is not JSON is marked invalid
<div class="field">
<label for="jv-edit-input">Metadata</label>
<div class="json-viewer" id="jv-edit" data-view="raw">
<textarea class="input" id="jv-edit-input" name="metadata">{
"gift_wrap": true,
"note": "Leave at the side door",
"priority": 2
}</textarea>
</div>
<small>Show parsed draws the tree from what is typed. The form sends the textarea.</small>
</div>
The page folds the tree with collapse() and
expand(), and replaces the JSON through
value()
<div class="stack" data-gap="sm">
<div class="stack" data-direction="row" data-gap="sm">
<button type="button" class="btn" data-size="sm" onclick="tsunami.jsonViewer.collapse(document.getElementById('jv-script'))">collapse()</button>
<button type="button" class="btn" data-size="sm" onclick="tsunami.jsonViewer.expand(document.getElementById('jv-script'))">expand()</button>
<button type="button" class="btn" data-size="sm" onclick="tsunami.jsonViewer.value(document.getElementById('jv-script'), { refunded: true, amount: 4500, lines: ['LAMP-BLK'] })">Set value</button>
</div>
<div class="json-viewer" id="jv-script">
<textarea class="input" readonly aria-label="Order">{"number": "110963", "status": "open", "total": "259.96", "lines": [{"sku": "LAMP-BLK", "quantity": 2}, {"sku": "SHEET-TWIN", "quantity": 1}], "shipping": {"method": "Standard", "tracking": null}}</textarea>
</div>
</div>
API
The functions live on window.tsunami.jsonViewer and
take the .json-viewer element. Tsugi puts the same
members on the element itself; the second column maps them.
| Function | Tsugi member | Description |
|---|---|---|
tsunami.jsonViewer.expand(el) |
el.expand() |
Unfolds every object and list. |
tsunami.jsonViewer.collapse(el) |
el.collapse() |
Folds every object and list inside the outermost one, which stays open so its keys can be read. |
tsunami.jsonViewer.view(el, v?) |
el.view |
Returns "parsed" or "raw". With
v: "raw" shows the textarea,
anything else draws the tree.
|
tsunami.jsonViewer.value(el, v?) |
el.value |
Returns the textarea's text. With v: takes
JSON text, or an object or list, and draws it.
|
Keyboard
| Key | Description |
|---|---|
| Tab | Through the buttons, then through each object and list in the tree. |
| Enter or Space |
On an object or a list: folds or unfolds it. This is the
browser's own behaviour for details.
|
The JSON viewer sends no events of its own. The textarea sends its
own input and change events when it is
edited.
Show raw indents the JSON by two spaces. Text that is not JSON is left as typed.
Keys use the text colour in semibold and strings the ok colour.
Numbers and booleans use the info colour. null uses
the danger colour.
Attributes
| Attribute / element | Values | Description |
|---|---|---|
.json-viewer |
The box around the textarea. The script adds the toolbar before it and the tree after it. | |
data-view |
parsed (default), raw |
On .json-viewer. raw starts on
the textarea. The script keeps it up to date as the view
changes.
|
data-collapsed |
present |
On .json-viewer. The tree starts folded to
its top level; the outermost object or list is open.
|
> textarea.input |
Holds the JSON and gives it the input look, so it reads as a field before the script runs. | |
> textarea[readonly] |
present | The JSON cannot be edited in the raw view. Without it the textarea is an ordinary field. |
> textarea[name] |
text | Sends the JSON with the form. |
aria-invalid |
true |
On the textarea, set by the script when Show parsed finds text that is not JSON; the viewer stays on the textarea. Removed on the next keystroke. |
.json-viewer-toolbar |
Added by the script: Show raw / Show parsed, Collapse all and Expand all. The fold buttons are hidden in the raw view. | |
data-json-viewer |
toggle, collapse,
expand
|
On each toolbar button; the click handler reads it. |
.json-viewer-tree |
Added by the script: a ul with one
li per value. Objects and lists are a
details whose summary is
key: {, followed by the closing bracket.
|
|
details[open] |
present |
Set by the script while that object or list is unfolded.
Folded, it reads key: {…} on one line.
|
data-kind |
object, array |
On each details in the tree. |
.json-viewer-key, -string,
-number, -boolean,
-null, -close
|
The spans that colour each part of a line. |