Initial Firefox port (base, messaging, locales)

This commit is contained in:
Deathamns 2014-11-24 20:00:27 +01:00
parent 2016eff2a1
commit 67f18d023c
11 changed files with 662 additions and 17 deletions

46
platform/firefox/bootstrap.js vendored Normal file
View File

@ -0,0 +1,46 @@
/* global Services, APP_STARTUP, APP_SHUTDOWN */
/* exported startup, shutdown, install, uninstall */
'use strict';
var bgProcess;
Components.utils['import']('resource://gre/modules/Services.jsm');
function startup(data, reason) {
bgProcess = function(ev) {
if (ev) {
this.removeEventListener('load', bgProcess);
}
bgProcess = Services.appShell.hiddenDOMWindow.document;
bgProcess = bgProcess.documentElement.appendChild(
bgProcess.createElementNS('http://www.w3.org/1999/xhtml', 'iframe')
);
bgProcess.setAttribute('src', 'chrome://ublock/content/background.html');
};
if (reason === APP_STARTUP) {
Services.ww.registerNotification({
observe: function(subject) {
Services.ww.unregisterNotification(this);
subject.addEventListener('load', bgProcess);
}
});
}
else {
bgProcess();
}
}
function shutdown(data, reason) {
if (reason !== APP_SHUTDOWN) {
bgProcess.parentNode.removeChild(bgProcess);
}
}
function install() {
// https://bugzil.la/719376
Services.strings.flushBundles();
}
function uninstall() {}

View File

@ -0,0 +1,31 @@
content ublock ./
locale ublock en ./locale/en/
locale ublock ar ./locale/ar/
locale ublock cs ./locale/cs/
locale ublock da ./locale/da/
locale ublock de ./locale/de/
locale ublock el ./locale/el/
locale ublock es ./locale/es/
locale ublock et ./locale/et/
locale ublock fi ./locale/fi/
locale ublock fr ./locale/fr/
locale ublock he ./locale/he/
locale ublock hi ./locale/hi/
locale ublock hr ./locale/hr/
locale ublock hu ./locale/hu/
locale ublock id ./locale/id/
locale ublock it ./locale/it/
locale ublock ja ./locale/ja/
locale ublock mr ./locale/mr/
locale ublock nb ./locale/nb/
locale ublock nl ./locale/nl/
locale ublock pl ./locale/pl/
locale ublock pt-BR ./locale/pt-BR/
locale ublock pt-PT ./locale/pt-PT/
locale ublock ro ./locale/ro/
locale ublock ru ./locale/ru/
locale ublock sv ./locale/sv/
locale ublock tr ./locale/tr/
locale ublock uk ./locale/uk/
locale ublock vi ./locale/vi/
locale ublock zh-CN ./locale/zh-CN/

View File

@ -0,0 +1,32 @@
/* globals Services, sendAsyncMessage, addMessageListener, removeMessageListener, content */
(function() {
'use strict';
var
app_name = 'ublock',
app_baseURI = 'chrome://' + app_name + '/content/js/',
listeners = {},
_addMessageListener = function(id, fn) {
_removeMessageListener(id);
listeners[id] = function(msg) {
fn(msg.data);
};
addMessageListener(id, listeners[id]);
},
_removeMessageListener = function(id) {
if (listeners[id]) {
removeMessageListener(id, listeners[id]);
}
delete listeners[id];
};
addMessageListener('µBlock:broadcast', function(msg) {
for (var id in listeners) {
listeners[id](msg.data);
}
});
})();

View File

