// jscs:disable // jshint ignore: start /* global console, jsonView */ /* * ViewJSON * Version 1.0 * A Google Chrome extension to display JSON in a user-friendly format * * This is a chromeified version of the JSONView Firefox extension by Ben Hollis: * http://jsonview.com * http://code.google.com/p/jsonview * * Also based on the XMLTree Chrome extension by Moonty & alan.stroop * https://chrome.google.com/extensions/detail/gbammbheopgpmaagmckhpjbfgdfkpadb * * port by Jamie Wilkinson (@jamiew) | http://jamiedubs.com | http://github.com/jamiew * MIT license / copyfree (f) F.A.T. Lab http://fffff.at * Speed Project Approved: 2h */ function collapse( evt ) { var collapser = evt.target; var target = collapser.parentNode.getElementsByClassName( 'collapsible' ); if ( ! target.length ) { return; } target = target[0]; if ( target.style.display === 'none' ) { var ellipsis = target.parentNode.getElementsByClassName( 'ellipsis' )[0]; target.parentNode.removeChild( ellipsis ); target.style.display = ''; } else { target.style.display = 'none'; var ellipsis = document.createElement( 'span' ); ellipsis.className = 'ellipsis'; ellipsis.innerHTML = ' … '; target.parentNode.insertBefore( ellipsis, target ); } collapser.innerHTML = (collapser.innerHTML === '-') ? '+' : '-'; } function addCollapser( item ) { // This mainly filters out the root object (which shouldn't be collapsible). if ( item.nodeName !== 'LI' ) { return; } var collapser = document.createElement( 'div' ); collapser.className = 'collapser'; collapser.innerHTML = '-'; collapser.addEventListener( 'click', collapse, false ); item.insertBefore( collapser, item.firstChild ); } function jsonView( id, target ) { this.debug = false; if ( id.indexOf( '#' ) !== - 1 ) { this.idType = 'id'; this.id = id.replace( '#', '' ); } else if ( id.indexOf( '.' ) !== - 1 ) { this.idType = 'class'; this.id = id.replace( '.', '' ); } else { if ( this.debug ) { console.log( 'Can\'t find that element' ); } return; } this.data = document.getElementById( this.id ).innerHTML; if ( typeof (target) !== undefined ) { if ( target.indexOf( '#' ) !== - 1 ) { this.targetType = 'id'; this.target = target.replace( '#', '' ); } else if ( id.indexOf( '.' ) !== - 1 ) { this.targetType = 'class'; this.target = target.replace( '.', '' ); } else { if ( this.debug ) { console.log( 'Can\'t find the target element' ); } return; } } // Note: now using "*.json*" URI matching rather than these page regexes -- save CPU cycles! // var is_json = /^\s*(\{.*\})\s*$/.test(this.data); // var is_jsonp = /^.*\(\s*(\{.*\})\s*\)$/.test(this.data); // if(is_json || is_jsonp){ // Our manifest specifies that we only do URLs matching '.json', so attempt to sanitize any HTML // added by Chrome's "text/plain" or "text/html" handlers. if ( /^\(.*)\<\/pre\>$/.test( this.data ) ) { if ( this.debug ) { console.log( 'JSONView: data is wrapped in
...
, stripping HTML...' ); } this.data = this.data.replace( /<(?:.|\s)*?>/g, '' ); // Aggressively strip HTML. } // Test if what remains is JSON or JSONp. var json_regex = /^\s*([\[\{].*[\}\]])\s*$/; // Ghetto, but it works. var jsonp_regex = /^[\s\u200B\uFEFF]*([\w$\[\]\.]+)[\s\u200B\uFEFF]*\([\s\u200B\uFEFF]*([\[{][\s\S]*[\]}])[\s\u200B\uFEFF]*\);?[\s\u200B\uFEFF]*$/; var jsonp_regex2 = /([\[\{][\s\S]*[\]\}])\)/; // more liberal support... this allows us to pass the jsonp.json & jsonp2.json tests. var is_json = json_regex.test( this.data ); var is_jsonp = jsonp_regex.test( this.data ); if ( this.debug ) { console.log( 'JSONView: is_json=' + is_json + ' is_jsonp=' + is_jsonp ); } if ( is_json || is_jsonp ) { if ( this.debug ) { console.log( 'JSONView: sexytime!' ); } // JSONFormatter json->HTML prototype straight from Firefox JSONView // For reference: http://code.google.com/p/jsonview. function JSONFormatter() { // No magic required. } JSONFormatter.prototype = { htmlEncode: function( t ) { return t != null ? t.toString().replace( /&/g, '&' ).replace( /"/g, '"' ).replace( //g, '>' ) : ''; }, decorateWithSpan: function( value, className ) { return '' + this.htmlEncode( value ) + ''; }, // Convert a basic JSON datatype (number, string, boolean, null, object, array) into an HTML fragment. valueToHTML: function( value ) { var valueType = typeof value; var output = ''; if ( value === null ) { output += this.decorateWithSpan( 'null', 'null' ); } else if ( value && value.constructor === Array ) { output += this.arrayToHTML( value ); } else if ( valueType === 'object' ) { output += this.objectToHTML( value ); } else if ( valueType === 'number' ) { output += this.decorateWithSpan( value, 'num' ); } else if ( valueType === 'string' ) { if ( /^(http|https):\/\/[^\s]+$/.test( value ) ) { output += '' + this.htmlEncode( value ) + ''; } else { output += this.decorateWithSpan( '"' + value + '"', 'string' ); } } else if ( valueType === 'boolean' ) { output += this.decorateWithSpan( value, 'bool' ); } return output; }, // Convert an array into an HTML fragment arrayToHTML: function( json ) { var output = '[]'; if ( ! hasContents ) { output = '[ ]'; } return output; }, // Convert a JSON object to an HTML fragment objectToHTML: function( json ) { var output = '{}'; if ( ! hasContents ) { output = '{ }'; } return output; }, // Convert a whole JSON object into a formatted HTML document. jsonToHTML: function( json, callback, uri ) { var output = ''; if ( callback ) { output += '
' + callback + ' (
'; output += '
'; } else { output += '
'; } output += this.valueToHTML( json ); output += '
'; if ( callback ) { output += '
)
'; } return this.toHTML( output, uri ); }, // Produce an error document for when parsing fails. errorPage: function( error, data, uri ) { // var output = '
' + this.stringbundle.GetStringFromName('errorParsing') + '
'; // output += '

