diff options
-rw-r--r-- | platform/firefox/install.rdf | 3 | ||||
-rw-r--r-- | platform/firefox/options.xul | 9 | ||||
-rw-r--r-- | platform/firefox/vapi-background.js | 190 | ||||
-rw-r--r-- | src/_locales/en/messages.json | 12 | ||||
-rw-r--r-- | src/dashboard.html | 2 | ||||
-rw-r--r-- | src/devtools.html | 2 | ||||
-rw-r--r-- | src/js/messaging.js | 15 | ||||
-rw-r--r-- | src/js/popup.js | 30 | ||||
-rw-r--r-- | src/popup.html | 3 | ||||
-rwxr-xr-x | tools/make-firefox.sh | 1 |
10 files changed, 199 insertions, 68 deletions
diff --git a/platform/firefox/install.rdf b/platform/firefox/install.rdf index f017f7c..8ace584 100644 --- a/platform/firefox/install.rdf +++ b/platform/firefox/install.rdf @@ -10,8 +10,7 @@ <type>2</type> <bootstrap>true</bootstrap> <multiprocessCompatible>true</multiprocessCompatible> - <optionsType>3</optionsType> - <optionsURL>chrome://ublock/content/dashboard.html</optionsURL> + <optionsType>2</optionsType> {localized} <!-- Firefox --> diff --git a/platform/firefox/options.xul b/platform/firefox/options.xul new file mode 100644 index 0000000..aee6f7c --- /dev/null +++ b/platform/firefox/options.xul @@ -0,0 +1,9 @@ +<?xml version="1.0" ?> +<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <setting type="control"> + <vbox> + <button id="showDashboardButton"/> + <button id="showNetworkLogButton"/> + </vbox> + </setting> +</vbox> diff --git a/platform/firefox/vapi-background.js b/platform/firefox/vapi-background.js index 5be481b..10cb25d 100644 --- a/platform/firefox/vapi-background.js +++ b/platform/firefox/vapi-background.js @@ -272,21 +272,17 @@ var windowWatcher = { if ( tabBrowser.deck ) { // Fennec tabContainer = tabBrowser.deck; - tabContainer.addEventListener( - 'DOMTitleChanged', - tabWatcher.onFennecLocationChange - ); } else if ( tabBrowser.tabContainer ) { // desktop Firefox tabContainer = tabBrowser.tabContainer; tabBrowser.addTabsProgressListener(tabWatcher); + vAPI.contextMenu.register(this.document); } else { return; } tabContainer.addEventListener('TabClose', tabWatcher.onTabClose); tabContainer.addEventListener('TabSelect', tabWatcher.onTabSelect); - vAPI.contextMenu.register(this.document); // when new window is opened TabSelect doesn't run on the selected tab? }, @@ -353,28 +349,6 @@ var tabWatcher = { url: location.asciiSpec }); }, - - onFennecLocationChange: function({target: doc}) { - // Fennec "equivalent" to onLocationChange - // note that DOMTitleChanged is selected as it fires very early - // (before DOMContentLoaded), and it does fire even if there is no title - - var win = doc.defaultView; - if ( win !== win.top ) { - return; - } - - var loc = win.location; - /*if ( loc.protocol === 'http' || loc.protocol === 'https' ) { - return; - }*/ - - vAPI.tabs.onNavigation({ - frameId: 0, - tabId: getOwnerWindow(win).BrowserApp.getTabForWindow(win).id, - url: Services.io.newURI(loc.href, null, null).asciiSpec - }); - } }; /******************************************************************************/ @@ -449,10 +423,6 @@ vAPI.tabs.registerListeners = function() { if ( tabBrowser.deck ) { // Fennec tabContainer = tabBrowser.deck; - tabContainer.removeEventListener( - 'DOMTitleChanged', - tabWatcher.onFennecLocationChange - ); } else if ( tabBrowser.tabContainer ) { tabContainer = tabBrowser.tabContainer; tabBrowser.removeTabsProgressListener(tabWatcher); @@ -773,6 +743,24 @@ vAPI.tabs.reload = function(tabId) { /******************************************************************************/ +vAPI.tabs.select = function(tabId) { + var tab = this.get(tabId); + + if ( !tab ) { + return; + } + + var tabBrowser = getTabBrowser(getOwnerWindow(tab)); + + if (vAPI.fennec) { + tabBrowser.selectTab(tab); + } else { + tabBrowser.selectedTab = tab; + } +}; + +/******************************************************************************/ + vAPI.tabs.injectScript = function(tabId, details, callback) { var tab = this.get(tabId); @@ -785,7 +773,7 @@ vAPI.tabs.injectScript = function(tabId, details, callback) { } details.file = vAPI.getURL(details.file); - tab.linkedBrowser.messageManager.sendAsyncMessage( + getBrowserForTab(tab).messageManager.sendAsyncMessage( location.host + ':broadcast', JSON.stringify({ broadcast: true, @@ -823,23 +811,7 @@ vAPI.setIcon = function(tabId, iconStatus, badge) { return; } - var button = win.document.getElementById(tb.id); - - if ( !button ) { - return; - } - - var icon = tb.tabs[tabId]; - button.setAttribute('badge', icon && icon.badge || ''); - - if ( !icon || !icon.img ) { - icon = ''; - } - else { - icon = 'url(' + vAPI.getURL('img/browsericons/icon16.svg') + ')'; - } - - button.style.listStyleImage = icon; + tb.updateState(win, tabId); }; /******************************************************************************/ @@ -1260,13 +1232,13 @@ var httpObserver = { return; } - /*if ( vAPI.fennec && lastRequest.type === this.MAIN_FRAME ) { + if ( vAPI.fennec && lastRequest.type === this.MAIN_FRAME && lastRequest.frameId === 0 ) { vAPI.tabs.onNavigation({ frameId: 0, tabId: lastRequest.tabId, url: URI.asciiSpec }); - }*/ + } // If request is not handled we may use the data in on-modify-request if ( channel instanceof Ci.nsIWritablePropertyBag ) { @@ -1412,8 +1384,67 @@ vAPI.toolbarButton = { tabs: {/*tabId: {badge: 0, img: boolean}*/} }; -/******************************************************************************/ +if (vAPI.fennec) { + // Menu UI + vAPI.toolbarButton.menuItemIds = new WeakMap(); + + vAPI.toolbarButton.getMenuItemLabel = function(tabId) { + var label = this.label; + if (tabId !== undefined) { + var tabDetails = this.tabs[tabId]; + if (tabDetails) { + if (tabDetails.img) { + if (tabDetails.badge) { + label = label + " (" + tabDetails.badge + ")"; + } + } else { + label = label + " (" + vAPI.i18n("fennecMenuItemBlockingOff") + ")"; + } + } + } + return label; + }; + + vAPI.toolbarButton.init = function() { + // Only actually expecting one window under Fennec (note, not tabs, windows) + for (var win of vAPI.tabs.getWindows()) { + this.addToWindow(win, this.getMenuItemLabel()); + } + + cleanupTasks.push(this.cleanUp); + }; + + vAPI.toolbarButton.addToWindow = function(win, label) { + var id = win.NativeWindow.menu.add({ + name: label, + callback: this.onClick + }); + this.menuItemIds.set(win, id); + }; + + vAPI.toolbarButton.removeFromWindow = function(win) { + var id = this.menuItemIds.get(win); + if (id) { + win.NativeWindow.menu.remove(id); + this.menuItemIds.delete(win); + } + }; + vAPI.toolbarButton.updateState = function(win, tabId) { + var id = this.menuItemIds.get(win); + if (!id) { + return; + } + win.NativeWindow.menu.update(id, { name: this.getMenuItemLabel(tabId) }); + }; + + vAPI.toolbarButton.onClick = function() { + var win = Services.wm.getMostRecentWindow('navigator:browser'); + var curTabId = vAPI.tabs.getTabId(getTabBrowser(win).selectedTab); + vAPI.tabs.open({ url: "popup.html?tabId=" + curTabId, index: -1, select: true }); + }; +} else { +// Toolbar button UI vAPI.toolbarButton.init = function() { var CustomizableUI; try { @@ -1622,6 +1653,27 @@ vAPI.toolbarButton.onViewHiding = function({target}) { target.firstChild.setAttribute('src', 'about:blank'); }; +vAPI.toolbarButton.updateState = function(win, tabId) { + var button = win.document.getElementById(this.id); + + if ( !button ) { + return; + } + + var icon = this.tabs[tabId]; + button.setAttribute('badge', icon && icon.badge || ''); + + if ( !icon || !icon.img ) { + icon = ''; + } + else { + icon = 'url(' + vAPI.getURL('img/browsericons/icon16.svg') + ')'; + } + + button.style.listStyleImage = icon; +}; +} + /******************************************************************************/ vAPI.toolbarButton.init(); @@ -1818,6 +1870,40 @@ vAPI.punycodeURL = function(url) { /******************************************************************************/ +vAPI.optionsObserver = { + register: function () { + var obs = Components.classes['@mozilla.org/observer-service;1'].getService(Components.interfaces.nsIObserverService); + obs.addObserver(this, "addon-options-displayed", false); + + cleanupTasks.push(this.unregister.bind(this)); + }, + + observe: function (aSubject, aTopic, aData) { + if (aTopic === "addon-options-displayed" && aData === "{2b10c1c8-a11f-4bad-fe9c-1c11e82cac42}") { + var doc = aSubject; + this.setupOptionsButton(doc, "showDashboardButton", "dashboard.html"); + this.setupOptionsButton(doc, "showNetworkLogButton", "devtools.html"); + } + }, + setupOptionsButton: function (doc, id, page) { + var button = doc.getElementById(id); + button.addEventListener("command", function () { + vAPI.tabs.open({ url: page, index: -1 }); + }); + button.label = vAPI.i18n(id); + }, + + unregister: function () { + var obs = Components.classes['@mozilla.org/observer-service;1'].getService(Components.interfaces.nsIObserverService); + obs.removeObserver(this, "addon-options-displayed"); + }, +}; + +vAPI.optionsObserver.register(); + +/******************************************************************************/ + + // clean up when the extension is disabled window.addEventListener('unload', function() { diff --git a/src/_locales/en/messages.json b/src/_locales/en/messages.json index 83dc11e..145c33f 100644 --- a/src/_locales/en/messages.json +++ b/src/_locales/en/messages.json @@ -555,6 +555,18 @@ "message":"{{value}} days ago", "description":"English: {{value}} days ago" }, + "showDashboardButton":{ + "message":"Show Dashboard", + "description":"English: Show Dashboard" + }, + "showNetworkLogButton":{ + "message":"Show Network Request Log", + "description":"English: Show Network Request Log" + }, + "fennecMenuItemBlockingOff": { + "message": "off", + "description": "Appears as µBlock (off)" + }, "dummy":{ "message":"This entry must be the last one", "description":"so we dont need to deal with comma for last entry" diff --git a/src/dashboard.html b/src/dashboard.html index ac7e5a6..8f68c21 100644 --- a/src/dashboard.html +++ b/src/dashboard.html @@ -2,6 +2,8 @@ <html> <head> <meta charset="utf-8"> +<meta name="viewport" content="initial-scale=1"> + <title data-i18n="dashboardName"></title> <link href="css/dashboard.css" rel="stylesheet" type="text/css"> <link href="css/common.css" rel="stylesheet" type="text/css"> diff --git a/src/devtools.html b/src/devtools.html index 2928899..f2daaec 100644 --- a/src/devtools.html +++ b/src/devtools.html @@ -2,6 +2,8 @@ <html> <head> <meta charset="utf-8"> +<meta name="viewport" content="initial-scale=1"> + <title data-i18n="statsPageName"></title> <link rel="stylesheet" type="text/css" href="css/common.css"> <link rel="stylesheet" type="text/css" href="css/devtools.css"> diff --git a/src/js/messaging.js b/src/js/messaging.js index 1afd993..71c2fa4 100644 --- a/src/js/messaging.js +++ b/src/js/messaging.js @@ -78,6 +78,9 @@ var onMessage = function(request, sender, callback) { case 'reloadTab': if ( vAPI.isNoTabId(request.tabId) === false ) { vAPI.tabs.reload(request.tabId); + if (request.select && vAPI.tabs.select) { + vAPI.tabs.select(request.tabId); + } } break; @@ -195,7 +198,7 @@ var getFirewallRules = function(srcHostname, desHostnames) { /******************************************************************************/ -var getStats = function(tabId) { +var getStats = function(tabId, tabTitle) { var r = { advancedUserEnabled: µb.userSettings.advancedUserEnabled, appName: vAPI.app.name, @@ -209,7 +212,8 @@ var getStats = function(tabId) { pageURL: '', pageAllowedRequestCount: 0, pageBlockedRequestCount: 0, - tabId: tabId + tabId: tabId, + tabTitle: tabTitle }; var pageStore = µb.pageStoreFromTabId(tabId); if ( pageStore ) { @@ -277,8 +281,8 @@ var onMessage = function(request, sender, callback) { // Async switch ( request.what ) { case 'getPopupData': - vAPI.tabs.get(null, function(tab) { - callback(getStats(getTargetTabId(tab))); + vAPI.tabs.get(request.tabId, function(tab) { + callback(getStats(getTargetTabId(tab), tab.title)); }); return; @@ -296,6 +300,9 @@ var onMessage = function(request, sender, callback) { µb.contextMenuClientX = -1; µb.contextMenuClientY = -1; µb.elementPickerExec(request.tabId); + if (request.select && vAPI.tabs.select) { + vAPI.tabs.select(request.tabId); + } break; case 'hasPopupContentChanged': diff --git a/src/js/popup.js b/src/js/popup.js index ded7ba1..291dd47 100644 --- a/src/js/popup.js +++ b/src/js/popup.js @@ -363,7 +363,10 @@ var renderPrivacyExposure = function() { // Assume everything has to be done incrementally. -var renderPopup = function() { +var renderPopup = function () { + if (popupData.tabTitle) { + document.title = popupData.appName + " - " + popupData.tabTitle; + } uDom('#appname').text(popupData.appName); uDom('#version').text(popupData.appVersion); uDom('body').toggleClass('advancedUser', popupData.advancedUserEnabled); @@ -449,8 +452,9 @@ var toggleNetFilteringSwitch = function(ev) { var gotoPick = function() { messager.send({ what: 'gotoPick', - tabId: popupData.tabId - }); + tabId: popupData.tabId, + select: true +}); vAPI.closePopup(); }; @@ -577,7 +581,7 @@ var setFirewallRuleHandler = function(ev) { /******************************************************************************/ var reloadTab = function() { - messager.send({ what: 'reloadTab', tabId: popupData.tabId }); + messager.send({ what: 'reloadTab', tabId: popupData.tabId, select: true }); // Polling will take care of refreshing the popup content @@ -651,7 +655,7 @@ var pollForContentChange = (function() { var queryCallback = function(response) { if ( response ) { - getPopupData(); + getPopupData(popupData.tabId); return; } poll(); @@ -669,22 +673,30 @@ var pollForContentChange = (function() { /******************************************************************************/ -var getPopupData = function() { +var getPopupData = function(tabId) { var onDataReceived = function(response) { cachePopupData(response); renderPopup(); hashFromPopupData(true); pollForContentChange(); }; - messager.send({ what: 'getPopupData' }, onDataReceived); + messager.send({ what: 'getPopupData', tabId: tabId }, onDataReceived); }; /******************************************************************************/ // Make menu only when popup html is fully loaded -uDom.onLoad(function() { - getPopupData(); +uDom.onLoad(function () { + var tabId = null; //If there's no tab ID specified in the query string, it will default to current tab. + + // Extract the tab id of the page this popup is for + var matches = window.location.search.match(/[\?&]tabId=([^&]+)/); + if (matches && matches.length === 2) { + tabId = matches[1]; + } + + getPopupData(tabId); uDom('#switch').on('click', toggleNetFilteringSwitch); uDom('#gotoPick').on('click', gotoPick); uDom('a[href]').on('click', gotoURL); diff --git a/src/popup.html b/src/popup.html index 252d133..b3bf5af 100644 --- a/src/popup.html +++ b/src/popup.html @@ -1,7 +1,8 @@ -<!DOCTYPE html> +<!DOCTYPE html> <html> <head> +<meta name="viewport" content="width=470"> <!-- When showing as a tab in fennec, scale to full size (150px + 320px)--> <meta charset="utf-8"> <link rel="stylesheet" href="css/common.css" type="text/css"> <link rel="stylesheet" href="css/popup.css" type="text/css"> diff --git a/tools/make-firefox.sh b/tools/make-firefox.sh index d52a3a8..91f3e5f 100755 --- a/tools/make-firefox.sh +++ b/tools/make-firefox.sh @@ -22,6 +22,7 @@ cp platform/firefox/bootstrap.js $DES/ cp platform/firefox/frame*.js $DES/ cp platform/firefox/chrome.manifest $DES/ cp platform/firefox/install.rdf $DES/ +cp platform/firefox/*.xul $DES/ cp LICENSE.txt $DES/ echo "*** uBlock.firefox: Generating meta..." |