jquery.jsonview.js 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295
  1. /*!
  2. jQuery JSONView.
  3. Licensed under the MIT License.
  4. */
  5. (function(jQuery) {
  6. var $, Collapser, JSONFormatter, JSONView, JSON_VALUE_TYPES;
  7. JSON_VALUE_TYPES = ['object', 'array', 'number', 'string', 'boolean', 'null'];
  8. JSONFormatter = (function() {
  9. function JSONFormatter(options) {
  10. if (options == null) {
  11. options = {};
  12. }
  13. this.options = options;
  14. }
  15. JSONFormatter.prototype.htmlEncode = function(html) {
  16. if (html !== null) {
  17. return html.toString().replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
  18. } else {
  19. return '';
  20. }
  21. };
  22. JSONFormatter.prototype.jsString = function(s) {
  23. s = JSON.stringify(s).slice(1, -1);
  24. return this.htmlEncode(s);
  25. };
  26. JSONFormatter.prototype.decorateWithSpan = function(value, className) {
  27. return "<span class=\"" + className + "\">" + (this.htmlEncode(value)) + "</span>";
  28. };
  29. JSONFormatter.prototype.valueToHTML = function(value, level) {
  30. var valueType;
  31. if (level == null) {
  32. level = 0;
  33. }
  34. valueType = Object.prototype.toString.call(value).match(/\s(.+)]/)[1].toLowerCase();
  35. if (this.options.strict && !jQuery.inArray(valueType, JSON_VALUE_TYPES)) {
  36. throw new Error("" + valueType + " is not a valid JSON value type");
  37. }
  38. return this["" + valueType + "ToHTML"].call(this, value, level);
  39. };
  40. JSONFormatter.prototype.nullToHTML = function(value) {
  41. return this.decorateWithSpan('null', 'null');
  42. };
  43. JSONFormatter.prototype.undefinedToHTML = function() {
  44. return this.decorateWithSpan('undefined', 'undefined');
  45. };
  46. JSONFormatter.prototype.numberToHTML = function(value) {
  47. return this.decorateWithSpan(value, 'num');
  48. };
  49. JSONFormatter.prototype.stringToHTML = function(value) {
  50. var multilineClass, newLinePattern;
  51. if (/^(http|https|file):\/\/[^\s]+$/i.test(value)) {
  52. return "<a href=\"" + (this.htmlEncode(value)) + "\" target=\"_blank\"><span class=\"q\">\"</span>" + (this.jsString(value)) + "<span class=\"q\">\"</span></a>";
  53. } else {
  54. multilineClass = '';
  55. value = this.jsString(value);
  56. if (this.options.nl2br) {
  57. newLinePattern = /([^>\\r\\n]?)(\\r\\n|\\n\\r|\\r|\\n)/g;
  58. if (newLinePattern.test(value)) {
  59. multilineClass = ' multiline';
  60. value = (value + '').replace(newLinePattern, '$1' + '<br />');
  61. }
  62. }
  63. return "<span class=\"string" + multilineClass + "\">\"" + value + "\"</span>";
  64. }
  65. };
  66. JSONFormatter.prototype.booleanToHTML = function(value) {
  67. return this.decorateWithSpan(value, 'bool');
  68. };
  69. JSONFormatter.prototype.arrayToHTML = function(array, level) {
  70. var collapsible, hasContents, index, numProps, output, value, _i, _len;
  71. if (level == null) {
  72. level = 0;
  73. }
  74. hasContents = false;
  75. output = '';
  76. numProps = array.length;
  77. for (index = _i = 0, _len = array.length; _i < _len; index = ++_i) {
  78. value = array[index];
  79. hasContents = true;
  80. output += '<li>' + this.valueToHTML(value, level + 1);
  81. if (numProps > 1) {
  82. output += ',';
  83. }
  84. output += '</li>';
  85. numProps--;
  86. }
  87. if (hasContents) {
  88. collapsible = level === 0 ? '' : ' collapsible';
  89. return "[<ul class=\"array level" + level + collapsible + "\">" + output + "</ul>]";
  90. } else {
  91. return '[ ]';
  92. }
  93. };
  94. JSONFormatter.prototype.objectToHTML = function(object, level) {
  95. var collapsible, hasContents, key, numProps, output, prop, value;
  96. if (level == null) {
  97. level = 0;
  98. }
  99. hasContents = false;
  100. output = '';
  101. numProps = 0;
  102. for (prop in object) {
  103. numProps++;
  104. }
  105. for (prop in object) {
  106. value = object[prop];
  107. hasContents = true;
  108. key = this.options.escape ? this.jsString(prop) : prop;
  109. output += "<li><a class=\"prop\" href=\"javascript:;\"><span class=\"q\">\"</span>" + key + "<span class=\"q\">\"</span></a>: " + (this.valueToHTML(value, level + 1));
  110. if (numProps > 1) {
  111. output += ',';
  112. }
  113. output += '</li>';
  114. numProps--;
  115. }
  116. if (hasContents) {
  117. collapsible = level === 0 ? '' : ' collapsible';
  118. return "{<ul class=\"obj level" + level + collapsible + "\">" + output + "</ul>}";
  119. } else {
  120. return '{ }';
  121. }
  122. };
  123. JSONFormatter.prototype.jsonToHTML = function(json) {
  124. return "<div class=\"jsonview\">" + (this.valueToHTML(json)) + "</div>";
  125. };
  126. return JSONFormatter;
  127. })();
  128. (typeof module !== "undefined" && module !== null) && (module.exports = JSONFormatter);
  129. Collapser = (function() {
  130. function Collapser() {}
  131. Collapser.bindEvent = function(item, options) {
  132. var collapser;
  133. item.firstChild.addEventListener('click', (function(_this) {
  134. return function(event) {
  135. return _this.toggle(event.target.parentNode.firstChild, options);
  136. };
  137. })(this));
  138. collapser = document.createElement('div');
  139. collapser.className = 'collapser';
  140. collapser.innerHTML = options.collapsed ? '+' : '-';
  141. collapser.addEventListener('click', (function(_this) {
  142. return function(event) {
  143. return _this.toggle(event.target, options);
  144. };
  145. })(this));
  146. item.insertBefore(collapser, item.firstChild);
  147. if (options.collapsed) {
  148. return this.collapse(collapser);
  149. }
  150. };
  151. Collapser.expand = function(collapser) {
  152. var ellipsis, target;
  153. target = this.collapseTarget(collapser);
  154. if (target.style.display === '') {
  155. return;
  156. }
  157. ellipsis = target.parentNode.getElementsByClassName('ellipsis')[0];
  158. target.parentNode.removeChild(ellipsis);
  159. target.style.display = '';
  160. return collapser.innerHTML = '-';
  161. };
  162. Collapser.collapse = function(collapser) {
  163. var ellipsis, target;
  164. target = this.collapseTarget(collapser);
  165. if (target.style.display === 'none') {
  166. return;
  167. }
  168. target.style.display = 'none';
  169. ellipsis = document.createElement('span');
  170. ellipsis.className = 'ellipsis';
  171. ellipsis.innerHTML = ' &hellip; ';
  172. target.parentNode.insertBefore(ellipsis, target);
  173. return collapser.innerHTML = '+';
  174. };
  175. Collapser.toggle = function(collapser, options) {
  176. var action, collapsers, target, _i, _len, _results;
  177. if (options == null) {
  178. options = {};
  179. }
  180. target = this.collapseTarget(collapser);
  181. action = target.style.display === 'none' ? 'expand' : 'collapse';
  182. if (options.recursive_collapser) {
  183. collapsers = collapser.parentNode.getElementsByClassName('collapser');
  184. _results = [];
  185. for (_i = 0, _len = collapsers.length; _i < _len; _i++) {
  186. collapser = collapsers[_i];
  187. _results.push(this[action](collapser));
  188. }
  189. return _results;
  190. } else {
  191. return this[action](collapser);
  192. }
  193. };
  194. Collapser.collapseTarget = function(collapser) {
  195. var target, targets;
  196. targets = collapser.parentNode.getElementsByClassName('collapsible');
  197. if (!targets.length) {
  198. return;
  199. }
  200. return target = targets[0];
  201. };
  202. return Collapser;
  203. })();
  204. $ = jQuery;
  205. JSONView = {
  206. collapse: function(el) {
  207. if (el.innerHTML === '-') {
  208. return Collapser.collapse(el);
  209. }
  210. },
  211. expand: function(el) {
  212. if (el.innerHTML === '+') {
  213. return Collapser.expand(el);
  214. }
  215. },
  216. toggle: function(el) {
  217. return Collapser.toggle(el);
  218. }
  219. };
  220. return $.fn.JSONView = function() {
  221. var args, defaultOptions, formatter, json, method, options, outputDoc;
  222. args = arguments;
  223. if (JSONView[args[0]] != null) {
  224. method = args[0];
  225. return this.each(function() {
  226. var $this, level;
  227. $this = $(this);
  228. if (args[1] != null) {
  229. level = args[1];
  230. return $this.find(".jsonview .collapsible.level" + level).siblings('.collapser').each(function() {
  231. return JSONView[method](this);
  232. });
  233. } else {
  234. return $this.find('.jsonview > ul > li .collapsible').siblings('.collapser').each(function() {
  235. return JSONView[method](this);
  236. });
  237. }
  238. });
  239. } else {
  240. json = args[0];
  241. options = args[1] || {};
  242. defaultOptions = {
  243. collapsed: false,
  244. nl2br: false,
  245. recursive_collapser: false,
  246. escape: true,
  247. strict: false
  248. };
  249. options = $.extend(defaultOptions, options);
  250. formatter = new JSONFormatter(options);
  251. if (Object.prototype.toString.call(json) === '[object String]') {
  252. json = JSON.parse(json);
  253. }
  254. outputDoc = formatter.jsonToHTML(json);
  255. return this.each(function() {
  256. var $this, item, items, _i, _len, _results;
  257. $this = $(this);
  258. $this.html(outputDoc);
  259. items = $this[0].getElementsByClassName('collapsible');
  260. _results = [];
  261. for (_i = 0, _len = items.length; _i < _len; _i++) {
  262. item = items[_i];
  263. if (item.parentNode.nodeName === 'LI') {
  264. _results.push(Collapser.bindEvent(item.parentNode, options));
  265. } else {
  266. _results.push(void 0);
  267. }
  268. }
  269. return _results;
  270. });
  271. }
  272. };
  273. })(jQuery);