Bug 1748449 - Part 4: Hide invitation display when switching tabs or folders. r=aleca

Also hides the message body when the invitation display is shown.

Differential Revision: https://phabricator.services.mozilla.com/D151040

--HG--
extra : histedit_source : 86d839553c7570a30f7cf6411caaeb21b981759b
This commit is contained in:
Lasana Murray 2022-07-26 20:57:36 +00:00
Родитель 2fdcc9feaf
Коммит efa2ae47c8
11 изменённых файлов: 237 добавлений и 31 удалений

Просмотреть файл

@ -12,18 +12,37 @@
*/
const CalInvitationDisplay = {
/**
* The node we render the invitation to.
* The hbox element that wraps the invitation. We need to make this
* scrollable so larger invitations can be seen.
*
* @type {XULElement}
*/
container: null,
/**
* The node the invitation details are rendered into.
*
* @type {HTMLElement}
*/
display: null,
/**
* The <browser> element that displays the message body. This is hidden
* when the invitation details are displayed.
*/
body: null,
/**
* Creates a new instance and sets up listeners.
*/
init() {
this.container = document.getElementById("messagepaneContainer");
this.display = document.getElementById("calendarInvitationDisplay");
this.body = document.getElementById("messagepane");
window.addEventListener("onItipItemCreation", this);
window.addEventListener("messagepane-unloaded", this);
document.getElementById("msgHeaderView").addEventListener("message-header-pane-hidden", this);
gMessageListeners.push(this);
},
@ -38,28 +57,58 @@
case "DOMContentLoaded":
this.init();
break;
case "onItipItemCreation":
let panel = document.createElement("calendar-invitation-panel");
this.display.replaceChildren(panel);
panel.itipItem = evt.detail;
this.display.hidden = false;
this.show(evt.detail);
break;
case "messagepane-unloaded":
case "message-header-pane-hidden":
this.hide();
break;
default:
break;
}
},
/**
* Removes the panel from view each time a new message is loaded.
* Hide the invitation display each time a new message to display is
* detected. If the message contains an invitation it will be displayed
* in the "onItipItemCreation" handler.
*/
onStartHeaders() {
this.display.hidden = true;
this.display.replaceChildren();
this.hide();
},
/**
* Called by messageHeaderSink.
*/
onEndHeaders() {},
/**
* Displays the invitation display with the data from the provided
* calIItipItem.
*
* @param {calIItipItem} item
*/
show(item) {
this.container.classList.add("scrollable");
let panel = document.createElement("calendar-invitation-panel");
this.display.replaceChildren(panel);
panel.itipItem = item;
this.display.hidden = false;
this.body.hidden = true;
},
/**
* Removes the invitation display from view, resetting any changes made
* to the container and message pane.
*/
hide() {
this.container.classList.remove("scrollable");
this.display.hidden = true;
this.display.replaceChildren();
this.body.hidden = false;
},
};
window.addEventListener("DOMContentLoaded", CalInvitationDisplay, { once: true });

Просмотреть файл

@ -60,16 +60,11 @@ var calImipBar = {
// Add a listener to gMessageListeners defined in msgHdrView.js
gMessageListeners.push(calImipBar);
// We need to extend the HideMessageHeaderPane function to also hide the
// message header pane. Otherwise, the imip bar will still be shown when
// changing folders.
if (!calImipBar.tbHideMessageHeaderPane) {
calImipBar.tbHideMessageHeaderPane = HideMessageHeaderPane;
HideMessageHeaderPane = function(...args) {
calImipBar.resetBar();
calImipBar.tbHideMessageHeaderPane(...args);
};
}
// Hook into this event to hide the message header pane otherwise, the imip
// bar will still be shown when changing folders.
document.getElementById("msgHeaderView").addEventListener("message-header-pane-hidden", () => {
calImipBar.resetBar();
});
// Set up our observers
Services.obs.addObserver(calImipBar, "onItipItemCreation");

Просмотреть файл

@ -97,6 +97,20 @@
}
}
/**
* Provides the value of the title displayed as a string.
* @type {string}
*/
get fullTitle() {
return [
...this.shadowRoot.querySelectorAll(
".calendar-invitation-panel-intro, .calendar-invitation-panel-title"
),
]
.map(node => node.textContent)
.join(" ");
}
disconnectedCallback() {
document.l10n.disconnectRoot(this.shadowRoot);
}

