[geary/mjog/493-undo-send: 6/20] Minimise DOM changes made by ComposerPageState::cleanContent JS
- From: Michael Gratton <mjog src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [geary/mjog/493-undo-send: 6/20] Minimise DOM changes made by ComposerPageState::cleanContent JS
- Date: Tue, 12 Nov 2019 21:42:21 +0000 (UTC)
commit 8ea19d2aa85a6b02b56658952272afc3179a1621
Author: Michael Gratton <mike vee net>
Date: Fri Nov 8 10:39:46 2019 +1100
Minimise DOM changes made by ComposerPageState::cleanContent JS
By overriding ComposerPageState::getHtml to accept a parameter that
supports getting HTML with empty composer parts removed, cleanContent
can simply be made to linkify the page, thus allowing a ComposerWidget
to be re-used multiple times when sending an email.
src/client/composer/composer-web-view.vala | 9 +++++
src/client/composer/composer-widget.vala | 14 +++++---
test/client/composer/composer-web-view-test.vala | 9 +++++
test/js/composer-page-state-test.vala | 24 +++++++------
ui/composer-web-view.js | 46 ++++++++++--------------
5 files changed, 59 insertions(+), 43 deletions(-)
---
diff --git a/src/client/composer/composer-web-view.vala b/src/client/composer/composer-web-view.vala
index 5a7fd526..98770197 100644
--- a/src/client/composer/composer-web-view.vala
+++ b/src/client/composer/composer-web-view.vala
@@ -178,6 +178,15 @@ public class ComposerWebView : ClientWebView {
base.load_html((string) html.data);
}
+ /**
+ * Returns the view's content as HTML without being cleaned.
+ */
+ public async string? get_html_for_draft() throws Error {
+ return Util.JS.to_string(
+ yield call(Util.JS.callable("geary.getHtml").bool(false), null)
+ );
+ }
+
/**
* Makes the view uneditable and stops signals from being sent.
*/
diff --git a/src/client/composer/composer-widget.vala b/src/client/composer/composer-widget.vala
index e16891af..ea39c3a8 100644
--- a/src/client/composer/composer-widget.vala
+++ b/src/client/composer/composer-widget.vala
@@ -1019,8 +1019,8 @@ public class ComposerWidget : Gtk.EventBox, Geary.BaseInterface {
return true;
}
- public async Geary.ComposedEmail get_composed_email(DateTime? date_override = null,
- bool only_html = false) {
+ public async Geary.ComposedEmail get_composed_email(GLib.DateTime? date_override = null,
+ bool for_draft = false) {
Geary.ComposedEmail email = new Geary.ComposedEmail(
date_override ?? new DateTime.now_local(),
from
@@ -1055,10 +1055,14 @@ public class ComposerWidget : Gtk.EventBox, Geary.BaseInterface {
email.img_src_prefix = ClientWebView.INTERNAL_URL_PREFIX;
try {
- if (this.editor.is_rich_text || only_html)
- email.body_html = yield this.editor.get_html();
- if (!only_html)
+ if (!for_draft) {
+ if (this.editor.is_rich_text) {
+ email.body_html = yield this.editor.get_html();
+ }
email.body_text = yield this.editor.get_text();
+ } else {
+ email.body_html = yield this.editor.get_html_for_draft();
+ }
} catch (Error error) {
debug("Error getting composer message body: %s", error.message);
}
diff --git a/test/client/composer/composer-web-view-test.vala
b/test/client/composer/composer-web-view-test.vala
index ef5b97e0..49b222ae 100644
--- a/test/client/composer/composer-web-view-test.vala
+++ b/test/client/composer/composer-web-view-test.vala
@@ -13,6 +13,7 @@ public class ComposerWebViewTest : ClientWebViewTestCase<ComposerWebView> {
add_test("load_resources", load_resources);
add_test("edit_context", edit_context);
add_test("get_html", get_html);
+ add_test("get_html_for_draft", get_html_for_draft);
add_test("get_text", get_text);
add_test("get_text_with_quote", get_text_with_quote);
add_test("get_text_with_nested_quote", get_text_with_nested_quote);
@@ -50,6 +51,14 @@ public class ComposerWebViewTest : ClientWebViewTestCase<ComposerWebView> {
load_body_fixture(BODY);
this.test_view.get_html.begin((obj, ret) => { async_complete(ret); });
string html = this.test_view.get_html.end(async_result());
+ assert_string(ComposerPageStateTest.CLEAN_BODY_TEMPLATE.printf(BODY), html);
+ }
+
+ public void get_html_for_draft() throws GLib.Error {
+ string BODY = "<p>para</p>";
+ load_body_fixture(BODY);
+ this.test_view.get_html_for_draft.begin((obj, ret) => { async_complete(ret); });
+ string html = this.test_view.get_html.end(async_result());
assert_string(ComposerPageStateTest.COMPLETE_BODY_TEMPLATE.printf(BODY), html);
}
diff --git a/test/js/composer-page-state-test.vala b/test/js/composer-page-state-test.vala
index 465bcc12..197efeff 100644
--- a/test/js/composer-page-state-test.vala
+++ b/test/js/composer-page-state-test.vala
@@ -9,7 +9,12 @@ class ComposerPageStateTest : ClientWebViewTestCase<ComposerWebView> {
public const string COMPLETE_BODY_TEMPLATE =
"""<div id="geary-body" dir="auto">%s<div><br></div><div><br></div></div><div id="geary-signature"
dir="auto"></div>""";
- public const string CLEAN_BODY_TEMPLATE = "%s<div><br></div><div><br></div>";
+ public const string DIRTY_BODY_TEMPLATE =
+ """
+<div id="geary-body" dir="auto" class="geary-focus"
contenteditable="true">%s<div><br></div><div><br></div></div>
+<div id="geary-signature" class="geary-no-display" dir="auto" contenteditable="true"></div>
+""";
+ public const string CLEAN_BODY_TEMPLATE = """<div id="geary-body"
dir="auto">%s<div><br></div><div><br></div></div>""";
public ComposerPageStateTest() {
base("ComposerPageStateTest");
@@ -254,12 +259,11 @@ I can send email through smtp.gmail.com:587 or through <a href="https://www.gmai
try {
run_javascript("geary.cleanContent();");
- assert(
- Util.JS.to_string(
- run_javascript("geary.bodyPart.innerHTML;")
- .get_js_value()
- ) == CLEAN_BODY_TEMPLATE.printf(expected)
+ string result = Util.JS.to_string(
+ run_javascript("window.document.body.innerHTML;")
+ .get_js_value()
);
+ assert(result == DIRTY_BODY_TEMPLATE.printf(expected));
} catch (Util.JS.Error err) {
print("Util.JS.Error: %s\n", err.message);
assert_not_reached();
@@ -273,12 +277,10 @@ I can send email through smtp.gmail.com:587 or through <a href="https://www.gmai
string html = "<p>para</p>";
load_body_fixture(html);
try {
- assert(
- Util.JS.to_string(
- run_javascript(@"window.geary.getHtml();")
- .get_js_value()
- ) == COMPLETE_BODY_TEMPLATE.printf(html)
+ string result = Util.JS.to_string(
+ run_javascript(@"window.geary.getHtml();").get_js_value()
);
+ assert(result == CLEAN_BODY_TEMPLATE.printf(html));
} catch (Util.JS.Error err) {
print("Util.JS.Error: %s\n", err.message);
assert_not_reached();
diff --git a/ui/composer-web-view.js b/ui/composer-web-view.js
index 848290ed..7b548be3 100644
--- a/ui/composer-web-view.js
+++ b/ui/composer-web-view.js
@@ -60,6 +60,9 @@ ComposerPageState.prototype = {
}
this.signaturePart = document.getElementById("geary-signature");
+ if (this.signaturePart != null) {
+ ComposerPageState.linkify(this.signaturePart);
+ }
this.quotePart = document.getElementById("geary-quote");
// Should be using 'e.key' in listeners below instead of
@@ -283,38 +286,32 @@ ComposerPageState.prototype = {
},
cleanContent: function() {
// Prevent any modification signals being sent when mutating
- // the document below.
+ // the document
this.stopBodyObserver();
-
- ComposerPageState.cleanPart(this.bodyPart, false);
ComposerPageState.linkify(this.bodyPart);
-
- this.signaturePart = ComposerPageState.cleanPart(this.signaturePart, true);
- this.quotePart = ComposerPageState.cleanPart(this.quotePart, true);
+ this.startBodyObserver();
},
- getHtml: function() {
- // Clone the message parts so we can clean them without
- // modifiying the DOM, needed when saving drafts. In contrast
- // with cleanContent above, we don't remove empty elements so
- // they still exist when restoring from draft
+ getHtml: function(removeEmpty) {
+ if (removeEmpty === undefined) {
+ removeEmpty = true;
+ }
+
let parent = document.createElement("DIV");
parent.appendChild(
- ComposerPageState.cleanPart(this.bodyPart.cloneNode(true), false)
+ ComposerPageState.cleanPart(this.bodyPart.cloneNode(true))
);
- if (this.signaturePart != null) {
+ if (this.signaturePart != null &&
+ (!removeEmpty || this.signaturePart.innerText.trim() != "")) {
parent.appendChild(
- ComposerPageState.cleanPart(
- this.signaturePart.cloneNode(true), false
- )
+ ComposerPageState.cleanPart(this.signaturePart.cloneNode(true))
);
}
- if (this.quotePart != null) {
+ if (this.quotePart != null &&
+ (!removeEmpty || this.quotePart.innerText.trim() != "")) {
parent.appendChild(
- ComposerPageState.cleanPart(
- this.quotePart.cloneNode(true), false
- )
+ ComposerPageState.cleanPart(this.quotePart.cloneNode(true))
);
}
@@ -433,17 +430,12 @@ ComposerPageState.containsKeywords = function(line, wordKeys, suffixKeys) {
};
/**
- * Removes internal attributes from a composer part..
+ * Removes internal attributes from a composer part.
*/
-ComposerPageState.cleanPart = function(part, removeIfEmpty) {
+ComposerPageState.cleanPart = function(part) {
if (part != null) {
part.removeAttribute("class");
part.removeAttribute("contenteditable");
-
- if (removeIfEmpty && part.innerText.trim() == "") {
- part.parentNode.removeChild(part);
- part = null;
- }
}
return part;
};
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]