Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pr/fix extension for plain text json html content type #89

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 64 additions & 33 deletions extension/js/content.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@
(function() {

"use strict" ;

var jfContent,
pre,
jfStyleEl,
Expand All @@ -48,31 +47,31 @@
exitedNotJsonTime,
displayedFormattedJsonTime
;

// Open the port "jf" now, ready for when we need it
// console.time('established port') ;
port = chrome.extension.connect({name: 'jf'}) ;

// Add listener to receive response from BG when ready
port.onMessage.addListener( function (msg) {
// console.log('Port msg received', msg[0], (""+msg[1]).substring(0,30)) ;

switch (msg[0]) {
case 'NOT JSON' :
pre.hidden = false ;
// console.log('Unhidden the PRE') ;
document.body.removeChild(jfContent) ;
exitedNotJsonTime = +(new Date()) ;
break ;

case 'FORMATTING' :
isJsonTime = +(new Date()) ;

// It is JSON, and it's now being formatted in the background worker.

// Clear the slowAnalysisTimeout (if the BG worker had taken longer than 1s to respond with an answer to whether or not this is JSON, then it would have fired, unhiding the PRE... But now that we know it's JSON, we can clear this timeout, ensuring the PRE stays hidden.)
clearTimeout(slowAnalysisTimeout) ;

// Insert CSS
jfStyleEl = document.createElement('style') ;
jfStyleEl.id = 'jfStyleEl' ;
Expand All @@ -83,7 +82,7 @@
'beforeend',
'body{-webkit-user-select:text;overflow-y:scroll !important;margin:0;position:relative}#optionBar{-webkit-user-select:none;display:block;position:absolute;top:9px;right:17px}#buttonFormatted,#buttonPlain{-webkit-border-radius:2px;-webkit-box-shadow:0px 1px 3px rgba(0,0,0,0.1);-webkit-user-select:none;background:-webkit-linear-gradient(#fafafa, #f4f4f4 40%, #e5e5e5);border:1px solid #aaa;color:#444;font-size:12px;margin-bottom:0px;min-width:4em;padding:3px 0;position:relative;z-index:10;display:inline-block;width:80px;text-shadow:1px 1px rgba(255,255,255,0.3)}#buttonFormatted{margin-left:0;border-top-left-radius:0;border-bottom-left-radius:0}#buttonPlain{margin-right:0;border-top-right-radius:0;border-bottom-right-radius:0;border-right:none}#buttonFormatted:hover,#buttonPlain:hover{-webkit-box-shadow:0px 1px 3px rgba(0,0,0,0.2);background:#ebebeb -webkit-linear-gradient(#fefefe, #f8f8f8 40%, #e9e9e9);border-color:#999;color:#222}#buttonFormatted:active,#buttonPlain:active{-webkit-box-shadow:inset 0px 1px 3px rgba(0,0,0,0.2);background:#ebebeb -webkit-linear-gradient(#f4f4f4, #efefef 40%, #dcdcdc);color:#333}#buttonFormatted.selected,#buttonPlain.selected{-webkit-box-shadow:inset 0px 1px 5px rgba(0,0,0,0.2);background:#ebebeb -webkit-linear-gradient(#e4e4e4, #dfdfdf 40%, #dcdcdc);color:#333}#buttonFormatted:focus,#buttonPlain:focus{outline:0}#jsonpOpener,#jsonpCloser{padding:4px 0 0 8px;color:#000;margin-bottom:-6px}#jsonpCloser{margin-top:0}#formattedJson{padding-left:28px;padding-top:6px}pre{padding:36px 5px 5px 5px}.kvov{display:block;padding-left:20px;margin-left:-20px;position:relative}.collapsed{white-space:nowrap}.collapsed>.blockInner{display:none}.collapsed>.ell:after{content:"…";font-weight:bold}.collapsed>.ell{margin:0 4px;color:#888}.collapsed .kvov{display:inline}.e{width:20px;height:18px;display:block;position:absolute;left:-2px;top:1px;z-index:5;background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAD1JREFUeNpiYGBgOADE%2F3Hgw0DM4IRHgSsDFOzFInmMAQnY49ONzZRjDFiADT7dMLALiE8y4AGW6LoBAgwAuIkf%2F%2FB7O9sAAAAASUVORK5CYII%3D");background-repeat:no-repeat;background-position:center center;display:block;opacity:0.15}.collapsed>.e{-webkit-transform:rotate(-90deg);width:18px;height:20px;left:0px;top:0px}.e:hover{opacity:0.35}.e:active{opacity:0.5}.collapsed .kvov .e{display:none}.blockInner{display:block;padding-left:24px;border-left:1px dotted #bbb;margin-left:2px}#formattedJson,#jsonpOpener,#jsonpCloser{color:#333;font:13px/18px monospace}#formattedJson{color:#444}.b{font-weight:bold}.s{color:#0B7500;word-wrap:break-word}a:link,a:visited{text-decoration:none;color:inherit}a:hover,a:active{text-decoration:underline;color:#050}.bl,.nl,.n{font-weight:bold;color:#1A01CC}.k{color:#000}#formattingMsg{font:13px "Lucida Grande","Segoe UI","Tahoma";padding:10px 0 0 8px;margin:0;color:#333}#formattingMsg>svg{margin:0 7px;position:relative;top:1px}[hidden]{display:none !important}span{white-space:pre-wrap}@-webkit-keyframes spin{from{-webkit-transform:rotate(0deg)}to{-webkit-transform:rotate(360deg)}}#spinner{-webkit-animation:spin 2s 0 infinite}*{-webkit-font-smoothing:antialiased}'
) ;

// Add custom font name if set - FROM FUTURE
// if (typeof settings.fontName === 'string') {
// jfStyleEl.insertAdjacentHTML(
Expand All @@ -104,13 +103,13 @@
setTimeout(function(){
formattingMsg.hidden = false ;
}, 250) ;


// Create option bar
var optionBar = document.createElement('div') ;
optionBar.id = 'optionBar' ;


// Show options link, if needed - FROM FUTURE
// if (settings.enableOptionsLink) {
// var optionsLink = document.createElement('a') ;
Expand All @@ -120,7 +119,7 @@
// optionsLink.target = '_BLANK' ;
// optionBar.appendChild(optionsLink) ;
// }

// Create toggleFormat button
var buttonPlain = document.createElement('button'),
buttonFormatted = document.createElement('button') ;
Expand All @@ -129,7 +128,7 @@
buttonFormatted.id = 'buttonFormatted' ;
buttonFormatted.innerText = 'Parsed' ;
buttonFormatted.classList.add('selected') ;

var plainOn = false ;
buttonPlain.addEventListener(
'click',
Expand All @@ -146,7 +145,7 @@
},
false
) ;

buttonFormatted.addEventListener(
'click',
function () {
Expand All @@ -162,7 +161,7 @@
},
false
) ;

// Put it in optionBar
optionBar.appendChild(buttonPlain) ;
optionBar.appendChild(buttonFormatted) ;
Expand All @@ -173,16 +172,16 @@
generalClick,
false // No need to propogate down
) ;

// Put option bar in DOM
document.body.insertBefore(optionBar, pre) ;

break ;

case 'FORMATTED' :
// Insert HTML content
jfContent.innerHTML = msg[1] ;

displayedFormattedJsonTime = Date.now() ;

// Log times
Expand All @@ -201,22 +200,44 @@
}, 100) ;

