зеркало из https://github.com/mozilla/gecko-dev.git
add popup blocking context menu item. bug 166442 r=brendan,jag
This commit is contained in:
Родитель
3e01ff0e77
Коммит
0dac6bc2ec
|
@ -130,6 +130,25 @@ const gHomepagePrefListener =
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// popup window permission change listener
|
||||||
|
const gPopupPermListener = {
|
||||||
|
|
||||||
|
observe: function(subject, topic, data) {
|
||||||
|
if (topic == "popup-perm-close") {
|
||||||
|
// close the window if we're a popup and our opener's URI matches
|
||||||
|
// the URI in the notification
|
||||||
|
var popupOpenerURI = maybeInitPopupContext();
|
||||||
|
if (popupOpenerURI) {
|
||||||
|
const IOS = Components.classes["@mozilla.org/network/io-service;1"]
|
||||||
|
.getService(Components.interfaces.nsIIOService);
|
||||||
|
closeURI = IOS.newURI(data, null, null);
|
||||||
|
if (closeURI.host == popupOpenerURI.host)
|
||||||
|
window.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pref listener handler functions.
|
* Pref listener handler functions.
|
||||||
* Both functions assume that observer.domain is set to
|
* Both functions assume that observer.domain is set to
|
||||||
|
@ -155,6 +174,20 @@ function removePrefListener(observer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function addPopupPermListener(observer)
|
||||||
|
{
|
||||||
|
const OS = Components.classes["@mozilla.org/observer-service;1"]
|
||||||
|
.getService(Components.interfaces.nsIObserverService);
|
||||||
|
OS.addObserver(observer, "popup-perm-close", false);
|
||||||
|
}
|
||||||
|
|
||||||
|
function removePopupPermListener(observer)
|
||||||
|
{
|
||||||
|
const OS = Components.classes["@mozilla.org/observer-service;1"]
|
||||||
|
.getService(Components.interfaces.nsIObserverService);
|
||||||
|
OS.removeObserver(observer, "popup-perm-close");
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* We can avoid adding multiple load event listeners and save some time by adding
|
* We can avoid adding multiple load event listeners and save some time by adding
|
||||||
* one listener that calls all real handlers.
|
* one listener that calls all real handlers.
|
||||||
|
@ -378,6 +411,7 @@ function Startup()
|
||||||
addPrefListener(gButtonPrefListener);
|
addPrefListener(gButtonPrefListener);
|
||||||
addPrefListener(gTabStripPrefListener);
|
addPrefListener(gTabStripPrefListener);
|
||||||
addPrefListener(gHomepagePrefListener);
|
addPrefListener(gHomepagePrefListener);
|
||||||
|
addPopupPermListener(gPopupPermListener);
|
||||||
|
|
||||||
window.browserContentListener =
|
window.browserContentListener =
|
||||||
new nsBrowserContentListener(window, getBrowser());
|
new nsBrowserContentListener(window, getBrowser());
|
||||||
|
@ -576,6 +610,7 @@ function Shutdown()
|
||||||
removePrefListener(gButtonPrefListener);
|
removePrefListener(gButtonPrefListener);
|
||||||
removePrefListener(gTabStripPrefListener);
|
removePrefListener(gTabStripPrefListener);
|
||||||
removePrefListener(gHomepagePrefListener);
|
removePrefListener(gHomepagePrefListener);
|
||||||
|
removePopupPermListener(gPopupPermListener);
|
||||||
|
|
||||||
window.browserContentListener.close();
|
window.browserContentListener.close();
|
||||||
// Close the app core.
|
// Close the app core.
|
||||||
|
@ -1953,3 +1988,34 @@ function checkTheme()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// opener may not have been initialized by load time (chrome windows only)
|
||||||
|
// so call this function some time later.
|
||||||
|
function maybeInitPopupContext()
|
||||||
|
{
|
||||||
|
// it's not a popup with no opener
|
||||||
|
if (!window.content.opener)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
// are we a popup window?
|
||||||
|
const CI = Components.interfaces;
|
||||||
|
var xulwin = window
|
||||||
|
.QueryInterface(CI.nsIInterfaceRequestor)
|
||||||
|
.getInterface(CI.nsIWebNavigation)
|
||||||
|
.QueryInterface(CI.nsIDocShellTreeItem).treeOwner
|
||||||
|
.QueryInterface(CI.nsIInterfaceRequestor)
|
||||||
|
.getInterface(CI.nsIXULWindow);
|
||||||
|
if (xulwin.contextFlags &
|
||||||
|
CI.nsIWindowCreator2.PARENT_IS_LOADING_OR_RUNNING_TIMEOUT) {
|
||||||
|
// return our opener's URI
|
||||||
|
const IOS = Components.classes["@mozilla.org/network/io-service;1"]
|
||||||
|
.getService(CI.nsIIOService);
|
||||||
|
var spec = Components.lookupMethod(window.content.opener, "location")
|
||||||
|
.call();
|
||||||
|
return IOS.newURI(spec, null, null);
|
||||||
|
}
|
||||||
|
} catch(e) {
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
|
@ -45,6 +45,16 @@
|
||||||
<popup id="contentAreaContextMenu"
|
<popup id="contentAreaContextMenu"
|
||||||
onpopupshowing="gContextMenu = new nsContextMenu( this ); return gContextMenu.shouldDisplay;"
|
onpopupshowing="gContextMenu = new nsContextMenu( this ); return gContextMenu.shouldDisplay;"
|
||||||
onpopuphiding="gContextMenu = null;">
|
onpopuphiding="gContextMenu = null;">
|
||||||
|
<menuitem id="popupwindow-reject"
|
||||||
|
label="&popupWindowRejectCmd.label;"
|
||||||
|
accesskey="&popupWindowRejectCmd.accesskey;"
|
||||||
|
oncommand="gContextMenu.rejectPopupWindows(event.shiftKey);"/>
|
||||||
|
<menuitem id="popupwindow-allow"
|
||||||
|
label="&popupWindowAllowCmd.label;"
|
||||||
|
accesskey="&popupWindowAllowCmd.accesskey;"
|
||||||
|
oncommand="gContextMenu.allowPopupWindows();"/>
|
||||||
|
<menuseparator id="context-sep-popup"/>
|
||||||
|
|
||||||
<menuitem id="context-openlink"
|
<menuitem id="context-openlink"
|
||||||
label="&openLinkCmd.label;"
|
label="&openLinkCmd.label;"
|
||||||
accesskey="&openLinkCmd.accesskey;"
|
accesskey="&openLinkCmd.accesskey;"
|
||||||
|
|
|
@ -36,6 +36,7 @@
|
||||||
function nsContextMenu( xulMenu ) {
|
function nsContextMenu( xulMenu ) {
|
||||||
this.target = null;
|
this.target = null;
|
||||||
this.menu = null;
|
this.menu = null;
|
||||||
|
this.popupURL = null;
|
||||||
this.onTextInput = false;
|
this.onTextInput = false;
|
||||||
this.onImage = false;
|
this.onImage = false;
|
||||||
this.onLink = false;
|
this.onLink = false;
|
||||||
|
@ -69,6 +70,8 @@ nsContextMenu.prototype = {
|
||||||
|
|
||||||
this.isTextSelected = this.isTextSelection();
|
this.isTextSelected = this.isTextSelection();
|
||||||
|
|
||||||
|
this.initPopupURL();
|
||||||
|
|
||||||
// Initialize (disable/remove) menu items.
|
// Initialize (disable/remove) menu items.
|
||||||
this.initItems();
|
this.initItems();
|
||||||
},
|
},
|
||||||
|
@ -149,6 +152,19 @@ nsContextMenu.prototype = {
|
||||||
this.showItem( "context-searchselect", this.isTextSelected );
|
this.showItem( "context-searchselect", this.isTextSelected );
|
||||||
this.showItem( "frame", this.inFrame );
|
this.showItem( "frame", this.inFrame );
|
||||||
this.showItem( "frame-sep", this.inFrame );
|
this.showItem( "frame-sep", this.inFrame );
|
||||||
|
var blocking = true;
|
||||||
|
if (this.popupURL)
|
||||||
|
try {
|
||||||
|
const PM = Components.classes["@mozilla.org/PopupWindowManager;1"]
|
||||||
|
.getService(Components.interfaces.nsIPopupWindowManager);
|
||||||
|
blocking = PM.testPermission(this.popupURL) ==
|
||||||
|
Components.interfaces.nsIPopupWindowManager.eDisallow;
|
||||||
|
} catch (e) {
|
||||||
|
}
|
||||||
|
|
||||||
|
this.showItem( "popupwindow-reject", this.popupURL && !blocking);
|
||||||
|
this.showItem( "popupwindow-allow", this.popupURL && blocking);
|
||||||
|
this.showItem( "context-sep-popup", this.popupURL);
|
||||||
},
|
},
|
||||||
initClipboardItems : function () {
|
initClipboardItems : function () {
|
||||||
|
|
||||||
|
@ -397,6 +413,48 @@ nsContextMenu.prototype = {
|
||||||
elem = elem.parentNode;
|
elem = elem.parentNode;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
initPopupURL: function() {
|
||||||
|
// quick check: if no opener, it can't be a popup
|
||||||
|
if (!window.content.opener)
|
||||||
|
return;
|
||||||
|
try {
|
||||||
|
var show = false;
|
||||||
|
// is it a popup window?
|
||||||
|
const CI = Components.interfaces;
|
||||||
|
var xulwin = window
|
||||||
|
.QueryInterface(CI.nsIInterfaceRequestor)
|
||||||
|
.getInterface(CI.nsIWebNavigation)
|
||||||
|
.QueryInterface(CI.nsIDocShellTreeItem)
|
||||||
|
.treeOwner
|
||||||
|
.QueryInterface(CI.nsIInterfaceRequestor)
|
||||||
|
.getInterface(CI.nsIXULWindow);
|
||||||
|
if (xulwin.contextFlags &
|
||||||
|
CI.nsIWindowCreator2.PARENT_IS_LOADING_OR_RUNNING_TIMEOUT) {
|
||||||
|
// do the pref settings allow site-by-site popup management?
|
||||||
|
const PB = Components.classes["@mozilla.org/preferences-service;1"]
|
||||||
|
.getService(CI.nsIPrefBranch);
|
||||||
|
show = !PB.getBoolPref("dom.disable_open_during_load") &&
|
||||||
|
PB.getIntPref("privacy.popups.policy") ==
|
||||||
|
CI.nsIPopupWindowManager.eAllow &&
|
||||||
|
PB.getBoolPref("privacy.popups.usecustom");
|
||||||
|
}
|
||||||
|
if (show) {
|
||||||
|
// initialize popupURL
|
||||||
|
const IOS = Components.classes["@mozilla.org/network/io-service;1"]
|
||||||
|
.getService(CI.nsIIOService);
|
||||||
|
var spec = Components.lookupMethod(window.content.opener, "location")
|
||||||
|
.call();
|
||||||
|
this.popupURL = IOS.newURI(spec, null, null);
|
||||||
|
|
||||||
|
// but cancel if it's an unsuitable URL
|
||||||
|
const PM = Components.classes["@mozilla.org/PopupWindowManager;1"]
|
||||||
|
.getService(CI.nsIPopupWindowManager);
|
||||||
|
if (!PM.testSuitability(this.popupURL))
|
||||||
|
this.popupURL = null;
|
||||||
|
}
|
||||||
|
} catch(e) {
|
||||||
|
}
|
||||||
|
},
|
||||||
// Returns the computed style attribute for the given element.
|
// Returns the computed style attribute for the given element.
|
||||||
getComputedStyle: function( elem, prop ) {
|
getComputedStyle: function( elem, prop ) {
|
||||||
return elem.ownerDocument.defaultView.getComputedStyle( elem, '' ).getPropertyValue( prop );
|
return elem.ownerDocument.defaultView.getComputedStyle( elem, '' ).getPropertyValue( prop );
|
||||||
|
@ -441,6 +499,23 @@ nsContextMenu.prototype = {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
// Block popup windows
|
||||||
|
rejectPopupWindows: function(andClose) {
|
||||||
|
const PM = Components.classes["@mozilla.org/PopupWindowManager;1"]
|
||||||
|
.getService(Components.interfaces.nsIPopupWindowManager);
|
||||||
|
PM.add(this.popupURL, false);
|
||||||
|
if (andClose) {
|
||||||
|
const OS = Components.classes["@mozilla.org/observer-service;1"]
|
||||||
|
.getService(Components.interfaces.nsIObserverService);
|
||||||
|
OS.notifyObservers(window, "popup-perm-close", this.popupURL.spec);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// Unblock popup windows
|
||||||
|
allowPopupWindows: function() {
|
||||||
|
const PM = Components.classes["@mozilla.org/PopupWindowManager;1"]
|
||||||
|
.getService(Components.interfaces.nsIPopupWindowManager);
|
||||||
|
PM.add(this.popupURL, true);
|
||||||
|
},
|
||||||
// Open linked-to URL in a new window.
|
// Open linked-to URL in a new window.
|
||||||
openLink : function () {
|
openLink : function () {
|
||||||
// Determine linked-to URL.
|
// Determine linked-to URL.
|
||||||
|
|
|
@ -1,4 +1,8 @@
|
||||||
<!-- Context Menu -->
|
<!-- Context Menu -->
|
||||||
|
<!ENTITY popupWindowRejectCmd.label "Reject pop-up windows from this site">
|
||||||
|
<!ENTITY popupWindowRejectCmd.accesskey "">
|
||||||
|
<!ENTITY popupWindowAllowCmd.label "Allow pop-up windows from this site">
|
||||||
|
<!ENTITY popupWindowAllowCmd.accesskey "">
|
||||||
<!ENTITY openLinkCmd.label "Open Link in New Window">
|
<!ENTITY openLinkCmd.label "Open Link in New Window">
|
||||||
<!ENTITY openLinkCmd.accesskey "W">
|
<!ENTITY openLinkCmd.accesskey "W">
|
||||||
<!ENTITY openLinkCmdInTab.label "Open Link in New Tab">
|
<!ENTITY openLinkCmdInTab.label "Open Link in New Tab">
|
||||||
|
@ -78,4 +82,4 @@
|
||||||
<!ENTITY undoCmd.accesskey "U">
|
<!ENTITY undoCmd.accesskey "U">
|
||||||
<!ENTITY thisFrameMenu.label "This Frame">
|
<!ENTITY thisFrameMenu.label "This Frame">
|
||||||
<!ENTITY thisFrameMenu.accesskey "h">
|
<!ENTITY thisFrameMenu.accesskey "h">
|
||||||
<!ENTITY search.accesskey "W">
|
<!ENTITY search.accesskey "W">
|
||||||
|
|
Загрузка…
Ссылка в новой задаче