[geary] New behavior for hiding quoted text



commit bc71300f381b704843409ec0b5868df32e15cedd
Author: Robert Schroll <rschroll gmail com>
Date:   Tue Jan 28 22:18:58 2014 -0500

    New behavior for hiding quoted text
    
    In their hidden state, quotes will be limited in length, with a link to
    extend them.  Only long quotes will be hidden; short ones will be
    displayed in their entirety.  Note that the threshold for hiding a quote
    is larger than the size of the hidden quote.  This ensures that there
    will always be a noticable expansion of a quote when it is shown.  (This
    also accounts for the fact that the height we measure includes padding.)
    
    We can only measure the size of a quote once it is actually shown as
    part of the document.  Notably, we can't figure out the sizes of quotes
    in hidden emails.  Therefore, we also decide which quotes in an email
    need to be hidden when the email is unhidden.  However, showing and then
    hiding quotes can lead to content flashing, so we start all quotes off
    in the hidden state, and remove this if they turn out to be short
    enough.

 .../conversation-viewer/conversation-viewer.vala   |   51 +++++++++-----------
 theming/message-viewer.css                         |   48 +++++++++++++-----
 2 files changed, 57 insertions(+), 42 deletions(-)
---
diff --git a/src/client/conversation-viewer/conversation-viewer.vala 
b/src/client/conversation-viewer/conversation-viewer.vala
index 2dc7692..d81fb1c 100644
--- a/src/client/conversation-viewer/conversation-viewer.vala
+++ b/src/client/conversation-viewer/conversation-viewer.vala
@@ -34,6 +34,7 @@ public class ConversationViewer : Gtk.Box {
     private const string REPLACED_IMAGE_CLASS = "replaced_inline_image";
     private const string DATA_IMAGE_CLASS = "data_inline_image";
     private const int MAX_INLINE_IMAGE_MAJOR_DIM = 1024;
+    private const int QUOTE_SIZE_THRESHOLD = 120;
     
     private enum SearchState {
         // Search/find states.
@@ -558,6 +559,9 @@ public class ConversationViewer : Gtk.Box {
         Idle.add(() => {
             try {
                 div_message.get_class_list().add("animate");
+                // This will only affect any open emails.  Those in the hidden state will have
+                // their quotes set when they're opened.
+                unset_controllable_quotes(div_message);
             } catch (Error error) {
                 debug("Could not enable animation class: %s", error.message);
             }
@@ -1119,12 +1123,14 @@ public class ConversationViewer : Gtk.Box {
                 return;
             
             WebKit.DOM.DOMTokenList class_list = email_element.get_class_list();
-            if (class_list.contains("compressed"))
+            if (class_list.contains("compressed")) {
                 decompress_emails(email_element);
-            else if (class_list.contains("hide"))
+            } else if (class_list.contains("hide")) {
                 class_list.remove("hide");
-            else
+                unset_controllable_quotes(email_element);
+            } else {
                 class_list.add("hide");
+            }
         } catch (Error error) {
             warning("Error toggling message: %s", error.message);
         }
@@ -1614,34 +1620,23 @@ public class ConversationViewer : Gtk.Box {
 
     private WebKit.DOM.HTMLDivElement create_quote_container() throws Error {
         WebKit.DOM.HTMLDivElement quote_container = web_view.create_div();
-        quote_container.set_attribute("class", "quote_container");
-        quote_container.set_inner_html("%s%s%s".printf("<div class=\"shower\">[show]</div>",
-            "<div class=\"hider\">[hide]</div>", "<div class=\"quote\"></div>"));
+        quote_container.set_attribute("class", "quote_container controllable hide");
+        quote_container.set_inner_html(
+            """<div class="shower"><input type="button" value="▼        ▼        ▼" /></div>""" +
+            """<div class="hider"><input type="button" value="▲        ▲        ▲" /></div>""" +
+            """<div class="quote"></div>""");
         return quote_container;
     }
 
-    private string set_up_quotes(string text) {
-        try {
-            // Extract any quote containers from the signature block and make them controllable.
-            WebKit.DOM.HTMLElement container = web_view.create_div();
-            container.set_inner_html(text);
-            WebKit.DOM.NodeList quote_list = container.query_selector_all(".signature .quote_container");
-            for (int i = 0; i < quote_list.length; ++i) {
-                WebKit.DOM.Element quote = quote_list.item(i) as WebKit.DOM.Element;
-                quote.set_attribute("class", "quote_container controllable hide");
-                container.append_child(quote);
+    private void unset_controllable_quotes(WebKit.DOM.HTMLElement element) throws GLib.Error {
+        WebKit.DOM.NodeList quote_list = element.query_selector_all(".quote_container.controllable");
+        for (int i = 0; i < quote_list.length; ++i) {
+            WebKit.DOM.Element quote_container = quote_list.item(i) as WebKit.DOM.Element;
+            long scroll_height = quote_container.query_selector(".quote").scroll_height;
+            // If the message is hidden, scroll_height will be 0.
+            if (scroll_height > 0 && scroll_height < QUOTE_SIZE_THRESHOLD) {
+                quote_container.set_attribute("class", "quote_container");
             }
-            
-            // If there is only one quote container in the message, set it up as controllable.
-            quote_list = container.query_selector_all(".quote_container");
-            if (quote_list.length == 1) {
-                ((WebKit.DOM.Element) quote_list.item(0)).set_attribute("class",
-                    "quote_container controllable hide");
-            }
-            return container.get_inner_html();
-        } catch (Error error) {
-            debug("Error adjusting final quote block: %s", error.message);
-            return text;
         }
     }
     
@@ -1732,7 +1727,7 @@ public class ConversationViewer : Gtk.Box {
             }
 
             // Now return the whole message.
-            return set_up_quotes(container.get_inner_html());
+            return container.get_inner_html();
         } catch (Error e) {
             debug("Error modifying HTML message: %s", e.message);
             return text;
diff --git a/theming/message-viewer.css b/theming/message-viewer.css
index 5fe5f4c..194dc41 100644
--- a/theming/message-viewer.css
+++ b/theming/message-viewer.css
@@ -487,12 +487,24 @@ body.nohide .email .compressed_note > span {
 }
 
 .quote_container {
+    position: relative;
     margin: 5px 0;
     padding: 12px;
     color: #303030;
     background-color: #e8e8e8;/* recv-quoted */
     border-radius: 4px;
 }
+.quote_container .quote {
+    overflow: hidden;
+    position: relative;
+    z-index: 0;
+}
+body:not(.nohide) .quote_container.controllable .quote {
+    max-height: 80px;
+}
+body:not(.nohide) .quote_container.controllable.show .quote {
+    max-height: none;
+}
 
 .email.sent .quote_container {
     background-color: #e8e8e8;/* sent-quoted */
@@ -500,30 +512,38 @@ body.nohide .email .compressed_note > span {
 
 .quote_container > .shower,
 .quote_container > .hider {
-    color: #777;
-    font-family: sans-serif;
-    font-size: 75%;
-    cursor: pointer;
+    position: absolute;
+    z-index: 1;
+    bottom: -7px;
+    left: 0;
+    right: 0;
+    padding: 0 20%;
     display: none;
 }
+.quote_container > .shower > input,
+.quote_container > .hider > input {
+    width: 100%;
+    height: 15px;
+    padding: 0;
+    font-size: 7px;
+    color: #888;
+}
+.quote_container > .shower:hover > input,
+.quote_container > .hider:hover > input {
+    color: #000;
+}
+body:not(.nohide) .quote_container.controllable {
+    margin-bottom: 7px;
+}
 body:not(.nohide) .quote_container.controllable > .shower {
     display: block;
 }
-.quote_container.controllable > .hider,
-body:not(.nohide) .quote_container.controllable > .quote {
-    display: none;
-}
 body:not(.nohide) .quote_container.controllable.show > .shower {
     display: none;
 }
-body:not(.nohide) .quote_container.controllable.show > .hider,
-body:not(.nohide) .quote_container.controllable.show > .quote {
+body:not(.nohide) .quote_container.controllable.show > .hider {
     display: block;
 }
-.quote_container > .shower:hover,
-.quote_container > .hider:hover {
-    color: black;
-}
 
 #message_container {
     position: absolute;


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]