Add eslint w/ Google styles, restyle

This commit is contained in:
Ilya Ig. Petrov 2016-11-29 09:27:15 -08:00
parent 9ef8939127
commit 77a88e5778
9 changed files with 1138 additions and 975 deletions

1
.gitignore vendored
View File

@ -1,2 +1,3 @@
node_modules
npm-debug.log
.swp

View File

@ -0,0 +1,27 @@
module.exports = {
"extends": ["eslint:recommended", "google"],
"plugins": [
//"hapi"
],
"env": {
"browser": true,
"webextensions": true,
"es6": true
},
"globals": {
"chrome": true
},
"parserOptions": {
"sourceType": "script",
"ecmaFeatures": {
"impliedStrict": false
}
},
"rules": {
"strict": ["error", "global"],
"no-console": "off",
"padded-blocks": "off",
"require-jsdoc": "off"
//"hapi/hapi-scope-start": ["warn"]
}
};

View File

@ -1,152 +1,169 @@
'use strict';
// Shows user browserAction icon if any part of the current site is being blocked and proxied.
/*
In what moment the title of the previous icon is cleared?
By my observations it usually takes place near tabs.onUpdate of tab status to "loading".
So if you set a title earlier it may be cleared by browser.
It pertains not only to page refesh but to newly opened pages too.
Also on loosing title see:
https://github.com/ilyaigpetrov/repository-for-chrome-bugs/blob/master/browserAction-title-lost-after-setting/background.js
Crazy parallel Chrome.
**/
window.chrome.browserAction.setBadgeBackgroundColor({
color: '#db4b2f'
});
window.tabWithError2ip = {}; // For errors only: Error? -> Check this IP!
{
const _tabCallbacks = {};
function afterTabUpdated(tabId, cb) {
if (_tabCallbacks[tabId])
_tabCallbacks[tabId].push(cb);
else _tabCallbacks[tabId] = [cb];
}
function onTabUpdate(tabId) {
if (_tabCallbacks[tabId]) {
_tabCallbacks[tabId].map( f => f() );
delete _tabCallbacks[tabId];
}
}
chrome.tabs.onUpdated.addListener( onTabUpdate );
function isInsideTabWithIp(requestDetails) {
return requestDetails.tabId !== -1 && requestDetails.ip
}
chrome.webRequest.onErrorOccurred.addListener(
(requestDetails) =>
isInsideTabWithIp(requestDetails) &&
(
isProxiedAndInformed(requestDetails) || requestDetails.type === 'main_frame' && ( window.tabWithError2ip[requestDetails.tabId] = requestDetails.ip )
),
{ urls: ['<all_urls>'] }
);
chrome.tabs.onRemoved.addListener( (tabId) => { onTabUpdate(tabId); delete window.tabWithError2ip[tabId] } );
function updateTitle(requestDetails, cb) {
chrome.browserAction.getTitle(
{ tabId: requestDetails.tabId },
(title) => {
const ifTitleSetAlready = /\n/.test(title);
const proxyHost = window.antiCensorRu.getPacProvider().proxyIps[ requestDetails.ip ];
const hostname = new URL( requestDetails.url ).hostname;
let ifShouldUpdateTitle = false;
const indent = ' ';
const proxyTitle = 'Прокси:';
if (!ifTitleSetAlready) {
title = 'Разблокированы:\n'+ indent + hostname +'\n'+ proxyTitle +'\n'+ indent + proxyHost;
ifShouldUpdateTitle = true;
chrome.browserAction.setBadgeText({
tabId: requestDetails.tabId,
text: requestDetails.type === 'main_frame' ? '1' : '%1'
});
}
else {
const hostsProxiesPair = title.split(proxyTitle);
if (hostsProxiesPair[1].indexOf(proxyHost) === -1) {
title = title.replace(hostsProxiesPair[1], hostsProxiesPair[1] +'\n'+ indent + proxyHost);
ifShouldUpdateTitle = true;
}
if (hostsProxiesPair[0].indexOf(hostname) === -1) {
title = title.replace(proxyTitle, indent + hostname +'\n'+ proxyTitle);
ifShouldUpdateTitle = true;
const _cb = cb;
cb = () => chrome.browserAction.getBadgeText(
{tabId: requestDetails.tabId},
(result) => {
chrome.browserAction.setBadgeText(
{
tabId: requestDetails.tabId,
text: ( isNaN( result.charAt(0) ) && result.charAt(0) || '' ) + (hostsProxiesPair[0].split('\n').length - 1)
}
);
return _cb();
}
);
}
}
if (ifShouldUpdateTitle) {
chrome.browserAction.setTitle({
title: title,
tabId: requestDetails.tabId
});
}
return cb();
}
);
}
let previousUpdateTitleFinished = Promise.resolve();
function isProxiedAndInformed(requestDetails) {
if ( !(requestDetails.ip && antiCensorRu.isProxied( requestDetails.ip )) ) {
return false;
}
const ifMainFrame = requestDetails.type === 'main_frame';
previousUpdateTitleFinished = previousUpdateTitleFinished.then(
() => new Promise(
(resolve) => {
const cb = () => updateTitle( requestDetails, resolve );
return ifMainFrame ? afterTabUpdated(requestDetails.tabId, cb) : cb();
}
)
);
return true;
}
chrome.webRequest.onResponseStarted.addListener(
(requestDetails) => isInsideTabWithIp(requestDetails) && isProxiedAndInformed(requestDetails),
{ urls: ['<all_urls>'] }
);
}
'use strict';
// Shows user browserAction icon if any part of the current site is being
// blocked and proxied.
/*
In what moment the title of the previous icon is cleared?
By my observations it usually takes place near tabs.onUpdate of tab status
to "loading".
So if you set a title earlier it may be cleared by browser.
It pertains not only to page refesh but to newly opened pages too.
Also on loosing title see:
https://github.com/ilyaigpetrov/repository-for-chrome-bugs/blob/master/browserAction-title-lost-after-setting/background.js
Crazy parallel Chrome.
**/
window.chrome.browserAction.setBadgeBackgroundColor({
color: '#db4b2f',
});
window.tabWithError2ip = {}; // For errors only: Error? -> Check this IP!
{
const _tabCallbacks = {};
function afterTabUpdated(tabId, cb) {
if (_tabCallbacks[tabId])
_tabCallbacks[tabId].push(cb);
else _tabCallbacks[tabId] = [cb];
}
function onTabUpdate(tabId) {
if (_tabCallbacks[tabId]) {
_tabCallbacks[tabId].map( (f) => f() );
delete _tabCallbacks[tabId];
}
}
chrome.tabs.onUpdated.addListener( onTabUpdate );
function isInsideTabWithIp(requestDetails) {
return requestDetails.tabId !== -1 && requestDetails.ip;
}
chrome.webRequest.onErrorOccurred.addListener(
(requestDetails) =>
isInsideTabWithIp(requestDetails) &&
(
isProxiedAndInformed(requestDetails)
|| requestDetails.type === 'main_frame'
&& (window.tabWithError2ip[requestDetails.tabId] = requestDetails.ip)
),
{urls: ['<all_urls>']}
);
chrome.tabs.onRemoved.addListener( (tabId) => {
onTabUpdate(tabId);
delete window.tabWithError2ip[tabId];
});
function updateTitle(requestDetails, cb) {
chrome.browserAction.getTitle(
{tabId: requestDetails.tabId},
(title) => {
const ifTitleSetAlready = /\n/.test(title);
const proxyHost = window.antiCensorRu.getPacProvider()
.proxyIps[requestDetails.ip];
const hostname = new URL( requestDetails.url ).hostname;
let ifShouldUpdateTitle = false;
const indent = ' ';
const proxyTitle = 'Прокси:';
if (!ifTitleSetAlready) {
title = 'Разблокированы:\n' + indent + hostname + '\n'
+ proxyTitle + '\n' + indent + proxyHost;
ifShouldUpdateTitle = true;
chrome.browserAction.setBadgeText({
tabId: requestDetails.tabId,
text: requestDetails.type === 'main_frame' ? '1' : '%1',
});
} else {
const hostsProxiesPair = title.split(proxyTitle);
if (hostsProxiesPair[1].indexOf(proxyHost) === -1) {
title = title.replace(
hostsProxiesPair[1],
hostsProxiesPair[1] + '\n' + indent + proxyHost
);
ifShouldUpdateTitle = true;
}
if (hostsProxiesPair[0].indexOf(hostname) === -1) {
title = title.replace(
proxyTitle,
indent + hostname + '\n' + proxyTitle
);
ifShouldUpdateTitle = true;
const _cb = cb;
cb = () => chrome.browserAction.getBadgeText(
{tabId: requestDetails.tabId},
(result) => {
chrome.browserAction.setBadgeText(
{
tabId: requestDetails.tabId,
text: (isNaN( result.charAt(0)) && result.charAt(0) || '')
+ (hostsProxiesPair[0].split('\n').length - 1),
}
);
return _cb();
}
);
}
}
if (ifShouldUpdateTitle) {
chrome.browserAction.setTitle({
title: title,
tabId: requestDetails.tabId,
});
}
return cb();
}
);
}
let previousUpdateTitleFinished = Promise.resolve();
function isProxiedAndInformed(requestDetails) {
if ( !(requestDetails.ip
&& window.antiCensorRu.isProxied( requestDetails.ip )) ) {
return false;
}
const ifMainFrame = requestDetails.type === 'main_frame';
previousUpdateTitleFinished = previousUpdateTitleFinished.then(
() => new Promise(
(resolve) => {
const cb = () => updateTitle( requestDetails, resolve );
return ifMainFrame
? afterTabUpdated(requestDetails.tabId, cb) : cb();
}
)
);
return true;
}
chrome.webRequest.onResponseStarted.addListener(
(requestDetails) => isInsideTabWithIp(requestDetails)
&& isProxiedAndInformed(requestDetails),
{urls: ['<all_urls>']}
);
}