@ -0,0 +1,34 @@
<?xml version="1.0" encoding="utf-8"?>
<r:RDF xmlns:r="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.mozilla.org/2004/em-rdf#">
<r:Description about="urn:mozilla:install-manifest">
<id>{2b10c1c8-a11f-4bad-fe9c-1c11e82cac42}</id>
<version>0.7.0.11</version>
<name>µBlock</name>
<description>Finally, an efficient blocker. Easy on CPU and memory.</description>
<homepageURL>https://github.com/gorhill/uBlock</homepageURL>
<creator>Raymond Hill</creator>
<type>2</type>
<bootstrap>true</bootstrap>
<multiprocessCompatible>true</multiprocessCompatible>
<optionsType>3</optionsType>
<optionsURL>chrome://ublock/content/dashboard.html</optionsURL>
<!-- Firefox -->
<targetApplication>
<r:Description>
<id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</id>
<minVersion>24.0</minVersion>
<maxVersion>37.0</maxVersion>
</r:Description>
</targetApplication>
<!-- SeaMonkey -->
<targetApplication>
<r:Description>
<id>{92650c4d-4b8e-4d2a-b7eb-24ecf4f6b63a}</id>
<minVersion>2.21</minVersion>
<maxVersion>2.34</maxVersion>
</r:Description>
</targetApplication>
</r:Description>
</r:RDF>

View File

@ -0,0 +1,181 @@
/*******************************************************************************
µBlock - a Chromium browser extension to block requests.
Copyright (C) 2014 The µBlock authors
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see {http://www.gnu.org/licenses/}.
Home: https://github.com/gorhill/uBlock
*/
/* global Services */
// For background page
/******************************************************************************/
(function() {
'use strict';
/******************************************************************************/
const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
Cu['import']('resource://gre/modules/Services.jsm');
/******************************************************************************/
self.vAPI = self.vAPI || {};
vAPI.firefox = true;
/******************************************************************************/
vAPI.messaging = {
gmm: Cc['@mozilla.org/globalmessagemanager;1'].getService(Ci.nsIMessageListenerManager),
frameScript: 'chrome://ublock/content/frameScript.js',
listeners: {},
defaultHandler: null,
NOOPFUNC: function(){},
UNHANDLED: 'vAPI.messaging.notHandled'
};
/******************************************************************************/
vAPI.messaging.gmm.loadFrameScript(vAPI.messaging.frameScript, true);
/******************************************************************************/
vAPI.messaging.listen = function(listenerName, callback) {
this.listeners[listenerName] = callback;
};
/******************************************************************************/
vAPI.messaging.onMessage = function(request) {
var messageManager = request.target.messageManager;
var listenerId = request.data.portName.split('|');
var portName = listenerId[1];
listenerId = listenerId[0];
var callback = vAPI.messaging.NOOPFUNC;
if ( request.data.requestId !== undefined ) {
callback = function(response) {
messageManager.sendAsyncMessage(
listenerId,
JSON.stringify({
requestId: request.data.requestId,
portName: portName,
msg: response !== undefined ? response : null
})
);
};
}
// TODO:
var sender = {
tab: {
id: 0
}
};
// Specific handler
var r = vAPI.messaging.UNHANDLED;
var listener = vAPI.messaging.listeners[portName];
if ( typeof listener === 'function' ) {
r = listener(request.data.msg, sender, callback);
}
if ( r !== vAPI.messaging.UNHANDLED ) {
return;
}
// Default handler
r = vAPI.messaging.defaultHandler(request.data.msg, sender, callback);
if ( r !== vAPI.messaging.UNHANDLED ) {
return;
}
console.error('µBlock> messaging > unknown request: %o', request.data);
// Unhandled:
// Need to callback anyways in case caller expected an answer, or
// else there is a memory leak on caller's side
callback();
};
/******************************************************************************/
vAPI.messaging.setup = function(defaultHandler) {
// Already setup?
if ( this.defaultHandler !== null ) {
return;
}
if ( typeof defaultHandler !== 'function' ) {
defaultHandler = function(){ return vAPI.messaging.UNHANDLED; };
}
this.defaultHandler = defaultHandler;
this.gmm.addMessageListener(vAPI.app.name + ':background', this.onMessage);
};
/******************************************************************************/
vAPI.messaging.broadcast = function(msg) {
this.gmm.broadcastAsyncMessage(vAPI.app.name + ':broadcast', msg);
};
/******************************************************************************/
vAPI.lastError = function() {
return null;
};
/******************************************************************************/
// clean up when the extension is disabled
window.addEventListener('unload', function() {
vAPI.messaging.gmm.removeMessageListener(
app.name + ':background',
vAPI.messaging.postMessage
);
vAPI.messaging.gmm.removeDelayedFrameScript(vAPI.messaging.frameScript);
// close extension tabs
var enumerator = Services.wm.getEnumerator('navigator:browser');
var host = 'ublock';
var gBrowser, tabs, i, extURI;
while (enumerator.hasMoreElements()) {
gBrowser = enumerator.getNext().gBrowser;
tabs = gBrowser.tabs;
i = tabs.length;
while (i--) {
extURI = tabs[i].linkedBrowser.currentURI;
if (extURI.scheme === 'chrome' && extURI.host === host) {
gBrowser.removeTab(tabs[i]);
}
}
}
});
/******************************************************************************/
})();
/******************************************************************************/