Просмотреть файл

@ -30,6 +30,21 @@
* glanced at quickly to figure out the date of an event.
*/
class CalendarMinidate extends HTMLElement {
/**
* @type {HTMLElement}
*/
_monthSpan;
/**
* @type {HTMLElement}
*/
_daySpan;
/**
* @type {HTMLElement}
*/
_yearSpan;
constructor() {
super();
this.attachShadow({ mode: "open" });
@ -37,6 +52,9 @@
this.shadowRoot.appendChild(
document.getElementById("calendarMinidate").content.cloneNode(true)
);
this._monthSpan = this.shadowRoot.querySelector(".calendar-minidate-month");
this._daySpan = this.shadowRoot.querySelector(".calendar-minidate-day");
this._yearSpan = this.shadowRoot.querySelector(".calendar-minidate-year");
}
/**
@ -45,12 +63,18 @@
*/
set date(value) {
let { month, day, year } = getParts(cal.dtz.dateTimeToJsDate(value));
let monthSpan = this.shadowRoot.querySelector(".calendar-minidate-month");
let daySpan = this.shadowRoot.querySelector(".calendar-minidate-day");
let yearSpan = this.shadowRoot.querySelector(".calendar-minidate-year");
monthSpan.textContent = month;
daySpan.textContent = day;
yearSpan.textContent = year;
this._monthSpan.textContent = month;
this._daySpan.textContent = day;
this._yearSpan.textContent = year;
}
/**
* Provides the displayed date as a string in the format
* "month day year".
* @type {string}
*/
get fullDate() {
return `${this._monthSpan.textContent} ${this._daySpan.textContent} ${this._yearSpan.textContent}`;
}
}
customElements.define("calendar-minidate", CalendarMinidate);

Просмотреть файл

@ -27,4 +27,5 @@ skip-if = os == 'win'
[browser_imipBarRepeatCancel.js]
[browser_imipBarRepeatUpdates.js]
[browser_imipBarUpdates.js]
[browser_invitationDisplaySwitching.js]
[browser_unsupportedFreq.js]

Просмотреть файл

@ -0,0 +1,109 @@
/* 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/. */
/**
* Tests the invitation display is hidden when appropriate.
*/
"use strict";
var {
add_message_sets_to_folders,
be_in_folder,
create_folder,
create_thread,
open_folder_in_new_tab,
close_tab,
wait_for_message_display_completion,
inboxFolder,
select_click_row,
} = ChromeUtils.import("resource://testing-common/mozmill/FolderDisplayHelpers.jsm");
let folderA;
let folderB;
/**
* Copied from mail/components/extensions/test/browser/head.js. Allows an .eml
* file to be added to a folder.
*/
async function createMessageFromFile(folder, path) {
let message = await IOUtils.readUTF8(path);
// A cheap hack to make this acceptable to addMessageBatch. It works for
// existing uses but may not work for future uses.
let fromChunks = message.match(/From: .* <(.*@.*)>/);
if (fromChunks) {
let fromAddress = fromChunks[0];
message = `From ${fromAddress}\r\n${message}`;
}
folder.addMessageBatch([message]);
folder.callFilterPlugins(null);
}
/**
* Initialize the folders used for testing.
*/
add_setup(async function() {
let identity = MailServices.accounts.createIdentity();
identity.email = "receiver@example.com";
identity.valid = true;
let account = MailServices.accounts.createAccount();
account.incomingServer = MailServices.accounts.createIncomingServer(
"receiver",
"example.com",
"imap"
);
account.addIdentity(identity);
folderA = await create_folder("Folder A");
folderB = await create_folder("Folder B");
Services.prefs.setBoolPref("calendar.itip.newInvitationDisplay", true);
registerCleanupFunction(async () => {
be_in_folder(inboxFolder);
let trash = folderA.rootFolder.getFolderWithFlags(Ci.nsMsgFolderFlags.Trash);
folderA.deleteSelf(null);
folderB.deleteSelf(null);
trash.emptyTrash(null, null);
MailServices.accounts.removeAccount(account);
Services.prefs.setBoolPref("calendar.itip.newInvitationDisplay", false);
});
});
/**
* Tests the invitation display is correctly hidden when switching between
* folders or to a tab.
*/
add_task(async function testInvitationDisplaySwitching() {
let display = document.getElementById("calendarInvitationDisplay");
be_in_folder(folderA);
await add_message_sets_to_folders([folderA], [create_thread(1)]);
await createMessageFromFile(folderA, getTestFilePath("../invitations/data/single-event.eml"));
await createMessageFromFile(folderA, getTestFilePath("../invitations/data/update-minor.eml"));
info("Ensuring invitation display is initially hidden.");
select_click_row(0);
Assert.ok(display.hidden, "invitation display is hidden");
info("Ensuring invitation display is shown when a message with an invitation is selected");
select_click_row(1);
Assert.ok(!display.hidden, "invitation display is not hidden");
let panel = document.querySelector("calendar-invitation-panel");
let minidate = panel.shadowRoot.querySelector("calendar-minidate");
Assert.equal(minidate.fullDate, "Mar 16 2022");
let header = panel.shadowRoot.querySelector("calendar-invitation-panel-header");
Assert.equal(header.fullTitle, "Sender has invited you to: Single Event");
info("Ensuring invitation display is hidden when switching folders.");
be_in_folder(folderB);
Assert.ok(display.hidden, "invitation display is hidden when switching folders");
info("Ensuring invitation display is hidden when opening a folder in a new tab.");
be_in_folder(folderA);
select_click_row(1);
Assert.ok(!display.hidden);
open_folder_in_new_tab(folderB);
wait_for_message_display_completion(null);
Assert.ok(display.hidden, "invitation display is hidden when viewing a new tab");
close_tab(1);
});

