Bug 1626066 - Move calendar modes code out of messenger-overlay-sidebar.js. r=darktrojan
authorPaul Morris <paul@thunderbird.net>
Thu, 02 Apr 2020 13:42:37 +0300
changeset 38668 3659c628e59178dfd5e930f16e4d1336201e658e
parent 38667 e9593a4b546ce716c4389b54307d4152dbd5791f
child 38669 4c4e4de548fab79aae78dbf69c3f3b0296300ec1
push id400
push userclokep@gmail.com
push dateMon, 04 May 2020 18:56:09 +0000
reviewersdarktrojan
bugs1626066
Bug 1626066 - Move calendar modes code out of messenger-overlay-sidebar.js. r=darktrojan
calendar/base/content/calendar-command-controller.js
calendar/base/content/calendar-modes.js
calendar/base/content/today-pane.js
calendar/base/jar.mn
calendar/lightning/content/messenger-overlay-sidebar.js
mail/base/content/hiddenWindow.xhtml
mail/base/content/messenger.xhtml
--- a/calendar/base/content/calendar-command-controller.js
+++ b/calendar/base/content/calendar-command-controller.js
@@ -3,16 +3,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /* import-globals-from ../../../../toolkit/content/globalOverlay.js */
 /* import-globals-from ../../lightning/content/messenger-overlay-sidebar.js */
 /* import-globals-from ../../resources/content/publish.js */
 /* import-globals-from agenda-listbox-utils.js */
 /* import-globals-from calendar-clipboard.js */
 /* import-globals-from calendar-management.js */
+/* import-globals-from calendar-modes.js */
 /* import-globals-from calendar-task-tree-utils.js */
 /* import-globals-from calendar-ui-utils.js */
 /* import-globals-from calendar-unifinder.js */
 /* import-globals-from calendar-views-utils.js */
 /* import-globals-from import-export.js */
 
 /* globals switchCalendarView */
 
copy from calendar/lightning/content/messenger-overlay-sidebar.js
copy to calendar/base/content/calendar-modes.js
--- a/calendar/lightning/content/messenger-overlay-sidebar.js
+++ b/calendar/base/content/calendar-modes.js
@@ -1,281 +1,22 @@
 /* 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/. */
 
-/* exported calendarOnToolbarsPopupShowing, customizeMailToolbarForTabType,
- *          gCurrentMode, InitViewCalendarPaneMenu, loadCalendarComponent,
- *          onToolbarsPopupShowingWithMode, openInvitationsDialog, refreshUIBits,
- *          rescheduleInvitationsUpdate, switchCalendarView
+/* exported calSwitchToCalendarMode, calSwitchToMode, calSwitchToTaskMode,
+ *          changeMode
  */
 
