diff --git a/calendar/base/content/dialogs/calendar-dialog-utils.js b/calendar/base/content/dialogs/calendar-dialog-utils.js
index 30215c1db0..561ddf5e84 100644
--- a/calendar/base/content/dialogs/calendar-dialog-utils.js
+++ b/calendar/base/content/dialogs/calendar-dialog-utils.js
@@ -4,7 +4,7 @@
/* exported gInTab, gMainWindow, gTabmail, intializeTabOrWindowVariables,
* dispose, setDialogId, loadReminders, saveReminder,
- * commonUpdateReminder, updateLink, rearrangeAttendees,
+ * commonUpdateReminder, updateLink,
* adaptScheduleAgent, sendMailToOrganizer,
* openAttachmentFromItemSummary,
*/
@@ -572,168 +572,6 @@ function updateLink(itemUrlString, linkRow, urlLink) {
}
}
-/**
- * Set up attendees in event and summary dialog.
- *
- * @param {calIAttendee[]} attendees - The attendees.
- * @param {Element} container - Element containing attendees rows, template, etc.
- * @param {number} attendeesInRow - The number of attendees that can fit in each row.
- * @param {number} maxLabelWidth - Maximum width of the label.
- * @return {{attendeesInRow: number, maxLabelWidth: number}} The new values.
- */
-function setupAttendees(attendees, container, attendeesInRow, maxLabelWidth) {
- let attBox = container.querySelector(".item-attendees-box");
- let attBoxRows = attBox.getElementsByClassName("item-attendees-row");
- let newAttendeesInRow = attendeesInRow;
- let newMaxLabelWidth = maxLabelWidth;
-
- if (attendees && attendees.length > 0) {
- // cloning of the template nodes
- let row = container.querySelector(".item-attendees-box-template .item-attendees-row");
-
- let clonedRow = row.cloneNode(false);
- let clonedCell = row.querySelector("box:nth-of-type(1)").cloneNode(true);
- let clonedSpacer = row.querySelector("box:nth-of-type(2)").cloneNode(false);
-
- // determining of attendee box setup
- let inRow = attendeesInRow || -1;
- if (inRow == -1) {
- inRow = determineAttendeesInRow(maxLabelWidth);
- newAttendeesInRow = inRow;
- } else {
- while (attBoxRows.length > 0) {
- attBox.removeChild(attBoxRows[0]);
- }
- }
-
- // set up of the required nodes
- let maxRows = Math.ceil(attendees.length / inRow);
- let inLastRow = attendees.length - (maxRows - 1) * inRow;
- let attCount = 0;
- while (attBox.getElementsByClassName("item-attendees-row").length < maxRows) {
- let newRow = clonedRow.cloneNode(false);
- let row = attBox.appendChild(newRow);
- row.removeAttribute("hidden");
- let rowCount = attBox.getElementsByClassName("item-attendees-row").length;
- let reqAtt = rowCount == maxRows ? inLastRow : inRow;
- // we add as many attendee cells as required
- while (row.children.length < reqAtt) {
- let newCell = clonedCell.cloneNode(true);
- let cell = row.appendChild(newCell);
- let icon = cell.getElementsByTagName("img")[0];
- let text = cell.getElementsByTagName("label")[0];
- let attendee = attendees[attCount];
-
- let label =
- attendee.commonName && attendee.commonName.length
- ? attendee.commonName
- : attendee.toString();
- let userType = attendee.userType || "INDIVIDUAL";
- let role = attendee.role || "REQ-PARTICIPANT";
- let partstat = attendee.participationStatus || "NEEDS-ACTION";
-
- icon.setAttribute("partstat", partstat);
- icon.setAttribute("usertype", userType);
- icon.setAttribute("role", role);
- cell.setAttribute("attendeeid", attendee.id);
- cell.removeAttribute("hidden");
-
- let userTypeString = cal.l10n.getCalString("dialog.tooltip.attendeeUserType2." + userType, [
- attendee.toString(),
- ]);
- let roleString = cal.l10n.getCalString("dialog.tooltip.attendeeRole2." + role, [
- userTypeString,
- ]);
- let partstatString = cal.l10n.getCalString("dialog.tooltip.attendeePartStat2." + partstat, [
- label,
- ]);
- let tooltip = cal.l10n.getCalString("dialog.tooltip.attendee.combined", [
- roleString,
- partstatString,
- ]);
-
- let del = cal.itip.resolveDelegation(attendee, attendees);
- if (del.delegators != "") {
- del.delegators = cal.l10n.getCalString("dialog.attendee.append.delegatedFrom", [
- del.delegators,
- ]);
- label += " " + del.delegators;
- tooltip += " " + del.delegators;
- }
- if (del.delegatees != "") {
- del.delegatees = cal.l10n.getCalString("dialog.attendee.append.delegatedTo", [
- del.delegatees,
- ]);
- tooltip += " " + del.delegatees;
- }
-
- text.setAttribute("value", label);
- cell.setAttribute("tooltiptext", tooltip);
- attCount++;
- }
- // we fill the row with placeholders if required
- if (attBox.getElementsByClassName("item-attendees-row").length > 1 && inRow > 1) {
- while (row.children.length < inRow) {
- let newSpacer = clonedSpacer.cloneNode(true);
- newSpacer.removeAttribute("hidden");
- row.appendChild(newSpacer);
- }
- }
- }
-
- // determining of the max width of an attendee label - this needs to
- // be done only once and is obsolete in case of resizing
- if (!maxLabelWidth) {
- let maxWidth = 0;
- for (let cell of attBox.getElementsByClassName("item-attendees-cell")) {
- cell = cell.cloneNode(true);
- cell.removeAttribute("flex");
- cell.getElementsByTagName("label")[0].removeAttribute("flex");
- maxWidth = cell.clientWidth > maxWidth ? cell.clientWidth : maxWidth;
- }
- newMaxLabelWidth = maxWidth;
- }
- } else {
- while (attBoxRows.length > 0) {
- attBox.removeChild(attBoxRows[0]);
- }
- }
- return { attendeesInRow: newAttendeesInRow, maxLabelWidth: newMaxLabelWidth };
-}
-
-/**
- * Re-arranges the attendees on dialog resizing in event and summary dialog
- *
- * @param {calIAttendee[]} attendees - The attendees.
- * @param {Element} parent - Element containing attendees rows, template, etc.
- * @param {number} attendeesInRow - The number of attendees that can fit in each row.
- * @param {number} maxLabelWidth - Maximum width of the label.
- * @return {{attendeesInRow: number, maxLabelWidth: number}} The new values.
- */
-function rearrangeAttendees(attendees, parent, attendeesInRow, maxLabelWidth) {
- if (attendees && attendees.length > 0 && attendeesInRow) {
- let inRow = determineAttendeesInRow(maxLabelWidth);
- if (inRow != attendeesInRow) {
- return setupAttendees(attendees, parent, inRow, maxLabelWidth);
- }
- }
- return { attendeesInRow, maxLabelWidth };
-}
-
-/**
- * Calculates the number of columns to distribute attendees for event and summary dialog
- *
- * @param {number} maxLabelWidth - The maximum width for the label.
- * @return {number} The number of attendees that can fit in a row.
- */
-function determineAttendeesInRow(maxLabelWidth) {
- // as default value a reasonable high value is appropriate
- // it will be recalculated anyway.
- let minWidth = maxLabelWidth || 200;
- let inRow = Math.floor(document.documentElement.clientWidth / minWidth);
- return inRow > 1 ? inRow : 1;
-}
-
/**
* Adapts the scheduling responsibility for caldav servers according to RfC 6638
* based on forceEmailScheduling preference for the respective calendar
diff --git a/calendar/base/content/dialogs/calendar-ics-file-dialog.js b/calendar/base/content/dialogs/calendar-ics-file-dialog.js
index 66a3aa8450..0f91c1668c 100644
--- a/calendar/base/content/dialogs/calendar-ics-file-dialog.js
+++ b/calendar/base/content/dialogs/calendar-ics-file-dialog.js
@@ -81,12 +81,6 @@ async function onWindowLoad() {
loadingMessage.remove();
document.addEventListener("dialogaccept", importRemainingItems);
-
- window.addEventListener("resize", () => {
- for (let summary of gModel.itemSummaries.values()) {
- summary.onWindowResize();
- }
- });
});
}
window.addEventListener("load", onWindowLoad);
diff --git a/calendar/base/content/dialogs/calendar-summary-dialog.js b/calendar/base/content/dialogs/calendar-summary-dialog.js
index b1de97542b..9b9c1c89c3 100644
--- a/calendar/base/content/dialogs/calendar-summary-dialog.js
+++ b/calendar/base/content/dialogs/calendar-summary-dialog.js
@@ -68,10 +68,6 @@ function onLoad() {
// Finish setting up the item summary custom element.
itemSummary.updateItemDetails();
- window.addEventListener("resize", () => {
- itemSummary.onWindowResize();
- });
-
updateToolbar();
updateDialogButtons(item);
diff --git a/calendar/base/content/widgets/calendar-item-summary.css b/calendar/base/content/widgets/calendar-item-summary.css
index b91a8df9d2..b496fab6c0 100644
--- a/calendar/base/content/widgets/calendar-item-summary.css
+++ b/calendar/base/content/widgets/calendar-item-summary.css
@@ -30,7 +30,10 @@
margin-inline: 0px;
}
-.calendar-summary-table .organizer-label,
.calendar-summary-table .attachments-label {
vertical-align: top;
}
+
+.item-attendees .item-attendees-list-container {
+ min-height: 48px;
+}
diff --git a/calendar/base/content/widgets/calendar-item-summary.js b/calendar/base/content/widgets/calendar-item-summary.js
index 3eb589d048..42d0cb9592 100644
--- a/calendar/base/content/widgets/calendar-item-summary.js
+++ b/calendar/base/content/widgets/calendar-item-summary.js
@@ -12,6 +12,7 @@
// Wrap in a block to prevent leaking to window scope.
{
+ var { ltn } = ChromeUtils.import("resource:///modules/calendar/ltnInvitationUtils.jsm");
var { cal } = ChromeUtils.import("resource:///modules/calendar/calUtils.jsm");
var { recurrenceStringFromItem } = ChromeUtils.import(
"resource:///modules/calendar/calRecurrenceUtils.jsm"
@@ -82,17 +83,11 @@
-
-
+
+
&read.only.organizer.label;
-
-
-
-
-
-
+
@@ -138,18 +133,6 @@
-
-
-
-
-
-
-
-
-
-
-
-
@@ -158,7 +141,8 @@
class="header"/>
-
+
+
@@ -303,15 +287,8 @@
this.mReadOnly = true;
this.mIsInvitation = false;
- this.mAttendeesInRow = null;
- this.mMaxLabelWidth = null;
-
this.mIsToDoItem = null;
- this.querySelector(".item-organizer-label").addEventListener("click", () => {
- sendMailToOrganizer(this.mItem);
- });
-
let urlLink = this.querySelector(".url-link");
urlLink.addEventListener("click", event => {
launchBrowser(urlLink.getAttribute("href"), event);
@@ -491,7 +468,7 @@
}
if (item.organizer && item.organizer.id) {
- this.updateOrganizer(item.organizer);
+ this.updateOrganizer(item);
}
let status = item.getProperty("STATUS");
@@ -577,16 +554,9 @@
let attendees = item.getAttendees();
if (attendees && attendees.length) {
this.querySelector(".item-attendees").removeAttribute("hidden");
-
- let { attendeesInRow, maxLabelWidth } = setupAttendees(
- attendees,
- this.querySelector(".item-summary-box"),
- this.mAttendeesInRow,
- this.mMaxLabelWidth
+ this.querySelector(".item-attendees-list-container").appendChild(
+ ltn.invitation.createAttendeesList(document, attendees)
);
-
- this.mAttendeesInRow = attendeesInRow;
- this.mMaxLabelWidth = maxLabelWidth;
}
}
@@ -618,60 +588,22 @@
}
}
- /**
- * Handle window resize event. Rearrange attendees.
- */
- onWindowResize() {
- let attendees = this.mItem.getAttendees();
- if (attendees.length) {
- let { attendeesInRow, maxLabelWidth } = rearrangeAttendees(
- attendees,
- this.querySelector(".item-summary-box"),
- this.mAttendeesInRow,
- this.mMaxLabelWidth
- );
- this.mAttendeesInRow = attendeesInRow;
- this.mMaxLabelWidth = maxLabelWidth;
- }
- }
-
/**
* Update the organizer part of the UI.
*
- * @param {calIAttendee} organizer - The organizer of the calendar item.
+ * @param {calIItemBase} item - The calendar item.
*/
- updateOrganizer(organizer) {
- this.querySelector(".organizer-row").removeAttribute("hidden");
- let cell = this.querySelector(".item-organizer-cell");
- let text = cell.querySelector("label");
- let icon = cell.querySelector("img");
-
- let role = organizer.role || "REQ-PARTICIPANT";
- let userType = organizer.userType || "INDIVIDUAL";
- let partstat = organizer.participationStatus || "NEEDS-ACTION";
- let orgName =
- organizer.commonName && organizer.commonName.length
- ? organizer.commonName
- : organizer.toString();
- let userTypeString = cal.l10n.getCalString("dialog.tooltip.attendeeUserType2." + userType, [
- organizer.toString(),
- ]);
- let roleString = cal.l10n.getCalString("dialog.tooltip.attendeeRole2." + role, [
- userTypeString,
- ]);
- let partstatString = cal.l10n.getCalString("dialog.tooltip.attendeePartStat2." + partstat, [
- orgName,
- ]);
- let tooltip = cal.l10n.getCalString("dialog.tooltip.attendee.combined", [
- roleString,
- partstatString,
- ]);
-
- text.setAttribute("value", orgName);
- cell.setAttribute("tooltiptext", tooltip);
- icon.setAttribute("partstat", partstat);
- icon.setAttribute("usertype", userType);
- icon.setAttribute("role", role);
+ updateOrganizer(item) {
+ this.querySelector(".item-organizer-row").removeAttribute("hidden");
+ let organizerLabel = ltn.invitation.createAttendeeLabel(
+ document,
+ item.organizer,
+ item.getAttendees()
+ );
+ let organizerName = organizerLabel.querySelector(".attendee-name");
+ organizerName.classList.add("text-link");
+ organizerName.addEventListener("click", () => sendMailToOrganizer(this.mItem));
+ this.querySelector(".item-organizer-cell").appendChild(organizerLabel);
}
/**
diff --git a/calendar/base/themes/common/calendar-attendees.css b/calendar/base/themes/common/calendar-attendees.css
index 63b68d4a96..c71e017b60 100644
--- a/calendar/base/themes/common/calendar-attendees.css
+++ b/calendar/base/themes/common/calendar-attendees.css
@@ -15,15 +15,14 @@ html|input.textbox-addressingWidget:disabled {
opacity: 0.5;
}
-.item-attendees-box {
+.item-attendees-list-container {
appearance: auto;
-moz-default-appearance: listbox;
margin: 2px 4px 0;
overflow-y: auto;
- min-height: 54px; /*at least two rows - otherwise a scrollbar (if required) wouldn't appear*/
}
-:root[lwt-tree] .item-attendees-box {
+:root[lwt-tree] .item-attendees-list-container {
appearance: none;
background-color: var(--field-background-color);
color: var(--field-text-color);
@@ -31,40 +30,36 @@ html|input.textbox-addressingWidget:disabled {
scrollbar-color: rgba(204, 204, 204, 0.5) rgba(230, 230, 235, 0.5);
}
-:root[lwt-tree-brighttext] .item-attendees-box {
+:root[lwt-tree-brighttext] .item-attendees-list-container {
scrollbar-color: rgba(249, 249, 250, 0.4) rgba(20, 20, 25, 0.3);
}
-#calendar-summary-dialog .item-attendees,
-#calendar-event-summary-dialog .item-attendees,
-#calendar-task-summary-dialog .item-attendees {
- max-height: 135px; /* displays up to four rows of attendees*/
+.attendee-list {
+ display: block;
+ padding: 0;
+ margin: 0;
}
-.item-attendees-cell {
- padding: 2px;
+.attendee-list-item {
+ display: contents;
}
-#calendar-event-dialog-inner .item-attendees-cell {
- -moz-user-focus: normal;
- margin-bottom: 1px;
- margin-inline-end: 1px;
+.attendee-label {
+ padding: 2px;
+ display: flex;
+ align-items: baseline;
}
-#calendar-event-dialog-inner .item-attendees-cell:focus {
- background-color: Highlight;
- color: Highlighttext;
+.itip-icon {
+ flex: 0 0 auto;
}
-.item-attendees-cell-label {
- border: 0;
- margin: 0 3px;
- padding: 0;
-}
-
-.item-organizer-cell {
- padding: 0;
- margin-left: 6px;
+.attendee-name {
+ margin: 0 3px;
+ flex: 0 1 auto;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
}
/* this is for the itip icon setup in calendar */
@@ -75,7 +70,6 @@ html|input.textbox-addressingWidget:disabled {
--itip-icon-usertype: -32px; /* default: INDIVIDUAL */
width: 16px;
height: 16px;
- max-height: 16px;
background-image: url(chrome://calendar/skin/shared/calendar-itip-icons.svg),
url(chrome://calendar/skin/shared/calendar-itip-icons.svg);
background-position: var(--itip-icon-partstat), var(--itip-icon-usertype) var(--itip-icon-role);
diff --git a/calendar/base/themes/common/dialogs/calendar-event-dialog.css b/calendar/base/themes/common/dialogs/calendar-event-dialog.css
index 48b3764fcc..2ad20d992b 100644
--- a/calendar/base/themes/common/dialogs/calendar-event-dialog.css
+++ b/calendar/base/themes/common/dialogs/calendar-event-dialog.css
@@ -322,8 +322,9 @@ label.label {
margin: 2px 4px;
}
-#event-grid-tabpanel-attendees > vbox > hbox > .item-attendees-box {
- margin: 2px 4px;
+#calendar-event-dialog-inner .attendee-label:focus {
+ background-color: Highlight;
+ color: Highlighttext;
}
/*--------------------------------------------------------------------
diff --git a/calendar/base/themes/common/imip.css b/calendar/base/themes/common/imip.css
index 5d55d5232f..7d8ab7a16e 100644
--- a/calendar/base/themes/common/imip.css
+++ b/calendar/base/themes/common/imip.css
@@ -2,115 +2,67 @@
* 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/. */
-.invitation-table .itip-icon {
- --itip-icon-partstat: -16px -16px; /* default: NEEDS-ACTION */
- --itip-icon-role: 0px; /* default: REQ-PARTICIPANT */
- --itip-icon-usertype: -32px; /* default: INDIVIDUAL */
- width: 16px;
- height: 16px;
- background-image: url(chrome://calendar/skin/shared/calendar-itip-icons.svg),
- url(chrome://calendar/skin/shared/calendar-itip-icons.svg);
- background-position: var(--itip-icon-partstat), var(--itip-icon-usertype) var(--itip-icon-role);
-}
-.invitation-table .itip-icon[partstat="ACCEPTED"] {
- --itip-icon-partstat: 0px 0px;
-}
-.invitation-table .itip-icon[partstat="DECLINED"] {
- --itip-icon-partstat: 0px -16px;
-}
-.invitation-table .itip-icon[partstat="DELEGATED"] {
- --itip-icon-partstat: 0px -32px;
-}
-.invitation-table .itip-icon[partstat="TENTATIVE"] {
- --itip-icon-partstat: -16px 0px;
-}
-.invitation-table .itip-icon[usertype="INDIVIDUAL"] {
- --itip-icon-usertype: -32px;
-}
-.invitation-table .itip-icon[usertype="GROUP"] {
- --itip-icon-usertype: -48px;
-}
-.invitation-table .itip-icon[usertype="RESOURCE"] {
- --itip-icon-usertype: -64px;
-}
-.invitation-table .itip-icon[usertype="ROOM"] {
- --itip-icon-usertype: -80px;
-}
-.invitation-table .itip-icon[usertype="UNKNOWN"] {
- --itip-icon-usertype: -96px;
-}
-.invitation-table .itip-icon[role="REQ-PARTICIPANT"] {
- --itip-icon-role: 0px;
-}
-.invitation-table .itip-icon[role="OPT-PARTICIPANT"] {
- --itip-icon-role: -16px;
-}
-.invitation-table .itip-icon[role="NON-PARTICIPANT"] {
- --itip-icon-role: -32px;
-}
-.invitation-table .itip-icon[role="CHAIR"] {
- --itip-icon-role: -32px;
- --itip-icon-usertype: -16px;
-}
-
-#imipHtml-attendees-row > .content,
-#imipHtml-organizer-row > .content,
-#attendee-table > tbody > tr > td,
-#organizer-table > tbody > tr > td {
- padding: 0
+.invitation-border {
+ border: 3px solid -moz-default-color;
+ margin-inline-start: auto;
+ margin-inline-end: auto;
+ width: -moz-fit-content;
+ height: -moz-fit-content;
}
.invitation-table {
- border: 3px solid -moz-default-color;
border-collapse: collapse;
width: 40em;
- margin-inline-start: auto;
- margin-inline-end: auto;
-}
-.invitation-table > tbody > tr > td {
- padding: 3px;
- vertical-align: top;
- width: 2em;
- text-align: left;
}
.invitation-table .header {
+ padding: 3px;
color: HighlightText;
font-size: 1em;
font-weight: bold;
background-color: Highlight;
}
+
+.invitation-table :is(td, th) {
+ padding: 3px;
+ vertical-align: baseline;
+}
+
.invitation-table .description {
width: 9em;
- text-align: right;
+ text-align: end;
+ font-weight: normal;
border-inline-end: 1px solid hsla(0, 0%, 50%, .2);
background-color: hsla(0, 0%, 50%, .2);
- vertical-align: top;
}
+
.invitation-table .content {
width: 29em;
}
-.invitation-table .content p {
- white-space: pre-wrap;
-}
+
.invitation-table .added {
color: rgb(255, 0, 0);
+ text-decoration-line: none;
}
+
.invitation-table .added[systemcolors] {
color: currentColor;
font-weight: bold;
}
+
.invitation-table .modified {
color: rgb(255, 0, 0);
font-style: italic;
}
+
.invitation-table .modified[systemcolors] {
color: currentColor;
}
+
.invitation-table .removed {
color: rgb(125, 125, 125);
- text-decoration: line-through;
}
+
.invitation-table .removed[systemcolors] {
color: currentColor;
}
diff --git a/calendar/lightning/content/imip-bar.js b/calendar/lightning/content/imip-bar.js
index 456472b370..507944fa54 100644
--- a/calendar/lightning/content/imip-bar.js
+++ b/calendar/lightning/content/imip-bar.js
@@ -304,22 +304,13 @@ var ltnImipBar = {
ltnImipBar.itipItem
);
let serializedOverlay = cal.xml.serializeDOM(foundOverlay);
- let organizerId = ltnImipBar.itipItem.targetCalendar.getProperty("organizerId");
if (diff == 1) {
// this is an update to previously accepted invitation
- msgOverlay = ltn.invitation.compareInvitationOverlay(
- serializedOverlay,
- msgOverlay,
- organizerId
- );
+ msgOverlay = ltn.invitation.compareInvitationOverlay(serializedOverlay, msgOverlay);
} else {
// this is a copy of a previously sent out invitation or a previous revision of a
// meanwhile accepted invitation, so we flip comparison order
- msgOverlay = ltn.invitation.compareInvitationOverlay(
- msgOverlay,
- serializedOverlay,
- organizerId
- );
+ msgOverlay = ltn.invitation.compareInvitationOverlay(msgOverlay, serializedOverlay);
}
}
msgWindow.displayHTMLInMessagePane("", msgOverlay, false);
diff --git a/calendar/lightning/content/lightning-invitation.xhtml b/calendar/lightning/content/lightning-invitation.xhtml
index 78cc7b5912..c29bfe795c 100644
--- a/calendar/lightning/content/lightning-invitation.xhtml
+++ b/calendar/lightning/content/lightning-invitation.xhtml
@@ -8,67 +8,74 @@
+
-
-
-
- |
- |
-
-
- |
- |
-
-
- |
- |
-
-
- |
- |
-
-
- |
- |
-
-
- |
-
-
- |
-
-
- |
- |
-
-
- |
- |
-
-
-
- |
-
-
- |
-
-
- |
- |
-
-
+
+
+
+
+ |
+ |
+
+
+ |
+ |
+
+
+ |
+ |
+
+
+
+ |
+ |
+
+
+
+ |
+ |
+
+
+
+ |
+ |
+
+
+
+ |
+ |
+
+
+ |
+ |
+
+
+
+
+ |
+ |
+
+
+ |
+ |
+
+
+