Просмотреть файл

@ -23,7 +23,7 @@ var { CalendarTestUtils } = ChromeUtils.import(
"resource://testing-common/calendar/CalendarTestUtils.jsm"
);
registerCleanupFunction(() => {
registerCleanupFunction(async () => {
// Some tests that open new windows don't return focus to the main window
// in a way that satisfies mochitest, and the test times out.
Services.focus.focusedWindow = window;
@ -32,6 +32,8 @@ registerCleanupFunction(() => {
let searchInput = document.getElementById("searchInput");
searchInput.focus();
searchInput.blur();
await CalendarTestUtils.closeCalendarTab(window);
});
class EmailTransport extends CalItipDefaultEmailTransport {

Просмотреть файл

@ -280,8 +280,10 @@
#include ../../../calendar/base/content/widgets/calendar-invitation-panel.xhtml
#include ../../../calendar/base/content/widgets/calendar-minidate.xhtml
<!-- The calendar invitation panel is displayed here. -->
<html:div id="calendarInvitationDisplay" hidden="hidden"></html:div>
<vbox id="messagepaneContainer" flex="1">
<!-- The calendar invitation panel is displayed here. -->
<html:div id="calendarInvitationDisplay" hidden="hidden"></html:div>
</vbox>
<!-- message view -->
<browser id="messagepane"

Просмотреть файл

@ -753,8 +753,11 @@
<vbox id="mail-notification-top">
<!-- notificationbox will be added here lazily. -->
</vbox>
<vbox flex="1" class="messagepane-container">
<html:div id="calendarInvitationDisplay" hidden="hidden"></html:div>
<vbox id="messagepaneContainer" flex="1">
<html:div id="calendarInvitationDisplay" hidden="true">
<!-- The calendar invitation display widget is loaded
here. -->
</html:div>
<!-- The messagepanewrapper hbox exists to allow
extensions to add sidebars to the message. -->
<hbox id="messagepanewrapper" flex="1">

Просмотреть файл

@ -1298,6 +1298,9 @@ function HideMessageHeaderPane() {
gMessageNotificationBar.clearMsgNotifications();
// Clear the DBListener since we don't have any visible UI to update.
clearFolderDBListener();
// Now let interested listeners know the pane has been hidden.
header.dispatchEvent(new Event("message-header-pane-hidden"));
}
/**

Просмотреть файл

@ -1743,3 +1743,7 @@ printpreview-pagination:focus-within,
.dialogOverlay[topmost="true"] {
background-color: rgba(28, 27, 34, 0.45);
}
#messagepaneContainer.scrollable {
overflow-y: auto;
}