-/* import-globals-from ../../base/content/calendar-command-controller.js */
-/* import-globals-from ../../base/content/calendar-invitations-manager.js */
-/* import-globals-from ../../base/content/today-pane.js */
-/* import-globals-from lightning-item-panel.js */
-
-/* globals gLastShownCalendarView */
-
-var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
-var { AddonManager } = ChromeUtils.import("resource://gre/modules/AddonManager.jsm");
-var { cal } = ChromeUtils.import("resource:///modules/calendar/calUtils.jsm");
-
-/**
- * Loads the calendar component. Called once at startup as the application
- * window is loaded, before tabs are restored.
- */
-async function loadCalendarComponent() {
-  await uninstallLightningAddon();
-
-  // Check if the binary component was loaded
-  checkCalendarBinaryComponent();
-
-  document
-    .getElementById("calendarDisplayDeck")
-    .addEventListener("select", LtnObserveDisplayDeckChange, true);
-
-  // Take care of common initialization
-  await commonInitCalendar();
-
-  // Add an unload function to the window so we don't leak any listeners
-  window.addEventListener("unload", ltnFinish);
-
-  // Set up invitations manager
-  scheduleInvitationsUpdate(FIRST_DELAY_STARTUP);
-  cal.getCalendarManager().addObserver(gInvitationsCalendarManagerObserver);
-
-  let filter = document.getElementById("task-tree-filtergroup");
-  filter.value = filter.value || "all";
-  changeMode();
-
-  let mailContextPopup = document.getElementById("mailContext");
-  if (mailContextPopup) {
-    mailContextPopup.addEventListener("popupshowing", gCalSetupMailContext.popup);
-  }
-
-  // Setup customizeDone handlers for our toolbars
-  let toolbox = document.getElementById("calendar-toolbox");
-  toolbox.customizeDone = function(aEvent) {
-    MailToolboxCustomizeDone(aEvent, "CustomizeCalendarToolbar");
-  };
-  toolbox = document.getElementById("task-toolbox");
-  toolbox.customizeDone = function(aEvent) {
-    MailToolboxCustomizeDone(aEvent, "CustomizeTaskToolbar");
-  };
-
-  updateTodayPaneButton();
-
-  Services.obs.notifyObservers(window, "lightning-startup-done");
-}
-
-/**
- * Uninstall the Lightning calendar addon, now that calendar is in Thunderbird.
- */
-async function uninstallLightningAddon() {
-  try {
-    let addon = await AddonManager.getAddonByID("{e2fda1a4-762b-4020-b5ad-a41df1933103}");
-    if (addon) {
-      await addon.uninstall();
-    }
-  } catch (err) {
-    console.error("Error while attempting to uninstall Lightning addon:", err);
-  }
-}
-
-/* Called at midnight to tell us to redraw date-specific widgets.  Do NOT call
- * this for normal refresh, since it also calls scheduleMidnightRefresh.
- */
-function refreshUIBits() {
-  try {
-    getMinimonth().refreshDisplay();
-
-    // Refresh the current view and just allow the refresh for the others
-    // views when will be displayed.
-    let currView = currentView();
-    currView.goToDay();
-    let views = ["day-view", "week-view", "multiweek-view", "month-view"];
-    for (let view of views) {
-      if (view != currView.id) {
-        document.getElementById(view).mToggleStatus = -1;
-      }
-    }
-
-    if (!TodayPane.showsToday()) {
-      TodayPane.setDay(cal.dtz.now());
-    }
-
-    // update the unifinder
-    refreshEventTree();
-
-    // update today's date on todaypane button
-    updateTodayPaneButtonDate();
-  } catch (exc) {
-    cal.ASSERT(false, exc);
-  }
-
-  // schedule our next update...
-  scheduleMidnightUpdate(refreshUIBits);
-}
-
-/**
- * Updates button structure to enable a duble image to both sides of the label.
- */
-function updateTodayPaneButton() {
-  let todaypane = document.getElementById("calendar-status-todaypane-button");
-
-  let iconStack = document.createXULElement("stack");
-  iconStack.setAttribute("pack", "center");
-  iconStack.setAttribute("align", "end");
-
-  let iconBegin = document.createXULElement("image");
-  iconBegin.classList.add("toolbarbutton-icon-begin");
-
-  let iconLabel = document.createXULElement("label");
-  iconLabel.classList.add("toolbarbutton-day-text");
-
-  let dayNumber = cal.l10n.getDateFmtString(`day.${cal.dtz.now().day}.number`);
-  iconLabel.textContent = dayNumber;
-
-  iconStack.appendChild(iconBegin);
-  iconStack.appendChild(iconLabel);
+/* import-globals-from calendar-views-utils.js */
+/* import-globals-from today-pane.js */
 
-  let iconEnd = document.createXULElement("image");
-  iconEnd.classList.add("toolbarbutton-icon-end");
-
-  let oldImage = todaypane.querySelector(".toolbarbutton-icon");
-  todaypane.replaceChild(iconStack, oldImage);
-  todaypane.appendChild(iconEnd);
-
-  let calSidebar = document.getElementById("ltnSidebar");
-  todaypane.setAttribute("checked", !calSidebar.getAttribute("collapsed"));
-}
-
-/**
- * Updates the date number in the calendar icon of the todaypane button
- */
-function updateTodayPaneButtonDate() {
-  let todaypane = document.getElementById("calendar-status-todaypane-button");
-
-  let dayNumber = cal.l10n.getDateFmtString(`day.${cal.dtz.now().day}.number`);
-  todaypane.querySelector(".toolbarbutton-day-text").textContent = dayNumber;
-}
-
-/**
- * This function has the sole responsibility to switch back to
- * mail mode (by calling calSwitchToMode("mail")) if we are getting
- * notifications from other panels (besides the calendar views)
- * but find out that we're not in mail mode. This situation can
- * for example happen if we're in calendar mode but the 'new mail'
- * slider gets clicked and wants to display the appropriate mail.
- * All necessary logic for switching between the different modes
- * should live inside of the corresponding functions like:
- * - calSwitchToCalendarMode()
- * - calSwitchToTaskMode()
- * - calSwitchToMode()
- */
-function LtnObserveDisplayDeckChange(event) {
-  let deck = event.target;
-
-  // Bug 309505: The 'select' event also fires when we change the selected
-  // panel of calendar-view-box.  Workaround with this check.
-  if (deck.id != "calendarDisplayDeck") {
-    return;
-  }
-
-  let id = deck.selectedPanel && deck.selectedPanel.id;
-
-  // Switch back to mail mode in case we find that this
-  // notification has been fired but we're still in calendar or task mode.
-  // Specifically, switch back if we're *not* in mail mode but the notification
-  // did *not* come from either the "calendar-view-box" or the "calendar-task-box".
-  if (
-    (gCurrentMode == "calendar" || gCurrentMode == "task") &&
-    id != "calendar-view-box" &&
-    id != "calendar-task-box"
-  ) {
-    calSwitchToMode("mail");
-  }
-}
-
-function ltnFinish() {
-  cal.getCalendarManager().removeObserver(gInvitationsCalendarManagerObserver);
-
-  // Remove listener for mailContext.
-  let mailContextPopup = document.getElementById("mailContext");
-  if (mailContextPopup) {
-    mailContextPopup.removeEventListener("popupshowing", gCalSetupMailContext.popup);
-  }
+/* globals ensureUnifinderLoaded gLastShownCalendarView */
 
-  // Common finish steps
-  commonFinishCalendar();
-}
-
-// == invitations link
-var FIRST_DELAY_STARTUP = 100;
-var FIRST_DELAY_RESCHEDULE = 100;
-var FIRST_DELAY_REGISTER = 10000;
-var FIRST_DELAY_UNREGISTER = 0;
-
-var gInvitationsOperationListener = {
-  mCount: 0,
-
-  QueryInterface: ChromeUtils.generateQI([Ci.calIOperationListener]),
-  onOperationComplete(aCalendar, aStatus, aOperationType, aId, aDetail) {
-    let invitationsBox = document.getElementById("calendar-invitations-panel");
-    if (Components.isSuccessCode(aStatus)) {
-      let value = cal.l10n.getLtnString("invitationsLink.label", [this.mCount]);
-      document.getElementById("calendar-invitations-label").value = value;
-      setElementValue(invitationsBox, this.mCount < 1 && "true", "hidden");
-    } else {
-      invitationsBox.setAttribute("hidden", "true");
-    }
-    this.mCount = 0;
-  },
-
-  onGetResult(aCalendar, aStatus, aItemType, aDetail, aItems) {
-    if (Components.isSuccessCode(aStatus)) {
-      this.mCount += aItems.length;
-    }
-  },
-};
-
-var gInvitationsCalendarManagerObserver = {
-  mSideBar: this,
-
-  QueryInterface: ChromeUtils.generateQI([Ci.calICalendarManagerObserver]),
-
-  onCalendarRegistered(aCalendar) {
-    this.mSideBar.rescheduleInvitationsUpdate(FIRST_DELAY_REGISTER);
-  },
-
-  onCalendarUnregistering(aCalendar) {
-    this.mSideBar.rescheduleInvitationsUpdate(FIRST_DELAY_UNREGISTER);
-  },
-
-  onCalendarDeleting(aCalendar) {},
-};
-
-function scheduleInvitationsUpdate(firstDelay) {
-  gInvitationsOperationListener.mCount = 0;
-  getInvitationsManager().scheduleInvitationsUpdate(firstDelay, gInvitationsOperationListener);
-}
-
-function rescheduleInvitationsUpdate(firstDelay) {
-  getInvitationsManager().cancelInvitationsUpdate();
-  scheduleInvitationsUpdate(firstDelay);
-}
-
-function openInvitationsDialog() {
-  getInvitationsManager().cancelInvitationsUpdate();
-  gInvitationsOperationListener.mCount = 0;
-  getInvitationsManager().openInvitationsDialog(gInvitationsOperationListener, () =>
-    scheduleInvitationsUpdate(FIRST_DELAY_RESCHEDULE)
-  );
-}
+var { cal } = ChromeUtils.import("resource:///modules/calendar/calUtils.jsm");
 
 /**
  * The current mode defining the current mode we're in. Allowed values are:
  *  - 'mail'
  *  - 'calendar'
  *  - 'task'
  *  - 'chat'
  *  - 'calendarEvent'
@@ -371,153 +112,8 @@ function calSwitchToTaskMode() {
     deck.selectedPanel = document.getElementById("calendar-task-box");
 
     document.getElementById("calMinimonth").setAttribute("freebusy", "true");
 
     document.commandDispatcher.updateCommands("calendar_commands");
     window.setCursor("auto");
   }
 }
-
-var gCalSetupMailContext = {
-  popup() {
-    let hasSelection = gFolderDisplay.selectedMessage != null;
-    // Disable the convert menu altogether.
-    setElementValue("mailContext-calendar-convert-menu", !hasSelection && "true", "hidden");
-  },
-};
-
-// Overwrite the InitMessageMenu function, since we never know in which order
-// the popupshowing event will be processed. This function takes care of
-// disabling the message menu when in calendar or task mode.
-function calInitMessageMenu() {
-  calInitMessageMenu.origFunc();
-
-  document.getElementById("markMenu").disabled = gCurrentMode != "mail";
-}
-calInitMessageMenu.origFunc = InitMessageMenu;
-InitMessageMenu = calInitMessageMenu;
-
-/**
- * Get the toolbox id for the current tab type.
- *
- * @return {string}  A toolbox id or null
- */
-function getToolboxIdForCurrentTabType() {
-  // A mapping from calendar tab types to toolbox ids.
-  const calendarToolboxIds = {
-    calendar: "calendar-toolbox",
-    tasks: "task-toolbox",
-    calendarEvent: "event-toolbox",
-    calendarTask: "event-toolbox",
-  };
-  let tabmail = document.getElementById("tabmail");
-  let tabType = tabmail.currentTabInfo.mode.type;
-
-  return calendarToolboxIds[tabType] || "mail-toolbox";
-}
-
-/**
- * Modify the contents of the "Toolbars" context menu for the current
- * tab type.  Menu items are inserted before (appear above) aInsertPoint.
- *
- * @param {MouseEvent} aEvent              The popupshowing event
- * @param {nsIDOMXULElement} aInsertPoint  (optional) menuitem node
- */
-function calendarOnToolbarsPopupShowing(aEvent, aInsertPoint) {
-  if (onViewToolbarsPopupShowing.length < 3) {
-    // SeaMonkey
-    onViewToolbarsPopupShowing(aEvent);
-    return;
-  }
-
-  let toolboxes = [];
-  let toolboxId = getToolboxIdForCurrentTabType();
-
-  // We add navigation-toolbox ("Menu Bar") for all tab types except
-  // mail tabs because mail-toolbox already includes navigation-toolbox,
-  // so we do not need to add it separately in that case.
-  if (toolboxId != "mail-toolbox") {
-    toolboxes.push("navigation-toolbox");
-  }
-  toolboxes.push(toolboxId);
-
-  onViewToolbarsPopupShowing(aEvent, toolboxes, aInsertPoint);
-}
-
-/**
- * Open the customize dialog for the toolbar for the current tab type.
- */
-function customizeMailToolbarForTabType() {
-  let toolboxId = getToolboxIdForCurrentTabType();
-  if (toolboxId == "event-toolbox") {
-    onCommandCustomize();
-  } else {
-    CustomizeMailToolbar(toolboxId, "CustomizeMailToolbar");
-  }
-}
-
-// Initialize the Calendar sidebar menu state
-function InitViewCalendarPaneMenu() {
-  let calSidebar = document.getElementById("ltnSidebar");
-
-  setBooleanAttribute("ltnViewCalendarPane", "checked", !calSidebar.getAttribute("collapsed"));
-
-  if (document.getElementById("appmenu_ltnViewCalendarPane")) {
-    setBooleanAttribute(
-      "appmenu_ltnViewCalendarPane",
-      "checked",
-      !calSidebar.getAttribute("collapsed")
-    );
-  }
-}
-
-/**
- * Checks if Lightning's binary component was successfully loaded.
- */
-function checkCalendarBinaryComponent() {
-  // Don't even get started if we are running ical.js or the binary component
-  // was successfully loaded.
-  if (
-    "@mozilla.org/calendar/datetime;1" in Cc ||
-    Services.prefs.getBoolPref("calendar.icaljs", false)
-  ) {
-    return;
-  }
-
-  const THUNDERBIRD_GUID = "{3550f703-e582-4d05-9a08-453d09bdfdc6}";
-  const SEAMONKEY_GUID = "{92650c4d-4b8e-4d2a-b7eb-24ecf4f6b63a}";
-  const LIGHTNING_GUID = "{e2fda1a4-762b-4020-b5ad-a41df1933103}";
-
-  AddonManager.getAddonByID(LIGHTNING_GUID, ext => {
-    if (!ext) {
-      return;
-    }
-
-    let version;
-    let appversion = Services.appinfo.version;
-    let versionparts = appversion.split(".");
-    let extbrand = cal.l10n.getLtnString("brandShortName");
-
-    switch (Services.appinfo.ID) {
-      case THUNDERBIRD_GUID: // e.g. 31.4.0 -> 3.3
-        version = ((parseInt(versionparts[0], 10) + 2) / 10).toFixed(1);
-        break;
-      case SEAMONKEY_GUID: // e.g. 2.28.4 -> 3.3
-        version = ((parseInt(versionparts[1], 10) + 5) / 10).toFixed(1);
-        break;
-    }
-
-    let text;
-    if (version && version != ext.version) {
-      let args = [extbrand, ext.version, version];
-      text = cal.l10n.getLtnString("binaryComponentKnown", args);
-    } else {
-      let brand = cal.l10n.getAnyString("branding", "brand", "brandShortName");
-      let args = [extbrand, brand, appversion, ext.version];
-      text = cal.l10n.getLtnString("binaryComponentUnknown", args);
-    }
-
-    let title = cal.l10n.getLtnString("binaryComponentTitle", [extbrand]);
-    openAddonsMgr("addons://detail/" + encodeURIComponent(LIGHTNING_GUID));
-    Services.prompt.alert(window, title, text);
-  });
-}
--- a/calendar/base/content/today-pane.js
+++ b/calendar/base/content/today-pane.js
@@ -1,15 +1,16 @@
 /* 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/. */
 
 /* import-globals-from ../../lightning/content/messenger-overlay-sidebar.js */
 /* import-globals-from agenda-listbox-utils.js */
 /* import-globals-from calendar-chrome-startup.js */
