[evolution/wip/mcrha/webkit-jsc-api] Stop using e_web_view_get_web_extension_proxy() in EMailDisplay



commit 106a7130e69c0d988a7c80aff91ae8a85ae4a20e
Author: Milan Crha <mcrha redhat com>
Date:   Thu Oct 3 18:03:23 2019 +0200

    Stop using e_web_view_get_web_extension_proxy() in EMailDisplay

 src/addressbook/gui/widgets/eab-contact-display.c  |  30 +-
 .../gui/widgets/eab-contact-formatter.c            |   2 +-
 src/e-util/e-web-view.c                            | 153 +++---
 src/e-util/e-web-view.h                            |   6 +-
 src/e-util/test-web-view.c                         |  61 +--
 src/em-format/e-mail-part-headers.c                |  21 -
 src/em-format/e-mail-part-secure-button.c          |   6 +-
 src/em-format/e-mail-part.c                        |  28 +-
 src/em-format/e-mail-part.h                        |  12 +-
 src/mail/e-mail-display.c                          | 472 ++++++-------------
 src/modules/itip-formatter/e-mail-part-itip.c      |  11 +-
 src/modules/vcard-inline/e-mail-formatter-vcard.c  | 104 +++--
 src/modules/vcard-inline/e-mail-parser-vcard.c     |   6 +-
 src/modules/vcard-inline/e-mail-part-vcard.c       | 244 ++--------
 src/modules/vcard-inline/e-mail-part-vcard.h       |  12 +-
 src/web-extensions/ext-utils.js                    | 519 +++++++++++++++++++--
 16 files changed, 861 insertions(+), 826 deletions(-)
---
diff --git a/src/addressbook/gui/widgets/eab-contact-display.c 
b/src/addressbook/gui/widgets/eab-contact-display.c
index 5389924d34..b9eae723e2 100644
--- a/src/addressbook/gui/widgets/eab-contact-display.c
+++ b/src/addressbook/gui/widgets/eab-contact-display.c
@@ -385,26 +385,14 @@ contact_display_link_clicked (EWebView *web_view,
 }
 
 static void
-contact_display_notify_web_extension_proxy_cb (GObject *web_view,
-                                              GParamSpec *param,
-                                              gpointer user_data)
+contact_display_content_loaded_cb (EWebView *web_view,
+                                  const gchar *iframe_id,
+                                  gpointer user_data)
 {
-       GDBusProxy *web_extension;
-       GVariant* result;
-
-       web_extension = e_web_view_get_web_extension_proxy (E_WEB_VIEW (web_view));
-       if (web_extension) {
-               result = e_util_invoke_g_dbus_proxy_call_sync_wrapper_with_error_check (
-                               web_extension,
-                               "EABContactFormatterBindDOM",
-                               g_variant_new (
-                                       "(t)",
-                                       webkit_web_view_get_page_id (WEBKIT_WEB_VIEW (web_view))),
-                               NULL);
-
-               if (result)
-                       g_variant_unref (result);
-       }
+       g_return_if_fail (EAB_IS_CONTACT_DISPLAY (web_view));
+
+       e_web_view_jsc_run_script (WEBKIT_WEB_VIEW (web_view), e_web_view_get_cancellable (web_view),
+               "Evo.VCardBind(%s);", iframe_id);
 }
 
 static void
@@ -532,8 +520,8 @@ eab_contact_display_init (EABContactDisplay *display)
                G_CALLBACK (contact_display_web_process_crashed_cb), NULL);
 
        g_signal_connect (
-               web_view, "notify::web-extension-proxy",
-               G_CALLBACK (contact_display_notify_web_extension_proxy_cb), NULL);
+               web_view, "content-loaded",
+               G_CALLBACK (contact_display_content_loaded_cb), NULL);
        g_signal_connect (
                web_view, "style-updated",
                G_CALLBACK (load_contact), NULL);
