jquery.json-viewer.js
4.35 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
/**
* jQuery json-viewer
* @author: Alexandre Bodelot <alexandre.bodelot@gmail.com>
*/
(function($){
/**
* Check if arg is either an array with at least 1 element, or a dict with at least 1 key
* @return boolean
*/
function isCollapsable(arg) {
return arg instanceof Object && Object.keys(arg).length > 0;
}
/**
* Check if a string represents a valid url
* @return boolean
*/
function isUrl(string) {
var regexp = /^(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?/;
return regexp.test(string);
}
/**
* Transform a json object into html representation
* @return string
*/
function json2html(json, options) {
var html = '';
if (typeof json === 'string') {
/* Escape tags */
json = json.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
if (isUrl(json))
html += '<a href="' + json + '" class="json-string">' + json + '</a>';
else
html += '<span class="json-string">"' + json + '"</span>';
}
else if (typeof json === 'number') {
html += '<span class="json-literal">' + json + '</span>';
}
else if (typeof json === 'boolean') {
html += '<span class="json-literal">' + json + '</span>';
}
else if (json === null) {
html += '<span class="json-literal">null</span>';
}
else if (json instanceof Array) {
if (json.length > 0) {
html += '[<ol class="json-array">';
for (var i = 0; i < json.length; ++i) {
html += '<li>';
/* Add toggle button if item is collapsable */
if (isCollapsable(json[i])) {
html += '<a href class="json-toggle"></a>';
}
html += json2html(json[i], options);
/* Add comma if item is not last */
if (i < json.length - 1) {
html += ',';
}
html += '</li>';
}
html += '</ol>]';
}
else {
html += '[]';
}
}
else if (typeof json === 'object') {
var key_count = Object.keys(json).length;
if (key_count > 0) {
html += '{<ul class="json-dict">';
for (var key in json) {
if (json.hasOwnProperty(key)) {
html += '<li>';
var keyRepr = options.withQuotes ?
'<span class="json-string">"' + key + '"</span>' : key;
/* Add toggle button if item is collapsable */
if (isCollapsable(json[key])) {
html += '<a href class="json-toggle">' + keyRepr + '</a>';
}
else {
html += keyRepr;
}
html += ': ' + json2html(json[key], options);
/* Add comma if item is not last */
if (--key_count > 0)
html += ',';
html += '</li>';
}
}
html += '</ul>}';
}
else {
html += '{}';
}
}
return html;
}
/**
* jQuery plugin method
* @param json: a javascript object
* @param options: an optional options hash
*/
$.fn.jsonViewer = function(json, options) {
options = options || {};
/* jQuery chaining */
return this.each(function() {
/* Transform to HTML */
var html = json2html(json, options);
if (isCollapsable(json))
html = '<a href class="json-toggle"></a>' + html;
/* Insert HTML in target DOM element */
$(this).html(html);
/* Bind click on toggle buttons */
$(this).off('click');
$(this).on('click', 'a.json-toggle', function() {
var target = $(this).toggleClass('collapsed').siblings('ul.json-dict, ol.json-array');
target.toggle();
if (target.is(':visible')) {
target.siblings('.json-placeholder').remove();
}
else {
var count = target.children('li').length;
var placeholder = count + (count > 1 ? ' items' : ' item');
target.after('<a href class="json-placeholder">' + placeholder + '</a>');
}
return false;
});
/* Simulate click on toggle button when placeholder is clicked */
$(this).on('click', 'a.json-placeholder', function() {
$(this).siblings('a.json-toggle').click();
return false;
});
if (options.collapsed == true) {
/* Trigger click to collapse all nodes */
$(this).find('a.json-toggle').click();
}
});
};
})(jQuery);