+/* import-globals-from calendar-modes.js */
 /* import-globals-from calendar-views-utils.js */
 
 /* globals switchCalendarView */
 
 var { cal } = ChromeUtils.import("resource:///modules/calendar/calUtils.jsm");
 
 /**
  * Namespace object to hold functions related to the today pane.
--- a/calendar/base/jar.mn
+++ b/calendar/base/jar.mn
@@ -19,16 +19,17 @@ calendar.jar:
     content/calendar-event-gripbar.js                           (content/calendar-event-gripbar.js)
     content/calendar-extract.js                                 (content/calendar-extract.js)
     content/calendar-invitations-manager.js                     (content/calendar-invitations-manager.js)
     content/calendar-item-bindings.js                           (content/calendar-item-bindings.js)
     content/calendar-item-editing.js                            (content/calendar-item-editing.js)
     content/calendar-management.js                              (content/calendar-management.js)
     content/calendar-menus.js                                   (content/calendar-menus.js)
     content/calendar-migration.js                               (content/calendar-migration.js)
+    content/calendar-modes.js                                   (content/calendar-modes.js)
     content/calendar-month-base-view.js                         (content/calendar-month-base-view.js)
     content/calendar-month-view.js                              (content/calendar-month-view.js)
     content/calendar-multiday-base-view.js                      (content/calendar-multiday-base-view.js)
     content/calendar-multiday-view.js                           (content/calendar-multiday-view.js)
     content/calendar-statusbar.js                               (content/calendar-statusbar.js)
     content/calendar-tabs.js                                    (content/calendar-tabs.js)
     content/calendar-task-editing.js                            (content/calendar-task-editing.js)
     content/calendar-task-tree-utils.js                         (content/calendar-task-tree-utils.js)
--- a/calendar/lightning/content/messenger-overlay-sidebar.js
+++ b/calendar/lightning/content/messenger-overlay-sidebar.js
@@ -8,17 +8,17 @@
  *          rescheduleInvitationsUpdate, switchCalendarView
  */
 
 /* import-globals-from ../../base/content/calendar-command-controller.js */
 /* import-globals-from ../../base/content/calendar-invitations-manager.js */
 /* import-globals-from ../../base/content/today-pane.js */
 /* import-globals-from lightning-item-panel.js */
 