View File

@ -0,0 +1,148 @@
/*******************************************************************************
µBlock - a Chromium browser extension to block requests.
Copyright (C) 2014 The µBlock authors
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see {http://www.gnu.org/licenses/}.
Home: https://github.com/gorhill/uBlock
*/
// For non background pages
/******************************************************************************/
(function() {
'use strict';
/******************************************************************************/
self.vAPI = self.vAPI || {};
vAPI.firefox = true;
/******************************************************************************/
var messagingConnector = function(response) {
if ( !response ) {
return;
}
var channels = vAPI.messaging.channels;
var channel, listener;
if ( response.broadcast === true ) {
for ( channel in channels ) {
if ( channels.hasOwnProperty(channel) === false ) {
continue;
}
listener = channels[channel].listener;
if ( typeof listener === 'function' ) {
listener(response.msg);
}
}
return;
}
if ( response.requestId ) {
listener = vAPI.messaging.listeners[response.requestId];
delete vAPI.messaging.listeners[response.requestId];
delete response.requestId;
}
if ( !listener ) {
channel = channels[response.portName];
listener = channel && channel.listener;
}
if ( typeof listener === 'function' ) {
listener(response.msg);
}
};
/******************************************************************************/
var uniqueId = function() {
return parseInt(Math.random() * 1e10, 10).toString(36);
};
/******************************************************************************/
vAPI.messaging = {
channels: {},
listeners: {},
requestId: 1,
connectorId: uniqueId(),
setup: function() {
this.connector = function(msg) {
messagingConnector(JSON.parse(msg));
};
addMessageListener(this.connectorId, this.connector);
},
close: function() {
if (this.connector) {
removeMessageListener(this.connectorId, this.connector);
this.connector = null;
this.channels = {};
this.listeners = {};
}
},
channel: function(channelName, callback) {
if ( !channelName ) {
return;
}
this.channels[channelName] = {
portName: channelName,
listener: typeof callback === 'function' ? callback : null,
send: function(message, callback) {
if ( !vAPI.messaging.connector ) {
vAPI.messaging.setup();
}
message = {
portName: vAPI.messaging.connectorId + '|' + this.portName,
msg: message
};
if ( callback ) {
message.requestId = vAPI.messaging.requestId++;
vAPI.messaging.listeners[message.requestId] = callback;
}
sendAsyncMessage('µBlock:background', message);
},
close: function() {
delete vAPI.messaging.channels[this.portName];
}
};
return this.channels[channelName];
}
};
/******************************************************************************/
vAPI.canExecuteContentScript = function() {
return true;
};
/******************************************************************************/
})();
/******************************************************************************/

View File

