: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
* JSON Tree library (a part of jsonTreeViewer)
* http://github.com/summerstyle/jsonTreeViewer
* Copyright 2017 Vera Lobacheva (http://iamvera.com)
* Released under the MIT license (LICENSE.txt)
var jsonTree = (function() {
/* ---------- Utilities ---------- */
* Returns js-"class" of value
* @param val {any type} - value
* @returns {string} - for example, "[object Function]"
getClass : function(val) {
return Object.prototype.toString.call(val);
* Checks for a type of value (for valid JSON data types).
* In other cases - throws an exception
* @param val {any type} - the value for new node
* @returns {string} ("object" | "array" | "null" | "boolean" | "number" | "string")
getType : function(val) {
switch(utils.getClass(val)) {
throw new Error('Bad type: ' + utils.getClass(val));
* Applies for each item of list some function
* and checks for last element of the list
* @param obj {Object | Array} - a list or a dict with child nodes
* @param func {Function} - the function for each item
forEachNode : function(obj, func) {
var type = utils.getType(obj),
obj.forEach(function(item, i) {
func(i, item, i === isLast);
var keys = Object.keys(obj).sort();
isLast = keys.length - 1;
keys.forEach(function(item, i) {
func(item, obj[item], i === isLast);
* Implements the kind of an inheritance by
* using parent prototype and
* creating intermediate constructor
* @param Child {Function} - a child constructor
* @param Parent {Function} - a parent constructor
return function(Child, Parent) {
F.prototype = Parent.prototype;
Child.prototype = new F();
Child.prototype.constructor = Child;
* Checks for a valid type of root node*
* @param {any type} jsonObj - a value for root node
* @returns {boolean} - true for an object or an array, false otherwise
isValidRoot : function(jsonObj) {
switch (utils.getType(jsonObj)) {
extend : function(targetObj, sourceObj) {
for (var prop in sourceObj) {
if (sourceObj.hasOwnProperty(prop)) {
targetObj[prop] = sourceObj[prop];
/* ---------- Node constructors ---------- */
* The factory for creating nodes of defined type.
* ~~~ Node ~~~ is a structure element of an onject or an array
* with own label (a key of an object or an index of an array)
* and value of any json data type. The root object or array
* is a node without label.
* <li class="jsontree_node [jsontree_node_expanded]">
* <span class="jsontree_label-wrapper">
* <span class="jsontree_label">
* <span class="jsontree_expand-button" />
* <(div|span) class="jsontree_value jsontree_value_(object|array|boolean|null|number|string)">
* @param label {string} - key name
* @param val {Object | Array | string | number | boolean | null} - a value of node
* @param isLast {boolean} - true if node is last in list of siblings
function Node(label, val, isLast) {
var nodeType = utils.getType(val);
if (nodeType in Node.CONSTRUCTORS) {
return new Node.CONSTRUCTORS[nodeType](label, val, isLast);
throw new Error('Bad type: ' + utils.getClass(val));
* The constructor for simple types (string, number, boolean, null)
* value = string || number || boolean || null
* <li class="jsontree_node">
* <span class="jsontree_label-wrapper">
* <span class="jsontree_label">"age"</span>
* <span class="jsontree_value jsontree_value_(number|boolean|string|null)">25</span>
* @param label {string} - key name
* @param val {string | number | boolean | null} - a value of simple types
* @param isLast {boolean} - true if node is last in list of parent childNodes
function _NodeSimple(label, val, isLast) {
if (this.constructor === _NodeSimple) {
throw new Error('This is abstract class');
el = document.createElement('li'),
template = function(label, val) {
<span class="jsontree_label-wrapper">\
<span class="jsontree_label">"' +
<span class="jsontree_value-wrapper">\
<span class="jsontree_value jsontree_value_' + self.type + '">' +
el.classList.add('jsontree_node');
el.innerHTML = template(label, val);
labelEl = el.querySelector('.jsontree_label');
labelEl.addEventListener('click', function(e) {
document.getSelection().removeAllRanges();
alert(self.getJSONPath());
_NodeSimple.prototype = {
constructor : _NodeSimple,
this.el.classList.add('jsontree_node_marked');
this.el.classList.remove('jsontree_node_marked');
toggleMarked : function() {
this.el.classList.toggle('jsontree_node_marked');
* Expands parent node of this node
* @param isRecursive {boolean} - if true, expands all parent nodes
expandParent : function(isRecursive) {
this.parent.expandParent(isRecursive);
* Returns JSON-path of this
* @param isInDotNotation {boolean} - kind of notation for returned json-path
* (by default, in bracket notation)
getJSONPath : function(isInDotNotation) {
if (this.parent.type === 'array') {
currentPath = "[" + this.label + "]";
currentPath = isInDotNotation ? "." + this.label : "['" + this.label + "']";
return this.parent.getJSONPath(isInDotNotation) + currentPath;
* The constructor for boolean values
* boolean = true || false
* @param label {string} - key name
* @param val {boolean} - value of boolean type, true or false
* @param isLast {boolean} - true if node is last in list of parent childNodes
function NodeBoolean(label, val, isLast) {
_NodeSimple.call(this, label, val, isLast);
utils.inherits(NodeBoolean,_NodeSimple);
* The constructor for number values
* @param label {string} - key name
* @param val {number} - value of number type, for example 123
* @param isLast {boolean} - true if node is last in list of parent childNodes
function NodeNumber(label, val, isLast) {
_NodeSimple.call(this, label, val, isLast);
utils.inherits(NodeNumber,_NodeSimple);
* The constructor for string values
* @param label {string} - key name
* @param val {string} - value of string type, for example "abc"
* @param isLast {boolean} - true if node is last in list of parent childNodes
function NodeString(label, val, isLast) {
_NodeSimple.call(this, label, '"' + val + '"', isLast);
utils.inherits(NodeString,_NodeSimple);
* The constructor for null values
* @param label {string} - key name
* @param val {null} - value (only null)
* @param isLast {boolean} - true if node is last in list of parent childNodes
function NodeNull(label, val, isLast) {
_NodeSimple.call(this, label, val, isLast);
utils.inherits(NodeNull,_NodeSimple);
* The constructor for complex types (object, array)
* value = object || array
* <li class="jsontree_node jsontree_node_(object|array) [expanded]">
* <span class="jsontree_label-wrapper">
* <span class="jsontree_label">
* <span class="jsontree_expand-button" />
* <div class="jsontree_value">
* <ul class="jsontree_child-nodes" />
* @param label {string} - key name
* @param val {Object | Array} - a value of complex types, object or array
* @param isLast {boolean} - true if node is last in list of parent childNodes
function _NodeComplex(label, val, isLast) {
if (this.constructor === _NodeComplex) {
throw new Error('This is abstract class');
el = document.createElement('li'),
template = function(label, sym) {
var comma = (!isLast) ? ',' : '',
<div class="jsontree_value-wrapper">\
<div class="jsontree_value jsontree_value_' + self.type + '">\
<span class="jsontree_show-more">…</span>\
<ul class="jsontree_child-nodes"></ul>\
<span class="jsontree_label-wrapper">\
<span class="jsontree_label">' +
'<span class="jsontree_expand-button"></span>' +
el.classList.add('jsontree_node');
el.classList.add('jsontree_node_complex');
el.innerHTML = template(label, self.sym);
childNodesUl = el.querySelector('.jsontree_child-nodes');
labelEl = el.querySelector('.jsontree_label');
moreContentEl = el.querySelector('.jsontree_show-more');
labelEl.addEventListener('click', function(e) {
document.getSelection().removeAllRanges();
alert(self.getJSONPath());
self.toggle(e.ctrlKey || e.metaKey);
moreContentEl.addEventListener('click', function(e) {