intl-tel-input
1 year ago
chart.min.js
1 year ago
circles.js
1 year ago
daterangepicker.min.js
1 year ago
dragula.min.js
1 year ago
jquery.inputmask.min.js
1 year ago
jquery.json-viewer.js
1 year ago
medium-editor.min.js
1 year ago
moment-with-locales.min.js
1 year ago
pickr.min.js
1 year ago
sprintf.min.js
1 year ago
jquery.json-viewer.js
182 lines
| 1 | /** |
| 2 | * jQuery json-viewer |
| 3 | * @author: Alexandre Bodelot <alexandre.bodelot@gmail.com> |
| 4 | * @link: https://github.com/abodelot/jquery.json-viewer |
| 5 | */ |
| 6 | (function($) { |
| 7 | |
| 8 | /** |
| 9 | * Check if arg is either an array with at least 1 element, or a dict with at least 1 key |
| 10 | * @return boolean |
| 11 | */ |
| 12 | function isCollapsable(arg) { |
| 13 | return arg instanceof Object && Object.keys(arg).length > 0; |
| 14 | } |
| 15 | |
| 16 | /** |
| 17 | * Check if a string looks like a URL, based on protocol |
| 18 | * This doesn't attempt to validate URLs, there's no use and syntax can be too complex |
| 19 | * @return boolean |
| 20 | */ |
| 21 | function isUrl(string) { |
| 22 | var protocols = ['http', 'https', 'ftp', 'ftps']; |
| 23 | for (var i = 0; i < protocols.length; ++i) { |
| 24 | if (string.startsWith(protocols[i] + '://')) { |
| 25 | return true; |
| 26 | } |
| 27 | } |
| 28 | return false; |
| 29 | } |
| 30 | |
| 31 | /** |
| 32 | * Return the input string html escaped |
| 33 | * @return string |
| 34 | */ |
| 35 | function htmlEscape(s) { |
| 36 | return s.replace(/&/g, '&') |
| 37 | .replace(/</g, '<') |
| 38 | .replace(/>/g, '>') |
| 39 | .replace(/'/g, ''') |
| 40 | .replace(/"/g, '"'); |
| 41 | } |
| 42 | |
| 43 | /** |
| 44 | * Transform a json object into html representation |
| 45 | * @return string |
| 46 | */ |
| 47 | function json2html(json, options) { |
| 48 | var html = ''; |
| 49 | if (typeof json === 'string') { |
| 50 | // Escape tags and quotes |
| 51 | json = htmlEscape(json); |
| 52 | |
| 53 | if (options.withLinks && isUrl(json)) { |
| 54 | html += '<a href="' + json + '" class="json-string" target="_blank">' + json + '</a>'; |
| 55 | } else { |
| 56 | // Escape double quotes in the rendered non-URL string. |
| 57 | json = json.replace(/"/g, '\\"'); |
| 58 | html += '<span class="json-string">"' + json + '"</span>'; |
| 59 | } |
| 60 | } else if (typeof json === 'number' || typeof json === 'bigint') { |
| 61 | html += '<span class="json-literal">' + json + '</span>'; |
| 62 | } else if (typeof json === 'boolean') { |
| 63 | html += '<span class="json-literal">' + json + '</span>'; |
| 64 | } else if (json === null) { |
| 65 | html += '<span class="json-literal">null</span>'; |
| 66 | } else if (json instanceof Array) { |
| 67 | if (json.length > 0) { |
| 68 | html += '[<ol class="json-array">'; |
| 69 | for (var i = 0; i < json.length; ++i) { |
| 70 | html += '<li>'; |
| 71 | // Add toggle button if item is collapsable |
| 72 | if (isCollapsable(json[i])) { |
| 73 | html += '<a href class="json-toggle"></a>'; |
| 74 | } |
| 75 | html += json2html(json[i], options); |
| 76 | // Add comma if item is not last |
| 77 | if (i < json.length - 1) { |
| 78 | html += ','; |
| 79 | } |
| 80 | html += '</li>'; |
| 81 | } |
| 82 | html += '</ol>]'; |
| 83 | } else { |
| 84 | html += '[]'; |
| 85 | } |
| 86 | } else if (typeof json === 'object') { |
| 87 | // Optional support different libraries for big numbers |
| 88 | // json.isLosslessNumber: package lossless-json |
| 89 | // json.toExponential(): packages bignumber.js, big.js, decimal.js, decimal.js-light, others? |
| 90 | if (options.bigNumbers && (typeof json.toExponential === 'function' || json.isLosslessNumber)) { |
| 91 | html += '<span class="json-literal">' + json.toString() + '</span>'; |
| 92 | } else { |
| 93 | var keyCount = Object.keys(json).length; |
| 94 | if (keyCount > 0) { |
| 95 | html += '{<ul class="json-dict">'; |
| 96 | for (var key in json) { |
| 97 | if (Object.prototype.hasOwnProperty.call(json, key)) { |
| 98 | key = htmlEscape(key); |
| 99 | var keyRepr = options.withQuotes ? |
| 100 | '<span class="json-string">"' + key + '"</span>' : key; |
| 101 | |
| 102 | html += '<li>'; |
| 103 | // Add toggle button if item is collapsable |
| 104 | if (isCollapsable(json[key])) { |
| 105 | html += '<a href class="json-toggle">' + keyRepr + '</a>'; |
| 106 | } else { |
| 107 | html += keyRepr; |
| 108 | } |
| 109 | html += ': ' + json2html(json[key], options); |
| 110 | // Add comma if item is not last |
| 111 | if (--keyCount > 0) { |
| 112 | html += ','; |
| 113 | } |
| 114 | html += '</li>'; |
| 115 | } |
| 116 | } |
| 117 | html += '</ul>}'; |
| 118 | } else { |
| 119 | html += '{}'; |
| 120 | } |
| 121 | } |
| 122 | } |
| 123 | return html; |
| 124 | } |
| 125 | |
| 126 | /** |
| 127 | * jQuery plugin method |
| 128 | * @param json: a javascript object |
| 129 | * @param options: an optional options hash |
| 130 | */ |
| 131 | $.fn.jsonViewer = function(json, options) { |
| 132 | // Merge user options with default options |
| 133 | options = Object.assign({}, { |
| 134 | collapsed: false, |
| 135 | rootCollapsable: true, |
| 136 | withQuotes: false, |
| 137 | withLinks: true, |
| 138 | bigNumbers: false |
| 139 | }, options); |
| 140 | |
| 141 | // jQuery chaining |
| 142 | return this.each(function() { |
| 143 | |
| 144 | // Transform to HTML |
| 145 | var html = json2html(json, options); |
| 146 | if (options.rootCollapsable && isCollapsable(json)) { |
| 147 | html = '<a href class="json-toggle"></a>' + html; |
| 148 | } |
| 149 | |
| 150 | // Insert HTML in target DOM element |
| 151 | $(this).html(html); |
| 152 | $(this).addClass('json-document'); |
| 153 | |
| 154 | // Bind click on toggle buttons |
| 155 | $(this).off('click'); |
| 156 | $(this).on('click', 'a.json-toggle', function() { |
| 157 | var target = $(this).toggleClass('collapsed').siblings('ul.json-dict, ol.json-array'); |
| 158 | target.toggle(); |
| 159 | if (target.is(':visible')) { |
| 160 | target.siblings('.json-placeholder').remove(); |
| 161 | } else { |
| 162 | var count = target.children('li').length; |
| 163 | var placeholder = count + (count > 1 ? ' items' : ' item'); |
| 164 | target.after('<a href class="json-placeholder">' + placeholder + '</a>'); |
| 165 | } |
| 166 | return false; |
| 167 | }); |
| 168 | |
| 169 | // Simulate click on toggle button when placeholder is clicked |
| 170 | $(this).on('click', 'a.json-placeholder', function() { |
| 171 | $(this).siblings('a.json-toggle').click(); |
| 172 | return false; |
| 173 | }); |
| 174 | |
| 175 | if (options.collapsed == true) { |
| 176 | // Trigger click to collapse all nodes |
| 177 | $(this).find('a.json-toggle').click(); |
| 178 | } |
| 179 | }); |
| 180 | }; |
| 181 | })(jQuery); |
| 182 |