From 32102460270093df5da02cd9db845938733006f1 Mon Sep 17 00:00:00 2001 From: William Chen Date: Mon, 18 Mar 2013 06:24:54 -0700 Subject: [PATCH] Bug 782211 - Part 8: Updated existing XUL alerts to implement the Notification API. r=enn --- toolkit/components/alerts/Makefile.in | 1 + toolkit/components/alerts/nsAlertsService.cpp | 80 +-------- toolkit/components/alerts/nsAlertsService.h | 2 + toolkit/components/alerts/nsXULAlerts.cpp | 159 ++++++++++++++++++ toolkit/components/alerts/nsXULAlerts.h | 64 +++++++ .../alerts/resources/content/alert.js | 138 ++++++++++++--- .../alerts/resources/content/alert.xul | 33 ++-- toolkit/locales/en-US/chrome/alerts/alert.dtd | 5 + toolkit/locales/jar.mn | 1 + toolkit/themes/linux/global/alerts/alert.css | 17 ++ .../linux/global/alerts/notification-48.png | Bin 0 -> 2517 bytes toolkit/themes/linux/global/jar.mn | 1 + toolkit/themes/osx/global/alerts/alert.css | 100 +++++++++++ .../osx/global/alerts/notification-48.png | Bin 0 -> 2517 bytes toolkit/themes/osx/global/jar.mn | 2 + .../themes/windows/global/alerts/alert.css | 26 +++ .../windows/global/alerts/notification-48.png | Bin 0 -> 2517 bytes toolkit/themes/windows/global/jar.mn | 2 + widget/cocoa/nsLookAndFeel.mm | 3 + widget/gtk2/nsLookAndFeel.cpp | 3 + 20 files changed, 529 insertions(+), 108 deletions(-) create mode 100644 toolkit/components/alerts/nsXULAlerts.cpp create mode 100644 toolkit/components/alerts/nsXULAlerts.h create mode 100644 toolkit/locales/en-US/chrome/alerts/alert.dtd create mode 100644 toolkit/themes/linux/global/alerts/notification-48.png create mode 100644 toolkit/themes/osx/global/alerts/alert.css create mode 100644 toolkit/themes/osx/global/alerts/notification-48.png create mode 100644 toolkit/themes/windows/global/alerts/notification-48.png diff --git a/toolkit/components/alerts/Makefile.in b/toolkit/components/alerts/Makefile.in index ac8610bc1f4..71de56eb577 100644 --- a/toolkit/components/alerts/Makefile.in +++ b/toolkit/components/alerts/Makefile.in @@ -15,6 +15,7 @@ FORCE_STATIC_LIB = 1 LIBXUL_LIBRARY = 1 CPPSRCS = \ nsAlertsService.cpp \ + nsXULAlerts.cpp \ $(NULL) LOCAL_INCLUDES += -I$(topsrcdir)/toolkit/components/build/ diff --git a/toolkit/components/alerts/nsAlertsService.cpp b/toolkit/components/alerts/nsAlertsService.cpp index 810bcc66d46..e8e4c266988 100644 --- a/toolkit/components/alerts/nsAlertsService.cpp +++ b/toolkit/components/alerts/nsAlertsService.cpp @@ -12,17 +12,11 @@ #include "AndroidBridge.h" #else -#include "nsISupportsArray.h" #include "nsXPCOM.h" -#include "nsISupportsPrimitives.h" #include "nsIServiceManager.h" #include "nsIDOMWindow.h" -#include "nsIWindowWatcher.h" #include "nsPromiseFlatString.h" #include "nsToolkitCompsCID.h" -#include "mozilla/LookAndFeel.h" - -#define ALERT_CHROME_URL "chrome://global/content/alerts/alert.xul" #endif // !MOZ_WIDGET_ANDROID @@ -118,74 +112,10 @@ NS_IMETHODIMP nsAlertsService::ShowAlertNotification(const nsAString & aImageUrl return NS_ERROR_NOT_IMPLEMENTED; #endif - nsCOMPtr wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID)); - nsCOMPtr newWindow; - - nsCOMPtr argsArray; - rv = NS_NewISupportsArray(getter_AddRefs(argsArray)); - NS_ENSURE_SUCCESS(rv, rv); - - // create scriptable versions of our strings that we can store in our nsISupportsArray.... - nsCOMPtr scriptableImageUrl (do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID)); - NS_ENSURE_TRUE(scriptableImageUrl, NS_ERROR_FAILURE); - - scriptableImageUrl->SetData(aImageUrl); - rv = argsArray->AppendElement(scriptableImageUrl); - NS_ENSURE_SUCCESS(rv, rv); - - nsCOMPtr scriptableAlertTitle (do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID)); - NS_ENSURE_TRUE(scriptableAlertTitle, NS_ERROR_FAILURE); - - scriptableAlertTitle->SetData(aAlertTitle); - rv = argsArray->AppendElement(scriptableAlertTitle); - NS_ENSURE_SUCCESS(rv, rv); - - nsCOMPtr scriptableAlertText (do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID)); - NS_ENSURE_TRUE(scriptableAlertText, NS_ERROR_FAILURE); - - scriptableAlertText->SetData(aAlertText); - rv = argsArray->AppendElement(scriptableAlertText); - NS_ENSURE_SUCCESS(rv, rv); - - nsCOMPtr scriptableIsClickable (do_CreateInstance(NS_SUPPORTS_PRBOOL_CONTRACTID)); - NS_ENSURE_TRUE(scriptableIsClickable, NS_ERROR_FAILURE); - - scriptableIsClickable->SetData(aAlertTextClickable); - rv = argsArray->AppendElement(scriptableIsClickable); - NS_ENSURE_SUCCESS(rv, rv); - - nsCOMPtr scriptableAlertCookie (do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID)); - NS_ENSURE_TRUE(scriptableAlertCookie, NS_ERROR_FAILURE); - - scriptableAlertCookie->SetData(aAlertCookie); - rv = argsArray->AppendElement(scriptableAlertCookie); - NS_ENSURE_SUCCESS(rv, rv); - - nsCOMPtr scriptableOrigin (do_CreateInstance(NS_SUPPORTS_PRINT32_CONTRACTID)); - NS_ENSURE_TRUE(scriptableOrigin, NS_ERROR_FAILURE); - - int32_t origin = - LookAndFeel::GetInt(LookAndFeel::eIntID_AlertNotificationOrigin); - scriptableOrigin->SetData(origin); - - rv = argsArray->AppendElement(scriptableOrigin); - NS_ENSURE_SUCCESS(rv, rv); - - if (aAlertListener) - { - nsCOMPtr ifptr = do_CreateInstance(NS_SUPPORTS_INTERFACE_POINTER_CONTRACTID, &rv); - NS_ENSURE_SUCCESS(rv, rv); - - nsCOMPtr iSupports (do_QueryInterface(aAlertListener)); - ifptr->SetData(iSupports); - ifptr->SetDataIID(&NS_GET_IID(nsIObserver)); - rv = argsArray->AppendElement(ifptr); - NS_ENSURE_SUCCESS(rv, rv); - } - - rv = wwatch->OpenWindow(0, ALERT_CHROME_URL, "_blank", - "chrome,dialog=yes,titlebar=no,popup=yes", argsArray, - getter_AddRefs(newWindow)); + // Use XUL notifications as a fallback if above methods have failed. + rv = mXULAlerts.ShowAlertNotification(aImageUrl, aAlertTitle, aAlertText, aAlertTextClickable, + aAlertCookie, aAlertListener, aAlertName, + aBidi, aLang); return rv; #endif // !MOZ_WIDGET_ANDROID } @@ -214,7 +144,7 @@ NS_IMETHODIMP nsAlertsService::CloseAlert(const nsAString& aAlertName) NS_ENSURE_SUCCESS(rv, rv); } - return NS_ERROR_NOT_IMPLEMENTED; + return mXULAlerts.CloseAlert(aAlertName); #endif // !MOZ_WIDGET_ANDROID } diff --git a/toolkit/components/alerts/nsAlertsService.h b/toolkit/components/alerts/nsAlertsService.h index 7dbd966ff84..c0f228417e5 100644 --- a/toolkit/components/alerts/nsAlertsService.h +++ b/toolkit/components/alerts/nsAlertsService.h @@ -8,6 +8,7 @@ #include "nsIAlertsService.h" #include "nsCOMPtr.h" +#include "nsXULAlerts.h" #ifdef XP_WIN typedef enum tagMOZ_QUERY_USER_NOTIFICATION_STATE { @@ -39,6 +40,7 @@ public: protected: bool ShouldShowAlert(); + nsXULAlerts mXULAlerts; }; #endif /* nsAlertsService_h__ */ diff --git a/toolkit/components/alerts/nsXULAlerts.cpp b/toolkit/components/alerts/nsXULAlerts.cpp new file mode 100644 index 00000000000..e764720cf8e --- /dev/null +++ b/toolkit/components/alerts/nsXULAlerts.cpp @@ -0,0 +1,159 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode:nil; c-basic-offset: 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/. */ + +#include "nsXULAlerts.h" + +#include "nsAutoPtr.h" +#include "mozilla/LookAndFeel.h" +#include "nsIServiceManager.h" +#include "nsISupportsArray.h" +#include "nsISupportsPrimitives.h" +#include "nsIWindowWatcher.h" + +#define ALERT_CHROME_URL "chrome://global/content/alerts/alert.xul" + +NS_IMPL_ISUPPORTS1(nsXULAlertObserver, nsIObserver) + +NS_IMETHODIMP +nsXULAlertObserver::Observe(nsISupports* aSubject, const char* aTopic, + const PRUnichar* aData) +{ + if (!strcmp("alertfinished", aTopic)) { + nsIDOMWindow* currentAlert = mXULAlerts->mNamedWindows.GetWeak(mAlertName); + // The window in mNamedWindows might be a replacement, thus it should only + // be removed if it is the same window that is associated with this listener. + if (currentAlert == mAlertWindow) { + mXULAlerts->mNamedWindows.Remove(mAlertName); + } + } + + nsresult rv = NS_OK; + if (mObserver) { + rv = mObserver->Observe(aSubject, aTopic, aData); + } + return rv; +} + +nsresult +nsXULAlerts::ShowAlertNotification(const nsAString& aImageUrl, const nsAString& aAlertTitle, + const nsAString& aAlertText, bool aAlertTextClickable, + const nsAString& aAlertCookie, nsIObserver* aAlertListener, + const nsAString& aAlertName, const nsAString& aBidi, + const nsAString& aLang) +{ + nsCOMPtr wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID)); + nsCOMPtr newWindow; + + nsCOMPtr argsArray; + nsresult rv = NS_NewISupportsArray(getter_AddRefs(argsArray)); + NS_ENSURE_SUCCESS(rv, rv); + + // create scriptable versions of our strings that we can store in our nsISupportsArray.... + nsCOMPtr scriptableImageUrl (do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID)); + NS_ENSURE_TRUE(scriptableImageUrl, NS_ERROR_FAILURE); + + scriptableImageUrl->SetData(aImageUrl); + rv = argsArray->AppendElement(scriptableImageUrl); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr scriptableAlertTitle (do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID)); + NS_ENSURE_TRUE(scriptableAlertTitle, NS_ERROR_FAILURE); + + scriptableAlertTitle->SetData(aAlertTitle); + rv = argsArray->AppendElement(scriptableAlertTitle); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr scriptableAlertText (do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID)); + NS_ENSURE_TRUE(scriptableAlertText, NS_ERROR_FAILURE); + + scriptableAlertText->SetData(aAlertText); + rv = argsArray->AppendElement(scriptableAlertText); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr scriptableIsClickable (do_CreateInstance(NS_SUPPORTS_PRBOOL_CONTRACTID)); + NS_ENSURE_TRUE(scriptableIsClickable, NS_ERROR_FAILURE); + + scriptableIsClickable->SetData(aAlertTextClickable); + rv = argsArray->AppendElement(scriptableIsClickable); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr scriptableAlertCookie (do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID)); + NS_ENSURE_TRUE(scriptableAlertCookie, NS_ERROR_FAILURE); + + scriptableAlertCookie->SetData(aAlertCookie); + rv = argsArray->AppendElement(scriptableAlertCookie); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr scriptableOrigin (do_CreateInstance(NS_SUPPORTS_PRINT32_CONTRACTID)); + NS_ENSURE_TRUE(scriptableOrigin, NS_ERROR_FAILURE); + + int32_t origin = + LookAndFeel::GetInt(LookAndFeel::eIntID_AlertNotificationOrigin); + scriptableOrigin->SetData(origin); + + rv = argsArray->AppendElement(scriptableOrigin); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr scriptableBidi (do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID)); + NS_ENSURE_TRUE(scriptableBidi, NS_ERROR_FAILURE); + + scriptableBidi->SetData(aBidi); + rv = argsArray->AppendElement(scriptableBidi); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr scriptableLang (do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID)); + NS_ENSURE_TRUE(scriptableLang, NS_ERROR_FAILURE); + + scriptableLang->SetData(aLang); + rv = argsArray->AppendElement(scriptableLang); + NS_ENSURE_SUCCESS(rv, rv); + + // Alerts with the same name should replace the old alert in the same position. + // Provide the new alert window with a pointer to the replaced window so that + // it may take the same position. + nsCOMPtr replacedWindow = do_CreateInstance(NS_SUPPORTS_INTERFACE_POINTER_CONTRACTID, &rv); + NS_ENSURE_TRUE(replacedWindow, NS_ERROR_FAILURE); + nsIDOMWindow* previousAlert = mNamedWindows.GetWeak(aAlertName); + replacedWindow->SetData(previousAlert); + replacedWindow->SetDataIID(&NS_GET_IID(nsIDOMWindow)); + rv = argsArray->AppendElement(replacedWindow); + NS_ENSURE_SUCCESS(rv, rv); + + nsRefPtr alertObserver; + if (aAlertListener) + { + nsCOMPtr ifptr = do_CreateInstance(NS_SUPPORTS_INTERFACE_POINTER_CONTRACTID, &rv); + NS_ENSURE_SUCCESS(rv, rv); + + alertObserver = new nsXULAlertObserver(this, aAlertName, aAlertListener); + nsCOMPtr iSupports(do_QueryInterface(alertObserver)); + ifptr->SetData(iSupports); + ifptr->SetDataIID(&NS_GET_IID(nsIObserver)); + rv = argsArray->AppendElement(ifptr); + NS_ENSURE_SUCCESS(rv, rv); + } + + rv = wwatch->OpenWindow(0, ALERT_CHROME_URL, "_blank", + "chrome,dialog=yes,titlebar=no,popup=yes", argsArray, + getter_AddRefs(newWindow)); + + mNamedWindows.Put(aAlertName, newWindow); + if (alertObserver) { + alertObserver->SetAlertWindow(newWindow); + } + + return rv; +} + +nsresult +nsXULAlerts::CloseAlert(const nsAString& aAlertName) +{ + nsCOMPtr domWindow = mNamedWindows.Get(aAlertName); + if (domWindow) { + return domWindow->Close(); + } + return NS_OK; +} + diff --git a/toolkit/components/alerts/nsXULAlerts.h b/toolkit/components/alerts/nsXULAlerts.h new file mode 100644 index 00000000000..746826107b3 --- /dev/null +++ b/toolkit/components/alerts/nsXULAlerts.h @@ -0,0 +1,64 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode:nil; c-basic-offset: 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/. */ + +#ifndef nsXULAlerts_h__ +#define nsXULAlerts_h__ + +#include "nsHashKeys.h" +#include "nsInterfaceHashtable.h" + +#include "nsIDOMWindow.h" +#include "nsIObserver.h" + +using namespace mozilla; + +class nsXULAlerts { + friend class nsXULAlertObserver; +public: + nsXULAlerts() + { + mNamedWindows.Init(); + } + + virtual ~nsXULAlerts() {} + + nsresult ShowAlertNotification(const nsAString& aImageUrl, const nsAString& aAlertTitle, + const nsAString& aAlertText, bool aAlertTextClickable, + const nsAString& aAlertCookie, nsIObserver* aAlertListener, + const nsAString& aAlertName, const nsAString& aBidi, + const nsAString& aLang); + + nsresult CloseAlert(const nsAString& aAlertName); +protected: + nsInterfaceHashtable mNamedWindows; +}; + +/** + * This class wraps observers for alerts and watches + * for the "alertfinished" event in order to release + * the reference on the nsIDOMWindow of the XUL alert. + */ +class nsXULAlertObserver : public nsIObserver { +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIOBSERVER + + nsXULAlertObserver(nsXULAlerts* aXULAlerts, const nsAString& aAlertName, + nsIObserver* aObserver) + : mXULAlerts(aXULAlerts), mAlertName(aAlertName), + mObserver(aObserver) {} + + void SetAlertWindow(nsIDOMWindow* aWindow) { mAlertWindow = aWindow; } + + virtual ~nsXULAlertObserver() {} +protected: + nsXULAlerts* mXULAlerts; + nsString mAlertName; + nsCOMPtr mAlertWindow; + nsCOMPtr mObserver; +}; + +#endif /* nsXULAlerts_h__ */ + diff --git a/toolkit/components/alerts/resources/content/alert.js b/toolkit/components/alerts/resources/content/alert.js index d34b7d5341a..128f541ccd7 100644 --- a/toolkit/components/alerts/resources/content/alert.js +++ b/toolkit/components/alerts/resources/content/alert.js @@ -6,16 +6,25 @@ Components.utils.import("resource://gre/modules/Services.jsm"); +const Ci = Components.interfaces; +const Cc = Components.classes; + +var windowMediator = Cc["@mozilla.org/appshell/window-mediator;1"] + .getService(Ci.nsIWindowMediator); + // Copied from nsILookAndFeel.h, see comments on eMetric_AlertNotificationOrigin const NS_ALERT_HORIZONTAL = 1; const NS_ALERT_LEFT = 2; const NS_ALERT_TOP = 4; +const WINDOW_MARGIN = 10; + var gOrigin = 0; // Default value: alert from bottom right. - +var gReplacedWindow = null; var gAlertListener = null; var gAlertTextClickable = false; var gAlertCookie = ""; +var gIsReplaced = false; function prefillAlertInfo() { // unwrap all the args.... @@ -25,12 +34,17 @@ function prefillAlertInfo() { // arguments[3] --> is the text clickable? // arguments[4] --> the alert cookie to be passed back to the listener // arguments[5] --> the alert origin reported by the look and feel - // arguments[6] --> an optional callback listener (nsIObserver) + // arguments[6] --> bidi + // arguments[7] --> lang + // arguments[8] --> replaced alert window (nsIDOMWindow) + // arguments[9] --> an optional callback listener (nsIObserver) switch (window.arguments.length) { default: - case 7: - gAlertListener = window.arguments[6]; + case 10: + gAlertListener = window.arguments[9]; + case 9: + gReplacedWindow = window.arguments[8]; case 6: gOrigin = window.arguments[5]; case 5: @@ -46,7 +60,9 @@ function prefillAlertInfo() { case 2: document.getElementById('alertTitleLabel').setAttribute('value', window.arguments[1]); case 1: - document.getElementById('alertImage').setAttribute('src', window.arguments[0]); + if (window.arguments[0]) { + document.getElementById('alertImage').setAttribute('src', window.arguments[0]); + } case 0: break; } @@ -60,20 +76,16 @@ function onAlertLoad() { sizeToContent(); - // Determine position - let x = gOrigin & NS_ALERT_LEFT ? screen.availLeft : - screen.availLeft + screen.availWidth - window.outerWidth; - let y = gOrigin & NS_ALERT_TOP ? screen.availTop : - screen.availTop + screen.availHeight - window.outerHeight; - - // Offset the alert by 10 pixels from the edge of the screen - y += gOrigin & NS_ALERT_TOP ? 10 : -10; - x += gOrigin & NS_ALERT_LEFT ? 10 : -10; - - window.moveTo(x, y); + if (gReplacedWindow) { + moveWindowToReplace(gReplacedWindow); + gReplacedWindow.gIsReplaced = true; + gReplacedWindow.close(); + } else { + moveWindowToEnd(); + } if (Services.prefs.getBoolPref("alerts.disableSlidingEffect")) { - setTimeout(closeAlert, ALERT_DURATION_IMMEDIATE); + setTimeout(function() { window.close(); }, ALERT_DURATION_IMMEDIATE); return; } @@ -81,20 +93,100 @@ function onAlertLoad() { alertBox.addEventListener("animationend", function hideAlert(event) { if (event.animationName == "alert-animation") { alertBox.removeEventListener("animationend", hideAlert, false); - closeAlert(); + window.close(); } }, false); alertBox.setAttribute("animate", true); + + if (gAlertListener) { + gAlertListener.observe(null, "alertshow", gAlertCookie); + } } -function closeAlert() { - if (gAlertListener) +function moveWindowToReplace(aReplacedAlert) { + let heightDelta = window.outerHeight - aReplacedAlert.outerHeight; + + // Move windows that come after the replaced alert if the height is different. + if (heightDelta != 0) { + let windows = windowMediator.getEnumerator('alert:alert'); + while (windows.hasMoreElements()) { + let alertWindow = windows.getNext(); + // boolean to determine if the alert window is after the replaced alert. + let alertIsAfter = gOrigin & NS_ALERT_TOP ? + alertWindow.screenY > aReplacedAlert.screenY : + aReplacedAlert.screenY > alertWindow.screenY; + if (alertIsAfter) { + // The new Y position of the window. + let adjustedY = gOrigin & NS_ALERT_TOP ? + alertWindow.screenY + heightDelta : + alertWindow.screenY - heightDelta; + alertWindow.moveTo(alertWindow.screenX, adjustedY); + } + } + } + + let adjustedY = gOrigin & NS_ALERT_TOP ? aReplacedAlert.screenY : + aReplacedAlert.screenY - heightDelta; + window.moveTo(aReplacedAlert.screenX, adjustedY); +} + +function moveWindowToEnd() { + // Determine position + let x = gOrigin & NS_ALERT_LEFT ? screen.availLeft : + screen.availLeft + screen.availWidth - window.outerWidth; + let y = gOrigin & NS_ALERT_TOP ? screen.availTop : + screen.availTop + screen.availHeight - window.outerHeight; + + // Position the window at the end of all alerts. + let windows = windowMediator.getEnumerator('alert:alert'); + while (windows.hasMoreElements()) { + let alertWindow = windows.getNext(); + if (alertWindow != window) { + if (gOrigin & NS_ALERT_TOP) { + y = Math.max(y, alertWindow.screenY + alertWindow.outerHeight); + } else { + y = Math.min(y, alertWindow.screenY - window.outerHeight); + } + } + } + + // Offset the alert by WINDOW_MARGIN pixels from the edge of the screen + y += gOrigin & NS_ALERT_TOP ? WINDOW_MARGIN : -WINDOW_MARGIN; + x += gOrigin & NS_ALERT_LEFT ? WINDOW_MARGIN : -WINDOW_MARGIN; + + window.moveTo(x, y); +} + +function onAlertBeforeUnload() { + if (!gIsReplaced) { + // Move other alert windows to fill the gap left by closing alert. + let heightDelta = window.outerHeight + WINDOW_MARGIN; + let windows = windowMediator.getEnumerator('alert:alert'); + while (windows.hasMoreElements()) { + let alertWindow = windows.getNext(); + if (alertWindow != window) { + if (gOrigin & NS_ALERT_TOP) { + if (alertWindow.screenY > window.screenY) { + alertWindow.moveTo(alertWindow.screenX, alertWindow.screenY - heightDelta); + } + } else { + if (window.screenY > alertWindow.screenY) { + alertWindow.moveTo(alertWindow.screenX, alertWindow.screenY + heightDelta); + } + } + } + } + } + + if (gAlertListener) { gAlertListener.observe(null, "alertfinished", gAlertCookie); - window.close(); + } } function onAlertClick() { - if (gAlertListener && gAlertTextClickable) + if (gAlertListener && gAlertTextClickable) { gAlertListener.observe(null, "alertclickcallback", gAlertCookie); - closeAlert(); + } + + window.close(); } diff --git a/toolkit/components/alerts/resources/content/alert.xul b/toolkit/components/alerts/resources/content/alert.xul index 4aa00f3dd30..7538be0afbd 100644 --- a/toolkit/components/alerts/resources/content/alert.xul +++ b/toolkit/components/alerts/resources/content/alert.xul @@ -3,6 +3,11 @@ - 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/. --> + +%alertDTD; +]> + @@ -12,22 +17,30 @@ xmlns:xhtml="http://www.w3.org/1999/xhtml" xhtml:role="alert" pack="start" - onload="onAlertLoad()" - onclick="onAlertClick();"> + onload="onAlertLoad();" + onclick="onAlertClick();" + onbeforeunload="onAlertBeforeUnload();">