View File

@ -1,23 +1,43 @@
'use strict';
{
const createMenuLinkEntry = (title, tab2url) => chrome.contextMenus.create({
title: title,
contexts: ['browser_action'],
onclick: (menuInfo, tab) => Promise.resolve( tab2url( tab ) ).then( (url) => chrome.tabs.create({url: url}) )
});
createMenuLinkEntry( 'Сайт доступен из-за границы? Is up?', (tab) => 'http://isup.me/'+ new URL(tab.url).hostname );
createMenuLinkEntry( 'Сайт в реестре блокировок?', (tab) => 'https://antizapret.info/index.php?search=' + tab.url );
createMenuLinkEntry( 'Из архива archive.org', (tab) => 'https://web.archive.org/web/*/' + tab.url );
createMenuLinkEntry( 'Открыть веб прокси (не наш)', (tab) => 'https://kproxy.com' );
createMenuLinkEntry( 'Другие варианты разблокировки', (tab) => 'https://rebrand.ly/unblock#' + tab.url );
createMenuLinkEntry( 'У меня проблемы с расширением!', (tab) => 'https://rebrand.ly/ac-support');
};
'use strict';
{
const createMenuLinkEntry = (title, tab2url) => chrome.contextMenus.create({
title: title,
contexts: ['browser_action'],
onclick:
(menuInfo, tab) => Promise.resolve( tab2url( tab ) )
.then( (url) => chrome.tabs.create({url: url}) ),
});
createMenuLinkEntry(
'Сайт доступен из-за границы? Is up?',
(tab) => 'http://isup.me/' + new URL(tab.url).hostname
);
createMenuLinkEntry(
'Сайт в реестре блокировок?',
(tab) => 'https://antizapret.info/index.php?search=' + tab.url
);
createMenuLinkEntry(
'Из архива archive.org',
(tab) => 'https://web.archive.org/web/*/' + tab.url
);
createMenuLinkEntry(
'Открыть веб прокси (не наш)',
(tab) => 'https://kproxy.com'
);
createMenuLinkEntry(
'Другие варианты разблокировки',
(tab) => 'https://rebrand.ly/unblock#' + tab.url
);
createMenuLinkEntry(
'У меня проблемы с расширением!',
(tab) => 'https://rebrand.ly/ac-support'
);
}