diff --git a/src/addressbook/gui/widgets/eab-contact-formatter.c 
b/src/addressbook/gui/widgets/eab-contact-formatter.c
index 3276743434..84e62a6b0d 100644
--- a/src/addressbook/gui/widgets/eab-contact-formatter.c
+++ b/src/addressbook/gui/widgets/eab-contact-formatter.c
@@ -621,7 +621,7 @@ render_contact_list_row (EABContactFormatter *formatter,
                g_string_append_printf (
                        buffer,
                        "<td width=" IMAGE_COL_WIDTH " valign=\"top\" align=\"left\">"
-                       "<button type=\"button\" id=\"%s\" class=\"header-collapse _evo_collapse_button\" 
style=\"display: inline-block;\">"
+                       "<button type=\"button\" id=\"%s\" class=\"header-collapse 
_evo_vcard_collapse_button\" style=\"display: inline-block;\">"
                        "<img src=\"gtk-stock://pan-down-symbolic\" />"
                        "</button>"
                        "</td><td width=\"100%%\" align=\"left\">%s",
diff --git a/src/e-util/e-web-view.c b/src/e-util/e-web-view.c
index 9dba47a704..122e08e717 100644
--- a/src/e-util/e-web-view.c
+++ b/src/e-util/e-web-view.c
@@ -101,7 +101,7 @@ struct _EWebViewPrivate {
        gboolean has_selection;
        gboolean need_input;
 
-       GCancellable *load_cancellable;
+       GCancellable *cancellable;
 
        gchar *last_popup_iframe_src;
        gchar *last_popup_iframe_id;
@@ -284,7 +284,7 @@ static void
 action_search_web_cb (GtkAction *action,
                      EWebView *web_view)
 {
-       e_web_view_jsc_get_selection (WEBKIT_WEB_VIEW (web_view), E_TEXT_FORMAT_PLAIN, 
web_view->priv->load_cancellable,
+       e_web_view_jsc_get_selection (WEBKIT_WEB_VIEW (web_view), E_TEXT_FORMAT_PLAIN, 
web_view->priv->cancellable,
                e_web_view_search_web_get_selection_cb, NULL);
 }
 
@@ -682,7 +682,7 @@ web_view_context_menu_cb (WebKitWebView *webkit_web_view,
                yy = 1;
        }
 
-       e_web_view_jsc_get_element_from_point (WEBKIT_WEB_VIEW (web_view), xx, yy, 
web_view->priv->load_cancellable,
+       e_web_view_jsc_get_element_from_point (WEBKIT_WEB_VIEW (web_view), xx, yy, 
web_view->priv->cancellable,
                web_view_got_elem_from_point_for_popup_event_cb, event ? gdk_event_copy (event) : NULL);
 
        return TRUE;
@@ -795,12 +795,14 @@ web_view_decide_policy_cb (EWebView *web_view,
 }
 
 static void
-style_updated_cb (EWebView *web_view)
+e_web_view_update_styles (EWebView *web_view,
+                         const gchar *iframe_id)
 {
        GdkRGBA color;
        gchar *color_value;
        gchar *style;
        GtkStyleContext *style_context;
+       WebKitWebView *webkit_web_view;
 
        style_context = gtk_widget_get_style_context (GTK_WIDGET (web_view));
 
@@ -818,13 +820,16 @@ style_updated_cb (EWebView *web_view)
 
        style = g_strconcat ("background-color: ", color_value, ";", NULL);
 
-       webkit_web_view_set_background_color (WEBKIT_WEB_VIEW (web_view), &color);
+       webkit_web_view = WEBKIT_WEB_VIEW (web_view);
+
+       webkit_web_view_set_background_color (webkit_web_view, &color);
 
-       e_web_view_add_css_rule_into_style_sheet (
-               web_view,
+       e_web_view_jsc_add_rule_into_style_sheet (webkit_web_view,
+               iframe_id,
                "-e-web-view-style-sheet",
                ".-e-web-view-background-color",
-               style);
+               style,
+               web_view->priv->cancellable);
 
        g_free (color_value);
        g_free (style);
@@ -836,16 +841,23 @@ style_updated_cb (EWebView *web_view)
 
        style = g_strconcat ("color: ", color_value, ";", NULL);
 
-       e_web_view_add_css_rule_into_style_sheet (
-               web_view,
+       e_web_view_jsc_add_rule_into_style_sheet (webkit_web_view,
+               iframe_id,
                "-e-web-view-style-sheet",
                ".-e-web-view-text-color",
-               style);
+               style,
+               web_view->priv->cancellable);
 
        g_free (color_value);
        g_free (style);
 }
 
+static void
+style_updated_cb (EWebView *web_view)
+{
+       e_web_view_update_styles (web_view, "*");
+}
+
 static void
 web_view_load_changed_cb (WebKitWebView *webkit_web_view,
                           WebKitLoadEvent load_event,
@@ -862,10 +874,10 @@ web_view_load_changed_cb (WebKitWebView *webkit_web_view,
                return;
 
        /* Make sure the initialize function is called for the top document when it is loaded. */
-       e_web_view_jsc_run_script (webkit_web_view, web_view->priv->load_cancellable,
-               "Evo.InitializeAndPostContentLoaded(null);");
+       e_web_view_jsc_run_script (webkit_web_view, web_view->priv->cancellable,
+               "Evo.EnsureMainDocumentInitialized();");
 
-       style_updated_cb (web_view);
+       e_web_view_update_styles (web_view, "");
 
        web_view_update_document_highlights (web_view);
 }
@@ -1092,9 +1104,9 @@ web_view_dispose (GObject *object)
 
        priv = E_WEB_VIEW_GET_PRIVATE (object);
 
-       if (priv->load_cancellable) {
-               g_cancellable_cancel (priv->load_cancellable);
-               g_clear_object (&priv->load_cancellable);
+       if (priv->cancellable) {
+               g_cancellable_cancel (priv->cancellable);
+               g_clear_object (&priv->cancellable);
        }
 
        if (priv->font_name_changed_handler_id > 0) {
@@ -1262,7 +1274,7 @@ web_view_process_uri_request_cb (WebKitURISchemeRequest *request,
                web_view = E_WEB_VIEW (requester);
        }
 
-       e_content_request_process (content_request, uri, requester, web_view ? 
web_view->priv->load_cancellable : NULL,
+       e_content_request_process (content_request, uri, requester, web_view ? web_view->priv->cancellable : 
NULL,
                web_view_uri_request_done_cb, g_object_ref (request));
 
        g_free (redirect_to_uri);
@@ -1417,7 +1429,7 @@ web_view_call_register_element_clicked (EWebView *web_view,
 
        e_web_view_jsc_register_element_clicked (WEBKIT_WEB_VIEW (web_view), iframe_id,
                only_elem_class ? only_elem_class : elem_classes,
-               web_view->priv->load_cancellable);
+               web_view->priv->cancellable);
 
        g_free (elem_classes);
 }
@@ -1439,10 +1451,10 @@ e_web_view_content_loaded_cb (WebKitUserContentManager *manager,
 
        iframe_id = jsc_value_to_string (jsc_value);
 
-       if (!iframe_id || !*iframe_id) {
+       if (!iframe_id || !*iframe_id)
                e_web_view_update_fonts (web_view);
-               style_updated_cb (web_view);
-       }
+       else
+               e_web_view_update_styles (web_view, iframe_id);
 
        web_view_call_register_element_clicked (web_view, iframe_id, NULL);
 
@@ -1565,17 +1577,17 @@ web_view_constructed (GObject *object)
 
        manager = webkit_web_view_get_user_content_manager (WEBKIT_WEB_VIEW (object));
 
-       g_signal_connect (manager, "script-message-received::elementClicked",
-               G_CALLBACK (e_web_view_element_clicked_cb), web_view);
+       g_signal_connect_object (manager, "script-message-received::elementClicked",
+               G_CALLBACK (e_web_view_element_clicked_cb), web_view, 0);
 
-       g_signal_connect (manager, "script-message-received::contentLoaded",
-               G_CALLBACK (e_web_view_content_loaded_cb), web_view);
+       g_signal_connect_object (manager, "script-message-received::contentLoaded",
+               G_CALLBACK (e_web_view_content_loaded_cb), web_view, 0);
 
-       g_signal_connect (manager, "script-message-received::hasSelection",
-               G_CALLBACK (e_web_view_has_selection_cb), web_view);
+       g_signal_connect_object (manager, "script-message-received::hasSelection",
+               G_CALLBACK (e_web_view_has_selection_cb), web_view, 0);
 
-       g_signal_connect (manager, "script-message-received::needInputChanged",
-               G_CALLBACK (e_web_view_need_input_changed_cb), web_view);
+       g_signal_connect_object (manager, "script-message-received::needInputChanged",
+               G_CALLBACK (e_web_view_need_input_changed_cb), web_view, 0);
 
        webkit_user_content_manager_register_script_message_handler (manager, "contentLoaded");
        webkit_user_content_manager_register_script_message_handler (manager, "elementClicked");
@@ -1589,13 +1601,13 @@ e_web_view_replace_load_cancellable (EWebView *web_view,
 {
        g_return_if_fail (E_IS_WEB_VIEW (web_view));
 
-       if (web_view->priv->load_cancellable) {
-               g_cancellable_cancel (web_view->priv->load_cancellable);
-               g_clear_object (&web_view->priv->load_cancellable);
+       if (web_view->priv->cancellable) {
+               g_cancellable_cancel (web_view->priv->cancellable);
+               g_clear_object (&web_view->priv->cancellable);
        }
 
        if (create_new)
-               web_view->priv->load_cancellable = g_cancellable_new ();
+               web_view->priv->cancellable = g_cancellable_new ();
 }
 
 static gboolean
@@ -1864,27 +1876,6 @@ e_web_view_set_web_extension_proxy (EWebView *web_view,
        g_object_notify (G_OBJECT (web_view), "web-extension-proxy");
 }
 
-static void
-e_web_view_page_proxy_changed_cb (EWebExtensionContainer *container,
-                                 guint64 page_id,
-                                 gint stamp,
-                                 GDBusProxy *proxy,
-                                 gpointer user_data)
-{
-       EWebView *web_view = user_data;
-
-       g_return_if_fail (E_IS_WEB_VIEW (web_view));
-
-       if (stamp == web_view->priv->stamp &&
-           page_id == webkit_web_view_get_page_id (WEBKIT_WEB_VIEW (web_view))) {
-               e_web_view_set_web_extension_proxy (web_view, proxy);
-
-               if (proxy) {
-                       style_updated_cb (web_view);
-               }
-       }
-}
-
 GDBusProxy *
 e_web_view_get_web_extension_proxy (EWebView *web_view)
 {
@@ -2526,9 +2517,6 @@ e_web_view_init (EWebView *web_view)
        web_view->priv->container = e_web_extension_container_new (E_WEB_EXTENSION_OBJECT_PATH, 
E_WEB_EXTENSION_INTERFACE);
        web_view->priv->old_settings = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, 
(GDestroyNotify) g_variant_unref);
 
-       g_signal_connect_object (web_view->priv->container, "page-proxy-changed",
-               G_CALLBACK (e_web_view_page_proxy_changed_cb), web_view, 0);
-
        g_signal_connect (
                web_view, "context-menu",
                G_CALLBACK (web_view_context_menu_cb), NULL);
@@ -2697,7 +2685,7 @@ e_web_view_init (EWebView *web_view)
 
        web_view->priv->element_clicked_cbs = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, 
(GDestroyNotify) g_ptr_array_unref);
 
-       web_view->priv->load_cancellable = NULL;
+       web_view->priv->cancellable = NULL;
 }
 
 GtkWidget *
@@ -3694,6 +3682,8 @@ e_web_view_update_fonts_settings (GSettings *font_settings,
                pango_font_description_free (ms);
        if (clean_vw)
                pango_font_description_free (vw);
+
+       e_web_view_update_styles (E_WEB_VIEW (view_widget), "*");
 }
 
 WebKitSettings *
@@ -3716,6 +3706,14 @@ e_web_view_get_default_webkit_settings (void)
                NULL);
 }
 
+GCancellable *
+e_web_view_get_cancellable (EWebView *web_view)
+{
+       g_return_val_if_fail (E_IS_WEB_VIEW (web_view), NULL);
+
+       return web_view->priv->cancellable;
+}
+
 void
 e_web_view_update_fonts (EWebView *web_view)
 {
@@ -4265,35 +4263,6 @@ e_web_view_request_finish (EWebView *web_view,
        return g_object_ref (async_context->input_stream);
 }
 
-/**
- * e_web_view_add_css_rule_into_style_sheet:
- * @web_view: an #EWebView
- * @style_sheet_id: CSS style sheet's id
- * @selector: CSS selector
- * @style: style for given selector
- *
- * Insert new CSS rule (defined with @selector and @style) into CSS style sheet
- * with given @style_sheet_id. If style sheet doesn't exist, it's created.
- *
- * The rule is inserted to every DOM document that is in page. That means also
- * into DOM documents inside iframe elements.
- **/
-void
-e_web_view_add_css_rule_into_style_sheet (EWebView *web_view,
-                                          const gchar *style_sheet_id,
-                                          const gchar *selector,
-                                          const gchar *style)
-{
-       g_return_if_fail (E_IS_WEB_VIEW (web_view));
-       g_return_if_fail (style_sheet_id && *style_sheet_id);
-       g_return_if_fail (selector && *selector);
-       g_return_if_fail (style && *style);
-
-       e_web_view_jsc_add_rule_into_style_sheet (WEBKIT_WEB_VIEW (web_view),
-               "", style_sheet_id, selector, style,
-               web_view->priv->load_cancellable);
-}
-
 /**
  * e_web_view_set_iframe_src:
  * @web_view: an #EWebView
@@ -4312,7 +4281,7 @@ e_web_view_set_iframe_src (EWebView *web_view,
 {
        g_return_if_fail (E_IS_WEB_VIEW (web_view));
 
-       e_web_view_jsc_run_script (WEBKIT_WEB_VIEW (web_view), web_view->priv->load_cancellable,
+       e_web_view_jsc_run_script (WEBKIT_WEB_VIEW (web_view), web_view->priv->cancellable,
                "Evo.SetIFrameSrc(%s, %s);",
                iframe_id, src_uri);
 }
@@ -4450,7 +4419,7 @@ e_web_view_set_element_hidden (EWebView *web_view,
 
        e_web_view_jsc_set_element_hidden (WEBKIT_WEB_VIEW (web_view),
                "*", element_id, hidden,
-               web_view->priv->load_cancellable);
+               web_view->priv->cancellable);
 }
 
 void
@@ -4465,7 +4434,7 @@ e_web_view_set_element_style_property (EWebView *web_view,
 
        e_web_view_jsc_set_element_style_property (WEBKIT_WEB_VIEW (web_view),
                "*", element_id, property_name, value,
-               web_view->priv->load_cancellable);
+               web_view->priv->cancellable);
 }
 
 void
@@ -4481,5 +4450,5 @@ e_web_view_set_element_attribute (EWebView *web_view,
 
        e_web_view_jsc_set_element_attribute (WEBKIT_WEB_VIEW (web_view),
                "*", element_id, namespace_uri, qualified_name, value,
-               web_view->priv->load_cancellable);
+               web_view->priv->cancellable);
 }
diff --git a/src/e-util/e-web-view.h b/src/e-util/e-web-view.h
index 6208afe7f8..6e7dcff02d 100644
--- a/src/e-util/e-web-view.h
+++ b/src/e-util/e-web-view.h
@@ -127,6 +127,7 @@ GtkWidget * e_web_view_new                  (void);
 WebKitSettings *
                e_web_view_get_default_webkit_settings
                                                (void);
+GCancellable * e_web_view_get_cancellable      (EWebView *web_view);
 void           e_web_view_register_content_request_for_scheme
                                                (EWebView *web_view,
                                                 const gchar *scheme,
@@ -236,11 +237,6 @@ GInputStream *     e_web_view_request_finish       (EWebView *web_view,
 void           e_web_view_install_request_handler
                                                (EWebView *web_view,
                                                 GType handler_type);
-void           e_web_view_add_css_rule_into_style_sheet
-                                               (EWebView *web_view,
-                                                const gchar *style_sheet_id,
-                                                const gchar *selector,
-                                                const gchar *style);
 const gchar *  e_web_view_get_citation_color_for_level
                                                (gint level);
 void           e_web_view_set_iframe_src       (EWebView *web_view,
diff --git a/src/e-util/test-web-view.c b/src/e-util/test-web-view.c
index 1820978515..ed58fabc96 100644
--- a/src/e-util/test-web-view.c
+++ b/src/e-util/test-web-view.c
@@ -793,18 +793,18 @@ test_style_sheets (TestFixture *fixture)
                NULL);
 
        g_assert_cmpint (1, ==, test_utils_jsc_call_int32_sync (fixture, "Test.nStyles(\"\")"));
-       g_assert_cmpint (0, ==, test_utils_jsc_call_int32_sync (fixture, "Test.nStyles(\"frm1\")"));
-       g_assert_cmpint (0, ==, test_utils_jsc_call_int32_sync (fixture, "Test.nStyles(\"frm1_1\")"));
-       g_assert_cmpint (0, ==, test_utils_jsc_call_int32_sync (fixture, "Test.nStyles(\"frm2\")"));
+       g_assert_cmpint (1, ==, test_utils_jsc_call_int32_sync (fixture, "Test.nStyles(\"frm1\")"));
+       g_assert_cmpint (1, ==, test_utils_jsc_call_int32_sync (fixture, "Test.nStyles(\"frm1_1\")"));
+       g_assert_cmpint (1, ==, test_utils_jsc_call_int32_sync (fixture, "Test.nStyles(\"frm2\")"));
        test_utils_jsc_call_string_and_verify (fixture, "Test.getStyle(\"\", \"sheet1\", \"body\", 
\"color\")", NULL);
 
        e_web_view_jsc_create_style_sheet (fixture->web_view, "", "sheet1", "body { color:green; }", NULL);
        test_utils_wait_noop (fixture);
 
        g_assert_cmpint (2, ==, test_utils_jsc_call_int32_sync (fixture, "Test.nStyles(\"\")"));
-       g_assert_cmpint (0, ==, test_utils_jsc_call_int32_sync (fixture, "Test.nStyles(\"frm1\")"));
-       g_assert_cmpint (0, ==, test_utils_jsc_call_int32_sync (fixture, "Test.nStyles(\"frm1_1\")"));
-       g_assert_cmpint (0, ==, test_utils_jsc_call_int32_sync (fixture, "Test.nStyles(\"frm2\")"));
+       g_assert_cmpint (1, ==, test_utils_jsc_call_int32_sync (fixture, "Test.nStyles(\"frm1\")"));
+       g_assert_cmpint (1, ==, test_utils_jsc_call_int32_sync (fixture, "Test.nStyles(\"frm1_1\")"));
+       g_assert_cmpint (1, ==, test_utils_jsc_call_int32_sync (fixture, "Test.nStyles(\"frm2\")"));
        test_utils_jsc_call_string_and_verify (fixture, "Test.getStyle(\"\", \"sheet1\", \"body\", 
\"color\")", "green");
        test_utils_jsc_call_string_and_verify (fixture, "Test.getStyle(\"frm1_1\", \"sheet2\", \"input\", 
\"background-color\")", NULL);
        test_utils_jsc_call_string_and_verify (fixture, "Test.getStyle(\"frm1_1\", \"sheet2\", \"table\", 
\"color\")", NULL);
@@ -814,9 +814,9 @@ test_style_sheets (TestFixture *fixture)
        test_utils_wait_noop (fixture);
 
        g_assert_cmpint (2, ==, test_utils_jsc_call_int32_sync (fixture, "Test.nStyles(\"\")"));
-       g_assert_cmpint (0, ==, test_utils_jsc_call_int32_sync (fixture, "Test.nStyles(\"frm1\")"));
-       g_assert_cmpint (1, ==, test_utils_jsc_call_int32_sync (fixture, "Test.nStyles(\"frm1_1\")"));
-       g_assert_cmpint (0, ==, test_utils_jsc_call_int32_sync (fixture, "Test.nStyles(\"frm2\")"));
+       g_assert_cmpint (1, ==, test_utils_jsc_call_int32_sync (fixture, "Test.nStyles(\"frm1\")"));
+       g_assert_cmpint (2, ==, test_utils_jsc_call_int32_sync (fixture, "Test.nStyles(\"frm1_1\")"));
+       g_assert_cmpint (1, ==, test_utils_jsc_call_int32_sync (fixture, "Test.nStyles(\"frm2\")"));
        test_utils_jsc_call_string_and_verify (fixture, "Test.getStyle(\"\", \"sheet1\", \"body\", 
\"color\")", "green");
        test_utils_jsc_call_string_and_verify (fixture, "Test.getStyle(\"frm1_1\", \"sheet2\", \"input\", 
\"background-color\")", "black");
        test_utils_jsc_call_string_and_verify (fixture, "Test.getStyle(\"frm1_1\", \"sheet2\", \"table\", 
\"color\")", "green");
@@ -831,9 +831,9 @@ test_style_sheets (TestFixture *fixture)
        test_utils_wait_noop (fixture);
 
        g_assert_cmpint (3, ==, test_utils_jsc_call_int32_sync (fixture, "Test.nStyles(\"\")"));
-       g_assert_cmpint (1, ==, test_utils_jsc_call_int32_sync (fixture, "Test.nStyles(\"frm1\")"));
-       g_assert_cmpint (2, ==, test_utils_jsc_call_int32_sync (fixture, "Test.nStyles(\"frm1_1\")"));
-       g_assert_cmpint (1, ==, test_utils_jsc_call_int32_sync (fixture, "Test.nStyles(\"frm2\")"));
+       g_assert_cmpint (2, ==, test_utils_jsc_call_int32_sync (fixture, "Test.nStyles(\"frm1\")"));
+       g_assert_cmpint (3, ==, test_utils_jsc_call_int32_sync (fixture, "Test.nStyles(\"frm1_1\")"));
+       g_assert_cmpint (2, ==, test_utils_jsc_call_int32_sync (fixture, "Test.nStyles(\"frm2\")"));
        test_utils_jsc_call_string_and_verify (fixture, "Test.getStyle(\"\", \"sheet1\", \"body\", 
\"color\")", "green");
        test_utils_jsc_call_string_and_verify (fixture, "Test.getStyle(\"frm1_1\", \"sheet2\", \"input\", 
\"background-color\")", "black");
        test_utils_jsc_call_string_and_verify (fixture, "Test.getStyle(\"frm1_1\", \"sheet2\", \"table\", 
\"color\")", "red");
@@ -856,9 +856,9 @@ test_style_sheets (TestFixture *fixture)
        g_assert_cmpint (1, ==, test_utils_jsc_call_bool_sync (fixture, "Test.hasStyle(\"frm1\", 
\"sheetA\")") ? 1 : 0);
        g_assert_cmpint (1, ==, test_utils_jsc_call_bool_sync (fixture, "Test.hasStyle(\"frm1_1\", 
\"sheetA\")") ? 1 : 0);
        g_assert_cmpint (4, ==, test_utils_jsc_call_int32_sync (fixture, "Test.nStyles(\"\")"));
-       g_assert_cmpint (2, ==, test_utils_jsc_call_int32_sync (fixture, "Test.nStyles(\"frm1\")"));
-       g_assert_cmpint (3, ==, test_utils_jsc_call_int32_sync (fixture, "Test.nStyles(\"frm1_1\")"));
-       g_assert_cmpint (1, ==, test_utils_jsc_call_int32_sync (fixture, "Test.nStyles(\"frm2\")"));
+       g_assert_cmpint (3, ==, test_utils_jsc_call_int32_sync (fixture, "Test.nStyles(\"frm1\")"));
+       g_assert_cmpint (4, ==, test_utils_jsc_call_int32_sync (fixture, "Test.nStyles(\"frm1_1\")"));
+       g_assert_cmpint (2, ==, test_utils_jsc_call_int32_sync (fixture, "Test.nStyles(\"frm2\")"));
 
        e_web_view_jsc_remove_style_sheet (fixture->web_view, "frm1", "sheetA", NULL);
        test_utils_wait_noop (fixture);
@@ -867,9 +867,9 @@ test_style_sheets (TestFixture *fixture)
        g_assert_cmpint (0, ==, test_utils_jsc_call_bool_sync (fixture, "Test.hasStyle(\"frm1\", 
\"sheetA\")") ? 1 : 0);
        g_assert_cmpint (1, ==, test_utils_jsc_call_bool_sync (fixture, "Test.hasStyle(\"frm1_1\", 
\"sheetA\")") ? 1 : 0);
        g_assert_cmpint (4, ==, test_utils_jsc_call_int32_sync (fixture, "Test.nStyles(\"\")"));
-       g_assert_cmpint (1, ==, test_utils_jsc_call_int32_sync (fixture, "Test.nStyles(\"frm1\")"));
-       g_assert_cmpint (3, ==, test_utils_jsc_call_int32_sync (fixture, "Test.nStyles(\"frm1_1\")"));
-       g_assert_cmpint (1, ==, test_utils_jsc_call_int32_sync (fixture, "Test.nStyles(\"frm2\")"));
+       g_assert_cmpint (2, ==, test_utils_jsc_call_int32_sync (fixture, "Test.nStyles(\"frm1\")"));
+       g_assert_cmpint (4, ==, test_utils_jsc_call_int32_sync (fixture, "Test.nStyles(\"frm1_1\")"));
+       g_assert_cmpint (2, ==, test_utils_jsc_call_int32_sync (fixture, "Test.nStyles(\"frm2\")"));
 
        e_web_view_jsc_remove_style_sheet (fixture->web_view, "*", "sheetA", NULL);
        test_utils_wait_noop (fixture);
@@ -878,43 +878,46 @@ test_style_sheets (TestFixture *fixture)
        g_assert_cmpint (0, ==, test_utils_jsc_call_bool_sync (fixture, "Test.hasStyle(\"frm1\", 
\"sheetA\")") ? 1 : 0);
        g_assert_cmpint (0, ==, test_utils_jsc_call_bool_sync (fixture, "Test.hasStyle(\"frm1_1\", 
\"sheetA\")") ? 1 : 0);
        g_assert_cmpint (3, ==, test_utils_jsc_call_int32_sync (fixture, "Test.nStyles(\"\")"));
-       g_assert_cmpint (1, ==, test_utils_jsc_call_int32_sync (fixture, "Test.nStyles(\"frm1\")"));
-       g_assert_cmpint (2, ==, test_utils_jsc_call_int32_sync (fixture, "Test.nStyles(\"frm1_1\")"));
-       g_assert_cmpint (1, ==, test_utils_jsc_call_int32_sync (fixture, "Test.nStyles(\"frm2\")"));
+       g_assert_cmpint (2, ==, test_utils_jsc_call_int32_sync (fixture, "Test.nStyles(\"frm1\")"));
+       g_assert_cmpint (3, ==, test_utils_jsc_call_int32_sync (fixture, "Test.nStyles(\"frm1_1\")"));
+       g_assert_cmpint (2, ==, test_utils_jsc_call_int32_sync (fixture, "Test.nStyles(\"frm2\")"));
 
        e_web_view_jsc_remove_style_sheet (fixture->web_view, "frm1_1", "*", NULL);
        test_utils_wait_noop (fixture);
 
        g_assert_cmpint (3, ==, test_utils_jsc_call_int32_sync (fixture, "Test.nStyles(\"\")"));
-       g_assert_cmpint (1, ==, test_utils_jsc_call_int32_sync (fixture, "Test.nStyles(\"frm1\")"));
+       g_assert_cmpint (2, ==, test_utils_jsc_call_int32_sync (fixture, "Test.nStyles(\"frm1\")"));
        g_assert_cmpint (0, ==, test_utils_jsc_call_int32_sync (fixture, "Test.nStyles(\"frm1_1\")"));
-       g_assert_cmpint (1, ==, test_utils_jsc_call_int32_sync (fixture, "Test.nStyles(\"frm2\")"));
+       g_assert_cmpint (2, ==, test_utils_jsc_call_int32_sync (fixture, "Test.nStyles(\"frm2\")"));
 
        e_web_view_jsc_add_rule_into_style_sheet (fixture->web_view, "", "sheetB", "body", "color:green;", 
NULL);
+       e_web_view_jsc_add_rule_into_style_sheet (fixture->web_view, "frm1", "sheetD", "body", "color:blue;", 
NULL);
        e_web_view_jsc_add_rule_into_style_sheet (fixture->web_view, "frm1_1", "sheetB", "body", 
"color:green;", NULL);
        e_web_view_jsc_add_rule_into_style_sheet (fixture->web_view, "frm1_1", "sheetC", "body", 
"color:yellow;", NULL);
+       e_web_view_jsc_add_rule_into_style_sheet (fixture->web_view, "frm2", "sheetD", "body", "color:blue;", 
NULL);
+       e_web_view_jsc_add_rule_into_style_sheet (fixture->web_view, "frm2", "sheetE", "body", 
"color:orange;", NULL);
        test_utils_wait_noop (fixture);
 
        g_assert_cmpint (4, ==, test_utils_jsc_call_int32_sync (fixture, "Test.nStyles(\"\")"));
-       g_assert_cmpint (1, ==, test_utils_jsc_call_int32_sync (fixture, "Test.nStyles(\"frm1\")"));
+       g_assert_cmpint (3, ==, test_utils_jsc_call_int32_sync (fixture, "Test.nStyles(\"frm1\")"));
        g_assert_cmpint (2, ==, test_utils_jsc_call_int32_sync (fixture, "Test.nStyles(\"frm1_1\")"));
-       g_assert_cmpint (1, ==, test_utils_jsc_call_int32_sync (fixture, "Test.nStyles(\"frm2\")"));
+       g_assert_cmpint (4, ==, test_utils_jsc_call_int32_sync (fixture, "Test.nStyles(\"frm2\")"));
 
        e_web_view_jsc_remove_style_sheet (fixture->web_view, "", "*", NULL);
        test_utils_wait_noop (fixture);
 
        g_assert_cmpint (0, ==, test_utils_jsc_call_int32_sync (fixture, "Test.nStyles(\"\")"));
-       g_assert_cmpint (1, ==, test_utils_jsc_call_int32_sync (fixture, "Test.nStyles(\"frm1\")"));
+       g_assert_cmpint (3, ==, test_utils_jsc_call_int32_sync (fixture, "Test.nStyles(\"frm1\")"));
        g_assert_cmpint (2, ==, test_utils_jsc_call_int32_sync (fixture, "Test.nStyles(\"frm1_1\")"));
-       g_assert_cmpint (1, ==, test_utils_jsc_call_int32_sync (fixture, "Test.nStyles(\"frm2\")"));
+       g_assert_cmpint (4, ==, test_utils_jsc_call_int32_sync (fixture, "Test.nStyles(\"frm2\")"));
 
        e_web_view_jsc_add_rule_into_style_sheet (fixture->web_view, "", "sheetC", "body", "color:yellow;", 
NULL);
        test_utils_wait_noop (fixture);
 
        g_assert_cmpint (1, ==, test_utils_jsc_call_int32_sync (fixture, "Test.nStyles(\"\")"));
-       g_assert_cmpint (1, ==, test_utils_jsc_call_int32_sync (fixture, "Test.nStyles(\"frm1\")"));
+       g_assert_cmpint (3, ==, test_utils_jsc_call_int32_sync (fixture, "Test.nStyles(\"frm1\")"));
        g_assert_cmpint (2, ==, test_utils_jsc_call_int32_sync (fixture, "Test.nStyles(\"frm1_1\")"));
-       g_assert_cmpint (1, ==, test_utils_jsc_call_int32_sync (fixture, "Test.nStyles(\"frm2\")"));
+       g_assert_cmpint (4, ==, test_utils_jsc_call_int32_sync (fixture, "Test.nStyles(\"frm2\")"));
 
        e_web_view_jsc_remove_style_sheet (fixture->web_view, "*", "*", NULL);
        test_utils_wait_noop (fixture);
diff --git a/src/em-format/e-mail-part-headers.c b/src/em-format/e-mail-part-headers.c
index 7f5a9b2a62..a08730bed1 100644
--- a/src/em-format/e-mail-part-headers.c
+++ b/src/em-format/e-mail-part-headers.c
@@ -207,28 +207,10 @@ mail_part_headers_constructed (GObject *object)
        e_mail_part_set_mime_type (part, E_MAIL_PART_HEADERS_MIME_TYPE);
 }
 
-static void
-mail_part_headers_bind_dom_element (EMailPart *part,
-                                    EWebView *web_view,
-                                    guint64 page_id,
-                                    const gchar *element_id)
-{
-       GDBusProxy *web_extension = e_web_view_get_web_extension_proxy (web_view);
-
-       if (web_extension) {
-               e_util_invoke_g_dbus_proxy_call_with_error_check (
-                       web_extension,
-                       "EMailPartHeadersBindDOMElement",
-                       g_variant_new ("(ts)", page_id, element_id),
-                       NULL);
-       }
-}
-
 static void
 e_mail_part_headers_class_init (EMailPartHeadersClass *class)
 {
        GObjectClass *object_class;
-       EMailPartClass *mail_part_class;
 
        g_type_class_add_private (class, sizeof (EMailPartHeadersPrivate));
 
@@ -239,9 +221,6 @@ e_mail_part_headers_class_init (EMailPartHeadersClass *class)
        object_class->finalize = mail_part_headers_finalize;
        object_class->constructed = mail_part_headers_constructed;
 
-       mail_part_class = E_MAIL_PART_CLASS (class);
-       mail_part_class->bind_dom_element = mail_part_headers_bind_dom_element;
-
        g_object_class_install_property (
                object_class,
                PROP_DEFAULT_HEADERS,
diff --git a/src/em-format/e-mail-part-secure-button.c b/src/em-format/e-mail-part-secure-button.c
index 1ddeef0045..a224376257 100644
--- a/src/em-format/e-mail-part-secure-button.c
+++ b/src/em-format/e-mail-part-secure-button.c
@@ -366,8 +366,8 @@ secure_button_clicked_cb (EWebView *web_view,
 }
 
 static void
-mail_part_secure_button_web_view_loaded (EMailPart *mail_part,
-                                        EWebView *web_view)
+mail_part_secure_button_content_loaded (EMailPart *mail_part,
+                                       EWebView *web_view)
 {
        g_return_if_fail (E_IS_MAIL_PART_SECURE_BUTTON (mail_part));
        g_return_if_fail (E_IS_WEB_VIEW (web_view));
@@ -381,7 +381,7 @@ e_mail_part_secure_button_class_init (EMailPartSecureButtonClass *class)
        EMailPartClass *mail_part_class;
 
        mail_part_class = E_MAIL_PART_CLASS (class);
-       mail_part_class->web_view_loaded = mail_part_secure_button_web_view_loaded;
+       mail_part_class->content_loaded = mail_part_secure_button_content_loaded;
 }
 
 static void
diff --git a/src/em-format/e-mail-part.c b/src/em-format/e-mail-part.c
index 4fccd77168..9a2e1ae179 100644
--- a/src/em-format/e-mail-part.c
+++ b/src/em-format/e-mail-part.c
@@ -631,39 +631,19 @@ e_mail_part_set_is_printable (EMailPart *part,
 }
 
 void
-e_mail_part_bind_dom_element (EMailPart *part,
-                              EWebView *web_view,
-                              guint64 page_id,
-                              const gchar *element_id)
+e_mail_part_content_loaded (EMailPart *part,
+                           EWebView *web_view)
 {
        EMailPartClass *class;
 
        g_return_if_fail (E_IS_MAIL_PART (part));
        g_return_if_fail (E_IS_WEB_VIEW (web_view));
-       g_return_if_fail (page_id != 0);
-       g_return_if_fail (element_id && *element_id);
 
        class = E_MAIL_PART_GET_CLASS (part);
        g_return_if_fail (class != NULL);
 
-       if (class->bind_dom_element != NULL)
-               class->bind_dom_element (part, web_view, page_id, element_id);
-}
-
-void
-e_mail_part_web_view_loaded (EMailPart *part,
-                            EWebView *web_view)
-{
-       EMailPartClass *klass;
-
-       g_return_if_fail (E_IS_MAIL_PART (part));
-       g_return_if_fail (E_IS_WEB_VIEW (web_view));
-
-       klass = E_MAIL_PART_GET_CLASS (part);
-       g_return_if_fail (klass != NULL);
-
-       if (klass->web_view_loaded)
-               klass->web_view_loaded (part, web_view);
+       if (class->content_loaded)
+               class->content_loaded (part, web_view);
 }
 
 static EMailPartValidityPair *
diff --git a/src/em-format/e-mail-part.h b/src/em-format/e-mail-part.h
index b872119979..8d2c8122c1 100644
--- a/src/em-format/e-mail-part.h
+++ b/src/em-format/e-mail-part.h
@@ -85,11 +85,7 @@ struct _EMailPart {
 struct _EMailPartClass {
        GObjectClass parent_class;
 
-       void            (*bind_dom_element)     (EMailPart *part,
-                                                EWebView *web_view,
-                                                guint64 page_id,
-                                                const gchar *element_id);
-       void            (*web_view_loaded)      (EMailPart *part,
+       void            (*content_loaded)       (EMailPart *part,
                                                 EWebView *web_view);
 };
 
@@ -126,11 +122,7 @@ void               e_mail_part_set_is_attachment   (EMailPart *part,
 gboolean       e_mail_part_get_is_printable    (EMailPart *part);
 void           e_mail_part_set_is_printable    (EMailPart *part,
                                                 gboolean is_printable);
-void           e_mail_part_bind_dom_element    (EMailPart *part,
-                                                EWebView *web_view,
-                                                guint64 page_id,
-                                                const gchar *element_id);
-void           e_mail_part_web_view_loaded     (EMailPart *part,
+void           e_mail_part_content_loaded      (EMailPart *part,
                                                 EWebView *web_view);
 void           e_mail_part_update_validity     (EMailPart *part,
                                                 CamelCipherValidity *validity,
diff --git a/src/mail/e-mail-display.c b/src/mail/e-mail-display.c
index 533e18bdaa..11f85b317e 100644
--- a/src/mail/e-mail-display.c
+++ b/src/mail/e-mail-display.c
@@ -59,6 +59,11 @@ typedef enum {
        E_ATTACHMENT_FLAG_ZOOMED_TO_100 = (1 << 1)
 } EAttachmentFlags;
 
+typedef enum {
+       E_MAGIC_SPACEBAR_CAN_GO_BOTTOM  = (1 << 0),
+       E_MAGIC_SPACEBAR_CAN_GO_TOP     = (1 << 1)
+} EMagicSpacebarFlags;
+
 struct _EMailDisplayPrivate {
        EAttachmentStore *attachment_store;
        EAttachmentView *attachment_view;
@@ -85,9 +90,7 @@ struct _EMailDisplayPrivate {
        EMailRemoteContent *remote_content;
        GHashTable *skipped_remote_content_sites;
 
-       GDBusConnection *web_extension_connection;
-       guint web_extension_headers_collapsed_signal_id;
-       guint web_extension_mail_part_appeared_signal_id;
+       guint32 magic_spacebar_state; /* bit-or of EMagicSpacebarFlags */
 };
 
 enum {
@@ -399,9 +402,10 @@ decide_policy_cb (WebKitWebView *web_view,
 }
 
 static void
-add_color_css_rule_for_web_view (EWebView *view,
-                                 const gchar *color_name,
-                                 const gchar *color_value)
+add_color_css_rule_for_web_view (EWebView *web_view,
+                                const gchar *iframe_id,
+                                const gchar *color_name,
+                                const gchar *color_value)
 {
        gchar *selector;
        gchar *style;
@@ -419,18 +423,21 @@ add_color_css_rule_for_web_view (EWebView *view,
                        "background-color: ", color_value, " !important;", NULL);
        }
 
-       e_web_view_add_css_rule_into_style_sheet (
-               view,
+       e_web_view_jsc_add_rule_into_style_sheet (
+               WEBKIT_WEB_VIEW (web_view),
+               iframe_id,
                "-e-mail-formatter-style-sheet",
                selector,
-               style);
+               style,
+               e_web_view_get_cancellable (web_view));
 
        g_free (style);
        g_free (selector);
 }
 
 static void
-initialize_web_view_colors (EMailDisplay *display)
+initialize_web_view_colors (EMailDisplay *display,
+                           const gchar *iframe_id)
 {
        EMailFormatter *formatter;
        GtkTextDirection direction;
@@ -456,6 +463,7 @@ initialize_web_view_colors (EMailDisplay *display)
 
                add_color_css_rule_for_web_view (
                        E_WEB_VIEW (display),
+                       iframe_id,
                        color_names[ii],
                        color_value);
 
@@ -463,11 +471,13 @@ initialize_web_view_colors (EMailDisplay *display)
                g_free (color_value);
        }
 
-       e_web_view_add_css_rule_into_style_sheet (
-               E_WEB_VIEW (display),
+       e_web_view_jsc_add_rule_into_style_sheet (
+               WEBKIT_WEB_VIEW (display),
+               iframe_id,
                "-e-mail-formatter-style-sheet",
                ".-e-mail-formatter-frame-security-none",
-               "border-width: 1px; border-style: solid");
+               "border-width: 1px; border-style: solid",
+               e_web_view_get_cancellable (E_WEB_VIEW (display)));
 
        /* the rgba values below were copied from e-formatter-secure-button */
        direction = gtk_widget_get_default_direction ();
@@ -476,168 +486,49 @@ initialize_web_view_colors (EMailDisplay *display)
                style = "border-width: 1px 1px 1px 4px; border-style: solid; border-color: rgba(53%, 73%, 
53%, 1.0)";
        else
                style = "border-width: 1px 4px 1px 1px; border-style: solid; border-color: rgba(53%, 73%, 
53%, 1.0)";
-       e_web_view_add_css_rule_into_style_sheet (
-               E_WEB_VIEW (display),
+       e_web_view_jsc_add_rule_into_style_sheet (
+               WEBKIT_WEB_VIEW (display),
+               iframe_id,
                "-e-mail-formatter-style-sheet",
                ".-e-mail-formatter-frame-security-good",
-               style);
+               style,
+               e_web_view_get_cancellable (E_WEB_VIEW (display)));
 
        if (direction == GTK_TEXT_DIR_RTL)
                style = "border-width: 1px 1px 1px 4px; border-style: solid; border-color: rgba(73%, 53%, 
53%, 1.0)";
        else
                style = "border-width: 1px 4px 1px 1px; border-style: solid; border-color: rgba(73%, 53%, 
53%, 1.0)";
-       e_web_view_add_css_rule_into_style_sheet (
-               E_WEB_VIEW (display),
+       e_web_view_jsc_add_rule_into_style_sheet (
+               WEBKIT_WEB_VIEW (display),
+               iframe_id,
                "-e-mail-formatter-style-sheet",
                ".-e-mail-formatter-frame-security-bad",
-               style);
+               style,
+               e_web_view_get_cancellable (E_WEB_VIEW (display)));
 
        if (direction == GTK_TEXT_DIR_RTL)
                style = "border-width: 1px 1px 1px 4px; border-style: solid; border-color: rgba(91%, 82%, 
13%, 1.0)";
        else
                style = "border-width: 1px 4px 1px 1px; border-style: solid; border-color: rgba(91%, 82%, 
13%, 1.0)";
-       e_web_view_add_css_rule_into_style_sheet (
-               E_WEB_VIEW (display),
+       e_web_view_jsc_add_rule_into_style_sheet (
+               WEBKIT_WEB_VIEW (display),
+               iframe_id,
                "-e-mail-formatter-style-sheet",
                ".-e-mail-formatter-frame-security-unknown",
-               style);
+               style,
+               e_web_view_get_cancellable (E_WEB_VIEW (display)));
 
        if (direction == GTK_TEXT_DIR_RTL)
                style = "border-width: 1px 1px 1px 4px; border-style: solid; border-color: rgba(91%, 82%, 
13%, 1.0)";
        else
                style = "border-width: 1px 4px 1px 1px; border-style: solid; border-color: rgba(91%, 82%, 
