diff options
author | Ruben Rodriguez <ruben@gnu.org> | 2017-09-01 16:35:50 -0400 |
---|---|---|
committer | Ruben Rodriguez <ruben@gnu.org> | 2017-09-01 16:35:50 -0400 |
commit | e8730f68798f173bd4d1c2f9b7ce02985e3fd771 (patch) | |
tree | 711132ed84ef8ae9e0621de5436a6818a5fa1e12 /data/extensions/spyblock@gnu.org/lib/requestNotifier.js | |
parent | edde38bbb0e0afb9b8a78c002996c758fb6023b6 (diff) |
SpyBlock updated to 2.9.1
Diffstat (limited to 'data/extensions/spyblock@gnu.org/lib/requestNotifier.js')
-rw-r--r-- | data/extensions/spyblock@gnu.org/lib/requestNotifier.js | 400 |
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); }; |