From 63bd26c924fed2b666697ed3b61d43c2f1dbda18 Mon Sep 17 00:00:00 2001 From: "jst@mozilla.org" Date: Thu, 26 Jul 2007 10:52:26 -0700 Subject: [PATCH] Fixing bug 194404. Adding support for window.showModalDialog() for compatibility with IE. r+sr=jonas@sicking.cc --- docshell/base/nsDocShell.cpp | 8 + dom/public/base/nsPIDOMWindow.h | 20 +- dom/public/idl/base/Makefile.in | 7 +- .../idl/base/nsIDOMModalContentWindow.idl | 58 ++++ dom/public/idl/base/nsIDOMWindowInternal.idl | 7 +- dom/public/nsDOMClassInfoID.h | 3 + dom/public/nsIDOMScriptObjectFactory.h | 6 +- dom/src/base/nsDOMClassInfo.cpp | 14 + dom/src/base/nsDOMScriptObjectFactory.cpp | 3 +- dom/src/base/nsDOMScriptObjectFactory.h | 1 + dom/src/base/nsGlobalWindow.cpp | 261 +++++++++++++++++- dom/src/base/nsGlobalWindow.h | 33 ++- dom/src/base/nsJSEnvironment.cpp | 26 +- .../windowwatcher/src/nsWindowWatcher.cpp | 26 +- xpfe/appshell/src/nsXULWindow.cpp | 14 +- 15 files changed, 452 insertions(+), 35 deletions(-) create mode 100644 dom/public/idl/base/nsIDOMModalContentWindow.idl diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp index b3172fdcb33..e6fc2d3488b 100644 --- a/docshell/base/nsDocShell.cpp +++ b/docshell/base/nsDocShell.cpp @@ -8500,7 +8500,15 @@ nsDocShell::EnsureScriptEnvironment() do_GetService(kDOMScriptObjectFactoryCID); NS_ENSURE_TRUE(factory, NS_ERROR_FAILURE); + nsCOMPtr parent; + GetParent(getter_AddRefs(parent)); + + nsCOMPtr pw(do_GetInterface(parent)); + + // If the parent (chrome or not) is a modal content window, make + // this window a modal content window as well. factory->NewScriptGlobalObject(mItemType == typeChrome, + pw && pw->IsModalContentWindow(), getter_AddRefs(mScriptGlobal)); NS_ENSURE_TRUE(mScriptGlobal, NS_ERROR_FAILURE); diff --git a/dom/public/base/nsPIDOMWindow.h b/dom/public/base/nsPIDOMWindow.h index d7e60534e5d..07efaa036d3 100644 --- a/dom/public/base/nsPIDOMWindow.h +++ b/dom/public/base/nsPIDOMWindow.h @@ -72,8 +72,8 @@ class nsPresContext; struct nsTimeout; #define NS_PIDOMWINDOW_IID \ -{ 0xbf81c452, 0xbd39, 0x4001, \ - { 0x85, 0xf4, 0x21, 0x79, 0x36, 0xc5, 0x85, 0x7d } } +{ 0x42764ad5, 0xa196, 0x408c, \ + { 0xa4, 0x87, 0x97, 0xf4, 0xc6, 0x31, 0x57, 0x21 } } class nsPIDOMWindow : public nsIDOMWindowInternal { @@ -361,6 +361,15 @@ public: virtual void EnterModalState() = 0; virtual void LeaveModalState() = 0; + void SetModalContentWindow(PRBool aIsModalContentWindow) + { + mIsModalContentWindow = aIsModalContentWindow; + } + + PRBool IsModalContentWindow() const + { + return mIsModalContentWindow; + } protected: // The nsPIDOMWindow constructor. The aOuterWindow argument should @@ -371,7 +380,8 @@ protected: : mFrameElement(nsnull), mDocShell(nsnull), mModalStateDepth(0), mRunningTimeout(nsnull), mMutationBits(0), mIsDocumentLoaded(PR_FALSE), mIsHandlingResizeEvent(PR_FALSE), mIsInnerWindow(aOuterWindow != nsnull), - mInnerWindow(nsnull), mOuterWindow(aOuterWindow) + mIsModalContentWindow(PR_FALSE), mInnerWindow(nsnull), + mOuterWindow(aOuterWindow) { } @@ -396,6 +406,10 @@ protected: PRPackedBool mIsHandlingResizeEvent; PRPackedBool mIsInnerWindow; + // This variable is used on both inner and outer windows (and they + // should match). + PRPackedBool mIsModalContentWindow; + // And these are the references between inner and outer windows. nsPIDOMWindow *mInnerWindow; nsPIDOMWindow *mOuterWindow; diff --git a/dom/public/idl/base/Makefile.in b/dom/public/idl/base/Makefile.in index 255cd7d5d3a..23ec2c59367 100644 --- a/dom/public/idl/base/Makefile.in +++ b/dom/public/idl/base/Makefile.in @@ -57,7 +57,7 @@ SDK_XPIDLSRCS = \ XPIDLSRCS = \ nsIBrowserDOMWindow.idl \ - nsIDOMClientInformation.idl \ + nsIDOMClientInformation.idl \ nsIDOMConstructor.idl \ nsIDOMCRMFObject.idl \ nsIDOMCrypto.idl \ @@ -74,10 +74,11 @@ XPIDLSRCS = \ nsIDOMScreen.idl \ nsIDOMWindowInternal.idl \ nsIDOMJSWindow.idl \ + nsIDOMModalContentWindow.idl \ nsIDOMChromeWindow.idl \ nsIDOMNSFeatureFactory.idl \ - nsIDOMTextRectangle.idl \ - nsIDOMTextRectangleList.idl \ + nsIDOMTextRectangle.idl \ + nsIDOMTextRectangleList.idl \ $(NULL) include $(topsrcdir)/config/rules.mk diff --git a/dom/public/idl/base/nsIDOMModalContentWindow.idl b/dom/public/idl/base/nsIDOMModalContentWindow.idl new file mode 100644 index 00000000000..dc36027579c --- /dev/null +++ b/dom/public/idl/base/nsIDOMModalContentWindow.idl @@ -0,0 +1,58 @@ +/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Mozilla. + * Portions created by the Initial Developer are Copyright (C) 2007 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Johnny Stenback (original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nsISupports.idl" + +interface nsIVariant; +interface nsIArray; + +[scriptable, uuid(51aebd45-b979-4ec6-9d11-3a3fd3d5d59e)] +interface nsIDOMModalContentWindow : nsISupports +{ + /** + * Readonly attribute containing an array of arguments that was + * passed to the code that opened this modal content window. + */ + readonly attribute nsIArray dialogArguments; + + /** + * The return value that will be returned to the function that + * opened the modal content window. + */ + attribute nsIVariant returnValue; +}; diff --git a/dom/public/idl/base/nsIDOMWindowInternal.idl b/dom/public/idl/base/nsIDOMWindowInternal.idl index 78de77f72e9..0b1e188895f 100644 --- a/dom/public/idl/base/nsIDOMWindowInternal.idl +++ b/dom/public/idl/base/nsIDOMWindowInternal.idl @@ -42,8 +42,9 @@ interface nsIPrompt; interface nsIControllers; interface nsIDOMLocation; +interface nsIVariant; -[scriptable, uuid(f914492c-0138-4123-a634-6ef8e3f126f8)] +[scriptable, uuid(0d12a345-3fe2-491e-af0d-bcfd5c4baa03)] interface nsIDOMWindowInternal : nsIDOMWindow2 { readonly attribute nsIDOMWindowInternal window; @@ -195,4 +196,8 @@ interface nsIDOMWindowInternal : nsIDOMWindow2 DOMString btoa(in DOMString aBase64Data); readonly attribute nsIDOMElement frameElement; + + nsIVariant showModalDialog(in DOMString aURI, + [optional] in nsIVariant aArgs, + [optional] in DOMString aOptions); }; diff --git a/dom/public/nsDOMClassInfoID.h b/dom/public/nsDOMClassInfoID.h index 96d68a83c6b..b9899612392 100644 --- a/dom/public/nsDOMClassInfoID.h +++ b/dom/public/nsDOMClassInfoID.h @@ -411,6 +411,9 @@ enum nsDOMClassInfoID { eDOMClassInfo_File_id, eDOMClassInfo_FileException_id, + // DOM modal content window class, almost identical to Window + eDOMClassInfo_ModalContentWindow_id, + // This one better be the last one in this list eDOMClassInfoIDCount }; diff --git a/dom/public/nsIDOMScriptObjectFactory.h b/dom/public/nsIDOMScriptObjectFactory.h index 5492276e63f..ae31d0400c0 100644 --- a/dom/public/nsIDOMScriptObjectFactory.h +++ b/dom/public/nsIDOMScriptObjectFactory.h @@ -43,9 +43,8 @@ #include "nsStringGlue.h" #define NS_IDOM_SCRIPT_OBJECT_FACTORY_IID \ - { /* {38EC7717-6CBE-44a8-B2BB-53F2BA998B31} */ \ - 0x38ec7717, 0x6cbe, 0x44a8, \ - { 0xb2, 0xbb, 0x53, 0xf2, 0xba, 0x99, 0x8b, 0x31 } } +{ 0xd5a4f935, 0xe428, 0x47ec, \ + { 0x8f, 0x36, 0x44, 0x23, 0xfa, 0xa2, 0x21, 0x90 } } class nsIScriptContext; class nsIScriptGlobalObject; @@ -74,6 +73,7 @@ public: PRUint32 *aScriptTypeID) = 0; NS_IMETHOD NewScriptGlobalObject(PRBool aIsChrome, + PRBool aIsModalContentWindow, nsIScriptGlobalObject **aGlobal) = 0; NS_IMETHOD_(nsISupports *) GetClassInfoInstance(nsDOMClassInfoID aID) = 0; diff --git a/dom/src/base/nsDOMClassInfo.cpp b/dom/src/base/nsDOMClassInfo.cpp index 2cbf92ee66e..73a469aa717 100644 --- a/dom/src/base/nsDOMClassInfo.cpp +++ b/dom/src/base/nsDOMClassInfo.cpp @@ -1214,6 +1214,9 @@ static nsDOMClassInfoData sClassInfoData[] = { NS_DEFINE_CLASSINFO_DATA(FileException, nsDOMGenericSH, DOM_DEFAULT_SCRIPTABLE_FLAGS) + NS_DEFINE_CLASSINFO_DATA(ModalContentWindow, nsWindowSH, + DEFAULT_SCRIPTABLE_FLAGS | + WINDOW_SCRIPTABLE_FLAGS) }; // Objects that shuld be constructable through |new Name();| @@ -3307,6 +3310,17 @@ nsDOMClassInfo::Init() DOM_CLASSINFO_MAP_ENTRY(nsIException) DOM_CLASSINFO_MAP_END + DOM_CLASSINFO_MAP_BEGIN(ModalContentWindow, nsIDOMWindow) + DOM_CLASSINFO_MAP_ENTRY(nsIDOMWindow) + DOM_CLASSINFO_MAP_ENTRY(nsIDOMJSWindow) + DOM_CLASSINFO_MAP_ENTRY(nsIDOMWindowInternal) + DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget) + DOM_CLASSINFO_MAP_ENTRY(nsIDOMViewCSS) + DOM_CLASSINFO_MAP_ENTRY(nsIDOMAbstractView) + DOM_CLASSINFO_MAP_ENTRY(nsIDOMStorageWindow) + DOM_CLASSINFO_MAP_ENTRY(nsIDOMModalContentWindow) + DOM_CLASSINFO_MAP_END + #ifdef NS_DEBUG { PRUint32 i = NS_ARRAY_LENGTH(sClassInfoData); diff --git a/dom/src/base/nsDOMScriptObjectFactory.cpp b/dom/src/base/nsDOMScriptObjectFactory.cpp index 47d7ac9d320..1114d3c6e33 100644 --- a/dom/src/base/nsDOMScriptObjectFactory.cpp +++ b/dom/src/base/nsDOMScriptObjectFactory.cpp @@ -212,9 +212,10 @@ nsDOMScriptObjectFactory::GetIDForScriptType(const nsAString &aLanguageName, NS_IMETHODIMP nsDOMScriptObjectFactory::NewScriptGlobalObject(PRBool aIsChrome, + PRBool aIsModalContentWindow, nsIScriptGlobalObject **aGlobal) { - return NS_NewScriptGlobalObject(aIsChrome, aGlobal); + return NS_NewScriptGlobalObject(aIsChrome, aIsModalContentWindow, aGlobal); } NS_IMETHODIMP_(nsISupports *) diff --git a/dom/src/base/nsDOMScriptObjectFactory.h b/dom/src/base/nsDOMScriptObjectFactory.h index cefe1121e32..21c92423c7f 100644 --- a/dom/src/base/nsDOMScriptObjectFactory.h +++ b/dom/src/base/nsDOMScriptObjectFactory.h @@ -82,6 +82,7 @@ public: PRUint32 *aLanguageID); NS_IMETHOD NewScriptGlobalObject(PRBool aIsChrome, + PRBool aIsModalContentWindow, nsIScriptGlobalObject **aGlobal); NS_IMETHOD_(nsISupports *) GetClassInfoInstance(nsDOMClassInfoID aID); diff --git a/dom/src/base/nsGlobalWindow.cpp b/dom/src/base/nsGlobalWindow.cpp index 193f021191e..2649d229296 100644 --- a/dom/src/base/nsGlobalWindow.cpp +++ b/dom/src/base/nsGlobalWindow.cpp @@ -260,6 +260,18 @@ PRInt32 gTimeoutCnt = 0; } \ PR_END_MACRO +#define FORWARD_TO_OUTER_MODAL_CONTENT_WINDOW(method, args, err_rval) \ + PR_BEGIN_MACRO \ + if (IsInnerWindow()) { \ + nsGlobalWindow *outer = GetOuterWindowInternal(); \ + if (!outer) { \ + NS_WARNING("No outer window available!"); \ + return err_rval; \ + } \ + return ((nsGlobalModalWindow *)outer)->method args; \ + } \ + PR_END_MACRO + #define FORWARD_TO_INNER(method, args, err_rval) \ PR_BEGIN_MACRO \ if (IsOuterWindow()) { \ @@ -271,6 +283,17 @@ PRInt32 gTimeoutCnt = 0; } \ PR_END_MACRO +#define FORWARD_TO_INNER_MODAL_CONTENT_WINDOW(method, args, err_rval) \ + PR_BEGIN_MACRO \ + if (IsOuterWindow()) { \ + if (!mInnerWindow) { \ + NS_WARNING("No inner window available!"); \ + return err_rval; \ + } \ + return ((nsGlobalModalWindow*)GetCurrentInnerWindowInternal())->method args; \ + } \ + PR_END_MACRO + #define FORWARD_TO_INNER_VOID(method, args) \ PR_BEGIN_MACRO \ if (IsOuterWindow()) { \ @@ -1426,7 +1449,11 @@ nsGlobalWindow::SetNewDocument(nsIDocument* aDocument, isChrome = PR_TRUE; } else { - newInnerWindow = new nsGlobalWindow(this); + if (mIsModalContentWindow) { + newInnerWindow = new nsGlobalModalWindow(this); + } else { + newInnerWindow = new nsGlobalWindow(this); + } } mLocation = nsnull; @@ -2053,7 +2080,11 @@ nsGlobalWindow::SetNewArguments(nsIArray *aArguments) void *glob = currentInner->GetScriptGlobal(langID); nsIScriptContext *ctx = GetScriptContext(langID); if (glob && ctx) { - rv = ctx->SetProperty(glob, "arguments", aArguments); + if (mIsModalContentWindow) { + rv = ctx->SetProperty(glob, "dialogArguments", aArguments); + } else { + rv = ctx->SetProperty(glob, "arguments", aArguments); + } NS_ENSURE_SUCCESS(rv, rv); } } @@ -5079,6 +5110,163 @@ nsGlobalWindow::GetFrameElement(nsIDOMElement** aFrameElement) return NS_OK; } +void +ConvertDialogOptions(const nsAString& aOptions, nsAString& aResult) +{ + nsAString::const_iterator end; + aOptions.EndReading(end); + + nsAString::const_iterator iter; + aOptions.BeginReading(iter); + + while (iter != end) { + // Skip whitespace. + while (nsCRT::IsAsciiSpace(*iter) && iter != end) { + ++iter; + } + + nsAString::const_iterator name_start = iter; + + // Skip characters until we find whitespace, ';', ':', or '=' + while (iter != end && !nsCRT::IsAsciiSpace(*iter) && + *iter != ';' && + *iter != ':' && + *iter != '=') { + ++iter; + } + + nsAString::const_iterator name_end = iter; + + // Skip whitespace. + while (nsCRT::IsAsciiSpace(*iter) && iter != end) { + ++iter; + } + + if (*iter == ';') { + // No value found, skip the ';' and keep going. + ++iter; + + continue; + } + + nsAString::const_iterator value_start = iter; + nsAString::const_iterator value_end = iter; + + if (*iter == ':' || *iter == '=') { + // We found name followed by ':' or '='. Look for a value. + + iter++; // Skip the ':' or '=' + + // Skip whitespace. + while (nsCRT::IsAsciiSpace(*iter) && iter != end) { + ++iter; + } + + value_start = iter; + + // Skip until we find whitespace, or ';'. + while (iter != end && !nsCRT::IsAsciiSpace(*iter) && + *iter != ';') { + ++iter; + } + + value_end = iter; + + // Skip whitespace. + while (nsCRT::IsAsciiSpace(*iter) && iter != end) { + ++iter; + } + } + + const nsDependentSubstring& name = Substring(name_start, name_end); + const nsDependentSubstring& value = Substring(value_start, value_end); + + if (name.LowerCaseEqualsLiteral("center")) { + if (value.LowerCaseEqualsLiteral("on") || + value.LowerCaseEqualsLiteral("yes") || + value.LowerCaseEqualsLiteral("1")) { + aResult.AppendLiteral(",centerscreen=1"); + } + } else if (name.LowerCaseEqualsLiteral("dialogwidth")) { + if (!value.IsEmpty()) { + aResult.AppendLiteral(",width="); + aResult.Append(value); + } + } else if (name.LowerCaseEqualsLiteral("dialogheight")) { + if (!value.IsEmpty()) { + aResult.AppendLiteral(",height="); + aResult.Append(value); + } + } else if (name.LowerCaseEqualsLiteral("dialogtop")) { + if (!value.IsEmpty()) { + aResult.AppendLiteral(",top="); + aResult.Append(value); + } + } else if (name.LowerCaseEqualsLiteral("dialogleft")) { + if (!value.IsEmpty()) { + aResult.AppendLiteral(",left="); + aResult.Append(value); + } + } else if (name.LowerCaseEqualsLiteral("resizable")) { + if (value.LowerCaseEqualsLiteral("on") || + value.LowerCaseEqualsLiteral("yes") || + value.LowerCaseEqualsLiteral("1")) { + aResult.AppendLiteral(",resizable=1"); + } + } else if (name.LowerCaseEqualsLiteral("scroll")) { + if (value.LowerCaseEqualsLiteral("off") || + value.LowerCaseEqualsLiteral("no") || + value.LowerCaseEqualsLiteral("0")) { + aResult.AppendLiteral(",scrollbars=0"); + } + } + + if (iter == end) { + break; + } + + iter++; + } +} + +NS_IMETHODIMP +nsGlobalWindow::ShowModalDialog(const nsAString& aURI, nsIVariant *aArgs, + const nsAString& aOptions, + nsIVariant **aRetVal) +{ + nsCOMPtr dlgWin; + + nsAutoString options(NS_LITERAL_STRING("modal=1,status=1")); + nsAutoString dialogOptions(aOptions); + + ConvertDialogOptions(dialogOptions, options); + + options.AppendLiteral(",scrollbars=1,centerscreen=1,resizable=0"); + + + nsresult rv = OpenInternal(aURI, EmptyString(), options, + PR_FALSE, // aDialog + PR_TRUE, // aCalledNoScript + PR_FALSE, // aDoJSFixups + nsnull, aArgs, // args + GetPrincipal(), // aCalleePrincipal + nsnull, // aJSCallerContext + getter_AddRefs(dlgWin)); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr win(do_QueryInterface(dlgWin)); + + nsPIDOMWindow *inner = win->GetCurrentInnerWindow(); + + nsCOMPtr dlgInner(do_QueryInterface(inner)); + + if (dlgInner) { + dlgInner->GetReturnValue(aRetVal); + } + + return NS_OK; +} + NS_IMETHODIMP nsGlobalWindow::UpdateCommands(const nsAString& anAction) { @@ -7651,6 +7839,8 @@ nsGlobalWindow::SetScriptTypeID(PRUint32 aScriptType) return NS_ERROR_NOT_IMPLEMENTED; } +// nsGlobalChromeWindow implementation + NS_IMPL_CYCLE_COLLECTION_CLASS(nsGlobalChromeWindow) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsGlobalChromeWindow, nsGlobalWindow) @@ -7666,8 +7856,6 @@ NS_INTERFACE_MAP_END_INHERITING(nsGlobalWindow) NS_IMPL_ADDREF_INHERITED(nsGlobalChromeWindow, nsGlobalWindow) NS_IMPL_RELEASE_INHERITED(nsGlobalChromeWindow, nsGlobalWindow) -// nsGlobalChromeWindow implementation - static void TitleConsoleWarning() { nsCOMPtr console(do_GetService("@mozilla.org/consoleservice;1")); @@ -7906,12 +8094,68 @@ nsGlobalChromeWindow::SetBrowserDOMWindow(nsIBrowserDOMWindow *aBrowserWindow) return NS_OK; } +// nsGlobalModalWindow implementation + +// QueryInterface implementation for nsGlobalModalWindow +NS_IMPL_CYCLE_COLLECTION_CLASS(nsGlobalModalWindow) +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsGlobalModalWindow, + nsGlobalWindow) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mArguments) +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END + +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsGlobalModalWindow) + NS_INTERFACE_MAP_ENTRY(nsIDOMModalContentWindow) + NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(ModalContentWindow) +NS_INTERFACE_MAP_END_INHERITING(nsGlobalWindow) + +NS_IMPL_ADDREF_INHERITED(nsGlobalModalWindow, nsGlobalWindow) +NS_IMPL_RELEASE_INHERITED(nsGlobalModalWindow, nsGlobalWindow) + + +NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsGlobalModalWindow, + nsGlobalWindow) + NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mReturnValue) +NS_IMPL_CYCLE_COLLECTION_UNLINK_END + + +NS_IMETHODIMP +nsGlobalModalWindow::GetDialogArguments(nsIArray **aArguments) +{ + FORWARD_TO_INNER_MODAL_CONTENT_WINDOW(GetDialogArguments, (aArguments), + NS_ERROR_NOT_INITIALIZED); + + *aArguments = mArguments; + + return NS_OK; +} + +NS_IMETHODIMP +nsGlobalModalWindow::GetReturnValue(nsIVariant **aRetVal) +{ + FORWARD_TO_OUTER_MODAL_CONTENT_WINDOW(GetReturnValue, (aRetVal), NS_OK); + + NS_IF_ADDREF(*aRetVal = mReturnValue); + + return NS_OK; +} + +NS_IMETHODIMP +nsGlobalModalWindow::SetReturnValue(nsIVariant *aRetVal) +{ + FORWARD_TO_OUTER_MODAL_CONTENT_WINDOW(SetReturnValue, (aRetVal), NS_OK); + + mReturnValue = aRetVal; + + return NS_OK; +} + //***************************************************************************** // nsGlobalWindow: Creator Function (This should go away) //***************************************************************************** nsresult -NS_NewScriptGlobalObject(PRBool aIsChrome, nsIScriptGlobalObject **aResult) +NS_NewScriptGlobalObject(PRBool aIsChrome, PRBool aIsModalContentWindow, + nsIScriptGlobalObject **aResult) { *aResult = nsnull; @@ -7919,14 +8163,17 @@ NS_NewScriptGlobalObject(PRBool aIsChrome, nsIScriptGlobalObject **aResult) if (aIsChrome) { global = new nsGlobalChromeWindow(nsnull); + } else if (aIsModalContentWindow) { + global = new nsGlobalModalWindow(nsnull); } else { global = new nsGlobalWindow(nsnull); } NS_ENSURE_TRUE(global, NS_ERROR_OUT_OF_MEMORY); - return CallQueryInterface(static_cast(global), - aResult); + NS_ADDREF(*aResult = global); + + return NS_OK; } //***************************************************************************** diff --git a/dom/src/base/nsGlobalWindow.h b/dom/src/base/nsGlobalWindow.h index 90f73824a3d..cf30dae7189 100644 --- a/dom/src/base/nsGlobalWindow.h +++ b/dom/src/base/nsGlobalWindow.h @@ -78,6 +78,7 @@ #include "nsITimer.h" #include "nsIWebBrowserChrome.h" #include "nsPIDOMWindow.h" +#include "nsIDOMModalContentWindow.h" #include "nsIScriptSecurityManager.h" #include "nsIEventListenerManager.h" #include "nsIDOMDocument.h" @@ -96,6 +97,7 @@ #include "nsIDOMStorageWindow.h" #include "nsIDOMOfflineResourceList.h" #include "nsPIDOMEventTarget.h" +#include "nsIArray.h" #define DEFAULT_HOME_PAGE "www.mozilla.org" #define PREF_BROWSER_STARTUP_HOMEPAGE "browser.startup.homepage" @@ -106,7 +108,6 @@ class nsIContent; class nsPresContext; class nsIDOMEvent; class nsIScrollableView; -class nsIArray; class nsBarProp; class nsLocation; @@ -729,6 +730,31 @@ protected: nsCOMPtr mBrowserDOMWindow; }; +/* + * nsGlobalModalWindow inherits from nsGlobalWindow. It is the global + * object created for a modal content windows only (i.e. not modal + * chrome dialogs). + */ +class nsGlobalModalWindow : public nsGlobalWindow, + public nsIDOMModalContentWindow +{ +public: + nsGlobalModalWindow(nsGlobalWindow *aOuterWindow) + : nsGlobalWindow(aOuterWindow) + { + mIsModalContentWindow = PR_TRUE; + } + + NS_DECL_ISUPPORTS_INHERITED + NS_DECL_NSIDOMMODALCONTENTWINDOW + + NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsGlobalModalWindow, nsGlobalWindow) + +protected: + nsCOMPtr mReturnValue; +}; + + //***************************************************************************** // nsNavigator: Script "navigator" object //***************************************************************************** @@ -812,7 +838,8 @@ protected: }; /* factory function */ -nsresult NS_NewScriptGlobalObject(PRBool aIsChrome, - nsIScriptGlobalObject **aResult); +nsresult +NS_NewScriptGlobalObject(PRBool aIsChrome, PRBool aIsModalContentWindow, + nsIScriptGlobalObject **aResult); #endif /* nsGlobalWindow_h___ */ diff --git a/dom/src/base/nsJSEnvironment.cpp b/dom/src/base/nsJSEnvironment.cpp index 2b9857a1b36..f0cb3ffc865 100644 --- a/dom/src/base/nsJSEnvironment.cpp +++ b/dom/src/base/nsJSEnvironment.cpp @@ -2364,18 +2364,32 @@ nsJSContext::SetProperty(void *aTarget, const char *aPropName, nsISupports *aArg void *mark; JSAutoRequest ar(mContext); - + nsresult rv; rv = ConvertSupportsTojsvals(aArgs, GetNativeGlobal(), &argc, reinterpret_cast(&argv), &mark); NS_ENSURE_SUCCESS(rv, rv); AutoFreeJSStack stackGuard(mContext, mark); // ensure always freed. - // got the array, now attach it. - JSObject *args = ::JS_NewArrayObject(mContext, argc, argv); - jsval vargs = OBJECT_TO_JSVAL(args); + jsval vargs; - rv = ::JS_SetProperty(mContext, reinterpret_cast(aTarget), aPropName, &vargs) ? + // got the arguments, now attach them. + + // window.dialogArguments is supposed to be an array if a JS array + // was passed to showModalDialog(), deal with that here. + if (strcmp(aPropName, "dialogArguments") == 0 && argc == 1 && + JSVAL_IS_OBJECT(argv[0]) && + ::JS_IsArrayObject(mContext, JSVAL_TO_OBJECT(argv[0]))) { + vargs = argv[0]; + } else { + JSObject *args = ::JS_NewArrayObject(mContext, argc, argv); + vargs = OBJECT_TO_JSVAL(args); + } + + // Make sure to use JS_DefineProperty here so that we can override + // readonly XPConnect properties here as well (read dialogArguments). + rv = ::JS_DefineProperty(mContext, reinterpret_cast(aTarget), + aPropName, vargs, nsnull, nsnull, 0) ? NS_OK : NS_ERROR_FAILURE; // free 'args'??? @@ -2446,7 +2460,7 @@ nsJSContext::ConvertSupportsTojsvals(nsISupports *aArgs, // as we have code for handling all, we may as well use it. rv = AddSupportsPrimitiveTojsvals(arg, thisval); if (rv == NS_ERROR_NO_INTERFACE) { - // something else - probably an event object or similar - just + // something else - probably an event object or similar - // just wrap it. #ifdef NS_DEBUG // but first, check its not another nsISupportsPrimitive, as diff --git a/embedding/components/windowwatcher/src/nsWindowWatcher.cpp b/embedding/components/windowwatcher/src/nsWindowWatcher.cpp index e9e61055945..1da6484a4cf 100644 --- a/embedding/components/windowwatcher/src/nsWindowWatcher.cpp +++ b/embedding/components/windowwatcher/src/nsWindowWatcher.cpp @@ -499,7 +499,8 @@ nsWindowWatcher::OpenWindowJSInternal(nsIDOMWindow *aParent, windowIsNew = PR_FALSE, windowNeedsName = PR_FALSE, windowIsModal = PR_FALSE, - uriToLoadIsChrome = PR_FALSE; + uriToLoadIsChrome = PR_FALSE, + windowIsModalContentDialog = PR_FALSE; PRUint32 chromeFlags; nsAutoString name; // string version of aName nsCAutoString features; // string version of aFeatures @@ -545,6 +546,14 @@ nsWindowWatcher::OpenWindowJSInternal(nsIDOMWindow *aParent, nsCOMPtr chromeParent(do_QueryInterface(aParent)); + // If we're not called through our JS version of the API, and we got + // a modal option, treat the window we're opening as a modal content + // window. + if (!aCalledFromJS && argv && + WinHasOption(features.get(), "modal", 0, nsnull)) { + windowIsModalContentDialog = PR_TRUE; + } + // Make sure we call CalculateChromeFlags() *before* we push the // callee context onto the context stack so that // CalculateChromeFlags() sees the actual caller when doing it's @@ -719,7 +728,7 @@ nsWindowWatcher::OpenWindowJSInternal(nsIDOMWindow *aParent, } } - if (aDialog && argv) { + if ((aDialog || windowIsModalContentDialog) && argv) { // Set the args on the new object. nsCOMPtr scriptGlobal(do_QueryInterface(*_retval)); NS_ENSURE_TRUE(scriptGlobal, NS_ERROR_UNEXPECTED); @@ -899,7 +908,7 @@ nsWindowWatcher::OpenWindowJSInternal(nsIDOMWindow *aParent, if (isNewToplevelWindow) SizeOpenedDocShellItem(newDocShellItem, aParent, sizeSpec); - if (windowIsModal) { + if (windowIsModal || windowIsModalContentDialog) { nsCOMPtr newTreeOwner; newDocShellItem->GetTreeOwner(getter_AddRefs(newTreeOwner)); nsCOMPtr newChrome(do_GetInterface(newTreeOwner)); @@ -1358,6 +1367,7 @@ void nsWindowWatcher::CheckWindowName(nsString& aName) * @param aDialog affects the assumptions made about unnamed features * @return the chrome bitmask */ +// static PRUint32 nsWindowWatcher::CalculateChromeFlags(const char *aFeatures, PRBool aFeaturesSpecified, PRBool aDialog, @@ -1366,9 +1376,9 @@ PRUint32 nsWindowWatcher::CalculateChromeFlags(const char *aFeatures, { if(!aFeaturesSpecified || !aFeatures) { if(aDialog) - return nsIWebBrowserChrome::CHROME_ALL | - nsIWebBrowserChrome::CHROME_OPENAS_DIALOG | - nsIWebBrowserChrome::CHROME_OPENAS_CHROME; + return nsIWebBrowserChrome::CHROME_ALL | + nsIWebBrowserChrome::CHROME_OPENAS_DIALOG | + nsIWebBrowserChrome::CHROME_OPENAS_CHROME; else return nsIWebBrowserChrome::CHROME_ALL; } @@ -1504,7 +1514,7 @@ PRUint32 nsWindowWatcher::CalculateChromeFlags(const char *aFeatures, prevents untrusted script from opening modal windows in general while still allowing alerts and the like. */ if (!aChromeURL) - chromeFlags &= ~(nsIWebBrowserChrome::CHROME_MODAL | nsIWebBrowserChrome::CHROME_OPENAS_CHROME); + chromeFlags &= ~nsIWebBrowserChrome::CHROME_OPENAS_CHROME; } if (!(chromeFlags & nsIWebBrowserChrome::CHROME_OPENAS_CHROME)) { @@ -1515,6 +1525,7 @@ PRUint32 nsWindowWatcher::CalculateChromeFlags(const char *aFeatures, return chromeFlags; } +// static PRInt32 nsWindowWatcher::WinHasOption(const char *aOptions, const char *aName, PRInt32 aDefault, PRBool *aPresenceFlag) @@ -1735,6 +1746,7 @@ nsWindowWatcher::ReadyOpenedDocShellItem(nsIDocShellTreeItem *aOpenedItem, return rv; } +// static void nsWindowWatcher::CalcSizeSpec(const char* aFeatures, SizeSpec& aResult) { diff --git a/xpfe/appshell/src/nsXULWindow.cpp b/xpfe/appshell/src/nsXULWindow.cpp index 43c3a816176..8458abc38f2 100644 --- a/xpfe/appshell/src/nsXULWindow.cpp +++ b/xpfe/appshell/src/nsXULWindow.cpp @@ -65,7 +65,7 @@ #include "nsIPrivateDOMEvent.h" #include "nsIDOMEventTarget.h" #include "nsIDOMXULElement.h" -#include "nsIDOMWindowInternal.h" +#include "nsPIDOMWindow.h" #include "nsIDOMScreen.h" #include "nsIEmbeddingSiteWindow.h" #include "nsIEmbeddingSiteWindow2.h" @@ -1798,6 +1798,18 @@ NS_IMETHODIMP nsXULWindow::CreateNewContentWindow(PRInt32 aChromeFlags, (static_cast (newWindow)); + nsCOMPtr newDocShell; + xulWin->GetDocShell(getter_AddRefs(newDocShell)); + + // If we're opening a non-chrome modal window (i.e. a modal content + // window), tell the DOM window that it is modal. + nsCOMPtr domWin(do_GetInterface(newDocShell)); + + if (domWin && (aChromeFlags & nsIWebBrowserChrome::CHROME_MODAL) && + !(aChromeFlags & nsIWebBrowserChrome::CHROME_OPENAS_CHROME)) { + domWin->SetModalContentWindow(PR_TRUE); + } + xulWin->LockUntilChromeLoad(); // Push nsnull onto the JSContext stack before we dispatch a native event.