13%, 1.0)";
-       e_web_view_add_css_rule_into_style_sheet (
-               E_WEB_VIEW (display),
+       e_web_view_jsc_add_rule_into_style_sheet (
+               WEBKIT_WEB_VIEW (display),
+               iframe_id,
                "-e-mail-formatter-style-sheet",
                ".-e-mail-formatter-frame-security-need-key",
-               style);
-}
-
-static void
-headers_collapsed_signal_cb (GDBusConnection *connection,
-                             const gchar *sender_name,
-                             const gchar *object_path,
-                             const gchar *interface_name,
-                             const gchar *signal_name,
-                             GVariant *parameters,
-                             EMailDisplay *display)
-{
-       gboolean collapsed = FALSE;
-
-       if (g_strcmp0 (signal_name, "HeadersCollapsed") != 0)
-               return;
-
-       if (parameters)
-               g_variant_get (parameters, "(b)", &collapsed);
-
-       e_mail_display_set_headers_collapsed (display, collapsed);
-}
-
-static void
-mail_display_mail_part_appeared_signal_cb (GDBusConnection *connection,
-                                          const gchar *sender_name,
-                                          const gchar *object_path,
-                                          const gchar *interface_name,
-                                          const gchar *signal_name,
-                                          GVariant *parameters,
-                                          gpointer user_data)
-{
-       EMailDisplay *display = user_data;
-       GDBusProxy *web_extension;
-       const gchar *part_id = NULL;
-       guint64 page_id = 0;
-       EMailPart *part;
-
-       if (g_strcmp0 (signal_name, "MailPartAppeared") != 0)
-               return;
-
-       g_return_if_fail (E_IS_MAIL_DISPLAY (display));
-
-       if (!parameters || !display->priv->part_list)
-               return;
-
-       g_variant_get (parameters, "(t&s)", &page_id, &part_id);
-
-       if (!part_id || !*part_id || page_id != webkit_web_view_get_page_id (WEBKIT_WEB_VIEW (display)))
-               return;
-
-       part = e_mail_part_list_ref_part (display->priv->part_list, part_id);
-       if (part && g_strcmp0 (e_mail_part_get_id (part), part_id) == 0) {
-               e_mail_part_bind_dom_element (part, E_WEB_VIEW (display), page_id, part_id);
-       }
-
-       g_clear_object (&part);
-
-       web_extension = e_web_view_get_web_extension_proxy (E_WEB_VIEW (display));
-       if (web_extension) {
-               e_util_invoke_g_dbus_proxy_call_with_error_check (
-                       web_extension,
-                       "EMailDisplayBindDOM",
-                       g_variant_new (
-                               "(t)",
-                               webkit_web_view_get_page_id (WEBKIT_WEB_VIEW (display))),
-                       NULL);
-       }
-}
-
-static void
-setup_dom_bindings (EMailDisplay *display)
-{
-       GDBusProxy *web_extension;
-
-       web_extension = e_web_view_get_web_extension_proxy (E_WEB_VIEW (display));
-
-       if (display->priv->web_extension_connection) {
-               if (display->priv->web_extension_headers_collapsed_signal_id) {
-                       g_dbus_connection_signal_unsubscribe (display->priv->web_extension_connection, 
display->priv->web_extension_headers_collapsed_signal_id);
-                       display->priv->web_extension_headers_collapsed_signal_id = 0;
-               }
-
-               if (display->priv->web_extension_mail_part_appeared_signal_id) {
-                       g_dbus_connection_signal_unsubscribe (display->priv->web_extension_connection, 
display->priv->web_extension_mail_part_appeared_signal_id);
-                       display->priv->web_extension_mail_part_appeared_signal_id = 0;
-               }
-
-               g_clear_object (&display->priv->web_extension_connection);
-       }
-
-       if (web_extension) {
-               display->priv->web_extension_connection = g_object_ref (g_dbus_proxy_get_connection 
(web_extension));
-
-               display->priv->web_extension_headers_collapsed_signal_id =
-                       g_dbus_connection_signal_subscribe (
-                               display->priv->web_extension_connection,
-                               g_dbus_proxy_get_name (web_extension),
-                               E_WEB_EXTENSION_INTERFACE,
-                               "HeadersCollapsed",
-                               E_WEB_EXTENSION_OBJECT_PATH,
-                               NULL,
-                               G_DBUS_SIGNAL_FLAGS_NONE,
-                               (GDBusSignalCallback) headers_collapsed_signal_cb,
-                               display,
-                               NULL);
-
-               display->priv->web_extension_mail_part_appeared_signal_id =
-                       g_dbus_connection_signal_subscribe (
-                               display->priv->web_extension_connection,
-                               g_dbus_proxy_get_name (web_extension),
-                               E_WEB_EXTENSION_INTERFACE,
-                               "MailPartAppeared",
-                               E_WEB_EXTENSION_OBJECT_PATH,
-                               NULL,
-                               G_DBUS_SIGNAL_FLAGS_NONE,
-                               mail_display_mail_part_appeared_signal_cb,
-                               display,
-                               NULL);
-
-               e_util_invoke_g_dbus_proxy_call_with_error_check (
-                       web_extension,
-                       "EMailDisplayBindDOM",
-                       g_variant_new (
-                               "(t)",
-                               webkit_web_view_get_page_id (WEBKIT_WEB_VIEW (display))),
-                       NULL);
-       }
+               style,
+               e_web_view_get_cancellable (E_WEB_VIEW (display)));
 }
 
 static void
