[evolution] EWebView: Use JavaScriptCore API of WebKitGTK+



commit 1d7e3e75cc1f02e9096125aad41f650a7c1fcb45
Author: Milan Crha <mcrha redhat com>
Date:   Wed Oct 9 12:26:12 2019 +0200

    EWebView: Use JavaScriptCore API of WebKitGTK+
    
    All the previews (in Mail, Contacts, Memos and Tasks) stop using
    deprecated WebKitGTK+ DOM API through a WebExtension (and its D-Bus
    API) and start using the JavaScriptCore API (and JavaScript as such).
    This allows to lightweight the WebExtension for the EWebView
    significantly, including drop of the D-Bus API of it, fully relying
    on the Inter-Process-Communication of WebKitGTK+ itself.

 CMakeLists.txt                                     |    3 +-
 data/CMakeLists.txt                                |    7 +-
 data/webkit/CMakeLists.txt                         |   10 +
 data/webkit/e-convert.js                           |   12 +
 data/webkit/e-web-view.js                          | 1437 ++++++++++++
 data/{ => webkit}/webview-print.css                |    0
 data/{ => webkit}/webview.css                      |    0
 src/addressbook/gui/widgets/eab-contact-display.c  |   30 +-
 .../gui/widgets/eab-contact-formatter.c            |    4 +-
 src/calendar/gui/CMakeLists.txt                    |    1 -
 src/calendar/gui/e-cal-component-preview.c         |    2 +-
 src/e-util/CMakeLists.txt                          |    8 +-
 src/e-util/e-file-request.c                        |   12 +-
 src/e-util/e-util-private.h                        |    4 +
 src/e-util/e-util.h                                |    3 +-
 src/e-util/e-web-view-jsc-utils.c                  |  711 ++++++
 src/e-util/e-web-view-jsc-utils.h                  |  181 ++
 src/e-util/e-web-view.c                            | 1376 ++++--------
 src/e-util/e-web-view.h                            |   84 +-
 src/e-util/e-win32-reloc.c                         |    7 +
 src/e-util/test-web-view-jsc.c                     | 1955 ++++++++++++++++
 src/em-format/CMakeLists.txt                       |    1 -
 src/em-format/e-mail-formatter-print.c             |    3 +-
 src/em-format/e-mail-formatter.c                   |    3 +-
 src/em-format/e-mail-part-headers.c                |   21 -
 src/em-format/e-mail-part-secure-button.c          |    8 +-
 src/em-format/e-mail-part.c                        |   28 +-
 src/em-format/e-mail-part.h                        |   12 +-
 src/mail/e-mail-display-popup-extension.c          |    8 +-
 src/mail/e-mail-display-popup-extension.h          |    6 +-
 src/mail/e-mail-display.c                          |  607 ++---
 src/mail/e-mail-display.h                          |    9 -
 src/mail/e-mail-reader-utils.c                     |  150 +-
 src/mail/e-mail-reader.c                           |    2 +-
 src/modules/CMakeLists.txt                         |   29 -
 src/modules/itip-formatter/e-mail-part-itip.c      |   29 +-
 src/modules/itip-formatter/itip-view.c             |  913 +++-----
 src/modules/itip-formatter/itip-view.h             |    4 +-
 .../e-mail-display-popup-prefer-plain.c            |   43 +-
 .../e-mail-display-popup-text-highlight.c          |   43 +-
 src/modules/vcard-inline/e-mail-formatter-vcard.c  |  107 +-
 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 +-
 .../webkit-editor/web-extension/CMakeLists.txt     |   26 +
 .../web-extension/e-composer-dom-functions.c       |    3 +-
 .../web-extension/e-dialogs-dom-functions.c        |    3 +-
 .../webkit-editor/web-extension/e-dom-utils.c      |  621 ++++++
 .../webkit-editor/web-extension/e-dom-utils.h      |   91 +
 .../web-extension/e-editor-dom-functions.c         |    3 +-
 .../webkit-editor/web-extension/e-editor-page.c    |    3 +-
 .../web-extension/e-editor-undo-redo-manager.c     |    3 +-
 .../web-extension/e-editor-web-extension.c         |    3 +-
 src/plugins/mail-to-task/mail-to-task.c            |   92 +-
 src/web-extensions/CMakeLists.txt                  |   55 +-
 src/web-extensions/e-dom-utils.c                   | 2349 --------------------
 src/web-extensions/e-dom-utils.h                   |  183 --
 src/web-extensions/e-itip-formatter-dom-utils.c    |  649 ------
 src/web-extensions/e-itip-formatter-dom-utils.h    |  111 -
 src/web-extensions/e-web-extension-main.c          |   49 +-
 src/web-extensions/e-web-extension-names.h         |   25 -
 src/web-extensions/e-web-extension.c               | 2144 +-----------------
 src/web-extensions/e-web-extension.h               |    6 -
 63 files changed, 6470 insertions(+), 8084 deletions(-)
---
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 2a325ef261..a14e730f2c 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -82,7 +82,7 @@ set(gsettings_desktop_schemas_minimum_version 2.91.92)
 set(libpst_minimum_version 0.6.54)
 set(libxml_minimum_version 2.7.3)
 set(shared_mime_info_minimum_version 0.22)
-set(webkit2gtk_minimum_version 2.16.0)
+set(webkit2gtk_minimum_version 2.24.0)
 
 # Optional Packages
 set(champlain_minimum_version 0.12)
@@ -178,6 +178,7 @@ set(plugindir "${privlibdir}/plugins")
 set(soundsdir "${privdatadir}/sounds")
 set(uidir "${privdatadir}/ui")
 set(viewsdir "${privdatadir}/views")
+set(webkitdatadir "${privdatadir}/webkit")
 set(webextensionsdir "${privlibdir}/web-extensions")
 set(webextensionswebkiteditordir "${webextensionsdir}/webkit-editor")
 
diff --git a/data/CMakeLists.txt b/data/CMakeLists.txt
index 5f5608a5d2..06e1e17006 100644
--- a/data/CMakeLists.txt
+++ b/data/CMakeLists.txt
@@ -1,6 +1,5 @@
 set(filedeps)
 set(desktopdir ${SHARE_INSTALL_PREFIX}/applications)
-set(themedir ${privdatadir}/theme)
 
 configure_file(org.gnome.Evolution.desktop.in.in
        org.gnome.Evolution.desktop.in
@@ -30,11 +29,6 @@ configure_file(org.gnome.Evolution.appdata.xml.in.in
 
 add_appdata_file(${CMAKE_CURRENT_BINARY_DIR}/org.gnome.Evolution.appdata.xml.in 
org.gnome.Evolution.appdata.xml)
 
-install(FILES webview.css
-               webview-print.css
-       DESTINATION ${themedir}
-)
-
 set(SCHEMAS
        org.gnome.evolution.gschema.xml
        org.gnome.evolution.addressbook.gschema.xml
@@ -83,3 +77,4 @@ add_subdirectory(images)
 add_subdirectory(sounds)
 add_subdirectory(ui)
 add_subdirectory(views)
+add_subdirectory(webkit)
diff --git a/data/webkit/CMakeLists.txt b/data/webkit/CMakeLists.txt
new file mode 100644
index 0000000000..37832ac9df
--- /dev/null
+++ b/data/webkit/CMakeLists.txt
@@ -0,0 +1,10 @@
+set(DATA_FILES
+       e-convert.js
+       e-web-view.js
+       webview.css
+       webview-print.css
+)
+
+install(FILES ${DATA_FILES}
+       DESTINATION ${webkitdatadir}
+)
diff --git a/data/webkit/e-convert.js b/data/webkit/e-convert.js
new file mode 100644
index 0000000000..4e67b92dc2
--- /dev/null
+++ b/data/webkit/e-convert.js
@@ -0,0 +1,12 @@
+'use strict';
+
+/* semi-convention: private functions start with lower-case letter,
+   public functions start with upper-case letter. */
+
+function EvoConvertToPlainText(element)
+{
+       if (!element)
+               return null;
+
+       return element.innerText;
+}
diff --git a/data/webkit/e-web-view.js b/data/webkit/e-web-view.js
new file mode 100644
index 0000000000..cd01ed870d
--- /dev/null
+++ b/data/webkit/e-web-view.js
@@ -0,0 +1,1437 @@
+'use strict';
+
+/* semi-convention: private functions start with lower-case letter,
+   public functions start with upper-case letter. */
+
+var Evo = {
+       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, level);
+   and it returns whether continue the traversar */
+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 : "", level))
+               return false;
+
+       var iframes, ii;
+
+       iframes = doc.getElementsByTagName("iframe");
+
+       for (ii = 0; ii < iframes.length; ii++) {
+               if (!traversar_obj.exec(iframes[ii].contentDocument, iframes[ii].id, level + 1))
+                       return false;
+
+               if (!Evo.foreachIFrameDocument(iframes[ii].contentDocument, traversar_obj, false, level + 1))
+                       return false;
+       }
+
+       return true;
+}
+
+Evo.findIFrame = function(iframe_id)
+{
+       if (iframe_id == "")
+               return null;
+
+       var traversar = {
+               iframe_id : iframe_id,
+               iframe : null,
+               exec : function(doc, iframe_id, level) {
+                       if (iframe_id == this.iframe_id) {
+                               this.iframe = doc.defaultView.frameElement;
+                               return false;
+                       }
+                       return true;
+               }
+       };
+
+       Evo.foreachIFrameDocument(document, traversar, true, 0);
+
+       return traversar.iframe;
+}
+
+Evo.findIFrameDocument = function(iframe_id)
+{
+       if (iframe_id == "")
+               return document;
+
+       var iframe = Evo.findIFrame(iframe_id);
+
+       if (iframe)
+               return iframe.contentDocument;
+
+       return null;
+}
+
+Evo.runTraversarForIFrameId = function(iframe_id, traversar_obj)
+{
+       if (iframe_id == "*") {
+               Evo.foreachIFrameDocument(document, traversar_obj, true, 0);
+       } else {
+               var doc = Evo.findIFrameDocument(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);
+               }
+       }
+}
+
+Evo.findElementInDocumentById = function(doc, element_id)
+{
+       if (!doc)
+               return null;
+
+       if (element_id == "*html")
+               return doc.documentElement;
+
+       if (element_id == "*head")
+               return doc.head;
+
+       if (element_id == "*body")
+               return doc.body;
+
+       return doc.getElementById(element_id);
+}
+
+Evo.findElement = function(iframe_id, element_id)
+{
+       var traversar = {
+               element_id : element_id,
+               res : null,
+               exec : function(doc, iframe_id, level) {
+                       this.res = Evo.findElementInDocumentById(doc, this.element_id);
+                       if (this.res)
+                               return false;
+                       return true;
+               }
+       };
+
+       Evo.runTraversarForIFrameId(iframe_id, traversar);
+
+       return traversar.res;
+}
+
+Evo.SetElementHidden = function(iframe_id, element_id, value)
+{
+       var elem = Evo.findElement(iframe_id, element_id);
+
+       if (elem)
+               elem.hidden = value;
+}
+
+Evo.SetElementDisabled = function(iframe_id, element_id, value)
+{
+       var elem = Evo.findElement(iframe_id, element_id);
+
+       if (elem)
+               elem.disabled = value;
+}
+
+Evo.SetElementChecked = function(iframe_id, element_id, value)
+{
+       var elem = Evo.findElement(iframe_id, element_id);
+
+       if (elem)
+               elem.checked = value;
+}
+
+Evo.SetElementStyleProperty = function(iframe_id, element_id, property_name, value)
+{
+       var elem = Evo.findElement(iframe_id, element_id);
+
+       if (elem) {
+               if (value != null && value != "")
+                       elem.style.setProperty(property_name, value);
+               else
+                       elem.style.removeProperty(property_name);
+       }
+}
+
+Evo.SetElementAttribute = function(iframe_id, element_id, namespace_uri, qualified_name, value)
+{
+       var elem = Evo.findElement(iframe_id, element_id);
+
+       if (elem) {
+               if (value != null && value != "")
+                       elem.setAttributeNS(namespace_uri, qualified_name, value);
+               else
+                       elem.removeAttributeNS(namespace_uri, qualified_name);
+       }
+}
+
+Evo.createStyleSheet = function(doc, style_sheet_id, content)
+{
+       var node;
+
+       node = doc.createElement("style");
+       node.id = style_sheet_id;
+       node.media = "screen";
+       node.innerText = content;
+
+       doc.head.append(node);
+
+       return node;
+}
+
+Evo.CreateStyleSheet = function(iframe_id, style_sheet_id, content)
+{
+       var doc = Evo.findIFrameDocument(iframe_id);
+
+       if (!doc)
+               return;
+
+       var styles = doc.head.getElementsByTagName("style"), ii;
+
+       for (ii = 0; ii < styles.length; ii++) {
+               if (styles[ii].id == style_sheet_id) {
+                       styles[ii].innerText = content;
+                       return;
+               }
+       }
+
+       Evo.createStyleSheet(doc, style_sheet_id, content);
+}
+
+Evo.RemoveStyleSheet = function(iframe_id, style_sheet_id)
+{
+       var traversar = {
+               style_sheet_id : style_sheet_id,
+               exec : function(doc, iframe_id, level) {
+                       if (doc && doc.head) {
+                               var ii, styles = doc.head.getElementsByTagName("style");
+
+                               for (ii = styles.length - 1; ii >= 0; ii--) {
+                                       if (this.style_sheet_id == "*" || styles[ii].id == 
this.style_sheet_id) {
+                                               doc.head.removeChild(styles[ii]);
+                                       }
+                               }
+                       }
+
+                       return true;
+               }
+       };
+
+       Evo.runTraversarForIFrameId(iframe_id, traversar);
+}
+
+Evo.addRuleIntoStyleSheetDocument = function(doc, style_sheet_id, selector, style)
+{
+       var styles = doc.head.getElementsByTagName("style"), ii, styleobj = null;
+
+       for (ii = 0; ii < styles.length; ii++) {
+               if (styles[ii].id == style_sheet_id) {
+                       styleobj = styles[ii];
+                       break;
+               }
+       }
+
+       if (!styleobj) {
+               Evo.createStyleSheet(doc, style_sheet_id, selector + " { " + style + " }");
+               return;
+       }
+
+       for (ii = 0; ii < styleobj.sheet.cssRules.length; ii++) {
+               if (styleobj.sheet.cssRules[ii].selectorText == selector) {
+                       styleobj.sheet.cssRules[ii].style.cssText = style;
+                       return;
+               }
+       }
+
+       styleobj.sheet.addRule(selector, style);
+}
+
+Evo.AddRuleIntoStyleSheet = function(iframe_id, style_sheet_id, selector, style)
+{
+       var traversar = {
+               style_sheet_id : style_sheet_id,
+               selector : selector,
+               style : style,
+               exec : function(doc, iframe_id, level) {
+                       if (doc && doc.head) {
+                               Evo.addRuleIntoStyleSheetDocument(doc, this.style_sheet_id, this.selector, 
this.style);
+                       }
+
+                       return true;
+               }
+       };
+
+       Evo.runTraversarForIFrameId(iframe_id, traversar);
+}
+
+Evo.SetDocumentContent = function(content)
+{
+       document.documentElement.innerHTML = content;
+
+       Evo.initialize(null);
+       window.webkit.messageHandlers.contentLoaded.postMessage("");
+}
+
+Evo.SetIFrameSrc = function(iframe_id, src_uri)
+{
+       var iframe = Evo.findIFrame(iframe_id);
+
+       if (iframe)
+               iframe.src = src_uri;
+}
+
+Evo.SetIFrameContent = function(iframe_id, content)
+{
+       var iframe = Evo.findIFrame(iframe_id);
+
+       if (iframe) {
+               iframe.contentDocument.documentElement.innerHTML = content;
+
+               Evo.initialize(iframe);
+               window.webkit.messageHandlers.contentLoaded.postMessage(iframe_id);
+       }
+}
+
+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 = "";
+
+       if (elem.ownerDocument.defaultView.frameElement)
+               parent_iframe_id = elem.ownerDocument.defaultView.frameElement.id;
+
+       with_parents_left = elem.offsetLeft;
+       with_parents_top = elem.offsetTop;
+
+       offset_parent = elem;
+       while (offset_parent = offset_parent.offsetParent, offset_parent) {
+               with_parents_left += offset_parent.offsetLeft;
+               with_parents_top += offset_parent.offsetTop;
+       }
+
+       dom_window = elem.ownerDocument.defaultView;
+       while (dom_window instanceof Window) {
+               var parent_dom_window, iframe_elem;
+
+               parent_dom_window = dom_window.parent;
+               iframe_elem = dom_window.frameElement;
+
+               while (iframe_elem) {
+                       with_parents_left += iframe_elem.offsetLeft;
+                       with_parents_top += iframe_elem.offsetTop;
+
+                       iframe_elem = iframe_elem.offsetParent;
+               }
+
+               scroll_x += dom_window.scrollX;
+               scroll_y += dom_window.scrollY;
+
+               if (parent_dom_window == dom_window)
+                       break;
+
+               dom_window = parent_dom_window;
+       }
+
+       var res = [];
+
+       res["iframe-id"] = parent_iframe_id;
+       res["elem-id"] = elem.id;
+       res["elem-class"] = elem.className;
+       res["elem-value"] = elem.getAttribute("value");
+       res["left"] = with_parents_left - scroll_x;
+       res["top"] = with_parents_top - scroll_y;
+       res["width"] = elem.offsetWidth;
+       res["height"] = elem.offsetHeight;
+
+       window.webkit.messageHandlers.elementClicked.postMessage(res);
+}
+
+Evo.RegisterElementClicked = function(iframe_id, elem_classes_str)
+{
+       var traversar = {
+               elem_classes : elem_classes_str.split("\n"),
+               exec : function(doc, iframe_id, level) {
+                       if (doc && this.elem_classes) {
+                               var ii;
+
+                               for (ii = 0; ii < this.elem_classes.length; ii++) {
+                                       if (this.elem_classes[ii] != "") {
+                                               var jj, elems;
+
+                                               elems = doc.getElementsByClassName(this.elem_classes[ii]);
+
+                                               for (jj = 0; jj < elems.length; jj++) {
+                                                       elems[jj].onclick = function() { 
Evo.elementClicked(this); };
+                                               }
+                                       }
+                               }
+                       }
+
+                       return true;
+               }
+       };
+
+       Evo.runTraversarForIFrameId(iframe_id, traversar);
+}
+
+Evo.checkAnyParentIsPre = function(node)
+{
+       if (!node)
+               return false;
+
+       while (node = node.parentElement, node) {
+               if (/* node instanceof HTMLPreElement */ node.tagName.toUpperCase() == "PRE")
+                       return true;
+               if (/* node instanceof HTMLIFrameElement */ node.tagName.toUpperCase() == "IFRAME")
+                       break;
+       }
+
+       return false;
+}
+
+Evo.getElementContent = function(node, format, useOuterHTML)
+{
+       if (!node)
+               return null;
+
+       var data;
+
+       if (format == 1) {
+               data = EvoConvertToPlainText(node);
+       } else if (format == 2) {
+               data = useOuterHTML ? node.outerHTML : node.innerHTML;
+       } else if (format == 3) {
+               data = {};
+               data["plain"] = EvoConvertToPlainText(node);
+               data["html"] = useOuterHTML ? node.outerHTML : node.innerHTML;
+       }
+
+       return data;
+}
+
+Evo.checkHasSelection = function(content)
+{
+       var traversar = {
+               content : content,
+               has : false,
+               exec : function(doc, iframe_id, level) {
+                       if (doc && !doc.defaultView.getSelection().isCollapsed) {
+                               if (content) {
+                                       var fragment, node, inpre;
+
+                                       fragment = 
doc.defaultView.getSelection().getRangeAt(0).cloneContents();
+                                       inpre = 
Evo.checkAnyParentIsPre(doc.defaultView.getSelection().getRangeAt(0).startContainer);
+                                       node = doc.createElement(inpre ? "PRE" : "DIV");
+                                       node.appendChild(fragment);
+
+                                       content.data = Evo.getElementContent(node, content.format, inpre);
+                               }
+
+                               this.has = true;
+
+                               return false;
+                       }
+
+                       return true;
+               }
+       };
+
+       Evo.foreachIFrameDocument(document, traversar, true, 0);
+
+       return traversar.has;
+}
+
+Evo.selectionChanged = function()
+{
+
+       var has;
+
+       has = Evo.checkHasSelection(null);
+
+       if (has != Evo.hasSelection) {
+               Evo.hasSelection = has;
+               window.webkit.messageHandlers.hasSelection.postMessage(has);
+       }
+}
+
+Evo.GetSelection = function(format)
+{
+       var content = { format: 0, data: null };
+
+       content.format = format;
+
+       if (!Evo.checkHasSelection(content))
+               return null;
+
+       return content.data;
+}
+
+Evo.GetDocumentContent = function(iframe_id, format)
+{
+       var doc;
+
+       if (iframe_id == "") {
+               doc = document;
+       } else {
+               var iframe = Evo.findIFrame(iframe_id);
+
+               if (!iframe)
+                       return null;
+
+               doc = iframe.contentDocument;
+       }
+
+       return Evo.getElementContent(doc.documentElement, format, true);
+}
+
+Evo.GetElementContent = function(iframe_id, element_id, format, use_outer_html)
+{
+       var elem = Evo.findElement(iframe_id, element_id);
+
+       if (!elem)
+               return null;
+
+       return Evo.getElementContent(elem, format, use_outer_html);
+}
+
+Evo.findElementFromPoint = function(doc, xx, yy, parent_elem)
+{
+       var elem;
+
+       if (!parent_elem) {
+               elem = doc.elementFromPoint(xx, yy);
+       } else {
+               var left_offset = 0, top_offset = 0, offset_parent, use_parent;
+
+               for (use_parent = parent_elem; use_parent; use_parent = 
use_parent.ownerDocument.defaultView.frameElement) {
+                       offset_parent = use_parent;
+                       do {
+                               left_offset += offset_parent.offsetLeft - offset_parent.scrollLeft;
+                               top_offset += offset_parent.offsetTop - offset_parent.scrollTop;
+
+                               offset_parent = offset_parent.offsetParent;
+                       /* Stop on body, because it sometimes have the same offset/scroll values as its 
iframe parent and sometimes not. */
+                       } while (offset_parent && !(/* offset_parent instanceof HTMLBodyElement */ 
offset_parent.tagName.toUpperCase() == "BODY"));
+               }
+
+               elem = doc.elementFromPoint(xx - left_offset + window.scrollX, yy - top_offset + 
window.scrollY);
+       }
+
+       if (!elem) {
+               return parent_elem;
+       }
+
+       if (/* !(elem instanceof HTMLIFrameElement) */ elem.tagName.toUpperCase() != "IFRAME") {
+               return elem;
+       }
+
+       if (parent_elem && parent_elem.isEqualNode(elem)) {
+               return parent_elem;
+       }
+
+       var iframedoc = elem.contentDocument;
+
+       if (!iframedoc) {
+               return parent_elem;
+       }
+
+       return Evo.findElementFromPoint(iframedoc, xx, yy, elem);
+}
+
+Evo.GetElementFromPoint = function(xx, yy)
+{
+       var elem;
+
+       if (xx == -1 && yy == -1)
+               elem = document.activeElement;
+       else
+               elem = Evo.findElementFromPoint(document, xx, yy, null);
+
+       if (!elem)
+               return null;
+
+       var res = [], iframe;
+
+       iframe = elem.ownerDocument.defaultView.frameElement;
+
+       res["iframe-src"] = iframe ? iframe.src : document.documentURI;
+       res["iframe-id"] = iframe ? iframe.id : "";
+       res["elem-id"] = elem.id;
+
+       return res;
+}
+
+Evo.initialize = function(elem)
+{
+       var doc, elems, ii;
+
+       if (elem && /*elem instanceof HTMLIFrameElement*/ elem.tagName.toUpperCase() == "IFRAME" && 
elem.contentDocument) {
+               elem.onload = function() { Evo.initializeAndPostContentLoaded(this); };
+               doc = elem.contentDocument;
+       } else
+               doc = document;
+
+       elems = doc.getElementsByTagName("iframe");
+
+       for (ii = 0; ii < elems.length; ii++) {
+               elems[ii].onload = function() { Evo.initializeAndPostContentLoaded(this); };
+
+               if (elems[ii].contentDocument.body && elems[ii].contentDocument.body.childElementCount > 0)
+                       Evo.initializeAndPostContentLoaded(elems[ii]);
+       }
+
+       if (!doc.body.hasAttribute("class"))
+               doc.body.className = "-e-web-view-background-color -e-web-view-text-color";
+
+       if (doc.documentElement.style.getPropertyValue("color") == "" ||
+           doc.documentElement.style.getPropertyValue("color") == "text") {
+               doc.documentElement.style.setProperty("color", "inherit");
+               doc.documentElement.style.setProperty("background-color", "inherit");
+       }
+
+       elems = doc.querySelectorAll("input, textarea, select, button, label");
+
+       for (ii = 0; ii < elems.length; ii++) {
+               elems[ii].onfocus = function() { 
window.webkit.messageHandlers.needInputChanged.postMessage(true); };
+               elems[ii].onblur = function() { 
window.webkit.messageHandlers.needInputChanged.postMessage(false); };
+       }
+
+       elems = doc.querySelectorAll("img[src^=\"file://\"]");
+
+       for (ii = 0; ii < elems.length; ii++) {
+               elems[ii].src = "evo-" + elems[ii].src;
+       }
+
+       if (doc.body && doc.querySelector("[data-evo-signature-plain-text-mode]")) {
+               doc.body.setAttribute("style", "font-family: Monospace;");
+       }
+
+       doc.onselectionchange = Evo.selectionChanged;
+}
+
+Evo.initializeAndPostContentLoaded = function(elem)
+{
+       var iframe_id = "";
+
+       if (elem && /*elem instanceof HTMLIFrameElement*/ elem.tagName.toUpperCase() == "IFRAME")
+               iframe_id = elem.id;
+       if (elem && elem.ownerDocument && elem.ownerDocument.defaultView.frameElement)
+               iframe_id = elem.ownerDocument.defaultView.frameElement.id;
+       else if (window.frameElement)
+               iframe_id = window.frameElement.id;
+
+       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); };
+
+       if (this.document.body && this.document.body.firstChild)
+               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();
+}
+
+var EvoItip = {
+       SELECT_ESOURCE : "select_esource",
+       TEXTAREA_RSVP_COMMENT : "textarea_rsvp_comment",
+       CHECKBOX_RSVP : "checkbox_rsvp",
+       CHECKBOX_RECUR : "checkbox_recur",
+       CHECKBOX_KEEP_ALARM : "checkbox_keep_alarm",
+       CHECKBOX_INHERIT_ALARM : "checkbox_inherit_alarm",
+       CHECKBOX_UPDATE : "checkbox_update",
+       CHECKBOX_FREE_TIME : "checkbox_free_time",
+       TABLE_ROW_BUTTONS : "table_row_buttons"
+};
+
+EvoItip.alarmCheckClickedCb = function(check1)
+{
+       var check2;
+
+       if (check1.id == EvoItip.CHECKBOX_KEEP_ALARM) {
+               check2 = check1.ownerDocument.getElementById(EvoItip.CHECKBOX_INHERIT_ALARM);
+       } else {
+               check2 = check1.ownerDocument.getElementById(EvoItip.CHECKBOX_KEEP_ALARM);
+       }
+
+       if (check2) {
+               check2.disabled = check1.hidden && check1.checked;
+       }
+}
+
+EvoItip.selectedSourceChanged = function(elem)
+{
+       var data = {};
+
+       data["iframe-id"] = elem.ownerDocument.defaultView.frameElement.id;
+       data["source-uid"] = elem.value;
+
+       window.webkit.messageHandlers.itipSourceChanged.postMessage(data);
+}
+
+EvoItip.Initialize = function(iframe_id)
+{
+       var doc = Evo.findIFrameDocument(iframe_id);
+
+       if (!doc) {
+               return;
+       }
+
+       var elem;
+
+       elem = doc.getElementById(EvoItip.SELECT_ESOURCE);
+       if (elem) {
+               elem.onchange = function() { EvoItip.selectedSourceChanged(this); };
+       }
+
+       elem = doc.getElementById(EvoItip.CHECKBOX_RECUR);
+       if (elem) {
+               elem.onclick = function() { 
window.webkit.messageHandlers.itipRecurToggled.postMessage(this.ownerDocument.defaultView.frameElement.id); };
+       }
+
+       elem = doc.getElementById(EvoItip.CHECKBOX_RSVP);
+       if (elem) {
+               elem.onclick = function() {
+                               var elem = this.ownerDocument.getElementById(EvoItip.TEXTAREA_RSVP_COMMENT);
+                               if (elem) {
+                                       elem.disabled = !this.checked;
+                               }
+                       };
+       }
+
+       elem = doc.getElementById(EvoItip.CHECKBOX_INHERIT_ALARM);
+       if (elem) {
+               elem.onclick = function() { EvoItip.alarmCheckClickedCb(this); };
+       }
+
+       elem = doc.getElementById(EvoItip.CHECKBOX_KEEP_ALARM);
+       if (elem) {
+               elem.onclick = function() { EvoItip.alarmCheckClickedCb(this); };
+       }
+}
+
+EvoItip.SetElementInnerHTML = function(iframe_id, element_id, html_content)
+{
+       var elem = Evo.findElement(iframe_id, element_id);
+
+       if (elem)
+               elem.innerHTML = html_content;
+}
+
+EvoItip.SetShowCheckbox = function(iframe_id, element_id, show, update_second)
+{
+       var elem = Evo.findElement(iframe_id, element_id);
+
+       if (elem) {
+               elem.hidden = !show;
+
+               if (elem.nextElementSibling) {
+                       elem.nextElementSibling.hidden = !show;
+               }
+
+               if (!show) {
+                       elem.checked = false;
+               }
+
+               if (update_second) {
+                       EvoItip.alarmCheckClickedCb(elem);
+               }
+
+               elem = elem.ownerDocument.getElementById("table_row_" + element_id);
+               if (elem) {
+                       elem.hidden = !show;
+               }
+       }
+}
+
+EvoItip.SetAreaText = function(iframe_id, element_id, text)
+{
+       var row = Evo.findElement(iframe_id, element_id);
+
+       if (row) {
+               row.hidden = text == "";
+
+               if (row.lastElementChild) {
+                       row.lastElementChild.innerHTML = text;
+               }
+       }
+}
+
+EvoItip.UpdateTimes = function(iframe_id, element_id, header, label)
+{
+       var elem = Evo.findElement(iframe_id, element_id);
+
+       if (elem) {
+               elem.hidden = false;
+
+               if (elem.firstElementChild) {
+                       elem.firstElementChild.innerHTML = header;
+               }
+
+               if (elem.lastElementChild) {
+                       elem.lastElementChild.innerHTML = label;
+               }
+       }
+}
+
+EvoItip.AppendInfoRow = function(iframe_id, table_id, row_id, icon_name, message)
+{
+       var cell, row, table = Evo.findElement(iframe_id, table_id);
+
+       if (!table) {
+               return;
+       }
+
+       row = table.insertRow(-1);
+       row.id = row_id;
+
+       cell = row.insertCell(-1);
+
+       if (icon_name && icon_name != "") {
+               var img;
+
+               img = table.ownerDocument.createElement("img");
+               img.src = "gtk-stock://" + icon_name;
+
+               cell.appendChild(img);
+       }
+
+       cell = row.insertCell(-1);
+       cell.innerHTML = message;
+}
+
+EvoItip.RemoveInfoRow = function(iframe_id, row_id)
+{
+       var row = Evo.findElement(iframe_id, row_id);
+
+       if (row && row.parentNode) {
+               row.parentNode.removeChild(row);
+       }
+}
+
+EvoItip.RemoveChildNodes = function(iframe_id, element_id)
+{
+       var elem = Evo.findElement(iframe_id, element_id);
+
+       if (elem) {
+               while (elem.lastChild) {
+                       elem.removeChild(elem.lastChild);
+               }
+       }
+}
+
+EvoItip.AddToSourceList = function(iframe_id, optgroup_id, optgroup_label, option_id, option_label, writable)
+{
+       var doc, select_elem;
+
+       doc = Evo.findIFrameDocument(iframe_id);
+       select_elem = doc ? doc.getElementById(EvoItip.SELECT_ESOURCE) : null;
+
+       if (!select_elem) {
+               return;
+       }
+
+       var option, optgroup;
+
+       optgroup = doc.getElementById (optgroup_id);
+
+       if (!optgroup) {
+               optgroup = doc.createElement("optgroup");
+               optgroup.id = optgroup_id;
+               optgroup.label = optgroup_label;
+
+               select_elem.appendChild(optgroup);
+       }
+
+       option = doc.createElement("option");
+       option.value = option_id;
+       option.label = option_label;
+       option.innerHTML = option_label;
+       option.className = "calendar";
+
+       if (!writable) {
+               option.disabled = true;
+       }
+
+       optgroup.appendChild(option);
+}
+
+EvoItip.HideButtons = function(iframe_id, element_id)
+{
+       var elem = Evo.findElement(iframe_id, element_id);
+
+       if (elem) {
+               var child;
+
+               for (child = elem.firstElementChild; child; child = child.nextElementSibling) {
+                       var button = child.firstElementChild;
+
+                       if (button)
+                               button.hidden = true;
+               }
+       }
+}
+
+EvoItip.SetElementAccessKey = function(iframe_id, element_id, access_key)
+{
+       var elem = Evo.findElement(iframe_id, element_id);
+
+       if (elem) {
+               elem.accessKey = access_key;
+       }
+}
+
+EvoItip.SetSelectSelected = function(iframe_id, element_id, option_value)
+{
+       var elem = Evo.findElement(iframe_id, element_id);
+
+       if (elem) {
+               var ii;
+
+               for (ii = 0; ii < elem.length; ii++) {
+                       if (elem.item(ii).value == option_value) {
+                               elem.item(ii).selected = true;
+                               break;
+                       }
+               }
+       }
+}
+
+EvoItip.SetButtonsDisabled = function(iframe_id, disabled)
+{
+       var doc = Evo.findIFrameDocument(iframe_id);
+
+       if (!doc) {
+               return;
+       }
+
+       var elem, cell;
+
+       elem = doc.getElementById(EvoItip.CHECKBOX_UPDATE);
+       if (elem)
+               elem.disabled = disabled;
+
+       elem = doc.getElementById(EvoItip.CHECKBOX_RECUR);
+       if (elem)
+               elem.disabled = disabled;
+
+       elem = doc.getElementById(EvoItip.CHECKBOX_FREE_TIME);
+       if (elem)
+               elem.disabled = disabled;
+
+       elem = doc.getElementById(EvoItip.CHECKBOX_KEEP_ALARM);
+       if (elem)
+               elem.disabled = disabled;
+
+       elem = doc.getElementById(EvoItip.CHECKBOX_INHERIT_ALARM);
+       if (elem)
+               elem.disabled = disabled;
+
+       elem = doc.getElementById(EvoItip.CHECKBOX_RSVP);
+       if (elem)
+               elem.disabled = disabled;
+
+       elem = doc.getElementById(EvoItip.TEXTAREA_RSVP_COMMENT);
+       if (elem)
+               elem.disabled = disabled;
+
+       elem = doc.getElementById(EvoItip.TABLE_ROW_BUTTONS);
+       if (!elem)
+               return;
+
+       for (cell = elem.firstElementChild; cell; cell = cell.nextElementSibling) {
+               var btn = cell.firstElementChild;
+
+               if (btn && !btn.hidden) {
+                       btn.disabled = disabled;
+               }
+       }
+}
+
+EvoItip.GetState = function(iframe_id)
+{
+       var doc;
+
+       doc = Evo.findIFrameDocument(iframe_id);
+
+       if (!doc) {
+               return null;
+       }
+
+       var elem, res = {};
+
+       elem = doc.getElementById(EvoItip.TEXTAREA_RSVP_COMMENT);
+       res["rsvp-comment"] = elem ? elem.value : null;
+
+       elem = doc.getElementById(EvoItip.CHECKBOX_RSVP);
+       res["rsvp-check"] = elem && elem.checked && !elem.hidden && !elem.disabled;
+
+       elem = doc.getElementById(EvoItip.CHECKBOX_UPDATE);
+       res["update-check"] = elem && elem.checked && !elem.hidden && !elem.disabled;
+
+       elem = doc.getElementById(EvoItip.CHECKBOX_RECUR);
+       res["recur-check"] = elem && elem.checked && !elem.hidden && !elem.disabled;
+
+       elem = doc.getElementById(EvoItip.CHECKBOX_FREE_TIME);
+       res["free-time-check"] = elem && elem.checked && !elem.hidden && !elem.disabled;
+
+       elem = doc.getElementById(EvoItip.CHECKBOX_KEEP_ALARM);
+       res["keep-alarm-check"] = elem && elem.checked && !elem.hidden && !elem.disabled;
+
+       elem = doc.getElementById(EvoItip.CHECKBOX_INHERIT_ALARM);
+       res["inherit-alarm-check"] = elem && elem.checked && !elem.hidden && !elem.disabled;
+
+       return res;
+}
diff --git a/data/webview-print.css b/data/webkit/webview-print.css
similarity index 100%
rename from data/webview-print.css
rename to data/webkit/webview-print.css
diff --git a/data/webview.css b/data/webkit/webview.css
similarity index 100%
rename from data/webview.css
rename to data/webkit/webview.css
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..197068a306 100644
--- a/src/addressbook/gui/widgets/eab-contact-formatter.c
+++ b/src/addressbook/gui/widgets/eab-contact-formatter.c
@@ -51,7 +51,7 @@
 
 #define HTML_HEADER "<!doctype html public \"-//W3C//DTD HTML 4.0 TRANSITIONAL//EN\">\n<html>\n" \
 "<head>\n<meta name=\"generator\" content=\"Evolution Addressbook Component\">\n" \
-"<link type=\"text/css\" rel=\"stylesheet\" href=\"evo-file://" EVOLUTION_PRIVDATADIR 
"/theme/webview.css\">" \
+"<link type=\"text/css\" rel=\"stylesheet\" href=\"evo-file://$EVOLUTION_WEBKITDATADIR/webview.css\">" \
 "<style type=\"text/css\">\n" \
 "  div#header { width:100%; clear: both; }\n" \
 "  div#columns { width: 100%; clear: both; }\n" \
@@ -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/calendar/gui/CMakeLists.txt b/src/calendar/gui/CMakeLists.txt
index dcf5fe171d..405773499f 100644
--- a/src/calendar/gui/CMakeLists.txt
+++ b/src/calendar/gui/CMakeLists.txt
@@ -185,7 +185,6 @@ add_dependencies(evolution-calendar
 target_compile_definitions(evolution-calendar PRIVATE
        -DG_LOG_DOMAIN=\"evolution-calendar\"
        -DEVOLUTION_ETSPECDIR=\"${etspecdir}\"
-       -DEVOLUTION_PRIVDATADIR=\"${privdatadir}\"
 )
 
 target_compile_options(evolution-calendar PUBLIC
diff --git a/src/calendar/gui/e-cal-component-preview.c b/src/calendar/gui/e-cal-component-preview.c
index e667131732..3f8a1a6aec 100644
--- a/src/calendar/gui/e-cal-component-preview.c
+++ b/src/calendar/gui/e-cal-component-preview.c
@@ -61,7 +61,7 @@ struct _ECalComponentPreviewPrivate {
 
 #define HTML_HEADER "<!doctype html public \"-//W3C//DTD HTML 4.0 TRANSITIONAL//EN\">\n<html>\n" \
                     "<head>\n<meta name=\"generator\" content=\"Evolution Calendar Component\">\n" \
-                   "<link type=\"text/css\" rel=\"stylesheet\" href=\"evo-file://" EVOLUTION_PRIVDATADIR 
"/theme/webview.css\">\n" \
+                   "<link type=\"text/css\" rel=\"stylesheet\" 
href=\"evo-file://$EVOLUTION_WEBKITDATADIR/webview.css\">\n" \
                    "<style>\n" \
                    ".description { font-family: monospace; font-size: 1em; }\n" \
                    "</style>\n" \
diff --git a/src/e-util/CMakeLists.txt b/src/e-util/CMakeLists.txt
index 81ae3cd72c..eb9523d37a 100644
--- a/src/e-util/CMakeLists.txt
+++ b/src/e-util/CMakeLists.txt
@@ -270,8 +270,9 @@ set(SOURCES
        e-util-private.h
        e-webdav-browser.c
        e-web-extension-container.c
-       e-web-view-preview.c
        e-web-view.c
+       e-web-view-jsc-utils.c
+       e-web-view-preview.c
        e-widget-undo.c
        e-xml-utils.c
        ea-calendar-cell.c
@@ -543,8 +544,9 @@ set(HEADERS
        e-util-enums.h
        e-webdav-browser.h
        e-web-extension-container.h
-       e-web-view-preview.h
        e-web-view.h
+       e-web-view-jsc-utils.h
+       e-web-view-preview.h
        e-widget-undo.h
        e-xml-utils.h
        ea-calendar-cell.h
@@ -613,6 +615,7 @@ target_compile_definitions(evolution-util PRIVATE
        -DEVOLUTION_UIDIR=\"${uidir}\"
        -DEVOLUTION_RULEDIR=\"${privdatadir}\"
        -DEVOLUTION_WEB_EXTENSIONS_DIR=\"${webextensionsdir}\"
+       -DEVOLUTION_WEBKITDATADIR=\"${webkitdatadir}\"
        -DEVOLUTION_TESTGIOMODULESDIR=\"${CMAKE_CURRENT_BINARY_DIR}\"
        -DEVOLUTION_TESTTOPSRCDIR=\"${CMAKE_SOURCE_DIR}\"
        -DLIBEUTIL_COMPILATION
@@ -808,6 +811,7 @@ add_private_programs_simple(
        test-source-config
        test-source-selector
        test-tree-view-frame
+       test-web-view-jsc
 )
 
 add_private_program(test-html-editor-units
diff --git a/src/e-util/e-file-request.c b/src/e-util/e-file-request.c
index f58c8093be..090f8cf100 100644
--- a/src/e-util/e-file-request.c
+++ b/src/e-util/e-file-request.c
@@ -59,6 +59,7 @@ e_file_request_process_sync (EContentRequest *request,
        GFileInputStream *file_input_stream;
        GFileInfo *info;
        goffset total_size;
+       gchar *filename = NULL;
        SoupURI *suri;
 
        g_return_val_if_fail (E_IS_FILE_REQUEST (request), FALSE);
@@ -70,7 +71,13 @@ e_file_request_process_sync (EContentRequest *request,
        suri = soup_uri_new (uri);
        g_return_val_if_fail (suri != NULL, FALSE);
 
-       file = g_file_new_for_path (suri->path);
+       if (g_strcmp0 (suri->host, "$EVOLUTION_WEBKITDATADIR") == 0) {
+               filename = g_build_filename (EVOLUTION_WEBKITDATADIR, suri->path, NULL);
+       } else if (g_strcmp0 (suri->host, "$EVOLUTION_IMAGESDIR") == 0) {
+               filename = g_build_filename (EVOLUTION_IMAGESDIR, suri->path, NULL);
+       }
+
+       file = g_file_new_for_path (filename ? filename : suri->path);
        file_input_stream = g_file_read (file, cancellable, error);
 
        if (file_input_stream) {
@@ -97,7 +104,7 @@ e_file_request_process_sync (EContentRequest *request,
        if (file_input_stream) {
                *out_stream = G_INPUT_STREAM (file_input_stream);
                *out_stream_length = (gint64) total_size;
-               *out_mime_type = g_content_type_guess (suri->path, NULL, 0, NULL);
+               *out_mime_type = g_content_type_guess (filename ? filename : suri->path, NULL, 0, NULL);
        } else {
                *out_stream = NULL;
                *out_stream_length = (gint64) total_size;
@@ -106,6 +113,7 @@ e_file_request_process_sync (EContentRequest *request,
 
        g_object_unref (file);
        soup_uri_free (suri);
+       g_free (filename);
 
        return file_input_stream != NULL;
 }
diff --git a/src/e-util/e-util-private.h b/src/e-util/e-util-private.h
index 030f2b6cbf..f3ce879f86 100644
--- a/src/e-util/e-util-private.h
+++ b/src/e-util/e-util-private.h
@@ -56,6 +56,7 @@ const gchar *_e_get_sounddir (void) G_GNUC_CONST;
 const gchar *_e_get_sysconfdir (void) G_GNUC_CONST;
 const gchar *_e_get_toolsdir (void) G_GNUC_CONST;
 const gchar *_e_get_uidir (void) G_GNUC_CONST;
+const gchar *_e_get_webkitdatadir (void) G_GNUC_CONST;
 
 #undef DATADIR
 #define DATADIR _e_get_datadir ()
@@ -123,6 +124,9 @@ const gchar *_e_get_uidir (void) G_GNUC_CONST;
 #undef EVOLUTION_RULEDIR
 #define EVOLUTION_RULEDIR _e_get_ruledir ()
 
+#undef EVOLUTION_WEBKITDATADIR
+#define EVOLUTION_WEBKITDATADIR _e_get_webkitdatadir ()
+
 #endif /* G_OS_WIN32 */
 
 #endif /* _E_UTIL_PRIVATE_H_ */
diff --git a/src/e-util/e-util.h b/src/e-util/e-util.h
index 84db520bed..fa0d82b540 100644
--- a/src/e-util/e-util.h
+++ b/src/e-util/e-util.h
@@ -266,8 +266,9 @@
 #include <e-util/e-webdav-browser.h>
 #include <e-util/e-web-extension-container.h>
 #ifndef E_UTIL_INCLUDE_WITHOUT_WEBKIT
-#include <e-util/e-web-view-preview.h>
 #include <e-util/e-web-view.h>
+#include <e-util/e-web-view-jsc-utils.h>
+#include <e-util/e-web-view-preview.h>
 #endif
 #include <e-util/e-widget-undo.h>
 #include <e-util/e-xml-utils.h>
diff --git a/src/e-util/e-web-view-jsc-utils.c b/src/e-util/e-web-view-jsc-utils.c
new file mode 100644
index 0000000000..ccdd8c84ff
--- /dev/null
+++ b/src/e-util/e-web-view-jsc-utils.c
@@ -0,0 +1,711 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2019 Red Hat (www.redhat.com)
+ *
+ * This library is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "evolution-config.h"
+
+#include <webkit2/webkit2.h>
+
+#include "e-web-view-jsc-utils.h"
+
+gboolean
+e_web_view_jsc_get_object_property_boolean (JSCValue *jsc_object,
+                                           const gchar *property_name,
+                                           gboolean default_value)
+{
+       JSCValue *value;
+       gboolean res = default_value;
+
+       g_return_val_if_fail (JSC_IS_VALUE (jsc_object), default_value);
+       g_return_val_if_fail (property_name != NULL, default_value);
+
+       value = jsc_value_object_get_property (jsc_object, property_name);
+       if (!value)
+               return default_value;
+
+       if (jsc_value_is_boolean (value))
+               res = jsc_value_to_boolean (value);
+
+       g_clear_object (&value);
+
+       return res;
+}
+
+gint32
+e_web_view_jsc_get_object_property_int32 (JSCValue *jsc_object,
+                                         const gchar *property_name,
+                                         gint32 default_value)
+{
+       JSCValue *value;
+       gint32 res = default_value;
+
+       g_return_val_if_fail (JSC_IS_VALUE (jsc_object), default_value);
+       g_return_val_if_fail (property_name != NULL, default_value);
+
+       value = jsc_value_object_get_property (jsc_object, property_name);
+       if (!value)
+               return default_value;
+
+       if (jsc_value_is_number (value))
+               res = jsc_value_to_int32 (value);
+
+       g_clear_object (&value);
+
+       return res;
+}
+
+gdouble
+e_web_view_jsc_get_object_property_double (JSCValue *jsc_object,
+                                          const gchar *property_name,
+                                          gdouble default_value)
+{
+       JSCValue *value;
+       gdouble res = default_value;
+
+       g_return_val_if_fail (JSC_IS_VALUE (jsc_object), default_value);
+       g_return_val_if_fail (property_name != NULL, default_value);
+
+       value = jsc_value_object_get_property (jsc_object, property_name);
+       if (!value)
+               return default_value;
+
+       if (jsc_value_is_number (value))
+               res = jsc_value_to_double (value);
+
+       g_clear_object (&value);
+
+       return res;
+}
+
+gchar *
+e_web_view_jsc_get_object_property_string (JSCValue *jsc_object,
+                                          const gchar *property_name,
+                                          const gchar *default_value)
+{
+       JSCValue *value;
+       gchar *res;
+
+       g_return_val_if_fail (JSC_IS_VALUE (jsc_object), NULL);
+       g_return_val_if_fail (property_name != NULL, NULL);
+
+       value = jsc_value_object_get_property (jsc_object, property_name);
+       if (!value)
+               return g_strdup (default_value);
+
+       if (jsc_value_is_string (value))
+               res = jsc_value_to_string (value);
+       else
+               res = g_strdup (default_value);
+
+       g_clear_object (&value);
+
+       return res;
+}
+
+gchar *
+e_web_view_jsc_printf_script (const gchar *script_format,
+                             ...)
+{
+       gchar *script;
+       va_list va;
+
+       g_return_val_if_fail (script_format != NULL, NULL);
+
+       va_start (va, script_format);
+       script = e_web_view_jsc_vprintf_script (script_format, va);
+       va_end (va);
+
+       return script;
+}
+
+gchar *
+e_web_view_jsc_vprintf_script (const gchar *script_format,
+                              va_list va)
+{
+       GString *script;
+
+       g_return_val_if_fail (script_format != NULL, NULL);
+
+       script = g_string_sized_new (128);
+
+       e_web_view_jsc_vprintf_script_gstring (script, script_format, va);
+
+       return g_string_free (script, FALSE);
+}
+
+void
+e_web_view_jsc_printf_script_gstring (GString *script,
+                                     const gchar *script_format,
+                                     ...)
+{
+       va_list va;
+
+       g_return_if_fail (script != NULL);
+       g_return_if_fail (script_format != NULL);
+
+       va_start (va, script_format);
+       e_web_view_jsc_vprintf_script_gstring (script, script_format, va);
+       va_end (va);
+}
+
+void
+e_web_view_jsc_vprintf_script_gstring (GString *script,
+                                      const gchar *script_format,
+                                      va_list va)
+{
+       const gchar *ptr;
+
+       g_return_if_fail (script != NULL);
+       g_return_if_fail (script_format != NULL);
+
+       if (script->len)
+               g_string_append_c (script, '\n');
+
+       for (ptr = script_format; *ptr; ptr++) {
+               if (*ptr == '\\') {
+                       g_warn_if_fail (ptr[1]);
+
+                       g_string_append_c (script, ptr[0]);
+                       g_string_append_c (script, ptr[1]);
+
+                       ptr++;
+               } else if (*ptr == '%') {
+                       g_warn_if_fail (ptr[1]);
+
+                       switch (ptr[1]) {
+                       case '%':
+                               g_string_append_c (script, ptr[1]);
+                               break;
+                       /* Using %x for boolean, because %b is unknown to gcc, thus it claims format warnings 
*/
+                       case 'x': {
+                               gboolean arg = va_arg (va, gboolean);
+
+                               g_string_append (script, arg ? "true" : "false");
+                               } break;
+                       case 'd': {
+                               gint arg = va_arg (va, gint);
+
+                               g_string_append_printf (script, "%d", arg);
+                               } break;
+                       case 'f': {
+                               gdouble arg = va_arg (va, gdouble);
+
+                               g_string_append_printf (script, "%f", arg);
+                               } break;
+                       case 's': {
+                               const gchar *arg = va_arg (va, const gchar *);
+
+                               /* Enclose strings into double-quotes */
+                               g_string_append_c (script, '\"');
+
+                               /* Escape significant characters */
+                               if (arg && (strchr (arg, '\"') ||
+                                   strchr (arg, '\\') ||
+                                   strchr (arg, '\n') ||
+                                   strchr (arg, '\r') ||
+                                   strchr (arg, '\t'))) {
+                                       const gchar *ptr2;
+
+                                       for (ptr2 = arg; *ptr2; ptr2++) {
+                                               if (*ptr2 == '\\')
+                                                       g_string_append (script, "\\\\");
+                                               else if (*ptr2 == '\"')
+                                                       g_string_append (script, "\\\"");
+                                               else if (*ptr2 == '\r')
+                                                       g_string_append (script, "\\r");
+                                               else if (*ptr2 == '\n')
+                                                       g_string_append (script, "\\n");
+                                               else if (*ptr2 == '\t')
+                                                       g_string_append (script, "\\t");
+                                               else
+                                                       g_string_append_c (script, *ptr2);
+                                       }
+                               } else if (arg && *arg) {
+                                       g_string_append (script, arg);
+                               }
+
+                               g_string_append_c (script, '\"');
+
+                               } break;
+                       default:
+                               g_warning ("%s: Unknown percent tag '%c'", G_STRFUNC, *ptr);
+                               break;
+                       }
+
+                       ptr++;
+               } else {
+                       g_string_append_c (script, *ptr);
+               }
+       }
+}
+
+static void
+ewv_jsc_call_done_cb (GObject *source,
+                     GAsyncResult *result,
+                     gpointer user_data)
+{
+       WebKitJavascriptResult *js_result;
+       gchar *script = user_data;
+       GError *error = NULL;
+
+       js_result = webkit_web_view_run_javascript_finish (WEBKIT_WEB_VIEW (source), result, &error);
+
+       if (error) {
+               if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED) &&
+                   (!g_error_matches (error, WEBKIT_JAVASCRIPT_ERROR, WEBKIT_JAVASCRIPT_ERROR_SCRIPT_FAILED) 
||
+                    /* WebKit can return empty error message, thus ignore those. */
+                    (error->message && *(error->message))))
+                       g_warning ("Failed to call '%s' function: %s:%d: %s", script, g_quark_to_string 
(error->domain), error->code, error->message);
+               g_clear_error (&error);
+       }
+
+       if (js_result) {
+               JSCException *exception;
+               JSCValue *value;
+
+               value = webkit_javascript_result_get_js_value (js_result);
+               exception = jsc_context_get_exception (jsc_value_get_context (value));
+
+               if (exception)
+                       g_warning ("Failed to call '%s': %s", script, jsc_exception_get_message (exception));
+
+               webkit_javascript_result_unref (js_result);
+       }
+
+       g_free (script);
+}
+
+void
+e_web_view_jsc_run_script (WebKitWebView *web_view,
+                          GCancellable *cancellable,
+                          const gchar *script_format,
+                          ...)
+{
+       gchar *script;
+       va_list va;
+
+       g_return_if_fail (WEBKIT_IS_WEB_VIEW (web_view));
+       g_return_if_fail (script_format != NULL);
+
+       va_start (va, script_format);
+       script = e_web_view_jsc_vprintf_script (script_format, va);
+       va_end (va);
+
+       e_web_view_jsc_run_script_take (web_view, script, cancellable);
+}
+
+/* Assumes ownership of the 'script' variable and frees is with g_free(), when no longe needed. */
+void
+e_web_view_jsc_run_script_take (WebKitWebView *web_view,
+                               gchar *script,
+                               GCancellable *cancellable)
+{
+       g_return_if_fail (WEBKIT_IS_WEB_VIEW (web_view));
+       g_return_if_fail (script != NULL);
+
+       webkit_web_view_run_javascript (web_view, script, cancellable, ewv_jsc_call_done_cb, script);
+}
+
+void
+e_web_view_jsc_set_element_hidden (WebKitWebView *web_view,
+                                  const gchar *iframe_id,
+                                  const gchar *element_id,
+                                  gboolean value,
+                                  GCancellable *cancellable)
+{
+       g_return_if_fail (WEBKIT_IS_WEB_VIEW (web_view));
+       g_return_if_fail (element_id != NULL);
+
+       e_web_view_jsc_run_script (web_view, cancellable,
+               "Evo.SetElementHidden(%s,%s,%d)",
+               iframe_id,
+               element_id,
+               value ? 1 : 0);
+}
+
+void
+e_web_view_jsc_set_element_disabled (WebKitWebView *web_view,
+                                    const gchar *iframe_id,
+                                    const gchar *element_id,
+                                    gboolean value,
+                                    GCancellable *cancellable)
+{
+       g_return_if_fail (WEBKIT_IS_WEB_VIEW (web_view));
+       g_return_if_fail (element_id != NULL);
+
+       e_web_view_jsc_run_script (web_view, cancellable,
+               "Evo.SetElementDisabled(%s,%s,%d)",
+               iframe_id,
+               element_id,
+               value ? 1 : 0);
+}
+
+void
+e_web_view_jsc_set_element_checked (WebKitWebView *web_view,
+                                   const gchar *iframe_id,
+                                   const gchar *element_id,
+                                   gboolean value,
+                                   GCancellable *cancellable)
+{
+       g_return_if_fail (WEBKIT_IS_WEB_VIEW (web_view));
+       g_return_if_fail (element_id != NULL);
+
+       e_web_view_jsc_run_script (web_view, cancellable,
+               "Evo.SetElementChecked(%s,%s,%d)",
+               iframe_id,
+               element_id,
+               value ? 1 : 0);
+}
+
+void
+e_web_view_jsc_set_element_style_property (WebKitWebView *web_view,
+                                          const gchar *iframe_id,
+                                          const gchar *element_id,
+                                          const gchar *property_name,
+                                          const gchar *value,
+                                          GCancellable *cancellable)
+{
+       g_return_if_fail (WEBKIT_IS_WEB_VIEW (web_view));
+       g_return_if_fail (element_id != NULL);
+       g_return_if_fail (property_name != NULL);
+
+       e_web_view_jsc_run_script (web_view, cancellable,
+               "Evo.SetElementStyleProperty(%s,%s,%s,%s)",
+               iframe_id,
+               element_id,
+               property_name,
+               value);
+}
+
+void
+e_web_view_jsc_set_element_attribute (WebKitWebView *web_view,
+                                     const gchar *iframe_id,
+                                     const gchar *element_id,
+                                     const gchar *namespace_uri,
+                                     const gchar *qualified_name,
+                                     const gchar *value,
+                                     GCancellable *cancellable)
+{
+       g_return_if_fail (WEBKIT_IS_WEB_VIEW (web_view));
+       g_return_if_fail (element_id != NULL);
+       g_return_if_fail (qualified_name != NULL);
+
+       e_web_view_jsc_run_script (web_view, cancellable,
+               "Evo.SetElementAttribute(%s,%s,%s,%s,%s)",
+               iframe_id,
+               element_id,
+               namespace_uri,
+               qualified_name,
+               value);
+}
+
+void
+e_web_view_jsc_create_style_sheet (WebKitWebView *web_view,
+                                  const gchar *iframe_id,
+                                  const gchar *style_sheet_id,
+                                  const gchar *content,
+                                  GCancellable *cancellable)
+{
+       g_return_if_fail (WEBKIT_IS_WEB_VIEW (web_view));
+       g_return_if_fail (style_sheet_id != NULL);
+
+       e_web_view_jsc_run_script (web_view, cancellable,
+               "Evo.CreateStyleSheet(%s,%s,%s)",
+               iframe_id,
+               style_sheet_id,
+               content);
+}
+
+void
+e_web_view_jsc_remove_style_sheet (WebKitWebView *web_view,
+                                  const gchar *iframe_id,
+                                  const gchar *style_sheet_id,
+                                  GCancellable *cancellable)
+{
+       g_return_if_fail (WEBKIT_IS_WEB_VIEW (web_view));
+       g_return_if_fail (style_sheet_id != NULL);
+
+       e_web_view_jsc_run_script (web_view, cancellable,
+               "Evo.RemoveStyleSheet(%s,%s)",
+               iframe_id,
+               style_sheet_id);
+}
+
+void
+e_web_view_jsc_add_rule_into_style_sheet (WebKitWebView *web_view,
+                                         const gchar *iframe_id,
+                                         const gchar *style_sheet_id,
+                                         const gchar *selector,
+                                         const gchar *style,
+                                         GCancellable *cancellable)
+{
+       g_return_if_fail (WEBKIT_IS_WEB_VIEW (web_view));
+       g_return_if_fail (style_sheet_id != NULL);
+
+       e_web_view_jsc_run_script (web_view, cancellable,
+               "Evo.AddRuleIntoStyleSheet(%s,%s,%s,%s)",
+               iframe_id,
+               style_sheet_id,
+               selector,
+               style);
+}
+
+void
+e_web_view_jsc_register_element_clicked (WebKitWebView *web_view,
+                                        const gchar *iframe_id,
+                                        const gchar *elem_classes,
+                                        GCancellable *cancellable)
+{
+       g_return_if_fail (WEBKIT_IS_WEB_VIEW (web_view));
+       g_return_if_fail (elem_classes != NULL);
+
+       e_web_view_jsc_run_script (web_view, cancellable,
+               "Evo.RegisterElementClicked(%s,%s)",
+               iframe_id,
+               elem_classes);
+}
+
+static gboolean
+ewv_jsc_get_content_finish (WebKitWebView *web_view,
+                           GAsyncResult *result,
+                           GSList **out_texts,
+                           GError **error)
+{
+       WebKitJavascriptResult *js_result;
+       GError *local_error = NULL;
+
+       g_return_val_if_fail (WEBKIT_IS_WEB_VIEW (web_view), FALSE);
+       g_return_val_if_fail (result != NULL, FALSE);
+       g_return_val_if_fail (out_texts != NULL, FALSE);
+
+       *out_texts = NULL;
+
+       js_result = webkit_web_view_run_javascript_finish (web_view, result, &local_error);
+
+       if (local_error) {
+               g_propagate_error (error, local_error);
+
+               if (js_result)
+                       webkit_javascript_result_unref (js_result);
+
+               return FALSE;
+       }
+
+       if (js_result) {
+               JSCException *exception;
+               JSCValue *value;
+
+               value = webkit_javascript_result_get_js_value (js_result);
+               exception = jsc_context_get_exception (jsc_value_get_context (value));
+
+               if (exception) {
+                       g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Call failed: %s", 
jsc_exception_get_message (exception));
+                       webkit_javascript_result_unref (js_result);
+                       return FALSE;
+               }
+
+               if (jsc_value_is_string (value)) {
+                       *out_texts = g_slist_prepend (*out_texts, jsc_value_to_string (value));
+               } else if (jsc_value_is_object (value)) {
+                       *out_texts = g_slist_prepend (*out_texts, e_web_view_jsc_get_object_property_string 
(value, "html", NULL));
+                       *out_texts = g_slist_prepend (*out_texts, e_web_view_jsc_get_object_property_string 
(value, "plain", NULL));
+               }
+
+               webkit_javascript_result_unref (js_result);
+       }
+
+       return TRUE;
+}
+
+void
+e_web_view_jsc_get_selection (WebKitWebView *web_view,
+                             ETextFormat format,
+                             GCancellable *cancellable,
+                             GAsyncReadyCallback callback,
+                             gpointer user_data)
+{
+       gchar *script;
+
+       g_return_if_fail (WEBKIT_IS_WEB_VIEW (web_view));
+
+       script = e_web_view_jsc_printf_script ("Evo.GetSelection(%d)", format);
+
+       webkit_web_view_run_javascript (web_view, script, cancellable, callback, user_data);
+
+       g_free (script);
+}
+
+gboolean
+e_web_view_jsc_get_selection_finish (WebKitWebView *web_view,
+                                    GAsyncResult *result,
+                                    GSList **out_texts,
+                                    GError **error)
+{
+       g_return_val_if_fail (WEBKIT_IS_WEB_VIEW (web_view), FALSE);
+       g_return_val_if_fail (result != NULL, FALSE);
+       g_return_val_if_fail (out_texts != NULL, FALSE);
+
+       return ewv_jsc_get_content_finish (web_view, result, out_texts, error);
+}
+
+void
+e_web_view_jsc_get_document_content (WebKitWebView *web_view,
+                                    const gchar *iframe_id,
+                                    ETextFormat format,
+                                    GCancellable *cancellable,
+                                    GAsyncReadyCallback callback,
+                                    gpointer user_data)
+{
+       gchar *script;
+
+       g_return_if_fail (WEBKIT_IS_WEB_VIEW (web_view));
+
+       script = e_web_view_jsc_printf_script ("Evo.GetDocumentContent(%s,%d)", iframe_id, format);
+
+       webkit_web_view_run_javascript (web_view, script, cancellable, callback, user_data);
+
+       g_free (script);
+}
+
+gboolean
+e_web_view_jsc_get_document_content_finish (WebKitWebView *web_view,
+                                           GAsyncResult *result,
+                                           GSList **out_texts,
+                                           GError **error)
+{
+       g_return_val_if_fail (WEBKIT_IS_WEB_VIEW (web_view), FALSE);
+       g_return_val_if_fail (result != NULL, FALSE);
+       g_return_val_if_fail (out_texts != NULL, FALSE);
+
+       return ewv_jsc_get_content_finish (web_view, result, out_texts, error);
+}
+
+void
+e_web_view_jsc_get_element_content (WebKitWebView *web_view,
+                                   const gchar *iframe_id,
+                                   const gchar *element_id,
+                                   ETextFormat format,
+                                   gboolean use_outer_html,
+                                   GCancellable *cancellable,
+                                   GAsyncReadyCallback callback,
+                                   gpointer user_data)
+{
+       gchar *script;
+
+       g_return_if_fail (WEBKIT_IS_WEB_VIEW (web_view));
+       g_return_if_fail (element_id != NULL);
+
+       script = e_web_view_jsc_printf_script ("Evo.GetElementContent(%s,%s,%d,%x)", iframe_id, element_id, 
format, use_outer_html);
+
+       webkit_web_view_run_javascript (web_view, script, cancellable, callback, user_data);
+
+       g_free (script);
+}
+
+gboolean
+e_web_view_jsc_get_element_content_finish (WebKitWebView *web_view,
+                                          GAsyncResult *result,
+                                          GSList **out_texts,
+                                          GError **error)
+{
+       g_return_val_if_fail (WEBKIT_IS_WEB_VIEW (web_view), FALSE);
+       g_return_val_if_fail (result != NULL, FALSE);
+       g_return_val_if_fail (out_texts != NULL, FALSE);
+
+       return ewv_jsc_get_content_finish (web_view, result, out_texts, error);
+}
+
+void
+e_web_view_jsc_get_element_from_point (WebKitWebView *web_view,
+                                      gint xx,
+                                      gint yy,
+                                      GCancellable *cancellable,
+                                      GAsyncReadyCallback callback,
+                                      gpointer user_data)
+{
+       gchar *script;
+
+       g_return_if_fail (WEBKIT_IS_WEB_VIEW (web_view));
+
+       script = e_web_view_jsc_printf_script ("Evo.GetElementFromPoint(%d,%d)", xx, yy);
+
+       webkit_web_view_run_javascript (web_view, script, cancellable, callback, user_data);
+
+       g_free (script);
+}
+
+/* Can return TRUE, but set all out parameters to NULL */
+gboolean
+e_web_view_jsc_get_element_from_point_finish (WebKitWebView *web_view,
+                                             GAsyncResult *result,
+                                             gchar **out_iframe_src,
+                                             gchar **out_iframe_id,
+                                             gchar **out_element_id,
+                                             GError **error)
+{
+       WebKitJavascriptResult *js_result;
+       GError *local_error = NULL;
+
+       g_return_val_if_fail (WEBKIT_IS_WEB_VIEW (web_view), FALSE);
+       g_return_val_if_fail (result != NULL, FALSE);
+
+       if (out_iframe_src)
+               *out_iframe_src = NULL;
+       if (out_iframe_id)
+               *out_iframe_id = NULL;
+       if (out_element_id)
+               *out_element_id = NULL;
+
+       js_result = webkit_web_view_run_javascript_finish (web_view, result, &local_error);
+
+       if (local_error) {
+               g_propagate_error (error, local_error);
+
+               if (js_result)
+                       webkit_javascript_result_unref (js_result);
+
+               return FALSE;
+       }
+
+       if (js_result) {
+               JSCException *exception;
+               JSCValue *value;
+
+               value = webkit_javascript_result_get_js_value (js_result);
+               exception = jsc_context_get_exception (jsc_value_get_context (value));
+
+               if (exception) {
+                       g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Call failed: %s", 
jsc_exception_get_message (exception));
+                       webkit_javascript_result_unref (js_result);
+                       return FALSE;
+               }
+
+               if (jsc_value_is_object (value)) {
+                       if (out_iframe_src)
+                               *out_iframe_src = e_web_view_jsc_get_object_property_string (value, 
"iframe-src", NULL);
+                       if (out_iframe_id)
+                               *out_iframe_id = e_web_view_jsc_get_object_property_string (value, 
"iframe-id", NULL);
+                       if (out_element_id)
+                               *out_element_id = e_web_view_jsc_get_object_property_string (value, 
"elem-id", NULL);
+               } else if (!jsc_value_is_null (value)) {
+                       g_warn_if_reached ();
+               }
+
+               webkit_javascript_result_unref (js_result);
+       }
+
+       return TRUE;
+}
diff --git a/src/e-util/e-web-view-jsc-utils.h b/src/e-util/e-web-view-jsc-utils.h
new file mode 100644
index 0000000000..8968e0bfb7
--- /dev/null
+++ b/src/e-util/e-web-view-jsc-utils.h
@@ -0,0 +1,181 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2019 Red Hat (www.redhat.com)
+ *
+ * This library is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#if !defined (__E_UTIL_H_INSIDE__) && !defined (LIBEUTIL_COMPILATION)
+#error "Only <e-util/e-util.h> should be included directly."
+#endif
+
+#ifndef E_WEB_VIEW_JSC_UTILS_H
+#define E_WEB_VIEW_JSC_UTILS_H
+
+#include <webkit2/webkit2.h>
+
+G_BEGIN_DECLS
+
+gboolean       e_web_view_jsc_get_object_property_boolean
+                                               (JSCValue *jsc_object,
+                                                const gchar *property_name,
+                                                gboolean default_value);
+gint32         e_web_view_jsc_get_object_property_int32
+                                               (JSCValue *jsc_object,
+                                                const gchar *property_name,
+                                                gint32 default_value);
+gdouble                e_web_view_jsc_get_object_property_double
+                                               (JSCValue *jsc_object,
+                                                const gchar *property_name,
+                                                gdouble default_value);
+gchar *                e_web_view_jsc_get_object_property_string
+                                               (JSCValue *jsc_object,
+                                                const gchar *property_name,
+                                                const gchar *default_value);
+
+gchar *                e_web_view_jsc_printf_script    (const gchar *script_format,
+                                                ...) G_GNUC_PRINTF (1, 2);
+gchar *                e_web_view_jsc_vprintf_script   (const gchar *script_format,
+                                                va_list va);
+void           e_web_view_jsc_printf_script_gstring
+                                               (GString *script,
+                                                const gchar *script_format,
+                                                ...) G_GNUC_PRINTF (2, 3);
+void           e_web_view_jsc_vprintf_script_gstring
+                                               (GString *script,
+                                                const gchar *script_format,
+                                                va_list va);
+void           e_web_view_jsc_run_script       (WebKitWebView *web_view,
+                                                GCancellable *cancellable,
+                                                const gchar *script_format,
+                                                ...) G_GNUC_PRINTF (3, 4);
+void           e_web_view_jsc_run_script_take  (WebKitWebView *web_view,
+                                                gchar *script,
+                                                GCancellable *cancellable);
+void           e_web_view_jsc_set_element_hidden
+                                               (WebKitWebView *web_view,
+                                                const gchar *iframe_id,
+                                                const gchar *element_id,
+                                                gboolean value,
+                                                GCancellable *cancellable);
+void           e_web_view_jsc_set_element_disabled
+                                               (WebKitWebView *web_view,
+                                                const gchar *iframe_id,
+                                                const gchar *element_id,
+                                                gboolean value,
+                                                GCancellable *cancellable);
+void           e_web_view_jsc_set_element_checked
+                                               (WebKitWebView *web_view,
+                                                const gchar *iframe_id,
+                                                const gchar *element_id,
+                                                gboolean value,
+                                                GCancellable *cancellable);
+void           e_web_view_jsc_set_element_style_property
+                                               (WebKitWebView *web_view,
+                                                const gchar *iframe_id,
+                                                const gchar *element_id,
+                                                const gchar *property_name,
+                                                const gchar *value,
+                                                GCancellable *cancellable);
+void           e_web_view_jsc_set_element_attribute
+                                               (WebKitWebView *web_view,
+                                                const gchar *iframe_id,
+                                                const gchar *element_id,
+                                                const gchar *namespace_uri,
+                                                const gchar *qualified_name,
+                                                const gchar *value,
+                                                GCancellable *cancellable);
+void           e_web_view_jsc_create_style_sheet
+                                               (WebKitWebView *web_view,
+                                                const gchar *iframe_id,
+                                                const gchar *style_sheet_id,
+                                                const gchar *content,
+                                                GCancellable *cancellable);
+void           e_web_view_jsc_remove_style_sheet
+                                               (WebKitWebView *web_view,
+                                                const gchar *iframe_id,
+                                                const gchar *style_sheet_id,
+                                                GCancellable *cancellable);
+void           e_web_view_jsc_add_rule_into_style_sheet
+                                               (WebKitWebView *web_view,
+                                                const gchar *iframe_id,
+                                                const gchar *style_sheet_id,
+                                                const gchar *selector,
+                                                const gchar *style,
+                                                GCancellable *cancellable);
+void           e_web_view_jsc_register_element_clicked
+                                               (WebKitWebView *web_view,
+                                                const gchar *iframe_id,
+                                                const gchar *elem_classes,
+                                                GCancellable *cancellable);
+
+typedef enum _ETextFormat {
+       E_TEXT_FORMAT_PLAIN = 1,
+       E_TEXT_FORMAT_HTML = 2,
+       E_TEXT_FORMAT_BOTH = 3
+} ETextFormat;
+
+void           e_web_view_jsc_get_selection    (WebKitWebView *web_view,
+                                                ETextFormat format,
+                                                GCancellable *cancellable,
+                                                GAsyncReadyCallback callback,
+                                                gpointer user_data);
+gboolean       e_web_view_jsc_get_selection_finish
+                                               (WebKitWebView *web_view,
+                                                GAsyncResult *result,
+                                                GSList **out_texts,
+                                                GError **error);
+void           e_web_view_jsc_get_document_content
+                                               (WebKitWebView *web_view,
+                                                const gchar *iframe_id,
+                                                ETextFormat format,
+                                                GCancellable *cancellable,
+                                                GAsyncReadyCallback callback,
+                                                gpointer user_data);
+gboolean       e_web_view_jsc_get_document_content_finish
+                                               (WebKitWebView *web_view,
+                                                GAsyncResult *result,
+                                                GSList **out_texts,
+                                                GError **error);
+void           e_web_view_jsc_get_element_content
+                                               (WebKitWebView *web_view,
+                                                const gchar *iframe_id,
+                                                const gchar *element_id,
+                                                ETextFormat format,
+                                                gboolean use_outer_html,
+                                                GCancellable *cancellable,
+                                                GAsyncReadyCallback callback,
+                                                gpointer user_data);
+gboolean       e_web_view_jsc_get_element_content_finish
+                                               (WebKitWebView *web_view,
+                                                GAsyncResult *result,
+                                                GSList **out_texts,
+                                                GError **error);
+void           e_web_view_jsc_get_element_from_point
+                                               (WebKitWebView *web_view,
+                                                gint xx,
+                                                gint yy,
+                                                GCancellable *cancellable,
+                                                GAsyncReadyCallback callback,
+                                                gpointer user_data);
+gboolean       e_web_view_jsc_get_element_from_point_finish
+                                               (WebKitWebView *web_view,
+                                                GAsyncResult *result,
+                                                gchar **out_iframe_src,
+                                                gchar **out_iframe_id,
+                                                gchar **out_element_id,
+                                                GError **error);
+
+G_END_DECLS
+
+#endif /* E_WEB_VIEW_JSC_UTILS_H */
diff --git a/src/e-util/e-web-view.c b/src/e-util/e-web-view.c
index 5caa586a6c..411a566c2d 100644
--- a/src/e-util/e-web-view.c
+++ b/src/e-util/e-web-view.c
@@ -39,8 +39,7 @@
 #include "e-selectable.h"
 #include "e-stock-request.h"
 #include "e-web-extension-container.h"
-
-#include "web-extensions/e-web-extension-names.h"
+#include "e-web-view-jsc-utils.h"
 
 #include "e-web-view.h"
 
@@ -48,8 +47,6 @@
        (G_TYPE_INSTANCE_GET_PRIVATE \
        ((obj), E_TYPE_WEB_VIEW, EWebViewPrivate))
 
-static void e_web_view_set_web_extension_proxy (EWebView *web_view, GDBusProxy *proxy);
-
 typedef struct _AsyncContext AsyncContext;
 
 typedef struct _ElementClickedData {
@@ -83,10 +80,6 @@ struct _EWebViewPrivate {
 
        GHashTable *old_settings;
 
-       EWebExtensionContainer *container;
-       GDBusProxy *web_extension_proxy;
-       gint stamp; /* Changed only in the main thread, doesn't need locking */
-
        WebKitFindController *find_controller;
        gulong found_text_handler_id;
        gulong failed_to_find_text_handler_id;
@@ -96,15 +89,16 @@ struct _EWebViewPrivate {
        GSList *content_requests; /* EContentRequest * */
 
        GHashTable *element_clicked_cbs; /* gchar *element_class ~> GPtrArray {ElementClickedData} */
-       guint web_extension_element_clicked_signal_id;
-
-       guint32 clipboard_flags;
-       guint web_extension_clipboard_flags_changed_signal_id;
 
+       gboolean has_selection;
        gboolean need_input;
-       guint web_extension_need_input_changed_signal_id;
 
-       GCancellable *load_cancellable;
+       GCancellable *cancellable;
+
+       gchar *last_popup_iframe_src;
+       gchar *last_popup_iframe_id;
+       gchar *last_popup_element_id;
+       gchar *last_popup_link_uri;
 };
 
 struct _AsyncContext {
@@ -118,18 +112,17 @@ struct _AsyncContext {
 enum {
        PROP_0,
        PROP_CARET_MODE,
-       PROP_CLIPBOARD_FLAGS,
        PROP_COPY_TARGET_LIST,
        PROP_CURSOR_IMAGE_SRC,
        PROP_DISABLE_PRINTING,
        PROP_DISABLE_SAVE_TO_DISK,
+       PROP_HAS_SELECTION,
        PROP_NEED_INPUT,
        PROP_OPEN_PROXY,
        PROP_PASTE_TARGET_LIST,
        PROP_PRINT_PROXY,
        PROP_SAVE_AS_PROXY,
-       PROP_SELECTED_URI,
-       PROP_WEB_EXTENSION_PROXY
+       PROP_SELECTED_URI
 };
 
 enum {
@@ -140,6 +133,8 @@ enum {
        UPDATE_ACTIONS,
        PROCESS_MAILTO,
        URI_REQUESTED,
+       CONTENT_LOADED,
+       BEFORE_POPUP_EVENT,
        LAST_SIGNAL
 };
 
@@ -213,36 +208,24 @@ action_copy_clipboard_cb (GtkAction *action,
        e_web_view_copy_clipboard (web_view);
 }
 
-static gint
-e_web_view_assign_new_stamp (EWebView *web_view)
-{
-       g_return_val_if_fail (E_IS_WEB_VIEW (web_view), 0);
-
-       if (web_view->priv->stamp)
-               e_web_extension_container_forget_stamp (web_view->priv->container, web_view->priv->stamp);
-
-       web_view->priv->stamp = e_web_extension_container_reserve_stamp (web_view->priv->container);
-
-       return web_view->priv->stamp;
-}
-
 static void
 e_web_view_search_web_get_selection_cb (GObject *source,
                                        GAsyncResult *result,
                                        gpointer user_data)
 {
-       gchar *text;
+       GSList *texts;
        GError *local_error = NULL;
 
        g_return_if_fail (E_IS_WEB_VIEW (source));
 
-       text = e_web_view_get_selection_content_text_finish (E_WEB_VIEW (source), result, &local_error);
+       e_web_view_jsc_get_selection_finish (WEBKIT_WEB_VIEW (source), result, &texts, &local_error);
 
        if (local_error &&
            !g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
                e_alert_submit (E_ALERT_SINK (source), "widgets:get-selected-text-failed", 
local_error->message, NULL);
-       } else if (!local_error) {
+       } else if (texts) {
                GSettings *settings;
+               gchar *text = texts->data;
                gchar *uri_prefix;
                gchar *escaped;
                gchar *uri;
@@ -272,14 +255,14 @@ e_web_view_search_web_get_selection_cb (GObject *source,
        }
 
        g_clear_error (&local_error);
-       g_free (text);
+       g_slist_free_full (texts, g_free);
 }
 
 static void
 action_search_web_cb (GtkAction *action,
                      EWebView *web_view)
 {
-       e_web_view_get_selection_content_text (web_view, 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);
 }
 
@@ -594,6 +577,46 @@ web_view_connect_proxy_cb (EWebView *web_view,
                G_CALLBACK (web_view_menu_item_deselect_cb), web_view);
 }
 
+static void
+web_view_got_elem_from_point_for_popup_event_cb (GObject *source_object,
+                                                GAsyncResult *result,
+                                                gpointer user_data)
+{
+       EWebView *web_view;
+       GdkEvent *event = user_data;
+       GError *error = NULL;
+
+       g_return_if_fail (E_IS_WEB_VIEW (source_object));
+
+       web_view = E_WEB_VIEW (source_object);
+
+       g_clear_pointer (&web_view->priv->last_popup_iframe_src, g_free);
+       g_clear_pointer (&web_view->priv->last_popup_iframe_id, g_free);
+       g_clear_pointer (&web_view->priv->last_popup_element_id, g_free);
+
+       if (!e_web_view_jsc_get_element_from_point_finish (WEBKIT_WEB_VIEW (web_view), result,
+               &web_view->priv->last_popup_iframe_src,
+               &web_view->priv->last_popup_iframe_id,
+               &web_view->priv->last_popup_element_id,
+               &error)) {
+               g_warning ("%s: Failed to get element from point: %s", G_STRFUNC, error ? error->message : 
"Unknown error");
+       }
+
+       if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
+               gboolean handled = FALSE;
+
+               g_signal_emit (web_view, signals[BEFORE_POPUP_EVENT], 0,
+                       web_view->priv->last_popup_link_uri, NULL);
+
+               g_signal_emit (web_view, signals[POPUP_EVENT], 0,
+                       web_view->priv->last_popup_link_uri, event, &handled);
+       }
+
+       if (event)
+               gdk_event_free (event);
+       g_clear_error (&error);
+}
+
 static gboolean
 web_view_context_menu_cb (WebKitWebView *webkit_web_view,
                           WebKitContextMenu *context_menu,
@@ -603,15 +626,18 @@ web_view_context_menu_cb (WebKitWebView *webkit_web_view,
 {
        WebKitHitTestResultContext context;
        EWebView *web_view;
-       gboolean event_handled = FALSE;
        gchar *link_uri = NULL;
+       gdouble xx, yy;
 
        web_view = E_WEB_VIEW (webkit_web_view);
 
-       g_free (web_view->priv->cursor_image_src);
-       web_view->priv->cursor_image_src = NULL;
+       g_clear_pointer (&web_view->priv->cursor_image_src, g_free);
+       g_clear_pointer (&web_view->priv->last_popup_iframe_src, g_free);
+       g_clear_pointer (&web_view->priv->last_popup_iframe_id, g_free);
+       g_clear_pointer (&web_view->priv->last_popup_element_id, g_free);
+       g_clear_pointer (&web_view->priv->last_popup_link_uri, g_free);
 
-       if (hit_test_result == NULL)
+       if (!hit_test_result)
                return FALSE;
 
        context = webkit_hit_test_result_get_context (hit_test_result);
@@ -621,23 +647,23 @@ web_view_context_menu_cb (WebKitWebView *webkit_web_view,
 
                g_object_get (hit_test_result, "image-uri", &image_uri, NULL);
 
-               if (image_uri != NULL) {
-                       g_free (web_view->priv->cursor_image_src);
-                       web_view->priv->cursor_image_src = image_uri;
-               }
+               web_view->priv->cursor_image_src = image_uri;
        }
 
        if (context & WEBKIT_HIT_TEST_RESULT_CONTEXT_LINK)
                g_object_get (hit_test_result, "link-uri", &link_uri, NULL);
 
-       g_signal_emit (
-               web_view,
-               signals[POPUP_EVENT], 0,
-               link_uri, event, &event_handled);
+       web_view->priv->last_popup_link_uri = link_uri;
 
-       g_free (link_uri);
+       if (!gdk_event_get_coords (event, &xx, &yy)) {
+               xx = 1;
+               yy = 1;
+       }
 
-       return event_handled;
+       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;
 }
 
 static void
@@ -747,27 +773,14 @@ web_view_decide_policy_cb (EWebView *web_view,
 }
 
 static void
-e_web_view_ensure_body_class (EWebView *web_view)
-{
-       guint64 page_id;
-
-       g_return_if_fail (E_IS_WEB_VIEW (web_view));
-
-       page_id = webkit_web_view_get_page_id (WEBKIT_WEB_VIEW (web_view));
-
-       e_web_extension_container_call_simple (web_view->priv->container,
-               page_id, web_view->priv->stamp,
-               "EWebViewEnsureBodyClass",
-               g_variant_new ("(ts)", page_id, "-e-web-view-background-color -e-web-view-text-color"));
-}
-
-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));
 
@@ -785,13 +798,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);
@@ -803,16 +819,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,
@@ -828,8 +851,11 @@ web_view_load_changed_cb (WebKitWebView *webkit_web_view,
        if (load_event != WEBKIT_LOAD_FINISHED)
                return;
 
-       e_web_view_ensure_body_class (web_view);
-       style_updated_cb (web_view);
+       /* 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->cancellable,
+               "Evo.EnsureMainDocumentInitialized();");
+
+       e_web_view_update_styles (web_view, "");
 
        web_view_update_document_highlights (web_view);
 }
@@ -906,12 +932,6 @@ web_view_set_property (GObject *object,
                                g_value_get_boolean (value));
                        return;
 
-               case PROP_CLIPBOARD_FLAGS:
-                       e_web_view_set_clipboard_flags (
-                               E_WEB_VIEW (object),
-                               g_value_get_uint (value));
-                       return;
-
                case PROP_COPY_TARGET_LIST:
                        /* This is a fake property. */
                        g_warning ("%s: EWebView::copy-target-list not used", G_STRFUNC);
@@ -935,12 +955,6 @@ web_view_set_property (GObject *object,
                                g_value_get_boolean (value));
                        return;
 
-               case PROP_NEED_INPUT:
-                       e_web_view_set_need_input (
-                               E_WEB_VIEW (object),
-                               g_value_get_boolean (value));
-                       return;
-
                case PROP_OPEN_PROXY:
                        e_web_view_set_open_proxy (
                                E_WEB_VIEW (object),
@@ -986,12 +1000,6 @@ web_view_get_property (GObject *object,
                                E_WEB_VIEW (object)));
                        return;
 
-               case PROP_CLIPBOARD_FLAGS:
-                       g_value_set_uint (
-                               value, e_web_view_get_clipboard_flags (
-                               E_WEB_VIEW (object)));
-                       return;
-
                case PROP_COPY_TARGET_LIST:
                        /* This is a fake property. */
                        g_value_set_boxed (value, NULL);
@@ -1015,6 +1023,10 @@ web_view_get_property (GObject *object,
                                E_WEB_VIEW (object)));
                        return;
 
+               case PROP_HAS_SELECTION:
+                       g_value_set_boolean (value, e_web_view_has_selection (E_WEB_VIEW (object)));
+                       return;
+
                case PROP_NEED_INPUT:
                        g_value_set_boolean (
                                value, e_web_view_get_need_input (
@@ -1049,12 +1061,6 @@ web_view_get_property (GObject *object,
                                value, e_web_view_get_selected_uri (
                                E_WEB_VIEW (object)));
                        return;
-
-               case PROP_WEB_EXTENSION_PROXY:
-                       g_value_set_object (
-                               value, e_web_view_get_web_extension_proxy (
-                               E_WEB_VIEW (object)));
-                       return;
        }
 
        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@@ -1065,11 +1071,14 @@ web_view_dispose (GObject *object)
 {
        EWebViewPrivate *priv;
 
+       /* This can be called during dispose, thus disconnect early */
+       g_signal_handlers_disconnect_by_func (object, G_CALLBACK (style_updated_cb), NULL);
+
        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) {
@@ -1112,18 +1121,12 @@ web_view_dispose (GObject *object)
        g_slist_free_full (priv->content_requests, g_object_unref);
        priv->content_requests = NULL;
 
-       e_web_view_set_web_extension_proxy (E_WEB_VIEW (object), NULL);
-
-       if (priv->container && priv->stamp)
-               e_web_extension_container_forget_stamp (priv->container, priv->stamp);
-
        g_clear_object (&priv->ui_manager);
        g_clear_object (&priv->open_proxy);
        g_clear_object (&priv->print_proxy);
        g_clear_object (&priv->save_as_proxy);
        g_clear_object (&priv->aliasing_settings);
        g_clear_object (&priv->font_settings);
-       g_clear_object (&priv->container);
 
        /* Chain up to parent's dispose() method. */
        G_OBJECT_CLASS (e_web_view_parent_class)->dispose (object);
@@ -1136,6 +1139,10 @@ web_view_finalize (GObject *object)
 
        priv = E_WEB_VIEW_GET_PRIVATE (object);
 
+       g_clear_pointer (&priv->last_popup_iframe_src, g_free);
+       g_clear_pointer (&priv->last_popup_iframe_id, g_free);
+       g_clear_pointer (&priv->last_popup_element_id, g_free);
+       g_clear_pointer (&priv->last_popup_link_uri, g_free);
        g_free (priv->selected_uri);
        g_free (priv->cursor_image_src);
 
@@ -1153,7 +1160,6 @@ web_view_finalize (GObject *object)
        G_OBJECT_CLASS (e_web_view_parent_class)->finalize (object);
 }
 
-
 static void
 web_view_uri_request_done_cb (GObject *source_object,
                              GAsyncResult *result,
@@ -1234,7 +1240,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);
@@ -1308,19 +1314,184 @@ e_web_view_initialize_web_extensions_cb (WebKitWebContext *web_context,
        EWebView *web_view = user_data;
 
        g_return_if_fail (E_IS_WEB_VIEW (web_view));
-       g_return_if_fail (web_view->priv->container);
 
        webkit_web_context_set_web_extensions_directory (web_context, EVOLUTION_WEB_EXTENSIONS_DIR);
-       webkit_web_context_set_web_extensions_initialization_user_data (web_context,
-               g_variant_new ("(ss)",
-                       e_web_extension_container_get_server_guid (web_view->priv->container),
-                       e_web_extension_container_get_server_address (web_view->priv->container)));
+}
+
+static void
+e_web_view_element_clicked_cb (WebKitUserContentManager *manager,
+                              WebKitJavascriptResult *js_result,
+                              gpointer user_data)
+{
+       EWebView *web_view = user_data;
+       GtkAllocation elem_position;
+       GPtrArray *listeners;
+       JSCValue *jsc_object;
+       gchar *iframe_id, *elem_id, *elem_class, *elem_value;
+
+       g_return_if_fail (web_view != NULL);
+       g_return_if_fail (js_result != NULL);
+
+       jsc_object = webkit_javascript_result_get_js_value (js_result);
+       g_return_if_fail (jsc_value_is_object (jsc_object));
+
+       iframe_id = e_web_view_jsc_get_object_property_string (jsc_object, "iframe-id", NULL);
+       elem_id = e_web_view_jsc_get_object_property_string (jsc_object, "elem-id", NULL);
+       elem_class = e_web_view_jsc_get_object_property_string (jsc_object, "elem-class", NULL);
+       elem_value = e_web_view_jsc_get_object_property_string (jsc_object, "elem-value", NULL);
+       elem_position.x = e_web_view_jsc_get_object_property_int32 (jsc_object, "left", 0);
+       elem_position.y = e_web_view_jsc_get_object_property_int32 (jsc_object, "top", 0);
+       elem_position.width = e_web_view_jsc_get_object_property_int32 (jsc_object, "width", 0);
+       elem_position.height = e_web_view_jsc_get_object_property_int32 (jsc_object, "height", 0);
+
+       listeners = g_hash_table_lookup (web_view->priv->element_clicked_cbs, elem_class);
+
+       if (listeners) {
+               guint ii;
+
+               for (ii = 0; ii < listeners->len; ii++) {
+                       ElementClickedData *ecd = g_ptr_array_index (listeners, ii);
+
+                       if (ecd && ecd->callback)
+                               ecd->callback (web_view, iframe_id, elem_id, elem_class, elem_value, 
&elem_position, ecd->user_data);
+               }
+       }
+
+       g_free (iframe_id);
+       g_free (elem_id);
+       g_free (elem_class);
+       g_free (elem_value);
+}
+
+static void
+web_view_call_register_element_clicked (EWebView *web_view,
+                                       const gchar *iframe_id,
+                                       const gchar *only_elem_class)
+{
+       gchar *elem_classes = NULL;
+
+       if (!only_elem_class) {
+               GHashTableIter iter;
+               gpointer key;
+               GString *classes;
+
+               classes = g_string_sized_new (128);
+
+               g_hash_table_iter_init (&iter, web_view->priv->element_clicked_cbs);
+               while (g_hash_table_iter_next (&iter, &key, NULL)) {
+                       if (classes->len)
+                               g_string_append_c (classes, '\n');
+
+                       g_string_append (classes, key);
+               }
+
+               elem_classes = g_string_free (classes, FALSE);
+       }
+
+       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->cancellable);
+
+       g_free (elem_classes);
+}
+
+static void
+e_web_view_content_loaded_cb (WebKitUserContentManager *manager,
+                             WebKitJavascriptResult *js_result,
+                             gpointer user_data)
+{
+       EWebView *web_view = user_data;
+       JSCValue *jsc_value;
+       gchar *iframe_id;
+
+       g_return_if_fail (web_view != 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_string (jsc_value));
+
+       iframe_id = jsc_value_to_string (jsc_value);
+
+       if (!iframe_id || !*iframe_id)
+               e_web_view_update_fonts (web_view);
+       else
+               e_web_view_update_styles (web_view, iframe_id);
+
+       web_view_call_register_element_clicked (web_view, iframe_id, NULL);
+
+       g_signal_emit (web_view, signals[CONTENT_LOADED], 0, iframe_id);
+
+       g_free (iframe_id);
+}
+
+static void
+e_web_view_set_has_selection (EWebView *web_view,
+                             gboolean has_selection)
+{
+       g_return_if_fail (E_IS_WEB_VIEW (web_view));
+
+       if ((!web_view->priv->has_selection) == (!has_selection))
+               return;
+
+       web_view->priv->has_selection = has_selection;
+
+       g_object_notify (G_OBJECT (web_view), "has-selection");
+}
+
+
+static void
+e_web_view_has_selection_cb (WebKitUserContentManager *manager,
+                            WebKitJavascriptResult *js_result,
+                            gpointer user_data)
+{
+       EWebView *web_view = user_data;
+       JSCValue *jsc_value;
+
+       g_return_if_fail (web_view != 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_boolean (jsc_value));
+
+       e_web_view_set_has_selection (web_view, jsc_value_to_boolean (jsc_value));
+}
+
+static void
+e_web_view_set_need_input (EWebView *web_view,
+                          gboolean need_input)
+{
+       g_return_if_fail (E_IS_WEB_VIEW (web_view));
+
+       if ((!web_view->priv->need_input) == (!need_input))
+               return;
+
+       web_view->priv->need_input = need_input;
+
+       g_object_notify (G_OBJECT (web_view), "need-input");
+}
+
+static void
+e_web_view_need_input_changed_cb (WebKitUserContentManager *manager,
+                                 WebKitJavascriptResult *js_result,
+                                 gpointer user_data)
+{
+       EWebView *web_view = user_data;
+       JSCValue *jsc_value;
+
+       g_return_if_fail (web_view != 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_boolean (jsc_value));
+
+       e_web_view_set_need_input (web_view, jsc_value_to_boolean (jsc_value));
 }
 
 static void
 web_view_constructed (GObject *object)
 {
        WebKitSettings *web_settings;
+       WebKitUserContentManager *manager;
        EWebView *web_view = E_WEB_VIEW (object);
 #ifndef G_OS_WIN32
        GSettings *settings;
@@ -1364,6 +1535,25 @@ web_view_constructed (GObject *object)
        web_view_initialize (WEBKIT_WEB_VIEW (object));
 
        web_view_set_find_controller (web_view);
+
+       manager = webkit_web_view_get_user_content_manager (WEBKIT_WEB_VIEW (object));
+
+       g_signal_connect_object (manager, "script-message-received::elementClicked",
+               G_CALLBACK (e_web_view_element_clicked_cb), web_view, 0);
+
+       g_signal_connect_object (manager, "script-message-received::contentLoaded",
+               G_CALLBACK (e_web_view_content_loaded_cb), web_view, 0);
+
+       g_signal_connect_object (manager, "script-message-received::hasSelection",
+               G_CALLBACK (e_web_view_has_selection_cb), web_view, 0);
+
+       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");
+       webkit_user_content_manager_register_script_message_handler (manager, "hasSelection");
+       webkit_user_content_manager_register_script_message_handler (manager, "needInputChanged");
 }
 
 static void
@@ -1372,13 +1562,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
@@ -1549,40 +1739,25 @@ static void
 web_view_load_string (EWebView *web_view,
                       const gchar *string)
 {
-       gchar *uri_with_stamp;
-
-       uri_with_stamp = g_strdup_printf ("evo-file:///?evo-stamp=%d", e_web_view_assign_new_stamp 
(web_view));
-
        if (!string || !*string) {
-               webkit_web_view_load_html (WEBKIT_WEB_VIEW (web_view), "", uri_with_stamp);
+               webkit_web_view_load_html (WEBKIT_WEB_VIEW (web_view), "", "evo-file:///");
        } else {
                GBytes *bytes;
 
                bytes = g_bytes_new (string, strlen (string));
-               webkit_web_view_load_bytes (WEBKIT_WEB_VIEW (web_view), bytes, NULL, NULL, uri_with_stamp);
+               webkit_web_view_load_bytes (WEBKIT_WEB_VIEW (web_view), bytes, NULL, NULL, "evo-file:///");
                g_bytes_unref (bytes);
        }
-
-       g_free (uri_with_stamp);
 }
 
 static void
 web_view_load_uri (EWebView *web_view,
                    const gchar *uri)
 {
-       gchar *uri_with_stamp;
-
-       if (uri == NULL)
+       if (!uri)
                uri = "about:blank";
 
-       if (strchr (uri, '?'))
-               uri_with_stamp = g_strdup_printf ("%s&evo-stamp=%d", uri, e_web_view_assign_new_stamp 
(web_view));
-       else
-               uri_with_stamp = g_strdup_printf ("%s?evo-stamp=%d", uri, e_web_view_assign_new_stamp 
(web_view));
-
-       webkit_web_view_load_uri (WEBKIT_WEB_VIEW (web_view), uri_with_stamp);
-
-       g_free (uri_with_stamp);
+       webkit_web_view_load_uri (WEBKIT_WEB_VIEW (web_view), uri);
 }
 
 static gchar *
@@ -1604,6 +1779,14 @@ web_view_suggest_filename (EWebView *web_view,
        return g_strdup (cp);
 }
 
+static void
+web_view_before_popup_event (EWebView *web_view,
+                            const gchar *uri)
+{
+       e_web_view_set_selected_uri (web_view, uri);
+       e_web_view_update_actions (web_view);
+}
+
 static gboolean
 web_view_popup_event (EWebView *web_view,
                       const gchar *uri,
@@ -1622,243 +1805,6 @@ web_view_stop_loading (EWebView *web_view)
        webkit_web_view_stop_loading (WEBKIT_WEB_VIEW (web_view));
 }
 
-static void
-web_view_register_element_clicked_hfunc (gpointer key,
-                                        gpointer value,
-                                        gpointer user_data)
-{
-       const gchar *elem_class = key;
-       EWebView *web_view = user_data;
-       guint64 page_id;
-
-       g_return_if_fail (elem_class && *elem_class);
-       g_return_if_fail (E_IS_WEB_VIEW (web_view));
-
-       page_id = webkit_web_view_get_page_id (WEBKIT_WEB_VIEW (web_view));
-
-       e_web_extension_container_call_simple (web_view->priv->container,
-               page_id, web_view->priv->stamp,
-               "RegisterElementClicked",
-               g_variant_new ("(ts)", page_id, elem_class));
-}
-
-static void
-web_view_need_input_changed_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)
-{
-       EWebView *web_view = user_data;
-       guint64 page_id = 0;
-       gboolean need_input = FALSE;
-
-       if (g_strcmp0 (signal_name, "NeedInputChanged") != 0)
-               return;
-
-       g_return_if_fail (E_IS_WEB_VIEW (web_view));
-
-       if (!parameters)
-               return;
-
-       g_variant_get (parameters, "(tb)", &page_id, &need_input);
-
-       if (page_id == webkit_web_view_get_page_id (WEBKIT_WEB_VIEW (web_view)))
-               e_web_view_set_need_input (web_view, need_input);
-}
-
-static void
-web_view_clipboard_flags_changed_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)
-{
-       EWebView *web_view = user_data;
-       guint64 page_id = 0;
-       guint32 clipboard_flags = 0;
-
-       if (g_strcmp0 (signal_name, "ClipboardFlagsChanged") != 0)
-               return;
-
-       g_return_if_fail (E_IS_WEB_VIEW (web_view));
-
-       if (!parameters)
-               return;
-
-       g_variant_get (parameters, "(tu)", &page_id, &clipboard_flags);
-
-       if (page_id == webkit_web_view_get_page_id (WEBKIT_WEB_VIEW (web_view)))
-               e_web_view_set_clipboard_flags (web_view, clipboard_flags);
-}
-
-static void
-web_view_element_clicked_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)
-{
-       EWebView *web_view = user_data;
-       const gchar *elem_class = NULL, *elem_value = NULL;
-       GtkAllocation elem_position;
-       guint64 page_id = 0;
-       gint position_left = 0, position_top = 0, position_width = 0, position_height = 0;
-       GPtrArray *listeners;
-
-       if (g_strcmp0 (signal_name, "ElementClicked") != 0)
-               return;
-
-       g_return_if_fail (E_IS_WEB_VIEW (web_view));
-
-       if (!parameters)
-               return;
-
-       g_variant_get (parameters, "(t&s&siiii)", &page_id, &elem_class, &elem_value, &position_left, 
&position_top, &position_width, &position_height);
-
-       if (!elem_class || !*elem_class || page_id != webkit_web_view_get_page_id (WEBKIT_WEB_VIEW 
(web_view)))
-               return;
-
-       elem_position.x = position_left;
-       elem_position.y = position_top;
-       elem_position.width = position_width;
-       elem_position.height = position_height;
-
-       listeners = g_hash_table_lookup (web_view->priv->element_clicked_cbs, elem_class);
-       if (listeners) {
-               guint ii;
-
-               for (ii = 0; ii <listeners->len; ii++) {
-                       ElementClickedData *ecd = g_ptr_array_index (listeners, ii);
-
-                       if (ecd && ecd->callback)
-                               ecd->callback (web_view, elem_class, elem_value, &elem_position, 
ecd->user_data);
-               }
-       }
-}
-
-static void
-e_web_view_set_web_extension_proxy (EWebView *web_view,
-                                   GDBusProxy *proxy)
-{
-       g_return_if_fail (E_IS_WEB_VIEW (web_view));
-
-       if (web_view->priv->web_extension_proxy == proxy)
-               return;
-
-       if (web_view->priv->web_extension_proxy) {
-               GDBusConnection *connection;
-
-               connection = g_dbus_proxy_get_connection (web_view->priv->web_extension_proxy);
-
-               if (connection && g_dbus_connection_is_closed (connection))
-                       connection = NULL;
-
-               if (web_view->priv->web_extension_clipboard_flags_changed_signal_id) {
-                       if (connection)
-                               g_dbus_connection_signal_unsubscribe (connection, 
web_view->priv->web_extension_clipboard_flags_changed_signal_id);
-                       web_view->priv->web_extension_clipboard_flags_changed_signal_id = 0;
-               }
-
-               if (web_view->priv->web_extension_need_input_changed_signal_id) {
-                       if (connection)
-                               g_dbus_connection_signal_unsubscribe (connection, 
web_view->priv->web_extension_need_input_changed_signal_id);
-                       web_view->priv->web_extension_need_input_changed_signal_id = 0;
-               }
-
-               if (web_view->priv->web_extension_element_clicked_signal_id) {
-                       if (connection)
-                               g_dbus_connection_signal_unsubscribe (connection, 
web_view->priv->web_extension_element_clicked_signal_id);
-                       web_view->priv->web_extension_element_clicked_signal_id = 0;
-               }
-
-               g_clear_object (&web_view->priv->web_extension_proxy);
-       }
-
-       if (proxy) {
-               web_view->priv->web_extension_proxy = g_object_ref (proxy);
-
-               web_view->priv->web_extension_clipboard_flags_changed_signal_id =
-                       g_dbus_connection_signal_subscribe (
-                               g_dbus_proxy_get_connection (proxy),
-                               g_dbus_proxy_get_name (proxy),
-                               E_WEB_EXTENSION_INTERFACE,
-                               "ClipboardFlagsChanged",
-                               E_WEB_EXTENSION_OBJECT_PATH,
-                               NULL,
-                               G_DBUS_SIGNAL_FLAGS_NONE,
-                               web_view_clipboard_flags_changed_signal_cb,
-                               web_view,
-                               NULL);
-
-               web_view->priv->web_extension_need_input_changed_signal_id =
-                       g_dbus_connection_signal_subscribe (
-                               g_dbus_proxy_get_connection (proxy),
-                               g_dbus_proxy_get_name (proxy),
-                               E_WEB_EXTENSION_INTERFACE,
-                               "NeedInputChanged",
-                               E_WEB_EXTENSION_OBJECT_PATH,
-                               NULL,
-                               G_DBUS_SIGNAL_FLAGS_NONE,
-                               web_view_need_input_changed_signal_cb,
-                               web_view,
-                               NULL);
-
-               web_view->priv->web_extension_element_clicked_signal_id =
-                       g_dbus_connection_signal_subscribe (
-                               g_dbus_proxy_get_connection (proxy),
-                               g_dbus_proxy_get_name (proxy),
-                               E_WEB_EXTENSION_INTERFACE,
-                               "ElementClicked",
-                               E_WEB_EXTENSION_OBJECT_PATH,
-                               NULL,
-                               G_DBUS_SIGNAL_FLAGS_NONE,
-                               web_view_element_clicked_signal_cb,
-                               web_view,
-                               NULL);
-       }
-
-       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) {
-                       g_hash_table_foreach (web_view->priv->element_clicked_cbs, 
web_view_register_element_clicked_hfunc, web_view);
-
-                       e_web_view_ensure_body_class (web_view);
-                       style_updated_cb (web_view);
-               }
-       }
-}
-
-GDBusProxy *
-e_web_view_get_web_extension_proxy (EWebView *web_view)
-{
-       g_return_val_if_fail (E_IS_WEB_VIEW (web_view), NULL);
-
-       return web_view->priv->web_extension_proxy;
-}
-
 static void
 web_view_update_actions (EWebView *web_view)
 {
@@ -1875,7 +1821,7 @@ web_view_update_actions (EWebView *web_view)
        g_return_if_fail (E_IS_WEB_VIEW (web_view));
 
        uri = e_web_view_get_selected_uri (web_view);
-       can_copy = (e_web_view_get_clipboard_flags (web_view) & E_CLIPBOARD_CAN_COPY) != 0;
+       can_copy = e_web_view_has_selection (web_view);
        cursor_image_src = e_web_view_get_cursor_image_src (web_view);
 
        /* Parse the URI early so we know if the actions will work. */
@@ -2088,7 +2034,7 @@ web_view_selectable_update_actions (ESelectable *selectable,
 
        web_view = E_WEB_VIEW (selectable);
 
-       can_copy = (e_web_view_get_clipboard_flags (web_view) & E_CLIPBOARD_CAN_COPY) != 0;
+       can_copy = e_web_view_has_selection (web_view);
 
        action = e_focus_tracker_get_copy_clipboard_action (focus_tracker);
        gtk_action_set_sensitive (action, can_copy);
@@ -2243,6 +2189,7 @@ e_web_view_class_init (EWebViewClass *class)
        class->load_string = web_view_load_string;
        class->load_uri = web_view_load_uri;
        class->suggest_filename = web_view_suggest_filename;
+       class->before_popup_event = web_view_before_popup_event;
        class->popup_event = web_view_popup_event;
        class->stop_loading = web_view_stop_loading;
        class->update_actions = web_view_update_actions;
@@ -2257,17 +2204,6 @@ e_web_view_class_init (EWebViewClass *class)
                        FALSE,
                        G_PARAM_READWRITE));
 
-       g_object_class_install_property (
-               object_class,
-               PROP_CLIPBOARD_FLAGS,
-               g_param_spec_uint (
-                       "clipboard-flags",
-                       "Clipboard Flags",
-                       NULL,
-                       0, G_MAXUINT, 0,
-                       G_PARAM_READWRITE |
-                       G_PARAM_CONSTRUCT));
-
        /* Inherited from ESelectableInterface; just a fake property here */
        g_object_class_override_property (
                object_class,
@@ -2312,6 +2248,16 @@ e_web_view_class_init (EWebViewClass *class)
                        G_PARAM_READWRITE |
                        G_PARAM_CONSTRUCT));
 
+       g_object_class_install_property (
+               object_class,
+               PROP_HAS_SELECTION,
+               g_param_spec_boolean (
+                       "has-selection",
+                       "Has Selection",
+                       NULL,
+                       FALSE,
+                       G_PARAM_READABLE));
+
        g_object_class_install_property (
                object_class,
                PROP_NEED_INPUT,
@@ -2319,9 +2265,8 @@ e_web_view_class_init (EWebViewClass *class)
                        "need-input",
                        "Need Input",
                        NULL,
-                       FALSE,
-                       G_PARAM_READWRITE |
-                       G_PARAM_CONSTRUCT));
+                       FALSE,
+                       G_PARAM_READABLE));
 
        g_object_class_install_property (
                object_class,
@@ -2363,16 +2308,6 @@ e_web_view_class_init (EWebViewClass *class)
                        NULL,
                        G_PARAM_READWRITE));
 
-       g_object_class_install_property (
-               object_class,
-               PROP_WEB_EXTENSION_PROXY,
-               g_param_spec_object (
-                       "web-extension-proxy",
-                       "Web Extension Proxy",
-                       NULL,
-                       G_TYPE_DBUS_PROXY,
-                       G_PARAM_READABLE));
-
        signals[NEW_ACTIVITY] = g_signal_new (
                "new-activity",
                G_TYPE_FROM_CLASS (class),
@@ -2392,6 +2327,15 @@ e_web_view_class_init (EWebViewClass *class)
                NULL,
                G_TYPE_BOOLEAN, 2, G_TYPE_STRING, GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
 
+       signals[BEFORE_POPUP_EVENT] = g_signal_new (
+               "before-popup-event",
+               G_TYPE_FROM_CLASS (class),
+               G_SIGNAL_RUN_LAST,
+               G_STRUCT_OFFSET (EWebViewClass, before_popup_event),
+               NULL, NULL,
+               g_cclosure_marshal_VOID__STRING,
+               G_TYPE_NONE, 1, G_TYPE_STRING);
+
        signals[STATUS_MESSAGE] = g_signal_new (
                "status-message",
                G_TYPE_FROM_CLASS (class),
@@ -2440,6 +2384,14 @@ e_web_view_class_init (EWebViewClass *class)
                G_STRUCT_OFFSET (EWebViewClass, uri_requested),
                NULL, NULL, NULL,
                G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_POINTER);
+
+       signals[CONTENT_LOADED] = g_signal_new (
+               "content-loaded",
+               G_TYPE_FROM_CLASS (class),
+               G_SIGNAL_RUN_LAST,
+               G_STRUCT_OFFSET (EWebViewClass, content_loaded),
+               NULL, NULL, NULL,
+               G_TYPE_NONE, 1, G_TYPE_STRING);
 }
 
 static void
@@ -2473,12 +2425,8 @@ e_web_view_init (EWebView *web_view)
 
        web_view->priv = E_WEB_VIEW_GET_PRIVATE (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);
@@ -2647,7 +2595,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 *
@@ -2758,117 +2706,6 @@ e_web_view_reload (EWebView *web_view)
        webkit_web_view_reload (WEBKIT_WEB_VIEW (web_view));
 }
 
-static void
-get_document_content_html_cb (GObject *source_object,
-                              GAsyncResult *result,
-                              gpointer user_data)
-{
-       GDBusProxy *web_extension;
-       GTask *task = user_data;
-       GVariant *result_variant;
-       gchar *html_content = NULL;
-       GError *error = NULL;
-
-       g_return_if_fail (G_IS_DBUS_PROXY (source_object));
-       g_return_if_fail (G_IS_TASK (task));
-
-       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, "(s)", &html_content);
-       g_variant_unref (result_variant);
-
-       g_task_return_pointer (task, html_content, g_free);
-       g_object_unref (task);
-
-       if (error)
-               g_dbus_error_strip_remote_error (error);
-
-       e_util_claim_dbus_proxy_call_error (web_extension, "GetDocumentContentHTML", error);
-       g_clear_error (&error);
-}
-
-void
-e_web_view_get_content_html (EWebView *web_view,
-                             GCancellable *cancellable,
-                             GAsyncReadyCallback callback,
-                             gpointer user_data)
-{
-       GDBusProxy *web_extension;
-       GTask *task;
-
-       g_return_if_fail (E_IS_WEB_VIEW (web_view));
-
-       task = g_task_new (web_view, cancellable, callback, user_data);
-
-       web_extension = e_web_view_get_web_extension_proxy (web_view);
-       if (web_extension) {
-               g_dbus_proxy_call (
-                       web_extension,
-                       "GetDocumentContentHTML",
-                       g_variant_new (
-                               "(t)",
-                               webkit_web_view_get_page_id (
-                                       WEBKIT_WEB_VIEW (web_view))),
-                       G_DBUS_CALL_FLAGS_NONE,
-                       -1,
-                       cancellable,
-                       get_document_content_html_cb,
-                       g_object_ref (task));
-       } else
-               g_task_return_pointer (task, NULL, NULL);
-}
-
-gchar *
-e_web_view_get_content_html_finish (EWebView *web_view,
-                                    GAsyncResult *result,
-                                    GError **error)
-{
-       g_return_val_if_fail (E_IS_WEB_VIEW (web_view), NULL);
-       g_return_val_if_fail (g_task_is_valid (result, web_view), FALSE);
-
-       return g_task_propagate_pointer (G_TASK (result), error);
-}
-
-gchar *
-e_web_view_get_content_html_sync (EWebView *web_view,
-                                  GCancellable *cancellable,
-                                  GError **error)
-{
-       GDBusProxy *web_extension;
-
-       g_return_val_if_fail (E_IS_WEB_VIEW (web_view), NULL);
-
-       web_extension = e_web_view_get_web_extension_proxy (web_view);
-       if (web_extension) {
-               GVariant *result;
-
-               result = e_util_invoke_g_dbus_proxy_call_sync_wrapper_full (
-                               web_extension,
-                               "GetDocumentContentHTML",
-                               g_variant_new (
-                                       "(t)",
-                                       webkit_web_view_get_page_id (
-                                               WEBKIT_WEB_VIEW (web_view))),
-                               G_DBUS_CALL_FLAGS_NONE,
-                               -1,
-                               cancellable,
-                               error);
-
-               if (result) {
-                       gchar *html_content = NULL;
-
-                       g_variant_get (result, "(s)", &html_content);
-                       g_variant_unref (result);
-
-                       return html_content;
-               }
-       }
-
-       return NULL;
-}
-
 gboolean
 e_web_view_get_caret_mode (EWebView *web_view)
 {
@@ -2963,28 +2800,6 @@ e_web_view_set_editable (EWebView *web_view,
        webkit_web_view_set_editable (WEBKIT_WEB_VIEW (web_view), editable);
 }
 
-guint32
-e_web_view_get_clipboard_flags (EWebView *web_view)
-{
-       g_return_val_if_fail (E_IS_WEB_VIEW (web_view), 0);
-
-       return web_view->priv->clipboard_flags;
-}
-
-void
-e_web_view_set_clipboard_flags (EWebView *web_view,
-                               guint32 clipboard_flags)
-{
-       g_return_if_fail (E_IS_WEB_VIEW (web_view));
-
-       if (web_view->priv->clipboard_flags == clipboard_flags)
-               return;
-
-       web_view->priv->clipboard_flags = clipboard_flags;
-
-       g_object_notify (G_OBJECT (web_view), "clipboard-flags");
-}
-
 gboolean
 e_web_view_get_need_input (EWebView *web_view)
 {
@@ -2993,20 +2808,6 @@ e_web_view_get_need_input (EWebView *web_view)
        return web_view->priv->need_input;
 }
 
-void
-e_web_view_set_need_input (EWebView *web_view,
-                          gboolean need_input)
-{
-       g_return_if_fail (E_IS_WEB_VIEW (web_view));
-
-       if ((!web_view->priv->need_input) == (!need_input))
-               return;
-
-       web_view->priv->need_input = need_input;
-
-       g_object_notify (G_OBJECT (web_view), "need-input");
-}
-
 const gchar *
 e_web_view_get_selected_uri (EWebView *web_view)
 {
@@ -3154,6 +2955,28 @@ e_web_view_set_save_as_proxy (EWebView *web_view,
        g_object_notify (G_OBJECT (web_view), "save-as-proxy");
 }
 
+void
+e_web_view_get_last_popup_place (EWebView *web_view,
+                                gchar **out_iframe_src,
+                                gchar **out_iframe_id,
+                                gchar **out_element_id,
+                                gchar **out_link_uri)
+{
+       g_return_if_fail (E_IS_WEB_VIEW (web_view));
+
+       if (out_iframe_src)
+               *out_iframe_src = g_strdup (web_view->priv->last_popup_iframe_src);
+
+       if (out_iframe_id)
+               *out_iframe_id = g_strdup (web_view->priv->last_popup_iframe_id);
+
+       if (out_element_id)
+               *out_element_id = g_strdup (web_view->priv->last_popup_element_id);
+
+       if (out_link_uri)
+               *out_link_uri = g_strdup (web_view->priv->last_popup_link_uri);
+}
+
 void
 e_web_view_add_highlight (EWebView *web_view,
                           const gchar *highlight)
@@ -3238,35 +3061,11 @@ e_web_view_cut_clipboard (EWebView *web_view)
 }
 
 gboolean
-e_web_view_is_selection_active (EWebView *web_view)
+e_web_view_has_selection (EWebView *web_view)
 {
-       GDBusProxy *web_extension;
-
        g_return_val_if_fail (E_IS_WEB_VIEW (web_view), FALSE);
 
-       web_extension = e_web_view_get_web_extension_proxy (web_view);
-       if (web_extension) {
-               GVariant *result;
-
-               result = e_util_invoke_g_dbus_proxy_call_sync_wrapper_with_error_check (
-                               web_extension,
-                               "DocumentHasSelection",
-                               g_variant_new (
-                                       "(t)",
-                                       webkit_web_view_get_page_id (
-                                               WEBKIT_WEB_VIEW (web_view))),
-                               NULL);
-
-               if (result) {
-                       gboolean value = FALSE;
-
-                       g_variant_get (result, "(b)", &value);
-                       g_variant_unref (result);
-                       return value;
-               }
-       }
-
-       return FALSE;
+       return web_view->priv->has_selection;
 }
 
 void
@@ -3476,226 +3275,6 @@ e_web_view_update_actions (EWebView *web_view)
        g_signal_emit (web_view, signals[UPDATE_ACTIONS], 0);
 }
 
-static void
-get_selection_content_html_cb (GObject *source_object,
-                              GAsyncResult *result,
-                              gpointer user_data)
-{
-       GDBusProxy *web_extension;
-       GTask *task = user_data;
-       GVariant *result_variant;
-       gchar *html_content = NULL;
-       GError *error = NULL;
-
-       g_return_if_fail (G_IS_DBUS_PROXY (source_object));
-       g_return_if_fail (G_IS_TASK (task));
-
-       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, "(s)", &html_content);
-       g_variant_unref (result_variant);
-
-       g_task_return_pointer (task, html_content, g_free);
-       g_object_unref (task);
-
-       if (error)
-               g_dbus_error_strip_remote_error (error);
-
-       e_util_claim_dbus_proxy_call_error (web_extension, "GetSelectionContentHTML", error);
-       g_clear_error (&error);
-}
-
-void
-e_web_view_get_selection_content_html (EWebView *web_view,
-                                       GCancellable *cancellable,
-                                       GAsyncReadyCallback callback,
-                                       gpointer user_data)
-{
-       GDBusProxy *web_extension;
-       GTask *task;
-
-       g_return_if_fail (E_IS_WEB_VIEW (web_view));
-
-       task = g_task_new (web_view, cancellable, callback, user_data);
-
-       web_extension = e_web_view_get_web_extension_proxy (web_view);
-       if (web_extension) {
-               g_dbus_proxy_call (
-                       web_extension,
-                       "GetSelectionContentHTML",
-                       g_variant_new (
-                               "(t)",
-                               webkit_web_view_get_page_id (
-                                       WEBKIT_WEB_VIEW (web_view))),
-                       G_DBUS_CALL_FLAGS_NONE,
-                       -1,
-                       cancellable,
-                       get_selection_content_html_cb,
-                       g_object_ref (task));
-       } else
-               g_task_return_pointer (task, NULL, NULL);
-}
-
-gchar *
-e_web_view_get_selection_content_html_finish (EWebView *web_view,
-                                              GAsyncResult *result,
-                                              GError **error)
-{
-       g_return_val_if_fail (E_IS_WEB_VIEW (web_view), NULL);
-       g_return_val_if_fail (g_task_is_valid (result, web_view), FALSE);
-
-       return g_task_propagate_pointer (G_TASK (result), error);
-}
-
-gchar *
-e_web_view_get_selection_content_html_sync (EWebView *web_view,
-                                            GCancellable *cancellable,
-                                            GError **error)
-{
-       GDBusProxy *web_extension;
-
-       g_return_val_if_fail (E_IS_WEB_VIEW (web_view), NULL);
-
-       web_extension = e_web_view_get_web_extension_proxy (web_view);
-       if (web_extension) {
-               GVariant *result;
-
-               result = e_util_invoke_g_dbus_proxy_call_sync_wrapper_full (
-                               web_extension,
-                               "GetSelectionContentHTML",
-                               g_variant_new (
-                                       "(t)",
-                                       webkit_web_view_get_page_id (
-                                               WEBKIT_WEB_VIEW (web_view))),
-                               G_DBUS_CALL_FLAGS_NONE,
-                               -1,
-                               cancellable,
-                               error);
-
-               if (result) {
-                       gchar *html_content = NULL;
-
-                       g_variant_get (result, "(s)", &html_content);
-                       g_variant_unref (result);
-                       return html_content;
-               }
-       }
-
-       return NULL;
-}
-
-static void
-get_selection_content_text_cb (GObject *source_object,
-                              GAsyncResult *result,
-                              gpointer user_data)
-{
-       GDBusProxy *web_extension;
-       GTask *task = user_data;
-       GVariant *result_variant;
-       gchar *text_content = NULL;
-       GError *error = NULL;
-
-       g_return_if_fail (G_IS_DBUS_PROXY (source_object));
-       g_return_if_fail (G_IS_TASK (task));
-
-       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, "(s)", &text_content);
-       g_variant_unref (result_variant);
-
-       g_task_return_pointer (task, text_content, g_free);
-       g_object_unref (task);
-
-       if (error)
-               g_dbus_error_strip_remote_error (error);
-
-       e_util_claim_dbus_proxy_call_error (web_extension, "GetSelectionContentText", error);
-       g_clear_error (&error);
-}
-
-void
-e_web_view_get_selection_content_text (EWebView *web_view,
-                                      GCancellable *cancellable,
-                                      GAsyncReadyCallback callback,
-                                      gpointer user_data)
-{
-       GDBusProxy *web_extension;
-       GTask *task;
-
-       g_return_if_fail (E_IS_WEB_VIEW (web_view));
-
-       task = g_task_new (web_view, cancellable, callback, user_data);
-
-       web_extension = e_web_view_get_web_extension_proxy (web_view);
-       if (web_extension) {
-               g_dbus_proxy_call (
-                       web_extension,
-                       "GetSelectionContentText",
-                       g_variant_new (
-                               "(t)",
-                               webkit_web_view_get_page_id (
-                                       WEBKIT_WEB_VIEW (web_view))),
-                       G_DBUS_CALL_FLAGS_NONE,
-                       -1,
-                       cancellable,
-                       get_selection_content_text_cb,
-                       g_object_ref (task));
-       } else
-               g_task_return_pointer (task, NULL, NULL);
-}
-
-gchar *
-e_web_view_get_selection_content_text_finish (EWebView *web_view,
-                                             GAsyncResult *result,
-                                             GError **error)
-{
-       g_return_val_if_fail (E_IS_WEB_VIEW (web_view), NULL);
-       g_return_val_if_fail (g_task_is_valid (result, web_view), FALSE);
-
-       return g_task_propagate_pointer (G_TASK (result), error);
-}
-
-gchar *
-e_web_view_get_selection_content_text_sync (EWebView *web_view,
-                                           GCancellable *cancellable,
-                                           GError **error)
-{
-       GDBusProxy *web_extension;
-
-       g_return_val_if_fail (E_IS_WEB_VIEW (web_view), NULL);
-
-       web_extension = e_web_view_get_web_extension_proxy (web_view);
-       if (web_extension) {
-               GVariant *result;
-
-               result = e_util_invoke_g_dbus_proxy_call_sync_wrapper_full (
-                               web_extension,
-                               "GetSelectionContentText",
-                               g_variant_new (
-                                       "(t)",
-                                       webkit_web_view_get_page_id (
-                                               WEBKIT_WEB_VIEW (web_view))),
-                               G_DBUS_CALL_FLAGS_NONE,
-                               -1,
-                               cancellable,
-                               error);
-
-               if (result) {
-                       gchar *text_content = NULL;
-
-                       g_variant_get (result, "(s)", &text_content);
-                       g_variant_unref (result);
-                       return text_content;
-               }
-       }
-
-       return NULL;
-}
-
 const gchar *
 e_web_view_get_citation_color_for_level (gint level)
 {
@@ -4013,6 +3592,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 *
@@ -4025,7 +3606,8 @@ e_web_view_get_default_webkit_settings (void)
                "enable-dns-prefetching", FALSE,
                "enable-html5-local-storage", FALSE,
                "enable-java", FALSE,
-               "enable-javascript", FALSE,
+               "enable-javascript", TRUE, /* Needed for JavaScriptCore API to work */
+               "enable-javascript-markup", FALSE, /* Discards user-provided javascript in HTML */
                "enable-offline-web-application-cache", FALSE,
                "enable-page-cache", FALSE,
                "enable-plugins", FALSE,
@@ -4034,6 +3616,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)
 {
@@ -4584,131 +4174,10 @@ e_web_view_request_finish (EWebView *web_view,
 }
 
 /**
- * e_web_view_create_and_add_css_style_sheet:
- * @web_view: an #EWebView
- * @style_sheet_id: CSS style sheet's id
- *
- * Creates new CSS style sheet with given @style_sheel_id and inserts
- * it into given @web_view document.
- **/
-void
-e_web_view_create_and_add_css_style_sheet (EWebView *web_view,
-                                           const gchar *style_sheet_id)
-{
-       guint64 page_id;
-
-       g_return_if_fail (E_IS_WEB_VIEW (web_view));
-       g_return_if_fail (style_sheet_id && *style_sheet_id);
-
-       page_id = webkit_web_view_get_page_id (WEBKIT_WEB_VIEW (web_view));
-
-       e_web_extension_container_call_simple (web_view->priv->container,
-               page_id, web_view->priv->stamp,
-               "CreateAndAddCSSStyleSheet",
-               g_variant_new ("(ts)", page_id, style_sheet_id));
-}
-
-/**
- * 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)
-{
-       guint64 page_id;
-
-       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);
-
-       page_id = webkit_web_view_get_page_id (WEBKIT_WEB_VIEW (web_view));
-
-       e_web_extension_container_call_simple (web_view->priv->container,
-               page_id, web_view->priv->stamp,
-               "AddCSSRuleIntoStyleSheet",
-               g_variant_new ("(tsss)", page_id, style_sheet_id, selector, style));
-}
-
-/**
- * e_web_view_get_document_uri_from_point:
- * @web_view: an #EWebView
- * @x: x-coordinate
- * @y: y-coordinate
- *
- * Returns: A document URI which is under the @x, @y coordinates or %NULL,
- * if there is none. Free the returned pointer with g_free() when done with it.
- *
- * Since: 3.22
- **/
-gchar *
-e_web_view_get_document_uri_from_point (EWebView *web_view,
-                                       gint32 x,
-                                       gint32 y)
-{
-       GDBusProxy *web_extension;
-       GVariant *result;
-       GError *local_error = NULL;
-
-       g_return_val_if_fail (E_IS_WEB_VIEW (web_view), NULL);
-
-       web_extension = e_web_view_get_web_extension_proxy (web_view);
-       if (!web_extension)
-               return NULL;
-
-       result = e_util_invoke_g_dbus_proxy_call_sync_wrapper_full (
-               web_extension,
-               "GetDocumentURIFromPoint",
-               g_variant_new (
-                       "(tii)",
-                       webkit_web_view_get_page_id (WEBKIT_WEB_VIEW (web_view)),
-                       x,
-                       y),
-               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, "GetDocumentURIFromPoint", local_error);
-       g_clear_error (&local_error);
-
-       if (result) {
-               gchar *uri = NULL;
-
-               g_variant_get (result, "(s)", &uri);
-               g_variant_unref (result);
-
-               if (g_strcmp0 (uri, "") == 0) {
-                       g_free (uri);
-                       uri = NULL;
-               }
-
-               return uri;
-       }
-
-       return NULL;
-}
-
-/**
- * e_web_view_set_document_iframe_src:
+ * e_web_view_set_iframe_src:
  * @web_view: an #EWebView
  * @document_uri: a document URI for whose IFrame change the source
- * @new_iframe_src: the source to change the IFrame to
+ * @src_uri: the source to change the IFrame to
  *
  * Change IFrame source for the given @document_uri IFrame
  * to the @new_iframe_src.
@@ -4716,29 +4185,22 @@ e_web_view_get_document_uri_from_point (EWebView *web_view,
  * Since: 3.22
  **/
 void
-e_web_view_set_document_iframe_src (EWebView *web_view,
-                                   const gchar *document_uri,
-                                   const gchar *new_iframe_src)
+e_web_view_set_iframe_src (EWebView *web_view,
+                          const gchar *iframe_id,
+                          const gchar *src_uri)
 {
-       guint64 page_id;
-
        g_return_if_fail (E_IS_WEB_VIEW (web_view));
 
-       /* Cannot call this synchronously, blocking the local main loop, because the reload
-          can on the WebProcess side can be asking for a redirection policy, waiting
-          for a response which may be waiting in the blocked main loop. */
-
-       page_id = webkit_web_view_get_page_id (WEBKIT_WEB_VIEW (web_view));
-
-       e_web_extension_container_call_simple (web_view->priv->container,
-               page_id, web_view->priv->stamp,
-               "SetDocumentIFrameSrc",
-               g_variant_new ("(tss)", page_id, document_uri, new_iframe_src));
+       e_web_view_jsc_run_script (WEBKIT_WEB_VIEW (web_view), web_view->priv->cancellable,
+               "Evo.SetIFrameSrc(%s, %s);",
+               iframe_id, src_uri);
 }
 
 /**
  * EWebViewElementClickedFunc:
  * @web_view: an #EWebView
+ * @iframe_id: an iframe ID in which the click happened; empty string for the main frame
+ * @element_id: an element ID
  * @element_class: an element class, as set on the element which had been clicked
  * @element_value: a 'value' attribute content of the clicked element
  * @element_position: a #GtkAllocation with the position of the clicked element
@@ -4790,7 +4252,7 @@ e_web_view_register_element_clicked (EWebView *web_view,
                        if (ecd && ecd->callback == callback && ecd->user_data == user_data) {
                                /* Callback is already registered, but re-register it, in case the page
                                   was changed dynamically and new elements with the given call are added. */
-                               web_view_register_element_clicked_hfunc ((gpointer) element_class, cbs, 
web_view);
+                               web_view_call_register_element_clicked (web_view, "*", element_class);
                                return;
                        }
                }
@@ -4810,7 +4272,7 @@ e_web_view_register_element_clicked (EWebView *web_view,
        }
 
        /* Dynamically changing page can call this multiple times; re-register all classes */
-       g_hash_table_foreach (web_view->priv->element_clicked_cbs, web_view_register_element_clicked_hfunc, 
web_view);
+       web_view_call_register_element_clicked (web_view, "*", NULL);
 }
 
 /**
@@ -4862,38 +4324,27 @@ e_web_view_set_element_hidden (EWebView *web_view,
                               const gchar *element_id,
                               gboolean hidden)
 {
-       guint64 page_id;
-
        g_return_if_fail (E_IS_WEB_VIEW (web_view));
        g_return_if_fail (element_id && *element_id);
 
-       page_id = webkit_web_view_get_page_id (WEBKIT_WEB_VIEW (web_view));
-
-       e_web_extension_container_call_simple (web_view->priv->container,
-               page_id, web_view->priv->stamp,
-               "SetElementHidden",
-               g_variant_new ("(tsb)", page_id, element_id, hidden));
+       e_web_view_jsc_set_element_hidden (WEBKIT_WEB_VIEW (web_view),
+               "*", element_id, hidden,
+               web_view->priv->cancellable);
 }
 
 void
 e_web_view_set_element_style_property (EWebView *web_view,
                                       const gchar *element_id,
                                       const gchar *property_name,
-                                      const gchar *value,
-                                      const gchar *priority)
+                                      const gchar *value)
 {
-       guint64 page_id;
-
        g_return_if_fail (E_IS_WEB_VIEW (web_view));
        g_return_if_fail (element_id && *element_id);
        g_return_if_fail (property_name && *property_name);
 
-       page_id = webkit_web_view_get_page_id (WEBKIT_WEB_VIEW (web_view));
-
-       e_web_extension_container_call_simple (web_view->priv->container,
-               page_id, web_view->priv->stamp,
-               "SetElementStyleProperty",
-               g_variant_new ("(tssss)", page_id, element_id, property_name, value ? value : "", priority ? 
priority : ""));
+       e_web_view_jsc_set_element_style_property (WEBKIT_WEB_VIEW (web_view),
+               "*", element_id, property_name, value,
+               web_view->priv->cancellable);
 }
 
 void
@@ -4903,16 +4354,11 @@ e_web_view_set_element_attribute (EWebView *web_view,
                                  const gchar *qualified_name,
                                  const gchar *value)
 {
-       guint64 page_id;
-
        g_return_if_fail (E_IS_WEB_VIEW (web_view));
        g_return_if_fail (element_id && *element_id);
        g_return_if_fail (qualified_name && *qualified_name);
 
-       page_id = webkit_web_view_get_page_id (WEBKIT_WEB_VIEW (web_view));
-
-       e_web_extension_container_call_simple (web_view->priv->container,
-               page_id, web_view->priv->stamp,
-               "SetElementAttribute",
-               g_variant_new ("(tssss)", page_id, element_id, namespace_uri ? namespace_uri : "", 
qualified_name, value ? value : ""));
+       e_web_view_jsc_set_element_attribute (WEBKIT_WEB_VIEW (web_view),
+               "*", element_id, namespace_uri, qualified_name, value,
+               web_view->priv->cancellable);
 }
diff --git a/src/e-util/e-web-view.h b/src/e-util/e-web-view.h
index 474140dfb6..8f403df411 100644
--- a/src/e-util/e-web-view.h
+++ b/src/e-util/e-web-view.h
@@ -67,6 +67,8 @@ typedef enum {
 } EURIScheme;
 
 typedef void (*EWebViewElementClickedFunc) (EWebView *web_view,
+                                           const gchar *iframe_id,
+                                           const gchar *element_id,
                                            const gchar *element_class,
                                            const gchar *element_value,
                                            const GtkAllocation *element_position,
@@ -111,6 +113,13 @@ struct _EWebViewClass {
        void            (*uri_requested)        (EWebView *web_view,
                                                 const gchar *uri,
                                                 gchar **redirect_to_uri);
+       void            (*content_loaded)       (EWebView *web_view,
+                                                const gchar *frame_id);
+       void            (*before_popup_event)   (EWebView *web_view,
+                                                const gchar *uri);
+
+       /* Padding for future expansion */
+       gpointer reserved[15];
 };
 
 GType          e_web_view_get_type             (void) G_GNUC_CONST;
@@ -118,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,
@@ -136,20 +146,6 @@ void               e_web_view_load_uri             (EWebView *web_view,
 gchar *                e_web_view_suggest_filename     (EWebView *web_view,
                                                 const gchar *uri);
 void           e_web_view_reload               (EWebView *web_view);
-void           e_web_view_get_content_html     (EWebView *web_view,
-                                                GCancellable *cancellable,
-                                                GAsyncReadyCallback callback,
-                                                gpointer user_data);
-gchar *                e_web_view_get_content_html_finish
-                                               (EWebView *web_view,
-                                                GAsyncResult *result,
-                                                GError **error);
-gchar *                e_web_view_get_content_html_sync
-                                               (EWebView *web_view,
-                                                GCancellable *cancellable,
-                                                GError **error);
-GDBusProxy *   e_web_view_get_web_extension_proxy
-                                               (EWebView *web_view);
 gboolean       e_web_view_get_caret_mode       (EWebView *web_view);
 void           e_web_view_set_caret_mode       (EWebView *web_view,
                                                 gboolean caret_mode);
@@ -165,12 +161,7 @@ void               e_web_view_set_disable_save_to_disk
 gboolean       e_web_view_get_editable         (EWebView *web_view);
 void           e_web_view_set_editable         (EWebView *web_view,
                                                 gboolean editable);
-guint32                e_web_view_get_clipboard_flags  (EWebView *web_view);
-void           e_web_view_set_clipboard_flags  (EWebView *web_view,
-                                                guint32 clipboard_flags);
 gboolean       e_web_view_get_need_input       (EWebView *web_view);
-void           e_web_view_set_need_input       (EWebView *web_view,
-                                                gboolean need_input);
 gboolean       e_web_view_get_inline_spelling  (EWebView *web_view);
 void           e_web_view_set_inline_spelling  (EWebView *web_view,
                                                 gboolean inline_spelling);
@@ -197,6 +188,11 @@ void               e_web_view_set_print_proxy      (EWebView *web_view,
 GtkAction *    e_web_view_get_save_as_proxy    (EWebView *web_view);
 void           e_web_view_set_save_as_proxy    (EWebView *web_view,
                                                 GtkAction *save_as_proxy);
+void           e_web_view_get_last_popup_place (EWebView *web_view,
+                                                gchar **out_iframe_src,
+                                                gchar **out_iframe_id,
+                                                gchar **out_element_id,
+                                                gchar **out_link_uri);
 void           e_web_view_add_highlight        (EWebView *web_view,
                                                 const gchar *highlight);
 void           e_web_view_clear_highlights     (EWebView *web_view);
@@ -207,7 +203,7 @@ GtkActionGroup *e_web_view_get_action_group (EWebView *web_view,
                                                 const gchar *group_name);
 void           e_web_view_copy_clipboard       (EWebView *web_view);
 void           e_web_view_cut_clipboard        (EWebView *web_view);
-gboolean       e_web_view_is_selection_active  (EWebView *web_view);
+gboolean       e_web_view_has_selection        (EWebView *web_view);
 void           e_web_view_paste_clipboard      (EWebView *web_view);
 gboolean       e_web_view_scroll_forward       (EWebView *web_view);
 gboolean       e_web_view_scroll_backward      (EWebView *web_view);
@@ -225,32 +221,6 @@ void               e_web_view_status_message       (EWebView *web_view,
                                                 const gchar *status_message);
 void           e_web_view_stop_loading         (EWebView *web_view);
 void           e_web_view_update_actions       (EWebView *web_view);
-void           e_web_view_get_selection_content_html
-                                               (EWebView *web_view,
-                                                GCancellable *cancellable,
-                                                GAsyncReadyCallback callback,
-                                                gpointer user_data);
-gchar *                e_web_view_get_selection_content_html_finish
-                                               (EWebView *web_view,
-                                                GAsyncResult *result,
-                                                GError **error);
-gchar *                e_web_view_get_selection_content_html_sync
-                                               (EWebView *web_view,
-                                                GCancellable *cancellable,
-                                                GError **error);
-void           e_web_view_get_selection_content_text
-                                               (EWebView *web_view,
-                                                GCancellable *cancellable,
-                                                GAsyncReadyCallback callback,
-                                                gpointer user_data);
-gchar *                e_web_view_get_selection_content_text_finish
-                                               (EWebView *web_view,
-                                                GAsyncResult *result,
-                                                GError **error);
-gchar *                e_web_view_get_selection_content_text_sync
-                                               (EWebView *web_view,
-                                                GCancellable *cancellable,
-                                                GError **error);
 void           e_web_view_update_fonts         (EWebView *web_view);
 void           e_web_view_cursor_image_copy    (EWebView *web_view);
 void           e_web_view_cursor_image_save    (EWebView *web_view);
@@ -265,24 +235,11 @@ 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_create_and_add_css_style_sheet
-                                               (EWebView *web_view,
-                                                const gchar *style_sheet_id);
-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);
-gchar *                e_web_view_get_document_uri_from_point
-                                               (EWebView *web_view,
-                                                gint32 x,
-                                                gint32 y);
-void           e_web_view_set_document_iframe_src
-                                               (EWebView *web_view,
-                                                const gchar *document_uri,
-                                                const gchar *new_iframe_src);
+void           e_web_view_set_iframe_src       (EWebView *web_view,
+                                                const gchar *iframe_id,
+                                                const gchar *new_src);
 void           e_web_view_register_element_clicked
                                                (EWebView *web_view,
                                                 const gchar *element_class,
@@ -300,8 +257,7 @@ void                e_web_view_set_element_style_property
                                                (EWebView *web_view,
                                                 const gchar *element_id,
                                                 const gchar *property_name,
-                                                const gchar *value,
-                                                const gchar *priority);
+                                                const gchar *value);
 void           e_web_view_set_element_attribute
                                                (EWebView *web_view,
                                                 const gchar *element_id,
diff --git a/src/e-util/e-win32-reloc.c b/src/e-util/e-win32-reloc.c
index 9a729058b8..dbc7434b06 100644
--- a/src/e-util/e-win32-reloc.c
+++ b/src/e-util/e-win32-reloc.c
@@ -52,6 +52,7 @@ static const gchar *sounddir;
 static const gchar *sysconfdir;
 static const gchar *toolsdir;
 static const gchar *uidir;
+static const gchar *webkitdatadir;
 
 static HMODULE hmodule;
 G_LOCK_DEFINE_STATIC (mutex);
@@ -130,6 +131,11 @@ setup (void)
                imagesdir = g_getenv ("EVOLUTION_IMAGESDIR");
        else
                imagesdir = replace_prefix (full_prefix, EVOLUTION_IMAGESDIR);
+       if (g_getenv ("EVOLUTION_WEBKITDATADIR") &&
+           g_file_test (g_getenv ("EVOLUTION_WEBKITDATADIR"), G_FILE_TEST_IS_DIR))
+               webkitdatadir = g_getenv ("EVOLUTION_WEBKITDATADIR");
+       else
+               webkitdatadir = replace_prefix (full_prefix, EVOLUTION_WEBKITDATADIR);
        libdir = replace_prefix (full_prefix, EVOLUTION_LIBDIR);
        libexecdir = replace_prefix (full_prefix, EVOLUTION_LIBEXECDIR);
        moduledir = replace_prefix (full_prefix, EVOLUTION_MODULEDIR);
@@ -176,6 +182,7 @@ GETTER(sounddir)
 GETTER(sysconfdir)
 GETTER(toolsdir)
 GETTER(uidir)
+GETTER(webkitdatadir)
 
 gpointer _e_get_dll_hmodule (void)
 {
diff --git a/src/e-util/test-web-view-jsc.c b/src/e-util/test-web-view-jsc.c
new file mode 100644
index 0000000000..f5dbdc43ca
--- /dev/null
+++ b/src/e-util/test-web-view-jsc.c
@@ -0,0 +1,1955 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2019 Red Hat (www.redhat.com)
+ *
+ * This library is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "evolution-config.h"
+
+#include <glib.h>
+#include <glib/gstdio.h>
+
+#include <locale.h>
+#include <e-util/e-util.h>
+
+enum {
+       LOAD_ALL = -1,
+       LOAD_MAIN = 0,
+       LOAD_FRM1 = 1,
+       LOAD_FRM1_1 = 2,
+       LOAD_FRM2 = 3
+};
+
+typedef struct _TestFlagClass {
+       GObjectClass parent_class;
+} TestFlagClass;
+
+typedef struct _TestFlag {
+       GObject parent;
+       gboolean is_set;
+} TestFlag;
+
+GType test_flag_get_type (void);
+
+G_DEFINE_TYPE (TestFlag, test_flag, G_TYPE_OBJECT)
+
+enum {
+       FLAGGED,
+       LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL];
+
+static void
+test_flag_class_init (TestFlagClass *klass)
+{
+       signals[FLAGGED] = g_signal_new (
+               "flagged",
+               G_TYPE_FROM_CLASS (klass),
+               G_SIGNAL_RUN_LAST,
+               0,
+               NULL, NULL, NULL,
+               G_TYPE_NONE, 0,
+               G_TYPE_NONE);
+}
+
+static void
+test_flag_init (TestFlag *flag)
+{
+       flag->is_set = FALSE;
+}
+
+static void
+test_flag_set (TestFlag *flag)
+{
+       flag->is_set = TRUE;
+
+       g_signal_emit (flag, signals[FLAGGED], 0, NULL);
+}
+
+typedef struct _TestFixture {
+       GtkWidget *window;
+       WebKitWebView *web_view;
+
+       TestFlag *flag;
+} TestFixture;
+
+typedef void (* ETestFixtureSimpleFunc) (TestFixture *fixture);
+
+/* The tests do not use the 'user_data' argument, thus the functions avoid them and the typecast is needed. 
*/
+typedef void (* ETestFixtureFunc) (TestFixture *fixture, gconstpointer user_data);
+
+static gboolean
+window_key_press_event_cb (GtkWindow *window,
+                          GdkEventKey *event,
+                          gpointer user_data)
+{
+       WebKitWebView *web_view = user_data;
+       WebKitWebInspector *inspector;
+       gboolean handled = FALSE;
+
+       inspector = webkit_web_view_get_inspector (web_view);
+
+       if ((event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK)) == (GDK_CONTROL_MASK | GDK_SHIFT_MASK) &&
+           event->keyval == GDK_KEY_I) {
+               webkit_web_inspector_show (inspector);
+               handled = TRUE;
+       }
+
+       return handled;
+}
+
+static gboolean
+window_delete_event_cb (GtkWidget *widget,
+                       GdkEvent *event,
+                       gpointer user_data)
+{
+       TestFixture *fixture = user_data;
+
+       gtk_widget_destroy (fixture->window);
+       fixture->window = NULL;
+       fixture->web_view = NULL;
+
+       test_flag_set (fixture->flag);
+
+       return TRUE;
+}
+
+static void
+test_utils_fixture_set_up (TestFixture *fixture,
+                          gconstpointer user_data)
+{
+       WebKitSettings *settings;
+
+       fixture->window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+
+       gtk_window_set_default_size (GTK_WINDOW (fixture->window), 320, 240);
+
+       fixture->web_view = WEBKIT_WEB_VIEW (e_web_view_new ());
+       g_object_set (G_OBJECT (fixture->web_view),
+               "halign", GTK_ALIGN_FILL,
+               "hexpand", TRUE,
+               "valign", GTK_ALIGN_FILL,
+               "vexpand", TRUE,
+               NULL);
+
+       gtk_container_add (GTK_CONTAINER (fixture->window), GTK_WIDGET (fixture->web_view));
+
+       settings = webkit_web_view_get_settings (fixture->web_view);
+       webkit_settings_set_enable_developer_extras (settings, TRUE);
+
+       g_signal_connect (
+               fixture->window, "key-press-event",
+               G_CALLBACK (window_key_press_event_cb), fixture->web_view);
+
+       g_signal_connect (
+               fixture->window, "delete-event",
+               G_CALLBACK (window_delete_event_cb), fixture);
+
+       gtk_widget_show_all (fixture->window);
+
+       fixture->flag = g_object_new (test_flag_get_type (), NULL);
+}
+
+static void
+test_utils_fixture_tear_down (TestFixture *fixture,
+                             gconstpointer user_data)
+{
+       if (fixture->window) {
+               gtk_widget_destroy (fixture->window);
+               fixture->web_view = NULL;
+       }
+
+       g_clear_object (&fixture->flag);
+}
+
+static void
+test_utils_add_test (const gchar *name,
+                    ETestFixtureSimpleFunc func)
+{
+       g_test_add (name, TestFixture, NULL,
+               test_utils_fixture_set_up, (ETestFixtureFunc) func, test_utils_fixture_tear_down);
+}
+
+static void
+test_utils_wait (TestFixture *fixture)
+{
+       GMainLoop *loop;
+       gulong handler_id;
+
+       g_return_if_fail (fixture != NULL);
+       g_return_if_fail (fixture->window != NULL);
+       g_return_if_fail (fixture->flag != NULL);
+
+       if (fixture->flag->is_set) {
+               fixture->flag->is_set = FALSE;
+               return;
+       }
+
+       loop = g_main_loop_new (NULL, FALSE);
+
+       handler_id = g_signal_connect_swapped (fixture->flag, "flagged", G_CALLBACK (g_main_loop_quit), loop);
+
+       g_main_loop_run (loop);
+       g_main_loop_unref (loop);
+
+       g_signal_handler_disconnect (fixture->flag, handler_id);
+
+       fixture->flag->is_set = FALSE;
+}
+
+static void
+test_utils_jsc_call_done_cb (GObject *source_object,
+                            GAsyncResult *result,
+                            gpointer user_data)
+{
+       gchar *script = user_data;
+       WebKitJavascriptResult *js_result;
+       GError *error = NULL;
+
+       g_return_if_fail (script != NULL);
+
+       js_result = webkit_web_view_run_javascript_finish (WEBKIT_WEB_VIEW (source_object), result, &error);
+
+       if (error) {
+               if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED) &&
+                   (!g_error_matches (error, WEBKIT_JAVASCRIPT_ERROR, WEBKIT_JAVASCRIPT_ERROR_SCRIPT_FAILED) 
||
+                    /* WebKit can return empty error message, thus ignore those. */
+                    (error->message && *(error->message))))
+                       g_warning ("Failed to call '%s' function: %s", script, error->message);
+               g_clear_error (&error);
+       }
+
+       if (js_result) {
+               JSCException *exception;
+               JSCValue *value;
+
+               value = webkit_javascript_result_get_js_value (js_result);
+               exception = jsc_context_get_exception (jsc_value_get_context (value));
+
+               if (exception)
+                       g_warning ("Failed to call '%s': %s", script, jsc_exception_get_message (exception));
+
+               webkit_javascript_result_unref (js_result);
+       }
+
+       g_free (script);
+}
+
+typedef struct _JSCCallData {
+       TestFixture *fixture;
+       const gchar *script;
+       JSCValue **out_result;
+} JSCCallData;
+
+static void
+test_utils_jsc_call_sync_done_cb (GObject *source_object,
+                                 GAsyncResult *result,
+                                 gpointer user_data)
+{
+       JSCCallData *jcd = user_data;
+       WebKitJavascriptResult *js_result;
+       GError *error = NULL;
+
+       g_return_if_fail (jcd != NULL);
+
+       js_result = webkit_web_view_run_javascript_finish (WEBKIT_WEB_VIEW (source_object), result, &error);
+
+       if (error) {
+               if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED) &&
+                   (!g_error_matches (error, WEBKIT_JAVASCRIPT_ERROR, WEBKIT_JAVASCRIPT_ERROR_SCRIPT_FAILED) 
||
+                    /* WebKit can return empty error message, thus ignore those. */
+                    (error->message && *(error->message))))
+                       g_warning ("Failed to call '%s': %s", jcd->script, error->message);
+               g_clear_error (&error);
+       }
+
+       if (js_result) {
+               JSCException *exception;
+               JSCValue *value;
+
+               value = webkit_javascript_result_get_js_value (js_result);
+               exception = jsc_context_get_exception (jsc_value_get_context (value));
+
+               if (exception)
+                       g_warning ("Failed to call '%s': %s", jcd->script, jsc_exception_get_message 
(exception));
+               else if (jcd->out_result)
+                       *(jcd->out_result) = value ? g_object_ref (value) : NULL;
+
+               webkit_javascript_result_unref (js_result);
+       }
+
+       test_flag_set (jcd->fixture->flag);
+}
+
+static void
+test_utils_jsc_call (TestFixture *fixture,
+                    const gchar *script)
+{
+       g_return_if_fail (fixture != NULL);
+       g_return_if_fail (fixture->web_view != NULL);
+       g_return_if_fail (script != NULL);
+
+       webkit_web_view_run_javascript (fixture->web_view, script, NULL, test_utils_jsc_call_done_cb, 
g_strdup (script));
+}
+
+static void
+test_utils_jsc_call_sync (TestFixture *fixture,
+                         const gchar *script,
+                         JSCValue **out_result)
+{
+       JSCCallData jcd;
+
+       g_return_if_fail (fixture != NULL);
+       g_return_if_fail (fixture->web_view != NULL);
+       g_return_if_fail (script != NULL);
+
+       if (out_result)
+               *out_result = NULL;
+
+       jcd.fixture = fixture;
+       jcd.script = script;
+       jcd.out_result = out_result;
+
+       webkit_web_view_run_javascript (fixture->web_view, script, NULL, test_utils_jsc_call_sync_done_cb, 
&jcd);
+
+       test_utils_wait (fixture);
+}
+
+static gboolean
+test_utils_jsc_call_bool_sync (TestFixture *fixture,
+                              const gchar *script)
+{
+       JSCValue *result = NULL;
+       gboolean res;
+
+       test_utils_jsc_call_sync (fixture, script, &result);
+
+       g_assert_nonnull (result);
+       g_assert (jsc_value_is_boolean (result));
+
+       res = jsc_value_to_boolean (result);
+
+       g_clear_object (&result);
+
+       return res;
+}
+
+static gint32
+test_utils_jsc_call_int32_sync (TestFixture *fixture,
+                               const gchar *script)
+{
+       JSCValue *result = NULL;
+       gint32 res;
+
+       test_utils_jsc_call_sync (fixture, script, &result);
+
+       g_assert_nonnull (result);
+       g_assert (jsc_value_is_number (result));
+
+       res = jsc_value_to_int32 (result);
+
+       g_clear_object (&result);
+
+       return res;
+}
+
+static gchar *
+test_utils_jsc_call_string_sync (TestFixture *fixture,
+                                const gchar *script)
+{
+       JSCValue *result = NULL;
+       gchar *res;
+
+       test_utils_jsc_call_sync (fixture, script, &result);
+
+       g_assert_nonnull (result);
+       g_assert (jsc_value_is_null (result) || jsc_value_is_string (result));
+
+       if (jsc_value_is_null (result))
+               res = NULL;
+       else
+               res = jsc_value_to_string (result);
+
+       g_clear_object (&result);
+
+       return res;
+}
+
+static void
+test_utils_jsc_call_string_and_verify (TestFixture *fixture,
+                                      const gchar *script,
+                                      const gchar *expected_value)
+{
+       gchar *value;
+
+       value = test_utils_jsc_call_string_sync (fixture, script);
+
+       g_assert_cmpstr (value, ==, expected_value);
+
+       g_free (value);
+}
+
+static void
+test_utils_wait_noop (TestFixture *fixture)
+{
+       test_utils_jsc_call_sync (fixture, "javascript:void(0);", NULL);
+}
+
+static void
+test_utils_iframe_loaded_cb (EWebView *web_view,
+                            const gchar *iframe_id,
+                            gpointer user_data)
+{
+       TestFixture *fixture = user_data;
+
+       g_return_if_fail (fixture != NULL);
+
+       test_flag_set (fixture->flag);
+}
+
+static void
+test_utils_load_iframe_content (TestFixture *fixture,
+                               const gchar *iframe_id,
+                               const gchar *content)
+{
+       gchar *script;
+       gulong handler_id;
+
+       handler_id = g_signal_connect (fixture->web_view, "content-loaded",
+               G_CALLBACK (test_utils_iframe_loaded_cb), fixture);
+
+       script = e_web_view_jsc_printf_script ("Evo.SetIFrameContent(%s,%s)", iframe_id, content);
+
+       test_utils_jsc_call (fixture, script);
+
+       g_free (script);
+
+       test_utils_wait (fixture);
+
+       g_signal_handler_disconnect (fixture->web_view, handler_id);
+
+       test_utils_wait_noop (fixture);
+}
+
+static void
+load_changed_cb (WebKitWebView *web_view,
+                WebKitLoadEvent load_event,
+                gpointer user_data)
+{
+       TestFixture *fixture = user_data;
+
+       g_return_if_fail (fixture != NULL);
+
+       if (load_event == WEBKIT_LOAD_FINISHED)
+               test_flag_set (fixture->flag);
+}
+
+static void
+test_utils_load_string (TestFixture *fixture,
+                       const gchar *content)
+{
+       gulong handler_id;
+
+       handler_id = g_signal_connect (fixture->web_view, "load-changed",
+               G_CALLBACK (load_changed_cb), fixture);
+
+       e_web_view_load_string (E_WEB_VIEW (fixture->web_view), content);
+
+       test_utils_wait (fixture);
+
+       g_signal_handler_disconnect (fixture->web_view, handler_id);
+
+       test_utils_wait_noop (fixture);
+}
+
+static void
+test_utils_load_body (TestFixture *fixture,
+                     gint index)
+{
+       if (index == LOAD_MAIN || index == LOAD_ALL) {
+               test_utils_load_string (fixture,
+                       "<html><body>"
+                       "Top<br>"
+                       "<input id=\"btn1\" class=\"cbtn1\" type=\"button\" value=\"Button1\"><br>"
+                       "<input id=\"chk1\" class=\"cchk1\" type=\"checkbox\" value=\"Check1\">"
+                       "<iframe id=\"frm1\" src=\"empty:///frm1\"></iframe><br>"
+                       "<iframe id=\"frm2\" src=\"empty:///frm2\"></iframe><br>"
+                       "<input id=\"btn3\" class=\"cbtn3\" type=\"button\" value=\"Button3\">"
+                       "<a name=\"dots\" id=\"dots1\" class=\"cdots\">...</a>"
+                       "</body></html>");
+       }
+
+       if (index == LOAD_FRM1 || index == LOAD_ALL) {
+               test_utils_load_iframe_content (fixture, "frm1",
+                       "<html><body>"
+                       "frm1<br>"
+                       "<iframe id=\"frm1_1\" src=\"empty:///frm1_1\"></iframe><br>"
+                       "<input id=\"btn1\" class=\"cbtn1\" type=\"button\" value=\"Button1\">"
+                       "</body></html>");
+       }
+
+       if (index == LOAD_FRM1_1 || index == LOAD_ALL) {
+               test_utils_load_iframe_content (fixture, "frm1_1",
+                       "<html><body>"
+                       "frm1_1<br>"
+                       "<input id=\"btn1\" class=\"cbtn1\" type=\"button\" value=\"Button1\">"
+                       "<input id=\"chk1\" class=\"cchk1\" type=\"checkbox\" value=\"Check1\">"
+                       "<a name=\"dots\" id=\"dots2\" class=\"cdots\">...</a>"
+                       "<input id=\"btn2\" class=\"cbtn2\" type=\"button\" value=\"Button2\">"
+                       "</body></html>");
+       }
+
+       if (index == LOAD_FRM2 || index == LOAD_ALL) {
+               test_utils_load_iframe_content (fixture, "frm2",
+                       "<html><body>"
+                       "frm2<br>"
+                       "<input id=\"btn1\" class=\"cbtn1\" type=\"button\" value=\"Button1\">"
+                       "<input id=\"btn2\" class=\"cbtn2\" type=\"button\" value=\"Button2\">"
+                       "<input id=\"chk2\" class=\"cchk2\" type=\"checkbox\" value=\"Check2\">"
+                       "</body></html>");
+       }
+}
+
+static void
+test_jsc_object_properties (TestFixture *fixture)
+{
+       JSCValue *jsc_object = NULL;
+       gchar *str;
+
+       str = e_web_view_jsc_printf_script (
+               "test_obj_props = function()\n"
+               "{\n"
+               "       var arrobj = [];\n"
+               "       arrobj[\"btrue\"] = true;\n"
+               "       arrobj[\"bfalse\"] = false;\n"
+               "       arrobj[\"i2\"] = 2;\n"
+               "       arrobj[\"i67890\"] = 67890;\n"
+               "       arrobj[\"i-12345\"] = -12345;\n"
+               "       arrobj[\"d-54.32\"] = -54.32;\n"
+               "       arrobj[\"d67.89\"] = 67.89;\n"
+               "       arrobj[\"s-it\"] = \"it\";\n"
+               "       arrobj[\"s-Is\"] = \"Is\";\n"
+               "       return arrobj;\n"
+               "}\n"
+               "test_obj_props();\n");
+
+       test_utils_jsc_call_sync (fixture, str, &jsc_object);
+
+       g_free (str);
+
+       g_assert_nonnull (jsc_object);
+       g_assert (jsc_value_is_object (jsc_object));
+
+       g_assert (e_web_view_jsc_get_object_property_boolean (jsc_object, "btrue", FALSE));
+       g_assert (!e_web_view_jsc_get_object_property_boolean (jsc_object, "bfalse", TRUE));
+       g_assert (!e_web_view_jsc_get_object_property_boolean (jsc_object, "budenfined", FALSE));
+       g_assert (e_web_view_jsc_get_object_property_boolean (jsc_object, "budenfined", TRUE));
+       g_assert_cmpint (e_web_view_jsc_get_object_property_int32 (jsc_object, "i2", 0), ==, 2);
+       g_assert_cmpint (e_web_view_jsc_get_object_property_int32 (jsc_object, "i67890", 0), ==, 67890);
+       g_assert_cmpint (e_web_view_jsc_get_object_property_int32 (jsc_object, "i-12345", 0), ==, -12345);
+       g_assert_cmpint (e_web_view_jsc_get_object_property_int32 (jsc_object, "iundefined", 333), ==, 333);
+       g_assert_cmpfloat (e_web_view_jsc_get_object_property_double (jsc_object, "d-54.32", 0.0), ==, 
-54.32);
+       g_assert_cmpfloat (e_web_view_jsc_get_object_property_double (jsc_object, "d67.89", 0.0), ==, 67.89);
+       g_assert_cmpfloat (e_web_view_jsc_get_object_property_double (jsc_object, "dundefined", 123.456), ==, 
123.456);
+
+       str = e_web_view_jsc_get_object_property_string (jsc_object, "s-it", NULL);
+       g_assert_cmpstr (str, ==, "it");
+       g_free (str);
+
+       str = e_web_view_jsc_get_object_property_string (jsc_object, "s-Is", NULL);
+       g_assert_cmpstr (str, ==, "Is");
+       g_free (str);
+
+       str = e_web_view_jsc_get_object_property_string (jsc_object, "sundefined", "xxx");
+       g_assert_cmpstr (str, ==, "xxx");
+       g_free (str);
+
+       str = e_web_view_jsc_get_object_property_string (jsc_object, "sundefined", NULL);
+       g_assert_null (str);
+
+       g_clear_object (&jsc_object);
+}
+
+static void
+test_set_element_hidden (TestFixture *fixture)
+{
+       test_utils_load_body (fixture, LOAD_ALL);
+
+       g_assert (!test_utils_jsc_call_bool_sync (fixture, "Evo.findElement(\"\", \"btn1\").hidden"));
+       g_assert (!test_utils_jsc_call_bool_sync (fixture, "Evo.findElement(\"\", \"btn3\").hidden"));
+       g_assert (!test_utils_jsc_call_bool_sync (fixture, "Evo.findElement(\"frm1\", \"btn1\").hidden"));
+       g_assert (!test_utils_jsc_call_bool_sync (fixture, "Evo.findElement(\"frm1_1\", \"btn1\").hidden"));
+       g_assert (!test_utils_jsc_call_bool_sync (fixture, "Evo.findElement(\"frm2\", \"btn1\").hidden"));
+       g_assert (!test_utils_jsc_call_bool_sync (fixture, "Evo.findElement(\"frm2\", \"btn2\").hidden"));
+
+       e_web_view_jsc_set_element_hidden (fixture->web_view, "", "btn1", TRUE, NULL);
+       test_utils_wait_noop (fixture);
+
+       g_assert (test_utils_jsc_call_bool_sync (fixture, "Evo.findElement(\"\", \"btn1\").hidden"));
+       g_assert (!test_utils_jsc_call_bool_sync (fixture, "Evo.findElement(\"\", \"btn3\").hidden"));
+       g_assert (!test_utils_jsc_call_bool_sync (fixture, "Evo.findElement(\"frm1\", \"btn1\").hidden"));
+       g_assert (!test_utils_jsc_call_bool_sync (fixture, "Evo.findElement(\"frm1_1\", \"btn1\").hidden"));
+       g_assert (!test_utils_jsc_call_bool_sync (fixture, "Evo.findElement(\"frm2\", \"btn1\").hidden"));
+       g_assert (!test_utils_jsc_call_bool_sync (fixture, "Evo.findElement(\"frm2\", \"btn2\").hidden"));
+
+       e_web_view_jsc_set_element_hidden (fixture->web_view, "frm1_1", "btn1", TRUE, NULL);
+       test_utils_wait_noop (fixture);
+
+       g_assert (test_utils_jsc_call_bool_sync (fixture, "Evo.findElement(\"\", \"btn1\").hidden"));
+       g_assert (!test_utils_jsc_call_bool_sync (fixture, "Evo.findElement(\"\", \"btn3\").hidden"));
+       g_assert (!test_utils_jsc_call_bool_sync (fixture, "Evo.findElement(\"frm1\", \"btn1\").hidden"));
+       g_assert (test_utils_jsc_call_bool_sync (fixture, "Evo.findElement(\"frm1_1\", \"btn1\").hidden"));
+       g_assert (!test_utils_jsc_call_bool_sync (fixture, "Evo.findElement(\"frm2\", \"btn1\").hidden"));
+       g_assert (!test_utils_jsc_call_bool_sync (fixture, "Evo.findElement(\"frm2\", \"btn2\").hidden"));
+
+       e_web_view_jsc_set_element_hidden (fixture->web_view, "frm2", "btn2", TRUE, NULL);
+       test_utils_wait_noop (fixture);
+
+       g_assert (test_utils_jsc_call_bool_sync (fixture, "Evo.findElement(\"\", \"btn1\").hidden"));
+       g_assert (!test_utils_jsc_call_bool_sync (fixture, "Evo.findElement(\"\", \"btn3\").hidden"));
+       g_assert (!test_utils_jsc_call_bool_sync (fixture, "Evo.findElement(\"frm1\", \"btn1\").hidden"));
+       g_assert (test_utils_jsc_call_bool_sync (fixture, "Evo.findElement(\"frm1_1\", \"btn1\").hidden"));
+       g_assert (!test_utils_jsc_call_bool_sync (fixture, "Evo.findElement(\"frm2\", \"btn1\").hidden"));
+       g_assert (test_utils_jsc_call_bool_sync (fixture, "Evo.findElement(\"frm2\", \"btn2\").hidden"));
+
+       e_web_view_jsc_set_element_hidden (fixture->web_view, "", "btn1", FALSE, NULL);
+       test_utils_wait_noop (fixture);
+
+       g_assert (!test_utils_jsc_call_bool_sync (fixture, "Evo.findElement(\"\", \"btn1\").hidden"));
+       g_assert (!test_utils_jsc_call_bool_sync (fixture, "Evo.findElement(\"\", \"btn3\").hidden"));
+       g_assert (!test_utils_jsc_call_bool_sync (fixture, "Evo.findElement(\"frm1\", \"btn1\").hidden"));
+       g_assert (test_utils_jsc_call_bool_sync (fixture, "Evo.findElement(\"frm1_1\", \"btn1\").hidden"));
+       g_assert (!test_utils_jsc_call_bool_sync (fixture, "Evo.findElement(\"frm2\", \"btn1\").hidden"));
+       g_assert (test_utils_jsc_call_bool_sync (fixture, "Evo.findElement(\"frm2\", \"btn2\").hidden"));
+
+       e_web_view_jsc_set_element_hidden (fixture->web_view, "frm2", "btn1", FALSE, NULL);
+       test_utils_wait_noop (fixture);
+
+       g_assert (!test_utils_jsc_call_bool_sync (fixture, "Evo.findElement(\"\", \"btn1\").hidden"));
+       g_assert (!test_utils_jsc_call_bool_sync (fixture, "Evo.findElement(\"\", \"btn3\").hidden"));
+       g_assert (!test_utils_jsc_call_bool_sync (fixture, "Evo.findElement(\"frm1\", \"btn1\").hidden"));
+       g_assert (test_utils_jsc_call_bool_sync (fixture, "Evo.findElement(\"frm1_1\", \"btn1\").hidden"));
+       g_assert (!test_utils_jsc_call_bool_sync (fixture, "Evo.findElement(\"frm2\", \"btn1\").hidden"));
+       g_assert (test_utils_jsc_call_bool_sync (fixture, "Evo.findElement(\"frm2\", \"btn2\").hidden"));
+
+       e_web_view_jsc_set_element_hidden (fixture->web_view, "frm1_1", "btn1", FALSE, NULL);
+       test_utils_wait_noop (fixture);
+
+       g_assert (!test_utils_jsc_call_bool_sync (fixture, "Evo.findElement(\"\", \"btn1\").hidden"));
+       g_assert (!test_utils_jsc_call_bool_sync (fixture, "Evo.findElement(\"\", \"btn3\").hidden"));
+       g_assert (!test_utils_jsc_call_bool_sync (fixture, "Evo.findElement(\"frm1\", \"btn1\").hidden"));
+       g_assert (!test_utils_jsc_call_bool_sync (fixture, "Evo.findElement(\"frm1_1\", \"btn1\").hidden"));
+       g_assert (!test_utils_jsc_call_bool_sync (fixture, "Evo.findElement(\"frm2\", \"btn1\").hidden"));
+       g_assert (test_utils_jsc_call_bool_sync (fixture, "Evo.findElement(\"frm2\", \"btn2\").hidden"));
+}
+
+static void
+test_set_element_disabled (TestFixture *fixture)
+{
+       test_utils_load_body (fixture, LOAD_ALL);
+
+       g_assert (!test_utils_jsc_call_bool_sync (fixture, "Evo.findElement(\"\", \"btn1\").disabled"));
+       g_assert (!test_utils_jsc_call_bool_sync (fixture, "Evo.findElement(\"\", \"btn3\").disabled"));
+       g_assert (!test_utils_jsc_call_bool_sync (fixture, "Evo.findElement(\"frm1\", \"btn1\").disabled"));
+       g_assert (!test_utils_jsc_call_bool_sync (fixture, "Evo.findElement(\"frm1_1\", \"btn1\").disabled"));
+       g_assert (!test_utils_jsc_call_bool_sync (fixture, "Evo.findElement(\"frm2\", \"btn1\").disabled"));
+       g_assert (!test_utils_jsc_call_bool_sync (fixture, "Evo.findElement(\"frm2\", \"btn2\").disabled"));
+
+       e_web_view_jsc_set_element_disabled (fixture->web_view, "", "btn1", TRUE, NULL);
+       test_utils_wait_noop (fixture);
+
+       g_assert (test_utils_jsc_call_bool_sync (fixture, "Evo.findElement(\"\", \"btn1\").disabled"));
+       g_assert (!test_utils_jsc_call_bool_sync (fixture, "Evo.findElement(\"\", \"btn3\").disabled"));
+       g_assert (!test_utils_jsc_call_bool_sync (fixture, "Evo.findElement(\"frm1\", \"btn1\").disabled"));
+       g_assert (!test_utils_jsc_call_bool_sync (fixture, "Evo.findElement(\"frm1_1\", \"btn1\").disabled"));
+       g_assert (!test_utils_jsc_call_bool_sync (fixture, "Evo.findElement(\"frm2\", \"btn1\").disabled"));
+       g_assert (!test_utils_jsc_call_bool_sync (fixture, "Evo.findElement(\"frm2\", \"btn2\").disabled"));
+
+       e_web_view_jsc_set_element_disabled (fixture->web_view, "frm1_1", "btn1", TRUE, NULL);
+       test_utils_wait_noop (fixture);
+
+       g_assert (test_utils_jsc_call_bool_sync (fixture, "Evo.findElement(\"\", \"btn1\").disabled"));
+       g_assert (!test_utils_jsc_call_bool_sync (fixture, "Evo.findElement(\"\", \"btn3\").disabled"));
+       g_assert (!test_utils_jsc_call_bool_sync (fixture, "Evo.findElement(\"frm1\", \"btn1\").disabled"));
+       g_assert (test_utils_jsc_call_bool_sync (fixture, "Evo.findElement(\"frm1_1\", \"btn1\").disabled"));
+       g_assert (!test_utils_jsc_call_bool_sync (fixture, "Evo.findElement(\"frm2\", \"btn1\").disabled"));
+       g_assert (!test_utils_jsc_call_bool_sync (fixture, "Evo.findElement(\"frm2\", \"btn2\").disabled"));
+
+       e_web_view_jsc_set_element_disabled (fixture->web_view, "frm2", "btn2", TRUE, NULL);
+       test_utils_wait_noop (fixture);
+
+       g_assert (test_utils_jsc_call_bool_sync (fixture, "Evo.findElement(\"\", \"btn1\").disabled"));
+       g_assert (!test_utils_jsc_call_bool_sync (fixture, "Evo.findElement(\"\", \"btn3\").disabled"));
+       g_assert (!test_utils_jsc_call_bool_sync (fixture, "Evo.findElement(\"frm1\", \"btn1\").disabled"));
+       g_assert (test_utils_jsc_call_bool_sync (fixture, "Evo.findElement(\"frm1_1\", \"btn1\").disabled"));
+       g_assert (!test_utils_jsc_call_bool_sync (fixture, "Evo.findElement(\"frm2\", \"btn1\").disabled"));
+       g_assert (test_utils_jsc_call_bool_sync (fixture, "Evo.findElement(\"frm2\", \"btn2\").disabled"));
+
+       e_web_view_jsc_set_element_disabled (fixture->web_view, "", "btn1", FALSE, NULL);
+       test_utils_wait_noop (fixture);
+
+       g_assert (!test_utils_jsc_call_bool_sync (fixture, "Evo.findElement(\"\", \"btn1\").disabled"));
+       g_assert (!test_utils_jsc_call_bool_sync (fixture, "Evo.findElement(\"\", \"btn3\").disabled"));
+       g_assert (!test_utils_jsc_call_bool_sync (fixture, "Evo.findElement(\"frm1\", \"btn1\").disabled"));
+       g_assert (test_utils_jsc_call_bool_sync (fixture, "Evo.findElement(\"frm1_1\", \"btn1\").disabled"));
+       g_assert (!test_utils_jsc_call_bool_sync (fixture, "Evo.findElement(\"frm2\", \"btn1\").disabled"));
+       g_assert (test_utils_jsc_call_bool_sync (fixture, "Evo.findElement(\"frm2\", \"btn2\").disabled"));
+
+       e_web_view_jsc_set_element_disabled (fixture->web_view, "frm2", "btn1", FALSE, NULL);
+       test_utils_wait_noop (fixture);
+
+       g_assert (!test_utils_jsc_call_bool_sync (fixture, "Evo.findElement(\"\", \"btn1\").disabled"));
+       g_assert (!test_utils_jsc_call_bool_sync (fixture, "Evo.findElement(\"\", \"btn3\").disabled"));
+       g_assert (!test_utils_jsc_call_bool_sync (fixture, "Evo.findElement(\"frm1\", \"btn1\").disabled"));
+       g_assert (test_utils_jsc_call_bool_sync (fixture, "Evo.findElement(\"frm1_1\", \"btn1\").disabled"));
+       g_assert (!test_utils_jsc_call_bool_sync (fixture, "Evo.findElement(\"frm2\", \"btn1\").disabled"));
+       g_assert (test_utils_jsc_call_bool_sync (fixture, "Evo.findElement(\"frm2\", \"btn2\").disabled"));
+
+       e_web_view_jsc_set_element_disabled (fixture->web_view, "frm1_1", "btn1", FALSE, NULL);
+       test_utils_wait_noop (fixture);
+
+       g_assert (!test_utils_jsc_call_bool_sync (fixture, "Evo.findElement(\"\", \"btn1\").disabled"));
+       g_assert (!test_utils_jsc_call_bool_sync (fixture, "Evo.findElement(\"\", \"btn3\").disabled"));
+       g_assert (!test_utils_jsc_call_bool_sync (fixture, "Evo.findElement(\"frm1\", \"btn1\").disabled"));
+       g_assert (!test_utils_jsc_call_bool_sync (fixture, "Evo.findElement(\"frm1_1\", \"btn1\").disabled"));
+       g_assert (!test_utils_jsc_call_bool_sync (fixture, "Evo.findElement(\"frm2\", \"btn1\").disabled"));
+       g_assert (test_utils_jsc_call_bool_sync (fixture, "Evo.findElement(\"frm2\", \"btn2\").disabled"));
+}
+
+static void
+test_set_element_checked (TestFixture *fixture)
+{
+       test_utils_load_body (fixture, LOAD_ALL);
+
+       g_assert (!test_utils_jsc_call_bool_sync (fixture, "Evo.findElement(\"\", \"chk1\").checked"));
+       g_assert (!test_utils_jsc_call_bool_sync (fixture, "Evo.findElement(\"frm1_1\", \"chk1\").checked"));
+       g_assert (!test_utils_jsc_call_bool_sync (fixture, "Evo.findElement(\"frm2\", \"chk2\").checked"));
+
+       e_web_view_jsc_set_element_checked (fixture->web_view, "", "chk1", TRUE, NULL);
+       test_utils_wait_noop (fixture);
+
+       g_assert (test_utils_jsc_call_bool_sync (fixture, "Evo.findElement(\"\", \"chk1\").checked"));
+       g_assert (!test_utils_jsc_call_bool_sync (fixture, "Evo.findElement(\"frm1_1\", \"chk1\").checked"));
+       g_assert (!test_utils_jsc_call_bool_sync (fixture, "Evo.findElement(\"frm2\", \"chk2\").checked"));
+
+       e_web_view_jsc_set_element_checked (fixture->web_view, "frm1_1", "chk1", TRUE, NULL);
+       test_utils_wait_noop (fixture);
+
+       g_assert (test_utils_jsc_call_bool_sync (fixture, "Evo.findElement(\"\", \"chk1\").checked"));
+       g_assert (test_utils_jsc_call_bool_sync (fixture, "Evo.findElement(\"frm1_1\", \"chk1\").checked"));
+       g_assert (!test_utils_jsc_call_bool_sync (fixture, "Evo.findElement(\"frm2\", \"chk2\").checked"));
+
+       e_web_view_jsc_set_element_checked (fixture->web_view, "", "chk1", FALSE, NULL);
+       test_utils_wait_noop (fixture);
+
+       g_assert (!test_utils_jsc_call_bool_sync (fixture, "Evo.findElement(\"\", \"chk1\").checked"));
+       g_assert (test_utils_jsc_call_bool_sync (fixture, "Evo.findElement(\"frm1_1\", \"chk1\").checked"));
+       g_assert (!test_utils_jsc_call_bool_sync (fixture, "Evo.findElement(\"frm2\", \"chk2\").checked"));
+
+       e_web_view_jsc_set_element_checked (fixture->web_view, "frm2", "chk2", FALSE, NULL);
+       test_utils_wait_noop (fixture);
+
+       g_assert (!test_utils_jsc_call_bool_sync (fixture, "Evo.findElement(\"\", \"chk1\").checked"));
+       g_assert (test_utils_jsc_call_bool_sync (fixture, "Evo.findElement(\"frm1_1\", \"chk1\").checked"));
+       g_assert (!test_utils_jsc_call_bool_sync (fixture, "Evo.findElement(\"frm2\", \"chk2\").checked"));
+
+       e_web_view_jsc_set_element_checked (fixture->web_view, "", "chk1", TRUE, NULL);
+       test_utils_wait_noop (fixture);
+
+       g_assert (test_utils_jsc_call_bool_sync (fixture, "Evo.findElement(\"\", \"chk1\").checked"));
+       g_assert (test_utils_jsc_call_bool_sync (fixture, "Evo.findElement(\"frm1_1\", \"chk1\").checked"));
+       g_assert (!test_utils_jsc_call_bool_sync (fixture, "Evo.findElement(\"frm2\", \"chk2\").checked"));
+
+       e_web_view_jsc_set_element_checked (fixture->web_view, "frm1_1", "chk1", FALSE, NULL);
+       e_web_view_jsc_set_element_checked (fixture->web_view, "frm2", "chk2", TRUE, NULL);
+       test_utils_wait_noop (fixture);
+
+       g_assert (test_utils_jsc_call_bool_sync (fixture, "Evo.findElement(\"\", \"chk1\").checked"));
+       g_assert (!test_utils_jsc_call_bool_sync (fixture, "Evo.findElement(\"frm1_1\", \"chk1\").checked"));
+       g_assert (test_utils_jsc_call_bool_sync (fixture, "Evo.findElement(\"frm2\", \"chk2\").checked"));
+}
+
+static void
+test_set_element_style_property (TestFixture *fixture)
+{
+       test_utils_load_body (fixture, LOAD_ALL);
+
+       test_utils_jsc_call_string_and_verify (fixture, "Evo.findElement(\"\", 
\"btn1\").style.getPropertyValue(\"color\")", "");
+       test_utils_jsc_call_string_and_verify (fixture, "Evo.findElement(\"\", 
\"btn3\").style.getPropertyValue(\"color\")", "");
+       test_utils_jsc_call_string_and_verify (fixture, "Evo.findElement(\"frm1\", 
\"btn1\").style.getPropertyValue(\"color\")", "");
+       test_utils_jsc_call_string_and_verify (fixture, "Evo.findElement(\"frm1_1\", 
\"btn1\").style.getPropertyValue(\"color\")", "");
+       test_utils_jsc_call_string_and_verify (fixture, "Evo.findElement(\"frm2\", 
\"btn1\").style.getPropertyValue(\"color\")", "");
+       test_utils_jsc_call_string_and_verify (fixture, "Evo.findElement(\"frm2\", 
\"btn2\").style.getPropertyValue(\"color\")", "");
+
+       e_web_view_jsc_set_element_style_property (fixture->web_view, "", "btn1", "color", "blue", NULL);
+       test_utils_wait_noop (fixture);
+
+       test_utils_jsc_call_string_and_verify (fixture, "Evo.findElement(\"\", 
\"btn1\").style.getPropertyValue(\"color\")", "blue");
+       test_utils_jsc_call_string_and_verify (fixture, "Evo.findElement(\"\", 
\"btn3\").style.getPropertyValue(\"color\")", "");
+       test_utils_jsc_call_string_and_verify (fixture, "Evo.findElement(\"frm1\", 
\"btn1\").style.getPropertyValue(\"color\")", "");
+       test_utils_jsc_call_string_and_verify (fixture, "Evo.findElement(\"frm1_1\", 
\"btn1\").style.getPropertyValue(\"color\")", "");
+       test_utils_jsc_call_string_and_verify (fixture, "Evo.findElement(\"frm2\", 
\"btn1\").style.getPropertyValue(\"color\")", "");
+       test_utils_jsc_call_string_and_verify (fixture, "Evo.findElement(\"frm2\", 
\"btn2\").style.getPropertyValue(\"color\")", "");
+
+       e_web_view_jsc_set_element_style_property (fixture->web_view, "frm2", "btn1", "color", "green", NULL);
+       test_utils_wait_noop (fixture);
+
+       test_utils_jsc_call_string_and_verify (fixture, "Evo.findElement(\"\", 
\"btn1\").style.getPropertyValue(\"color\")", "blue");
+       test_utils_jsc_call_string_and_verify (fixture, "Evo.findElement(\"\", 
\"btn3\").style.getPropertyValue(\"color\")", "");
+       test_utils_jsc_call_string_and_verify (fixture, "Evo.findElement(\"frm1\", 
\"btn1\").style.getPropertyValue(\"color\")", "");
+       test_utils_jsc_call_string_and_verify (fixture, "Evo.findElement(\"frm1_1\", 
\"btn1\").style.getPropertyValue(\"color\")", "");
+       test_utils_jsc_call_string_and_verify (fixture, "Evo.findElement(\"frm2\", 
\"btn1\").style.getPropertyValue(\"color\")", "green");
+       test_utils_jsc_call_string_and_verify (fixture, "Evo.findElement(\"frm2\", 
\"btn2\").style.getPropertyValue(\"color\")", "");
+
+       e_web_view_jsc_set_element_style_property (fixture->web_view, "frm2", "btn1", "color", NULL, NULL);
+       test_utils_wait_noop (fixture);
+
+       test_utils_jsc_call_string_and_verify (fixture, "Evo.findElement(\"\", 
\"btn1\").style.getPropertyValue(\"color\")", "blue");
+       test_utils_jsc_call_string_and_verify (fixture, "Evo.findElement(\"\", 
\"btn3\").style.getPropertyValue(\"color\")", "");
+       test_utils_jsc_call_string_and_verify (fixture, "Evo.findElement(\"frm1\", 
\"btn1\").style.getPropertyValue(\"color\")", "");
+       test_utils_jsc_call_string_and_verify (fixture, "Evo.findElement(\"frm1_1\", 
\"btn1\").style.getPropertyValue(\"color\")", "");
+       test_utils_jsc_call_string_and_verify (fixture, "Evo.findElement(\"frm2\", 
\"btn1\").style.getPropertyValue(\"color\")", "");
+       test_utils_jsc_call_string_and_verify (fixture, "Evo.findElement(\"frm2\", 
\"btn2\").style.getPropertyValue(\"color\")", "");
+}
+
+static void
+test_set_element_attribute (TestFixture *fixture)
+{
+       test_utils_load_body (fixture, LOAD_ALL);
+
+       test_utils_jsc_call_string_and_verify (fixture, "Evo.findElement(\"\", \"btn1\").getAttributeNS(\"\", 
\"myattr\")", NULL);
+       test_utils_jsc_call_string_and_verify (fixture, "Evo.findElement(\"\", \"btn3\").getAttributeNS(\"\", 
\"myattr\")", NULL);
+       test_utils_jsc_call_string_and_verify (fixture, "Evo.findElement(\"frm1\", 
\"btn1\").getAttributeNS(\"\", \"myattr\")", NULL);
+       test_utils_jsc_call_string_and_verify (fixture, "Evo.findElement(\"frm1_1\", 
\"btn1\").getAttributeNS(\"\", \"myattr\")", NULL);
+       test_utils_jsc_call_string_and_verify (fixture, "Evo.findElement(\"frm2\", 
\"btn1\").getAttributeNS(\"\", \"myattr\")", NULL);
+       test_utils_jsc_call_string_and_verify (fixture, "Evo.findElement(\"frm2\", 
\"btn2\").getAttributeNS(\"\", \"myattr\")", NULL);
+
+       e_web_view_jsc_set_element_attribute (fixture->web_view, "", "btn1", NULL, "myattr", "val1", NULL);
+       test_utils_wait_noop (fixture);
+
+       test_utils_jsc_call_string_and_verify (fixture, "Evo.findElement(\"\", \"btn1\").getAttributeNS(\"\", 
\"myattr\")", "val1");
+       test_utils_jsc_call_string_and_verify (fixture, "Evo.findElement(\"\", \"btn3\").getAttributeNS(\"\", 
\"myattr\")", NULL);
+       test_utils_jsc_call_string_and_verify (fixture, "Evo.findElement(\"frm1\", 
\"btn1\").getAttributeNS(\"\", \"myattr\")", NULL);
+       test_utils_jsc_call_string_and_verify (fixture, "Evo.findElement(\"frm1_1\", 
\"btn1\").getAttributeNS(\"\", \"myattr\")", NULL);
+       test_utils_jsc_call_string_and_verify (fixture, "Evo.findElement(\"frm2\", 
\"btn1\").getAttributeNS(\"\", \"myattr\")", NULL);
+       test_utils_jsc_call_string_and_verify (fixture, "Evo.findElement(\"frm2\", 
\"btn2\").getAttributeNS(\"\", \"myattr\")", NULL);
+
+       e_web_view_jsc_set_element_attribute (fixture->web_view, "frm2", "btn1", NULL, "myattr", "val2", 
NULL);
+       test_utils_wait_noop (fixture);
+
+       test_utils_jsc_call_string_and_verify (fixture, "Evo.findElement(\"\", \"btn1\").getAttributeNS(\"\", 
\"myattr\")", "val1");
+       test_utils_jsc_call_string_and_verify (fixture, "Evo.findElement(\"\", \"btn3\").getAttributeNS(\"\", 
\"myattr\")", NULL);
+       test_utils_jsc_call_string_and_verify (fixture, "Evo.findElement(\"frm1\", 
\"btn1\").getAttributeNS(\"\", \"myattr\")", NULL);
+       test_utils_jsc_call_string_and_verify (fixture, "Evo.findElement(\"frm1_1\", 
\"btn1\").getAttributeNS(\"\", \"myattr\")", NULL);
+       test_utils_jsc_call_string_and_verify (fixture, "Evo.findElement(\"frm2\", 
\"btn1\").getAttributeNS(\"\", \"myattr\")", "val2");
+       test_utils_jsc_call_string_and_verify (fixture, "Evo.findElement(\"frm2\", 
\"btn2\").getAttributeNS(\"\", \"myattr\")", NULL);
+
+       e_web_view_jsc_set_element_attribute (fixture->web_view, "frm2", "btn1", NULL, "myattr", NULL, NULL);
+       test_utils_wait_noop (fixture);
+
+       test_utils_jsc_call_string_and_verify (fixture, "Evo.findElement(\"\", \"btn1\").getAttributeNS(\"\", 
\"myattr\")", "val1");
+       test_utils_jsc_call_string_and_verify (fixture, "Evo.findElement(\"\", \"btn3\").getAttributeNS(\"\", 
\"myattr\")", NULL);
+       test_utils_jsc_call_string_and_verify (fixture, "Evo.findElement(\"frm1\", 
\"btn1\").getAttributeNS(\"\", \"myattr\")", NULL);
+       test_utils_jsc_call_string_and_verify (fixture, "Evo.findElement(\"frm1_1\", 
\"btn1\").getAttributeNS(\"\", \"myattr\")", NULL);
+       test_utils_jsc_call_string_and_verify (fixture, "Evo.findElement(\"frm2\", 
\"btn1\").getAttributeNS(\"\", \"myattr\")", NULL);
+       test_utils_jsc_call_string_and_verify (fixture, "Evo.findElement(\"frm2\", 
\"btn2\").getAttributeNS(\"\", \"myattr\")", NULL);
+}
+
+static void
+test_style_sheets (TestFixture *fixture)
+{
+       test_utils_load_body (fixture, LOAD_ALL);
+
+       test_utils_jsc_call_sync (fixture,
+               "var Test = {};\n"
+               "\n"
+               "Test.nStyles = function(iframe_id)\n"
+               "{\n"
+               "       return 
Evo.findIFrameDocument(iframe_id).head.getElementsByTagName(\"style\").length;\n"
+               "}\n"
+               "\n"
+               "Test.hasStyle = function(iframe_id, style_sheet_id)\n"
+               "{\n"
+               "       var doc = Evo.findIFrameDocument(iframe_id);\n"
+               "       var styles = doc.head.getElementsByTagName(\"style\"), ii;\n"
+               "\n"
+               "       for (ii = styles.length - 1; ii >= 0; ii--) {\n"
+               "               if (styles[ii].id == style_sheet_id) {\n"
+               "                       return true;\n"
+               "               }\n"
+               "       }\n"
+               "       return false;\n"
+               "}\n"
+               "\n"
+               "Test.getStyle = function(iframe_id, style_sheet_id, selector, property_name)\n"
+               "{\n"
+               "       var styles = Evo.findIFrameDocument(iframe_id).head.getElementsByTagName(\"style\"), 
ii;\n"
+               "\n"
+               "       for (ii = 0; ii < styles.length; ii++) {\n"
+               "               if (styles[ii].id == style_sheet_id) {\n"
+               "                       break;\n"
+               "               }\n"
+               "       }\n"
+               "\n"
+               "       if (ii >= styles.length)\n"
+               "               return null;\n"
+               "\n"
+               "       styles = styles[ii].sheet;\n"
+               "\n"
+               "       for (ii = 0; ii < styles.cssRules.length; ii++) {\n"
+               "               if (styles.cssRules[ii].selectorText == selector) {\n"
+               "                       var value = 
styles.cssRules[ii].style.getPropertyValue(property_name);\n"
+               "                       return (!value || value == \"\") ? null : value;\n"
+               "               }\n"
+               "       }\n"
+               "\n"
+               "       return null;\n"
+               "}\n"
+               "\n"
+               "javascript:void(0);\n",
+               NULL);
+
+       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 (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 (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);
+
+       e_web_view_jsc_add_rule_into_style_sheet (fixture->web_view, "frm1_1", "sheet2", "input", 
"background-color:black;", NULL);
+       e_web_view_jsc_add_rule_into_style_sheet (fixture->web_view, "frm1_1", "sheet2", "table", 
"color:green;", NULL);
+       test_utils_wait_noop (fixture);
+
+       g_assert_cmpint (2, ==, 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\")"));
+       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");
+       test_utils_jsc_call_string_and_verify (fixture, "Test.getStyle(\"frm1_1\", \"sheet2\", \"table\", 
\"background-color\")", NULL);
+       test_utils_jsc_call_string_and_verify (fixture, "Test.getStyle(\"\", \"sheet3\", \"body\", 
\"color\")", NULL);
+       test_utils_jsc_call_string_and_verify (fixture, "Test.getStyle(\"frm1\", \"sheet3\", \"body\", 
\"color\")", NULL);
+       test_utils_jsc_call_string_and_verify (fixture, "Test.getStyle(\"frm1_1\", \"sheet3\", \"body\", 
\"color\")", NULL);
+       test_utils_jsc_call_string_and_verify (fixture, "Test.getStyle(\"frm2\", \"sheet3\", \"body\", 
\"color\")", NULL);
+
+       e_web_view_jsc_add_rule_into_style_sheet (fixture->web_view, "*", "sheet3", "body", "color:orange;", 
NULL);
+       e_web_view_jsc_add_rule_into_style_sheet (fixture->web_view, "frm1_1", "sheet2", "table", "color:red; 
background-color:white;", NULL);
+       test_utils_wait_noop (fixture);
+
+       g_assert_cmpint (3, ==, 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 (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");
+       test_utils_jsc_call_string_and_verify (fixture, "Test.getStyle(\"frm1_1\", \"sheet2\", \"table\", 
\"background-color\")", "white");
+       test_utils_jsc_call_string_and_verify (fixture, "Test.getStyle(\"\", \"sheet3\", \"body\", 
\"color\")", "orange");
+       test_utils_jsc_call_string_and_verify (fixture, "Test.getStyle(\"frm1\", \"sheet3\", \"body\", 
\"color\")", "orange");
+       test_utils_jsc_call_string_and_verify (fixture, "Test.getStyle(\"frm1_1\", \"sheet3\", \"body\", 
\"color\")", "orange");
+       test_utils_jsc_call_string_and_verify (fixture, "Test.getStyle(\"frm2\", \"sheet3\", \"body\", 
\"color\")", "orange");
+
+       g_assert_cmpint (0, ==, test_utils_jsc_call_bool_sync (fixture, "Test.hasStyle(\"\", \"sheetA\")") ? 
1 : 0);
+       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);
+
+       e_web_view_jsc_add_rule_into_style_sheet (fixture->web_view, "", "sheetA", "body", "color:blue;", 
NULL);
+       e_web_view_jsc_add_rule_into_style_sheet (fixture->web_view, "frm1", "sheetA", "body", "color:blue;", 
NULL);
+       e_web_view_jsc_add_rule_into_style_sheet (fixture->web_view, "frm1_1", "sheetA", "body", 
"color:blue;", NULL);
+       test_utils_wait_noop (fixture);
+
+       g_assert_cmpint (1, ==, test_utils_jsc_call_bool_sync (fixture, "Test.hasStyle(\"\", \"sheetA\")") ? 
1 : 0);
+       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 (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);
+
+       g_assert_cmpint (1, ==, test_utils_jsc_call_bool_sync (fixture, "Test.hasStyle(\"\", \"sheetA\")") ? 
1 : 0);
+       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 (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);
+
+       g_assert_cmpint (0, ==, test_utils_jsc_call_bool_sync (fixture, "Test.hasStyle(\"\", \"sheetA\")") ? 
1 : 0);
+       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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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\")"));
+}
+
+typedef struct _ElementClickedData {
+       TestFixture *fixture;
+       const gchar *iframe_id;
+       const gchar *element_id;
+       const gchar *element_class;
+       const gchar *element_value;
+} ElementClickedData;
+
+static void
+test_verify_element_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)
+{
+       ElementClickedData *expects = user_data;
+
+       g_assert_nonnull (expects);
+       g_assert_cmpstr (iframe_id, ==, expects->iframe_id);
+       g_assert_cmpstr (element_id, ==, expects->element_id);
+       g_assert_cmpstr (element_class, ==, expects->element_class);
+       g_assert_cmpstr (element_value, ==, expects->element_value);
+       g_assert_cmpint (element_position->x, >, 0);
+       g_assert_cmpint (element_position->y, >, 0);
+       g_assert_cmpint (element_position->width, >, 0);
+       g_assert_cmpint (element_position->height, >, 0);
+
+       test_flag_set (expects->fixture->flag);
+}
+
+static void
+test_verify_element_clicked (TestFixture *fixture,
+                            ElementClickedData *expects,
+                            const gchar *iframe_id,
+                            const gchar *element_id,
+                            const gchar *element_class,
+                            const gchar *element_value,
+                            gboolean wait_response)
+{
+       gchar *script;
+
+       expects->iframe_id = iframe_id;
+       expects->element_id = element_id;
+       expects->element_class = element_class;
+       expects->element_value = element_value;
+
+       script = e_web_view_jsc_printf_script ("Evo.findIFrameDocument(%s).getElementById(%s).click();",
+               iframe_id, element_id);
+
+       test_utils_jsc_call (fixture, script);
+
+       g_free (script);
+
+       if (wait_response)
+               test_utils_wait (fixture);
+}
+
+static void
+test_element_clicked (TestFixture *fixture)
+{
+       ElementClickedData expects;
+
+       test_utils_load_body (fixture, LOAD_MAIN);
+
+       expects.fixture = fixture;
+
+       e_web_view_register_element_clicked (E_WEB_VIEW (fixture->web_view), "cbtn1", 
test_verify_element_clicked_cb, &expects);
+
+       test_verify_element_clicked (fixture, &expects, "", "dots1", "cdots", NULL, FALSE);
+       test_verify_element_clicked (fixture, &expects, "", "btn1", "cbtn1", "Button1", TRUE);
+
+       test_utils_load_body (fixture, LOAD_FRM1);
+
+       test_verify_element_clicked (fixture, &expects, "", "btn1", "cbtn1", "Button1", TRUE);
+       test_verify_element_clicked (fixture, &expects, "frm1", "btn1", "cbtn1", "Button1", TRUE);
+
+       test_utils_load_body (fixture, LOAD_FRM1_1);
+
+       test_verify_element_clicked (fixture, &expects, "frm1_1", "btn2", "cbtn2", "Button2", FALSE);
+
+       e_web_view_register_element_clicked (E_WEB_VIEW (fixture->web_view), "cbtn2", 
test_verify_element_clicked_cb, &expects);
+
+       test_verify_element_clicked (fixture, &expects, "frm1_1", "btn1", "cbtn1", "Button1", TRUE);
+       test_verify_element_clicked (fixture, &expects, "frm1_1", "btn2", "cbtn2", "Button2", TRUE);
+
+       test_utils_load_body (fixture, LOAD_FRM2);
+
+       test_verify_element_clicked (fixture, &expects, "frm1_1", "btn2", "cbtn2", "Button2", TRUE);
+       test_verify_element_clicked (fixture, &expects, "frm2", "btn2", "cbtn2", "Button2", TRUE);
+
+       e_web_view_register_element_clicked (E_WEB_VIEW (fixture->web_view), "cdots", 
test_verify_element_clicked_cb, &expects);
+
+       test_verify_element_clicked (fixture, &expects, "", "btn3", "cbtn3", "Button3", FALSE);
+       test_verify_element_clicked (fixture, &expects, "", "dots1", "cdots", NULL, TRUE);
+       test_verify_element_clicked (fixture, &expects, "", "btn1", "cbtn1", "Button1", TRUE);
+       test_verify_element_clicked (fixture, &expects, "frm1", "btn1", "cbtn1", "Button1", TRUE);
+       test_verify_element_clicked (fixture, &expects, "frm1_1", "btn1", "cbtn1", "Button1", TRUE);
+       test_verify_element_clicked (fixture, &expects, "frm1_1", "btn2", "cbtn2", "Button2", TRUE);
+       test_verify_element_clicked (fixture, &expects, "frm2", "btn1", "cbtn1", "Button1", TRUE);
+       test_verify_element_clicked (fixture, &expects, "frm2", "btn2", "cbtn2", "Button2", TRUE);
+       test_verify_element_clicked (fixture, &expects, "frm1_1", "dots2", "cdots", NULL, TRUE);
+
+       e_web_view_unregister_element_clicked (E_WEB_VIEW (fixture->web_view), "cbtn1", 
test_verify_element_clicked_cb, &expects);
+
+       test_verify_element_clicked (fixture, &expects, "", "btn3", "cbtn3", "Button3", FALSE);
+       test_verify_element_clicked (fixture, &expects, "", "btn1", "cbtn1", "Button1", FALSE);
+       test_verify_element_clicked (fixture, &expects, "frm1", "btn1", "cbtn1", "Button1", FALSE);
+       test_verify_element_clicked (fixture, &expects, "frm1_1", "btn1", "cbtn1", "Button1", FALSE);
+       test_verify_element_clicked (fixture, &expects, "frm2", "btn1", "cbtn1", "Button1", FALSE);
+       test_verify_element_clicked (fixture, &expects, "", "dots1", "cdots", NULL, TRUE);
+       test_verify_element_clicked (fixture, &expects, "frm1_1", "btn2", "cbtn2", "Button2", TRUE);
+       test_verify_element_clicked (fixture, &expects, "frm2", "btn2", "cbtn2", "Button2", TRUE);
+       test_verify_element_clicked (fixture, &expects, "frm1_1", "dots2", "cdots", NULL, TRUE);
+
+       e_web_view_unregister_element_clicked (E_WEB_VIEW (fixture->web_view), "cbtn2", 
test_verify_element_clicked_cb, &expects);
+       e_web_view_unregister_element_clicked (E_WEB_VIEW (fixture->web_view), "cdots", 
test_verify_element_clicked_cb, &expects);
+
+       test_verify_element_clicked (fixture, &expects, "", "btn3", "cbtn3", "Button3", FALSE);
+       test_verify_element_clicked (fixture, &expects, "", "dots1", "cdots", NULL, FALSE);
+       test_verify_element_clicked (fixture, &expects, "", "btn1", "cbtn1", "Button1", FALSE);
+       test_verify_element_clicked (fixture, &expects, "frm1", "btn1", "cbtn1", "Button1", FALSE);
+       test_verify_element_clicked (fixture, &expects, "frm1_1", "btn1", "cbtn1", "Button1", FALSE);
+       test_verify_element_clicked (fixture, &expects, "frm1_1", "btn2", "cbtn2", "Button2", FALSE);
+       test_verify_element_clicked (fixture, &expects, "frm2", "btn1", "cbtn1", "Button1", FALSE);
+       test_verify_element_clicked (fixture, &expects, "frm2", "btn2", "cbtn2", "Button2", FALSE);
+       test_verify_element_clicked (fixture, &expects, "frm1_1", "dots2", "cdots", NULL, FALSE);
+
+       test_utils_wait_noop (fixture);
+}
+
+typedef struct _NeedInputData {
+       TestFixture *fixture;
+       gboolean expects;
+} NeedInputData;
+
+static void
+test_verify_need_input_cb (GObject *object,
+                          GParamSpec *param,
+                          gpointer user_data)
+{
+       NeedInputData *nid = user_data;
+
+       g_assert_nonnull (nid);
+       g_assert_cmpint ((e_web_view_get_need_input (E_WEB_VIEW (nid->fixture->web_view)) ? 1 : 0), ==, 
(nid->expects ? 1 : 0));
+
+       test_flag_set (nid->fixture->flag);
+}
+
+static void
+test_verify_need_input (TestFixture *fixture,
+                       NeedInputData *nid,
+                       const gchar *iframe_id,
+                       const gchar *element_id,
+                       gboolean expects)
+{
+       nid->expects = expects;
+
+       if (iframe_id) {
+               gchar *script;
+
+               script = e_web_view_jsc_printf_script 
("Evo.findIFrameDocument(%s).getElementById(%s).focus();",
+                       iframe_id, element_id);
+
+               test_utils_jsc_call (fixture, script);
+
+               g_free (script);
+       } else {
+               test_utils_jsc_call (fixture, "document.activeElement.blur();");
+       }
+
+       test_utils_wait (fixture);
+}
+
+static void
+test_need_input_changed (TestFixture *fixture)
+{
+       gulong handler_id;
+       NeedInputData nid;
+
+       test_utils_load_string (fixture,
+               "<html><body>"
+               "Top<br>"
+               "<input id=\"btn1\" class=\"cbtn1\" type=\"button\" value=\"Button1\"><br>"
+               "<iframe id=\"frm1_1\" src=\"empty:///\"></iframe><br>"
+               "<input id=\"btn3\" class=\"cbtn3\" type=\"button\" value=\"Button3\">"
+               "<a name=\"dots\" id=\"dots1\" class=\"cdots\">...</a>"
+               "<label for=\"inptrdo\" id=\"lblradio\">Radio</label>"
+               "<input type=\"radio\" name=\"rdo\" id=\"inptrdo\" value=\"rdoval\"><br>"
+               "<textarea id=\"txt\" rows=\"3\" cols=\"20\">Text area text</textarea><br>"
+               "<select id=\"slct\">"
+               "   <option value=\"opt1\">opt1</option>"
+               "   <option value=\"opt2\">opt2</option>"
+               "   <option value=\"opt3\">opt3</option>"
+               "</select><br>"
+               "<button id=\"bbtn\" type=\"button\">Button</button>"
+               "</body></html>");
+
+       test_utils_load_body (fixture, LOAD_FRM1_1);
+
+       g_assert (!e_web_view_get_need_input (E_WEB_VIEW (fixture->web_view)));
+
+       nid.fixture = fixture;
+       nid.expects = FALSE;
+
+       handler_id = g_signal_connect (fixture->web_view, "notify::need-input",
+               G_CALLBACK (test_verify_need_input_cb), &nid);
+
+       test_verify_need_input (fixture, &nid, "", "btn1", TRUE);
+       test_verify_need_input (fixture, &nid, NULL, NULL, FALSE);
+       test_verify_need_input (fixture, &nid, "frm1_1", "btn2", TRUE);
+       test_verify_need_input (fixture, &nid, NULL, NULL, FALSE);
+       test_verify_need_input (fixture, &nid, "", "btn3", TRUE);
+       test_verify_need_input (fixture, &nid, NULL, NULL, FALSE);
+       test_verify_need_input (fixture, &nid, "", "lblradio", TRUE);
+       test_verify_need_input (fixture, &nid, NULL, NULL, FALSE);
+       test_verify_need_input (fixture, &nid, "", "inptrdo", TRUE);
+       test_verify_need_input (fixture, &nid, NULL, NULL, FALSE);
+       test_verify_need_input (fixture, &nid, "", "inptrdo", TRUE);
+       test_verify_need_input (fixture, &nid, NULL, NULL, FALSE);
+       test_verify_need_input (fixture, &nid, "", "txt", TRUE);
+       test_verify_need_input (fixture, &nid, NULL, NULL, FALSE);
+       test_verify_need_input (fixture, &nid, "", "slct", TRUE);
+       test_verify_need_input (fixture, &nid, NULL, NULL, FALSE);
+       test_verify_need_input (fixture, &nid, "", "bbtn", TRUE);
+       test_verify_need_input (fixture, &nid, NULL, NULL, FALSE);
+
+       g_signal_handler_disconnect (fixture->web_view, handler_id);
+
+       g_assert (!e_web_view_get_need_input (E_WEB_VIEW (fixture->web_view)));
+}
+
+static void
+test_selection_select_in_iframe (TestFixture *fixture,
+                                const gchar *iframe_id,
+                                const gchar *start_elem_id,
+                                const gchar *end_elem_id)
+{
+       gchar *script;
+
+       script = e_web_view_jsc_printf_script (
+               /* Clean selection in both places first, otherwise the previous selection
+                  can stay when changing it only in one of them. */
+               "Evo.findIFrameDocument(\"\").defaultView.getSelection().empty();\n"
+               "Evo.findIFrameDocument(\"frm1\").defaultView.getSelection().empty();\n"
+               "\n"
+               "var doc, range;\n"
+               "doc = Evo.findIFrameDocument(%s);\n"
+               "range = doc.createRange();\n"
+               "range.selectNodeContents(doc.getElementById(%s));"
+               "doc.defaultView.getSelection().addRange(range);\n"
+               "doc.defaultView.getSelection().extend(doc.getElementById(%s));\n",
+               iframe_id, start_elem_id, end_elem_id);
+
+       test_utils_jsc_call_sync (fixture, script, NULL);
+
+       g_free (script);
+
+       /* Wait for the notification from JS about changed selection
+          to be propagated into EWebView's has-selection. */
+       test_utils_wait_noop (fixture);
+}
+
+typedef struct _GetContentData {
+       TestFixture *fixture;
+       const gchar *expect_plain;
+       const gchar *expect_html;
+} GetContentData;
+
+static void
+test_verify_get_content_data (GetContentData *gcd,
+                             const GSList *texts)
+{
+       g_assert_nonnull (gcd);
+
+       if (gcd->expect_plain && gcd->expect_html) {
+               g_assert_cmpint (g_slist_length ((GSList *) texts), ==, 2);
+               g_assert_cmpstr (texts->data, ==, gcd->expect_plain);
+               g_assert_cmpstr (texts->next->data, ==, gcd->expect_html);
+       } else if (gcd->expect_plain) {
+               g_assert_cmpint (g_slist_length ((GSList *) texts), ==, 1);
+               g_assert_cmpstr (texts->data, ==, gcd->expect_plain);
+       } else if (gcd->expect_html) {
+               g_assert_cmpint (g_slist_length ((GSList *) texts), ==, 1);
+               g_assert_cmpstr (texts->data, ==, gcd->expect_html);
+       } else {
+               g_assert_cmpint (g_slist_length ((GSList *) texts), ==, 0);
+       }
+}
+
+static void
+test_selection_ready_cb (GObject *source_object,
+                        GAsyncResult *result,
+                        gpointer user_data)
+{
+       GetContentData *gcd = user_data;
+       GSList *texts = NULL;
+       gboolean success;
+       GError *error = NULL;
+
+       g_assert (WEBKIT_IS_WEB_VIEW (source_object));
+       g_assert_nonnull (gcd);
+
+       success = e_web_view_jsc_get_selection_finish (WEBKIT_WEB_VIEW (source_object), result, &texts, 
&error);
+
+       g_assert_no_error (error);
+       g_assert (success);
+
+       test_verify_get_content_data (gcd, texts);
+
+       g_slist_free_full (texts, g_free);
+
+       test_flag_set (gcd->fixture->flag);
+}
+
+static void
+test_selection_verify (TestFixture *fixture,
+                      const gchar *expect_plain,
+                      const gchar *expect_html)
+{
+       ETextFormat format;
+       GetContentData gcd;
+
+       if (expect_plain && expect_html)
+               format = E_TEXT_FORMAT_BOTH;
+       else if (expect_html)
+               format = E_TEXT_FORMAT_HTML;
+       else
+               format = E_TEXT_FORMAT_PLAIN;
+
+       gcd.fixture = fixture;
+       gcd.expect_plain = expect_plain;
+       gcd.expect_html = expect_html;
+
+       e_web_view_jsc_get_selection (fixture->web_view, format, NULL, test_selection_ready_cb, &gcd);
+
+       test_utils_wait (fixture);
+}
+
+static void
+test_selection (TestFixture *fixture)
+{
+       test_utils_load_string (fixture,
+               "<html><body>"
+               "<pre id=\"pr\">Out<span id=\"pr1\"></span>er text\nin PR<span id=\"pr2\"></span>E</pre><br 
id=\"br1\">"
+               "o<font color=\"orange\">rang</font>e; <b>bold</b><i>italic</i><br id=\"br2\">"
+               "<iframe id=\"frm1\" src=\"empty:///\"></iframe><br>"
+               "</body></html>");
+
+       test_utils_load_iframe_content (fixture, "frm1",
+               "<html><body>"
+               "frm1<br>"
+               "<div id=\"plain\">unformatted text</div><br>"
+               "<div id=\"rgb\">"
+               "<font color=\"red\">R</font>"
+               "<font color=\"green\">G</font>"
+               "<font color=\"blue\">B</font>"
+               "</div>"
+               "<div id=\"styled\">"
+               "<span style=\"color:blue;\">bb</span>"
+               "<span style=\"color:green;\">gg</span>"
+               "<span style=\"color:red;\">rr</span>"
+               "</div>"
+               "<div id=\"end\"></div>"
+               "</body></html>");
+
+       g_assert_cmpint (e_web_view_has_selection (E_WEB_VIEW (fixture->web_view)) ? 1 : 0, ==, 0);
+       test_selection_verify (fixture, NULL, NULL);
+
+       test_selection_select_in_iframe (fixture, "", "pr1", "pr2");
+
+       g_assert_cmpint (e_web_view_has_selection (E_WEB_VIEW (fixture->web_view)) ? 1 : 0, ==, 1);
+       test_selection_verify (fixture, "er text\nin PR", NULL);
+       test_selection_verify (fixture, NULL, "<pre>er text\nin PR</pre>");
+       test_selection_verify (fixture, "er text\nin PR", "<pre>er text\nin PR</pre>");
+
+       test_selection_select_in_iframe (fixture, "", "br1", "br2");
+
+       g_assert_cmpint (e_web_view_has_selection (E_WEB_VIEW (fixture->web_view)) ? 1 : 0, ==, 1);
+       test_selection_verify (fixture, "\norange; bolditalic", NULL);
+       test_selection_verify (fixture, NULL, "<br id=\"br1\">o<font color=\"orange\">rang</font>e; 
<b>bold</b><i>italic</i>");
+       test_selection_verify (fixture, "\norange; bolditalic", "<br id=\"br1\">o<font 
color=\"orange\">rang</font>e; <b>bold</b><i>italic</i>");
+
+       test_selection_select_in_iframe (fixture, "frm1", "plain", "rgb");
+
+       g_assert_cmpint (e_web_view_has_selection (E_WEB_VIEW (fixture->web_view)) ? 1 : 0, ==, 1);
+       test_selection_verify (fixture, "unformatted text\n", NULL);
+       test_selection_verify (fixture, NULL, "<div id=\"plain\">unformatted text</div><br><div 
id=\"rgb\"></div>");
+       test_selection_verify (fixture, "unformatted text\n", "<div id=\"plain\">unformatted 
text</div><br><div id=\"rgb\"></div>");
+
+       test_selection_select_in_iframe (fixture, "frm1", "rgb", "styled");
+
+       g_assert_cmpint (e_web_view_has_selection (E_WEB_VIEW (fixture->web_view)) ? 1 : 0, ==, 1);
+       test_selection_verify (fixture, "RGB", NULL);
+       test_selection_verify (fixture, NULL, "<div id=\"rgb\"><font color=\"red\">R</font><font 
color=\"green\">G</font><font color=\"blue\">B</font></div><div id=\"styled\"></div>");
+       test_selection_verify (fixture, "RGB", "<div id=\"rgb\"><font color=\"red\">R</font><font 
color=\"green\">G</font><font color=\"blue\">B</font></div><div id=\"styled\"></div>");
+
+       test_selection_select_in_iframe (fixture, "frm1", "styled", "end");
+
+       g_assert_cmpint (e_web_view_has_selection (E_WEB_VIEW (fixture->web_view)) ? 1 : 0, ==, 1);
+       test_selection_verify (fixture, "bbggrr", NULL);
+       test_selection_verify (fixture, NULL, "<span style=\"color:blue;\">bb</span><span 
style=\"color:green;\">gg</span><span style=\"color:red;\">rr</span>");
+       test_selection_verify (fixture, "bbggrr", "<span style=\"color:blue;\">bb</span><span 
style=\"color:green;\">gg</span><span style=\"color:red;\">rr</span>");
+
+       test_selection_select_in_iframe (fixture, "frm1", "end", "end");
+
+       g_assert_cmpint (e_web_view_has_selection (E_WEB_VIEW (fixture->web_view)) ? 1 : 0, ==, 0);
+       test_selection_verify (fixture, NULL, NULL);
+}
+
+static void
+test_get_document_content_ready_cb (GObject *source_object,
+                                   GAsyncResult *result,
+                                   gpointer user_data)
+{
+       GetContentData *gcd = user_data;
+       GSList *texts = NULL;
+       gboolean success;
+       GError *error = NULL;
+
+       g_assert (WEBKIT_IS_WEB_VIEW (source_object));
+       g_assert_nonnull (gcd);
+
+       success = e_web_view_jsc_get_document_content_finish (WEBKIT_WEB_VIEW (source_object), result, 
&texts, &error);
+
+       g_assert_no_error (error);
+       g_assert (success);
+
+       test_verify_get_content_data (gcd, texts);
+
+       g_slist_free_full (texts, g_free);
+
+       test_flag_set (gcd->fixture->flag);
+}
+
+static void
+test_get_document_content_verify (TestFixture *fixture,
+                                 const gchar *iframe_id,
+                                 const gchar *expect_plain,
+                                 const gchar *expect_html)
+{
+       ETextFormat format;
+       GetContentData gcd;
+
+       if (expect_plain && expect_html)
+               format = E_TEXT_FORMAT_BOTH;
+       else if (expect_html)
+               format = E_TEXT_FORMAT_HTML;
+       else
+               format = E_TEXT_FORMAT_PLAIN;
+
+       gcd.fixture = fixture;
+       gcd.expect_plain = expect_plain;
+       gcd.expect_html = expect_html;
+
+       e_web_view_jsc_get_document_content (fixture->web_view, iframe_id, format, NULL, 
test_get_document_content_ready_cb, &gcd);
+
+       test_utils_wait (fixture);
+}
+
+static void
+test_get_element_content_ready_cb (GObject *source_object,
+                                  GAsyncResult *result,
+                                  gpointer user_data)
+{
+       GetContentData *gcd = user_data;
+       GSList *texts = NULL;
+       gboolean success;
+       GError *error = NULL;
+
+       g_assert (WEBKIT_IS_WEB_VIEW (source_object));
+       g_assert_nonnull (gcd);
+
+       success = e_web_view_jsc_get_element_content_finish (WEBKIT_WEB_VIEW (source_object), result, &texts, 
&error);
+
+       g_assert_no_error (error);
+       g_assert (success);
+
+       test_verify_get_content_data (gcd, texts);
+
+       g_slist_free_full (texts, g_free);
+
+       test_flag_set (gcd->fixture->flag);
+}
+
+static void
+test_get_element_content_verify (TestFixture *fixture,
+                                const gchar *iframe_id,
+                                const gchar *element_id,
+                                gboolean use_outer_html,
+                                const gchar *expect_plain,
+                                const gchar *expect_html)
+{
+       ETextFormat format;
+       GetContentData gcd;
+
+       if (expect_plain && expect_html)
+               format = E_TEXT_FORMAT_BOTH;
+       else if (expect_html)
+               format = E_TEXT_FORMAT_HTML;
+       else
+               format = E_TEXT_FORMAT_PLAIN;
+
+       gcd.fixture = fixture;
+       gcd.expect_plain = expect_plain;
+       gcd.expect_html = expect_html;
+
+       e_web_view_jsc_get_element_content (fixture->web_view, iframe_id, element_id, format, use_outer_html, 
NULL, test_get_element_content_ready_cb, &gcd);
+
+       test_utils_wait (fixture);
+}
+
+static void
+test_get_content (TestFixture *fixture)
+{
+       const gchar *html_main =
+               "<html style=\"\"><head><meta charset=\"utf-8\"></head><body>"
+               "<div id=\"frst\">first div</div>"
+               "<div id=\"scnd\">second div</div>"
+               "<iframe id=\"frm1\" src=\"empty:///\"></iframe>"
+               "</body></html>";
+       const gchar *html_frm1 =
+               "<html style=\"\"><head><meta name=\"keywords\" value=\"test\"></head><body>"
+               "<span id=\"frm1p\">"
+               "<div id=\"frst\">frm1 div</div>"
+               "</span>"
+               "</body></html>";
+       const gchar *expect_html, *expect_plain;
+
+       test_utils_load_string (fixture, html_main);
+       test_utils_load_iframe_content (fixture, "frm1", html_frm1);
+
+       /* Clean up styles added by EWebView */
+       test_utils_jsc_call_sync (fixture, "Evo.SetElementStyleProperty(\"\",\"*html\",\"color\",null);", 
NULL);
+       test_utils_jsc_call_sync (fixture, 
"Evo.SetElementStyleProperty(\"\",\"*html\",\"background-color\",null);", NULL);
+       test_utils_jsc_call_sync (fixture, "Evo.SetElementAttribute(\"\",\"*body\",\"\",\"class\",null);", 
NULL);
+       test_utils_jsc_call_sync (fixture, "Evo.SetElementStyleProperty(\"frm1\",\"*html\",\"color\",null);", 
NULL);
+       test_utils_jsc_call_sync (fixture, 
"Evo.SetElementStyleProperty(\"frm1\",\"*html\",\"background-color\",null);", NULL);
+       test_utils_jsc_call_sync (fixture, 
"Evo.SetElementAttribute(\"frm1\",\"*body\",\"\",\"class\",null);", NULL);
+       test_utils_jsc_call_sync (fixture, "Evo.RemoveStyleSheet(\"*\",\"*\");", NULL);
+
+       expect_plain = "first div\nsecond div\n";
+       expect_html = html_main;
+
+       test_get_document_content_verify (fixture, "", expect_plain, NULL);
+       test_get_document_content_verify (fixture, "", NULL, expect_html);
+       test_get_document_content_verify (fixture, "", expect_plain, expect_html);
+
+       expect_plain = "frm1 div";
+       expect_html = html_frm1;
+       test_get_document_content_verify (fixture, "frm1", expect_plain, NULL);
+       test_get_document_content_verify (fixture, "frm1", NULL, expect_html);
+       test_get_document_content_verify (fixture, "frm1", expect_plain, expect_html);
+
+       expect_plain = "";
+       expect_html = "<meta charset=\"utf-8\">";
+       test_get_element_content_verify (fixture, "", "*head", FALSE, expect_plain, NULL);
+       test_get_element_content_verify (fixture, "", "*head", FALSE, NULL, expect_html);
+       test_get_element_content_verify (fixture, "", "*head", FALSE, expect_plain, expect_html);
+
+       expect_html = "<head><meta charset=\"utf-8\"></head>";
+       test_get_element_content_verify (fixture, "", "*head", TRUE, expect_plain, NULL);
+       test_get_element_content_verify (fixture, "", "*head", TRUE, NULL, expect_html);
+       test_get_element_content_verify (fixture, "", "*head", TRUE, expect_plain, expect_html);
+
+       expect_html = "<meta name=\"keywords\" value=\"test\">";
+       test_get_element_content_verify (fixture, "frm1", "*head", FALSE, expect_plain, NULL);
+       test_get_element_content_verify (fixture, "frm1", "*head", FALSE, NULL, expect_html);
+       test_get_element_content_verify (fixture, "frm1", "*head", FALSE, expect_plain, expect_html);
+
+       expect_html = "<head><meta name=\"keywords\" value=\"test\"></head>";
+       test_get_element_content_verify (fixture, "frm1", "*head", TRUE, expect_plain, NULL);
+       test_get_element_content_verify (fixture, "frm1", "*head", TRUE, NULL, expect_html);
+       test_get_element_content_verify (fixture, "frm1", "*head", TRUE, expect_plain, expect_html);
+
+       expect_plain = "first div\nsecond div\n";
+       expect_html =
+               "<div id=\"frst\">first div</div>"
+               "<div id=\"scnd\">second div</div>"
+               "<iframe id=\"frm1\" src=\"empty:///\"></iframe>";
+       test_get_element_content_verify (fixture, "", "*body", FALSE, expect_plain, NULL);
+       test_get_element_content_verify (fixture, "", "*body", FALSE, NULL, expect_html);
+       test_get_element_content_verify (fixture, "", "*body", FALSE, expect_plain, expect_html);
+
+       expect_html = "<body>"
+               "<div id=\"frst\">first div</div>"
+               "<div id=\"scnd\">second div</div>"
+               "<iframe id=\"frm1\" src=\"empty:///\"></iframe></body>";
+       test_get_element_content_verify (fixture, "", "*body", TRUE, expect_plain, NULL);
+       test_get_element_content_verify (fixture, "", "*body", TRUE, NULL, expect_html);
+       test_get_element_content_verify (fixture, "", "*body", TRUE, expect_plain, expect_html);
+
+       expect_plain = "frm1 div";
+       expect_html ="<span id=\"frm1p\"><div id=\"frst\">frm1 div</div></span>";
+       test_get_element_content_verify (fixture, "frm1", "*body", FALSE, expect_plain, NULL);
+       test_get_element_content_verify (fixture, "frm1", "*body", FALSE, NULL, expect_html);
+       test_get_element_content_verify (fixture, "frm1", "*body", FALSE, expect_plain, expect_html);
+
+       expect_html = "<body><span id=\"frm1p\"><div id=\"frst\">frm1 div</div></span></body>";
+       test_get_element_content_verify (fixture, "frm1", "*body", TRUE, expect_plain, NULL);
+       test_get_element_content_verify (fixture, "frm1", "*body", TRUE, NULL, expect_html);
+       test_get_element_content_verify (fixture, "frm1", "*body", TRUE, expect_plain, expect_html);
+
+       expect_plain = "first div";
+       expect_html = "first div";
+       test_get_element_content_verify (fixture, "", "frst", FALSE, expect_plain, NULL);
+       test_get_element_content_verify (fixture, "", "frst", FALSE, NULL, expect_html);
+       test_get_element_content_verify (fixture, "", "frst", FALSE, expect_plain, expect_html);
+
+       expect_html = "<div id=\"frst\">first div</div>";
+       test_get_element_content_verify (fixture, "", "frst", TRUE, expect_plain, NULL);
+       test_get_element_content_verify (fixture, "", "frst", TRUE, NULL, expect_html);
+       test_get_element_content_verify (fixture, "", "frst", TRUE, expect_plain, expect_html);
+
+       expect_plain = "frm1 div";
+       expect_html = "frm1 div";
+       test_get_element_content_verify (fixture, "frm1", "frst", FALSE, expect_plain, NULL);
+       test_get_element_content_verify (fixture, "frm1", "frst", FALSE, NULL, expect_html);
+       test_get_element_content_verify (fixture, "frm1", "frst", FALSE, expect_plain, expect_html);
+
+       expect_html = "<div id=\"frst\">frm1 div</div>";
+       test_get_element_content_verify (fixture, "frm1", "frst", TRUE, expect_plain, NULL);
+       test_get_element_content_verify (fixture, "frm1", "frst", TRUE, NULL, expect_html);
+       test_get_element_content_verify (fixture, "frm1", "frst", TRUE, expect_plain, expect_html);
+
+       test_get_element_content_verify (fixture, "frm1", "frm1p", FALSE, expect_plain, NULL);
+       test_get_element_content_verify (fixture, "frm1", "frm1p", FALSE, NULL, expect_html);
+       test_get_element_content_verify (fixture, "frm1", "frm1p", FALSE, expect_plain, expect_html);
+
+       expect_html = "<span id=\"frm1p\"><div id=\"frst\">frm1 div</div></span>";
+       test_get_element_content_verify (fixture, "frm1", "frm1p", TRUE, expect_plain, NULL);
+       test_get_element_content_verify (fixture, "frm1", "frm1p", TRUE, NULL, expect_html);
+       test_get_element_content_verify (fixture, "frm1", "frm1p", TRUE, expect_plain, expect_html);
+}
+
+typedef struct _GetElementFromPoint {
+       TestFixture *fixture;
+       const gchar *expect_iframe_src;
+       const gchar *expect_iframe_id;
+       const gchar *expect_element_id;
+} GetElementFromPoint;
+
+static void
+test_get_element_from_point_ready_cb (GObject *source_object,
+                                     GAsyncResult *result,
+                                     gpointer user_data)
+{
+       GetElementFromPoint *gefp = user_data;
+       gchar *iframe_src = NULL, *iframe_id = NULL, *element_id = NULL;
+       gboolean success;
+       GError *error = NULL;
+
+       g_assert (WEBKIT_IS_WEB_VIEW (source_object));
+       g_assert_nonnull (gefp);
+
+       success = e_web_view_jsc_get_element_from_point_finish (WEBKIT_WEB_VIEW (source_object), result, 
&iframe_src, &iframe_id, &element_id, &error);
+
+       g_assert_no_error (error);
+       g_assert (success);
+
+       g_assert_cmpstr (iframe_src, ==, gefp->expect_iframe_src);
+       g_assert_cmpstr (iframe_id, ==, gefp->expect_iframe_id);
+       g_assert_cmpstr (element_id, ==, gefp->expect_element_id);
+
+       g_free (iframe_src);
+       g_free (iframe_id);
+       g_free (element_id);
+
+       test_flag_set (gefp->fixture->flag);
+}
+
+static void
+test_utils_verify_get_element_from_point (TestFixture *fixture,
+                                         gint xx,
+                                         gint yy,
+                                         const gchar *expect_iframe_src,
+                                         const gchar *expect_iframe_id,
+                                         const gchar *expect_element_id)
+{
+       GetElementFromPoint gefp;
+
+       gefp.fixture = fixture;
+       gefp.expect_iframe_src = expect_iframe_src;
+       gefp.expect_iframe_id = expect_iframe_id;
+       gefp.expect_element_id = expect_element_id;
+
+       e_web_view_jsc_get_element_from_point (fixture->web_view, xx, yy, NULL, 
test_get_element_from_point_ready_cb, &gefp);
+
+       test_utils_wait (fixture);
+}
+
+static void
+window_size_allocated_cb (GtkWidget *widget,
+                         GdkRectangle *allocation,
+                         gpointer user_data)
+{
+       TestFixture *fixture = user_data;
+
+       test_flag_set (fixture->flag);
+}
+
+static void
+test_get_element_from_point (TestFixture *fixture)
+{
+       struct _elems {
+               const gchar *iframe_src;
+               const gchar *iframe_id;
+               const gchar *elem_id;
+       } elems[] = {
+               { NULL, "", "btn1" },
+               { NULL, "", "btn3" },
+               { NULL, "", "dots1" },
+               { "empty:///frm1", "frm1", "btn1" },
+               { "empty:///frm1_1", "frm1_1", "btn1" },
+               { "empty:///frm1_1", "frm1_1", "dots2" },
+               { "empty:///frm1_1", "frm1_1", "btn2" },
+               { "empty:///frm2", "frm2", "btn1" },
+               { "empty:///frm2", "frm2", "btn2" }
+       };
+       gchar *script;
+       gint ii, scroll_x, scroll_y, client_width, client_height, tested;
+
+       test_utils_load_body (fixture, LOAD_ALL);
+
+       ii = test_utils_jsc_call_int32_sync (fixture,
+               "function TestGetPosition(iframe_id, elem_id)\n"
+               "{\n"
+               "       var elem = Evo.findElement(iframe_id, elem_id);\n"
+               "       var xx = 0, yy = 0, off_elem, check_elem;\n"
+               "       for (check_elem = elem; check_elem; check_elem = 
check_elem.ownerDocument.defaultView.frameElement) {\n"
+               "               for (ii = check_elem; ii; ii = ii.parentOffset) {\n"
+               "                       xx += ii.offsetLeft - ii.scrollLeft;\n"
+               "                       yy += ii.offsetTop - ii.scrollTop;\n"
+               "               }\n"
+               "       }\n"
+               "       var res = [];\n"
+               "       res[\"left\"] = xx + (elem.offsetWidth / 2) - window.scrollX;\n"
+               "       res[\"right\"] = xx + elem.offsetWidth - 2 - window.scrollX;\n"
+               "       res[\"top\"] = yy + (elem.offsetHeight / 2) - window.scrollY;\n"
+               "       return res;"
+               "}\n"
+               "\n"
+               /* To not scroll in the frm1 */
+               "document.getElementById(\"frm1\").height = 
document.getElementById(\"frm1\").contentDocument.getElementById(\"btn1\").offsetTop +"
+               " 2 * 
document.getElementById(\"frm1\").contentDocument.getElementById(\"btn1\").offsetHeight;\n"
+               "\n"
+               "document.body.scrollHeight;\n");
+
+       /* To not scroll in the overall document */
+       gtk_widget_set_size_request (fixture->window, -1, ii);
+
+       /* Window/widget resize is done asynchronously, thus wait for it */
+       g_signal_connect (fixture->window, "size-allocate",
+               G_CALLBACK (window_size_allocated_cb), fixture);
+
+       test_utils_wait (fixture);
+
+       g_signal_handlers_disconnect_by_func (fixture->window, G_CALLBACK (window_size_allocated_cb), 
fixture);
+
+       for (ii = 0; ii < G_N_ELEMENTS (elems); ii++) {
+               const gchar *iframe_src;
+               gchar *script;
+               JSCValue *value;
+               gint xx, yy;
+
+               script = e_web_view_jsc_printf_script ("TestGetPosition(%s, %s);", elems[ii].iframe_id, 
elems[ii].elem_id);
+
+               test_utils_jsc_call_sync (fixture, script, &value);
+
+               g_assert_nonnull (value);
+               g_assert (jsc_value_is_object (value));
+
+               xx = e_web_view_jsc_get_object_property_int32 (value, "left", -1);
+               yy = e_web_view_jsc_get_object_property_int32 (value, "top", -1);
+
+               g_assert_cmpint (xx, >, -1);
+               g_assert_cmpint (yy, >, -1);
+
+               g_clear_object (&value);
+               g_free (script);
+
+               iframe_src = elems[ii].iframe_src;
+
+               if (!iframe_src)
+                       iframe_src = webkit_web_view_get_uri (fixture->web_view);
+
+               test_utils_verify_get_element_from_point (fixture, xx, yy, iframe_src, elems[ii].iframe_id, 
elems[ii].elem_id);
+       }
+
+       test_utils_verify_get_element_from_point (fixture, -1, -1, webkit_web_view_get_uri 
(fixture->web_view), "", "");
+
+       test_utils_jsc_call_sync (fixture, "Evo.findIFrameDocument(\"\").getElementById(\"btn3\").focus();", 
NULL);
+
+       test_utils_verify_get_element_from_point (fixture, -1, -1, webkit_web_view_get_uri 
(fixture->web_view), "", "btn3");
+
+       scroll_x = test_utils_jsc_call_int32_sync (fixture, "document.body.scrollWidth;") / 2;
+       scroll_y = test_utils_jsc_call_int32_sync (fixture, "document.body.scrollHeight;") / 2;
+
+       /* To scroll in the overall document */
+       gtk_widget_set_size_request (fixture->window, -1, -1);
+       gtk_window_resize (GTK_WINDOW (fixture->window), scroll_x, scroll_y);
+
+       /* Window/widget resize is done asynchronously, thus wait for it */
+       g_signal_connect (fixture->window, "size-allocate",
+               G_CALLBACK (window_size_allocated_cb), fixture);
+
+       test_utils_wait (fixture);
+
+       g_signal_handlers_disconnect_by_func (fixture->window, G_CALLBACK (window_size_allocated_cb), 
fixture);
+
+       /* Scroll by some value */
+       scroll_x /= 2;
+       scroll_y /= 2;
+       script = e_web_view_jsc_printf_script ("window.scrollBy(%d,%d);", scroll_x, scroll_y);
+       test_utils_jsc_call_sync (fixture, script, NULL);
+       g_free (script);
+
+       test_utils_wait_noop (fixture);
+
+       scroll_x = test_utils_jsc_call_int32_sync (fixture, "window.scrollX;");
+       scroll_y = test_utils_jsc_call_int32_sync (fixture, "window.scrollY;");
+       client_width = test_utils_jsc_call_int32_sync (fixture, "document.body.clientWidth;");
+       client_height = test_utils_jsc_call_int32_sync (fixture, "document.body.clientHeight;");
+
+       tested = 0;
+
+       for (ii = 0; ii < G_N_ELEMENTS (elems); ii++) {
+               const gchar *iframe_src;
+               gchar *script;
+               JSCValue *value;
+               gint xx, yy;
+
+               script = e_web_view_jsc_printf_script ("TestGetPosition(%s, %s);", elems[ii].iframe_id, 
elems[ii].elem_id);
+
+               test_utils_jsc_call_sync (fixture, script, &value);
+
+               g_assert_nonnull (value);
+               g_assert (jsc_value_is_object (value));
+
+               xx = e_web_view_jsc_get_object_property_int32 (value, "right", -1);
+               yy = e_web_view_jsc_get_object_property_int32 (value, "top", -1);
+
+               g_clear_object (&value);
+               g_free (script);
+
+               if (xx >= 0 && xx < client_width && yy >= 0 && yy < client_height) {
+                       iframe_src = elems[ii].iframe_src;
+
+                       if (!iframe_src)
+                               iframe_src = webkit_web_view_get_uri (fixture->web_view);
+
+                       test_utils_verify_get_element_from_point (fixture, xx, yy, iframe_src, 
elems[ii].iframe_id, elems[ii].elem_id);
+
+                       tested++;
+               }
+       }
+
+       g_assert_cmpint (tested, >, 0);
+}
+
+gint
+main (gint argc,
+      gchar *argv[])
+{
+       gint res;
+
+       setlocale (LC_ALL, "");
+
+       g_test_init (&argc, &argv, NULL);
+       g_test_bug_base ("https://gitlab.gnome.org/GNOME/evolution/issues/";);
+
+       gtk_init (&argc, &argv);
+
+       e_util_init_main_thread (NULL);
+       e_passwords_init ();
+
+       test_utils_add_test ("/EWebView/JSCObjectProperties", test_jsc_object_properties);
+       test_utils_add_test ("/EWebView/SetElementHidden", test_set_element_hidden);
+       test_utils_add_test ("/EWebView/SetElementDisabled", test_set_element_disabled);
+       test_utils_add_test ("/EWebView/SetElementChecked", test_set_element_checked);
+       test_utils_add_test ("/EWebView/SetElementStyleProperty", test_set_element_style_property);
+       test_utils_add_test ("/EWebView/SetElementAttribute", test_set_element_attribute);
+       test_utils_add_test ("/EWebView/StyleSheets", test_style_sheets);
+       test_utils_add_test ("/EWebView/ElementClicked", test_element_clicked);
+       test_utils_add_test ("/EWebView/NeedInputChanged", test_need_input_changed);
+       test_utils_add_test ("/EWebView/Selection", test_selection);
+       test_utils_add_test ("/EWebView/GetContent", test_get_content);
+       test_utils_add_test ("/EWebView/GetElementFromPoint", test_get_element_from_point);
+
+       res = g_test_run ();
+
+       e_misc_util_free_global_memory ();
+
+       return res;
+}
diff --git a/src/em-format/CMakeLists.txt b/src/em-format/CMakeLists.txt
index 7b6a3d9b21..4a88b8cf95 100644
--- a/src/em-format/CMakeLists.txt
+++ b/src/em-format/CMakeLists.txt
@@ -113,7 +113,6 @@ add_dependencies(evolution-mail-formatter
 target_compile_definitions(evolution-mail-formatter PRIVATE
        -DG_LOG_DOMAIN=\"evolution-mail-formatter\"
        -DEVOLUTION_IMAGESDIR=\"${imagesdir}\"
-       -DEVOLUTION_PRIVDATADIR=\"${privdatadir}\"
 )
 
 target_compile_options(evolution-mail-formatter PUBLIC
diff --git a/src/em-format/e-mail-formatter-print.c b/src/em-format/e-mail-formatter-print.c
index 1f6cff2721..d302b17a5e 100644
--- a/src/em-format/e-mail-formatter-print.c
+++ b/src/em-format/e-mail-formatter-print.c
@@ -25,8 +25,7 @@
 #include <gdk/gdk.h>
 #include <glib/gi18n.h>
 
-#define STYLESHEET_URI \
-       "evo-file://" EVOLUTION_PRIVDATADIR "/theme/webview-print.css"
+#define STYLESHEET_URI "evo-file://$EVOLUTION_WEBKITDATADIR/webview-print.css"
 
 /* internal formatter extensions */
 GType e_mail_formatter_print_headers_get_type (void);
diff --git a/src/em-format/e-mail-formatter.c b/src/em-format/e-mail-formatter.c
index ce738a85e2..fb88f875ff 100644
--- a/src/em-format/e-mail-formatter.c
+++ b/src/em-format/e-mail-formatter.c
@@ -36,8 +36,7 @@
        (G_TYPE_INSTANCE_GET_PRIVATE \
        ((obj), E_TYPE_MAIL_FORMATTER, EMailFormatterPrivate))
 
-#define STYLESHEET_URI \
-       "evo-file://" EVOLUTION_PRIVDATADIR "/theme/webview.css"
+#define STYLESHEET_URI "evo-file://$EVOLUTION_WEBKITDATADIR/webview.css"
 
 typedef struct _AsyncContext AsyncContext;
 
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 4719448e16..a224376257 100644
--- a/src/em-format/e-mail-part-secure-button.c
+++ b/src/em-format/e-mail-part-secure-button.c
@@ -324,6 +324,8 @@ secure_button_show_validity_dialog (EWebView *web_view,
 
 static void
 secure_button_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,
@@ -364,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));
@@ -379,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-popup-extension.c b/src/mail/e-mail-display-popup-extension.c
index 2f9e91948e..b199f4f249 100644
--- a/src/mail/e-mail-display-popup-extension.c
+++ b/src/mail/e-mail-display-popup-extension.c
@@ -33,14 +33,16 @@ e_mail_display_popup_extension_default_init (EMailDisplayPopupExtensionInterface
  * e_mail_display_popup_extension_update_actions:
  *
  * @extension: An object derived from #EMailDisplayPopupExtension
- * @popup_document_uri: Document URI on top of which the popup menu had been invoked
+ * @popup_iframe_src: iframe source URI on top of which the popup menu had been invoked
+ * @popup_iframe_id: iframe ID on top of which the popup menu had been invoked
  *
  * When #EMailDisplay is about to display a popup menu, it calls this function
  * on every extension so that they can add their items to the menu.
  */
 void
 e_mail_display_popup_extension_update_actions (EMailDisplayPopupExtension *extension,
-                                              const gchar *popup_document_uri)
+                                              const gchar *popup_iframe_src,
+                                              const gchar *popup_iframe_id)
 {
        EMailDisplayPopupExtensionInterface *iface;
 
@@ -49,5 +51,5 @@ e_mail_display_popup_extension_update_actions (EMailDisplayPopupExtension *exten
        iface = E_MAIL_DISPLAY_POPUP_EXTENSION_GET_INTERFACE (extension);
        g_return_if_fail (iface->update_actions != NULL);
 
-       iface->update_actions (extension, popup_document_uri);
+       iface->update_actions (extension, popup_iframe_src, popup_iframe_id);
 }
diff --git a/src/mail/e-mail-display-popup-extension.h b/src/mail/e-mail-display-popup-extension.h
index bedd23ed7d..3ea5b1d3c5 100644
--- a/src/mail/e-mail-display-popup-extension.h
+++ b/src/mail/e-mail-display-popup-extension.h
@@ -48,14 +48,16 @@ struct _EMailDisplayPopupExtensionInterface {
        GTypeInterface parent_interface;
 
        void    (*update_actions)               (EMailDisplayPopupExtension *extension,
-                                                const gchar *popup_document_uri);
+                                                const gchar *popup_iframe_src,
+                                                const gchar *popup_iframe_id);
 };
 
 GType          e_mail_display_popup_extension_get_type (void);
 
 void           e_mail_display_popup_extension_update_actions
                                                        (EMailDisplayPopupExtension *extension,
-                                                        const gchar *popup_document_uri);
+                                                        const gchar *popup_iframe_src,
+                                                        const gchar *popup_iframe_id);
 
 G_END_DECLS
 
diff --git a/src/mail/e-mail-display.c b/src/mail/e-mail-display.c
index 76e2c9189a..c343f32ddd 100644
--- a/src/mail/e-mail-display.c
+++ b/src/mail/e-mail-display.c
@@ -44,8 +44,6 @@
 #include "em-composer-utils.h"
 #include "em-utils.h"
 
-#include "web-extensions/e-web-extension-names.h"
-
 #include "e-mail-display.h"
 
 #define d(x)
@@ -59,6 +57,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 +88,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 +400,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 +421,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 +461,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 +469,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 +484,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 +557,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);
@@ -749,7 +640,7 @@ mail_attachment_change_zoom (EMailDisplay *display,
 
                element_id = g_strdup_printf ("attachment-wrapper-%p::child", attachment);
 
-               e_web_view_set_element_style_property (E_WEB_VIEW (display), element_id, "max-width", 
max_width, "");
+               e_web_view_set_element_style_property (E_WEB_VIEW (display), element_id, "max-width", 
max_width);
 
                g_free (element_id);
        }
@@ -916,6 +807,8 @@ call_attachment_save_handle_error (GObject *source_object,
 
 static void
 mail_display_attachment_expander_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,
@@ -1099,6 +992,8 @@ mail_display_attachment_select_path (EAttachmentView *view,
 
 static void
 mail_display_attachment_menu_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,
@@ -1181,154 +1076,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));
+       EMailDisplay *mail_display;
 
-       if (display->priv->part_list == NULL)
-               return;
-
-       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);
+       g_return_if_fail (E_IS_MAIL_DISPLAY (web_view));
 
-               e_mail_part_web_view_loaded (part, web_view);
+       mail_display = E_MAIL_DISPLAY (web_view);
 
-               meed = g_new0 (MailElementExistsData, 1);
-               meed->web_view = g_object_ref (web_view);
-               meed->part = g_object_ref (part);
+       initialize_web_view_colors (mail_display, iframe_id);
 
-               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);
-       }
-
-       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
@@ -1457,20 +1272,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);
@@ -1562,31 +1363,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);
@@ -1625,6 +1449,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
@@ -1648,38 +1485,33 @@ mail_display_style_updated (GtkWidget *widget)
                style_updated (widget);
 }
 
-static gboolean
-mail_display_button_press_event (GtkWidget *widget,
-                                 GdkEventButton *event)
+static void
+mail_display_before_popup_event (EWebView *web_view,
+                                const gchar *uri)
 {
-       if (event->button == 3) {
-               EWebView *web_view = E_WEB_VIEW (widget);
-               gchar *popup_document_uri;
-               GList *list, *link;
+       gchar *popup_iframe_src = NULL, *popup_iframe_id = NULL;
+       GList *list, *link;
 
-               popup_document_uri = e_web_view_get_document_uri_from_point (web_view, event->x, event->y);
+       e_web_view_get_last_popup_place (web_view, &popup_iframe_src, &popup_iframe_id, NULL, NULL);
 
-               list = e_extensible_list_extensions (
-                       E_EXTENSIBLE (web_view), E_TYPE_EXTENSION);
-               for (link = list; link != NULL; link = g_list_next (link)) {
-                       EExtension *extension = link->data;
+       list = e_extensible_list_extensions (E_EXTENSIBLE (web_view), E_TYPE_EXTENSION);
 
-                       if (!E_IS_MAIL_DISPLAY_POPUP_EXTENSION (extension))
-                               continue;
+       for (link = list; link; link = g_list_next (link)) {
+               EExtension *extension = link->data;
 
-                       e_mail_display_popup_extension_update_actions (
-                               E_MAIL_DISPLAY_POPUP_EXTENSION (extension), popup_document_uri);
-               }
+               if (!E_IS_MAIL_DISPLAY_POPUP_EXTENSION (extension))
+                       continue;
 
-               g_list_free (list);
-               g_free (popup_document_uri);
+               e_mail_display_popup_extension_update_actions (E_MAIL_DISPLAY_POPUP_EXTENSION (extension), 
popup_iframe_src, popup_iframe_id);
        }
 
-       /* Chain up to parent's button_press_event() method. */
-       return GTK_WIDGET_CLASS (e_mail_display_parent_class)->
-               button_press_event (widget, event);
-}
+       g_free (popup_iframe_src);
+       g_free (popup_iframe_id);
+       g_list_free (list);
 
+       /* Chain up to parent's method. */
+       E_WEB_VIEW_CLASS (e_mail_display_parent_class)->before_popup_event (web_view, uri);
+}
 
 static gboolean
 mail_display_image_exists_in_cache (const gchar *image_uri)
@@ -2127,11 +1959,11 @@ e_mail_display_class_init (EMailDisplayClass *class)
        widget_class = GTK_WIDGET_CLASS (class);
        widget_class->realize = mail_display_realize;
        widget_class->style_updated = mail_display_style_updated;
-       widget_class->button_press_event = mail_display_button_press_event;
 
        web_view_class = E_WEB_VIEW_CLASS (class);
        web_view_class->suggest_filename = mail_display_suggest_filename;
        web_view_class->set_fonts = mail_display_set_fonts;
+       web_view_class->before_popup_event = mail_display_before_popup_event;
 
        g_object_class_install_property (
                object_class,
@@ -2283,6 +2115,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,
@@ -2316,9 +2152,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
@@ -2338,6 +2171,7 @@ e_mail_display_update_colors (EMailDisplay *display,
 
        add_color_css_rule_for_web_view (
                E_WEB_VIEW (display),
+               "*",
                param_spec->name,
                color_value);
 
@@ -2762,90 +2596,6 @@ e_mail_display_set_status (EMailDisplay *display,
        g_free (str);
 }
 
-gchar *
-e_mail_display_get_selection_content_multipart_sync (EMailDisplay *display,
-                                                     gboolean *is_html,
-                                                     GCancellable *cancellable,
-                                                     GError **error)
-{
-       GDBusProxy *web_extension;
-
-       g_return_val_if_fail (E_IS_MAIL_DISPLAY (display), NULL);
-
-       if (!e_web_view_is_selection_active (E_WEB_VIEW (display)))
-               return NULL;
-
-       web_extension = e_web_view_get_web_extension_proxy (E_WEB_VIEW (display));
-       if (web_extension) {
-               GVariant *result;
-
-               result = e_util_invoke_g_dbus_proxy_call_sync_wrapper_full (
-                               web_extension,
-                               "GetSelectionContentMultipart",
-                               g_variant_new (
-                                       "(t)",
-                                       webkit_web_view_get_page_id (
-                                               WEBKIT_WEB_VIEW (display))),
-                               G_DBUS_CALL_FLAGS_NONE,
-                               -1,
-                               cancellable,
-                               error);
-
-               if (result) {
-                       gchar *content = NULL;
-                       gboolean text_html = FALSE;
-
-                       g_variant_get (result, "(sb)", &content, &text_html);
-                       g_variant_unref (result);
-                       if (is_html)
-                               *is_html = text_html;
-                       return content;
-               }
-       }
-
-       return NULL;
-}
-
-gchar *
-e_mail_display_get_selection_plain_text_sync (EMailDisplay *display,
-                                              GCancellable *cancellable,
-                                              GError **error)
-{
-       GDBusProxy *web_extension;
-
-       g_return_val_if_fail (E_IS_MAIL_DISPLAY (display), NULL);
-
-       if (!e_web_view_is_selection_active (E_WEB_VIEW (display)))
-               return NULL;
-
-       web_extension = e_web_view_get_web_extension_proxy (E_WEB_VIEW (display));
-       if (web_extension) {
-               GVariant *result;
-
-               result = e_util_invoke_g_dbus_proxy_call_sync_wrapper_full (
-                               web_extension,
-                               "GetSelectionContentText",
-                               g_variant_new (
-                                       "(t)",
-                                       webkit_web_view_get_page_id (
-                                               WEBKIT_WEB_VIEW (display))),
-                               G_DBUS_CALL_FLAGS_NONE,
-                               -1,
-                               cancellable,
-                               error);
-
-               if (result) {
-                       gchar *text;
-
-                       g_variant_get (result, "(s)", &text);
-                       g_variant_unref (result);
-                       return text;
-               }
-       }
-
-       return NULL;
-}
-
 void
 e_mail_display_load_images (EMailDisplay *display)
 {
@@ -2947,36 +2697,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/mail/e-mail-display.h b/src/mail/e-mail-display.h
index ed02f189e5..cacf64e2d5 100644
--- a/src/mail/e-mail-display.h
+++ b/src/mail/e-mail-display.h
@@ -94,15 +94,6 @@ GtkAction *  e_mail_display_get_action       (EMailDisplay *display,
                                                 const gchar *action_name);
 void           e_mail_display_set_status       (EMailDisplay *display,
                                                 const gchar *status);
-gchar *                e_mail_display_get_selection_content_multipart_sync
-                                               (EMailDisplay *display,
-                                                gboolean *is_html,
-                                                GCancellable *cancellable,
-                                                GError **error);
-gchar *                e_mail_display_get_selection_plain_text_sync
-                                               (EMailDisplay *display,
-                                                GCancellable *cancellable,
-                                                GError **error);
 void           e_mail_display_load_images      (EMailDisplay *display);
 void           e_mail_display_set_force_load_images
                                                (EMailDisplay *display,
diff --git a/src/mail/e-mail-reader-utils.c b/src/mail/e-mail-reader-utils.c
index 997bc93570..8b0c95aab7 100644
--- a/src/mail/e-mail-reader-utils.c
+++ b/src/mail/e-mail-reader-utils.c
@@ -2615,10 +2615,12 @@ mail_reader_reply_to_message_composer_created_cb (GObject *source_object,
        create_composer_data_free (ccd);
 }
 
-void
-e_mail_reader_reply_to_message (EMailReader *reader,
-                                CamelMimeMessage *src_message,
-                                EMailReplyType reply_type)
+static void
+e_mail_reader_reply_to_message_with_selection (EMailReader *reader,
+                                              CamelMimeMessage *src_message,
+                                              EMailReplyType reply_type,
+                                              const gchar *selection,
+                                              gboolean selection_is_html)
 {
        EShell *shell;
        EMailBackend *backend;
@@ -2626,17 +2628,14 @@ e_mail_reader_reply_to_message (EMailReader *reader,
        EMailDisplay *display;
        EMailPartList *part_list = NULL;
        GtkWidget *message_list;
-       CamelContentType *content_type;
        CamelMimeMessage *new_message;
        CamelInternetAddress *address = NULL;
        CamelFolder *folder;
        EMailReplyStyle reply_style;
        EWebView *web_view;
-       gboolean src_is_text_html = FALSE;
        const CamelNameValueArray *headers;
        guint ii, len;
        const gchar *uid;
-       gchar *selection = NULL;
        gint length;
        gchar *mail_uri;
        CamelObjectBag *registry;
@@ -2734,34 +2733,17 @@ e_mail_reader_reply_to_message (EMailReader *reader,
 
        g_clear_object (&part_list);
 
-       if (!e_web_view_is_selection_active (web_view))
+       if (!e_web_view_has_selection (web_view))
                goto whole_message;
 
-       content_type = camel_mime_part_get_content_type (CAMEL_MIME_PART (src_message));
-
-       if (camel_content_type_is (content_type, "text", "plain")) {
-               selection = e_mail_display_get_selection_plain_text_sync (display, NULL, NULL);
-               src_is_text_html = FALSE;
-       } else if (camel_content_type_is (content_type, "text", "html")) {
-               selection = e_web_view_get_selection_content_html_sync (E_WEB_VIEW (display), NULL, NULL);
-               src_is_text_html = TRUE;
-       } else {
-               selection = e_mail_display_get_selection_content_multipart_sync (display, &src_is_text_html, 
NULL, NULL);
-       }
-
        if (selection == NULL || *selection == '\0')
                goto whole_message;
 
        length = strlen (selection);
-       if ((src_is_text_html && !html_contains_nonwhitespace (selection, length)) ||
-           (!src_is_text_html && !plaintext_contains_nonwhitespace (selection, length)))
+       if ((selection_is_html && !html_contains_nonwhitespace (selection, length)) ||
+           (!selection_is_html && !plaintext_contains_nonwhitespace (selection, length)))
                goto whole_message;
 
-       if (!src_is_text_html) {
-               maybe_mangle_plaintext_signature_delimiter (&selection);
-               length = strlen (selection);
-       }
-
        new_message = camel_mime_message_new ();
 
        /* Filter out "content-*" headers. */
@@ -2789,7 +2771,7 @@ e_mail_reader_reply_to_message (EMailReader *reader,
                CAMEL_MIME_PART (new_message),
                selection,
                length,
-               src_is_text_html ? "text/html; charset=utf-8" : "text/plain; charset=utf-8");
+               selection_is_html ? "text/html; charset=utf-8" : "text/plain; charset=utf-8");
 
        ccd = g_new0 (CreateComposerData, 1);
        ccd->reader = g_object_ref (reader);
@@ -2853,11 +2835,121 @@ whole_message:
        }
 
 exit:
-       g_free (selection);
        g_clear_object (&address);
        g_clear_object (&folder);
 }
 
+typedef struct _GetSelectionData {
+       EMailReader *reader;
+       CamelMimeMessage *src_message;
+       EMailReplyType reply_type;
+       gboolean selection_is_html;
+} GetSelectionData;
+
+static void
+reply_got_message_selection_jsc_cb (GObject *source_object,
+                                   GAsyncResult *result,
+                                   gpointer user_data)
+{
+       GetSelectionData *gsd = user_data;
+       gchar *selection;
+       GSList *texts = NULL;
+       GError *error = NULL;
+
+       g_return_if_fail (gsd != NULL);
+       g_return_if_fail (E_IS_WEB_VIEW (source_object));
+
+       if (!e_web_view_jsc_get_selection_finish (WEBKIT_WEB_VIEW (source_object), result, &texts, &error)) {
+               texts = NULL;
+               g_warning ("%s: Failed to get view selection: %s", G_STRFUNC, error ? error->message : 
"Unknown error");
+       }
+
+       selection = texts ? texts->data : NULL;
+
+       if (selection && !gsd->selection_is_html) {
+               maybe_mangle_plaintext_signature_delimiter (&selection);
+               texts->data = selection;
+       }
+
+       e_mail_reader_reply_to_message_with_selection (gsd->reader, gsd->src_message, gsd->reply_type, 
selection, gsd->selection_is_html);
+
+       g_slist_free_full (texts, g_free);
+       g_clear_error (&error);
+       g_clear_object (&gsd->reader);
+       g_clear_object (&gsd->src_message);
+       g_slice_free (GetSelectionData, gsd);
+}
+
+void
+e_mail_reader_reply_to_message (EMailReader *reader,
+                                CamelMimeMessage *src_message,
+                                EMailReplyType reply_type)
+{
+       CamelContentType *ct;
+       GetSelectionData *gsd;
+       EMailDisplay *mail_display;
+       EMailPartList *part_list = NULL;
+       EWebView *web_view;
+
+       g_return_if_fail (E_IS_MAIL_READER (reader));
+
+       mail_display = e_mail_reader_get_mail_display (reader);
+       g_return_if_fail (E_IS_MAIL_DISPLAY (mail_display));
+
+       web_view = E_WEB_VIEW (mail_display);
+
+       if (!gtk_widget_get_visible (GTK_WIDGET (web_view)) ||
+           !e_web_view_has_selection (web_view)) {
+               e_mail_reader_reply_to_message_with_selection (reader, src_message, reply_type, NULL, FALSE);
+               return;
+       }
+
+       if (!src_message) {
+               CamelFolder *folder;
+               GtkWidget *message_list;
+               const gchar *uid;
+               gchar *mail_uri;
+
+               message_list = e_mail_reader_get_message_list (reader);
+
+               uid = MESSAGE_LIST (message_list)->cursor_uid;
+               g_return_if_fail (uid != NULL);
+
+               folder = e_mail_reader_ref_folder (reader);
+               mail_uri = e_mail_part_build_uri (folder, uid, NULL, NULL);
+               part_list = camel_object_bag_get (e_mail_part_list_get_registry (), mail_uri);
+               g_clear_object (&folder);
+               g_free (mail_uri);
+
+               src_message = part_list ? e_mail_part_list_get_message (part_list) : NULL;
+
+               if (!src_message) {
+                       e_mail_reader_reply_to_message_with_selection (reader, src_message, reply_type, NULL, 
FALSE);
+                       g_clear_object (&part_list);
+                       return;
+               }
+       }
+
+       gsd = g_slice_new0 (GetSelectionData);
+       gsd->reader = g_object_ref (reader);
+       gsd->src_message = src_message ? g_object_ref (src_message) : NULL;
+       gsd->reply_type = reply_type;
+
+       ct = camel_mime_part_get_content_type (CAMEL_MIME_PART (src_message));
+
+       if (camel_content_type_is (ct, "text", "plain")) {
+               gsd->selection_is_html = FALSE;
+               e_web_view_jsc_get_selection (WEBKIT_WEB_VIEW (web_view), E_TEXT_FORMAT_PLAIN, NULL,
+                       reply_got_message_selection_jsc_cb, gsd);
+       } else {
+               gsd->selection_is_html = TRUE;
+               e_web_view_jsc_get_selection (WEBKIT_WEB_VIEW (web_view), E_TEXT_FORMAT_HTML, NULL,
+                       reply_got_message_selection_jsc_cb, gsd);
+       }
+
+       g_clear_object (&part_list);
+}
+
 static void
 mail_reader_save_messages_cb (GObject *source_object,
                               GAsyncResult *result,
diff --git a/src/mail/e-mail-reader.c b/src/mail/e-mail-reader.c
index 9898602880..e9edcd857e 100644
--- a/src/mail/e-mail-reader.c
+++ b/src/mail/e-mail-reader.c
@@ -4831,7 +4831,7 @@ mail_reader_update_actions (EMailReader *reader,
 
        action = e_mail_reader_get_action (reader, "mail-search-web");
        gtk_action_set_sensitive (action, single_message_selected &&
-               mail_display && e_web_view_is_selection_active (E_WEB_VIEW (mail_display)));
+               mail_display && e_web_view_has_selection (E_WEB_VIEW (mail_display)));
 
        mail_reader_update_labels_menu (reader);
 }
diff --git a/src/modules/CMakeLists.txt b/src/modules/CMakeLists.txt
index 9e326d99e5..88fefb2f49 100644
--- a/src/modules/CMakeLists.txt
+++ b/src/modules/CMakeLists.txt
@@ -58,35 +58,6 @@ macro(add_evolution_module _name _sourcesvar _depsvar _defsvar _cflagsvar _incdi
        add_simple_module(${_name} ${_sourcesvar} ${_depsvar} ${_defsvar} ${_cflagsvar} ${_incdirsvar} 
${_ldflagsvar} ${moduledir})
 endmacro(add_evolution_module)
 
-macro(add_simple_webextension_module _name _sourcesvar _depsvar _defsvar _cflagsvar _incdirsvar _ldflagsvar 
_destdir)
-       set(wex_deps
-               ${${_depsvar}}
-               edomutils
-       )
-       set(wex_cflags
-               ${${_cflagsvar}}
-               ${WEB_EXTENSIONS_CFLAGS}
-       )
-       set(wex_incdirs
-               ${${_incdirsvar}}
-               ${WEB_EXTENSIONS_INCLUDE_DIRS}
-       )
-       set(wex_ldflags
-               ${${_ldflagsvar}}
-               ${WEB_EXTENSIONS_LDFLAGS}
-       )
-
-       add_simple_module(${_name} ${_sourcesvar} wex_deps ${_defsvar} wex_cflags wex_incdirs wex_ldflags 
${_destdir})
-endmacro(add_simple_webextension_module)
-
-macro(add_webextension_module _name _sourcesvar _depsvar _defsvar _cflagsvar _incdirsvar _ldflagsvar)
-       add_simple_webextension_module(${_name} ${_sourcesvar} ${_depsvar} ${_defsvar} ${_cflagsvar} 
${_incdirsvar} ${_ldflagsvar} "${webextensionsdir}")
-endmacro(add_webextension_module)
-
-macro(add_webextension_editor_module _name _sourcesvar _depsvar _defsvar _cflagsvar _incdirsvar _ldflagsvar)
-       add_simple_webextension_module(${_name} ${_sourcesvar} ${_depsvar} ${_defsvar} ${_cflagsvar} 
${_incdirsvar} ${_ldflagsvar} "${webextensionswebkiteditordir}")
-endmacro(add_webextension_editor_module)
-
 add_subdirectory(addressbook)
 add_subdirectory(calendar)
 add_subdirectory(mail)
diff --git a/src/modules/itip-formatter/e-mail-part-itip.c b/src/modules/itip-formatter/e-mail-part-itip.c
index 03672cc1db..eabdbd7621 100644
--- a/src/modules/itip-formatter/e-mail-part-itip.c
+++ b/src/modules/itip-formatter/e-mail-part-itip.c
@@ -70,23 +70,34 @@ 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;
 
        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) {
+               ItipView *itip_view;
+               GSList *link;
+
+               for (link = pitip->priv->views; link; link = g_slist_next (link)) {
+                       EWebView *used_web_view;
+
+                       itip_view = link->data;
+                       used_web_view = itip_view_ref_web_view (itip_view);
+
+                       if (used_web_view == web_view) {
+                               g_clear_object (&used_web_view);
+                               return;
+                       }
+
+                       g_clear_object (&used_web_view);
+               }
+
                itip_view = itip_view_new (
                        e_mail_part_get_id (part),
                        pitip,
@@ -116,7 +127,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/itip-formatter/itip-view.c b/src/modules/itip-formatter/itip-view.c
index 52e694c15c..66ecb63ddc 100644
--- a/src/modules/itip-formatter/itip-view.c
+++ b/src/modules/itip-formatter/itip-view.c
@@ -32,8 +32,6 @@
 #include "calendar/gui/comp-util.h"
 #include "calendar/gui/itip-utils.h"
 
-#include "web-extensions/e-web-extension-names.h"
-
 #include <mail/em-config.h>
 #include <mail/em-utils.h>
 #include <em-format/e-mail-formatter-utils.h>
@@ -110,11 +108,8 @@ struct _ItipViewPrivate {
 
         gpointer itip_part_ptr; /* not referenced, only for a "reference" to which part this belongs */
 
-       GDBusConnection *dbus_connection;
-       guint web_extension_source_changed_cb_signal_id;
-       guint web_extension_recur_toggled_signal_id;
-
        gchar *part_id;
+       gchar *selected_source_uid;
 
         gchar *error;
        GWeakRef *web_view_weakref;
@@ -183,6 +178,15 @@ struct _ItipViewPrivate {
        guint update_item_error_info_id;
        ItipViewResponse update_item_response;
        GHashTable *real_comps; /* ESource's UID -> ECalComponent stored on the server */
+
+       gchar *state_rsvp_comment;
+       gboolean state_rsvp_check;
+       gboolean state_update_check;
+       gboolean state_recur_check;
+       gboolean state_free_time_check;
+       gboolean state_keep_alarm_check;
+       gboolean state_inherit_alarm_check;
+       gint state_response_id;
 };
 
 enum {
@@ -199,27 +203,6 @@ enum {
 
 static guint signals[LAST_SIGNAL] = { 0 };
 
-static GDBusProxy *
-itip_view_ref_web_extension_proxy (ItipView *view)
-{
-       EWebView *web_view;
-       GDBusProxy *proxy = NULL;
-
-       g_return_val_if_fail (ITIP_IS_VIEW (view), NULL);
-
-       web_view = g_weak_ref_get (view->priv->web_view_weakref);
-       if (!web_view)
-               return NULL;
-
-       proxy = e_web_view_get_web_extension_proxy (web_view);
-       if (proxy)
-               g_object_ref (proxy);
-
-       g_object_unref (web_view);
-
-       return proxy;
-}
-
 static void
 format_date_and_time_x (struct tm *date_tm,
                         struct tm *current_tm,
@@ -663,60 +646,19 @@ set_journal_sender_text (ItipView *view)
        return sender;
 }
 
-static guint64
-itip_view_get_page_id (ItipView *view)
-{
-       EWebView *web_view;
-       guint64 page_id = 0;
-
-       web_view = g_weak_ref_get (view->priv->web_view_weakref);
-       if (web_view) {
-               page_id = webkit_web_view_get_page_id (WEBKIT_WEB_VIEW (web_view));
-               g_object_unref (web_view);
-       }
-
-       return page_id;
-}
-
 static void
 enable_button (ItipView *view,
               const gchar *button_id,
                gboolean enable)
 {
-       GDBusProxy *proxy;
-
-       proxy = itip_view_ref_web_extension_proxy (view);
-
-       if (!proxy)
-               return;
-
-       e_util_invoke_g_dbus_proxy_call_with_error_check (
-               proxy,
-               "ItipEnableButton",
-               g_variant_new ("(tssb)", itip_view_get_page_id (view), view->priv->part_id, button_id, 
enable),
-               NULL);
-
-       g_object_unref (proxy);
-}
-
-static void
-show_button (ItipView *view,
-             const gchar *id)
-{
-       GDBusProxy *proxy;
-
-       proxy = itip_view_ref_web_extension_proxy (view);
-
-       if (!proxy)
-               return;
-
-       e_util_invoke_g_dbus_proxy_call_with_error_check (
-               proxy,
-               "ItipShowButton",
-               g_variant_new ("(tss)", itip_view_get_page_id (view), view->priv->part_id, id),
-               NULL);
+       EWebView *web_view;
 
-       g_object_unref (proxy);
+       web_view = itip_view_ref_web_view (view);
+       if (web_view) {
+               e_web_view_jsc_set_element_disabled (WEBKIT_WEB_VIEW (web_view), view->priv->part_id, 
button_id, !enable,
+                       e_web_view_get_cancellable (web_view));
+               g_object_unref (web_view);
+       }
 }
 
 static void
@@ -724,72 +666,32 @@ hide_element (ItipView *view,
              const gchar *element_id,
               gboolean hide)
 {
-       GDBusProxy *proxy;
-
-       proxy = itip_view_ref_web_extension_proxy (view);
-
-       if (!proxy)
-               return;
-
-       e_util_invoke_g_dbus_proxy_call_with_error_check (
-               proxy,
-               "ItipHideElement",
-               g_variant_new ("(tssb)", itip_view_get_page_id (view), view->priv->part_id, element_id, hide),
-               NULL);
-
-       g_object_unref (proxy);
-}
-
-static gboolean
-element_is_hidden (ItipView *view,
-                   const gchar *element_id)
-{
-       GVariant *result;
-       gboolean hidden;
-       GDBusProxy *proxy;
-
-       proxy = itip_view_ref_web_extension_proxy (view);
-
-       if (!proxy)
-               return FALSE;
-
-       result = e_util_invoke_g_dbus_proxy_call_sync_wrapper_with_error_check (
-                       proxy,
-                       "ItipElementIsHidden",
-                       g_variant_new ("(tss)", itip_view_get_page_id (view), view->priv->part_id, 
element_id),
-                       NULL);
+       EWebView *web_view;
 
-       if (result) {
-               g_variant_get (result, "(b)", &hidden);
-               g_variant_unref (result);
-               g_object_unref (proxy);
-               return hidden;
+       web_view = itip_view_ref_web_view (view);
+       if (web_view) {
+               e_web_view_jsc_set_element_hidden (WEBKIT_WEB_VIEW (web_view), view->priv->part_id, 
element_id, hide,
+                       e_web_view_get_cancellable (web_view));
+               g_object_unref (web_view);
        }
-
-       g_object_unref (proxy);
-
-       return FALSE;
 }
 
+#define show_button(_view, _id) hide_element(_view, _id, FALSE)
+
 static void
 set_inner_html (ItipView *view,
                const gchar *element_id,
                 const gchar *inner_html)
 {
-       GDBusProxy *proxy;
-
-       proxy = itip_view_ref_web_extension_proxy (view);
-
-       if (!proxy)
-               return;
-
-       e_util_invoke_g_dbus_proxy_call_with_error_check (
-               proxy,
-               "ItipElementSetInnerHTML",
-               g_variant_new ("(tsss)", itip_view_get_page_id (view), view->priv->part_id, element_id, 
inner_html),
-               NULL);
+       EWebView *web_view;
 
-       g_object_unref (proxy);
+       web_view = itip_view_ref_web_view (view);
+       if (web_view) {
+               e_web_view_jsc_run_script (WEBKIT_WEB_VIEW (web_view), e_web_view_get_cancellable (web_view),
+                       "EvoItip.SetElementInnerHTML(%s, %s, %s);",
+                       view->priv->part_id, element_id, inner_html);
+               g_object_unref (web_view);
+       }
 }
 
 static void
@@ -797,73 +699,31 @@ input_set_checked (ItipView *view,
                    const gchar *input_id,
                    gboolean checked)
 {
-       GDBusProxy *proxy;
-
-       proxy = itip_view_ref_web_extension_proxy (view);
-
-       if (!proxy)
-               return;
-
-       e_util_invoke_g_dbus_proxy_call_with_error_check (
-               proxy,
-               "ItipInputSetChecked",
-               g_variant_new ("(tssb)", itip_view_get_page_id (view), view->priv->part_id, input_id, 
checked),
-               NULL);
-
-       g_object_unref (proxy);
-}
-
-static gboolean
-input_is_checked (ItipView *view,
-                  const gchar *input_id)
-{
-       GVariant *result;
-       gboolean checked;
-       GDBusProxy *proxy;
-
-       proxy = itip_view_ref_web_extension_proxy (view);
-
-       if (!proxy)
-               return FALSE;
-
-       result = e_util_invoke_g_dbus_proxy_call_sync_wrapper_with_error_check (
-                       proxy,
-                       "ItipInputIsChecked",
-                       g_variant_new ("(tss)", itip_view_get_page_id (view), view->priv->part_id, input_id),
-                       NULL);
+       EWebView *web_view;
 
-       if (result) {
-               g_variant_get (result, "(b)", &checked);
-               g_variant_unref (result);
-               g_object_unref (proxy);
-               return checked;
+       web_view = itip_view_ref_web_view (view);
+       if (web_view) {
+               e_web_view_jsc_set_element_checked (WEBKIT_WEB_VIEW (web_view), view->priv->part_id, 
input_id, checked,
+                       e_web_view_get_cancellable (web_view));
+               g_object_unref (web_view);
        }
-
-       g_object_unref (proxy);
-
-       return FALSE;
 }
 
 static void
 show_checkbox (ItipView *view,
-               const gchar *id,
+               const gchar *element_id,
                gboolean show,
               gboolean update_second)
 {
-       GDBusProxy *proxy;
-
-       proxy = itip_view_ref_web_extension_proxy (view);
-
-       if (!proxy)
-               return;
-
-       e_util_invoke_g_dbus_proxy_call_with_error_check (
-               proxy,
-               "ItipShowCheckbox",
-               g_variant_new ("(tssbb)", itip_view_get_page_id (view), view->priv->part_id, id, show, 
update_second),
-               NULL);
+       EWebView *web_view;
 
-       g_object_unref (proxy);
+       web_view = itip_view_ref_web_view (view);
+       if (web_view) {
+               e_web_view_jsc_run_script (WEBKIT_WEB_VIEW (web_view), e_web_view_get_cancellable (web_view),
+                       "EvoItip.SetShowCheckbox(%s, %s, %x, %x);",
+                       view->priv->part_id, element_id, show, update_second);
+               g_object_unref (web_view);
+       }
 }
 
 static void
@@ -871,20 +731,15 @@ set_area_text (ItipView *view,
                const gchar *id,
                const gchar *text)
 {
-       GDBusProxy *proxy;
-
-       proxy = itip_view_ref_web_extension_proxy (view);
-
-       if (!proxy)
-               return;
-
-       e_util_invoke_g_dbus_proxy_call_with_error_check (
-               proxy,
-               "ItipSetAreaText",
-               g_variant_new ("(tsss)", itip_view_get_page_id (view), view->priv->part_id, id, text ? text : 
""),
-               NULL);
+       EWebView *web_view;
 
-       g_object_unref (proxy);
+       web_view = itip_view_ref_web_view (view);
+       if (web_view) {
+               e_web_view_jsc_run_script (WEBKIT_WEB_VIEW (web_view), e_web_view_get_cancellable (web_view),
+                       "EvoItip.SetAreaText(%s, %s, %s);",
+                       view->priv->part_id, id, text);
+               g_object_unref (web_view);
+       }
 }
 
 static void
@@ -919,7 +774,7 @@ static void
 update_start_end_times (ItipView *view)
 {
        ItipViewPrivate *priv;
-       GDBusProxy *proxy;
+       EWebView *web_view;
        gchar buffer[256];
        time_t now;
        struct tm *now_tm;
@@ -964,46 +819,98 @@ update_start_end_times (ItipView *view)
        }
        #undef is_same
 
-       proxy = itip_view_ref_web_extension_proxy (view);
+       web_view = itip_view_ref_web_view (view);
 
-       if (!proxy)
+       if (!web_view)
                return;
 
        if (priv->start_header && priv->start_label) {
-               e_util_invoke_g_dbus_proxy_call_with_error_check (
-                       proxy,
-                       "ItipUpdateTimes",
-                       g_variant_new (
-                               "(tssss)",
-                               itip_view_get_page_id (view),
-                               view->priv->part_id,
-                               TABLE_ROW_START_DATE,
-                               priv->start_header,
-                               priv->start_label),
-                       NULL);
-       } else
+               e_web_view_jsc_run_script (WEBKIT_WEB_VIEW (web_view), e_web_view_get_cancellable (web_view),
+                       "EvoItip.UpdateTimes(%s, %s, %s, %s);",
+                       view->priv->part_id,
+                       TABLE_ROW_START_DATE,
+                       priv->start_header,
+                       priv->start_label);
+       } else {
                hide_element (view, TABLE_ROW_START_DATE, TRUE);
+       }
 
        if (priv->end_header && priv->end_label) {
-               e_util_invoke_g_dbus_proxy_call_with_error_check (
-                       proxy,
-                       "ItipUpdateTimes",
-                       g_variant_new (
-                               "(tssss)",
-                               itip_view_get_page_id (view),
-                               view->priv->part_id,
-                               TABLE_ROW_END_DATE,
-                               priv->end_header,
-                               priv->end_label),
-                       NULL);
-       } else
+               e_web_view_jsc_run_script (WEBKIT_WEB_VIEW (web_view), e_web_view_get_cancellable (web_view),
+                       "EvoItip.UpdateTimes(%s, %s, %s, %s);",
+                       view->priv->part_id,
+                       TABLE_ROW_END_DATE,
+                       priv->end_header,
+                       priv->end_label);
+       } else {
                hide_element (view, TABLE_ROW_END_DATE, TRUE);
+       }
+
+       g_object_unref (web_view);
+}
+
+static void
+itip_view_get_state_cb (GObject *source_object,
+                       GAsyncResult *result,
+                       gpointer user_data)
+{
+       ItipView *view;
+       GWeakRef *wkrf = user_data;
+
+       g_return_if_fail (E_IS_WEB_VIEW (source_object));
+       g_return_if_fail (wkrf != NULL);
+
+       view = g_weak_ref_get (wkrf);
+       if (view) {
+               WebKitJavascriptResult *js_result;
+               GError *error = NULL;
+
+               g_clear_pointer (&view->priv->state_rsvp_comment, g_free);
+
+               js_result = webkit_web_view_run_javascript_finish (WEBKIT_WEB_VIEW (source_object), result, 
&error);
+
+               if (error) {
+                       if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED) &&
+                           (!g_error_matches (error, WEBKIT_JAVASCRIPT_ERROR, 
WEBKIT_JAVASCRIPT_ERROR_SCRIPT_FAILED) ||
+                            /* WebKit can return empty error message, thus ignore those. */
+                            (error->message && *(error->message))))
+                               g_warning ("Failed to call 'ItipView.GetState()' function: %s:%d: %s", 
g_quark_to_string (error->domain), error->code, error->message);
+                       g_clear_error (&error);
+               }
+
+               if (js_result) {
+                       JSCException *exception;
+                       JSCValue *value;
+
+                       value = webkit_javascript_result_get_js_value (js_result);
+                       exception = jsc_context_get_exception (jsc_value_get_context (value));
+
+                       if (exception)
+                               g_warning ("Failed to call 'ItipView.GetState()': %s", 
jsc_exception_get_message (exception));
+
+                       view->priv->state_rsvp_comment = e_web_view_jsc_get_object_property_string (value, 
"rsvp-comment", NULL);
+                       view->priv->state_rsvp_check = e_web_view_jsc_get_object_property_boolean (value, 
"rsvp-check", FALSE);
+                       view->priv->state_update_check = e_web_view_jsc_get_object_property_boolean (value, 
"update-check", FALSE);
+                       view->priv->state_recur_check = e_web_view_jsc_get_object_property_boolean (value, 
"recur-check", FALSE);
+                       view->priv->state_free_time_check = e_web_view_jsc_get_object_property_boolean 
(value, "free-time-check", FALSE);
+                       view->priv->state_keep_alarm_check = e_web_view_jsc_get_object_property_boolean 
(value, "keep-alarm-check", FALSE);
+                       view->priv->state_inherit_alarm_check = e_web_view_jsc_get_object_property_boolean 
(value, "inherit-alarm-check", FALSE);
 
-       g_object_unref (proxy);
+                       webkit_javascript_result_unref (js_result);
+
+                       g_signal_emit (view, signals[RESPONSE], 0, view->priv->state_response_id);
+               }
+
+               g_object_unref (view);
+       }
+
+       e_weak_ref_free (wkrf);
 }
 
 static void
 itip_view_itip_button_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,
@@ -1026,8 +933,16 @@ itip_view_itip_button_clicked_cb (EWebView *web_view,
 
        if (can_use) {
                gint response = atoi (element_value);
+               gchar *script;
 
-               g_signal_emit (view, signals[RESPONSE], 0, response);
+               view->priv->state_response_id = response;
+
+               script = e_web_view_jsc_printf_script ("EvoItip.GetState(%s);", view->priv->part_id);
+
+               webkit_web_view_run_javascript (WEBKIT_WEB_VIEW (web_view),
+                       script, e_web_view_get_cancellable (web_view), itip_view_get_state_cb, e_weak_ref_new 
(view));
+
+               g_free (script);
        }
 }
 
@@ -1048,27 +963,13 @@ itip_view_register_clicked_listener (ItipView *view)
 }
 
 static void
-recur_toggled_signal_cb (GDBusConnection *connection,
-                         const gchar *sender_name,
-                         const gchar *object_path,
-                         const gchar *interface_name,
-                         const gchar *signal_name,
-                         GVariant *parameters,
-                         ItipView *view)
+itip_set_selected_source_uid (ItipView *view,
+                             const gchar *uid)
 {
-       guint64 page_id = 0;
-       const gchar *part_id = NULL;
-
-       g_return_if_fail (ITIP_IS_VIEW (view));
-
-       if (g_strcmp0 (signal_name, "ItipRecurToggled") != 0)
-               return;
-
-       g_variant_get (parameters, "(t&s)", &page_id, &part_id);
-
-       if (itip_view_get_page_id (view) == page_id &&
-           g_strcmp0 (view->priv->part_id, part_id) == 0)
-               itip_view_set_mode (view, view->priv->mode);
+       if (g_strcmp0 (view->priv->selected_source_uid, uid) != 0) {
+               g_free (view->priv->selected_source_uid);
+               view->priv->selected_source_uid = g_strdup (uid);
+       }
 }
 
 static void
@@ -1086,31 +987,6 @@ source_changed_cb (ItipView *view)
        }
 }
 
-static void
-source_changed_cb_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)
-{
-       ItipView *view = user_data;
-       guint64 page_id = 0;
-       const gchar *part_id = NULL;
-
-       g_return_if_fail (ITIP_IS_VIEW (view));
-
-       if (g_strcmp0 (signal_name, "ItipSourceChanged") != 0)
-               return;
-
-       g_variant_get (parameters, "(t&s)", &page_id, &part_id);
-
-       if (itip_view_get_page_id (view) == page_id &&
-           g_strcmp0 (view->priv->part_id, part_id) == 0)
-               source_changed_cb (view);
-}
-
 static void
 append_checkbox_table_row (GString *buffer,
                            const gchar *name,
@@ -1177,13 +1053,13 @@ append_info_item_row (ItipView *view,
                       const gchar *table_id,
                       ItipViewInfoItem *item)
 {
-       GDBusProxy *proxy;
+       EWebView *web_view;
        const gchar *icon_name;
        gchar *row_id;
 
-       proxy = itip_view_ref_web_extension_proxy (view);
+       web_view = itip_view_ref_web_view (view);
 
-       if (!proxy)
+       if (!web_view)
                return;
 
        switch (item->type) {
@@ -1207,20 +1083,15 @@ append_info_item_row (ItipView *view,
 
        row_id = g_strdup_printf ("%s_row_%d", table_id, item->id);
 
-       e_util_invoke_g_dbus_proxy_call_with_error_check (
-               proxy,
-               "ItipAppendInfoItemRow",
-               g_variant_new (
-                       "(tsssss)",
-                       itip_view_get_page_id (view),
-                       view->priv->part_id,
-                       table_id,
-                       row_id,
-                       icon_name,
-                       item->message),
-               NULL);
+       e_web_view_jsc_run_script (WEBKIT_WEB_VIEW (web_view), e_web_view_get_cancellable (web_view),
+               "EvoItip.AppendInfoRow(%s, %s, %s, %s, %s);",
+               view->priv->part_id,
+               table_id,
+               row_id,
+               icon_name,
+               item->message);
 
-       g_object_unref (proxy);
+       g_object_unref (web_view);
        g_free (row_id);
 
        d (printf ("Added row %s_row_%d ('%s')\n", table_id, item->id, item->message));
@@ -1231,23 +1102,22 @@ remove_info_item_row (ItipView *view,
                       const gchar *table_id,
                       guint id)
 {
+       EWebView *web_view;
        gchar *row_id;
-       GDBusProxy *proxy;
 
-       proxy = itip_view_ref_web_extension_proxy (view);
+       web_view = itip_view_ref_web_view (view);
 
-       if (!proxy)
+       if (!web_view)
                return;
 
        row_id = g_strdup_printf ("%s_row_%d", table_id, id);
 
-       e_util_invoke_g_dbus_proxy_call_with_error_check (
-               proxy,
-               "ItipRemoveElement",
-               g_variant_new ("(tss)", itip_view_get_page_id (view), view->priv->part_id, row_id),
-               NULL);
+       e_web_view_jsc_run_script (WEBKIT_WEB_VIEW (web_view), e_web_view_get_cancellable (web_view),
+               "EvoItip.RemoveInfoRow(%s, %s);",
+               view->priv->part_id,
+               row_id);
 
-       g_object_unref (proxy);
+       g_object_unref (web_view);
        g_free (row_id);
 
        d (printf ("Removed row %s_row_%d\n", table_id, id));
@@ -1345,30 +1215,32 @@ static void
 itip_view_rebuild_source_list (ItipView *view)
 {
        ESourceRegistry *registry;
-       GDBusProxy *proxy;
+       EWebView *web_view;
        GList *list, *link;
+       GString *script;
        const gchar *extension_name;
 
        d (printf ("Assigning a new source list!\n"));
 
-       proxy = itip_view_ref_web_extension_proxy (view);
+       web_view = itip_view_ref_web_view (view);
 
-       if (!proxy)
+       if (!web_view)
                return;
 
        registry = view->priv->registry;
        extension_name = itip_view_get_extension_name (view);
 
        if (!extension_name) {
-               g_object_unref (proxy);
+               g_object_unref (web_view);
                return;
        }
 
-       e_util_invoke_g_dbus_proxy_call_with_error_check (
-               proxy,
-               "ItipElementRemoveChildNodes",
-               g_variant_new ("(tss)", itip_view_get_page_id (view), view->priv->part_id, SELECT_ESOURCE),
-               NULL);
+       script = g_string_sized_new (1024);
+
+       e_web_view_jsc_printf_script_gstring (script,
+               "EvoItip.RemoveChildNodes(%s, %s);",
+               view->priv->part_id,
+               SELECT_ESOURCE);
 
        list = e_source_registry_list_enabled (registry, extension_name);
 
@@ -1379,25 +1251,23 @@ itip_view_rebuild_source_list (ItipView *view)
                parent = e_source_registry_ref_source (
                        registry, e_source_get_parent (source));
 
-               e_util_invoke_g_dbus_proxy_call_with_error_check (
-                       proxy,
-                       "ItipRebuildSourceList",
-                       g_variant_new (
-                               "(tsssssb)",
-                               itip_view_get_page_id (view),
-                               view->priv->part_id,
-                               e_source_get_uid (parent),
-                               e_source_get_display_name (parent),
-                               e_source_get_uid (source),
-                               e_source_get_display_name (source),
-                               e_source_get_writable (source)),
-                       NULL);
+               e_web_view_jsc_printf_script_gstring (script,
+                       "EvoItip.AddToSourceList(%s, %s, %s, %s, %s, %x);",
+                       view->priv->part_id,
+                       e_source_get_uid (parent),
+                       e_source_get_display_name (parent),
+                       e_source_get_uid (source),
+                       e_source_get_display_name (source),
+                       e_source_get_writable (source));
 
                g_object_unref (parent);
        }
 
+       e_web_view_jsc_run_script_take (WEBKIT_WEB_VIEW (web_view), g_string_free (script, FALSE),
+               e_web_view_get_cancellable (web_view));
+
        g_list_free_full (list, (GDestroyNotify) g_object_unref);
-       g_object_unref (proxy);
+       g_object_unref (web_view);
 
        source_changed_cb (view);
 }
@@ -1438,25 +1308,6 @@ itip_view_source_removed_cb (ESourceRegistry *registry,
                itip_view_rebuild_source_list (view);
 }
 
-static void
-itip_view_unregister_dbus_signals (ItipView *view)
-{
-       g_return_if_fail (ITIP_IS_VIEW (view));
-
-       if (view->priv->dbus_connection && !g_dbus_connection_is_closed (view->priv->dbus_connection)) {
-               if (view->priv->web_extension_recur_toggled_signal_id)
-                       g_dbus_connection_signal_unsubscribe (view->priv->dbus_connection, 
view->priv->web_extension_recur_toggled_signal_id);
-
-               if (view->priv->web_extension_source_changed_cb_signal_id)
-                       g_dbus_connection_signal_unsubscribe (view->priv->dbus_connection, 
view->priv->web_extension_source_changed_cb_signal_id);
-       }
-
-       view->priv->web_extension_recur_toggled_signal_id = 0;
-       view->priv->web_extension_source_changed_cb_signal_id = 0;
-
-       g_clear_object (&view->priv->dbus_connection);
-}
-
 static void
 itip_view_set_client_cache (ItipView *view,
                             EClientCache *client_cache)
@@ -1536,11 +1387,8 @@ itip_view_dispose (GObject *object)
                priv->source_removed_handler_id = 0;
        }
 
-       itip_view_unregister_dbus_signals (ITIP_VIEW (object));
-
        g_clear_object (&priv->client_cache);
        g_clear_object (&priv->registry);
-       g_clear_object (&priv->dbus_connection);
        g_clear_object (&priv->cancellable);
        g_clear_object (&priv->comp);
 
@@ -1577,6 +1425,7 @@ itip_view_finalize (GObject *object)
        g_free (priv->description);
        g_free (priv->error);
        g_free (priv->part_id);
+       g_free (priv->selected_source_uid);
 
        for (iter = priv->lower_info_items; iter; iter = iter->next) {
                ItipViewInfoItem *item = iter->data;
@@ -1606,6 +1455,7 @@ itip_view_finalize (GObject *object)
        g_free (priv->delegator_name);
        g_free (priv->my_address);
        g_free (priv->message_uid);
+       g_free (priv->state_rsvp_comment);
 
        g_clear_object (&priv->folder);
        g_clear_object (&priv->message);
@@ -1919,65 +1769,6 @@ itip_view_write_for_printing (ItipView *view,
        g_string_append (buffer, "</div>");
 }
 
-static void
-itip_view_web_extension_proxy_notify_cb (GObject *web_view,
-                                        GParamSpec *param,
-                                        gpointer user_data)
-{
-       ItipView *view = user_data;
-       GDBusConnection *connection;
-       GDBusProxy *proxy;
-
-       if (!view)
-               return;
-
-       itip_view_unregister_dbus_signals (view);
-
-       proxy = e_web_view_get_web_extension_proxy (E_WEB_VIEW (web_view));
-       if (!proxy)
-               return;
-
-       connection = g_dbus_proxy_get_connection (proxy);
-       if (!connection || g_dbus_connection_is_closed (connection))
-               return;
-
-       view->priv->dbus_connection = g_object_ref (connection);
-
-       view->priv->web_extension_source_changed_cb_signal_id =
-               g_dbus_connection_signal_subscribe (
-                       view->priv->dbus_connection,
-                       g_dbus_proxy_get_name (proxy),
-                       E_WEB_EXTENSION_INTERFACE,
-                       "ItipSourceChanged",
-                       E_WEB_EXTENSION_OBJECT_PATH,
-                       NULL,
-                       G_DBUS_SIGNAL_FLAGS_NONE,
-                       source_changed_cb_signal_cb,
-                       view,
-                       NULL);
-
-       view->priv->web_extension_recur_toggled_signal_id =
-               g_dbus_connection_signal_subscribe (
-                       view->priv->dbus_connection,
-                       g_dbus_proxy_get_name (proxy),
-                       E_WEB_EXTENSION_INTERFACE,
-                       "ItipRecurToggled",
-                       E_WEB_EXTENSION_OBJECT_PATH,
-                       NULL,
-                       G_DBUS_SIGNAL_FLAGS_NONE,
-                       (GDBusSignalCallback) recur_toggled_signal_cb,
-                       view,
-                       NULL);
-
-       e_util_invoke_g_dbus_proxy_call_with_error_check (
-               proxy,
-               "ItipCreateDOMBindings",
-               g_variant_new ("(ts)", itip_view_get_page_id (view), view->priv->part_id),
-               NULL);
-
-       itip_view_init_view (view);
-}
-
 static void
 itip_view_init (ItipView *view)
 {
@@ -2022,23 +1813,22 @@ void
 itip_view_set_mode (ItipView *view,
                     ItipViewMode mode)
 {
-       GDBusProxy *proxy;
+       EWebView *web_view;
        g_return_if_fail (ITIP_IS_VIEW (view));
 
        view->priv->mode = mode;
 
        set_sender_text (view);
 
-       proxy = itip_view_ref_web_extension_proxy (view);
+       web_view = itip_view_ref_web_view (view);
 
-       if (!proxy)
+       if (!web_view)
                return;
 
-       e_util_invoke_g_dbus_proxy_call_with_error_check (
-               proxy,
-               "ItipElementHideChildNodes",
-               g_variant_new ("(tss)", itip_view_get_page_id (view), view->priv->part_id, TABLE_ROW_BUTTONS),
-               NULL);
+       e_web_view_jsc_run_script (WEBKIT_WEB_VIEW (web_view), e_web_view_get_cancellable (web_view),
+               "EvoItip.HideButtons(%s, %s);",
+               view->priv->part_id,
+               TABLE_ROW_BUTTONS);
 
        view->priv->is_recur_set = itip_view_get_recur_check_state (view);
 
@@ -2083,7 +1873,7 @@ itip_view_set_mode (ItipView *view,
                break;
        }
 
-       g_object_unref (proxy);
+       g_object_unref (web_view);
 }
 
 ItipViewMode
@@ -2098,16 +1888,16 @@ void
 itip_view_set_item_type (ItipView *view,
                          ECalClientSourceType type)
 {
-       GDBusProxy *proxy;
+       EWebView *web_view;
        const gchar *header;
        gchar *access_key, *html_label;
 
        g_return_if_fail (ITIP_IS_VIEW (view));
 
        view->priv->type = type;
-       proxy = itip_view_ref_web_extension_proxy (view);
+       web_view = itip_view_ref_web_view (view);
 
-       if (!proxy)
+       if (!web_view)
                return;
 
        switch (view->priv->type) {
@@ -2127,21 +1917,21 @@ itip_view_set_item_type (ItipView *view,
 
        if (!header) {
                set_sender_text (view);
-               g_object_unref (proxy);
+               g_object_unref (web_view);
                return;
        }
 
        html_label = e_mail_formatter_parse_html_mnemonics (header, &access_key);
 
-       e_util_invoke_g_dbus_proxy_call_with_error_check (
-               proxy,
-               "ItipElementSetAccessKey",
-               g_variant_new ("(tsss)", itip_view_get_page_id (view), view->priv->part_id, 
TABLE_ROW_ESCB_LABEL, access_key),
-               NULL);
+       e_web_view_jsc_run_script (WEBKIT_WEB_VIEW (web_view), e_web_view_get_cancellable (web_view),
+               "EvoItip.SetElementAccessKey(%s, %s, %s);",
+               view->priv->part_id,
+               TABLE_ROW_ESCB_LABEL,
+               access_key);
 
        set_inner_html (view, TABLE_ROW_ESCB_LABEL, html_label);
 
-       g_object_unref (proxy);
+       g_object_unref (web_view);
        g_free (html_label);
 
        if (access_key)
@@ -2829,7 +2619,7 @@ itip_view_set_source (ItipView *view,
                       ESource *source)
 {
        ESource *selected_source;
-       GDBusProxy *proxy;
+       EWebView *web_view;
 
        g_return_if_fail (ITIP_IS_VIEW (view));
 
@@ -2852,110 +2642,56 @@ itip_view_set_source (ItipView *view,
        if (selected_source != NULL)
                g_object_unref (selected_source);
 
-       proxy = itip_view_ref_web_extension_proxy (view);
+       web_view = itip_view_ref_web_view (view);
 
-       if (!proxy)
+       if (!web_view)
                return;
 
-       e_util_invoke_g_dbus_proxy_call_with_error_check (
-               proxy,
-               "ItipEnableSelect",
-               g_variant_new ("(tssb)", itip_view_get_page_id (view), view->priv->part_id, SELECT_ESOURCE, 
TRUE),
-               NULL);
+       e_web_view_jsc_set_element_disabled (WEBKIT_WEB_VIEW (web_view),
+               view->priv->part_id, SELECT_ESOURCE, FALSE,
+               e_web_view_get_cancellable (web_view));
 
-       e_util_invoke_g_dbus_proxy_call_with_error_check (
-               proxy,
-               "ItipSelectSetSelected",
-               g_variant_new ("(tsss)", itip_view_get_page_id (view), view->priv->part_id, SELECT_ESOURCE, 
e_source_get_uid (source)),
-               NULL);
+       e_web_view_jsc_run_script (WEBKIT_WEB_VIEW (web_view), e_web_view_get_cancellable (web_view),
+               "EvoItip.SetSelectSelected(%s, %s, %s);",
+               view->priv->part_id,
+               SELECT_ESOURCE,
+               e_source_get_uid (source));
+
+       itip_set_selected_source_uid (view, e_source_get_uid (source));
 
        source_changed_cb (view);
-       g_object_unref (proxy);
+       g_object_unref (web_view);
 }
 
 ESource *
 itip_view_ref_source (ItipView *view)
 {
-       ESource *source = NULL;
-       gboolean disable = FALSE, enabled = FALSE;
-       GDBusProxy *proxy;
-       GVariant *result;
-
        g_return_val_if_fail (ITIP_IS_VIEW (view), NULL);
 
-       proxy = itip_view_ref_web_extension_proxy (view);
-
-       if (!proxy)
+       if (!view->priv->selected_source_uid || !*view->priv->selected_source_uid)
                return NULL;
 
-       result = e_util_invoke_g_dbus_proxy_call_sync_wrapper_with_error_check (
-                       proxy,
-                       "ItipSelectIsEnabled",
-                       g_variant_new ("(tss)", itip_view_get_page_id (view), view->priv->part_id, 
SELECT_ESOURCE),
-                       NULL);
-
-       if (result) {
-               g_variant_get (result, "(b)", &enabled);
-               g_variant_unref (result);
-       }
-
-       if (!enabled) {
-               e_util_invoke_g_dbus_proxy_call_with_error_check (
-                       proxy,
-                       "ItipEnableSelect",
-                       g_variant_new ("(tssb)", itip_view_get_page_id (view), view->priv->part_id, 
SELECT_ESOURCE, TRUE),
-                       NULL);
-
-               disable = TRUE;
-       }
-
-       result = e_util_invoke_g_dbus_proxy_call_sync_wrapper_with_error_check (
-               proxy,
-               "ItipSelectGetValue",
-               g_variant_new ("(tss)", itip_view_get_page_id (view), view->priv->part_id, SELECT_ESOURCE),
-               NULL);
-
-       if (result) {
-               const gchar *uid;
-
-               g_variant_get (result, "(&s)", &uid);
-               source = e_source_registry_ref_source (view->priv->registry, uid);
-               g_variant_unref (result);
-       }
-
-       if (disable) {
-               e_util_invoke_g_dbus_proxy_call_with_error_check (
-                       proxy,
-                       "ItipEnableSelect",
-                       g_variant_new ("(tssb)", itip_view_get_page_id (view), view->priv->part_id, 
SELECT_ESOURCE, FALSE),
-                       NULL);
-       }
-
-       g_object_unref (proxy);
-
-       return source;
+       return e_source_registry_ref_source (view->priv->registry, view->priv->selected_source_uid);
 }
 
 void
 itip_view_set_rsvp (ItipView *view,
                     gboolean rsvp)
 {
-       GDBusProxy *proxy;
+       EWebView *web_view;
 
-       proxy = itip_view_ref_web_extension_proxy (view);
+       web_view = itip_view_ref_web_view (view);
 
-       if (!proxy)
+       if (!web_view)
                return;
 
        input_set_checked (view, CHECKBOX_RSVP, rsvp);
 
-       e_util_invoke_g_dbus_proxy_call_with_error_check (
-               proxy,
-               "ItipEnableTextArea",
-               g_variant_new ("(tssb)", itip_view_get_page_id (view), view->priv->part_id, 
TEXTAREA_RSVP_COMMENT, !rsvp),
-               NULL);
+       e_web_view_jsc_set_element_disabled (WEBKIT_WEB_VIEW (web_view),
+               view->priv->part_id, TEXTAREA_RSVP_COMMENT, rsvp,
+               e_web_view_get_cancellable (web_view));
 
-       g_object_unref (proxy);
+       g_object_unref (web_view);
 }
 
 gboolean
@@ -2963,7 +2699,7 @@ itip_view_get_rsvp (ItipView *view)
 {
        g_return_val_if_fail (ITIP_IS_VIEW (view), FALSE);
 
-       return input_is_checked (view, CHECKBOX_RSVP);
+       return view->priv->state_rsvp_check;
 }
 
 void
@@ -2976,14 +2712,6 @@ itip_view_set_show_rsvp_check (ItipView *view,
        hide_element (view, TABLE_ROW_RSVP_COMMENT, !show);
 }
 
-gboolean
-itip_view_get_show_rsvp_check (ItipView *view)
-{
-       g_return_val_if_fail (ITIP_IS_VIEW (view), FALSE);
-
-       return !element_is_hidden (view, CHECKBOX_RSVP);
-}
-
 void
 itip_view_set_update (ItipView *view,
                       gboolean update)
@@ -2998,7 +2726,7 @@ itip_view_get_update (ItipView *view)
 {
        g_return_val_if_fail (ITIP_IS_VIEW (view), FALSE);
 
-       return input_is_checked (view, CHECKBOX_UPDATE);
+       return view->priv->state_update_check;
 }
 
 void
@@ -3010,72 +2738,32 @@ itip_view_set_show_update_check (ItipView *view,
        show_checkbox (view, CHECKBOX_UPDATE, show, FALSE);
 }
 
-gboolean
-itip_view_get_show_update_check (ItipView *view)
-{
-       g_return_val_if_fail (ITIP_IS_VIEW (view), FALSE);
-
-       return !element_is_hidden (view, CHECKBOX_UPDATE);
-}
-
 void
 itip_view_set_rsvp_comment (ItipView *view,
                             const gchar *comment)
 {
-       GDBusProxy *proxy;
+       EWebView *web_view;
 
-       proxy = itip_view_ref_web_extension_proxy (view);
+       web_view = itip_view_ref_web_view (view);
 
-       if (!proxy)
+       if (!web_view)
                return;
 
-       if (comment) {
-               e_util_invoke_g_dbus_proxy_call_with_error_check (
-                       proxy,
-                       "ItipTextAreaSetValue",
-                       g_variant_new ("(tsss)", itip_view_get_page_id (view), view->priv->part_id, 
TEXTAREA_RSVP_COMMENT, comment),
-                       NULL);
-       }
+       e_web_view_jsc_run_script (WEBKIT_WEB_VIEW (web_view), e_web_view_get_cancellable (web_view),
+               "EvoItip.SetAreaText(%s, %s, %s);",
+               view->priv->part_id,
+               TEXTAREA_RSVP_COMMENT,
+               comment);
 
-       g_object_unref (proxy);
+       g_object_unref (web_view);
 }
 
-gchar *
+const gchar *
 itip_view_get_rsvp_comment (ItipView *view)
 {
-       GDBusProxy *proxy;
-       GVariant *result;
-
        g_return_val_if_fail (ITIP_IS_VIEW (view), NULL);
 
-       proxy = itip_view_ref_web_extension_proxy (view);
-
-       if (!proxy)
-               return NULL;
-
-       if (element_is_hidden (view, TEXTAREA_RSVP_COMMENT)) {
-               g_object_unref (proxy);
-               return NULL;
-       }
-
-       result = e_util_invoke_g_dbus_proxy_call_sync_wrapper_with_error_check (
-               proxy,
-               "ItipTextAreaGetValue",
-               g_variant_new ("(tss)", itip_view_get_page_id (view), view->priv->part_id, 
TEXTAREA_RSVP_COMMENT),
-               NULL);
-
-       if (result) {
-               gchar *value;
-
-               g_variant_get (result, "(s)", &value);
-               g_variant_unref (result);
-               g_object_unref (proxy);
-               return value;
-       }
-
-       g_object_unref (proxy);
-
-       return NULL;
+       return view->priv->state_rsvp_comment;
 }
 
 void
@@ -3091,25 +2779,23 @@ void
 itip_view_set_buttons_sensitive (ItipView *view,
                                  gboolean sensitive)
 {
-       GDBusProxy *proxy;
+       EWebView *web_view;
 
        g_return_if_fail (ITIP_IS_VIEW (view));
 
        d (printf ("Settings buttons %s\n", sensitive ? "sensitive" : "insensitive"));
 
        view->priv->buttons_sensitive = sensitive;
-       proxy = itip_view_ref_web_extension_proxy (view);
 
-       if (!proxy)
-               return;
-
-       e_util_invoke_g_dbus_proxy_call_with_error_check (
-               proxy,
-               "ItipSetButtonsSensitive",
-               g_variant_new ("(tsb)", itip_view_get_page_id (view), view->priv->part_id, sensitive),
-               NULL);
+       web_view = itip_view_ref_web_view (view);
 
-       g_object_unref (proxy);
+       if (web_view) {
+               e_web_view_jsc_run_script (WEBKIT_WEB_VIEW (web_view), e_web_view_get_cancellable (web_view),
+                       "EvoItip.SetButtonsDisabled(%s, %x);",
+                       view->priv->part_id,
+                       !sensitive);
+               g_object_unref (web_view);
+       }
 }
 
 gboolean
@@ -3125,7 +2811,7 @@ itip_view_get_recur_check_state (ItipView *view)
 {
        g_return_val_if_fail (ITIP_IS_VIEW (view), FALSE);
 
-       return input_is_checked (view, CHECKBOX_RECUR);
+       return view->priv->state_recur_check;
 }
 
 void
@@ -3151,7 +2837,7 @@ itip_view_get_free_time_check_state (ItipView *view)
 {
        g_return_val_if_fail (ITIP_IS_VIEW (view), FALSE);
 
-       return input_is_checked (view, CHECKBOX_FREE_TIME);
+       return view->priv->state_free_time_check;
 }
 
 void
@@ -3179,7 +2865,7 @@ itip_view_get_keep_alarm_check_state (ItipView *view)
 {
        g_return_val_if_fail (ITIP_IS_VIEW (view), FALSE);
 
-       return input_is_checked (view, CHECKBOX_KEEP_ALARM);
+       return view->priv->state_keep_alarm_check;
 }
 
 void
@@ -3196,7 +2882,7 @@ itip_view_get_inherit_alarm_check_state (ItipView *view)
 {
        g_return_val_if_fail (ITIP_IS_VIEW (view), FALSE);
 
-       return input_is_checked (view, CHECKBOX_INHERIT_ALARM);
+       return view->priv->state_inherit_alarm_check;
 }
 
 void
@@ -4926,7 +4612,7 @@ finish_message_delete_with_rsvp (ItipView *view,
                ICalComponent *icomp;
                ICalProperty *prop;
                const gchar *attendee;
-               gchar *comment;
+               const gchar *comment;
                GSList *l, *list = NULL;
                gboolean found;
 
@@ -4983,7 +4669,6 @@ finish_message_delete_with_rsvp (ItipView *view,
                        e_cal_component_set_comments (comp, &comments);
 
                        e_cal_component_text_free (text);
-                       g_free (comment);
                }
 
                if (itip_send_comp_sync (
@@ -6939,6 +6624,55 @@ itip_view_init_view (ItipView *view)
        }
 }
 
+static void
+itip_source_changed_cb (WebKitUserContentManager *manager,
+                       WebKitJavascriptResult *js_result,
+                       gpointer user_data)
+{
+       ItipView *view = user_data;
+       JSCValue *jsc_value;
+       gchar *iframe_id, *source_uid;
+
+       g_return_if_fail (view != 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_object (jsc_value));
+
+       iframe_id = e_web_view_jsc_get_object_property_string (jsc_value, "iframe-id", NULL);
+       source_uid = e_web_view_jsc_get_object_property_string (jsc_value, "source-uid", NULL);
+
+       if (g_strcmp0 (iframe_id, view->priv->part_id) == 0) {
+               itip_set_selected_source_uid (view, source_uid);
+               source_changed_cb (view);
+       }
+
+       g_free (iframe_id);
+}
+
+static void
+itip_recur_toggled_cb (WebKitUserContentManager *manager,
+                      WebKitJavascriptResult *js_result,
+                      gpointer user_data)
+{
+       ItipView *view = user_data;
+       JSCValue *jsc_value;
+       gchar *iframe_id;
+
+       g_return_if_fail (view != 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_string (jsc_value));
+
+       iframe_id = jsc_value_to_string (jsc_value);
+
+       if (g_strcmp0 (iframe_id, view->priv->part_id) == 0)
+               itip_view_set_mode (view, view->priv->mode);
+
+       g_free (iframe_id);
+}
+
 void
 itip_view_set_web_view (ItipView *view,
                        EWebView *web_view)
@@ -6950,13 +6684,24 @@ itip_view_set_web_view (ItipView *view,
        g_weak_ref_set (view->priv->web_view_weakref, web_view);
 
        if (web_view) {
-               g_signal_connect_object (web_view, "notify::web-extension-proxy",
-                       G_CALLBACK (itip_view_web_extension_proxy_notify_cb), view, 0);
+               WebKitUserContentManager *manager;
 
-               if (e_web_view_get_web_extension_proxy (web_view))
-                       itip_view_web_extension_proxy_notify_cb (G_OBJECT (web_view), NULL, view);
-       } else {
-               itip_view_unregister_dbus_signals (view);
+               manager = webkit_web_view_get_user_content_manager (WEBKIT_WEB_VIEW (web_view));
+
+               g_signal_connect_object (manager, "script-message-received::itipSourceChanged",
+                       G_CALLBACK (itip_source_changed_cb), view, 0);
+
+               g_signal_connect_object (manager, "script-message-received::itipRecurToggled",
+                       G_CALLBACK (itip_recur_toggled_cb), view, 0);
+
+               webkit_user_content_manager_register_script_message_handler (manager, "itipSourceChanged");
+               webkit_user_content_manager_register_script_message_handler (manager, "itipRecurToggled");
+
+               e_web_view_jsc_run_script (WEBKIT_WEB_VIEW (web_view), e_web_view_get_cancellable (web_view),
+                       "EvoItip.Initialize(%s);",
+                       view->priv->part_id);
+
+               itip_view_init_view (view);
        }
 
        itip_view_register_clicked_listener (view);
diff --git a/src/modules/itip-formatter/itip-view.h b/src/modules/itip-formatter/itip-view.h
index 696f614d33..05e26f84a6 100644
--- a/src/modules/itip-formatter/itip-view.h
+++ b/src/modules/itip-formatter/itip-view.h
@@ -211,16 +211,14 @@ void              itip_view_set_source            (ItipView *view,
 gboolean       itip_view_get_rsvp              (ItipView *view);
 void           itip_view_set_rsvp              (ItipView *view,
                                                 gboolean rsvp);
-gboolean       itip_view_get_show_rsvp_check   (ItipView *view);
 void           itip_view_set_show_rsvp_check   (ItipView *view,
                                                 gboolean show);
 gboolean       itip_view_get_update            (ItipView *view);
 void           itip_view_set_update            (ItipView *view,
                                                 gboolean update);
-gboolean       itip_view_get_show_update_check (ItipView *view);
 void           itip_view_set_show_update_check (ItipView *view,
                                                 gboolean show);
-gchar *                itip_view_get_rsvp_comment      (ItipView *view);
+const gchar *  itip_view_get_rsvp_comment      (ItipView *view);
 void           itip_view_set_rsvp_comment      (ItipView *view,
                                                 const gchar *comment);
 gboolean       itip_view_get_buttons_sensitive (ItipView *view);
diff --git a/src/modules/prefer-plain/e-mail-display-popup-prefer-plain.c 
b/src/modules/prefer-plain/e-mail-display-popup-prefer-plain.c
index 4d6c360242..8b613fb546 100644
--- a/src/modules/prefer-plain/e-mail-display-popup-prefer-plain.c
+++ b/src/modules/prefer-plain/e-mail-display-popup-prefer-plain.c
@@ -35,7 +35,8 @@ struct _EMailDisplayPopupPreferPlain {
 
        gchar *text_plain_id;
        gchar *text_html_id;
-       gchar *document_uri;
+       gchar *iframe_src;
+       gchar *iframe_id;
 
        GtkActionGroup *action_group;
 };
@@ -95,10 +96,10 @@ toggle_part (GtkAction *action,
        GHashTable *query;
        gchar *uri;
 
-       if (!pp_extension->document_uri)
+       if (!pp_extension->iframe_src)
                return;
 
-       soup_uri = soup_uri_new (pp_extension->document_uri);
+       soup_uri = soup_uri_new (pp_extension->iframe_src);
 
        if (!soup_uri || !soup_uri->query) {
                if (soup_uri)
@@ -124,8 +125,8 @@ toggle_part (GtkAction *action,
        uri = soup_uri_to_string (soup_uri, FALSE);
        soup_uri_free (soup_uri);
 
-       e_web_view_set_document_iframe_src (E_WEB_VIEW (e_extension_get_extensible (E_EXTENSION (extension))),
-               pp_extension->document_uri, uri);
+       e_web_view_set_iframe_src (E_WEB_VIEW (e_extension_get_extensible (E_EXTENSION (extension))),
+               pp_extension->iframe_id, uri);
 
        g_free (uri);
 }
@@ -168,14 +169,19 @@ set_text_html_id (EMailDisplayPopupPreferPlain *extension,
 }
 
 static void
-set_document_uri (EMailDisplayPopupPreferPlain *extension,
-                  const gchar *document_uri)
+set_popup_place (EMailDisplayPopupPreferPlain *extension,
+                const gchar *iframe_src,
+                const gchar *iframe_id)
 {
-       if (extension->document_uri == document_uri)
-               return;
+       if (g_strcmp0 (extension->iframe_src, iframe_src)) {
+               g_free (extension->iframe_src);
+               extension->iframe_src = g_strdup (iframe_src);
+       }
 
-       g_free (extension->document_uri);
-       extension->document_uri = g_strdup (document_uri);
+       if (g_strcmp0 (extension->iframe_id, iframe_id)) {
+               g_free (extension->iframe_id);
+               extension->iframe_id = g_strdup (iframe_id);
+       }
 }
 
 static GtkActionGroup *
@@ -227,7 +233,8 @@ create_group (EMailDisplayPopupExtension *extension)
 
 static void
 mail_display_popup_prefer_plain_update_actions (EMailDisplayPopupExtension *extension,
-                                               const gchar *popup_document_uri)
+                                               const gchar *popup_iframe_src,
+                                               const gchar *popup_iframe_id)
 {
        EMailDisplay *display;
        EMailDisplayPopupPreferPlain *pp_extension;
@@ -249,10 +256,10 @@ mail_display_popup_prefer_plain_update_actions (EMailDisplayPopupExtension *exte
        if (!pp_extension->action_group)
                pp_extension->action_group = create_group (extension);
 
-       set_document_uri (pp_extension, popup_document_uri);
+       set_popup_place (pp_extension, popup_iframe_src, popup_iframe_id);
 
-       if (pp_extension->document_uri)
-               soup_uri = soup_uri_new (pp_extension->document_uri);
+       if (pp_extension->iframe_src)
+               soup_uri = soup_uri_new (pp_extension->iframe_src);
        else
                soup_uri = NULL;
 
@@ -383,7 +390,8 @@ e_mail_display_popup_prefer_plain_finalize (GObject *object)
 
        g_free (extension->text_html_id);
        g_free (extension->text_plain_id);
-       g_free (extension->document_uri);
+       g_free (extension->iframe_src);
+       g_free (extension->iframe_id);
 
        /* Chain up to parent's finalize() method. */
        G_OBJECT_CLASS (e_mail_display_popup_prefer_plain_parent_class)->finalize (object);
@@ -420,5 +428,6 @@ e_mail_display_popup_prefer_plain_init (EMailDisplayPopupPreferPlain *extension)
        extension->action_group = NULL;
        extension->text_html_id = NULL;
        extension->text_plain_id = NULL;
-       extension->document_uri = NULL;
+       extension->iframe_src = NULL;
+       extension->iframe_id = NULL;
 }
diff --git a/src/modules/text-highlight/e-mail-display-popup-text-highlight.c 
b/src/modules/text-highlight/e-mail-display-popup-text-highlight.c
index cae12f12f1..51cd3acbe8 100644
--- a/src/modules/text-highlight/e-mail-display-popup-text-highlight.c
+++ b/src/modules/text-highlight/e-mail-display-popup-text-highlight.c
@@ -35,7 +35,8 @@ typedef struct _EMailDisplayPopupTextHighlight {
        GtkActionGroup *action_group;
 
        volatile gint updating;
-       gchar *document_uri;
+       gchar *iframe_src;
+       gchar *iframe_id;
 } EMailDisplayPopupTextHighlight;
 
 typedef struct _EMailDisplayPopupTextHighlightClass {
@@ -106,14 +107,19 @@ static GtkActionEntry entries[] = {
 };
 
 static void
-set_document_uri (EMailDisplayPopupTextHighlight *extension,
-                  const gchar *document_uri)
+set_popup_place (EMailDisplayPopupTextHighlight *extension,
+                const gchar *iframe_src,
+                const gchar *iframe_id)
 {
-       if (extension->document_uri == document_uri)
-               return;
+       if (g_strcmp0 (extension->iframe_src, iframe_src)) {
+               g_free (extension->iframe_src);
+               extension->iframe_src = g_strdup (iframe_src);
+       }
 
-       g_free (extension->document_uri);
-       extension->document_uri = g_strdup (document_uri);
+       if (g_strcmp0 (extension->iframe_id, iframe_id)) {
+               g_free (extension->iframe_id);
+               extension->iframe_id = g_strdup (iframe_id);
+       }
 }
 
 static void
@@ -131,8 +137,8 @@ reformat (GtkAction *old,
        if (g_atomic_int_get (&th_extension->updating))
                return;
 
-       if (th_extension->document_uri)
-               soup_uri = soup_uri_new (th_extension->document_uri);
+       if (th_extension->iframe_src)
+               soup_uri = soup_uri_new (th_extension->iframe_src);
        else
                soup_uri = NULL;
 
@@ -158,8 +164,8 @@ reformat (GtkAction *old,
        uri = soup_uri_to_string (soup_uri, FALSE);
        soup_uri_free (soup_uri);
 
-       e_web_view_set_document_iframe_src (E_WEB_VIEW (e_extension_get_extensible (E_EXTENSION 
(th_extension))),
-               th_extension->document_uri, uri);
+       e_web_view_set_iframe_src (E_WEB_VIEW (e_extension_get_extensible (E_EXTENSION (th_extension))),
+               th_extension->iframe_id, uri);
 
        g_free (uri);
 }
@@ -293,7 +299,8 @@ emdp_text_highlight_is_enabled (void)
 
 static void
 update_actions (EMailDisplayPopupExtension *extension,
-               const gchar *popup_document_uri)
+               const gchar *popup_iframe_src,
+               const gchar *popup_iframe_id)
 {
        EMailDisplayPopupTextHighlight *th_extension;
 
@@ -302,17 +309,17 @@ update_actions (EMailDisplayPopupExtension *extension,
        if (!th_extension->action_group)
                th_extension->action_group = create_group (extension);
 
-       set_document_uri (th_extension, popup_document_uri);
+       set_popup_place (th_extension, popup_iframe_src, popup_iframe_id);
 
        /* If the part below context menu was made by text-highlight formatter,
         * then try to check what formatter it's using at the moment and set
         * it as active in the popup menu */
-       if (th_extension->document_uri && strstr (th_extension->document_uri, ".text-highlight") != NULL) {
+       if (th_extension->iframe_src && strstr (th_extension->iframe_src, ".text-highlight") != NULL) {
                SoupURI *soup_uri;
                gtk_action_group_set_visible (
                        th_extension->action_group, TRUE);
 
-               soup_uri = soup_uri_new (th_extension->document_uri);
+               soup_uri = soup_uri_new (th_extension->iframe_src);
                if (soup_uri && soup_uri->query) {
                        GHashTable *query = soup_form_decode (soup_uri->query);
                        const gchar *highlighter;
@@ -356,7 +363,8 @@ e_mail_display_popup_text_highlight_finalize (GObject *object)
        extension = E_MAIL_DISPLAY_POPUP_TEXT_HIGHLIGHT (object);
 
        g_clear_object (&extension->action_group);
-       g_free (extension->document_uri);
+       g_free (extension->iframe_src);
+       g_free (extension->iframe_id);
 
        /* Chain up to parent's method */
        G_OBJECT_CLASS (e_mail_display_popup_text_highlight_parent_class)->finalize (object);
@@ -398,5 +406,6 @@ static void
 e_mail_display_popup_text_highlight_init (EMailDisplayPopupTextHighlight *extension)
 {
        extension->action_group = NULL;
-       extension->document_uri = NULL;
+       extension->iframe_src = NULL;
+       extension->iframe_id = NULL;
 }
diff --git a/src/modules/vcard-inline/e-mail-formatter-vcard.c 
b/src/modules/vcard-inline/e-mail-formatter-vcard.c
index a92ce37e44..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);
+
+               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);
 
-               g_free (access_key);
-               access_key = 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);
@@ -170,18 +212,17 @@ mail_formatter_vcard_format (EMailFormatterExtension *extension,
                                "<iframe width=\"100%%\" height=\"auto\" "
                                " class=\"-e-mail-formatter-frame-color -e-web-view-background-color\" "
                                " style=\"border: 1px solid;\""
-                               " src=\"%s\" name=\"%s\"></iframe>"
+                               " src=\"%s\" id=\"%s\" name=\"%s\"></iframe>"
                        "</div>",
                        e_mail_part_get_id (part),
                        access_key, html_label, uri,
+                       e_mail_part_get_id (part),
                        e_mail_part_get_id (part));
                g_output_stream_write_all (
                        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/modules/webkit-editor/web-extension/CMakeLists.txt 
b/src/modules/webkit-editor/web-extension/CMakeLists.txt
index a7f07ff742..ed59c7ebc7 100644
--- a/src/modules/webkit-editor/web-extension/CMakeLists.txt
+++ b/src/modules/webkit-editor/web-extension/CMakeLists.txt
@@ -1,3 +1,27 @@
+macro(add_simple_webextension_module _name _sourcesvar _depsvar _defsvar _cflagsvar _incdirsvar _ldflagsvar 
_destdir)
+       set(wex_deps
+               ${${_depsvar}}
+       )
+       set(wex_cflags
+               ${${_cflagsvar}}
+               ${WEB_EXTENSIONS_CFLAGS}
+       )
+       set(wex_incdirs
+               ${${_incdirsvar}}
+               ${WEB_EXTENSIONS_INCLUDE_DIRS}
+       )
+       set(wex_ldflags
+               ${${_ldflagsvar}}
+               ${WEB_EXTENSIONS_LDFLAGS}
+       )
+
+       add_simple_module(${_name} ${_sourcesvar} wex_deps ${_defsvar} wex_cflags wex_incdirs wex_ldflags 
${_destdir})
+endmacro(add_simple_webextension_module)
+
+macro(add_webextension_editor_module _name _sourcesvar _depsvar _defsvar _cflagsvar _incdirsvar _ldflagsvar)
+       add_simple_webextension_module(${_name} ${_sourcesvar} ${_depsvar} ${_defsvar} ${_cflagsvar} 
${_incdirsvar} ${_ldflagsvar} "${webextensionswebkiteditordir}")
+endmacro(add_webextension_editor_module)
+
 set(extra_deps
        evolution-mail
 )
@@ -6,6 +30,8 @@ set(sources
        e-composer-dom-functions.h
        e-dialogs-dom-functions.c
        e-dialogs-dom-functions.h
+       e-dom-utils.c
+       e-dom-utils.h
        e-editor-dom-functions.c
        e-editor-dom-functions.h
        e-editor-page.c
diff --git a/src/modules/webkit-editor/web-extension/e-composer-dom-functions.c 
b/src/modules/webkit-editor/web-extension/e-composer-dom-functions.c
index 4e1b7d1cc5..bd840c2537 100644
--- a/src/modules/webkit-editor/web-extension/e-composer-dom-functions.c
+++ b/src/modules/webkit-editor/web-extension/e-composer-dom-functions.c
@@ -24,8 +24,7 @@
 
 #include <camel/camel.h>
 
-#include "web-extensions/e-dom-utils.h"
-
+#include "e-dom-utils.h"
 #include "e-editor-page.h"
 #include "e-editor-dom-functions.h"
 #include "e-editor-undo-redo-manager.h"
diff --git a/src/modules/webkit-editor/web-extension/e-dialogs-dom-functions.c 
b/src/modules/webkit-editor/web-extension/e-dialogs-dom-functions.c
index 64f6c28c10..ce3c2d6ad4 100644
--- a/src/modules/webkit-editor/web-extension/e-dialogs-dom-functions.c
+++ b/src/modules/webkit-editor/web-extension/e-dialogs-dom-functions.c
@@ -19,8 +19,7 @@
 
 #include <webkitdom/webkitdom.h>
 
-#include "web-extensions/e-dom-utils.h"
-
+#include "e-dom-utils.h"
 #include "e-editor-dom-functions.h"
 #include "e-editor-undo-redo-manager.h"
 
diff --git a/src/modules/webkit-editor/web-extension/e-dom-utils.c 
b/src/modules/webkit-editor/web-extension/e-dom-utils.c
new file mode 100644
index 0000000000..33776dc0dd
--- /dev/null
+++ b/src/modules/webkit-editor/web-extension/e-dom-utils.c
@@ -0,0 +1,621 @@
+/*
+ * e-dom-utils.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#include "evolution-config.h"
+
+#include <string.h>
+
+#include <webkitdom/webkitdom.h>
+
+#include "e-dom-utils.h"
+
+void
+e_dom_utils_create_and_add_css_style_sheet (WebKitDOMDocument *document,
+                                            const gchar *style_sheet_id)
+{
+       WebKitDOMElement *style_element;
+
+       style_element = webkit_dom_document_get_element_by_id (document, style_sheet_id);
+
+       if (!style_element) {
+               WebKitDOMText *dom_text;
+               WebKitDOMHTMLHeadElement *head;
+
+               dom_text = webkit_dom_document_create_text_node (document, "");
+
+               /* Create new <style> element */
+               style_element = webkit_dom_document_create_element (document, "style", NULL);
+               webkit_dom_element_set_id (
+                       style_element,
+                       style_sheet_id);
+               webkit_dom_html_style_element_set_media (
+                       WEBKIT_DOM_HTML_STYLE_ELEMENT (style_element),
+                       "screen");
+               webkit_dom_node_append_child (
+                       WEBKIT_DOM_NODE (style_element),
+                       /* WebKit hack - we have to insert empty TextNode into style element */
+                       WEBKIT_DOM_NODE (dom_text),
+                       NULL);
+
+               head = webkit_dom_document_get_head (document);
+
+               webkit_dom_node_append_child (
+                       WEBKIT_DOM_NODE (head),
+                       WEBKIT_DOM_NODE (style_element),
+                       NULL);
+       }
+}
+
+/**
+ * e_html_editor_dom_node_find_parent_element:
+ * @node: Start node
+ * @tagname: Tag name of element to search
+ *
+ * Recursively searches for first occurance of element with given @tagname
+ * that is parent of given @node.
+ *
+ * Returns: A #WebKitDOMElement with @tagname representing parent of @node or
+ * @NULL when @node has no parent with given @tagname. When @node matches @tagname,
+ * then the @node is returned.
+ */
+WebKitDOMElement *
+dom_node_find_parent_element (WebKitDOMNode *node,
+                              const gchar *tagname)
+{
+       WebKitDOMNode *tmp_node = node;
+       gint taglen = strlen (tagname);
+
+       while (tmp_node) {
+               if (WEBKIT_DOM_IS_ELEMENT (tmp_node)) {
+                       gchar *node_tagname;
+
+                       node_tagname = webkit_dom_element_get_tag_name (
+                               WEBKIT_DOM_ELEMENT (tmp_node));
+
+                       if (node_tagname &&
+                           (strlen (node_tagname) == taglen) &&
+                           (g_ascii_strncasecmp (node_tagname, tagname, taglen) == 0)) {
+                               g_free (node_tagname);
+                               return WEBKIT_DOM_ELEMENT (tmp_node);
+                       }
+
+                       g_free (node_tagname);
+               }
+
+               tmp_node = webkit_dom_node_get_parent_node (tmp_node);
+       }
+
+       return NULL;
+}
+
+gboolean
+element_has_id (WebKitDOMElement *element,
+                const gchar* id)
+{
+       gchar *element_id;
+
+       if (!element)
+               return FALSE;
+
+       if (!WEBKIT_DOM_IS_ELEMENT (element))
+               return FALSE;
+
+       element_id = webkit_dom_element_get_id (element);
+
+       if (element_id && g_ascii_strcasecmp (element_id, id) == 0) {
+               g_free (element_id);
+               return TRUE;
+       }
+       g_free (element_id);
+
+       return FALSE;
+}
+
+gboolean
+element_has_tag (WebKitDOMElement *element,
+                 const gchar* tag)
+{
+       gchar *element_tag;
+
+       if (!WEBKIT_DOM_IS_ELEMENT (element))
+               return FALSE;
+
+       element_tag = webkit_dom_element_get_tag_name (element);
+
+       if (g_ascii_strcasecmp (element_tag, tag) != 0) {
+               g_free (element_tag);
+               return FALSE;
+       }
+       g_free (element_tag);
+
+       return TRUE;
+}
+
+gboolean
+element_has_class (WebKitDOMElement *element,
+                   const gchar* class)
+{
+       gchar *element_class;
+
+       if (!element)
+               return FALSE;
+
+       if (!WEBKIT_DOM_IS_ELEMENT (element))
+               return FALSE;
+
+       element_class = webkit_dom_element_get_class_name (element);
+
+       if (element_class && g_strstr_len (element_class, -1, class)) {
+               g_free (element_class);
+               return TRUE;
+       }
+       g_free (element_class);
+
+       return FALSE;
+}
+
+void
+element_add_class (WebKitDOMElement *element,
+                   const gchar* class)
+{
+       gchar *element_class;
+       gchar *new_class;
+
+       if (!WEBKIT_DOM_IS_ELEMENT (element))
+               return;
+
+       if (element_has_class (element, class))
+               return;
+
+       element_class = webkit_dom_element_get_class_name (element);
+
+       if (!element_class)
+               new_class = g_strdup (class);
+       else
+               new_class = g_strconcat (element_class, " ", class, NULL);
+
+       webkit_dom_element_set_class_name (element, new_class);
+
+       g_free (element_class);
+       g_free (new_class);
+}
+
+void
+element_remove_class (WebKitDOMElement *element,
+                      const gchar* class)
+{
+       gchar *element_class, *final_class;
+       GRegex *regex;
+       gchar *pattern = NULL;
+
+       if (!WEBKIT_DOM_IS_ELEMENT (element))
+               return;
+
+       if (!element_has_class (element, class))
+               return;
+
+       element_class = webkit_dom_element_get_class_name (element);
+
+       pattern = g_strconcat ("[\\s]*", class, "[\\s]*", NULL);
+       regex = g_regex_new (pattern, 0, 0, NULL);
+       final_class = g_regex_replace (regex, element_class, -1, 0, " ", 0, NULL);
+
+       if (g_strcmp0 (final_class, " ") != 0)
+               webkit_dom_element_set_class_name (element, final_class);
+       else
+               webkit_dom_element_remove_attribute (element, "class");
+
+       g_free (element_class);
+       g_free (final_class);
+       g_free (pattern);
+       g_regex_unref (regex);
+}
+
+void
+element_rename_attribute (WebKitDOMElement *element,
+                      const gchar *from,
+                      const gchar *to)
+{
+       gchar *value;
+
+       if (!webkit_dom_element_has_attribute (element, from))
+               return;
+
+       value = webkit_dom_element_get_attribute (element, from);
+       webkit_dom_element_set_attribute (element, to, (value && *value) ? value : "", NULL);
+       webkit_dom_element_remove_attribute (element, from);
+       g_free (value);
+}
+
+void
+remove_node (WebKitDOMNode *node)
+{
+       WebKitDOMNode *parent = webkit_dom_node_get_parent_node (node);
+
+       if (parent)
+               webkit_dom_node_remove_child (parent, node, NULL);
+}
+
+void
+remove_node_if_empty (WebKitDOMNode *node)
+{
+       WebKitDOMNode *child;
+
+       if (!WEBKIT_DOM_IS_NODE (node))
+               return;
+
+       if ((child = webkit_dom_node_get_first_child (node))) {
+               WebKitDOMNode *prev_sibling, *next_sibling;
+
+               prev_sibling = webkit_dom_node_get_previous_sibling (child);
+               next_sibling = webkit_dom_node_get_next_sibling (child);
+               /* Empty or BR as sibling, but no sibling after it. */
+               if (!webkit_dom_node_get_first_child (child) &&
+                   !WEBKIT_DOM_IS_TEXT (child) &&
+                   (!prev_sibling ||
+                    (WEBKIT_DOM_IS_HTML_BR_ELEMENT (prev_sibling) &&
+                     !webkit_dom_node_get_previous_sibling (prev_sibling))) &&
+                   (!next_sibling ||
+                    (WEBKIT_DOM_IS_HTML_BR_ELEMENT (next_sibling) &&
+                     !webkit_dom_node_get_next_sibling (next_sibling)))) {
+
+                       remove_node (node);
+               } else {
+                       gchar *text_content;
+
+                       text_content = webkit_dom_node_get_text_content (node);
+                       if (!text_content)
+                               remove_node (node);
+
+                       if (text_content && !*text_content)
+                               remove_node (node);
+
+                       if (g_strcmp0 (text_content, UNICODE_ZERO_WIDTH_SPACE) == 0)
+                               remove_node (node);
+
+                       g_free (text_content);
+               }
+       } else
+               remove_node (node);
+}
+
+WebKitDOMNode *
+split_list_into_two (WebKitDOMNode *item,
+                    gint level)
+{
+       gint current_level = 1;
+       WebKitDOMDocument *document;
+       WebKitDOMDocumentFragment *fragment;
+       WebKitDOMNode *parent, *prev_parent = NULL, *tmp;
+
+       document = webkit_dom_node_get_owner_document (item);
+       fragment = webkit_dom_document_create_document_fragment (document);
+
+       tmp = item;
+       parent = webkit_dom_node_get_parent_node (item);
+       while (!WEBKIT_DOM_IS_HTML_BODY_ELEMENT (parent)) {
+               WebKitDOMNode *clone, *first_child, *insert_before = NULL, *sibling;
+
+               first_child = webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (fragment));
+               clone = webkit_dom_node_clone_node_with_error (parent, FALSE, NULL);
+               webkit_dom_node_insert_before (
+                       WEBKIT_DOM_NODE (fragment), clone, first_child, NULL);
+
+               if (first_child)
+                       insert_before = webkit_dom_node_get_first_child (first_child);
+
+               while (first_child && (sibling = webkit_dom_node_get_next_sibling (first_child)))
+                       webkit_dom_node_insert_before (first_child, sibling, insert_before, NULL);
+
+               while (tmp && (sibling = webkit_dom_node_get_next_sibling (tmp)))
+                       webkit_dom_node_append_child (clone, sibling, NULL);
+
+               if (tmp)
+                       webkit_dom_node_insert_before (
+                               clone, tmp, webkit_dom_node_get_first_child (clone), NULL);
+
+               prev_parent = parent;
+               tmp = webkit_dom_node_get_next_sibling (parent);
+               parent = webkit_dom_node_get_parent_node (parent);
+               if (WEBKIT_DOM_IS_HTML_BODY_ELEMENT (parent)) {
+                       first_child = webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (fragment));
+                       insert_before = webkit_dom_node_get_first_child (first_child);
+                       while (first_child && (sibling = webkit_dom_node_get_next_sibling (first_child))) {
+                               webkit_dom_node_insert_before (
+                                       first_child, sibling, insert_before, NULL);
+                       }
+               }
+
+               if (current_level >= level && level >= 0)
+                       break;
+
+               current_level++;
+       }
+
+       tmp = webkit_dom_node_insert_before (
+               parent,
+               webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (fragment)),
+               prev_parent ? webkit_dom_node_get_next_sibling (prev_parent) : NULL,
+               NULL);
+       remove_node_if_empty (prev_parent);
+
+       return tmp;
+}
+
+WebKitDOMElement *
+dom_create_selection_marker (WebKitDOMDocument *document,
+                             gboolean selection_start_marker)
+{
+       WebKitDOMElement *element;
+
+       element = webkit_dom_document_create_element (
+               document, "SPAN", NULL);
+       webkit_dom_element_set_id (
+               element,
+               selection_start_marker ?
+                       "-x-evo-selection-start-marker" :
+                       "-x-evo-selection-end-marker");
+
+       return element;
+}
+
+void
+dom_remove_selection_markers (WebKitDOMDocument *document)
+{
+       WebKitDOMElement *marker;
+
+       marker = webkit_dom_document_get_element_by_id (
+               document, "-x-evo-selection-start-marker");
+       if (marker)
+               remove_node (WEBKIT_DOM_NODE (marker));
+       marker = webkit_dom_document_get_element_by_id (
+               document, "-x-evo-selection-end-marker");
+       if (marker)
+               remove_node (WEBKIT_DOM_NODE (marker));
+}
+
+void
+dom_add_selection_markers_into_element_start (WebKitDOMDocument *document,
+                                              WebKitDOMElement *element,
+                                              WebKitDOMElement **selection_start_marker,
+                                              WebKitDOMElement **selection_end_marker)
+{
+       WebKitDOMElement *marker;
+
+       dom_remove_selection_markers (document);
+       marker = dom_create_selection_marker (document, FALSE);
+       webkit_dom_node_insert_before (
+               WEBKIT_DOM_NODE (element),
+               WEBKIT_DOM_NODE (marker),
+               webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (element)),
+               NULL);
+       if (selection_end_marker)
+               *selection_end_marker = marker;
+
+       marker = dom_create_selection_marker (document, TRUE);
+       webkit_dom_node_insert_before (
+               WEBKIT_DOM_NODE (element),
+               WEBKIT_DOM_NODE (marker),
+               webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (element)),
+               NULL);
+       if (selection_start_marker)
+               *selection_start_marker = marker;
+}
+
+void
+dom_add_selection_markers_into_element_end (WebKitDOMDocument *document,
+                                            WebKitDOMElement *element,
+                                            WebKitDOMElement **selection_start_marker,
+                                            WebKitDOMElement **selection_end_marker)
+{
+       WebKitDOMElement *marker;
+
+       dom_remove_selection_markers (document);
+       marker = dom_create_selection_marker (document, TRUE);
+       webkit_dom_node_append_child (
+               WEBKIT_DOM_NODE (element), WEBKIT_DOM_NODE (marker), NULL);
+       if (selection_start_marker)
+               *selection_start_marker = marker;
+
+       marker = dom_create_selection_marker (document, FALSE);
+       webkit_dom_node_append_child (
+               WEBKIT_DOM_NODE (element), WEBKIT_DOM_NODE (marker), NULL);
+       if (selection_end_marker)
+               *selection_end_marker = marker;
+}
+
+gboolean
+node_is_list_or_item (WebKitDOMNode *node)
+{
+       return node && (
+               WEBKIT_DOM_IS_HTML_O_LIST_ELEMENT (node) ||
+               WEBKIT_DOM_IS_HTML_U_LIST_ELEMENT (node) ||
+               WEBKIT_DOM_IS_HTML_LI_ELEMENT (node));
+}
+
+gboolean
+node_is_list (WebKitDOMNode *node)
+{
+       return node && (
+               WEBKIT_DOM_IS_HTML_O_LIST_ELEMENT (node) ||
+               WEBKIT_DOM_IS_HTML_U_LIST_ELEMENT (node));
+}
+
+/**
+ * e_html_editor_selection_get_list_format_from_node:
+ * @node: an #WebKitDOMNode
+ *
+ * Returns block format of given list.
+ *
+ * Returns: #EContentEditorBlockFormat
+ */
+EContentEditorBlockFormat
+dom_get_list_format_from_node (WebKitDOMNode *node)
+{
+       EContentEditorBlockFormat format =
+               E_CONTENT_EDITOR_BLOCK_FORMAT_UNORDERED_LIST;
+
+       if (WEBKIT_DOM_IS_HTML_LI_ELEMENT (node))
+               return E_CONTENT_EDITOR_BLOCK_FORMAT_NONE;
+
+       if (WEBKIT_DOM_IS_HTML_U_LIST_ELEMENT (node))
+               return format;
+
+       if (WEBKIT_DOM_IS_HTML_O_LIST_ELEMENT (node)) {
+               gchar *type_value = webkit_dom_element_get_attribute (
+                       WEBKIT_DOM_ELEMENT (node), "type");
+
+               if (!type_value)
+                       return E_CONTENT_EDITOR_BLOCK_FORMAT_ORDERED_LIST;
+
+               if (!*type_value)
+                       format = E_CONTENT_EDITOR_BLOCK_FORMAT_ORDERED_LIST;
+               else if (g_ascii_strcasecmp (type_value, "A") == 0)
+                       format = E_CONTENT_EDITOR_BLOCK_FORMAT_ORDERED_LIST_ALPHA;
+               else if (g_ascii_strcasecmp (type_value, "I") == 0)
+                       format = E_CONTENT_EDITOR_BLOCK_FORMAT_ORDERED_LIST_ROMAN;
+               g_free (type_value);
+
+               return format;
+       }
+
+       return E_CONTENT_EDITOR_BLOCK_FORMAT_NONE;
+}
+
+void
+merge_list_into_list (WebKitDOMNode *from,
+                      WebKitDOMNode *to,
+                      gboolean insert_before)
+{
+       WebKitDOMNode *item, *insert_before_node;
+
+       if (!(to && from))
+               return;
+
+       insert_before_node = webkit_dom_node_get_first_child (to);
+       while ((item = webkit_dom_node_get_first_child (from)) != NULL) {
+               if (insert_before)
+                       webkit_dom_node_insert_before (
+                               to, item, insert_before_node, NULL);
+               else
+                       webkit_dom_node_append_child (to, item, NULL);
+       }
+
+       if (!webkit_dom_node_has_child_nodes (from))
+               remove_node (from);
+
+}
+
+void
+merge_lists_if_possible (WebKitDOMNode *list)
+{
+       EContentEditorBlockFormat format, prev, next;
+       gint ii, length;
+       WebKitDOMNode *prev_sibling, *next_sibling;
+       WebKitDOMNodeList *lists = NULL;
+
+       prev_sibling = webkit_dom_node_get_previous_sibling (WEBKIT_DOM_NODE (list));
+       next_sibling = webkit_dom_node_get_next_sibling (WEBKIT_DOM_NODE (list));
+
+       format = dom_get_list_format_from_node (list),
+       prev = dom_get_list_format_from_node (prev_sibling);
+       next = dom_get_list_format_from_node (next_sibling);
+
+       if (format != E_CONTENT_EDITOR_BLOCK_FORMAT_NONE) {
+               if (format == prev && prev != E_CONTENT_EDITOR_BLOCK_FORMAT_NONE)
+                       merge_list_into_list (prev_sibling, list, TRUE);
+
+               if (format == next && next != E_CONTENT_EDITOR_BLOCK_FORMAT_NONE)
+                       merge_list_into_list (next_sibling, list, FALSE);
+       }
+
+       lists = webkit_dom_element_query_selector_all (
+               WEBKIT_DOM_ELEMENT (list), "ol + ol, ul + ul", NULL);
+       length = webkit_dom_node_list_get_length (lists);
+       for (ii = 0; ii < length; ii++) {
+               WebKitDOMNode *node;
+
+               node = webkit_dom_node_list_item (lists, ii);
+               merge_lists_if_possible (node);
+       }
+       g_clear_object (&lists);
+}
+
+WebKitDOMElement *
+get_parent_block_element (WebKitDOMNode *node)
+{
+       WebKitDOMElement *parent = webkit_dom_node_get_parent_element (node);
+
+       if (WEBKIT_DOM_IS_HTML_BODY_ELEMENT (parent))
+               return WEBKIT_DOM_IS_ELEMENT (node) ? WEBKIT_DOM_ELEMENT (node) : NULL;
+
+       while (parent &&
+              !WEBKIT_DOM_IS_HTML_PARAGRAPH_ELEMENT (parent) &&
+              !WEBKIT_DOM_IS_HTML_DIV_ELEMENT (parent) &&
+              !WEBKIT_DOM_IS_HTML_QUOTE_ELEMENT (parent) &&
+              !WEBKIT_DOM_IS_HTML_U_LIST_ELEMENT (parent) &&
+              !WEBKIT_DOM_IS_HTML_O_LIST_ELEMENT (parent) &&
+              !WEBKIT_DOM_IS_HTML_PRE_ELEMENT (parent) &&
+              !WEBKIT_DOM_IS_HTML_HEADING_ELEMENT (parent) &&
+              !WEBKIT_DOM_IS_HTML_TABLE_CELL_ELEMENT (parent) &&
+              !element_has_tag (parent, "address")) {
+               parent = webkit_dom_node_get_parent_element (
+                       WEBKIT_DOM_NODE (parent));
+       }
+
+       return parent;
+}
+
+gchar *
+dom_get_node_inner_html (WebKitDOMNode *node)
+{
+       gchar *inner_html;
+       WebKitDOMDocument *document;
+       WebKitDOMElement *div;
+
+       document = webkit_dom_node_get_owner_document (node);
+       div = webkit_dom_document_create_element (document, "div", NULL);
+       webkit_dom_node_append_child (
+                       WEBKIT_DOM_NODE (div),
+                       webkit_dom_node_clone_node_with_error (node, TRUE, NULL),
+                       NULL);
+
+       inner_html = webkit_dom_element_get_inner_html (div);
+       remove_node (WEBKIT_DOM_NODE (div));
+
+       return inner_html;
+}
+
+void
+dom_element_swap_attributes (WebKitDOMElement *element,
+                             const gchar *from,
+                             const gchar *to)
+{
+       gchar *value_from, *value_to;
+
+       if (!webkit_dom_element_has_attribute (element, from) ||
+           !webkit_dom_element_has_attribute (element, to))
+               return;
+
+       value_from = webkit_dom_element_get_attribute (element, from);
+       value_to = webkit_dom_element_get_attribute (element, to);
+       webkit_dom_element_set_attribute (element, to, (value_from && *value_from) ? value_from : "", NULL);
+       webkit_dom_element_set_attribute (element, from, (value_to && *value_to) ? value_to : "", NULL);
+       g_free (value_from);
+       g_free (value_to);
+}
diff --git a/src/modules/webkit-editor/web-extension/e-dom-utils.h 
b/src/modules/webkit-editor/web-extension/e-dom-utils.h
new file mode 100644
index 0000000000..dceb65c17e
--- /dev/null
+++ b/src/modules/webkit-editor/web-extension/e-dom-utils.h
@@ -0,0 +1,91 @@
+/*
+ * e-dom-utils.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef E_DOM_UTILS_H
+#define E_DOM_UTILS_H
+
+#define E_UTIL_INCLUDE_WITHOUT_WEBKIT
+#include <e-util/e-util.h>
+#undef E_UTIL_INCLUDE_WITHOUT_WEBKIT
+
+#include <webkitdom/webkitdom.h>
+
+#include <gtk/gtk.h>
+
+#define UNICODE_ZERO_WIDTH_SPACE "\xe2\x80\x8b"
+#define UNICODE_NBSP "\xc2\xa0"
+
+#define E_EVOLUTION_BLOCKQUOTE_STYLE "margin:0 0 0 .8ex; border-left:2px #729fcf solid;padding-left:1ex"
+
+G_BEGIN_DECLS
+
+void           e_dom_utils_create_and_add_css_style_sheet
+                                               (WebKitDOMDocument *document,
+                                                const gchar *style_sheet_id);
+WebKitDOMElement *
+               dom_node_find_parent_element    (WebKitDOMNode *node,
+                                                const gchar *tagname);
+gboolean       element_has_id                  (WebKitDOMElement *element,
+                                                const gchar* id);
+gboolean       element_has_tag                 (WebKitDOMElement *element,
+                                                const gchar* tag);
+gboolean       element_has_class               (WebKitDOMElement *element,
+                                                const gchar* class);
+void           element_add_class               (WebKitDOMElement *element,
+                                                const gchar* class);
+void           element_remove_class            (WebKitDOMElement *element,
+                                                const gchar* class);
+void           element_rename_attribute        (WebKitDOMElement *element,
+                                                const gchar *from,
+                                                const gchar *to);
+void           remove_node                     (WebKitDOMNode *node);
+void           remove_node_if_empty            (WebKitDOMNode *node);
+WebKitDOMNode *        split_list_into_two             (WebKitDOMNode *item,
+                                                gint level);
+WebKitDOMElement *
+               dom_create_selection_marker     (WebKitDOMDocument *document,
+                                                gboolean start);
+void           dom_add_selection_markers_into_element_start
+                                               (WebKitDOMDocument *document,
+                                                WebKitDOMElement *element,
+                                                WebKitDOMElement **selection_start_marker,
+                                                WebKitDOMElement **selection_end_marker);
+void           dom_add_selection_markers_into_element_end
+                                               (WebKitDOMDocument *document,
+                                                WebKitDOMElement *element,
+                                                WebKitDOMElement **selection_start_marker,
+                                                WebKitDOMElement **selection_end_marker);
+void           dom_remove_selection_markers    (WebKitDOMDocument *document);
+gboolean       node_is_list                    (WebKitDOMNode *node);
+gboolean       node_is_list_or_item            (WebKitDOMNode *node);
+EContentEditorBlockFormat
+               dom_get_list_format_from_node   (WebKitDOMNode *node);
+void           merge_list_into_list            (WebKitDOMNode *from,
+                                                WebKitDOMNode *to,
+                                                gboolean insert_before);
+void           merge_lists_if_possible         (WebKitDOMNode *list);
+WebKitDOMElement *
+               get_parent_block_element        (WebKitDOMNode *node);
+gchar *                dom_get_node_inner_html         (WebKitDOMNode *node);
+void           dom_element_swap_attributes     (WebKitDOMElement *element,
+                                                 const gchar *from,
+                                                 const gchar *to);
+
+G_END_DECLS
+
+#endif /* E_DOM_UTILS_H */
diff --git a/src/modules/webkit-editor/web-extension/e-editor-dom-functions.c 
b/src/modules/webkit-editor/web-extension/e-editor-dom-functions.c
index 97bf1ac350..35cab8cc10 100644
--- a/src/modules/webkit-editor/web-extension/e-editor-dom-functions.c
+++ b/src/modules/webkit-editor/web-extension/e-editor-dom-functions.c
@@ -20,8 +20,7 @@
 
 #include <webkitdom/webkitdom.h>
 
-#include "web-extensions/e-dom-utils.h"
-
+#include "e-dom-utils.h"
 #include "e-editor-page.h"
 #include "e-editor-undo-redo-manager.h"
 
diff --git a/src/modules/webkit-editor/web-extension/e-editor-page.c 
b/src/modules/webkit-editor/web-extension/e-editor-page.c
index 18d50837b6..8164900575 100644
--- a/src/modules/webkit-editor/web-extension/e-editor-page.c
+++ b/src/modules/webkit-editor/web-extension/e-editor-page.c
@@ -20,8 +20,7 @@
 #include <glib.h>
 #include <webkit2/webkit-web-extension.h>
 
-#include "web-extensions/e-dom-utils.h"
-
+#include "e-dom-utils.h"
 #include "e-editor-dom-functions.h"
 #include "e-editor-web-extension.h"
 #include "e-editor-undo-redo-manager.h"
diff --git a/src/modules/webkit-editor/web-extension/e-editor-undo-redo-manager.c 
b/src/modules/webkit-editor/web-extension/e-editor-undo-redo-manager.c
index ff1b8f5c63..c4053eb47f 100644
--- a/src/modules/webkit-editor/web-extension/e-editor-undo-redo-manager.c
+++ b/src/modules/webkit-editor/web-extension/e-editor-undo-redo-manager.c
@@ -20,8 +20,7 @@
 
 #include <webkitdom/webkitdom.h>
 
-#include "web-extensions/e-dom-utils.h"
-
+#include "e-dom-utils.h"
 #include "e-editor-page.h"
 #include "e-editor-dom-functions.h"
 #include "e-editor-undo-redo-manager.h"
diff --git a/src/modules/webkit-editor/web-extension/e-editor-web-extension.c 
b/src/modules/webkit-editor/web-extension/e-editor-web-extension.c
index 3138556dcd..05a1d4ac8d 100644
--- a/src/modules/webkit-editor/web-extension/e-editor-web-extension.c
+++ b/src/modules/webkit-editor/web-extension/e-editor-web-extension.c
@@ -32,8 +32,7 @@
 #include "mail/e-http-request.h"
 #undef E_UTIL_INCLUDE_WITHOUT_WEBKIT
 
-#include "web-extensions/e-dom-utils.h"
-
+//#include "e-dom-utils.h"
 #include "e-editor-page.h"
 #include "e-composer-dom-functions.h"
 #include "e-dialogs-dom-functions.h"
diff --git a/src/plugins/mail-to-task/mail-to-task.c b/src/plugins/mail-to-task/mail-to-task.c
index e28dba3e8d..ca443dcda5 100644
--- a/src/plugins/mail-to-task/mail-to-task.c
+++ b/src/plugins/mail-to-task/mail-to-task.c
@@ -1091,43 +1091,71 @@ text_contains_nonwhitespace (const gchar *text,
        return p - text < len - 1 && c != 0;
 }
 
-static gchar *
-get_selected_text (EMailReader *reader)
+static void
+get_charsets (EMailReader *reader,
+             gchar **default_charset,
+             gchar **forced_charset)
 {
        EMailDisplay *display;
-       gchar *text = NULL;
+       EMailFormatter *formatter;
 
        display = e_mail_reader_get_mail_display (reader);
+       formatter = e_mail_display_get_formatter (display);
 
-       if (!e_web_view_is_selection_active (E_WEB_VIEW (display)))
-               return NULL;
+       *default_charset = e_mail_formatter_dup_default_charset (formatter);
+       *forced_charset = e_mail_formatter_dup_charset (formatter);
+}
 
-       text = e_mail_display_get_selection_plain_text_sync (display, NULL, NULL);
+static void
+start_mail_to_event_thread (AsyncData *data)
+{
+       GThread *thread = NULL;
+       GError *error = NULL;
 
-       if (!text)
-               return NULL;
+       thread = g_thread_try_new (NULL, (GThreadFunc) do_mail_to_event, data, &error);
 
-       if (!text_contains_nonwhitespace (text, strlen (text))) {
-               g_free (text);
-               return NULL;
+       if (error != NULL) {
+               g_warning (G_STRLOC ": %s", error->message);
+               g_error_free (error);
+       } else {
+               g_thread_unref (thread);
        }
-
-       return text;
 }
 
 static void
-get_charsets (EMailReader *reader,
-             gchar **default_charset,
-             gchar **forced_charset)
+mail_to_task_got_selection_jsc_cb (GObject *source_object,
+                                  GAsyncResult *result,
+                                  gpointer user_data)
 {
-       EMailDisplay *display;
-       EMailFormatter *formatter;
+       AsyncData *data = user_data;
+       GSList *texts = NULL;
+       gchar *text;
+       GError *error = NULL;
 
-       display = e_mail_reader_get_mail_display (reader);
-       formatter = e_mail_display_get_formatter (display);
+       g_return_if_fail (data != NULL);
+       g_return_if_fail (E_IS_WEB_VIEW (source_object));
 
-       *default_charset = e_mail_formatter_dup_default_charset (formatter);
-       *forced_charset = e_mail_formatter_dup_charset (formatter);
+       if (!e_web_view_jsc_get_selection_finish (WEBKIT_WEB_VIEW (source_object), result, &texts, &error)) {
+               texts = NULL;
+               g_warning ("%s: Failed to get view selection: %s", G_STRFUNC, error ? error->message : 
"Unknown error");
+       }
+
+       text = texts ? texts->data : NULL;
+
+       if (text && !text_contains_nonwhitespace (text, strlen (text))) {
+               text = NULL;
+       } else {
+               /* Steal the pointer */
+               if (texts)
+                       texts->data = NULL;
+       }
+
+       data->selected_text = text;
+
+       start_mail_to_event_thread (data);
+
+       g_slist_free_full (texts, g_free);
+       g_clear_error (&error);
 }
 
 static void
@@ -1227,8 +1255,7 @@ mail_to_event (ECalClientSourceType source_type,
        if (source) {
                /* if a source has been selected, perform the mail2event operation */
                AsyncData *data = NULL;
-               GThread *thread = NULL;
-               GError *error = NULL;
+               EMailDisplay *mail_display;
 
                /* Fill the elements in AsynData */
                data = g_new0 (AsyncData, 1);
@@ -1241,18 +1268,15 @@ mail_to_event (ECalClientSourceType source_type,
                data->with_attendees = with_attendees;
                get_charsets (reader, &data->default_charset, &data->forced_charset);
 
-               if (uids->len == 1)
-                       data->selected_text = get_selected_text (reader);
-               else
-                       data->selected_text = NULL;
+               mail_display = e_mail_reader_get_mail_display (reader);
 
-               thread = g_thread_try_new (
-                       NULL, (GThreadFunc) do_mail_to_event, data, &error);
-               if (error != NULL) {
-                       g_warning (G_STRLOC ": %s", error->message);
-                       g_error_free (error);
+               if (uids->len == 1 && e_web_view_has_selection (E_WEB_VIEW (mail_display))) {
+                       e_web_view_jsc_get_selection (WEBKIT_WEB_VIEW (mail_display), E_TEXT_FORMAT_PLAIN, 
NULL,
+                               mail_to_task_got_selection_jsc_cb, data);
                } else {
-                       g_thread_unref (thread);
+                       data->selected_text = NULL;
+
+                       start_mail_to_event_thread (data);
                }
        }
 
diff --git a/src/web-extensions/CMakeLists.txt b/src/web-extensions/CMakeLists.txt
index 82ba059de0..35151503fe 100644
--- a/src/web-extensions/CMakeLists.txt
+++ b/src/web-extensions/CMakeLists.txt
@@ -3,56 +3,9 @@ set(DEPENDENCIES
 )
 
 set(SOURCES
-       e-dom-utils.h
-       e-dom-utils.c
-)
-
-add_library(edomutils SHARED
-       ${SOURCES}
-)
-
-add_dependencies(edomutils
-       ${DEPENDENCIES}
-)
-
-target_compile_definitions(edomutils PRIVATE
-       -DG_LOG_DOMAIN=\"edomutils\"
-       -DEVOLUTION_IMAGESDIR=\"${imagesdir}\"
-)
-
-target_compile_options(edomutils PUBLIC
-       ${EVOLUTION_DATA_SERVER_CFLAGS}
-       ${GNOME_PLATFORM_CFLAGS}
-)
-
-target_include_directories(edomutils PUBLIC
-       ${CMAKE_BINARY_DIR}
-       ${CMAKE_BINARY_DIR}/src
-       ${CMAKE_SOURCE_DIR}/src
-       ${CMAKE_CURRENT_BINARY_DIR}
-       ${EVOLUTION_DATA_SERVER_INCLUDE_DIRS}
-       ${GNOME_PLATFORM_INCLUDE_DIRS}
-)
-
-target_link_libraries(edomutils
-       ${DEPENDENCIES}
-       ${EVOLUTION_DATA_SERVER_LDFLAGS}
-       ${GNOME_PLATFORM_LDFLAGS}
-)
-
-install(TARGETS edomutils
-       DESTINATION ${privsolibdir}
-)
-
-set(SOURCES
-       e-dom-utils.h
-       e-dom-utils.c
-       e-itip-formatter-dom-utils.h
-       e-itip-formatter-dom-utils.c
        e-web-extension.h
        e-web-extension.c
        e-web-extension-main.c
-       e-web-extension-names.h
 )
 
 add_library(ewebextension MODULE
@@ -65,12 +18,10 @@ add_dependencies(ewebextension
 
 target_compile_definitions(ewebextension PRIVATE
        -DG_LOG_DOMAIN=\"ewebextension\"
-       -DEVOLUTION_IMAGESDIR=\"${imagesdir}\"
+       -DEVOLUTION_WEBKITDATADIR=\"${webkitdatadir}\"
 )
 
 target_compile_options(ewebextension PUBLIC
-       ${EVOLUTION_DATA_SERVER_CFLAGS}
-       ${GNOME_PLATFORM_CFLAGS}
        ${WEB_EXTENSIONS_CFLAGS}
 )
 
@@ -79,15 +30,11 @@ target_include_directories(ewebextension PUBLIC
        ${CMAKE_BINARY_DIR}/src
        ${CMAKE_SOURCE_DIR}/src
        ${CMAKE_CURRENT_BINARY_DIR}
-       ${EVOLUTION_DATA_SERVER_INCLUDE_DIRS}
-       ${GNOME_PLATFORM_INCLUDE_DIRS}
        ${WEB_EXTENSIONS_INCLUDE_DIRS}
 )
 
 target_link_libraries(ewebextension
        ${DEPENDENCIES}
-       ${EVOLUTION_DATA_SERVER_LDFLAGS}
-       ${GNOME_PLATFORM_LDFLAGS}
        ${WEB_EXTENSIONS_LDFLAGS}
 )
 
diff --git a/src/web-extensions/e-web-extension-main.c b/src/web-extensions/e-web-extension-main.c
index cb09f246ee..185c519670 100644
--- a/src/web-extensions/e-web-extension-main.c
+++ b/src/web-extensions/e-web-extension-main.c
@@ -18,38 +18,7 @@
 
 #include "evolution-config.h"
 
-#include <camel/camel.h>
-
-#define E_UTIL_INCLUDE_WITHOUT_WEBKIT
-#include <e-util/e-util.h>
-#undef E_UTIL_INCLUDE_WITHOUT_WEBKIT
-
 #include "e-web-extension.h"
-#include "e-web-extension-names.h"
-
-static void
-connected_to_server_cb (GObject *source_object,
-                       GAsyncResult *result,
-                       gpointer user_data)
-{
-       EWebExtension *extension = user_data;
-       GDBusConnection *connection;
-       GError *error = NULL;
-
-       g_return_if_fail (E_IS_WEB_EXTENSION (extension));
-
-       connection = e_web_extension_container_utils_connect_to_server_finish (result, &error);
-       if (!connection) {
-               g_warning ("%d %s: Failed to connect to the UI D-Bus server: %s", getpid (), G_STRFUNC,
-                       error ? error->message : "Unknown error");
-               g_clear_error (&error);
-               return;
-       }
-
-       e_web_extension_dbus_register (extension, connection);
-       g_object_unref (connection);
-       g_object_unref (extension);
-}
 
 /* Forward declaration */
 G_MODULE_EXPORT void webkit_web_extension_initialize_with_user_data (WebKitWebExtension *wk_extension,
@@ -60,24 +29,8 @@ webkit_web_extension_initialize_with_user_data (WebKitWebExtension *wk_extension
                                                GVariant *user_data)
 {
        EWebExtension *extension;
-       const gchar *guid = NULL, *server_address = NULL;
-
-       g_return_if_fail (user_data != NULL);
-
-       g_variant_get (user_data, "(&s&s)", &guid, &server_address);
-
-       if (!server_address) {
-               g_warning ("%d %s: The UI process didn't provide server address", getpid (), G_STRFUNC);
-               return;
-       }
-
-       camel_debug_init ();
-
-       if (camel_debug ("webkit:preview"))
-               printf ("%s\n", G_STRFUNC);
 
        extension = e_web_extension_get ();
-       e_web_extension_initialize (extension, wk_extension);
 
-       e_web_extension_container_utils_connect_to_server (server_address, NULL, connected_to_server_cb, 
g_object_ref (extension));
+       e_web_extension_initialize (extension, wk_extension);
 }
diff --git a/src/web-extensions/e-web-extension.c b/src/web-extensions/e-web-extension.c
index 9d85388a13..87c52fd91e 100644
--- a/src/web-extensions/e-web-extension.c
+++ b/src/web-extensions/e-web-extension.c
@@ -24,1851 +24,23 @@
 #include <glib/gstdio.h>
 #include <gtk/gtk.h>
 
-#include <camel/camel.h>
-#include <libedataserver/libedataserver.h>
-
-#include "e-web-extension.h"
-#include "e-dom-utils.h"
-#include "e-itip-formatter-dom-utils.h"
-#include "e-web-extension-names.h"
-
 #include <webkitdom/webkitdom.h>
 
-#define WEB_EXTENSION_PAGE_ID_KEY "web-extension-page-id"
-
-#define E_WEB_EXTENSION_GET_PRIVATE(obj) \
-       (G_TYPE_INSTANCE_GET_PRIVATE \
-       ((obj), E_TYPE_WEB_EXTENSION, EWebExtensionPrivate))
+#define E_UTIL_INCLUDE_WITHOUT_WEBKIT
+#include <e-util/e-util.h>
+#undef E_UTIL_INCLUDE_WITHOUT_WEBKIT
 
-typedef struct _EWebPageData {
-       WebKitWebPage *web_page; /* not referenced */
-       gint stamp;
-       gboolean need_input;
-       guint32 clipboard_flags;
-} EWebPageData;
+#include "e-web-extension.h"
 
 struct _EWebExtensionPrivate {
        WebKitWebExtension *wk_extension;
 
-       GDBusConnection *dbus_connection;
-       guint registration_id;
-
        gboolean initialized;
-
-       GSList *pages; /* EWebPageData * */
-};
-
-enum {
-       REGISTER_DBUS_CONNECTION,
-       LAST_SIGNAL
 };
 
-static guint signals[LAST_SIGNAL];
-
-static const char introspection_xml[] =
-"<node>"
-"  <interface name='" E_WEB_EXTENSION_INTERFACE "'>"
-"    <signal name='ExtensionObjectReady'>"
-"    </signal>"
-"    <method name='GetExtensionHandlesPages'>"
-"      <arg type='at' name='array' direction='out'/>"
-"    </method>"
-"    <signal name='ExtensionHandlesPage'>"
-"      <arg type='t' name='page_id' direction='out'/>"
-"      <arg type='i' name='stamp' direction='out'/>"
-"    </signal>"
-"    <method name='RegisterElementClicked'>"
-"      <arg type='t' name='page_id' direction='in'/>"
-"      <arg type='s' name='element_class' direction='in'/>"
-"    </method>"
-"    <signal name='ElementClicked'>"
-"      <arg type='t' name='page_id' direction='out'/>"
-"      <arg type='s' name='element_class' direction='out'/>"
-"      <arg type='s' name='element_value' direction='out'/>"
-"      <arg type='i' name='position_left' direction='out'/>"
-"      <arg type='i' name='position_top' direction='out'/>"
-"      <arg type='i' name='position_width' direction='out'/>"
-"      <arg type='i' name='position_height' direction='out'/>"
-"    </signal>"
-"    <method name='SetElementHidden'>"
-"      <arg type='t' name='page_id' direction='in'/>"
-"      <arg type='s' name='element_id' direction='in'/>"
-"      <arg type='b' name='hidden' direction='in'/>"
-"    </method>"
-"    <method name='SetElementStyleProperty'>"
-"      <arg type='t' name='page_id' direction='in'/>"
-"      <arg type='s' name='element_id' direction='in'/>"
-"      <arg type='s' name='property_name' direction='in'/>"
-"      <arg type='s' name='value' direction='in'/>"
-"      <arg type='s' name='priority' direction='in'/>"
-"    </method>"
-"    <method name='SetElementAttribute'>"
-"      <arg type='t' name='page_id' direction='in'/>"
-"      <arg type='s' name='element_id' direction='in'/>"
-"      <arg type='s' name='namespace_uri' direction='in'/>"
-"      <arg type='s' name='qualified_name' direction='in'/>"
-"      <arg type='s' name='value' direction='in'/>"
-"    </method>"
-"    <signal name='HeadersCollapsed'>"
-"      <arg type='b' name='expanded' direction='out'/>"
-"    </signal>"
-"    <method name='DocumentHasSelection'>"
-"      <arg type='t' name='page_id' direction='in'/>"
-"      <arg type='b' name='has_selection' direction='out'/>"
-"    </method>"
-"    <method name='GetDocumentContentHTML'>"
-"      <arg type='t' name='page_id' direction='in'/>"
-"      <arg type='s' name='html_content' direction='out'/>"
-"    </method>"
-"    <method name='GetSelectionContentHTML'>"
-"      <arg type='t' name='page_id' direction='in'/>"
-"      <arg type='s' name='html_content' direction='out'/>"
-"    </method>"
-"    <method name='GetSelectionContentText'>"
-"      <arg type='t' name='page_id' direction='in'/>"
-"      <arg type='s' name='text_content' direction='out'/>"
-"    </method>"
-"    <method name='GetSelectionContentMultipart'>"
-"      <arg type='t' name='page_id' direction='in'/>"
-"      <arg type='s' name='content' direction='out'/>"
-"      <arg type='b' name='is_html' direction='out'/>"
-"    </method>"
-"    <method name='CreateAndAddCSSStyleSheet'>"
-"      <arg type='t' name='page_id' direction='in'/>"
-"      <arg type='s' name='style_sheet_id' direction='in'/>"
-"    </method>"
-"    <method name='AddCSSRuleIntoStyleSheet'>"
-"      <arg type='t' name='page_id' direction='in'/>"
-"      <arg type='s' name='style_sheet_id' direction='in'/>"
-"      <arg type='s' name='selector' direction='in'/>"
-"      <arg type='s' name='style' direction='in'/>"
-"    </method>"
-"    <method name='EABContactFormatterBindDOM'>"
-"      <arg type='t' name='page_id' direction='in'/>"
-"    </method>"
-"    <method name='EMailDisplayBindDOM'>"
-"      <arg type='t' name='page_id' direction='in'/>"
-"    </method>"
-"    <method name='ElementExists'>"
-"      <arg type='t' name='page_id' direction='in'/>"
-"      <arg type='s' name='element_id' direction='in'/>"
-"      <arg type='b' name='element_exists' direction='out'/>"
-"      <arg type='t' name='page_id' direction='out'/>"
-"    </method>"
-"    <method name='GetActiveElementName'>"
-"      <arg type='t' name='page_id' direction='in'/>"
-"      <arg type='s' name='element_name' direction='out'/>"
-"    </method>"
-"    <method name='EMailPartHeadersBindDOMElement'>"
-"      <arg type='t' name='page_id' direction='in'/>"
-"      <arg type='s' name='element_id' direction='in'/>"
-"    </method>"
-"    <signal name='VCardInlineDisplayModeToggled'>"
-"      <arg type='s' name='button_id' direction='out'/>"
-"    </signal>"
-"    <signal name='VCardInlineSaveButtonPressed'>"
-"      <arg type='s' name='button_value' direction='out'/>"
-"    </signal>"
-"    <method name='VCardInlineBindDOM'>"
-"      <arg type='t' name='page_id' direction='in'/>"
-"      <arg type='s' name='element_id' direction='in'/>"
-"    </method>"
-"    <method name='VCardInlineUpdateButton'>"
-"      <arg type='t' name='page_id' direction='in'/>"
-"      <arg type='s' name='button_id' direction='in'/>"
-"      <arg type='s' name='html_label' direction='in'/>"
-"      <arg type='s' name='access_key' direction='in'/>"
-"    </method>"
-"    <method name='VCardInlineSetIFrameSrc'>"
-"      <arg type='t' name='page_id' direction='in'/>"
-"      <arg type='s' name='button_id' direction='in'/>"
-"      <arg type='s' name='src' direction='in'/>"
-"    </method>"
-"    <method name='GetDocumentURIFromPoint'>"
-"      <arg type='t' name='page_id' direction='in'/>"
-"      <arg type='i' name='x' direction='in'/>"
-"      <arg type='i' name='y' direction='in'/>"
-"      <arg type='s' name='document_uri' direction='out'/>"
-"    </method>"
-"    <method name='SetDocumentIFrameSrc'>"
-"      <arg type='t' name='page_id' direction='in'/>"
-"      <arg type='s' name='document_uri' direction='in'/>"
-"      <arg type='s' name='new_iframe_src' direction='in'/>"
-"    </method>"
-"    <method name='ProcessMagicSpacebar'>"
-"      <arg type='t' name='page_id' direction='in'/>"
-"      <arg type='b' name='towards_bottom' direction='in'/>"
-"      <arg type='b' name='processed' direction='out'/>"
-"    </method>"
-"    <method name='EWebViewEnsureBodyClass'>"
-"      <arg type='t' name='page_id' direction='in'/>"
-"      <arg type='s' name='body_class' direction='in'/>"
-"    </method>"
-"    <signal name='NeedInputChanged'>"
-"      <arg type='t' name='page_id' direction='out'/>"
-"      <arg type='b' name='need_input' direction='out'/>"
-"    </signal>"
-"    <signal name='ClipboardFlagsChanged'>"
-"      <arg type='t' name='page_id' direction='out'/>"
-"      <arg type='u' name='flags' direction='out'/>"
-"    </signal>"
-"    <signal name='MailPartAppeared'>"
-"      <arg type='t' name='page_id' direction='out'/>"
-"      <arg type='s' name='part_id' direction='out'/>"
-"    </signal>"
-"    <signal name='ItipRecurToggled'>"
-"      <arg type='t' name='page_id' direction='out'/>"
-"      <arg type='s' name='part_id' direction='out'/>"
-"    </signal>"
-"    <signal name='ItipSourceChanged'>"
-"      <arg type='t' name='page_id' direction='out'/>"
-"      <arg type='s' name='part_id' direction='out'/>"
-"    </signal>"
-"    <method name='ItipCreateDOMBindings'>"
-"      <arg type='t' name='page_id' direction='in'/>"
-"      <arg type='s' name='part_id' direction='in'/>"
-"    </method>"
-"    <method name='ItipShowButton'>"
-"      <arg type='t' name='page_id' direction='in'/>"
-"      <arg type='s' name='part_id' direction='in'/>"
-"      <arg type='s' name='button_id' direction='in'/>"
-"    </method>"
-"    <method name='ItipElementSetInnerHTML'>"
-"      <arg type='t' name='page_id' direction='in'/>"
-"      <arg type='s' name='part_id' direction='in'/>"
-"      <arg type='s' name='element_id' direction='in'/>"
-"      <arg type='s' name='inner_html' direction='in'/>"
-"    </method>"
-"    <method name='ItipRemoveElement'>"
-"      <arg type='t' name='page_id' direction='in'/>"
-"      <arg type='s' name='part_id' direction='in'/>"
-"      <arg type='s' name='element_id' direction='in'/>"
-"    </method>"
-"    <method name='ItipElementRemoveChildNodes'>"
-"      <arg type='t' name='page_id' direction='in'/>"
-"      <arg type='s' name='part_id' direction='in'/>"
-"      <arg type='s' name='element_id' direction='in'/>"
-"    </method>"
-"    <method name='ItipEnableButton'>"
-"      <arg type='t' name='page_id' direction='in'/>"
-"      <arg type='s' name='part_id' direction='in'/>"
-"      <arg type='s' name='button_id' direction='in'/>"
-"      <arg type='b' name='enable' direction='in'/>"
-"    </method>"
-"    <method name='ItipElementIsHidden'>"
-"      <arg type='t' name='page_id' direction='in'/>"
-"      <arg type='s' name='part_id' direction='in'/>"
-"      <arg type='s' name='element_id' direction='in'/>"
-"      <arg type='b' name='is_hidden' direction='out'/>"
-"    </method>"
-"    <method name='ItipHideElement'>"
-"      <arg type='t' name='page_id' direction='in'/>"
-"      <arg type='s' name='part_id' direction='in'/>"
-"      <arg type='s' name='element_id' direction='in'/>"
-"      <arg type='b' name='hide' direction='in'/>"
-"    </method>"
-"    <method name='ItipInputSetChecked'>"
-"      <arg type='t' name='page_id' direction='in'/>"
-"      <arg type='s' name='part_id' direction='in'/>"
-"      <arg type='s' name='input_id' direction='in'/>"
-"      <arg type='b' name='checked' direction='in'/>"
-"    </method>"
-"    <method name='ItipInputIsChecked'>"
-"      <arg type='t' name='page_id' direction='in'/>"
-"      <arg type='s' name='part_id' direction='in'/>"
-"      <arg type='s' name='input_id' direction='in'/>"
-"      <arg type='b' name='checked' direction='out'/>"
-"    </method>"
-"    <method name='ItipShowCheckbox'>"
-"      <arg type='t' name='page_id' direction='in'/>"
-"      <arg type='s' name='part_id' direction='in'/>"
-"      <arg type='s' name='id' direction='in'/>"
-"      <arg type='b' name='show' direction='in'/>"
-"      <arg type='b' name='update_second' direction='in'/>"
-"    </method>"
-"    <method name='ItipSetButtonsSensitive'>"
-"      <arg type='t' name='page_id' direction='in'/>"
-"      <arg type='s' name='part_id' direction='in'/>"
-"      <arg type='b' name='sensitive' direction='in'/>"
-"    </method>"
-"    <method name='ItipSetAreaText'>"
-"      <arg type='t' name='page_id' direction='in'/>"
-"      <arg type='s' name='part_id' direction='in'/>"
-"      <arg type='s' name='id' direction='in'/>"
-"      <arg type='s' name='text' direction='in'/>"
-"    </method>"
-"    <method name='ItipElementSetAccessKey'>"
-"      <arg type='t' name='page_id' direction='in'/>"
-"      <arg type='s' name='part_id' direction='in'/>"
-"      <arg type='s' name='element_id' direction='in'/>"
-"      <arg type='s' name='access_key' direction='in'/>"
-"    </method>"
-"    <method name='ItipElementHideChildNodes'>"
-"      <arg type='t' name='page_id' direction='in'/>"
-"      <arg type='s' name='part_id' direction='in'/>"
-"      <arg type='s' name='element_id' direction='in'/>"
-"    </method>"
-"    <method name='ItipEnableSelect'>"
-"      <arg type='t' name='page_id' direction='in'/>"
-"      <arg type='s' name='part_id' direction='in'/>"
-"      <arg type='s' name='select_id' direction='in'/>"
-"      <arg type='b' name='enable' direction='in'/>"
-"    </method>"
-"    <method name='ItipSelectIsEnabled'>"
-"      <arg type='t' name='page_id' direction='in'/>"
-"      <arg type='s' name='part_id' direction='in'/>"
-"      <arg type='s' name='select_id' direction='in'/>"
-"      <arg type='b' name='enable' direction='out'/>"
-"    </method>"
-"    <method name='ItipSelectGetValue'>"
-"      <arg type='t' name='page_id' direction='in'/>"
-"      <arg type='s' name='part_id' direction='in'/>"
-"      <arg type='s' name='select_id' direction='in'/>"
-"      <arg type='s' name='value' direction='out'/>"
-"    </method>"
-"    <method name='ItipSelectSetSelected'>"
-"      <arg type='t' name='page_id' direction='in'/>"
-"      <arg type='s' name='part_id' direction='in'/>"
-"      <arg type='s' name='select_id' direction='in'/>"
-"      <arg type='s' name='option' direction='in'/>"
-"    </method>"
-"    <method name='ItipUpdateTimes'>"
-"      <arg type='t' name='page_id' direction='in'/>"
-"      <arg type='s' name='part_id' direction='in'/>"
-"      <arg type='s' name='element_id' direction='in'/>"
-"      <arg type='s' name='header' direction='in'/>"
-"      <arg type='s' name='label' direction='in'/>"
-"    </method>"
-"    <method name='ItipAppendInfoItemRow'>"
-"      <arg type='t' name='page_id' direction='in'/>"
-"      <arg type='s' name='part_id' direction='in'/>"
-"      <arg type='s' name='table_id' direction='in'/>"
-"      <arg type='s' name='row_id' direction='in'/>"
-"      <arg type='s' name='icon_name' direction='in'/>"
-"      <arg type='s' name='message' direction='in'/>"
-"    </method>"
-"    <method name='ItipEnableTextArea'>"
-"      <arg type='t' name='page_id' direction='in'/>"
-"      <arg type='s' name='part_id' direction='in'/>"
-"      <arg type='s' name='area_id' direction='in'/>"
-"      <arg type='b' name='enable' direction='in'/>"
-"    </method>"
-"    <method name='ItipTextAreaSetValue'>"
-"      <arg type='t' name='page_id' direction='in'/>"
-"      <arg type='s' name='part_id' direction='in'/>"
-"      <arg type='s' name='area_id' direction='in'/>"
-"      <arg type='s' name='value' direction='in'/>"
-"    </method>"
-"    <method name='ItipTextAreaGetValue'>"
-"      <arg type='t' name='page_id' direction='in'/>"
-"      <arg type='s' name='part_id' direction='in'/>"
-"      <arg type='s' name='area_id' direction='in'/>"
-"      <arg type='s' name='value' direction='out'/>"
-"    </method>"
-"    <method name='ItipRebuildSourceList'>"
-"      <arg type='t' name='page_id' direction='in'/>"
-"      <arg type='s' name='part_id' direction='in'/>"
-"      <arg type='s' name='optgroup_id' direction='in'/>"
-"      <arg type='s' name='optgroup_label' direction='in'/>"
-"      <arg type='s' name='option_id' direction='in'/>"
-"      <arg type='s' name='option_label' direction='in'/>"
-"      <arg type='b' name='writable' direction='in'/>"
-"    </method>"
-"  </interface>"
-"</node>";
-
 G_DEFINE_TYPE_WITH_CODE (EWebExtension, e_web_extension, G_TYPE_OBJECT,
        G_IMPLEMENT_INTERFACE (E_TYPE_EXTENSIBLE, NULL))
 
-static WebKitWebPage *
-get_webkit_web_page_or_return_dbus_error (GDBusMethodInvocation *invocation,
-                                          WebKitWebExtension *web_extension,
-                                          guint64 page_id)
-{
-       WebKitWebPage *web_page = webkit_web_extension_get_page (web_extension, page_id);
-       if (!web_page) {
-               g_dbus_method_invocation_return_error (
-                       invocation, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
-                       "Invalid page ID: %" G_GUINT64_FORMAT, page_id);
-       }
-       return web_page;
-}
-
-static WebKitDOMDocument *
-get_webkit_document_or_return_dbus_error (GDBusMethodInvocation *invocation,
-                                          WebKitWebExtension *web_extension,
-                                          guint64 page_id)
-{
-       WebKitDOMDocument *document;
-       WebKitWebPage *web_page;
-
-       web_page = webkit_web_extension_get_page (web_extension, page_id);
-       if (!web_page) {
-               g_dbus_method_invocation_return_error (
-                       invocation, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
-                       "Invalid page ID: %" G_GUINT64_FORMAT, page_id);
-               return NULL;
-       }
-
-       document = webkit_web_page_get_dom_document (web_page);
-       if (!document) {
-               g_dbus_method_invocation_return_error (
-                       invocation, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
-                       "No document for page ID: %" G_GUINT64_FORMAT, page_id);
-               return NULL;
-       }
-
-       return document;
-}
-
-static WebKitDOMDocument *
-find_webkit_document_for_partid_or_return_dbus_error (GDBusMethodInvocation *invocation,
-                                                     WebKitDOMDocument *owner,
-                                                     const gchar *part_id)
-{
-       WebKitDOMElement *element;
-
-       g_return_val_if_fail (G_IS_DBUS_METHOD_INVOCATION (invocation), NULL);
-       g_return_val_if_fail (WEBKIT_DOM_IS_DOCUMENT (owner), NULL);
-       g_return_val_if_fail (part_id && *part_id, NULL);
-
-       element = e_dom_utils_find_element_by_id (owner, part_id);
-       if (element && WEBKIT_DOM_IS_HTML_IFRAME_ELEMENT (element)) {
-               WebKitDOMDocument *document = webkit_dom_html_iframe_element_get_content_document 
(WEBKIT_DOM_HTML_IFRAME_ELEMENT (element));
-               return document;
-       }
-
-       if (element)
-               g_dbus_method_invocation_return_error (
-                       invocation, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
-                       "Part ID '%s' is not IFRAME, but %s", part_id, G_OBJECT_TYPE_NAME (element));
-       else
-               g_dbus_method_invocation_return_error (
-                       invocation, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
-                       "Part ID '%s' not found", part_id);
-       return NULL;
-}
-
-static void
-element_clicked_cb (WebKitDOMElement *element,
-                   WebKitDOMEvent *event,
-                   gpointer user_data)
-{
-       EWebExtension *extension = user_data;
-       WebKitDOMElement *offset_parent;
-       WebKitDOMDOMWindow *dom_window = NULL;
-       gchar *attr_class, *attr_value;
-       const guint64 *ppage_id;
-       gdouble with_parents_left, with_parents_top;
-       glong scroll_x = 0, scroll_y = 0;
-       GError *error = NULL;
-
-       g_return_if_fail (E_IS_WEB_EXTENSION (extension));
-       g_return_if_fail (G_IS_OBJECT (element));
-
-       ppage_id = g_object_get_data (G_OBJECT (element), WEB_EXTENSION_PAGE_ID_KEY);
-       g_return_if_fail (ppage_id != NULL);
-
-       with_parents_left = webkit_dom_element_get_offset_left (element);
-       with_parents_top = webkit_dom_element_get_offset_top (element);
-
-       offset_parent = element;
-       while (offset_parent = webkit_dom_element_get_offset_parent (offset_parent), offset_parent) {
-               with_parents_left += webkit_dom_element_get_offset_left (offset_parent);
-               with_parents_top += webkit_dom_element_get_offset_top (offset_parent);
-       }
-
-       dom_window = webkit_dom_document_get_default_view (webkit_dom_node_get_owner_document 
(WEBKIT_DOM_NODE (element)));
-       while (WEBKIT_DOM_IS_DOM_WINDOW (dom_window)) {
-               WebKitDOMDOMWindow *parent_dom_window = webkit_dom_dom_window_get_parent (dom_window);
-               WebKitDOMElement *frame_element;
-               glong scrll_x = 0, scrll_y = 0;
-
-               frame_element = webkit_dom_dom_window_get_frame_element (dom_window);
-
-               if (parent_dom_window != dom_window && frame_element) {
-                       with_parents_left += webkit_dom_element_get_client_left (frame_element);
-                       with_parents_top += webkit_dom_element_get_client_top (frame_element);
-               }
-
-               while (frame_element) {
-                       with_parents_left += webkit_dom_element_get_offset_left (frame_element);
-                       with_parents_top += webkit_dom_element_get_offset_top (frame_element);
-
-                       frame_element = webkit_dom_element_get_offset_parent (frame_element);
-               }
-
-               g_object_get (G_OBJECT (dom_window),
-                       "scroll-x", &scrll_x,
-                       "scroll-y", &scrll_y,
-                       NULL);
-
-               scroll_x += scrll_x;
-               scroll_y += scrll_y;
-
-               if (parent_dom_window == dom_window) {
-                       g_clear_object (&parent_dom_window);
-                       break;
-               }
-
-               g_object_unref (dom_window);
-               dom_window = parent_dom_window;
-       }
-       g_clear_object (&dom_window);
-
-       attr_class = webkit_dom_element_get_class_name (element);
-       attr_value = webkit_dom_element_get_attribute (element, "value");
-
-       g_dbus_connection_emit_signal (
-               extension->priv->dbus_connection,
-               NULL,
-               E_WEB_EXTENSION_OBJECT_PATH,
-               E_WEB_EXTENSION_INTERFACE,
-               "ElementClicked",
-               g_variant_new ("(tssiiii)", *ppage_id, attr_class ? attr_class : "", attr_value ? attr_value 
: "",
-                       (gint) (with_parents_left - scroll_x),
-                       (gint) (with_parents_top - scroll_y),
-                       (gint) webkit_dom_element_get_offset_width (element),
-                       (gint) webkit_dom_element_get_offset_height (element)),
-               &error);
-
-       if (error) {
-               g_warning ("Error emitting signal ElementClicked: %s\n", error->message);
-               g_error_free (error);
-       }
-
-       g_free (attr_class);
-       g_free (attr_value);
-}
-
-static void
-web_extension_register_element_clicked_in_document (EWebExtension *extension,
-                                                   guint64 page_id,
-                                                   WebKitDOMDocument *document,
-                                                   const gchar *element_class)
-{
-       WebKitDOMHTMLCollection *collection = NULL;
-       gulong ii, len;
-
-       g_return_if_fail (E_IS_WEB_EXTENSION (extension));
-       g_return_if_fail (WEBKIT_DOM_IS_DOCUMENT (document));
-       g_return_if_fail (element_class && *element_class);
-
-       collection = webkit_dom_document_get_elements_by_class_name_as_html_collection (document, 
element_class);
-       if (collection) {
-               len = webkit_dom_html_collection_get_length (collection);
-               for (ii = 0; ii < len; ii++) {
-                       WebKitDOMNode *node;
-
-                       node = webkit_dom_html_collection_item (collection, ii);
-                       if (WEBKIT_DOM_IS_EVENT_TARGET (node)) {
-                               guint64 *ppage_id;
-
-                               ppage_id = g_new0 (guint64, 1);
-                               *ppage_id = page_id;
-
-                               g_object_set_data_full (G_OBJECT (node), WEB_EXTENSION_PAGE_ID_KEY, ppage_id, 
g_free);
-
-                               /* Remove first, in case there was a listener already (it's when
-                                  the page is dynamically filled and not all the elements are
-                                  available in time of the first call. */
-                               webkit_dom_event_target_remove_event_listener (
-                                       WEBKIT_DOM_EVENT_TARGET (node), "click",
-                                       G_CALLBACK (element_clicked_cb), FALSE);
-
-                               webkit_dom_event_target_add_event_listener (
-                                       WEBKIT_DOM_EVENT_TARGET (node), "click",
-                                       G_CALLBACK (element_clicked_cb), FALSE, extension);
-                       }
-               }
-       }
-       g_clear_object (&collection);
-
-       /* Traverse also iframe-s */
-       collection = webkit_dom_document_get_elements_by_tag_name_as_html_collection (document, "iframe");
-       if (collection) {
-               len = webkit_dom_html_collection_get_length (collection);
-               for (ii = 0; ii < len; ii++) {
-                       WebKitDOMNode *node;
-
-                       node = webkit_dom_html_collection_item (collection, ii);
-                       if (WEBKIT_DOM_IS_HTML_IFRAME_ELEMENT (node)) {
-                               WebKitDOMDocument *content;
-
-                               content = webkit_dom_html_iframe_element_get_content_document 
(WEBKIT_DOM_HTML_IFRAME_ELEMENT (node));
-                               if (content)
-                                       web_extension_register_element_clicked_in_document (extension, 
page_id, content, element_class);
-                       }
-               }
-       }
-       g_clear_object (&collection);
-}
-
-static guint64
-e_web_extension_find_page_id_from_document (WebKitDOMDocument *document)
-{
-       guint64 *ppage_id;
-
-       g_return_val_if_fail (WEBKIT_DOM_IS_DOCUMENT (document), 0);
-
-       while (document) {
-               WebKitDOMDocument *prev_document = document;
-
-               ppage_id = g_object_get_data (G_OBJECT (document), WEB_EXTENSION_PAGE_ID_KEY);
-               if (ppage_id)
-                       return *ppage_id;
-
-               document = webkit_dom_node_get_owner_document (WEBKIT_DOM_NODE (document));
-               if (prev_document == document)
-                       break;
-       }
-
-       return 0;
-}
-
-static EWebPageData *
-e_web_extension_get_page_data (EWebExtension *extension,
-                              guint64 page_id)
-{
-       GSList *link;
-
-       for (link = extension->priv->pages; link; link = g_slist_next (link)) {
-               EWebPageData *page_data = link->data;
-
-               if (page_data && webkit_web_page_get_id (page_data->web_page) == page_id)
-                       return page_data;
-       }
-
-       return NULL;
-}
-
-static void
-e_web_extension_set_need_input (EWebExtension *extension,
-                               guint64 page_id,
-                               gboolean need_input)
-{
-       EWebPageData *page_data;
-       GError *error = NULL;
-
-       g_return_if_fail (E_IS_WEB_EXTENSION (extension));
-       g_return_if_fail (page_id != 0);
-
-       page_data = e_web_extension_get_page_data (extension, page_id);
-
-       if (!page_data || (!page_data->need_input) == (!need_input))
-               return;
-
-       page_data->need_input = need_input;
-
-       g_dbus_connection_emit_signal (
-               extension->priv->dbus_connection,
-               NULL,
-               E_WEB_EXTENSION_OBJECT_PATH,
-               E_WEB_EXTENSION_INTERFACE,
-               "NeedInputChanged",
-               g_variant_new ("(tb)", page_id, need_input),
-               &error);
-
-       if (error) {
-               g_warning ("Error emitting signal NeedInputChanged: %s\n", error->message);
-               g_error_free (error);
-       }
-}
-
-static void
-element_focus_cb (WebKitDOMElement *element,
-                 WebKitDOMEvent *event,
-                 EWebExtension *extension)
-{
-       guint64 *ppage_id;
-
-       g_return_if_fail (E_IS_WEB_EXTENSION (extension));
-
-       ppage_id = g_object_get_data (G_OBJECT (element), WEB_EXTENSION_PAGE_ID_KEY);
-       g_return_if_fail (ppage_id != NULL);
-
-       e_web_extension_set_need_input (extension, *ppage_id, TRUE);
-}
-
-static void
-element_blur_cb (WebKitDOMElement *element,
-                WebKitDOMEvent *event,
-                EWebExtension *extension)
-{
-       guint64 *ppage_id;
-
-       g_return_if_fail (E_IS_WEB_EXTENSION (extension));
-
-       ppage_id = g_object_get_data (G_OBJECT (element), WEB_EXTENSION_PAGE_ID_KEY);
-       g_return_if_fail (ppage_id != NULL);
-
-       e_web_extension_set_need_input (extension, *ppage_id, FALSE);
-}
-
-static void
-e_web_extension_bind_focus_and_blur_recursively (EWebExtension *extension,
-                                                WebKitDOMDocument *document,
-                                                const gchar *selector,
-                                                guint64 page_id)
-{
-       WebKitDOMNodeList *nodes = NULL;
-       WebKitDOMHTMLCollection *frames = NULL;
-       gulong ii, length;
-
-       g_return_if_fail (E_IS_WEB_EXTENSION (extension));
-
-       nodes = webkit_dom_document_query_selector_all (document, selector, NULL);
-
-       length = webkit_dom_node_list_get_length (nodes);
-       for (ii = 0; ii < length; ii++) {
-               WebKitDOMNode *node;
-               guint64 *ppage_id;
-
-               node = webkit_dom_node_list_item (nodes, ii);
-
-               ppage_id = g_new (guint64, 1);
-               *ppage_id = page_id;
-
-               g_object_set_data_full (G_OBJECT (node), WEB_EXTENSION_PAGE_ID_KEY, ppage_id, g_free);
-
-               webkit_dom_event_target_add_event_listener (
-                       WEBKIT_DOM_EVENT_TARGET (node), "focus",
-                       G_CALLBACK (element_focus_cb), FALSE, extension);
-
-               webkit_dom_event_target_add_event_listener (
-                       WEBKIT_DOM_EVENT_TARGET (node), "blur",
-                       G_CALLBACK (element_blur_cb), FALSE, extension);
-       }
-       g_clear_object (&nodes);
-
-       frames = webkit_dom_document_get_elements_by_tag_name_as_html_collection (document, "iframe");
-       length = webkit_dom_html_collection_get_length (frames);
-
-       /* Add rules to every sub document */
-       for (ii = 0; ii < length; ii++) {
-               WebKitDOMDocument *content_document = NULL;
-               WebKitDOMNode *node;
-
-               node = webkit_dom_html_collection_item (frames, ii);
-               content_document =
-                       webkit_dom_html_iframe_element_get_content_document (
-                               WEBKIT_DOM_HTML_IFRAME_ELEMENT (node));
-
-               if (!content_document)
-                       continue;
-
-               e_web_extension_bind_focus_and_blur_recursively (
-                       extension,
-                       content_document,
-                       selector,
-                       page_id);
-       }
-       g_clear_object (&frames);
-}
-
-static void
-e_web_extension_bind_focus_on_elements (EWebExtension *extension,
-                                       WebKitDOMDocument *document)
-{
-       const gchar *elements = "input, textarea, select, button, label";
-       guint64 page_id;
-
-       g_return_if_fail (E_IS_WEB_EXTENSION (extension));
-       g_return_if_fail (WEBKIT_DOM_IS_DOCUMENT (document));
-
-       page_id = e_web_extension_find_page_id_from_document (document);
-       g_return_if_fail (page_id != 0);
-
-       e_web_extension_bind_focus_and_blur_recursively (
-               extension,
-               document,
-               elements,
-               page_id);
-}
-
-typedef struct _MailPartAppearedData {
-       GWeakRef *dbus_connection;
-       GWeakRef *web_page;
-       gchar *element_id;
-       GVariant *params;
-} MailPartAppearedData;
-
-static void
-mail_part_appeared_data_free (gpointer ptr)
-{
-       MailPartAppearedData *mpad = ptr;
-
-       if (mpad) {
-               e_weak_ref_free (mpad->dbus_connection);
-               e_weak_ref_free (mpad->web_page);
-               g_free (mpad->element_id);
-               if (mpad->params)
-                       g_variant_unref (mpad->params);
-               g_free (mpad);
-       }
-}
-
-static gboolean
-web_extension_can_emit_mail_part_appeared (WebKitWebPage *web_page,
-                                          const gchar *element_id,
-                                          gboolean *out_abort_wait)
-{
-       WebKitDOMDocument *document;
-       WebKitDOMElement *element;
-       WebKitDOMElement *iframe;
-       WebKitDOMDocument *iframe_document;
-       WebKitDOMHTMLElement *iframe_body;
-
-       g_return_val_if_fail (out_abort_wait != NULL, FALSE);
-
-       *out_abort_wait = TRUE;
-
-       if (!web_page)
-               return FALSE;
-
-       if (!element_id || !*element_id)
-               return FALSE;
-
-       document = webkit_web_page_get_dom_document (web_page);
-       if (!document)
-               return FALSE;
-
-       element = e_dom_utils_find_element_by_id (document, element_id);
-
-       if (!WEBKIT_DOM_IS_HTML_ELEMENT (element))
-               return FALSE;
-
-       iframe = webkit_dom_element_query_selector (element, "iframe", NULL);
-       if (!iframe)
-               return FALSE;
-
-       iframe_document = webkit_dom_html_iframe_element_get_content_document (WEBKIT_DOM_HTML_IFRAME_ELEMENT 
(iframe));
-       if (!iframe_document)
-               return FALSE;
-
-       iframe_body = webkit_dom_document_get_body (iframe_document);
-       if (!iframe_body)
-               return FALSE;
-
-       *out_abort_wait = FALSE;
-
-       return webkit_dom_element_get_first_element_child (WEBKIT_DOM_ELEMENT (iframe_body)) != NULL;
-}
-
-static gboolean
-web_extension_emit_mail_part_appeared_cb (gpointer user_data)
-{
-       MailPartAppearedData *mpad = user_data;
-       GDBusConnection *dbus_connection;
-       WebKitWebPage *web_page;
-       gboolean abort_wait = TRUE;
-
-       g_return_val_if_fail (mpad != NULL, FALSE);
-
-       dbus_connection = g_weak_ref_get (mpad->dbus_connection);
-       web_page = g_weak_ref_get (mpad->web_page);
-
-       if (dbus_connection && web_page &&
-           web_extension_can_emit_mail_part_appeared (web_page, mpad->element_id, &abort_wait)) {
-               GError *error = NULL;
-
-               g_dbus_connection_emit_signal (
-                       dbus_connection,
-                       NULL,
-                       E_WEB_EXTENSION_OBJECT_PATH,
-                       E_WEB_EXTENSION_INTERFACE,
-                       "MailPartAppeared",
-                       mpad->params,
-                       &error);
-
-               if (error) {
-                       g_warning ("Error emitting signal MailPartAppeared: %s", error->message);
-                       g_error_free (error);
-               }
-
-               abort_wait = TRUE;
-               mpad->params = NULL;
-       }
-
-       if (abort_wait)
-               mail_part_appeared_data_free (mpad);
-
-       g_clear_object (&dbus_connection);
-       g_clear_object (&web_page);
-
-       return !abort_wait;
-}
-
-static void
-handle_method_call (GDBusConnection *connection,
-                    const char *sender,
-                    const char *object_path,
-                    const char *interface_name,
-                    const char *method_name,
-                    GVariant *parameters,
-                    GDBusMethodInvocation *invocation,
-                    gpointer user_data)
-{
-       guint64 page_id;
-        EWebExtension *extension = E_WEB_EXTENSION (user_data);
-       WebKitDOMDocument *document;
-       WebKitWebExtension *web_extension = extension->priv->wk_extension;
-       WebKitWebPage *web_page;
-
-       if (g_strcmp0 (interface_name, E_WEB_EXTENSION_INTERFACE) != 0)
-               return;
-
-       if (camel_debug ("webkit:preview"))
-               printf ("EWebExtension - %s - %s\n", G_STRFUNC, method_name);
-
-       if (g_strcmp0 (method_name, "GetExtensionHandlesPages") == 0) {
-               GVariantBuilder *builder;
-               GSList *link;
-
-               builder = g_variant_builder_new (G_VARIANT_TYPE ("at"));
-
-               for (link = extension->priv->pages; link; link = g_slist_next (link)) {
-                       EWebPageData *page_data = link->data;
-
-                       if (page_data) {
-                               g_variant_builder_add (builder, "t", webkit_web_page_get_id 
(page_data->web_page));
-                               g_variant_builder_add (builder, "t", (guint64) page_data->stamp);
-                       }
-               }
-
-               g_dbus_method_invocation_return_value (invocation,
-                       g_variant_new ("(at)", builder));
-
-               g_variant_builder_unref (builder);
-       } else if (g_strcmp0 (method_name, "RegisterElementClicked") == 0) {
-               const gchar *element_class = NULL;
-
-               g_variant_get (parameters, "(t&s)", &page_id, &element_class);
-
-               web_page = get_webkit_web_page_or_return_dbus_error (invocation, web_extension, page_id);
-               if (!web_page)
-                       return;
-
-               if (!element_class || !*element_class) {
-                       g_warn_if_fail (element_class && *element_class);
-               } else {
-                       document = webkit_web_page_get_dom_document (web_page);
-                       web_extension_register_element_clicked_in_document (extension, page_id, document, 
element_class);
-               }
-
-               g_dbus_method_invocation_return_value (invocation, NULL);
-       } else if (g_strcmp0 (method_name, "SetElementHidden") == 0) {
-               const gchar *element_id = NULL;
-               gboolean hidden = FALSE;
-
-               g_variant_get (parameters, "(t&sb)", &page_id, &element_id, &hidden);
-
-               web_page = get_webkit_web_page_or_return_dbus_error (invocation, web_extension, page_id);
-               if (!web_page)
-                       return;
-
-               if (!element_id || !*element_id) {
-                       g_warn_if_fail (element_id && *element_id);
-               } else {
-                       gboolean expand_inner_data = FALSE;
-
-                       document = webkit_web_page_get_dom_document (web_page);
-                       /* A secret short-cut, to not have two functions for basically the same thing ("hide 
attachment" and "hide element") */
-                       if (!hidden && g_str_has_prefix (element_id, "attachment-wrapper-")) {
-                               WebKitDOMElement *element;
-
-                               element = e_dom_utils_find_element_by_id (document, element_id);
-
-                               if (WEBKIT_DOM_IS_HTML_ELEMENT (element) &&
-                                   webkit_dom_element_get_child_element_count (element) == 0) {
-                                       gchar *inner_html_data;
-
-                                       expand_inner_data = TRUE;
-
-                                       inner_html_data = webkit_dom_element_get_attribute (element, 
"inner-html-data");
-                                       if (inner_html_data && *inner_html_data) {
-                                               gchar *related_part_id;
-
-                                               webkit_dom_element_set_inner_html (element, inner_html_data, 
NULL);
-                                               webkit_dom_element_remove_attribute (element, 
"inner-html-data");
-
-                                               related_part_id = webkit_dom_element_get_attribute (element, 
"related-part-id");
-                                               webkit_dom_element_remove_attribute (element, 
"related-part-id");
-
-                                               if (related_part_id && *related_part_id) {
-                                                       GVariant *params = g_variant_new ("(ts)", page_id, 
related_part_id);
-                                                       WebKitDOMElement *iframe;
-
-                                                       iframe = webkit_dom_element_query_selector (element, 
"iframe", NULL);
-                                                       if (iframe) {
-                                                               WebKitDOMDocument *iframe_document;
-
-                                                               iframe_document = 
webkit_dom_html_iframe_element_get_content_document (WEBKIT_DOM_HTML_IFRAME_ELEMENT (iframe));
-                                                               if (iframe_document) {
-                                                                       WebKitDOMHTMLElement *iframe_body;
-
-                                                                       iframe_body = 
webkit_dom_document_get_body (iframe_document);
-                                                                       if (iframe_body && 
!webkit_dom_element_get_first_element_child (WEBKIT_DOM_ELEMENT (iframe_body))) {
-                                                                               /* The iframe document is 
still empty, wait until it's loaded;
-                                                                                  wish being there something 
better than this busy-wait... */
-                                                                               MailPartAppearedData *mpad;
-
-                                                                               mpad = g_new0 
(MailPartAppearedData, 1);
-                                                                               mpad->dbus_connection = 
e_weak_ref_new (extension->priv->dbus_connection);
-                                                                               mpad->web_page = 
e_weak_ref_new (web_page);
-                                                                               mpad->element_id = g_strdup 
(element_id);
-                                                                               mpad->params = params;
-
-                                                                               /* Try 10 times per second */
-                                                                               g_timeout_add (100, 
web_extension_emit_mail_part_appeared_cb, mpad);
-
-                                                                               /* To not emit the signal 
below */
-                                                                               params = NULL;
-                                                                       }
-                                                               }
-                                                       }
-
-                                                       if (params) {
-                                                               GError *error = NULL;
-
-                                                               g_dbus_connection_emit_signal (
-                                                                       extension->priv->dbus_connection,
-                                                                       NULL,
-                                                                       E_WEB_EXTENSION_OBJECT_PATH,
-                                                                       E_WEB_EXTENSION_INTERFACE,
-                                                                       "MailPartAppeared",
-                                                                       params,
-                                                                       &error);
-
-                                                               if (error) {
-                                                                       g_warning ("Error emitting signal 
MailPartAppeared: %s", error->message);
-                                                                       g_error_free (error);
-                                                               }
-                                                       }
-                                               }
-
-                                               g_free (related_part_id);
-                                       }
-
-                                       g_free (inner_html_data);
-                               }
-                       }
-
-                       e_dom_utils_hide_element (document, element_id, hidden);
-
-                       if (expand_inner_data)
-                               e_dom_resize_document_content_to_preview_width (document);
-               }
-
-               g_dbus_method_invocation_return_value (invocation, NULL);
-       } else if (g_strcmp0 (method_name, "SetElementStyleProperty") == 0) {
-               const gchar *element_id = NULL, *property_name = NULL, *value = NULL, *priority = NULL;
-
-               g_variant_get (parameters, "(t&s&s&s&s)", &page_id, &element_id, &property_name, &value, 
&priority);
-
-               web_page = get_webkit_web_page_or_return_dbus_error (invocation, web_extension, page_id);
-               if (!web_page)
-                       return;
-
-               if (!element_id || !*element_id || !property_name || !*property_name) {
-                       g_warn_if_fail (element_id && *element_id);
-                       g_warn_if_fail (property_name && *property_name);
-               } else {
-                       WebKitDOMElement *element;
-                       gboolean use_child = FALSE;
-                       gchar *tmp = NULL;
-
-                       /* element_id can be also of the form: "id::child", where the change will
-                          be done on the first child of it */
-                       use_child = g_str_has_suffix (element_id, "::child");
-                       if (use_child) {
-                               tmp = g_strdup (element_id);
-                               tmp[strlen (tmp) - 7] = '\0';
-
-                               element_id = tmp;
-                       }
-
-                       document = webkit_web_page_get_dom_document (web_page);
-                       element = e_dom_utils_find_element_by_id (document, element_id);
-
-                       if (use_child && element)
-                               element = webkit_dom_element_get_first_element_child (element);
-
-                       if (element) {
-                               WebKitDOMCSSStyleDeclaration *css;
-
-                               css = webkit_dom_element_get_style (element);
-
-                               if (value && *value)
-                                       webkit_dom_css_style_declaration_set_property (css, property_name, 
value, priority, NULL);
-                               else
-                                       g_free (webkit_dom_css_style_declaration_remove_property (css, 
property_name, NULL));
-
-                               g_clear_object (&css);
-                       }
-
-                       g_free (tmp);
-               }
-
-               g_dbus_method_invocation_return_value (invocation, NULL);
-       } else if (g_strcmp0 (method_name, "SetElementAttribute") == 0) {
-               const gchar *element_id = NULL, *namespace_uri = NULL, *qualified_name = NULL, *value = NULL;
-
-               g_variant_get (parameters, "(t&s&s&s&s)", &page_id, &element_id, &namespace_uri, 
&qualified_name, &value);
-
-               web_page = get_webkit_web_page_or_return_dbus_error (invocation, web_extension, page_id);
-               if (!web_page)
-                       return;
-
-               if (!element_id || !*element_id || !qualified_name || !*qualified_name) {
-                       g_warn_if_fail (element_id && *element_id);
-                       g_warn_if_fail (qualified_name && *qualified_name);
-               } else {
-                       WebKitDOMElement *element;
-                       gboolean use_child = FALSE;
-                       gchar *tmp = NULL;
-
-                       /* element_id can be also of the form: "id::child", where the change will
-                          be done on the first child of it */
-                       use_child = g_str_has_suffix (element_id, "::child");
-                       if (use_child) {
-                               tmp = g_strdup (element_id);
-                               tmp[strlen (tmp) - 7] = '\0';
-
-                               element_id = tmp;
-                       }
-
-                       if (namespace_uri && !*namespace_uri)
-                               namespace_uri = NULL;
-
-                       document = webkit_web_page_get_dom_document (web_page);
-                       element = e_dom_utils_find_element_by_id (document, element_id);
-
-                       if (use_child && element)
-                               element = webkit_dom_element_get_first_element_child (element);
-
-                       if (element) {
-                               if (value && *value)
-                                       webkit_dom_element_set_attribute_ns (element, namespace_uri, 
qualified_name, value, NULL);
-                               else
-                                       webkit_dom_element_remove_attribute_ns (element, namespace_uri, 
qualified_name);
-                       }
-
-                       g_free (tmp);
-               }
-
-               g_dbus_method_invocation_return_value (invocation, NULL);
-       } else if (g_strcmp0 (method_name, "DocumentHasSelection") == 0) {
-               gboolean has_selection;
-
-               g_variant_get (parameters, "(t)", &page_id);
-               web_page = get_webkit_web_page_or_return_dbus_error (
-                       invocation, web_extension, page_id);
-               if (!web_page)
-                       return;
-
-               document = webkit_web_page_get_dom_document (web_page);
-               has_selection = e_dom_utils_document_has_selection (document);
-
-               g_dbus_method_invocation_return_value (
-                       invocation, g_variant_new ("(b)", has_selection));
-       } else if (g_strcmp0 (method_name, "GetDocumentContentHTML") == 0) {
-               gchar *html_content;
-
-               g_variant_get (parameters, "(t)", &page_id);
-               web_page = get_webkit_web_page_or_return_dbus_error (
-                       invocation, web_extension, page_id);
-               if (!web_page)
-                       return;
-
-               document = webkit_web_page_get_dom_document (web_page);
-               html_content = e_dom_utils_get_document_content_html (document);
-
-               g_dbus_method_invocation_return_value (
-                       invocation,
-                       g_variant_new (
-                               "(@s)",
-                               g_variant_new_take_string (
-                                       html_content ? html_content : g_strdup (""))));
-       } else if (g_strcmp0 (method_name, "GetSelectionContentHTML") == 0) {
-               gchar *html_content;
-
-               g_variant_get (parameters, "(t)", &page_id);
-               web_page = get_webkit_web_page_or_return_dbus_error (
-                       invocation, web_extension, page_id);
-               if (!web_page)
-                       return;
-
-               document = webkit_web_page_get_dom_document (web_page);
-               html_content = e_dom_utils_get_selection_content_html (document);
-
-               g_dbus_method_invocation_return_value (
-                       invocation,
-                       g_variant_new (
-                               "(@s)",
-                               g_variant_new_take_string (
-                                       html_content ? html_content : g_strdup (""))));
-       } else if (g_strcmp0 (method_name, "GetSelectionContentMultipart") == 0) {
-               gchar *text_content;
-               gboolean is_html = FALSE;
-
-               g_variant_get (parameters, "(t)", &page_id);
-               web_page = get_webkit_web_page_or_return_dbus_error (
-                       invocation, web_extension, page_id);
-               if (!web_page)
-                       return;
-
-               document = webkit_web_page_get_dom_document (web_page);
-               text_content = e_dom_utils_get_selection_content_multipart (document, &is_html);
-
-               g_dbus_method_invocation_return_value (
-                       invocation,
-                       g_variant_new (
-                               "(@sb)",
-                               g_variant_new_take_string (
-                                       text_content ? text_content : g_strdup ("")),
-                               is_html));
-       } else if (g_strcmp0 (method_name, "GetSelectionContentText") == 0) {
-               gchar *text_content;
-
-               g_variant_get (parameters, "(t)", &page_id);
-               web_page = get_webkit_web_page_or_return_dbus_error (
-                       invocation, web_extension, page_id);
-               if (!web_page)
-                       return;
-
-               document = webkit_web_page_get_dom_document (web_page);
-               text_content = e_dom_utils_get_selection_content_text (document);
-
-               g_dbus_method_invocation_return_value (
-                       invocation,
-                       g_variant_new (
-                               "(@s)",
-                               g_variant_new_take_string (
-                                       text_content ? text_content : g_strdup (""))));
-       } else if (g_strcmp0 (method_name, "AddCSSRuleIntoStyleSheet") == 0) {
-               const gchar *style_sheet_id, *selector, *style;
-
-               g_variant_get (
-                       parameters,
-                       "(t&s&s&s)",
-                       &page_id, &style_sheet_id, &selector, &style);
-
-               web_page = get_webkit_web_page_or_return_dbus_error (
-                       invocation, web_extension, page_id);
-               if (!web_page)
-                       return;
-
-               document = webkit_web_page_get_dom_document (web_page);
-               e_dom_utils_add_css_rule_into_style_sheet (document, style_sheet_id, selector, style);
-
-               g_dbus_method_invocation_return_value (invocation, NULL);
-       } else if (g_strcmp0 (method_name, "CreateAndAddCSSStyleSheet") == 0) {
-               const gchar *style_sheet_id;
-
-               g_variant_get (parameters, "(t&s)", &page_id, &style_sheet_id);
-               web_page = get_webkit_web_page_or_return_dbus_error (
-                       invocation, web_extension, page_id);
-               if (!web_page)
-                       return;
-
-               document = webkit_web_page_get_dom_document (web_page);
-               e_dom_utils_create_and_add_css_style_sheet (document, style_sheet_id);
-
-               g_dbus_method_invocation_return_value (invocation, NULL);
-       } else if (g_strcmp0 (method_name, "EABContactFormatterBindDOM") == 0) {
-               g_variant_get (parameters, "(t)", &page_id);
-               web_page = get_webkit_web_page_or_return_dbus_error (
-                       invocation, web_extension, page_id);
-               if (!web_page)
-                       return;
-
-               document = webkit_web_page_get_dom_document (web_page);
-               e_dom_utils_eab_contact_formatter_bind_dom (document);
-
-               g_dbus_method_invocation_return_value (invocation, NULL);
-       } else if (g_strcmp0 (method_name, "EMailDisplayBindDOM") == 0) {
-               g_variant_get (parameters, "(t)", &page_id);
-               web_page = get_webkit_web_page_or_return_dbus_error (
-                       invocation, web_extension, page_id);
-               if (!web_page)
-                       return;
-
-               document = webkit_web_page_get_dom_document (web_page);
-               e_dom_utils_e_mail_display_unstyle_blockquotes (document);
-               e_dom_utils_e_mail_display_bind_dom (document, connection);
-               e_web_extension_bind_focus_on_elements (extension, document);
-
-               g_dbus_method_invocation_return_value (invocation, NULL);
-       } else if (g_strcmp0 (method_name, "ElementExists") == 0) {
-               const gchar *element_id;
-               gboolean element_exists;
-
-               g_variant_get (parameters, "(t&s)", &page_id, &element_id);
-               web_page = get_webkit_web_page_or_return_dbus_error (
-                       invocation, web_extension, page_id);
-               if (!web_page)
-                       return;
-
-               document = webkit_web_page_get_dom_document (web_page);
-               element_exists = e_dom_utils_element_exists (document, element_id);
-
-               g_dbus_method_invocation_return_value (
-                       invocation, g_variant_new ("(bt)", element_exists, page_id));
-       } else if (g_strcmp0 (method_name, "GetActiveElementName") == 0) {
-               gchar *element_name;
-
-               g_variant_get (parameters, "(t)", &page_id);
-               web_page = get_webkit_web_page_or_return_dbus_error (
-                       invocation, web_extension, page_id);
-               if (!web_page)
-                       return;
-
-               document = webkit_web_page_get_dom_document (web_page);
-               element_name = e_dom_utils_get_active_element_name (document);
-
-               g_dbus_method_invocation_return_value (
-                       invocation,
-                       g_variant_new (
-                               "(@s)",
-                               g_variant_new_take_string (
-                                       element_name ? element_name : g_strdup (""))));
-       } else if (g_strcmp0 (method_name, "EMailPartHeadersBindDOMElement") == 0) {
-               const gchar *element_id;
-
-               g_variant_get (parameters, "(t&s)", &page_id, &element_id);
-               web_page = get_webkit_web_page_or_return_dbus_error (
-                       invocation, web_extension, page_id);
-               if (!web_page)
-                       return;
-
-               document = webkit_web_page_get_dom_document (web_page);
-               e_dom_utils_e_mail_part_headers_bind_dom_element (document, element_id);
-
-               g_dbus_method_invocation_return_value (invocation, NULL);
-       } else if (g_strcmp0 (method_name, "VCardInlineBindDOM") == 0) {
-               const gchar *element_id;
-
-               g_variant_get (parameters, "(t&s)", &page_id, &element_id);
-               web_page = get_webkit_web_page_or_return_dbus_error (
-                       invocation, web_extension, page_id);
-               if (!web_page)
-                       return;
-
-               document = webkit_web_page_get_dom_document (web_page);
-               e_dom_utils_module_vcard_inline_bind_dom (
-                       document, element_id, connection);
-
-               g_dbus_method_invocation_return_value (invocation, NULL);
-       } else if (g_strcmp0 (method_name, "VCardInlineUpdateButton") == 0) {
-               const gchar *button_id, *html_label, *access_key;
-
-               g_variant_get (
-                       parameters,
-                       "(t&s&s&s)",
-                       &page_id, &button_id, &html_label, &access_key);
-
-               web_page = get_webkit_web_page_or_return_dbus_error (
-                       invocation, web_extension, page_id);
-               if (!web_page)
-                       return;
-
-               document = webkit_web_page_get_dom_document (web_page);
-               e_dom_utils_module_vcard_inline_update_button (
-                       document, button_id, html_label, access_key);
-
-               g_dbus_method_invocation_return_value (invocation, NULL);
-       } else if (g_strcmp0 (method_name, "VCardInlineSetIFrameSrc") == 0) {
-               const gchar *src, *button_id;
-
-               g_variant_get (parameters, "(t&s&s)", &page_id, &button_id, &src);
-               web_page = get_webkit_web_page_or_return_dbus_error (
-                       invocation, web_extension, page_id);
-               if (!web_page)
-                       return;
-
-               document = webkit_web_page_get_dom_document (web_page);
-               e_dom_utils_module_vcard_inline_set_iframe_src (document, button_id, src);
-
-               g_dbus_method_invocation_return_value (invocation, NULL);
-       } else if (g_strcmp0 (method_name, "GetDocumentURIFromPoint") == 0) {
-               WebKitDOMDocument *document_at_point;
-               gchar *document_uri = NULL;
-               gint32 xx = 0, yy = 0;
-
-               g_variant_get (parameters, "(tii)", &page_id, &xx, &yy);
-               web_page = get_webkit_web_page_or_return_dbus_error (invocation, web_extension, page_id);
-               if (!web_page)
-                       return;
-
-               document = webkit_web_page_get_dom_document (web_page);
-               document_at_point = e_dom_utils_get_document_from_point (document, xx, yy);
-
-               if (document_at_point)
-                       document_uri = webkit_dom_document_get_document_uri (document_at_point);
-
-               g_dbus_method_invocation_return_value (
-                       invocation,
-                       g_variant_new ("(@s)", g_variant_new_take_string (document_uri ? document_uri : 
g_strdup (""))));
-       } else if (g_strcmp0 (method_name, "SetDocumentIFrameSrc") == 0) {
-               const gchar *document_uri = NULL, *new_iframe_src = NULL;
-               WebKitDOMDocument *iframe_document;
-
-               g_variant_get (parameters, "(t&s&s)", &page_id, &document_uri, &new_iframe_src);
-               web_page = get_webkit_web_page_or_return_dbus_error (invocation, web_extension, page_id);
-               if (!web_page)
-                       return;
-
-               document = webkit_web_page_get_dom_document (web_page);
-               iframe_document = e_dom_utils_find_document_with_uri (document, document_uri);
-
-               if (iframe_document) {
-                       WebKitDOMDOMWindow *dom_window;
-                       WebKitDOMElement *frame_element;
-
-                       /* Get frame's window and from the window the actual <iframe> element */
-                       dom_window = webkit_dom_document_get_default_view (iframe_document);
-                       frame_element = webkit_dom_dom_window_get_frame_element (dom_window);
-                       webkit_dom_html_iframe_element_set_src (
-                               WEBKIT_DOM_HTML_IFRAME_ELEMENT (frame_element), new_iframe_src);
-                       g_clear_object (&dom_window);
-               }
-
-               g_dbus_method_invocation_return_value (invocation, NULL);
-       } else if (g_strcmp0 (method_name, "ProcessMagicSpacebar") == 0) {
-               gboolean towards_bottom = FALSE, processed = FALSE;
-               WebKitDOMDOMWindow *dom_window;
-               glong inner_height = -1, scroll_y_before = -1, scroll_y_after = -1;
-
-               g_variant_get (parameters, "(tb)", &page_id, &towards_bottom);
-               web_page = get_webkit_web_page_or_return_dbus_error (invocation, web_extension, page_id);
-               if (!web_page)
-                       return;
-
-               document = webkit_web_page_get_dom_document (web_page);
-               dom_window = webkit_dom_document_get_default_view (document);
-
-               g_object_get (G_OBJECT (dom_window),
-                       "inner-height", &inner_height,
-                       "scroll-y", &scroll_y_before,
-                       NULL);
-
-               if (inner_height) {
-                       webkit_dom_dom_window_scroll_by (dom_window, 0, towards_bottom ? inner_height : 
-inner_height);
-
-                       g_object_get (G_OBJECT (dom_window),
-                               "scroll-y", &scroll_y_after,
-                               NULL);
-
-                       processed = scroll_y_before != scroll_y_after;
-               }
-
-               g_dbus_method_invocation_return_value (invocation, g_variant_new ("(b)", processed));
-       } else if (g_strcmp0 (method_name, "EWebViewEnsureBodyClass") == 0) {
-               const gchar *body_class = NULL;
-               WebKitDOMHTMLElement *body;
-
-               g_variant_get (parameters, "(t&s)", &page_id, &body_class);
-               web_page = get_webkit_web_page_or_return_dbus_error (invocation, web_extension, page_id);
-               if (!web_page)
-                       return;
-
-               document = webkit_web_page_get_dom_document (web_page);
-
-               body = webkit_dom_document_get_body (document);
-               if (body && !webkit_dom_element_has_attribute (WEBKIT_DOM_ELEMENT (body), "class"))
-                       webkit_dom_element_set_class_name (WEBKIT_DOM_ELEMENT (body), body_class);
-
-               g_dbus_method_invocation_return_value (invocation, NULL);
-       } else if (g_strcmp0 (method_name, "ItipCreateDOMBindings") == 0) {
-               const gchar *part_id = NULL;
-
-               g_variant_get (parameters, "(t&s)", &page_id, &part_id);
-
-               document = get_webkit_document_or_return_dbus_error (invocation, web_extension, page_id);
-               if (document)
-                       document = find_webkit_document_for_partid_or_return_dbus_error (invocation, 
document, part_id);
-               if (document) {
-                       e_itip_formatter_dom_utils_create_dom_bindings (document, page_id, part_id, 
connection);
-                       g_dbus_method_invocation_return_value (invocation, NULL);
-               }
-       } else if (g_strcmp0 (method_name, "ItipShowButton") == 0) {
-               const gchar *button_id, *part_id = NULL;
-
-               g_variant_get (parameters, "(t&s&s)", &page_id, &part_id, &button_id);
-
-               document = get_webkit_document_or_return_dbus_error (invocation, web_extension, page_id);
-               if (document)
-                       document = find_webkit_document_for_partid_or_return_dbus_error (invocation, 
document, part_id);
-               if (document) {
-                       e_itip_formatter_dom_utils_show_button (document, button_id);
-                       g_dbus_method_invocation_return_value (invocation, NULL);
-               }
-       } else if (g_strcmp0 (method_name, "ItipEnableButton") == 0) {
-               const gchar *button_id, *part_id = NULL;
-               gboolean enable;
-
-               g_variant_get (parameters, "(t&s&sb)", &page_id, &part_id, &button_id, &enable);
-
-               document = get_webkit_document_or_return_dbus_error (invocation, web_extension, page_id);
-               if (document)
-                       document = find_webkit_document_for_partid_or_return_dbus_error (invocation, 
document, part_id);
-               if (document) {
-                       e_itip_formatter_dom_utils_enable_button (document, button_id, enable);
-                       g_dbus_method_invocation_return_value (invocation, NULL);
-               }
-       } else if (g_strcmp0 (method_name, "ItipElementSetInnerHTML") == 0) {
-               const gchar *element_id, *inner_html, *part_id = NULL;
-
-               g_variant_get (parameters, "(t&s&s&s)", &page_id, &part_id, &element_id, &inner_html);
-
-               document = get_webkit_document_or_return_dbus_error (invocation, web_extension, page_id);
-               if (document)
-                       document = find_webkit_document_for_partid_or_return_dbus_error (invocation, 
document, part_id);
-               if (document) {
-                       e_dom_utils_element_set_inner_html (document, element_id, inner_html);
-                       g_dbus_method_invocation_return_value (invocation, NULL);
-               }
-       } else if (g_strcmp0 (method_name, "ItipRemoveElement") == 0) {
-               const gchar *element_id, *part_id = NULL;
-
-               g_variant_get (parameters, "(t&s&s)", &page_id, &part_id, &element_id);
-
-               document = get_webkit_document_or_return_dbus_error (invocation, web_extension, page_id);
-               if (document)
-                       document = find_webkit_document_for_partid_or_return_dbus_error (invocation, 
document, part_id);
-               if (document) {
-                       e_dom_utils_remove_element (document, element_id);
-                       g_dbus_method_invocation_return_value (invocation, NULL);
-               }
-       } else if (g_strcmp0 (method_name, "ItipElementRemoveChildNodes") == 0) {
-               const gchar *element_id, *part_id = NULL;
-
-               g_variant_get (parameters, "(t&s&s)", &page_id, &part_id, &element_id);
-
-               document = get_webkit_document_or_return_dbus_error (invocation, web_extension, page_id);
-               if (document)
-                       document = find_webkit_document_for_partid_or_return_dbus_error (invocation, 
document, part_id);
-               if (document) {
-                       e_dom_utils_element_remove_child_nodes (document, element_id);
-                       g_dbus_method_invocation_return_value (invocation, NULL);
-               }
-       } else if (g_strcmp0 (method_name, "ItipHideElement") == 0) {
-               const gchar *element_id, *part_id = NULL;
-               gboolean hide;
-
-               g_variant_get (parameters, "(t&s&sb)", &page_id, &part_id, &element_id, &hide);
-
-               document = get_webkit_document_or_return_dbus_error (invocation, web_extension, page_id);
-               if (document)
-                       document = find_webkit_document_for_partid_or_return_dbus_error (invocation, 
document, part_id);
-               if (document) {
-                       e_dom_utils_hide_element (document, element_id, hide);
-                       g_dbus_method_invocation_return_value (invocation, NULL);
-               }
-       } else if (g_strcmp0 (method_name, "ItipElementIsHidden") == 0) {
-               const gchar *element_id, *part_id = NULL;
-               gboolean hidden;
-
-               g_variant_get (parameters, "(t&s&s)", &page_id, &part_id, &element_id);
-
-               document = get_webkit_document_or_return_dbus_error (invocation, web_extension, page_id);
-               if (document)
-                       document = find_webkit_document_for_partid_or_return_dbus_error (invocation, 
document, part_id);
-               if (document) {
-                       hidden = e_dom_utils_element_is_hidden (document, element_id);
-                       g_dbus_method_invocation_return_value (invocation, g_variant_new ("(b)", hidden));
-               }
-       } else if (g_strcmp0 (method_name, "ItipInputSetChecked") == 0) {
-               const gchar *input_id, *part_id = NULL;
-               gboolean checked;
-
-               g_variant_get (parameters, "(t&s&sb)", &page_id, &part_id, &input_id, &checked);
-
-               document = get_webkit_document_or_return_dbus_error (invocation, web_extension, page_id);
-               if (document)
-                       document = find_webkit_document_for_partid_or_return_dbus_error (invocation, 
document, part_id);
-               if (document) {
-                       e_itip_formatter_dom_utils_input_set_checked (document, input_id, checked);
-                       g_dbus_method_invocation_return_value (invocation, NULL);
-               }
-       } else if (g_strcmp0 (method_name, "ItipInputIsChecked") == 0) {
-               const gchar *input_id, *part_id = NULL;
-               gboolean checked;
-
-               g_variant_get (parameters, "(t&s&s)", &page_id, &part_id, &input_id);
-
-               document = get_webkit_document_or_return_dbus_error (invocation, web_extension, page_id);
-               if (document)
-                       document = find_webkit_document_for_partid_or_return_dbus_error (invocation, 
document, part_id);
-               if (document) {
-                       checked = e_itip_formatter_dom_utils_input_is_checked (document, input_id);
-                       g_dbus_method_invocation_return_value (invocation, g_variant_new ("(b)", checked));
-               }
-       } else if (g_strcmp0 (method_name, "ItipShowCheckbox") == 0) {
-               const gchar *id, *part_id = NULL;
-               gboolean show, update_second;
-
-               g_variant_get (parameters, "(t&s&sbb)", &page_id, &part_id, &id, &show, &update_second);
-
-               document = get_webkit_document_or_return_dbus_error (invocation, web_extension, page_id);
-               if (document)
-                       document = find_webkit_document_for_partid_or_return_dbus_error (invocation, 
document, part_id);
-               if (document) {
-                       e_itip_formatter_dom_utils_show_checkbox (document, id, show, update_second);
-                       g_dbus_method_invocation_return_value (invocation, NULL);
-               }
-       } else if (g_strcmp0 (method_name, "ItipSetButtonsSensitive") == 0) {
-               const gchar *part_id = NULL;
-               gboolean sensitive;
-
-               g_variant_get (parameters, "(t&sb)", &page_id, &part_id, &sensitive);
-
-               document = get_webkit_document_or_return_dbus_error (invocation, web_extension, page_id);
-               if (document)
-                       document = find_webkit_document_for_partid_or_return_dbus_error (invocation, 
document, part_id);
-               if (document) {
-                       e_itip_formatter_dom_utils_set_buttons_sensitive (document, sensitive);
-                       g_dbus_method_invocation_return_value (invocation, NULL);
-               }
-       } else if (g_strcmp0 (method_name, "ItipSetAreaText") == 0) {
-               const gchar *id, *text, *part_id = NULL;
-
-               g_variant_get (parameters, "(t&s&s&s)", &page_id, &part_id, &id, &text);
-
-               document = get_webkit_document_or_return_dbus_error (invocation, web_extension, page_id);
-               if (document)
-                       document = find_webkit_document_for_partid_or_return_dbus_error (invocation, 
document, part_id);
-               if (document) {
-                       e_itip_formatter_dom_utils_set_area_text (document, id, text);
-                       g_dbus_method_invocation_return_value (invocation, NULL);
-               }
-       } else if (g_strcmp0 (method_name, "ItipElementSetAccessKey") == 0) {
-               const gchar *element_id, *access_key, *part_id = NULL;
-
-               g_variant_get (parameters, "(t&s&s&s)", &page_id, &part_id, &element_id, &access_key);
-
-               document = get_webkit_document_or_return_dbus_error (invocation, web_extension, page_id);
-               if (document)
-                       document = find_webkit_document_for_partid_or_return_dbus_error (invocation, 
document, part_id);
-               if (document) {
-                       e_itip_formatter_dom_utils_element_set_access_key (document, element_id, access_key);
-                       g_dbus_method_invocation_return_value (invocation, NULL);
-               }
-       } else if (g_strcmp0 (method_name, "ItipElementHideChildNodes") == 0) {
-               const gchar *element_id, *part_id = NULL;
-
-               g_variant_get (parameters, "(t&s&s)", &page_id, &part_id, &element_id);
-
-               document = get_webkit_document_or_return_dbus_error (invocation, web_extension, page_id);
-               if (document)
-                       document = find_webkit_document_for_partid_or_return_dbus_error (invocation, 
document, part_id);
-               if (document) {
-                       e_itip_formatter_dom_utils_element_hide_child_nodes (document, element_id);
-                       g_dbus_method_invocation_return_value (invocation, NULL);
-               }
-       } else if (g_strcmp0 (method_name, "ItipEnableSelect") == 0) {
-               const gchar *select_id, *part_id = NULL;
-               gboolean enable;
-
-               g_variant_get (parameters, "(t&s&sb)", &page_id, &part_id, &select_id, &enable);
-
-               document = get_webkit_document_or_return_dbus_error (invocation, web_extension, page_id);
-               if (document)
-                       document = find_webkit_document_for_partid_or_return_dbus_error (invocation, 
document, part_id);
-               if (document) {
-                       e_itip_formatter_dom_utils_enable_select (document, select_id, enable);
-                       g_dbus_method_invocation_return_value (invocation, NULL);
-               }
-       } else if (g_strcmp0 (method_name, "ItipSelectIsEnabled") == 0) {
-               const gchar *select_id, *part_id = NULL;
-               gboolean enabled;
-
-               g_variant_get (parameters, "(t&s&s)", &page_id, &part_id, &select_id);
-
-               document = get_webkit_document_or_return_dbus_error (invocation, web_extension, page_id);
-               if (document)
-                       document = find_webkit_document_for_partid_or_return_dbus_error (invocation, 
document, part_id);
-               if (document) {
-                       enabled = e_itip_formatter_dom_utils_select_is_enabled (document, select_id);
-                       g_dbus_method_invocation_return_value (invocation, g_variant_new ("(b)", enabled));
-               }
-       } else if (g_strcmp0 (method_name, "ItipSelectGetValue") == 0) {
-               const gchar *select_id, *part_id = NULL;
-               gchar *value;
-
-               g_variant_get (parameters, "(t&s&s)", &page_id, &part_id, &select_id);
-
-               document = get_webkit_document_or_return_dbus_error (invocation, web_extension, page_id);
-               if (document)
-                       document = find_webkit_document_for_partid_or_return_dbus_error (invocation, 
document, part_id);
-               if (document) {
-                       value = e_itip_formatter_dom_utils_select_get_value (document, select_id);
-                       g_dbus_method_invocation_return_value (invocation,
-                               g_variant_new (
-                                       "(@s)",
-                                       g_variant_new_take_string (value ? value : g_strdup (""))));
-               }
-       } else if (g_strcmp0 (method_name, "ItipSelectSetSelected") == 0) {
-               const gchar *select_id, *option, *part_id = NULL;
-
-               g_variant_get (parameters, "(t&s&s&s)", &page_id, &part_id, &select_id, &option);
-
-               document = get_webkit_document_or_return_dbus_error (invocation, web_extension, page_id);
-               if (document)
-                       document = find_webkit_document_for_partid_or_return_dbus_error (invocation, 
document, part_id);
-               if (document) {
-                       e_itip_formatter_dom_utils_select_set_selected (document, select_id, option);
-                       g_dbus_method_invocation_return_value (invocation, NULL);
-               }
-       } else if (g_strcmp0 (method_name, "ItipUpdateTimes") == 0) {
-               const gchar *element_id, *header, *label, *part_id = NULL;
-
-               g_variant_get (parameters, "(t&s&s&s&s)", &page_id, &part_id, &element_id, &header, &label);
-
-               document = get_webkit_document_or_return_dbus_error (invocation, web_extension, page_id);
-               if (document)
-                       document = find_webkit_document_for_partid_or_return_dbus_error (invocation, 
document, part_id);
-               if (document) {
-                       e_itip_formatter_dom_utils_update_times (document, element_id, header, label);
-                       g_dbus_method_invocation_return_value (invocation, NULL);
-               }
-       } else if (g_strcmp0 (method_name, "ItipAppendInfoItemRow") == 0) {
-               const gchar *table_id, *row_id, *icon_name, *message, *part_id = NULL;
-
-               g_variant_get (parameters, "(t&s&s&s&s&s)", &page_id, &part_id, &table_id, &row_id, 
&icon_name, &message);
-
-               document = get_webkit_document_or_return_dbus_error (invocation, web_extension, page_id);
-               if (document)
-                       document = find_webkit_document_for_partid_or_return_dbus_error (invocation, 
document, part_id);
-               if (document) {
-                       e_itip_formatter_dom_utils_append_info_item_row (document, table_id, row_id, 
icon_name, message);
-                       g_dbus_method_invocation_return_value (invocation, NULL);
-               }
-       } else if (g_strcmp0 (method_name, "ItipEnableTextArea") == 0) {
-               const gchar *area_id, *part_id = NULL;
-               gboolean enable;
-
-               g_variant_get (parameters, "(t&s&sb)", &page_id, &part_id, &area_id, &enable);
-
-               document = get_webkit_document_or_return_dbus_error (invocation, web_extension, page_id);
-               if (document)
-                       document = find_webkit_document_for_partid_or_return_dbus_error (invocation, 
document, part_id);
-               if (document) {
-                       e_itip_formatter_dom_utils_enable_text_area (document, area_id, enable);
-                       g_dbus_method_invocation_return_value (invocation, NULL);
-               }
-       } else if (g_strcmp0 (method_name, "ItipTextAreaSetValue") == 0) {
-               const gchar *area_id, *value, *part_id = NULL;
-
-               g_variant_get (parameters, "(t&s&s&s)", &page_id, &part_id, &area_id, &value);
-
-               document = get_webkit_document_or_return_dbus_error (invocation, web_extension, page_id);
-               if (document)
-                       document = find_webkit_document_for_partid_or_return_dbus_error (invocation, 
document, part_id);
-               if (document) {
-                       e_itip_formatter_dom_utils_text_area_set_value (document, area_id, value);
-                       g_dbus_method_invocation_return_value (invocation, NULL);
-               }
-       } else if (g_strcmp0 (method_name, "ItipTextAreaGetValue") == 0) {
-               const gchar *area_id, *part_id = NULL;
-               gchar *value;
-
-               g_variant_get (parameters, "(t&s&s)", &page_id, &part_id, &area_id);
-
-               document = get_webkit_document_or_return_dbus_error (invocation, web_extension, page_id);
-               if (document)
-                       document = find_webkit_document_for_partid_or_return_dbus_error (invocation, 
document, part_id);
-               if (document) {
-                       value = e_itip_formatter_dom_utils_text_area_get_value (document, area_id);
-                       g_dbus_method_invocation_return_value (invocation,
-                               g_variant_new (
-                                       "(@s)",
-                                       g_variant_new_take_string (value ? value : g_strdup (""))));
-               }
-       } else if (g_strcmp0 (method_name, "ItipRebuildSourceList") == 0) {
-               const gchar *optgroup_id, *optgroup_label, *option_id, *option_label, *part_id = NULL;
-               gboolean writable;
-
-               g_variant_get (parameters,"(t&s&s&s&s&sb)", &page_id, &part_id, &optgroup_id, 
&optgroup_label, &option_id, &option_label, &writable);
-
-               document = get_webkit_document_or_return_dbus_error (invocation, web_extension, page_id);
-               if (document)
-                       document = find_webkit_document_for_partid_or_return_dbus_error (invocation, 
document, part_id);
-               if (document) {
-                       e_itip_formatter_dom_utils_rebuild_source_list (
-                               document,
-                               optgroup_id,
-                               optgroup_label,
-                               option_id,
-                               option_label,
-                               writable);
-
-                       g_dbus_method_invocation_return_value (invocation, NULL);
-               }
-       }
-}
-
-static GVariant *
-handle_get_property (GDBusConnection *connection,
-                     const gchar *sender,
-                     const gchar *object_path,
-                     const gchar *interface_name,
-                     const gchar *property_name,
-                     GError **error,
-                     gpointer user_data)
-{
-       /* EWebExtension *extension = E_WEB_EXTENSION (user_data); */
-       GVariant *variant = NULL;
-
-       g_warn_if_reached ();
-
-       return variant;
-}
-
-static gboolean
-handle_set_property (GDBusConnection *connection,
-                     const gchar *sender,
-                     const gchar *object_path,
-                     const gchar *interface_name,
-                     const gchar *property_name,
-                     GVariant *variant,
-                     GError **error,
-                     gpointer user_data)
-{
-       /* EWebExtension *extension = E_WEB_EXTENSION (user_data); */
-
-       g_warn_if_reached ();
-
-       return TRUE;
-}
-
-static const GDBusInterfaceVTable interface_vtable = {
-       handle_method_call,
-       handle_get_property,
-       handle_set_property
-};
-
-static void
-web_page_gone_cb (gpointer user_data,
-                  GObject *gone_web_page)
-{
-       EWebExtension *extension = user_data;
-       GSList *link;
-
-       g_return_if_fail (E_IS_WEB_EXTENSION (extension));
-
-       for (link = extension->priv->pages; link; link = g_slist_next (link)) {
-               EWebPageData *page_data = link->data;
-
-               if (page_data && page_data->web_page == (gpointer) gone_web_page) {
-                       extension->priv->pages = g_slist_remove (extension->priv->pages, page_data);
-                       g_free (page_data);
-                       break;
-               }
-       }
-}
-
 static void
 e_web_extension_constructed (GObject *object)
 {
@@ -1882,17 +54,6 @@ e_web_extension_dispose (GObject *object)
 {
        EWebExtension *extension = E_WEB_EXTENSION (object);
 
-       if (extension->priv->dbus_connection) {
-               g_dbus_connection_unregister_object (
-                       extension->priv->dbus_connection,
-                       extension->priv->registration_id);
-               extension->priv->registration_id = 0;
-               g_clear_object (&extension->priv->dbus_connection);
-       }
-
-       g_slist_free_full (extension->priv->pages, g_free);
-       extension->priv->pages = NULL;
-
        g_clear_object (&extension->priv->wk_extension);
 
        G_OBJECT_CLASS (e_web_extension_parent_class)->dispose (object);
@@ -1907,15 +68,6 @@ e_web_extension_class_init (EWebExtensionClass *class)
 
        object_class->constructed = e_web_extension_constructed;
        object_class->dispose = e_web_extension_dispose;
-
-       signals[REGISTER_DBUS_CONNECTION] = g_signal_new (
-               "register-dbus-connection",
-               G_TYPE_FROM_CLASS (class),
-               G_SIGNAL_RUN_LAST,
-               0,
-               NULL, NULL,
-               NULL,
-               G_TYPE_NONE, 1, G_TYPE_DBUS_CONNECTION);
 }
 
 static void
@@ -1927,7 +79,7 @@ e_web_extension_init (EWebExtension *extension)
 }
 
 static gpointer
-e_web_extension_create_instance(gpointer data)
+e_web_extension_create_instance (gpointer data)
 {
        return g_object_new (E_TYPE_WEB_EXTENSION, NULL);
 }
@@ -1936,6 +88,7 @@ EWebExtension *
 e_web_extension_get (void)
 {
        static GOnce once_init = G_ONCE_INIT;
+
        return E_WEB_EXTENSION (g_once (&once_init, e_web_extension_create_instance, NULL));
 }
 
@@ -1973,218 +126,87 @@ web_page_send_request_cb (WebKitWebPage *web_page,
 }
 
 static void
-e_web_extension_store_page_id_on_document (WebKitWebPage *web_page)
-{
-       WebKitDOMDocument *document;
-       guint64 *ppage_id;
-
-       g_return_if_fail (WEBKIT_IS_WEB_PAGE (web_page));
-
-       ppage_id = g_new (guint64, 1);
-       *ppage_id = webkit_web_page_get_id (web_page);
-
-       document = webkit_web_page_get_dom_document (web_page);
-
-       g_object_set_data_full (G_OBJECT (document), WEB_EXTENSION_PAGE_ID_KEY, ppage_id, g_free);
-}
-
-static void
-web_page_document_loaded_cb (WebKitWebPage *web_page,
-                             gpointer user_data)
+web_page_created_cb (WebKitWebExtension *wk_extension,
+                     WebKitWebPage *web_page,
+                     EWebExtension *extension)
 {
-       WebKitDOMDocument *document;
-
-       e_web_extension_store_page_id_on_document (web_page);
-
-       document = webkit_web_page_get_dom_document (web_page);
-
-       e_dom_utils_replace_local_image_links (document);
-
-       if ((webkit_dom_document_query_selector (
-               document, "[data-evo-signature-plain-text-mode]", NULL))) {
-
-               WebKitDOMHTMLElement *body;
-
-               body = webkit_dom_document_get_body (document);
-
-               webkit_dom_element_set_attribute (
-                       WEBKIT_DOM_ELEMENT (body),
-                       "style",
-                       "font-family: Monospace;",
-                       NULL);
-       }
+       g_signal_connect_object (
+               web_page, "send-request",
+               G_CALLBACK (web_page_send_request_cb),
+               extension, 0);
 }
 
 static void
-e_web_extension_set_clipboard_flags (EWebExtension *extension,
-                                    WebKitDOMDocument *document,
-                                    guint32 clipboard_flags)
+load_javascript_file (JSCContext *jsc_context,
+                     const gchar *js_filename)
 {
-       EWebPageData *page_data = NULL;
-       guint64 page_id;
+       JSCValue *result;
+       JSCException *exception;
+       gchar *content, *filename, *resource_uri;
+       gsize length = 0;
        GError *error = NULL;
 
-       g_return_if_fail (E_IS_WEB_EXTENSION (extension));
-       g_return_if_fail (WEBKIT_DOM_IS_DOCUMENT (document));
-
-       page_id = e_web_extension_find_page_id_from_document (document);
-       g_return_if_fail (page_id != 0);
+       g_return_if_fail (jsc_context != NULL);
 
-       page_data = e_web_extension_get_page_data (extension, page_id);
+       filename = g_build_filename (EVOLUTION_WEBKITDATADIR, js_filename, NULL);
 
-       if (!page_data || page_data->clipboard_flags == clipboard_flags)
-               return;
+       if (!g_file_get_contents (filename, &content, &length, &error)) {
+               g_warning ("Failed to load '%s': %s", filename, error ? error->message : "Unknown error");
 
-       page_data->clipboard_flags = clipboard_flags;
+               g_clear_error (&error);
+               g_free (filename);
 
-       g_dbus_connection_emit_signal (
-               extension->priv->dbus_connection,
-               NULL,
-               E_WEB_EXTENSION_OBJECT_PATH,
-               E_WEB_EXTENSION_INTERFACE,
-               "ClipboardFlagsChanged",
-               g_variant_new ("(tu)", page_id, clipboard_flags),
-               &error);
-
-       if (error) {
-               g_warning ("Error emitting signal ClipboardFlagsChanged: %s\n", error->message);
-               g_error_free (error);
+               return;
        }
-}
-
-static void
-web_editor_selection_changed_cb (WebKitWebEditor *web_editor,
-                                 EWebExtension *extension)
-{
-       WebKitWebPage *web_page;
-       WebKitDOMDocument *document;
-       guint32 clipboard_flags = 0;
-
-       web_page = webkit_web_editor_get_page (web_editor);
-
-       document = webkit_web_page_get_dom_document (web_page);
-
-       if (e_dom_utils_document_has_selection (document))
-               clipboard_flags |= E_CLIPBOARD_CAN_COPY;
-
-       e_web_extension_set_clipboard_flags (extension, document, clipboard_flags);
-}
-
-static void
-web_page_notify_uri_cb (GObject *object,
-                       GParamSpec *param,
-                       gpointer user_data)
-{
-       EWebExtension *extension = user_data;
-       WebKitWebPage *web_page;
-       GSList *link;
-       const gchar *uri;
-
-       g_return_if_fail (E_IS_WEB_EXTENSION (extension));
-
-       web_page = WEBKIT_WEB_PAGE (object);
-       uri = webkit_web_page_get_uri (web_page);
-
-       for (link = extension->priv->pages; link; link = g_slist_next (link)) {
-               EWebPageData *page_data = link->data;
-
-               if (page_data && page_data->web_page == web_page) {
-                       gint new_stamp = 0;
-
-                       if (uri && *uri) {
-                               SoupURI *suri;
-
-                               suri = soup_uri_new (uri);
-                               if (suri) {
-                                       if (soup_uri_get_query (suri)) {
-                                               GHashTable *form;
-
-                                               form = soup_form_decode (soup_uri_get_query (suri));
-                                               if (form) {
-                                                       const gchar *evo_stamp;
-
-                                                       evo_stamp = g_hash_table_lookup (form, "evo-stamp");
-                                                       if (evo_stamp)
-                                                               new_stamp = (gint) g_ascii_strtoll 
(evo_stamp, NULL, 10);
 
-                                                       g_hash_table_destroy (form);
-                                               }
-                                       }
+       resource_uri = g_strconcat ("resource:///", js_filename, NULL);
 
-                                       soup_uri_free (suri);
-                               }
-                       }
+       result = jsc_context_evaluate_with_source_uri (jsc_context, content, length, resource_uri, 1);
 
-                       if (extension->priv->dbus_connection) {
-                               GError *error = NULL;
+       g_free (resource_uri);
 
-                               g_dbus_connection_emit_signal (
-                                       extension->priv->dbus_connection,
-                                       NULL,
-                                       E_WEB_EXTENSION_OBJECT_PATH,
-                                       E_WEB_EXTENSION_INTERFACE,
-                                       "ExtensionHandlesPage",
-                                       g_variant_new ("(ti)", webkit_web_page_get_id (web_page), new_stamp),
-                                       &error);
+       exception = jsc_context_get_exception (jsc_context);
 
-                               if (error) {
-                                       g_warning ("Error emitting signal ExtensionHandlesPage: %s", 
error->message);
-                                       g_error_free (error);
-                               }
-                       }
-
-                       page_data->stamp = new_stamp;
-                       return;
-               }
+       if (exception) {
+               g_warning ("Failed to call script '%s': %d:%d: %s",
+                       filename,
+                       jsc_exception_get_line_number (exception),
+                       jsc_exception_get_column_number (exception),
+                       jsc_exception_get_message (exception));
        }
 
-       g_warning ("%s: Cannot find web_page %p\n", G_STRFUNC, web_page);
+       g_clear_object (&result);
+       g_free (filename);
+       g_free (content);
 }
 
 static void
-web_page_created_cb (WebKitWebExtension *wk_extension,
-                     WebKitWebPage *web_page,
-                     EWebExtension *extension)
+window_object_cleared_cb (WebKitScriptWorld *world,
+                         WebKitWebPage *page,
+                         WebKitFrame *frame,
+                         gpointer user_data)
 {
-       EWebPageData *page_data;
-
-       page_data = g_new0 (EWebPageData, 1);
-       page_data->web_page = web_page;
-       page_data->need_input = FALSE;
-       page_data->clipboard_flags = 0;
-       page_data->stamp = 0;
-
-       e_web_extension_store_page_id_on_document (web_page);
-
-       extension->priv->pages = g_slist_prepend (extension->priv->pages, page_data);
+       JSCContext *jsc_context;
 
-       g_object_weak_ref (G_OBJECT (web_page), web_page_gone_cb, extension);
+       /* Load the javascript files only to the main frame, not to the subframes */
+       if (!webkit_frame_is_main_frame (frame))
+               return;
 
-       g_signal_connect_object (
-               web_page, "send-request",
-               G_CALLBACK (web_page_send_request_cb),
-               extension, 0);
+       jsc_context = webkit_frame_get_js_context (frame);
 
-       g_signal_connect_object (
-               web_page, "document-loaded",
-               G_CALLBACK (web_page_document_loaded_cb),
-               extension, 0);
+       /* Read e-convert.js first, because e-web-view.js uses it */
+       load_javascript_file (jsc_context, "e-convert.js");
+       load_javascript_file (jsc_context, "e-web-view.js");
 
-       g_signal_connect_object (
-               web_page, "notify::uri",
-               G_CALLBACK (web_page_notify_uri_cb),
-               extension, 0);
-
-       g_signal_connect_object (
-               webkit_web_page_get_editor (web_page), "selection-changed",
-               G_CALLBACK (web_editor_selection_changed_cb),
-               extension, 0);
+       g_clear_object (&jsc_context);
 }
 
 void
 e_web_extension_initialize (EWebExtension *extension,
                             WebKitWebExtension *wk_extension)
 {
+       WebKitScriptWorld *script_world;
+
        g_return_if_fail (E_IS_WEB_EXTENSION (extension));
 
        if (extension->priv->initialized)
@@ -2197,55 +219,11 @@ e_web_extension_initialize (EWebExtension *extension,
        g_signal_connect (
                wk_extension, "page-created",
                G_CALLBACK (web_page_created_cb), extension);
-}
-
-void
-e_web_extension_dbus_register (EWebExtension *extension,
-                               GDBusConnection *connection)
-{
-       GError *error = NULL;
-       static GDBusNodeInfo *introspection_data = NULL;
-
-       g_return_if_fail (E_IS_WEB_EXTENSION (extension));
-       g_return_if_fail (G_IS_DBUS_CONNECTION (connection));
-
-       if (!introspection_data) {
-               introspection_data =
-                       g_dbus_node_info_new_for_xml (introspection_xml, NULL);
-
-               extension->priv->registration_id =
-                       g_dbus_connection_register_object (
-                               connection,
-                               E_WEB_EXTENSION_OBJECT_PATH,
-                               introspection_data->interfaces[0],
-                               &interface_vtable,
-                               extension,
-                               NULL,
-                               &error);
-
-               if (!extension->priv->registration_id) {
-                       g_warning ("Failed to register object: %s\n", error->message);
-                       g_error_free (error);
-               } else {
-                       extension->priv->dbus_connection = g_object_ref (connection);
 
-                       g_signal_emit (extension, signals[REGISTER_DBUS_CONNECTION], 0, connection);
+       script_world = webkit_script_world_get_default ();
 
-                       g_dbus_connection_emit_signal (
-                               extension->priv->dbus_connection,
-                               NULL,
-                               E_WEB_EXTENSION_OBJECT_PATH,
-                               E_WEB_EXTENSION_INTERFACE,
-                               "ExtensionObjectReady",
-                               NULL,
-                               &error);
-
-                       if (error) {
-                               g_warning ("Error emitting signal ExtensionObjectReady: %s", error->message);
-                               g_error_free (error);
-                       }
-               }
-       }
+       g_signal_connect (script_world, "window-object-cleared",
+               G_CALLBACK (window_object_cleared_cb), NULL);
 }
 
 WebKitWebExtension *
@@ -2255,11 +233,3 @@ e_web_extension_get_webkit_extension (EWebExtension *extension)
 
        return extension->priv->wk_extension;
 }
-
-GDBusConnection *
-e_web_extension_get_dbus_connection (EWebExtension *extension)
-{
-       g_return_val_if_fail (E_IS_WEB_EXTENSION (extension), NULL);
-
-       return extension->priv->dbus_connection;
-}
diff --git a/src/web-extensions/e-web-extension.h b/src/web-extensions/e-web-extension.h
index 834b63c7fd..5bb941338c 100644
--- a/src/web-extensions/e-web-extension.h
+++ b/src/web-extensions/e-web-extension.h
@@ -20,7 +20,6 @@
 #define E_WEB_EXTENSION_H
 
 #include <glib-object.h>
-#include <gio/gio.h>
 #include <webkit2/webkit-web-extension.h>
 
 /* Standard GObject macros */
@@ -65,14 +64,9 @@ EWebExtension *      e_web_extension_get             (void);
 void           e_web_extension_initialize      (EWebExtension *extension,
                                                 WebKitWebExtension *wk_extension);
 
-void           e_web_extension_dbus_register   (EWebExtension *extension,
-                                                GDBusConnection *connection);
 WebKitWebExtension *
                e_web_extension_get_webkit_extension
                                                (EWebExtension *extension);
-GDBusConnection *
-               e_web_extension_get_dbus_connection
-                                               (EWebExtension *extension);
 G_END_DECLS
 
 #endif /* E_WEB_EXTENSION_H */



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