diff --git a/calendar/base/content/item-editing/calendar-item-iframe.js b/calendar/base/content/item-editing/calendar-item-iframe.js index 82f9df50f2..bdabd21356 100644 --- a/calendar/base/content/item-editing/calendar-item-iframe.js +++ b/calendar/base/content/item-editing/calendar-item-iframe.js @@ -1560,8 +1560,9 @@ function saveDialog(item) { // The editor gives us output wrapped in a body tag. We don't really want // that, so strip it. (Yes, it's a regex with HTML, but a _very_ specific - // one.) - item.descriptionHTML = editorOutput.replace(/^
(.+)<\/body>$/, "$1"); + // one.) We use the `s` flag to match across newlines in case there's a + // tag, in which caseThis event is one which includes\nan explicit linebreak inside a pre tag.
";
+
+ // Create a paste which includes HTML data, which the editor will recognize as
+ // HTML and paste with formatting by default.
+ const stringData = Cc["@mozilla.org/supports-string;1"].createInstance(Ci.nsISupportsString);
+ stringData.data = expectedHTML;
+
+ const transferable = Cc["@mozilla.org/widget/transferable;1"].createInstance(Ci.nsITransferable);
+ transferable.init(null);
+ transferable.addDataFlavor("text/html");
+ transferable.setTransferData("text/html", stringData);
+ Services.clipboard.setData(transferable, null, Ci.nsIClipboard.kGlobalClipboard);
+
+ // Paste.
+ EventUtils.synthesizeKey("v", { accelKey: true }, eventWindow);
+
+ await CalendarTestUtils.items.saveAndCloseItemDialog(eventWindow);
+
+ await TestUtils.waitForCondition(async () => {
+ const item = await calendar.getItem(eventId);
+ return item.lastModifiedTime != eventModified;
+ });
+
+ const editedEvent = await calendar.getItem(eventId);
+
+ // Verify that the description has been set appropriately. There should be no
+ // change to the HTML, which is preformatted, and the text description should
+ // include a linebreak in the same place as the HTML.
+ Assert.equal(editedEvent.descriptionHTML, expectedHTML, "HTML description should match input");
+ Assert.equal(
+ editedEvent.descriptionText,
+ "This event is one which includes\nan explicit linebreak inside a pre tag.",
+ "text description should include linebreak"
+ );
+
+ CalendarTestUtils.removeCalendar(calendar);
+});
+
+add_task(async function testTypeLongTextWithLinebreaks() {
+ const calendar = CalendarTestUtils.createCalendar();
+
+ // Create an event which currently has no description.
+ const event = await calendar.addItem(
+ new CalEvent(CalendarTestUtils.dedent`
+ BEGIN:VEVENT
+ SUMMARY:An event
+ DTSTART:20230218T100000Z
+ DTEND:20230218T110000Z
+ END:VEVENT
+ `)
+ );
+
+ // Remember event details so we can refetch it after editing.
+ const eventId = event.id;
+ const eventModified = event.lastModifiedTime;
+
+ // Sanity check.
+ Assert.equal(event.descriptionHTML, null, "event should not have an HTML description");
+ Assert.equal(event.descriptionText, null, "event should not have a text description");
+
+ // Open our event for editing.
+ const {
+ dialogWindow: eventWindow,
+ iframeDocument,
+ iframeWindow,
+ } = await CalendarTestUtils.dayView.editEventAt(window, 1);
+
+ const editor = iframeDocument.getElementById("item-description");
+ editor.focus();
+
+ // Insert text with several long lines and explicit linebreaks.
+ const firstLine =
+ "This event is pretty much just plain text, albeit it has some pretty long lines so that we can ensure that we don't accidentally wrap it during conversion.";
+ EventUtils.sendString(firstLine, iframeWindow);
+ EventUtils.sendKey("RETURN", iframeWindow);
+
+ const secondLine = "This line follows immediately after a linebreak.";
+ EventUtils.sendString(secondLine, iframeWindow);
+ EventUtils.sendKey("RETURN", iframeWindow);
+ EventUtils.sendKey("RETURN", iframeWindow);
+
+ const thirdLine =
+ "And one after a couple more linebreaks, for good measure. It might as well be a fairly long string as well, just so we're certain.";
+ EventUtils.sendString(thirdLine, iframeWindow);
+
+ await CalendarTestUtils.items.saveAndCloseItemDialog(eventWindow);
+
+ await TestUtils.waitForCondition(async () => {
+ const item = await calendar.getItem(eventId);
+ return item.lastModifiedTime != eventModified;
+ });
+
+ const editedEvent = await calendar.getItem(eventId);
+
+ // Verify that the description has been set appropriately. The HTML should
+ // match the input and use