@@ -668,7 +559,9 @@ mail_display_change_one_attachment_visibility (EMailDisplay *display,
        g_hash_table_insert (display->priv->attachment_flags, attachment, GUINT_TO_POINTER (flags));
 
        element_id = g_strdup_printf ("attachment-wrapper-%p", attachment);
-       e_web_view_set_element_hidden (E_WEB_VIEW (display), element_id, !show);
+       e_web_view_jsc_run_script (WEBKIT_WEB_VIEW (display), e_web_view_get_cancellable (E_WEB_VIEW 
(display)),
+               "Evo.MailDisplayShowAttachment(%s,%x);",
+               element_id, show);
        g_free (element_id);
 
        element_id = g_strdup_printf ("attachment-expander-img-%p", attachment);
@@ -1185,154 +1078,74 @@ mail_display_attachment_removed_cb (EAttachmentStore *store,
        g_hash_table_remove (display->priv->attachment_flags, attachment);
 }
 
-typedef struct _MailElementExistsData {
-       EWebView *web_view;
-       EMailPart *part;
-} MailElementExistsData;
-
 static void
-mail_element_exists_cb (GObject *source_object,
-                        GAsyncResult *result,
-                        gpointer user_data)
-{
-       GDBusProxy *web_extension;
-       MailElementExistsData *meed = user_data;
-       gboolean element_exists = FALSE;
-       GVariant *result_variant;
-       guint64 page_id;
-       GError *error = NULL;
-
-       g_return_if_fail (G_IS_DBUS_PROXY (source_object));
-       g_return_if_fail (meed != NULL);
-
-       web_extension = G_DBUS_PROXY (source_object);
-
-       result_variant = g_dbus_proxy_call_finish (web_extension, result, &error);
-       if (result_variant) {
-               g_variant_get (result_variant, "(bt)", &element_exists, &page_id);
-               g_variant_unref (result_variant);
-       }
-
-       if (element_exists)
-               e_mail_part_bind_dom_element (
-                       meed->part,
-                       meed->web_view,
-                       page_id,
-                       e_mail_part_get_id (meed->part));
+mail_display_load_changed_cb (WebKitWebView *wk_web_view,
+                             WebKitLoadEvent load_event,
+                             gpointer user_data)
+{
+       EMailDisplay *display;
 
-       g_object_unref (meed->web_view);
-       g_object_unref (meed->part);
-       g_free (meed);
+       g_return_if_fail (E_IS_MAIL_DISPLAY (wk_web_view));
 
-       if (error)
-               g_dbus_error_strip_remote_error (error);
+       display = E_MAIL_DISPLAY (wk_web_view);
 
-       e_util_claim_dbus_proxy_call_error (web_extension, "ElementExists", error);
-       g_clear_error (&error);
+       if (load_event == WEBKIT_LOAD_STARTED) {
+               display->priv->magic_spacebar_state = 0;
+               e_mail_display_cleanup_skipped_uris (display);
+               e_attachment_store_remove_all (display->priv->attachment_store);
+       }
 }
 
 static void
-mail_parts_bind_dom (EMailDisplay *display)
+mail_display_content_loaded_cb (EWebView *web_view,
+                               const gchar *iframe_id,
+                               gpointer user_data)
 {
-       EWebView *web_view;
-       GQueue queue = G_QUEUE_INIT;
-       GList *head, *link;
-       GDBusProxy *web_extension;
-       gboolean has_attachment = FALSE;
-
-       g_return_if_fail (E_IS_MAIL_DISPLAY (display));
-
-       if (display->priv->part_list == NULL)
-               return;
+       EMailDisplay *mail_display;
 
-       initialize_web_view_colors (display);
-
-       web_view = E_WEB_VIEW (display);
-
-       web_extension = e_web_view_get_web_extension_proxy (web_view);
-       if (!web_extension)
-               return;
-
-       e_mail_part_list_queue_parts (display->priv->part_list, NULL, &queue);
-       head = g_queue_peek_head_link (&queue);
-
-       for (link = head; link != NULL; link = g_list_next (link)) {
-               MailElementExistsData *meed;
-               EMailPart *part = E_MAIL_PART (link->data);
-               const gchar *part_id;
-
-               part_id = e_mail_part_get_id (part);
-
-               has_attachment = has_attachment || E_IS_MAIL_PART_ATTACHMENT (part);
-
-               e_mail_part_web_view_loaded (part, web_view);
+       g_return_if_fail (E_IS_MAIL_DISPLAY (web_view));
 
-               meed = g_new0 (MailElementExistsData, 1);
-               meed->web_view = g_object_ref (web_view);
-               meed->part = g_object_ref (part);
+       mail_display = E_MAIL_DISPLAY (web_view);
 
-               g_dbus_proxy_call (
-                       web_extension,
-                       "ElementExists",
-                       g_variant_new (
-                               "(ts)",
-                               webkit_web_view_get_page_id (
-                                       WEBKIT_WEB_VIEW (display)),
-                               part_id),
-                       G_DBUS_CALL_FLAGS_NONE,
-                       -1,
-                       NULL,
-                       mail_element_exists_cb,
-                       meed);
-       }
+       initialize_web_view_colors (mail_display, iframe_id);
 
-       while (!g_queue_is_empty (&queue))
-               g_object_unref (g_queue_pop_head (&queue));
-
-       if (has_attachment) {
+       if (!iframe_id || !*iframe_id) {
                e_web_view_register_element_clicked (web_view, "attachment-expander",
                        mail_display_attachment_expander_clicked_cb, NULL);
                e_web_view_register_element_clicked (web_view, "attachment-menu",
                        mail_display_attachment_menu_clicked_cb, NULL);
        }
-}
 
-static void
-mail_display_load_changed_cb (WebKitWebView *wk_web_view,
-                             WebKitLoadEvent load_event,
-                             gpointer user_data)
-{
-       EMailDisplay *display;
+       e_web_view_jsc_run_script (WEBKIT_WEB_VIEW (web_view), e_web_view_get_cancellable (web_view),
+               "Evo.MailDisplayBindDOM(%s);", iframe_id);
 
-       g_return_if_fail (E_IS_MAIL_DISPLAY (wk_web_view));
+       if (mail_display->priv->part_list) {
+               if (!iframe_id || !*iframe_id) {
+                       GQueue queue = G_QUEUE_INIT;
+                       GList *head, *link;
 
-       display = E_MAIL_DISPLAY (wk_web_view);
+                       e_mail_part_list_queue_parts (mail_display->priv->part_list, NULL, &queue);
+                       head = g_queue_peek_head_link (&queue);
 
-       if (load_event == WEBKIT_LOAD_STARTED) {
-               e_mail_display_cleanup_skipped_uris (display);
-               e_attachment_store_remove_all (display->priv->attachment_store);
-               return;
-       }
+                       for (link = head; link; link = g_list_next (link)) {
+                               EMailPart *part = E_MAIL_PART (link->data);
 
-       if (load_event == WEBKIT_LOAD_FINISHED) {
-               setup_dom_bindings (display);
-               mail_parts_bind_dom (display);
-       }
-}
+                               e_mail_part_content_loaded (part, web_view);
+                       }
 
-static void
-mail_display_web_extension_proxy_notify_cb (GObject *object,
-                                           GParamSpec *param,
-                                           gpointer user_data)
-{
-       EMailDisplay *display;
+                       while (!g_queue_is_empty (&queue))
+                               g_object_unref (g_queue_pop_head (&queue));
+               } else {
+                       EMailPart *part;
 
-       g_return_if_fail (E_IS_MAIL_DISPLAY (object));
+                       part = e_mail_part_list_ref_part (mail_display->priv->part_list, iframe_id);
 
-       display = E_MAIL_DISPLAY (object);
+                       if (part)
+                               e_mail_part_content_loaded (part, web_view);
 
-       setup_dom_bindings (display);
-       mail_parts_bind_dom (display);
+                       g_clear_object (&part);
+               }
+       }
 }
 
 static void
@@ -1461,20 +1274,6 @@ mail_display_dispose (GObject *object)
                        0, 0, NULL, NULL, object);
        }
 
-       if (priv->web_extension_connection) {
-               if (priv->web_extension_headers_collapsed_signal_id) {
-                       g_dbus_connection_signal_unsubscribe (priv->web_extension_connection, 
priv->web_extension_headers_collapsed_signal_id);
-                       priv->web_extension_headers_collapsed_signal_id = 0;
-               }
-
-               if (priv->web_extension_mail_part_appeared_signal_id) {
-                       g_dbus_connection_signal_unsubscribe (priv->web_extension_connection, 
priv->web_extension_mail_part_appeared_signal_id);
-                       priv->web_extension_mail_part_appeared_signal_id = 0;
-               }
-
-               g_clear_object (&priv->web_extension_connection);
-       }
-
        if (priv->attachment_store) {
                /* To have called the mail_display_attachment_removed_cb() before it's disconnected */
                e_attachment_store_remove_all (priv->attachment_store);
@@ -1566,31 +1365,54 @@ mail_display_set_fonts (EWebView *web_view,
 }
 
 static void
-mail_display_web_view_initialize (WebKitWebView *web_view)
+mail_display_headers_collapsed_cb (WebKitUserContentManager *manager,
+                                  WebKitJavascriptResult *js_result,
+                                  gpointer user_data)
 {
-       WebKitSettings *webkit_settings;
+       EMailDisplay *mail_display = user_data;
+       JSCValue *jsc_value;
 
-       webkit_settings = webkit_web_view_get_settings (web_view);
+       g_return_if_fail (mail_display != NULL);
+       g_return_if_fail (js_result != NULL);
 
-       g_object_set (webkit_settings,
-               "enable-frame-flattening", TRUE,
-               NULL);
+       jsc_value = webkit_javascript_result_get_js_value (js_result);
+       g_return_if_fail (jsc_value_is_boolean (jsc_value));
+
+       e_mail_display_set_headers_collapsed (mail_display, jsc_value_to_boolean (jsc_value));
+}
+
+static void
+mail_display_magic_spacebar_state_changed_cb (WebKitUserContentManager *manager,
+                                             WebKitJavascriptResult *js_result,
+                                             gpointer user_data)
+{
+       EMailDisplay *mail_display = user_data;
+       JSCValue *jsc_value;
+
+       g_return_if_fail (mail_display != NULL);
+       g_return_if_fail (js_result != NULL);
+
+       jsc_value = webkit_javascript_result_get_js_value (js_result);
+       g_return_if_fail (jsc_value_is_number (jsc_value));
+
+       mail_display->priv->magic_spacebar_state = jsc_value_to_int32 (jsc_value);
 }
 
 static void
 mail_display_constructed (GObject *object)
 {
        EContentRequest *content_request;
+       WebKitUserContentManager *manager;
        EWebView *web_view;
        EMailDisplay *display;
        GtkUIManager *ui_manager;
 
-       e_extensible_load_extensions (E_EXTENSIBLE (object));
-
        /* Chain up to parent's constructed() method. */
        G_OBJECT_CLASS (e_mail_display_parent_class)->constructed (object);
 
-       mail_display_web_view_initialize (WEBKIT_WEB_VIEW (object));
+       g_object_set (webkit_web_view_get_settings (WEBKIT_WEB_VIEW (object)),
+               "enable-frame-flattening", TRUE,
+               NULL);
 
        display = E_MAIL_DISPLAY (object);
        web_view = E_WEB_VIEW (object);
@@ -1629,6 +1451,19 @@ mail_display_constructed (GObject *object)
                        g_clear_error (&error);
                }
        }
+
+       manager = webkit_web_view_get_user_content_manager (WEBKIT_WEB_VIEW (object));
+
+       g_signal_connect_object (manager, "script-message-received::mailDisplayHeadersCollapsed",
+               G_CALLBACK (mail_display_headers_collapsed_cb), display, 0);
+
+       g_signal_connect_object (manager, "script-message-received::mailDisplayMagicSpacebarStateChanged",
+               G_CALLBACK (mail_display_magic_spacebar_state_changed_cb), display, 0);
+
+       webkit_user_content_manager_register_script_message_handler (manager, "mailDisplayHeadersCollapsed");
+       webkit_user_content_manager_register_script_message_handler (manager, 
"mailDisplayMagicSpacebarStateChanged");
+
+       e_extensible_load_extensions (E_EXTENSIBLE (object));
 }
 
 static void