break ;

default :
throw new Error('Message not understood: ' + msg[0]) ;
}
});

// console.timeEnd('established port') ;

function determineCorrectPre(bodyChildren){
var manualPre, plainTextPageWithTextHtmlHeader;

// This could be a 'plain text' page with a text/html response header --
// in that case, it's just a body with text inside of it
plainTextPageWithTextHtmlHeader = (
bodyChildren.length === 1 && bodyChildren[0].nodeName === "#text"
);

if(plainTextPageWithTextHtmlHeader){
// Manually make own pre, clear out body
manualPre = document.createElement('pre');
manualPre.style = "word-wrap: break-word; white-space: pre-wrap;";
manualPre.innerText = bodyChildren[0].textContent;
document.body.innerHTML = "";
document.body.appendChild(manualPre);
return manualPre;
}

// Otherwise probably not an json response -- continue on as normal
return bodyChildren[0];
}

function ready () {

domReadyTime = Date.now() ;

// First, check if it's a PRE and exit if not
var bodyChildren = document.body.childNodes ;
pre = bodyChildren[0] ;
pre = determineCorrectPre(bodyChildren);
var jsonLength = (pre && pre.innerText || "").length ;
if (
bodyChildren.length !== 1 ||
Expand All @@ -226,22 +247,32 @@
// console.log('Not even text (or longer than 3MB); exiting') ;
// console.log(bodyChildren.length,pre.tagName, pre.innerText.length) ;

// Give some Feedback in the console as to why it may not be working
// if first node is text, JSON could contain an unsanitized html
// tag
if(bodyChildren.length > 1 && pre.nodeName === '#text'){
console.log('JSON Formatter: Body has ' + bodyChildren.length +
' nodes -- is json Valid? Try inspecting document.body.childNodes' +
' in the console.'
);
}

// Disconnect the port (without even having used it)
port.disconnect() ;

// EXIT POINT: NON-PLAIN-TEXT PAGE (or longer than 3MB)
}
else {
// This is a 'plain text' page (just a body with one PRE child).
// It might be JSON/JSONP, or just some other kind of plain text (eg CSS).

// Hide the PRE immediately (until we know what to do, to prevent FOUC)
pre.hidden = true ;
//console.log('It is text; hidden pre at ') ;
slowAnalysisTimeout = setTimeout(function(){
pre.hidden = false ;
}, 1000) ;

// Send the contents of the PRE to the BG script
// Add jfContent DIV, ready to display stuff
jfContent = document.createElement('div') ;
Expand All @@ -254,7 +285,7 @@
text: pre.innerText,
length: jsonLength
});

