From 338bf595078d0a7e52c70edd93f7b866dd00d314 Mon Sep 17 00:00:00 2001 From: Raymond Hill Date: Sun, 16 Nov 2014 11:09:28 -0200 Subject: [PATCH] give specific message handlers priority over default one --- meta/crx/vapi-background.js | 394 +++++++++++++++-------------- meta/safariextz/vapi-background.js | 2 +- src/js/messaging.js | 43 +++- src/js/tab.js | 5 +- src/js/traffic.js | 2 +- src/js/vapi-background.js | 2 +- src/js/xal.js | 10 - 7 files changed, 248 insertions(+), 210 deletions(-) diff --git a/meta/crx/vapi-background.js b/meta/crx/vapi-background.js index d5a0eda0c..700e13936 100644 --- a/meta/crx/vapi-background.js +++ b/meta/crx/vapi-background.js @@ -19,9 +19,9 @@ Home: https://github.com/gorhill/uBlock */ -// For background page +/* global self */ -/* global SafariBrowserTab, Services, XPCOMUtils */ +// For background page /******************************************************************************/ @@ -44,142 +44,150 @@ vAPI.storage = chrome.storage.local; /******************************************************************************/ -vAPI.tabs = { - registerListeners: function() { - if (typeof this.onNavigation === 'function') { - chrome.webNavigation.onCommitted.addListener(this.onNavigation); +vAPI.tabs = {}; + +/******************************************************************************/ + +vAPI.tabs.registerListeners = function() { + if ( typeof this.onNavigation === 'function' ) { + chrome.webNavigation.onCommitted.addListener(this.onNavigation); + } + + if ( typeof this.onUpdated === 'function' ) { + chrome.tabs.onUpdated.addListener(this.onUpdated); + } + + if ( typeof this.onClosed === 'function' ) { + chrome.tabs.onRemoved.addListener(this.onClosed); + } + + if ( typeof this.onPopup === 'function' ) { + chrome.webNavigation.onCreatedNavigationTarget.addListener(this.onPopup); + } +}; + +/******************************************************************************/ + +vAPI.tabs.get = function(tabId, callback) { + if ( tabId !== null ) { + chrome.tabs.get(tabId, callback); + return; + } + var onTabReceived = function(tabs) { + callback(tabs[0]); + }; + chrome.tabs.query({ active: true, currentWindow: true }, onTabReceived); +}; + +/******************************************************************************/ + +// properties of the details object: +// url: 'URL', // the address that will be opened +// tabId: 1, // the tab is used if set, instead of creating a new one +// index: -1, // undefined: end of the list, -1: following tab, or after index +// active: false, // opens the tab in background - true and undefined: foreground +// 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) { + var url = details.url; + if ( typeof url !== 'string' || url === '' ) { + return null; + } + // extension pages + if ( /^[\w-]{2,}:/.test(url) !== true ) { + url = vAPI.getURL(url); + } + + // dealing with Chrome's asynchronous API + var wrapper = function() { + if ( details.active === undefined ) { + details.active = true; } - if (typeof this.onUpdated === 'function') { - chrome.tabs.onUpdated.addListener(this.onUpdated); - } - - if (typeof this.onClosed === 'function') { - chrome.tabs.onRemoved.addListener(this.onClosed); - } - - if (typeof this.onPopup === 'function') { - chrome.webNavigation.onCreatedNavigationTarget.addListener(this.onPopup); - } - }, - - get: function(tabId, callback) { - if (tabId === null) { - chrome.tabs.query( - { - active: true, - currentWindow: true - }, - function(tabs) { - callback(tabs[0]); - } - ); - } - else { - chrome.tabs.get(tabId, callback); - } - }, - /*open: function(details) { - // to keep incognito context? - chrome.windows.getCurrent(function(win) { - details.windowId = win.windowId; - chrome.tabs.create(details); - }); - },*/ - open: function(details) { - if (!details.url) { - return null; - } - // extension pages - else if (!details.url.match(/^\w{2,20}:/)) { - details.url = vAPI.getURL(details.url); - } - - // dealing with Chrome's asynhronous API - var wrapper = function() { - if (details.active === undefined) { - details.active = true; - } - - var subWrapper = function() { - var _details = { - url: details.url, - active: !!details.active - }; - - if (details.tabId) { - // update doesn't accept index, must use move - chrome.tabs.update(details.tabId, _details, function(tab) { - // if the tab doesn't exist - if ( vAPI.lastError() ) { - chrome.tabs.create(_details); - } else if ( details.index !== undefined ) { - chrome.tabs.move(tab.id, {index: details.index}); - } - }); - } - else { - if (details.index !== undefined) { - _details.index = details.index; - } - - chrome.tabs.create(_details); - } + var subWrapper = function() { + var _details = { + url: details.url, + active: !!details.active }; - if (details.index === -1) { - vAPI.tabs.get(null, function(tab) { - if (tab) { - details.index = tab.index + 1; + if ( details.tabId ) { + // update doesn't accept index, must use move + chrome.tabs.update(details.tabId, _details, function(tab) { + // if the tab doesn't exist + if ( vAPI.lastError() ) { + chrome.tabs.create(_details); + } else if ( details.index !== undefined ) { + chrome.tabs.move(tab.id, {index: details.index}); } - else { - delete details.index; - } - - subWrapper(); }); - } - else { - subWrapper(); + } else { + if ( details.index !== undefined ) { + _details.index = details.index; + } + + chrome.tabs.create(_details); } }; - if (details.select) { - // note that currentWindow may be even the window of Developer Tools - // so, test with setTimeout... - chrome.tabs.query({currentWindow: true}, function(tabs) { - var url = details.url.replace(rgxHash, ''); - // this is questionable - var rgxHash = /#.*/; - - tabs = tabs.some(function(tab) { - if (tab.url.replace(rgxHash, '') === url) { - chrome.tabs.update(tab.id, {active: true}); - return true; - } - }); - - if (!tabs) { - wrapper(); + if ( details.index === -1 ) { + vAPI.tabs.get(null, function(tab) { + if ( tab ) { + details.index = tab.index + 1; + } else { + delete details.index; } + + subWrapper(); }); } else { - wrapper(); - } - }, - close: chrome.tabs.remove.bind(chrome.tabs), - injectScript: function(tabId, details, callback) { - if (!callback) { - callback = function(){}; + subWrapper(); } + }; - if (tabId) { - chrome.tabs.executeScript(tabId, details, callback); - } - else { - chrome.tabs.executeScript(details, callback); + if ( details.select ) { + chrome.tabs.query({ currentWindow: true }, function(tabs) { + var url = details.url.replace(rgxHash, ''); + // this is questionable + var rgxHash = /#.*/; + var selected = tabs.some(function(tab) { + if ( tab.url.replace(rgxHash, '') === url ) { + chrome.tabs.update(tab.id, { active: true }); + return true; + } + }); + + if ( selected.length === 0 ) { + wrapper(); + } + }); + } + else { + wrapper(); + } +}; + +/******************************************************************************/ + +vAPI.tabs.remove = function(tabId) { + var onTabRemoved = function() { + if ( vAPI.lastError() ) { } + }; + chrome.tabs.remove(tabId, onTabRemoved); +}; + +/******************************************************************************/ + +vAPI.tabs.injectScript = function(tabId, details, callback) { + if ( typeof callback !== 'function' ) { + callback = function(){}; + } + + if ( tabId ) { + chrome.tabs.executeScript(tabId, details, callback); + } else { + chrome.tabs.executeScript(details, callback); } }; @@ -197,9 +205,7 @@ vAPI.setIcon = function(tabId, img, badge) { if ( vAPI.lastError() ) { return; } - chrome.browserAction.setBadgeText({ tabId: tabId, text: badge }); - if ( badge !== '' ) { chrome.browserAction.setBadgeBackgroundColor({ tabId: tabId, color: '#666' }); } @@ -212,71 +218,93 @@ vAPI.setIcon = function(tabId, img, badge) { vAPI.messaging = { ports: {}, listeners: {}, - connector: null, + defaultHandler: null, + UNHANDLED: 'vAPI.messaging.notHandled' +}; - listen: function(listenerName, callback) { - this.listeners[listenerName] = callback; - }, +/******************************************************************************/ - setup: function(connector) { - if ( this.connector ) { +vAPI.messaging.listen = function(listenerName, callback) { + this.listeners[listenerName] = callback; +}; + +/******************************************************************************/ + +vAPI.messaging.onConnect = function(port) { + var onMessage = function(request) { + var callback = function(response) { + if ( vAPI.lastError() || response === undefined ) { + return; + } + + if ( request.requestId ) { + port.postMessage({ + requestId: request.requestId, + portName: request.portName, + msg: response + }); + } + }; + + // Specific handler + var r; + var listener = vAPI.messaging.listeners[request.portName]; + if ( typeof listener === 'function' ) { + r = listener(request.msg, port.sender, callback); + } + if ( r !== vAPI.messaging.UNHANDLED ) { return; } - this.connector = function(port) { - var onMessage = function(request) { - var callback = function(response) { - if ( vAPI.lastError() || response === undefined ) { - return; - } - - if ( request.requestId ) { - port.postMessage({ - requestId: request.requestId, - portName: request.portName, - msg: response - }); - } - }; - - // Default handler - var listener = connector(request.msg, port.sender, callback); - if ( listener !== null ) { - return; - } - - // Specific handler - listener = vAPI.messaging.listeners[request.portName]; - if ( typeof listener === 'function' ) { - listener(request.msg, port.sender, callback); - } else { - console.error('µBlock> messaging > unknown request: %o', request); - } - }; - - var onDisconnect = function(port) { - port.onDisconnect.removeListener(onDisconnect); - port.onMessage.removeListener(onMessage); - delete vAPI.messaging.ports[port.name]; - }; - - port.onDisconnect.addListener(onDisconnect); - port.onMessage.addListener(onMessage); - vAPI.messaging.ports[port.name] = port; - }; - - chrome.runtime.onConnect.addListener(this.connector); - }, - - broadcast: function(message) { - message = { - broadcast: true, - msg: message - }; - - for ( var portName in this.ports ) { - this.ports[portName].postMessage(message); + // Default handler + r = vAPI.messaging.defaultHandler(request.msg, port.sender, callback); + if ( r !== vAPI.messaging.UNHANDLED ) { + return; } + + console.error('µBlock> messaging > unknown request: %o', request); + }; + + var onDisconnect = function(port) { + port.onDisconnect.removeListener(onDisconnect); + port.onMessage.removeListener(onMessage); + delete vAPI.messaging.ports[port.name]; + }; + + port.onDisconnect.addListener(onDisconnect); + port.onMessage.addListener(onMessage); + vAPI.messaging.ports[port.name] = port; +}; + +/******************************************************************************/ + +vAPI.messaging.setup = function(defaultHandler) { + // Already setup? + if ( this.defaultHandler !== null ) { + return; + } + + if ( typeof defaultHandler !== 'function' ) { + defaultHandler = function(){ return null; }; + }; + this.defaultHandler = defaultHandler; + + chrome.runtime.onConnect.addListener(this.onConnect); +}; + +/******************************************************************************/ + +vAPI.messaging.broadcast = function(message) { + var messageWrapper = { + broadcast: true, + msg: message + }; + + for ( var portName in this.ports ) { + if ( this.ports.hasOwnProperty(portName) === false ) { + continue; + } + this.ports[portName].postMessage(messageWrapper); } }; diff --git a/meta/safariextz/vapi-background.js b/meta/safariextz/vapi-background.js index 905b4e955..f976b1ef3 100644 --- a/meta/safariextz/vapi-background.js +++ b/meta/safariextz/vapi-background.js @@ -471,7 +471,7 @@ vAPI.messaging = { var listener = connector(request.message.msg, sender, callback); - if (listener === null) { + if (listener === vAPI.messaging.UNHANDLED) { listener = vAPI.messaging.listeners[request.message.portName]; if (typeof listener === 'function') { diff --git a/src/js/messaging.js b/src/js/messaging.js index 246623bc0..12f2bc40b 100644 --- a/src/js/messaging.js +++ b/src/js/messaging.js @@ -19,13 +19,15 @@ Home: https://github.com/gorhill/uBlock */ -/* global µBlock, YaMD5 */ +/* global µBlock, vAPI, YaMD5 */ 'use strict'; +/******************************************************************************/ /******************************************************************************/ -// message router and default handler +// Message router and default handler + vAPI.messaging.setup(function(request, sender, callback) { var µb = µBlock; @@ -45,10 +47,6 @@ vAPI.messaging.setup(function(request, sender, callback) { µb.contextMenuClientY = request.clientY; break; - /*case 'forceReloadTab': - µb.forceReload(request.pageURL); - break;*/ - case 'getUserSettings': callback(µb.userSettings); break; @@ -66,12 +64,10 @@ vAPI.messaging.setup(function(request, sender, callback) { break; default: - // if none of the above, then check the channel listeners - return null; + return vAPI.messaging.UNHANDLED; } }); - /******************************************************************************/ /******************************************************************************/ @@ -169,6 +165,9 @@ var onMessage = function(request, sender, callback) { response['.'] = getDynamicFilterResults(request.pageHostname); } break; + + default: + return vAPI.messaging.UNHANDLED; } callback(response); @@ -214,6 +213,9 @@ var onMessage = function(request, sender, callback) { response = µb.cosmeticFilteringEngine.retrieveDomainSelectors(request); } break; + + default: + return vAPI.messaging.UNHANDLED; } callback(response); @@ -340,6 +342,9 @@ var onMessage = function(details, sender, callback) { response = filterRequest(pageStore, details); } break; + + default: + return vAPI.messaging.UNHANDLED; } callback(response); @@ -399,6 +404,8 @@ var onMessage = function(request, sender, callback) { µb.appendUserFilters(request.filters); break; + default: + return vAPI.messaging.UNHANDLED; } callback(response); @@ -471,6 +478,8 @@ var onMessage = function(request, sender, callback) { µb.assets.purge(request.path); break; + default: + return vAPI.messaging.UNHANDLED; } callback(response); @@ -512,6 +521,8 @@ var onMessage = function(request, sender, callback) { var response; switch ( request.what ) { + default: + return vAPI.messaging.UNHANDLED; } callback(response); @@ -556,6 +567,8 @@ var onMessage = function(request, sender, callback) { µb.saveWhitelist(); break; + default: + return vAPI.messaging.UNHANDLED; } callback(response); @@ -631,6 +644,10 @@ var getPageDetails = function(µb, tabId) { var onMessage = function(request, sender, callback) { // Async switch ( request.what ) { + case 'getTabForStats': + vAPI.tabs.get(request.tabId, callback); + return; + default: break; } @@ -647,9 +664,8 @@ var onMessage = function(request, sender, callback) { response = getPageDetails(µb, request.tabId); break; - case 'getTabForStats': - vAPI.tabs.get(request.tabId, callback); - return; + default: + return vAPI.messaging.UNHANDLED; } callback(response); @@ -745,6 +761,9 @@ var onMessage = function(request, sender, callback) { case 'resetUserData': resetUserData(); break; + + default: + return vAPI.messaging.UNHANDLED; } callback(response); diff --git a/src/js/tab.js b/src/js/tab.js index 0128deb73..69dff3aa3 100644 --- a/src/js/tab.js +++ b/src/js/tab.js @@ -81,13 +81,14 @@ vAPI.tabs.onPopup = function(details) { // Blocked // Safari blocks before the pop-up opens, so there is no window to remove. - if (vAPI.safari) { + // TODO: Can't this test be done within the platform-specific code? + if ( vAPI.safari ) { return true; } // It is a popup, block and remove the tab. µBlock.unbindTabFromPageStats(details.tabId); - µBlock.XAL.destroyTab(details.tabId); + vAPI.tabs.remove(details.tabId); }; vAPI.tabs.registerListeners(); diff --git a/src/js/traffic.js b/src/js/traffic.js index a0c3e24fa..ef65865ba 100644 --- a/src/js/traffic.js +++ b/src/js/traffic.js @@ -207,7 +207,7 @@ var onBeforeSendHeaders = function(details) { // It is a popup, block and remove the tab. µb.unbindTabFromPageStats(tabId); - µb.XAL.destroyTab(tabId); + vAPI.tabs.remove(tabId); return { 'cancel': true }; }; diff --git a/src/js/vapi-background.js b/src/js/vapi-background.js index 2996836b1..bccf934da 100644 --- a/src/js/vapi-background.js +++ b/src/js/vapi-background.js @@ -695,7 +695,7 @@ if (self.chrome) { var listener = connector(request.message.msg, sender, callback); - if (listener === null) { + if (listener === vAPI.messaging.UNHANDLED) { listener = vAPI.messaging.listeners[request.message.portName]; if (typeof listener === 'function') { diff --git a/src/js/xal.js b/src/js/xal.js index 6097c5435..45fc67f82 100644 --- a/src/js/xal.js +++ b/src/js/xal.js @@ -62,16 +62,6 @@ exports.restart = function() { /******************************************************************************/ -exports.destroyTab = function(tabId) { - vAPI.tabs.remove(tabId, function() { - // required by chrome API, or else warnings at console (also, mind jshint) - if ( chrome.runtime.lastError ) { - } - }); -}; - -/******************************************************************************/ - return exports; /******************************************************************************/