Index: lib/child/elemHide.js |
=================================================================== |
--- a/lib/child/elemHide.js |
+++ b/lib/child/elemHide.js |
@@ -11,17 +11,17 @@ |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
* GNU General Public License for more details. |
* |
* You should have received a copy of the GNU General Public License |
* along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>. |
*/ |
/** |
- * @fileOverview Hit counts for element hiding. |
+ * @fileOverview Serves CSS for element hiding and processes hits. |
*/ |
try |
{ |
// Hack: SDK loader masks our Components object with a getter. |
let proto = Object.getPrototypeOf(this); |
let property = Object.getOwnPropertyDescriptor(proto, "Components"); |
if (property && property.get) |
@@ -36,22 +36,16 @@ let {XPCOMUtils} = Cu.import("resource:/ |
let {Services} = Cu.import("resource://gre/modules/Services.jsm", {}); |
let {shouldAllowAsync} = require("child/contentPolicy"); |
let {getFrames, isPrivate} = require("child/utils"); |
let {RequestNotifier} = require("child/requestNotifier"); |
let {port} = require("messaging"); |
let {Utils} = require("utils"); |
-// The allowXBL binding below won't have any effect on the element. For elements |
-// that should be hidden however we don't return any binding at all, this makes |
-// Gecko stop constructing the node - it cannot be shown. |
-const allowXBL = "<bindings xmlns='http://www.mozilla.org/xbl'><binding id='dummy' bindToUntrustedContent='true'/></bindings>"; |
-const hideXBL = "<bindings xmlns='http://www.mozilla.org/xbl'/>"; |
- |
const notImplemented = () => Cr.NS_ERROR_NOT_IMPLEMENTED; |
/** |
* about: URL module used to count hits. |
* @class |
*/ |
let AboutHandler = |
{ |
@@ -91,24 +85,28 @@ let AboutHandler = |
getURIFlags: function(uri) |
{ |
return Ci.nsIAboutModule.HIDE_FROM_ABOUTABOUT; |
}, |
newChannel: function(uri, loadInfo) |
{ |
- let match = /\?(?:hit(\d+)|css)$/.exec(uri.path); |
- if (!match) |
- throw Cr.NS_ERROR_FAILURE; |
+ let match = /\?hit(\d+)$/.exec(uri.path); |
+ if (match) |
+ return new HitRegistrationChannel(uri, loadInfo, match[1]); |
- if (match[1]) |
- return new HitRegistrationChannel(uri, loadInfo, match[1]); |
- else |
- return new StyleDataChannel(uri, loadInfo); |
+ match = /\?css(?:=(.*?))?$/.exec(uri.path); |
+ if (match) |
+ { |
+ return new StyleDataChannel(uri, loadInfo, |
+ match[1] ? decodeURIComponent(match[1]) : null); |
+ } |
+ |
+ throw Cr.NS_ERROR_FAILURE; |
}, |
QueryInterface: XPCOMUtils.generateQI([Ci.nsIFactory, Ci.nsIAboutModule]) |
}; |
AboutHandler.init(); |
/** |
* Base class for channel implementations, subclasses usually only need to |
@@ -207,68 +205,52 @@ BaseChannel.prototype = { |
cancel: notImplemented, |
suspend: notImplemented, |
resume: notImplemented, |
QueryInterface: XPCOMUtils.generateQI([Ci.nsIChannel, Ci.nsIRequest]) |
}; |
/** |
- * Channel returning CSS data for the global stylesheet. |
+ * Channel returning CSS data for the global as well as site-specific stylesheet. |
* @constructor |
*/ |
-function StyleDataChannel(uri, loadInfo) |
+function StyleDataChannel(uri, loadInfo, domain) |
{ |
BaseChannel.call(this, uri, loadInfo); |
+ this._domain = domain; |
} |
StyleDataChannel.prototype = { |
__proto__: BaseChannel.prototype, |
contentType: "text/css", |
+ _domain: null, |
_getResponse: function() |
{ |
function escapeChar(match) |
{ |
return "\\" + match.charCodeAt(0).toString(16) + " "; |
} |
// Would be great to avoid sync messaging here but nsIStyleSheetService |
// insists on opening channels synchronously. |
- let domains = port.emitSync("getSelectors"); |
+ let [selectors, keys] = (this._domain ? |
+ port.emitSync("getSelectorsForDomain", this._domain) : |
+ port.emitSync("getUnconditionalSelectors")); |
let cssPrefix = "{-moz-binding: url(about:abp-elemhide?hit"; |
let cssSuffix = "#dummy) !important;}\n"; |
let result = []; |
- for (let [domain, selectors] of domains) |
+ for (let i = 0; i < selectors.length; i++) |
{ |
- if (domain) |
- { |
- result.push('@-moz-document domain("', |
- domain.replace(/[^\x01-\x7F]/g, escapeChar) |
- .split(",").join('"),domain("'), |
- '"){\n'); |
- } |
- else |
- { |
- // Only allow unqualified rules on a few protocols to prevent them |
- // from blocking chrome content |
- result.push('@-moz-document url-prefix("http://"),', |
- 'url-prefix("https://"),url-prefix("mailbox://"),', |
- 'url-prefix("imap://"),url-prefix("news://"),', |
- 'url-prefix("snews://"){\n'); |
- } |
- |
- for (let [selector, key] of selectors) |
- { |
- result.push(selector.replace(/[^\x01-\x7F]/g, escapeChar), |
- cssPrefix, key, cssSuffix); |
- } |
- |
- result.push("}\n"); |
+ let selector = selectors[i]; |
+ let key = keys[i]; |
+ result.push(selector.replace(/[^\x01-\x7F]/g, escapeChar), |
+ cssPrefix, key, cssSuffix); |
} |
return result.join(""); |
} |
}; |
/** |
* Channel returning data for element hiding hits. |
@@ -281,24 +263,27 @@ function HitRegistrationChannel(uri, loa |
} |
HitRegistrationChannel.prototype = { |
__proto__: BaseChannel.prototype, |
key: null, |
contentType: "text/xml", |
_getResponse: function() |
{ |
- return new Promise((resolve, reject) => |
+ let window = Utils.getRequestWindow(this); |
+ port.emitWithResponse("registerElemHideHit", { |
+ key: this.key, |
+ frames: getFrames(window), |
+ isPrivate: isPrivate(window) |
+ }).then(hit => |
{ |
- let window = Utils.getRequestWindow(this); |
- shouldAllowAsync(window, window.document, "ELEMHIDE", this.key, allow => |
- { |
- resolve(allow ? allowXBL : hideXBL); |
- }); |
+ if (hit) |
+ RequestNotifier.addNodeData(window.document, window.top, hit); |
kzar
2016/10/06 13:02:32
(Doesn't storing all the details returned by regis
Wladimir Palant
2016/10/06 13:08:48
That's how the list of blockable items works - it
|
}); |
+ return "<bindings xmlns='http://www.mozilla.org/xbl'/>"; |
} |
}; |
let observer = { |
QueryInterface: XPCOMUtils.generateQI([ |
Ci.nsIObserver, Ci.nsISupportsWeakReference |
]), |
@@ -370,16 +355,34 @@ let observer = { |
catch (e) |
{ |
// Ignore NS_ERROR_ILLEGAL_VALUE - it will be thrown if we try to add |
// the stylesheet multiple times to the same document (the observer |
// will be notified twice for some documents). |
if (e.result != Cr.NS_ERROR_ILLEGAL_VALUE) |
throw e; |
} |
+ |
+ let host = subject.location.hostname; |
+ if (host) |
+ { |
+ try |
+ { |
+ utils.loadSheetUsingURIString(this.styleURL.spec + "=" + |
+ encodeURIComponent(host), Ci.nsIStyleSheetService.USER_SHEET); |
+ } |
+ catch (e) |
+ { |
+ // Ignore NS_ERROR_ILLEGAL_VALUE - it will be thrown if we try to add |
+ // the stylesheet multiple times to the same document (the observer |
+ // will be notified twice for some documents). |
+ if (e.result != Cr.NS_ERROR_ILLEGAL_VALUE) |
+ throw e; |
+ } |
+ } |
} |
else if (filter) |
{ |
RequestNotifier.addNodeData(window.document, window.top, { |
contentType, docDomain, thirdParty, location, filter, filterType |
}); |
} |
}); |