@@ -2282,6 +2117,10 @@ e_mail_display_init (EMailDisplay *display)
                display, "load-changed",
                G_CALLBACK (mail_display_load_changed_cb), NULL);
 
+       g_signal_connect (
+               display, "content-loaded",
+               G_CALLBACK (mail_display_content_loaded_cb), NULL);
+
        actions = e_web_view_get_action_group (E_WEB_VIEW (display), "mailto");
        gtk_action_group_add_actions (
                actions, mailto_entries,
@@ -2315,9 +2154,6 @@ e_mail_display_init (EMailDisplay *display)
                        g_clear_error (&error);
                }
        }
-
-       g_signal_connect (display, "notify::web-extension-proxy",
-               G_CALLBACK (mail_display_web_extension_proxy_notify_cb), NULL);
 }
 
 static void
@@ -2337,6 +2173,7 @@ e_mail_display_update_colors (EMailDisplay *display,
 
        add_color_css_rule_for_web_view (
                E_WEB_VIEW (display),
+               "*",
                param_spec->name,
                color_value);
 
@@ -2862,36 +2699,15 @@ gboolean
 e_mail_display_process_magic_spacebar (EMailDisplay *display,
                                       gboolean towards_bottom)
 {
-       GDBusProxy *web_extension;
-       GVariant *result;
-       GError *local_error = NULL;
-       gboolean processed = FALSE;
-
        g_return_val_if_fail (E_IS_MAIL_DISPLAY (display), FALSE);
 
-       web_extension = e_web_view_get_web_extension_proxy (E_WEB_VIEW (display));
-       if (!web_extension)
+       if ((towards_bottom && !(display->priv->magic_spacebar_state & E_MAGIC_SPACEBAR_CAN_GO_BOTTOM)) ||
+           (!towards_bottom && !(display->priv->magic_spacebar_state & E_MAGIC_SPACEBAR_CAN_GO_TOP)))
                return FALSE;
 
-       result = e_util_invoke_g_dbus_proxy_call_sync_wrapper_full (
-               web_extension,
-               "ProcessMagicSpacebar",
-               g_variant_new ("(tb)", webkit_web_view_get_page_id (WEBKIT_WEB_VIEW (display)), 
towards_bottom),
-               G_DBUS_CALL_FLAGS_NONE,
-               -1,
-               NULL,
-               &local_error);
-
-       if (local_error)
-               g_dbus_error_strip_remote_error (local_error);
-
-       e_util_claim_dbus_proxy_call_error (web_extension, "ProcessMagicSpacebar", local_error);
-       g_clear_error (&local_error);
-
-       if (result) {
-               g_variant_get (result, "(b)", &processed);
-               g_variant_unref (result);
-       }
+       e_web_view_jsc_run_script (WEBKIT_WEB_VIEW (display), e_web_view_get_cancellable (E_WEB_VIEW 
(display)),
+               "Evo.MailDisplayProcessMagicSpacebar(%x);",
+               towards_bottom);
 
-       return processed;
+       return TRUE;
 }
diff --git a/src/modules/itip-formatter/e-mail-part-itip.c b/src/modules/itip-formatter/e-mail-part-itip.c
index 03672cc1db..66007594bb 100644
--- a/src/modules/itip-formatter/e-mail-part-itip.c
+++ b/src/modules/itip-formatter/e-mail-part-itip.c
@@ -70,10 +70,8 @@ mail_part_itip_finalize (GObject *object)
 }
 
 static void
