aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--assets/checksums.txt2
-rw-r--r--assets/ublock/filters.txt24
-rw-r--r--dist/description/description-da.txt26
-rw-r--r--dist/description/description-sv.txt2
-rw-r--r--doc/img/rlogger-01.pngbin0 -> 428354 bytes
-rw-r--r--doc/img/rlogger-02.pngbin0 -> 75451 bytes
-rw-r--r--doc/img/rlogger-03.pngbin0 -> 76571 bytes
-rw-r--r--doc/img/rlogger-04.pngbin0 -> 76476 bytes
-rw-r--r--doc/img/rlogger-05.pngbin0 -> 76650 bytes
-rw-r--r--doc/img/rlogger-06.pngbin0 -> 76912 bytes
-rw-r--r--platform/chromium/manifest.json2
-rw-r--r--platform/firefox/install.rdf23
-rw-r--r--platform/firefox/vapi-background.js537
-rw-r--r--platform/safari/vapi-background.js29
-rw-r--r--platform/safari/vapi-client.js20
-rw-r--r--src/_locales/ar/messages.json10
-rw-r--r--src/_locales/bg/messages.json12
-rw-r--r--src/_locales/ca/messages.json8
-rw-r--r--src/_locales/cs/messages.json8
-rw-r--r--src/_locales/da/messages.json12
-rw-r--r--src/_locales/de/messages.json8
-rw-r--r--src/_locales/el/messages.json8
-rw-r--r--src/_locales/en/messages.json8
-rw-r--r--src/_locales/es/messages.json10
-rw-r--r--src/_locales/et/messages.json8
-rw-r--r--src/_locales/fa/messages.json8
-rw-r--r--src/_locales/fi/messages.json8
-rw-r--r--src/_locales/fil/messages.json8
-rw-r--r--src/_locales/fr/messages.json8
-rw-r--r--src/_locales/he/messages.json8
-rw-r--r--src/_locales/hi/messages.json8
-rw-r--r--src/_locales/hr/messages.json8
-rw-r--r--src/_locales/hu/messages.json10
-rw-r--r--src/_locales/id/messages.json8
-rw-r--r--src/_locales/it/messages.json8
-rw-r--r--src/_locales/ja/messages.json8
-rw-r--r--src/_locales/ko/messages.json8
-rw-r--r--src/_locales/lv/messages.json8
-rw-r--r--src/_locales/mr/messages.json8
-rw-r--r--src/_locales/nb/messages.json8
-rw-r--r--src/_locales/nl/messages.json12
-rw-r--r--src/_locales/pl/messages.json8
-rw-r--r--src/_locales/pt_BR/messages.json8
-rw-r--r--src/_locales/pt_PT/messages.json8
-rw-r--r--src/_locales/ro/messages.json8
-rw-r--r--src/_locales/ru/messages.json8
-rw-r--r--src/_locales/sq/messages.json8
-rw-r--r--src/_locales/sv/messages.json14
-rw-r--r--src/_locales/tr/messages.json8
-rw-r--r--src/_locales/uk/messages.json8
-rw-r--r--src/_locales/vi/messages.json10
-rw-r--r--src/_locales/zh_CN/messages.json8
-rw-r--r--src/_locales/zh_TW/messages.json18
-rw-r--r--src/css/devtool-log.css39
-rw-r--r--src/css/devtools.css3
-rw-r--r--src/css/popup.css3
-rw-r--r--src/devtool-log.html6
-rw-r--r--src/js/background.js3
-rw-r--r--src/js/contentscript-end.js66
-rw-r--r--src/js/contentscript-start.js5
-rw-r--r--src/js/cosmetic-filtering.js2
-rw-r--r--src/js/devtool-log.js189
-rw-r--r--src/js/dynamic-net-filtering.js2
-rw-r--r--src/js/i18n.js3
-rw-r--r--src/js/pagestore.js2
-rw-r--r--src/js/start.js4
-rw-r--r--src/js/static-net-filtering.js250
-rw-r--r--src/js/storage.js2
-rw-r--r--src/js/tab.js2
-rw-r--r--src/js/traffic.js15
-rwxr-xr-xtools/make-fennec.sh38
71 files changed, 1238 insertions, 401 deletions
diff --git a/assets/checksums.txt b/assets/checksums.txt
index 4351bcc..6a3862a 100644
--- a/assets/checksums.txt
+++ b/assets/checksums.txt
@@ -1,5 +1,5 @@
59371e23b383053da7cd2e8d31d4ccf7 assets/ublock/privacy.txt
-23650c591607d84833a151ff3a197378 assets/ublock/filters.txt
+15d35142fc2d3fc87a4956f683f7e8dc assets/ublock/filters.txt
dcf3e05bae803343c9d632f0baf8bedd assets/ublock/mirror-candidates.txt
96e088c2dbb8759e046d2a44ed375000 assets/ublock/filter-lists.json
132b3ecc9da8a68c3faf740c00af734b assets/thirdparties/adblock-plus-japanese-filter.googlecode.com/hg/abp_jp.txt
diff --git a/assets/ublock/filters.txt b/assets/ublock/filters.txt
index b0fd705..9ba97dd 100644
--- a/assets/ublock/filters.txt
+++ b/assets/ublock/filters.txt
@@ -4,10 +4,6 @@
# => blocking counterpart in Peter Lowe's Ad Server
@@||www.google-analytics.com/ga.js^$domain=xda-developers.com
-# https://github.com/gorhill/uBlock/wiki/My-answer-to-web-store-reviews-where-appropriate#barfin-bob-chrome-store-24-june-2014
-# => blocking counterpart in EasyPrivacy
-@@||media.star-telegram.com/mistats/sites/dfw/startelegram.js^$domain=star-telegram.com
-
# https://github.com/gorhill/uBlock/issues/17
# => blocking counterpart in hpHosts Ad Server: `l.yimg.com`
@@||l.yimg.com^$stylesheet,domain=yahoo.com
@@ -197,7 +193,7 @@ www.thesimsresource.com##.ad-topleader
# https://github.com/gorhill/uBlock/issues/374
# To counter `2mdn.net` in Peter Lowe's, `s0.2mdn.net` in hpHosts
-@@||s0.2mdn.net/instream/*$object,script
+@@||s0.2mdn.net/instream/*$object,script,domain=wsmv.com
# https://github.com/gorhill/uBlock/issues/380#issuecomment-64916258
# Let's see how long this works
@@ -313,3 +309,21 @@ deviantart.com##.dp-ad-chrome.dp-ad-visible
# https://github.com/gorhill/uBlock/issues/841
# To counter `quantcast.com` in hpHosts, Peter Lowe's
@@||quantcast.com^$~third-party
+
+# Chrome store feedback: "on gaana.com it blocks the site"
+# To counter `_social_tracking.` in EasyPrivacy
+@@||css5.gaanacdn.com/minify-*/min/?$script
+
+# http://support.getadblock.com/discussions/problems/73955-specific-web-site-causes-thousands-infinite-blocks-locks-up-chrome
+||www.notempire.com/js/gridview$script
+
+# https://github.com/gorhill/uBlock/issues/919
+@@||s.youtube.com/api/stats/playback?$image,object-subrequest
+
+# https://twitter.com/Urre/status/572742363069714432
+# To counter `/keen.min.js` in EasyPrivacy
+@@||keen.github.io/*/keen.min.js$domain=keen.github.io
+
+# Feedback from Chrome store: "videos dont work on this site"
+# http://www.okgoals.com/match-highlights-1425491618---41
+@@||cdn.phoenix.intergi.com^$domain=okgoals.com
diff --git a/dist/description/description-da.txt b/dist/description/description-da.txt
index 665f893..b7537f7 100644
--- a/dist/description/description-da.txt
+++ b/dist/description/description-da.txt
@@ -1,21 +1,21 @@
-En effektiv blocker: let på hukommelse og CPU fodaftryk, og endnu kan indlæse og håndhæve tusindvis flere filtre end andre populære blokkere derude.
+En effektiv blocker: let på hukommelse og CPU forbrug,. Kan indlæse og anvende tusindvis af flere filtre end andre populære blockere derude.
-Illustreret oversigt over dens effektivitet: https://github.com/gorhill/uBlock/wiki/%C2%B5Block-vs.-ABP :-Efficiency-compared
+Illustreret oversigt over effektiviteten: https://github.com/gorhill/uBlock/wiki/%C2%B5Block-vs.-ABP :-Efficiency-compared
-Brug: Den Store power knap i pop-up-vinduet er til permanent deaktivere/aktivere µBlock for det aktuelle websted. Det gælder kun for det aktuelle websted , det er ikke en global afbryderknap.
+Anvendelse: Den Store power knap i pop-up-vinduet kan permanent deaktivere/aktivere µBlock på det aktuelle websted. Dette gælder kun for det aktuelle websted, det er ikke en global afbryderknap.
***
-Fleksibel, det er mere end en "ad blocker": det kan også læse og oprette filtre fra hosts-filer.
+Fleksibel, det er mere end en "ad blocker": den kan også læse og oprette filtre fra hosts-filer.
-Ud af boksen, er disse lister over filtre indlæses og håndhævet:
+Fra starten af er disse lister over filtre indlæst og anvendt:
- EasyList
- Peter Lowe’s Ad server list
- EasyPrivacy
- Malware domains
-Flere lister er tilgængelige for dig at vælge når du ønsker det:
+Flere lister er tilgængelige hvis du ønsker det:
- Fanboy’s Enhanced Tracking List
- Dan Pollock’s hosts file
@@ -24,26 +24,26 @@ Flere lister er tilgængelige for dig at vælge når du ønsker det:
- Spam404
- Osv.
-Selvfølgelig, jo flere aktive filtre mere jo højere hukommelse fodtryk. Endnu, selv efter at tilføje Fanboys to ekstra lister, Hphosts's annonce og tracking servere, µBlock stadig har en ringere hukommelse footprint end andre meget populære blokkere derude.
+Selvfølgelig vil flere aktive filtre betyde højere hukommelsesforbrug. Selv efter tilføjelse af Fanboys to ekstra lister, og hpHosts’s Ad and tracking server, har µBlock stadig et lavere hukommelsesforbrug end andre blockere derude.
-Desuden være opmærksom på at vælge nogle af disse ekstra lister kan føre til højere sandsynlighed for webstedet brud - især de lister, der normalt anvendes som host-filel.
+Vær desuden opmærksom på, at hvis du vælger nogle af disse ekstra lister kan det føre til højere sandsynlighed for, at webstedet bliver vist forkert - især de lister der normalt anvendes som hosts-fil.
***
-Uden de forudindstillede lister over filtre er denne udvidelse intet. Så hvis du nogensinde virkelig ønsker at bidrage med noget, tænk på de mennesker, der arbejder hårdt for at vedligeholde filterlister, du bruger, som blev stillet til rådighed til brug af alle gratis.
+Uden de forudindstillede lister med filtre er denne udvidelse intet. Hvis du nogensinde virkelig ønsker at bidrage med noget, så tænk på de mennesker der arbejder hårdt for at vedligeholde de filterlister du bruger, som alle blev stillet gratis til rådighed for alle.
***
Gratis.
-Open source med offentlige licens (GPLv3)
-For brugere af brugere.
+Open source med offentlig licens (GPLv3)
+For brugere, af brugere.
Bidragydere @ Github: https://github.com/gorhill/uBlock/graphs/contributors
Bidragydere @ Crowdin: https://crowdin.net/project/ublock
***
-Det er ganske en tidlig version, holde dette i tankerne, når du gennemser.
+Dette er en tidlig version. Hav dette i tankerne når du skriver en anmeldelse.
-Projekt Ændringslog:
+Projekt changelog:
https://github.com/gorhill/uBlock/releases \ No newline at end of file
diff --git a/dist/description/description-sv.txt b/dist/description/description-sv.txt
index 3e32183..3d61f69 100644
--- a/dist/description/description-sv.txt
+++ b/dist/description/description-sv.txt
@@ -23,7 +23,7 @@ Fler filterlistor finns tillgängliga att använda om du vill:
- hpHosts’s Ad and tracking servers
- MVPS HOSTS
- Spam404
-- m.fl.
+- med flera
Ju fler aktiverade filter, desto högre minnesanvändning. Men även efter att ha lagt till Fanboys två extra filterlistor och hpHosts' Ad and tracking servers så använder µBlock mindre minne än andra väldigt populära blockerare.
diff --git a/doc/img/rlogger-01.png b/doc/img/rlogger-01.png
new file mode 100644
index 0000000..b25e7b1
--- /dev/null
+++ b/doc/img/rlogger-01.png
Binary files differ
diff --git a/doc/img/rlogger-02.png b/doc/img/rlogger-02.png
new file mode 100644
index 0000000..8e6a1fc
--- /dev/null
+++ b/doc/img/rlogger-02.png
Binary files differ
diff --git a/doc/img/rlogger-03.png b/doc/img/rlogger-03.png
new file mode 100644
index 0000000..fde49f2
--- /dev/null
+++ b/doc/img/rlogger-03.png
Binary files differ
diff --git a/doc/img/rlogger-04.png b/doc/img/rlogger-04.png
new file mode 100644
index 0000000..f27db52
--- /dev/null
+++ b/doc/img/rlogger-04.png
Binary files differ
diff --git a/doc/img/rlogger-05.png b/doc/img/rlogger-05.png
new file mode 100644
index 0000000..de66d0a
--- /dev/null
+++ b/doc/img/rlogger-05.png
Binary files differ
diff --git a/doc/img/rlogger-06.png b/doc/img/rlogger-06.png
new file mode 100644
index 0000000..cce3aae
--- /dev/null
+++ b/doc/img/rlogger-06.png
Binary files differ
diff --git a/platform/chromium/manifest.json b/platform/chromium/manifest.json
index 57ff1ab..51bf2e5 100644
--- a/platform/chromium/manifest.json
+++ b/platform/chromium/manifest.json
@@ -2,7 +2,7 @@
"manifest_version": 2,
"name": "µBlock",
- "version": "0.8.9.1",
+ "version": "0.8.9.2",
"default_locale": "en",
"description": "__MSG_extShortDesc__",
diff --git a/platform/firefox/install.rdf b/platform/firefox/install.rdf
index 38337c2..e1fefc2 100644
--- a/platform/firefox/install.rdf
+++ b/platform/firefox/install.rdf
@@ -23,31 +23,22 @@
</r:Description>
</targetApplication>
- <!-- SeaMonkey -->
- <targetApplication>
- <r:Description>
- <id>{{92650c4d-4b8e-4d2a-b7eb-24ecf4f6b63a}}</id>
- <minVersion>2.21</minVersion>
- <maxVersion>2.36</maxVersion>
- </r:Description>
- </targetApplication>
-
- <!-- Firefox for Android
+ <!-- Fennec -->
<targetApplication>
<r:Description>
<id>{{aa3c5121-dab2-40e2-81ca-7ea25febc110}}</id>
<minVersion>24.0</minVersion>
<maxVersion>39.0</maxVersion>
</r:Description>
- </targetApplication> -->
+ </targetApplication>
- <!-- Thunderbird
+ <!-- SeaMonkey -->
<targetApplication>
<r:Description>
- <id>{{3550f703-e582-4d05-9a08-453d09bdfdc6}}</id>
- <minVersion>24.0</minVersion>
- <maxVersion>39.0</maxVersion>
+ <id>{{92650c4d-4b8e-4d2a-b7eb-24ecf4f6b63a}}</id>
+ <minVersion>2.21</minVersion>
+ <maxVersion>2.36</maxVersion>
</r:Description>
- </targetApplication> -->
+ </targetApplication>
</r:Description>
</r:RDF>
diff --git a/platform/firefox/vapi-background.js b/platform/firefox/vapi-background.js
index 83e40b5..4b3ed7f 100644
--- a/platform/firefox/vapi-background.js
+++ b/platform/firefox/vapi-background.js
@@ -38,8 +38,8 @@ const {Services} = Cu.import('resource://gre/modules/Services.jsm', null);
/******************************************************************************/
var vAPI = self.vAPI = self.vAPI || {};
-
vAPI.firefox = true;
+vAPI.fennec = Services.appinfo.ID === '{aa3c5121-dab2-40e2-81ca-7ea25febc110}';
/******************************************************************************/
@@ -262,16 +262,30 @@ var windowWatcher = {
return;
}
- if ( !this.gBrowser || !this.gBrowser.tabContainer ) {
+ var tabContainer;
+ var tabBrowser = getTabBrowser(this);
+
+ if ( !tabBrowser ) {
return;
}
- var tC = this.gBrowser.tabContainer;
-
- this.gBrowser.addTabsProgressListener(tabWatcher);
- tC.addEventListener('TabClose', tabWatcher.onTabClose);
- tC.addEventListener('TabSelect', tabWatcher.onTabSelect);
+ if ( tabBrowser.deck ) {
+ // Fennec
+ tabContainer = tabBrowser.deck;
+ tabContainer.addEventListener(
+ 'DOMTitleChanged',
+ tabWatcher.onFennecLocationChange
+ );
+ } else if ( tabBrowser.tabContainer ) {
+ // desktop Firefox
+ tabContainer = tabBrowser.tabContainer;
+ tabBrowser.addTabsProgressListener(tabWatcher);
+ } 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?
@@ -287,19 +301,23 @@ var windowWatcher = {
/******************************************************************************/
var tabWatcher = {
- onTabClose: function({target: tab}) {
- var tabId = vAPI.tabs.getTabId(tab);
+ SAME_DOCUMENT: Ci.nsIWebProgressListener.LOCATION_CHANGE_SAME_DOCUMENT,
+
+ onTabClose: function({target}) {
+ // target is tab in Firefox, browser in Fennec
+ var tabId = vAPI.tabs.getTabId(target);
vAPI.tabs.onClosed(tabId);
delete vAPI.toolbarButton.tabs[tabId];
},
- onTabSelect: function({target: tab}) {
- var URI = tab.linkedBrowser.currentURI;
+ onTabSelect: function({target}) {
+ // target is tab in Firefox, browser in Fennec
+ var URI = (target.linkedBrowser || target).currentURI;
var aboutPath = URI.schemeIs('about') && URI.path;
- var tabId = vAPI.tabs.getTabId(tab);
+ var tabId = vAPI.tabs.getTabId(target);
if ( !aboutPath || (aboutPath !== 'blank' && aboutPath !== 'newtab') ) {
- vAPI.setIcon(tabId, tab.ownerDocument.defaultView);
+ vAPI.setIcon(tabId, getOwnerWindow(target));
return;
}
@@ -318,7 +336,7 @@ var tabWatcher = {
var tabId = vAPI.tabs.getTabId(browser);
// LOCATION_CHANGE_SAME_DOCUMENT = "did not load a new document"
- if ( flags & 1 ) {
+ if ( flags & this.SAME_DOCUMENT ) {
vAPI.tabs.onUpdated(tabId, {url: location.asciiSpec}, {
frameId: 0,
tabId: tabId,
@@ -334,6 +352,28 @@ var tabWatcher = {
tabId: tabId,
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
+ });
}
};
@@ -347,6 +387,37 @@ vAPI.noTabId = '-1';
/******************************************************************************/
+var getTabBrowser = function(win) {
+ return vAPI.fennec && win.BrowserApp || win.gBrowser || null;
+};
+
+/******************************************************************************/
+
+var getBrowserForTab = function(tab) {
+ return vAPI.fennec && tab.browser || tab.linkedBrowser || null;
+};
+
+/******************************************************************************/
+
+var getOwnerWindow = function(target) {
+ if ( target.ownerDocument ) {
+ return target.ownerDocument.defaultView;
+ }
+
+ // Fennec
+ for ( var win of vAPI.tabs.getWindows() ) {
+ for ( var tab of win.BrowserApp.tabs) {
+ if ( tab === target || tab.window === target ) {
+ return win;
+ }
+ }
+ }
+
+ return null;
+};
+
+/******************************************************************************/
+
vAPI.tabs = {};
/******************************************************************************/
@@ -367,20 +438,38 @@ vAPI.tabs.registerListeners = function() {
for ( var win of vAPI.tabs.getWindows() ) {
vAPI.contextMenu.unregister(win.document);
-
win.removeEventListener('DOMContentLoaded', windowWatcher.onReady);
- win.gBrowser.removeTabsProgressListener(tabWatcher);
- var tC = win.gBrowser.tabContainer;
- tC.removeEventListener('TabClose', tabWatcher.onTabClose);
- tC.removeEventListener('TabSelect', tabWatcher.onTabSelect);
+ var tabContainer;
+ var tabBrowser = getTabBrowser(win);
+ if ( !tabBrowser ) {
+ continue;
+ }
- // close extension tabs
- for ( var tab of win.gBrowser.tabs ) {
- var URI = tab.linkedBrowser.currentURI;
+ if ( tabBrowser.deck ) {
+ // Fennec
+ tabContainer = tabBrowser.deck;
+ tabContainer.removeEventListener(
+ 'DOMTitleChanged',
+ tabWatcher.onFennecLocationChange
+ );
+ } else if ( tabBrowser.tabContainer ) {
+ tabContainer = tabBrowser.tabContainer;
+ tabBrowser.removeTabsProgressListener(tabWatcher);
+ }
+
+ tabContainer.removeEventListener('TabClose', tabWatcher.onTabClose);
+ tabContainer.removeEventListener('TabSelect', tabWatcher.onTabSelect);
+ // Close extension tabs
+ for ( var tab of tabBrowser.tabs ) {
+ var browser = getBrowserForTab(tab);
+ if ( browser === null ) {
+ continue;
+ }
+ var URI = browser.currentURI;
if ( URI.schemeIs('chrome') && URI.host === location.host ) {
- win.gBrowser.removeTab(tab);
+ vAPI.tabs._remove(tab, getTabBrowser(win));
}
}
}
@@ -390,11 +479,30 @@ vAPI.tabs.registerListeners = function() {
/******************************************************************************/
vAPI.tabs.getTabId = function(target) {
+ if ( vAPI.fennec ) {
+ if ( target.browser ) {
+ // target is a tab
+ return target.id;
+ }
+
+ for ( var win of this.getWindows() ) {
+ var tab = win.BrowserApp.getTabForBrowser(target);
+ if ( tab && tab.id !== undefined ) {
+ return tab.id;
+ }
+ }
+
+ return -1;
+ }
+
if ( target.linkedPanel ) {
+ // target is a tab
return target.linkedPanel;
}
- var i, gBrowser = target.ownerDocument.defaultView.gBrowser;
+ // target is a browser
+ var i;
+ var gBrowser = getOwnerWindow(target).gBrowser;
if ( !gBrowser ) {
return -1;
@@ -421,27 +529,57 @@ vAPI.tabs.getTabId = function(target) {
/******************************************************************************/
+// If tabIds is an array, then an array of tabs will be returned,
+// otherwise a single tab
+
+vAPI.tabs.getTabsForIds = function(tabIds, tabBrowser) {
+ var tabId;
+ var tabs = [];
+ var singleTab = !Array.isArray(tabIds);
+
+ if ( singleTab ) {
+ tabIds = [tabIds];
+ }
+
+ if ( vAPI.fennec ) {
+ for ( tabId of tabIds ) {
+ var tab = tabBrowser.getTabForId(tabId);
+ if ( tab ) {
+ tabs.push(tab);
+ }
+ }
+ } else {
+ var query = [];
+ for ( tabId of tabIds ) {
+ query.push('tab[linkedpanel="' + tabId + '"]');
+ }
+ query = query.join(',');
+ tabs = [].slice.call(tabBrowser.tabContainer.querySelectorAll(query));
+ }
+
+ return singleTab ? tabs[0] || null : tabs;
+};
+
+/******************************************************************************/
+
vAPI.tabs.get = function(tabId, callback) {
- var tab, windows;
+ var tab, windows, win;
if ( tabId === null ) {
- tab = Services.wm.getMostRecentWindow('navigator:browser').gBrowser.selectedTab;
- tabId = vAPI.tabs.getTabId(tab);
+ win = Services.wm.getMostRecentWindow('navigator:browser');
+ tab = getTabBrowser(win).selectedTab;
+ tabId = this.getTabId(tab);
} else {
windows = this.getWindows();
-
- for ( var win of windows ) {
- tab = win.gBrowser.tabContainer.querySelector(
- 'tab[linkedpanel="' + tabId + '"]'
- );
-
+ for ( win of windows ) {
+ tab = vAPI.tabs.getTabsForIds(tabId, getTabBrowser(win));
if ( tab ) {
break;
}
}
}
- // for internal use
+ // For internal use
if ( typeof callback !== 'function' ) {
return tab;
}
@@ -451,34 +589,48 @@ vAPI.tabs.get = function(tabId, callback) {
return;
}
- var browser = tab.linkedBrowser;
- var gBrowser = browser.ownerDocument.defaultView.gBrowser;
-
if ( !windows ) {
windows = this.getWindows();
}
+ var browser = getBrowserForTab(tab);
+ var tabBrowser = getTabBrowser(win);
+ var tabIndex, tabTitle;
+ if ( vAPI.fennec ) {
+ tabIndex = tabBrowser.tabs.indexOf(tab);
+ tabTitle = browser.contentTitle;
+ } else {
+ tabIndex = tabBrowser.browsers.indexOf(browser);
+ tabTitle = tab.label;
+ }
+
callback({
id: tabId,
- index: gBrowser.browsers.indexOf(browser),
- windowId: windows.indexOf(browser.ownerDocument.defaultView),
- active: tab === gBrowser.selectedTab,
+ index: tabIndex,
+ windowId: windows.indexOf(win),
+ active: tab === tabBrowser.selectedTab,
url: browser.currentURI.asciiSpec,
- title: tab.label
+ title: tabTitle
});
};
/******************************************************************************/
vAPI.tabs.getAll = function(window) {
- var win, tab, tabs = [];
+ var win, tab;
+ var tabs = [];
for ( win of this.getWindows() ) {
if ( window && window !== win ) {
continue;
}
- for ( tab of win.gBrowser.tabs ) {
+ var tabBrowser = getTabBrowser(win);
+ if ( tabBrowser === null ) {
+ continue;
+ }
+
+ for ( tab of tabBrowser.tabs ) {
tabs.push(tab);
}
}
@@ -521,20 +673,26 @@ vAPI.tabs.open = function(details) {
details.url = vAPI.getURL(details.url);
}
- var tab, tabs;
+ var win, tab, tabBrowser;
if ( details.select ) {
var URI = Services.io.newURI(details.url, null, null);
- tabs = this.getAll();
- for ( tab of tabs ) {
- var browser = tab.linkedBrowser;
+ for ( tab of this.getAll() ) {
+ var browser = getBrowserForTab(tab);
// Or simply .equals if we care about the fragment
- if ( URI.equalsExceptRef(browser.currentURI) ) {
- browser.ownerDocument.defaultView.gBrowser.selectedTab = tab;
- return;
+ if ( URI.equalsExceptRef(browser.currentURI) === false ) {
+ continue;
}
+
+ tabBrowser = getTabBrowser(getOwnerWindow(tab));
+ if ( vAPI.fennec ) {
+ tabBrowser.selectTab(tab);
+ } else {
+ tabBrowser.selectedTab = tab;
+ }
+ return;
}
}
@@ -542,28 +700,44 @@ vAPI.tabs.open = function(details) {
details.active = true;
}
- var gBrowser = Services.wm.getMostRecentWindow('navigator:browser').gBrowser;
-
- if ( details.index === -1 ) {
- details.index = gBrowser.browsers.indexOf(gBrowser.selectedBrowser) + 1;
- }
-
if ( details.tabId ) {
- tabs = tabs || this.getAll();
-
- for ( tab of tabs ) {
- if ( vAPI.tabs.getTabId(tab) === details.tabId ) {
- tab.linkedBrowser.loadURI(details.url);
+ for ( win in this.getWindows() ) {
+ tab = this.getTabsForIds(details.tabId, win);
+ if ( tab ) {
+ getBrowserForTab(tab).loadURI(details.url);
return;
}
}
}
- tab = gBrowser.loadOneTab(details.url, {inBackground: !details.active});
+ win = Services.wm.getMostRecentWindow('navigator:browser');
+ tabBrowser = getTabBrowser(win);
+
+ if ( vAPI.fennec ) {
+ tabBrowser.addTab(details.url, {selected: details.active !== false});
+ // Note that it's impossible to move tabs on Fennec, so don't bother
+ return;
+ }
+
+ if ( details.index === -1 ) {
+ details.index = tabBrowser.browsers.indexOf(tabBrowser.selectedBrowser) + 1;
+ }
+
+ tab = tabBrowser.loadOneTab(details.url, {inBackground: !details.active});
if ( details.index !== undefined ) {
- gBrowser.moveTabTo(tab, details.index);
+ tabBrowser.moveTabTo(tab, details.index);
+ }
+};
+
+/******************************************************************************/
+
+vAPI.tabs._remove = function(tab, tabBrowser) {
+ if ( vAPI.fennec ) {
+ tabBrowser.closeTab(tab);
+ return;
}
+ tabBrowser.removeTab(tab);
};
/******************************************************************************/
@@ -573,19 +747,14 @@ vAPI.tabs.remove = function(tabIds) {
tabIds = [tabIds];
}
- tabIds = tabIds.map(function(tabId) {
- return 'tab[linkedpanel="' + tabId + '"]';
- }).join(',');
-
for ( var win of this.getWindows() ) {
- var tabs = win.gBrowser.tabContainer.querySelectorAll(tabIds);
-
+ var tabBrowser = getTabBrowser(win);
+ var tabs = this.getTabsForIds(tabIds, tabBrowser);
if ( !tabs ) {
continue;
}
-
for ( var tab of tabs ) {
- win.gBrowser.removeTab(tab);
+ this._remove(tab, tabBrowser);
}
}
};
@@ -595,15 +764,17 @@ vAPI.tabs.remove = function(tabIds) {
vAPI.tabs.reload = function(tabId) {
var tab = this.get(tabId);
- if ( tab ) {
- tab.ownerDocument.defaultView.gBrowser.reloadTab(tab);
+ if ( !tab ) {
+ return;
}
+
+ getBrowserForTab(tab).webNavigation.reload(0);
};
/******************************************************************************/
vAPI.tabs.injectScript = function(tabId, details, callback) {
- var tab = vAPI.tabs.get(tabId);
+ var tab = this.get(tabId);
if ( !tab ) {
return;
@@ -638,7 +809,7 @@ vAPI.setIcon = function(tabId, iconStatus, badge) {
var win = badge === undefined
? iconStatus
: Services.wm.getMostRecentWindow('navigator:browser');
- var curTabId = vAPI.tabs.getTabId(win.gBrowser.selectedTab);
+ var curTabId = vAPI.tabs.getTabId(getTabBrowser(win).selectedTab);
var tb = vAPI.toolbarButton;
// from 'TabSelect' event
@@ -699,9 +870,9 @@ vAPI.messaging.onMessage = function({target, data}) {
if ( !messageManager ) {
// Message came from a popup, and its message manager is not usable.
// So instead we broadcast to the parent window.
- messageManager = target
- .webNavigation.QueryInterface(Ci.nsIDocShell)
- .chromeEventHandler.ownerDocument.defaultView.messageManager;
+ messageManager = getOwnerWindow(
+ target.webNavigation.QueryInterface(Ci.nsIDocShell).chromeEventHandler
+ ).messageManager;
}
var channelNameRaw = data.channelName;
@@ -857,6 +1028,7 @@ var httpObserver = {
classDescription: 'net-channel-event-sinks for ' + location.host,
classID: Components.ID('{dc8d6319-5f6e-4438-999e-53722db99e84}'),
contractID: '@' + location.host + '/net-channel-event-sinks;1',
+ REQDATAKEY: location.host + 'reqdata',
ABORT: Components.results.NS_BINDING_ABORTED,
ACCEPT: Components.results.NS_SUCCEEDED,
// Request types: https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XPCOM/Reference/Interface/nsIContentPolicy#Constants
@@ -875,14 +1047,7 @@ var httpObserver = {
12: 'object',
14: 'font'
},
- lastRequest: {
- url: null,
- type: null,
- tabId: null,
- frameId: null,
- parentFrameId: null,
- openerURL: null
- },
+ lastRequest: [{}, {}],
get componentRegistrar() {
return Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
@@ -987,13 +1152,13 @@ var httpObserver = {
return true;
}
- if ( result.redirectUrl ) {
+ /*if ( result.redirectUrl ) {
channel.redirectionLimit = 1;
channel.redirectTo(
Services.io.newURI(result.redirectUrl, null, null)
);
return true;
- }
+ }*/
return false;
},
@@ -1012,14 +1177,7 @@ var httpObserver = {
}
try {
- /*[
- type,
- tabId,
- sourceTabId - given if it was a popup,
- frameId,
- parentFrameId
- ]*/
- channelData = channel.getProperty(location.host + 'reqdata');
+ channelData = channel.getProperty(this.REQDATAKEY);
} catch (ex) {
return;
}
@@ -1028,7 +1186,7 @@ var httpObserver = {
return;
}
- if ( (1 << channelData[0] & this.VALID_CSP_TARGETS) === 0 ) {
+ if ( (1 << channelData[4] & this.VALID_CSP_TARGETS) === 0 ) {
return;
}
@@ -1042,9 +1200,9 @@ var httpObserver = {
result = vAPI.net.onHeadersReceived.callback({
hostname: URI.asciiHost,
- parentFrameId: channelData[4],
+ parentFrameId: channelData[1],
responseHeaders: result ? [{name: topic, value: result}] : [],
- tabId: channelData[1],
+ tabId: channelData[3],
url: URI.asciiSpec
});
@@ -1061,63 +1219,64 @@ var httpObserver = {
// http-on-opening-request
- var lastRequest = this.lastRequest;
+ var lastRequest = this.lastRequest[0];
+
+ if ( lastRequest.url !== URI.spec ) {
+ if ( this.lastRequest[1].url === URI.spec ) {
+ lastRequest = this.lastRequest[1];
+ } else {
+ lastRequest.url = null;
+ }
+ }
if ( lastRequest.url === null ) {
- this.handleRequest(channel, URI, {
+ lastRequest.type = channel.loadInfo && channel.loadInfo.contentPolicyType || 1;
+ result = this.handleRequest(channel, URI, {
tabId: vAPI.noTabId,
- type: channel.loadInfo && channel.loadInfo.contentPolicyType || 1
+ type: lastRequest.type
});
- return;
- }
-
- // Important! When loading file via XHR for mirroring,
- // the URL will be the same, so it could fall into an infinite loop
- lastRequest.url = null;
- var sourceTabId = null;
-
- // Popup candidate (only for main_frame type)
- if ( lastRequest.openerURL ) {
- for ( var tab of vAPI.tabs.getAll() ) {
- var tabURI = tab.linkedBrowser.currentURI;
-
- // Probably isn't the best method to identify the source tab
- if ( tabURI.spec !== lastRequest.openerURL ) {
- continue;
- }
-
- sourceTabId = vAPI.tabs.getTabId(tab);
-
- if ( sourceTabId !== lastRequest.tabId ) {
- break;
- }
-
- sourceTabId = null;
+ if ( result === true ) {
+ return;
}
- if ( this.handlePopup(channel.URI, lastRequest.tabId, sourceTabId) ) {
- channel.cancel(this.ABORT);
+ if ( channel instanceof Ci.nsIWritablePropertyBag === false ) {
return;
}
+
+ // Carry data for behind-the-scene redirects
+ channel.setProperty(
+ this.REQDATAKEY,
+ [lastRequest.type, vAPI.noTabId, null, 0, -1]
+ );
+ return;
}
+ // Important! When loading file via XHR for mirroring,
+ // the URL will be the same, so it could fall into an infinite loop
+ lastRequest.url = null;
+
if ( this.handleRequest(channel, URI, lastRequest) ) {
return;
}
+ /*if ( vAPI.fennec && lastRequest.type === this.MAIN_FRAME ) {
+ 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 ) {
- channel.setProperty(
- location.host + 'reqdata',
- [
- lastRequest.type,
- lastRequest.tabId,
- sourceTabId,
- lastRequest.frameId,
- lastRequest.parentFrameId
- ]
- );
+ channel.setProperty(this.REQDATAKEY, [
+ lastRequest.frameId,
+ lastRequest.parentFrameId,
+ lastRequest.sourceTabId,
+ lastRequest.tabId,
+ lastRequest.type
+ ]);
}
},
@@ -1127,12 +1286,6 @@ var httpObserver = {
// If error thrown, the redirect will fail
try {
- // skip internal redirects?
- /*if ( flags & 4 ) {
- console.log('internal redirect skipped');
- return;
- }*/
-
var URI = newChannel.URI;
if ( !URI.schemeIs('http') && !URI.schemeIs('https') ) {
@@ -1143,21 +1296,18 @@ var httpObserver = {
return;
}
- // TODO: what if a behind-the-scene request is being redirected?
- // This data is present only for tabbed requests, so if this throws,
- // the redirection won't be evaluated and canceled (if necessary)
- var channelData = oldChannel.getProperty(location.host + 'reqdata');
+ var channelData = oldChannel.getProperty(this.REQDATAKEY);
- if ( this.handlePopup(URI, channelData[1], channelData[2]) ) {
+ if ( this.handlePopup(URI, channelData[3], channelData[2]) ) {
result = this.ABORT;
return;
}
var details = {
- type: channelData[0],
- tabId: channelData[1],
- frameId: channelData[3],
- parentFrameId: channelData[4]
+ frameId: channelData[0],
+ parentFrameId: channelData[1],
+ tabId: channelData[3],
+ type: channelData[4]
};
if ( this.handleRequest(newChannel, URI, details) ) {
@@ -1167,7 +1317,7 @@ var httpObserver = {
// Carry the data on in case of multiple redirects
if ( newChannel instanceof Ci.nsIWritablePropertyBag ) {
- newChannel.setProperty(location.host + 'reqdata', channelData);
+ newChannel.setProperty(this.REQDATAKEY, channelData);
}
} catch (ex) {
// console.error(ex);
@@ -1192,13 +1342,46 @@ vAPI.net.registerListeners = function() {
var shouldLoadListenerMessageName = location.host + ':shouldLoad';
var shouldLoadListener = function(e) {
var details = e.data;
+ var tabId = vAPI.tabs.getTabId(e.target);
+ var sourceTabId = null;
+
+ // Popup candidate
+ if ( details.openerURL ) {
+ for ( var tab of vAPI.tabs.getAll() ) {
+ var URI = tab.linkedBrowser.currentURI;
+
+ // Probably isn't the best method to identify the source tab
+ if ( URI.spec !== details.openerURL ) {
+ continue;
+ }
+
+ sourceTabId = vAPI.tabs.getTabId(tab);
+
+ if ( sourceTabId === tabId ) {
+ sourceTabId = null;
+ continue;
+ }
+
+ URI = Services.io.newURI(details.url, null, null);
+
+ if ( httpObserver.handlePopup(URI, tabId, sourceTabId) ) {
+ return;
+ }
+
+ break;
+ }
+ }
+
var lastRequest = httpObserver.lastRequest;
- lastRequest.url = details.url;
- lastRequest.type = details.type;
- lastRequest.tabId = vAPI.tabs.getTabId(e.target);
- lastRequest.frameId = details.frameId;
- lastRequest.parentFrameId = details.parentFrameId;
- lastRequest.openerURL = details.openerURL;
+ lastRequest[1] = lastRequest[0];
+ lastRequest[0] = {
+ frameId: details.frameId,
+ parentFrameId: details.parentFrameId,
+ sourceTabId: sourceTabId,
+ tabId: tabId,
+ type: details.type,
+ url: details.url
+ };
};
vAPI.messaging.globalMessageManager.addMessageListener(
@@ -1232,8 +1415,9 @@ vAPI.toolbarButton = {
/******************************************************************************/
vAPI.toolbarButton.init = function() {
+ var CustomizableUI;
try {
- var {CustomizableUI} = Cu.import('resource:///modules/CustomizableUI.jsm', null);
+ CustomizableUI = Cu.import('resource:///modules/CustomizableUI.jsm', null).CustomizableUI;
} catch (ex) {
return;
}
@@ -1270,6 +1454,7 @@ vAPI.toolbarButton.init = function() {
);
} else {
this.CUIEvents = {};
+
this.CUIEvents.onCustomizeEnd = function() {
var wId = vAPI.toolbarButton.id;
var buttonInPanel = CustomizableUI.getWidget(wId).areaType === CustomizableUI.TYPE_MENU_PANEL;
@@ -1291,8 +1476,9 @@ vAPI.toolbarButton.init = function() {
}
// Anonymous elements need some time to be reachable
- setTimeout(this.updateBadgeStyle, 0);
+ setTimeout(this.updateBadgeStyle, 250);
}.bind(this.CUIEvents);
+
this.CUIEvents.updateBadgeStyle = function() {
var css = [
'background: #666',
@@ -1319,7 +1505,7 @@ vAPI.toolbarButton.init = function() {
this.onCreated = function(button) {
button.setAttribute('badge', '');
- setTimeout(this.CUIEvents.onCustomizeEnd, 0);
+ setTimeout(this.CUIEvents.onCustomizeEnd, 250);
};
CustomizableUI.addListener(this.CUIEvents);
@@ -1452,8 +1638,8 @@ vAPI.contextMenu = {
/******************************************************************************/
-vAPI.contextMenu.displayMenuItem = function(e) {
- var doc = e.target.ownerDocument;
+vAPI.contextMenu.displayMenuItem = function({target}) {
+ var doc = target.ownerDocument;
var gContextMenu = doc.defaultView.gContextMenu;
if ( !gContextMenu.browser ) {
@@ -1503,6 +1689,17 @@ vAPI.contextMenu.register = function(doc) {
return;
}
+ if ( vAPI.fennec ) {
+ // TODO https://developer.mozilla.org/en-US/Add-ons/Firefox_for_Android/API/NativeWindow/contextmenus/add
+ /*var nativeWindow = doc.defaultView.NativeWindow;
+ contextId = nativeWindow.contextmenus.add(
+ this.menuLabel,
+ nativeWindow.contextmenus.linkOpenableContext,
+ this.onCommand
+ );*/
+ return;
+ }
+
var contextMenu = doc.getElementById('contentAreaContextMenu');
var menuitem = doc.createElement('menuitem');
menuitem.setAttribute('id', this.menuItemId);
@@ -1521,6 +1718,11 @@ vAPI.contextMenu.unregister = function(doc) {
return;
}
+ if ( vAPI.fennec ) {
+ // TODO
+ return;
+ }
+
var menuitem = doc.getElementById(this.menuItemId);
var contextMenu = menuitem.parentNode;
menuitem.removeEventListener('command', this.onCommand);
@@ -1543,13 +1745,14 @@ vAPI.contextMenu.create = function(details, callback) {
}
this.onCommand = function() {
- var gContextMenu = this.ownerDocument.defaultView.gContextMenu;
+ var gContextMenu = getOwnerWindow(this).gContextMenu;
var details = {
menuItemId: this.id
};
if ( gContextMenu.inFrame ) {
details.tagName = 'iframe';
+ // Probably won't work with e10s
details.frameUrl = gContextMenu.focusedWindow.location.href;
} else if ( gContextMenu.onImage ) {
details.tagName = 'img';
diff --git a/platform/safari/vapi-background.js b/platform/safari/vapi-background.js
index d93646a..6b34892 100644
--- a/platform/safari/vapi-background.js
+++ b/platform/safari/vapi-background.js
@@ -42,6 +42,29 @@
/******************************************************************************/
+ if(navigator.userAgent.indexOf("Safari/6") === -1) { // If we're not on at least Safari 8
+ var _open = XMLHttpRequest.prototype.open;
+ XMLHttpRequest.prototype.open = function(m, u) {
+ if(u.lastIndexOf("safari-extension:", 0) === 0) {
+ var i = u.length, seeDot = false;
+ while(i --) {
+ if(u[i] === ".") {
+ seeDot = true;
+ }
+ else if(u[i] === "/") {
+ break;
+ }
+ }
+ if(seeDot === false) {
+ throw 'InvalidAccessError'; // Avoid crash
+ return;
+ }
+ }
+ _open.apply(this, arguments);
+ };
+ }
+ /******************************************************************************/
+
vAPI.app.restart = function() {};
/******************************************************************************/
@@ -59,7 +82,7 @@
vAPI.storage = {
_storage: safari.extension.settings,
- QUOTA_BYTES: 52428800, // copied from Info.plist
+ QUOTA_BYTES: 104857600, // copied from Info.plist
get: function(keys, callback) {
if(typeof callback !== 'function') {
@@ -457,7 +480,7 @@
if(typeof state === "undefined") {
state = vAPI.tabIconState[tabId] = new TabIconState();
}
- icon.badge = state.badge;
+ icon.badge = state.badge;
icon.image = vAPI.getURL("img/browsericons/icon16" + state.img + ".png");
};
vAPI.setIcon = function(tabId, iconStatus, badge) {
@@ -475,7 +498,7 @@
vAPI.messaging = {
listeners: {},
defaultHandler: null,
- NOOPFUNC: function() {},
+ NOOPFUNC: function() {},
UNHANDLED: 'vAPI.messaging.notHandled'
};
diff --git a/platform/safari/vapi-client.js b/platform/safari/vapi-client.js
index a6d5d14..59c08de 100644
--- a/platform/safari/vapi-client.js
+++ b/platform/safari/vapi-client.js
@@ -27,6 +27,13 @@
if(vAPI.vapiClientInjected) {
return;
}
+ var safari;
+ if(typeof self.safari === "undefined") {
+ safari = self.top.safari;
+ }
+ else {
+ safari = self.safari;
+ }
vAPI.vapiClientInjected = true;
vAPI.safari = true;
vAPI.sessionId = String.fromCharCode(Date.now() % 25 + 97) +
@@ -71,9 +78,6 @@
listeners: {},
requestId: 1,
setup: function() {
- if(typeof safari === "undefined") {
- return;
- }
this.connector = function(msg) {
// messages from the background script are sent to every frame,
// so we need to check the vAPI.sessionId to accept only
@@ -107,9 +111,6 @@
channelName: channelName,
listener: typeof callback === 'function' ? callback : null,
send: function(message, callback) {
- if(typeof safari === "undefined") {
- return;
- }
if(!vAPI.messaging.connector) {
vAPI.messaging.setup();
}
@@ -236,7 +237,6 @@ return e.detail.url === false;\
wo = open,\
xo = XMLHttpRequest.prototype.open,\
img = Image;\
-_noOP = function(){};\
Image = function() {\
var x = new img();\
Object.defineProperty(x, 'src', {\
@@ -252,9 +252,9 @@ return x;\
open = function(u) {\
return block(u, 'popup') ? null : wo.apply(this, arguments);\
};\
-XMLHttpRequest.prototype.open = function(m, u, s) {\
-if(block(u, 'xmlhttprequest')) return {send: _noOP};\
-else return xo.apply(this, arguments);\
+XMLHttpRequest.prototype.open = function(m, u) {\
+if(block(u, 'xmlhttprequest')) {throw 'InvalidAccessError'; return;}\
+else {xo.apply(this, arguments); return;}\
};";
if(frameId === 0) {
tmpScript += "\
diff --git a/src/_locales/ar/messages.json b/src/_locales/ar/messages.json
index ac3cc93..2b2f823 100644
--- a/src/_locales/ar/messages.json
+++ b/src/_locales/ar/messages.json
@@ -352,7 +352,7 @@
"description":"This will remove all temporary rules"
},
"rulesCommit":{
- "message":"حفظ",
+ "message":"تعليق",
"description":"This will persist temporary rules"
},
"rulesEdit":{
@@ -451,6 +451,14 @@
"message":"خلف الكواليس",
"description":"Pretty name for behind-the-scene network requests"
},
+ "logFilterPrompt":{
+ "message":"فلتر سجل الإدخالات",
+ "description":"English: filter log entries"
+ },
+ "logMaxEntriesTip":{
+ "message":"العدد الأقصى للإدخالات في السجلات",
+ "description":"Tooltip informaing that the input field is to set the maximum number of entries in the log"
+ },
"aboutChangelog":{
"message":"سجل التغيير",
"description":"English: Change log"
diff --git a/src/_locales/bg/messages.json b/src/_locales/bg/messages.json
index 75a49b1..396353c 100644
--- a/src/_locales/bg/messages.json
+++ b/src/_locales/bg/messages.json
@@ -192,11 +192,11 @@
"description":"English: Create"
},
"pickerPick":{
- "message":"Избиране",
+ "message":"Нов избор",
"description":"English: Pick"
},
"pickerQuit":{
- "message":"Изход",
+ "message":"Отказ",
"description":"English: Quit"
},
"pickerNetFilters":{
@@ -451,6 +451,14 @@
"message":"Скрити",
"description":"Pretty name for behind-the-scene network requests"
},
+ "logFilterPrompt":{
+ "message":"филтриране на записи",
+ "description":"English: filter log entries"
+ },
+ "logMaxEntriesTip":{
+ "message":"Максимален брой записи в дневника",
+ "description":"Tooltip informaing that the input field is to set the maximum number of entries in the log"
+ },
"aboutChangelog":{
"message":"Списък с промени",
"description":"English: Change log"
diff --git a/src/_locales/ca/messages.json b/src/_locales/ca/messages.json
index d08bc30..b05163d 100644
--- a/src/_locales/ca/messages.json
+++ b/src/_locales/ca/messages.json
@@ -451,6 +451,14 @@
"message":"Peticions ocultes",
"description":"Pretty name for behind-the-scene network requests"
},
+ "logFilterPrompt":{
+ "message":"filter log entries",
+ "description":"English: filter log entries"
+ },
+ "logMaxEntriesTip":{
+ "message":"Maximum number of log entries",
+ "description":"Tooltip informaing that the input field is to set the maximum number of entries in the log"
+ },
"aboutChangelog":{
"message":"Registre de canvis",
"description":"English: Change log"
diff --git a/src/_locales/cs/messages.json b/src/_locales/cs/messages.json
index c65f2b8..786d755 100644
--- a/src/_locales/cs/messages.json
+++ b/src/_locales/cs/messages.json
@@ -451,6 +451,14 @@
"message":"Za oponou",
"description":"Pretty name for behind-the-scene network requests"
},
+ "logFilterPrompt":{
+ "message":"filtrovat záznamy",
+ "description":"English: filter log entries"
+ },
+ "logMaxEntriesTip":{
+ "message":"Maximum number of log entries",
+ "description":"Tooltip informaing that the input field is to set the maximum number of entries in the log"
+ },
"aboutChangelog":{
"message":"Change log",
"description":"English: Change log"
diff --git a/src/_locales/da/messages.json b/src/_locales/da/messages.json
index 0c819ae..5c0dd11 100644
--- a/src/_locales/da/messages.json
+++ b/src/_locales/da/messages.json
@@ -180,7 +180,7 @@
"description":""
},
"popupHitDomainCountPrompt":{
- "message":"Tilsluttede domæner",
+ "message":"Forbundne domæner",
"description":"appears in popup"
},
"popupHitDomainCount":{
@@ -380,7 +380,7 @@
"description":"default file name to use"
},
"rulesHint":{
- "message":"Liste af dine dynamiske filtreringsregler.",
+ "message":"Liste over dine dynamiske filtreringsregler.",
"description":"English: List of your dynamic filtering rules."
},
"rulesFormatHint":{
@@ -451,6 +451,14 @@
"message":"Bag kulisserne",
"description":"Pretty name for behind-the-scene network requests"
},
+ "logFilterPrompt":{
+ "message":"Filtrér elementer i log",
+ "description":"English: filter log entries"
+ },
+ "logMaxEntriesTip":{
+ "message":"Maksimalt antal elementer i log",
+ "description":"Tooltip informaing that the input field is to set the maximum number of entries in the log"
+ },
"aboutChangelog":{
"message":"Changelog",
"description":"English: Change log"
diff --git a/src/_locales/de/messages.json b/src/_locales/de/messages.json
index 65d5450..dd63771 100644
--- a/src/_locales/de/messages.json
+++ b/src/_locales/de/messages.json
@@ -451,6 +451,14 @@
"message":"Hintergrundanfragen",
"description":"Pretty name for behind-the-scene network requests"
},
+ "logFilterPrompt":{
+ "message":"Protokoll-Einträge filtern",
+ "description":"English: filter log entries"
+ },
+ "logMaxEntriesTip":{
+ "message":"Maximale Anzahl an Protokoll-Einträgen",
+ "description":"Tooltip informaing that the input field is to set the maximum number of entries in the log"
+ },
"aboutChangelog":{
"message":"Änderungsprotokoll",
"description":"English: Change log"
diff --git a/src/_locales/el/messages.json b/src/_locales/el/messages.json
index d64787f..5e2668d 100644
--- a/src/_locales/el/messages.json
+++ b/src/_locales/el/messages.json
@@ -451,6 +451,14 @@
"message":"Behind the scene",
"description":"Pretty name for behind-the-scene network requests"
},
+ "logFilterPrompt":{
+ "message":"filter log entries",
+ "description":"English: filter log entries"
+ },
+ "logMaxEntriesTip":{
+ "message":"Maximum number of log entries",
+ "description":"Tooltip informaing that the input field is to set the maximum number of entries in the log"
+ },
"aboutChangelog":{
"message":"Change log",
"description":"English: Change log"
diff --git a/src/_locales/en/messages.json b/src/_locales/en/messages.json
index 5c88964..2fdc432 100644
--- a/src/_locales/en/messages.json
+++ b/src/_locales/en/messages.json
@@ -451,6 +451,14 @@
"message":"Behind the scene",
"description":"Pretty name for behind-the-scene network requests"
},
+ "logFilterPrompt":{
+ "message":"filter log entries",
+ "description": "English: filter log entries"
+ },
+ "logMaxEntriesTip":{
+ "message":"Maximum number of log entries",
+ "description":"Tooltip informaing that the input field is to set the maximum number of entries in the log"
+ },
"aboutChangelog":{
"message":"Change log",
"description":"English: Change log"
diff --git a/src/_locales/es/messages.json b/src/_locales/es/messages.json
index e54bd66..afade6e 100644
--- a/src/_locales/es/messages.json
+++ b/src/_locales/es/messages.json
@@ -451,8 +451,16 @@
"message":"Peticiones ocultas",
"description":"Pretty name for behind-the-scene network requests"
},
+ "logFilterPrompt":{
+ "message":"filtrar entradas del registro",
+ "description":"English: filter log entries"
+ },
+ "logMaxEntriesTip":{
+ "message":"Cantidad máxima de entradas del registro",
+ "description":"Tooltip informaing that the input field is to set the maximum number of entries in the log"
+ },
"aboutChangelog":{
- "message":"Cambios",
+ "message":"Registro de cambios",
"description":"English: Change log"
},
"aboutWiki":{
diff --git a/src/_locales/et/messages.json b/src/_locales/et/messages.json
index 791bda0..0f86442 100644
--- a/src/_locales/et/messages.json
+++ b/src/_locales/et/messages.json
@@ -451,6 +451,14 @@
"message":"Telgitagus",
"description":"Pretty name for behind-the-scene network requests"
},
+ "logFilterPrompt":{
+ "message":"filtreeri logikirjeid",
+ "description":"English: filter log entries"
+ },
+ "logMaxEntriesTip":{
+ "message":"Maksimaalne logikirjete arv",
+ "description":"Tooltip informaing that the input field is to set the maximum number of entries in the log"
+ },
"aboutChangelog":{
"message":"Muudatuste logi",
"description":"English: Change log"
diff --git a/src/_locales/fa/messages.json b/src/_locales/fa/messages.json
index de410d3..3f143b7 100644
--- a/src/_locales/fa/messages.json
+++ b/src/_locales/fa/messages.json
@@ -451,6 +451,14 @@
"message":"پشت صحنه",
"description":"Pretty name for behind-the-scene network requests"
},
+ "logFilterPrompt":{
+ "message":"filter log entries",
+ "description":"English: filter log entries"
+ },
+ "logMaxEntriesTip":{
+ "message":"Maximum number of log entries",
+ "description":"Tooltip informaing that the input field is to set the maximum number of entries in the log"
+ },
"aboutChangelog":{
"message":"تغییرات اخیر",
"description":"English: Change log"
diff --git a/src/_locales/fi/messages.json b/src/_locales/fi/messages.json
index 51e26f6..be181c4 100644
--- a/src/_locales/fi/messages.json
+++ b/src/_locales/fi/messages.json
@@ -451,6 +451,14 @@
"message":"Behind the scene",
"description":"Pretty name for behind-the-scene network requests"
},
+ "logFilterPrompt":{
+ "message":"filter log entries",
+ "description":"English: filter log entries"
+ },
+ "logMaxEntriesTip":{
+ "message":"Maximum number of log entries",
+ "description":"Tooltip informaing that the input field is to set the maximum number of entries in the log"
+ },
"aboutChangelog":{
"message":"Muutosloki",
"description":"English: Change log"
diff --git a/src/_locales/fil/messages.json b/src/_locales/fil/messages.json
index c82f6af..40303a8 100644
--- a/src/_locales/fil/messages.json
+++ b/src/_locales/fil/messages.json
@@ -451,6 +451,14 @@
"message":"Behind the scene",
"description":"Pretty name for behind-the-scene network requests"
},
+ "logFilterPrompt":{
+ "message":"filter log entries",
+ "description":"English: filter log entries"
+ },
+ "logMaxEntriesTip":{
+ "message":"Maximum number of log entries",
+ "description":"Tooltip informaing that the input field is to set the maximum number of entries in the log"
+ },
"aboutChangelog":{
"message":"Change log",
"description":"English: Change log"
diff --git a/src/_locales/fr/messages.json b/src/_locales/fr/messages.json
index bad4662..72e8756 100644
--- a/src/_locales/fr/messages.json
+++ b/src/_locales/fr/messages.json
@@ -451,6 +451,14 @@
"message":"Requêtes en coulisses",
"description":"Pretty name for behind-the-scene network requests"
},
+ "logFilterPrompt":{
+ "message":"Filtrer les entrées du journal",
+ "description":"English: filter log entries"
+ },
+ "logMaxEntriesTip":{
+ "message":"Nombre maximum d'entrées à conserver dans le journal",
+ "description":"Tooltip informaing that the input field is to set the maximum number of entries in the log"
+ },
"aboutChangelog":{
"message":"Journal des changements (en Anglais)",
"description":"English: Change log"
diff --git a/src/_locales/he/messages.json b/src/_locales/he/messages.json
index 750e9eb..cdebd14 100644
--- a/src/_locales/he/messages.json
+++ b/src/_locales/he/messages.json
@@ -451,6 +451,14 @@
"message":"מאחורי הקלעים",
"description":"Pretty name for behind-the-scene network requests"
},
+ "logFilterPrompt":{
+ "message":"סנן רשומות",
+ "description":"English: filter log entries"
+ },
+ "logMaxEntriesTip":{
+ "message":"מספר רשומות מקסימליות",
+ "description":"Tooltip informaing that the input field is to set the maximum number of entries in the log"
+ },
"aboutChangelog":{
"message":"רשימת שינויים",
"description":"English: Change log"
diff --git a/src/_locales/hi/messages.json b/src/_locales/hi/messages.json
index a76f54c..ae402e0 100644
--- a/src/_locales/hi/messages.json
+++ b/src/_locales/hi/messages.json
@@ -451,6 +451,14 @@
"message":"पर्दे के पीछे",
"description":"Pretty name for behind-the-scene network requests"
},
+ "logFilterPrompt":{
+ "message":"filter log entries",
+ "description":"English: filter log entries"
+ },
+ "logMaxEntriesTip":{
+ "message":"Maximum number of log entries",
+ "description":"Tooltip informaing that the input field is to set the maximum number of entries in the log"
+ },
"aboutChangelog":{
"message":"Change log",
"description":"English: Change log"
diff --git a/src/_locales/hr/messages.json b/src/_locales/hr/messages.json
index 51c30fa..a9a326e 100644
--- a/src/_locales/hr/messages.json
+++ b/src/_locales/hr/messages.json
@@ -451,6 +451,14 @@
"message":"Iza scene",
"description":"Pretty name for behind-the-scene network requests"
},
+ "logFilterPrompt":{
+ "message":"filtrirajte zabilješke",
+ "description":"English: filter log entries"
+ },
+ "logMaxEntriesTip":{
+ "message":"Maximum number of log entries",
+ "description":"Tooltip informaing that the input field is to set the maximum number of entries in the log"
+ },
"aboutChangelog":{
"message":"Popis promjena",
"description":"English: Change log"
diff --git a/src/_locales/hu/messages.json b/src/_locales/hu/messages.json
index 097e606..8d65e89 100644
--- a/src/_locales/hu/messages.json
+++ b/src/_locales/hu/messages.json
@@ -184,7 +184,7 @@
"description":"appears in popup"
},
"popupHitDomainCount":{
- "message":"{{count}} a(z) {{total}}-böl",
+ "message":"{{count}}, összesen: {{total}}",
"description":"appears in popup"
},
"pickerCreate":{
@@ -451,6 +451,14 @@
"message":"Hálózati forgalom a háttérben",
"description":"Pretty name for behind-the-scene network requests"
},
+ "logFilterPrompt":{
+ "message":"Naplóbejegyzések szűrése",
+ "description":"English: filter log entries"
+ },
+ "logMaxEntriesTip":{
+ "message":"Maximum naplóbejegyzések száma",
+ "description":"Tooltip informaing that the input field is to set the maximum number of entries in the log"
+ },
"aboutChangelog":{
"message":"Változások listája",
"description":"English: Change log"
diff --git a/src/_locales/id/messages.json b/src/_locales/id/messages.json
index 68b56d8..1f3b47d 100644
--- a/src/_locales/id/messages.json
+++ b/src/_locales/id/messages.json
@@ -451,6 +451,14 @@
"message":"Di balik layar",
"description":"Pretty name for behind-the-scene network requests"
},
+ "logFilterPrompt":{
+ "message":"saring entri catatan",
+ "description":"English: filter log entries"
+ },
+ "logMaxEntriesTip":{
+ "message":"Jumlah maximum entri catatan",
+ "description":"Tooltip informaing that the input field is to set the maximum number of entries in the log"
+ },
"aboutChangelog":{
"message":"Catatan perubahan",
"description":"English: Change log"
diff --git a/src/_locales/it/messages.json b/src/_locales/it/messages.json
index 906fbdc..568b072 100644
--- a/src/_locales/it/messages.json
+++ b/src/_locales/it/messages.json
@@ -451,6 +451,14 @@
"message":"Dietro le quinte",
"description":"Pretty name for behind-the-scene network requests"
},
+ "logFilterPrompt":{
+ "message":"filter log entries",
+ "description":"English: filter log entries"
+ },
+ "logMaxEntriesTip":{
+ "message":"Maximum number of log entries",
+ "description":"Tooltip informaing that the input field is to set the maximum number of entries in the log"
+ },
"aboutChangelog":{
"message":"Change log",
"description":"English: Change log"
diff --git a/src/_locales/ja/messages.json b/src/_locales/ja/messages.json
index 33b35e4..4f061c1 100644
--- a/src/_locales/ja/messages.json
+++ b/src/_locales/ja/messages.json
@@ -451,6 +451,14 @@
"message":"Behind the scene",
"description":"Pretty name for behind-the-scene network requests"
},
+ "logFilterPrompt":{
+ "message":"絞り込み",
+ "description":"English: filter log entries"
+ },
+ "logMaxEntriesTip":{
+ "message":"Maximum number of log entries",
+ "description":"Tooltip informaing that the input field is to set the maximum number of entries in the log"
+ },
"aboutChangelog":{
"message":"バージョン更新履歴 (Change log)",
"description":"English: Change log"
diff --git a/src/_locales/ko/messages.json b/src/_locales/ko/messages.json
index 5d6a884..a0fffb0 100644
--- a/src/_locales/ko/messages.json
+++ b/src/_locales/ko/messages.json
@@ -451,6 +451,14 @@
"message":"숨겨진 구성 요소",
"description":"Pretty name for behind-the-scene network requests"
},
+ "logFilterPrompt":{
+ "message":"필터 로그 항목",
+ "description":"English: filter log entries"
+ },
+ "logMaxEntriesTip":{
+ "message":"로그 항목의 최대 갯수",
+ "description":"Tooltip informaing that the input field is to set the maximum number of entries in the log"
+ },
"aboutChangelog":{
"message":"변경사항",
"description":"English: Change log"
diff --git a/src/_locales/lv/messages.json b/src/_locales/lv/messages.json
index 22227c5..a92a2dc 100644
--- a/src/_locales/lv/messages.json
+++ b/src/_locales/lv/messages.json
@@ -451,6 +451,14 @@
"message":"Aizkulisēs",
"description":"Pretty name for behind-the-scene network requests"
},
+ "logFilterPrompt":{
+ "message":"žurnāla ierakstu filtrs",
+ "description":"English: filter log entries"
+ },
+ "logMaxEntriesTip":{
+ "message":"Žurnāla ierakstu maksimālais skaits",
+ "description":"Tooltip informaing that the input field is to set the maximum number of entries in the log"
+ },
"aboutChangelog":{
"message":"Izmaiņu žurnāls",
"description":"English: Change log"
diff --git a/src/_locales/mr/messages.json b/src/_locales/mr/messages.json
index 45ee80e..2e4b7f4 100644
--- a/src/_locales/mr/messages.json
+++ b/src/_locales/mr/messages.json
@@ -451,6 +451,14 @@
"message":"Behind the scene",
"description":"Pretty name for behind-the-scene network requests"
},
+ "logFilterPrompt":{
+ "message":"filter log entries",
+ "description":"English: filter log entries"
+ },
+ "logMaxEntriesTip":{
+ "message":"Maximum number of log entries",
+ "description":"Tooltip informaing that the input field is to set the maximum number of entries in the log"
+ },
"aboutChangelog":{
"message":"बदल नोंदी",
"description":"English: Change log"
diff --git a/src/_locales/nb/messages.json b/src/_locales/nb/messages.json
index b02ce3e..4b34175 100644
--- a/src/_locales/nb/messages.json
+++ b/src/_locales/nb/messages.json
@@ -451,6 +451,14 @@
"message":"Bak kulissene",
"description":"Pretty name for behind-the-scene network requests"
},
+ "logFilterPrompt":{
+ "message":"filter log entries",
+ "description":"English: filter log entries"
+ },
+ "logMaxEntriesTip":{
+ "message":"Maximum number of log entries",
+ "description":"Tooltip informaing that the input field is to set the maximum number of entries in the log"
+ },
"aboutChangelog":{
"message":"Endringslogg",
"description":"English: Change log"
diff --git a/src/_locales/nl/messages.json b/src/_locales/nl/messages.json
index 2a03591..b87cadc 100644
--- a/src/_locales/nl/messages.json
+++ b/src/_locales/nl/messages.json
@@ -32,7 +32,7 @@
"description":"appears as tab name in dashboard"
},
"statsPageName":{
- "message":"µBlock — Log van netwerkverzoeken",
+ "message":"µBlock — Logboek van netwerkverzoeken",
"description":"Title for the network request log window"
},
"aboutPageName":{
@@ -68,7 +68,7 @@
"description":"English: Enter element picker mode"
},
"popupTipLog":{
- "message":"Ga naar verzoekenlog",
+ "message":"Naar verzoekenlogboek gaan",
"description":"English: Go to request log"
},
"popupSiteInlineScriptEnabled":{
@@ -451,6 +451,14 @@
"message":"Achter de schermen",
"description":"Pretty name for behind-the-scene network requests"
},
+ "logFilterPrompt":{
+ "message":"logboekitems filteren",
+ "description":"English: filter log entries"
+ },
+ "logMaxEntriesTip":{
+ "message":"Maximum aantal logboekitems",
+ "description":"Tooltip informaing that the input field is to set the maximum number of entries in the log"
+ },
"aboutChangelog":{
"message":"Veranderingenlogboek",
"description":"English: Change log"
diff --git a/src/_locales/pl/messages.json b/src/_locales/pl/messages.json
index 6fa04b2..b9591d4 100644
--- a/src/_locales/pl/messages.json
+++ b/src/_locales/pl/messages.json
@@ -451,6 +451,14 @@
"message":"Za kulisami",
"description":"Pretty name for behind-the-scene network requests"
},
+ "logFilterPrompt":{
+ "message":"filtruj wpisy w logu",
+ "description":"English: filter log entries"
+ },
+ "logMaxEntriesTip":{
+ "message":"Maksymalna ilość wpisów do wyświetlenia",
+ "description":"Tooltip informaing that the input field is to set the maximum number of entries in the log"
+ },
"aboutChangelog":{
"message":"Dziennik zmian",
"description":"English: Change log"
diff --git a/src/_locales/pt_BR/messages.json b/src/_locales/pt_BR/messages.json
index c83a80c..d6fcda0 100644
--- a/src/_locales/pt_BR/messages.json
+++ b/src/_locales/pt_BR/messages.json
@@ -451,6 +451,14 @@
"message":"Por trás da cena",
"description":"Pretty name for behind-the-scene network requests"
},
+ "logFilterPrompt":{
+ "message":"filtrar entradas de registro",
+ "description":"English: filter log entries"
+ },
+ "logMaxEntriesTip":{
+ "message":"Número máximo de entradas de registro",
+ "description":"Tooltip informaing that the input field is to set the maximum number of entries in the log"
+ },
"aboutChangelog":{
"message":"Registro de alterações",
"description":"English: Change log"
diff --git a/src/_locales/pt_PT/messages.json b/src/_locales/pt_PT/messages.json
index 512288c..d499585 100644
--- a/src/_locales/pt_PT/messages.json
+++ b/src/_locales/pt_PT/messages.json
@@ -451,6 +451,14 @@
"message":"Bastidores",
"description":"Pretty name for behind-the-scene network requests"
},
+ "logFilterPrompt":{
+ "message":"filtrar entradas de registo",
+ "description":"English: filter log entries"
+ },
+ "logMaxEntriesTip":{
+ "message":"Maximum number of log entries",
+ "description":"Tooltip informaing that the input field is to set the maximum number of entries in the log"
+ },
"aboutChangelog":{
"message":"Registo de alterações",
"description":"English: Change log"
diff --git a/src/_locales/ro/messages.json b/src/_locales/ro/messages.json
index 52c7e1d..74c95b8 100644
--- a/src/_locales/ro/messages.json
+++ b/src/_locales/ro/messages.json
@@ -451,6 +451,14 @@
"message":"În spatele scenei",
"description":"Pretty name for behind-the-scene network requests"
},
+ "logFilterPrompt":{
+ "message":"Filtrează intrările din jurnal",
+ "description":"English: filter log entries"
+ },
+ "logMaxEntriesTip":{
+ "message":"Numărul maxim de intrări în jurnal",
+ "description":"Tooltip informaing that the input field is to set the maximum number of entries in the log"
+ },
"aboutChangelog":{
"message":"Jurnalul de modificări",
"description":"English: Change log"
diff --git a/src/_locales/ru/messages.json b/src/_locales/ru/messages.json
index 9fefe1a..a489851 100644
--- a/src/_locales/ru/messages.json
+++ b/src/_locales/ru/messages.json
@@ -451,6 +451,14 @@
"message":"За кулисами",
"description":"Pretty name for behind-the-scene network requests"
},
+ "logFilterPrompt":{
+ "message":"фильтр записей в журнале",
+ "description":"English: filter log entries"
+ },
+ "logMaxEntriesTip":{
+ "message":"Максимальное количество записей в журнале",
+ "description":"Tooltip informaing that the input field is to set the maximum number of entries in the log"
+ },
"aboutChangelog":{
"message":"Список изменений",
"description":"English: Change log"
diff --git a/src/_locales/sq/messages.json b/src/_locales/sq/messages.json
index 8436629..ebd2e1f 100644
--- a/src/_locales/sq/messages.json
+++ b/src/_locales/sq/messages.json
@@ -451,6 +451,14 @@
"message":"Në prapaskenë",
"description":"Pretty name for behind-the-scene network requests"
},
+ "logFilterPrompt":{
+ "message":"filtroni elementet e ditarit",
+ "description":"English: filter log entries"
+ },
+ "logMaxEntriesTip":{
+ "message":"Numri maksimal i elementeve të ditarit",
+ "description":"Tooltip informaing that the input field is to set the maximum number of entries in the log"
+ },
"aboutChangelog":{
"message":"Ditari i ndryshimeve",
"description":"English: Change log"
diff --git a/src/_locales/sv/messages.json b/src/_locales/sv/messages.json
index 33ce3df..2541c6e 100644
--- a/src/_locales/sv/messages.json
+++ b/src/_locales/sv/messages.json
@@ -160,7 +160,7 @@
"description":""
},
"popup3pAnyRulePrompt":{
- "message":"Tredjeparts",
+ "message":"Tredjepart",
"description":""
},
"popupInlineScriptRulePrompt":{
@@ -232,7 +232,7 @@
"description":"English: "
},
"settingsExperimentalPrompt":{
- "message":"Aktivera experimentella funktioner",
+ "message":"Aktivera experimentella funktioner (<a href='https:\/\/github.com\/gorhill\/uBlock\/wiki\/Experimental-features'>Om<\/a>)",
"description":"English: Enable experimental features"
},
"3pListsOfBlockedHostsPrompt":{
@@ -372,7 +372,7 @@
"description":""
},
"rulesExport":{
- "message":"Exportera till fil...",
+ "message":"Exportera till fil",
"description":""
},
"rulesDefaultFileName":{
@@ -451,6 +451,14 @@
"message":"Under huven",
"description":"Pretty name for behind-the-scene network requests"
},
+ "logFilterPrompt":{
+ "message":"filtrera loggposter",
+ "description":"English: filter log entries"
+ },
+ "logMaxEntriesTip":{
+ "message":"Maximalt antal loggposter",
+ "description":"Tooltip informaing that the input field is to set the maximum number of entries in the log"
+ },
"aboutChangelog":{
"message":"Ändringslogg",
"description":"English: Change log"
diff --git a/src/_locales/tr/messages.json b/src/_locales/tr/messages.json
index 966c3c1..956aa7e 100644
--- a/src/_locales/tr/messages.json
+++ b/src/_locales/tr/messages.json
@@ -451,6 +451,14 @@
"message":"Sahne arkası",
"description":"Pretty name for behind-the-scene network requests"
},
+ "logFilterPrompt":{
+ "message":"filter log entries",
+ "description":"English: filter log entries"
+ },
+ "logMaxEntriesTip":{
+ "message":"Maximum number of log entries",
+ "description":"Tooltip informaing that the input field is to set the maximum number of entries in the log"
+ },
"aboutChangelog":{
"message":"Değişiklikler",
"description":"English: Change log"
diff --git a/src/_locales/uk/messages.json b/src/_locales/uk/messages.json
index 8e5bcf2..f0ce2fb 100644
--- a/src/_locales/uk/messages.json
+++ b/src/_locales/uk/messages.json
@@ -451,6 +451,14 @@
"message":"За лаштунками",
"description":"Pretty name for behind-the-scene network requests"
},
+ "logFilterPrompt":{
+ "message":"фільтр журналу записів",
+ "description":"English: filter log entries"
+ },
+ "logMaxEntriesTip":{
+ "message":"Максимальна кількість записів в журналі",
+ "description":"Tooltip informaing that the input field is to set the maximum number of entries in the log"
+ },
"aboutChangelog":{
"message":"Журнал змін",
"description":"English: Change log"
diff --git a/src/_locales/vi/messages.json b/src/_locales/vi/messages.json
index 9fff306..0eac71a 100644
--- a/src/_locales/vi/messages.json
+++ b/src/_locales/vi/messages.json
@@ -180,7 +180,7 @@
"description":""
},
"popupHitDomainCountPrompt":{
- "message":"tên miền",
+ "message":"tên miền đã kết nối",
"description":"appears in popup"
},
"popupHitDomainCount":{
@@ -451,6 +451,14 @@
"message":"Behind the scene",
"description":"Pretty name for behind-the-scene network requests"
},
+ "logFilterPrompt":{
+ "message":"lọc mục ghi nhận",
+ "description":"English: filter log entries"
+ },
+ "logMaxEntriesTip":{
+ "message":"Số mục ghi nhận tối đa",
+ "description":"Tooltip informaing that the input field is to set the maximum number of entries in the log"
+ },
"aboutChangelog":{
"message":"Thay đổi",
"description":"English: Change log"
diff --git a/src/_locales/zh_CN/messages.json b/src/_locales/zh_CN/messages.json
index e76353f..7c860a9 100644
--- a/src/_locales/zh_CN/messages.json
+++ b/src/_locales/zh_CN/messages.json
@@ -451,6 +451,14 @@
"message":"后台",
"description":"Pretty name for behind-the-scene network requests"
},
+ "logFilterPrompt":{
+ "message":"过滤日志条目",
+ "description":"English: filter log entries"
+ },
+ "logMaxEntriesTip":{
+ "message":"日志条目最大数量",
+ "description":"Tooltip informaing that the input field is to set the maximum number of entries in the log"
+ },
"aboutChangelog":{
"message":"更新日志",
"description":"English: Change log"
diff --git a/src/_locales/zh_TW/messages.json b/src/_locales/zh_TW/messages.json
index 8ee47cf..f827916 100644
--- a/src/_locales/zh_TW/messages.json
+++ b/src/_locales/zh_TW/messages.json
@@ -332,7 +332,7 @@
"description":"English: Export"
},
"1pExportFilename":{
- "message":"ublock-自訂過濾_{{datetime}}.txt",
+ "message":"我的-ublock-自訂過濾_{{datetime}}.txt",
"description":"English: my-ublock-static-filters_{{datetime}}.txt"
},
"1pApplyChanges":{
@@ -376,7 +376,7 @@
"description":""
},
"rulesDefaultFileName":{
- "message":"ublock-自訂動態規則_{{datetime}}.txt",
+ "message":"我的-ublock-自訂動態規則_{{datetime}}.txt",
"description":"default file name to use"
},
"rulesHint":{
@@ -384,7 +384,7 @@
"description":"English: List of your dynamic filtering rules."
},
"rulesFormatHint":{
- "message":"規則語法: <code>來源主機名稱 目標主機名稱 需求類型 行為<\/code> (<a href='https:\/\/github.com\/gorhill\/uBlock\/wiki\/Dynamic-filtering:-rule-syntax'>說明文件<\/a>)。",
+ "message":"規則語法:<code>來源主機名稱 目標主機名稱 連線請求類型 操作<\/code>(<a href='https:\/\/github.com\/gorhill\/uBlock\/wiki\/Dynamic-filtering:-rule-syntax'>完整說明<\/a>)。",
"description":"English: dynamic rule syntax and full documentation."
},
"whitelistPrompt":{
@@ -400,7 +400,7 @@
"description":"English: Export"
},
"whitelistExportFilename":{
- "message":"ublock-白名單_{{datetime}}.txt",
+ "message":"我的-ublock-白名單_{{datetime}}.txt",
"description":"English: my-ublock-whitelist_{{datetime}}.txt"
},
"whitelistApply":{
@@ -451,6 +451,14 @@
"message":"幕後",
"description":"Pretty name for behind-the-scene network requests"
},
+ "logFilterPrompt":{
+ "message":"過濾規則的日誌項目",
+ "description":"English: filter log entries"
+ },
+ "logMaxEntriesTip":{
+ "message":"紀錄的最大項目數量",
+ "description":"Tooltip informaing that the input field is to set the maximum number of entries in the log"
+ },
"aboutChangelog":{
"message":"更新日誌",
"description":"English: Change log"
@@ -472,7 +480,7 @@
"description":"English: Backup to file"
},
"aboutBackupFilename":{
- "message":"ublock-備份_{{datetime}}.txt",
+ "message":"我的-ublock-備份_{{datetime}}.txt",
"description":"English: my-ublock-backup_{{datetime}}.txt"
},
"aboutRestoreDataButton":{
diff --git a/src/css/devtool-log.css b/src/css/devtool-log.css
index 3655792..d3ea119 100644
--- a/src/css/devtool-log.css
+++ b/src/css/devtool-log.css
@@ -10,32 +10,44 @@ body {
width: 100%;
}
#toolbar {
- padding: 8px 0;
+ background-color: white;
+ border: 0;
+ box-sizing: border-box;
+ height: 36px;
+ margin: 0;
+ padding: 0;
position: fixed;
text-align: center;
top: 0;
- width: 4em;
+ width: 100%;
}
#toolbar .button {
background-color: white;
border: none;
+ box-sizing: border-box;
cursor: pointer;
- display: block;
- font-size: large;
+ display: inline-block;
+ font-size: 20px;
margin: 0;
- padding: 0.5em 0;
+ padding: 8px;
}
#toolbar .button:hover {
background-color: #eee;
}
-#content {
- width: calc(100% - 4em);
+body.filterOff #toolbar #filterButton {
+ opacity: 0.25;
+ }
+#filterExpression.bad {
+ background-color: #fee;
}
-body[dir="ltr"] #content {
- margin-left: 4em;
+#maxEntries {
+ margin-left: 3em;
}
-body[dir="rtl"] #content {
- margin-right: 4em;
+input:focus {
+ background-color: #ffe;
+ }
+#content {
+ margin-top: 36px;
}
#content table {
border: 0;
@@ -55,6 +67,9 @@ body[dir="rtl"] #content {
#content table tr.maindoc {
background-color: #eee;
}
+body:not(.filterOff) #content table tr.hidden {
+ display: none;
+ }
#content table tr td {
border: 1px solid #ccc;
padding: 3px;
@@ -63,6 +78,8 @@ body[dir="rtl"] #content {
#content table tr td:nth-of-type(1) {
padding: 3px 0;
text-align: center;
+ white-space: pre;
+ width: 1em;
}
#content table tr td:nth-of-type(2) {
white-space: normal;
diff --git a/src/css/devtools.css b/src/css/devtools.css
index 4f29fb1..44a5892 100644
--- a/src/css/devtools.css
+++ b/src/css/devtools.css
@@ -27,6 +27,9 @@ body {
margin: 0 0 0 1em;
vertical-align: middle;
}
+#pageSelector {
+ max-width: 80%;
+ }
#toolbar #refresh {
margin-left: 4px;
}
diff --git a/src/css/popup.css b/src/css/popup.css
index c453a85..67b83be 100644
--- a/src/css/popup.css
+++ b/src/css/popup.css
@@ -72,6 +72,9 @@ body[dir="ltr"] #panes > div:nth-of-type(2) {
body[dir="rtl"] #panes > div:nth-of-type(2) {
direction: ltr; /* scroll bar to the right */
}
+#panes:not(.dfEnabled) > div:nth-of-type(2) {
+ display: none;
+ }
#panes.dfEnabled > div:nth-of-type(2) {
overflow-y: auto;
width: 320px;
diff --git a/src/devtool-log.html b/src/devtool-log.html
index 3b6ecd8..cd6ae64 100644
--- a/src/devtool-log.html
+++ b/src/devtool-log.html
@@ -10,12 +10,16 @@
<div id="toolbar">
<span id="reload" class="button fa">&#xf021;</span>
<span id="clear" class="button fa">&#xf12d;</span>
- </div><!-- DO NOT REMOVE --><div id="content">
+ <span id="filterButton" class="button fa">&#xf0b0;</span><input id="filterExpression" type="text" placeholder="logFilterPrompt">
+ <input id="maxEntries" type="text" size="5" title="logMaxEntriesTip">
+ </div>
+<div id="content">
<table><tbody></tbody></table>
</div>
<script src="js/vapi-common.js"></script>
<script src="js/vapi-client.js"></script>
<script src="js/udom.js"></script>
+<script src="js/i18n.js"></script>
<script src="js/devtool-log.js"></script>
</body>
</html>
diff --git a/src/js/background.js b/src/js/background.js
index aa8033f..5beaff7 100644
--- a/src/js/background.js
+++ b/src/js/background.js
@@ -63,6 +63,7 @@ return {
externalLists: defaultExternalLists,
firewallPaneMinimized: true,
parseAllABPHideFilters: true,
+ requestLogMaxEntries: 0,
showIconBadge: true
},
@@ -85,7 +86,7 @@ return {
// read-only
systemSettings: {
- compiledMagic: 'iolkecdtfsiy',
+ compiledMagic: 'shztbfhkfjit',
selfieMagic: 'spqmeuaftfra'
},
diff --git a/src/js/contentscript-end.js b/src/js/contentscript-end.js
index a1ecfbc..5efbeb7 100644
--- a/src/js/contentscript-end.js
+++ b/src/js/contentscript-end.js
@@ -93,25 +93,23 @@ var messager = vAPI.messaging.channel('contentscript-end.js');
return;
}
+ //var timer = window.performance || Date;
+ //var tStart = timer.now();
+
var queriedSelectors = {};
var injectedSelectors = {};
- var classSelectors = null;
- var idSelectors = null;
+ var lowGenericSelectors = [];
var highGenerics = null;
var contextNodes = [document];
var nullArray = { push: function(){} };
var retrieveGenericSelectors = function() {
- var selectors = classSelectors !== null ? Object.keys(classSelectors) : [];
- if ( idSelectors !== null ) {
- selectors = selectors.concat(idSelectors);
- }
- if ( selectors.length > 0 || highGenerics === null ) {
- //console.log('µBlock> ABP cosmetic filters: retrieving CSS rules using %d selectors', selectors.length);
+ if ( lowGenericSelectors.length !== 0 || highGenerics === null ) {
+ //console.log('µBlock> ABP cosmetic filters: retrieving CSS rules using %d selectors', lowGenericSelectors.length);
messager.send({
what: 'retrieveGenericCosmeticSelectors',
pageURL: window.location.href,
- selectors: selectors,
+ selectors: lowGenericSelectors,
highGenerics: highGenerics === null
},
retrieveHandler
@@ -122,8 +120,7 @@ var messager = vAPI.messaging.channel('contentscript-end.js');
} else {
otherRetrieveHandler(null);
}
- idSelectors = null;
- classSelectors = null;
+ lowGenericSelectors = [];
};
// https://github.com/gorhill/uBlock/issues/452
@@ -139,7 +136,7 @@ var messager = vAPI.messaging.channel('contentscript-end.js');
var selectors = vAPI.hideCosmeticFilters;
if ( typeof selectors === 'object' ) {
injectedSelectors = selectors;
- hideElements(Object.keys(selectors).join(','));
+ //hideElements(Object.keys(selectors));
}
// Add exception filters into injected filters collection, in order
// to force them to be seen as "already injected".
@@ -158,6 +155,7 @@ var messager = vAPI.messaging.channel('contentscript-end.js');
};
var otherRetrieveHandler = function(selectors) {
+ //var tStart = timer.now();
//console.debug('µBlock> contextNodes = %o', contextNodes);
if ( selectors && selectors.highGenerics ) {
highGenerics = selectors.highGenerics;
@@ -196,6 +194,7 @@ var messager = vAPI.messaging.channel('contentscript-end.js');
addStyleTag(hideSelectors);
}
contextNodes.length = 0;
+ //console.debug('%f: uBlock: CSS injection time', timer.now() - tStart);
};
var retrieveHandler = firstRetrieveHandler;
@@ -206,10 +205,10 @@ var messager = vAPI.messaging.channel('contentscript-end.js');
// - Injecting a style tag
var addStyleTag = function(selectors) {
- hideElements(selectors);
+ //hideElements(selectors);
var style = document.createElement('style');
// The linefeed before the style block is very important: do no remove!
- style.appendChild(document.createTextNode(selectors.join(',\n') + '\n{display:none !important;}'));
+ style.appendChild(document.createTextNode(selectors.toString() + '\n{display:none !important;}'));
var parent = document.body || document.documentElement;
if ( parent ) {
parent.appendChild(style);
@@ -349,12 +348,26 @@ var messager = vAPI.messaging.channel('contentscript-end.js');
// requests to process high-high generics into as few requests as possible.
// The gain is *significant* on bloated pages.
+ var processHighHighGenericsMisses = 8;
var processHighHighGenericsTimer = null;
var processHighHighGenerics = function() {
processHighHighGenericsTimer = null;
- if ( injectedSelectors.hasOwnProperty('{{highHighGenerics}}') ) { return; }
- if ( document.querySelector(highGenerics.hideHigh) === null ) { return; }
+ if ( injectedSelectors.hasOwnProperty('{{highHighGenerics}}') ) {
+ return;
+ }
+ //var tStart = timer.now();
+ if ( document.querySelector(highGenerics.hideHigh) === null ) {
+ //console.debug('%f: high-high generic test time', timer.now() - tStart);
+ processHighHighGenericsMisses -= 1;
+ // Too many misses for these nagging highly generic CSS rules,
+ // so we will just skip them from now on.
+ if ( processHighHighGenericsMisses === 0 ) {
+ injectedSelectors['{{highHighGenerics}}'] = true;
+ console.debug('high-high generic: apparently not needed...');
+ }
+ return;
+ }
injectedSelectors['{{highHighGenerics}}'] = true;
// We need to filter out possible exception cosmetic filters from
// high-high generics selectors.
@@ -388,11 +401,8 @@ var messager = vAPI.messaging.channel('contentscript-end.js');
if ( !nodes || !nodes.length ) {
return;
}
- if ( idSelectors === null ) {
- idSelectors = [];
- }
var qq = queriedSelectors;
- var ii = idSelectors;
+ var ll = lowGenericSelectors;
var node, v;
var i = nodes.length;
while ( i-- ) {
@@ -404,8 +414,8 @@ var messager = vAPI.messaging.channel('contentscript-end.js');
v = v.trim();
if ( v === '' ) { continue; }
v = '#' + v;
- if ( qq[v] ) { continue; }
- ii.push(v);
+ if ( qq.hasOwnProperty(v) ) { continue; }
+ ll.push(v);
qq[v] = true;
}
};
@@ -417,11 +427,8 @@ var messager = vAPI.messaging.channel('contentscript-end.js');
if ( !nodes || !nodes.length ) {
return;
}
- if ( classSelectors === null ) {
- classSelectors = {};
- }
var qq = queriedSelectors;
- var cc = classSelectors;
+ var ll = lowGenericSelectors;
var node, v, vv, j;
var i = nodes.length;
while ( i-- ) {
@@ -433,8 +440,8 @@ var messager = vAPI.messaging.channel('contentscript-end.js');
v = vv[j];
if ( typeof v !== 'string' ) { continue; }
v = '.' + v;
- if ( qq[v] ) { continue; }
- cc[v] = true;
+ if ( qq.hasOwnProperty(v) ) { continue; }
+ ll.push(v);
qq[v] = true;
}
}
@@ -446,6 +453,8 @@ var messager = vAPI.messaging.channel('contentscript-end.js');
classesFromNodeList(document.querySelectorAll('[class]'));
retrieveGenericSelectors();
+ //console.debug('%f: uBlock: survey time', timer.now() - tStart);
+
// Below this point is the code which takes care to observe changes in
// the page and to add if needed relevant CSS rules as a result of the
// changes.
@@ -528,7 +537,6 @@ var messager = vAPI.messaging.channel('contentscript-end.js');
(function() {
// https://github.com/gorhill/uBlock/issues/683
// Instead of a closure we use a map to remember the element to collapse
- // or hide.
var filterRequestId = 1;
var filterRequests = {};
diff --git a/src/js/contentscript-start.js b/src/js/contentscript-start.js
index e2eb6f0..6fba573 100644
--- a/src/js/contentscript-start.js
+++ b/src/js/contentscript-start.js
@@ -156,11 +156,12 @@ var hideElements = function(selectors) {
}
};
+var url = window.location.href;
localMessager.send(
{
what: 'retrieveDomainCosmeticSelectors',
- pageURL: window.location.href,
- locationURL: window.location.href
+ pageURL: url,
+ locationURL: url
},
filteringHandler
);
diff --git a/src/js/cosmetic-filtering.js b/src/js/cosmetic-filtering.js
index 1f54e0b..e4b66eb 100644
--- a/src/js/cosmetic-filtering.js
+++ b/src/js/cosmetic-filtering.js
@@ -1199,7 +1199,7 @@ FilterContainer.prototype.retrieveDomainSelectors = function(request) {
/******************************************************************************/
FilterContainer.prototype.getFilterCount = function() {
- return this.acceptedCount;
+ return this.acceptedCount - this.duplicateCount;
};
/******************************************************************************/
diff --git a/src/js/devtool-log.js b/src/js/devtool-log.js
index e707552..6f2bd19 100644
--- a/src/js/devtool-log.js
+++ b/src/js/devtool-log.js
@@ -36,6 +36,16 @@ var doc = document;
var body = doc.body;
var tbody = doc.querySelector('#content tbody');
var rowJunkyard = [];
+var reFilter = null;
+var filterTargetTestResult = true;
+var maxEntries = 0;
+
+var prettyRequestTypes = {
+ 'main_frame': 'doc',
+ 'stylesheet': 'css',
+ 'sub_frame': 'frame',
+ 'xmlhttprequest': 'xhr'
+};
/******************************************************************************/
@@ -59,6 +69,8 @@ var renderURL = function(url, filter) {
.replace(/\?/g, '\\?')
.replace('||', '')
.replace(/\^/g, '.')
+ .replace(/^\|/g, '^')
+ .replace(/\|$/g, '$')
.replace(/\*/g, '.*')
;
}
@@ -99,15 +111,15 @@ var renderLogEntry = function(entry) {
var tr = createRow();
if ( entry.result.charAt(1) === 'b' ) {
tr.classList.add('blocked');
- tr.cells[0].textContent = '\u2009\u2212\u2009';
+ tr.cells[0].textContent = ' -\u00A0';
} else if ( entry.result.charAt(1) === 'a' ) {
tr.classList.add('allowed');
if ( entry.result.charAt(0) === 'm' ) {
tr.classList.add('mirrored');
}
- tr.cells[0].textContent = '\u2009+\u2009';
+ tr.cells[0].textContent = ' +\u00A0';
} else {
- tr.cells[0].textContent = '\u2009\u00A0\u2009';
+ tr.cells[0].textContent = '';
}
if ( entry.type === 'main_frame' ) {
tr.classList.add('maindoc');
@@ -116,9 +128,10 @@ var renderLogEntry = function(entry) {
if ( entry.result.lastIndexOf('sa', 0) === 0 ) {
filterText = '@@' + filterText;
}
- tr.cells[1].textContent = filterText;
- tr.cells[2].textContent = entry.type;
+ tr.cells[1].textContent = filterText + '\t';
+ tr.cells[2].textContent = (prettyRequestTypes[entry.type] || entry.type) + '\t';
vAPI.insertHTML(tr.cells[3], renderURL(entry.url, entry.result));
+ applyFilterToRow(tr);
tbody.insertBefore(tr, tbody.firstChild);
};
@@ -137,6 +150,11 @@ var renderLogBuffer = function(buffer) {
renderLogEntry(buffer[i]);
}
+ // Prevent logger from growing infinitely and eating all memory. For
+ // instance someone could forget that it is left opened for some
+ // dynamically refreshed pages.
+ truncateLog(maxEntries);
+
var yDelta = tbody.offsetHeight - height;
if ( yDelta === 0 ) {
return;
@@ -161,6 +179,18 @@ var renderLogBuffer = function(buffer) {
/******************************************************************************/
+var truncateLog = function(size) {
+ if ( size === 0 ) {
+ size = 25000;
+ }
+ size = Math.min(size, 25000);
+ while ( tbody.childElementCount > size ) {
+ rowJunkyard.push(tbody.removeChild(tbody.lastElementChild));
+ }
+};
+
+/******************************************************************************/
+
var onBufferRead = function(buffer) {
if ( Array.isArray(buffer) ) {
renderLogBuffer(buffer);
@@ -194,6 +224,146 @@ var reloadTab = function() {
/******************************************************************************/
+var applyFilterToRow = function(row) {
+ var re = reFilter;
+ if ( re === null || re.test(row.textContent) === filterTargetTestResult ) {
+ row.classList.remove('hidden');
+ } else {
+ row.classList.add('hidden');
+ }
+};
+
+/******************************************************************************/
+
+var applyFilter = function() {
+ if ( reFilter === null ) {
+ unapplyFilter();
+ return;
+ }
+ var row = document.querySelector('#content tr');
+ if ( row === null ) {
+ return;
+ }
+ var re = reFilter;
+ var target = filterTargetTestResult;
+ while ( row !== null ) {
+ if ( re.test(row.textContent) === target ) {
+ row.classList.remove('hidden');
+ } else {
+ row.classList.add('hidden');
+ }
+ row = row.nextSibling;
+ }
+};
+
+/******************************************************************************/
+
+var unapplyFilter = function() {
+ var row = document.querySelector('#content tr');
+ if ( row === null ) {
+ return;
+ }
+ while ( row !== null ) {
+ row.classList.remove('hidden');
+ row = row.nextSibling;
+ }
+};
+
+/******************************************************************************/
+
+var onFilterButton = function() {
+ uDom('body').toggleClass('filterOff');
+};
+
+/******************************************************************************/
+
+var onFilterChanged = function() {
+ var filterExpression = uDom('#filterExpression');
+ var filterRaw = filterExpression.val().trim();
+
+ // Assume good filter expression
+ filterExpression.removeClass('bad');
+
+ // Invert resultset?
+ filterTargetTestResult = filterRaw.charAt(0) !== '!';
+ if ( filterTargetTestResult === false ) {
+ filterRaw = filterRaw.slice(1);
+ }
+
+ // No filter
+ if ( filterRaw === '') {
+ reFilter = null;
+ return;
+ }
+
+ // Regex?
+ if ( filterRaw.length > 1 && filterRaw.charAt(0) === '/' && filterRaw.slice(-1) === '/' ) {
+ try {
+ reFilter = new RegExp(filterRaw.slice(1, -1));
+ } catch (e) {
+ reFilter = null;
+ filterExpression.addClass('bad');
+ }
+ return;
+ }
+
+ // Plain filtering
+ var filterParts = filterRaw
+ .replace(/^\s*-(\s+|$)/, '-\xA0 ')
+ .replace(/^\s*\\+(\s+|$)/, '+\xA0 ')
+ .split(/[ \f\n\r\t\v​]+/);
+ var n = filterParts.length;
+ for ( var i = 0; i < n; i++ ) {
+ filterParts[i] = filterParts[i].replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
+ }
+ reFilter = new RegExp(filterParts.join('.*\\s+.*'));
+};
+
+/******************************************************************************/
+
+var onFilterChangedAsync = (function() {
+ var timer = null;
+
+ var commit = function() {
+ timer = null;
+ onFilterChanged();
+ applyFilter();
+ };
+
+ var changed = function() {
+ if ( timer !== null ) {
+ clearTimeout(timer);
+ }
+ timer = setTimeout(commit, 750);
+ };
+
+ return changed;
+})();
+
+/******************************************************************************/
+
+var onMaxEntriesChanged = function() {
+ var raw = uDom(this).val();
+ try {
+ maxEntries = parseInt(raw, 10);
+ if ( isNaN(maxEntries) ) {
+ maxEntries = 0;
+ }
+ } catch (e) {
+ maxEntries = 0;
+ }
+
+ messager.send({
+ what: 'userSettings',
+ name: 'requestLogMaxEntries',
+ value: maxEntries
+ });
+
+ truncateLog(maxEntries);
+};
+
+/******************************************************************************/
+
uDom.onLoad(function() {
// Extract the tab id of the page we need to pull the log
var matches = window.location.search.match(/[\?&]tabId=([^&]+)/);
@@ -201,10 +371,19 @@ uDom.onLoad(function() {
inspectedTabId = matches[1];
}
+ var onSettingsReady = function(settings) {
+ maxEntries = settings.requestLogMaxEntries || 0;
+ uDom('#maxEntries').val(maxEntries || '');
+ };
+ messager.send({ what: 'getUserSettings' }, onSettingsReady);
+
readLogBuffer();
uDom('#reload').on('click', reloadTab);
uDom('#clear').on('click', clearBuffer);
+ uDom('#filterButton').on('click', onFilterButton);
+ uDom('#filterExpression').on('input', onFilterChangedAsync);
+ uDom('#maxEntries').on('change', onMaxEntriesChanged);
});
/******************************************************************************/
diff --git a/src/js/dynamic-net-filtering.js b/src/js/dynamic-net-filtering.js
index 312cb32..4db9e1d 100644
--- a/src/js/dynamic-net-filtering.js
+++ b/src/js/dynamic-net-filtering.js
@@ -26,6 +26,8 @@
µBlock.Firewall = (function() {
+'use strict';
+
/******************************************************************************/
var magicId = 'chmdgxwtetgu';
diff --git a/src/js/i18n.js b/src/js/i18n.js
index bee0b96..231a1db 100644
--- a/src/js/i18n.js
+++ b/src/js/i18n.js
@@ -36,6 +36,9 @@ uDom.onLoad(function() {
elem.attr('title', title);
}
});
+ uDom('[placeholder]').forEach(function(elem) {
+ elem.attr('placeholder', vAPI.i18n(elem.attr('placeholder')));
+ });
uDom('[data-i18n-tip]').forEach(function(elem) {
elem.attr(
'data-tip',
diff --git a/src/js/pagestore.js b/src/js/pagestore.js
index 09dc193..a8cb32d 100644
--- a/src/js/pagestore.js
+++ b/src/js/pagestore.js
@@ -575,7 +575,7 @@ PageStore.prototype.disposeFrameStores = function() {
/******************************************************************************/
PageStore.prototype.getFrame = function(frameId) {
- return this.frames[frameId];
+ return this.frames[frameId] || null;
};
/******************************************************************************/
diff --git a/src/js/start.js b/src/js/start.js
index de71253..bca966b 100644
--- a/src/js/start.js
+++ b/src/js/start.js
@@ -158,11 +158,11 @@ var onSystemSettingsReady = function(fetched) {
mustSaveSystemSettings = true;
}
if ( fetched.selfieMagic !== µb.systemSettings.selfieMagic ) {
- fetched.selfie = null;
- µb.destroySelfie();
mustSaveSystemSettings = true;
}
if ( mustSaveSystemSettings ) {
+ fetched.selfie = null;
+ µb.destroySelfie();
vAPI.storage.set(µb.systemSettings, µb.noopFunc);
}
};
diff --git a/src/js/static-net-filtering.js b/src/js/static-net-filtering.js
index 792d130..d77ef6e 100644
--- a/src/js/static-net-filtering.js
+++ b/src/js/static-net-filtering.js
@@ -19,16 +19,15 @@
Home: https://github.com/gorhill/uBlock
*/
-/* jshint bitwise: false, esnext: true */
-/* global µBlock */
-
-// Older Safari throws an exception for const when it's used with 'use strict'.
-// 'use strict';
+/* jshint bitwise: false, esnext: true, boss: true */
+/* global punycode, µBlock */
/******************************************************************************/
µBlock.staticNetFilteringEngine = (function(){
+'use strict';
+
/******************************************************************************/
var µb = µBlock;
@@ -45,17 +44,17 @@ var µb = µBlock;
// | +---- bit 8-15: unused
// +---- bit 15: never use! (to ensure valid unicode character)
-const BlockAction = 0 << 0;
-const AllowAction = 1 << 0;
-const ToggleAction = BlockAction ^ AllowAction;
+var BlockAction = 0 << 0;
+var AllowAction = 1 << 0;
+var ToggleAction = BlockAction ^ AllowAction;
-const Important = 1 << 1;
+var Important = 1 << 1;
-const AnyParty = 0 << 2;
-const FirstParty = 1 << 2;
-const ThirdParty = 2 << 2;
+var AnyParty = 0 << 2;
+var FirstParty = 1 << 2;
+var ThirdParty = 2 << 2;
-const AnyType = 1 << 4;
+var AnyType = 1 << 4;
var typeNameToTypeValue = {
'stylesheet': 2 << 4,
'image': 3 << 4,
@@ -80,17 +79,15 @@ var typeOtherValue = typeNameToTypeValue.other;
// The 2 lsb *must* be zeroed
var allNetRequestTypesBitmap = (1 << (typeOtherValue >>> 4) + 2) - 4;
-const BlockAnyTypeAnyParty = BlockAction | AnyType | AnyParty;
-const BlockAnyType = BlockAction | AnyType;
-const BlockAnyParty = BlockAction | AnyParty;
+var BlockAnyTypeAnyParty = BlockAction | AnyType | AnyParty;
+var BlockAnyType = BlockAction | AnyType;
+var BlockAnyParty = BlockAction | AnyParty;
-const AllowAnyTypeAnyParty = AllowAction | AnyType | AnyParty;
-const AllowAnyType = AllowAction | AnyType;
-const AllowAnyParty = AllowAction | AnyParty;
+var AllowAnyTypeAnyParty = AllowAction | AnyType | AnyParty;
+var AllowAnyType = AllowAction | AnyType;
+var AllowAnyParty = AllowAction | AnyParty;
-var reHostnameRule = /^[0-9a-z][0-9a-z.-]+[0-9a-z]$/;
-var reHostnameToken = /^[0-9a-z]+/g;
-var reGoodToken = /[%0-9a-z]{2,}/g;
+var reHostnameRule = /^[0-9a-z][0-9a-z.-]*[0-9a-z]$/;
var reURLPostHostnameAnchors = /[\/?#]/;
// ABP filters: https://adblockplus.org/en/filters
@@ -168,6 +165,12 @@ var isFirstParty = function(firstPartyDomain, hostname) {
return c === '.' || c === '';
};
+var strToRegex = function(prefix, s) {
+ var reStr = s.replace(/([.+?^=!:${}()|\[\]\/\\])/g, '\\$1')
+ .replace(/\*/g, '.*');
+ return new RegExp(prefix + reStr);
+};
+
/*******************************************************************************
Filters family tree:
@@ -872,6 +875,85 @@ FilterSingleWildcardRightAnchoredHostname.fromSelfie = function(s) {
/******************************************************************************/
+// Generic filter: hostname-anchored: it has that extra test to find out
+// whether the start of the match falls within the hostname part of the
+// URL.
+
+var FilterGenericHnAnchored = function(s) {
+ this.s = s;
+ this.re = null;
+};
+
+FilterGenericHnAnchored.prototype.match = function(url) {
+ if ( this.re === null ) {
+ this.re = strToRegex('', this.s);
+ }
+ // Quick test first
+ if ( this.re.test(url) === false ) {
+ return false;
+ }
+ // Valid only if begininning of match is within the hostname
+ // part of the url
+ var match = this.re.exec(url);
+ var pos = url.indexOf('://');
+ return pos !== -1 &&
+ reURLPostHostnameAnchors.test(url.slice(pos + 3, match.index)) === false;
+};
+
+FilterGenericHnAnchored.fid = FilterGenericHnAnchored.prototype.fid = '||_';
+
+FilterGenericHnAnchored.prototype.toString = function() {
+ return '||' + this.s;
+};
+
+FilterGenericHnAnchored.prototype.toSelfie = function() {
+ return this.s;
+};
+
+FilterGenericHnAnchored.compile = function(details) {
+ return details.f;
+};
+
+FilterGenericHnAnchored.fromSelfie = function(s) {
+ return new FilterGenericHnAnchored(s);
+};
+
+/******************************************************************************/
+
+var FilterGenericHnAnchoredHostname = function(s, hostname) {
+ FilterGenericHnAnchored.call(this, s);
+ this.hostname = hostname;
+};
+FilterGenericHnAnchoredHostname.prototype = Object.create(FilterGenericHnAnchored.prototype);
+
+FilterGenericHnAnchoredHostname.prototype.match = function(url) {
+ if ( pageHostnameRegister.slice(-this.hostname.length) !== this.hostname ) {
+ return false;
+ }
+ return FilterGenericHnAnchored.prototype.match.call(this, url);
+};
+
+FilterGenericHnAnchoredHostname.fid = FilterGenericHnAnchoredHostname.prototype.fid = '||_h';
+
+FilterGenericHnAnchoredHostname.prototype.toString = function() {
+ return '||' + this.s + '$domain=' + this.hostname;
+};
+
+FilterGenericHnAnchoredHostname.prototype.toSelfie = function() {
+ return this.s + '\t' + this.hostname;
+};
+
+FilterGenericHnAnchoredHostname.compile = function(details, hostname) {
+ return details.f + '\t' + hostname;
+};
+
+FilterGenericHnAnchoredHostname.fromSelfie = function(s) {
+ var pos = s.indexOf('\t');
+ return new FilterGenericHnAnchoredHostname(s.slice(0, pos), s.slice(pos + 1));
+};
+
+/******************************************************************************/
+
// With many wildcards, a regex is best.
// Ref: regex escaper taken from:
@@ -881,10 +963,13 @@ FilterSingleWildcardRightAnchoredHostname.fromSelfie = function(s) {
var FilterManyWildcards = function(s, tokenBeg) {
this.s = s;
this.tokenBeg = tokenBeg;
- this.re = new RegExp('^' + s.replace(/([.+?^=!:${}()|\[\]\/\\])/g, '\\$1').replace(/\*/g, '.*'));
+ this.re = null;
};
FilterManyWildcards.prototype.match = function(url, tokenBeg) {
+ if ( this.re === null ) {
+ this.re = strToRegex('^', this.s);
+ }
return this.re.test(url.slice(tokenBeg - this.tokenBeg));
};
@@ -912,13 +997,18 @@ FilterManyWildcards.fromSelfie = function(s) {
var FilterManyWildcardsHostname = function(s, tokenBeg, hostname) {
this.s = s;
this.tokenBeg = tokenBeg;
- this.re = new RegExp('^' + s.replace(/([.+?^=!:${}()|\[\]\/\\])/g, '\\$1').replace(/\*/g, '.*'));
+ this.re = null;
this.hostname = hostname;
};
FilterManyWildcardsHostname.prototype.match = function(url, tokenBeg) {
- return pageHostnameRegister.slice(-this.hostname.length) === this.hostname &&
- this.re.test(url.slice(tokenBeg - this.tokenBeg));
+ if ( pageHostnameRegister.slice(-this.hostname.length) !== this.hostname ) {
+ return false;
+ }
+ if ( this.re === null ) {
+ this.re = strToRegex('^', this.s);
+ }
+ return this.re.test(url.slice(tokenBeg - this.tokenBeg));
};
FilterManyWildcardsHostname.fid = FilterManyWildcardsHostname.prototype.fid = '*+h';
@@ -1316,6 +1406,9 @@ var getFilterClass = function(details) {
var s = details.f;
var wcOffset = s.indexOf('*');
if ( wcOffset !== -1 ) {
+ if ( details.hostnameAnchored ) {
+ return FilterGenericHnAnchored;
+ }
if ( s.indexOf('*', wcOffset + 1) !== -1 ) {
return details.anchor === 0 ? FilterManyWildcards : null;
}
@@ -1357,6 +1450,9 @@ var getHostnameBasedFilterClass = function(details) {
var s = details.f;
var wcOffset = s.indexOf('*');
if ( wcOffset !== -1 ) {
+ if ( details.hostnameAnchored ) {
+ return FilterGenericHnAnchoredHostname;
+ }
if ( s.indexOf('*', wcOffset + 1) !== -1 ) {
return details.anchor === 0 ? FilterManyWildcardsHostname : null;
}
@@ -1388,47 +1484,6 @@ var getHostnameBasedFilterClass = function(details) {
/******************************************************************************/
-// Given a string, find a good token. Tokens which are too generic, i.e. very
-// common with a high probability of ending up as a miss, are not
-// good. Avoid if possible. This has a *significant* positive impact on
-// performance.
-// These "bad tokens" are collated manually.
-
-var badTokens = {
- 'com': true,
- 'http': true,
- 'https': true,
- 'icon': true,
- 'images': true,
- 'img': true,
- 'js': true,
- 'net': true,
- 'news': true,
- 'www': true
-};
-
-var findFirstGoodToken = function(s) {
- reGoodToken.lastIndex = 0;
- var matches;
- while ( matches = reGoodToken.exec(s) ) {
- if ( badTokens[matches[0]] === undefined ) {
- return matches;
- }
- }
- // No good token found, just return the first token from left
- reGoodToken.lastIndex = 0;
- return reGoodToken.exec(s);
-};
-
-/******************************************************************************/
-
-var findHostnameToken = function(s) {
- reHostnameToken.lastIndex = 0;
- return reHostnameToken.exec(s);
-};
-
-/******************************************************************************/
-
// Trim leading/trailing char "c"
var trimChar = function(s, c) {
@@ -1690,6 +1745,58 @@ FilterParser.prototype.parse = function(raw) {
/******************************************************************************/
+// Given a string, find a good token. Tokens which are too generic, i.e. very
+// common with a high probability of ending up as a miss, are not
+// good. Avoid if possible. This has a *significant* positive impact on
+// performance.
+// These "bad tokens" are collated manually.
+
+var reHostnameToken = /^[0-9a-z]+/g;
+var reGoodToken = /[%0-9a-z]{2,}/g;
+
+var badTokens = {
+ 'com': true,
+ 'http': true,
+ 'https': true,
+ 'icon': true,
+ 'images': true,
+ 'img': true,
+ 'js': true,
+ 'net': true,
+ 'news': true,
+ 'www': true
+};
+
+var findFirstGoodToken = function(s) {
+ reGoodToken.lastIndex = 0;
+ var matches;
+ while ( matches = reGoodToken.exec(s) ) {
+ if ( s.charAt(reGoodToken.lastIndex) === '*' ) {
+ continue;
+ }
+ if ( badTokens.hasOwnProperty(matches[0]) ) {
+ continue;
+ }
+ return matches;
+ }
+ // No good token found, try again without minding "bad" tokens
+ reGoodToken.lastIndex = 0;
+ while ( matches = reGoodToken.exec(s) ) {
+ if ( s.charAt(reGoodToken.lastIndex) === '*' ) {
+ continue;
+ }
+ return matches;
+ }
+ return null;
+};
+
+var findHostnameToken = function(s) {
+ reHostnameToken.lastIndex = 0;
+ return reHostnameToken.exec(s);
+};
+
+/******************************************************************************/
+
FilterParser.prototype.makeToken = function() {
if ( this.isRegex ) {
this.token = '*';
@@ -1698,7 +1805,8 @@ FilterParser.prototype.makeToken = function() {
var matches;
- if ( this.hostnameAnchored ) {
+ // Hostname-anchored with no wildcard always have a token index of 0.
+ if ( this.hostnameAnchored && this.f.indexOf('*') === -1 ) {
matches = findHostnameToken(this.f);
if ( !matches || matches[0].length === 0 ) {
return;
@@ -1710,7 +1818,7 @@ FilterParser.prototype.makeToken = function() {
}
matches = findFirstGoodToken(this.f);
- if ( !matches || matches[0].length === 0 ) {
+ if ( matches === null || matches[0].length === 0 ) {
return;
}
this.tokenBeg = matches.index;
@@ -1799,7 +1907,9 @@ FilterContainer.prototype.factories = {
'*+h': FilterManyWildcardsHostname,
'//': FilterRegex,
'//h': FilterRegexHostname,
- '{h}': FilterHostnameDict
+ '{h}': FilterHostnameDict,
+ '||_': FilterGenericHnAnchored,
+ '||_h': FilterGenericHnAnchoredHostname
};
/******************************************************************************/
diff --git a/src/js/storage.js b/src/js/storage.js
index f3d3589..beb3ede 100644
--- a/src/js/storage.js
+++ b/src/js/storage.js
@@ -288,7 +288,7 @@
if ( µb.remoteBlacklists.hasOwnProperty(path) ) {
var entry = µb.remoteBlacklists[path];
entry.entryCount = snfe.acceptedCount + cfe.acceptedCount - acceptedCount;
- entry.entryUsedCount = entry.entryCount - snfe.duplicateCount - cfe.duplicateCount + duplicateCount;
+ entry.entryUsedCount = entry.entryCount - (snfe.duplicateCount + cfe.duplicateCount - duplicateCount);
}
};
diff --git a/src/js/tab.js b/src/js/tab.js
index dbdb45b..1c19455 100644
--- a/src/js/tab.js
+++ b/src/js/tab.js
@@ -47,7 +47,7 @@ vAPI.tabs.onNavigation = function(details) {
// The hostname of the bound document must always be present in the
// mini-matrix. That's the best place I could find for the fix, all other
// options had bad side-effects or complications.
- // TODO: Evantually, we will have to use an API to check whether a scheme
+ // TODO: Evantually, we will have to use an API to check whether a scheme
// is supported as I suspect we are going to start to see `ws`, `wss`
// as well soon.
if ( pageStore && details.url.lastIndexOf('http', 0) === 0 ) {
diff --git a/src/js/traffic.js b/src/js/traffic.js
index 9f11486..a17d8e4 100644
--- a/src/js/traffic.js
+++ b/src/js/traffic.js
@@ -100,8 +100,13 @@ var onBeforeRequest = function(details) {
//console.debug('traffic.js > onBeforeRequest(): ALLOW "%s" (%o) because "%s"', details.url, details, result);
// https://github.com/gorhill/uBlock/issues/114
- if ( isFrame && details.frameId > 0 ) {
- pageStore.setFrame(details.frameId, requestURL);
+ frameId = details.frameId;
+ if ( frameId > 0 ) {
+ if ( isFrame ) {
+ pageStore.setFrame(frameId, requestURL);
+ } else if ( pageStore.getFrame(frameId) === null ) {
+ pageStore.setFrame(frameId, requestURL);
+ }
}
// https://code.google.com/p/chromium/issues/detail?id=387198
@@ -125,7 +130,11 @@ var onBeforeRequest = function(details) {
pageStore.logRequest(requestContext, result);
- µb.updateBadgeAsync(tabId);
+ // https://github.com/gorhill/uBlock/issues/905#issuecomment-76543649
+ // No point updating the badge if it's not being displayed.
+ if ( µb.userSettings.showIconBadge ) {
+ µb.updateBadgeAsync(tabId);
+ }
// https://github.com/gorhill/uBlock/issues/18
// Do not use redirection, we need to block outright to be sure the request
diff --git a/tools/make-fennec.sh b/tools/make-fennec.sh
deleted file mode 100755
index 7e4b81e..0000000
--- a/tools/make-fennec.sh
+++ /dev/null
@@ -1,38 +0,0 @@
-#!/bin/bash
-#
-# This script assumes a linux environment
-
-echo "*** uBlock.fennec: Copying files"
-
-DES=dist/build/uBlock.fennec
-rm -rf $DES
-mkdir -p $DES
-
-cp -R assets $DES/
-rm $DES/assets/*.sh
-cp -R src/css $DES/
-cp -R src/img $DES/
-cp -R src/js $DES/
-cp -R src/lib $DES/
-cp -R src/_locales $DES/
-cp src/*.html $DES/
-mv $DES/img/icon_128.png $DES/icon.png
-cp platform/firefox/vapi-*.js $DES/js/
-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/fennec/vapi-*.js $DES/
-cp LICENSE.txt $DES/
-
-echo "*** uBlock.fennec: Generating meta..."
-python tools/make-firefox-meta.py $DES/
-
-if [ "$1" = all ]; then
- echo "*** uBlock.fennec: Creating package..."
- pushd $DES/
- zip ../uBlock.fennec.xpi -qr *
- popd
-fi
-
-echo "*** uBlock.fennec: Package done."