@ -0,0 +1,96 @@
/*******************************************************************************
µBlock - a Chromium browser extension to block requests.
Copyright (C) 2014 The µBlock authors
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see {http://www.gnu.org/licenses/}.
Home: https://github.com/gorhill/uBlock
*/
// For background page or non-background pages
/******************************************************************************/
(function() {
'use strict';
self.vAPI = self.vAPI || {};
/******************************************************************************/
// http://www.w3.org/International/questions/qa-scripts#directions
var setScriptDirection = function(language) {
document.body.setAttribute(
'dir',
['ar', 'he', 'fa', 'ps', 'ur'].indexOf(language) !== -1 ? 'rtl' : 'ltr'
);
};
/******************************************************************************/
vAPI.download = function(details) {
if ( !details.url ) {
return;
}
var a = document.createElement('a');
if ( 'download' in a ) {
a.href = details.url;
a.setAttribute('download', details.filename || '');
a.dispatchEvent(new MouseEvent('click'));
return;
}
var messager = vAPI.messaging.channel('_download');
messager.send({
what: 'gotoURL',
details: {
url: details.url,
index: -1
}
});
messager.close();
};
/******************************************************************************/
vAPI.getURL = function(path) {
return 'chrome://ublock/content/' + path.replace(/^\/+/, '');
};
vAPI.i18n = (function() {
var stringBundle = Components.classes['@mozilla.org/intl/stringbundle;1']
.getService(Components.interfaces.nsIStringBundleService)
.createBundle('chrome://ublock/locale/messages.properties');
return function(s) {
try {
return stringBundle.GetStringFromName(s);
} catch (ex) {
return s;
}
};
})();
setScriptDirection(navigator.language);
/******************************************************************************/
})();
/******************************************************************************/

View File

@ -2,21 +2,21 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<array>
<dict>
<key>DefaultValue</key>
<false/>
<key>FalseValue</key>
<false/>
<key>Key</key>
<string>open_prefs</string>
<key>Secure</key>
<false/>
<key>Title</key>
<string>Click to see the Preferences</string>
<key>TrueValue</key>
<true/>
<key>Type</key>
<string>CheckBox</string>
</dict>
<dict>
<key>DefaultValue</key>
<false/>
<key>FalseValue</key>
<false/>
<key>Key</key>
<string>open_prefs</string>
<key>Secure</key>
<false/>
<key>Title</key>
<string>Click to see the Preferences</string>
<key>TrueValue</key>
<true/>
<key>Type</key>
<string>CheckBox</string>
</dict>
</array>
</plist>

View File

@ -14,7 +14,7 @@
<key>CFBundleVersion</key>
<string>{buildNumber}</string>
<key>URL</key>
<string>https://.../uBlock.safariextz</string>
<string>https://github.com/gorhill/uBlock/releases/download/0.7.0.11/uBlock-0.7.0.11.safariextz</string>
</dict>
</array>
</dict>

28
tools/make-firefox.sh Normal file
View File

@ -0,0 +1,28 @@
#!/bin/bash
#
# This script assumes a linux environment
echo "*** uBlock_xpi: Copying files"
# use underscore instead of a dot!
DES=dist/build/uBlock_xpi
rm -r $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/
cp src/img/icon_128.png $DES/icon.png
cp platform/vapi-appinfo.js $DES/js/
cp platform/firefox/vapi-*.js $DES/js/
cp platform/firefox/bootstrap.js $DES/
cp platform/firefox/frameScript.js $DES/
cp platform/firefox/chrome.manifest $DES/
cp platform/firefox/install.rdf $DES/
python tools/xpi-convert-locale.py $DES/
echo "*** uBlock_xpi: Package done."

View File

@ -0,0 +1,49 @@
#!/usr/bin/env python3
import os
import json
import sys
from shutil import rmtree as rmt
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)
build_dir = osp.abspath(sys.argv[1])
source_locale_dir = pj(build_dir, '_locales')
target_locale_dir = pj(build_dir, 'locale')
for alpha2 in os.listdir(source_locale_dir):
locale_path = pj(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))
locale_path = pj(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)
f.write('=')
f.write(string_data[string_name]['message'].replace('\n', r'\n'))
f.write('\n')
rmtree(source_locale_dir)