-/* globals gLastShownCalendarView */
+/* globals calSwitchToMode, changeMode, */
 
 var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
 var { AddonManager } = ChromeUtils.import("resource://gre/modules/AddonManager.jsm");
 var { cal } = ChromeUtils.import("resource:///modules/calendar/calUtils.jsm");
 
 /**
  * Loads the calendar component. Called once at startup as the application
  * window is loaded, before tabs are restored.
@@ -267,121 +267,16 @@ function rescheduleInvitationsUpdate(fir
 function openInvitationsDialog() {
   getInvitationsManager().cancelInvitationsUpdate();
   gInvitationsOperationListener.mCount = 0;
   getInvitationsManager().openInvitationsDialog(gInvitationsOperationListener, () =>
     scheduleInvitationsUpdate(FIRST_DELAY_RESCHEDULE)
   );
 }
 
-/**
- * The current mode defining the current mode we're in. Allowed values are:
- *  - 'mail'
- *  - 'calendar'
- *  - 'task'
- *  - 'chat'
- *  - 'calendarEvent'
- *  - 'calendarTask'
- *  - 'special' - For special tabs like preferences, add-ons manager, about:xyz, etc.
- * @global
- */
-var gCurrentMode = "mail";
-
-/**
- * Changes the mode (gCurrentMode) and adapts the UI to the new mode.
- * @param {string} [mode="mail"] - the new mode: 'mail', 'calendar', 'task', etc.
- */
-function changeMode(mode = "mail") {
-  gCurrentMode = mode; // eslint-disable-line no-global-assign
-
-  document
-    .querySelectorAll(
-      `menuitem[command="switch2calendar"],menuitem[command="switch2task"],
-       toolbarbutton[command="switch2calendar"],toolbarbutton[command="switch2task"]`
-    )
-    .forEach(elem => {
-      elem.setAttribute("checked", elem.getAttribute("value") == gCurrentMode);
-    });
-
-  document.querySelectorAll("calendar-modebox,calendar-modevbox").forEach(elem => {
-    elem.setAttribute("current", gCurrentMode);
-  });
-
-  TodayPane.onModeModified();
-  if (gCurrentMode != "calendar") {
-    timeIndicator.cancel();
-  }
-}
-
-/**
- * For switching to modes like "mail", "chat", "calendarEvent", "calendarTask", or "special".
- * (For "calendar" and "task" modes use calSwitchToCalendarMode and calSwitchToTaskMode.)
- *
- * @param {string} mode  The mode to switch to.
- */
-function calSwitchToMode(mode) {
-  if (!["mail", "chat", "calendarEvent", "calendarTask", "special"].includes(mode)) {
-    cal.WARN("Attempted to switch to unknown mode: " + mode);
-    return;
-  }
-  if (gCurrentMode != mode) {
-    const previousMode = gCurrentMode;
-    changeMode(mode);
-
-    if (previousMode == "calendar" || previousMode == "task") {
-      document.commandDispatcher.updateCommands("calendar_commands");
-    }
-    window.setCursor("auto");
-  }
-}
-
-/**
- * Switches to the calendar mode.
- */
-function calSwitchToCalendarMode() {
-  if (gCurrentMode != "calendar") {
-    changeMode("calendar");
-
-    // display the calendar panel on the display deck
-    let deck = document.getElementById("calendarDisplayDeck");
-    deck.selectedPanel = document.getElementById("calendar-view-box");
-
-    // show the last displayed type of calendar view
-    switchToView(gLastShownCalendarView.get());
-    document.getElementById("calMinimonth").setAttribute("freebusy", "true");
-
-    document.commandDispatcher.updateCommands("calendar_commands");
-    window.setCursor("auto");
-
-    // make sure the view is sized correctly
-    document.dispatchEvent(new CustomEvent("viewresize", { bubbles: true }));
-
-    // Load the unifinder if it isn't already loaded.
-    ensureUnifinderLoaded();
-  }
-}
-
-/**
- * Switches to the task mode.
- */
-function calSwitchToTaskMode() {
-  if (gCurrentMode != "task") {
-    changeMode("task");
-
-    // display the task panel on the display deck
-    let deck = document.getElementById("calendarDisplayDeck");
-    deck.selectedPanel = document.getElementById("calendar-task-box");
-
-    document.getElementById("calMinimonth").setAttribute("freebusy", "true");
-
-    document.commandDispatcher.updateCommands("calendar_commands");
-    window.setCursor("auto");
-  }
-}
-
 var gCalSetupMailContext = {
   popup() {
     let hasSelection = gFolderDisplay.selectedMessage != null;
     // Disable the convert menu altogether.
     setElementValue("mailContext-calendar-convert-menu", !hasSelection && "true", "hidden");
   },
 };
 
