diff --git a/platform/firefox/frameScript.js b/platform/firefox/frameScript.js
index 12644490b..c94f260de 100644
--- a/platform/firefox/frameScript.js
+++ b/platform/firefox/frameScript.js
@@ -4,7 +4,7 @@
'use strict';
-var
+let
appName = 'ublock',
contentBaseURI = 'chrome://' + appName + '/content/js/',
listeners = {},
@@ -25,7 +25,7 @@ var
addMessageListener('µBlock:broadcast', function(msg) {
for (var id in listeners) {
- listeners[id](msg.data);
+ listeners[id](msg);
}
});
diff --git a/platform/firefox/install.rdf b/platform/firefox/install.rdf
index bc2f7b3b5..17fd41513 100644
--- a/platform/firefox/install.rdf
+++ b/platform/firefox/install.rdf
@@ -1,34 +1,34 @@
-
- {2b10c1c8-a11f-4bad-fe9c-1c11e82cac42}
- 0.7.0.11
- µBlock
- Finally, an efficient blocker. Easy on CPU and memory.
- https://github.com/gorhill/uBlock
- Raymond Hill
- 2
- true
- true
- 3
- chrome://ublock/content/dashboard.html
+
+ {2b10c1c8-a11f-4bad-fe9c-1c11e82cac42}
+ 0.7.0.11
+ µBlock
+ Finally, an efficient blocker. Easy on CPU and memory.
+ https://github.com/gorhill/uBlock
+ Raymond Hill
+ 2
+ true
+ true
+ 3
+ chrome://ublock/content/dashboard.html
-
-
-
- {ec8030f7-c20a-464f-9b0e-13a3a9e97384}
- 24.0
- 37.0
-
-
+
+
+
+ {ec8030f7-c20a-464f-9b0e-13a3a9e97384}
+ 24.0
+ 37.0
+
+
-
-
-
- {92650c4d-4b8e-4d2a-b7eb-24ecf4f6b63a}
- 2.21
- 2.34
-
-
-
+
+
+
+ {92650c4d-4b8e-4d2a-b7eb-24ecf4f6b63a}
+ 2.21
+ 2.34
+
+
+
diff --git a/platform/firefox/vapi-background.js b/platform/firefox/vapi-background.js
index a80bc51e1..733c694fe 100644
--- a/platform/firefox/vapi-background.js
+++ b/platform/firefox/vapi-background.js
@@ -43,6 +43,180 @@ vAPI.firefox = true;
/******************************************************************************/
+var SQLite = {
+ open: function() {
+ var path = Services.dirsvc.get('ProfD', Ci.nsIFile);
+ path.append('extension-data');
+
+ if (!path.exists()) {
+ path.create(Ci.nsIFile.DIRECTORY_TYPE, parseInt('0774', 8));
+ }
+
+ if (!path.isDirectory()) {
+ throw Error('Should be a directory...');
+ }
+
+ path.append('uBlock.sqlite');
+ this.db = Services.storage.openDatabase(path);
+ this.db.executeSimpleSQL(
+ 'CREATE TABLE IF NOT EXISTS settings' +
+ '(name TEXT PRIMARY KEY NOT NULL, value TEXT);'
+ );
+ },
+ close: function() {
+ this.run('VACUUM');
+ this.db.asyncClose();
+ },
+ run: function(query, values, callback) {
+ if (!this.db) {
+ this.open();
+ }
+
+ var result = {};
+
+ query = this.db.createAsyncStatement(query);
+
+ if (Array.isArray(values) && values.length) {
+ var i = values.length;
+
+ while (i--) {
+ query.bindByIndex(i, values[i]);
+ }
+ }
+
+ query.executeAsync({
+ handleResult: function(rows) {
+ if (!rows || typeof callback !== 'function') {
+ return;
+ }
+
+ var row;
+
+ while (row = rows.getNextRow()) {
+ // we assume that there will be two columns, since we're
+ // using it only for preferences
+ result[row.getResultByIndex(0)] = row.getResultByIndex(1);
+ }
+ },
+ handleCompletion: function(reason) {
+ if (typeof callback === 'function' && reason === 0) {
+ callback(result);
+ }
+ },
+ handleError: function(error) {
+ console.error('SQLite error ', error.result, error.message);
+ }
+ });
+ }
+};
+
+/******************************************************************************/
+
+vAPI.storage = {
+ QUOTA_BYTES: 100 * 1024 * 1024,
+ sqlWhere: function(col, valNum) {
+ if (valNum > 0) {
+ valNum = Array(valNum + 1).join('?, ').slice(0, -2);
+ return ' WHERE ' + col + ' IN (' + valNum + ')';
+ }
+
+ return '';
+ },
+ get: function(details, callback) {
+ if (typeof callback !== 'function') {
+ return;
+ }
+
+ var values = [], defaults = false;
+
+ if (details !== null) {
+ if (Array.isArray(details)) {
+ values = details;
+ }
+ else if (typeof details === 'object') {
+ defaults = true;
+ values = Object.keys(details);
+ }
+ else {
+ values = [details.toString()];
+ }
+ }
+
+ SQLite.run(
+ 'SELECT * FROM settings' + this.sqlWhere('name', values.length),
+ values,
+ function(result) {
+ var key;
+
+ for (key in result) {
+ result[key] = JSON.parse(result[key]);
+ }
+
+ if (defaults) {
+ for (key in details) {
+ if (!result[key]) {
+ result[key] = details[key];
+ }
+ }
+ }
+
+ callback(result);
+ }
+ );
+ },
+ set: function(details, callback) {
+ var key, values = [], questionmarks = [];
+
+ for (key in details) {
+ values.push(key);
+ values.push(JSON.stringify(details[key]));
+ questionmarks.push('?, ?');
+ }
+
+ if (!values.length) {
+ return;
+ }
+
+ SQLite.run(
+ 'INSERT OR REPLACE INTO settings (name, value) SELECT ' +
+ questionmarks.join(' UNION SELECT '),
+ values,
+ callback
+ );
+ },
+ remove: function(keys, callback) {
+ if (typeof keys === 'string') {
+ keys = [keys];
+ }
+
+ SQLite.run(
+ 'DELETE FROM settings' + this.sqlWhere('name', keys.length),
+ keys,
+ callback
+ );
+ },
+ clear: function(callback) {
+ SQLite.run('DELETE FROM settings', null, callback);
+ SQLite.run('VACUUM');
+ },
+ getBytesInUse: function(keys, callback) {
+ if (typeof callback !== 'function') {
+ return;
+ }
+
+ SQLite.run(
+ "SELECT 'size' AS size, SUM(LENGTH(value)) FROM settings" +
+ this.sqlWhere('name', Array.isArray(keys) ? keys.length : 0),
+ keys,
+ function(result) {
+ callback(result.size);
+ }
+ );
+ }
+};
+
+/******************************************************************************/
+
vAPI.messaging = {
gmm: Cc['@mozilla.org/globalmessagemanager;1'].getService(Ci.nsIMessageListenerManager),
frameScript: 'chrome://ublock/content/frameScript.js',
@@ -133,8 +307,11 @@ vAPI.messaging.setup = function(defaultHandler) {
/******************************************************************************/
-vAPI.messaging.broadcast = function(msg) {
- this.gmm.broadcastAsyncMessage(vAPI.app.name + ':broadcast', msg);
+vAPI.messaging.broadcast = function(message) {
+ this.gmm.broadcastAsyncMessage(
+ vAPI.app.name + ':broadcast',
+ JSON.stringify({broadcast: true, msg: message})
+ );
};
/******************************************************************************/
@@ -148,8 +325,9 @@ vAPI.lastError = function() {
// clean up when the extension is disabled
window.addEventListener('unload', function() {
+ SQLite.close();
vAPI.messaging.gmm.removeMessageListener(
- app.name + ':background',
+ vAPI.app.name + ':background',
vAPI.messaging.postMessage
);
vAPI.messaging.gmm.removeDelayedFrameScript(vAPI.messaging.frameScript);
diff --git a/platform/firefox/vapi-common.js b/platform/firefox/vapi-common.js
index 45825e77d..71a0e5453 100644
--- a/platform/firefox/vapi-common.js
+++ b/platform/firefox/vapi-common.js
@@ -93,4 +93,3 @@ setScriptDirection(navigator.language);
})();
/******************************************************************************/
-
diff --git a/platform/safari/Settings.plist b/platform/safari/Settings.plist
index 40cc1ff16..6c80bbb43 100644
--- a/platform/safari/Settings.plist
+++ b/platform/safari/Settings.plist
@@ -2,21 +2,21 @@
-
- DefaultValue
-
- FalseValue
-
- Key
- open_prefs
- Secure
-
- Title
- Click to see the Preferences
- TrueValue
-
- Type
- CheckBox
-
+
+ DefaultValue
+
+ FalseValue
+
+ Key
+ open_prefs
+ Secure
+
+ Title
+ Click to see the Preferences
+ TrueValue
+
+ Type
+ CheckBox
+
diff --git a/src/css/3p-filters.css b/src/css/3p-filters.css
index a5bbde3a8..a9b13ea47 100644
--- a/src/css/3p-filters.css
+++ b/src/css/3p-filters.css
@@ -119,7 +119,7 @@ body[dir=rtl] #externalListsDiv {
font-size: smaller;
width: 48em;
height: 8em;
- white-space: nowrap;
+ white-space: pre;
}
body #busyOverlay {
position: fixed;
diff --git a/tools/xpi-convert-locale.py b/tools/xpi-convert-locale.py
index 1467f3612..582e9a288 100644
--- a/tools/xpi-convert-locale.py
+++ b/tools/xpi-convert-locale.py
@@ -3,42 +3,34 @@
import os
import json
import sys
-from shutil import rmtree as rmt
+from shutil import rmtree
from collections import OrderedDict
if not sys.argv[1]:
raise SystemExit('Build dir missing.')
-osp = os.path
-pj = osp.join
-
-
-def rmtree(path):
- if osp.exists(path):
- rmt(path)
-
def mkdirs(path):
try:
os.makedirs(path)
finally:
- return osp.exists(path)
+ return os.path.exists(path)
-build_dir = osp.abspath(sys.argv[1])
-source_locale_dir = pj(build_dir, '_locales')
-target_locale_dir = pj(build_dir, 'locale')
+build_dir = os.path.abspath(sys.argv[1])
+source_locale_dir = os.path.join(build_dir, '_locales')
+target_locale_dir = os.path.join(build_dir, 'locale')
for alpha2 in os.listdir(source_locale_dir):
- locale_path = pj(source_locale_dir, alpha2, 'messages.json')
+ locale_path = os.path.join(source_locale_dir, alpha2, 'messages.json')
with open(locale_path, encoding='utf-8') as f:
string_data = json.load(f, object_pairs_hook=OrderedDict)
alpha2 = alpha2.replace('_', '-')
- mkdirs(pj(target_locale_dir, alpha2))
+ mkdirs(os.path.join(target_locale_dir, alpha2))
- locale_path = pj(target_locale_dir, alpha2, 'messages.properties')
+ locale_path = os.path.join(target_locale_dir, alpha2, 'messages.properties')
with open(locale_path, 'wt', encoding='utf-8', newline='\n') as f:
for string_name in string_data:
f.write(string_name)