Merge branch 'mjog/283-plain-text-whitespace-fixes' into 'mainline'

Email body whitespace fixes

See merge request GNOME/geary!610
This commit is contained in:
Michael Gratton 2020-11-05 08:19:16 +00:00
commit ec7ea98494
7 changed files with 37 additions and 73 deletions

View file

@ -59,7 +59,7 @@ private class Geary.RFC822.FilterBlockquotes : GMime.Filter {
if (!initial_element) {
// We set the style explicitly so it will be set in HTML emails. We also give it a
// class so users can customize the style in the viewer.
insert_string("<div class=\"plaintext\" style=\"white-space: pre-wrap;\">", ref out_index);
insert_string("<div class=\"plaintext\" style=\"white-space: break-spaces;\">", ref out_index);
initial_element = true;
}

View file

@ -15,7 +15,7 @@ class Geary.RFC822.MessageTest : TestCase {
private const string BASIC_MULTIPART_TNEF = "basic-multipart-tnef.eml";
private const string HTML_CONVERSION_TEMPLATE =
"<div class=\"plaintext\" style=\"white-space: pre-wrap;\">%s</div>";
"<div class=\"plaintext\" style=\"white-space: break-spaces;\">%s</div>";
private const string BASIC_PLAIN_BODY = """This is the first line.

View file

@ -26,77 +26,31 @@ PageState.prototype = {
this._commandStackChanged = MessageSender("command_stack_changed");
this._documentModified = MessageSender("document_modified");
let state = this;
// Set up an observer to keep track of modifications made to
// the document when editing.
let modifiedId = null;
this.bodyObserver = new MutationObserver(function(records) {
this.bodyObserver = new MutationObserver((records) => {
if (modifiedId == null) {
modifiedId = window.setTimeout(function() {
state.documentModified();
state.checkCommandStack();
modifiedId = window.setTimeout(() => {
this.documentModified();
this.checkCommandStack();
modifiedId = null;
}, 1000);
}
});
document.addEventListener("DOMContentLoaded", function(e) {
state.loaded();
this.heightObserver = new ResizeObserver((entries) => {
this.updatePreferredHeight();
});
document.addEventListener("selectionchange", function(e) {
state.selectionChanged();
document.addEventListener("DOMContentLoaded", (e) => {
this.heightObserver.observe(window.document.documentElement);
this.loaded();
});
// Coalesce multiple calls to updatePreferredHeight using a
// timeout to avoid the overhead of multiple JS messages sent
// to the app and hence view multiple resizes being queued.
let queueTimeout = null;
let queuePreferredHeightUpdate = function() {
if (queueTimeout != null) {
clearTimeout(queueTimeout);
}
queueTimeout = setTimeout(
function() { state.updatePreferredHeight(); }, 100
);
};
// Queues an update when the complete document is loaded.
//
// Note also that the delay introduced here by this last call
// to queuePreferredHeightUpdate when the complete document is
// loaded seems to be important to get an accurate idea of the
// final document size.
window.addEventListener("load", function(e) {
queuePreferredHeightUpdate();
}, true); // load does not bubble
// Queues updates for any STYLE, IMG and other loaded
// elements, hence handles resizing when the user later
// requests remote images loading.
document.addEventListener("load", function(e) {
queuePreferredHeightUpdate();
}, true); // load does not bubble
// Queues an update if the window changes size, e.g. if the
// user resized the window. Only trigger when the width has
// changed however since the height should only change as the
// body is being loaded.
let width = window.innerWidth;
window.addEventListener("resize", function(e) {
let currentWidth = window.innerWidth;
if (width != currentWidth) {
width = currentWidth;
queuePreferredHeightUpdate();
}
}, false); // load does not bubble
// Queues an update when a transition has completed, e.g. if the
// user resized the window
window.addEventListener("transitionend", function(e) {
queuePreferredHeightUpdate();
}, false); // load does not bubble
document.addEventListener("selectionchange", (e) => {
this.selectionChanged();
});
this.testResult = null;
},

View file

@ -60,6 +60,6 @@ blockquote {
}
pre {
white-space: pre-wrap;
white-space: break-spaces;
margin: 0;
}

View file

@ -264,7 +264,7 @@ ComposerPageState.prototype = {
},
tabOut: function() {
document.execCommand(
"inserthtml", false, "<span style='white-space: pre-wrap'>\t</span>"
"inserthtml", false, "<span style='white-space: break-spaces'>\t</span>"
);
},
tabIn: function() {

View file

@ -1,5 +1,8 @@
/**
* Style that is inserted into the message after it is loaded.
*
* Copyright © 2016 Software Freedom Conservancy Inc.
* Copyright © 2020 Michael Gratton <mike@vee.net>
*/
/*
@ -14,17 +17,24 @@ html {
color: black;
background-color: white;
/* Trigger CSS 2.1 § 10.6.7 to get a shrink-wrapped height. */
position: absolute !important;
top: 0 !important;
bottom: auto !important;
height: auto !important;
/* Width must always be defined by the viewport so content doesn't
overflow inside the WebView, height must always be defined by the
content so the WebView can be sized to fit exactly. */
width: 100vw !important;
height: max-content !important;
/* Fix up the width after going to absolute positioning above. */
width: 100%;
/* Despite the fact that the width must always be defined by the
viewport, the viewport width will be 0 if the email is loaded before
its WebView is laid out in the widget hierarchy. As a workaround, to
prevent this causing the email being squished down to is minimum
width and hence being stretched right out in height, set a
reasonable minimum width. See
https://gitlab.gnome.org/GNOME/geary/-/issues/283 */
min-width: 400px !important;
/* Lock down the box just enough so we don't get an incrementally
expanding web view */
/* Lock down the box sizing just enough so that the width and height
constraints above work as expected, and so the element's
scrollHeight is accurate. */
box-sizing: border-box !important;
margin: 0 !important;
border-width: 0 !important;
@ -67,7 +77,7 @@ blockquote {
}
pre {
white-space: pre-wrap;
white-space: break-spaces;
}
/**

View file

@ -213,7 +213,7 @@ ConversationPageState.prototype = {
if (ConversationPageState.isDescendantOf(
ancestor, "DIV", "plaintext", false)) {
dummy.classList.add("plaintext");
dummy.setAttribute("style", "white-space: pre-wrap;");
dummy.setAttribute("style", "white-space: break-spaces;");
includeDummy = true;
}
dummy.appendChild(range.cloneContents());