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

Unified Diff: assets/js/start.js

Issue 8482109: ABP/Android JavaScript code (Closed)
Patch Set: ABP/Android JavaScript code Created Nov. 12, 2012, 9:32 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
« assets/js/XMLHttpRequest.jsm ('K') | « assets/js/punycode.js ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: assets/js/start.js
===================================================================
new file mode 100755
--- /dev/null
+++ b/assets/js/start.js
@@ -0,0 +1,589 @@
+/*
+ * 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/.
+ */
+
+function removeTrailingDots(string)
+{
+ return string.replace(/\.+$/, "");
+}
+
+/**
+ * Checks whether a request is third party for the given document, uses
+ * information from the public suffix list to determine the effective domain
+ * name for the document.
+ */
+function isThirdParty(requestHost, documentHost)
+{
+ requestHost = removeTrailingDots(requestHost);
+ documentHost = removeTrailingDots(documentHost);
+
+ // Extract domain name - leave IP addresses unchanged, otherwise leave only base domain
+ var documentDomain = getBaseDomain(documentHost);
+ if (requestHost.length > documentDomain.length)
+ return (requestHost.substr(requestHost.length - documentDomain.length - 1) != "." + documentDomain);
+ else
+ return (requestHost != documentDomain);
+}
+
+function reportError(exp)
+{
+ Android.print("Error: " + exp);
+ if (typeof exp == "string")
+ {
+ Android.showToast(exp);
+ }
+ Android.print(exp.stack);
+}
+
+function MatcherPatch()
+{
+ // Very ugly - we need to rewrite _checkEntryMatch() function to make sure
+ // it calls Filter.fromText() instead of assuming that the filter exists.
+ var origFunction = Matcher.prototype._checkEntryMatch.toString();
+ var newFunction = origFunction.replace(/\bFilter\.knownFilters\[(.*?)\];/g, "Filter.fromText($1);");
+ eval("Matcher.prototype._checkEntryMatch = " + newFunction);
+}
+
+var window = this;
+
+var Components =
+{
+ interfaces:
+ {
+ nsIFile: {DIRECTORY_TYPE: 0},
+ nsIFileURL: function() {},
+ nsIFileInputStream: null,
+ nsIFileOutputStream: null,
+ nsIHttpChannel: function() {},
+ nsIConverterInputStream: {DEFAULT_REPLACEMENT_CHARACTER: null},
+ nsIConverterOutputStream: null,
+ nsIUnicharLineInputStream: null,
+ nsISafeOutputStream: null,
+ nsITimer: {TYPE_REPEATING_SLACK: 0},
+ nsIInterfaceRequestor: null,
+ nsIChannelEventSink: null
+ },
+ classes:
+ {
+ "@mozilla.org/network/file-input-stream;1":
+ {
+ createInstance: function()
+ {
+ return new FakeInputStream();
+ }
+ },
+ "@mozilla.org/network/file-output-stream;1":
+ {
+ createInstance: function()
+ {
+ return new FakeOutputStream();
+ }
+ },
+ "@mozilla.org/dom/json;1":
+ {
+ createInstance: function() {
+ return {
+ decodeFromStream: function(stream, encoding)
+ {
+ var line = {};
+ var haveMore = true;
+ var s = new String();
+ while (true)
+ {
+ if (haveMore)
+ haveMore = stream.readLine(line);
+ else
+ break;
+ s += line.value;
+ }
+ return JSON.parse(s);
+ },
+ encodeToStream: function(stream, encoding, something, obj)
+ {
+ var s = JSON.stringify(obj);
+ stream.writeString(s);
+ }
+ }
+ }
+ },
+ "@mozilla.org/timer;1":
+ {
+ createInstance: function()
+ {
+ return new FakeTimer();
+ }
+ }
+ },
+ results: {},
+ utils: {
+ reportError: reportError
+ },
+ manager: null,
+ ID: function()
+ {
+ return null;
+ },
+ Constructor: function()
+ {
+ // This method is only used to get XMLHttpRequest constructor
+ return XMLHttpRequest;
+ }
+};
+const Cc = Components.classes;
+const Ci = Components.interfaces;
+const Cr = Components.results;
+const Cu = Components.utils;
+
+Cc["@mozilla.org/intl/converter-input-stream;1"] = Cc["@mozilla.org/network/file-input-stream;1"];
+Cc["@mozilla.org/network/safe-file-output-stream;1"] = Cc["@mozilla.org/intl/converter-output-stream;1"] = Cc["@mozilla.org/network/file-output-stream;1"];
+
+var Prefs =
+{
+ patternsbackups: 5,
+ patternsbackupinterval: 24,
+ data_directory: _datapath,
+ savestats: false,
+ privateBrowsing: false,
+ get subscriptions_autoupdate() { return Android.canAutoupdate() },
+ subscriptions_fallbackerrors: 5,
+ subscriptions_fallbackurl: "https://adblockplus.org/getSubscription?version=%VERSION%&url=%SUBSCRIPTION%&downloadURL=%URL%&error=%ERROR%&channelStatus=%CHANNELSTATUS%&responseStatus=%RESPONSESTATUS%",
+ addListener: function() {}
+};
+
+var Utils =
+{
+ systemPrincipal: null,
+ getString: function(id)
+ {
+ return id;
+ },
+ getLineBreak: function()
+ {
+ return "\n";
+ },
+ resolveFilePath: function(path)
+ {
+ return new FakeFile(path);
+ },
+ ioService:
+ {
+ 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};
+ }
+ },
+ observerService:
+ {
+ addObserver: function() {},
+ removeObserver: function() {}
+ },
+ chromeRegistry:
+ {
+ convertChromeURL: function() {}
+ },
+ runAsync: function(callback, thisPtr)
+ {
+ var params = Array.prototype.slice.call(arguments, 2);
+ Android.setTimeout(function()
+ {
+ callback.apply(thisPtr, params);
+ }, 0);
+ },
+ addonVersion: _version,
+ platformVersion: "10.0",
+ get appLocale()
+ {
+ Android.getLocale();
+ },
+ generateChecksum: function(lines)
+ {
+ // We cannot calculate MD5 checksums yet :-(
+ return null;
+ },
+ makeURI: function(url)
+ {
+ return Utils.ioService.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(Utils.appLocale))
+ return list[i];
+
+ return null;
+ },
+ versionComparator:
+ {
+ compare: function(v1, v2)
+ {
+ var parts1 = v1.split(".");
+ var parts2 = v2.split(".");
+ for (var i = 0; i < Math.max(parts1.length, parts2.length); i++)
+ {
+ // TODO: Handle non-integer version parts properly
+ var part1 = parseInt(i < parts1.length ? parts1[i] : "0");
+ var part2 = parseInt(i < parts2.length ? parts2[i] : "0");
+ if (part1 != part2)
+ return part1 - part2;
+ }
+ return 0;
+ }
+ }
+};
+
+var XPCOMUtils =
+{
+ generateQI: function() {}
+};
+
+function FakeFile(path)
+{
+ this.path = path;
+}
+FakeFile.prototype =
+{
+ get leafName()
+ {
+ return this.path;
+ },
+ set leafName(value)
+ {
+ this.path = value;
+ },
+ append: function(path)
+ {
+ this.path += _separator + path;
+ },
+ clone: function()
+ {
+ return new FakeFile(this.path);
+ },
+ exists: function()
+ {
+ return Android.fileExists(this.path);
+ },
+ remove: function()
+ {
+ Android.fileRemove(this.path);
+ },
+ moveTo: function(parent, newPath)
+ {
+ Android.fileRename(this.path, newPath);
+ },
+ get lastModifiedTime()
+ {
+ return Android.fileLastModified(this.path);
+ },
+ get parent()
+ {
+ return {create: function() {}};
+ },
+ normalize: function() {}
+};
+
+function FakeInputStream()
+{
+}
+FakeInputStream.prototype =
+{
+ lines: null,
+ currentIndex: 0,
+
+ init: function(file)
+ {
+ if (file instanceof FakeInputStream)
+ this.lines = file.lines;
+ else
+ this.lines = Android.fileRead(file.path).split(/\n/);
+ },
+ readLine: function(line)
+ {
+ if (this.currentIndex < this.lines.length)
+ line.value = this.lines[this.currentIndex];
+ this.currentIndex++;
+ return (this.currentIndex < this.lines.length);
+ },
+ close: function() {},
+ QueryInterface: function()
+ {
+ return this;
+ }
+};
+
+function FakeOutputStream()
+{
+}
+FakeOutputStream.prototype =
+{
+ file: null,
+ buffer: null,
+
+ init: function(file)
+ {
+ if (file instanceof FakeOutputStream)
+ {
+ this.file = file.file;
+ this.buffer = file.buffer;
+ }
+ else
+ {
+ this.file = file;
+ this.buffer = [];
+ }
+ },
+ writeString: function(string)
+ {
+ this.buffer.push(string);
+ },
+ close: function()
+ {
+ Android.fileWrite(this.file.path, this.buffer.join(""));
+ },
+ finish: function()
+ {
+ this.close();
+ },
+ flush: function() {},
+ QueryInterface: function()
+ {
+ return this;
+ }
+};
+
+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;
+ Android.setTimeout(function()
+ {
+ try
+ {
+ me.callback();
+ }
+ catch(e)
+ {
+ reportError(e);
+ }
+ me.scheduleTimeout();
+ }, this.delay);
+ }
+};
+
+function ElemHidePatch()
+{
+ /**
+ * Returns a list of selectors to be applied on a particular domain. With
+ * specificOnly parameter set to true only the rules listing specific domains
+ * will be considered.
+ */
+ ElemHide.getSelectorsForDomain = function(/**String*/ domain, /**Boolean*/ specificOnly)
+ {
+ var result = [];
+ for (var key in filterByKey)
+ {
+ var filter = Filter.knownFilters[filterByKey[key]];
+ if (specificOnly && (!filter.domains || filter.domains[""]))
+ continue;
+
+ if (filter.isActiveOnDomain(domain))
+ result.push(filter.selector);
+ }
+ if (result.length)
+ return "<style type=\"text/css\">" + result.join() + " { display: none !important }</style>";
+ else
+ return null;
+ };
+
+ ElemHide.init = function() {};
+}
+
+/**
+ * Removes all subscriptions from storage.
+ */
+function clearSubscriptions()
+{
+ while (FilterStorage.subscriptions.length)
+ FilterStorage.removeSubscription(FilterStorage.subscriptions[0]);
+}
+
+/**
+ * Adds selected subscription to storage.
+ */
+function addSubscription(jsonSub)
+{
+ var newSub = JSON.parse(jsonSub);
+
+ var subscription = Subscription.fromURL(newSub["url"]);
+ if (subscription)
+ {
+ subscription.disabled = false;
+ subscription.title = newSub["title"];
+ subscription.homepage = newSub["homepage"];
+ if (subscription instanceof DownloadableSubscription && !subscription.lastDownload)
+ {
+ Synchronizer.execute(subscription);
+ }
+ FilterStorage.addSubscription(subscription);
+ FilterStorage.saveToDisk();
+ }
+}
+
+/**
+ * Forces subscriptions refresh.
+ */
+function refreshSubscriptions()
+{
+ for (var i = 0; i < FilterStorage.subscriptions.length; i++)
+ {
+ var subscription = FilterStorage.subscriptions[i];
+ if (subscription instanceof DownloadableSubscription)
+ Synchronizer.execute(subscription, true, true);
+ }
+}
+
+/**
+ * Verifies that subscriptions are loaded and returns flag of subscription presence.
+ */
+function verifySubscriptions()
+{
+ var hasSubscriptions = false;
+ for (var i = 0; i < FilterStorage.subscriptions.length; i++)
+ {
+ var subscription = FilterStorage.subscriptions[i];
+ if (subscription instanceof DownloadableSubscription)
+ {
+ hasSubscriptions = true;
+ updateSubscriptionStatus(subscription);
+ if (!subscription.lastDownload)
+ {
+ Synchronizer.execute(subscription);
+ }
+ }
+ }
+ return hasSubscriptions;
+}
+
+/**
+ * Callback for subscription status updates.
+ */
+function updateSubscriptionStatus(subscription)
+{
+ var status = "";
+ var time = 0;
+ if (Synchronizer.isExecuting(subscription.url))
+ status = "synchronize_in_progress";
+ else if (subscription.downloadStatus && subscription.downloadStatus != "synchronize_ok")
+ status = subscription.downloadStatus;
+ else if (subscription.lastDownload > 0)
+ {
+ time = subscription.lastDownload * 1000;
+ status = "synchronize_last_at";
+ }
+ else
+ status = "synchronize_never";
+
+ Android.setStatus(status, time);
+}
+
+function onFilterChange(action, subscription, param1, param2)
+{
+ switch (action)
+ {
+ case "subscription.lastDownload":
+ case "subscription.downloadStatus":
+ updateSubscriptionStatus(subscription);
+ break;
+ }
+}
+
+function startInteractive()
+{
+ FilterNotifier.addListener(onFilterChange);
+}
+
+function stopInteractive()
+{
+ FilterNotifier.removeListener(onFilterChange);
+}
+
+function matchesAny(url, query, reqHost, refHost, accept)
+{
+ var contentType = null;
+ var thirdParty = true;
+
+ if (accept != "")
+ {
+ if (accept.indexOf("text/css") != -1)
+ contentType = "STYLESHEET";
+ else if (accept.indexOf("image/*" != -1))
+ contentType = "IMAGE";
+ }
+
+ if (contentType == null)
+ {
+ var lurl = url.toLowerCase();
+ if (/\.js$/.test(lurl))
+ contentType = "SCRIPT";
+ else if (/\.css$/.test(lurl))
+ contentType = "STYLESHEET";
+ else if (/\.(?:gif|png|jpe?g|bmp|ico)$/.test(lurl))
+ contentType = "IMAGE";
+ else if (/\.(?:ttf|woff)$/.test(lurl))
+ contentType = "FONT";
+ }
+ if (contentType == null)
+ contentType = "OTHER";
+
+ if (refHost != "")
+ {
+ thirdParty = isThirdParty(reqHost, refHost);
+ }
+
+ if (query != "")
+ url = url + "?" + query;
+
+ var filter = defaultMatcher.matchesAny(url, contentType, null, thirdParty);
+
+ return (filter != null && !(filter instanceof WhitelistFilter));
+}
+
+Android.load("XMLHttpRequest.jsm");
+Android.load("FilterNotifier.jsm");
+Android.load("FilterClasses.jsm");
+Android.load("SubscriptionClasses.jsm");
+Android.load("FilterStorage.jsm");
+Android.load("FilterListener.jsm");
+Android.load("Matcher.jsm");
+Android.load("ElemHide.jsm");
+Android.load("Synchronizer.jsm");
+
+FilterListener.startup();
+Synchronizer.startup();
+
+Android.load("publicSuffixList.js");
+Android.load("punycode.js");
+Android.load("basedomain.js");
« assets/js/XMLHttpRequest.jsm ('K') | « assets/js/punycode.js ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld