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

Remove the page reload when pressing reset #80

Merged
merged 13 commits into from
Mar 24, 2017
Merged
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
37 changes: 13 additions & 24 deletions app/components/ColorPicker.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import React, { PropTypes } from 'react';
import { ChromePicker } from 'react-color';
import reactCSS from 'reactcss';
import style from './ColorPicker.css';
import Icon from './Icon';
import BaseComponent from '../BaseComponent';
import Reset from './Reset';

export default class ColorPicker extends BaseComponent {

Expand Down Expand Up @@ -118,26 +118,6 @@ export default class ColorPicker extends BaseComponent {
});
};

handleReset = () => {
const name = this.props.name;
this.setDefaultState();

chrome.storage.local.get('style', result => {
delete result.style[name];
chrome.storage.local.set(result);

this.sendReload();
});
};

sendReload = () => {
chrome.tabs.query({ active: true, currentWindow: true }, tabs => {
chrome.tabs.sendMessage(tabs[0].id, {
update: 'reload'
});
});
}

render() {
const colorpicker = this.props;
const inputId = `${this.props.name}_input`;
Expand Down Expand Up @@ -192,9 +172,18 @@ export default class ColorPicker extends BaseComponent {
/>
</div>
{!this.isDefaultColor(color) ?
<div onClick={this.handleReset} className={style.resetButton}>
<Icon name={'undo'} size="24" color="221, 221, 221, 1" />
</div>
<Reset
type="color"
iconProps={{
name: 'undo',
size: '24',
color: '221, 221, 221, 1',
}}
selector={this.props.selector}
colorName={this.props.name}
colorProperty={this.props.property}
className={style.resetButton}
/>
: null}
{this.state.displayColorPicker ?
<div style={styles.popover}>
Expand Down
60 changes: 45 additions & 15 deletions app/components/Reset.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,30 @@ import BaseComponent from '../BaseComponent';
export default class Reset extends BaseComponent {

static propTypes = {
type: PropTypes.string.isRequired,
icon: PropTypes.string
type: PropTypes.oneOf(['all', 'color']).isRequired,
className: PropTypes.string,
iconProps: PropTypes.object.isRequired,
selector: PropTypes.string.isRequired,
colorName: (props, propName, componentName) => {
// This is the name given in the Config file and used to
// store the styles of this kind of node in the local storage
if (props.type === 'color' &&
((typeof props.colorName) !== 'string' ||
!props.colorName)) {
return new Error(`Invalid prop '${propName}' supplied to \
'${componentName}'. Validation failed`);
}
},
colorProperty: (props, propName, componentName) => {
// This is the name of the property in the inline-styling
// that should be reset
if (props.type === 'color' &&
((typeof props.colorProperty) !== 'string' ||
!props.colorProperty)) {
return new Error(`Invalid prop '${propName}' supplied to \
'${componentName}'. Validation failed`);
}
},
};

handleClick = () => {
Expand All @@ -16,24 +38,32 @@ export default class Reset extends BaseComponent {
display: {},
fontFamily: ''
});
this.sendReload();
}
}

sendReload = () => {
chrome.tabs.query({ active: true, currentWindow: true }, tabs => {
chrome.tabs.sendMessage(tabs[0].id, {
update: 'reload'
chrome.tabs.query({ active: true, currentWindow: true }, tabs => {
chrome.tabs.sendMessage(tabs[0].id, {
update: 'reset',
selector: this.props.selector,
});
});
} else if (this.props.type === 'color') {
const name = this.props.colorName;
chrome.storage.local.get('style', result => {
delete result.style[name];
chrome.storage.local.set(result);
});
});
chrome.tabs.query({ active: true, currentWindow: true }, tabs => {
chrome.tabs.sendMessage(tabs[0].id, {
update: 'style',
selector: this.props.selector,
property: this.props.colorProperty,
});
});
}
}

render() {
return (
<div onClick={this.handleClick}>
{ this.props.icon ?
<Icon name={this.props.icon} size="24" />
: null }
<div onClick={this.handleClick} className={this.props.className}>
<Icon {...this.props.iconProps} />
{ this.props.type === 'all' ?
<span>Reset All</span>
: null }
Expand Down
22 changes: 21 additions & 1 deletion app/components/ResetBar.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React from 'react';
import style from './ResetBar.css';
import Icon from './Icon.js';
import Config from './Options/Config';
import Reset from '../components/Reset';
import BaseComponent from '../BaseComponent';

Expand All @@ -12,10 +13,29 @@ export default class ResetBar extends BaseComponent {
}

render() {
let resetAllSelector = '';
Config.groups.forEach(group => {
group.options.forEach(option => {
if (!Object.hasOwnProperty.call(option, 'selector')) {
return;
}
const localSelectorArray = option.selector;
if (resetAllSelector) {
// Only do this if it's not the first time
resetAllSelector += ',';
}
resetAllSelector += localSelectorArray.join(',');
});
});

return (
<div className={style.resetBar}>
<div className={style.resetButton}>
<Reset type="all" icon="undo" />
<Reset
type="all"
iconProps={{ name: 'undo', size: '24' }}
selector={resetAllSelector}
/>
</div>
<div className={style.suggestions} onClick={this.handleSuggestionsClick}>
<div className={style.suggestionsIcon}>
Expand Down
34 changes: 4 additions & 30 deletions app/components/ToggleDisplay.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export default class ToggleDisplay extends BaseComponent {
visible: true,
helpers: this.props.helpers
};
this.addStorageListener();
this.checkIfStorageAlreadyExists();
}

componentDidUpdate = () => {
Expand All @@ -47,11 +47,11 @@ export default class ToggleDisplay extends BaseComponent {
});
}

checkIfStorageAlreadyExists(name) {
checkIfStorageAlreadyExists() {
const name = this.props.name;
chrome.storage.local.get(result => {
if (!{}.hasOwnProperty.call(result, 'display')) {
chrome.storage.local.set({ display: {} });
return;
return chrome.storage.local.set({ display: {} });
}

if ({}.hasOwnProperty.call(result.display, name)) {
Expand All @@ -60,24 +60,6 @@ export default class ToggleDisplay extends BaseComponent {
});
}

addStorageListener = () => {
this.checkIfStorageAlreadyExists(this.props.name);

// Reset toggle display when reset button is hit
chrome.storage.onChanged.addListener(changes => {
try {
const newValue = changes.display.newValue;

if (Object.keys(newValue).length === 0 && newValue.constructor === Object) {
this.setState({ visible: true });
this.sendReload();
}
} catch (e) {
this.checkIfStorageAlreadyExists();
}
});
}

runHelpers = () => {
if (this.state.helpers) {
chrome.storage.local.get('display', result => {
Expand Down Expand Up @@ -136,14 +118,6 @@ export default class ToggleDisplay extends BaseComponent {
}
}

sendReload = () => {
chrome.tabs.query({ active: true, currentWindow: true }, tabs => {
chrome.tabs.sendMessage(tabs[0].id, {
update: 'reload'
});
});
}

render() {
const toggle = cx({
toggle: true,
Expand Down
85 changes: 67 additions & 18 deletions chrome/extension/background.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,13 @@ function injectCSS(tabId, style) {
const color = prop.color;
const property = jsNameToCssName(prop.property);
const rgba = `rgba(${color.r},${color.g},${color.b},${color.a})`;
const css = `${prop.selector} { ${property}: ${rgba} }`;
let selector = prop.selector;
if (selector) {
selector = selector.split(',').map(singleSelector => (
`body.removable-initial-styles ${singleSelector}`
)).join(',');
}
const css = `${selector} { ${property}: ${rgba} }`;
chrome.tabs.insertCSS(tabId, {
code: css,
runAt: 'document_start'
Expand All @@ -35,9 +41,15 @@ function injectCSS(tabId, style) {

function injectDisplay(tabId, display) {
Object.keys(display).forEach(key => {
const name = display[key];
const visible = name.visible ? 'block' : 'none';
const css = `${name.selector} { display: ${visible} }`;
const prop = display[key];
const visible = prop.visible ? 'block' : 'none';
let selector = prop.selector;
if (selector) {
selector = selector.split(',').map(singleSelector => (
`body.removable-initial-styles ${singleSelector}`
)).join(',');
}
const css = `${selector} { display: ${visible} }`;
chrome.tabs.insertCSS(tabId, {
code: css,
runAt: 'document_start'
Expand All @@ -46,13 +58,42 @@ function injectDisplay(tabId, display) {
}

function injectFontFamily(tabId, fontFamily) {
const code = `body { font-family: ${fontFamily} !important }`;
const code = `body.removable-initial-styles { font-family: ${fontFamily} !important }`;
chrome.tabs.insertCSS(tabId, {
code,
runAt: 'document_start'
});
}

function injectTempStylesClass(tabId) {
// We use a mutation observer to be able to modify the DOM
// as soon as the body element is created but before anything is
// rendered so as to avoid FOUC
const code = (`
const observer = new MutationObserver(function(mutations) {
// Use .some instead of .forEach as .forEach can't be cancelled and
// .some cancels as soon as a truthy return value is given
mutations.some(function(mutation) {
if (mutation.target.nodeName === 'HTML' && mutation.addedNodes &&
mutation.addedNodes.length && mutation.addedNodes[0].nodeName === 'BODY') {
// The body element was created in the dom
const body = mutation.addedNodes[0];
body.classList.add('removable-initial-styles');
// Stop observer listening
observer.disconnect();
// Stop the loop by returning true to .some
return true;
}
});
});

const config = {childList: true, subtree: true};
observer.observe(document, config);
`);

chrome.tabs.executeScript(tabId, { code, runAt: 'document_start' });
}

function updateBadge() {
chrome.runtime.onMessage.addListener((request) => {
if (request.badge || request.badge === 0) {
Expand All @@ -68,22 +109,30 @@ function updateBadge() {
});
}

const arrowURLs = ['^https://www\\.chess\\.com'];
function onLoading(tabId) {
// Get cached styles to inject before the DOM loads on each page load
chrome.storage.local.get(storage => {
injectCSS(tabId, storage.style || {});
injectDisplay(tabId, storage.display || {});
injectFontFamily(tabId, storage.fontFamily || '');
});
// Insert the temp styles class in body so initial css shows
injectTempStylesClass(tabId);

chrome.tabs.onUpdated.addListener(async (tabId, changeInfo, tab) => {
if (changeInfo.status === 'loading' && tab.url.match(arrowURLs.join('|'))) {
// Get cached styles to inject before the DOM loads on each page load
chrome.storage.local.get(storage => {
injectCSS(tabId, storage.style || {});
injectDisplay(tabId, storage.display || {});
injectFontFamily(tabId, storage.fontFamily || '');
});
updateBadge();

if (chrome.runtime.lastError) return;

updateBadge();
// Loads content script to manipulate the dom in real time
loadScript('handleLiveChanges', tabId);
}

if (chrome.runtime.lastError) return;
const arrowURLs = ['^https://www\\.chess\\.com'];

// Loads content script to manipulate the dom in real time
loadScript('handleLiveChanges', tabId);
chrome.tabs.onUpdated.addListener(async (tabId, changeInfo, tab) => {
if (tab.url.match(arrowURLs.join('|'))) {
if (changeInfo.status === 'loading') {
onLoading(tabId);
}
}
});
Loading