Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code

Unified Diff: lib/adblockplus_compat.js

Issue 8483154: Adding ABP core modules to ABP/Opera (Closed)
Patch Set: Created Oct. 11, 2012, 9:35 a.m.
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View side-by-side diff with in-line comments
Download patch
« background.js ('K') | « lib/adblockplus.js ('k') | lib/matcher.js » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: lib/adblockplus_compat.js
===================================================================
new file mode 100644
--- /dev/null
+++ b/lib/adblockplus_compat.js
@@ -0,0 +1,501 @@
+/*
+ * This Source Code is subject to the terms of the Mozilla Public License
+ * version 2.0 (the "License"). You can obtain a copy of the License at
+ * http://mozilla.org/MPL/2.0/.
+ */
+
+// TODO: Parts of this file are identical to ABP/Chrome, these should be split
+// away into a separate file.
+
+//
+// Module framework stuff
+//
+
+function require(module)
+{
+ return require.scopes[module];
+}
+require.scopes = {__proto__: null};
+
+function importAll(module, globalObj)
+{
+ var exports = require(module);
+ for (var key in exports)
+ globalObj[key] = exports[key];
+}
+
+onShutdown = {
+ done: false,
+ add: function() {},
+ remove: function() {}
+};
+
+//
+// XPCOM emulation
+//
+
+var Components =
+{
+ interfaces:
+ {
+ nsIFile: {DIRECTORY_TYPE: 0},
+ nsIFileURL: function() {},
+ nsIHttpChannel: function() {},
+ nsITimer: {TYPE_REPEATING_SLACK: 0},
+ nsIInterfaceRequestor: null,
+ nsIChannelEventSink: null
+ },
+ classes:
+ {
+ "@mozilla.org/timer;1":
+ {
+ createInstance: function()
+ {
+ return new FakeTimer();
+ }
+ },
+ "@mozilla.org/xmlextras/xmlhttprequest;1":
+ {
+ createInstance: function()
+ {
+ return new XMLHttpRequest();
+ }
+ }
+ },
+ results: {},
+ utils: {
+ reportError: function(e)
+ {
+ opera.postError(e + "\n" + (typeof e == "object" ? e.stack : new Error().stack));
+ }
+ },
+ manager: null,
+ ID: function()
+ {
+ return null;
+ }
+};
+const Cc = Components.classes;
+const Ci = Components.interfaces;
+const Cr = Components.results;
+const Cu = Components.utils;
+
+var XPCOMUtils =
+{
+ generateQI: function() {}
+};
+
+//
+// Info pseudo-module
+//
+
+require.scopes.info =
+{
+ get addonID()
+ {
+ return widget.id;
+ },
+ addonVersion: "2.0.3", // Hardcoded for now
+ addonRoot: "",
+ get addonName()
+ {
+ return widget.name;
+ },
+ application: "opera"
+};
+
+//
+// IO module: no direct file system access, using FileSystem API
+//
+
+require.scopes.io =
+{
+ IO: {
+ _getFilePath: function(file)
+ {
+ if (file instanceof FakeFile)
+ return file.path;
+ else if ("spec" in file)
+ return file.spec;
+
+ throw new Error("Unexpected file type");
+ },
+
+ _setFileContents: function(path, contents, lastModified)
+ {
+ window.localStorage[path] = contents;
+ window.localStorage[path + "/lastModified"] = lastModified || 0;
+ },
+
+ lineBreak: "\n",
+
+ resolveFilePath: function(path)
+ {
+ return new FakeFile(path);
+ },
+
+ readFromFile: function(file, decode, listener, callback, timeLineID)
+ {
+ // Fake asynchronous execution
+ setTimeout(function()
+ {
+ if ("spec" in file && /^defaults\b/.test(file.spec))
+ {
+ // Code attempts to read the default patterns.ini, we don't have that.
+ // Make sure to execute first-run actions instead.
+ callback(null);
+ executeFirstRunActions();
Felix Dahlke 2012/10/11 13:10:02 This function cannot be called from here.
+ return;
+ }
+
+ var path = this._getFilePath(file);
+ if (!(path in window.localStorage))
+ {
+ callback(new Error("File doesn't exist"))
+ return;
+ }
+
+ var lines = window.localStorage[path].split(/[\r\n]+/);
+ for (var i = 0; i < lines.length; i++)
+ listener.process(lines[i]);
+ listener.process(null);
+ callback(null);
+ }.bind(this), 0);
+ },
+
+ writeToFile: function(file, encode, data, callback, timeLineID)
+ {
+ var path = this._getFilePath(file);
+ this._setFileContents(path, data.join(this.lineBreak) + this.lineBreak, Date.now());
+
+ // Fake asynchronous execution
+ setTimeout(callback.bind(null, null), 0);
+ },
+
+ copyFile: function(fromFile, toFile, callback)
+ {
+ // Simply combine read and write operations
+ var data = [];
+ this.readFromFile(fromFile, false, {
+ process: function(line)
+ {
+ if (line !== null)
+ data.push(line);
+ }
+ }, function(e)
+ {
+ if (e)
+ callback(e);
+ else
+ this.writeToFile(toFile, false, data, callback);
+ }.bind(this));
+ },
+
+ renameFile: function(fromFile, newName, callback)
+ {
+ var path = this._getFilePath(fromFile);
+ if (!(path in window.localStorage))
+ {
+ callback(new Error("File doesn't exist"))
+ return;
+ }
+
+ this._setFileContents(newName, window.localStorage[path], window.localStorage[path + "/lastModified"]);
+ this.removeFile(fromFile, callback);
+ },
+
+ removeFile: function(file, callback)
+ {
+ var path = this._getFilePath(file);
+ delete window.localStorage[path];
+ delete window.localStorage[path + "/lastModified"];
+ callback(null);
+ },
+
+ statFile: function(file, callback)
+ {
+ var path = this._getFilePath(file);
+ callback(null, {
+ exists: path in window.localStorage,
+ isDirectory: false,
+ isFile: true,
+ lastModified: parseInt(window.localStorage[path + "/lastModified"], 10) || 0
+ });
+ }
+ }
+};
+
+//
+// Fake nsIFile implementation for our I/O
+//
+
+function FakeFile(path)
+{
+ this.path = path;
+}
+FakeFile.prototype =
+{
+ get leafName()
+ {
+ return this.path;
+ },
+ set leafName(value)
+ {
+ this.path = value;
+ },
+ append: function(path)
+ {
+ this.path += path;
+ },
+ clone: function()
+ {
+ return new FakeFile(this.path);
+ },
+ get parent()
+ {
+ return {create: function() {}};
+ },
+ normalize: function() {}
+};
+
+//
+// Prefs module: the values are hardcoded for now.
+//
+
+require.scopes.prefs = {
+ Prefs: {
+ enabled: true,
+ patternsfile: "patterns.ini",
+ patternsbackups: 0,
+ patternsbackupinterval: 24,
+ data_directory: "",
+ savestats: false,
+ privateBrowsing: false,
+ subscriptions_fallbackerrors: 5,
+ subscriptions_fallbackurl: "https://adblockplus.org/getSubscription?version=%VERSION%&url=%SUBSCRIPTION%&downloadURL=%URL%&error=%ERROR%&channelStatus=%CHANNELSTATUS%&responseStatus=%RESPONSESTATUS%",
+ subscriptions_autoupdate: true,
+ subscriptions_exceptionsurl: "https://easylist-downloads.adblockplus.org/exceptionrules.txt",
+ documentation_link: "https://adblockplus.org/redirect?link=%LINK%&lang=%LANG%",
+ addListener: function() {}
+ }
+};
+
+//
+// Utils module
+//
+
+require.scopes.utils =
+{
+ Utils: {
+ systemPrincipal: null,
+ getString: function(id)
+ {
+ return id;
+ },
+ runAsync: function(callback, thisPtr)
+ {
+ var params = Array.prototype.slice.call(arguments, 2);
+ window.setTimeout(function()
+ {
+ callback.apply(thisPtr, params);
+ }, 0);
+ },
+ get appLocale()
+ {
+ // Note: navigator.language
+ return window.navigator.browserLanguage;
+ },
+ generateChecksum: function(lines)
+ {
+ // We cannot calculate MD5 checksums yet :-(
+ return null;
+ },
+ makeURI: function(url)
+ {
+ return Services.io.newURI(url);
+ },
+ checkLocalePrefixMatch: function(prefixes)
+ {
+ if (!prefixes)
+ return null;
+
+ var list = prefixes.split(",");
+ for (var i = 0; i < list.length; i++)
+ if (new RegExp("^" + list[i] + "\\b").test(this.appLocale))
+ return list[i];
+
+ return null;
+ }
+ }
+};
+
+//
+// ElemHideHitRegistration dummy implementation
+//
+
+require.scopes.elemHideHitRegistration =
+{
+ AboutHandler: {}
+};
+
+//
+// Services.jsm module emulation
+//
+
+var Services =
+{
+ io: {
+ newURI: function(uri)
+ {
+ if (!uri.length || uri[0] == "~")
+ throw new Error("Invalid URI");
+
+ /^([^:\/]*)/.test(uri);
+ var scheme = RegExp.$1.toLowerCase();
+
+ return {
+ scheme: scheme,
+ spec: uri,
+ QueryInterface: function()
+ {
+ return this;
+ }
+ };
+ },
+ newFileURI: function(file)
+ {
+ var result = this.newURI("file:///" + file.path);
+ result.file = file;
+ return result;
+ }
+ },
+ obs: {
+ addObserver: function() {},
+ removeObserver: function() {}
+ },
+ vc: {
+ compare: function(v1, v2)
+ {
+ function parsePart(s)
+ {
+ if (!s)
+ return parsePart("0");
+
+ var part = {
+ numA: 0,
+ strB: "",
+ numC: 0,
+ extraD: ""
+ };
+
+ if (s === "*")
+ {
+ part.numA = Number.MAX_VALUE;
+ return part;
+ }
+
+ var matches = s.match(/(\d*)(\D*)(\d*)(.*)/);
+ part.numA = parseInt(matches[1], 10) || part.numA;
+ part.strB = matches[2] || part.strB;
+ part.numC = parseInt(matches[3], 10) || part.numC;
+ part.extraD = matches[4] || part.extraD;
+
+ if (part.strB == "+")
+ {
+ part.numA++;
+ part.strB = "pre";
+ }
+
+ return part;
+ }
+
+ function comparePartElement(s1, s2)
+ {
+ if (s1 === "" && s2 !== "")
+ return 1;
+ if (s1 !== "" && s2 === "")
+ return -1;
+ return s1 === s2 ? 0 : (s1 > s2 ? 1 : -1);
+ }
+
+ function compareParts(p1, p2)
+ {
+ var result = 0;
+ var elements = ["numA", "strB", "numC", "extraD"];
+ elements.some(function(element)
+ {
+ result = comparePartElement(p1[element], p2[element]);
+ return result;
+ });
+ return result;
+ }
+
+ var parts1 = v1.split(".");
+ var parts2 = v2.split(".");
+ for (var i = 0; i < Math.max(parts1.length, parts2.length); i++)
+ {
+ var result = compareParts(parsePart(parts1[i]), parsePart(parts2[i]));
+ if (result)
+ return result;
+ }
+ return 0;
+ }
+ }
+}
+
+//
+// FileUtils.jsm module emulation
+//
+
+var FileUtils =
+{
+ PERMS_DIRECTORY: 0
+};
+
+function FakeTimer()
+{
+}
+FakeTimer.prototype =
+{
+ delay: 0,
+ callback: null,
+ initWithCallback: function(callback, delay)
+ {
+ this.callback = callback;
+ this.delay = delay;
+ this.scheduleTimeout();
+ },
+ scheduleTimeout: function()
+ {
+ var me = this;
+ window.setTimeout(function()
+ {
+ try
+ {
+ me.callback();
+ }
+ catch(e)
+ {
+ Cu.reportError(e);
+ }
+ me.scheduleTimeout();
+ }, this.delay);
+ }
+};
+
+//
+// Add a channel property to XMLHttpRequest, Synchronizer needs it
+//
+
+XMLHttpRequest.prototype.channel =
+{
+ status: -1,
+ notificationCallbacks: {},
+ loadFlags: 0,
+ INHIBIT_CACHING: 0,
+ VALIDATE_ALWAYS: 0,
+ QueryInterface: function()
+ {
+ return this;
+ }
+};
« background.js ('K') | « lib/adblockplus.js ('k') | lib/matcher.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld