Code styling

This commit is contained in:
Deathamns 2014-12-28 21:26:06 +01:00
parent 9169388849
commit 5e55ba772d
14 changed files with 482 additions and 464 deletions

View File

@ -295,7 +295,7 @@ vAPI.messaging.onPortMessage = function(request, port) {
} }
port.postMessage({ port.postMessage({
requestId: request.requestId, requestId: request.requestId,
portName: request.portName, channelName: request.channelName,
msg: response !== undefined ? response : null msg: response !== undefined ? response : null
}); });
}; };
@ -303,7 +303,7 @@ vAPI.messaging.onPortMessage = function(request, port) {
// Specific handler // Specific handler
var r = vAPI.messaging.UNHANDLED; var r = vAPI.messaging.UNHANDLED;
var listener = vAPI.messaging.listeners[request.portName]; var listener = vAPI.messaging.listeners[request.channelName];
if ( typeof listener === 'function' ) { if ( typeof listener === 'function' ) {
r = listener(request.msg, port.sender, callback); r = listener(request.msg, port.sender, callback);
} }
@ -383,7 +383,7 @@ vAPI.net = {
'onHeadersReceived' 'onHeadersReceived'
]; ];
for (var i = 0; i < listeners.length; ++i) { for ( var i = 0; i < listeners.length; i++ ) {
chrome.webRequest[listeners[i]].addListener( chrome.webRequest[listeners[i]].addListener(
this[listeners[i]].callback, this[listeners[i]].callback,
{ {

View File

@ -55,7 +55,7 @@ var messagingConnector = function(response) {
var channels = vAPI.messaging.channels; var channels = vAPI.messaging.channels;
var channel, listener; var channel, listener;
if ( response.broadcast === true && !response.portName ) { if ( response.broadcast === true && !response.channelName ) {
for ( channel in channels ) { for ( channel in channels ) {
if ( channels.hasOwnProperty(channel) === false ) { if ( channels.hasOwnProperty(channel) === false ) {
continue; continue;
@ -75,7 +75,7 @@ var messagingConnector = function(response) {
} }
if ( !listener ) { if ( !listener ) {
channel = channels[response.portName]; channel = channels[response.channelName];
listener = channel && channel.listener; listener = channel && channel.listener;
} }
@ -121,7 +121,7 @@ vAPI.messaging = {
} }
this.channels[channelName] = { this.channels[channelName] = {
portName: channelName, channelName: channelName,
listener: typeof callback === 'function' ? callback : null, listener: typeof callback === 'function' ? callback : null,
send: function(message, callback) { send: function(message, callback) {
if ( vAPI.messaging.port === null ) { if ( vAPI.messaging.port === null ) {
@ -129,7 +129,7 @@ vAPI.messaging = {
} }
message = { message = {
portName: this.portName, channelName: this.channelName,
msg: message msg: message
}; };
@ -141,7 +141,7 @@ vAPI.messaging = {
vAPI.messaging.port.postMessage(message); vAPI.messaging.port.postMessage(message);
}, },
close: function() { close: function() {
delete vAPI.messaging.channels[this.portName]; delete vAPI.messaging.channels[this.channelName];
} }
}; };

View File

@ -26,48 +26,48 @@
/******************************************************************************/ /******************************************************************************/
let bgProcess; let bgProcess = function(e) {
if ( e ) {
this.removeEventListener('DOMContentLoaded', bgProcess);
}
let hDoc = Components.classes['@mozilla.org/appshell/appShellService;1']
.getService(Components.interfaces.nsIAppShellService)
.hiddenDOMWindow.document;
bgProcess = hDoc.documentElement.appendChild(
hDoc.createElementNS('http://www.w3.org/1999/xhtml', 'iframe')
);
bgProcess.setAttribute('src', 'chrome://ublock/content/background.html');
};
/******************************************************************************/ /******************************************************************************/
function startup(data, reason) { function startup(data, reason) {
bgProcess = function(e) { if ( reason !== APP_STARTUP ) {
if (e) {
this.removeEventListener('DOMContentLoaded', bgProcess);
}
let hDoc = Components.classes['@mozilla.org/appshell/appShellService;1']
.getService(Components.interfaces.nsIAppShellService)
.hiddenDOMWindow.document;
bgProcess = hDoc.documentElement.appendChild(
hDoc.createElementNS('http://www.w3.org/1999/xhtml', 'iframe')
);
bgProcess.setAttribute('src', 'chrome://ublock/content/background.html');
};
if (reason === APP_STARTUP) {
let ww = Components.classes['@mozilla.org/embedcomp/window-watcher;1']
.getService(Components.interfaces.nsIWindowWatcher);
ww.registerNotification({
observe: function(win) {
ww.unregisterNotification(this);
win.addEventListener('DOMContentLoaded', bgProcess);
}
});
}
else {
bgProcess(); bgProcess();
return;
} }
let ww = Components.classes['@mozilla.org/embedcomp/window-watcher;1']
.getService(Components.interfaces.nsIWindowWatcher);
ww.registerNotification({
observe: function(win) {
ww.unregisterNotification(this);
win.addEventListener('DOMContentLoaded', bgProcess);
}
});
} }
/******************************************************************************/ /******************************************************************************/
function shutdown(data, reason) { function shutdown(data, reason) {
if (reason !== APP_SHUTDOWN) { if ( reason === APP_SHUTDOWN ) {
bgProcess.parentNode.removeChild(bgProcess); return;
} }
bgProcess.parentNode.removeChild(bgProcess);
} }
/******************************************************************************/ /******************************************************************************/

View File

@ -54,20 +54,24 @@ const contentPolicy = {
contractID: '@' + appName + '/content-policy;1', contractID: '@' + appName + '/content-policy;1',
ACCEPT: Ci.nsIContentPolicy.ACCEPT, ACCEPT: Ci.nsIContentPolicy.ACCEPT,
messageName: appName + ':shouldLoad', messageName: appName + ':shouldLoad',
get componentRegistrar() { get componentRegistrar() {
return Components.manager.QueryInterface(Ci.nsIComponentRegistrar); return Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
}, },
get categoryManager() { get categoryManager() {
return Components.classes['@mozilla.org/categorymanager;1'] return Components.classes['@mozilla.org/categorymanager;1']
.getService(Ci.nsICategoryManager); .getService(Ci.nsICategoryManager);
}, },
QueryInterface: XPCOMUtils.generateQI([ QueryInterface: XPCOMUtils.generateQI([
Ci.nsIFactory, Ci.nsIFactory,
Ci.nsIContentPolicy, Ci.nsIContentPolicy,
Ci.nsISupportsWeakReference Ci.nsISupportsWeakReference
]), ]),
createInstance: function(outer, iid) { createInstance: function(outer, iid) {
if (outer) { if ( outer ) {
throw Components.results.NS_ERROR_NO_AGGREGATION; throw Components.results.NS_ERROR_NO_AGGREGATION;
} }
@ -88,6 +92,7 @@ const contentPolicy = {
true true
); );
}, },
unregister: function() { unregister: function() {
this.componentRegistrar.unregisterFactory(this.classID, this); this.componentRegistrar.unregisterFactory(this.classID, this);
this.categoryManager.deleteCategoryEntry( this.categoryManager.deleteCategoryEntry(
@ -96,6 +101,7 @@ const contentPolicy = {
false false
); );
}, },
// https://bugzil.la/612921 // https://bugzil.la/612921
shouldLoad: function(type, location, origin, context) { shouldLoad: function(type, location, origin, context) {
// If we don't know what initiated the request, probably it's not a tab // If we don't know what initiated the request, probably it's not a tab
@ -128,14 +134,16 @@ const contentPolicy = {
const docObserver = { const docObserver = {
contentBaseURI: 'chrome://' + appName + '/content/js/', contentBaseURI: 'chrome://' + appName + '/content/js/',
QueryInterface: XPCOMUtils.generateQI([ QueryInterface: XPCOMUtils.generateQI([
Ci.nsIObserver, Ci.nsIObserver,
Ci.nsISupportsWeakReference Ci.nsISupportsWeakReference
]), ]),
initContext: function(win, sandbox) { initContext: function(win, sandbox) {
let messager = getMessageManager(win); let messager = getMessageManager(win);
if (sandbox) { if ( sandbox ) {
win = Cu.Sandbox([win], { win = Cu.Sandbox([win], {
sandboxPrototype: win, sandboxPrototype: win,
wantComponents: false, wantComponents: false,
@ -147,7 +155,7 @@ const docObserver = {
// anonymous function needs to be used here // anonymous function needs to be used here
win.injectScript = Cu.exportFunction( win.injectScript = Cu.exportFunction(
function(script, evalCode) { function(script, evalCode) {
if (evalCode) { if ( evalCode ) {
Cu.evalInSandbox(script, win); Cu.evalInSandbox(script, win);
return; return;
} }
@ -164,23 +172,26 @@ const docObserver = {
return win; return win;
}, },
register: function() { register: function() {
Services.obs.addObserver(this, 'document-element-inserted', true); Services.obs.addObserver(this, 'document-element-inserted', true);
}, },
unregister: function() { unregister: function() {
Services.obs.removeObserver(this, 'document-element-inserted'); Services.obs.removeObserver(this, 'document-element-inserted');
}, },
observe: function(doc) { observe: function(doc) {
let win = doc.defaultView; let win = doc.defaultView;
if (!win) { if ( !win ) {
return; return;
} }
let loc = win.location; let loc = win.location;
if (loc.protocol !== 'http:' && loc.protocol !== 'https:') { if ( loc.protocol !== 'http:' && loc.protocol !== 'https:' ) {
if (loc.protocol === 'chrome:' && loc.host === appName) { if ( loc.protocol === 'chrome:' && loc.host === appName ) {
this.initContext(win); this.initContext(win);
} }

View File

@ -19,7 +19,7 @@
Home: https://github.com/gorhill/uBlock Home: https://github.com/gorhill/uBlock
*/ */
/* globals Services, sendAsyncMessage, addMessageListener, removeMessageListener */ /* globals addMessageListener, removeMessageListener */
/******************************************************************************/ /******************************************************************************/
@ -47,7 +47,7 @@ frameScriptContext[appName + '_addMessageListener'] = function(id, fn) {
}; };
frameScriptContext[appName + '_removeMessageListener'] = function(id) { frameScriptContext[appName + '_removeMessageListener'] = function(id) {
if (listeners[id]) { if ( listeners[id] ) {
removeMessageListener(id, listeners[id]); removeMessageListener(id, listeners[id]);
} }
@ -57,7 +57,7 @@ frameScriptContext[appName + '_removeMessageListener'] = function(id) {
/******************************************************************************/ /******************************************************************************/
addMessageListener(appName + ':broadcast', function(msg) { addMessageListener(appName + ':broadcast', function(msg) {
for (let id in listeners) { for ( let id in listeners ) {
listeners[id](msg); listeners[id](msg);
} }
}); });

View File

@ -55,8 +55,8 @@ vAPI.app.restart = function() {};
/******************************************************************************/ /******************************************************************************/
// list of things that needs to be destroyed when disabling the extension // List of things that needs to be destroyed when disabling the extension
// only functions should be added to it // Only functions should be added to it
vAPI.unload = []; vAPI.unload = [];
@ -67,11 +67,11 @@ var SQLite = {
var path = Services.dirsvc.get('ProfD', Ci.nsIFile); var path = Services.dirsvc.get('ProfD', Ci.nsIFile);
path.append('extension-data'); path.append('extension-data');
if (!path.exists()) { if ( !path.exists() ) {
path.create(Ci.nsIFile.DIRECTORY_TYPE, parseInt('0774', 8)); path.create(Ci.nsIFile.DIRECTORY_TYPE, parseInt('0774', 8));
} }
if (!path.isDirectory()) { if ( !path.isDirectory() ) {
throw Error('Should be a directory...'); throw Error('Should be a directory...');
} }
@ -88,8 +88,9 @@ var SQLite = {
SQLite.db.asyncClose(); SQLite.db.asyncClose();
}); });
}, },
run: function(query, values, callback) { run: function(query, values, callback) {
if (!this.db) { if ( !this.db ) {
this.open(); this.open();
} }
@ -97,30 +98,30 @@ var SQLite = {
query = this.db.createAsyncStatement(query); query = this.db.createAsyncStatement(query);
if (Array.isArray(values) && values.length) { if ( Array.isArray(values) && values.length ) {
var i = values.length; var i = values.length;
while (i--) { while ( i-- ) {
query.bindByIndex(i, values[i]); query.bindByIndex(i, values[i]);
} }
} }
query.executeAsync({ query.executeAsync({
handleResult: function(rows) { handleResult: function(rows) {
if (!rows || typeof callback !== 'function') { if ( !rows || typeof callback !== 'function' ) {
return; return;
} }
var row; var row;
while (row = rows.getNextRow()) { while ( row = rows.getNextRow() ) {
// we assume that there will be two columns, since we're // we assume that there will be two columns, since we're
// using it only for preferences // using it only for preferences
result[row.getResultByIndex(0)] = row.getResultByIndex(1); result[row.getResultByIndex(0)] = row.getResultByIndex(1);
} }
}, },
handleCompletion: function(reason) { handleCompletion: function(reason) {
if (typeof callback === 'function' && reason === 0) { if ( typeof callback === 'function' && reason === 0 ) {
callback(result); callback(result);
} }
}, },
@ -135,30 +136,30 @@ var SQLite = {
vAPI.storage = { vAPI.storage = {
QUOTA_BYTES: 100 * 1024 * 1024, QUOTA_BYTES: 100 * 1024 * 1024,
sqlWhere: function(col, params) { sqlWhere: function(col, params) {
if (params > 0) { if ( params > 0 ) {
params = Array(params + 1).join('?, ').slice(0, -2); params = Array(params + 1).join('?, ').slice(0, -2);
return ' WHERE ' + col + ' IN (' + params + ')'; return ' WHERE ' + col + ' IN (' + params + ')';
} }
return ''; return '';
}, },
get: function(details, callback) { get: function(details, callback) {
if (typeof callback !== 'function') { if ( typeof callback !== 'function' ) {
return; return;
} }
var values = [], defaults = false; var values = [], defaults = false;
if (details !== null) { if ( details !== null ) {
if (Array.isArray(details)) { if ( Array.isArray(details) ) {
values = details; values = details;
} } else if ( typeof details === 'object' ) {
else if (typeof details === 'object') {
defaults = true; defaults = true;
values = Object.keys(details); values = Object.keys(details);
} } else {
else {
values = [details.toString()]; values = [details.toString()];
} }
} }
@ -169,13 +170,13 @@ vAPI.storage = {
function(result) { function(result) {
var key; var key;
for (key in result) { for ( key in result ) {
result[key] = JSON.parse(result[key]); result[key] = JSON.parse(result[key]);
} }
if (defaults) { if ( defaults ) {
for (key in details) { for ( key in details ) {
if (result[key] === undefined) { if ( result[key] === undefined ) {
result[key] = details[key]; result[key] = details[key];
} }
} }
@ -185,16 +186,17 @@ vAPI.storage = {
} }
); );
}, },
set: function(details, callback) { set: function(details, callback) {
var key, values = [], placeholders = []; var key, values = [], placeholders = [];
for (key in details) { for ( key in details ) {
values.push(key); values.push(key);
values.push(JSON.stringify(details[key])); values.push(JSON.stringify(details[key]));
placeholders.push('?, ?'); placeholders.push('?, ?');
} }
if (!values.length) { if ( !values.length ) {
return; return;
} }
@ -205,8 +207,9 @@ vAPI.storage = {
callback callback
); );
}, },
remove: function(keys, callback) { remove: function(keys, callback) {
if (typeof keys === 'string') { if ( typeof keys === 'string' ) {
keys = [keys]; keys = [keys];
} }
@ -216,12 +219,14 @@ vAPI.storage = {
callback callback
); );
}, },
clear: function(callback) { clear: function(callback) {
SQLite.run('DELETE FROM settings'); SQLite.run('DELETE FROM settings');
SQLite.run('VACUUM', null, callback); SQLite.run('VACUUM', null, callback);
}, },
getBytesInUse: function(keys, callback) { getBytesInUse: function(keys, callback) {
if (typeof callback !== 'function') { if ( typeof callback !== 'function' ) {
return; return;
} }
@ -244,24 +249,26 @@ var windowWatcher = {
vAPI.tabs.onClosed(tabId); vAPI.tabs.onClosed(tabId);
delete vAPI.tabIcons[tabId]; delete vAPI.tabIcons[tabId];
}, },
onTabSelect: function(e) { onTabSelect: function(e) {
vAPI.setIcon( vAPI.setIcon(
vAPI.tabs.getTabId(e.target), vAPI.tabs.getTabId(e.target),
e.target.ownerDocument.defaultView e.target.ownerDocument.defaultView
); );
}, },
onReady: function(e) { onReady: function(e) {
if (e) { if ( e ) {
this.removeEventListener(e.type, windowWatcher.onReady); this.removeEventListener(e.type, windowWatcher.onReady);
} }
var wintype = this.document.documentElement.getAttribute('windowtype'); var wintype = this.document.documentElement.getAttribute('windowtype');
if (wintype !== 'navigator:browser') { if ( wintype !== 'navigator:browser' ) {
return; return;
} }
if (!this.gBrowser || !this.gBrowser.tabContainer) { if ( !this.gBrowser || !this.gBrowser.tabContainer ) {
return; return;
} }
@ -276,8 +283,9 @@ var windowWatcher = {
// when new window is opened TabSelect doesn't run on the selected tab? // when new window is opened TabSelect doesn't run on the selected tab?
}, },
observe: function(win, topic) { observe: function(win, topic) {
if (topic === 'domwindowopened') { if ( topic === 'domwindowopened' ) {
win.addEventListener('DOMContentLoaded', this.onReady); win.addEventListener('DOMContentLoaded', this.onReady);
} }
} }
@ -287,20 +295,19 @@ var windowWatcher = {
var tabsProgressListener = { var tabsProgressListener = {
onLocationChange: function(browser, webProgress, request, location, flags) { onLocationChange: function(browser, webProgress, request, location, flags) {
if (!webProgress.isTopLevel) { if ( !webProgress.isTopLevel ) {
return; return;
} }
var tabId = vAPI.tabs.getTabId(browser); var tabId = vAPI.tabs.getTabId(browser);
if (flags & 1) { if ( flags & 1 ) {
vAPI.tabs.onUpdated(tabId, {url: location.spec}, { vAPI.tabs.onUpdated(tabId, {url: location.spec}, {
frameId: 0, frameId: 0,
tabId: tabId, tabId: tabId,
url: browser.currentURI.spec url: browser.currentURI.spec
}); });
} } else {
else {
vAPI.tabs.onNavigation({ vAPI.tabs.onNavigation({
frameId: 0, frameId: 0,
tabId: tabId, tabId: tabId,
@ -321,7 +328,7 @@ vAPI.tabs.registerListeners = function() {
// onClosed - handled in windowWatcher.onTabClose // onClosed - handled in windowWatcher.onTabClose
// onPopup ? // onPopup ?
for (var win of this.getWindows()) { for ( var win of this.getWindows() ) {
windowWatcher.onReady.call(win); windowWatcher.onReady.call(win);
} }
@ -331,7 +338,7 @@ vAPI.tabs.registerListeners = function() {
vAPI.unload.push(function() { vAPI.unload.push(function() {
Services.ww.unregisterNotification(windowWatcher); Services.ww.unregisterNotification(windowWatcher);
for (var win of vAPI.tabs.getWindows()) { for ( var win of vAPI.tabs.getWindows() ) {
vAPI.toolbarButton.unregister(win.document); vAPI.toolbarButton.unregister(win.document);
vAPI.contextMenu.unregister(win.document); vAPI.contextMenu.unregister(win.document);
@ -343,10 +350,10 @@ vAPI.tabs.registerListeners = function() {
tC.removeEventListener('TabSelect', windowWatcher.onTabSelect); tC.removeEventListener('TabSelect', windowWatcher.onTabSelect);
// close extension tabs // close extension tabs
for (var tab of win.gBrowser.tabs) { for ( var tab of win.gBrowser.tabs ) {
var URI = tab.linkedBrowser.currentURI; var URI = tab.linkedBrowser.currentURI;
if (URI.scheme === 'chrome' && URI.host === location.host) { if ( URI.scheme === 'chrome' && URI.host === location.host ) {
win.gBrowser.removeTab(tab); win.gBrowser.removeTab(tab);
} }
} }
@ -357,21 +364,21 @@ vAPI.tabs.registerListeners = function() {
/******************************************************************************/ /******************************************************************************/
vAPI.tabs.getTabId = function(target) { vAPI.tabs.getTabId = function(target) {
if (target.linkedPanel) { if ( target.linkedPanel ) {
return target.linkedPanel.slice(6); return target.linkedPanel.slice(6);
} }
var i, gBrowser = target.ownerDocument.defaultView.gBrowser; var i, gBrowser = target.ownerDocument.defaultView.gBrowser;
// This should be more efficient from version 35 // This should be more efficient from version 35
if (gBrowser.getTabForBrowser) { if ( gBrowser.getTabForBrowser ) {
i = gBrowser.getTabForBrowser(target); i = gBrowser.getTabForBrowser(target);
return i ? i.linkedPanel.slice(6) : -1; return i ? i.linkedPanel.slice(6) : -1;
} }
i = gBrowser.browsers.indexOf(target); i = gBrowser.browsers.indexOf(target);
if (i !== -1) { if ( i !== -1 ) {
i = gBrowser.tabs[i].linkedPanel.slice(6); i = gBrowser.tabs[i].linkedPanel.slice(6);
} }
@ -383,30 +390,29 @@ vAPI.tabs.getTabId = function(target) {
vAPI.tabs.get = function(tabId, callback) { vAPI.tabs.get = function(tabId, callback) {
var tab, windows; var tab, windows;
if (tabId === null) { if ( tabId === null ) {
tab = Services.wm.getMostRecentWindow('navigator:browser').gBrowser.selectedTab; tab = Services.wm.getMostRecentWindow('navigator:browser').gBrowser.selectedTab;
tabId = vAPI.tabs.getTabId(tab); tabId = vAPI.tabs.getTabId(tab);
} } else {
else {
windows = this.getWindows(); windows = this.getWindows();
for (var win of windows) { for ( var win of windows ) {
tab = win.gBrowser.tabContainer.querySelector( tab = win.gBrowser.tabContainer.querySelector(
'tab[linkedpanel="panel-' + tabId + '"]' 'tab[linkedpanel="panel-' + tabId + '"]'
); );
if (tab) { if ( tab ) {
break; break;
} }
} }
} }
// for internal use // for internal use
if (tab && callback === undefined) { if ( tab && typeof callback !== 'function' ) {
return tab; return tab;
} }
if (!tab) { if ( !tab ) {
callback(); callback();
return; return;
} }
@ -414,7 +420,7 @@ vAPI.tabs.get = function(tabId, callback) {
var browser = tab.linkedBrowser; var browser = tab.linkedBrowser;
var gBrowser = browser.ownerDocument.defaultView.gBrowser; var gBrowser = browser.ownerDocument.defaultView.gBrowser;
if (!windows) { if ( !windows ) {
windows = this.getWindows(); windows = this.getWindows();
} }
@ -433,12 +439,12 @@ vAPI.tabs.get = function(tabId, callback) {
vAPI.tabs.getAll = function(window) { vAPI.tabs.getAll = function(window) {
var win, tab, tabs = []; var win, tab, tabs = [];
for (win of this.getWindows()) { for ( win of this.getWindows() ) {
if (window && window !== win) { if ( window && window !== win ) {
continue; continue;
} }
for (tab of win.gBrowser.tabs) { for ( tab of win.gBrowser.tabs ) {
tabs.push(tab); tabs.push(tab);
} }
} }
@ -452,10 +458,10 @@ vAPI.tabs.getWindows = function() {
var winumerator = Services.wm.getEnumerator('navigator:browser'); var winumerator = Services.wm.getEnumerator('navigator:browser');
var windows = []; var windows = [];
while (winumerator.hasMoreElements()) { while ( winumerator.hasMoreElements() ) {
var win = winumerator.getNext(); var win = winumerator.getNext();
if (!win.closed) { if ( !win.closed ) {
windows.push(win); windows.push(win);
} }
} }
@ -473,47 +479,47 @@ vAPI.tabs.getWindows = function() {
// select: true // if a tab is already opened with that url, then select it instead of opening a new one // select: true // if a tab is already opened with that url, then select it instead of opening a new one
vAPI.tabs.open = function(details) { vAPI.tabs.open = function(details) {
if (!details.url) { if ( !details.url ) {
return null; return null;
} }
// extension pages // extension pages
if (!/^[\w-]{2,}:/.test(details.url)) { if ( /^[\w-]{2,}:/.test(details.url) === false ) {
details.url = vAPI.getURL(details.url); details.url = vAPI.getURL(details.url);
} }
var tab, tabs; var tab, tabs;
if (details.select) { if ( details.select ) {
var rgxHash = /#.*/; var rgxHash = /#.*/;
// this is questionable // this is questionable
var url = details.url.replace(rgxHash, ''); var url = details.url.replace(rgxHash, '');
tabs = this.getAll(); tabs = this.getAll();
for (tab of tabs) { for ( tab of tabs ) {
var browser = tab.linkedBrowser; var browser = tab.linkedBrowser;
if (browser.currentURI.spec.replace(rgxHash, '') === url) { if ( browser.currentURI.spec.replace(rgxHash, '') === url ) {
browser.ownerDocument.defaultView.gBrowser.selectedTab = tab; browser.ownerDocument.defaultView.gBrowser.selectedTab = tab;
return; return;
} }
} }
} }
if (details.active === undefined) { if ( details.active === undefined ) {
details.active = true; details.active = true;
} }
var gBrowser = Services.wm.getMostRecentWindow('navigator:browser').gBrowser; var gBrowser = Services.wm.getMostRecentWindow('navigator:browser').gBrowser;
if (details.index === -1) { if ( details.index === -1 ) {
details.index = gBrowser.browsers.indexOf(gBrowser.selectedBrowser) + 1; details.index = gBrowser.browsers.indexOf(gBrowser.selectedBrowser) + 1;
} }
if (details.tabId) { if ( details.tabId ) {
tabs = tabs || this.getAll(); tabs = tabs || this.getAll();
for (tab of tabs) { for ( tab of tabs ) {
if (vAPI.tabs.getTabId(tab) === details.tabId) { if ( vAPI.tabs.getTabId(tab) === details.tabId ) {
tab.linkedBrowser.loadURI(details.url); tab.linkedBrowser.loadURI(details.url);
return; return;
} }
@ -522,7 +528,7 @@ vAPI.tabs.open = function(details) {
tab = gBrowser.loadOneTab(details.url, {inBackground: !details.active}); tab = gBrowser.loadOneTab(details.url, {inBackground: !details.active});
if (details.index !== undefined) { if ( details.index !== undefined ) {
gBrowser.moveTabTo(tab, details.index); gBrowser.moveTabTo(tab, details.index);
} }
}; };
@ -530,7 +536,7 @@ vAPI.tabs.open = function(details) {
/******************************************************************************/ /******************************************************************************/
vAPI.tabs.close = function(tabIds) { vAPI.tabs.close = function(tabIds) {
if (!Array.isArray(tabIds)) { if ( !Array.isArray(tabIds) ) {
tabIds = [tabIds]; tabIds = [tabIds];
} }
@ -538,14 +544,14 @@ vAPI.tabs.close = function(tabIds) {
return 'tab[linkedpanel="panel-' + tabId + '"]'; return 'tab[linkedpanel="panel-' + tabId + '"]';
}).join(','); }).join(',');
for (var win of this.getWindows()) { for ( var win of this.getWindows() ) {
var tabs = win.gBrowser.tabContainer.querySelectorAll(tabIds); var tabs = win.gBrowser.tabContainer.querySelectorAll(tabIds);
if (!tabs) { if ( !tabs ) {
continue; continue;
} }
for (var tab of tabs) { for ( var tab of tabs ) {
win.gBrowser.removeTab(tab); win.gBrowser.removeTab(tab);
} }
} }
@ -556,11 +562,11 @@ vAPI.tabs.close = function(tabIds) {
vAPI.tabs.injectScript = function(tabId, details, callback) { vAPI.tabs.injectScript = function(tabId, details, callback) {
var tab = vAPI.tabs.get(tabId); var tab = vAPI.tabs.get(tabId);
if (!tab) { if ( !tab ) {
return; return;
} }
if (details.file) { if ( details.file ) {
details.file = vAPI.getURL(details.file); details.file = vAPI.getURL(details.file);
} }
@ -568,7 +574,7 @@ vAPI.tabs.injectScript = function(tabId, details, callback) {
location.host + ':broadcast', location.host + ':broadcast',
JSON.stringify({ JSON.stringify({
broadcast: true, broadcast: true,
portName: 'vAPI', channelName: 'vAPI',
msg: { msg: {
cmd: 'injectScript', cmd: 'injectScript',
details: details details: details
@ -576,7 +582,7 @@ vAPI.tabs.injectScript = function(tabId, details, callback) {
}) })
); );
if (typeof callback === 'function') { if ( typeof callback === 'function' ) {
setTimeout(callback, 13); setTimeout(callback, 13);
} }
}; };
@ -592,27 +598,26 @@ vAPI.setIcon = function(tabId, iconStatus, badge) {
var curTabId = vAPI.tabs.getTabId(curWin.gBrowser.selectedTab); var curTabId = vAPI.tabs.getTabId(curWin.gBrowser.selectedTab);
// from 'TabSelect' event // from 'TabSelect' event
if (tabId === undefined) { if ( tabId === undefined ) {
tabId = curTabId; tabId = curTabId;
} } else if ( badge !== undefined ) {
else if (badge !== undefined) {
vAPI.tabIcons[tabId] = { vAPI.tabIcons[tabId] = {
badge: badge, badge: badge,
img: iconStatus === 'on' img: iconStatus === 'on'
}; };
} }
if (tabId !== curTabId) { if ( tabId !== curTabId ) {
return; return;
} }
var button = curWin.document.getElementById(vAPI.toolbarButton.widgetId); var button = curWin.document.getElementById(vAPI.toolbarButton.widgetId);
if (!button) { if ( !button ) {
return; return;
} }
/*if (!button.classList.contains('badged-button')) { /*if ( !button.classList.contains('badged-button') ) {
button.classList.add('badged-button'); button.classList.add('badged-button');
}*/ }*/
@ -685,7 +690,7 @@ vAPI.toolbarButton.register = function(doc) {
var updateTimer = null; var updateTimer = null;
var delayedResize = function() { var delayedResize = function() {
if (updateTimer) { if ( updateTimer ) {
return; return;
} }
@ -703,7 +708,7 @@ vAPI.toolbarButton.register = function(doc) {
var onPopupReady = function() { var onPopupReady = function() {
var win = this.contentWindow; var win = this.contentWindow;
if (!win || win.location.host !== location.host) { if ( !win || win.location.host !== location.host ) {
return; return;
} }
@ -719,7 +724,7 @@ vAPI.toolbarButton.register = function(doc) {
iframe.addEventListener('load', onPopupReady, true); iframe.addEventListener('load', onPopupReady, true);
if (!this.styleURI) { if ( !this.styleURI ) {
this.styleURI = 'data:text/css,' + encodeURIComponent([ this.styleURI = 'data:text/css,' + encodeURIComponent([
'#' + this.widgetId + ' {', '#' + this.widgetId + ' {',
'list-style-image: url(', 'list-style-image: url(',
@ -785,7 +790,7 @@ vAPI.messaging.listen = function(listenerName, callback) {
vAPI.messaging.onMessage = function({target, data}) { vAPI.messaging.onMessage = function({target, data}) {
var messageManager = target.messageManager; var messageManager = target.messageManager;
if (!messageManager) { if ( !messageManager ) {
// Message came from a popup, and its message manager is not usable. // Message came from a popup, and its message manager is not usable.
// So instead we broadcast to the parent window. // So instead we broadcast to the parent window.
messageManager = target messageManager = target
@ -793,9 +798,9 @@ vAPI.messaging.onMessage = function({target, data}) {
.chromeEventHandler.ownerDocument.defaultView.messageManager; .chromeEventHandler.ownerDocument.defaultView.messageManager;
} }
var listenerId = data.portName.split('|'); var listenerId = data.channelName.split('|');
var requestId = data.requestId; var requestId = data.requestId;
var portName = listenerId[1]; var channelName = listenerId[1];
listenerId = listenerId[0]; listenerId = listenerId[0];
var callback = vAPI.messaging.NOOPFUNC; var callback = vAPI.messaging.NOOPFUNC;
@ -803,14 +808,13 @@ vAPI.messaging.onMessage = function({target, data}) {
callback = function(response) { callback = function(response) {
var message = JSON.stringify({ var message = JSON.stringify({
requestId: requestId, requestId: requestId,
portName: portName, channelName: channelName,
msg: response !== undefined ? response : null msg: response !== undefined ? response : null
}); });
if (messageManager.sendAsyncMessage) { if ( messageManager.sendAsyncMessage ) {
messageManager.sendAsyncMessage(listenerId, message); messageManager.sendAsyncMessage(listenerId, message);
} } else {
else {
messageManager.broadcastAsyncMessage(listenerId, message); messageManager.broadcastAsyncMessage(listenerId, message);
} }
}; };
@ -824,7 +828,7 @@ vAPI.messaging.onMessage = function({target, data}) {
// Specific handler // Specific handler
var r = vAPI.messaging.UNHANDLED; var r = vAPI.messaging.UNHANDLED;
var listener = vAPI.messaging.listeners[portName]; var listener = vAPI.messaging.listeners[channelName];
if ( typeof listener === 'function' ) { if ( typeof listener === 'function' ) {
r = listener(data.msg, sender, callback); r = listener(data.msg, sender, callback);
} }
@ -897,6 +901,7 @@ var httpObserver = {
frameId: null, frameId: null,
parentFrameId: null parentFrameId: null
}, },
QueryInterface: (function() { QueryInterface: (function() {
var {XPCOMUtils} = Cu['import']('resource://gre/modules/XPCOMUtils.jsm', {}); var {XPCOMUtils} = Cu['import']('resource://gre/modules/XPCOMUtils.jsm', {});
return XPCOMUtils.generateQI([ return XPCOMUtils.generateQI([
@ -904,38 +909,41 @@ var httpObserver = {
Ci.nsISupportsWeakReference Ci.nsISupportsWeakReference
]); ]);
})(), })(),
register: function() { register: function() {
Services.obs.addObserver(httpObserver, 'http-on-opening-request', true); Services.obs.addObserver(httpObserver, 'http-on-opening-request', true);
// Services.obs.addObserver(httpObserver, 'http-on-modify-request', true); // Services.obs.addObserver(httpObserver, 'http-on-modify-request', true);
Services.obs.addObserver(httpObserver, 'http-on-examine-response', true); Services.obs.addObserver(httpObserver, 'http-on-examine-response', true);
}, },
unregister: function() { unregister: function() {
Services.obs.removeObserver(httpObserver, 'http-on-opening-request'); Services.obs.removeObserver(httpObserver, 'http-on-opening-request');
// Services.obs.removeObserver(httpObserver, 'http-on-modify-request'); // Services.obs.removeObserver(httpObserver, 'http-on-modify-request');
Services.obs.removeObserver(httpObserver, 'http-on-examine-response'); Services.obs.removeObserver(httpObserver, 'http-on-examine-response');
}, },
observe: function(httpChannel, topic) { observe: function(httpChannel, topic) {
// No need for QueryInterface if this check is performed? // No need for QueryInterface if this check is performed?
if (!(httpChannel instanceof Ci.nsIHttpChannel)) { if ( !(httpChannel instanceof Ci.nsIHttpChannel) ) {
return; return;
} }
var URI = httpChannel.URI, tabId, result; var URI = httpChannel.URI, tabId, result;
if (topic === 'http-on-modify-request') { if ( topic === 'http-on-modify-request' ) {
// var onHeadersReceived = vAPI.net.onHeadersReceived; // var onHeadersReceived = vAPI.net.onHeadersReceived;
return; return;
} }
if (topic === 'http-on-examine-request') { if ( topic === 'http-on-examine-request' ) {
try { try {
tabId = httpChannel.getProperty('tabId'); tabId = httpChannel.getProperty('tabId');
} catch (ex) { } catch (ex) {
return; return;
} }
if (!tabId) { if ( !tabId ) {
return; return;
} }
@ -954,7 +962,7 @@ var httpObserver = {
responseHeaders: result ? [{name: topic, value: result}] : [] responseHeaders: result ? [{name: topic, value: result}] : []
}); });
if (result) { if ( result ) {
httpChannel.setResponseHeader( httpChannel.setResponseHeader(
topic, topic,
result.responseHeaders.pop().value, result.responseHeaders.pop().value,
@ -969,7 +977,7 @@ var httpObserver = {
var lastRequest = this.lastRequest; var lastRequest = this.lastRequest;
if (!lastRequest.url || lastRequest.url !== URI.spec) { if ( !lastRequest.url || lastRequest.url !== URI.spec ) {
lastRequest.url = null; lastRequest.url = null;
return; return;
} }
@ -978,14 +986,14 @@ var httpObserver = {
// the URL will be the same, so it could fall into an infinite loop // the URL will be the same, so it could fall into an infinite loop
lastRequest.url = null; lastRequest.url = null;
if (lastRequest.type === 'main_frame' if ( lastRequest.type === 'main_frame'
&& httpChannel instanceof Ci.nsIWritablePropertyBag) { && httpChannel instanceof Ci.nsIWritablePropertyBag ) {
httpChannel.setProperty('tabId', lastRequest.tabId); httpChannel.setProperty('tabId', lastRequest.tabId);
} }
var onBeforeRequest = vAPI.net.onBeforeRequest; var onBeforeRequest = vAPI.net.onBeforeRequest;
if (!onBeforeRequest.types.has(lastRequest.type)) { if ( !onBeforeRequest.types.has(lastRequest.type) ) {
return; return;
} }
@ -997,14 +1005,13 @@ var httpObserver = {
parentFrameId: lastRequest.parentFrameId parentFrameId: lastRequest.parentFrameId
}); });
if (!result || typeof result !== 'object') { if ( !result || typeof result !== 'object' ) {
return; return;
} }
if (result.cancel === true) { if ( result.cancel === true ) {
httpChannel.cancel(this.ABORT); httpChannel.cancel(this.ABORT);
} } else if ( result.redirectUrl ) {
else if (result.redirectUrl) {
httpChannel.redirectionLimit = 1; httpChannel.redirectionLimit = 1;
httpChannel.redirectTo( httpChannel.redirectTo(
Services.io.newURI(result.redirectUrl, null, null) Services.io.newURI(result.redirectUrl, null, null)
@ -1079,29 +1086,29 @@ vAPI.contextMenu.displayMenuItem = function(e) {
var gContextMenu = doc.defaultView.gContextMenu; var gContextMenu = doc.defaultView.gContextMenu;
var menuitem = doc.getElementById(vAPI.contextMenu.menuItemId); var menuitem = doc.getElementById(vAPI.contextMenu.menuItemId);
if (!/^https?$/.test(gContextMenu.browser.currentURI.scheme)) { if ( /^https?$/.test(gContextMenu.browser.currentURI.scheme) === false) {
menuitem.hidden = true; menuitem.hidden = true;
return; return;
} }
var ctx = vAPI.contextMenu.contexts; var ctx = vAPI.contextMenu.contexts;
if (!ctx) { if ( !ctx ) {
menuitem.hidden = false; menuitem.hidden = false;
return; return;
} }
var ctxMap = vAPI.contextMenu.contextMap; var ctxMap = vAPI.contextMenu.contextMap;
for (var context of ctx) { for ( var context of ctx ) {
if (context === 'page' && !gContextMenu.onLink && !gContextMenu.onImage if ( context === 'page' && !gContextMenu.onLink && !gContextMenu.onImage
&& !gContextMenu.onEditableArea && !gContextMenu.inFrame && !gContextMenu.onEditableArea && !gContextMenu.inFrame
&& !gContextMenu.onVideo && !gContextMenu.onAudio) { && !gContextMenu.onVideo && !gContextMenu.onAudio ) {
menuitem.hidden = false; menuitem.hidden = false;
return; return;
} }
if (gContextMenu[ctxMap[context]]) { if ( gContextMenu[ctxMap[context]] ) {
menuitem.hidden = false; menuitem.hidden = false;
return; return;
} }
@ -1113,7 +1120,7 @@ vAPI.contextMenu.displayMenuItem = function(e) {
/******************************************************************************/ /******************************************************************************/
vAPI.contextMenu.register = function(doc) { vAPI.contextMenu.register = function(doc) {
if (!this.menuItemId) { if ( !this.menuItemId ) {
return; return;
} }
@ -1134,7 +1141,7 @@ vAPI.contextMenu.register = function(doc) {
/******************************************************************************/ /******************************************************************************/
vAPI.contextMenu.unregister = function(doc) { vAPI.contextMenu.unregister = function(doc) {
if (!this.menuItemId) { if ( !this.menuItemId ) {
return; return;
} }
@ -1153,10 +1160,9 @@ vAPI.contextMenu.create = function(details, callback) {
this.menuLabel = details.title; this.menuLabel = details.title;
this.contexts = details.contexts; this.contexts = details.contexts;
if (Array.isArray(this.contexts) && this.contexts.length) { if ( Array.isArray(this.contexts) && this.contexts.length ) {
this.contexts = this.contexts.indexOf('all') === -1 ? this.contexts : null; this.contexts = this.contexts.indexOf('all') === -1 ? this.contexts : null;
} } else {
else {
// default in Chrome // default in Chrome
this.contexts = ['page']; this.contexts = ['page'];
} }
@ -1168,15 +1174,11 @@ vAPI.contextMenu.create = function(details, callback) {
tagName: gContextMenu.target.tagName.toLowerCase() tagName: gContextMenu.target.tagName.toLowerCase()
}; };
if (gContextMenu.inFrame) { if ( gContextMenu.inFrame ) {
details.frameUrl = gContextMenu.focusedWindow.location.href; details.frameUrl = gContextMenu.focusedWindow.location.href;
} } else if ( gContextMenu.onImage || gContextMenu.onAudio || gContextMenu.onVideo ) {
else if (gContextMenu.onImage
|| gContextMenu.onAudio
|| gContextMenu.onVideo) {
details.srcUrl = gContextMenu.mediaURL; details.srcUrl = gContextMenu.mediaURL;
} } else if ( gContextMenu.onLink ) {
else if (gContextMenu.onLink) {
details.linkUrl = gContextMenu.linkURL; details.linkUrl = gContextMenu.linkURL;
} }
@ -1186,7 +1188,7 @@ vAPI.contextMenu.create = function(details, callback) {
}); });
}; };
for (var win of vAPI.tabs.getWindows()) { for ( var win of vAPI.tabs.getWindows() ) {
this.register(win.document); this.register(win.document);
} }
}; };
@ -1194,7 +1196,7 @@ vAPI.contextMenu.create = function(details, callback) {
/******************************************************************************/ /******************************************************************************/
vAPI.contextMenu.remove = function() { vAPI.contextMenu.remove = function() {
for (var win of vAPI.tabs.getWindows()) { for ( var win of vAPI.tabs.getWindows() ) {
this.unregister(win.document); this.unregister(win.document);
} }
@ -1224,7 +1226,7 @@ vAPI.onLoadAllCompleted = function() {};
// clean up when the extension is disabled // clean up when the extension is disabled
window.addEventListener('unload', function() { window.addEventListener('unload', function() {
for (var unload of vAPI.unload) { for ( var unload of vAPI.unload ) {
unload(); unload();
} }

View File

@ -44,7 +44,7 @@ var messagingConnector = function(response) {
var channels = vAPI.messaging.channels; var channels = vAPI.messaging.channels;
var channel, listener; var channel, listener;
if ( response.broadcast === true && !response.portName ) { if ( response.broadcast === true && !response.channelName ) {
for ( channel in channels ) { for ( channel in channels ) {
if ( channels.hasOwnProperty(channel) === false ) { if ( channels.hasOwnProperty(channel) === false ) {
continue; continue;
@ -64,7 +64,7 @@ var messagingConnector = function(response) {
} }
if ( !listener ) { if ( !listener ) {
channel = channels[response.portName]; channel = channels[response.channelName];
listener = channel && channel.listener; listener = channel && channel.listener;
} }
@ -124,7 +124,7 @@ vAPI.messaging = {
} }
this.channels[channelName] = { this.channels[channelName] = {
portName: channelName, channelName: channelName,
listener: typeof callback === 'function' ? callback : null, listener: typeof callback === 'function' ? callback : null,
send: function(message, callback) { send: function(message, callback) {
if ( !vAPI.messaging.connector ) { if ( !vAPI.messaging.connector ) {
@ -132,7 +132,7 @@ vAPI.messaging = {
} }
message = { message = {
portName: vAPI.messaging.connectorId + '|' + this.portName, channelName: vAPI.messaging.connectorId + '|' + this.channelName,
msg: message msg: message
}; };
@ -144,7 +144,7 @@ vAPI.messaging = {
sendAsyncMessage('ublock:background', message); sendAsyncMessage('ublock:background', message);
}, },
close: function() { close: function() {
delete vAPI.messaging.channels[this.portName]; delete vAPI.messaging.channels[this.channelName];
} }
}; };

View File

@ -19,6 +19,7 @@
Home: https://github.com/gorhill/uBlock Home: https://github.com/gorhill/uBlock
*/ */
/* global ytspf */
'use strict'; 'use strict';
/******************************************************************************/ /******************************************************************************/
@ -31,25 +32,29 @@
self.vAPI = self.vAPI || {}; self.vAPI = self.vAPI || {};
if (/^www\.youtube(-nocookie)?\.com/.test(location.host)) { if ( /^www\.youtube(-nocookie)?\.com/.test(location.host) ) {
vAPI.sitePatch = function() { vAPI.sitePatch = function() {
// disable spf // disable spf
window.ytspf = {}; window.ytspf = {};
Object.defineProperty(ytspf, 'enabled', {'value': false}); Object.defineProperty(ytspf, 'enabled', {'value': false});
// based on ExtendTube's ad removing solution // Based on ExtendTube's ad removing solution
var p, yt = {}, config_ = {}, ytplayer = {}, playerConfig = { args: {} }; var p;
var yt = {};
var config_ = {};
var ytplayer = {};
var playerConfig = { args: {} };
Object.defineProperties(yt, { Object.defineProperties(yt, {
'playerConfig': { 'playerConfig': {
get: function() { return playerConfig; }, get: function() { return playerConfig; },
set: function(data) { set: function(data) {
if (data && typeof data === 'object' if ( data && typeof data === 'object'
&& data.args && typeof data.args === 'object') { && data.args && typeof data.args === 'object' ) {
var nope = /ad\d?_|afv|watermark|adsense|xfp/; var nope = /ad\d?_|afv|watermark|adsense|xfp/;
for (var prop in data.args) { for ( var prop in data.args ) {
if (nope.test(prop) && !/policy/.test(prop)) { if ( nope.test(prop) && !/policy/.test(prop) ) {
delete data.args[prop]; delete data.args[prop];
} }
} }
@ -59,7 +64,7 @@ if (/^www\.youtube(-nocookie)?\.com/.test(location.host)) {
var playerRoot = document.querySelector('[data-swf-config]'); var playerRoot = document.querySelector('[data-swf-config]');
if (playerRoot) { if ( playerRoot ) {
playerRoot.dataset.swfConfig = JSON.stringify(yt.playerConfig); playerRoot.dataset.swfConfig = JSON.stringify(yt.playerConfig);
} }
} }
@ -80,8 +85,8 @@ if (/^www\.youtube(-nocookie)?\.com/.test(location.host)) {
set: function(value) { yt.playerConfig = value; } set: function(value) { yt.playerConfig = value; }
}); });
if (window.yt) { if ( window.yt ) {
for (p in window.yt) { yt[p] = window.yt[p]; } for ( p in window.yt ) { yt[p] = window.yt[p]; }
window.yt = yt; window.yt = yt;
} }
else { else {
@ -91,8 +96,8 @@ if (/^www\.youtube(-nocookie)?\.com/.test(location.host)) {
}); });
} }
if (window.ytplayer) { if ( window.ytplayer ) {
for (p in window.ytplayer) { ytplayer[p] = window.ytplayer[p]; } for ( p in window.ytplayer ) { ytplayer[p] = window.ytplayer[p]; }
window.ytplayer = ytplayer; window.ytplayer = ytplayer;
} }
else { else {
@ -103,6 +108,6 @@ if (/^www\.youtube(-nocookie)?\.com/.test(location.host)) {
} }
}; };
} }
/*else if (check url) { /*else if ( check url ) {
vAPI.sitePatch do something vAPI.sitePatch do something
}*/ }*/

View File

@ -65,8 +65,11 @@ safari.extension.addContentScriptFromURL(
/******************************************************************************/ /******************************************************************************/
safari.extension.settings.addEventListener('change', function(e) { safari.extension.settings.addEventListener('change', function(e) {
if (e.key === 'open_prefs') { if ( e.key === 'open_prefs' ) {
vAPI.tabs.open({url: 'dashboard.html', active: true}); vAPI.tabs.open({
url: 'dashboard.html',
active: true
});
} }
}, false); }, false);
@ -75,46 +78,43 @@ safari.extension.settings.addEventListener('change', function(e) {
vAPI.storage = { vAPI.storage = {
_storage: safari.extension.settings, _storage: safari.extension.settings,
QUOTA_BYTES: 52428800, // copied from Info.plist QUOTA_BYTES: 52428800, // copied from Info.plist
get: function(keys, callback) { get: function(keys, callback) {
if (typeof callback !== 'function') { if ( typeof callback !== 'function' ) {
return; return;
} }
var i, value, result = {}; var i, value, result = {};
if (keys === null) { if ( keys === null ) {
for (i in this._storage) { for ( i in this._storage ) {
value = this._storage[i]; value = this._storage[i];
if (typeof value === 'string') { if ( typeof value === 'string' ) {
result[i] = JSON.parse(value); result[i] = JSON.parse(value);
} }
} }
} } else if ( typeof keys === 'string' ) {
else if (typeof keys === 'string') {
value = this._storage[keys]; value = this._storage[keys];
if (typeof value === 'string') { if ( typeof value === 'string' ) {
result[keys] = JSON.parse(value); result[keys] = JSON.parse(value);
} }
} } else if ( Array.isArray(keys) ) {
else if (Array.isArray(keys)) { for ( i = 0; i < keys.length; i++ ) {
for ( i = 0; i < keys.length; ++i) {
value = this._storage[i]; value = this._storage[i];
if (typeof value === 'string') { if ( typeof value === 'string' ) {
result[keys[i]] = JSON.parse(value); result[keys[i]] = JSON.parse(value);
} }
} }
} } else if ( typeof keys === 'object' ) {
else if (typeof keys === 'object') { for ( i in keys ) {
for (i in keys) {
value = this._storage[i]; value = this._storage[i];
if (typeof value === 'string') { if ( typeof value === 'string' ) {
result[i] = JSON.parse(value); result[i] = JSON.parse(value);
} } else {
else {
result[i] = keys[i]; result[i] = keys[i];
} }
} }
@ -122,46 +122,49 @@ vAPI.storage = {
callback(result); callback(result);
}, },
set: function(details, callback) { set: function(details, callback) {
for (var key in details) { for ( var key in details ) {
this._storage.setItem(key, JSON.stringify(details[key])); this._storage.setItem(key, JSON.stringify(details[key]));
} }
if (typeof callback === 'function') { if ( typeof callback === 'function' ) {
callback(); callback();
} }
}, },
remove: function(keys) { remove: function(keys) {
if (typeof keys === 'string') { if ( typeof keys === 'string' ) {
keys = [keys]; keys = [keys];
} }
for (var i = 0; i < keys.length; ++i) { for ( var i = 0; i < keys.length; i++ ) {
this._storage.removeItem(keys[i]); this._storage.removeItem(keys[i]);
} }
}, },
clear: function(callback) { clear: function(callback) {
this._storage.clear(); this._storage.clear();
callback(); callback();
}, },
getBytesInUse: function(keys, callback) { getBytesInUse: function(keys, callback) {
if (typeof callback !== 'function') { if ( typeof callback !== 'function' ) {
return; return;
} }
var key, size = 0; var key, size = 0;
if (keys === null) { if ( keys === null ) {
for (key in this._storage) { for ( key in this._storage ) {
size += (this._storage[key] || '').length; size += (this._storage[key] || '').length;
} }
} } else {
else { if ( typeof keys === 'string' ) {
if (typeof keys === 'string') {
keys = [keys]; keys = [keys];
} }
for (key = 0; key < keys.length; ++key) { for ( key = 0; key < keys.length; key++ ) {
size += (this._storage[keys[key]] || '').length; size += (this._storage[keys[key]] || '').length;
} }
} }
@ -182,23 +185,21 @@ vAPI.tabs = {
vAPI.tabs.registerListeners = function() { vAPI.tabs.registerListeners = function() {
var onNavigation = this.onNavigation; var onNavigation = this.onNavigation;
if (typeof onNavigation === 'function') { this.onNavigation = function(e) {
this.onNavigation = function(e) { // e.url is not present for local files or data URIs,
// e.url is not present for local files or data URIs, // or probably for those URLs which we don't have access to
// or probably for those URLs which we don't have access to if ( !e.target || !e.target.url ) {
if (!e.target || !e.target.url) { return;
return; }
}
onNavigation({ onNavigation({
frameId: 0, frameId: 0,
tabId: vAPI.tabs.getTabId(e.target), tabId: vAPI.tabs.getTabId(e.target),
url: e.target.url url: e.target.url
}); });
}; };
safari.application.addEventListener('navigate', this.onNavigation, true); safari.application.addEventListener('navigate', this.onNavigation, true);
}
// onClosed handled in the main tab-close event // onClosed handled in the main tab-close event
// onUpdated handled via monitoring the history.pushState on web-pages // onUpdated handled via monitoring the history.pushState on web-pages
@ -208,8 +209,8 @@ vAPI.tabs.registerListeners = function() {
/******************************************************************************/ /******************************************************************************/
vAPI.tabs.getTabId = function(tab) { vAPI.tabs.getTabId = function(tab) {
for (var i in vAPI.tabs.stack) { for ( var i in vAPI.tabs.stack ) {
if (vAPI.tabs.stack[i] === tab) { if ( vAPI.tabs.stack[i] === tab ) {
return +i; return +i;
} }
} }
@ -222,15 +223,14 @@ vAPI.tabs.getTabId = function(tab) {
vAPI.tabs.get = function(tabId, callback) { vAPI.tabs.get = function(tabId, callback) {
var tab; var tab;
if (tabId === null) { if ( tabId === null ) {
tab = safari.application.activeBrowserWindow.activeTab; tab = safari.application.activeBrowserWindow.activeTab;
tabId = this.getTabId(tab); tabId = this.getTabId(tab);
} } else {
else {
tab = this.stack[tabId]; tab = this.stack[tabId];
} }
if (!tab) { if ( !tab ) {
callback(); callback();
return; return;
} }
@ -255,36 +255,36 @@ vAPI.tabs.get = function(tabId, callback) {
// select: true // if a tab is already opened with that url, then select it instead of opening a new one // select: true // if a tab is already opened with that url, then select it instead of opening a new one
vAPI.tabs.open = function(details) { vAPI.tabs.open = function(details) {
if (!details.url) { if ( !details.url ) {
return null; return null;
} }
// extension pages // extension pages
if (!/^[\w-]{2,}:/.test(details.url)) { if ( /^[\w-]{2,}:/.test(details.url) === false ) {
details.url = vAPI.getURL(details.url); details.url = vAPI.getURL(details.url);
} }
var curWin, tab; var curWin, tab;
if (details.select) { if ( details.select ) {
tab = safari.application.browserWindows.some(function(win) { tab = safari.application.browserWindows.some(function(win) {
var rgxHash = /#.*/; var rgxHash = /#.*/;
// this is questionable // this is questionable
var url = details.url.replace(rgxHash, ''); var url = details.url.replace(rgxHash, '');
for (var i = 0; i < win.tabs.length; ++i) { for ( var i = 0; i < win.tabs.length; i++ ) {
if (win.tabs[i].url.replace(rgxHash, '') === url) { if ( win.tabs[i].url.replace(rgxHash, '') === url ) {
win.tabs[i].activate(); win.tabs[i].activate();
return true; return true;
} }
} }
}); });
if (tab) { if ( tab ) {
return; return;
} }
} }
if (details.active === undefined) { if ( details.active === undefined ) {
details.active = true; details.active = true;
} }
@ -292,14 +292,14 @@ vAPI.tabs.open = function(details) {
// it must be calculated before opening a new tab, // it must be calculated before opening a new tab,
// otherwise the new tab will be the active tab here // otherwise the new tab will be the active tab here
if (details.index === -1) { if ( details.index === -1 ) {
details.index = curWin.tabs.indexOf(curWin.activeTab) + 1; details.index = curWin.tabs.indexOf(curWin.activeTab) + 1;
} }
tab = details.tabId && this.stack[details.tabId] tab = details.tabId && this.stack[details.tabId]
|| curWin.openTab(details.active ? 'foreground' : 'background'); || curWin.openTab(details.active ? 'foreground' : 'background');
if (details.index !== undefined) { if ( details.index !== undefined ) {
curWin.insertTab(tab, details.index); curWin.insertTab(tab, details.index);
} }
@ -309,16 +309,16 @@ vAPI.tabs.open = function(details) {
/******************************************************************************/ /******************************************************************************/
vAPI.tabs.remove = function(tabIds) { vAPI.tabs.remove = function(tabIds) {
if (tabIds instanceof SafariBrowserTab) { if ( tabIds instanceof SafariBrowserTab ) {
tabIds = this.getTabId(tabIds); tabIds = this.getTabId(tabIds);
} }
if (!Array.isArray(tabIds)) { if ( !Array.isArray(tabIds) ) {
tabIds = [tabIds]; tabIds = [tabIds];
} }
for (var i = 0; i < tabIds.length; i++) { for ( var i = 0; i < tabIds.length; i++ ) {
if (this.stack[tabIds[i]]) { if ( this.stack[tabIds[i]] ) {
this.stack[tabIds[i]].close(); this.stack[tabIds[i]].close();
} }
} }
@ -329,14 +329,13 @@ vAPI.tabs.remove = function(tabIds) {
vAPI.tabs.injectScript = function(tabId, details, callback) { vAPI.tabs.injectScript = function(tabId, details, callback) {
var tab; var tab;
if (tabId) { if ( tabId ) {
tab = this.stack[tabId]; tab = this.stack[tabId];
} } else {
else {
tab = safari.application.activeBrowserWindow.activeTab; tab = safari.application.activeBrowserWindow.activeTab;
} }
if (details.file) { if ( details.file ) {
var xhr = new XMLHttpRequest; var xhr = new XMLHttpRequest;
xhr.overrideMimeType('application/x-javascript;charset=utf-8'); xhr.overrideMimeType('application/x-javascript;charset=utf-8');
xhr.open('GET', details.file, false); xhr.open('GET', details.file, false);
@ -345,14 +344,14 @@ vAPI.tabs.injectScript = function(tabId, details, callback) {
} }
tab.page.dispatchMessage('broadcast', { tab.page.dispatchMessage('broadcast', {
portName: 'vAPI', channelName: 'vAPI',
msg: { msg: {
cmd: 'injectScript', cmd: 'injectScript',
details: details details: details
} }
}); });
if (typeof callback === 'function') { if ( typeof callback === 'function' ) {
setTimeout(callback, 13); setTimeout(callback, 13);
} }
}; };
@ -364,10 +363,10 @@ vAPI.tabs.injectScript = function(tabId, details, callback) {
(function() { (function() {
var wins = safari.application.browserWindows, i = wins.length, j; var wins = safari.application.browserWindows, i = wins.length, j;
while (i--) { while ( i-- ) {
j = wins[i].tabs.length; j = wins[i].tabs.length;
while (j--) { while ( j-- ) {
vAPI.tabs.stack[vAPI.tabs.stackId++] = wins[i].tabs[j]; vAPI.tabs.stack[vAPI.tabs.stackId++] = wins[i].tabs[j];
} }
} }
@ -377,7 +376,7 @@ vAPI.tabs.injectScript = function(tabId, details, callback) {
safari.application.addEventListener('open', function(e) { safari.application.addEventListener('open', function(e) {
// ignore windows // ignore windows
if (e.target instanceof SafariBrowserTab) { if ( e.target instanceof SafariBrowserTab ) {
vAPI.tabs.stack[vAPI.tabs.stackId++] = e.target; vAPI.tabs.stack[vAPI.tabs.stackId++] = e.target;
} }
}, true); }, true);
@ -386,16 +385,16 @@ safari.application.addEventListener('open', function(e) {
safari.application.addEventListener('close', function(e) { safari.application.addEventListener('close', function(e) {
// ignore windows // ignore windows
if (!(e.target instanceof SafariBrowserTab)) { if ( !(e.target instanceof SafariBrowserTab) ) {
return; return;
} }
var tabId = vAPI.tabs.getTabId(e.target); var tabId = vAPI.tabs.getTabId(e.target);
if (tabId !== -1) { if ( tabId !== -1 ) {
// to not add another listener, put this here // to not add another listener, put this here
// instead of vAPI.tabs.registerListeners // instead of vAPI.tabs.registerListeners
if (typeof vAPI.tabs.onClosed === 'function') { if ( typeof vAPI.tabs.onClosed === 'function' ) {
vAPI.tabs.onClosed(tabId); vAPI.tabs.onClosed(tabId);
} }
@ -409,7 +408,7 @@ safari.application.addEventListener('close', function(e) {
// update badge when tab is activated // update badge when tab is activated
safari.application.addEventListener('activate', function(e) { safari.application.addEventListener('activate', function(e) {
// ignore windows // ignore windows
if (!(e.target instanceof SafariBrowserTab)) { if ( !(e.target instanceof SafariBrowserTab) ) {
return; return;
} }
@ -434,11 +433,10 @@ vAPI.setIcon = function(tabId, iconStatus, badge) {
); );
// from 'activate' event // from 'activate' event
if (tabId === undefined) { if ( tabId === undefined ) {
tabId = curTabId; tabId = curTabId;
} } else {
else { if ( badge && /\D/.test(badge) ) {
if (badge && typeof badge !== 'number') {
badge = 999; badge = 999;
} }
@ -448,17 +446,17 @@ vAPI.setIcon = function(tabId, iconStatus, badge) {
}; };
} }
if (tabId !== curTabId) { if ( tabId !== curTabId ) {
return; return;
} }
// if the selected tab has the same ID, then update the badge too, // if the selected tab has the same ID, then update the badge too,
// or always update it when changing tabs ('activate' event) // or always update it when changing tabs ('activate' event)
var items = safari.extension.toolbarItems var items = safari.extension.toolbarItems;
var i = items.length; var i = items.length;
while (i--) { while ( i-- ) {
if (items[i].browserWindow === safari.application.activeBrowserWindow) { if ( items[i].browserWindow === safari.application.activeBrowserWindow ) {
var icon = vAPI.tabIcons[tabId]; var icon = vAPI.tabIcons[tabId];
items[i].badge = icon && icon.badge || 0; items[i].badge = icon && icon.badge || 0;
// TODO: a disabled icon for Safari // TODO: a disabled icon for Safari
@ -493,7 +491,7 @@ vAPI.messaging.onMessage = function(request) {
request.name, request.name,
{ {
requestId: request.message.requestId, requestId: request.message.requestId,
portName: request.message.portName, channelName: request.message.channelName,
msg: response !== undefined ? response : null msg: response !== undefined ? response : null
} }
); );
@ -508,7 +506,7 @@ vAPI.messaging.onMessage = function(request) {
// Specific handler // Specific handler
var r = vAPI.messaging.UNHANDLED; var r = vAPI.messaging.UNHANDLED;
var listener = vAPI.messaging.listeners[request.message.portName]; var listener = vAPI.messaging.listeners[request.message.channelName];
if ( typeof listener === 'function' ) { if ( typeof listener === 'function' ) {
r = listener(request.message.msg, sender, callback); r = listener(request.message.msg, sender, callback);
} }
@ -557,7 +555,7 @@ vAPI.messaging.broadcast = function(message) {
msg: message msg: message
}; };
for (var tabId in vAPI.tabs.stack) { for ( var tabId in vAPI.tabs.stack ) {
vAPI.tabs.stack[tabId].page.dispatchMessage('broadcast', message); vAPI.tabs.stack[tabId].page.dispatchMessage('broadcast', message);
} }
}; };
@ -565,22 +563,22 @@ vAPI.messaging.broadcast = function(message) {
/******************************************************************************/ /******************************************************************************/
safari.application.addEventListener('beforeNavigate', function(e) { safari.application.addEventListener('beforeNavigate', function(e) {
if (!vAPI.tabs.expectPopUpFrom || e.url === 'about:blank') { if ( !vAPI.tabs.popupCandidate || e.url === 'about:blank' ) {
return; return;
} }
var details = { var details = {
url: e.url, url: e.url,
tabId: vAPI.tabs.getTabId(e.target), tabId: vAPI.tabs.getTabId(e.target),
sourceTabId: vAPI.tabs.expectPopUpFrom sourceTabId: vAPI.tabs.popupCandidate
}; };
vAPI.tabs.expectPopUpFrom = null; vAPI.tabs.popupCandidate = null;
if (vAPI.tabs.onPopup(details)) { if ( vAPI.tabs.onPopup(details) ) {
e.preventDefault(); e.preventDefault();
if (vAPI.tabs.stack[details.sourceTabId]) { if ( vAPI.tabs.stack[details.sourceTabId] ) {
vAPI.tabs.stack[details.sourceTabId].activate(); vAPI.tabs.stack[details.sourceTabId].activate();
} }
} }
@ -595,92 +593,86 @@ vAPI.net = {};
vAPI.net.registerListeners = function() { vAPI.net.registerListeners = function() {
var onBeforeRequest = this.onBeforeRequest; var onBeforeRequest = this.onBeforeRequest;
if (typeof onBeforeRequest.callback === 'function') { if ( !Array.isArray(onBeforeRequest.types) ) {
if (!Array.isArray(onBeforeRequest.types)) { onBeforeRequest.types = [];
onBeforeRequest.types = []; }
onBeforeRequest = onBeforeRequest.callback;
this.onBeforeRequest.callback = function(e) {
var block;
if ( e.name !== 'canLoad' ) {
return;
} }
onBeforeRequest = onBeforeRequest.callback; // No stopPropagation if it was called from beforeNavigate event
this.onBeforeRequest.callback = function(e) { if ( e.stopPropagation ) {
var block; e.stopPropagation();
}
if (e.name !== 'canLoad') { if ( e.message.isURLWhiteListed ) {
return; block = µBlock.URI.hostnameFromURI(e.message.isURLWhiteListed);
} block = µBlock.URI.domainFromHostname(block) || block;
e.message = !!µBlock.netWhitelist[block];
return e.message;
}
// no stopPropagation if it was called from beforeNavigate event // When the URL changes, but the document doesn't
if (e.stopPropagation) { if ( e.message.type === 'popstate' ) {
e.stopPropagation(); vAPI.tabs.onUpdated(
} vAPI.tabs.getTabId(e.target),
{url: e.message.url},
if (e.message.isWhiteListed) { {url: e.message.url}
block = µBlock.URI.hostnameFromURI(e.message.isWhiteListed); );
block = µBlock.URI.domainFromHostname(block) || block; return;
e.message = !!µBlock.netWhitelist[block]; } else if ( e.message.type === 'popup' ) {
return e.message;
}
// when the URL changes, but the document doesn't
if (e.message.type === 'popstate') {
vAPI.tabs.onUpdated(
vAPI.tabs.getTabId(e.target),
{url: e.message.url},
{url: e.message.url}
);
return;
}
// blocking unwanted pop-ups // blocking unwanted pop-ups
else if (e.message.type === 'popup') { if ( e.message.url === 'about:blank' ) {
if (e.message.url === 'about:blank') { vAPI.tabs.popupCandidate = vAPI.tabs.getTabId(e.target);
vAPI.tabs.expectPopUpFrom = vAPI.tabs.getTabId(e.target); e.message = true;
e.message = true;
return;
}
e.message = !vAPI.tabs.onPopup({
url: e.message.url,
tabId: 0,
sourceTabId: vAPI.tabs.getTabId(e.target)
});
return; return;
} }
block = vAPI.net.onBeforeRequest; e.message = !vAPI.tabs.onPopup({
url: e.message.url,
tabId: 0,
sourceTabId: vAPI.tabs.getTabId(e.target)
});
return;
}
if (block.types.indexOf(e.message.type) < 0) { block = vAPI.net.onBeforeRequest;
return true;
}
e.message.tabId = vAPI.tabs.getTabId(e.target); if ( block.types.indexOf(e.message.type) === -1 ) {
block = onBeforeRequest(e.message); return true;
}
// truthy return value will allow the request, e.message.tabId = vAPI.tabs.getTabId(e.target);
// except when redirectUrl is present block = onBeforeRequest(e.message);
if (block && typeof block === 'object') {
if (block.cancel === true) { // Truthy return value will allow the request,
e.message = false; // except when redirectUrl is present
} if ( block && typeof block === 'object' ) {
else if (e.message.type === 'script' if ( block.cancel === true ) {
&& typeof block.redirectUrl === 'string') { e.message = false;
e.message = block.redirectUrl; } else if ( e.message.type === 'script'
} && typeof block.redirectUrl === 'string' ) {
else { e.message = block.redirectUrl;
e.message = true; } else {
}
}
else {
e.message = true; e.message = true;
} }
} else {
e.message = true;
}
return e.message; return e.message;
}; };
safari.application.addEventListener( safari.application.addEventListener(
'message', 'message',
this.onBeforeRequest.callback, this.onBeforeRequest.callback,
true true
); );
}
}; };
/******************************************************************************/ /******************************************************************************/
@ -701,10 +693,9 @@ vAPI.contextMenu.create = function(details, callback) {
var menuItemId = details.id; var menuItemId = details.id;
var menuTitle = details.title; var menuTitle = details.title;
if (Array.isArray(contexts) && contexts.length) { if ( Array.isArray(contexts) && contexts.length ) {
contexts = contexts.indexOf('all') === -1 ? contexts : null; contexts = contexts.indexOf('all') === -1 ? contexts : null;
} } else {
else {
// default in Chrome // default in Chrome
contexts = ['page']; contexts = ['page'];
} }
@ -712,44 +703,44 @@ vAPI.contextMenu.create = function(details, callback) {
this.onContextMenu = function(e) { this.onContextMenu = function(e) {
var uI = e.userInfo; var uI = e.userInfo;
if (uI && /^https?:\/\//i.test(uI.pageUrl)) { if ( !uI || /^https?:\/\//i.test(uI.pageUrl) === false ) {
if (contexts) { return;
var invalidContext = true; }
var ctxMap = vAPI.contextMenu.contextMap;
for (var i = 0; i < contexts.length; ++i) { if ( contexts ) {
var ctx = contexts[i]; var invalidContext = true;
var ctxMap = vAPI.contextMenu.contextMap;
if (ctx === 'audio' || ctx === 'video') { for ( var i = 0; i < contexts.length; i++ ) {
if (uI[ctxMap['image']] && uI.tagName === ctx) { var ctx = contexts[i];
invalidContext = false;
break; if ( ctx === 'audio' || ctx === 'video' ) {
} if ( uI[ctxMap['image']] && uI.tagName === ctx ) {
}
else if (uI[ctxMap[ctx]]) {
invalidContext = false; invalidContext = false;
break; break;
} }
else if (ctx === 'page') { } else if ( uI[ctxMap[ctx]] ) {
if (!(uI.insideFrame || uI.linkHref invalidContext = false;
|| uI.mediaType || uI.editable)) { break;
invalidContext = false; } else if ( ctx === 'page' ) {
break; if ( !(uI.insideFrame || uI.linkHref
} || uI.mediaType || uI.editable) ) {
invalidContext = false;
break;
} }
} }
if (invalidContext) {
return;
}
} }
e.contextMenu.appendContextMenuItem(menuItemId, menuTitle); if ( invalidContext ) {
return;
}
} }
e.contextMenu.appendContextMenuItem(menuItemId, menuTitle);
}; };
this.onContextMenuCmd = function(e) { this.onContextMenuCmd = function(e) {
if (e.command === menuItemId) { if ( e.command === menuItemId ) {
var tab = e.currentTarget.activeBrowserWindow.activeTab; var tab = e.currentTarget.activeBrowserWindow.activeTab;
e.userInfo.menuItemId = menuItemId; e.userInfo.menuItemId = menuItemId;
callback(e.userInfo, tab ? { callback(e.userInfo, tab ? {

View File

@ -42,7 +42,7 @@ var messagingConnector = function(response) {
var channels = vAPI.messaging.channels; var channels = vAPI.messaging.channels;
var channel, listener; var channel, listener;
if ( response.broadcast === true && !response.portName ) { if ( response.broadcast === true && !response.channelName ) {
for ( channel in channels ) { for ( channel in channels ) {
if ( channels.hasOwnProperty(channel) === false ) { if ( channels.hasOwnProperty(channel) === false ) {
continue; continue;
@ -62,7 +62,7 @@ var messagingConnector = function(response) {
} }
if ( !listener ) { if ( !listener ) {
channel = channels[response.portName]; channel = channels[response.channelName];
listener = channel && channel.listener; listener = channel && channel.listener;
} }
@ -79,7 +79,7 @@ var uniqueId = function() {
/******************************************************************************/ /******************************************************************************/
// relevant? // Relevant?
// https://developer.apple.com/library/safari/documentation/Tools/Conceptual/SafariExtensionGuide/MessagesandProxies/MessagesandProxies.html#//apple_ref/doc/uid/TP40009977-CH14-SW12 // https://developer.apple.com/library/safari/documentation/Tools/Conceptual/SafariExtensionGuide/MessagesandProxies/MessagesandProxies.html#//apple_ref/doc/uid/TP40009977-CH14-SW12
vAPI.messaging = { vAPI.messaging = {
channels: {}, channels: {},
@ -92,8 +92,8 @@ vAPI.messaging = {
// messages from the background script are sent to every frame, // messages from the background script are sent to every frame,
// so we need to check the connectorId to accept only // so we need to check the connectorId to accept only
// what is meant for the current context // what is meant for the current context
if (msg.name === vAPI.messaging.connectorId if ( msg.name === vAPI.messaging.connectorId
|| msg.name === 'broadcast') { || msg.name === 'broadcast' ) {
messagingConnector(msg.message); messagingConnector(msg.message);
} }
}; };
@ -101,35 +101,37 @@ vAPI.messaging = {
this.channels['vAPI'] = { this.channels['vAPI'] = {
listener: function(msg) { listener: function(msg) {
if (msg.cmd === 'injectScript' && msg.details.code) { if ( msg.cmd === 'injectScript' && msg.details.code ) {
Function(msg.details.code).call(self); Function(msg.details.code).call(self);
} }
} }
}; };
}, },
close: function() { close: function() {
if (this.connector) { if ( this.connector ) {
safari.self.removeEventListener('message', this.connector, false); safari.self.removeEventListener('message', this.connector, false);
this.connector = null; this.connector = null;
this.channels = {}; this.channels = {};
this.listeners = {}; this.listeners = {};
} }
}, },
channel: function(channelName, callback) { channel: function(channelName, callback) {
if ( !channelName ) { if ( !channelName ) {
return; return;
} }
this.channels[channelName] = { this.channels[channelName] = {
portName: channelName, channelName: channelName,
listener: typeof callback === 'function' ? callback : null, listener: typeof callback === 'function' ? callback : null,
send: function(message, callback) { send: function(message, callback) {
if (!vAPI.messaging.connector) { if ( !vAPI.messaging.connector ) {
vAPI.messaging.setup(); vAPI.messaging.setup();
} }
message = { message = {
portName: this.portName, channelName: this.channelName,
msg: message msg: message
}; };
@ -139,8 +141,8 @@ vAPI.messaging = {
} }
// popover content doesn't know messaging... // popover content doesn't know messaging...
if (safari.extension.globalPage) { if ( safari.extension.globalPage ) {
if (!safari.self.visible) { if ( !safari.self.visible ) {
return; return;
} }
@ -156,8 +158,7 @@ vAPI.messaging = {
} }
} }
}); });
} } else {
else {
safari.self.tab.dispatchMessage( safari.self.tab.dispatchMessage(
vAPI.messaging.connectorId, vAPI.messaging.connectorId,
message message
@ -165,7 +166,7 @@ vAPI.messaging = {
} }
}, },
close: function() { close: function() {
delete vAPI.messaging.channels[this.portName]; delete vAPI.messaging.channels[this.channelName];
} }
}; };
@ -184,7 +185,7 @@ vAPI.canExecuteContentScript = function() {
// This file can be included into extensin pages, // This file can be included into extensin pages,
// but the following code should run only in content pages. // but the following code should run only in content pages.
if (location.protocol === 'safari-extension:') { if ( location.protocol === 'safari-extension:' ) {
return; return;
} }
@ -192,13 +193,13 @@ if (location.protocol === 'safari-extension:') {
window.MutationObserver = window.MutationObserver || window.WebKitMutationObserver; window.MutationObserver = window.MutationObserver || window.WebKitMutationObserver;
if (!window.MutationObserver) { if ( !window.MutationObserver ) {
// dummy, minimalistic shim for older versions (<6) // Dummy, minimalistic shim for older versions (<6)
// only supports node insertions, but currently we don't use it for anything else // only supports node insertions, but currently we don't use it for anything else
window.MutationObserver = function(handler) { window.MutationObserver = function(handler) {
this.observe = function(target) { this.observe = function(target) {
target.addEventListener('DOMNodeInserted', function(e) { target.addEventListener('DOMNodeInserted', function(e) {
handler([{addedNodes: [e.target]}]); handler([{ addedNodes: [e.target] }]);
}, true); }, true);
}; };
}; };
@ -214,25 +215,26 @@ beforeLoadEvent.initEvent('beforeload');
var frameId = window === window.top ? 0 : Date.now() % 1E5; var frameId = window === window.top ? 0 : Date.now() % 1E5;
var linkHelper = document.createElement('a'); var linkHelper = document.createElement('a');
var onBeforeLoad = function(e, details) { var onBeforeLoad = function(e, details) {
if (e.url && e.url.slice(0, 5) === 'data:') { if ( e.url && e.url.slice(0, 5) === 'data:' ) {
return; return;
} }
linkHelper.href = details ? details.url : e.url; linkHelper.href = details ? details.url : e.url;
if (!(/^https?:/.test(linkHelper.protocol) || (details && details.type === 'popup'))) { if ( linkHelper.protocol !== 'http:' && linkHelper.protocol !== 'https:' ) {
return; if ( !(details && details.type === 'popup') ) {
return;
}
} }
if (details) { if ( details ) {
details.url = linkHelper.href; details.url = linkHelper.href;
} } else {
else {
details = { details = {
url: linkHelper.href url: linkHelper.href
}; };
switch (e.target.nodeName.toLowerCase()) { switch ( e.target.nodeName.toLowerCase() ) {
case 'frame': case 'frame':
case 'iframe': case 'iframe':
details.type = 'sub_frame'; details.type = 'sub_frame';
@ -251,11 +253,10 @@ var onBeforeLoad = function(e, details) {
case 'link': case 'link':
var rel = e.target.rel.trim().toLowerCase(); var rel = e.target.rel.trim().toLowerCase();
if (rel.indexOf('icon') > -1) { if ( rel.indexOf('icon') !== -1 ) {
details.type = 'image'; details.type = 'image';
break; break;
} } else if ( rel === 'stylesheet' ) {
else if (rel === 'stylesheet') {
details.type = 'stylesheet'; details.type = 'stylesheet';
break; break;
} }
@ -263,10 +264,11 @@ var onBeforeLoad = function(e, details) {
details.type = 'other'; details.type = 'other';
} }
// This can run even before the first DOMSubtreeModified event fired }
if (firstMutation) {
firstMutation(); // This can run even before the first DOMSubtreeModified event fired
} if ( firstMutation ) {
firstMutation();
} }
// tabId is determined in the background script // tabId is determined in the background script
@ -277,35 +279,36 @@ var onBeforeLoad = function(e, details) {
var response = safari.self.tab.canLoad(e, details); var response = safari.self.tab.canLoad(e, details);
if (!response) { if ( !response ) {
if (details.type === 'main_frame') { if ( details.type === 'main_frame' ) {
window.stop(); window.stop();
} } else {
else {
e.preventDefault(); e.preventDefault();
} }
return false; return false;
} }
// local mirroring, response is a data: URL here
else if (typeof response === 'string' && details.type === 'script') {
// Content Security Policy with disallowed inline scripts may break things
e.preventDefault();
details = document.createElement('script');
details.textContent = atob(response.slice(response.indexOf(',', 20) + 1));
if (e.target.hasAttribute('defer') && document.readyState === 'loading') { // Local mirroring, response should be a data: URL here
var jsOnLoad = function(ev) { if ( typeof response !== 'string' || details.type !== 'script' ) {
this.removeEventListener(ev.type, jsOnLoad, true); return;
this.body.removeChild(this.body.appendChild(details)); }
};
document.addEventListener('DOMContentLoaded', jsOnLoad, true); // Content Security Policy with disallowed inline scripts may break things
} e.preventDefault();
else { details = document.createElement('script');
e.target.parentNode.insertBefore(details, e.target); details.textContent = atob(response.slice(response.indexOf(',', 20) + 1));
details.parentNode.removeChild(details);
} if ( e.target.hasAttribute('defer') && document.readyState === 'loading' ) {
var jsOnLoad = function(ev) {
this.removeEventListener(ev.type, jsOnLoad, true);
this.body.removeChild(this.body.appendChild(details));
};
document.addEventListener('DOMContentLoaded', jsOnLoad, true);
} else {
e.target.parentNode.insertBefore(details, e.target);
details.parentNode.removeChild(details);
} }
}; };
@ -317,12 +320,13 @@ document.addEventListener('beforeload', onBeforeLoad, true);
var firstMutation = function() { var firstMutation = function() {
document.removeEventListener('DOMSubtreeModified', firstMutation, true); document.removeEventListener('DOMSubtreeModified', firstMutation, true);
firstMutation = null; firstMutation = null;
var randEventName = parseInt(Math.random() * 1e15, 10).toString(36);
var randEventName = uniqueId();
window.addEventListener(randEventName, function(e) { window.addEventListener(randEventName, function(e) {
var result = onBeforeLoad(beforeLoadEvent, e.detail); var result = onBeforeLoad(beforeLoadEvent, e.detail);
if (result === false) { if ( result === false ) {
e.detail.url = false; e.detail.url = false;
} }
}, true); }, true);
@ -334,19 +338,22 @@ var firstMutation = function() {
'var block = function(u, t) {', 'var block = function(u, t) {',
'var e = document.createEvent("CustomEvent"),', 'var e = document.createEvent("CustomEvent"),',
'd = {url: u, type: t};', 'd = {url: u, type: t};',
'e.initCustomEvent("' + randEventName + '", !1, !1, d);', 'e.initCustomEvent("' + randEventName + '", false, false, d);',
'dispatchEvent(e);', 'dispatchEvent(e);',
'return d.url === !1;', 'return d.url === false;',
'}, wo = open, xo = XMLHttpRequest.prototype.open;', '}, wo = open, xo = XMLHttpRequest.prototype.open;',
'open = function(u) {', 'open = function(u) {',
'return block(u, "popup") ? null : wo.apply(this, arguments);', 'return block(u, "popup") ? null : wo.apply(this, arguments);',
'};', '};',
'XMLHttpRequest.prototype.open = function(m, u, s) {', 'XMLHttpRequest.prototype.open = function(m, u, s) {',
'return xo.apply(this, block(u, "xmlhttprequest") ? ["HEAD", u, s] : arguments);', 'return xo.apply(',
'this,',
'block(u, "xmlhttprequest") ? ["HEAD", u, s] : arguments',
');',
'};' '};'
]; ];
if (frameId === 0) { if ( frameId === 0 ) {
tmpScript.push( tmpScript.push(
'var pS = history.pushState, rS = history.replaceState,', 'var pS = history.pushState, rS = history.replaceState,',
'onpopstate = function(e) {', 'onpopstate = function(e) {',
@ -367,16 +374,18 @@ var firstMutation = function() {
} }
var block = safari.self.tab.canLoad(beforeLoadEvent, { var block = safari.self.tab.canLoad(beforeLoadEvent, {
isWhiteListed: location.href isURLWhiteListed: location.href
}); });
if (vAPI.sitePatch && !block) { if ( vAPI.sitePatch && !block ) {
tmpScript.push('(' + vAPI.sitePatch + ')();'); tmpScript.push('(' + vAPI.sitePatch + ')();');
} }
tmpScript.push('})();'); tmpScript.push('})();');
tmpJS.textContent = tmpScript.join(''); tmpJS.textContent = tmpScript.join('');
document.documentElement.removeChild(document.documentElement.appendChild(tmpJS)); document.documentElement.removeChild(
document.documentElement.appendChild(tmpJS)
);
}; };
document.addEventListener('DOMSubtreeModified', firstMutation, true); document.addEventListener('DOMSubtreeModified', firstMutation, true);
@ -384,29 +393,29 @@ document.addEventListener('DOMSubtreeModified', firstMutation, true);
/******************************************************************************/ /******************************************************************************/
var onContextMenu = function(e) { var onContextMenu = function(e) {
var target = e.target;
var details = { var details = {
tagName: e.target.tagName.toLowerCase(), tagName: target.tagName.toLowerCase(),
pageUrl: location.href, pageUrl: location.href,
insideFrame: window !== window.top insideFrame: window !== window.top
}; };
details.editable = details.tagName === 'textarea' || details.tagName === 'input'; details.editable = details.tagName === 'textarea' || details.tagName === 'input';
if (e.target.hasOwnProperty('checked')) { if ( target.hasOwnProperty('checked') ) {
details.checked = e.target.checked; details.checked = target.checked;
} }
if (details.tagName === 'a') { if ( details.tagName === 'a' ) {
details.linkUrl = e.target.href; details.linkUrl = target.href;
} }
if (e.target.hasOwnProperty('src')) { if ( target.hasOwnProperty('src') ) {
details.srcUrl = e.target.src; details.srcUrl = target.src;
if (details.tagName === 'img') { if ( details.tagName === 'img' ) {
details.mediaType = 'image'; details.mediaType = 'image';
} } else if ( details.tagName === 'video' || details.tagName === 'audio' ) {
else if (details.tagName === 'video' || details.tagName === 'audio') {
details.mediaType = details.tagName; details.mediaType = details.tagName;
} }
} }
@ -419,7 +428,7 @@ self.addEventListener('contextmenu', onContextMenu, true);
/******************************************************************************/ /******************************************************************************/
// 'main_frame' simulation // 'main_frame' simulation
if (frameId === 0) { if ( frameId === 0 ) {
onBeforeLoad(beforeLoadEvent, { onBeforeLoad(beforeLoadEvent, {
url: location.href, url: location.href,
type: 'main_frame' type: 'main_frame'

View File

@ -84,10 +84,10 @@ vAPI.i18nData = [
vAPI.i18n = navigator.language; vAPI.i18n = navigator.language;
if (vAPI.i18nData.indexOf(vAPI.i18n) === -1) { if ( vAPI.i18nData.indexOf(vAPI.i18n) === -1 ) {
vAPI.i18n = vAPI.i18n.slice(0, 2); vAPI.i18n = vAPI.i18n.slice(0, 2);
if (vAPI.i18nData.indexOf(vAPI.i18n) === -1) { if ( vAPI.i18nData.indexOf(vAPI.i18n) === -1 ) {
vAPI.i18n = vAPI.i18nData[0]; vAPI.i18n = vAPI.i18nData[0];
} }
} }
@ -110,12 +110,12 @@ vAPI.closePopup = function() {
var safr = safari.extension.globalPage.contentWindow.safari; var safr = safari.extension.globalPage.contentWindow.safari;
var items = safr.extension.toolbarItems; var items = safr.extension.toolbarItems;
for (var i = 0; i < items.length; i++) { for ( var i = 0; i < items.length; i++ ) {
if (items[i].browserWindow !== safr.application.activeBrowserWindow) { if ( items[i].browserWindow !== safr.application.activeBrowserWindow ) {
continue; continue;
} }
if (items[i].popover && items[i].popover.visible) { if ( items[i].popover && items[i].popover.visible ) {
items[i].popover.hide(); items[i].popover.hide();
} }
} }

View File

@ -48,7 +48,7 @@ var onContextMenuClicked = function(details, tab) {
var tagName = details.tagName || ''; var tagName = details.tagName || '';
var src = details.frameUrl || details.srcUrl || details.linkUrl || ''; var src = details.frameUrl || details.srcUrl || details.linkUrl || '';
if (!tagName) { if ( !tagName ) {
if ( typeof details.frameUrl === 'string' ) { if ( typeof details.frameUrl === 'string' ) {
tagName = 'iframe'; tagName = 'iframe';
} else if ( typeof details.srcUrl === 'string' ) { } else if ( typeof details.srcUrl === 'string' ) {

View File

@ -121,7 +121,7 @@
/******************************************************************************/ /******************************************************************************/
// don't run in frames // don't run in frames
if (window.top !== window) { if ( window.top !== window ) {
return; return;
} }
@ -912,7 +912,7 @@ var startPicker = function(details) {
'ul > li#cosmeticFilters > span:nth-of-type(2)': 'cosmeticFiltersHint' 'ul > li#cosmeticFilters > span:nth-of-type(2)': 'cosmeticFiltersHint'
}; };
if (details.i18n['@@bidi_dir']) { if ( details.i18n['@@bidi_dir'] ) {
divDialog.style.direction = details.i18n['@@bidi_dir']; divDialog.style.direction = details.i18n['@@bidi_dir'];
delete i18nMap['#µBlock > div']; delete i18nMap['#µBlock > div'];
} }

View File

@ -394,7 +394,7 @@ var gotoPick = function() {
/******************************************************************************/ /******************************************************************************/
var gotoURL = function(ev) { var gotoURL = function(ev) {
if (!this.hasAttribute('href')) { if ( this.hasAttribute('href') === false) {
return; return;
} }