View File

@ -1,174 +1,189 @@
'use strict';
chrome.runtime.getBackgroundPage( (backgroundPage) => {
const getStatus = () => document.querySelector('#status');
const setStatusTo = (msg) => {
const status = getStatus();
if (msg) {
status.classList.remove('off');
status.innerHTML = msg;
}
else {
status.classList.add('off');
}
};
const antiCensorRu = backgroundPage.antiCensorRu;
// SET DATE
const setDate = () => {
let dateForUser = 'никогда';
if( antiCensorRu.lastPacUpdateStamp ) {
let diff = Date.now() - antiCensorRu.lastPacUpdateStamp;
let units = ' мс';
const gauges = [
[1000, ' с'],
[60, ' мин'],
[60, ' ч'],
[24, ' дн'],
[7, ' недель'],
[4, ' месяцев'],
[12, ' г']
];
for(const g of gauges) {
const diffy = Math.floor(diff / g[0]);
if (!diffy)
break;
diff = diffy;
units = g[1];
}
dateForUser = diff + units + ' назад';
}
const dateElement = document.querySelector('.update-date');
dateElement.innerText = dateForUser;
dateElement.title = new Date(antiCensorRu.lastPacUpdateStamp).toLocaleString('ru-RU');
};
setDate();
chrome.storage.onChanged.addListener( (changes) => changes.lastPacUpdateStamp.newValue && setDate() );
// CLOSE BUTTON
document.querySelector('.close-button').onclick = () => window.close();
// RADIOS
const currentProviderRadio = () => {
const id = antiCensorRu.currentPacProviderKey || 'none';
return document.querySelector('#'+id);
}
const checkChosenProvider = () => currentProviderRadio().checked = true;
const showError = (err) => {
let clarification = err.clarification;
const ifNotCritical = clarification && clarification.ifNotCritical;
let message = err.message || '';
while( clarification ) {
message = (clarification && (clarification.message + ' ')) + message;
clarification = clarification.prev;
}
message = message.trim();
setStatusTo(
`<span style="color:red">${ifNotCritical ? 'Некритичная ошибка.' : 'Ошибка!'}</span>
<br/>
<span style="font-size: 0.9em; color: darkred">${message}</span>
<a href class="link-button">[Ещё&nbsp;подробнее]</a>`
);
getStatus().querySelector('.link-button').onclick = function() {
const div = document.createElement('div');
div.innerHTML = `
Более подробную информацию можно узнать из логов фоновой страницы:<br/>
<a href="chrome://extensions?id=${chrome.runtime.id}" data-in-bg="true">chrome://extensions</a> Это расширение Отладка страниц: фоновая страница Console (DevTools)
<br>
Ещё: ${JSON.stringify({err: err, stack: err.stack})}
`;
getStatus().replaceChild(div, this);
return false;
};
};
const enableDisableInputs = function () {
const inputs = document.querySelectorAll('input');
for ( let i = 0; i < inputs.length; i++ ) {
inputs[i].disabled = !inputs[i].disabled;
}
};
const conduct = (beforeStatus, operation, afterStatus, onSuccess) => {
setStatusTo(beforeStatus);
enableDisableInputs();
operation((err) => {
if (err) {
showError(err);
}
else {
setStatusTo(afterStatus);
onSuccess && onSuccess();
}
enableDisableInputs();
})
};
const ul = document.querySelector('#list-of-providers');
const _firstChild = ul.firstChild;
for( const providerKey of Object.keys(antiCensorRu.pacProviders).sort() ) {
const li = document.createElement('li');
li.innerHTML = `<input type="radio" name="pacProvider" id="${providerKey}"> <label for="${providerKey}">${providerKey}</label> <a href class="link-button checked-radio-panel">[обновить]</a>`;
li.querySelector('.link-button').onclick = () => { conduct( 'Обновляем...', (cb) => antiCensorRu.syncWithPacProvider(cb), 'Обновлено.' ); return false; };
ul.insertBefore( li, _firstChild );
}
checkChosenProvider();
const radios = [].slice.apply( document.querySelectorAll('[name=pacProvider]') );
for(const radio of radios) {
radio.onclick = function(event) {
if (event.target.id === (antiCensorRu.currentPacProviderKey || 'none')) {
return false;
}
const pacKey = event.target.id;
if (pacKey === 'none') {
conduct(
'Отключение...',
(cb) => antiCensorRu.clearPac(cb),
'Отключено.',
checkChosenProvider
);
}
else {
conduct(
'Установка...',
(cb) => antiCensorRu.installPac(pacKey, cb),
'PAC-скрипт установлен.',
checkChosenProvider
);
}
return false;
};
}
setStatusTo('');
if (antiCensorRu.ifFirstInstall) {
currentProviderRadio().click();
}
});
'use strict';
chrome.runtime.getBackgroundPage( (backgroundPage) => {
const getStatus = () => document.querySelector('#status');
const setStatusTo = (msg) => {
const status = getStatus();
if (msg) {
status.classList.remove('off');
status.innerHTML = msg;
} else {
status.classList.add('off');
}
};
const antiCensorRu = backgroundPage.antiCensorRu;
// SET DATE
const setDate = () => {
let dateForUser = 'никогда';
if( antiCensorRu.lastPacUpdateStamp ) {
let diff = Date.now() - antiCensorRu.lastPacUpdateStamp;
let units = ' мс';
const gauges = [
[1000, ' с'],
[60, ' мин'],
[60, ' ч'],
[24, ' дн'],
[7, ' недель'],
[4, ' месяцев'],
[12, ' г'],
];
for(const g of gauges) {
const diffy = Math.floor(diff / g[0]);
if (!diffy)
break;
diff = diffy;
units = g[1];
}
dateForUser = diff + units + ' назад';
}
const dateElement = document.querySelector('.update-date');
dateElement.innerText = dateForUser;
dateElement.title = new Date(antiCensorRu.lastPacUpdateStamp)
.toLocaleString('ru-RU');
};
setDate();
chrome.storage.onChanged.addListener(
(changes) => changes.lastPacUpdateStamp.newValue && setDate()
);
// CLOSE BUTTON
document.querySelector('.close-button').onclick = () => window.close();
// RADIOS
const currentProviderRadio = () => {
const id = antiCensorRu.currentPacProviderKey || 'none';
return document.querySelector('#'+id);
};
const checkChosenProvider = () => currentProviderRadio().checked = true;
const showError = (err) => {
let clarification = err.clarification;
const ifNotCritical = clarification && clarification.ifNotCritical;
let message = err.message || '';
while( clarification ) {
message = (clarification && (clarification.message + ' ')) + message;
clarification = clarification.prev;
}
message = message.trim();
setStatusTo(
`<span style="color:red">
${ifNotCritical ? 'Некритичная ошибка.' : 'Ошибка!'}
</span>
<br/>
<span style="font-size: 0.9em; color: darkred">${message}</span>
<a href class="link-button">[Ещё&nbsp;подробнее]</a>`
);
getStatus().querySelector('.link-button').onclick = function() {
const div = document.createElement('div');
div.innerHTML = `
Более подробную информацию можно узнать из логов фоновой страницы:<br/>
<a href="chrome://extensions?id=${chrome.runtime.id}" data-in-bg="true">
chrome://extensions</a>
Это расширение Отладка страниц: фоновая страница Console (DevTools)
<br>
Ещё: ${JSON.stringify({err: err, stack: err.stack})}
`;
getStatus().replaceChild(div, this);
return false;
};
};
const enableDisableInputs = function() {
const inputs = document.querySelectorAll('input');
for ( let i = 0; i < inputs.length; i++ ) {
inputs[i].disabled = !inputs[i].disabled;
}
};
const conduct = (beforeStatus, operation, afterStatus, onSuccess) => {
setStatusTo(beforeStatus);
enableDisableInputs();
operation((err) => {
if (err) {
showError(err);
} else {
setStatusTo(afterStatus);
onSuccess && onSuccess();
}
enableDisableInputs();
});
};
const ul = document.querySelector('#list-of-providers');
const _firstChild = ul.firstChild;
for( const providerKey of Object.keys(antiCensorRu.pacProviders).sort() ) {
const li = document.createElement('li');
li.innerHTML = `<input type="radio" name="pacProvider" id="${providerKey}">
<label for="${providerKey}">${providerKey}</label>
<a href class="link-button checked-radio-panel">[обновить]</a>`;
li.querySelector('.link-button').onclick =
() => {
conduct(
'Обновляем...', (cb) => antiCensorRu.syncWithPacProvider(cb),
'Обновлено.'
);
return false;
};
ul.insertBefore( li, _firstChild );
}
checkChosenProvider();
const radios = [].slice.apply(
document.querySelectorAll('[name=pacProvider]')
);
for(const radio of radios) {
radio.onclick = function(event) {
if (event.target.id === (antiCensorRu.currentPacProviderKey || 'none')) {
return false;
}
const pacKey = event.target.id;
if (pacKey === 'none') {
conduct(
'Отключение...',
(cb) => antiCensorRu.clearPac(cb),
'Отключено.',
checkChosenProvider
);
} else {
conduct(
'Установка...',
(cb) => antiCensorRu.installPac(pacKey, cb),
'PAC-скрипт установлен.',
checkChosenProvider
);
}
return false;
};
}
setStatusTo('');
if (antiCensorRu.ifFirstInstall) {
currentProviderRadio().click();
}
});