-mail_part_itip_bind_dom_element (EMailPart *part,
-                                EWebView *web_view,
-                                guint64 page_id,
-                                const gchar *element_id)
+mail_part_itip_content_loaded (EMailPart *part,
+                              EWebView *web_view)
 {
        EMailPartItip *pitip;
        ItipView *itip_view;
@@ -81,9 +79,6 @@ mail_part_itip_bind_dom_element (EMailPart *part,
        g_return_if_fail (E_IS_MAIL_PART_ITIP (part));
        g_return_if_fail (E_IS_WEB_VIEW (web_view));
 
-       if (g_strcmp0 (element_id, e_mail_part_get_id (part)) != 0)
-               return;
-
        pitip = E_MAIL_PART_ITIP (part);
 
        if (pitip->folder && pitip->message_uid && pitip->message) {
@@ -116,7 +111,7 @@ e_mail_part_itip_class_init (EMailPartItipClass *class)
        object_class->finalize = mail_part_itip_finalize;
 
        mail_part_class = E_MAIL_PART_CLASS (class);
-       mail_part_class->bind_dom_element = mail_part_itip_bind_dom_element;
+       mail_part_class->content_loaded = mail_part_itip_content_loaded;
 }
 
 static void
diff --git a/src/modules/vcard-inline/e-mail-formatter-vcard.c 
b/src/modules/vcard-inline/e-mail-formatter-vcard.c
index e930bce9c1..d1affd4474 100644
--- a/src/modules/vcard-inline/e-mail-formatter-vcard.c
+++ b/src/modules/vcard-inline/e-mail-formatter-vcard.c
@@ -62,42 +62,58 @@ mail_formatter_vcard_format (EMailFormatterExtension *extension,
                              GCancellable *cancellable)
 {
        EMailPartVCard *vcard_part;
+       const GSList *contacts;
 
        g_return_val_if_fail (E_IS_MAIL_PART_VCARD (part), FALSE);
 
        vcard_part = (EMailPartVCard *) part;
-       g_return_val_if_fail (vcard_part->contact_list != NULL, FALSE);
+       contacts = e_mail_part_vcard_get_contacts (vcard_part);
+
+       if (!contacts)
+               return FALSE;
 
        if (context->mode == E_MAIL_FORMATTER_MODE_RAW)  {
+               EABContactFormatter *vcard_formatter;
+               EABContactDisplayMode display_mode = EAB_CONTACT_DISPLAY_RENDER_COMPACT;
                EContact *contact;
                GString *buffer;
 
-               contact = E_CONTACT (vcard_part->contact_list->data);
+               contact = E_CONTACT (contacts->data);
 
                buffer = g_string_sized_new (1024);
 
-               eab_contact_formatter_format_contact (
-                       vcard_part->formatter, contact, buffer);
+               if (context && context->uri) {
+                       if (camel_strstrcase (context->uri, "vcard-format=normal"))
+                               display_mode = EAB_CONTACT_DISPLAY_RENDER_NORMAL;
+                       else if (camel_strstrcase (context->uri, "vcard-format=compact"))
+                               display_mode = EAB_CONTACT_DISPLAY_RENDER_COMPACT;
+               }
+
+               vcard_formatter = g_object_new (EAB_TYPE_CONTACT_FORMATTER,
+                       "display-mode", display_mode,
+                       "render-maps", FALSE,
+                       NULL);
+
+               eab_contact_formatter_format_contact (vcard_formatter, contact, buffer);
 
                g_output_stream_write_all (
                        stream, buffer->str, buffer->len,
                        NULL, cancellable, NULL);
 
                g_string_free (buffer, TRUE);
-
+               g_object_unref (vcard_formatter);
        } else {
                CamelFolder *folder;
                const gchar *message_uid;
                const gchar *default_charset, *charset;
-               gchar *str, *uri;
+               gchar *str, *uri, *button_iframe_uri;
                gint length;
                const gchar *label = NULL;
-               EABContactDisplayMode mode;
                const gchar *info = NULL;
                gchar *access_key = NULL;
                gchar *html_label;
 
-               length = g_slist_length (vcard_part->contact_list);
+               length = g_slist_length ((GSList *) contacts);
 
                folder = e_mail_part_list_get_folder (context->part_list);
                message_uid = e_mail_part_list_get_message_uid (context->part_list);
@@ -109,29 +125,15 @@ mail_formatter_vcard_format (EMailFormatterExtension *extension,
                if (!charset)
                        charset = "";
 
-               if (vcard_part->message_uid == NULL && message_uid != NULL)
-                       vcard_part->message_uid = g_strdup (message_uid);
-
-               if (vcard_part->folder == NULL && folder != NULL)
-                       vcard_part->folder = g_object_ref (folder);
-
                uri = e_mail_part_build_uri (
                        folder, message_uid,
                        "part_id", G_TYPE_STRING, e_mail_part_get_id (part),
                        "mode", G_TYPE_INT, E_MAIL_FORMATTER_MODE_RAW,
                        "formatter_default_charset", G_TYPE_STRING, default_charset,
                        "formatter_charset", G_TYPE_STRING, charset,
+                       "vcard-format", G_TYPE_STRING, "compact",
                        NULL);
 
-               mode = eab_contact_formatter_get_display_mode (vcard_part->formatter);
-               if (mode == EAB_CONTACT_DISPLAY_RENDER_COMPACT) {
-                       mode = EAB_CONTACT_DISPLAY_RENDER_NORMAL;
-                       label = _("Show F_ull vCard");
-               } else {
-                       mode = EAB_CONTACT_DISPLAY_RENDER_COMPACT;
-                       label = _("Show Com_pact vCard");
-               }
-
                str = g_strdup_printf (
                        "<div id=\"%s\">",
                        e_mail_part_get_id (part));
@@ -139,25 +141,65 @@ mail_formatter_vcard_format (EMailFormatterExtension *extension,
                        stream, str, strlen (str), NULL, cancellable, NULL);
                g_free (str);
 
-               html_label = e_mail_formatter_parse_html_mnemonics (
-                       label, &access_key);
+               button_iframe_uri = e_mail_part_build_uri (
+                       folder, message_uid,
+                       "part_id", G_TYPE_STRING, e_mail_part_get_id (part),
+                       "mode", G_TYPE_INT, E_MAIL_FORMATTER_MODE_RAW,
+                       "formatter_default_charset", G_TYPE_STRING, default_charset,
+                       "formatter_charset", G_TYPE_STRING, charset,
+                       "vcard-format", G_TYPE_STRING, "normal",
+                       NULL);
+
+               label = _("Show F_ull vCard");
+               html_label = e_mail_formatter_parse_html_mnemonics (label, &access_key);
                str = g_strdup_printf (
                        "<button type=\"button\" "
-                               "name=\"set-display-mode\" "
+                               "name=\"set-display-mode-normal\" "
                                "id=\"%s\" "
                                "class=\"org-gnome-vcard-display-mode-button\" "
                                "value=\"%d\" "
+                               "evo-iframe-uri=\"%s\" "
                                "style=\"margin-left: 0px\""
                                "accesskey=\"%s\">%s</button>",
                        e_mail_part_get_id (part),
-                       mode, access_key, html_label);
+                       EAB_CONTACT_DISPLAY_RENDER_NORMAL, button_iframe_uri, access_key,
+                       html_label);
                g_output_stream_write_all (
                        stream, str, strlen (str), NULL, cancellable, NULL);
                g_free (str);
                g_free (html_label);
+               g_free (button_iframe_uri);
+               g_clear_pointer (&access_key, g_free);
 
-               g_free (access_key);
-               access_key = NULL;
+               button_iframe_uri = e_mail_part_build_uri (
+                       folder, message_uid,
+                       "part_id", G_TYPE_STRING, e_mail_part_get_id (part),
+                       "mode", G_TYPE_INT, E_MAIL_FORMATTER_MODE_RAW,
+                       "formatter_default_charset", G_TYPE_STRING, default_charset,
+                       "formatter_charset", G_TYPE_STRING, charset,
+                       "vcard-format", G_TYPE_STRING, "compact",
+                       NULL);
+
+               label = _("Show Com_pact vCard");
+               html_label = e_mail_formatter_parse_html_mnemonics (label, &access_key);
+               str = g_strdup_printf (
+                       "<button type=\"button\" "
+                               "name=\"set-display-mode-compact\" "
+                               "id=\"%s\" "
+                               "class=\"org-gnome-vcard-display-mode-button\" "
+                               "value=\"%d\" "
+                               "evo-iframe-uri=\"%s\" "
+                               "style=\"margin-left: 0px\""
+                               "accesskey=\"%s\" hidden>%s</button>",
+                       e_mail_part_get_id (part),
+                       EAB_CONTACT_DISPLAY_RENDER_COMPACT, button_iframe_uri, access_key,
+                       html_label);
+               g_output_stream_write_all (
+                       stream, str, strlen (str), NULL, cancellable, NULL);
+               g_free (str);
+               g_free (html_label);
+               g_free (button_iframe_uri);
+               g_clear_pointer (&access_key, g_free);
 
                html_label = e_mail_formatter_parse_html_mnemonics (
                                _("Save _To Addressbook"), &access_key);
@@ -180,9 +222,7 @@ mail_formatter_vcard_format (EMailFormatterExtension *extension,
                        stream, str, strlen (str), NULL, cancellable, NULL);
                g_free (str);
                g_free (html_label);
-
-               g_free (access_key);
-               access_key = NULL;
+               g_clear_pointer (&access_key, g_free);
 
                if (length == 2) {
                        info = _("There is one other contact.");
diff --git a/src/modules/vcard-inline/e-mail-parser-vcard.c b/src/modules/vcard-inline/e-mail-parser-vcard.c
index 6ec7e1cd4d..557b599edb 100644
--- a/src/modules/vcard-inline/e-mail-parser-vcard.c
+++ b/src/modules/vcard-inline/e-mail-parser-vcard.c
@@ -86,7 +86,7 @@ decode_vcard (EMailPartVCard *vcard_part,
 
        string = (gchar *) array->data;
        contact_list = eab_contact_list_from_string (string);
-       vcard_part->contact_list = contact_list;
+       e_mail_part_vcard_take_contacts (vcard_part, contact_list);
 
        g_object_unref (mime_part);
        g_object_unref (stream);
@@ -109,10 +109,6 @@ empe_vcard_parse (EMailParserExtension *extension,
 
        vcard_part = e_mail_part_vcard_new (part, part_id->str);
 
-       vcard_part->formatter = g_object_new (
-               EAB_TYPE_CONTACT_FORMATTER,
-               "display-mode", EAB_CONTACT_DISPLAY_RENDER_COMPACT,
-               "render-maps", FALSE, NULL);
        g_object_ref (part);
 
        decode_vcard (vcard_part, part);
diff --git a/src/modules/vcard-inline/e-mail-part-vcard.c b/src/modules/vcard-inline/e-mail-part-vcard.c
index 72cea885f3..57ac2cc433 100644
--- a/src/modules/vcard-inline/e-mail-part-vcard.c
+++ b/src/modules/vcard-inline/e-mail-part-vcard.c
@@ -32,13 +32,7 @@
        ((obj), E_TYPE_MAIL_PART_VCARD, EMailPartVCardPrivate))
 
 struct _EMailPartVCardPrivate {
-       gint placeholder;
-
-       guint display_mode_toggled_signal_id;
-       guint save_vcard_button_pressed_signal_id;
-
-       GDBusProxy *web_extension;
-       guint64 page_id;
+       GSList *contacts;
 };
 
 G_DEFINE_DYNAMIC_TYPE (
@@ -92,30 +86,28 @@ client_connect_cb (GObject *source_object,
 }
 
 static void
-save_vcard_cb (GDBusConnection *connection,
-               const gchar *sender_name,
-               const gchar *object_path,
-               const gchar *interface_name,
-               const gchar *signal_name,
-               GVariant *parameters,
-               EMailPartVCard *vcard_part)
+mail_part_vcard_save_clicked_cb (EWebView *web_view,
+                                const gchar *iframe_id,
+                                const gchar *element_id,
+                                const gchar *element_class,
+                                const gchar *element_value,
+                                const GtkAllocation *element_position,
+                                gpointer user_data)
 {
+       EMailPartVCard *vcard_part = user_data;
        EShell *shell;
        ESource *source;
        ESourceRegistry *registry;
        ESourceSelector *selector;
        GSList *contact_list;
-       const gchar *extension_name, *button_value, *part_id;
+       const gchar *extension_name, *part_id;
        GtkWidget *dialog;
 
-       if (g_strcmp0 (signal_name, "VCardInlineSaveButtonPressed") != 0)
-               return;
-
-       g_variant_get (parameters, "(&s)", &button_value);
+       g_return_if_fail (E_IS_MAIL_PART_VCARD (vcard_part));
 
        part_id = e_mail_part_get_id (E_MAIL_PART (vcard_part));
 
-       if (!strstr (part_id, button_value))
+       if (!strstr (part_id, element_value))
                return;
 
        shell = e_shell_get_default ();
@@ -144,179 +136,19 @@ save_vcard_cb (GDBusConnection *connection,
        g_return_if_fail (source != NULL);
 
        contact_list = g_slist_copy_deep (
-               vcard_part->contact_list,
+               vcard_part->priv->contacts,
                (GCopyFunc) g_object_ref, NULL);
 
        e_book_client_connect (
                source, 30, NULL, client_connect_cb, contact_list);
 }
 
-static void
-display_mode_toggle_cb (GDBusConnection *connection,
-                        const gchar *sender_name,
-                        const gchar *object_path,
-                        const gchar *interface_name,
-                        const gchar *signal_name,
-                        GVariant *parameters,
-                        EMailPartVCard *vcard_part)
-{
-       EABContactDisplayMode mode;
-       gchar *uri;
-       gchar *html_label;
-       gchar *access_key;
-       const gchar *part_id;
-       const gchar *button_id;
-
-       if (g_strcmp0 (signal_name, "VCardInlineDisplayModeToggled") != 0)
-               return;
-
-       if (!vcard_part->priv->web_extension)
-               return;
-
-       g_variant_get (parameters, "(&s)", &button_id);
-
-       part_id = e_mail_part_get_id (E_MAIL_PART (vcard_part));
-
-       if (!strstr (part_id, button_id))
-               return;
-
-       mode = eab_contact_formatter_get_display_mode (vcard_part->formatter);
-       if (mode == EAB_CONTACT_DISPLAY_RENDER_NORMAL) {
-               mode = EAB_CONTACT_DISPLAY_RENDER_COMPACT;
-
-               html_label = e_mail_formatter_parse_html_mnemonics (
-                               _("Show F_ull vCard"), &access_key);
-       } else {
-               mode = EAB_CONTACT_DISPLAY_RENDER_NORMAL;
-
-               html_label = e_mail_formatter_parse_html_mnemonics (
-                               _("Show Com_pact vCard"), &access_key);
-       }
-
-       e_util_invoke_g_dbus_proxy_call_with_error_check (
-               vcard_part->priv->web_extension,
-               "VCardInlineUpdateButton",
-               g_variant_new (
-                       "(tsss)",
-                       vcard_part->priv->page_id,
-                       button_id,
-                       html_label,
-                       access_key),
-               NULL);
-
-       if (access_key)
-               g_free (access_key);
-
-       g_free (html_label);
-
-       eab_contact_formatter_set_display_mode (vcard_part->formatter, mode);
-
-       uri = e_mail_part_build_uri (
-               vcard_part->folder, vcard_part->message_uid,
-               "part_id", G_TYPE_STRING, part_id,
-               "mode", G_TYPE_INT, E_MAIL_FORMATTER_MODE_RAW, NULL);
-
-       e_util_invoke_g_dbus_proxy_call_with_error_check (
-               vcard_part->priv->web_extension,
-               "VCardInlineSetIFrameSrc",
-               g_variant_new (
-                       "(tss)",
-                       vcard_part->priv->page_id,
-                       button_id,
-                       uri),
-               NULL);
-
-       g_free (uri);
-}
-
-static void
-mail_part_vcard_set_web_extension_proxy (EMailPartVCard *part,
-                                        GDBusProxy *proxy)
-{
-       g_return_if_fail (E_IS_MAIL_PART_VCARD (part));
-
-       if (part->priv->web_extension) {
-               GDBusConnection *connection;
-
-               connection = g_dbus_proxy_get_connection (part->priv->web_extension);
-
-               if (connection && g_dbus_connection_is_closed (connection))
-                       connection = NULL;
-
-               if (connection && part->priv->display_mode_toggled_signal_id)
-                       g_dbus_connection_signal_unsubscribe (connection, 
part->priv->display_mode_toggled_signal_id);
-               part->priv->display_mode_toggled_signal_id = 0;
-
-               if (connection && part->priv->save_vcard_button_pressed_signal_id)
-                       g_dbus_connection_signal_unsubscribe (connection, 
part->priv->save_vcard_button_pressed_signal_id);
-               part->priv->save_vcard_button_pressed_signal_id = 0;
-
-               g_clear_object (&part->priv->web_extension);
-       }
-
-       if (proxy) {
-               GDBusConnection *connection;
-
-               part->priv->web_extension = g_object_ref (proxy);
-
-               connection = g_dbus_proxy_get_connection (proxy);
-
-               if (connection && g_dbus_connection_is_closed (connection))
-                       connection = NULL;
-
-               if (connection) {
-                       part->priv->display_mode_toggled_signal_id =
-                               g_dbus_connection_signal_subscribe (
-                                       connection,
-                                       g_dbus_proxy_get_name (proxy),
-                                       g_dbus_proxy_get_interface_name (proxy),
-                                       "VCardInlineDisplayModeToggled",
-                                       g_dbus_proxy_get_object_path (proxy),
-                                       NULL,
-                                       G_DBUS_SIGNAL_FLAGS_NONE,
-                                       (GDBusSignalCallback) display_mode_toggle_cb,
-                                       part,
-                                       NULL);
-
-                       part->priv->save_vcard_button_pressed_signal_id =
-                               g_dbus_connection_signal_subscribe (
-                                       connection,
-                                       g_dbus_proxy_get_name (proxy),
-                                       g_dbus_proxy_get_interface_name (proxy),
-                                       "VCardInlineSaveButtonPressed",
-                                       g_dbus_proxy_get_object_path (proxy),
-                                       NULL,
-                                       G_DBUS_SIGNAL_FLAGS_NONE,
-                                       (GDBusSignalCallback) save_vcard_cb,
-                                       part,
-                                       NULL);
-               }
-       }
-}
-
-static void
-mail_part_vcard_dispose (GObject *object)
-{
-       EMailPartVCard *part = E_MAIL_PART_VCARD (object);
-
-       g_clear_object (&part->contact_display);
-       g_clear_object (&part->message_label);
-       g_clear_object (&part->formatter);
-       g_clear_object (&part->folder);
-
-       mail_part_vcard_set_web_extension_proxy (part, NULL);
-
-       /* Chain up to parent's dispose() method. */
-       G_OBJECT_CLASS (e_mail_part_vcard_parent_class)->dispose (object);
-}
-
 static void
 mail_part_vcard_finalize (GObject *object)
 {
        EMailPartVCard *part = E_MAIL_PART_VCARD (object);
 
-       g_slist_free_full (part->contact_list, g_object_unref);
-       g_free (part->message_uid);
+       g_slist_free_full (part->priv->contacts, g_object_unref);
 
        /* Chain up to parent's finalize() method. */
        G_OBJECT_CLASS (e_mail_part_vcard_parent_class)->finalize (object);
@@ -348,34 +180,14 @@ mail_part_vcard_constructed (GObject *object)
 }
 
 static void
-mail_part_vcard_bind_dom_element (EMailPart *part,
-                                  EWebView *web_view,
-                                  guint64 page_id,
-                                  const gchar *element_id)
+mail_part_vcard_content_loaded (EMailPart *part,
+                               EWebView *web_view)
 {
-       EMailPartVCard *vcard_part;
-       GDBusProxy *web_extension;
-
        g_return_if_fail (E_IS_WEB_VIEW (web_view));
        g_return_if_fail (E_IS_MAIL_PART_VCARD (part));
 
-       web_extension = e_web_view_get_web_extension_proxy (web_view);
-       if (!web_extension)
-               return;
-
-       vcard_part = E_MAIL_PART_VCARD (part);
-       vcard_part->priv->page_id = page_id;
-
-       mail_part_vcard_set_web_extension_proxy (vcard_part, web_extension);
-
-       e_util_invoke_g_dbus_proxy_call_with_error_check (
-               web_extension,
-               "VCardInlineBindDOM",
-               g_variant_new (
-                       "(ts)",
-                       vcard_part->priv->page_id,
-                       element_id),
-               NULL);
+       e_web_view_register_element_clicked (web_view, "org-gnome-vcard-save-button",
+               mail_part_vcard_save_clicked_cb, part);
 }
 
 static void
@@ -387,12 +199,11 @@ e_mail_part_vcard_class_init (EMailPartVCardClass *class)
        g_type_class_add_private (class, sizeof (EMailPartVCardPrivate));
 
        object_class = G_OBJECT_CLASS (class);
-       object_class->dispose = mail_part_vcard_dispose;
        object_class->finalize = mail_part_vcard_finalize;
        object_class->constructed = mail_part_vcard_constructed;
 
        mail_part_class = E_MAIL_PART_CLASS (class);
-       mail_part_class->bind_dom_element = mail_part_vcard_bind_dom_element;
+       mail_part_class->content_loaded = mail_part_vcard_content_loaded;
 }
 
 static void
@@ -426,3 +237,20 @@ e_mail_part_vcard_new (CamelMimePart *mime_part,
                "id", id, "mime-part", mime_part, NULL);
 }
 
+void
+e_mail_part_vcard_take_contacts (EMailPartVCard *vcard_part,
+                                GSList *contacts)
+{
+       g_return_if_fail (E_IS_MAIL_PART_VCARD (vcard_part));
+
+       g_slist_free_full (vcard_part->priv->contacts, g_object_unref);
+       vcard_part->priv->contacts = contacts;
+}
+
+const GSList *
+e_mail_part_vcard_get_contacts (EMailPartVCard *vcard_part)
+{
+       g_return_val_if_fail (E_IS_MAIL_PART_VCARD (vcard_part), NULL);
+
+       return vcard_part->priv->contacts;
+}
diff --git a/src/modules/vcard-inline/e-mail-part-vcard.h b/src/modules/vcard-inline/e-mail-part-vcard.h
index 9aeb595482..c2e3b0a360 100644
--- a/src/modules/vcard-inline/e-mail-part-vcard.h
+++ b/src/modules/vcard-inline/e-mail-part-vcard.h
@@ -50,15 +50,6 @@ typedef struct _EMailPartVCardPrivate EMailPartVCardPrivate;
 struct _EMailPartVCard {
        EMailPart parent;
        EMailPartVCardPrivate *priv;
-
-       GSList *contact_list;
-       GtkWidget *contact_display;
-       GtkWidget *message_label;
-
-       EABContactFormatter *formatter;
-
-       CamelFolder *folder;
-       gchar *message_uid;
 };
 
 struct _EMailPartVCardClass {
@@ -70,6 +61,9 @@ void          e_mail_part_vcard_type_register (GTypeModule *type_module);
 EMailPartVCard *
                e_mail_part_vcard_new           (CamelMimePart *mime_part,
                                                 const gchar *id);
+void           e_mail_part_vcard_take_contacts (EMailPartVCard *vcard_part,
+                                                GSList *contacts);
+const GSList * e_mail_part_vcard_get_contacts  (EMailPartVCard *vcard_part);
 
 G_END_DECLS
 
diff --git a/src/web-extensions/ext-utils.js b/src/web-extensions/ext-utils.js
index 51116bb779..1e6db68da6 100644
--- a/src/web-extensions/ext-utils.js
+++ b/src/web-extensions/ext-utils.js
@@ -1,18 +1,23 @@
 'use strict';
 
+/* semi-convention: private functions start with lower-case letter,
+   public functions start with upper-case letter. */
+
 var Evo = {
-       hasSelection : false
+       hasSelection : false,
+       blockquoteStyle : "margin:0 0 0 .8ex; border-left:2px #729fcf solid;padding-left:1ex",
+       magicSpacebarState: -1
 };
 
 /* The 'traversar_obj' is an object, which implements a callback function:
-   boolean exec(doc, iframe_id);
+   boolean exec(doc, iframe_id, level);
    and it returns whether continue the traversar */
-Evo.foreachIFrameDocument = function(doc, traversar_obj, call_also_for_doc)
+Evo.foreachIFrameDocument = function(doc, traversar_obj, call_also_for_doc, level)
 {
        if (!doc)
                return false;
 
-       if (call_also_for_doc && !traversar_obj.exec(doc, doc.defaultView.frameElement ? 
doc.defaultView.frameElement.id : ""))
+       if (call_also_for_doc && !traversar_obj.exec(doc, doc.defaultView.frameElement ? 
doc.defaultView.frameElement.id : "", level))
                return false;
 
        var iframes, ii;
@@ -20,10 +25,10 @@ Evo.foreachIFrameDocument = function(doc, traversar_obj, call_also_for_doc)
        iframes = doc.getElementsByTagName("iframe");
 
        for (ii = 0; ii < iframes.length; ii++) {
-               if (!traversar_obj.exec(iframes[ii].contentDocument, iframes[ii].id))
+               if (!traversar_obj.exec(iframes[ii].contentDocument, iframes[ii].id, level + 1))
                        return false;
 
-               if (!Evo.foreachIFrameDocument(iframes[ii].contentDocument, traversar_obj, false))
+               if (!Evo.foreachIFrameDocument(iframes[ii].contentDocument, traversar_obj, false, level + 1))
                        return false;
        }
 
@@ -38,7 +43,7 @@ Evo.findIFrame = function(iframe_id)
        var traversar = {
                iframe_id : iframe_id,
                iframe : null,
-               exec : function(doc, iframe_id) {
+               exec : function(doc, iframe_id, level) {
                        if (iframe_id == this.iframe_id) {
                                this.iframe = doc.defaultView.frameElement;
                                return false;
@@ -47,7 +52,7 @@ Evo.findIFrame = function(iframe_id)
                }
        };
 
-       Evo.foreachIFrameDocument(document, traversar, true);
+       Evo.foreachIFrameDocument(document, traversar, true, 0);
 
        return traversar.iframe;
 }
@@ -68,12 +73,19 @@ Evo.findIFrameDocument = function(iframe_id)
 Evo.runTraversarForIFrameId = function(iframe_id, traversar_obj)
 {
        if (iframe_id == "*") {
-               Evo.foreachIFrameDocument(document, traversar_obj, true);
+               Evo.foreachIFrameDocument(document, traversar_obj, true, 0);
        } else {
                var doc = Evo.findIFrameDocument(iframe_id);
 
-               if (doc)
-                       traversar_obj.exec(doc, iframe_id);
+               if (doc) {
+                       var level = 0, parent;
+
+                       for (parent = doc.defaultView.frameElement; parent; parent = 
parent.ownerDocument.defaultView.frameElement) {
+                               level++;
+                       }
+
+                       traversar_obj.exec(doc, iframe_id, level);
+               }
        }
 }
 
@@ -99,7 +111,7 @@ Evo.findElement = function(iframe_id, element_id)
        var traversar = {
                element_id : element_id,
                res : null,
-               exec : function(doc, iframe_id) {
+               exec : function(doc, iframe_id, level) {
                        this.res = Evo.findElementInDocumentById(doc, this.element_id);
                        if (this.res)
                                return false;
@@ -181,7 +193,7 @@ Evo.RemoveStyleSheet = function(iframe_id, style_sheet_id)
 {
        var traversar = {
                style_sheet_id : style_sheet_id,
-               exec : function(doc, iframe_id) {
+               exec : function(doc, iframe_id, level) {
                        if (doc && doc.head) {
                                var ii, styles = doc.head.getElementsByTagName("style");
 
@@ -231,7 +243,7 @@ Evo.AddRuleIntoStyleSheet = function(iframe_id, style_sheet_id, selector, style)
                style_sheet_id : style_sheet_id,
                selector : selector,
                style : style,
-               exec : function(doc, iframe_id) {
+               exec : function(doc, iframe_id, level) {
                        if (doc && doc.head) {
                                Evo.addRuleIntoStyleSheetDocument(doc, this.style_sheet_id, this.selector, 
this.style);
                        }
@@ -247,7 +259,7 @@ Evo.SetDocumentContent = function(content)
 {
        document.documentElement.innerHTML = content;
 
-       Evo.Initialize(null);
+       Evo.initialize(null);
        window.webkit.messageHandlers.contentLoaded.postMessage("");
 }
 
@@ -266,12 +278,12 @@ Evo.SetIFrameContent = function(iframe_id, content)
        if (iframe) {
                iframe.contentDocument.documentElement.innerHTML = content;
 
-               Evo.Initialize(iframe);
+               Evo.initialize(iframe);
                window.webkit.messageHandlers.contentLoaded.postMessage(iframe_id);
        }
 }
 
-Evo.ElemClicked = function(elem)
+Evo.elementClicked = function(elem)
 {
        var with_parents_left, with_parents_top, scroll_x = 0, scroll_y = 0, offset_parent, dom_window;
        var parent_iframe_id = "";
@@ -329,7 +341,7 @@ Evo.RegisterElementClicked = function(iframe_id, elem_classes_str)
 {
        var traversar = {
                elem_classes : elem_classes_str.split("\n"),
-               exec : function(doc, iframe_id) {
+               exec : function(doc, iframe_id, level) {
                        if (doc && this.elem_classes) {
                                var ii;
 
@@ -340,7 +352,7 @@ Evo.RegisterElementClicked = function(iframe_id, elem_classes_str)
                                                elems = doc.getElementsByClassName(this.elem_classes[ii]);
 
                                                for (jj = 0; jj < elems.length; jj++) {
-                                                       elems[jj].onclick = function() { 
Evo.ElemClicked(this); };
+                                                       elems[jj].onclick = function() { 
Evo.elementClicked(this); };
                                                }
                                        }
                                }
@@ -399,7 +411,7 @@ Evo.checkHasSelection = function(content)
        var traversar = {
                content : content,
                has : false,
-               exec : function(doc, iframe_id) {
+               exec : function(doc, iframe_id, level) {
                        if (doc && !doc.defaultView.getSelection().isCollapsed) {
                                if (content) {
                                        var fragment, node, inpre;
@@ -421,7 +433,7 @@ Evo.checkHasSelection = function(content)
                }
        };
 
-       Evo.foreachIFrameDocument(document, traversar, true);
+       Evo.foreachIFrameDocument(document, traversar, true, 0);
 
        return traversar.has;
 }
@@ -544,22 +556,23 @@ Evo.GetElementFromPoint = function(xx, yy)
        return res;
 }
 
-Evo.Initialize = function(elem)
+Evo.initialize = function(elem)
 {
        var doc, elems, ii;
 
-       if (elem && /*elem instanceof HTMLIFrameElement*/ elem.tagName.toUpperCase() == "IFRAME" && 
elem.contentDocument)
+       if (elem && /*elem instanceof HTMLIFrameElement*/ elem.tagName.toUpperCase() == "IFRAME" && 
elem.contentDocument) {
+               elem.onload = function() { Evo.initializeAndPostContentLoaded(this); };
                doc = elem.contentDocument;
-       else
+       } else
                doc = document;
 
        elems = doc.getElementsByTagName("iframe");
 
        for (ii = 0; ii < elems.length; ii++) {
-               elems[ii].onload = function() { Evo.InitializeAndPostContentLoaded(this); };
+               elems[ii].onload = function() { Evo.initializeAndPostContentLoaded(this); };
 
                if (elems[ii].contentDocument.body && elems[ii].contentDocument.body.childElementCount > 0)
-                       Evo.InitializeAndPostContentLoaded(elems[ii]);
+                       Evo.initializeAndPostContentLoaded(elems[ii]);
        }
 
        if (!doc.body.hasAttribute("class"))
@@ -581,7 +594,7 @@ Evo.Initialize = function(elem)
        doc.onselectionchange = Evo.selectionChanged;
 }
 
-Evo.InitializeAndPostContentLoaded = function(elem)
+Evo.initializeAndPostContentLoaded = function(elem)
 {
        var iframe_id = "";
 
@@ -592,13 +605,459 @@ Evo.InitializeAndPostContentLoaded = function(elem)
        else if (window.frameElement)
                iframe_id = window.frameElement.id;
 
-       Evo.Initialize(elem);
+       Evo.initialize(elem);
        window.webkit.messageHandlers.contentLoaded.postMessage(iframe_id);
+
+       if (window.webkit.messageHandlers.mailDisplayMagicSpacebarStateChanged)
+               Evo.mailDisplayUpdateMagicSpacebarState();
+}
+
+Evo.EnsureMainDocumentInitialized = function()
+{
+       Evo.initializeAndPostContentLoaded(null);
 }
 
 if (this instanceof Window && this.document) {
-       this.document.onload = function() { Evo.InitializeAndPostContentLoaded(this); };
+       this.document.onload = function() { Evo.initializeAndPostContentLoaded(this); };
 
        if (this.document.body && this.document.body.firstChild)
-               Evo.InitializeAndPostContentLoaded(this.document);
+               Evo.initializeAndPostContentLoaded(this.document);
+}
+
+Evo.vCardCollapseContactList = function(elem)
+{
+       if (elem && elem.id && elem.id != "" && elem.ownerDocument) {
+               var list;
+
+               list = elem.ownerDocument.getElementById("list-" + elem.id);
+               if (list) {
+                       var child;
+
+                       list.hidden = !list.hidden;
+
+                       for (child = elem.firstElementChild; child; child = child.nextElementSibling) {
+                               if (/*child instanceof HTMLImageElement*/ child.tagName.toUpperCase() == 
"IMG") {
+                                       child.src = list.hidden ? "gtk-stock://pan-end-symbolic" : 
"gtk-stock://pan-down-symbolic";
+                               }
+                       }
+               }
+       }
+}
+
+Evo.vCardBindInDocument = function(doc)
+{
+       if (!doc)
+               return;
+
+       var elems, ii;
+
+       elems = doc.querySelectorAll("._evo_vcard_collapse_button");
+       for (ii = 0; ii < elems.length; ii++) {
+               elems[ii].onclick = function() { Evo.vCardCollapseContactList(this); };
+       }
+}
+
+Evo.VCardBind = function(iframe_id)
+{
+       var traversar = {
+               exec : function(doc, iframe_id, level) {
+                       Evo.vCardBindInDocument(doc);
+               }
+       };
+
+       Evo.runTraversarForIFrameId(iframe_id, traversar);
+}
+
+Evo.mailDisplayResizeContentToPreviewWidth = function()
+{
+       if (!document || !document.documentElement ||
+           document.documentElement.scrollWidth < document.documentElement.clientWidth) {
+               return;
+       }
+
+       var traversar = {
+               can_force_width_on_iframe : function(iframe) {
+                       if (!iframe || !iframe.contentDocument)
+                               return false;
+
+                       /* We can force the width on every message that was not formatted
+                        * by text-highlight module. */
+                       if (iframe.id.indexOf("text-highlight") < 0)
+                               return true;
+
+                       /* If the message was formatted with text-highlight we can adjust the
+                        * width just for the messages that were formatted as plain text. */
+                       return iframe.src.indexOf("__formatas=txt") >= 0;
+               },
+
+               set_iframe_and_body_width : function(doc, width, original_width, level) {
+                       if (!doc)
+                               return;
+
+                       var ii, iframes, local_width = width;
+
+                       iframes = doc.getElementsByTagName("iframe");
+
+                       if (level == 0) {
+                               local_width -= 2; /* 1 + 1 frame borders */
+                       } else if (!iframes.length) {
+                               /* Message main body */
+                               local_width -= 8; /* 8 + 8 margins of body without iframes */
+                               if (level > 1)
+                                       local_width -= 8;
+
+                               Evo.addRuleIntoStyleSheetDocument(doc, "-e-mail-formatter-style-sheet", 
"body", "width: " + local_width + "px;");
+                               Evo.addRuleIntoStyleSheetDocument(doc, "-e-mail-formatter-style-sheet", 
".part-container", "width: " + local_width + "px;");
+                       } else if (level == 1) {
+                               local_width -= 20; /* 10 + 10 margins of body with iframes */
+
+                               Evo.addRuleIntoStyleSheetDocument(doc, "-e-mail-formatter-style-sheet", 
"body",
+                                       "width: " + local_width + "px;");
+
+                               local_width -= 2; /* 1 + 1 frame borders */
+
+                               Evo.addRuleIntoStyleSheetDocument(doc, "-e-mail-formatter-style-sheet", 
".part-container-nostyle iframe",
+                                       "width: " + local_width + "px;");
+
+                               /* We need to subtract another 10 pixels from the iframe width to
+                                * have the iframe's borders on the correct place. We can't subtract
+                                * it from local_width as we don't want to propagate this change
+                                * further. */
+                               Evo.addRuleIntoStyleSheetDocument(doc, "-e-mail-formatter-style-sheet", 
".part-container iframe",
+                                       "width: " + (local_width - 10) + "px;");
+                       } else {
+                               local_width -= 20; /* 10 + 10 margins of body with iframes */
+                               local_width -= 8; /* attachment margin */
+                               local_width -= 2; /* 1 + 1 frame borders */
+
+                               /* We need to subtract another 10 pixels from the iframe width to
+                                * have the iframe's borders on the correct place. We can't subtract
+                                * it from local_width as we don't want to propagate this change
+                                * further. */
+                               Evo.addRuleIntoStyleSheetDocument(doc, "-e-mail-formatter-style-sheet", 
".part-container-nostyle iframe",
+                                       "width: " + (local_width - 10) + "px;");
+
+                               Evo.addRuleIntoStyleSheetDocument(doc, "-e-mail-formatter-style-sheet", "body 
.part-container-nostyle iframe",
+                                       "width: " + (local_width - 10) + "px;");
+                       }
+
+                       /* Add rules to every sub document */
+                       for (ii = 0; ii < iframes.length; ii++) {
+                               if (!this.can_force_width_on_iframe (iframes[ii]))
+                                       continue;
+
+                               var tmp_local_width = local_width;
+
+                               if (level == 0) {
+                                       tmp_local_width -= 8; /* attachment's margin */
+
+                                       Evo.addRuleIntoStyleSheetDocument(doc, 
"-e-mail-formatter-style-sheet", ".attachment-wrapper iframe:not([src*=\"__formatas=\"])",
+                                               "width: " + tmp_local_width + "px;");
+
+                                       Evo.addRuleIntoStyleSheetDocument(doc, 
"-e-mail-formatter-style-sheet", ".attachment-wrapper iframe[src*=\"__formatas=txt\"]",
+                                               "width: " + tmp_local_width + "px;");
+
+                                       Evo.addRuleIntoStyleSheetDocument(doc, 
"-e-mail-formatter-style-sheet", "body > .part-container-nostyle iframe",
+                                               "width: " + local_width + "px;");
+                               }
+
+                               this.set_iframe_and_body_width (iframes[ii].contentDocument, tmp_local_width, 
original_width, level + 1);
+                       }
+               }
+       };
+
+       var width = document.documentElement.clientWidth;
+
+       width -= 20; /* 10 + 10 margins of body */
+
+       traversar.set_iframe_and_body_width(document, width, width, 0);
+}
+
+Evo.mailDisplayUpdateMagicSpacebarState = function()
+{
+       var new_state = 0;
+
+       if (document && document.defaultView && document.documentElement && 
document.documentElement.scrollHeight) {
+               if (document.defaultView.scrollY + document.defaultView.innerHeight < 
document.documentElement.scrollHeight)
+                       new_state |= (1 << 0); /* E_MAGIC_SPACEBAR_CAN_GO_BOTTOM */
+
+               if (document.defaultView.scrollY > 0)
+                       new_state |= (1 << 1); /* E_MAGIC_SPACEBAR_CAN_GO_TOP */
+       }
+
+       if (new_state != Evo.magicSpacebarState) {
+               Evo.magicSpacebarState = new_state;
+               
window.webkit.messageHandlers.mailDisplayMagicSpacebarStateChanged.postMessage(Evo.magicSpacebarState);
+       }
+}
+
+Evo.mailDisplayResized = function()
+{
+       Evo.mailDisplayResizeContentToPreviewWidth();
+       Evo.mailDisplayUpdateMagicSpacebarState();
+}
+
+Evo.mailDisplayToggleHeadersVisibility = function(elem)
+{
+       if (!elem || !elem.ownerDocument)
+               return;
+
+       var short_headers, full_headers;
+
+       short_headers = elem.ownerDocument.getElementById("__evo-short-headers");
+       full_headers = elem.ownerDocument.getElementById("__evo-full-headers");
+
+       if (!short_headers || !full_headers)
+               return;
+
+       var expanded = full_headers.style.getPropertyValue("display") == "table";
+
+       full_headers.style.setProperty("display", expanded ? "none" : "table");
+       short_headers.style.setProperty("display", expanded ? "table" : "none");
+
+       if (elem.firstElementChild && /* elem.firstElementChild instanceof HTMLImageElement */ 
elem.firstElementChild.tagName.toUpperCase() == "IMG") {
+               elem.firstElementChild.src = expanded ? "gtk-stock://pan-end-symbolic" : 
"gtk-stock://pan-down-symbolic";
+       }
+
+       window.webkit.messageHandlers.mailDisplayHeadersCollapsed.postMessage(expanded);
+}
+
+Evo.mailDisplayToggleAddressVisibility = function(elem)
+{
+       if (!elem || !elem.ownerDocument)
+               return;
+
+       var parent, img;
+
+       /* get img and parent depending on which element the click came from (button/ellipsis) */
+       if (/* elem instanceof HTMLButtonElement */ elem.tagName.toUpperCase() == "BUTTON") {
+               parent = elem.parentElement.parentElement;
+               img = elem.firstElementChild;
+       } else {
+               var button;
+
+               parent = elem.parentElement;
+               button = parent.parentElement.querySelector("#__evo-moreaddr-button");
+               img = button.firstElementChild;
+       }
+
+       var full_addr, ellipsis;
+
+       full_addr = parent.querySelector("#__evo-moreaddr");
+       ellipsis = parent.querySelector("#__evo-moreaddr-ellipsis");
+
+       if (full_addr && ellipsis) {
+               var expanded;
+
+               expanded = full_addr.style.getPropertyValue("display") == "inline";
+
+               full_addr.style.setProperty("display", expanded ? "none" : "inline");
+               ellipsis.style.setProperty("display", expanded ? "inline" : "none");
+               img.src = expanded ? "gtk-stock://pan-end-symbolic" : "gtk-stock://pan-down-symbolic";
+       }
+}
+
+Evo.mailDisplayVCardModeButtonClicked = function(elem)
+{
+       if (!elem || !elem.parentElement)
+               return;
+
+       var normal_btn = null, compact_btn = null, iframe_elem = null, child;
+
+       for (child = elem.parentElement.firstElementChild; child; child = child.nextElementSibling) {
+               if (!iframe_elem && /* child instanceof HTMLImageElement */ child.tagName.toUpperCase() == 
"IFRAME") {
+                       iframe_elem = child;
+
+                       if (normal_btn && compact_btn)
+                               break;
+
+                       continue;
+               }
+
+               var name = child.getAttribute("name");
+
+               if (name) {
+                       if (!normal_btn && name == "set-display-mode-normal")
+                               normal_btn = child;
+                       else if (!compact_btn && name == "set-display-mode-compact")
+                               compact_btn = child;
+
+                       if (normal_btn && compact_btn && iframe_elem)
+                               break;
+               }
+       }
+
+       if (normal_btn && compact_btn && iframe_elem) {
+               normal_btn.hidden = normal_btn.isEqualNode(elem);
+               compact_btn.hidden = !normal_btn.hidden;
+               iframe_elem.src = elem.getAttribute("evo-iframe-uri");
+       }
+}
+
+Evo.MailDisplayBindDOM = function(iframe_id)
+{
+       var traversar = {
+               unstyleBlockquotes : function(doc) {
+                       var ii, elems;
+
+                       elems = doc.getElementsByTagName("blockquote");
+                       for (ii = 0; ii < elems.length; ii++) {
+                               var elem = elems[ii];
+
+                               if (elem.hasAttribute("type")) {
+                                       if (elem.getAttribute("type").toLowerCase() == "cite")
+                                               elem.removeAttribute("style");
+                               } else {
+                                       elem.removeAttribute("style");
+                                       elem.setAttribute("type", "cite");
+                               }
+
+                               if (elem.hasAttribute("style") &&
+                                   elem.getAttribute("style") == Evo.blockquoteStyle) {
+                                       elem.removeAttribute("style");
+                               }
+                       }
+               },
+               textRequiresWrap : function(text) {
+                       if (!text || text.length <= 80)
+                               return false;
+
+                       var cnt = -1, ii;
+
+                       for (ii = 0; ii < text.length; ii++) {
+                               cnt++;
+
+                               var chr = text.charAt(ii);
+
+                               if (chr == ' ' || chr == '\t' || chr == '\r' || chr == '\n')
+                                       cnt == -1;
+                               else if (cnt > 80)
+                                       return true;
+                       }
+
+                       return false;
+               },
+               wrapLongAchors : function(doc) {
+                       var ii, elems;
+
+                       elems = doc.getElementsByTagName("blockquote");
+                       for (ii = 0; ii < elems.length; ii++) {
+                               var elem = elems[ii];
+
+                               if (this.textRequiresWrap(elem.innerText))
+                                       elem.classList.add("evo-awrap");
+                               else
+                                       elem.classList.remove("evo-awrap");
+                       }
+               },
+               bind : function(doc) {
+                       var ii, elems;
+
+                       elems = doc.querySelectorAll("#__evo-collapse-headers-img");
+                       for (ii = 0; ii < elems.length; ii++) {
+                               elems[ii].onclick = function() { 
Evo.mailDisplayToggleHeadersVisibility(this); };
+                       }
+
+                       elems = doc.querySelectorAll("#__evo-moreaddr-ellipsis");
+                       for (ii = 0; ii < elems.length; ii++) {
+                               elems[ii].onclick = function() { 
Evo.mailDisplayToggleAddressVisibility(this); };
+                       }
+
+                       elems = doc.querySelectorAll("#__evo-moreaddr-button");
+                       for (ii = 0; ii < elems.length; ii++) {
+                               elems[ii].onclick = function() { 
Evo.mailDisplayToggleAddressVisibility(this); };
+                       }
+
+                       elems = doc.querySelectorAll(".org-gnome-vcard-display-mode-button");
+                       for (ii = 0; ii < elems.length; ii++) {
+                               elems[ii].onclick = function() { Evo.mailDisplayVCardModeButtonClicked(this); 
};
+                       }
+
+                       var elem;
+
+                       elem = doc.getElementById("__evo-contact-photo");
+
+                       if (elem && elem.hasAttribute("data-mailaddr")) {
+                               var mail_addr;
+
+                               mail_addr = elem.getAttribute("data-mailaddr");
+                               if (mail_addr != "") {
+                                       elem.src = "mail://contact-photo?mailaddr=" + mail_addr;
+                               }
+                       }
+               },
+               exec : function(doc, iframe_id, level) {
+                       if (doc) {
+                               this.unstyleBlockquotes(doc);
+                               this.wrapLongAchors(doc);
+                               this.bind(doc);
+
+                               Evo.vCardBindInDocument(doc);
+
+                               Evo.addRuleIntoStyleSheetDocument(doc,
+                                       "-e-mail-formatter-style-sheet",
+                                       "a.evo-awrap",
+                                       "white-space: normal; word-break: break-all;");
+                       }
+
+                       return true;
+               }
+       };
+
+       Evo.runTraversarForIFrameId(iframe_id, traversar);
+
+       Evo.mailDisplayResizeContentToPreviewWidth();
+       Evo.mailDisplayUpdateMagicSpacebarState();
+
+       document.defaultView.onresize = Evo.mailDisplayResized;
+       document.defaultView.onscroll = Evo.mailDisplayUpdateMagicSpacebarState;
+}
+
+Evo.MailDisplayShowAttachment = function(element_id, show)
+{
+       var elem;
+
+       elem = Evo.findElement("*", element_id);
+
+       if (!elem) {
+               return;
+       }
+
+       elem.hidden = !show;
+
+       if (elem.hasAttribute("inner-html-data")) {
+               var html_data = elem.getAttribute("inner-html-data");
+
+               elem.removeAttribute("inner-html-data");
+
+               if (html_data && html_data != "") {
+                       elem.innerHTML = html_data;
+
+                       var iframe;
+
+                       iframe = elem.querySelector("iframe");
+
+                       if (iframe) {
+                               Evo.initializeAndPostContentLoaded(iframe);
+                               Evo.MailDisplayBindDOM(iframe.id);
+                       }
+
+                       var iframe_id = "";
+
+                       if (elem.ownerDocument.defaultView.frameElement)
+                               iframe_id = elem.ownerDocument.defaultView.frameElement.id;
+
+                       window.webkit.messageHandlers.contentLoaded.postMessage(iframe_id);
+                       Evo.mailDisplayUpdateMagicSpacebarState();
+               }
+       }
+}
+
+Evo.MailDisplayProcessMagicSpacebar = function(towards_bottom)
+{
+       if (document && document.defaultView && document.defaultView.innerHeight) {
+               document.defaultView.scrollBy(0, (towards_bottom ? 1 : -1) * 
document.defaultView.innerHeight);
+       }
+
+       Evo.mailDisplayUpdateMagicSpacebarState();
 }



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