Block window.close() calls on a window which just had a popup blocked. This

allows the popup notification to actually be visible to the user.  Bug 297980,
patch by Joerg Bornemann <jobor@gmx.de>, r=bzbarsky, sr=jst
This commit is contained in:
bzbarsky%mit.edu 2006-08-29 22:25:12 +00:00
Родитель 724ccdb167
Коммит 6a2e7a2685
2 изменённых файлов: 47 добавлений и 1 удалений

Просмотреть файл

@ -355,6 +355,7 @@ nsGlobalWindow::nsGlobalWindow(nsGlobalWindow *aOuterWindow)
mHavePendingClose(PR_FALSE),
mHadOriginalOpener(PR_FALSE),
mIsPopupSpam(PR_FALSE),
mBlockScriptedClosingFlag(PR_FALSE),
mFireOfflineStatusChangeEventOnThaw(PR_FALSE),
mGlobalObjectOwner(nsnull),
mTimeouts(nsnull),
@ -4316,6 +4317,7 @@ nsGlobalWindow::Open(const nsAString& aUrl, const nsAString& aName,
PR_FALSE, // aDoJSFixups
nsnull, nsnull, // No args
GetPrincipal(), // aCalleePrincipal
nsnull, // aJSCallerContext
_retval);
}
@ -4366,6 +4368,7 @@ nsGlobalWindow::Open(nsIDOMWindow **_retval)
PR_TRUE, // aDoJSFixups
nsnull, nsnull, // No args
GetPrincipal(), // aCalleePrincipal
cx, // aJSCallerContext
_retval);
}
@ -4382,6 +4385,7 @@ nsGlobalWindow::OpenDialog(const nsAString& aUrl, const nsAString& aName,
PR_FALSE, // aDoJSFixups
nsnull, aExtraArgument, // Arguments
GetPrincipal(), // aCalleePrincipal
nsnull, // aJSCallerContext
_retval);
}
@ -4440,6 +4444,7 @@ nsGlobalWindow::OpenDialog(nsIDOMWindow** _retval)
PR_FALSE, // aDoJSFixups
argvArray, nsnull, // Arguments
GetPrincipal(), // aCalleePrincipal
cx, // aJSCallerContext
_retval);
}
@ -4491,6 +4496,14 @@ nsGlobalWindow::Close()
return NS_OK;
}
if (mBlockScriptedClosingFlag)
{
// A script's popup has been blocked and we don't want
// the window to be closed directly after this event,
// so the user can see that there was a blocked popup.
return NS_OK;
}
// Don't allow scripts from content to close windows
// that were not opened by script
nsresult rv = NS_OK;
@ -5941,6 +5954,15 @@ nsGlobalWindow::GetParentInternal()
return parentInternal;
}
// static
void
nsGlobalWindow::CloseBlockScriptTerminationFunc(nsISupports *aRef)
{
nsGlobalWindow* pwin = NS_STATIC_CAST(nsGlobalWindow*,
NS_STATIC_CAST(nsPIDOMWindow*, aRef));
pwin->mBlockScriptedClosingFlag = PR_FALSE;
}
nsresult
nsGlobalWindow::OpenInternal(const nsAString& aUrl, const nsAString& aName,
const nsAString& aOptions, PRBool aDialog,
@ -5948,12 +5970,13 @@ nsGlobalWindow::OpenInternal(const nsAString& aUrl, const nsAString& aName,
nsIArray *argv,
nsISupports *aExtraArgument,
nsIPrincipal *aCalleePrincipal,
JSContext *aJSCallerContext,
nsIDOMWindow **aReturn)
{
FORWARD_TO_OUTER(OpenInternal, (aUrl, aName, aOptions, aDialog,
aCalledNoScript, aDoJSFixups,
argv, aExtraArgument, aCalleePrincipal,
aReturn),
aJSCallerContext, aReturn),
NS_ERROR_NOT_INITIALIZED);
#ifdef NS_DEBUG
@ -5967,6 +5990,8 @@ nsGlobalWindow::OpenInternal(const nsAString& aUrl, const nsAString& aName,
"Can't pass JS args when called via the noscript methods");
NS_PRECONDITION(!aDoJSFixups || !aCalledNoScript,
"JS fixups should not be done when called noscript");
NS_PRECONDITION(!aJSCallerContext || !aCalledNoScript,
"Shouldn't have caller context when called noscript");
*aReturn = nsnull;
@ -5996,6 +6021,20 @@ nsGlobalWindow::OpenInternal(const nsAString& aUrl, const nsAString& aName,
abuseLevel = CheckForAbusePoint();
allowReason = CheckOpenAllow(abuseLevel);
if (allowReason == allowNot) {
if (aJSCallerContext) {
// If script in some other window is doing a window.open on us and
// it's being blocked, then it's OK to close us afterwards, probably.
// But if we're doing a window.open on ourselves and block the popup,
// prevent this window from closing until after this script terminates
// so that whatever popup blocker UI the app has will be visible.
if (mContext == GetScriptContextFromJSContext(aJSCallerContext)) {
mBlockScriptedClosingFlag = PR_TRUE;
mContext->SetTerminationFunction(CloseBlockScriptTerminationFunc,
NS_STATIC_CAST(nsPIDOMWindow*,
this));
}
}
FireAbuseEvents(PR_TRUE, PR_FALSE, aUrl, aName, aOptions);
return aDoJSFixups ? NS_OK : NS_ERROR_FAILURE;
}

Просмотреть файл

@ -333,6 +333,7 @@ public:
static void ShutDown();
static PRBool IsCallerChrome();
static void CloseBlockScriptTerminationFunc(nsISupports *aRef);
friend class WindowStateHolder;
@ -398,6 +399,8 @@ protected:
* @param argc The number of arguments in argv.
* @param aExtraArgument Another way to pass arguments in. This is mutually
* exclusive with the argv/argc approach.
* @param aJSCallerContext The calling script's context. This must be nsnull
* when aCalledNoScript is true.
* @param aReturn [out] The window that was opened, if any.
*
* @note that the boolean args are const because the function shouldn't be
@ -413,6 +416,7 @@ protected:
nsIArray *argv,
nsISupports *aExtraArgument,
nsIPrincipal *aCalleePrincipal,
JSContext *aJSCallerContext,
nsIDOMWindow **aReturn);
static void CloseWindow(nsISupports* aWindow);
@ -536,6 +540,9 @@ protected:
PRPackedBool mHadOriginalOpener : 1;
PRPackedBool mIsPopupSpam : 1;
// Indicates whether scripts are allowed to close this window.
PRPackedBool mBlockScriptedClosingFlag : 1;
// Track what sorts of events we need to fire when thawed
PRPackedBool mFireOfflineStatusChangeEventOnThaw : 1;