mirror of
https://github.com/roytam1/boc-uxp.git
synced 2021-11-05 16:13:16 +00:00
812 lines
27 KiB
JavaScript
812 lines
27 KiB
JavaScript
/* -*- 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/. */
|
|
|
|
/*
|
|
* Core mail routines used by all of the major mail windows (address book,
|
|
* 3-pane, compose and stand alone message window).
|
|
* Routines to support custom toolbars in mail windows, opening up a new window
|
|
* of a particular type all live here.
|
|
* Before adding to this file, ask yourself, is this a JS routine that is going
|
|
* to be used by all of the main mail windows?
|
|
*/
|
|
|
|
Components.utils.import("resource://gre/modules/BrowserUtils.jsm");
|
|
Components.utils.import("resource://gre/modules/Services.jsm");
|
|
Components.utils.import("resource://gre/modules/AppConstants.jsm");
|
|
Components.utils.import("resource:///modules/mailServices.js");
|
|
|
|
var gCustomizeSheet = false;
|
|
|
|
function overlayRestoreDefaultSet() {
|
|
let toolbox = null;
|
|
if ("arguments" in window && window.arguments[0])
|
|
toolbox = window.arguments[0];
|
|
else if (window.frameElement && "toolbox" in window.frameElement)
|
|
toolbox = window.frameElement.toolbox;
|
|
|
|
let mode = toolbox.getAttribute("defaultmode");
|
|
let align = toolbox.getAttribute("defaultlabelalign");
|
|
let menulist = document.getElementById("modelist");
|
|
|
|
if (mode == "full" && align == "end") {
|
|
toolbox.setAttribute("mode", "textbesideicon");
|
|
toolbox.setAttribute("labelalign", align);
|
|
overlayUpdateToolbarMode("textbesideicon");
|
|
}
|
|
else if (mode == "full" && align == ""){
|
|
toolbox.setAttribute("mode", "full");
|
|
toolbox.removeAttribute("labelalign");
|
|
overlayUpdateToolbarMode(mode);
|
|
}
|
|
|
|
restoreDefaultSet();
|
|
|
|
if (mode == "full" && align == "end") {
|
|
menulist.value = "textbesideicon";
|
|
}
|
|
}
|
|
|
|
function overlayUpdateToolbarMode(aModeValue)
|
|
{
|
|
let toolbox = null;
|
|
if ("arguments" in window && window.arguments[0])
|
|
toolbox = window.arguments[0];
|
|
else if (window.frameElement && "toolbox" in window.frameElement)
|
|
toolbox = window.frameElement.toolbox;
|
|
|
|
// If they chose a mode of textbesideicon or full,
|
|
// then map that to a mode of full, and a labelalign of true or false.
|
|
if( aModeValue == "textbesideicon" || aModeValue == "full") {
|
|
var align = aModeValue == "textbesideicon" ? "end" : "bottom";
|
|
toolbox.setAttribute("labelalign", align);
|
|
toolbox.ownerDocument.persist(toolbox.id, "labelalign");
|
|
aModeValue = "full";
|
|
}
|
|
updateToolbarMode(aModeValue);
|
|
}
|
|
|
|
function overlayOnLoad()
|
|
{
|
|
let restoreButton = document.getElementById("main-box")
|
|
.querySelector("[oncommand*='restore']");
|
|
restoreButton.setAttribute("oncommand", "overlayRestoreDefaultSet();");
|
|
|
|
// Add the textBesideIcon menu item if it's not already there.
|
|
let menuitem = document.getElementById("textbesideiconItem");
|
|
if (!menuitem) {
|
|
let menulist = document.getElementById("modelist");
|
|
let label = document.getElementById("iconsBesideText.label")
|
|
.getAttribute("value");
|
|
menuitem = menulist.appendItem(label, "textbesideicon");
|
|
menuitem.id = "textbesideiconItem";
|
|
}
|
|
|
|
// If they have a mode of full and a labelalign of true,
|
|
// then pretend the mode is textbesideicon when populating the popup.
|
|
let toolbox = null;
|
|
if ("arguments" in window && window.arguments[0])
|
|
toolbox = window.arguments[0];
|
|
else if (window.frameElement && "toolbox" in window.frameElement)
|
|
toolbox = window.frameElement.toolbox;
|
|
|
|
let toolbarWindow = document.getElementById("CustomizeToolbarWindow");
|
|
toolbarWindow.setAttribute("toolboxId", toolbox.id);
|
|
if (toolbox.getAttribute("inlinetoolbox") == "true")
|
|
toolbarWindow.setAttribute("inlinetoolbox", "true");
|
|
toolbox.setAttribute("doCustomization", "true");
|
|
|
|
let mode = toolbox.getAttribute("mode");
|
|
let align = toolbox.getAttribute("labelalign");
|
|
if (mode == "full" && align == "end")
|
|
toolbox.setAttribute("mode", "textbesideicon");
|
|
|
|
onLoad();
|
|
overlayRepositionDialog();
|
|
|
|
// Re-set and re-persist the mode, if we changed it above.
|
|
if (mode == "full" && align == "end") {
|
|
toolbox.setAttribute("mode", mode);
|
|
toolbox.ownerDocument.persist(toolbox.id, "mode");
|
|
}
|
|
}
|
|
|
|
function overlayRepositionDialog()
|
|
{
|
|
// Position the dialog so it is fully visible on the screen
|
|
// (if possible)
|
|
|
|
// Seems to be necessary to get the correct dialog height/width
|
|
window.sizeToContent();
|
|
var wH = window.outerHeight;
|
|
var wW = window.outerWidth;
|
|
var sH = window.screen.height;
|
|
var sW = window.screen.width;
|
|
var sX = window.screenX;
|
|
var sY = window.screenY;
|
|
var sAL = window.screen.availLeft;
|
|
var sAT = window.screen.availTop;
|
|
|
|
var nX = Math.max(Math.min(sX, sW - wW), sAL);
|
|
var nY = Math.max(Math.min(sY, sH - wH), sAT);
|
|
window.moveTo(nX, nY);
|
|
}
|
|
|
|
function CustomizeMailToolbar(toolboxId, customizePopupId)
|
|
{
|
|
// Disable the toolbar context menu items
|
|
var menubar = document.getElementById("mail-menubar");
|
|
for (var i = 0; i < menubar.childNodes.length; ++i)
|
|
menubar.childNodes[i].setAttribute("disabled", true);
|
|
|
|
var customizePopup = document.getElementById(customizePopupId);
|
|
customizePopup.setAttribute("disabled", "true");
|
|
|
|
var toolbox = document.getElementById(toolboxId);
|
|
|
|
var customizeURL = "chrome://global/content/customizeToolbar.xul";
|
|
gCustomizeSheet = Services.prefs.getBoolPref("toolbar.customization.usesheet");
|
|
|
|
if (gCustomizeSheet) {
|
|
var sheetFrame = document.getElementById("customizeToolbarSheetIFrame");
|
|
var panel = document.getElementById("customizeToolbarSheetPopup");
|
|
sheetFrame.hidden = false;
|
|
sheetFrame.toolbox = toolbox;
|
|
sheetFrame.panel = panel;
|
|
|
|
// The document might not have been loaded yet, if this is the first time.
|
|
// If it is already loaded, reload it so that the onload intialization code
|
|
// re-runs.
|
|
if (sheetFrame.getAttribute("src") == customizeURL)
|
|
sheetFrame.contentWindow.location.reload()
|
|
else
|
|
sheetFrame.setAttribute("src", customizeURL);
|
|
|
|
// Open the panel, but make it invisible until the iframe has loaded so
|
|
// that the user doesn't see a white flash.
|
|
panel.style.visibility = "hidden";
|
|
toolbox.addEventListener("beforecustomization", function removeProp() {
|
|
panel.style.removeProperty("visibility");
|
|
}, {capture: false, once: true});
|
|
panel.openPopup(toolbox, "after_start", 0, 0);
|
|
}
|
|
else {
|
|
var wintype = document.documentElement.getAttribute("windowtype");
|
|
wintype = wintype.replace(/:/g, "");
|
|
|
|
window.openDialog(customizeURL,
|
|
"CustomizeToolbar"+wintype,
|
|
"chrome,all,dependent", toolbox);
|
|
}
|
|
}
|
|
|
|
function MailToolboxCustomizeDone(aEvent, customizePopupId)
|
|
{
|
|
if (gCustomizeSheet) {
|
|
document.getElementById("customizeToolbarSheetIFrame").hidden = true;
|
|
document.getElementById("customizeToolbarSheetPopup").hidePopup();
|
|
}
|
|
|
|
// Update global UI elements that may have been added or removed
|
|
|
|
// Re-enable parts of the UI we disabled during the dialog
|
|
var menubar = document.getElementById("mail-menubar");
|
|
for (var i = 0; i < menubar.childNodes.length; ++i)
|
|
menubar.childNodes[i].setAttribute("disabled", false);
|
|
|
|
// make sure the mail views search box is initialized
|
|
if (document.getElementById("mailviews-container"))
|
|
ViewPickerOnLoad();
|
|
|
|
// make sure the folder location picker is initialized
|
|
if (document.getElementById("folder-location-container"))
|
|
FolderPaneSelectionChange();
|
|
|
|
var customizePopup = document.getElementById(customizePopupId);
|
|
customizePopup.removeAttribute("disabled");
|
|
|
|
// make sure our toolbar buttons have the correct enabled state restored to them...
|
|
if (this.UpdateMailToolbar != undefined)
|
|
UpdateMailToolbar(focus);
|
|
|
|
let toolbox = document.querySelector('[doCustomization="true"]');
|
|
if (toolbox) {
|
|
toolbox.removeAttribute("doCustomization");
|
|
|
|
// The GetMail button is stuck in a strange state right now, since the
|
|
// customization wrapping preserves its children, but not its initialized
|
|
// state. Fix that here.
|
|
// That is also true for the File -> "Get new messages for" menuitems in both
|
|
// menus (old and new App menu). And also Go -> Folder.
|
|
// TODO bug 904223: try to fix folderWidgets.xml to not do this.
|
|
// See Bug 520457 and Bug 534448 and Bug 709733.
|
|
// Fix Bug 565045: Only treat "Get Message Button" if it is in our toolbox
|
|
for (let popup of [ toolbox.querySelector("#button-getMsgPopup"),
|
|
document.getElementById("menu_getAllNewMsgPopup"),
|
|
document.getElementById("appmenu_getAllNewMsgPopup"),
|
|
document.getElementById("menu_GoFolderPopup"),
|
|
document.getElementById("appmenu_GoFolderPopup") ])
|
|
{
|
|
if (!popup)
|
|
continue;
|
|
|
|
// .teardown() is only available here if the menu has its frame
|
|
// otherwise the folderWidgets.xml::folder-menupopup binding is not
|
|
// attached to the popup. So if it is not available, remove the items
|
|
// explicitly. Only remove elements that were generated by the binding.
|
|
if ("_teardown" in popup) {
|
|
popup._teardown();
|
|
} else {
|
|
for (let i = popup.childNodes.length - 1; i >= 0; i--) {
|
|
let child = popup.childNodes[i];
|
|
if (child.getAttribute("generated") != "true")
|
|
continue;
|
|
if ("_teardown" in child)
|
|
child._teardown();
|
|
child.remove();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function onViewToolbarsPopupShowing(aEvent, toolboxIds, aInsertPoint)
|
|
{
|
|
if (!Array.isArray(toolboxIds))
|
|
toolboxIds = [toolboxIds];
|
|
|
|
let popup = aEvent.target;
|
|
|
|
// Empty the menu
|
|
for (let i = popup.childNodes.length - 1; i >= 0; --i) {
|
|
let deadItem = popup.childNodes[i];
|
|
|
|
// Remove all of the nodes with the iscollapsible
|
|
// attribute.
|
|
if (deadItem.hasAttribute("iscollapsible"))
|
|
deadItem.remove();
|
|
}
|
|
|
|
// We'll insert the menuitems before the first item in the list if no insert
|
|
// point is defined.
|
|
let firstMenuItem = aInsertPoint || popup.firstChild;
|
|
|
|
for (let toolboxId of toolboxIds) {
|
|
let toolbox = document.getElementById(toolboxId);
|
|
|
|
// We'll consider either childnodes that have a toolbarname attribute,
|
|
// or externalToolbars.
|
|
let potentialToolbars = Array.slice(
|
|
toolbox.querySelectorAll("[toolbarname]")
|
|
);
|
|
for (let externalToolbar of toolbox.externalToolbars) {
|
|
if (externalToolbar.getAttribute("prependmenuitem"))
|
|
potentialToolbars.unshift(externalToolbar);
|
|
else
|
|
potentialToolbars.push(externalToolbar);
|
|
}
|
|
|
|
let mailToolbarMenubar = false;
|
|
for (let toolbarElement of potentialToolbars) {
|
|
|
|
// We have to bind to toolbar because Javascript doesn't do fresh
|
|
// let-bindings per Iteration.
|
|
let toolbar = toolbarElement;
|
|
|
|
let toolbarName = toolbar.getAttribute("toolbarname");
|
|
if (toolbarName) {
|
|
if (toolbar.id == "mail-toolbar-menubar2") {
|
|
if (!mailToolbarMenubar) {
|
|
mailToolbarMenubar = true;
|
|
}
|
|
else {
|
|
continue;
|
|
}
|
|
}
|
|
|
|
let menuItem = document.createElement("menuitem");
|
|
let hidingAttribute = toolbar.getAttribute("type") == "menubar" ?
|
|
"autohide" : "collapsed";
|
|
menuItem.setAttribute("type", "checkbox");
|
|
// Mark this menuitem with an iscollapsible attribute, so we
|
|
// know we can wipe it out later on.
|
|
menuItem.setAttribute("iscollapsible", true);
|
|
menuItem.setAttribute("toolbarid", toolbar.id);
|
|
menuItem.setAttribute("label", toolbarName);
|
|
menuItem.setAttribute("accesskey", toolbar.getAttribute("accesskey"));
|
|
menuItem.setAttribute("checked",
|
|
toolbar.getAttribute(hidingAttribute) != "true");
|
|
popup.insertBefore(menuItem, firstMenuItem);
|
|
|
|
let onMenuItemCommand = function(aEvent) {
|
|
let hidden = aEvent.originalTarget.getAttribute("checked") != "true";
|
|
toolbar.setAttribute(hidingAttribute, hidden);
|
|
document.persist(toolbar.id, hidingAttribute);
|
|
}
|
|
|
|
menuItem.addEventListener("command", onMenuItemCommand, false);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function toJavaScriptConsole()
|
|
{
|
|
let pref = Services.prefs.getBoolPref("toolkit.console.openInTab");
|
|
let url = "chrome://global/content/console.xul";
|
|
|
|
if (pref) {
|
|
let tabmail = document.getElementById("tabmail");
|
|
let jsConsole = tabmail.getBrowserForDocumentId("JSConsoleWindow");
|
|
if (jsConsole)
|
|
tabmail.switchToTab(jsConsole);
|
|
else {
|
|
tabmail.openTab("chromeTab", {chromePage: url,
|
|
clickHandler: "specialTabs.aboutClickHandler(event);"});
|
|
}
|
|
}
|
|
else {
|
|
toOpenWindowByType("global:console", url);
|
|
}
|
|
}
|
|
|
|
function openAboutDebugging(hash)
|
|
{
|
|
let url = "about:debugging" + (hash ? "#" + hash : "");
|
|
document.getElementById('tabmail').openTab("contentTab", { contentPage: url });
|
|
}
|
|
|
|
function toOpenWindowByType(inType, uri, features)
|
|
{
|
|
var topWindow = Services.wm.getMostRecentWindow(inType);
|
|
|
|
if (topWindow)
|
|
topWindow.focus();
|
|
else if (features)
|
|
window.open(uri, "_blank", features);
|
|
else
|
|
window.open(uri, "_blank", "chrome,extrachrome,menubar,resizable,scrollbars,status,toolbar");
|
|
}
|
|
|
|
function toMessengerWindow()
|
|
{
|
|
toOpenWindowByType("mail:3pane", "chrome://messenger/content/messenger.xul");
|
|
}
|
|
|
|
|
|
function focusOnMail(tabNo, event)
|
|
{
|
|
// this is invoked by accel-<number>
|
|
// if the window isn't visible or focused, make it so
|
|
var topWindow = Services.wm.getMostRecentWindow("mail:3pane");
|
|
if (topWindow) {
|
|
if (topWindow != window)
|
|
topWindow.focus();
|
|
else
|
|
document.getElementById('tabmail').selectTabByIndex(event, tabNo);
|
|
}
|
|
else {
|
|
window.open("chrome://messenger/content/messenger.xul",
|
|
"_blank",
|
|
"chrome,extrachrome,menubar,resizable,scrollbars,status,toolbar");
|
|
}
|
|
}
|
|
|
|
function toAddressBook()
|
|
{
|
|
toOpenWindowByType("mail:addressbook",
|
|
"chrome://messenger/content/addressbook/addressbook.xul");
|
|
}
|
|
|
|
function showChatTab()
|
|
{
|
|
let tabmail = document.getElementById("tabmail");
|
|
if (gChatTab)
|
|
tabmail.switchToTab(gChatTab);
|
|
else
|
|
tabmail.openTab("chat", {});
|
|
}
|
|
|
|
function toImport()
|
|
{
|
|
window.openDialog("chrome://messenger/content/importDialog.xul", "importDialog",
|
|
"chrome, modal, titlebar, centerscreen");
|
|
}
|
|
|
|
function toSanitize()
|
|
{
|
|
Components.classes["@mozilla.org/mail/mailglue;1"]
|
|
.getService(Components.interfaces.nsIMailGlue)
|
|
.sanitize(window);
|
|
}
|
|
|
|
function toProfileManager()
|
|
{
|
|
var promgrWin = Services.wm.getMostRecentWindow("mozilla:profileSelection");
|
|
if (promgrWin) {
|
|
promgrWin.focus();
|
|
} else {
|
|
var params = Components.classes["@mozilla.org/embedcomp/dialogparam;1"]
|
|
.createInstance(Components.interfaces.nsIDialogParamBlock);
|
|
|
|
params.SetNumberStrings(1);
|
|
params.SetString(0, "menu");
|
|
window.openDialog("chrome://communicator/content/profile/profileSelection.xul",
|
|
"",
|
|
"centerscreen,chrome,titlebar",
|
|
params);
|
|
}
|
|
// Here, we don't care about the result code
|
|
// that was returned in the param block.
|
|
}
|
|
|
|
/**
|
|
* Opens the Preferences (Options) dialog.
|
|
*
|
|
* @param aPaneID ID of prefpane to select automatically.
|
|
* @param aTabID ID of tab to select on the prefpane.
|
|
* @param aOtherArgs other prefpane specific arguments
|
|
*/
|
|
function openOptionsDialog(aPaneID, aTabID, aOtherArgs)
|
|
{
|
|
let loadInContent = Services.prefs.getBoolPref("mail.preferences.inContent");
|
|
// Load the prefs in a tab?
|
|
if (loadInContent) {
|
|
// Yes, load the prefs in a tab
|
|
openPreferencesTab(aPaneID, aTabID, aOtherArgs);
|
|
} else {
|
|
// No, load the prefs in a dialog
|
|
let win = Services.wm.getMostRecentWindow("Mail:Preferences");
|
|
if (win) {
|
|
// the dialog is already open
|
|
win.focus();
|
|
if (aPaneID) {
|
|
let prefWindow = win.document.getElementById("MailPreferences");
|
|
win.selectPaneAndTab(prefWindow, aPaneID, aTabID);
|
|
}
|
|
} else {
|
|
// the dialog must be created
|
|
let instantApply = Services.prefs
|
|
.getBoolPref("browser.preferences.instantApply");
|
|
let features = "chrome,titlebar,toolbar,centerscreen" +
|
|
(instantApply ? ",dialog=no" : ",modal");
|
|
|
|
openDialog("chrome://messenger/content/preferences/preferences.xul",
|
|
"Preferences", features, aPaneID, aTabID, aOtherArgs);
|
|
}
|
|
}
|
|
}
|
|
|
|
function openAddonsMgr(aView)
|
|
{
|
|
let pref = Services.prefs.getBoolPref("extensions.openInTab");
|
|
let type = "Addons:Manager";
|
|
let url = "chrome://mozapps/content/extensions/extensions.xul";
|
|
let features = "chrome,titlebar,resizable,centerscreen";
|
|
|
|
if (pref) {
|
|
if (aView) {
|
|
let emWindow;
|
|
let browserWindow;
|
|
|
|
let receivePong = function receivePong(aSubject, aTopic, aData) {
|
|
let browserWin = aSubject.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
|
|
.getInterface(Components.interfaces.nsIWebNavigation)
|
|
.QueryInterface(Components.interfaces.nsIDocShellTreeItem)
|
|
.rootTreeItem
|
|
.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
|
|
.getInterface(Components.interfaces.nsIDOMWindow);
|
|
if (!emWindow || browserWin == window /* favor the current window */) {
|
|
emWindow = aSubject;
|
|
browserWindow = browserWin;
|
|
}
|
|
}
|
|
Services.obs.addObserver(receivePong, "EM-pong", false);
|
|
Services.obs.notifyObservers(null, "EM-ping", "");
|
|
Services.obs.removeObserver(receivePong, "EM-pong");
|
|
|
|
if (emWindow) {
|
|
emWindow.loadView(aView);
|
|
let tabmail = browserWindow.document.getElementById("tabmail");
|
|
tabmail.switchToTab(tabmail.getBrowserForDocument(emWindow));
|
|
emWindow.focus();
|
|
return;
|
|
}
|
|
}
|
|
|
|
openContentTab(url, "tab", "addons.mozilla.org");
|
|
|
|
|
|
if (aView) {
|
|
// This must be a new load, else the ping/pong would have
|
|
// found the window above.
|
|
Services.obs.addObserver(function loadViewOnLoad(aSubject, aTopic, aData) {
|
|
Services.obs.removeObserver(loadViewOnLoad, aTopic);
|
|
aSubject.loadView(aView);
|
|
}, "EM-loaded", false);
|
|
}
|
|
}
|
|
else {
|
|
toOpenWindowByType(type, url, features);
|
|
}
|
|
|
|
}
|
|
|
|
function openActivityMgr()
|
|
{
|
|
Components.classes['@mozilla.org/activity-manager-ui;1'].
|
|
getService(Components.interfaces.nsIActivityManagerUI).show(window);
|
|
}
|
|
|
|
function openIMAccountMgr()
|
|
{
|
|
// XXXTobin: Remove consumers
|
|
return;
|
|
}
|
|
|
|
function openIMAccountWizard()
|
|
{
|
|
// XXXTobin: Remove consumers
|
|
return;
|
|
}
|
|
|
|
function openSavedFilesWnd()
|
|
{
|
|
let tabmail = document.getElementById("tabmail");
|
|
let downloadsBrowser = tabmail.getBrowserForDocumentId("aboutDownloads");
|
|
if (downloadsBrowser)
|
|
tabmail.switchToTab(downloadsBrowser);
|
|
else {
|
|
tabmail.openTab("chromeTab",
|
|
{ chromePage: "about:downloads",
|
|
clickHandler: "specialTabs.aboutClickHandler(event);" });
|
|
}
|
|
}
|
|
|
|
function SetBusyCursor(window, enable)
|
|
{
|
|
// setCursor() is only available for chrome windows.
|
|
// However one of our frames is the start page which
|
|
// is a non-chrome window, so check if this window has a
|
|
// setCursor method
|
|
if ("setCursor" in window) {
|
|
if (enable)
|
|
window.setCursor("progress");
|
|
else
|
|
window.setCursor("auto");
|
|
}
|
|
|
|
var numFrames = window.frames.length;
|
|
for(var i = 0; i < numFrames; i++)
|
|
SetBusyCursor(window.frames[i], enable);
|
|
}
|
|
|
|
function openAboutDialog()
|
|
{
|
|
let enumerator = Services.wm.getEnumerator("Mail:About");
|
|
while (enumerator.hasMoreElements()) {
|
|
// Only open one about window
|
|
let win = enumerator.getNext();
|
|
win.focus();
|
|
return;
|
|
}
|
|
|
|
let features;
|
|
if (AppConstants.platform == "win")
|
|
features = "chrome,centerscreen,dependent";
|
|
else if (AppConstants.platform == "macosx")
|
|
features = "chrome,resizable=no,minimizable=no";
|
|
else
|
|
features = "chrome,centerscreen,dependent,dialog=no";
|
|
|
|
window.openDialog("chrome://messenger/content/aboutDialog.xul", "About", features);
|
|
}
|
|
|
|
/**
|
|
* Opens the support page based on the app.support.baseURL pref.
|
|
*/
|
|
function openSupportURL()
|
|
{
|
|
openFormattedURL("app.support.baseURL");
|
|
}
|
|
|
|
/**
|
|
* Fetches the url for the passed in pref name, formats it and then loads it in the default
|
|
* browser.
|
|
*
|
|
* @param aPrefName - name of the pref that holds the url we want to format and open
|
|
*/
|
|
function openFormattedURL(aPrefName)
|
|
{
|
|
var urlToOpen = Services.urlFormatter.formatURLPref(aPrefName);
|
|
|
|
var uri = Services.io.newURI(urlToOpen, null, null);
|
|
|
|
var protocolSvc = Components.classes["@mozilla.org/uriloader/external-protocol-service;1"]
|
|
.getService(Components.interfaces.nsIExternalProtocolService);
|
|
protocolSvc.loadURI(uri);
|
|
}
|
|
|
|
/**
|
|
* Prompt the user to restart the browser in safe mode.
|
|
*/
|
|
function safeModeRestart()
|
|
{
|
|
// prompt the user to confirm
|
|
let bundle = Services.strings.createBundle(
|
|
"chrome://messenger/locale/messenger.properties");
|
|
let promptTitle = bundle.GetStringFromName("safeModeRestartPromptTitle");
|
|
let promptMessage = bundle.GetStringFromName("safeModeRestartPromptMessage");
|
|
let restartText = bundle.GetStringFromName("safeModeRestartButton");
|
|
let buttonFlags = (Services.prompt.BUTTON_POS_0 *
|
|
Services.prompt.BUTTON_TITLE_IS_STRING) +
|
|
(Services.prompt.BUTTON_POS_1 *
|
|
Services.prompt.BUTTON_TITLE_CANCEL) +
|
|
Services.prompt.BUTTON_POS_0_DEFAULT;
|
|
|
|
let rv = Services.prompt.confirmEx(window, promptTitle, promptMessage,
|
|
buttonFlags, restartText, null, null,
|
|
null, {});
|
|
if (rv == 0) {
|
|
let environment = Components.classes["@mozilla.org/process/environment;1"]
|
|
.getService(Components.interfaces.nsIEnvironment);
|
|
environment.set("MOZ_SAFE_MODE_RESTART", "1");
|
|
BrowserUtils.restartApplication();
|
|
}
|
|
}
|
|
|
|
function getMostRecentMailWindow() {
|
|
let win = null;
|
|
if (AppConstants.platform != "win") {
|
|
// Platforms other than Windows have a broken z-order...
|
|
win = Services.wm.getMostRecentWindow("mail:3pane", true);
|
|
|
|
// If we're lucky, this isn't a popup, and we can just return this.
|
|
if (win && win.document.documentElement.getAttribute("chromehidden")) {
|
|
win = null;
|
|
let windowList = Services.wm.getEnumerator("mail:3pane", true);
|
|
// This is oldest to newest, so this gets a bit ugly.
|
|
while (windowList.hasMoreElements()) {
|
|
let nextWin = windowList.getNext();
|
|
if (!nextWin.document.documentElement.getAttribute("chromehidden"))
|
|
win = nextWin;
|
|
}
|
|
}
|
|
} else {
|
|
let windowList = Services.wm.getZOrderDOMWindowEnumerator("mail:3pane", true);
|
|
if (!windowList.hasMoreElements())
|
|
return null;
|
|
|
|
win = windowList.getNext();
|
|
while (win.document.documentElement.getAttribute("chromehidden")) {
|
|
if (!windowList.hasMoreElements())
|
|
return null;
|
|
|
|
win = windowList.getNext();
|
|
}
|
|
}
|
|
|
|
return win;
|
|
}
|
|
|
|
/**
|
|
* Create a sanitized display name for an attachment in order to help prevent
|
|
* people from hiding malicious extensions behind a run of spaces, etc. To do
|
|
* this, we strip leading/trailing whitespace and collapse long runs of either
|
|
* whitespace or identical characters. Windows especially will drop trailing
|
|
* dots and whitespace from filename extensions.
|
|
*
|
|
* @param aAttachment the AttachmentInfo object
|
|
* @return a sanitized display name for the attachment
|
|
*/
|
|
function SanitizeAttachmentDisplayName(aAttachment)
|
|
{
|
|
let displayName = aAttachment.name.trim().replace(/\s+/g, " ");
|
|
if (AppConstants.platform == "win")
|
|
displayName = displayName.replace(/[ \.]+$/, "");
|
|
return displayName.replace(/(.)\1{9,}/g, "$1…$1");
|
|
}
|
|
|
|
/**
|
|
* Create a TransferData object for a message attachment, either from the
|
|
* message reader or the composer.
|
|
*
|
|
* @param aAttachment the attachment object
|
|
* @return the TransferData
|
|
*/
|
|
function CreateAttachmentTransferData(aAttachment)
|
|
{
|
|
// For now, disallow drag-and-drop on cloud attachments. In the future, we
|
|
// should allow this.
|
|
if (aAttachment.contentType == "text/x-moz-deleted" ||
|
|
aAttachment.sendViaCloud)
|
|
return null;
|
|
|
|
var name = aAttachment.name || aAttachment.displayName;
|
|
|
|
var data = new TransferData();
|
|
if (aAttachment.url && name)
|
|
{
|
|
// Only add type/filename info for non-file URLs that don't already
|
|
// have it.
|
|
if (/(^file:|&filename=)/.test(aAttachment.url))
|
|
var info = aAttachment.url;
|
|
else
|
|
var info = aAttachment.url + "&type=" + aAttachment.contentType +
|
|
"&filename=" + encodeURIComponent(name);
|
|
|
|
data.addDataForFlavour("text/x-moz-url",
|
|
info + "\n" + name + "\n" + aAttachment.size);
|
|
data.addDataForFlavour("text/x-moz-url-data", aAttachment.url);
|
|
data.addDataForFlavour("text/x-moz-url-desc", name);
|
|
data.addDataForFlavour("application/x-moz-file-promise-url",
|
|
aAttachment.url);
|
|
data.addDataForFlavour("application/x-moz-file-promise",
|
|
new nsFlavorDataProvider(), 0,
|
|
Components.interfaces.nsISupports);
|
|
}
|
|
return data;
|
|
}
|
|
|
|
function nsFlavorDataProvider()
|
|
{
|
|
}
|
|
|
|
nsFlavorDataProvider.prototype =
|
|
{
|
|
QueryInterface : function(iid)
|
|
{
|
|
if (iid.equals(Components.interfaces.nsIFlavorDataProvider) ||
|
|
iid.equals(Components.interfaces.nsISupports))
|
|
return this;
|
|
throw Components.results.NS_NOINTERFACE;
|
|
},
|
|
|
|
getFlavorData : function(aTransferable, aFlavor, aData, aDataLen)
|
|
{
|
|
// get the url for the attachment
|
|
if (aFlavor == "application/x-moz-file-promise")
|
|
{
|
|
var urlPrimitive = { };
|
|
var dataSize = { };
|
|
aTransferable.getTransferData("application/x-moz-file-promise-url",
|
|
urlPrimitive, dataSize);
|
|
|
|
var srcUrlPrimitive = urlPrimitive.value.QueryInterface(Components.interfaces.nsISupportsString);
|
|
|
|
// now get the destination file location from kFilePromiseDirectoryMime
|
|
var dirPrimitive = {};
|
|
aTransferable.getTransferData("application/x-moz-file-promise-dir",
|
|
dirPrimitive, dataSize);
|
|
var destDirectory = dirPrimitive.value.QueryInterface(Components.interfaces.nsILocalFile);
|
|
|
|
// now save the attachment to the specified location
|
|
// XXX: we need more information than just the attachment url to save it,
|
|
// fortunately, we have an array of all the current attachments so we can
|
|
// cheat and scan through them
|
|
|
|
var attachment = null;
|
|
for (let index of currentAttachments.keys())
|
|
{
|
|
attachment = currentAttachments[index];
|
|
if (attachment.url == srcUrlPrimitive)
|
|
break;
|
|
}
|
|
|
|
// call our code for saving attachments
|
|
if (attachment)
|
|
{
|
|
var name = attachment.name || attachment.displayName;
|
|
var destFilePath = messenger.saveAttachmentToFolder(attachment.contentType,
|
|
attachment.url,
|
|
encodeURIComponent(name),
|
|
attachment.uri,
|
|
destDirectory);
|
|
aData.value = destFilePath.QueryInterface(Components.interfaces.nsISupports);
|
|
aDataLen.value = 4;
|
|
}
|
|
}
|
|
}
|
|
}
|