// Now, this script will just wait to receive anything back via another port message. The returned message will be something like "NOT JSON" or "IS JSON"
}

Expand All @@ -267,7 +298,7 @@
}
});
}

document.addEventListener("DOMContentLoaded", ready, false);

var lastKvovIdGiven = 0 ;
Expand Down Expand Up @@ -328,7 +359,7 @@

if (ev.which === 1) {
var elem = ev.target ;

if (elem.className === 'e') {
// It's a click on an expander.

Expand All @@ -340,7 +371,7 @@
scrollTop = document.body.scrollTop,
parentSiblings
;

// Expand or collapse
if (parent.classList.contains('collapsed')) {
// EXPAND
Expand Down Expand Up @@ -374,10 +405,10 @@
}

// console.log('Scrolltop HAS changed. document.body.scrollTop is now '+document.body.scrollTop+'; was '+scrollTop) ;

// The body has got a bit shorter.
// We need to increase the body height by a bit (by increasing the bottom margin on the jfContent div). The amount to increase it is whatever is the difference between our previous scrollTop and our new one.

// Work out how much more our target scrollTop is than this.
var difference = scrollTop - document.body.scrollTop + 8 ; // it always loses 8px; don't know why

Expand All @@ -387,7 +418,7 @@

// Now change the scrollTop back to what it was
document.body.scrollTop = scrollTop ;

return ;
}
}
Expand Down
2 changes: 1 addition & 1 deletion extension/manifest.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "JSON Formatter",
"version": "0.6.0",
"version": "0.7.0",
"manifest_version": 2,
"description": "Makes JSON easy to read. Open source.",
"homepage_url": "https://github.com/callumlocke/json-formatter",
Expand Down