summaryrefslogtreecommitdiff
path: root/data/extensions/spyblock@gnu.org/lib/requestNotifier.js
diff options
context:
space:
mode:
Diffstat (limited to 'data/extensions/spyblock@gnu.org/lib/requestNotifier.js')
-rw-r--r--data/extensions/spyblock@gnu.org/lib/requestNotifier.js400
1 files changed, 109 insertions, 291 deletions
diff --git a/data/extensions/spyblock@gnu.org/lib/requestNotifier.js b/data/extensions/spyblock@gnu.org/lib/requestNotifier.js
index 8b9ca30..f42eaac 100644
--- a/data/extensions/spyblock@gnu.org/lib/requestNotifier.js
+++ b/data/extensions/spyblock@gnu.org/lib/requestNotifier.js
@@ -1,6 +1,6 @@
/*
* This file is part of Adblock Plus <https://adblockplus.org/>,
- * Copyright (C) 2006-2015 Eyeo GmbH
+ * Copyright (C) 2006-2017 eyeo GmbH
*
* Adblock Plus is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
@@ -19,86 +19,59 @@
* @fileOverview Stores Adblock Plus data to be attached to a window.
*/
-Cu.import("resource://gre/modules/Services.jsm");
+let {port} = require("messaging");
-let {Utils} = require("utils");
-let {BlockingFilter, WhitelistFilter, ElemHideBase, ElemHideFilter, ElemHideException} = require("filterClasses");
+let requestNotifierMaxId = 0;
-let nodeData = new WeakMap();
-let windowStats = new WeakMap();
-let windowSelection = new WeakMap();
-let requestEntryMaxId = 0;
+/**
+ * Active RequestNotifier instances by their ID
+ * @type Map.<number,RequestNotifier>
+ */
+let notifiers = new Map();
-let setEntry, hasEntry, getEntry;
-// Last issue(Bug 982561) preventing us from using WeakMap fixed for FF version 32
-if (Services.vc.compare(Utils.platformVersion, "32.0a1") >= 0)
-{
- setEntry = (map, key, value) => map.set(key, value);
- hasEntry = (map, key) => map.has(key);
- getEntry = (map, key) => map.get(key);
-}
-else
+port.on("foundNodeData", ({notifierID, data}, sender) =>
{
- // Fall back to user data
- let dataSeed = Math.random();
- let nodeDataProp = "abpNodeData" + dataSeed;
- let windowStatsProp = "abpWindowStats" + dataSeed;
- let windowSelectionProp = "abpWindowSelection" + dataSeed;
- let getProp = function(map)
- {
- switch (map)
- {
- case nodeData:
- return nodeDataProp;
- case windowStats:
- return windowStatsProp;
- case windowSelection:
- return windowSelectionProp;
- default:
- return null;
- }
- };
-
- setEntry = (map, key, value) => key.setUserData(getProp(map), value, null);
- hasEntry = (map, key) => key.getUserData(getProp(map));
- getEntry = (map, key) => key.getUserData(getProp(map)) || undefined;
-}
+ let notifier = notifiers.get(notifierID);
+ if (notifier)
+ notifier.notifyListener(data);
+});
-/**
- * List of notifiers in use - these notifiers need to receive notifications on
- * new requests.
- * @type RequestNotifier[]
- */
-let activeNotifiers = [];
+port.on("scanComplete", (notifierID, sender) =>
+{
+ let notifier = notifiers.get(notifierID);
+ if (notifier)
+ notifier.onComplete();
+});
/**
* Creates a notifier object for a particular window. After creation the window
* will first be scanned for previously saved requests. Once that scan is
* complete only new requests for this window will be reported.
- * @param {Window} wnd window to attach the notifier to
+ * @param {Integer} outerWindowID ID of the window to attach the notifier to
* @param {Function} listener listener to be called whenever a new request is found
* @param {Object} [listenerObj] "this" pointer to be used when calling the listener
*/
-function RequestNotifier(wnd, listener, listenerObj)
+function RequestNotifier(outerWindowID, listener, listenerObj)
{
- this.window = wnd;
this.listener = listener;
this.listenerObj = listenerObj || null;
- activeNotifiers.push(this);
- if (wnd)
- this.startScan(wnd);
- else
- this.scanComplete = true;
+ this.id = ++requestNotifierMaxId;
+ notifiers.set(this.id, this);
+
+ port.emit("startWindowScan", {
+ notifierID: this.id,
+ outerWindowID: outerWindowID
+ });
}
exports.RequestNotifier = RequestNotifier;
RequestNotifier.prototype =
{
/**
- * The window this notifier is associated with.
- * @type Window
+ * The unique ID of this notifier.
+ * @type Integer
*/
- window: null,
+ id: null,
/**
* The listener to be called when a new request is found.
@@ -124,268 +97,113 @@ RequestNotifier.prototype =
*/
shutdown: function()
{
- delete this.window;
- delete this.listener;
- delete this.listenerObj;
-
- for (let i = activeNotifiers.length - 1; i >= 0; i--)
- if (activeNotifiers[i] == this)
- activeNotifiers.splice(i, 1);
+ notifiers.delete(this.id);
+ port.emit("shutdownNotifier", this.id);
},
/**
* Notifies listener about a new request.
- * @param {Window} wnd
- * @param {Node} node
- * @param {RequestEntry} entry
+ * @param {Object} entry
*/
- notifyListener: function(wnd, node, entry)
+ notifyListener: function(entry)
{
- this.listener.call(this.listenerObj, wnd, node, entry, this.scanComplete);
+ this.listener.call(this.listenerObj, entry, this.scanComplete);
},
- /**
- * Number of currently posted scan events (will be 0 when the scan finishes
- * running).
- */
- eventsPosted: 0,
+ onComplete: function()
+ {
+ this.scanComplete = true;
+ this.notifyListener(null);
+ },
/**
- * Starts the initial scan of the window (will recurse into frames).
- * @param {Window} wnd the window to be scanned
+ * Makes the nodes associated with the given requests blink.
+ * @param {number[]} requests list of request IDs that were previously
+ * reported by this notifier.
+ * @param {Boolean} scrollToItem if true, scroll to first node
*/
- startScan: function(wnd)
+ flashNodes: function(requests, scrollToItem)
{
- let doc = wnd.document;
- let walker = doc.createTreeWalker(doc, Ci.nsIDOMNodeFilter.SHOW_ELEMENT, null, false);
+ if (!requests)
+ requests = [];
- let process = function()
- {
- if (!this.listener)
- return;
+ port.emit("flashNodes", {
+ notifierID: this.id,
+ requests,
+ scrollToItem
+ });
+ },
- let node = walker.currentNode;
- let data = getEntry(nodeData, node);
- if (typeof data != "undefined")
- for (let k in data)
- this.notifyListener(wnd, node, data[k]);
+ /**
+ * Attempts to calculate the size of the nodes associated with the requests.
+ * @param {number[]} requests list of request IDs that were previously
+ * reported by this notifier.
+ * @param {Function} callback function to be called with two parameters (x,y)
+ */
+ retrieveNodeSize: function(requests, callback)
+ {
+ if (!requests)
+ requests = [];
- if (walker.nextNode())
- Utils.runAsync(process);
- else
- {
- // Done with the current window, start the scan for its frames
- for (let i = 0; i < wnd.frames.length; i++)
- this.startScan(wnd.frames[i]);
+ port.emitWithResponse("retrieveNodeSize", {
+ notifierID: this.id,
+ requests
+ }).then(callback);
+ },
- this.eventsPosted--;
- if (!this.eventsPosted)
- {
- this.scanComplete = true;
- this.notifyListener(wnd, null, null);
- }
- }
- }.bind(this);
+ /**
+ * Stores the nodes associated with the requests and generates a unique ID
+ * for them that can be used with Policy.refilterNodes(). Note that
+ * Policy.deleteNodes() always has to be called to release the memory.
+ * @param {number[]} requests list of request IDs that were previously
+ * reported by this notifier.
+ * @param {Function} callback function to be called with the nodes ID.
+ */
+ storeNodesForEntries: function(requests, callback)
+ {
+ if (!requests)
+ requests = [];
- // Process each node in a separate event to allow other events to process
- this.eventsPosted++;
- Utils.runAsync(process);
+ port.emitWithResponse("storeNodesForEntries", {
+ notifierID: this.id,
+ requests
+ }).then(callback);
}
};
-RequestNotifier.storeSelection = function(/**Window*/ wnd, /**String*/ selection)
-{
- setEntry(windowSelection, wnd.document, selection);
-};
-RequestNotifier.getSelection = function(/**Window*/ wnd) /**String*/
-{
- if (hasEntry(windowSelection, wnd.document))
- return getEntry(windowSelection, wnd.document);
- else
- return null;
-};
-
-/**
- * Attaches request data to a DOM node.
- * @param {Node} node node to attach data to
- * @param {Window} topWnd top-level window the node belongs to
- * @param {Integer} contentType request type, one of the Policy.type.* constants
- * @param {String} docDomain domain of the document that initiated the request
- * @param {Boolean} thirdParty will be true if a third-party server has been requested
- * @param {String} location the address that has been requested
- * @param {Filter} filter filter applied to the request or null if none
- */
-RequestNotifier.addNodeData = function(/**Node*/ node, /**Window*/ topWnd, /**Integer*/ contentType, /**String*/ docDomain, /**Boolean*/ thirdParty, /**String*/ location, /**Filter*/ filter)
-{
- return new RequestEntry(node, topWnd, contentType, docDomain, thirdParty, location, filter);
-}
-
/**
- * Retrieves the statistics for a window.
- * @result {Object} Object with the properties items, blocked, whitelisted, hidden, filters containing statistics for the window (might be null)
+ * Associates a piece of data with a particular window.
+ * @param {number} outerWindowID the ID of the window
+ * @static
*/
-RequestNotifier.getWindowStatistics = function(/**Window*/ wnd)
+RequestNotifier.storeWindowData = function(outerWindowID, data)
{
- if (hasEntry(windowStats, wnd.document))
- return getEntry(windowStats, wnd.document);
- else
- return null;
-}
+ port.emit("storeWindowData", {
+ outerWindowID,
+ data
+ });
+};
/**
- * Retrieves the request entry associated with a DOM node.
- * @param {Node} node
- * @param {Boolean} noParent if missing or false, the search will extend to the parent nodes until one is found that has data associated with it
- * @param {Integer} [type] request type to be looking for
- * @param {String} [location] request location to be looking for
- * @result {[Node, RequestEntry]}
+ * Retrieves a piece of data previously associated with the window by calling
+ * storeWindowData.
+ * @param {number} outerWindowID the ID of the window
+ * @param {Function} callback function to be called with the data.
* @static
*/
-RequestNotifier.getDataForNode = function(node, noParent, type, location)
+RequestNotifier.retrieveWindowData = function(outerWindowID, callback)
{
- while (node)
- {
- let data = getEntry(nodeData, node);
- if (typeof data != "undefined")
- {
- let entry = null;
- // Look for matching entry
- for (let k in data)
- {
- if ((!entry || entry.id < data[k].id) &&
- (typeof type == "undefined" || data[k].type == type) &&
- (typeof location == "undefined" || data[k].location == location))
- {
- entry = data[k];
- }
- }
- if (entry)
- return [node, entry];
- }
-
- // If we don't have any match on this node then maybe its parent will do
- if ((typeof noParent != "boolean" || !noParent) &&
- node.parentNode instanceof Ci.nsIDOMElement)
- {
- node = node.parentNode;
- }
- else
- {
- node = null;
- }
- }
-
- return null;
+ port.emitWithResponse("retrieveWindowData", outerWindowID).then(callback);
};
-function RequestEntry(node, topWnd, contentType, docDomain, thirdParty, location, filter)
-{
- this.type = contentType;
- this.docDomain = docDomain;
- this.thirdParty = thirdParty;
- this.location = location;
- this.filter = filter;
- this.id = ++requestEntryMaxId;
-
- this.attachToNode(node);
-
- // Update window statistics
- if (!hasEntry(windowStats, topWnd.document))
- {
- setEntry(windowStats, topWnd.document, {
- items: 0,
- hidden: 0,
- blocked: 0,
- whitelisted: 0,
- filters: {}
- });
- }
-
- let stats = getEntry(windowStats, topWnd.document);
- if (!filter || !(filter instanceof ElemHideBase))
- stats.items++;
- if (filter)
- {
- if (filter instanceof BlockingFilter)
- stats.blocked++;
- else if (filter instanceof WhitelistFilter || filter instanceof ElemHideException)
- stats.whitelisted++;
- else if (filter instanceof ElemHideFilter)
- stats.hidden++;
-
- if (filter.text in stats.filters)
- stats.filters[filter.text]++;
- else
- stats.filters[filter.text] = 1;
- }
-
- // Notify listeners
- for (let notifier of activeNotifiers)
- if (!notifier.window || notifier.window == topWnd)
- notifier.notifyListener(topWnd, node, this);
-}
-RequestEntry.prototype =
+/**
+ * Retrieves the statistics for a window.
+ * @param {number} outerWindowID the ID of the window
+ * @param {Function} callback the callback to be called with the resulting
+ * object (object properties will be items, blocked,
+ * whitelisted, hidden, filters) or null.
+ */
+RequestNotifier.getWindowStatistics = function(outerWindowID, callback)
{
- /**
- * id of request (used to determine last entry attached to a node)
- * @type integer
- */
- id: 0,
- /**
- * Content type of the request (one of the nsIContentPolicy constants)
- * @type Integer
- */
- type: null,
- /**
- * Domain name of the requesting document
- * @type String
- */
- docDomain: null,
- /**
- * True if the request goes to a different domain than the domain of the containing document
- * @type Boolean
- */
- thirdParty: false,
- /**
- * Address being requested
- * @type String
- */
- location: null,
- /**
- * Filter that was applied to this request (if any)
- * @type Filter
- */
- filter: null,
- /**
- * String representation of the content type, e.g. "subdocument"
- * @type String
- */
- get typeDescr()
- {
- return require("contentPolicy").Policy.typeDescr[this.type];
- },
- /**
- * User-visible localized representation of the content type, e.g. "frame"
- * @type String
- */
- get localizedDescr()
- {
- return require("contentPolicy").Policy.localizedDescr[this.type];
- },
-
- /**
- * Attaches this request object to a DOM node.
- */
- attachToNode: function(/**Node*/ node)
- {
- let existingData = getEntry(nodeData, node);
- if (typeof existingData == "undefined")
- {
- existingData = {};
- setEntry(nodeData, node, existingData);
- }
-
- // Add this request to the node data
- existingData[this.type + " " + this.location] = this;
- }
+ port.emitWithResponse("retrieveWindowStats", outerWindowID).then(callback);
};