Index: lib/child/requestNotifier.js |
=================================================================== |
--- a/lib/child/requestNotifier.js |
+++ b/lib/child/requestNotifier.js |
@@ -16,33 +16,36 @@ |
*/ |
/** |
* @fileOverview Stores Adblock Plus data to be attached to a window. |
*/ |
let {Services} = Cu.import("resource://gre/modules/Services.jsm", {}); |
let {Utils} = require("utils"); |
+let {Flasher} = require("child/flasher"); |
let nodeData = new WeakMap(); |
let windowStats = new WeakMap(); |
let requestEntryMaxId = 0; |
/** |
* Active RequestNotifier instances by their ID |
* @type Map.<number,RequestNotifier> |
*/ |
let notifiers = new Map(); |
addMessageListener("AdblockPlus:StartWindowScan", onStartScan); |
addMessageListener("AdblockPlus:ShutdownNotifier", onNotifierShutdown); |
+addMessageListener("AdblockPlus:FlashNodes", onFlashNodes); |
onShutdown.add(() => { |
removeMessageListener("AdblockPlus:StartWindowScan", onStartScan); |
removeMessageListener("AdblockPlus:ShutdownNotifier", onNotifierShutdown); |
+ removeMessageListener("AdblockPlus:FlashNodes", onFlashNodes); |
}); |
function onStartScan(message) |
{ |
let {notifierID, outerWindowID} = message.data; |
let window = Services.wm.getOuterWindowWithId(outerWindowID); |
if (window) |
new RequestNotifier(window, notifierID); |
@@ -50,28 +53,37 @@ function onStartScan(message) |
function onNotifierShutdown(message) |
{ |
let notifier = notifiers.get(message.data); |
if (notifier) |
notifier.shutdown(); |
} |
+function onFlashNodes(message) |
+{ |
+ let {notifierID, requests, scrollToItem} = message.data; |
+ let notifier = notifiers.get(notifierID); |
+ if (notifier) |
+ notifier.flashNodes(requests, scrollToItem); |
+} |
+ |
/** |
* 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} id Parent notifier ID to be messaged |
*/ |
function RequestNotifier(window, notifierID) |
{ |
this.window = window; |
this.id = notifierID; |
notifiers.set(this.id, this); |
+ this.nodes = new Map(); |
this.startScan(window); |
} |
exports.RequestNotifier = RequestNotifier; |
RequestNotifier.prototype = |
{ |
/** |
* Parent notifier ID to be messaged |
@@ -81,31 +93,42 @@ RequestNotifier.prototype = |
/** |
* The window this notifier is associated with. |
* @type Window |
*/ |
window: null, |
/** |
+ * Nodes associated with a particular request ID. |
+ * @type Map.<number,Node> |
+ */ |
+ nodes: null, |
+ |
+ /** |
* Shuts down the notifier once it is no longer used. The listener |
* will no longer be called after that. |
*/ |
shutdown: function() |
{ |
delete this.window; |
+ delete this.nodes; |
+ this.stopFlashing(); |
notifiers.delete(this.id); |
}, |
/** |
* Notifies the parent about a new request. |
+ * @param {Node} node DOM node that the request is associated with |
* @param {Object} entry |
*/ |
- notifyListener: function(entry) |
+ notifyListener: function(node, entry) |
{ |
+ if (this.nodes) |
+ this.nodes.set(entry.id, node); |
sendAsyncMessage("AdblockPlus:FoundNodeData", { |
notifierID: this.id, |
data: entry |
}); |
}, |
onComplete: function() |
{ |
@@ -131,17 +154,17 @@ RequestNotifier.prototype = |
{ |
if (!this.window) |
return; |
let node = walker.currentNode; |
let data = nodeData.get(node); |
if (typeof data != "undefined") |
for (let k in data) |
- this.notifyListener(data[k]); |
+ this.notifyListener(node, data[k]); |
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]); |
@@ -153,16 +176,52 @@ RequestNotifier.prototype = |
this.onComplete(); |
} |
} |
}.bind(this); |
// Process each node in a separate event to allow other events to process |
this.eventsPosted++; |
Utils.runAsync(process); |
+ }, |
+ |
+ /** |
+ * 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 |
+ */ |
+ flashNodes: function(requests, scrollToItem) |
+ { |
+ this.stopFlashing(); |
+ |
+ let nodes = []; |
+ for (let id of requests) |
+ { |
+ if (!this.nodes.has(id)) |
+ continue; |
+ |
+ let node = this.nodes.get(id); |
+ if (Cu.isDeadWrapper(node)) |
+ this.nodes.delete(node); |
+ else if (node.nodeType == Ci.nsIDOMNode.ELEMENT_NODE) |
+ nodes.push(node); |
+ } |
+ if (nodes.length) |
+ this.flasher = new Flasher(nodes, scrollToItem); |
+ }, |
+ |
+ /** |
+ * Stops flashing nodes after a previous flashNodes() call. |
+ */ |
+ stopFlashing: function() |
+ { |
+ if (this.flasher) |
+ this.flasher.stop(); |
+ this.flasher = 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 {String} contentType request type, e.g. "IMAGE" |
@@ -218,10 +277,10 @@ RequestNotifier.addNodeData = function(n |
stats.filters[filter.text]++; |
else |
stats.filters[filter.text] = 1; |
} |
// Notify listeners |
for (let notifier of notifiers.values()) |
if (!notifier.window || notifier.window == topWnd) |
- notifier.notifyListener(entry); |
+ notifier.notifyListener(node, entry); |
} |