first commit
This commit is contained in:
File diff suppressed because one or more lines are too long
@@ -0,0 +1,25 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>JSON VIEW</title>
|
||||
<link href="https://fonts.googleapis.com/css?family=Open+Sans" rel="stylesheet">
|
||||
<link rel="stylesheet" type="text/css" href="jsonview.css">
|
||||
<script type="text/javascript" src="jsonview.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div class="root"></div>
|
||||
|
||||
<script type="text/javascript">
|
||||
fetch('example.json')
|
||||
.then((res)=> {
|
||||
return res.text();
|
||||
})
|
||||
.then((data) => {
|
||||
jsonView.format(data, '.root');
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
})
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,85 @@
|
||||
body {
|
||||
font-family: 'Open Sans';
|
||||
font-size: 16px;
|
||||
background-color: #fff;
|
||||
color: #808080;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.line {
|
||||
margin: 4px 0;
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
.caret-icon {
|
||||
width: 18px;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.empty-icon {
|
||||
width: 18px;
|
||||
}
|
||||
|
||||
.json-type {
|
||||
margin-right: 4px;
|
||||
margin-left: 4px;
|
||||
}
|
||||
|
||||
.json-key {
|
||||
color: #444;
|
||||
margin-right: 4px;
|
||||
margin-left: 4px;
|
||||
}
|
||||
|
||||
.json-index {
|
||||
margin-right: 4px;
|
||||
margin-left: 4px;
|
||||
}
|
||||
|
||||
.json-separator {
|
||||
|
||||
}
|
||||
|
||||
.json-value {
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
.json-number {
|
||||
color: #f9ae58;
|
||||
}
|
||||
|
||||
.json-boolean {
|
||||
color: #ec5f66;
|
||||
}
|
||||
|
||||
.json-string {
|
||||
color: #3333cc;
|
||||
}
|
||||
|
||||
.json-size {
|
||||
margin-right: 4px;
|
||||
margin-left: 4px;
|
||||
}
|
||||
|
||||
.hide {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.fas {
|
||||
display: inline-block;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-style: solid;
|
||||
}
|
||||
|
||||
.fa-caret-down {
|
||||
border-width: 6px 5px 0 5px;
|
||||
border-color: #808080 transparent
|
||||
}
|
||||
|
||||
.fa-caret-right {
|
||||
border-width: 5px 0 5px 6px;
|
||||
border-color: transparent transparent transparent #808080;
|
||||
}
|
||||
@@ -0,0 +1,331 @@
|
||||
(function() {
|
||||
'use strict';
|
||||
/**
|
||||
* Create html element
|
||||
* @param {String} type html element
|
||||
* @param {Object} config
|
||||
*/
|
||||
function createElement(type, config) {
|
||||
const htmlElement = document.createElement(type);
|
||||
|
||||
if (config === undefined) {
|
||||
return htmlElement;
|
||||
}
|
||||
|
||||
if (config.className) {
|
||||
htmlElement.className = config.className;
|
||||
}
|
||||
|
||||
if (config.content) {
|
||||
htmlElement.textContent = config.content;
|
||||
}
|
||||
|
||||
if (config.children) {
|
||||
config.children.forEach((el) => {
|
||||
if (el !== null) {
|
||||
htmlElement.appendChild(el);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return htmlElement;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param {Object} node
|
||||
* @return {HTMLElement}
|
||||
*/
|
||||
function createExpandedElement(node) {
|
||||
const iElem = createElement('i');
|
||||
|
||||
if (node.expanded) {
|
||||
iElem.className = 'fas fa-caret-down';
|
||||
} else {
|
||||
iElem.className = 'fas fa-caret-right';
|
||||
}
|
||||
|
||||
const caretElem = createElement('div', {
|
||||
className: 'caret-icon',
|
||||
children: [iElem],
|
||||
});
|
||||
|
||||
const handleClick = node.toggle.bind(node);
|
||||
caretElem.addEventListener('click', handleClick);
|
||||
|
||||
const indexElem = createElement('div', {
|
||||
className: 'json-index',
|
||||
content: node.key,
|
||||
});
|
||||
|
||||
const typeElem = createElement('div', {
|
||||
className: 'json-type',
|
||||
content: node.type,
|
||||
});
|
||||
|
||||
const keyElem = createElement('div', {
|
||||
className: 'json-key',
|
||||
content: node.key,
|
||||
});
|
||||
|
||||
const sizeElem = createElement('div', {
|
||||
className: 'json-size'
|
||||
});
|
||||
|
||||
if (node.type === 'array') {
|
||||
sizeElem.innerText = '[' + node.children.length + ']';
|
||||
} else if (node.type === 'object') {
|
||||
sizeElem.innerText = '{' + node.children.length + '}';
|
||||
}
|
||||
|
||||
let lineChildren;
|
||||
if (node.key === null) {
|
||||
lineChildren = [caretElem, typeElem, sizeElem]
|
||||
} else if (node.parent.type === 'array') {
|
||||
lineChildren = [caretElem, indexElem, sizeElem]
|
||||
} else {
|
||||
lineChildren = [caretElem, keyElem, sizeElem]
|
||||
}
|
||||
|
||||
const lineElem = createElement('div', {
|
||||
className: 'line',
|
||||
children: lineChildren
|
||||
});
|
||||
|
||||
if (node.depth > 0) {
|
||||
lineElem.style = 'margin-left: ' + node.depth * 24 + 'px;';
|
||||
}
|
||||
|
||||
return lineElem;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param {Object} node
|
||||
* @return {HTMLElement}
|
||||
*/
|
||||
function createNotExpandedElement(node) {
|
||||
const caretElem = createElement('div', {
|
||||
className: 'empty-icon',
|
||||
});
|
||||
|
||||
const keyElem = createElement('div', {
|
||||
className: 'json-key',
|
||||
content: node.key
|
||||
});
|
||||
|
||||
const separatorElement = createElement('div', {
|
||||
className: 'json-separator',
|
||||
content: ':'
|
||||
});
|
||||
|
||||
const valueType = ' json-' + typeof node.value;
|
||||
const valueContent = String(node.value);
|
||||
const valueElement = createElement('div', {
|
||||
className: 'json-value' + valueType,
|
||||
content: valueContent
|
||||
});
|
||||
|
||||
const lineElem = createElement('div', {
|
||||
className: 'line',
|
||||
children: [caretElem, keyElem, separatorElement, valueElement]
|
||||
});
|
||||
|
||||
if (node.depth > 0) {
|
||||
lineElem.style = 'margin-left: ' + node.depth * 24 + 'px;';
|
||||
}
|
||||
|
||||
return lineElem;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* create tree node
|
||||
* @return {Object}
|
||||
*/
|
||||
function createNode() {
|
||||
return {
|
||||
key: null,
|
||||
parent: null,
|
||||
value: null,
|
||||
expanded: false,
|
||||
type: null,
|
||||
children: null,
|
||||
elem: null,
|
||||
depth: 0,
|
||||
|
||||
setCaretIconRight() {
|
||||
const icon = this.elem.querySelector('.fas');
|
||||
icon.classList.replace('fa-caret-down', 'fa-caret-right');
|
||||
},
|
||||
|
||||
setCaretIconDown() {
|
||||
const icon = this.elem.querySelector('.fas');
|
||||
icon.classList.replace('fa-caret-right', 'fa-caret-down');
|
||||
},
|
||||
|
||||
hideChildren() {
|
||||
if (this.children !== null) {
|
||||
this.children.forEach((item) => {
|
||||
item.elem.classList.add('hide');
|
||||
if (item.expanded) {
|
||||
item.hideChildren();
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
showChildren() {
|
||||
if (this.children !== null) {
|
||||
this.children.forEach((item) => {
|
||||
item.elem.classList.remove('hide');
|
||||
if (item.expanded) {
|
||||
item.showChildren();
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
toggle: function() {
|
||||
if (this.expanded) {
|
||||
this.expanded = false;
|
||||
this.hideChildren();
|
||||
this.setCaretIconRight();
|
||||
} else {
|
||||
this.expanded = true;
|
||||
this.showChildren();
|
||||
this.setCaretIconDown();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return object length
|
||||
* @param {Object} obj
|
||||
* @return {number}
|
||||
*/
|
||||
function getLength(obj) {
|
||||
let length = 0;
|
||||
for (let key in obj) {
|
||||
length += 1;
|
||||
};
|
||||
return length;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return variable type
|
||||
* @param {*} val
|
||||
*/
|
||||
function getType(val) {
|
||||
let type = typeof val;
|
||||
if (Array.isArray(val)) {
|
||||
type = 'array';
|
||||
} else if (val === null) {
|
||||
type = 'null';
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Recursively traverse json object
|
||||
* @param {Object} obj parsed json object
|
||||
* @param {Object} parent of object tree
|
||||
*/
|
||||
function traverseObject(obj, parent) {
|
||||
for (let key in obj) {
|
||||
const child = createNode();
|
||||
child.parent = parent;
|
||||
child.key = key;
|
||||
child.type = getType(obj[key]);
|
||||
child.depth = parent.depth + 1;
|
||||
child.expanded = false;
|
||||
|
||||
if (typeof obj[key] === 'object') {
|
||||
child.children = [];
|
||||
parent.children.push(child);
|
||||
traverseObject(obj[key], child);
|
||||
child.elem = createExpandedElement(child);
|
||||
} else {
|
||||
child.value = obj[key];
|
||||
child.elem = createNotExpandedElement(child);
|
||||
parent.children.push(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create root of a tree
|
||||
* @param {Object} obj Json object
|
||||
* @return {Object}
|
||||
*/
|
||||
function createTree(obj) {
|
||||
const tree = createNode();
|
||||
tree.type = getType(obj);
|
||||
tree.children = [];
|
||||
tree.expanded = true;
|
||||
|
||||
traverseObject(obj, tree);
|
||||
tree.elem = createExpandedElement(tree);
|
||||
|
||||
return tree;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Recursively traverse Tree object
|
||||
* @param {Object} node
|
||||
* @param {Callback} callback
|
||||
*/
|
||||
function traverseTree(node, callback) {
|
||||
callback(node);
|
||||
if (node.children !== null) {
|
||||
node.children.forEach((item) => {
|
||||
traverseTree(item, callback);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Render Tree object
|
||||
* @param {Object} tree
|
||||
* @param {String} targetElem
|
||||
*/
|
||||
function render(tree, targetElem) {
|
||||
let rootElem;
|
||||
if (targetElem) {
|
||||
rootElem = document.querySelector(targetElem);
|
||||
} else {
|
||||
rootElem = document.body;
|
||||
}
|
||||
|
||||
traverseTree(tree, (node) => {
|
||||
if (!node.expanded) {
|
||||
node.hideChildren();
|
||||
}
|
||||
rootElem.appendChild(node.elem);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/* Export jsonView object */
|
||||
window.jsonView = {
|
||||
/**
|
||||
* Render JSON into DOM container
|
||||
* @param {String} jsonData
|
||||
* @param {String} targetElem
|
||||
*/
|
||||
format: function(jsonData, targetElem) {
|
||||
let parsedData = jsonData;
|
||||
if (typeof jsonData === 'string' || jsonData instanceof String) parsedData = JSON.parse(jsonData);
|
||||
const tree = createTree(parsedData);
|
||||
render(tree, targetElem);
|
||||
}
|
||||
}
|
||||
|
||||
})();
|
||||
Reference in New Issue
Block a user