gecko-dev/toolkit/actors/PopupBlockingChild.jsm

147 строки
4.6 KiB
JavaScript

/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* eslint no-unused-vars: ["error", {args: "none"}] */
var EXPORTED_SYMBOLS = ["PopupBlockingChild"];
const {ActorChild} = ChromeUtils.import("resource://gre/modules/ActorChild.jsm");
const {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
class PopupBlockingChild extends ActorChild {
constructor(dispatcher) {
super(dispatcher);
this.popupData = null;
this.popupDataInternal = null;
this.mm.addEventListener("pageshow", this, true);
this.mm.addEventListener("pagehide", this, true);
this.mm.addMessageListener("PopupBlocking:UnblockPopup", this);
this.mm.addMessageListener("PopupBlocking:GetBlockedPopupList", this);
}
receiveMessage(msg) {
switch (msg.name) {
case "PopupBlocking:UnblockPopup": {
let i = msg.data.index;
if (this.popupData && this.popupData[i]) {
let data = this.popupData[i];
let internals = this.popupDataInternal[i];
let dwi = internals.requestingWindow;
// If we have a requesting window and the requesting document is
// still the current document, open the popup.
if (dwi && dwi.document == internals.requestingDocument) {
dwi.open(data.popupWindowURIspec, data.popupWindowName, data.popupWindowFeatures);
}
}
break;
}
case "PopupBlocking:GetBlockedPopupList": {
let popupData = [];
let length = this.popupData ? this.popupData.length : 0;
// Limit 15 popup URLs to be reported through the UI
length = Math.min(length, 15);
for (let i = 0; i < length; i++) {
let popupWindowURIspec = this.popupData[i].popupWindowURIspec;
if (popupWindowURIspec == this.mm.content.location.href) {
popupWindowURIspec = "<self>";
} else {
// Limit 500 chars to be sent because the URI will be cropped
// by the UI anyway, and data: URIs can be significantly larger.
popupWindowURIspec = popupWindowURIspec.substring(0, 500);
}
popupData.push({popupWindowURIspec});
}
this.mm.sendAsyncMessage("PopupBlocking:ReplyGetBlockedPopupList", {popupData});
break;
}
}
}
handleEvent(ev) {
switch (ev.type) {
case "DOMPopupBlocked":
return this.onPopupBlocked(ev);
case "pageshow":
return this._removeIrrelevantPopupData();
case "pagehide":
return this._removeIrrelevantPopupData(ev.target);
}
return undefined;
}
onPopupBlocked(ev) {
if (!this.popupData) {
this.popupData = [];
this.popupDataInternal = [];
}
// Avoid spamming the parent process with too many blocked popups.
if (this.popupData.length >= PopupBlockingChild.maxReportedPopups) {
return;
}
let obj = {
popupWindowURIspec: ev.popupWindowURI ? ev.popupWindowURI.spec : "about:blank",
popupWindowFeatures: ev.popupWindowFeatures,
popupWindowName: ev.popupWindowName,
};
let internals = {
requestingWindow: ev.requestingWindow,
requestingDocument: ev.requestingWindow.document,
};
this.popupData.push(obj);
this.popupDataInternal.push(internals);
this.updateBlockedPopups(true);
}
_removeIrrelevantPopupData(removedDoc = null) {
if (this.popupData) {
let i = 0;
let oldLength = this.popupData.length;
while (i < this.popupData.length) {
let {requestingWindow, requestingDocument} = this.popupDataInternal[i];
// Filter out irrelevant reports.
if (requestingWindow && requestingWindow.document == requestingDocument &&
requestingDocument != removedDoc) {
i++;
} else {
this.popupData.splice(i, 1);
this.popupDataInternal.splice(i, 1);
}
}
if (this.popupData.length == 0) {
this.popupData = null;
this.popupDataInternal = null;
}
if (!this.popupData || oldLength > this.popupData.length) {
this.updateBlockedPopups(false);
}
}
}
updateBlockedPopups(freshPopup) {
this.mm.sendAsyncMessage("PopupBlocking:UpdateBlockedPopups",
{
count: this.popupData ? this.popupData.length : 0,
freshPopup,
});
}
}
XPCOMUtils.defineLazyPreferenceGetter(PopupBlockingChild, "maxReportedPopups",
"privacy.popups.maxReported");