--- a/mail/base/content/hiddenWindow.xhtml
+++ b/mail/base/content/hiddenWindow.xhtml
@@ -72,16 +72,17 @@
 <script src="chrome://global/content/macWindowMenu.js"/>
 #endif
 
 <script src="chrome://lightning/content/lightning-utils.js"/>
 <script src="chrome://lightning/content/imip-bar.js"/>
 <script src="chrome://calendar/content/calendar-management.js"/>
 <script src="chrome://calendar/content/calendar-ui-utils.js"/>
 <script src="chrome://calendar/content/calendar-tabs.js"/>
+<script src="chrome://calendar/content/calendar-modes.js"/>
 <script src="chrome://lightning/content/messenger-overlay-sidebar.js"/>
 <script src="chrome://calendar/content/calendar-day-label.js"/>
 <script src="chrome://calendar/content/calendar-clipboard.js"/>
 <script src="chrome://calendar/content/import-export.js"/>
 <script src="chrome://calendar/content/publish.js"/>
 <script src="chrome://calendar/content/calendar-item-editing.js"/>
 <script src="chrome://calendar/content/calendar-chrome-startup.js"/>
 <script src="chrome://calendar/content/mouseoverPreviews.js"/>
--- a/mail/base/content/messenger.xhtml
+++ b/mail/base/content/messenger.xhtml
@@ -221,16 +221,17 @@
 <!-- calendar imip bar -->
 <script src="chrome://lightning/content/lightning-utils.js"/>
 <script src="chrome://lightning/content/imip-bar.js"/>
 <!-- calendar-management.js also needed for multiple calendar support and today pane -->
 <script src="chrome://calendar/content/calendar-management.js"/>
 <script src="chrome://calendar/content/calendar-ui-utils.js"/>
 
 <script src="chrome://calendar/content/calendar-tabs.js"/>
+<script src="chrome://calendar/content/calendar-modes.js"/>
 <script src="chrome://lightning/content/messenger-overlay-sidebar.js"/>
 
 <script src="chrome://calendar/content/calendar-day-label.js"/>
 
 <!-- NEEDED FOR CLIPBOARD SUPPORT -->
 <script src="chrome://calendar/content/calendar-clipboard.js"/>
 
 <!-- NEEDED FOR IMPORT / EXPORT SUPPORT -->