jclyo1's picture
updates
18d463f
raw history blame
No virus
7.61 kB
/**
* JSONViewer - by Roman Makudera 2016 (c) MIT licence.
*/
var JSONViewer = (function(document) {
var Object_prototype_toString = ({}).toString;
var DatePrototypeAsString = Object_prototype_toString.call(new Date);
/** @constructor */
function JSONViewer() {
this._dom_container = document.createElement("pre");
this._dom_container.classList.add("json-viewer");
};
/**
* Visualise JSON object.
*
* @param {Object|Array} json Input value
* @param {Number} [inputMaxLvl] Process only to max level, where 0..n, -1 unlimited
* @param {Number} [inputColAt] Collapse at level, where 0..n, -1 unlimited
*/
JSONViewer.prototype.showJSON = function(jsonValue, inputMaxLvl, inputColAt) {
// Process only to maxLvl, where 0..n, -1 unlimited
var maxLvl = typeof inputMaxLvl === "number" ? inputMaxLvl : -1; // max level
// Collapse at level colAt, where 0..n, -1 unlimited
var colAt = typeof inputColAt === "number" ? inputColAt : -1; // collapse at
this._dom_container.innerHTML = "";
walkJSONTree(this._dom_container, jsonValue, maxLvl, colAt, 0);
};
/**
* Get container with pre object - this container is used for visualise JSON data.
*
* @return {Element}
*/
JSONViewer.prototype.getContainer = function() {
return this._dom_container;
};
/**
* Recursive walk for input value.
*
* @param {Element} outputParent is the Element that will contain the new DOM
* @param {Object|Array} value Input value
* @param {Number} maxLvl Process only to max level, where 0..n, -1 unlimited
* @param {Number} colAt Collapse at level, where 0..n, -1 unlimited
* @param {Number} lvl Current level
*/
function walkJSONTree(outputParent, value, maxLvl, colAt, lvl) {
var isDate = Object_prototype_toString.call(value) === DatePrototypeAsString;
var realValue = !isDate && typeof value === "object" && value !== null && "toJSON" in value ? value.toJSON() : value;
if (typeof realValue === "object" && realValue !== null && !isDate) {
var isMaxLvl = maxLvl >= 0 && lvl >= maxLvl;
var isCollapse = colAt >= 0 && lvl >= colAt;
var isArray = Array.isArray(realValue);
var items = isArray ? realValue : Object.keys(realValue);
if (lvl === 0) {
// root level
var rootCount = _createItemsCount(items.length);
// hide/show
var rootLink = _createLink(isArray ? "[" : "{");
if (items.length) {
rootLink.addEventListener("click", function() {
if (isMaxLvl) return;
rootLink.classList.toggle("collapsed");
rootCount.classList.toggle("hide");
// main list
outputParent.querySelector("ul").classList.toggle("hide");
});
if (isCollapse) {
rootLink.classList.add("collapsed");
rootCount.classList.remove("hide");
}
}
else {
rootLink.classList.add("empty");
}
rootLink.appendChild(rootCount);
outputParent.appendChild(rootLink); // output the rootLink
}
if (items.length && !isMaxLvl) {
var len = items.length - 1;
var ulList = document.createElement("ul");
ulList.setAttribute("data-level", lvl);
ulList.classList.add("type-" + (isArray ? "array" : "object"));
items.forEach(function(key, ind) {
var item = isArray ? key : value[key];
var li = document.createElement("li");
if (typeof item === "object") {
// null && date
if (!item || item instanceof Date) {
li.appendChild(document.createTextNode(isArray ? "" : key + ": "));
li.appendChild(createSimpleViewOf(item ? item : null, true));
}
// array & object
else {
var itemIsArray = Array.isArray(item);
var itemLen = itemIsArray ? item.length : Object.keys(item).length;
// empty
if (!itemLen) {
li.appendChild(document.createTextNode(key + ": " + (itemIsArray ? "[]" : "{}")));
}
else {
// 1+ items
var itemTitle = (typeof key === "string" ? key + ": " : "") + (itemIsArray ? "[" : "{");
var itemLink = _createLink(itemTitle);
var itemsCount = _createItemsCount(itemLen);
// maxLvl - only text, no link
if (maxLvl >= 0 && lvl + 1 >= maxLvl) {
li.appendChild(document.createTextNode(itemTitle));
}
else {
itemLink.appendChild(itemsCount);
li.appendChild(itemLink);
}
walkJSONTree(li, item, maxLvl, colAt, lvl + 1);
li.appendChild(document.createTextNode(itemIsArray ? "]" : "}"));
var list = li.querySelector("ul");
var itemLinkCb = function() {
itemLink.classList.toggle("collapsed");
itemsCount.classList.toggle("hide");
list.classList.toggle("hide");
};
// hide/show
itemLink.addEventListener("click", itemLinkCb);
// collapse lower level
if (colAt >= 0 && lvl + 1 >= colAt) {
itemLinkCb();
}
}
}
}
// simple values
else {
// object keys with key:
if (!isArray) {
li.appendChild(document.createTextNode(key + ": "));
}
// recursive
walkJSONTree(li, item, maxLvl, colAt, lvl + 1);
}
// add comma to the end
if (ind < len) {
li.appendChild(document.createTextNode(","));
}
ulList.appendChild(li);
}, this);
outputParent.appendChild(ulList); // output ulList
}
else if (items.length && isMaxLvl) {
var itemsCount = _createItemsCount(items.length);
itemsCount.classList.remove("hide");
outputParent.appendChild(itemsCount); // output itemsCount
}
if (lvl === 0) {
// empty root
if (!items.length) {
var itemsCount = _createItemsCount(0);
itemsCount.classList.remove("hide");
outputParent.appendChild(itemsCount); // output itemsCount
}
// root cover
outputParent.appendChild(document.createTextNode(isArray ? "]" : "}"));
// collapse
if (isCollapse) {
outputParent.querySelector("ul").classList.add("hide");
}
}
} else {
// simple values
outputParent.appendChild( createSimpleViewOf(value, isDate) );
}
};
/**
* Create simple value (no object|array).
*
* @param {Number|String|null|undefined|Date} value Input value
* @return {Element}
*/
function createSimpleViewOf(value, isDate) {
var spanEl = document.createElement("span");
var type = typeof value;
var asText = "" + value;
if (type === "string") {
asText = '"' + value + '"';
} else if (value === null) {
type = "null";
//asText = "null";
} else if (isDate) {
type = "date";
asText = value.toLocaleString();
}
spanEl.className = "type-" + type;
spanEl.textContent = asText;
return spanEl;
};
/**
* Create items count element.
*
* @param {Number} count Items count
* @return {Element}
*/
function _createItemsCount(count) {
var itemsCount = document.createElement("span");
itemsCount.className = "items-ph hide";
itemsCount.innerHTML = _getItemsTitle(count);
return itemsCount;
};
/**
* Create clickable link.
*
* @param {String} title Link title
* @return {Element}
*/
function _createLink(title) {
var linkEl = document.createElement("a");
linkEl.classList.add("list-link");
linkEl.href = "javascript:void(0)";
linkEl.innerHTML = title || "";
return linkEl;
};
/**
* Get correct item|s title for count.
*
* @param {Number} count Items count
* @return {String}
*/
function _getItemsTitle(count) {
var itemsTxt = count > 1 || count === 0 ? "items" : "item";
return (count + " " + itemsTxt);
};
return JSONViewer;
})(document);