' + this.stringbundle.GetStringFromName('docContents') + ':

';. var output = '
Error parsing JSON: ' + error.message + '
'; output += '

' + error.stack + ':

'; output += '
' + this.htmlEncode( data ) + '
'; return this.toHTML( output, uri + ' - Error' ); }, // Wrap the HTML fragment in a full document. Used by jsonToHTML and errorPage. toHTML: function( content ) { return content; } }; // Sanitize & output -- all magic from JSONView Firefox. this.jsonFormatter = new JSONFormatter(); // This regex attempts to match a JSONP structure: // * Any amount of whitespace (including unicode nonbreaking spaces) between the start of the file and the callback name. // * Callback name (any valid JavaScript function name according to ECMA-262 Edition 3 spec). // * Any amount of whitespace (including unicode nonbreaking spaces). // * Open parentheses. // * Any amount of whitespace (including unicode nonbreaking spaces). // * Either { or [, the only two valid characters to start a JSON string. // * Any character, any number of times. // * Either } or ], the only two valid closing characters of a JSON string. // * Any amount of whitespace (including unicode nonbreaking spaces). // * A closing parenthesis, an optional semicolon, and any amount of whitespace (including unicode nonbreaking spaces) until the end of the file. // This will miss anything that has comments, or more than one callback, or requires modification before use. var outputDoc = ''; // text = text.match(jsonp_regex)[1]; . var cleanData = '', callback = ''; var callback_results = jsonp_regex.exec( this.data ); if ( callback_results && callback_results.length === 3 ) { if ( this.debug ) { console.log( 'THIS IS JSONp' ); } callback = callback_results[1]; cleanData = callback_results[2]; } else { if ( this.debug ) { console.log( 'Vanilla JSON' ); } cleanData = this.data; } if ( this.debug ) { console.log( cleanData ); } // Covert, and catch exceptions on failure. try { // var jsonObj = this.nativeJSON.decode(cleanData); . var jsonObj = JSON.parse( cleanData ); if ( jsonObj ) { outputDoc = this.jsonFormatter.jsonToHTML( jsonObj, callback ); } else { throw 'There was no object!'; } } catch ( e ) { if ( this.debug ) { console.log( e ); } outputDoc = this.jsonFormatter.errorPage( e, this.data ); } var links = ''; if ( this.targetType !== undefined ) { this.idType = this.targetType; this.id = this.target; } var el; if ( this.idType === 'class' ) { el = document.getElementsByClassName( this.id ); if ( el ) { el.className += el.className ? ' jsonViewOutput' : 'jsonViewOutput'; el.innerHTML = links + outputDoc; } } else if ( this.idType === 'id' ) { el = document.getElementById( this.id ); if ( el ) { el.className += el.className ? ' jsonViewOutput' : 'jsonViewOutput'; el.innerHTML = links + outputDoc; } el.innerHTML = links + outputDoc; } var items = document.getElementsByClassName( 'collapsible' ); var len = items.length; for ( var i = 0; i < len; i ++ ) { addCollapser( items[i].parentNode ); } } else { // console.log("JSONView: this is not json, not formatting."); . } }