Skip to content

Commit

Permalink
Move to using WebExtension APIs for CSS injection
Browse files Browse the repository at this point in the history
This is to prevent it being blocked on sites with CSP headers.
  • Loading branch information
nicole-ashley committed Feb 4, 2018
1 parent 64eae22 commit afd0f57
Show file tree
Hide file tree
Showing 47 changed files with 1,160 additions and 1,165 deletions.
1 change: 0 additions & 1 deletion gulpfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@ gulp.task('build:dist', ['configs', 'icons', 'scripts:dist']);

gulp.task('release', ['build:dist'], () => {
const manifest = require(`${BUILD_DIR}/manifest.json`);

return gulp.src(`${BUILD_DIR}/**/*`)
.pipe(zip(`json-formatter-${manifest.version}.zip`))
.pipe(gulp.dest(RELEASE_DIR));
Expand Down
6 changes: 5 additions & 1 deletion src/js/background.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ browser.storage.local.set({appVersion: browser.runtime.getManifest().version});
listen((port, msg) => {
let jsonpFunctionName = null;
let validJsonText;
let tab = port.sender.tab;

if (msg.type === 'SENDING TEXT') {
// Try to parse as JSON
Expand Down Expand Up @@ -79,9 +80,10 @@ listen((port, msg) => {
}

// If still running, we now have obj, which is valid JSON.
browser.tabs.insertCSS(tab.id, {code: require('../sass/content.scss')});

// Ensure it's not a number or string (technically valid JSON, but no point prettifying it)
if (typeof obj !== 'object' && typeof obj !== 'array') {
if (typeof obj !== 'object') {
port.postMessage(['NOT JSON', 'technically JSON but not an object or array']);
port.disconnect();
return;
Expand All @@ -101,5 +103,7 @@ listen((port, msg) => {
browser.storage.sync.set({theme: msg.theme}, () => {
port.postMessage({type: 'STORED THEME', themeName: msg.theme});
});
} else if (msg.type === 'INSERT CSS') {
browser.tabs.insertCSS(tab.id, {code: msg.code});
}
});
23 changes: 10 additions & 13 deletions src/js/content.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { connect } from './lib/messaging';
import { enableTheming } from './lib/theme-switcher';
import browser from "./lib/browser";

let jfContent;
let pre;
Expand Down Expand Up @@ -32,13 +33,6 @@ port.onMessage.addListener(function(message) {
// 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';
document.head.appendChild(jfStyleEl);

jfStyleEl.insertAdjacentHTML('beforeend', require('../sass/content.scss'));

jfContent.innerHTML = '<p id="formattingMsg"><svg id="spinner" width="16" height="16" viewBox="0 0 300 300" xmlns="http://www.w3.org/2000/svg" version="1.1"><path d="M 150,0 a 150,150 0 0,1 106.066,256.066 l -35.355,-35.355 a -100,-100 0 0,0 -70.711,-170.711 z" fill="#3d7fe6"></path></svg> Formatting...</p>';

const formattingMsg = document.getElementById('formattingMsg');
Expand All @@ -57,11 +51,14 @@ port.onMessage.addListener(function(message) {
pre.hidden = true;

// Export parsed JSON for easy access in console
// Only works if target page's CSP allows it
setTimeout(function() {
const script = document.createElement('script');
script.innerHTML = `window.json=${message[2]};`;
script.innerHTML = `
window.json=${message[2]};
console.info("JSON Formatter: Type 'json' to inspect.");
`;
document.head.appendChild(script);
console.info(`JSON Formatter: Type 'json' to inspect.`);
}, 100);

// Attach event handlers
Expand Down Expand Up @@ -203,10 +200,10 @@ function collapse(elements) {
// Generate comment text eg '4 items'
const comment = count + (count === 1 ? ' item' : ' items');
// Add CSS that targets it
jfStyleEl.insertAdjacentHTML(
'beforeend',
`\n#keyValueOrValue${lastKeyValueOrValueIdGiven}.collapsed:after{content:" // ${comment}"}`
);
port.postMessage({
type: 'INSERT CSS',
code: `#keyValueOrValue${lastKeyValueOrValueIdGiven}.collapsed:after{content:" // ${comment}"}`
});
}
}
}
Expand Down
3 changes: 3 additions & 0 deletions src/js/lib/browser.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ export default {
},
get storage() {
return getBrowser().storage;
},
get tabs() {
return getBrowser().tabs;
}
};

Expand Down
39 changes: 14 additions & 25 deletions src/js/lib/theme-switcher.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { themes } from './themes';
import { connect } from "./messaging";
import {themes} from './themes';
import {connect} from "./messaging";

const transitionStyles = require('../../sass/transition.scss');
let port, themeStyleElement, transitionStyleElement;
let port, transitionStylesInject;

export function enableTheming() {
port = connect();
Expand Down Expand Up @@ -68,36 +68,25 @@ function generateOptionsHTML() {

function switchToTheme(themeName) {
themeName = themes[themeName] ? themeName : themes.default;
const theme = themes[themeName];
const element = getThemeElement();

if (element.innerHTML) {
insertTransitionThemes();
}
if (element.innerHTML !== theme.styles) {
element.innerHTML = theme.styles;
}
document.body.className = `theme-${themeName}`;

const themeSelect = getThemeSelect();
const themeSelectOption = themeSelect && themeSelect.querySelector(`[value="${themeName}"]`);
if (themeSelectOption) {
themeSelectOption.selected = true;
}
}

function getThemeElement() {
if (!themeStyleElement) {
themeStyleElement = document.createElement('style');
document.head.appendChild(themeStyleElement);
}

return themeStyleElement;
insertTransitionStylesOnce();
}

function insertTransitionThemes() {
if (!transitionStyleElement) {
transitionStyleElement = document.createElement('style');
transitionStyleElement.innerHTML = transitionStyles;
document.head.appendChild(transitionStyleElement);
function insertTransitionStylesOnce() {
if (!transitionStylesInject) {
transitionStylesInject = true;
window.setTimeout(() => {
port.postMessage({
type: 'INSERT CSS',
code: transitionStyles
});
}, 1000);
}
}
108 changes: 36 additions & 72 deletions src/js/lib/themes.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,182 +2,146 @@ export const themes = {
default: 'dawn',
chrome: {
name: 'Chrome',
type: 'Light',
styles: require('../../sass/themes/chrome.scss')
type: 'Light'
},
clouds: {
name: 'Clouds',
type: 'Light',
styles: require('../../sass/themes/clouds.scss')
type: 'Light'
},
crimsonEditor: {
name: 'Crimson Editor',
type: 'Light',
styles: require('../../sass/themes/crimson-editor.scss')
type: 'Light'
},
dawn: {
name: 'Dawn',
type: 'Light',
styles: require('../../sass/themes/dawn.scss')
type: 'Light'
},
dreamweaver: {
name: 'Dreamweaver',
type: 'Light',
styles: require('../../sass/themes/dreamweaver.scss')
type: 'Light'
},
eclipse: {
name: 'Eclipse',
type: 'Light',
styles: require('../../sass/themes/eclipse.scss')
type: 'Light'
},
github: {
name: 'GitHub',
type: 'Light',
styles: require('../../sass/themes/github.scss')
type: 'Light'
},
iplastic: {
name: 'iPlastic',
type: 'Light',
styles: require('../../sass/themes/iplastic.scss')
type: 'Light'
},
katzenMilch: {
name: 'KatzenMilch',
type: 'Light',
styles: require('../../sass/themes/katzen-milch.scss')
type: 'Light'
},
kuroir: {
name: 'Kuroir',
type: 'Light',
styles: require('../../sass/themes/kuroir.scss')
type: 'Light'
},
solarizedLight: {
name: 'Solarized Light',
type: 'Light',
styles: require('../../sass/themes/solarized-light.scss')
type: 'Light'
},
sqlServer: {
name: 'SQL Server',
type: 'Light',
styles: require('../../sass/themes/sql-server.scss')
type: 'Light'
},
textmate: {
name: 'TextMate',
type: 'Light',
styles: require('../../sass/themes/textmate.scss')
type: 'Light'
},
tomorrow: {
name: 'Tomorrow',
type: 'Light',
styles: require('../../sass/themes/tomorrow.scss')
type: 'Light'
},
xcode: {
name: 'XCode',
type: 'Light',
styles: require('../../sass/themes/xcode.scss')
type: 'Light'
},
ambiance: {
name: 'Ambiance',
type: 'Dark',
styles: require('../../sass/themes/ambiance.scss')
type: 'Dark'
},
chaos: {
name: 'Chaos',
type: 'Dark',
styles: require('../../sass/themes/chaos.scss')
type: 'Dark'
},
cloudsMidnight: {
name: 'Clouds Midnight',
type: 'Dark',
styles: require('../../sass/themes/clouds-midnight.scss')
type: 'Dark'
},
cobalt: {
name: 'Cobalt',
type: 'Dark',
styles: require('../../sass/themes/cobalt.scss')
type: 'Dark'
},
gob: {
name: 'Gob',
type: 'Dark',
styles: require('../../sass/themes/gob.scss')
type: 'Dark'
},
gruvbox: {
name: 'Gruvbox',
type: 'Dark',
styles: require('../../sass/themes/gruvbox.scss')
type: 'Dark'
},
idleFingers: {
name: 'idle Fingers',
type: 'Dark',
styles: require('../../sass/themes/idle-fingers.scss')
type: 'Dark'
},
krTheme: {
name: 'krTheme',
type: 'Dark',
styles: require('../../sass/themes/kr-theme.scss')
type: 'Dark'
},
merbivore: {
name: 'Merbivore',
type: 'Dark',
styles: require('../../sass/themes/merbivore.scss')
type: 'Dark'
},
merbivoreSoft: {
name: 'Merbivore Soft',
type: 'Dark',
styles: require('../../sass/themes/merbivore-soft.scss')
type: 'Dark'
},
monoIndustrial: {
name: 'Mono Industrial',
type: 'Dark',
styles: require('../../sass/themes/mono-industrial.scss')
type: 'Dark'
},
monokai: {
name: 'Monokai',
type: 'Dark',
styles: require('../../sass/themes/monokai.scss')
type: 'Dark'
},
pastelOnDark: {
name: 'Pastel on dark',
type: 'Dark',
styles: require('../../sass/themes/pastel-on-dark.scss')
type: 'Dark'
},
solarizedDark: {
name: 'Solarized Dark',
type: 'Dark',
styles: require('../../sass/themes/solarized-dark.scss')
type: 'Dark'
},
terminal: {
name: 'Terminal',
type: 'Dark',
styles: require('../../sass/themes/terminal.scss')
type: 'Dark'
},
tomorrowNight: {
name: 'Tomorrow Night',
type: 'Dark',
styles: require('../../sass/themes/tomorrow-night.scss')
type: 'Dark'
},
tomorrowNightBlue: {
name: 'Tomorrow Night Blue',
type: 'Dark',
styles: require('../../sass/themes/tomorrow-night-blue.scss')
type: 'Dark'
},
tomorrowNightBright: {
name: 'Tomorrow Night Bright',
type: 'Dark',
styles: require('../../sass/themes/tomorrow-night-bright.scss')
type: 'Dark'
},
tomorrowNightEighties: {
name: 'Tomorrow Night ’80s',
type: 'Dark',
styles: require('../../sass/themes/tomorrow-night-eighties.scss')
type: 'Dark'
},
twilight: {
name: 'Twilight',
type: 'Dark',
styles: require('../../sass/themes/twilight.scss')
type: 'Dark'
},
vibrantInk: {
name: 'Vibrant Ink',
type: 'Dark',
styles: require('../../sass/themes/vibrant-ink.scss')
type: 'Dark'
}
};
2 changes: 1 addition & 1 deletion src/manifest.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "JSON Formatter",
"version": "0.10.0",
"version": "0.11.0",
"manifest_version": 2,
"description": "Makes JSON easy to read. Open source.",
"homepage_url": "https://github.com/nikrolls/json-formatter",
Expand Down
2 changes: 2 additions & 0 deletions src/sass/content.scss
Original file line number Diff line number Diff line change
Expand Up @@ -248,3 +248,5 @@ span {
* {
font-smoothing: antialiased;
}

@import 'themes/all';
Loading

0 comments on commit afd0f57

Please sign in to comment.