Skip to content

Commit deb9928

Browse files
committed
Add getState() function and state parameter to loadJSON(), allowing collapse state to be maintained while (re)loading JSON.
1 parent f274087 commit deb9928

File tree

2 files changed

+44
-11
lines changed

2 files changed

+44
-11
lines changed

src/json-viewer.js

Lines changed: 34 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,16 @@ var JSONViewer = (function(document) {
1717
* @param {Object|Array} json Input value
1818
* @param {Number} [inputMaxLvl] Process only to max level, where 0..n, -1 unlimited
1919
* @param {Number} [inputColAt] Collapse at level, where 0..n, -1 unlimited
20+
* @param {Object} [inputState] Expand or collapse according to given state.
2021
*/
21-
JSONViewer.prototype.showJSON = function(jsonValue, inputMaxLvl, inputColAt) {
22+
JSONViewer.prototype.showJSON = function(jsonValue, inputMaxLvl, inputColAt, inputState) {
2223
// Process only to maxLvl, where 0..n, -1 unlimited
2324
var maxLvl = typeof inputMaxLvl === "number" ? inputMaxLvl : -1; // max level
2425
// Collapse at level colAt, where 0..n, -1 unlimited
2526
var colAt = typeof inputColAt === "number" ? inputColAt : -1; // collapse at
2627

2728
this._dom_container.innerHTML = "";
28-
walkJSONTree(this._dom_container, jsonValue, maxLvl, colAt, 0);
29+
walkJSONTree(this._dom_container, jsonValue, maxLvl, colAt, 0, 'root', inputState);
2930
};
3031

3132
/**
@@ -37,6 +38,18 @@ var JSONViewer = (function(document) {
3738
return this._dom_container;
3839
};
3940

41+
/**
42+
* Get current expand/collapse state - this can be passed to showJSON to set initial state.
43+
* For each key, true == expanded and false == collapsed. For missing keys, colAt will apply.
44+
*/
45+
JSONViewer.prototype.getState = function() {
46+
var state = {};
47+
this._dom_container.querySelectorAll('a').forEach(function(a) {
48+
state[a.getAttribute('data-key')] = !a.classList.contains('collapsed')
49+
})
50+
return state;
51+
};
52+
4053
/**
4154
* Recursive walk for input value.
4255
*
@@ -46,12 +59,15 @@ var JSONViewer = (function(document) {
4659
* @param {Number} colAt Collapse at level, where 0..n, -1 unlimited
4760
* @param {Number} lvl Current level
4861
*/
49-
function walkJSONTree(outputParent, value, maxLvl, colAt, lvl) {
62+
function walkJSONTree(outputParent, value, maxLvl, colAt, lvl, path, state) {
5063
var isDate = Object_prototype_toString.call(value) === DatePrototypeAsString;
5164
var realValue = !isDate && typeof value === "object" && value !== null && "toJSON" in value ? value.toJSON() : value;
5265
if (typeof realValue === "object" && realValue !== null && !isDate) {
5366
var isMaxLvl = maxLvl >= 0 && lvl >= maxLvl;
5467
var isCollapse = colAt >= 0 && lvl >= colAt;
68+
if (state && state.hasOwnProperty(path)) {
69+
isCollapse = !state[path];
70+
}
5571

5672
var isArray = Array.isArray(realValue);
5773
var items = isArray ? realValue : Object.keys(realValue);
@@ -60,7 +76,7 @@ var JSONViewer = (function(document) {
6076
// root level
6177
var rootCount = _createItemsCount(items.length);
6278
// hide/show
63-
var rootLink = _createLink(isArray ? "[" : "{");
79+
var rootLink = _createLink(isArray ? "[" : "{", path);
6480

6581
if (items.length) {
6682
rootLink.addEventListener("click", function() {
@@ -94,6 +110,7 @@ var JSONViewer = (function(document) {
94110

95111
items.forEach(function(key, ind) {
96112
var item = isArray ? key : value[key];
113+
var itemPath = path + "." + (isArray ? ind : key);
97114
var li = document.createElement("li");
98115

99116
if (typeof item === "object") {
@@ -114,7 +131,7 @@ var JSONViewer = (function(document) {
114131
else {
115132
// 1+ items
116133
var itemTitle = (typeof key === "string" ? key + ": " : "") + (itemIsArray ? "[" : "{");
117-
var itemLink = _createLink(itemTitle);
134+
var itemLink = _createLink(itemTitle, itemPath);
118135
var itemsCount = _createItemsCount(itemLen);
119136

120137
// maxLvl - only text, no link
@@ -126,7 +143,7 @@ var JSONViewer = (function(document) {
126143
li.appendChild(itemLink);
127144
}
128145

129-
walkJSONTree(li, item, maxLvl, colAt, lvl + 1);
146+
walkJSONTree(li, item, maxLvl, colAt, lvl + 1, itemPath, state);
130147
li.appendChild(document.createTextNode(itemIsArray ? "]" : "}"));
131148

132149
var list = li.querySelector("ul");
@@ -140,8 +157,14 @@ var JSONViewer = (function(document) {
140157
itemLink.addEventListener("click", itemLinkCb);
141158

142159
// collapse lower level
143-
if (colAt >= 0 && lvl + 1 >= colAt) {
144-
itemLinkCb();
160+
if (state && state.hasOwnProperty(itemPath)) {
161+
if (!state[itemPath]) {
162+
itemLinkCb();
163+
}
164+
} else {
165+
if (colAt >= 0 && lvl + 1 >= colAt) {
166+
itemLinkCb();
167+
}
145168
}
146169
}
147170
}
@@ -154,7 +177,7 @@ var JSONViewer = (function(document) {
154177
}
155178

156179
// recursive
157-
walkJSONTree(li, item, maxLvl, colAt, lvl + 1);
180+
walkJSONTree(li, item, maxLvl, colAt, lvl + 1, itemPath, state);
158181
}
159182

160183
// add comma to the end
@@ -244,11 +267,12 @@ var JSONViewer = (function(document) {
244267
* @param {String} title Link title
245268
* @return {Element}
246269
*/
247-
function _createLink(title) {
270+
function _createLink(title, path) {
248271
var linkEl = document.createElement("a");
249272
linkEl.classList.add("list-link");
250273
linkEl.href = "javascript:void(0)";
251274
linkEl.innerHTML = title || "";
275+
linkEl.setAttribute("data-key", path);
252276

253277
return linkEl;
254278
};

test/index.html

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ <h2>JSON stringified value:</h2>
1616
<button type="button" class="load-json">Load JSON</button>
1717
<button type="button" class="collapse">Collapse to level 1</button>
1818
<button type="button" class="maxlvl">Show JSON to level 1</button>
19+
<input id="remember" type="checkbox"></input>
20+
<label for="remember">Remember expand/collapse state when loading</label>
1921
</div>
2022
<h2>Output:</h2>
2123
<div id="json"></div>
@@ -66,10 +68,17 @@ <h2>Output:</h2>
6668
var loadJsonBtn = document.querySelector("button.load-json");
6769
var collapseBtn = document.querySelector("button.collapse");
6870
var maxlvlBtn = document.querySelector("button.maxlvl");
71+
var rememberCb = document.querySelector("input#remember");
72+
73+
var maybeOldState = function() {
74+
if (rememberCb.checked) {
75+
return jsonViewer.getState();
76+
}
77+
}
6978

7079
loadJsonBtn.addEventListener("click", function() {
7180
setJSON();
72-
jsonViewer.showJSON(jsonObj);
81+
jsonViewer.showJSON(jsonObj, null, null, maybeOldState());
7382
});
7483

7584
collapseBtn.addEventListener("click", function() {

0 commit comments

Comments
 (0)