View File

@ -13,9 +13,9 @@ const updateLinks = () => {
for (let i = 0; i < links.length; i++) {
const ln = links[i];
const location = ln.href;
ln.onclick = function () {
ln.onclick = function() {
chrome.tabs.create({ active: !this.dataset.inBg, url: location });
chrome.tabs.create({active: !this.dataset.inBg, url: location});
return false;
};
@ -24,6 +24,11 @@ const updateLinks = () => {
};
new MutationObserver( updateLinks )
.observe(target, { attributes: false, subtree: true, childList: true, characterData: false });
.observe(target, {
attributes: false,
subtree: true,
childList: true,
characterData: false,
});
document.addEventListener('DOMContentLoaded', updateLinks);

View File

@ -4,13 +4,15 @@ const setStatusTo = (msg) => document.getElementById('status').innerHTML = msg;
const red = (text) => '<span style="color: red">' + text + '</span>';
const editor = ace.edit('editor');
const editor = window.ace.edit('editor');
editor.getSession().setOptions({
mode: "ace/mode/javascript",
useSoftTabs: true
mode: 'ace/mode/javascript',
useSoftTabs: true,
});
chrome.proxy.settings.onChange.addListener( (details) => setStatusTo(red( details.levelOfControl + '!') ) );
chrome.proxy.settings.onChange.addListener(
(details) => setStatusTo(red( details.levelOfControl + '!') )
);
document.querySelector('#read-button').onclick = () => {
@ -36,8 +38,8 @@ document.querySelector('#save-button').onclick = () => {
mode: 'pac_script',
pacScript: {
mandatory: false,
data: editor.getValue()
}
data: editor.getValue(),
},
};
chrome.proxy.settings.set( {value: config}, () => alert('Saved!') );

View File

@ -0,0 +1,21 @@
{
"name": "russian-censorship-bypass",
"version": "0.0.15",
"description": "Development tools for chromium extension",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"lint": "./node_modules/.bin/eslint ./extension/**/*.js --ignore-pattern vendor"
},
"author": "Ilya Ig. Petrov",
"license": "GPLv3",
"devDependencies": {
"eslint": "^3.11.1",
"eslint-config-airbnb": "^13.0.0",
"eslint-config-google": "^0.7.1",
"eslint-plugin-hapi": "^4.0.0",
"eslint-plugin-import": "^2.2.0",
"eslint-plugin-jsx-a11y": "^2.2.3",
"eslint-plugin-react": "^6.7.1"
}
}