michael@0: // -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- michael@0: michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: Components.utils.import("resource://gre/modules/Services.jsm"); michael@0: michael@0: const Ci = Components.interfaces; michael@0: const Cc = Components.classes; michael@0: michael@0: var windowMediator = Cc["@mozilla.org/appshell/window-mediator;1"] michael@0: .getService(Ci.nsIWindowMediator); michael@0: michael@0: // Copied from nsILookAndFeel.h, see comments on eMetric_AlertNotificationOrigin michael@0: const NS_ALERT_HORIZONTAL = 1; michael@0: const NS_ALERT_LEFT = 2; michael@0: const NS_ALERT_TOP = 4; michael@0: michael@0: const WINDOW_MARGIN = 10; michael@0: michael@0: var gOrigin = 0; // Default value: alert from bottom right. michael@0: var gReplacedWindow = null; michael@0: var gAlertListener = null; michael@0: var gAlertTextClickable = false; michael@0: var gAlertCookie = ""; michael@0: var gIsReplaced = false; michael@0: michael@0: function prefillAlertInfo() { michael@0: // unwrap all the args.... michael@0: // arguments[0] --> the image src url michael@0: // arguments[1] --> the alert title michael@0: // arguments[2] --> the alert text michael@0: // arguments[3] --> is the text clickable? michael@0: // arguments[4] --> the alert cookie to be passed back to the listener michael@0: // arguments[5] --> the alert origin reported by the look and feel michael@0: // arguments[6] --> bidi michael@0: // arguments[7] --> lang michael@0: // arguments[8] --> replaced alert window (nsIDOMWindow) michael@0: // arguments[9] --> an optional callback listener (nsIObserver) michael@0: michael@0: switch (window.arguments.length) { michael@0: default: michael@0: case 10: michael@0: gAlertListener = window.arguments[9]; michael@0: case 9: michael@0: gReplacedWindow = window.arguments[8]; michael@0: case 6: michael@0: gOrigin = window.arguments[5]; michael@0: case 5: michael@0: gAlertCookie = window.arguments[4]; michael@0: case 4: michael@0: gAlertTextClickable = window.arguments[3]; michael@0: if (gAlertTextClickable) { michael@0: document.getElementById('alertNotification').setAttribute('clickable', true); michael@0: document.getElementById('alertTextLabel').setAttribute('clickable', true); michael@0: } michael@0: case 3: michael@0: document.getElementById('alertTextLabel').textContent = window.arguments[2]; michael@0: case 2: michael@0: document.getElementById('alertTitleLabel').setAttribute('value', window.arguments[1]); michael@0: case 1: michael@0: if (window.arguments[0]) { michael@0: document.getElementById('alertImage').setAttribute('src', window.arguments[0]); michael@0: } michael@0: case 0: michael@0: break; michael@0: } michael@0: } michael@0: michael@0: function onAlertLoad() { michael@0: const ALERT_DURATION_IMMEDIATE = 4000; michael@0: let alertTextBox = document.getElementById("alertTextBox"); michael@0: let alertImageBox = document.getElementById("alertImageBox"); michael@0: alertImageBox.style.minHeight = alertTextBox.scrollHeight + "px"; michael@0: michael@0: sizeToContent(); michael@0: michael@0: if (gReplacedWindow && !gReplacedWindow.closed) { michael@0: moveWindowToReplace(gReplacedWindow); michael@0: gReplacedWindow.gIsReplaced = true; michael@0: gReplacedWindow.close(); michael@0: } else { michael@0: moveWindowToEnd(); michael@0: } michael@0: michael@0: window.addEventListener("XULAlertClose", function() { window.close(); }); michael@0: michael@0: if (Services.prefs.getBoolPref("alerts.disableSlidingEffect")) { michael@0: setTimeout(function() { window.close(); }, ALERT_DURATION_IMMEDIATE); michael@0: return; michael@0: } michael@0: michael@0: let alertBox = document.getElementById("alertBox"); michael@0: alertBox.addEventListener("animationend", function hideAlert(event) { michael@0: if (event.animationName == "alert-animation") { michael@0: alertBox.removeEventListener("animationend", hideAlert, false); michael@0: window.close(); michael@0: } michael@0: }, false); michael@0: alertBox.setAttribute("animate", true); michael@0: michael@0: if (gAlertListener) { michael@0: gAlertListener.observe(null, "alertshow", gAlertCookie); michael@0: } michael@0: } michael@0: michael@0: function moveWindowToReplace(aReplacedAlert) { michael@0: let heightDelta = window.outerHeight - aReplacedAlert.outerHeight; michael@0: michael@0: // Move windows that come after the replaced alert if the height is different. michael@0: if (heightDelta != 0) { michael@0: let windows = windowMediator.getEnumerator('alert:alert'); michael@0: while (windows.hasMoreElements()) { michael@0: let alertWindow = windows.getNext(); michael@0: // boolean to determine if the alert window is after the replaced alert. michael@0: let alertIsAfter = gOrigin & NS_ALERT_TOP ? michael@0: alertWindow.screenY > aReplacedAlert.screenY : michael@0: aReplacedAlert.screenY > alertWindow.screenY; michael@0: if (alertIsAfter) { michael@0: // The new Y position of the window. michael@0: let adjustedY = gOrigin & NS_ALERT_TOP ? michael@0: alertWindow.screenY + heightDelta : michael@0: alertWindow.screenY - heightDelta; michael@0: alertWindow.moveTo(alertWindow.screenX, adjustedY); michael@0: } michael@0: } michael@0: } michael@0: michael@0: let adjustedY = gOrigin & NS_ALERT_TOP ? aReplacedAlert.screenY : michael@0: aReplacedAlert.screenY - heightDelta; michael@0: window.moveTo(aReplacedAlert.screenX, adjustedY); michael@0: } michael@0: michael@0: function moveWindowToEnd() { michael@0: // Determine position michael@0: let x = gOrigin & NS_ALERT_LEFT ? screen.availLeft : michael@0: screen.availLeft + screen.availWidth - window.outerWidth; michael@0: let y = gOrigin & NS_ALERT_TOP ? screen.availTop : michael@0: screen.availTop + screen.availHeight - window.outerHeight; michael@0: michael@0: // Position the window at the end of all alerts. michael@0: let windows = windowMediator.getEnumerator('alert:alert'); michael@0: while (windows.hasMoreElements()) { michael@0: let alertWindow = windows.getNext(); michael@0: if (alertWindow != window) { michael@0: if (gOrigin & NS_ALERT_TOP) { michael@0: y = Math.max(y, alertWindow.screenY + alertWindow.outerHeight); michael@0: } else { michael@0: y = Math.min(y, alertWindow.screenY - window.outerHeight); michael@0: } michael@0: } michael@0: } michael@0: michael@0: // Offset the alert by WINDOW_MARGIN pixels from the edge of the screen michael@0: y += gOrigin & NS_ALERT_TOP ? WINDOW_MARGIN : -WINDOW_MARGIN; michael@0: x += gOrigin & NS_ALERT_LEFT ? WINDOW_MARGIN : -WINDOW_MARGIN; michael@0: michael@0: window.moveTo(x, y); michael@0: } michael@0: michael@0: function onAlertBeforeUnload() { michael@0: if (!gIsReplaced) { michael@0: // Move other alert windows to fill the gap left by closing alert. michael@0: let heightDelta = window.outerHeight + WINDOW_MARGIN; michael@0: let windows = windowMediator.getEnumerator('alert:alert'); michael@0: while (windows.hasMoreElements()) { michael@0: let alertWindow = windows.getNext(); michael@0: if (alertWindow != window) { michael@0: if (gOrigin & NS_ALERT_TOP) { michael@0: if (alertWindow.screenY > window.screenY) { michael@0: alertWindow.moveTo(alertWindow.screenX, alertWindow.screenY - heightDelta); michael@0: } michael@0: } else { michael@0: if (window.screenY > alertWindow.screenY) { michael@0: alertWindow.moveTo(alertWindow.screenX, alertWindow.screenY + heightDelta); michael@0: } michael@0: } michael@0: } michael@0: } michael@0: } michael@0: michael@0: if (gAlertListener) { michael@0: gAlertListener.observe(null, "alertfinished", gAlertCookie); michael@0: } michael@0: } michael@0: michael@0: function onAlertClick() { michael@0: if (gAlertListener && gAlertTextClickable) { michael@0: gAlertListener.observe(null, "alertclickcallback", gAlertCookie); michael@0: } michael@0: michael@0: window.close(); michael@0: }