├── .gitignore
├── LICENSE
├── README.md
├── demo
├── example2.json
└── index.html
├── dist
└── jsonview.js
├── package.json
├── src
├── .babelrc
├── json-view.js
├── jsonview.scss
└── utils
│ ├── dom.js
│ ├── getDataType.js
│ └── traverseObject.js
└── webpack.config.js
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | package-lock.json
3 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 Pavel Grabovets
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # json-view
2 | This is a javascript library for displaying json data into a DOM. [link to demo](http://pgrabovets.github.io/json-view/)
3 |
4 | ### Installation
5 | ```javascript
6 | npm install '@pgrabovets/json-view';
7 | ```
8 |
9 | ### How to use
10 | include jsonview.js from dist directory in your html page
11 | ```html
12 |
13 | ```
14 | or you can use import
15 | ```javascript
16 | import jsonview from '@pgrabovets/json-view';
17 | ```
18 |
19 | get json data and render tree into DOM
20 | ```javascript
21 | // get json data
22 | const data = '{"name": "json-view","version": "1.0.0"}';
23 |
24 | // create json tree object
25 | const tree = jsonview.create(data);
26 |
27 | // render tree into dom element
28 | jsonview.render(tree, document.querySelector('.tree'));
29 |
30 | // you can render json data without creating tree
31 | const tree = jsonview.renderJSON(data, document.querySelector('.tree'));
32 | ```
33 |
34 | control methods
35 | ```javascript
36 | // expand tree
37 | jsonview.expand(tree);
38 |
39 | // collapse tree
40 | jsonview.collapse(tree);
41 |
42 | // traverse tree object
43 | jsonview.traverse(tree, function(node) {
44 | console.log(node);
45 | });
46 |
47 | // function toggles between show or hide
48 | jsonview.toggleNode(tree);
49 |
50 | // destroy and unmount json tree from the dom
51 | jsonview.destroy(tree);
52 | ```
53 |
54 | ### Example1
55 | ```html
56 |
57 |
58 |
59 | JSON VIEW
60 |
61 |
62 |
63 |
64 |
65 |
79 |
80 |
81 |
82 | ```
83 |
84 | ### Example2
85 | ```javascript
86 | import jsonview from '@pgrabovets/json-view';
87 |
88 | fetch('example2.json')
89 | .then((res)=> {
90 | return res.text();
91 | })
92 | .then((data) => {
93 | const tree = jsonview.create(data);
94 | jsonview.render(tree, document.querySelector('.root'));
95 | jsonview.expand(tree);
96 | })
97 | .catch((err) => {
98 | console.log(err);
99 | })
100 | ```
101 |
102 | ### For development install dependencies and run scripts
103 | ```
104 | $ npm install
105 |
106 | $ npm run serve
107 | $ npm run build
108 |
109 | open http://localhost:3000/
110 | ```
111 |
--------------------------------------------------------------------------------
/demo/example2.json:
--------------------------------------------------------------------------------
1 | {
2 | "givenName": "Vas",
3 | "surName": "Sudanagunta",
4 | "children": [
5 | {
6 | "givenName": "Natalia",
7 | "age": 5
8 | },
9 | {
10 | "givenName": "Aida",
11 | "age": 17
12 | }
13 | ],
14 | "address": {
15 | "state": "NY",
16 | "city": "Brooklyn",
17 | "street": "718 Marcus Garvey Ave"
18 | },
19 | "emptyObject": {},
20 | "prop-with-null": null,
21 | "prop-empty-string": ""
22 | }
23 |
--------------------------------------------------------------------------------
/demo/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | jsonview demo
5 |
6 |
7 |
8 |
9 |
10 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/dist/jsonview.js:
--------------------------------------------------------------------------------
1 | !function(e,n){"object"==typeof exports&&"object"==typeof module?module.exports=n():"function"==typeof define&&define.amd?define([],n):"object"==typeof exports?exports.jsonview=n():e.jsonview=n()}(self,(()=>(()=>{"use strict";var e={767:(e,n,t)=>{t.d(n,{Z:()=>s});var r=t(81),o=t.n(r),i=t(645),a=t.n(i)()(o());a.push([e.id,'.json-container{font-family:"Open Sans";font-size:16px;background-color:#fff;color:gray;box-sizing:border-box}.json-container .line{margin:4px 0;display:flex;justify-content:flex-start}.json-container .caret-icon{width:18px;text-align:center;cursor:pointer}.json-container .empty-icon{width:18px}.json-container .json-type{margin-right:4px;margin-left:4px}.json-container .json-key{color:#444;margin-right:4px;margin-left:4px}.json-container .json-index{margin-right:4px;margin-left:4px}.json-container .json-value{margin-left:8px}.json-container .json-number{color:#f9ae58}.json-container .json-boolean{color:#ec5f66}.json-container .json-string{color:#86b25c}.json-container .json-size{margin-right:4px;margin-left:4px}.json-container .hidden{display:none}.json-container .fas{display:inline-block;border-style:solid;width:0;height:0}.json-container .fa-caret-down{border-width:6px 5px 0 5px;border-color:gray rgba(0,0,0,0)}.json-container .fa-caret-right{border-width:5px 0 5px 6px;border-color:rgba(0,0,0,0) rgba(0,0,0,0) rgba(0,0,0,0) gray}',""]);const s=a},645:e=>{e.exports=function(e){var n=[];return n.toString=function(){return this.map((function(n){var t="",r=void 0!==n[5];return n[4]&&(t+="@supports (".concat(n[4],") {")),n[2]&&(t+="@media ".concat(n[2]," {")),r&&(t+="@layer".concat(n[5].length>0?" ".concat(n[5]):""," {")),t+=e(n),r&&(t+="}"),n[2]&&(t+="}"),n[4]&&(t+="}"),t})).join("")},n.i=function(e,t,r,o,i){"string"==typeof e&&(e=[[null,e,void 0]]);var a={};if(r)for(var s=0;s0?" ".concat(d[5]):""," {").concat(d[1],"}")),d[5]=i),t&&(d[2]?(d[1]="@media ".concat(d[2]," {").concat(d[1],"}"),d[2]=t):d[2]=t),o&&(d[4]?(d[1]="@supports (".concat(d[4],") {").concat(d[1],"}"),d[4]=o):d[4]="".concat(o)),n.push(d))}},n}},81:e=>{e.exports=function(e){return e[1]}},379:e=>{var n=[];function t(e){for(var t=-1,r=0;r{var n={};e.exports=function(e,t){var r=function(e){if(void 0===n[e]){var t=document.querySelector(e);if(window.HTMLIFrameElement&&t instanceof window.HTMLIFrameElement)try{t=t.contentDocument.head}catch(e){t=null}n[e]=t}return n[e]}(e);if(!r)throw new Error("Couldn't find a style target. This probably means that the value for the 'insert' parameter is invalid.");r.appendChild(t)}},216:e=>{e.exports=function(e){var n=document.createElement("style");return e.setAttributes(n,e.attributes),e.insert(n,e.options),n}},565:(e,n,t)=>{e.exports=function(e){var n=t.nc;n&&e.setAttribute("nonce",n)}},795:e=>{e.exports=function(e){if("undefined"==typeof document)return{update:function(){},remove:function(){}};var n=e.insertStyleElement(e);return{update:function(t){!function(e,n,t){var r="";t.supports&&(r+="@supports (".concat(t.supports,") {")),t.media&&(r+="@media ".concat(t.media," {"));var o=void 0!==t.layer;o&&(r+="@layer".concat(t.layer.length>0?" ".concat(t.layer):""," {")),r+=t.css,o&&(r+="}"),t.media&&(r+="}"),t.supports&&(r+="}");var i=t.sourceMap;i&&"undefined"!=typeof btoa&&(r+="\n/*# sourceMappingURL=data:application/json;base64,".concat(btoa(unescape(encodeURIComponent(JSON.stringify(i))))," */")),n.styleTagTransform(r,e,n.options)}(n,e,t)},remove:function(){!function(e){if(null===e.parentNode)return!1;e.parentNode.removeChild(e)}(n)}}}},589:e=>{e.exports=function(e,n){if(n.styleSheet)n.styleSheet.cssText=e;else{for(;n.firstChild;)n.removeChild(n.firstChild);n.appendChild(document.createTextNode(e))}}}},n={};function t(r){var o=n[r];if(void 0!==o)return o.exports;var i=n[r]={id:r,exports:{}};return e[r](i,i.exports,t),i.exports}t.n=e=>{var n=e&&e.__esModule?()=>e.default:()=>e;return t.d(n,{a:n}),n},t.d=(e,n)=>{for(var r in n)t.o(n,r)&&!t.o(e,r)&&Object.defineProperty(e,r,{enumerable:!0,get:n[r]})},t.o=(e,n)=>Object.prototype.hasOwnProperty.call(e,n),t.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},t.nc=void 0;var r={};return(()=>{t.r(r),t.d(r,{collapse:()=>A,create:()=>S,default:()=>H,destroy:()=>L,expand:()=>D,render:()=>w,renderJSON:()=>k,toggleNode:()=>N,traverse:()=>C});var e=t(379),n=t.n(e),o=t(795),i=t.n(o),a=t(569),s=t.n(a),c=t(565),l=t.n(c),d=t(216),u=t.n(d),p=t(589),f=t.n(p),v=t(767),y={};function h(e){return Array.isArray(e)?"array":null===e?"null":typeof e}function m(e){return document.createElement(e)}y.styleTagTransform=f(),y.setAttributes=l(),y.insert=s().bind(null,"head"),y.domAPI=i(),y.insertStyleElement=u(),n()(v.Z,y),v.Z&&v.Z.locals&&v.Z.locals;const g={HIDDEN:"hidden",CARET_ICON:"caret-icon",CARET_RIGHT:"fa-caret-right",CARET_DOWN:"fa-caret-down",ICON:"fas"};function x(e){e.children.forEach((e=>{e.el.classList.add(g.HIDDEN),e.isExpanded&&x(e)}))}function j(e){e.children.forEach((e=>{e.el.classList.remove(g.HIDDEN),e.isExpanded&&j(e)}))}function b(e){if(e.children.length>0){const n=e.el.querySelector("."+g.ICON);n&&n.classList.replace(g.CARET_RIGHT,g.CARET_DOWN)}}function E(e){if(e.children.length>0){const n=e.el.querySelector("."+g.ICON);n&&n.classList.replace(g.CARET_DOWN,g.CARET_RIGHT)}}function N(e){e.isExpanded?(e.isExpanded=!1,E(e),x(e)):(e.isExpanded=!0,b(e),j(e))}function C(e,n){n(e),e.children.length>0&&e.children.forEach((e=>{C(e,n)}))}function T(e={}){let n=e.hasOwnProperty("value")?e.value:null;return(e=>"object"===h(e)&&0===Object.keys(e).length)(n)&&(n="{}"),{key:e.key||null,parent:e.parent||null,value:n,isExpanded:e.isExpanded||!1,type:e.type||null,children:e.children||[],el:e.el||null,depth:e.depth||0,dispose:null}}function I(e,n){if("object"==typeof e)for(let t in e){const r=T({value:e[t],key:t,depth:n.depth+1,type:h(e[t]),parent:n});n.children.push(r),I(e[t],r)}}function O(e){return"string"==typeof e?JSON.parse(e):e}function S(e){const n=O(e),t=T({value:n,key:h(n),type:h(n)});return I(n,t),t}function k(e,n){const t=S(O(e));return w(t,n),t}function w(e,n){const t=function(){const e=m("div");return e.className="json-container",e}();C(e,(function(e){e.el=function(e){let n=m("div");const t=e=>{const n=e.children.length;return"array"===e.type?`[${n}]`:"object"===e.type?`{${n}}`:null};if(e.children.length>0){n.innerHTML=function(e={}){const{key:n,size:t}=e;return`\n \n `}({key:e.key,size:t(e)});const r=n.querySelector("."+g.CARET_ICON);e.dispose=function(e,n,t){return e.addEventListener(n,t),()=>e.removeEventListener(n,t)}(r,"click",(()=>N(e)))}else n.innerHTML=function(e={}){const{key:n,value:t,type:r}=e;return`\n \n `}({key:e.key,value:""===e.value?'""':e.value,type:"{}"===e.value?"object":typeof e.value});const r=n.children[0];return null!==e.parent&&r.classList.add(g.HIDDEN),r.style="margin-left: "+18*e.depth+"px;",r}(e),t.appendChild(e.el)})),n.appendChild(t)}function D(e){C(e,(function(e){e.el.classList.remove(g.HIDDEN),e.isExpanded=!0,b(e)}))}function A(e){C(e,(function(n){n.isExpanded=!1,n.depth>e.depth&&n.el.classList.add(g.HIDDEN),E(n)}))}function L(e){var n;C(e,(e=>{e.dispose&&e.dispose()})),(n=e.el.parentNode).parentNode.removeChild(n)}const H={toggleNode:N,render:w,create:S,renderJSON:k,expand:D,collapse:A,traverse:C,destroy:L}})(),r})()));
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@pgrabovets/json-view",
3 | "version": "2.7.6",
4 | "description": "",
5 | "main": "dist/jsonview.js",
6 | "scripts": {
7 | "dev": "webpack serve",
8 | "serve": "webpack serve",
9 | "build": "webpack"
10 | },
11 | "repository": {
12 | "type": "git",
13 | "url": "git+https://github.com/pgrabovets/json-view.git"
14 | },
15 | "keywords": [
16 | "json"
17 | ],
18 | "author": "pavel grabovets",
19 | "license": "MIT",
20 | "devDependencies": {
21 | "css-loader": "^6.5.1",
22 | "sass": "^1.45.2",
23 | "sass-loader": "^12.4.0",
24 | "style-loader": "^3.3.1",
25 | "webpack": "^5.65.0",
26 | "webpack-cli": "^4.9.1",
27 | "webpack-dev-server": "^4.7.1"
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | ["@babel/env", {"modules": false}]
4 | ],
5 | "comments": false
6 | }
7 |
--------------------------------------------------------------------------------
/src/json-view.js:
--------------------------------------------------------------------------------
1 | import './jsonview.scss';
2 |
3 | import getDataType from './utils/getDataType';
4 | import { listen, detach, element } from './utils/dom';
5 |
6 | const classes = {
7 | HIDDEN: 'hidden',
8 | CARET_ICON: 'caret-icon',
9 | CARET_RIGHT: 'fa-caret-right',
10 | CARET_DOWN: 'fa-caret-down',
11 | ICON: 'fas'
12 | }
13 |
14 | function expandedTemplate(params = {}) {
15 | const { key, size } = params;
16 | return `
17 |
18 |
19 |
${key}
20 |
${size}
21 |
22 | `
23 | }
24 |
25 | function notExpandedTemplate(params = {}) {
26 | const { key, value, type } = params;
27 | return `
28 |
29 |
30 |
${key}
31 |
:
32 |
${value}
33 |
34 | `
35 | }
36 |
37 | function createContainerElement() {
38 | const el = element('div');
39 | el.className = 'json-container';
40 | return el;
41 | }
42 |
43 | function hideNodeChildren(node) {
44 | node.children.forEach((child) => {
45 | child.el.classList.add(classes.HIDDEN);
46 | if (child.isExpanded) {
47 | hideNodeChildren(child);
48 | }
49 | });
50 | }
51 |
52 | function showNodeChildren(node) {
53 | node.children.forEach((child) => {
54 | child.el.classList.remove(classes.HIDDEN);
55 | if (child.isExpanded) {
56 | showNodeChildren(child);
57 | }
58 | });
59 | }
60 |
61 | function setCaretIconDown(node) {
62 | if (node.children.length > 0) {
63 | const icon = node.el.querySelector('.' + classes.ICON);
64 | if (icon) {
65 | icon.classList.replace(classes.CARET_RIGHT, classes.CARET_DOWN);
66 | }
67 | }
68 | }
69 |
70 | function setCaretIconRight(node) {
71 | if (node.children.length > 0) {
72 | const icon = node.el.querySelector('.' + classes.ICON);
73 | if (icon) {
74 | icon.classList.replace(classes.CARET_DOWN, classes.CARET_RIGHT);
75 | }
76 | }
77 | }
78 |
79 | export function toggleNode(node) {
80 | if (node.isExpanded) {
81 | node.isExpanded = false;
82 | setCaretIconRight(node);
83 | hideNodeChildren(node);
84 | } else {
85 | node.isExpanded = true;
86 | setCaretIconDown(node);
87 | showNodeChildren(node);
88 | }
89 | }
90 |
91 | /**
92 | * Create node html element
93 | * @param {object} node
94 | * @return html element
95 | */
96 | function createNodeElement(node) {
97 | let el = element('div');
98 |
99 | const getSizeString = (node) => {
100 | const len = node.children.length;
101 | if (node.type === 'array') return `[${len}]`;
102 | if (node.type === 'object') return `{${len}}`;
103 | return null;
104 | }
105 |
106 | if (node.children.length > 0) {
107 | el.innerHTML = expandedTemplate({
108 | key: node.key,
109 | size: getSizeString(node),
110 | })
111 | const caretEl = el.querySelector('.' + classes.CARET_ICON);
112 | node.dispose = listen(caretEl, 'click', () => toggleNode(node));
113 | } else {
114 | el.innerHTML = notExpandedTemplate({
115 | key: node.key,
116 | value: node.value === "" ? '""' : node.value,
117 | type: node.value === '{}' ? 'object' : typeof node.value
118 | })
119 | }
120 |
121 | const lineEl = el.children[0];
122 |
123 | if (node.parent !== null) {
124 | lineEl.classList.add(classes.HIDDEN);
125 | }
126 |
127 | lineEl.style = 'margin-left: ' + node.depth * 18 + 'px;';
128 |
129 | return lineEl;
130 | }
131 |
132 | /**
133 | * Recursively traverse Tree object
134 | * @param {Object} node
135 | * @param {Callback} callback
136 | */
137 | export function traverse(node, callback) {
138 | callback(node);
139 | if (node.children.length > 0) {
140 | node.children.forEach((child) => {
141 | traverse(child, callback);
142 | });
143 | }
144 | }
145 |
146 | /**
147 | * Create node object
148 | * @param {object} opt options
149 | * @return {object}
150 | */
151 | function createNode(opt = {}) {
152 | const isEmptyObject = (value) => {
153 | return (
154 | getDataType(value) === 'object' &&
155 | Object.keys(value).length === 0
156 | )
157 | }
158 |
159 | let value = opt.hasOwnProperty('value') ? opt.value : null;
160 |
161 | if (isEmptyObject(value)) {
162 | value = "{}";
163 | }
164 |
165 | return {
166 | key: opt.key || null,
167 | parent: opt.parent || null,
168 | value: value,
169 | isExpanded: opt.isExpanded || false,
170 | type: opt.type || null,
171 | children: opt.children || [],
172 | el: opt.el || null,
173 | depth: opt.depth || 0,
174 | dispose: null
175 | }
176 | }
177 |
178 | /**
179 | * Create subnode for node
180 | * @param {object} Json data
181 | * @param {object} node
182 | */
183 | function createSubnode(data, node) {
184 | if (typeof data === 'object') {
185 | for (let key in data) {
186 | const child = createNode({
187 | value: data[key],
188 | key: key,
189 | depth: node.depth + 1,
190 | type: getDataType(data[key]),
191 | parent: node,
192 | });
193 | node.children.push(child);
194 | createSubnode(data[key], child);
195 | }
196 | }
197 | }
198 |
199 | function getJsonObject(data) {
200 | return typeof data === 'string' ? JSON.parse(data) : data;
201 | }
202 |
203 | /**
204 | * Create tree
205 | * @param {object | string} jsonData
206 | * @return {object}
207 | */
208 | export function create(jsonData) {
209 | const parsedData = getJsonObject(jsonData);
210 | const rootNode = createNode({
211 | value: parsedData,
212 | key: getDataType(parsedData),
213 | type: getDataType(parsedData),
214 | });
215 | createSubnode(parsedData, rootNode);
216 | return rootNode;
217 | }
218 |
219 | /**
220 | * Render JSON string into DOM container
221 | * @param {string | object} jsonData
222 | * @param {htmlElement} targetElement
223 | * @return {object} tree
224 | */
225 | export function renderJSON(jsonData, targetElement) {
226 | const parsedData = getJsonObject(jsonData);
227 | const tree = create(parsedData);
228 | render(tree, targetElement);
229 | return tree;
230 | }
231 |
232 | /**
233 | * Render tree into DOM container
234 | * @param {object} tree
235 | * @param {htmlElement} targetElement
236 | */
237 | export function render(tree, targetElement) {
238 | const containerEl = createContainerElement();
239 |
240 | traverse(tree, function(node) {
241 | node.el = createNodeElement(node);
242 | containerEl.appendChild(node.el);
243 | });
244 |
245 | targetElement.appendChild(containerEl);
246 | }
247 |
248 | export function expand(node) {
249 | traverse(node, function(child) {
250 | child.el.classList.remove(classes.HIDDEN);
251 | child.isExpanded = true;
252 | setCaretIconDown(child);
253 | });
254 | }
255 |
256 | export function collapse(node) {
257 | traverse(node, function(child) {
258 | child.isExpanded = false;
259 | if (child.depth > node.depth) child.el.classList.add(classes.HIDDEN);
260 | setCaretIconRight(child);
261 | });
262 | }
263 |
264 | export function destroy(tree) {
265 | traverse(tree, (node) => {
266 | if (node.dispose) {
267 | node.dispose();
268 | }
269 | })
270 | detach(tree.el.parentNode);
271 | }
272 |
273 | /**
274 | * Export public interface
275 | */
276 | export default {
277 | toggleNode,
278 | render,
279 | create,
280 | renderJSON,
281 | expand,
282 | collapse,
283 | traverse,
284 | destroy
285 | }
286 |
--------------------------------------------------------------------------------
/src/jsonview.scss:
--------------------------------------------------------------------------------
1 | .json-container {
2 | font-family: 'Open Sans';
3 | font-size: 16px;
4 | background-color: #fff;
5 | color: #808080;
6 | box-sizing: border-box;
7 |
8 | .line {
9 | margin: 4px 0;
10 | display: flex;
11 | justify-content: flex-start;
12 | }
13 |
14 | .caret-icon {
15 | width: 18px;
16 | text-align: center;
17 | cursor: pointer;
18 | }
19 |
20 | .empty-icon {
21 | width: 18px;
22 | }
23 |
24 | .json-type {
25 | margin-right: 4px;
26 | margin-left: 4px;
27 | }
28 |
29 | .json-key {
30 | color: #444;
31 | margin-right: 4px;
32 | margin-left: 4px;
33 | }
34 |
35 | .json-index {
36 | margin-right: 4px;
37 | margin-left: 4px;
38 | }
39 |
40 | .json-value {
41 | margin-left: 8px;
42 | }
43 |
44 | .json-number {
45 | color: #f9ae58;
46 | }
47 |
48 | .json-boolean {
49 | color: #ec5f66;
50 | }
51 |
52 | .json-string {
53 | color: #86b25c;
54 | }
55 |
56 | .json-size {
57 | margin-right: 4px;
58 | margin-left: 4px;
59 | }
60 |
61 | .hidden {
62 | display: none;
63 | }
64 |
65 | .fas {
66 | display: inline-block;
67 | border-style: solid;
68 | width: 0;
69 | height: 0;
70 | }
71 |
72 | .fa-caret-down {
73 | border-width: 6px 5px 0 5px;
74 | border-color: #808080 transparent;
75 | }
76 |
77 | .fa-caret-right {
78 | border-width: 5px 0 5px 6px;
79 | border-color: transparent transparent transparent #808080;
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/src/utils/dom.js:
--------------------------------------------------------------------------------
1 | export function element(name) {
2 | return document.createElement(name);
3 | }
4 |
5 | export function append(target, node) {
6 | target.appendChild(node);
7 | }
8 |
9 | export function listen(node, event, handler) {
10 | node.addEventListener(event, handler);
11 | return () => node.removeEventListener(event, handler);
12 | }
13 |
14 | export function detach(node) {
15 | node.parentNode.removeChild(node);
16 | }
17 |
--------------------------------------------------------------------------------
/src/utils/getDataType.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Get value data type
3 | * @param {*} data
4 | */
5 | export default function getDataType(val) {
6 | if (Array.isArray(val)) return 'array';
7 | if (val === null) return 'null';
8 | return typeof val;
9 | }
10 |
--------------------------------------------------------------------------------
/src/utils/traverseObject.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Recursively traverse json object
3 | * @param {object} target
4 | * @param {function} callback
5 | */
6 | function traverseObject(target, callback) {
7 | callback(target);
8 | if (typeof target === 'object') {
9 | for (let key in target) {
10 | traverseObject(target[key], callback);
11 | }
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 |
3 | module.exports = {
4 | mode: 'production',
5 | entry: './src/json-view.js',
6 | output: {
7 | filename: 'jsonview.js',
8 | library: {
9 | name: 'jsonview',
10 | type: 'umd'
11 | },
12 | path: path.resolve(__dirname, 'dist'),
13 | },
14 | devServer: {
15 | static: path.join(__dirname, 'demo'),
16 | port: 3000,
17 | },
18 | module: {
19 | rules: [
20 | {
21 | test: /\.s[ac]ss$/i,
22 | use: [
23 | "style-loader",
24 | "css-loader",
25 | "sass-loader",
26 | ],
27 | },
28 | ],
29 | },
30 | };
31 |
--------------------------------------------------------------------------------